Docker 多阶段构建实战 (multi-stage builds)
编写 Dockerfile
在/home/willzhao/temp/201906/02 目录下创建文件 Dockerfile,内容如下所示:
Docker image for multi stage build
VERSION 0.0.1
Author: bolingcavalry
第一阶段,用 maven 镜像进行编译
FROM maven:3.6.1 AS compile_stage
####################定义环境变量 start####################
#定义工程名称,也是源文件的文件夹名称
ENV PROJECT_NAME eureka-server
#定义工作目录
ENV WORK_PATH /usr/src/$PROJECT_NAME
####################定义环境变量 start####################
#作者
MAINTAINER BolingCavalry zq2599@gmail.com
#将源码复制到当前目录
COPY ./WORK_PATH
#如果前面您已经准备好了 repository 目录,就可以用来替换镜像中的 repository 目录了,先删除镜像中已有的 repository
RUN rm -rf /root/.m2/repository
#将准备好的 repository 文件夹复制进来,这样相当于镜像环境中已经有了 java 工程所需的 jar,可以避免去 maven 中央仓库下载
COPY ./repository /root/.m2/repository
#编译构建
RUN cd $WORK_PATH && mvn clean package -U -DskipTests
第二阶段,用第一阶段的 jar 和 jre 镜像合成一个小体积的镜像
FROM java:8-jre-alpine
####################定义环境变量 start####################
#定义工程名称,也是源文件的文件夹名称
ENV PROJECT_NAME eureka-server
#定义工程版本
ENV PROJECT_VERSION 0.0.1-SNAPSHOT
#定义工作目录
ENV WORK_PATH /usr/src/$PROJECT_NAME
####################定义环境变量 start####################
#安全起见不用 root 账号,新建用户 admin
RUN adduser -Dh /home/admin admin
#工作目录是/app
WORKDIR /app
#从名为 compile_stage 的 stage 复制构建结果到工作目录
COPY --from=compile_stage {PROJECT_NAME}-${PROJECT_VERSION}.jar .
#启动应用
CMD ["sh", "-c", "java -jar /app/{PROJECT_VERSION}.jar --spring.profiles.active=dev"]
上面就是分成了两个阶段构建的 Dockerfile 脚本,请参考每行的注释来理解,有以下几点需要重点关注:
一共有两次 FROM 指令出现,而最终的镜像是基于最后一个 FROM 生成的;
PROJECT_NAME 这个环境变量被定义了两次(ENV PROJECT_NAME),因为前面阶段定义的环境变量在后面的阶段是用不了的;
COPY --from=compile_stage 这个命令,可以将指定阶段的文件复制到当前阶段来,这一步很关键,第一阶段用 maven 构建出来的 jar 文件,通过该命令复制到后面的阶段来使用了;
最后一个 FROM 是 java:8-jre-alpine,这是精简版的 java 运行环境镜像,最终镜像的内容就是 jre 和 maven 的构建结果,而前面的 maven 镜像和最终构建结果无关;
构建镜像
在 Dockerfile 所在目录执行以下命令即可构建镜像:
docker build -t bolingcavalry/multi-stage-build:0.0.1-S
NAPSHOT .
输出的部分结果信息如下:
...
Step 13/16 : RUN adduser -Dh /home/admin admin
---> Running in 20421e52c3e6
Removing intermediate container 20421e52c3e6
---> dfb33f654436
Step 14/16 : WORKDIR /app
---> Running in d17f74e9c119
Removing intermediate container d17f74e9c119
---> bbd17f2d0777
Step 15/16 : COPY --from=compile_stage {PROJECT_NAME}-${PROJECT_VERSION}.jar .
---> 5d194c2a6b17
Step 16/16 : CMD ["sh", "-c", "java -jar /app/{PROJECT_VERSION}.jar --spring.profiles.active=dev"]
---> Running in 2cb771e5af44
Removing intermediate container 2cb771e5af44
---> b05fc74903ed
Successfully built b05fc74903ed
Successfully tagged bolingcavalry/multi-stage-build:0.0.1-SNAPSHOT
查看镜像的体积如下,148 兆,符合预期:
REPOSITORY TAG IMAGE ID CREATED SIZE
bolingcavalry/multi-stage-build 0.0.1-SNAPSHOT b05fc74903ed 2 minutes ago 148MB
maven 3.6.1 740262c47f21 3 days ago 614MB
java 8-jre-alpine fdc893b19a14 2 years ago 108MB
验证镜像是否可用
执行以下命令可以用最新的镜像启动一个容器:
docker run -p 8080:8082 bolingcavalry/multi-stage-build:0.0.1-SNAPSHOT
在前面 Dockerfile 文件的 CMD 命令中指定了 profile 参数为 dev,所以 application-dev.properties 文件会生效,这里面定义的端口号是 8082,所以 docker run 命令中通过-p 参数将容器的 8082 端口映射到宿主机 8080 端口
2. 用浏览器访问宿主机的 8080 端口,看服务是否正常,如下图:
评论