Docker多阶段构建还是gitlab runner

有些Docker镜像的生成有时候分为多个阶段,如:

  • 构建阶段:maven将java源代码转为jar
  • 运行阶段:tomcat运行jar

可以看到构建阶段需要依赖于maven,运行阶段需要依赖于tomcat。为了减小镜像大小,理想的镜像是仅包含运行环境的tomcat而不包含编译打包环境maven的镜像。

这时候有两种方式可以实现该目的。

方式一:使用gitlab runner的Docker excutor构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
stages:
- build
- deploy

build:
stage: build
image: maven:3.6.3-jdk-8
script:
# 生成 JAR 文件
- mvn clean package
# 使用 Dockerfile 构建 JAR 镜像
- docker build -t myapp-jar:latest .

deploy:
stage: deploy
image: docker:latest
services:
- docker:dind
script:
# 将 JAR 文件复制到 Tomcat 镜像中
- docker run --rm -v $CI_PROJECT_DIR:/app myapp-jar:latest cp /app/target/myapp.jar /path/to/tomcat/webapps/
# 最终构建包含 JAR 的 Tomcat 镜像
- docker build -t my-tomcat-image:latest .

通过runner启动一个maven容器,在maven容器中将java源代码转为jar,然后使用dind技术将jar放入tomcat镜像,这时候就得到tomcat + jar的镜像。

方式二:使用docker的多阶段构建

1
2
3
4
5
6
7
8
9
10
# 构建阶段
FROM maven:3.6.3-jdk-8 AS build
WORKDIR /app
COPY . .
RUN mvn clean package # 生成 jar

# 运行阶段
FROM tomcat:9.0
# 将上一个镜像生成的jar复制到当前镜像,构建包含 JAR 的 Tomcat 镜像
COPY --from=build /app/target/myapp.jar /usr/local/tomcat/webapps/myapp.jar

将生成jar逻辑放在Dockerfile中,先用maven镜像生成jar,得到一个maven + jar的镜像,然后使用tomcat镜像将刚刚生成的镜像中的jar复制过来,得到一个tomcat + jar的镜像。

二者的区别就是生成jar的逻辑是写在gitlab的.gitlab-ci.yml中还是写在Dockerfile中。

我个人倾向写在Dockerfile中,主要有一下几点考量。

  • gitlab runner专注cicd如git push触发钩子、ssh、测试、发布,运行脚本等宏观的事情,细节交给其他工具来做,如Dockerfile负责构建镜像、docker-compose负责挂载和网络。
  • 减少对gitlab runner的依赖,即使没有gitlab runner也能通过Docker build命令构建镜像
  • 可利用Docker layer的缓存,加快镜像构建速度。