根据jar名称动态打包带版本的镜像, 并创建对应容器的脚本实现

根据jar名称动态打包带版本的镜像以及容器

利用shell脚本, 实现根据jar名称中的项目名和版本号来动态制作带版本的Docker镜像以及带版本的容器

背景

人人都逃不过的墨菲定律

事情的原因来自最近发生的一次生产环境事故: 我们在甲方那里环境中有两个服务器, 一个用于灰度测试另一个用于盛传. 我负责的某项目在完成缺陷修复并测试通过后, 产品便提交生产环境发版流程. 流程走到我这里时, 我找到流程中负责现场发版的运维要求发版, 而他也发了版, 并且把脚本启动的成功截图给我了, 但是截图中没有当前服务器的ip, 这就为后来问题的暴露埋下伏笔…

在 ‘新版本’ 运行约一周之后, 实施反映之前修复的bug又复现了. 于是让运维下载下日志给我, 结果发现当前业务并没有走新版本修复后的逻辑, 并且未显示新版本追加的日志信息. 因此我推测包没有发上, 于是让运维比对下docker容器创建时间和jar包上传时间发现, 真的没有发上去. 于是我查了之前的聊天记录, 恰好发现之前运维截的图没有截到服务器的ip地址. 正如墨菲定律说的那样: 凡是可能出错的事情就一定出错.

事件反思

事后通过和运维和其他同事沟通了解到: 其实在工作中, 运维每天的量也很大. 即使之前帮过你发过包, 由于时间和个人的原因, 仍会导致再次发包时会忘记一些环境配置的情况. 而我这边也存在问题, 在发布后没有仔细确认…

基于以上反思, 我决定:

  1. 在每次需要运维协助发包前, 整理好发包文档, 让其严格按照文档来发包
  2. 优化原有启动脚本, 根据jar名称动态打包带版本的镜像,
    让运维那边也可以看到新版本jar是否发送成功

辛路历程

整个脚本制作过程结合了ChatGPT使用, 中间过程有些曲折且漫长,
因此特地花点时间复盘一下, 希望能够带给自己和大家一些启发.
如果想要直接看最终脚本请直接跳转至最终脚本部分即可

前提准备

idea开启远程调试这一章节, 我就分享过docker打包jar包环境的脚本.
这个脚本的核心是利用DockerFIle, 将jar制作成镜像, 然后利用启动脚本将镜像生成容器并启动.
但因为之前分享的jar都是0.0.1版本(图1), 因此无论是镜像的tag(图2), 还是启动时容器中的镜像信息(图3)都是0.0.1.
那么如何动态的将jar包中的版本信息动态的打入镜像的tag和容器名称中呢?

图1

图2

在这里插入图片描述

图3

在这里插入图片描述

再次将该脚本再一次分享与大家

# 1.DockerFIle
FROM java:8

COPY 待启动jar-0.0.1-SNAPSHOT.jar 待启动jar-0.0.1-SNAPSHOT.jar

EXPOSE 项目对外端口

ENTRYPOINT ["java","-Duser.timezone=GMT+8","-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=远程调试端口","-jar","待启动jar-0.0.1-SNAPSHOT.jar"]


# 2.start.sh
sudo docker build --no-cache -f DockerFile -t 待启动jar:0.0.1 .;

sudo docker stop 待启动jar;

sudo docker rm 待启动jar;

sudo docker run -d --restart=always --name 待启动jar \
	-p 项目对外端口:项目对外端口 -p 远程调试端口:远程调试端口 \
	-v /home:/home \
	-v /home/待启动jar/logs:/logs \
	待启动jar:0.0.1 --spring.profiles.active=sit

1. 脚本启动顺序

在这里需要梳理下脚本的启动顺序, 这对我们后面问问题有所帮助, 正确的顺序为

->运行脚本start.sh
->通过DockerFIle制作新版本镜像
->停止并删除原来镜像对应的容器
->根据新的镜像创建容器
->执行根据DockerFIle中ENTRYPOINT关键字添加的, 启动容器所需执行的命令

2. 前置知识

本文的编写用到了大量的DockerFIle的关键字shell脚本的基础知识.
如果后续阅读遇到了困难可以点击这里的链接, 来简单了解下(或者通过ChatGPT来简单了解下)

PS: 如果不理解上面的脚本是干什么的, 可以直接让ChatGPT为你翻译

在这里插入图片描述

一股脑提问法

  1. 在一开始, 我便选择最"简单粗暴的方式", 直接提问
    在这里插入图片描述

  2. 可以看到, 给出DockerFIle文件看起来还是没有问题的, 但是继续往下看
    在这里插入图片描述

  3. 可以看到启动脚本这里就有问题了, 我想要的是根据jar名称动态获取项目名称和版本号
    但这里提供的脚本是在一开始就写死的
    , 也就是说GPT并没有正确理会我这个动态读取的意思,
    在这里插入图片描述

  4. 并且, 我即使使用上面的方式, 运行ChatGPT提供给我的DockerFIle和启动脚本,
    发现还是未成功. 原因是启动脚本中的参数的值虽然被--build-arg 传入到DockerFIle,
    但是在ENTRYPOINT中在替换jar名称后依然执行报错,
    并且DockerFIle中通过arg定义的参数, 在ENTRYPOINT通过${}获取不到,
    我尝试用CMD来执行该参数, 但是这种方式下仍然失败.
    因此, 发现在整体上一点点调试, 不如重头在细节上一点点攻破.
    所以我调整了提问策略: 由整体提问, 改为分步骤提问

分步骤提问法

在规划步骤时, 核心就是动态获取jar包版本号和jar名称,
因此在一开始时, 我把主要步骤分为3步:动态读取jar包名称中的信息->动态打包镜像->动态创建并运行容器
在后续的思考中, 我又添加了: 获取服务器ip-> 删除原有容器, 镜像 这两步.
如果时间有限的同学, 想直接获取最终脚本, 可以跳转至"最终脚本"这一部分.
下面就开始介绍如何分步提问, 来让ChatGP解决问题

1. 动态读取jar包名称中的信息

根据上面前提准备-脚本启动顺序那部分我们归纳得到启动顺序, 我决定先对启动文件start.sh进行改造,
将动态获取jar名称和版本好的问题交给ChatGPT, 可以看到很快就得到了一个方案

在这里插入图片描述
通过阅读上面脚本发现, 提供脚本还是存在瑕疵, 因为jar包名称JAR_FILE还是在脚本里面写死的,
而不是动态获取的, 可以看出来当前ChatGPT并没有理解我的需求.
因此我们需要将问题继续抛给ChatGPT
在这里插入图片描述
可以看到之前的问题已经得以解决
至此, 整个脚本最核心的三行脚本已经获取完毕

	# 获取当前jar全称
	JAR_FILE=$(ls  *.jar | head -n 1)
	# 获取当前jar实际名称(通过-分隔的第1列信息, 这里后续需要根据自己jar的格式进行调整)
	BASE_NAME=$(echo "$JAR_FILE" | 

猜你喜欢

转载自blog.csdn.net/qq_43371556/article/details/131116610