Pods parando no status “ContainerCreating” com o Karpenter. Como resolver?

Introdução

Nos ecossistemas modernos de orquestração de contêineres, como o Kubernetes, a eficiência na alocação de recursos é fundamental para garantir o desempenho e a escalabilidade de aplicativos. Nesse cenário, o Karpenter emerge como uma ferramenta valiosa, automatizando o provisionamento de nós (nodes) para otimizar a utilização dos recursos disponíveis.

Problemática

Contudo, enfrentamos uma questão intrigante e desafiadora: a ocorrência recorrente de Pods ficando presos no status “ContainerCreating” ao tentarem subir em nós provisionados através do Karpenter. Esse fenômeno tem impactos significativos na operação normal do Kubernetes, impedindo a implementação eficiente de contêineres e, consequentemente, afetando a agilidade e a confiabilidade do ambiente.

Durante a minha jornada de implantação do Karpenter, foram percebidos que os Pods que utilizavam Docker Image baseada no PHP Alpine estavam ficando travados no status “ContainerCreating”, conforme:


usuario1@lab-k8s   ~  kubectl get pods -A -o wide --watch | grep 23-144                                                                                                        
default                         inflate-b9d769f59-v98tf                             1/1     Running            0          25m     192.16821.32    ip-192-168-23-144.ec2.internal   <none>           <none>
kube-system                     aws-node-hgwvk                                      1/1     Running            0          33m     192.16823.144   ip-192-168-23-144.ec2.internal   <none>           <none>
kube-system                     filebeat-bjcsx                                      1/1     Running            0          33m     192.16823.144   ip-192-168-23-144.ec2.internal   <none>           <none>
kube-system                     kube-proxy-fzwfp                                    1/1     Running            0          33m     192.16823.144   ip-192-168-23-144.ec2.internal   <none>           <none>
kube-system                     metricbeat-szq58                                    1/1     Running            0          33m     192.16823.144   ip-192-168-23-144.ec2.internal   <none>           <none>
lens-metrics                    node-exporter-pllfr                                 1/1     Running            0          33m     192.16827.199   ip-192-168-23-144.ec2.internal   <none>           <none>
monitoring                      zabbix-agent-48hc7                                  1/1     Running            0          33m     192.16823.144   ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-pt6ct             0/1     Pending             0          0s      <none>          ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-h8km8             0/1     Pending             0          0s      <none>          ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-pt6ct             0/1     ContainerCreating   0          0s      <none>          ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-h8km8             0/1     ContainerCreating   0          0s      <none>          ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-zrv7z             0/1     Pending             0          0s      <none>          ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-zrv7z             0/1     ContainerCreating   0          0s      <none>          ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-pt6ct             0/1     Terminating         0          0s      <none>          ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-pt6ct             0/1     Terminating         0          10s     <none>          ip-192-168-23-144.ec2.internal   <none>           <none>
api-teste             api-teste-supervisor-59644cc6c6-pt6ct             0/1     Terminating         0          10s     <none>          ip-192-168-23-144.ec2.internal   <none>           <none>

Os Pods que apresentavam problemas eram aleatórios, muitos Pods de outros projetos subiam corretamente.

Foram revisados diversos componentes do Cluster Kubernetes durante o Troubleshooting, como os logs do Pod, Kubelet, Karpenter e demais itens pertinentes.

Nos Pods haviam estes logs:


Warning   Failed  Pod api-teste-supervisor-59644cc6c6-pt6ct   spec.containers{api-teste-supervisor}   kubelet, ip-192-168-23-144.ec2.internal  Error: cannot find 
volume "kube-api-access-338lv5h" to mount into container "api-teste-supervisor"

Enquanto o serviço do Kubelet tinha estas informações:


