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
1.查看容器内部环境变量
#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参数,同时触类旁通,帮我们更好的在以后深入学习docker时打好基础。