Kubernetes pod/deployment 在将参数传递给容器时?

Kubernetes pod/deployment while passing args to container?

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

这是一个简单的验证测试。我制作了一个带有脚本的自定义图像: role.sh:

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

Docker 文件:

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 文件。我尝试了几种方法,但 none 奏效了。

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

但是其中 none 有效,我的 pods 总是处于 CrashLoopBackOff 状态。 预先感谢您的帮助!

在具体领域方面:

  • Kubernetes的command:符合Docker的"entrypoint"概念,这里指定的就是运行作为容器的主进程。如果您的 Docker 文件已经具有正确的 ENTRYPOINT,则无需在 pod 规范中指定 command:
  • Kubernetes 的 args: 匹配 Docker 的 "command" 概念,这里指定的任何内容都作为命令行参数传递给入口点。
  • Docker 和 Kubernetes 中的环境变量都有它们通常的 Unix 语义。
  • Dockerfile ARG 指定图像的 build-time 配置设置。 expansion rules and interaction with environment variables 有点奇怪。根据我的经验,这有几个有用的用例 ("which JVM version do I actually want to build against?"),但是 每个从图像构建的 容器将具有相同的继承 ARG 值;这不是 运行-time 配置的好机制。
  • 对于可以在 Docker 文件中或在 运行 时间设置的各种东西(ENV 变量,EXPOSEd 端口,默认 CMD,尤其是 VOLUME) 没有特别需要在 Docker 文件中 "declare" 它们,以便能够在 运行 时间设置它们。

有几种或多或少等效的方法可以完成您所描述的事情。 (为了简洁起见,我将使用 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

在这种情况下,您可以根据需要在 Docker 文件中指定默认值 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=""
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

我可能更喜欢环境变量路径,因为它更容易提供多个不相关的选项,并且不会在 "command" 部分混合使用 "settings" 和 "the command" Docker 调用。

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

为了回答您的具体情况,考虑到您声明它们的方式,您的 ARG 或 ENV 似乎都没有效果。

您的工作流程应该是:

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

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

你的 ARG ROLE 意味着你需要将一个 ROLE 传递给你的 docker build 命令,它将在构建期间的整个 Dockerfile 中可用,大概会覆盖你之前声明的 ENV,但除了构建过程。

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

这个规范看起来是正确的,别忘了你可以用 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"]