自定义Dockerfile构建一个生产可用的jre base image
配置maven-docker-plugin
插件完成从源码的 打包fatjar
-> build docker image with fatjar
-> push image
支持docker对JVM相关参数的配置。比如Xmx,Xms,以及完全自定义的java启动参数。
说打包之前我们先了解linux内核与发行版操作系统(如centos,ubuntu,debian)之间的关系。
由于linux内核与具体的操作系统是解耦的。即互相不干涉的,docker利用了这个特性,将操作系统的文件打包成一个压缩文件。
在运行时,解压这个压缩包,并通过chroot进行挂载,就完成了容器的内部我们看到的操作系统了。即我们的rootfs。
那么这个和我们docker打包java应用的关系在哪里呢?
总所周知的是java是又提供打包解决方案的,打包成jar,但是此方案的问题在于我并不能在任何一个环境里面运行直接运行(因为依赖JRE),而每一个操作系统又不一样,这就导致许多环境带来的时间浪费。
结合前面提到了docker打包是把操作系统的文件打包的,所以我们能不能把操作系统+jre+application.jar
这三老铁一锅端,全给他打包起来不就解决了吗?没错,这就是我们要构建镜像。
没错我们想到了一个好的办法来解决打包的问题。那我们在来看看这个东西是不是还有啥问题?你看啊,我们最初了发布一个fatjar也就60M,要结合上OS jre
岂不是每次都大很多,浪费很多的磁盘,网络传送开销也加大的蛮多。
这个问题的docker中利用了分层文件系统来解决这个问题,即我们的OS JRE 这些不变的东西只会在第一次使用时下载一次或者上传一次,其他时候我们只有变化的application.jar层需要进行上传和下载
alpine
镜像构建,apline提供的包管理器是apk, FROM alpine:3.11.2
MAINTAINER qingmu [email protected]
ENV LANG=C.UTF-8 \
TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk update \
&& apk add --update procps \
&& apk add --no-cache ca-certificates ttf-dejavu tzdata tini bash
# 变动层
RUN apk add --no-cache openjdk8-jre
ENV JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk/jre \
PATH=$PATH:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin
RUN rm -rf /var/cache/apk/*
echo 'dockerfile' > Dockerfile
docker build -t freemanliu/openjre .
apk add --no-cache ttf-dejavu
spring-boot-dependencies
后,springboot默认在pluginManagement中配置好了 maven-shade-plugin
插件
org.apache.maven.plugins
maven-shade-plugin
com.qingmu.account.Application
mvn clean package
java -jar target/${artifactId}.jar
也能正确的启动成功。ENTRYPOINT和CMD命令最大的不同点,在于使用cmd命令是可以在运行是通过传递参数修改镜像的运行命令的,而ENTRYPOINT命令则是不支持的。
简单的说就是ENTRYPOINT类似编程中的常量,一旦定义好了就无法改变。而cmd则类似与变量,你可以在运行时随时赋值。
一起来看下这个例子,这是一个常见的使用docker打包java应用的dockerfile描述文件,。使用了ENTRYPOINT来指定启动命令。
freemanliu/openjre:8.232
FROM java:8
ADD app.jar app.jar
EXPOSE 8800
ENTRYPOINT ["java","-jar","/app.jar"]
docker run -it -rm freemanliu/app:v1.0.0
docker run -it -rm freemanliu/app:v1.0.0 sh
至于CMD也好还是ENTRYPOINT也罢,都可以用,看你的喜好了,我是更喜欢freedom一点的,我推荐CMD
那么好的,基础的东西我们就讨论到这里。
在具体配置之前我们先总结下需要干些什么:
第一步,肯定是先引入插件,不多说。
第二步,既然我们想要插件帮我们完成image的push,那的让插件知道我们的私服地址吧,得知道username/password吧,所以第二步我们得配置setting.xml,添加server。
第三步,插件有了,私服配好了,接下来就的琢磨插件的配置了吧,所有第三步我们配置插件。
第四步,配置完成一个插件之后,我们该考虑一下多环境打包的事儿吧。第四步处理profiles
com.spotify
docker-maven-plugin
1.1.1
~/.m2/settings.xml
这是因为maven默认读取的配置目录是当前用户目录下的.m2目录,windows的话你需要找到你当前用户。 vim ~/.m2/settings.xml
# 找到servers标签添加如下如下信息
aliyun-registry # id将在后面插件中用到
你的私服的username
你私服的密码
你的email
git-commit-id-plugin
通过该插件我们可以在maven的其他插件中很方便的用到git相关信息,比如获取到当前的git tag。
pl.project13.maven
git-commit-id-plugin
2.2.4
get-the-git-infos
revision
true
yyyyMMddHHmmss
true
${project.basedir}/.git
false
true
git.properties
false
false
40
-dirty
false
properties
标签中的大写的变量取值,意思为取得系统上下的属性,至于为什么要这么做呢?是因为为了让我们的镜像在运行是可以通过环境变量的形式对其进行修改优化。仔细看你会发现这些值都是有可能对于不同的硬件服务器有着完全不同的设定。避免了修改java内存及一些相关参数而重写打包镜像,也提供了一个修改的便捷渠道。env
标签,有没有觉得眼熟?这里是定义系统环境变量的地方,这里的定义与我们在properties
标签中定义的名称一致,可以看到我们在这里有进行一次变量取值,为什么又是变量取值,而不是写死一个值呢?
freemanliu/openjre
1.8.0_171
-Dservice.name=${project.artifactId} \
-XX:+UnlockExperimentalVMOptions \
-Xms${JAVA_HEAP_XMS} \
-Xmx${JAVA_HEAP_XMX} \
-XX:CICompilerCount=${CI_COMPILER_COUNT} \
-XX:G1NewSizePercent=${G1_NEW_SIZE_PERCENT} \
-XX:G1MaxNewSizePercent=${G1_MAX_NEW_SIZE_PERCENT} \
-DEUREKA_SERVER=${EUREKA_SERVER} \
-Dspring.profiles.active=${spring.profile} \
-Dspring.cloud.config.profile=${spring.profile} \
-XX:+UseG1GC \
-XX:+AggressiveOpts \
-XX:+UseFastAccessorMethods \
-XX:+UseStringDeduplication \
-XX:+UseCompressedOops \
-XX:+OptimizeStringConcat
1G
1G
5
60
true
8
${prod.eureka}
test
com.spotify
docker-maven-plugin
${docker.repository}/${docker.registry.name}/${project.artifactId}:${git.commit.id.describe-short}
${docker.repository}
/work
true
Asia/Shanghai
${jvm.Xms}
${jvm.Xmx}
${g1.new.size.percent}
${g1.max.size.percent}
${ci.compiler.count}
${eureka.url}
${java.opts}
${docker.jre}:${docker.jre.version}
/sbin/tini java ${JAVA_OPTS} -jar ${project.build.finalName}.jar
${pushImage}
${project.build.directory}
${project.build.finalName}.jar
aliyun-registry
package
build
docker
org.apache.maven.plugins
maven-shade-plugin
com.spotify
docker-maven-plugin
prod
${docker.registry}
${prod.eureka}
${g1.new.size.percent}
${g1.max.size.percent}
${prod.jvm.Xms}
${prod.jvm.Xmx}
true
prod
org.apache.maven.plugins
maven-shade-plugin
pl.project13.maven
git-commit-id-plugin
com.spotify
docker-maven-plugin
test
${test.docker.repository}
${test.eureka}
40
70
${test.jvm.Xms}
${test.jvm.Xmx}
false
latest
test
org.apache.maven.plugins
maven-shade-plugin
com.spotify
docker-maven-plugin
## [](https://qingmu.io/2018/08/07/How-to-run-springcloud-in-docker/#构建 "构建")构建
mvn clean pacakge -Pprod
mvn clean pacakge -Ptest
mvn clean pacakge -Djvm.Xms=8G -Djvm.Xmx=8G -Pdocker
[INFO] --- docker-maven-plugin:1.2.0:build (default) @ user-server ---
[INFO] Using authentication suppliers: [ConfigFileRegistryAuthSupplier, FixedRegistryAuthSupplier]
[INFO] Copying /Users/freeman/IdeaProjects2/user-server/target/user-server.jar -> /Users/freeman/IdeaProjects2/user-server/target/docker/user-server.jar
[INFO] Building image hub.mayixiaoke.com/my/user-server:latest
Step 1/12 : FROM freemanliu/openjre:1.8.0_171_font
---> 753ecb9267d1
Step 2/12 : ENV CI_COMPILER_COUNT 8
---> Using cache
---> 93bebb3621d4
Step 3/12 : ENV EUREKA_SERVER "-DEUREKA_SERVER=http://192.168.0.204:8761/eureka/"
---> Running in 42d31fcd4a7d
Removing intermediate container 42d31fcd4a7d
---> c1e478140e99
Step 4/12 : ENV G1_MAX_NEW_SIZE_PERCENT 70
---> Running in 794778b524dc
Removing intermediate container 794778b524dc
---> 6cf5ff851174
Step 5/12 : ENV G1_NEW_SIZE_PERCENT 40
---> Running in 85592d62fe30
Removing intermediate container 85592d62fe30
---> 8b69e9c6371e
Step 6/12 : ENV JAVA_HEAP_XMS 450m
---> Running in 683b34295fec
Removing intermediate container 683b34295fec
---> 24917bf053e6
Step 7/12 : ENV JAVA_HEAP_XMX 2G
---> Running in 74ba3caadd4b
Removing intermediate container 74ba3caadd4b
---> d1bd5ba01b7d
Step 8/12 : ENV JAVA_OPTS -Dservice.name=user-server -XX:+UnlockExperimentalVMOptions -Xms${JAVA_HEAP_XMS} -Xmx${JAVA_HEAP_XMX} -XX:CICompilerCount=${CI_COMPILER_COUNT} -XX:G1NewSizePercent=${G1_NEW_SIZE_PERCENT} -XX:G1MaxNewSizePercent=${G1_MAX_NEW_SIZE_PERCENT} -DEUREKA_SERVER=${EUREKA_SERVER} -Dspring.profiles.active=test -Dspring.cloud.config.profile=test -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:+UseStringDeduplication -XX:+UseCompressedOops -XX:+OptimizeStringConcat
---> Running in 2b4e73c01ad7
Removing intermediate container 2b4e73c01ad7
---> 2fd9b3ffa0ad
Step 9/12 : ENV TZ Asia/Shanghai
---> Running in 85946bd9bb3c
Removing intermediate container 85946bd9bb3c
---> b588ab3d7e2c
Step 10/12 : WORKDIR /work
---> Running in a41a0545883f
Removing intermediate container a41a0545883f
---> 53c863bbcdbf
Step 11/12 : ADD user-server.jar .
---> a3cf23754886
Step 12/12 : CMD /sbin/tini java ${JAVA_OPTS} -jar user-server.jar
---> Running in c3a716574080
Removing intermediate container c3a716574080
---> 262898825ee2
ProgressMessage{id=null, status=null, stream=null, error=null, progress=null, progressDetail=null}
Successfully built 262898825ee2
Successfully tagged hub.xxxx.com/my/user-server:latest
[INFO] Built hub.xxxx.com/my/user-server:latest
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 26.332 s
[INFO] Finished at:
[INFO] ------------------------------------------------------------------------
docker run -it --rm hub.xxx.com/my/user-server:latest sh
echo $JAVA_OPTS
-Dservice.name=user-server -XX:+UnlockExperimentalVMOptions -Xms450M -Xmx2G -XX:CICompilerCount=8 -XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60 -DEUREKA_SERVER=-DEUREKA_SERVER=http://192.168.0.204:8761/eureka/ -Dspring.profiles.active=prod -Dspring.cloud.config.profile=prod -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:+UseStringDeduplication -XX:+UseCompressedOops -XX:+OptimizeStringConcat
docker run -it --rm -e JAVA_HEAP_XMS=8G -e JAVA_HEAP_XMX=8G hub.xxx.com/my/user-server:latest sh
echo $JAVA_OPTS
-Dservice.name=user-server -XX:+UnlockExperimentalVMOptions -Xms4G -Xmx4G -XX:CICompilerCount=8 -XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60 -DEUREKA_SERVER=-DEUREKA_SERVER=http://192.168.0.204:8761/eureka/ -Dspring.profiles.active=prod -Dspring.cloud.config.profile=prod -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:+UseStringDeduplication -XX:+UseCompressedOops -XX:+OptimizeStringConcat