![ece8a757ecc54865ee8d7b974433e9db.png](https://i-blog.csdnimg.cn/blog_migrate/90cc84078aa98a465a8962c4667b0833.jpeg)
Docker中传递变量主要使用ARG和ENV,虽然功能相同,但是他们的作用范围是不一样的。下面我们结合SpringBoot启动的JVM参数来详细了解下。通过本文介绍,我们可以知道这两个命令的具体使用方式。
ARG传递变量
ARG只在Dockerfile中生效,且在docker build阶段生效,构建好的镜像内不存在此环境变量。意味着在容器启动后ARG定义的变量已经无效,如果想让其生效,需要将其赋值给ENV。
#Dockerfilevim DockerfileFrom javaVOLUME /tmpARG JAR_FILE=*.jarCOPY ${JAR_FILE} helloworld.jarARG OPTS="-Xmx512m -Xms512m -Dspring.profiles.active=test"ENV JAVA_OPTS=${OPTS}ENTRYPOINT ["/bin/sh","-c","java $JAVA_OPTS -jar /helloworld.jar"]#builddocker build -t helloworld:v1 .#rundocker run -p 8080:8080 --name helloworld helloworld:v1#docker exec -it 29a90e0be2b3 /bin/bashroot@29a90e0be2b3:/# ps -ef|grep javaroot 1 0 0 13:22 ? 00:00:00 /bin/sh -c java $JAVA_OPTS -jar /helloworld.jarroot 6 1 10 13:22 ? 00:00:07 java -Xmx512m -Xms512m -Dspring.profiles.active=test -jar /helloworld.jarroot 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:v1docker exec -it 9aed3266d244 /bin/bashroot@9aed3266d244:/# ps -ef|grep javaroot 1 0 0 13:30 ? 00:00:00 /bin/sh -c java $JAVA_OPTS -jar /helloworld.jarroot 6 1 23 13:30 ? 00:00:07 java -Xmx216m -Xms216m -Dspring.profiles.active=test -jar /helloworld.jarroot 45 39 0 13:31 pts/0 00:00:00 grep java
此时可以看到"-Xmx216m -Xms216m -Dspring.profiles.active=test"已经覆盖dockerfile中的ARG变量。
ENV传递环境变量
Dockerfile中可以通过ENV来设置环境变量,并且可以在容器启动后使用。
#Dockerfilevim DockerfileFrom javaVOLUME /tmpARG JAR_FILE=*.jarCOPY ${JAR_FILE} helloworld.jarENV JAVA_OPTS="-Xmx512m -Xms512m -Dspring.profiles.active=test"ENTRYPOINT ["/bin/sh","-c","java $JAVA_OPTS -jar /helloworld.jar"]#builddocker build -t helloworld:v1 .#rundocker run -p 8080:8080 --name helloworld helloworld:v1#sudo docker exec -it 301aced67bb4 /bin/bashroot@301aced67bb4:/# ps -ef|grep javaroot 1 0 0 12:24 ? 00:00:00 /bin/sh -c java $JAVA_OPTS -jar /helloworld.jarroot 6 1 22 12:24 ? 00:00:10 java -Xmx512m -Xms512m -Dspring.profiles.active=test -jar /helloworld.jarroot 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定义的环境变量。
- ENV定义变量
#Dockerfilevim DockerfileFrom javaVOLUME /tmpARG JAR_FILE=*.jarCOPY ${JAR_FILE} helloworld.jarENV JAVA_OPTS="-Xmx512m -Xms512m -Dspring.profiles.active=test"ENTRYPOINT ["java","-jar","/helloworld.jar"]#builddocker build -t helloworld:v1 .#rundocker run -p 8080:8080 --name helloworld helloworld:v1
- 查看容器内部环境变量
#docker exec 3ca86b42c732 envPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=3ca86b42c732JAVA_OPTS=-Xmx512m -Xms512m -Dspring.profiles.active=testLANG=C.UTF-8JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64JAVA_VERSION=8u111JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1CA_CERTIFICATES_JAVA_VERSION=20140324HOME=/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 envPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=fed826eb25faJAVA_OPTS='-Xmx256m -Xms256m -Dspring.profiles.active=test'LANG=C.UTF-8JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64JAVA_VERSION=8u111JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1CA_CERTIFICATES_JAVA_VERSION=20140324HOME=/root
此时我们看到通过JAVA_OPTS自定义的环境变量为'-Xmx256m -Xms256m -Dspring.profiles.active=test',已经覆盖了ENV定义的环境变量,剩下的工作就是在容器内部来使用JAVA_OPTS 变量。
#修改Dockerfilevim DockerfileFrom javaVOLUME /tmpARG JAR_FILE=*.jarCOPY ${JAR_FILE} helloworld.jarENV JAVA_OPTS="-Xmx512m -Xms512m -Dspring.profiles.active=test"ENTRYPOINT ["java","$JAVA_OPTS","-jar","/helloworld.jar"]#builddocker build -t helloworld:v2 .#rundocker run -e JAVA_OPTS='-Xmx256m -Xms256m -Dspring.profiles.active=test' -p 8080:8080 -d --name helloworld2 helloworld:v2
此时helloworld2容器并没有正常启动,报错如下:
#docker logs 335ac14921d1Error: Could not find or load main class $JAVA_OPTS
看来JAVA_OPTS并没有接收到环境变量参数,而将其直接识别为字符串$JAVA_OPTS,因此会被java启动命令识别为class报错,这是为什么呢?
这就要从ENTRYPOINT的shell形式和exec形式说起,这两种形式的区别在于exec形式不像shell那样能够调用环境变量,因此我们必须使用shell形式。
#vim DockerfileFrom javaVOLUME /tmpARG JAR_FILE=*.jarCOPY ${JAR_FILE} helloworld.jarENV JAVA_OPTS="-Xmx512m -Xms512m -Dspring.profiles.active=test"ENTRYPOINT ["/bin/sh","-c","java $JAVA_OPTS -jar /helloworld.jar"]#builddocker build -t helloworld:v2 .#rundocker run -e JAVA_OPTS="-Xmx256m -Xms256m -Dspring.profiles.active=test" -p 8080:8080 -d --name helloworld2 helloworld:v2#测试curl 127.0.0.1:8080Hello world
此时我们启动容器,可以看到正常访问。由此我们得知通过docker run -e传输环境变量不能使用ENTRYPOINT的exec形式。
总结
通过本文的讲解,我们熟悉了docker部署SpringBoot项目时如何传递JVM参数,同时触类旁通,帮我们更好的在以后深入学习docker时打好基础。