在将args传递到容器时,Kubernetes容器/部署?

时间:2019-01-18 15:28:47

标签: docker kubernetes yaml args

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

这是验证的简单测试。我用脚本创建了一个自定义图像: role.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

现在,我想使用Yaml文件在k8s上具有相同的行为。我尝试了几种方法,但都无济于事。

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

但是这些都不起作用,我的吊舱始终处于CrashLoopBackOff状态。 预先感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

在特定字段方面:

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

有两种或多或少的等效方法可以完成您所描述的事情。 (为了简洁起见,我将使用VOLUME语法。)也许最灵活的方法是将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 "$@"

在这种情况下,您可以根据需要在Dockerfile中指定默认的docker run --rm -e ROLE=some_role docker.local:5000/test /bin/true

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调用的“命令”部分中混合“设置”和“命令”。

关于您的Pod为何“崩溃”的原因:Kubernetes通常期望Pod能够长时间运行,因此,如果您编写一个只打印某些内容并退出的容器,Kubernetes会重新启动它,并且当它没有停顿时,它将始终以docker run --rm docker.local:5000/test some_role /bin/true 状态结束。对于您现在要尝试执行的操作,不必担心,请查看窗格的CrashLoopBackOff。如果这困扰您,请考虑设置广告连播规范的restart policy

答案 1 :(得分:0)

要回答您的具体情况,就您声明它们的方式而言,您的ARG或ENV似乎都不起作用。

您的工作流程应为:

  1. 编写您的Dockerfile(就像您一样,好的)
  2. build 您的容器(您没有提供所使用的build命令,但是鉴于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: ["master"]之类的东西替换args: ["$(ROLE)"](例如:它将期望在执行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"]