摘要:前言自动化构建是应用发布过程中必不可少的环节,常用的构建工具有等。当然,我推荐个人体验的话就用官方的吧,因为这样你构建的镜像还可以与他人共享。
前言
自动化构建是应用发布过程中必不可少的环节, 常用的构建工具有jenkins ,walle 等。而这些工具在构建应用时通常会有以下问题:
需要直接或间接的写一坨用于构建的shell命令等,不易管理、兼容性较差
上面一点可能还比较容易解决,但最为致命的是:重度依赖如jenkins宿主机或打包机上的软件环境,如git, maven,java等
理想情况是: 不同的应用如java应用、go应用、php应用等等,都可以在某台负责构建的宿主机上并行无干扰的执行构建操作,且构建中依赖的软件环境、构建流程等都可以由开发人员控制。
到目前为止,能很好的完成以上使命的,可能非docker莫属了!
在docker的世界里,构建交付的是镜像,而能够产生镜像的是Dockerfile (手动使用docker commit 的另当别论).
在docker ce 17.05 之后,出现了一个很重要的特性Multi-Stage Build (多阶段构建) , 它将显著提升你的运维生产力!
下文将用实战案例来详细解读Multi-Stage Build这一特性在Multi-Stage Build之前
以下演示以java hello world 为例,完整代码在: https://github.com/zhouzhipeng/docker-multi-stage-demo
这是一个标准的maven 项目,仅有个HelloWorld主类。大体构建思路为:
在maven镜像中编译并打包项目
将步骤1中生成的jar拷贝出来
用步骤2得到的jar,在jre镜像中构建并运行jar中的主类
Dockerfile.build 用于编译和打包jar
FROM maven:3.5.2-alpine MAINTAINER zhouzhipengWORKDIR /app COPY . . # 编译打包 RUN mvn package -Dmaven.test.skip=true
Dockerfile.old 用于运行jar中的主类
FROM openjdk:8-jre-alpine MAINTAINER zhouzhipengWORKDIR /app COPY docker-multi-stage-demo-1.0-SNAPSHOT.jar . # 运行main类 CMD java -cp docker-multi-stage-demo-1.0-SNAPSHOT.jar com.zhouzhipeng.HelloWorld
注意到,两个dockerfile之间关联的 docker-multi-stage-demo-1.0-SNAPSHOT.jar 文件,需要另外一个build.sh 脚本来串起来.
build.sh
#!/usr/bin/env bash # 1. 先构建出带有产物jar的镜像 docker build -t zhouzhipeng/dockermultistagedemo-build -f Dockerfile.build . # 2. 临时创建 dockermultistagedemo-build 容器 docker create --name build zhouzhipeng/dockermultistagedemo-build # 3. 将上面容器中的jar拷贝出来 docker cp build:/app/target/docker-multi-stage-demo-1.0-SNAPSHOT.jar ./ # 4. 构建java执行的镜像 docker build -t zhouzhipeng/dockermultistagedemo -f Dockerfile.old . # 5. 删除临时jar文件 rm -rf docker-multi-stage-demo-1.0-SNAPSHOT.jar
对Dockerfile和shell也了解的朋友相信应该都看得懂,在此不做过多赘述.
在Multi-Stage Build之后看过上一节后,你也许会感觉是不是有点麻烦呢? 是的,麻烦之处在于不仅要写多个dockerfile,而且还需要一个build.sh 脚本来额外执行。 无疑是增大了构建应用的复杂度!
将上面的Dockerfile.build 和Dockerfile.old 结合起来,稍加修饰,得到如下全新的Dockerfile:
FROM maven:3.5.2-alpine as builder MAINTAINER zhouzhipengWORKDIR /app COPY src . COPY pom.xml . # 编译打包 (jar包生成路径:/app/target) RUN mvn package -Dmaven.test.skip=true FROM openjdk:8-jre-alpine MAINTAINER zhouzhipeng WORKDIR /app COPY --from=builder /app/target/docker-multi-stage-demo-1.0-SNAPSHOT.jar . # 运行main类 CMD java -cp docker-multi-stage-demo-1.0-SNAPSHOT.jar com.zhouzhipeng.HelloWorld
然后,仍然是熟悉的docker build命令
docker build -t zhouzhipeng/dockermultistagedemo-new .
即可。
细心的你应该不难发现,上面的Dockerfile 中有两处地方不一样,
出现了多个FROM 语句
COPY 命令后多了--from=builder
这就是今天的主咖 Multi-Stage Build , 先来通过一张图来直观感受下什么是所谓的Multi-Stage Build (多阶段构建 ):
通过多阶段构建,既可以保持Dockerfile简洁易读,又可以让最终的产物镜像很“干净”。
简单理解还是以上文中的Dockerfile为例, 如下图所示:
红框中的部分可以看作是一个个独立的“stage” ,可以粗略想象成就是一个独立的Dockerfile内容。
大家知道镜像构建是一层一层叠加的,按照Dockerfile的命令行顺序,由上至下依次执行叠加。 所以,下层的stage才可以引用到上层的stage,为了方便引用到上层的stage,故需要给其取一个名字, 用as 操作符。
FROM 命令的完整格式如下:
FROM[: ] [AS ]
stage之间交互的是文件,故COPY 命令需要扩展,通过--from=
COPY --from=... # 注意--from 是可选的,当上层的stage没有名字时可以按照index(从0开始)的顺序引用,eg. --from=0
值得一提的是,默认情况下使用docker build 命令构建一个包含多个stage的dockerfile时,最终的产物是最下方的一个stage 所产生的镜像。
当然,如果出于调试原因或其他需求,docker也是支持构建到指定的stage的,使用 --target builder 就可以只构建builder镜像。
docker build -t zhouzhipeng/builder --target builder .最后一步
到目前为止,我们已经有了一个能够一键构建的Dockerfile 文件,接下来就只差让它能够自动构建了!
你可以用你熟悉的jenkins 结合github的webhook来实现提交一次代码,就执行一次docker build命令。
当然,我推荐个人体验的话就用官方的docker hub 吧,因为这样你构建的镜像还可以与他人共享。
具体的用Docker hub 的 automated build 功能就不详细说明了, 下面用一张gif图快速演示下,感兴趣的朋友可以自行去探索下。
总结Multi-Stage Build 这一特性非常适合做构建管道流,对于那些依赖环境复杂、流程也复杂的应用来说最合适不过了。
可以clone下上面的源码试下哦: https://github.com/zhouzhipeng/docker-multi-stage-demo
by zhouzhipeng from https://blog.zhouzhipeng.com/...参考文献
本文可全文转载,但需要保留原作者和出处。
https://docs.docker.com/v17.09/engine/userguide/eng-image/multistage-build/https://blog.alexellis.io/mutli-stage-docker-builds/
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/27297.html
摘要:本文已获得原作者授权。在构建镜像的过程中会缓存一系列中间镜像。镜像时,会顺序执行中的指令,并同时比较当前指令和其基础镜像的所有子镜像,若发现有一个子镜像也是由相同的指令生成,则命中缓存,同时可以直接使用该子镜像而避免再去重新生成了。 本文已获得原作者 CodeSheep 授权。 概述 Dockerfile 是专门用来进行自动化构建镜像的编排文件(就像 Jenkins 2.0时代的 J...
摘要:在构建镜像的过程中会缓存一系列中间镜像。镜像时,会顺序执行中的指令,并同时比较当前指令和其基础镜像的所有子镜像,若发现有一个子镜像也是由相同的指令生成,则命中缓存,同时可以直接使用该子镜像而避免再去重新生成了。 showImg(https://segmentfault.com/img/remote/1460000015606308?w=2000&h=1428); 概述 Docker...
摘要:指令这条命令是指明最后容器需要暴露哪些端口号,这样其他系统才能使用这个端口。但是灵活性不高,后面我在编排的时候会教大家用编排来统一开发环境。更多还有更多指令大家看下官方文档,我自己觉得上面的指令算是使用比较多的了。 前言 上一篇文章呢,我们简单的了解了Docker的基本命令,这篇文章呢,我们来了解下Dockerfile这个文件。 一个神奇的文件:Dockerfile 我不知道有多少同学...
摘要:指令这条命令是指明最后容器需要暴露哪些端口号,这样其他系统才能使用这个端口。但是灵活性不高,后面我在编排的时候会教大家用编排来统一开发环境。更多还有更多指令大家看下官方文档,我自己觉得上面的指令算是使用比较多的了。 前言 上一篇文章呢,我们简单的了解了Docker的基本命令,这篇文章呢,我们来了解下Dockerfile这个文件。 一个神奇的文件:Dockerfile 我不知道有多少同学...
摘要:采用虚拟化的技术来虚拟化出应用程序的运行环境。安装成功后,可以通过查看版本号尽量使用最新的稳定版本。是镜像名,是镜像的版本号,到此你已经成功构建了一个新的镜像,你可以通过,查看你的镜像。部署时将此文件到生产环境服务器上。 Docker docker是一个开源的应用容器引擎,可以为我们提供安全、可移植、可重复的自动化部署的方式。docker采用虚拟化的技术来虚拟化出应用程序的运行环境。此...
阅读 2736·2021-10-11 10:57
阅读 1567·2021-09-26 09:55
阅读 1308·2021-09-06 15:11
阅读 3446·2021-08-26 14:16
阅读 660·2019-08-30 15:54
阅读 534·2019-08-30 12:43
阅读 3288·2019-08-29 16:18
阅读 2564·2019-08-23 16:14