我是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状态。 预先感谢您的帮助!
答案 0 :(得分:3)
在特定字段方面:
command:
与Docker的“入口点”概念相匹配,此处指定的任何内容都作为容器的主要过程运行。如果您的Dockerfile已经具有正确的command:
,则无需在pod规范中指定ENTRYPOINT
。args:
与Docker的“命令”概念相匹配,此处指定的任何内容均作为命令行参数传递给入口点。ARG
指定映像的构建时间配置设置。 expansion rules and interaction with environment variables有点奇怪。以我的经验,这有几个有用的用例(“我实际上要针对哪个JVM版本构建?”),但是从图像构建的每个容器将具有相同的继承{{1} }价值;这不是运行时配置的好机制。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似乎都不起作用。
您的工作流程应为:
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"]