应用上K8S第一步:Dockerfile参数化构建技巧

需求
SpringBoot应用容器化上K8S,第一步就是通过maven或gradle进行镜像打包,准备工作如下:

maven/gradle docker-plugin实行应用编译打包;
Dockerfile,通过传递变量实现镜像的参数化打包;
Docker中传递变量主要使用ARG和ENV,虽然功能相同,但是他们的作用范围是不一样的。下面我们结合SpringBoot启动的JVM参数来详细了解下。通过本文介绍,我们可以知道这两个命令的具体使用方式。

ARG传递变量
ARG只在Dockerfile中生效,且在docker build阶段生效,构建好的镜像内不存在此环境变量。意味着在容器启动后ARG定义的变量已经无效,如果想让其生效,需要将其赋值给ENV。

Dockerfile

vim Dockerfile

From java

VOLUME /tmp

ARG JAR_FILE=*.jar

COPY ${JAR_FILE} helloworld.jar

ARG OPTS=”-Xmx512m -Xms512m -Dspring.profiles.active=test”

ENV JAVA_OPTS=${OPTS}

ENTRYPOINT [“/bin/sh”,”-c”,”java $JAVA_OPTS -jar /helloworld.jar”]

build

docker build -t helloworld:v1 .

run

docker run -p 8080:8080 –name helloworld helloworld:v1

docker exec -it 29a90e0be2b3 /bin/bash

root@29a90e0be2b3:/# ps -ef|grep java

root 1 0 0 13:22 ? 00:00:00 /bin/sh -c java $JAVA_OPTS -jar /helloworld.jar

root 6 1 10 13:22 ? 00:00:07 java -Xmx512m -Xms512m -Dspring.profiles.active=test -jar /helloworld.jar

root 49 39 0 13:23 pts/0 00:00:00 grep java
此时通过ARG定义的变量OPTS,已经成功通过ENV环境变量作为java启动参数。当然我们也可以在docker build –build-arg 传递ARG变量,此时将覆盖dockerfile内部的ARG变量。

–build-arg 定义变量

docker build –build-arg OPTS=”-Xmx216m -Xms216m -Dspring.profiles.active=test” -t helloworld:v1 .

docker run -p 8080:8080 -d –name helloworld1 helloworld:v1

docker exec -it 9aed3266d244 /bin/bash

root@9aed3266d244:/# ps -ef|grep java

root 1 0 0 13:30 ? 00:00:00 /bin/sh -c java $JAVA_OPTS -jar /helloworld.jar

root 6 1 23 13:30 ? 00:00:07 java -Xmx216m -Xms216m -Dspring.profiles.active=test -jar /helloworld.jar

root 45 39 0 13:31 pts/0 00:00:00 grep java
此时可以看到”-Xmx216m -Xms216m -Dspring.profiles.active=test”已经覆盖dockerfile中的ARG变量。

ENV传递环境变量
Dockerfile中可以通过ENV来设置环境变量,并且可以在容器启动后使用。

Dockerfile

vim Dockerfile

From java

VOLUME /tmp

ARG JAR_FILE=*.jar

COPY ${JAR_FILE} helloworld.jar

ENV JAVA_OPTS=”-Xmx512m -Xms512m -Dspring.profiles.active=test”

ENTRYPOINT [“/bin/sh”,”-c”,”java $JAVA_OPTS -jar /helloworld.jar”]

build

docker build -t helloworld:v1 .

run

docker run -p 8080:8080 –name helloworld helloworld:v1

sudo docker exec -it 301aced67bb4 /bin/bash

root@301aced67bb4:/# ps -ef|grep java

root 1 0 0 12:24 ? 00:00:00 /bin/sh -c java $JAVA_OPTS -jar /helloworld.jar

root 6 1 22 12:24 ? 00:00:10 java -Xmx512m -Xms512m -Dspring.profiles.active=test -jar /helloworld.jar

root 45 39 0 12:24 pts/0 00:00:00 grep java
通过以上我们可以看出容器启动后,在dockerfile中通过ENV定义的环境变量JAVA_OPTS已经被成功应用到java启动命令中。

