本人在做实验过程中,需要通过Java程序部署docker容器。故尝试搜集资料,实现在Java端可以操作部署docker容器。过程中遇到一些bug和坑,在此总结,供有需要的童鞋使用。主体配置以Ubuntu16为例。后面会附加给出mac的配置说明。
- 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
- 开放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
- 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>
- 编写工具类,用于操作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());
}
}
- 运行程序后,可以在服务器中查看是否成功创建容器
docker ps -a
- 至此,完成了通过Java来操作docker的全过程,enjoy!!
附:若只想操作本机的话,另外本机是mac系统,可以进行如下操作来开放2375对外暴露端口
- 首先,需要下载安装docker的mac版本,在此不做过多赘述,可以参考其他博客文章
- 可以用 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
- 验证是否开放成功
lsof -i:2375
- Java程序端,将ip地址变为本机地址 localhost 即可成功部署到本地容器