如何向 Docker 容器传递参数

原文:https://yanbin.blog/pass-arguments-to-docker-container/#more-8608

我们在运行 docker 镜像时希望能用下面的命令向容器传递命令行参数

docker run <image-name> <command> arg1 arg2
docker run <image-name> arg1 arg2

其实只有第一种形式,紧随镜像名后那个总是一个命令,其后才是参数。如果要向 docker 容器传递参数时,Dockerfile 该如何写,这就有必要稍稍了解一下 Dockerfile 中  CMD 和 ENTRYPOINT 这两个指令,并且它们有 exec 和 shell 两种格式的写法。详情请见上篇 Dockerfile 中命令的两种书写方式的区别

对于一个 docker 镜像,我们可以这么来理解  ENTRYPOINT 与 CMD 的关系

  1. 如果没有定义 ENTRYPOINT, CMD 将作为它的 ENTRYPOINT
  2. 定义了 ENTRYPOINT 的话,CMD 只为 ENTRYPOINT 提供参数
  3. CMD 可由 docker run <image> 后的命令覆盖,同时覆盖参数

对于 #1 和  #2 更精致的理解是容器运行的最终入口由 ENTRYPOINT 和实际的 CMD 拼接而成。ENTRYPOINT 和 CMD 需转换为实际镜像中的 exec 格式来拼接,合并后的第一个元素是命令,其余是它的参数。

举四个例子进行说明

一, 未定义 ENTRYPOINT, 定义了 CMD

#ENTRYPOINT []
CMD ["echo", "hello"]

实际入口是它们拼接后还是 CMD 本身,["echo", "hello"]

二, 定义了 ENTRYPOINT 和 CMD

ENTRYPOINT ["echo", "hello"]
CMD ["echo", "world"]

实际入口是它们拼接起来,形成 ["echo", "hello", "echo", "world"], 执行 docker run test 显示为 hello echo world

三, 定义了 ENTRYPOINT, CMD 由 docker run 提供

ENTRYPOINT  ["echo", "hello"]

执行命令 docker run <image> rm -rf /, 实际入口是由 ["echo", "hello"] 与 ["rm", "-rf", "/"] 拼接而成的 ["echo", "hello", "rm", "-rf", "/"], 输出为 hello rm -rf /。看到 rm -rf / 也不用担心,用 ENTRYPOINT 就是让人放心

注:ENTRYPOINT 同样可以被覆盖,如 docker run --entrypoint ls test -l /,将会执行 ls -l / 命令。

四, 如果 ENTRYPOINT 用 shell 格式定义的

ENTRYPOINT java -jar /app.jar
CMD ["hello", "world"]

通过 docker inspect 命令看到镜像中实际的 ENTRYPOINT 是

ENTRYPOINT ["/bin/sh", "-c", "java -jar /app.jar"]

所以与 CMD 连接起来的入口就是 ["/bin/sh", "-c", "java -jar /app.jar", "hello", "world"], "bin/sh" 直接忽略掉后面的 "hello" 与 "world",这就是为什么  shell 命令方式无法获取参数。

有了以上几点概念,以及四个实例作为感观认识后,想要怎么往容器传递参数应该很容易确定了。

未定义 ENTRYPOINT

没有定义 ENTRYPOINT 的镜像想怎么来就怎么来,docker run <image> 后面的输入你自己作主。

有定义 ENTRYPOINT

定义了 ENTRYPOINT 的镜像,则是 CMD 或 docker run <image> 后的输入作为  ENTRYPOINT 中命令的附加参数。再次提醒 shell 格式的 ENTRYPOINT 和 CMD  务必要转换为相应 exec  格式来理解。

shell 格式的 ENTRYPOINT

如果是复杂的 shell 命令不容易拆解出一个个参数,而希望用  shell 格式来定义 ENTRYPOINT 的话,也有办法。shell 格式的 ENTRYPOINT 是由 "/bin/sh -c" 启动的,而它是可以解析变量的。另一方面 CMD 或 docker run <image> 的输入第一个元素存成了 $0,其他剩余元素存为 $@, 所以 shell 格式的 ENTRYPOINT 可以这么写

ENTRYPOINT echo hello $0 $@

注:shell 中 $0 表示命令本身,$@ 为所有参数

这样执行下面 docker 命令将可获得所有的参数输入

$ docker run test world and China
hello world and China

如果只是按常规 shell 脚本来对待,想当然的写成

ENTRYPOINT echo hello $@

效果将是

$ docker run test world and China
hello and China

第一个参数将被丢失,docker run <image> 后第一个输入通常是一个命令,所以是 $0, 而 ENTRYPOINT 又希望它是一个普通参数,因此$0 $@ 要同时写上。