[root@ip-192-168-23-144 bin]# 
[root@ip-192-168-23-144 bin]# 
[root@ip-192-168-23-144 bin]# systemctl status kubelet.service
 kubelet.service - Kubernetes Kubelet
   Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/kubelet.service.d
           └─10-kubelet-args.conf, 30-kubelet-extra-args.conf
   Active: active (running) since Thu 2023-06-22 18:33:15 UTC; 1h 24min ago
     Docs: https://github.com/kubernetes/kubernetes
 Main PID: 2949 (kubelet)
   CGroup: /runtime.slice/kubelet.service
           └─2949 /usr/bin/kubelet --cloud-provider aws --config /etc/kubernetes/kubelet/kubelet-config.json --kubeconfig /var/lib/kubelet/kubeconfig --container-runtime remote --container-runtime-endpoint un...

Jun 22 19:22:31 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:31.402350    2949 kubelet.go:1951] "SyncLoop DELETE" source="api" pods=[api-teste/api-teste-supervisor-59644cc6c6-pt6ct]
Jun 22 19:22:31 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:31.408804    2949 kubelet.go:1945] "SyncLoop REMOVE" source="api" pods=[api-teste/api-teste-supervisor-59644cc6c6-pt6ct]
Jun 22 19:22:31 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:31.408869    2949 kubelet.go:2144] "Failed to delete pod" pod="api-teste/api-teste-supervisor-59644cc6c6-pt6ct"...d not found"
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: E0622 19:22:32.034178    2949 kubelet_pods.go:160] "Mount cannot be satisfied for the container, because the volume is missing or the volume mounte...
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: E0622 19:22:32.034515    2949 kuberuntime_manager.go:864] container &Container{Name:api-teste-supervisor,Image:123456789.dkr.ecr.u...inerPort:900
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: ],},HTTPGet:nil,TCPSocket:nil,},PreStop:nil,},TerminationMessagePath:/dev/termination-log,ImagePullPolicy:IfNotPresent,SecurityContext:...lObjectRefer
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: E0622 19:22:32.037294    2949 pod_workers.go:190] "Error syncing pod, skipping" err="failed to \"StartContainer\" for \"api-teste-supervisor\" wi...
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:32.326023    2949 kubelet.go:1973] "SyncLoop (PLEG): event for pod" pod="api-teste/api-teste-supervisor-59644cc...285179c693f}
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:32.337575    2949 kubelet.go:1973] "SyncLoop (PLEG): event for pod" pod="api-teste/api-teste-supervisor-59644cc...3ee0fbe11b0}
Jun 22 19:22:33 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:33.383158    2949 kubelet_volumes.go:140] "Cleaned up orphaned pod volumes dir" podUID=22966fe3-4ceb-481d-9d57-4586953a8692...692/volumes"
Hint: Some lines were ellipsized, use -l to show in full.
[root@ip-192-168-23-144 bin]# 

Versão completa:


[root@ip-192-168-23-144 bin]# systemctl status kubelet.service -l
 kubelet.service - Kubernetes Kubelet
   Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/kubelet.service.d
           └─10-kubelet-args.conf, 30-kubelet-extra-args.conf
   Active: active (running) since Thu 2023-06-22 18:33:15 UTC; 1h 28min ago
     Docs: https://github.com/kubernetes/kubernetes
 Main PID: 2949 (kubelet)
   CGroup: /runtime.slice/kubelet.service
           └─2949 /usr/bin/kubelet --cloud-provider aws --config /etc/kubernetes/kubelet/kubelet-config.json --kubeconfig /var/lib/kubelet/kubeconfig --container-runtime remote --container-runtime-endpoint unix:///run/containerd/containerd.sock --node-ip=192.16823.144 --pod-infra-container-image=602401143452.dkr.ecr.us-east-1.amazonaws.com/eks/pause:3.5 --v=2 --node-labels=intent=apps,karpenter.sh/capacity-type=spot,karpenter.sh/provisioner-name=default

