DevOps Mind
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.
![](https://devopsmind.com.br/wp-content/uploads/2023/11/karpenter_banner-1024x512.png)
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
![](https://devopsmind.com.br/wp-content/uploads/2023/11/9e7ea6a0976a96cc45e860706c1a1738-software-blogging-2490890841.jpg)
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
- Documentação oficial do Karpenter – https://karpenter.sh/
- Repositório oficial do PHP – https://hub.docker.com/_/php/
- Maiores detalhes sobre a movimentação para o ContainerD:
https://aws.amazon.com/pt/blogs/containers/all-you-need-to-know-about-moving-to-containerd-on-amazon-eks/ - Detalhes importantes a respeito da depreciação do Dockershim e algumas particularidades para workloads que estão no AWS EKS:
https://docs.aws.amazon.com/eks/latest/userguide/dockershim-deprecation.html - Dockershim Deprecation FAQ:
https://kubernetes.io/blog/2020/12/02/dockershim-faq/