【问题标题】:Kubernetes pod/deployment while passing args to container?将参数传递给容器时Kubernetes pod /部署?
【发布时间】:2019-06-12 21:30:06
【问题描述】:

我是 docker/k8s 世界的新手...有人问我是否可以使用 args 部署容器来修改行为(通常如果应用程序在“主”或“从”版本中运行),我做过。也许不是最佳解决方案,但它有效:

这是一个简单的验证测试。我制作了一个自定义图像,里面有一个脚本: 角色.sh:

#!/bin/sh
ROLE=$1
echo "You are running "$ROLE" version of your app"

Dockerfile:

FROM centos:7.4.1708

COPY ./role.sh /usr/local/bin
RUN chmod a+x /usr/local/bin/role.sh
ENV ROLE=""
ARG ROLE

ENTRYPOINT ["role.sh"]
CMD ["${ROLE}"]

如果我使用以下命令通过 docker 启动这个容器:

docker run -dit --name test docker.local:5000/test master

我最终得到以下日志,这正是我正在寻找的:

You are running master version of your app

现在我想在 k8s 上使用 yaml 文件来实现相同的行为。我尝试了几种方法,但都没有奏效。

YAML 文件:

apiVersion: v1
kind: Pod
metadata:
  name: master-pod
  labels:
     app: test-master
spec:
  containers:
    - name: test-master-container
      image: docker.local:5000/test
      command: ["role.sh"]
      args: ["master"]

我看到了很多不同的方法来做到这一点,我必须说我仍然不明白 ARG 和 ENV 之间的区别。

我也试过

 - name: test-master-container
   image: docker.local:5000/test
   env:
     - name: ROLE
       value: master

 - name: test-master-container
   image: docker.local:5000/test    
   args:
     - master

但是这些都不起作用,我的 pod 始终处于 CrashLoopBackOff 状态。 提前感谢您的帮助!

【问题讨论】:

    标签: docker kubernetes yaml args


    【解决方案1】:

    就具体领域而言:

    • Kubernetes 的command: 符合Docker 的“入口点”概念,此处指定的任何内容都作为容器的主进程运行。如果您的 Dockerfile 已经有正确的 ENTRYPOINT,则无需在 pod 规范中指定 command:
    • Kubernetes 的args: 符合 Docker 的“命令”概念,此处指定的任何内容都作为命令行参数传递给入口点。
    • Docker 和 Kubernetes 中的环境变量都有其通常的 Unix 语义。
    • Dockerfile ARG 为映像指定 build-time 配置设置。 expansion rules and interaction with environment variables 有点奇怪。以我的经验,这有几个有用的用例(“我实际上想要构建哪个 JVM 版本?”),但是 每个 从图像构建的容器都将具有相同的继承 ARG 值;这不是 run-time 配置的好机制。
    • 对于可以在 Dockerfile 或运行时设置的各种内容(ENV 变量、EXPOSEd 端口、默认的CMD,尤其是VOLUME),没有特别需要在Dockerfile 以便能够在运行时设置它们。

    有几种或多或少等效的方法可以执行您所描述的操作。 (为了简洁起见,我将使用docker run 语法。)可能最灵活的方法是将ROLE 设置为环境变量;当您运行入口点脚本时,您可以假设 $ROLE 有一个值,但值得检查。

    #!/bin/sh
    # --> I expect $ROLE to be set
    # --> Pass some command to run as additional arguments
    if [ -z "$ROLE" ]; then
      echo "Please set a ROLE environment variable" >&2
      exit 1
    fi
    echo "You are running $ROLE version of your app"
    exec "$@"
    
    docker run --rm -e ROLE=some_role docker.local:5000/test /bin/true
    

    在这种情况下,您可以根据需要在 Dockerfile 中指定默认的 ROLE

    FROM centos:7.4.1708
    COPY ./role.sh /usr/local/bin
    RUN chmod a+x /usr/local/bin/role.sh
    ENV ROLE="default_role"
    ENTRYPOINT ["role.sh"]
    

    第二条路径是将角色作为命令行参数:

    #!/bin/sh
    # --> pass a role name, then a command, as parameters
    ROLE="$1"
    if [ -z "$ROLE" ]; then
      echo "Please pass a role as a command-line option" >&2
      exit 1
    fi
    echo "You are running $ROLE version of your app"
    shift        # drops first parameter
    export ROLE  # makes it an environment variable
    exec "$@"
    
    docker run --rm docker.local:5000/test some_role /bin/true
    

    我可能更喜欢环境变量路径,因为它更容易提供多个不相关的选项,并且不会在 Docker 调用的“命令”部分混合“设置”和“命令”。

    至于为什么你的 pod 会“崩溃”:Kubernetes 一般期望 pod 是长时间运行的,所以如果你写一个只打印一些东西并退出的容器,Kubernetes 会重新启动它,当它没有保持运行时,它将总是CrashLoopBackOff 状态结束。对于您现在正在尝试做的事情,请不要担心并查看 pod 的 kubectl logs。如果这让您感到困扰,请考虑设置 pod 规范的 restart policy

    【讨论】:

    • 非常感谢您的帮助!我的第一个目标是有一个-e参数,但我一个人做不到。。现在我还不清楚,但我会继续测试,最终得到整个东西。我尝试了您的解决方案,它完美无缺。我现在有两个 yaml 文件,一个用于单个 master,另一个用于多个 slave,它们按预期工作(现在只是打印消息)。
    【解决方案2】:

    为了回答您的具体情况,您的 ARG 或 ENV 似乎都没有影响您声明它们的方式。

    您的工作流程将是:

    1. 编写你的 Dockerfile(就像你做的那样,好的)
    2. 构建你的容器(你没有提供你使用的构建命令,但给出了你的 ARG 的声明,我假设你必须在那里传递一个值)
    3. 运行您的容器(docker run 或在 kubernetes pod/deployment/etc 中)

    你的ENV ROLE="" 意味着在构建期间你应该有一个空变量 $ROLE ,你可以在整个 Dockerfile 中使用它,并且它将在运行容器的环境中以相同的名称可用(可能是一个空字符串)。

    您的 ARG ROLE 意味着您需要将 ROLE 传递给您的 docker build 命令,该命令将在构建期间的整个 Dockerfile 中可用,可能会覆盖您之前声明的 ENV,但在构建过程之外没有任何影响。

    就您的运行脚本而言,唯一重要的角色是ROLE=$1,例如。变量 $ROLE 采用第一个参数的值。这意味着在你的 kubernetes yml 中指定一个 env RULE 是没有意义的,因为当你的脚本运行时,它会用你脚本的第一个参数覆盖 RULE,即使没有(导致空值)。

    这个规范看起来是正确的,别忘了你可以用类似args: ["$(ROLE)"]的东西替换args: ["master"](例如:它会期望在执行你的kubectl的机器上设置一个ROLE env var。

    apiVersion: v1
    kind: Pod
    metadata:
      name: master-pod
      labels:
         app: test-master
    spec:
      containers:
        - name: test-master-container
          image: docker.local:5000/test
          command: ["role.sh"]
          args: ["master"]
    

    【讨论】:

    • 感谢安德烈。我仍然不清楚,但从现在起 3 周后我什至没有碰过 Docker,所以我想我很快就会明白这一切。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2020-09-08
    • 2020-02-14
    • 2017-08-24
    • 2020-07-02
    • 2017-06-22
    • 2020-11-07
    • 1970-01-01
    • 2018-05-20
    相关资源
    最近更新 更多