0


干货含源码!如何用Java后端操作Docker(命令行篇)

作者:watermelo37

涉及领域:Vue、SpingBoot、Docker、LLM、python等


温柔地对待温柔的人,包容的三观就是最大的温柔。


干货含源码!如何用Java后端操作Docker(命令行篇)

一、为什么要用后端程序操作Docker

  1. Docker 是现代开发和部署流程中不可或缺的一部分。它简化了应用程序的环境配置、打包和分发,使得在不同机器上运行相同的应用变得更加轻松和一致。本文将详细介绍如何使用命令行工具(CMD)操控 Docker 来配置环境。
  2. 实现后端操作docker,可以用来实现云端IDE、一键环境搭建、多人协作环境、互动编程教学、可视化部署和管理等等功能。是Docker从服务器走向客户端的必经之路。

二、安装Docker

1、安装Docker

  1. 我写过一份详细的博客,请移步:Docker 入门全攻略:安装、操作与常用命令指南

2、启动Docker

  1. 安装完成后,启动 Docker Desktop,并确保其正常运行。可以在 CMD 中通过以下命令来验证:
  1. docker --version

三、使用Java后端操作docker

1、构建docker镜像并生成容器

  1. 这一步的目的是通过Docker根据本地目录中的DockerFlie文件、代码、和其他配置数据文件生成新的镜像,并生成容器。
  2. 一个简单的DockerFile示例:
  1. # 使用官方Python运行时作为父镜像
  2. FROM python:3.8-slim
  3. # 设置工作目录
  4. WORKDIR /app
  5. # 将当前目录内容复制到位于/app中的容器中
  6. COPY . /app
  7. # 安装requirements.txt中指定的任何所需包
  8. RUN pip install --no-cache-dir -r requirements.txt
  9. # 使端口80可供此容器外的环境使用
  10. EXPOSE 80
  11. # 定义环境变量
  12. ENV NAME World
  13. # 在容器启动时运行app.py
  14. CMD ["python", "app.py"]
  1. 其中0419test是构建镜像的tag名。
  2. 注意修改工作目录,将其改为你实际的文件夹目录。
  1. public void buildImageAndContainer(){
  2. try {
  3. // 设置第一个命令:构建Docker镜像
  4. ProcessBuilder buildProcessBuilder = new ProcessBuilder("docker", "build", "-t", "test0419", ".");
  5. // 设置工作目录为 "E:\\code\\docker\\test"
  6. buildProcessBuilder.directory(new File("E:\\code\\docker\\test"));
  7. // 启动构建镜像的命令并等待其完成
  8. Process buildProcess = buildProcessBuilder.start();
  9. buildProcess.waitFor();
  10. // 读取并打印出构建镜像的输出
  11. printProcessOutput(buildProcess);
  12. // 检查构建是否成功
  13. if (buildProcess.exitValue() == 0) {
  14. // 设置第二个命令:运行Docker容器
  15. ProcessBuilder runProcessBuilder = new ProcessBuilder("docker", "run", "-v", "E:/code/docker/test:/app", "-p", "80:80", "test0419");
  16. // 启动运行容器的命令
  17. Process runProcess = runProcessBuilder.start();
  18. // 读取并打印出运行容器的输出
  19. printProcessOutput(runProcess);
  20. // 可以在这里等待容器运行的进程结束,或者根据需要进行其他操作
  21. // runProcess.waitFor();
  22. } else {
  23. System.out.println("Docker image build failed.");
  24. }
  25. } catch (IOException | InterruptedException e) {
  26. System.out.println(e);
  27. e.printStackTrace();
  28. }
  29. }
  30. // 输出打印内容的私有方法
  31. private static String printProcessOutput(Process process) throws IOException {
  32. String output;
  33. String errorInfo;
  34. // 读取并打印标准输出
  35. output = readAndPrint(process.getInputStream(), "");
  36. // 读取并打印标准错误
  37. errorInfo = readAndPrint(process.getErrorStream(), "");
  38. return output+errorInfo;
  39. }
  40. private static String readAndPrint(InputStream inputStream, String prefix) throws IOException {
  41. StringBuilder output = new StringBuilder();
  42. try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
  43. String line;
  44. while ((line = reader.readLine()) != null) {
  45. output.append(prefix).append(line).append(System.lineSeparator());
  46. System.out.println(prefix + line); // 同时打印到控制台
  47. }
  48. }
  49. return output.toString();
  50. }