docker run -e传递环境变量
我们也可以使用docker run 启动容器是,通过-e参数来传递变量,这时它会覆盖Dockfile内部通过ENV定义的环境变量。

1.ENV定义变量

Dockerfile

vim Dockerfile

From java

VOLUME /tmp

ARG JAR_FILE=*.jar

COPY ${JAR_FILE} helloworld.jar

ENV JAVA_OPTS=”-Xmx512m -Xms512m -Dspring.profiles.active=test”

ENTRYPOINT [“java”,”-jar”,”/helloworld.jar”]

build

docker build -t helloworld:v1 .

run

docker run -p 8080:8080 –name helloworld helloworld:v1
2.查看容器内部环境变量

docker exec 3ca86b42c732 env

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

HOSTNAME=3ca86b42c732

JAVA_OPTS=-Xmx512m -Xms512m -Dspring.profiles.active=test

LANG=C.UTF-8

JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

JAVA_VERSION=8u111

JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1

CA_CERTIFICATES_JAVA_VERSION=20140324

HOME=/root
通过以上命令我们可以看到容器默认的环境变量,也可以通过”docker run -e”方式添加自定义环境变量:

通过docker run -e 传递环境变量

docker run -e JAVA_OPTS=’-Xmx256m -Xms256m -Dspring.profiles.active=test’ -p 8080:8080 -d –name helloworld helloworld:v1

docker exec fed826eb25fa env

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

HOSTNAME=fed826eb25fa

JAVA_OPTS=’-Xmx256m -Xms256m -Dspring.profiles.active=test’

LANG=C.UTF-8

JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

JAVA_VERSION=8u111

JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1

CA_CERTIFICATES_JAVA_VERSION=20140324

HOME=/root
此时我们看到通过JAVA_OPTS自定义的环境变量为’-Xmx256m -Xms256m -Dspring.profiles.active=test’,已经覆盖了ENV定义的环境变量,剩下的工作就是在容器内部来使用JAVA_OPTS 变量。

修改Dockerfile

vim Dockerfile

From java

VOLUME /tmp

ARG JAR_FILE=*.jar

COPY ${JAR_FILE} helloworld.jar

ENV JAVA_OPTS=”-Xmx512m -Xms512m -Dspring.profiles.active=test”

ENTRYPOINT [“java”,”$JAVA_OPTS”,”-jar”,”/helloworld.jar”]

build

docker build -t helloworld:v2 .

run

docker run -e JAVA_OPTS=’-Xmx256m -Xms256m -Dspring.profiles.active=test’ -p 8080:8080 -d –name helloworld2 helloworld:v2
此时helloworld2容器并没有正常启动,报错如下:

docker logs 335ac14921d1

Error: Could not find or load main class $JAVA_OPTS
看来JAVA_OPTS并没有接收到环境变量参数,而将其直接识别为字符串$JAVA_OPTS,因此会被java启动命令识别为class报错,这是为什么呢?

这就要从ENTRYPOINT的shell形式和exec形式说起,「这两种形式的区别在于exec形式不像shell那样能够调用环境变量,因此我们必须使用shell的形式。」

vim Dockerfile

From java

VOLUME /tmp

ARG JAR_FILE=*.jar

COPY ${JAR_FILE} helloworld.jar

ENV JAVA_OPTS=”-Xmx512m -Xms512m -Dspring.profiles.active=test”

ENTRYPOINT [“/bin/sh”,”-c”,”java $JAVA_OPTS -jar /helloworld.jar”]

build

docker build -t helloworld:v2 .

run

docker run -e JAVA_OPTS=”-Xmx256m -Xms256m -Dspring.profiles.active=test” -p 8080:8080 -d –name helloworld2 helloworld:v2

测试

curl 127.0.0.1:8080

Hello world
此时我们启动容器,可以看到正常访问。由此我们得知通过docker run -e传输环境变量不能使用ENTRYPOINT的exec形式。

总结
通过本文的讲解,我们熟悉了docker部署SpringBoot项目时如何传递JVM参数,同时触类旁通,帮我们在后续应用上K8S 通过configmap或env环境变量传递参数做好准备。

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/164554.html

(0)
联系我们
联系我们
分享本页
返回顶部