package space.anyi.docker; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectImageResponse; import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.model.Image; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.List; /** * Docker 镜像管理 API 示例 * 演示拉取、列出、查看详情、删除、标记、导入导出等镜像操作 */ public class ImageManageAPI { private static final Logger log = LoggerFactory.getLogger(ImageManageAPI.class); private final DockerClient dockerClient; public ImageManageAPI() { // 使用工厂类创建统一的 DockerClient 实例 this.dockerClient = DockerClientFactory.createDockerClient(); } /** * 列出自定义节点上所有存在的镜像 * @return 镜像列表 */ public List listImages() { List images = dockerClient.listImagesCmd() .withShowAll(true) // 展示所有镜像(包括中间层) .exec(); log.info("本机共有 {} 个镜像", images.size()); return images; } /** * 获取镜像的详细信息 * 包括镜像的 ID、仓库、标签、创建时间、大小、Layer 等 * @param imageId 镜像 ID 或名称 * @return 镜像详情 */ public InspectImageResponse inspectImage(String imageId) { InspectImageResponse response = dockerClient.inspectImageCmd(imageId).exec(); log.info("镜像 {} 详情: {}", imageId, response); return response; } /** * 拉取指定名称的镜像 * 优化:如果本地已存在同名镜像则直接使用,无需访问网络 * @param imageName 镜像名称,如 "hello-world" 或 "nginx:latest" * @return 拉取是否成功 */ public boolean pullImage(String imageName) { // 先检查本地是否已存在该镜像,避免无谓的网络访问 boolean exists = dockerClient.listImagesCmd().exec().stream() .anyMatch(img -> img.getRepoTags() != null && Arrays.asList(img.getRepoTags()).contains(imageName)); if (exists) { log.info("镜像 {} 已存在于本地,跳过拉取", imageName); return true; } try { // exec() 执行命令,awaitCompletion() 阻塞等待镜像拉取完成 dockerClient.pullImageCmd(imageName) .exec(new PullImageResultCallback()) .awaitCompletion(); log.info("镜像 {} 拉取成功!", imageName); return true; } catch (InterruptedException e) { log.error("镜像拉取被中断: {}", e.getMessage()); Thread.currentThread().interrupt(); return false; } } /** * 删除本地镜像 * @param imageId 镜像 ID 或名称 * @param force 是否强制删除(即使镜像被容器使用) */ public void removeImage(String imageId, boolean force) { dockerClient.removeImageCmd(imageId) .withForce(force) // 强制删除 .exec(); log.info("镜像 {} 已删除", imageId); } /** * 为镜像添加标签(相当于 docker tag) * @param imageId 源镜像 ID 或名称 * @param repository 新的仓库名 * @param tag 新的标签名 */ public void tagImage(String imageId, String repository, String tag) { dockerClient.tagImageCmd(imageId, repository, tag).exec(); log.info("镜像 {} 已标记为 {}:{}", imageId, repository, tag); } /** * 检查本地是否存在指定镜像 * @param imageName 镜像名称(仓库名:标签) * @return 是否存在 */ public boolean checkImageExists(String imageName) { boolean exists = dockerClient.listImagesCmd().exec().stream() .anyMatch(img -> img.getRepoTags() != null && Arrays.asList(img.getRepoTags()).contains(imageName)); log.info("镜像 {} 是否存在: {}", imageName, exists); return exists; } }