影刀RPA Docker容器自动化:镜像构建与服务部署 影刀RPA Docker容器自动化镜像构建与服务部署什么情况用什么 → 怎么做 → 有什么坑作者林焱 | 飞行社出品什么情况用什么开发团队每次发版都要手动构建Docker镜像、重启容器、检查服务状态重复性工作多到爆。这套方案适合开发团队自动化Docker镜像构建运维团队自动化容器部署定时清理无用镜像和容器节省磁盘空间核心工具影刀RPA Docker SDK for Pythondocker-py 容器健康检查怎么做第一步安装Docker SDK并配置连接# 安装Docker SDK for Pythonpipinstalldocker[video(video-9C9AxRNR-1783410559902)(type-csdn)(url-https://live.csdn.net/v/embed/525000)(image-https://v-blog.csdnimg.cn/asset/23da3fe1f67a47106d725406cfde9a97/cover/Cover0.jpg)(title-拼多多店群自动化上架方案)]importdockerimportosdefinit_docker_client(base_urlNone,tls_verifyFalse): 初始化Docker客户端 base_url: Docker守护进程地址本地为 None远程为 tcp://192.168.1.100:2375 tls_verify: 是否启用TLS验证生产环境必须启用 try:# 方法1连接到本地Docker守护进程Linux/Macifbase_urlisNone:clientdocker.from_env()# 方法2连接到远程Docker守护进程else:iftls_verify:# 启用TLS生产环境tls_configdocker.tls.TLSConfig(client_cert(cert.pem,key.pem),ca_certca.pem,verifyTrue)clientdocker.DockerClient(base_urlbase_url,tlstls_config)else:# 不启用TLS测试环境不安全clientdocker.DockerClient(base_urlbase_url)# 验证连接client.ping()print(fDocker连接成功:{client.version()[ApiVersion]})returnclientexceptExceptionase:print(f⚠️ Docker连接失败:{e})returnNone# 使用示例本地Dockerclientinit_docker_client()# 使用示例远程Docker# client init_docker_client(base_urltcp://192.168.1.100:2375)第二步自动化Docker镜像构建defbuild_docker_image(client,dockerfile_path,image_name,taglatest,build_argsNone): 构建Docker镜像 dockerfile_path: Dockerfile所在目录 image_name: 镜像名称如 myapp tag: 镜像标签如 v1.0, latest build_args: 构建参数如 {NODE_VERSION: 16} try:print(f开始构建镜像:{image_name}:{tag})# 构建镜像image,logsclient.images.build(pathdockerfile_path,tagf{image_name}:{tag},buildargsbuild_args,rmTrue,# 构建成功后删除中间容器forcermTrue# 构建失败后也删除中间容器)# 打印构建日志forloginlogs:ifstreaminlog:print(log[stream].strip())print(f镜像构建成功:{image.tags})returnimageexceptExceptionase:print(f镜像构建失败:{e})returnNonedefpush_docker_image(client,image_name,taglatest,registryNone): 推送Docker镜像到镜像仓库 registry: 镜像仓库地址如 registry.cn-beijing.aliyuncs.com try:# 如果指定了镜像仓库需要重新打标签ifregistry:new_tagf{registry}/{image_name}:{tag}imageclient.images.get(f{image_name}:{tag})image.tag(new_tag)else:new_tagf{image_name}:{tag}print(f开始推送镜像:{new_tag})# 推送镜像responseclient.images.push(new_tag)print(f镜像推送成功:{new_tag})print(response)returnTrueexceptExceptionase:print(f镜像推送失败:{e})returnFalse# 完整构建推送流程defbuild_and_push_image(client,dockerfile_path,image_name,tag,registryNone):构建并推送Docker镜像# 1. 构建镜像imagebuild_docker_image(client,dockerfile_path,image_name,tag)ifnotimage:returnFalse# 2. 推送镜像ifregistry:successpush_docker_image(client,image_name,tag,registry)ifnotsuccess:returnFalsereturnTrue第三步自动化容器部署defdeploy_container(client,image_name,taglatest,container_nameNone,portsNone,volumesNone,environmentNone,networkNone): 部署Docker容器 image_name: 镜像名称 tag: 镜像标签 container_name: 容器名称如 myapp-web ports: 端口映射如 {80/tcp: 8080} volumes: 数据卷挂载如 {/data: {bind: /app/data, mode: rw}} environment: 环境变量如 {DB_HOST: mysql, REDIS_HOST: redis} network: 网络模式如 bridge, host, my-network try:# 1. 检查是否已存在同名容器ifcontainer_name:try:existing_containerclient.containers.get(container_name)print(f容器已存在:{container_name})print(f 状态:{existing_container.status})# 停止并删除已存在的容器ifexisting_container.statusrunning:print(f 停止容器:{container_name})existing_container.stop()print(f 删除容器:{container_name})existing_container.remove(forceTrue)exceptdocker.errors.NotFound:# 容器不存在继续pass# 2. 拉取最新镜像如果本地没有try:client.images.get(f{image_name}:{tag})print(f镜像已存在:{image_name}:{tag})exceptdocker.errors.ImageNotFound:print(f拉取镜像:{image_name}:{tag})client.images.pull(f{image_name}:{tag})# 3. 创建并启动容器print(f创建容器:{container_nameor自动生成})containerclient.containers.run(imagef{image_name}:{tag},namecontainer_name,portsports,volumesvolumes,environmentenvironment,networknetwork,detachTrue,# 后台运行restart_policy{Name:unless-stopped}# 自动重启除非手动停止)print(f容器启动成功:{container.name})print(f 容器ID:{container.id})print(f 状态:{container.status})returncontainerexceptExceptionase:print(f容器部署失败:{e})returnNonedefcheck_container_health(client,container_name,health_check_urlNone,timeout60): 检查容器健康状态 health_check_url: 健康检查URL如 http://localhost:8080/health timeout: 超时时间秒 importtimeimportrequeststry:containerclient.containers.get(container_name)# 1. 检查容器状态ifcontainer.status!running:print(f⚠️ 容器未运行:{container_name}(状态:{container.status}))returnFalseprint(f容器运行中:{container_name})# 2. 健康检查如果有配置ifhealth_check_url:print(f健康检查:{health_check_url})start_timetime.time()whiletime.time()-start_timetimeout:try:responserequests.get(health_check_url,timeout5)ifresponse.status_code200:print(f健康检查通过:{health_check_url})returnTrueelse:print(f健康检查失败: HTTP{response.status_code})exceptExceptionase:print(f健康检查失败:{e})time.sleep(5)# 等待5秒后重试print(f⚠️ 健康检查超时:{health_check_url})returnFalsereturnTrueexceptExceptionase:print(f检查容器健康状态失败:{e})returnFalse第四步自动化容器清理节省磁盘空间defclean_docker_system(client,remove_unused_imagesTrue,remove_stopped_containersTrue,remove_unused_volumesFalse,remove_unused_networksTrue): 清理Docker系统镜像、容器、数据卷、网络 ⚠️ 注意此操作不可逆 try:# 1. 删除已停止的容器ifremove_stopped_containers:containersclient.containers.list(allTrue,filters{status:[exited,created]})ifcontainers:print(f删除已停止的容器:{len(containers)}个)forcontainerincontainers:print(f 删除:{container.name}({container.short_id}))container.remove(forceTrue)else:print(没有已停止的容器需要删除)# 2. 删除未使用的镜像ifremove_unused_images:# 获取所有容器使用的镜像containersclient.containers.list(allTrue)used_imagesset()forcontainerincontainers:used_images.add(container.image.id)# 获取所有镜像imagesclient.images.list()unused_images[imgforimginimagesifimg.idnotinused_images]ifunused_images:print(f删除未使用的镜像:{len(unused_images)}个)forimageinunused_images:fortaginimage.tags:print(f 删除:{tag})client.images.remove(tag,forceTrue)else:print(没有未使用的镜像需要删除)# 3. 删除未使用的数据卷⚠️ 危险会删除数据ifremove_unused_volumes:volumesclient.volumes.list(filters{dangling:True})ifvolumes:print(f删除未使用的数据卷:{len(volumes)}个)forvolumeinvolumes:print(f 删除:{volume.name})volume.remove(forceTrue)else:print(没有未使用的数据卷需要删除)# 4. 删除未使用的网络ifremove_unused_networks:networksclient.networks.list()unused_networks[netfornetinnetworksifnet.containers[]andnet.name!bridgeandnet.name!hostandnet.name!none]ifunused_networks:print(f删除未使用的网络:{len(unused_networks)}个)fornetworkinunused_networks:print(f 删除:{network.name})network.remove()else:print(没有未使用的网络需要删除)print(Docker系统清理完成)returnTrueexceptExceptionase:print(fDocker系统清理失败:{e})returnFalsedefclean_old_images(client,image_name_prefix,keep_latest5): 清理旧镜像保留最新的N个版本 image_name_prefix: 镜像名称前缀如 myapp keep_latest: 保留最新的几个版本 try:# 获取所有镜像imagesclient.images.list(filters{reference:f{image_name_prefix}*})# 按创建时间排序images.sort(keylambdax:x.attrs[Created],reverseTrue)# 保留最新的N个版本images_to_deleteimages[keep_latest:]ifimages_to_delete:print(f清理旧镜像:{len(images_to_delete)}个)forimageinimages_to_delete:fortaginimage.tags:print(f 删除:{tag})client.images.remove(tag,forceTrue)else:print(f没有旧镜像需要清理已保留最新{keep_latest}个版本)returnTrueexceptExceptionase:print(f清理旧镜像失败:{e})returnFalse第五步影刀RPA完整流程编排【定时触发】每次代码合并到master分支时触发Webhook ↓ 【Python节点】init_docker_client() → 初始化Docker客户端 ↓ 【Python节点】build_docker_image() → 构建Docker镜像 ↓ 【条件判断】镜像构建是否成功 ├─ 否 → 【企微通知】发送构建失败告警 └─ 是 → 继续 ↓ 【Python节点】push_docker_image() → 推送镜像到镜像仓库 ↓ 【Python节点】deploy_container() → 部署容器 ↓ 【Python节点】check_container_health() → 检查容器健康状态 ↓ 【条件判断】容器是否健康 ├─ 否 → 【回滚】部署上一个版本的容器 └─ 是 → 继续 ↓ 【Python节点】clean_old_images() → 清理旧镜像 ↓ 【生成报告】Docker部署报告.xlsx → 包含镜像名称、容器状态、健康检查记录 ↓ 【发送邮件】将报告发送给开发团队有什么坑坑1Docker守护进程远程访问安全风险开放Docker守护进程的TCP端口2375/2376如果不启用TLS任何人都可以远程控制你的Docker解决方案启用TLS验证生产环境必须使用SSH隧道ssh -L 2375:/var/run/docker.sock userremote-host使用Docker Machine统一管理多个Docker主机# 使用SSH隧道连接远程Docker安全# 1. 先建立SSH隧道ssh -L 2375:/var/run/docker.sock userremote-host# 2. 连接到本地隧道端口clientdocker.DockerClient(base_urltcp://localhost:2375)坑2镜像构建失败排查困难Dockerfile有问题镜像构建失败但错误信息不够详细难以排查。解决方案查看详细构建日志docker build --progressplain .分步调试先手动执行Dockerfile里的每一条指令使用多阶段构建减少镜像层数降低出错概率# 获取详细的构建日志defbuild_docker_image_verbose(client,dockerfile_path,image_name,taglatest):构建Docker镜像详细日志try:# 使用streamTrue获取实时日志responseclient.api.build(pathdockerfile_path,tagf{image_name}:{tag},streamTrue,rmTrue,forcermTrue)# 打印实时日志forchunkinresponse:ifisinstance(chunk,dict):ifstreaminchunk:print(chunk[stream].strip())eliferrorinchunk:print(f错误:{chunk[error]})returnNoneprint(f镜像构建成功:{image_name}:{tag})returnclient.images.get(f{image_name}:{tag})exceptExceptionase:print(f镜像构建失败:{e})returnNone坑3容器删除后数据丢失容器被删除后容器内的所有数据都会丢失除非使用了数据卷。解决方案TEMU店群如何管理运营使用数据卷Volume持久化存储数据使用绑定挂载Bind Mount将主机目录挂载到容器定期备份数据卷# 使用数据卷推荐containerclient.containers.run(imagemysql:8.0,namemysql,volumes{mysql-data:{bind:/var/lib/mysql,mode:rw}},# 使用数据卷environment{MYSQL_ROOT_PASSWORD:password},detachTrue)# 使用绑定挂载containerclient.containers.run(imagenginx:latest,namenginx,volumes{/host/path:{bind:/container/path,mode:ro}},# 挂载主机目录detachTrue)坑4磁盘空间被Docker占用过多长时间运行Docker不清理镜像和容器磁盘空间会被占满。解决方案定期清理docker system prune -a --volumes⚠️ 危险设置日志轮转限制容器日志大小使用外部存储将数据卷存储到外部存储如NFS# 限制容器日志大小在docker-compose.yml或Dockerfile中配置# docker-compose.yml:# services:# myapp:# image: myapp:latest# logging:# driver: json-file# options:# max-size: 10m# max-file: 3总结功能节省时间附加价值自动构建镜像每次省10分钟确保构建过程一致自动部署容器每次省15分钟减少人为错误自动清理镜像每周省30分钟节省磁盘空间健康检查—及时发现问题实际落地建议先小范围测试在一个非关键服务上测试完整流程使用Docker Compose管理多容器应用设置资源限制限制容器使用的CPU和内存定期备份数据卷避免数据丢失Docker自动化能为开发/运维团队节省60%以上的部署时间同时减少人为错误提高发布质量。