Jun 22 19:22:31 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:31.402350    2949 kubelet.go:1951] "SyncLoop DELETE" source="api" pods=[api-teste/api-teste-supervisor-59644cc6c6-pt6ct]
Jun 22 19:22:31 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:31.408804    2949 kubelet.go:1945] "SyncLoop REMOVE" source="api" pods=[api-teste/api-teste-supervisor-59644cc6c6-pt6ct]
Jun 22 19:22:31 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:31.408869    2949 kubelet.go:2144] "Failed to delete pod" pod="api-teste/api-teste-supervisor-59644cc6c6-pt6ct" err="pod not found"
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: E0622 19:22:32.034178    2949 kubelet_pods.go:160] "Mount cannot be satisfied for the container, because the volume is missing or the volume mounter (vol.Mounter) is nil" containerName="api-teste-supervisor" ok=false volumeMounter={Name:kube-api-access-8lv5h ReadOnly:true MountPath:/var/run/secrets/kubernetes.io/serviceaccount SubPath: MountPropagation:<nil> SubPathExpr:}
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: E0622 19:22:32.034515    2949 kuberuntime_manager.go:864] container &Container{Name:api-teste-supervisor,Image:123456789.dkr.ecr.us-east-1.amazonaws.com/api-teste:supervisor-193,Command:[],Args:[],WorkingDir:,Ports:[]ContainerPort{ContainerPort{Name:9000tcp,HostPort:0,ContainerPort:9000,Protocol:TCP,HostIP:,},},Env:[]EnvVar{},Resources:ResourceRequirements{Limits:ResourceList{cpu: {{500 -3} {<nil>} 500m DecimalSI},memory: {{536870912 0} {<nil>}  BinarySI},},Requests:ResourceList{cpu: {{200 -3} {<nil>} 200m DecimalSI},memory: {{268435456 0} {<nil>}  BinarySI},},},VolumeMounts:[]VolumeMount{VolumeMount{Name:kube-api-access-8lv5h,ReadOnly:true,MountPath:/var/run/secrets/kubernetes.io/serviceaccount,SubPath:,MountPropagation:nil,SubPathExpr:,},},LivenessProbe:nil,ReadinessProbe:nil,Lifecycle:&Lifecycle{PostStart:&Handler{Exec:&ExecAction{Command:[/bin/bash -c touch /var/www/storage/logs/laravel.log && chgrp -R www-data /var/www/bootstrap/ /var/www/storage/ /var/www/storage/logs/ && chmod -R g+w /var/www/bootstrap/ /var/www/storage/ /var/www/storage/logs/ && tail -f /var/www/storage/logs/laravel.log > /proc/1/fd/2 &
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: ],},HTTPGet:nil,TCPSocket:nil,},PreStop:nil,},TerminationMessagePath:/dev/termination-log,ImagePullPolicy:IfNotPresent,SecurityContext:nil,Stdin:false,StdinOnce:false,TTY:false,EnvFrom:[]EnvFromSource{EnvFromSource{Prefix:,ConfigMapRef:&ConfigMapEnvSource{LocalObjectReference:LocalObjectReference{Name:api-teste-php,},Optional:nil,},SecretRef:nil,},},TerminationMessagePolicy:File,VolumeDevices:[]VolumeDevice{},StartupProbe:nil,} start failed in pod api-teste-supervisor-59644cc6c6-pt6ct_api-teste(22966fe3-4ceb-481d-9d57-4586953a8692): CreateContainerConfigError: cannot find volume "kube-api-access-8lv5h" to mount into container "api-teste-supervisor"
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: E0622 19:22:32.037294    2949 pod_workers.go:190] "Error syncing pod, skipping" err="failed to \"StartContainer\" for \"api-teste-supervisor\" with CreateContainerConfigError: \"cannot find volume \\\"kube-api-access-8lv5h\\\" to mount into container \\\"api-teste-supervisor\\\"\"" pod="api-teste/api-teste-supervisor-59644cc6c6-pt6ct" podUID=22966fe3-4ceb-481d-9d57-4586953a8692
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:32.326023    2949 kubelet.go:1973] "SyncLoop (PLEG): event for pod" pod="api-teste/api-teste-supervisor-59644cc6c6-h8km8" event=&{ID:5a5e6258-6d1e-4faa-ac8c-4a0c10670eb6 Type:ContainerStarted Data:9af88fa8f99000720300c1d7f7cab91501db31b5a4ba36d51c9a0285179c693f}
Jun 22 19:22:32 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:32.337575    2949 kubelet.go:1973] "SyncLoop (PLEG): event for pod" pod="api-teste/api-teste-supervisor-59644cc6c6-zrv7z" event=&{ID:eabe3711-a972-494b-922a-3ad1d5c72936 Type:ContainerStarted Data:f9cdd2dd078343c8f2fa9f4744a14d19d4a24992011c0b31ef33f3ee0fbe11b0}
Jun 22 19:22:33 ip-192-168-23-144.ec2.internal kubelet[2949]: I0622 19:22:33.383158    2949 kubelet_volumes.go:140] "Cleaned up orphaned pod volumes dir" podUID=22966fe3-4ceb-481d-9d57-4586953a8692 path="/var/lib/kubelet/pods/22966fe3-4ceb-481d-9d57-4586953a8692/volumes"
[root@ip-192-168-23-144 bin]# 

