打包的docker镜像,启动时使用docker run -e 参数添加环境变量时,环境变量名称中包含".",有时能在环境变量里获取到,有时不能在环境变量里获取到;
由于linux设置环境变量的规范中,不允许带".",但公司老的内部java框架中使用了读取带"."的环境变量做配置,所以需要解决该问题;
先打包基础的docker镜像:
Dockerfile如下
FROM openjdk:8u151-jdk
MAINTAINER Ma Qian
RUN curl -sSL 'https://raw.githubusercontent.com/maqian/toolbox/master/debian/stretch/set-sources-cn' | sh \
&& curl -sSL 'https://raw.githubusercontent.com/maqian/toolbox/master/debian/set-timezone-cn' | sh \
&& curl -sSL 'https://raw.githubusercontent.com/maqian/toolbox/master/debian/set-locale-cn' | sh \
&& curl -sSL 'https://raw.githubusercontent.com/maqian/toolbox/master/sysfree/install-ejava' | sh \
&& apt-get install -y openjdk-8-dbg
ENV TIMEZONE=Asia/Shanghai TZ=Asia/Shanghai \
LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8:zh:en_US:en
dockerfile目录下,执行docker build -t hub.wentjiang.com/base/java:openjdk-8u151 ./
执行完成后可以看到基础镜像创建成功
启动docker容器进行测试:
使用-e参数添加了两个环境变量
docker run --rm -it \
-e test.name=wentao.jiang \
-e test=wentao.jiang \
hub.wentjiang.com/base/java:openjdk-8u151 \
/bin/bash
执行后进入命令行,输入printenv打印当前容器内所有的环境变量:
目前可以获取到test.name的环境变量
编写一个helloWorld程序,使用上述的基础镜像进行打包,模拟实际业务部署时的场景;
java代码如下:
/**
* @author wentaojiang
* @date 2019/5/30 11:46 PM
* @description
*/
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello docker java");
System.out.println(System.getenv("test.name"));
System.out.println(System.getenv("test"));
}
}
使用javac HelloWrold.java 得到HelloWorld.class文件
将HelloWorld.class打包到镜像中进行测试
Dockerfile如下:
FROM hub.wentjiang.com/base/java:openjdk-8u151
COPY HelloWorld.class /HelloWorld.class
ENTRYPOINT ["sh","-c","printenv;java HelloWorld"]
执行打包镜像命令:
docker build -t hub.wentjiang.com/java/helloworld:1.0.0 ./
可以看到镜像已经生成
使用docker run命令启动容器进行测试
docker run -it --rm \
-e test.name=wentao.jiang \
-e test=wentao.jiang \
hub.wentjiang.com/java/helloworld:1.0.0
这次启动之后,在环境变量里边添加的test.name环境变量已经不见了,在我们模拟的java进程中同样也获取不到test.name的环境变量;
公司内有两种基础镜像,open-jdk版本的,和oracle-jdk版本的
open-jdk使用的打包基础镜像为openjdk:8u151-jdk,经过一层一层的向上查找,该镜像使用的是https://github.com/debuerreotype/docker-debian-artifacts/blob/fd138cb56a6a6a4fd9cb30c2acce9e8d9cccd28a/stretch/Dockerfile debian发行版;
oracle-jdk使用的是centos:7镜像;
使用oracle-jdk任何情况都能够读取到带"."的环境变量,使用open-jdk的镜像,在部分情况下会出现不能读取的情况,下边再进行操作分心;
使用测试的Dockerfile为:
FROM hub.wentjiang.com/base/java:openjdk-8u151
COPY HelloWorld.class /HelloWorld.class
#CMD ["java","HelloWorld"] #可以打印带"."环境变量 1.0.1
#ENTRYPOINT ["java","HelloWorld"] #可以打印带"."环境变量 1.0.2
#CMD ["sh","-c", "java HelloWorld;"] #不能打印带"."环境变量 1.0.3
#ENTRYPOINT ["sh","-c","java HelloWorld"] #不能打印带"."环境变量 1.0.4
分别打包了四个docker镜像并启动测试,前两个可以打印出来带"."环境变量,后两个不行;
至此可以判断是由于debian操作系统,在使用sh 命令执行后,不能获取带"."环境变量;
为了验证,我们直接使用上边注释掉执行命令的docker,打包docker build -t hub.wentjiang.com/java/helloworld:3.0.0 ./
使用命令进入容器中:
docker run -it --rm \
-e test.name=wentao.jiang \
-e test=wentao.jiang \
hub.wentjiang.com/java/helloworld:3.0.0 bash
可以看到直接执行printenv能够输出带"."环境变量
使用sh -c printenv不能输出带"."环境变量
目前的推测是:sh命令新启了个shell进程,新的shell进程按照规范,忽略了带"."环境变量,导致该问题的发生;