docker使用dockerfile和shell脚本,动态参数控制,docker通过dockerfile构建spring boot项目
前言
最近在写搞项目中的测试环境远程debug,需要修改一下dockerfile中的shell脚本配置启动java程序中的参数,所以有在研究dockerfile和shell脚本
shell中传入参数
shell脚本,名称为start.up
#!/bin/bash
a=$1
b=$2
if [ "$a" == "1" ];then
echo "a=1"
else
echo "a!=1"
fi
if [ "$b" == "2" ];then
echo "b=2"
else
echo "b!=2"
fi
linux命令
[root@VM_0_8_centos shellTest]# sh startup.sh
a!=1
b!=2
[root@VM_0_8_centos shellTest]# sh startup.sh 1 2
a=1
b=2
可以看到。这样shell脚本中获得了从外部传入的参数
docker中获得参数并且传入到shell中
dockerfile
FROM centos:7
COPY startup.sh /opt
RUN chmod +x /opt/startup.sh
ARG a
ARG b
ENV a=${a} \
b=${b}
CMD /opt/startup.sh ${a} ${b}
linux命令
[root@VM_0_8_centos shellTest]# docker build -ttest:1.6 --build-arg a=1 --build-arg b=2 .
[root@VM_0_8_centos shellTest]# docker run -ti --rm=true test:1.6
a=1
b=2
[root@VM_0_8_centos shellTest]# docker run -ti -e a=2 -e b=3 --rm=true test:1.6
a!=1
b!=2
[root@VM_0_8_centos shellTest]# docker build -ttest:1.7 .
[root@VM_0_8_centos shellTest]# docker run -ti -e a=1 -e b=2 --rm=true test:1.7
a=1
b=2
就可以看到外部参数被传入了
修改
后面我才知道,当docker run -e的时候其实就是在容器之中写入环境变量,dodckerfile中ENV也是写入环境变量,而shell脚本其实可以直接读取到环境变量的参数,不需要sh启动的时候再传入参数这种比较繁琐的操作了
修改后的dockerfile
FROM centos:7
COPY startup.sh /opt
RUN chmod +x /opt/startup.sh
CMD /opt/startup.sh
修改后的shell脚本
#!/bin/bash
if [ ${a} == "1" ];then
echo "a=1"
else
echo "a!=1"
fi
if [ ${b} == "2" ];then
echo "b=2"
else
echo "b!=2"
fi
其中a , {a},a,{b}就是直接读取环境变量的a,b两个参数的数值
linux运行参数
[root@VM_0_8_centos shellTest]# docker build -ttest:1.9 .
[root@VM_0_8_centos shellTest]# docker run -ti -e a=1 -e b=2 --rm=true test:1.9
a=1
b=2
shell中的一个有趣的用法
shell脚本说明
:-
${a:-1} #获得环境变量a的值,如果没有,则设置默认值为1
修改后的shell脚本
#!/bin/bash
if [ ${a:-1} == "1" ];then
echo "a=1"
else
echo "a!=1"
fi
if [ ${b} == "2" ];then
echo "b=2"
else
echo "b!=2"
fi
linux命令
[root@VM_0_8_centos shellTest]# docker run -ti -e -e b=2 --rm=true test:2.0
[root@VM_0_8_centos shellTest]# docker run -ti -e b=2 --rm=true test:2.0
a=1
b=2
可以看到,这次我docker run的时候没有设置a环境变量,但是由于默认值的存在,还是给a设置了一个1的默认值。所以就有很多可控制的地方了
:-的用处
回到我们开始的地方,我现在需要做一个配置,在测试环境开启远程debug,在其他环境不开启。那么就可以在启动的shell脚本中设置这么一个参数,-jar 启动的时候传入这个参数,并且设置默认值为空,如果我需要开启远程debug,就可以在docker run -e 的时候把远程debug的参数穿进去就可以进行是否开启远程debug的控制了,置于远程debug的命令,可以参照我上一篇dockerfile开启spring boot远程debug
前期准备
既然是要启动一个spring cloud的项目,那么自然需要准备一个eureka的,这边可以参照我之前搭建过的eureka项目
eureka搭建
dockerfile的一般使用
这个是我的eureka的docker启动的dockerfile,但是里面其实是有点问题的
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD eureka.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
问题
我们通过docker exec 进入镜像之后,使用top。会发现java的进程占据了pid=1的位置。没法用jstack或者arthas这种工具进行分析,非常影响使用体验。
解决方法
使用一个shell脚本启动对应的java进场,这样shell脚本会占据pid的位置,或者直接让/bin/bash占据pid为1的进程位置。
具体过程
准备4个文件,一个dockerfile,一个jdk版本,一个srping boot jar包,一个sh脚本
dockerfile
FROM centos:7
#准备一个centos镜像
VOLUME /tmp
#挂载一个位置
ADD jdk-8u221-linux-x64.tar.gz /usr/local/
#复制jdk版本
ENV JAVA_HOME /usr/local/jdk1.8.0_221
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin
#设置java环境变量
ADD service-hi.jar app.jar
#复制jar包
ADD my-start.sh my-start.sh
#复制sh脚本
RUN chmod +x my-start.sh
#设置优先级
CMD ["sh","my-start.sh"]
#启动sh脚本
shell脚本
#!/bin/sh
#仅仅是一条简单的启动jar的命令,并且开启远程debug,端口为8888,我的spring boot项目占据的端口是8761
java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8888 app.jar
docker命令
docker build -t service:my .
docker run --name service -p 8762:8762 -p 8888:8888 -v /root/mySpringBoot/log:/log -d -it service:my
docker exec -it service /bin/sh
docker exec -it service /bin/bash
这样一个dockerfile的spring cloud项目就启动了。
一些小说明
dockerfile文件还可以写的更加好。我这种的话会导致docker build的时候层级过多,很影响build体验,或者docker from可以直接使用jdk8的centos镜像版本。可以节省更多的工作量。不过自从我对于dockerfile找到一点感觉之后,会更加倾向于自己控制所有的文件的构建,所有的环境的处理,这样会感觉更加在自己的掌握中。然后通过shell脚本,可以做更加多的控制。例如设置java的jvm参数等等操作,也很有意思。