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参数等等操作,也很有意思。

 

posted @ 2024-06-20 10:02  CharyGao  阅读(212)  评论(0编辑  收藏  举报