Porém, analisando os logs não chegava a nada conclusivo.

Solução

Após realizar muitas pesquisas e testes, foi encontrada a solução:

Necessário modificar o Container Runtime utilizado no Provisioner do Karpenter.

De:
containerd

Para:
dockerd

Nas configurações do Provisioner no Karpenter, foi necessário ajustar o ContainerRuntime desta maneira:

############### ContainerRuntime
  kubeletConfiguration:
    containerRuntime: dockerd

Nodes subindo após o ajuste:


usuario1@lab-k8s   ~                                                                                                                                                               
kubectl get node --selector=intent=apps -L kubernetes.io/arch -L node.kubernetes.io/instance-type -L karpenter.sh/provisioner-name -L topology.kubernetes.io/zone -L karpenter.sh/capacity-type --watch
NAME                            STATUS    ROLES    AGE   VERSION   ARCH    INSTANCE-TYPE   PROVISIONER-NAME   ZONE         CAPACITY-TYPE
ip-192-168-21-230.ec2.internal   Unknown   <none>   0s              amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Unknown   <none>   0s              amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Unknown   <none>   0s              amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Unknown   <none>   0s              amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Unknown   <none>   0s              amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Unknown   <none>   0s              amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Unknown   <none>   2s              amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Unknown   <none>   20s             amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   NotReady   <none>   20s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   NotReady   <none>   20s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   NotReady   <none>   20s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   NotReady   <none>   20s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   NotReady   <none>   50s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Ready      <none>   60s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Ready      <none>   60s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Ready      <none>   60s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Ready      <none>   60s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Ready      <none>   78s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Ready      <none>   80s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot
ip-192-168-21-230.ec2.internal   Ready      <none>   110s   v1.21.14-eks-48e63af   amd64   c5.large        default            us-east-1b   spot

E agora os Pods conseguiram subir, todos eles com status em running, conforme o esperado:


usuario1@lab-k8s   ~  kubectl get pods -A -o wide --watch | grep 21-230                                                                                                 1|SIGINT(2) ↵  11116  17:20:59  
api-teste-homolog            api-teste-nginx-574bf47b65-whd9l                 1/1     Running   0          3m28s   192.16822.233   ip-192-168-21-230.ec2.internal   <none>           <none>
api-teste-homolog            api-teste-supervisor-56479db977-28hbv            1/1     Running   0          3m28s   192.16831.106   ip-192-168-21-230.ec2.internal   <none>           <none>
default                         inflate-b9d769f59-nm6z2                             1/1     Running   0          8m35s   192.16826.33    ip-192-168-21-230.ec2.internal   <none>           <none>
kube-system                     aws-node-n2n6w                                      1/1     Running   0          4m40s   192.16821.230   ip-192-168-21-230.ec2.internal   <none>           <none>
kube-system                     filebeat-clprj                                      1/1     Running   0          4m39s   192.16821.230   ip-192-168-21-230.ec2.internal   <none>           <none>
kube-system                     kube-proxy-zhzdt                                    1/1     Running   0          4m40s   192.16821.230   ip-192-168-21-230.ec2.internal   <none>           <none>
kube-system                     metricbeat-cbsql                                    1/1     Running   0          4m40s   192.16821.230   ip-192-168-21-230.ec2.internal   <none>           <none>
lens-metrics                    node-exporter-nlsbf                                 1/1     Running   0          4m40s   192.16828.153   ip-192-168-21-230.ec2.internal   <none>           <none>
monitoring                      zabbix-agent-5fqb5                                  1/1     Running   0          4m39s   192.16821.230   ip-192-168-21-230.ec2.internal   <none>           <none>

