Spring官网提供了一个简明的基于SpringBoot项目构建docker镜像的教程(Getting Started | Spring Boot with Docker)。这个教程给我了很大的启发,结合我现在实际项目,又进行一些改造。
引入多阶段构建
原始教程都是基于构建好的jar包做操作,这样就要求宿主机配置好JDK和Maven,这样就存在在不同的宿主机下,可能构建出不同的镜像,不够The Docker Way
。
通过多阶段构建我们一个在一个 Dockerfile 里使用多个FROM
。每一个FROM
都可以使用不同的基础镜像,没一个都开启一个构建的新阶段。 我们可以选择性的复制构建物从一个阶段到另一个,这样在最终的镜像里就不会有我们不需要的中间产物了。
1 2 3 4 5 6 7 8 9 10 11 |
FROM maven:3.8.2-adoptopenjdk-8 AS builder WORKDIR /build COPY . . RUN mvn clean package FROM adoptopenjdk:8-jdk-hotspot COPY --from=builder /build/target/*.jar /app/ ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"] |
减少文件复制
构建时.git,target等目录是不需要的,创建.dockerignore
文件:
1 2 3 4 5 |
.git/ target/ .idea/ Dockerfile |
减少与Maven服务器交互
如果项目严格按照每次部署jar包时版本号都改变,可以认为pom文件没发生变化时maven不需要向服务器更新依赖. mvn dependency:go-offline
可以下载所有的项目依赖,后续的所有mvn操作我们都可以添加-o
参数,maven就工作的离线模式,不再需要和maven服务器交互,提高构建速度。
1 2 3 4 5 6 7 8 9 10 11 12 |
FROM maven:3.8.2-adoptopenjdk-8 AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline COPY . . RUN mvn -o clean package FROM adoptopenjdk:8-jdk-hotspot ARG JAR_FILE=target/*.jar COPY --from=builder ${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"] |
缓存maven repository
现在每个项目的构建都有一个独立的本地maven repository,极大的浪费磁盘空间,同时也浪费网络带宽。共享maven repository有两个选择: 一个是通过挂载VOLUME
,或者利用BuildKit
(>=18.09)的Cache
.
VOLUME:
1 2 3 |
VOLUME "/root/.m2" RUN mvn xxx |
BuildKit:
1 2 |
RUN --mount=type=cache,id=mvnrepo,target=/root/.m2 mvn xxx |
启用BuildKit
docker默认是不启用BuildKit的。可以在执行docker build
之前设置环境变量DOCKER_BUILDKIT=1
,例如:
1 2 |
DOCKER_BUILDKIT=1 docker build . |
如果想默认启用BuildKit,可以通过配置/etc/docker/daemon.json
,然后重启daemon。
1 2 |
{ "features": { "buildkit": true } } |
更精细的镜像分层
原始教程镜像分为/BOOT-INF/lib
,/META-INF
,/BOOT-INF/classes
三层。对于普通项目来说是够用的,但是我司有一些自有jar包,更新频率高于三方的外部库,同时低于业务代码。为最大程序利用 docker 构建缓存及镜像层,我把/BOOT-INF/lib
分为两层,一层是外部依赖的jars,一层是公司的jars。
jar包的分层我是通过maven的dependency:copy-dependencies
并指定excludeGroupIds
和includeGroupIds
来实现的。
1 2 3 |
mvn dependency:copy-dependencies -DexcludeGroupIds=org.xobo -DoutputDirectory=./target/lib/3rd mvn dependency:copy-dependencies -DincludeGroupIds=org.xobo -DoutputDirectory=./target/lib/xobo |
额外要注意:
1. 如果项目有更精细的分层需求,有一点要注意,COPY 虽然支持模糊匹配,但是在复制目录的时候会把匹配上的目录内的内容复制到目的文件夹下。这样文件夹目录少了一层。
2. Maven 3.8.1禁止了HTTP repository, 必须使用HTTPS协议。 可以升级HTTP为HTTPS,或者添加一个mirror,或者版本降到3.6.3。
3. 不要追求镜像的绝对最小,像alpine这种镜像很多命令、基础库都和我们日常使用的Linux不一样,虽然一共能省了不到100M空间(docker基础层是共享的)但留下很多隐患。
最终的Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
FROM maven:3.8.2-adoptopenjdk-8 AS builder WORKDIR /build COPY pom.xml . RUN --mount=type=cache,id=mvnrepo,target=/root/.m2 mvn dependency:go-offline COPY . . RUN --mount=type=cache,id=mvnrepo,target=/root/.m2 mvn -B -o clean package && \ mvn -o dependency:copy-dependencies -DexcludeGroupIds=org.xobo -DoutputDirectory=./target/lib/3rd && \ mvn -o dependency:copy-dependencies -DincludeGroupIds=org.xobo -DoutputDirectory=./target/lib/my && \ jar xf ./target/demo.jar FROM adoptopenjdk:8-jdk-hotspot RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN adduser --system --no-create-home --group app USER app:app COPY --from=builder --chown app:app /build/target/lib/3rd /app/lib COPY --from=builder --chown app:app /build/target/lib/my /app/lib COPY --from=builder --chown app:app /build/BOOT-INF/classes /app COPY --from=builder --chown app:app /build/META-INF /app/META-INF EXPOSE 8080 ENTRYPOINT ["java","-cp","app:app/lib/*","org.xobo.DemoApplication"] |
最新评论
昨天发现的,然后在application.yml中配置“hibernate.dialect.storage_engine=innodb”。但是自动生成的表还是不会设置为innoDB,看了底层源码。这个配置也是没有加载到的 原来是要在hibernate.properties中加这个配置。感谢
将virtualbox虚拟网卡驱动卸载了,然后就会好了,但是这个时候virtualbox虚拟网络就无法使用了,重新安装一下virtualbox就好了
我也发现了这个注释:注释“Use "hibernate.dialect.storage_engine=innodb" environment variable or JVM system property instead.” ----- 坑啊。。。。。。。
卸载蓝牙驱动·在设备里面找,一般在网卡那里 卸载重启就行了
高