本人在做实验过程中,需要通过Java程序部署docker容器。故尝试搜集资料,实现在Java端可以操作部署docker容器。过程中遇到一些bug和坑,在此总结,供有需要的童鞋使用。主体配置以Ubuntu16为例。后面会附加给出mac的配置说明。

  1. docker安装
# 安装docker
curl -sSL https://get.daocloud.io/docker | sh 

# 查看是否安装成功
docker version

# 配置镜像加速
vim /etc/docker/daemon.json

{
    "registry-mirrors": [
        "https://registry.docker-cn.com"
    ]
}

# 重启docker服务
systemctl restart docker
systemctl enable docker

# 查看是否配置成功
docker info

# 安装hello-world
docker pull hello-world
# 运行容器
docker run hello-world
  1. 开放docker的对外访问端口2375(docker默认只能通过本地访问,我们需要开放其对外暴露的端口,供Java连接使用)
# docker.service的位置可以通过 systemctl status docker.service 查看获取
root@WebServer:~# systemctl status docker.service
● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2021-08-07 15:19:45 CST; 2h 11min ago
    
# 编辑 docker.service文件
vim /lib/systemd/system/docker.service

# 替换文件中的ExecStart字段
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock

# 使配置生效 需要重启docker服务
systemctl daemon-reload
systemctl restart docker

# 再次运行该命令,可以看到已经暴露2375端口
systemctl status docker.service
  1. Java端添加pom依赖
<dependency>
  <groupId>com.github.docker-java</groupId>
  <artifactId>docker-java</artifactId>
  <version>3.0.14</version>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.4</version>
</dependency>
<dependency>
  <groupId>javax.ws.rs</groupId>
  <artifactId>javax.ws.rs-api</artifactId>
  <version>2.1</version>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.inject</groupId>
  <artifactId>jersey-hk2</artifactId>
  <version>2.26</version>
</dependency>

注意:测试过程中,我在项目中使用到了springboot和eureka,后两个依赖是为了解决和springboot中的依赖冲突问题而引入的依赖。另外,eureka中也会存在依赖冲突,需要再多做一个配置(如果项目中没有eureka依赖可以忽略下面的配置)

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  <exclusions>
    <!-- Causes java.lang.NoSuchMethodError: javax.ws.rs.core.Response$Status$Family.familyOf(I)Ljavax/ws/rs/core/Response$Status$Family; -->
    <exclusion>
      <groupId>javax.ws.rs</groupId>
      <artifactId>jsr311-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>
  1. 编写工具类,用于操作docker

注:使用该工具类来操作docker,需要将main中的ip换为自己的服务器ip地址。通过运行该main方法,可以实现在远端服务器中创建一个hello-world的容器(远端服务器已经存在hello-world的镜像,没有镜像需要先拉取)

package com.ustb.zerotrust.util;

import com.alibaba.fastjson.JSONObject;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.core.DockerClientBuilder;



/*
# 开放docker的对外服务端口
vim /lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock

systemctl daemon-reload
systemctl restart docker
 */

public class DockerClientUtils {
    /**
     * 连接Docker服务器
     * @return
     */
    public DockerClient connectDocker(String dockerInstance){
        DockerClient dockerClient = DockerClientBuilder.getInstance(dockerInstance).build();
        dockerClient.infoCmd().exec();
        return dockerClient;
    }

    /**
     * 创建容器
     * @param client
     * @return
     */
    public CreateContainerResponse createContainers(DockerClient client, String containerName, String imageName){
        CreateContainerResponse container = client.createContainerCmd(imageName)
                .withName(containerName)
                .exec();
        return container;
    }

    /**
     * 启动容器
     * @param client
     * @param containerId
     */
    public void startContainer(DockerClient client,String containerId){
        client.startContainerCmd(containerId).exec();
    }

    /**
     * 启动容器
     * @param client
     * @param containerId
     */
    public void stopContainer(DockerClient client,String containerId){
        client.stopContainerCmd(containerId).exec();
    }

    /**
     * 删除容器
     * @param client
     * @param containerId
     */
    public void removeContainer(DockerClient client,String containerId){
        client.removeContainerCmd(containerId).exec();

    }

    public static void main(String[] args){
        DockerClientUtils dockerClientUtils =new DockerClientUtils();
        //连接Docker服务器
        DockerClient client = dockerClientUtils.connectDocker("tcp://远程服务器的ip:2375");
        //创建容器
        CreateContainerResponse container = dockerClientUtils.createContainers(client,"sny_hello","hello-world");
        //启动容器
        dockerClientUtils.startContainer(client,container.getId());
    }

}
  1. 运行程序后,可以在服务器中查看是否成功创建容器
docker ps -a
  1. 至此,完成了通过Java来操作docker的全过程,enjoy!!

附:若只想操作本机的话,另外本机是mac系统,可以进行如下操作来开放2375对外暴露端口

  1. 首先,需要下载安装docker的mac版本,在此不做过多赘述,可以参考其他博客文章
  2. 可以用 socat 来 fork 一个端口出来执行
docker run -it -d --name=socat -p 2375:2375 -v    /var/run/docker.sock:/var/run/docker.sock bobrik/socat TCP4-LISTEN:2375,fork,reuseaddr UNIX-CONNECT:/var/run/docker.sock
  1. 验证是否开放成功
lsof -i:2375
  1. Java程序端,将ip地址变为本机地址 localhost 即可成功部署到本地容器
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