【Jenkins】构建Docker镜像失败时的提醒
编辑一、需求
往 git 仓库 push 代码的时候,自动将代码上传到指定服务器,并通过 Dockerfile 进行镜像的构建,然后通过 docker-compose 进行容器的编排,根据最终的容器运行结果,推送构建结果。
二、方案介绍
目录结构
.
├── docker-compose.yaml
├── Dockerfile
├── main.py
├── README.md
└── requirements.txt
Dockerfile
FROM python:3
ADD . /code
WORKDIR /code
RUN pip3 install -r requirements.txt -i https://pypi.douban.com/simple
CMD python -u main.py
docker-compose.yaml
version: "3.5"
services:
test:
image: test
build: .
container_name: test
environment:
- TZ=Asia/Shanghai
主要用到的 Jenkins 插件
仓库推送触发构建插件:Generic Webhook Trigger Plugin
构建结果消息通知插件:Qy Wechat Notification Plugin
推送代码到服务器插件:Publish over SSH
一些需要注意的插件配置,主要是 Publish over SSH
将详细的命令执行过程输出到 Jenkins 控制台
仓库全部代码发送到远程服务器(看需求,也可以写些文件的过滤规则)
命令执行超时等待时间(看需求,我这里调整的无限等待)
命令执行失败则构建失败(这个比较重要,关系到后续的消息推送)
需要注意的是 Publish over SSH 判定命令执行成功还是失败是根据其退出码来决定的
三、遇到的问题
成功的构建只有一种,但是导致失败的构建原因有很多,比如
docker-compose.yaml 语法错误
镜像构建过程失败
镜像构建成功,容器运行失败
针对不同的失败情况,又衍生出来一些不同的问题要解决,比如产生的一些垃圾镜像/容器的清除,如何判断容器运行成功还是失败。
四、解决方案
# 基础构建命令
# --build,每次更新代码从头构建镜像,然后编排容器
# 不然每次都是用已经存在的镜像进行容器的编排,不会更新代码
cd /root/docker_build&&
docker-compose up -d --build&&
1. docker-compose.yaml 语法错误
问题分析
导致
docker-compose up -d --build
执行失败,可以正常推送 Jenkins 构建失败通知不会产生垃圾镜像和容器
处理方式
无需处理
2. 镜像构建过程失败
比如缺少 requirements.txt, 或者 Dockerfile 中间执行某条命令失败,总之一切导致不能正常生成镜像的操作
问题分析
导致
docker-compose up -d --build
执行失败,可以正常推送 Jenkins 构建失败通知会产生垃圾镜像和容器,下次构建成功,也不会清理这些失败的镜像和容器
处理方式
构建失败的时候不做处理,当更新代码,构建成功时删除之前失败构建产生的中间容器
docker images -qf "dangling=true" | xargs -i docker ps -aqf "ancestor={}" | xargs -i docker rm {}&&
docker images -qf "dangling=true" | xargs -i docker rmi {}
冗余处理
构建失败的镜像,名称为 \<none>:\<none> 的「孤立镜像」,基于这个失败的镜像运行的容器,则名称和 ID 都是随机的,且会「运行失败」,所以思路为
先删除所有基于孤立镜像运行的容器
再删除孤立镜像
问题:
导致「孤立镜像」的原因不一定全是构建失败,可能某些镜像是正常的,但是由于某些原因,变成了「孤立镜像」,而且还有「正在运行」的基于这个正常的「孤立镜像」的容器,这种情况的「容器」和「镜像」不应该被删除。
比如,给一个正常镜像打 tag 的时候,使用其他镜像的 tag 名称,会导致其他镜像变成「孤立镜像」
「孤立镜像」仅仅代表一个镜像没有 tag,不表示他是一个失败的构建,也不表示没有基于其运行的容器)
docker images -f "dangling=true"
可以筛选出所有的「孤立镜像」
场景:
A 镜像为构建失败的「孤立镜像」,a 为基于 A 镜像的容器,运行状态为 exited
B 镜像是正常镜像,由于某种原因变成了「孤立镜像」, b 为基于 B 镜像的容器,运行状态为 running
思路:
删除容器
考虑到那些「正在运行」的基于正常「孤立镜像」的容器(b),所以不能使用
-f
强制删除。使用
xargs -i docker rm {}
可以避免删除掉正在运行的容器。删除到 b 容器的时候,因为其「正在运行」,导致
docker rm
命令执行失败。按照需求,虽然删除失败,但这种情况应当认为命令执行成功,不应该推送失败信息,所以改进为,忽略删除失败的情况docker images -qf "dangling=true" | xargs -i docker ps -aqf "ancestor={}" | (xargs -i docker rm {} || ehco 0)
删除镜像
同上,因为「正在运行」的容器没有删除,删除到对应镜像的时候,也会导致命令执行失败触发失败消息推送,改进为
docker images -qf "dangling=true" | (xargs -i docker rmi {} || echo 0)
3. 镜像构建成功,容器运行失败
问题分析
docker-compose up -d --build
执行成功不产生垃圾镜像和容器,下次构建成功,会重置镜像和容器
容器运行失败,但是无法触发构建失败通知(触发是根据命令来的,虽然容器运行失败,但是命令
docker-compose up -d --build
执行是成功的)
处理方式
检测「最近」运行的容器的运行状态,看是否为「running」状态,若不是,则执行错误的退出码,需要注意的是,有些容器运行需要一些时间,应该延迟一段时间检测
sleep 10&&
docker ps -l --format="{{.State}}" | xargs -i bash -c "[[ "{}" == "running" ]]"
五、总结
基于需求,完整的解决方案为
cd /root/docker_build&&
docker-compose up -d --build&&
docker images -qf "dangling=true" | xargs -i docker ps -aqf "ancestor={}" | xargs -i docker rm {}&&
docker images -qf "dangling=true" | xargs -i docker rmi {}&&
sleep 10&&
docker ps -l --format="{{.State}}" | xargs -i bash -c "[[ "{}" == "running" ]]"
构建镜像和容器
构建失败 - > 错误构建消息推送(但不清理失败构建的容器和镜像,方便排查错误信息)
构建成功 -> 删除失败构建的中间容器和镜像(不存在或删除失败也不报错) -> 检测容器是否正常运行 -> 成功构建消息推送
冗余「正常的孤立镜像」的解决方案(这种情况很少,或者说不应该存在「正常的孤立镜像」)
cd /root/docker_build&&
docker-compose up -d --build&&
docker images -qf "dangling=true" | xargs -i docker ps -aqf "ancestor={}" | (xargs -i docker rm {} || ehco 0)}&&
docker images -qf "dangling=true" | (xargs -i docker rmi {} || echo 0)&&
sleep 10&&
docker ps -l --format="{{.State}}" | xargs -i bash -c "[[ "{}" == "running" ]]"
- 0
- 0
-
赞助
微信 -
分享