2、执行完毕后删除容器和镜像

  1. 删除容器和镜像,释放资源,一般在容器执行完代码之后运行。
  1. // 删除容器和镜像
  2. public String deleteContainerAndImage(String imageName){
  3. // 定义一个线程池用于执行删除操作
  4. ExecutorService executorService = Executors.newFixedThreadPool(2);
  5. // 异步获取容器 ID 列表并删除容器
  6. executorService.submit(() -> {
  7. try {
  8. List<String> containerIds = new ArrayList<>();
  9. String command = "docker ps -a -q --filter ancestor=" + imageName;
  10. ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
  11. Process process = processBuilder.start();
  12. BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
  13. String line;
  14. while ((line = reader.readLine()) != null) {
  15. containerIds.add(line.trim());
  16. }
  17. int exitCode = process.waitFor();
  18. if (exitCode != 0) {
  19. System.err.println("Command executed with error. Exit code: " + exitCode);
  20. return ;
  21. }
  22. // 删除容器
  23. for (String containerId : containerIds) {
  24. String deleteContainerCommand = "docker rm -f " + containerId;
  25. executeCommand(deleteContainerCommand);
  26. }
  27. } catch (IOException | InterruptedException e) {
  28. e.printStackTrace();
  29. }
  30. });
  31. // 异步删除镜像
  32. executorService.submit(() -> {
  33. // 等待容器被删除
  34. try {
  35. TimeUnit.SECONDS.sleep(5); // 等待5秒,可以根据实际情况调整
  36. // 同样,如果你使用的是Docker,可以使用以下命令:
  37. String deleteImageCommand = "docker rmi " + imageName;
  38. executeCommand(deleteImageCommand);
  39. } catch (InterruptedException e) {
  40. e.printStackTrace();
  41. }
  42. });
  43. // 关闭线程池
  44. executorService.shutdown();
  45. return "镜像与容器已删除";
  46. }
  47. // 用来执行cmd命令的方法
  48. private void executeCommand(String command) {
  49. try {
  50. // 使用ProcessBuilder执行命令
  51. ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
  52. Process process = processBuilder.start();
  53. // 调用已有的方法来打印输出
  54. printProcessOutput(process);
  55. // 等待进程结束
  56. int exitCode = process.waitFor();
  57. if (exitCode != 0) {
  58. // 处理非零退出码,可能表示命令执行出错
  59. System.err.println("Command executed with error. Exit code: " + exitCode);
  60. }
  61. } catch (IOException e) {
  62. // 处理命令执行过程中可能遇到的IO异常
  63. e.printStackTrace();
  64. } catch (InterruptedException e) {
  65. // 如果waitFor()方法被中断,重新设置中断状态并处理
  66. Thread.currentThread().interrupt();
  67. e.printStackTrace();
  68. } catch (Exception e) {
  69. // 处理命令字符串分割可能出现的异常
  70. e.printStackTrace();
  71. }
  72. }

3、在此基础上开发其他功能

  1. 在生成与删除之间,就可以自由添加和微调其中的部分步骤,比如删除DockerFile中的CMD ["python", "app.py"],让容器持续化后台运行,这样就可以通过宿主机与容器的文件映射关系修改代码内容,然后择机运行代码了;又比如创建一个满足需求的镜像,然后只创建和删除容器来节省服务器资源等等。

四、总结

  1. 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
  2. 更多优质内容,请关注:
  3. 你真的会使用Vue3onMounted钩子函数吗?Vue3onMounted的用法详解
  4. 通过array.filter()实现数组的数据筛选、数据清洗和链式调用
  5. el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

** **极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

  1. shpfileGeoJSON且控制转化精度;如何获取GeoJSONGeoJson结构详解
  2. Docker 入门全攻略:安装、操作与常用命令指南
  3. 通过array.reduce()实现数据汇总、条件筛选和映射、对象属性的扁平化、转换数据格式等
  4. 巧用Array.forEach:简化循环与增强代码可读性
  5. Mapbox添加行政区矢量图层、分级设色图层、自定义鼠标悬浮框、添加天地图底图等
  6. 管理数据必备!侦听器watch用法详解

本文转载自: https://blog.csdn.net/RenGJ010617/article/details/141821862
版权归原作者 watermelo37 所有, 如有侵权,请联系我们删除。

“干货含源码!如何用Java后端操作Docker(命令行篇)”的评论:

还没有评论