整合环境:
- 与docker 版本差异不大,基本都可以
API version: 1.26
开放docker api ,两种方式
- /etc/sysconfig/docker ,最后一行添加;开放端口:2375
-H tcp://0.0.0.0:2375- systemctl status docker 查询 docker.service 路径
vi /lib/systemd/system/docker.service
-H tcp://0.0.0.0:2375
重启docker
- systemctl daemon-reload && systemctl restart docker
开放端口:- irewall-cmd --zone=public --add-port=2375/tcp --permanent
测试API:- GET ip:2375/images/json
Java client 对接 docker api
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>3.3.0</version>
</dependency>
初始化client
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.core.DockerClientBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author xiaoshu
* @description docker client初始化
* @date 2023年03月19日 15:31
*/
@Slf4j
@Component
public class DockerApiConfig {
@Resource
private VirtualProperties virtualProperties;
@Bean
public DockerClient dockerClient(){
String url=virtualProperties.getDockerUrl();
//String url="tcp://192.168.1.250:2375";
DockerClient dockerClient = DockerClientBuilder.getInstance(url).build();
log.info("docker API初始化成功");
return dockerClient;
}
}
常用api封装
import com.github.dockerjava.api.model.Container;
import com.github.dockerjava.api.model.Image;
import com.param.ImageParam;
import com.vo.DockerBuildImageVo;
import com.vo.DockerContainerVo;
import com.vo.DockerPushVo;
import java.io.InputStream;
import java.util.List;
/**
* java-client docker-api 相关接口
*
* @author heyonghao
* @date 2023/4/12
*/
public interface DockerService {
/**
* 容器列表
* @return List<Container>
*/
List<Container> listContainer(Boolean showAll);
/**
* 查询容器日志信息
* @param containerId 容器id
* @param tail 行数
* @return List<String>
*/
List<String> logContainer(String containerId,Integer tail);
/**
* 查询容器详情,返回vo待定
* @param containerId
* @return
*/
String infoContainer(String containerId);
/**
* 删除容器
* @param containerId 容器id
* @return Boolean
*/
Boolean removeContainer(String containerId);
/**
* 停止容器
* @param containerId 容器id
* @return Boolean
*/
Boolean stopContainer(String containerId);
/**
* 启动容器
* @param containerId 容器id
* @return Boolean
*/
Boolean startContainer(String containerId);
/**
* 创建容器
* @param dockerContainerVo dockerContainerVo
* @return Boolean
*/
Boolean createContainer(DockerContainerVo dockerContainerVo);
/**
* 镜像列表
* @param imageParam
* @return List<Image>
*/
List<Image> images(ImageParam imageParam);
/**
* 镜像详情
* 返回vo待封装
* @param imageId 镜像id
* @return Image
*/
String imageInfo(String imageId);
/**
* 导入镜像文件
* @param tarInputStream 镜像tar文件流
* @return Boolean
*/
Boolean importImage(InputStream tarInputStream);
/**
* 镜像构建vo
* @param dockerBuildImageVo 构建参数
* @return Boolean
*/
Boolean buildImage(DockerBuildImageVo dockerBuildImageVo);
/**
* 推送本地镜像到 harbor 仓库
* @param dockerPushVo 推送参数
* @return Boolean
*/
Boolean pushDockerImageToHarbor(DockerPushVo dockerPushVo);
}
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.config.VirtualProperties;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.*;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.command.LogContainerResultCallback;
import com.param.ImageParam;
import com.service.DockerService;
import com.vo.DockerBuildImageVo;
import com.vo.DockerContainerVo;
import com.vo.DockerPushVo;
import com.vo.LabelsOrKvVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.io.InputStream;
import java.util.*;
/**
* xxx
*
* @author heyonghao
* @date 2023/4/12
*/
@Slf4j
@Service
public class DockerServiceImpl implements DockerService {
@Resource
private DockerClient dockerClient;
@Resource
private VirtualProperties virtualProperties;
@Override
public List<Container> listContainer(Boolean showAll) {
ListContainersCmd listContainersCmd = dockerClient.listContainersCmd();
ListContainersCmd containersCmd = listContainersCmd.withShowAll(showAll);
return containersCmd.exec();
}
@Override
public List<String> logContainer(String containerId, Integer tail) {
List<String> logs = new LinkedList<>();
LogContainerCmd logContainerCmd = dockerClient.logContainerCmd(containerId);
logContainerCmd.withStdOut(true).withStdErr(true);
//显示行数
logContainerCmd.withTail(10);
try {
logContainerCmd.exec(new LogContainerResultCallback() {
@Override
public void onNext(Frame item) {
logs.add(item.toString());
}
}).awaitCompletion();
} catch (InterruptedException e) {
throw new RuntimeException("Failed to retrieve logs of container " + containerId, e);
}
return logs;
}
@Override
public String infoContainer(String containerId) {
InspectContainerCmd inspectContainerCmd = dockerClient.inspectContainerCmd(containerId);
InspectContainerResponse response = inspectContainerCmd.exec();
return response.toString();
}
@Override
public Boolean removeContainer(String containerId) {
RemoveContainerCmd removeContainerCmd = dockerClient.removeContainerCmd(containerId);
try {
removeContainerCmd.exec();
}catch (Exception e){
e.printStackTrace();
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public Boolean stopContainer(String containerId) {
StopContainerCmd stopContainerCmd = dockerClient.stopContainerCmd(containerId);
try {
stopContainerCmd.exec();
}catch (Exception e){
e.printStackTrace();
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public Boolean startContainer(String containerId) {
StartContainerCmd startContainerCmd = dockerClient.startContainerCmd(containerId);
try {
startContainerCmd.exec();
}catch (Exception e){
e.printStackTrace();
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public Boolean createContainer(DockerContainerVo dockerContainerVo) {
//会在服务器目录: home/dockerdata/docker/tmp ,上传打包容器文件
String containerName = dockerContainerVo.getContainerName();
if (StrUtil.isEmpty(containerName)){
return Boolean.FALSE;
}
CreateContainerCmd containerCmd = dockerClient.createContainerCmd(containerName);
containerCmd.withImage(dockerContainerVo.getImageName());
containerCmd.withName(containerName);
HostConfig hostConfig=HostConfig.newHostConfig();
List<LabelsOrKvVo> exposePorts = dockerContainerVo.getExposePorts();
exposePorts.forEach(e->{
ExposedPort tcp8300 = ExposedPort.tcp(Integer.parseInt(e.getValue()));
Ports portBindings = new Ports();
portBindings.bind(tcp8300, Ports.Binding.bindPort(Integer.parseInt(e.getKey())));
hostConfig.withPortBindings(portBindings);
containerCmd.withExposedPorts(tcp8300);
});
List<LabelsOrKvVo> volumePaths = dockerContainerVo.getVolumePath();
if (CollectionUtil.isEmpty(volumePaths)){
return Boolean.FALSE;
}
List<Bind> binds = new LinkedList<>();
volumePaths.forEach(e->{
Bind bind = new Bind(e.getKey(),new Volume(e.getValue()));
binds.add(bind);
});
containerCmd.withHostConfig(hostConfig);
hostConfig.setBinds(binds.toArray(new Bind[]{}));
try {
containerCmd.exec();
}catch (Exception e){
e.printStackTrace();
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public List<Image> images(ImageParam imageParam) {
ListImagesCmd imagesCmd = dockerClient.listImagesCmd();
List<LabelsOrKvVo> labelsOrKvVo = imageParam.getLabelsOrKvVo();
if (CollectionUtil.isNotEmpty(labelsOrKvVo)){
Map<String,String> lables = new HashMap<>(labelsOrKvVo.size());
labelsOrKvVo.forEach(e->{
lables.put(e.getKey(), e.getValue());
});
imagesCmd.withLabelFilter(lables);
}
if (StrUtil.isNotEmpty(imageParam.getName())){
imagesCmd.withImageNameFilter(imageParam.getName());
}
ListImagesCmd all = imagesCmd.withShowAll(false);
return all.exec();
}
@Override
public String imageInfo(String imageId) {
InspectImageCmd imageCmd = dockerClient.inspectImageCmd(imageId);
InspectImageResponse response = imageCmd.exec();
return response.toString();
}
@Override
public Boolean importImage(InputStream tarInputStream) {
dockerClient.loadImageCmd(tarInputStream).exec();
return Boolean.TRUE;
}
@Override
public Boolean buildImage(DockerBuildImageVo dockerBuildImageVo) {
boolean flag =true;
try {
String dockerFilePath = dockerBuildImageVo.getDockerFilePath();
if (StrUtil.isEmpty(dockerFilePath)){
return false;
}
List<LabelsOrKvVo> tagsVo = dockerBuildImageVo.getTags();
Set<String> tags = new HashSet<>();
if (CollectionUtil.isNotEmpty(tagsVo)){
tagsVo.forEach(e->{
String curTag = String.format("%s:%s", e.getKey(), e.getValue());
tags.add(curTag);
});
}
List<LabelsOrKvVo> labelsVo = dockerBuildImageVo.getLabels();
Map<String,String> labels = new HashMap<>(2);
if (CollectionUtil.isNotEmpty(labelsVo)){
//添加元数据,user-id 或者 xxx-id 与本地数据绑定起来
labelsVo.forEach(e->{
labels.put(e.getKey(),e.getValue());
});
}
BuildImageCmd buildImageCmd = dockerClient
.buildImageCmd(new File(dockerFilePath))
.withLabels(labels)
.withTags(tags);
BuildImageResultCallback callback = new BuildImageResultCallback();
buildImageCmd.exec(callback);
String imageId = callback.awaitImageId();
System.out.println("镜像创建成功,镜像id:"+imageId);
} catch (Exception e) {
flag=false;
e.printStackTrace();
}
return flag;
}
@Override
public Boolean pushDockerImageToHarbor(DockerPushVo dockerPushVo) {
AuthConfig autoConfig = new AuthConfig().withRegistryAddress(virtualProperties.getHarborUrl())
.withUsername(virtualProperties.getHarborUname()).withPassword(virtualProperties.getHarborPwd());
String localImg=dockerPushVo.getImageName()+":"+dockerPushVo.getImageTag();
String pushImg=virtualProperties.getHarborUrl()+"/"+dockerPushVo.getPushProject()+"/"+dockerPushVo.getImageName();
dockerClient.tagImageCmd(localImg,pushImg,dockerPushVo.getPushImgVersion()).exec();
String pushTo=virtualProperties.getHarborUrl()+"/"+dockerPushVo.getPushProject()+"/"+dockerPushVo.getImageName()+":"+dockerPushVo.getPushImgVersion();
try {
dockerClient.pushImageCmd(pushTo).withAuthConfig(autoConfig).start().awaitCompletion();
} catch (InterruptedException e) {
log.info(e.getMessage());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}
涉及vo
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author xiaoshu
* @description
* @date 2023年05月01日 15:23
*/
@Data
@ApiModel(value = "镜像构建Vo")
public class DockerBuildImageVo implements Serializable {
private static final long serialVersionUID = -6058239843827052127L;
@ApiModelProperty(value = "tags")
List<LabelsOrKvVo> tags;
@ApiModelProperty(value = "labels")
List<LabelsOrKvVo> labels;
@ApiModelProperty(value = "镜像文件路径;最后是 docker与镜像文件单独放一个目录")
private String dockerFilePath;
}
@ApiModel(value = "docker 容器创建VO")
@Data
public class DockerContainerVo implements Serializable {
private static final long serialVersionUID = 5791026160216793895L;
@ApiModelProperty(value = "容器名称")
private String containerName;
@ApiModelProperty(value = "镜像名称:tag")
private String imageName;
@ApiModelProperty(value = "暴露端口 容器端口 :内部端口")
private List<LabelsOrKvVo> exposePorts;
@ApiModelProperty(value = "挂载路径 主机路径 :容器路径")
private List<LabelsOrKvVo> volumePath;
}
@ApiModel(value = "k-v Vo")
@Data
public class LabelsOrKvVo implements Serializable {
@ApiModelProperty(value = "标签key")
private String key;
@ApiModelProperty(value = "标签value")
private String value;
}
@ApiModel(value = "docker 镜像推送VO")
@Data
public class DockerPushVo implements Serializable {
@ApiModelProperty(value = "原镜像名称")
private String imageName;
@ApiModelProperty(value = "原镜像tag")
private String imageTag;
@ApiModelProperty(value = "推送项目名称")
private String pushProject;
@ApiModelProperty(value = "推送后镜像版本号")
private String pushImgVersion;
}
yml 配置
virtual:
docker-url: tcp://192.168.2.207:8088
k8s-url: https://192.168.2.207:6443
k8s-token: xxx
server-url: 192.168.2.207
server-name: root
server-pwd: 123456
harbor-url: core.harbor.domain
harbor-uname: admin
harbor-pwd: Harbor12345
@Data
@ConfigurationProperties(prefix = "virtual")
@Configuration
public class VirtualProperties {
/**
* docker服务地址
*/
private String dockerUrl;
/**
* k8s服务地址
*/
private String k8sUrl;
/**
* k8s服务token
*/
private String k8sToken;
/**
* 服务器地址
*/
private String serverUrl;
/**
* 服务器账号
*/
private String serverName;
/**
* 服务器账号密码
*/
private String serverPwd;
/**
* harbor私有仓库地址
*/
private String harborUrl;
/**
* harbor 账号
*/
private String harborUname;
/**
* harbor 密码
*/
private String harborPwd;
}