直接用 docker inspect <container-id> 查看

最简单且准确的方式就是直接用 docker inspect <container-id> 查看实际启动的命令及参数

<think>好的,我现在需要帮用户解决如何在执行docker run传递环境变量并运行带有参数的Python脚本的问题。用户之前已经问过如何在dockerrun中执行带参数的脚本,现在想进一步了解如何结合环境变量传递。首先,我得回顾之前的对话。用户之前的问题是关于如何在docker run命令中运行带有参数的Python脚本,比如python3 smbSETool.py加上各种参数。我的回答提到了直接覆盖CMD指令和使用环境变量的方法,现在用户想更详细地了解环境变量的传递。接下来,我需要参考用户提供的引用内容。引用[3]提到了使用-e选项传递环境变量,并在容器内通过echo和Python脚本获取。引用[4]解释了CMD指令被docker run参数覆盖的情况。用户现在需要结合这两个点,既要传递环境变量,又要执行带参数的脚本。 用户的需求可能是在运行容器时,既能动态设置环境变量,又能传递参数给Python脚本。可能的场景是,有些参数通过环境变量传递,有些则直接作为脚本参数,或者用户希望灵活地选择两种方式中的一种。 我需要分步骤说明如何操作。首先,使用dockerrun的-e选项设置环境变量,然后在命令末尾指定Python脚本及其参数。同时,要确保脚本能够读取环境变量,比如通过os.getenv()。还要注意,如果同时使用环境变量和命令行参数,脚本内部需要正确处理这两者的优先级或结合使用。 另外,用户可能关心如何同时使用环境变量和覆盖CMD指令。比如,Dockerfile中的CMD可能已经指定了默认参数,但用户想在运行时覆盖这些参数,并添加环境变量。这时候,docker run的命令结构应该是先环境变量,再镜像名,然后是完整的执行命令和参数。还需要考虑路径问题,确保脚本在容器内的正确位置,并且依赖项已安装。引用[1]提到需要正确COPY脚本到容器,所以用户需要确认Dockerfile中的路径设置是否正确。可能的问题点:环境变量和命令行参数在脚本中的处理方式,如何确保两者不冲突;特殊字符在环境变量中的处理,比如逗号是否需要转义;容器启动后是否立即退出,需要保持进程运行等。 最后,生成相关问题,帮助用户深入理解,比如如何调试环境变量,如何处理多个变量,安全注意事项等。</think>### 在`docker run`中传递环境变量并运行Python脚本的方法 --- #### 1. **基础命令结构** 通过`-e`选项传递环境变量,在命令末尾指定Python脚本及其参数。格式如下: ```bash docker run [通用选项] -e 环境变量键=值 <镜像名称> python3 脚本路径 [脚本参数] ``` **实际案例**: ```bash docker run -it --rm \ -e IMAGE_TYPE=1 \ -e PAYLOAD_PATH=/data/calix-gp1100x.img \ my-python-image:latest \ python3 /app/smbSETool.py \ --image_version 25.1.1.0 \ --supported_device_ids '1,2' ``` --- #### 2. **混合传参模式** 可同时使用环境变量和直接参数,在Python脚本中灵活处理: ```python # smbSETool.py示例 import os import argparse parser = argparse.ArgumentParser() parser.add_argument('--image_version') parser.add_argument('--supported_device_ids') args = parser.parse_args() # 从环境变量获取参数 image_type = os.getenv("IMAGE_TYPE") # 值为'1' payload = os.getenv("PAYLOAD_PATH") # 值为'/data/calix-gp1100x.img' # 结合使用两种参数 print(f"构建参数:类型={image_type}, 版本={args.image_version}") ``` --- #### 3. **特殊参数处理技巧** - **多值参数**:使用`$''`保持参数完整性 ```bash docker run -e DEVICE_IDS='1,2,3' my-image python3 script.py ``` - **文件路径映射**:通过`-v`挂载宿主目录 ```bash docker run -v $(pwd)/images:/data my-image python3 script.py --payload /data/calix.img ``` - **默认值覆盖**:Dockerfile中定义环境变量默认值 ```dockerfile ENV IMAGE_TYPE=0 # 运行时可通过-e覆盖 ``` --- #### 4. **调试技巧** - **查看环境变量**:启动临时shell检查变量 ```bash docker run --entrypoint /bin/sh my-image -c "echo $IMAGE_TYPE" ``` - **日志输出**:在Python脚本开头添加调试语句 ```python print("当前环境变量:", os.environ) print("命令行参数:", sys.argv) ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值