Springboot项目镜像制作&传递环境变量、设置hostname、动态设置JVM参数、cmd&entrypoint区别&docker-entrypoint.sh 用法
实现制作一个springboot 的镜像,并且可以传递环境变量实现动态JVM参数和端口。
0. 准备 & cmd、entrypoint 区别
1. 准备
- springboot 项目
一个简单的springboot 项目,默认启动8001 端口,里面只有一个接口。
xxx % curl localhost:8081
index
- docker 环境
2. CMD、entrypoint 区别
在Docker中,CMD和ENTRYPOINT都是Dockerfile中用于指定容器启动时运行的命令,但它们之间有重要的区别:
CMD:
用途:CMD是可选的,它提供了一个默认的命令或参数集,可以被docker run命令中的参数覆盖。
执行方式:CMD可以以两种形式存在:
Shell形式:CMD command param1 param2 ...(内部使用/bin/sh -c 运行)
Exec形式:CMD ["executable", "param1", "param2"](不依赖shell,直接执行)
覆盖性:当使用docker run命令时,如果提供了命令,CMD的内容会被替换。
ENTRYPOINT:
用途:ENTRYPOINT是强制性的,它定义了一个容器启动时的入口点,类似于一个固定前缀,不会被docker run命令中的参数覆盖,而是将这些参数附加到ENTRYPOINT后面。
执行方式:ENTRYPOINT也支持两种形式,但通常推荐使用Exec形式,因为它更稳定且不依赖于shell。
Shell形式:ENTRYPOINT command param1 param2 ...(内部使用/bin/sh -c 运行)
Exec形式:ENTRYPOINT ["executable", "param1", "param2"]
组合性:即使docker run提供了命令,这些命令也会作为参数传递给ENTRYPOINT,而不是替换它。
举例来说,如果你有一个Dockerfile,其中设置了ENTRYPOINT ["java", "-jar", "app.jar"],然后运行docker run myimage arg1 arg2,容器将会启动并执行java -jar app.jar arg1 arg2。而如果只有CMD,docker run命令中的参数会替换CMD,不再是默认命令。
总结来说,ENTRYPOINT更像是容器的固定启动脚本,而CMD提供了默认参数,这两者结合使用可以创建出灵活且可配置的容器启动行为。
如果同一个Dockerfile 写了多个CMD或者ENTRYPOINT, 只有最后一个生效。
1. 第一版本: 构建基础能跑的
1. 编写dockerfile
# 使用官方的Java 8运行时作为基础镜像
FROM openjdk:8-jdk-alpine
# 维护者信息
LABEL maintainer="qlq@163.com"
# 设置工作目录
WORKDIR /app
# 将本地的JAR文件复制到容器中的工作目录
COPY app.jar /app/app.jar
# 暴露应用的端口,假设应用默认监听8081端口
EXPOSE 8081
# 使用exec形式的ENTRYPOINT以获得更好的信号处理能力
ENTRYPOINT ["/usr/bin/java", "-jar", "/app/app.jar"]
# 或者直接使用CMD,根据个人偏好和需求选择
# CMD ["java", "-jar", "app.jar"]
2. 构建和运行
xxx % docker build -t qlq_app:latest .
...
xxx % docker run -d -p 8081:8081 qlq_app
9c31ed3c0b3777a6fea2c855d1b8654e5dc949bc957f990d27a315b00384db32
2. 第二版本:增加一个sh 脚本验证cmd、entrypoint 区别
1. 操作-cmd
- 准备docker-entrypoint.sh, 内容如下:
#!/bin/bash
# 定义日志文件路径
LOG_FILE="/app/app.log"
echo 'start~~~' >> "$LOG_FILE"
# 使用追加模式(>>)将所有参数输出到日志文件
echo "Parameters passed to the script: $*" >> "$LOG_FILE"
echo "Each parameter on a new line:" >> "$LOG_FILE"
for arg in "$@"; do
echo "$arg" >> "$LOG_FILE"
done
echo 'end~~~' >> "$LOG_FILE"
/usr/bin/java -jar /app/app.jar
- 编写Dockerfile
# 使用官方的Java 8运行时作为基础镜像
FROM openjdk:8-jdk-alpine
# 维护者信息
LABEL maintainer="qlq@163.com"
# 设置工作目录
WORKDIR /app
# 将本地的文件复制到容器中的工作目录
COPY app.jar /app/app.jar
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN chmod +x /app/docker-entrypoint.sh
# 改用root启动
USER root
# 使用exec形式的ENTRYPOINT以获得更好的信号处理能力
# ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
# 或者直接使用CMD,根据个人偏好和需求选择
CMD ["/bin/sh", "/app/docker-entrypoint.sh"]
- 构建后执行-正常执行启动
# 构建
docker build -t app_cmd:latest .
# 启动
docker run -d -p 8081:8081 app_cmd
05f08bf21e7df4852b8e4bb146503280ec1f7fbbe1a3bf051883b0bd084ab022
# 测试
xxx % docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
05f08bf21e7d app_cmd "/bin/sh /app/docker…" 4 seconds ago Up 3 seconds 0.0.0.0:8081->8081/tcp pedantic_merkle
17d8e50240b9 portainer/portainer-ce "/portainer" 6 weeks ago Up 4 hours 0.0.0.0:8000->8000/tcp, 0.0.0.0:9000->9000/tcp, 9443/tcp portainer
xxx % curl localhost:8081
index%
# 进入容器查看日志
/app # cat app.log
start~~~
Parameters passed to the script:
Each parameter on a new line:
end~~~
- 尝试启动传递其他命令
# 启动传递其他命令
xxx % docker run -d -p 8081:8081 app_cmd sh -c "cat /app/app.log"
bff4d7c8144db99664fb46f4c04fe1d2b8e448e8d1675dbdae77ebac61459f44
# 查看容器日志
xxx % docker logs bff4d7c8144db99664fb46f4c04fe1d2b8e448e8d1675dbdae77ebac61459f44
cat: can't open '/app/app.log': No such file or directory
# 查看容器,可以看到。 命令被覆盖, 也就是Dockerfile CMD 指定的命令没有执行,被自己的sh -c "cat /app/app.log" 覆盖
xxx % docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bff4d7c8144d app_cmd "sh -c 'cat /app/app…" 11 seconds ago Exited (1) 10 seconds ago interesting_agnesi
2. 操作-entrypoint
- 操作都相同,只是Dockerfile 启动缓存entrypoint
# 使用官方的Java 8运行时作为基础镜像
FROM openjdk:8-jdk-alpine
# 维护者信息
LABEL maintainer="qlq@163.com"
# 设置工作目录
WORKDIR /app
# 将本地的文件复制到容器中的工作目录
COPY app.jar /app/app.jar
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN chmod +x /app/docker-entrypoint.sh
# 改用root启动
USER root
# 使用exec形式的ENTRYPOINT以获得更好的信号处理能力
ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
- 正常启动-没问题
- 尝试启动传递其他命令
# 启动
xxx % docker run -d -p 8081:8081 app_entry sh -c "cat /app/app.log"
d644cb6be72757959296d97b56588d14c3aa6206f6eb2bfced2c2ff683fc4818
# 查看容器状态
xxx % docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d644cb6be727 app_entry "/bin/sh /app/docker…" 3 seconds ago Up 2 seconds 0.0.0.0:8081->8081/tcp gracious_proskuriakova
# 进容器查看日志
/app # cat app.log
start~~~
Parameters passed to the script: sh -c cat /app/app.log
Each parameter on a new line:
sh
-c
cat /app/app.log
end~~~
3. 两者结合
- Dockerfile
# 使用官方的Java 8运行时作为基础镜像
FROM openjdk:8-jdk-alpine
# 维护者信息
LABEL maintainer="qlq@163.com"
# 设置工作目录
WORKDIR /app
# 将本地的文件复制到容器中的工作目录
COPY app.jar /app/app.jar
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN chmod +x /app/docker-entrypoint.sh
# 改用root启动
USER root
# 使用exec形式的ENTRYPOINT以获得更好的信号处理能力
ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
CMD ["default", "argument"]
- 构建
docker build -t app_entry_cmd:latest .
- 正常执行然后查看容器内日志 (可以看到cmd 作为 参数传进去了)
# 执行
docker run -d -p 8081:8081 app_entry_cmd
# 容器内查看日志
/app # cat app.log
start~~~
Parameters passed to the script: default argument
Each parameter on a new line:
default
argument
end~~~
- 增加外部参数调用(可以看到覆盖默认的cmd参数)
# 执行
docker run -d -p 8081:8081 app_entry_cmd arg1 arg2 arg3
# 容器内查看日志
/app # cat app.log
start~~~
Parameters passed to the script: arg1 arg2 arg3
Each parameter on a new line:
arg1
arg2
arg3
end~~~
4. docker 查看镜像的cmd 和 entrypoint&docker-entrypoint.sh 用法
docker-entrypoint.sh 一般默认的规约是作为容器的ENTRYPOINT, 是个不成文的约定吧。
1. 查看rabbitMQ 的详情: 可以看到cmd、entrypoint
进容器内部也可以看到 docker-entrypoint.sh 文件。
xxx % docker inspect fb11f4e0a6b6
[
{
"Id": "sha256:fb11f4e0a6b6fa0d04d5a997ac9ad91c3950dfe8954e30f541fae35de7a02cc6",
"RepoTags": [
"hub.c.163.com/library/rabbitmq:management"
],
"RepoDigests": [
"hub.c.163.com/library/rabbitmq@sha256:c588cd42513f67a4c54cdb58303c4f56ccea4ddd32c2dbfea6e15c3668d54314"
],
"Parent": "",
"Comment": "",
"Created": "2017-08-17T18:49:07.435927944Z",
"Container": "877e376f642c7f6872818857767cab5b37544c52d4ae30602e28c2109ccabf58",
"ContainerConfig": {
"Hostname": "b3b330cec4cc",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"15671/tcp": {},
"15672/tcp": {},
"25672/tcp": {},
"4369/tcp": {},
"5671/tcp": {},
"5672/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/lib/rabbitmq/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.10",
"RABBITMQ_LOGS=-",
"RABBITMQ_SASL_LOGS=-",
"RABBITMQ_VERSION=3.6.11",
"RABBITMQ_DEBIAN_VERSION=3.6.11-1",
"HOME=/var/lib/rabbitmq"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"EXPOSE 15671/tcp 15672/tcp"
],
"ArgsEscaped": true,
"Image": "sha256:eeb9f873546cd6b77562f875aefbfc56bab3f2f7f8a47f0b06d9b5eb51c37464",
"Volumes": {
"/var/lib/rabbitmq": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": [],
"Labels": {}
},
"DockerVersion": "17.03.2-ce",
"Author": "",
"Config": {
"Hostname": "b3b330cec4cc",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"15671/tcp": {},
"15672/tcp": {},
"25672/tcp": {},
"4369/tcp": {},
"5671/tcp": {},
"5672/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/lib/rabbitmq/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.10",
"RABBITMQ_LOGS=-",
"RABBITMQ_SASL_LOGS=-",
"RABBITMQ_VERSION=3.6.11",
"RABBITMQ_DEBIAN_VERSION=3.6.11-1",
"HOME=/var/lib/rabbitmq"
],
"Cmd": [
"rabbitmq-server"
],
"ArgsEscaped": true,
"Image": "sha256:eeb9f873546cd6b77562f875aefbfc56bab3f2f7f8a47f0b06d9b5eb51c37464",
"Volumes": {
"/var/lib/rabbitmq": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": [],
"Labels": {}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 123727273,
"VirtualSize": 123727273,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/497f3e9e83addeb470091b482e265ef7f5cdbd79e8625a905fedea8c09947a45/diff:/var/lib/docker/overlay2/32e2e530bbf46db672efa4e20716e3e77cc82d090343df0e60795ae641296644/diff:/var/lib/docker/overlay2/c8f06059a4c7f6c27f89d7f213fdd8dc3d072435a269de44094c65344e3ecf57/diff:/var/lib/docker/overlay2/37c80b17edc7f10653ce860b8fb4ff176e14a2a7597d589df4a3e925fbeeb59c/diff:/var/lib/docker/overlay2/b540da80b28ce2e2fc0c90e3d7a55a4176d996c6fa6ff6e7897c07bf618b1c5c/diff:/var/lib/docker/overlay2/172c2cc503f1592b118f3c4ec9d33ce47cd76926195a959be96c81d4f79602c5/diff:/var/lib/docker/overlay2/7cb75cd98f107f2943ec8e2c62779cd5b600ade64d7678343283153990979fb1/diff:/var/lib/docker/overlay2/88b075b0d07ac8db854ca2bddd09efc71c220a601c72b76e6fca53cb86fe5b9e/diff:/var/lib/docker/overlay2/c36eae1bb17acc9c62e71a3482f681b39e3f47f1d9182ccb90a701c9581447b5/diff:/var/lib/docker/overlay2/16a3b893e3ee41b05517ae956352ed7ee5aa51f1c8390b4e351823759e5e4e0f/diff:/var/lib/docker/overlay2/25f314e67ff6db2576eee170998062bcd8ef08b4e7f742ec9067c43ac1c20258/diff:/var/lib/docker/overlay2/8eeac5a5c1f484cec00940cd8c98794ec591c26ad311c990a323726f99112f59/diff:/var/lib/docker/overlay2/153eebc683924191c39646054d95b1ec0b4da937b5c7f4b91da42885cd4b3254/diff",
"MergedDir": "/var/lib/docker/overlay2/e10ffb7662a639a7ab8f7b97db10d35915ad095243dec160c47e9b30da14bcfc/merged",
"UpperDir": "/var/lib/docker/overlay2/e10ffb7662a639a7ab8f7b97db10d35915ad095243dec160c47e9b30da14bcfc/diff",
"WorkDir": "/var/lib/docker/overlay2/e10ffb7662a639a7ab8f7b97db10d35915ad095243dec160c47e9b30da14bcfc/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:eb78099fbf7fdc70c65f286f4edc6659fcda510b3d1cfe1caa6452cc671427bf",
"sha256:54941f24e370c04208be9442119185303b696a38c42998648b2bdd16825957c0",
"sha256:88d342d3fd370a0d3d9c1140b23cb436491cdac62fdc3233cd657c2c9dfdb4d0",
"sha256:f470bb60dd6ce2f4b2011080d52f0fd5e3ea5fea652fc296d7c5d9b2412cf090",
"sha256:816c1661a4c6c6ab91f7c839aff27c7a098c12916b77e3e85f55fa57a2e13a83",
"sha256:e9f373b59af0d96326d93601662bf5a90b43d5943d4229034fce439b5cff4d44",
"sha256:f4ea331ee3a51c8534a4fdf17412176d98932f515b523d2b92c52508b253e642",
"sha256:e847abd1a23965b6019c79d46f33203d9a6564545232746491f2634d3fbb5ecb",
"sha256:284605e8c05898078109f43699038bbb46ead329cbb871792f76c16b683e15dc",
"sha256:516229927aa61bb9515eddefab90ffaa7483401f39dcd1b8978b08f8e515ca76",
"sha256:d23ea6f1414e50962032e5d078b13e97bc0b14ff3aec9bcc63d4664af67c933f",
"sha256:15f319f2f139a1eed09420fae8337633aa7e002d3a6cb5e34188978f66041261",
"sha256:ea7f2a59b7a0cf567cd5f305ad4b992be40bade9baec9b930ced968c2cea65cf",
"sha256:adf3a737c13661970c890c53a4492d49f0722b4dc5c8790f897f1808a34bb4a2"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
2. 查看上面 app_entry_cmd 镜像的cmd、entrypoint
可以看到能和自己Dockerfile 中声明的CMD 和 ENTRYPOINT 对应上。
qiao-zhi@qiao-zhideMacBook-Pro tmp % docker inspect app_entry_cmd
[
{
"Id": "sha256:16ca5c639a17db1a0f61498b3fc977ce35035c216ab4fec9b9cc3f1bc118932d",
"RepoTags": [
"app_entry_cmd:latest"
],
"RepoDigests": [],
"Parent": "",
"Comment": "buildkit.dockerfile.v0",
"Created": "2024-05-09T15:12:03.496072777Z",
"Container": "",
"ContainerConfig": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": null,
"Cmd": null,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "root",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin",
"LANG=C.UTF-8",
"JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk",
"JAVA_VERSION=8u212",
"JAVA_ALPINE_VERSION=8.212.04-r0"
],
"Cmd": [
"default",
"argument"
],
"ArgsEscaped": true,
"Image": "",
"Volumes": null,
"WorkingDir": "/app",
"Entrypoint": [
"/bin/sh",
"/app/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"maintainer": "qlq@163.com"
}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 121434700,
"VirtualSize": 121434700,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/ku69j15l65pocazc2ev2mj29k/diff:/var/lib/docker/overlay2/4trwseu9aepinl1bwihsu8fyh/diff:/var/lib/docker/overlay2/ktu86m63blp9c7rarafvfhu3q/diff:/var/lib/docker/overlay2/41058cb29f4e8971087a5c955e649ff7c3a6d1a5af53153f563679b2545c9270/diff:/var/lib/docker/overlay2/13137b164b8529e7d981b9b882926cd8b4a06c20f7a4373258b7f29dcccf279d/diff:/var/lib/docker/overlay2/d33f9d0e332ca61edb2e025fd6851fab8f8e0ea82ec8f168878d9de64b1fde4c/diff",
"MergedDir": "/var/lib/docker/overlay2/ow2hvpx0j6khynbvmstw7czgx/merged",
"UpperDir": "/var/lib/docker/overlay2/ow2hvpx0j6khynbvmstw7czgx/diff",
"WorkDir": "/var/lib/docker/overlay2/ow2hvpx0j6khynbvmstw7czgx/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:f1b5933fe4b5f49bbe8258745cf396afe07e625bdab3168e364daf7c956b6b81",
"sha256:9b9b7f3d56a01e3d9076874990c62e7a516cc4032f784f421574d06b18ef9aa4",
"sha256:ceaf9e1ebef5f9eaa707a838848a3c13800fcf32d7757be10d4b08fb85f1bc8a",
"sha256:f160dca9bc02791c6b22203afd735197dce5960385c920ddfa0d9800e16f9d17",
"sha256:643be441a85d47717541963d68b9a1cfb7a79f4f6ddef5022396452526abf26e",
"sha256:33b27dcbef4c83860491699ebd42644598ee60422f48475750e3f1de76dc8ea6",
"sha256:7cabbb46baf13365bba454e7f022421b7186216f79555ef8793396a6a872a7d6"
]
},
"Metadata": {
"LastTagTime": "2024-05-09T15:17:28.758064656Z"
}
}
]
5. 结论
容器的启动脚本可以用cmd,也可以用entrypoint, 也可以两者结合。
外部命令:(sh -c "cat /app/app.log" 可以理解为自己定义的新命令)
docker run -d -p 8081:8081 app_entry sh -c "cat /app/app.log"
如果是cmd,外部的命令会替换cmd 指定的脚本,也就是cmd 指定的将不会执行;
如果是 entrypoint :外部命令会作为参数传递给自己的entrypoint 命令;
也可以两者结合,两者结合的情况下:cmd 会作为参数传递给entrypoint的程序,如果有外部命令,外部命令会覆盖cmd然后继续传给entrypoint 作为参数。
3. 终版-传递环境变量、设置hostsname,脚本动态调整启动服务参数
1. 设置环境变量启动java 程序
- Dockerfile
# 使用官方的Java 8运行时作为基础镜像
FROM openjdk:8-jdk-alpine
# 维护者信息
LABEL maintainer="qlq@163.com"
# 设置工作目录
WORKDIR /app
# 将本地的文件复制到容器中的工作目录
COPY app.jar /app/app.jar
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN chmod +x /app/docker-entrypoint.sh
# 改用root启动
USER root
# 使用exec形式的ENTRYPOINT以获得更好的信号处理能力
ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
- docker-entrypoint.sh
读取环境变量,然后设置JVM 参数
#!/bin/bash
# 定义日志文件路径
LOG_FILE="/app/app.log"
echo 'start~~~' >> "$LOG_FILE"
# 1. 处理默认参数
# 使用追加模式(>>)将所有参数输出到日志文件
echo "Parameters passed to the script: $*" >> "$LOG_FILE"
echo "Each parameter on a new line:" >> "$LOG_FILE"
for arg in "$@"; do
echo "$arg" >> "$LOG_FILE"
done
echo 'end~~~' >> "$LOG_FILE"
# 2. 处理java 相关参数
# 2.1 默认的Java选项
DEFAULT_JAVA_OPTS="-Xms256m -Xmx256g"
# 检查JAVA_OPTS环境变量是否存在
if [ -z "${JAVA_OPTS}" ]; then
echo "JAVA_OPTS is not set. Using default settings: ${DEFAULT_JAVA_OPTS}" >> "$LOG_FILE"
JAVA_OPTS="${DEFAULT_JAVA_OPTS}"
else
echo "JAVA_OPTS is set to: ${JAVA_OPTS}" >> "$LOG_FILE"
fi
# 2.2 默认的端口
DEFAULT_SERVER_PORT='8081'
if [ -z "${SERVER_PORT}" ]; then
echo "SERVER_PORT is not set. Using default SERVER_PORT: ${DEFAULT_SERVER_PORT}" >> "$LOG_FILE"
SERVER_PORT="${DEFAULT_SERVER_PORT}"
else
echo "SERVER_PORT is set to: ${SERVER_PORT}" >> "$LOG_FILE"
fi
# 执行Java应用,使用最终确定的信息
/usr/bin/java -jar ${JAVA_OPTS} -Dserver.port=${SERVER_PORT} /app/app.jar
- 打包运行测试
# build
docker build -t app:latest .
# run 默认设置
xxx % docker run -d -p 8081:8081 app
aed44593836eca3e3f5e727bfe5abe8024214d8528311634158fb9a3b458c85d
xxx % docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aed44593836e app "/bin/sh /app/docker…" 3 seconds ago Up 2 seconds 0.0.0.0:8081->8081/tcp confident_ardinghelli
xxx % curl localhost:8081
index
# 查看启动日志
/app # cat app.log
start~~~
Parameters passed to the script:
Each parameter on a new line:
end~~~
JAVA_OPTS is not set. Using default settings: -Xms256m -Xmx256g
SERVER_PORT is not set. Using default SERVER_PORT: 8081
/app # ps -ef
PID USER TIME COMMAND
1 root 0:00 /bin/sh /app/docker-entrypoint.sh
7 root 0:10 /usr/bin/java -jar -Xms256m -Xmx256g -Dserver.port=8081 /app/app.jar
52 root 0:00 sh
69 root 0:00 ps -ef
/app # jps -lv
7 /app/app.jar -Xms256m -Xmx256g -Dserver.port=8081
90 sun.tools.jps.Jps -Dapplication.home=/usr/lib/jvm/java-1.8-openjdk -Xms8m
- 自己设置环境变量、主机名称然后启动
# 启动
xxx tmp % docker run -d -p 8082:8082 \
-e JAVA_OPTS="-Xmx100m -Xms100m" \
-e SERVER_PORT=8082 \
--hostname 8082host \
app
9f2c71511097005bc523db236ce75b7952fac52470afb6d5cce592ebd10a0f2c
xxx tmp % docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9f2c71511097 app "/bin/sh /app/docker…" 3 seconds ago Up 3 seconds 0.0.0.0:8082->8082/tcp beautiful_kilby
17d8e50240b9 portainer/portainer-ce "/portainer" 6 weeks ago Up 5 hours 0.0.0.0:8000->8000/tcp, 0.0.0.0:9000->9000/tcp, 9443/tcp portainer
xxx tmp % curl localhost:8082
index
# 外部查看容器传递的环境变量
docker inspect 9f2c71511097
# 容器内部查看信息
xxx tmp % docker exec -it 9f2c71511097 sh
# 启动日志
/app # cat app.log
start~~~
Parameters passed to the script:
Each parameter on a new line:
end~~~
JAVA_OPTS is set to: -Xmx100m -Xms100m
SERVER_PORT is set to: 8082
# java 进程信息
/app # jps -lv
64 sun.tools.jps.Jps -Dapplication.home=/usr/lib/jvm/java-1.8-openjdk -Xms8m
7 /app/app.jar -Xmx100m -Xms100m -Dserver.port=8082
# 环境变量
/app # env
JAVA_ALPINE_VERSION=8.212.04-r0
HOSTNAME=8082host
SHLVL=1
HOME=/root
JAVA_VERSION=8u212
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin
JAVA_OPTS=-Xmx100m -Xms100m
LANG=C.UTF-8
JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk
PWD=/app
SERVER_PORT=8082
# 主机名称
/app # hostname
8082host
2. 设置网络,多个容器可以互相访问
1. 创建桥接网络
1. 创建自定义网络: 首先,使用 docker network create 命令创建一个自定义的Docker网络。例如,创建一个名为 my_network 的桥接网络:
# 创建
docker network create my_network
# 查看
xxx tmp % docker network ls
NETWORK ID NAME DRIVER SCOPE
8668a26df163 bridge bridge local
1135abf81b7e host host local
d462de8fcc37 my_network bridge local
2357d5b05bcd none null local
# 查看详细信息
xxx tmp % docker network inspect my_network
[
{
"Name": "my_network",
"Id": "d462de8fcc3734136d0ba33231de22123a98091c2d2bc7e10b1cbb938c92fe4a",
"Created": "2024-05-09T08:30:19.530915045Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
2. 启动两个容器&测试
- 启动
docker run -d -p 8082:8082 \
-e JAVA_OPTS="-Xmx100m -Xms100m" \
-e SERVER_PORT=8082 \
--hostname 8082host \
--network my_network \
app
docker run -d -p 8083:8083 \
-e JAVA_OPTS="-Xmx100m -Xms100m" \
-e SERVER_PORT=8083 \
--hostname 8083host \
--network my_network \
app
- 测试
1. 查看
xxx tmp % docker ps | grep app
4febe1c700fd app "/bin/sh /app/docker…" 13 seconds ago Up 13 seconds 0.0.0.0:8083->8083/tcp stupefied_hamilton
8667b58f2c43 app "/bin/sh /app/docker…" 50 seconds ago Up 49 seconds 0.0.0.0:8082->8082/tcp frosty_chebyshev
2. 查看容器详细信息
docker inspect 4febe1c700fd
# 输出
...
"Networks": {
"my_network": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"4febe1c700fd",
"8083host"
],
"MacAddress": "02:42:ac:12:00:03",
"NetworkID": "d462de8fcc3734136d0ba33231de22123a98091c2d2bc7e10b1cbb938c92fe4a",
"EndpointID": "b6118332fc47744d6321f07da2d289002fe28cd20c0126827d3d85d96ae96582",
"Gateway": "172.18.0.1",
"IPAddr
...
3. 容器内部ping
可以用主机名称互相ping 通,证明可以访问到
ping 8082host
ping 8083host
【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】