【问题标题】:Kubernetes postStart lifecycle hook blocks CNIKubernetes postStart 生命周期钩子块 CNI
【发布时间】:2019-08-13 08:46:53
【问题描述】:

我的工作负载需要网络连接才能正常启动,我想使用 postStart lifecycle hook 等待它准备好然后执行某些操作。然而,生命周期钩子似乎阻止了 CNI。永远不会为以下工作负载分配 IP:

kubectl apply -f <(cat <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        lifecycle:
          postStart:
            exec:
              command:
              - "/bin/sh"
              - "-c"
              - |
                while true; do
                  sleep
                done
EOF
)
kubectl get pods -o wide

这意味着我的工作负载永远不会开始(尝试连接时挂起)并且我的生命周期挂钩会永远循环。有没有办法解决这个问题?

编辑:我使用 sidecar 而不是生命周期钩子来实现相同的目标 - 仍然不确定为什么生命周期钩子不起作用,执行 CNI 是容器创建 IMO 的一部分,所以我希望生命周期钩子在联网后触发已配置

【问题讨论】:

  • 在生命周期钩子的文档中,您可以看到 if the hook takes too long to run or hangs, the Container cannot reach a running state. 我通常给它 10 秒的延迟,在我的情况下它可以完成工作。您也可以查看jobs,以防您不知道连接需要多长时间。
  • 不确定你在这里建议什么,但钩子只是挂起,因为没有为 Pod 配置网络连接 - 我希望一旦钩子开始就已经设置好了

标签: kubernetes cni


【解决方案1】:

这是一个有趣的问题 :-) 这不是一个很好的答案,但我做了一些调查,我认为我分享了它 - 也许它有一些用处。

我从问题中发布的 yaml 开始。然后我登录到运行这个 pod 的机器并找到了容器。

$ kubectl get pod -o wide
NAME                    READY   STATUS              RESTARTS   AGE   IP       NODE
nginx-8f59d655b-ds7x2   0/1     ContainerCreating   0          3m    <none>   node-x

$ ssh node-x
node-x$ docker ps | grep nginx-8f59d655b-ds7x2
2064320d1562        881bd08c0b08                                                                                                   "nginx -g 'daemon off"   3 minutes ago       Up 3 minutes                                              k8s_nginx_nginx-8f59d655b-ds7x2_default_14d1e071-4cd4-11e9-8104-42010af00004_0
2f09063ed20b        k8s.gcr.io/pause-amd64:3.1                                                                                     "/pause"                 3 minutes ago       Up 3 minutes                                              k8s_POD_nginx-8f59d655b-ds7x2_default_14d1e071-4cd4-11e9-8104-42010af00004_0

运行/pause 的第二个容器是基础架构容器。另一个是 Pod 的 nginx 容器。请注意,通常这些信息也可以通过kubectl get pod 获得,但在这种情况下它不是。奇怪。

在容器中,我希望网络已设置并且 nginx 正在运行。让我们验证一下:

node-x$ docker exec -it 2064320d1562 bash
root@nginx-8f59d655b-ds7x2:/# apt update && apt install -y iproute2 procps
...installs correctly...
root@nginx-8f59d655b-ds7x2:/# ip a s eth0
3: eth0@if2136: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UP group default
    link/ether 0a:58:0a:f4:00:a9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.244.0.169/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::da:d3ff:feda:1cbe/64 scope link
       valid_lft forever preferred_lft forever

这样网络就建立了,路由就位,eth0 上的 IP 地址实际上是在覆盖网络上,因为它应该是。现在查看进程列表:

root@nginx-8f59d655b-ds7x2:/# ps auwx
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  32652  4900 ?        Ss   18:56   0:00 nginx: master process nginx -g daemon off;
root         5  5.9  0.0   4276  1332 ?        Ss   18:56   0:46 /bin/sh -c while true; do   sleep done
nginx       94  0.0  0.0  33108  2520 ?        S    18:56   0:00 nginx: worker process
root     13154  0.0  0.0  36632  2824 ?        R+   19:09   0:00 ps auwx
root     24399  0.0  0.0  18176  3212 ?        Ss   19:02   0:00 bash

哈,nginx 正在运行,preStop 命令也在运行。但是请注意大型 PID。部署文件中存在拼写错误,它正在执行 sleep 没有参数 - 这是一个错误。

root@nginx-8f59d655b-ds7x2:/# sleep
sleep: missing operand
Try 'sleep --help' for more information.

这是从循环中运行的,因此分叉的负载会导致较大的 PID。

作为另一个测试,我也尝试从一个节点卷曲服务器:

node-x$ curl http://10.244.0.169
...
<p><em>Thank you for using nginx.</em></p>
...

这是非常值得期待的。所以最后我想强制 preStop 命令完成,所以我从容器内部杀死了包含外壳:

root@nginx-8f59d655b-ds7x2:/# kill -9 5
...container is terminated in a second, result of the preStop hook failure...

$ kubectl get pod
NAME                    READY     STATUS                                                                                                                          RESTARTS   AGE
nginx-8f59d655b-ds7x2   0/1       PostStartHookError: rpc error: code = ResourceExhausted desc = grpc: received message larger than max (53423560 vs. 16777216)   0          21m

嗯,所以我想这 50MB (!) 的消息是由于缺少参数而导致睡眠失败。实际上,更令人毛骨悚然的是,Deployment 并没有从这次失败中恢复过来。这个 Pod 会一直挂着,而不是你所期望的(生成另一个 Pod 并重试)。

此时,我删除了部署,并使用 preStop 钩子 (sleep 1) 中固定的睡眠重新创建了它。结果大致相同,在这种情况下,Deployment 也不会生成另一个 Pod(所以不仅仅是它在日志上阻塞)。

现在我确实在顶部说这不是一个真正的答案。但也许有一些收获:生命周期挂钩需要一些工作才能被认为是有用和安全的。

【讨论】:

  • 感谢所有调查 - 是的,这是一个拼写错误,不包括 sleep 命令的秒数,真正的生命周期挂钩位于试图解封它的保险库集群上,但看到来自 PID 1 的错误,例如: 2019-03-23T08:33:39.684Z [WARN] storage migration check error: error="Get https://consul:8501/v1/kv/vault/core/migration: dial tcp: i/o timeout"防止开封
  • 正如你所说,CNI 似乎很困惑,为什么网络似乎只在生命周期挂钩完成后才“工作”——我唯一能想到的是 kubelet 没有发布分配的 IP 和我的覆盖(编织)一旦发布到 apiserver 就需要做一些额外的事情 - 一个奇怪的
  • 我调查的集群使用flannel
猜你喜欢
  • 2021-09-27
  • 1970-01-01
  • 2021-10-27
  • 2020-01-15
  • 2017-11-22
  • 1970-01-01
  • 1970-01-01
  • 2018-03-13
相关资源
最近更新 更多