# 构建以及运行Springboot Docker镜像时的变量传递
Docker可以把我们的运行环境打包,然后我们只要run就可以了。大部分hello world都是这么写的。但都缺少了实际应用环节。以springboot为例,hello world的Dockerfile是这样的:
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
我们实际使用的时候通常是
java -jar app.jar --spring.profiles.active=prod
也就是说,需要分环境。那直接
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar", "--spring.profiles.active=prod"]
这样确实可以直接打出prod的运行包。直接run就可以了。
当同时需要打test环境的时候,我重新写一个新的Dockerfile,改成test, 然后构建,就可以了。
docker build -t demo -f Dockerfile.test .
写两个Dockerfile看起来太傻逼了,构建时替换好了。
暴力替换 -- shell替换
准备好我们的Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar", "--spring.profiles.active=<active-profile>"]
然后我们的构建脚本:
function build(){
local env=$1
sed -i 's/<active-profile>/${env}/g' Dockerfile
docker build -t demo --build-arg JAR_FILE=demo.jar .
}
# 构建测试环境的包
build test
# 构建生产环境的包
build prod
# 运行
docker run -d demo
使用运行时指定参数
我们可以打一份镜像,在运行的时候传递profile来确定激活哪个配置文件,就和springboot原生一样。
ENTRYPOINT里是Docker容器的运行命令, CMD则是追加的参数,也就是说可以在后面加参数的。
docker run -d demo --spring.profiles.active=prod
运行时还可以传递环境变量,就是系统的环境变量。
$ docker run -e "SPRING_PROFILES_ACTIVE=prod" -p 8080:8080 -t springio/gs-spring-boot-docker
按照Springboot属性覆盖优先级,命令行优先级超过系统环境变量的,所以还是选择其中一种方式就好了。
构建时传递参数
如果我们开发模式是master模式,即所有的分发部署都是同一个分支master, 先将master部署到test环境,没问题后直接发布到prod。同样的镜像,只是运行时指定配置文件。那么,我们是可以走运行时配置的。这样,不同环境的K8s配置文件要修改对应的cmd命令。
我现在开发模式类似gitflow. dev分支开发结束后,merge到test分支,test分支发布到测试环境,测试环境ready后,再merge到master分支,master分支发布到生产环境。即,test环境和prod环境是不同的分支打出的镜像。这就使得在打镜像的时候就指定配置文件。可以选择上文的暴力方式,文本替换。
也可以使用Docker参数。
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
ARG profile=prod
ENV SPRING_PROFILES_ACTIVE ${profile}
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
构建
docker build -t demo --build-arg JAR_FILE=demo.jar --build-arg profile=test .
ARG
允许通过--build-arg
传递参数ENV
等同于docker run -e来设置系统环境变量,但优先级弱于-e
上述几种方案差不多解决了我的springboot容器化部署方式。在构建其他docker镜像也可以通过类似的方案去传递参数。
大部分Dockerfile都是有docker-entrypoint.sh
, 将启动逻辑都放在一个脚本里,然后
ENTRYPOINT ["/docker-entrypoint.sh"]
这样,我们也可以在启动的时候传递参数到脚本里,脚本按照shell接受参数就可以了。
当前公司发布方案
- 流水线从feature分支拉取代码,merge master,以流水号组装分支release/20211012000
- 以该分支打包jar
- 用该jar包构建docker镜像, 上传docker仓库
- 触发k8s deploy
- 测试环境配置config map, 里面存储application.yml。 这样不同环境的配置文件通过加载config map的方式生效
- appliction里填写的配置中心的地址和版本号,修改配置只要修改配置中心的配置即可。
前文的各种魔改构建方案 纯粹个人设计的一个方案,在某些项目中采用,自己搭建gitlab jenkins k8s, 代码分支git flow,部署模型等。而实际大型公司,CI CD流程固定,用户无感知。
参考
关注我的公众号