如何在Kubernetes上保持一个容器的运行?

284

我现在正在尝试在 Kubernetes 集群上运行带有 Shell (/bin/bash) 的简单容器。

我认为可以通过使用伪终端和分离选项(docker run 命令中的 -td 选项)来使 Docker 容器上的容器保持运行状态。

例如,

$ sudo docker run -td ubuntu:latest

Kubernetes 中有这样的选项吗?

我尝试使用 kubectl run-container 命令运行容器,例如:

kubectl run-container test_container ubuntu:latest --replicas=1

然而容器将会在几秒钟内退出(就像使用我上面提到的不带选项的docker run命令一样)。然而ReplicationController将再次重复启动它。

在Kubernetes中是否有一种像docker run命令中的-td选项一样保持容器运行的方法?


1
使用此图像(如Kubernetes文档所示)非常方便:kubectl run curl --image=radial/busyboxplus:curl -i --tty - Matheus Santana
1
这个问题在这个视频中被提到:Kubernetes the very hard way at Datadog,幻灯片标题为“模仿航运文化”。根据维基百科:当一个不熟练或初学者的计算机程序员(或者对手头问题缺乏经验的程序员)在没有理解代码工作原理或是否需要在新位置使用的情况下,从一个地方复制一些程序代码到另一个地方时,可能会应用“模仿航运文化程序员”的术语。 - tgogos
1
我承认我在学习Kubernetes方面还很初级,但将此称为“空运信仰”似乎不公平。有一个非常好的原因,你可能希望Kubernetes pod永久存在(或者手动杀死)——如果你想使用pod内可用的工具、环境等来测试集群内的网络。是的,你可以反复启动短寿命的pod来执行你想要的命令,但是启动一个持久的pod并在其上启动一个shell难道不更容易吗? - scubbo
16个回答

342

容器的运行是为了完成特定任务。你需要提供一个永远不会结束的任务给你的容器。可以使用类似以下方式实现:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu:latest
    # Just spin & wait forever
    command: [ "/bin/bash", "-c", "--" ]
    args: [ "while true; do sleep 30; done;" ]

4
这是最佳实践吗? - aneesh joshi
18
@aneeshjoshi 我不会说这是最佳实践。这只是提供一个能运行而不立即退出的 pod 的例子。最佳实践是创建容器来完成它们设计的工作(运行到完成的工作,持续运行的 Web 服务器等)。我发布此示例是因为当您不断创建 pod 却仅出现默认命令立即退出时,Kubernetes 可能会感到令人沮丧。 - Joel B
2
非常感谢您提供的帮助,因为我需要一个可以保持一段时间并允许我进入其中的容器。我试图使用比ubuntu更轻的映像来实现相同的目的,并尝试了bash映像,但无法使其正常工作。您有没有任何想法如何使用bash映像实现相同的目的? - cryanbhu
4
我知道这是一个旧问题,但是Kubernetes开始支持短暂容器了。链接: https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/。这些容器有一些限制,比如资源限制,但它们是为了调试目的而设计的。 - Shubham Singh
8
为了让镜像更轻量化,您可以使用Alpine,容器规范如下:{"name": "util", "image": "alpine", "command": [ "/bin/sh", "-c", "--" ], "args": [ "while true; do sleep 30; done;" ]}(在此处仅使用JSON格式,因为yaml无法在评论中格式化)。重要的是使用/bin/sh而不是/bin/bash - bschlueter
显示剩余5条评论

216

您可以在 Dockerfile 中使用此 CMD:

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

使用trap和wait将可以使你的容器立即响应停止请求,从而保持容器处于运行状态,如果没有使用trap/wait,则容器可能需要几秒钟才能停止。

对于基于busybox的镜像(在alpine基础上使用),sleep命令不支持无限参数。以下解决方法可以让你的容器在收到docker stop命令时立即响应,与上面的例子相同:

CMD exec /bin/sh -c "trap : TERM INT; sleep 9999999999d & wait"

2
我在使用相同的Kubernetes部署YAML文件来进行调试。 - user3905644
1
@arunkjn 谢谢你。你可能被卡在使用busybox的镜像上了(比如alpine镜像)。请查看更新后的答案。 - itsafire
感谢您提供有关捕获TERM/INT的信息!我之前无法理解为什么我的容器无法正确停止,因为sleep会从终端响应它。 - Tobias J
3
如果有人可以提供适用于 Kubernetes YAML 的可用 args 版本,那就太好了。 更新: 使用以下内容:command: ["/bin/bash"]args: ["-c", "trap : TERM INT; sleep infinity & wait"] - NeverEndingQueue
2
通常情况下,使用["json array"]语法来编写CMD更为推荐。 如果您需要这样做,可以按照以下方式编写:CMD ["/bin/bash", "-c", "exec /bin/bash -c 'trap : TERM INT; sleep 9999999999d & wait'"] - h3r3
显示剩余2条评论

74

当容器的主进程退出时,容器也会退出。比如执行以下操作:

docker run -itd debian

将容器保持打开实际上是一个hack,只应该用于快速测试和示例。如果你只想要一个测试用的容器,在几分钟内完成,我会这样做:

docker run -d debian sleep 300

使用该方法的优点是,如果您忘记它了,容器将自动退出。或者,您可以将类似于以下内容的代码放入 while 循环中以使其永久运行,或者仅运行诸如 top 的应用程序。在 Kubernetes 中执行这些操作都很容易。

真正的问题是为什么要这样做?您的容器应提供一个服务,其进程将在后台保持容器运行。


谢谢您的回答。我现在正在尝试理解容器的行为,因为有数十个容器同时运行。无限循环和使用其他重型命令,阻止我了解容器的行为。这就是为什么我需要简单的容器,比如只运行/bin/bash的原因。 - springwell
52
sleep infinity 在许多情况下(非 busybox)都有效。 - Reese
1
有很多理由这样做。例如,您可能会使用helm releases和注入配置部署您的pod,这将使得重新创建类似环境变得繁琐和麻烦。但是,在其他pod崩溃/被删除的情况下拥有具有该配置的容器可以无限地有用。 - Richard Løvehjerte
3
嗨,年轻的我!你想要制作一个“Pod”!不要把所有东西都放在一个“容器”中。 - Константин Ван
3
“真正的问题是,你为什么想要这样做?” - 调试。也许您的服务没有立即崩溃,因此您需要在检查所有内部内容时保持容器处于活动状态(例如通过交互式执行shell)。 - ProgrammingLlama
显示剩余3条评论

73
  1. 在您的Dockerfile中使用以下命令:

  2. CMD ["sh", "-c", "tail -f /dev/null"]
    
  3. 构建你的 Docker 镜像。

  4. 将其推送到你的集群或类似环境,以确保镜像可用。
  5. kubectl run debug-container -it --image=<your-image>
    

1
调试容器的好方法。 - kta
1
你需要 sh -c 吗?我非常确定这个也可以:CMD ["tail", "-f", "/dev/null"] - Peter V. Mørch
@PeterV.Mørch,我有疑问,但仍然认为如果您不使用sh -c编写它,它将起作用。 - Shahnur Isgandarli

63
为了保持POD运行,它应该执行某些任务,否则Kubernetes会认为它是不必要的,并因此停止运行。有许多方法可以保持POD运行。
当我需要一个POD连续运行而不执行任何有用操作时,我遇到了类似的问题。以下是对我有效的两种方法:
1. 在容器运行时运行sleep命令。 2. 在容器内部运行无限循环。
虽然第一种选项比第二种选项更容易并且可能足够满足要求,但它并非最佳选择。因为在sleep命令中分配的秒数是有限制的。
但是,具有在其内部运行无限循环的容器永远不会退出。无论如何,我将描述两种方法(假设您正在运行busybox容器):
1. Sleep命令
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  containers:
  - name: busybox
    image: busybox
    ports:
    - containerPort: 80
    command: ["/bin/sh", "-ec", "sleep 1000"]

2. 无限循环

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  containers:
  - name: busybox
    image: busybox
    ports:
    - containerPort: 80
    command: ["/bin/sh", "-ec", "while :; do echo '.'; sleep 5 ; done"]
运行以下命令以运行Pod:

运行以下命令以运行Pod:

kubectl apply -f <pod-yaml-file-name>.yaml

希望能对你有所帮助!


我可以问一下,什么是sleep?它是Ubuntu内部命令还是docker命令? - Faraz
@Faraz 这是一个Linux shell命令,与Docker无关。 - Arbaaz

61

对于k8s pod清单来说,最简单的命令就是让容器永远运行:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu:latest
    # Just sleep forever
    command: [ "sleep" ]
    args: [ "infinity" ]

5
最优雅、极简的解决方案。 - 9ilsdx 9rvj 0lo
使用该代码时出现错误: Pod“ubuntu”无效:spec:Forbidden:pod更新可能不会更改除`spec.containers [*] .image`,`spec.initContainers [*] .image`,`spec.activeDeadlineSeconds`或`spec.tolerations`(仅限对现有容忍度的添加)之外的字段。 ``` - insideClaw
1
这意味着您正在尝试更改不可变的清单部分(使用kubectl apply)。请尝试使用带有可选“--force”标志的kubectl replace。 - Wlodek B.

25

我对这个主题的看法。假设kubectl能够工作,那么最接近你在问题中提到的docker命令的等效命令将类似于以下内容。

$ kubectl run ubuntu --image=ubuntu --restart=Never --command sleep infinity
上述命令将在default命名空间中创建一个单一的Pod,并使用参数为infinitysleep命令执行-这样您就会有一个在前台运行的进程,使容器保持活动状态。

之后,您可以通过运行kubectl exec命令与Pod进行交互。

$ kubectl exec ubuntu -it -- bash

这种技术对于创建Pod资源和临时调试非常有用。


2
非常好用。不需要 --restart=Never,只需调用 kubectl run ubuntu --image=ubuntu -- sleep infinity 即可。 - Noam Manos
或者,如果你想使用老式的更厚重的命令,你总是可以执行类似于 kubectl run busybox --image=busybox --restart=Never -- /bin/sh -c 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done;' 这样的命令。 - iamnicoj

15

我能够在Kubernetes中使用命令sleep infinity使容器保持开启状态。当该命令无效时,可以参考此答案中提供的其他替代方法。


1
这并没有提供问题的答案。如果要批评或请求作者澄清,请在他们的帖子下留言。-【来自审查】 - Will
1
@Will 当然可以。sleep infinity 命令可以保持容器开启,提供了与问题所询问的相同类型的功能(对于大多数类型的容器而言)。它还提供了替代方案的链接,以便在特定情况下该命令无法使用时使用。 - Reese
这是从评论中得出的结论。如果您将评论文本添加到答案中,则会成为高质量的答案 :) 我最初的标记/推荐是基于说您的评论不成功,让我认为这应该是一条评论。增加了一个快速编辑并进行了点赞。 - Will
“在 Kubernetes 中睡眠无限期”是一个不准确的说法。它意味着 Unix 和 Docker 都不在考虑范围内。 - mmla

8
在模板中添加此行代码:在spec->containers->ports中的容器端口行之后加入该行。
    command: ["/bin/sh", "-ec", "while :; do echo '.'; sleep 6 ; done"]

与其使用命令,将整个文件共享会更有助于他人。 - Harsh Manvar

8

在Dockerfile中使用以下命令,使容器在K8s集群中保持运行状态:

  • CMD tail -f /dev/null

该命令的作用是保持容器一直处于运行状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接