Observação

Dockershim vs CRI(Container Runtime Interface)

Este artigo aborda a solução do problema que ocorria num cluster EKS na versão 1.21, onde a utilização do Dockershim era uma opção viável. O “dockershim” era uma interface entre o “kubelet” (componente do Kubernetes) e o Docker Engine, mas foi descontinuado em prol de runtimes que seguem o padrão CRI(Container Runtime Interface).

O Amazon Elastic Kubernetes Service (Amazon EKS) também encerrou o suporte ao “dockershim” a partir da versão 1.24 do Kubernetes. As imagens de máquina Amazon (AMI) oficiais para a versão 1.24 e posteriores incluem apenas o “containerd” como runtime, enquanto versões anteriores a 1.24 incluíam tanto o Docker Engine quanto o “containerd,” com o Docker Engine como runtime padrão.

É necessário ter em mente que existem Amazon Machine Images (AMIs) específicas para o AWS EKS que não usam o Dockershim, mas sim o “containerd” diretamente. Um exemplo é o Bottlerocket, por isto é importante ficar atento durante esta alteração, para não acabar impactando outros workloads existentes no mesmo cluster.

Versões

Seguem alguns detalhes sobre as versões dos recursos utilizados no ambiente:

  • Kubernetes gerenciado pela AWS(EKS), na versão 1.21.
  • Karpenter v0.23.0.
  • Container Runtime: docker://20.10.17
  • Container Runtime Version: containerd://1.6.6
  • Kubelet Version: v1.21.14-eks-48e63af
  • Kube-Proxy Version: v1.21.14-eks-48e63af

Kubernetes Version Matrix

Durante a manipulação de Container Runtime, versões e etc, é interessante avaliar se a versão escolhida é compatível com a versão do cluster Kubernetes.

ContainerD

Para avaliar a versão mais adequada do ContainerD, podemos utilizar o site abaixo:

https://containerd.io/releases/

Este site apresenta uma matriz que mostra as versões do “containerd” recomendadas para uma determinada versão do Kubernetes. Indica que qualquer versão ativamente suportada do “containerd” pode receber correções de bugs para resolver problemas encontrados em qualquer versão do Kubernetes. A recomendação é baseada nas versões mais extensivamente testadas.

Caso a versão não esteja disponível nesta matriz, é possível encontrar no histórico de releases:

https://github.com/containerd/containerd/releases

Dockershim

Já para o Docker, é possível averiguar os changelog, conforme a tag da versão do Kubernetes:

https://github.com/kubernetes/kubernetes/tree/v1.21.0/pkg/kubelet/dockershim

Não temos uma matriz contendo as versões do Dockershim compatíveis com cada versão do Kubernetes, porém no caso do AWS EKS, temos bastantes detalhes a respeito da depreciação do Dockershim na página abaixo:
https://docs.aws.amazon.com/eks/latest/userguide/dockershim-deprecation.html

Material de apoio

Fernando Müller Junior
Fernando Müller Junior

Eu sou o Fernando Müller, um Tech Lead SRE com 16 anos de experiência em TI, atualmente eu trabalho na Appmax, uma fintech localizada no Brasil. Apaixonado por trabalhar com arquiteturas e aplicações Cloud Native, ferramentas Open Source e tudo que existe no mundo SRE, sempre procurando se desenvolver e aprender constantemente(Lifelong learning), atuando em projetos inovadores!

Artigos: 28

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *