Criando e atualizando um cluster Kubernetes com kubeadm
Introdução
Este post faz parte de uma série sobre a certificação CKA – Certified Kubernetes Administrator [1].
Dentre os tópicos que possuem mais peso na certificação, o item Cluster Architeture, Instalation & Configuration chama atenção por dois motivos:
- Faz referência a preparação de um cluster mínimo viável
- Apresenta uma forma canônica de instalação através da ferramenta kubeadm
Com a finalidade de apresentar uma forma de preparar um cluster para iniciar os estudos sobre Kubernetes, e ao mesmo tempo abordar itens que são cobrados nesta certificação, será apresentado a seguir um hands on que:
- Prepara uma infraestrutura local através do uso de máquinas virtuais com VirtualBox e Vagrant
- Utiliza o kubeadm para preparar um cluster kubernetes em uma determinada versão
- Performa a atualização do cluster para versão mais atualizada até o momento -v.1.23.5-00
Trata-se de um post de maior fôlego, com exemplos e a apresentação das saídas dos comandos: tudo isso para ficar mais fácil o entendimento e esclarecer qualquer dúvida durante a execução dos passos.
Pré Requisitos
Virtualização
Para simular o cluster de forma local, será preciso ter configurado um hypervisor em seu sistema operacional. O Virtualbox está presente em todos os sistemas operacionais, e por isso será a escolha deste hands on.
Além do Virtualbox, para não precisar realizar etapas de instalação de sistemas linux, será utilizado o Vagrant. Para instalar esses softwares acessem:
- Virtuabox : https://www.virtualbox.org/wiki/Downloads
- Vagrant: https://www.vagrantup.com/downloads
Requisitos computacionais
Do ponto de vista de recursos computacionais, na documentação oficial do kubernetes [2] é exigido de cada nó do cluster as seguintes configurações:
- Um host linux compatível
- 2GB de RAM
- 2CPUs
- Conectividade de rede entre os nós
Tendo em vista que um dos objetivos do laboratório é simular uma atualização do cluster, para termos uma experiência comportamental mais próxima da realidade, será preparado um cluster com 3 nós: o primeiro com a finalidade de ser o gerenciador, que na nomenclatura do kubernetes é chamado de control-plane e os demais como nós responsáveis por abrigar os workloads, chamados de worker nodes.
Nesse sentido, teremos que ter livre ao menos 6GB de RAM para subir essa infraestrutura. Entendemos que não são todos que possuem uma máquina com essas configurações e há alternativas possíveis utilizando recursos de cloud provider – quem optar por essa forma, não é necessário seguir os passos da seção a seguir, mas tenha em mente que algumas configurações de rede serão necessárias, e isso pode variar de acordo com o provedor escolhido e não será abordada nesse post.
Preparando as máquinas virtuais
Com o Virtuabox e Vagrant instalado em seu sistema, iremos instalar 3 máquinas com Linux, com a distribuição Debian na versão 11 (Bullseye).
É possível utilizar o kubernetes em outras distribuições, especialmente aquelas baseadas em Debian e Red Hat, para maiores detalhes, ver a documentação oficial para diretrizes específicas de acordo com a distribuição desejada.
Para facilitar a reprodutibilidade, o Vagrant será nosso gerenciador para implementar as máquinas virtuais – ele nos permite declarar nossa infraestrutura como código na linguagem ruby. O script a seguir será responsável por indicar a quantidade máquinas virtuais a ser criada, os recursos computacionais alocados para cada um, endereços de rede, entre outros elementos importantes.
Em sua máquina local, crie um diretório específico e um arquivo em branco chamado Vagrantfile. O conteúdo deste arquivo será o seguinte:
# -*- mode: ruby -*-
# vi: set ft=ruby :
## 1. Definindo as características das máquinas virtuais
vms = {
'control-plane' => {'memory' => '2048', 'cpus' => 2, 'ip' => '10', 'box' => 'geerlingguy/debian11'},
'worker-1' => {'memory' => '2048', 'cpus' => 1, 'ip' => '20', 'box' => 'geerlingguy/debian11'},
'worker-2' => {'memory' => '2048', 'cpus' => 1, 'ip' => '30', 'box' => 'geerlingguy/debian11'},
}
## 1. Aplicando as configurações no virtualbox
Vagrant.configure('2') do |config|
config.vm.box_check_update = false ## opcional: adiar a checagem de updates
vms.each do |name, conf| ## para cada item do dicionário de vms, faça:
config.vm.define "#{name}" do |my|
my.vm.box = conf['box'] ## seleciona a box com a distribuição linux a ser utilizada
my.vm.hostname = "#{name}.example.com" ## define o hostname da máquina
my.vm.network 'private_network', ip: "192.168.56.#{conf['ip']}" ## define o ip de cada máquina de acordo com o range do Virtualbox
my.vm.provider 'virtualbox' do |vb|
vb.memory = conf['memory'] ## define quantidade de recurso de memória
vb.cpus = conf['cpus'] ## define quantidade de vCPUs
end
end
end
end
O vagrant possui um repositório de boxes, que nada mais são que imagens de sistemas operacionais já instalados prontos para serem importados em hypervisors quaisquer. No exemplo em questão estamos utilizando uma box mínima do Debian 11, criada pelo Jeff Geerling [3].
Não se preocupe em entender cada linha desse arquivo, apenas salve em seu diretório e em seguida digite na sua linha de comando vagrant up. Essa diretiva será responsável em ler as definições do arquivo Vagrantfile e aplicar no virtualbox – por ser 3 máquinas, pode ser que leve um tempo para criar e configurar as máquinas virtuais.
treinamento@4linux:~/infra/cka$ ls
Vagrantfile
treinamento@4linux:~/infra/cka$ vagrant up
Bringing machine 'control-plane' up with 'virtualbox' provider...
Bringing machine 'worker-1' up with 'virtualbox' provider...
Bringing machine 'worker-2' up with 'virtualbox' provider...
==> control-plane: Importing base box 'geerlingguy/debian11'...
(...continua)
Para checar se todas as máquinas foram criadas, após o término da execução do comando, utilize a diretiva vagrant status
.
treinamento@4linux:~/infra/cka$ vagrant status
Current machine states:
control-plane running (virtualbox)
worker-1 running (virtualbox)
worker-2 running (virtualbox)
This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.
Note que o vagrant irá associar os nomes definidos no Vagrantfile com as máquinas virtuais criadas. Isso será importante para diferenciar as máquinas entre si e realizar ações como acesso via secure shell.
Sobre a arquitetura de um cluster Kubernetes e o utilitário Kubeadm
Sob a perspectiva de software, o kubernetes é um sistema distribuído que possui diversos componentes, que em conjunto, tem a finalidade de orquestrar ambientes contêinerizados. Dentre estes componentes, existem aqueles que fazem parte da configuração de nó de gerenciamento (control plane), e também aqueles que são indispensáveis para comunicação e provisionamento de infraestrutura de contêineres.
O kubeadm visa instalar e configurar alguns destes componentes, a fim de facilitar a administração, ingresso de nós, atualização, entre outras funcionalidades. Ele serve tanto para nós com papel de control plane quanto para worker nodes.
No que se refere ao control plane, o kubeadm irá preparar a infraestrutura PKI para comunicação TLS entre os componentes, e a instalação dos componentes:
- kubeapi-server
- kube-controller-manager
- kube-scheduler
- etcd
Os componentes runtime estão de fora do escopo do kubeadm por serem requisitos para o funcionamento do cluster, e por isso será preciso instalar antes, de forma manual.
Configurações a nível de sistema operacional
Além dos requisitos computacionais mencionados anteriormente, cada nó do cluster precisa de algumas configurações específicas a nível de sistema operacional. Uma delas está relacionada à configuração do iptables para receber tráfego de pacotes no modo bridge, e a outra está ligada à remoção do suporte ao swap no sistema.
Deste modo, precisamos acessar a máquina através do comando vagrant ssh:
treinamento@4linux:~/infra/cka$ vagrant ssh control-plane
Linux control-plane 5.10.0-11-amd64 #1 SMP Debian 5.10.92-1 (2022-01-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
vagrant@control-plane:~$
Em seguida aplicaremos a configuração de swap:
vagrant@control-plane:~$ sudo swapoff -a
Para habilitar o tráfego em modo bridge no iptables
, é preciso antes verificar se o módulo br_netfilter
está carregado no sistema através do comando sudo lsmod | grep br_nefilter
. Caso não esteja, será necessário carregar o módulo através do comando modprobe
.
Para persistir a configuração no nó, é preciso adicionar no caminho /etc/modules-load.d/
um arquivo de configuração com os nomes dos módulos a serem carregados na inicialização:
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
br_netfilter
EOF
sudo modprobe br_netfilter
Após carregar o módulo e adicionar a configuração, é preciso modificar os parâmetros do kernel atual para ativar a configuração:
# Adiciona parametrização
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
# Atualiza parâmetros sem precisar reiniciar
sudo sysctl --system
Container runtime
O Kubernetes precisa de um container runtime presente, seja um host de control-plane ou um worker node. Para este laboratório utilizaremos um container runtime diferente do Docker, tendo em vista que seu suporte será descontinuado a partir da versão v1.25+. Nesse sentido utilizaremos o CRI-O [4].
O processo de instalação do container runtime é bem parecido como qualquer outra instalação de serviço no Linux – é necessário 1) verificar a fonte dos pacotes; 2) adicionar o repositório na lista de repositórios do gerenciador de pacotes da sua distribuição; 3) atualizar os metadados dos pacotes e por fim 4) instalar os pacotes a partir do gerenciador de pacotes em questão.
No caso atual, estamos em uma distribuição Debian, e por isso utilizaremos o apt
.
De acordo com as instruções no site do cri-o
, é preciso adicionar o repositório de acordo com a versão do seu sistema. Para descobrir a versão da sua distribuição, basta executar o comando cat /etc/os-release
. Como estamos utilizamos o Debian 11, podemos informar de forma direta.
Além da versão do sistema operacional, é preciso também informar a versão do cri-o
. Em geral, as versões acompanham a versão do kubernetes. Iremos instalar a versão v.1.22
haja vista que simularemos uma atualização do cluster.
Com isso, de acordo com a informações de instalação oficial do cri-o, temos os seguintes comandos a serem executados:
# adiciona repositório nas listas de pacotes
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
# adiciona as chaves dos repositórios
curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | apt-key add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -
# atualiza a lista de pacotes e instala o cri-o
apt-get update
apt-get install cri-o cri-o-runc
Note que devemos substituir as variáveis $OS
e $VERSION
por Debian_11
e 1.22
respectivamente. Isso pode ser feito de duas formas, a primeira exportando as variáveis com as diretivas export OS='Debian_11'; export VERSION='1.22'
ou trocando manualmente:
vagrant@control-plane:~$ sudo su -c 'echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list'
vagrant@control-plane:~$ sudo su -c 'echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.22/Debian_11/ /"> /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:1.22.list'
vagrant@control-plane:~$ curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:1.22/Debian_11/Release.key | sudo apt-key add -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
100 389 100 389 0 0 325 0 0:00:01 0:00:01 --:--:-- 325
100 390 100 390 0 0 244 0 0:00:01 0:00:01 --:--:-- 0
100 391 100 391 0 0 194 0 0:00:02 0:00:02 --:--:-- 194
100 392 100 392 0 0 161 0 0:00:02 0:00:02 --:--:-- 0
100 393 100 393 0 0 138 0 0:00:02 0:00:02 --:--:-- 138
100 1093 100 1093 0 0 337 0 0:00:03 0:00:03 --:--:-- 337
OK
vagrant@control-plane:~$ curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_11/Release.key | sudo apt-key add -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
100 1093 100 1093 0 0 852 0 0:00:01 0:00:01 --:--:-- 853
OK
vagrant@control-plane:$ sudo apt update && sudo apt install cri-o cri-o-runc
...
Após a concluída a instalação, podemos inspecionar o status do serviço do cri-o
através do comando systemctl status crio.service
:
vagrant@control-plane:~$ sudo systemctl status crio.service
● crio.service - Container Runtime Interface for OCI (CRI-O)
Loaded: loaded (/lib/systemd/system/crio.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: https://github.com/cri-o/cri-o
Note que o serviço está parado. Será necessário habilitá-lo para ser inicializado conjuntamente com o sistema e ao mesmo tempo iniciar o servico. Para tal, utilizamos sudo systemctl enable crio.service && sudo systemctl start crio.service
.
vagrant@control-plane:~$ sudo systemctl enable crio.service && sudo systemctl start crio.service
Created symlink /etc/systemd/system/cri-o.service → /lib/systemd/system/crio.service.
Created symlink /etc/systemd/system/multi-user.target.wants/crio.service → /lib/systemd/system/crio.service.
vagrant@control-plane:~$ systemctl status crio.service
● crio.service - Container Runtime Interface for OCI (CRI-O)
Loaded: loaded (/lib/systemd/system/crio.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2022-04-22 13:21:12 UTC; 9s ago
Docs: https://github.com/cri-o/cri-o
Main PID: 3536 (crio)
Tasks: 9
Memory: 11.9M
CPU: 110ms
CGroup: /system.slice/crio.service
└─3536 /usr/bin/crio
vagrant@control-plane:~$
Com isso temos todas as dependências satisfeitas e podemos prosseguir com a instalação de componentes do kubernetes e o próprio kubeadm.
kubeadm, kubelet e kubectl
Antes de performar as instalações do binários, é importante certificar se algumas dependências estão satisfeitas. De acordo com a documentação oficial é necessário instalar os seguintes pacotes:
apt-transport-https
ca-certificates
curl
Para tal:
vagrant@controlplane:~/$ sudo apt update && sudo apt install apt transport-https ca-certificates curl
Depois de instalado as dependências, vamos adicionar a chave publica do repositório do google referente aos componentes do kubernetes em questão:
vagrant@control-plane:~/$ sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
vagrant@control-plane:~/$ sudo su -c 'echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list'
Em seguida atualizamos a lista de pacotes e instalamos os binários kubeadm
, kubectl
e kubelet
:
vagrant@control-plane:~/$ sudo apt update && sudo apt install kubelet=1.22.0-00 kubeadm=1.22.0-00 kubectl=1.22.0-00
Uma vez instalado os binários é importando aplicar uma flag que previne que esses pacotes sejam modificados e/ou atualizados automaticamente. Isso porque pode acontecer problemas no cluster se este processo não for feito de acordo com alguns protocolos. Para efetuar esse tipo de marcação, utilizamos o utilitário do apt apt-mark
:
vagrant@control-plane:~/$ sudo apt-mark hold kubectl kubeadm kubelet
kubelet set on hold.
kubeadm set on hold.
kubectl set on hold.
Desta forma estamos prontos para performar o bootstrap do control-plane.
Bootstrap do Control Plane
Para performar o bootstrap do control-plane certifique-se que as configurações a nível de sistema operacional foram satifeitas. O kubeadm
possui uma API específica para esta tarefa, que é a kubeadm init
.
Existem algumas opções importantes, tendo em vista que estamos em um ambiente de máquinas virtuais utilizando Virtualbox – uma delas é referente ao IP que será exposto para o control-plane. Por padrão ele pega o endereço da interface padrão da máquina virtual em questão e isso pode ocasionar alguns conflitos haja vista que o Virtuabox cria uma interface NAT para que as máquinas possam sair para internet. Para evitar conflitos , utilizaremos o ip definido no Vagrant – ou seja, 192.168.56.10
. Da mesma forma, definiremos o range dos PODs para que não tenha nenhum tipo de conflito com as configurações do virtuabox.
Para indicar isso no comando kubeadm init
utilizamos os parâmetros --apiserver-advertise-address
e --pod-network-cidr
:
vagrant@control-plane:~/$ sudo kubeadm init --apiserver-advertise-address 192.168.56.10 --pod-network-cidr 10.244.0.0/16
A execução do kubeadm init
pode levar alguns minutos, e sua saída é bem interessante pois lista as checagens e o que está sendo realizado. Ao final da execução, caso tudo tenha ocorrido de forma satisfatória, a seguinte mensagem será apresentada:
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.56.10:6443 --token bgkad3.sdumad8yig8thife \
--discovery-token-ca-cert-hash sha256:1959fbfddb23f869b4e1f60f2a5d89b2f94e12df998c7da53e393855a0934b63
Guarde essas informações, especificamente a linha que contém o comando kubeadm join
– ela será utilizada para ingressar os demais nós em nosso cluster.
IMPORTANTE: as informações de token e hash serão diferentes para cada execução. Na hora do ingresso dos outros nós, certifique-se de utilizar as informações que foram apresentados na sua saída padrão ao invés da apresentada neste post.
Com isso estamos quase prontos para ingressar os demais nós em nosso cluster, basta apenas configurar o plugin de rede. Existem diversos sendo desenvolvidos para o Kubernetes, e um dos mais famosos é o Calico
[5]. Para aplicar em seu cluster utilize as seguintes diretivas:
vagrant@control-plane:~/$ sudo export KUBECONFIG=/etc/kubernetes/admin.conf
vagrant@control-plane:~/$ curl https://projectcalico.docs.tigera.io/manifests/calico.yaml -O > calico.yaml
vagrant@control-plane:~/$ kubectl apply -f calico.yaml
configmap/calico-config created
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created
clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrole.rbac.authorization.k8s.io/calico-node created
clusterrolebinding.rbac.authorization.k8s.io/calico-node created
daemonset.apps/calico-node created
serviceaccount/calico-node created
deployment.apps/calico-kube-controllers created
serviceaccount/calico-kube-controllers created
Warning: policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget
poddisruptionbudget.policy/calico-kube-controllers created
Pode demorar alguns minutos até que os pods
do Calico estejam prontos, você pode acompanhar esse processo através do comando watch kubectl get nodes
Ao final desse processo, o control-plane deverá apresentar o seguinte status:
vagrant@control-plane:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane Ready control-plane,master 10m v1.22.0
Com isso o control-plane está pronto. Para sair do watch
utilize a tecla de atalho `CRTL + C` retorne a sua máquina local através das teclas de atalho CRTL + D
.
Ingressando Worker Nodes
Os worker nodes possuem quase as mesmas dependências em relação ao control-plane. Isso significa que será necessário:
- desabilitar o swap
- habilitar o módulo br_netfilter
- configurar o kernel para aceitar o tráfego
- instalar o container runtime
- instalar kubeadm, kubelet e kubectl
- aplicar a flag
hold
nos binários em questão
Para facilitar esse processo, acesse a máquina virtual worker-1
com o comando vagrant ssh worker-1
e crie um arquivo chamado setup-worker-node.sh
com o seguinte conteúdo:
#!/bin/bash
#1: desabilitando swap
sudo swapoff -a
#2: configurações bridge e parâmetros do kernel
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
br_netfilter
EOF
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system
#3: instalação do CRI-O
OS=Debian_11
CRIO_VERSION=1.22
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /"|sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$CRIO_VERSION/$OS/ /"|sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$CRIO_VERSION.list
curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$CRIO_VERSION/$OS/Release.key | sudo apt-key add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key add -
sudo apt update && sudo apt install -y cri-o cri-o-runc
sudo systemctl enable crio.service
sudo systemctl start crio.service
#4: Instalação kubeadm, kubelet, kubectl
sudo apt-get install -y apt-transport-https ca-certificates curl
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet=1.22.0-00 kubeadm=1.22.0-00 kubectl=1.22.0-00
sudo apt-mark hold kubelet kubeadm kubectl
Após criado o arquivo, modifique a permissão do arquivo para se tornar executável com a diretiva chmod +x setup-worker-node.sh`
e em seguida execute com o comando ./setup-worker-node.sh:
vagrant@worker-1:~/$ chmod +x setup-worker-node.sh
vagrant@worker-1:~/$ ./setup-worker-node.sh
Ao final da execução, ingresse o nó no cluster com o comando que apareceu na saída do kubeadm init
no processo de bootstrap do control-plane:
vagrant@worker1:~/$ sudo kubeadm join 192.168.56.10:6443 --token bgkad3.sdumad8yig8thife \
--discovery-token-ca-cert-hash sha256:1959fbfddb23f869b4e1f60f2a5d89b2f94e12df998c7da53e393855a0934b63
Ao final do processo a seguinte mensagem será apresentada:
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
Para o segundo worker node, repita os mesmos passos executados – copie o conteúdo do script, execute na máquina worker-2
e execute o comando kubeadm join
informado na saída do bootstrap do control-plane.
Ao final, retorne ao nó do control-plane e execute a diretiva kubectl get nodes
e verifique se todos os nós estão com status Ready
:
root@control-plane:/home/vagrant# kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane Ready control-plane,master 93m v1.22.0
worker-1 Ready <none> 44m v1.22.0
worker-2 Ready <none> 3m18s v1.22.0
Lembre-se de exportar o kubeconfig de admin:
export KUBECONFIG=/etc/kubernetes/admin.conf
Testando o cluster
Para testar o nosso cluster, subiremos 2 aplicações idênticas, com configurações de replicas distintas para vermos a distribuição dos pods no cluster.
Para tal, utilizaremos o próprio nginx
. Na documentação oficial sobre deployment
há um exemplo de um manifest do nginx:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx1-deployment
labels:
app: nginx-1
spec:
replicas: 3
selector:
matchLabels:
app: nginx-1
template:
metadata:
labels:
app: nginx-1
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx1-service
spec:
type: NodePort
selector:
app: nginx-1
ports:
- port: 80
protocol: TCP
nodePort: 31000
Crie um arquivo chamado app1.yaml
com o conteúdo acima – não se preocupe em entender cada linha do manifest, apenas estamos testando as funcionalidades do cluster. Para criar os pods no cluster use a diretiva kubectl apply -f app1.yaml
.
Você pode inspecionar o local de criação dos pods através do comando kubectl get pods -o wide
:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx1-deployment-645c6857b7-b4vx6 1/1 Running 0 11m 10.244.226.65 worker-1 <none> <none>
nginx1-deployment-645c6857b7-bm9w7 1/1 Running 0 11m 10.244.133.193 worker-2 <none> <none>
nginx1-deployment-645c6857b7-rtm7m 1/1 Running 0 11m 10.244.133.194 worker-2 <none> <none>
Você pode acessar diretamente através do comando curl http://192.168.56.20:31000
root@control-plane:/home/vagrant# curl 192.168.56.20:31000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Dica: você também pode acessar essa página através do seu navegador
Com a aplicação de pé, vamos criar mais duas apps, só que agora trocando o número de réplicas, nome e a porta para não termos conflito. Basta copiar o arquivo app1.yaml
para app2.yaml
e fazer as alterações:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx2-deployment
labels:
app: nginx-2
spec:
replicas: 5
selector:
matchLabels:
app: nginx-2
template:
metadata:
labels:
app: nginx-2
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx2-service
spec:
type: NodePort
selector:
app: nginx-2
ports:
- port: 80
protocol: TCP
nodePort: 31002
Ao aplicar o manifest desta nova aplicação, teremos a seguinte disposição dos pods no cluster:
root@control-plane:/home/vagrant# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx1-deployment-645c6857b7-b4vx6 1/1 Running 0 17m 10.244.226.65 worker-1 <none> <none>
nginx1-deployment-645c6857b7-bm9w7 1/1 Running 0 17m 10.244.133.193 worker-2 <none> <none>
nginx1-deployment-645c6857b7-rtm7m 1/1 Running 0 17m 10.244.133.194 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-bx9ln 1/1 Running 0 2m46s 10.244.226.67 worker-1 <none> <none>
nginx2-deployment-7cd5cb6d4b-nks2s 1/1 Running 0 2m46s 10.244.226.66 worker-1 <none> <none>
nginx2-deployment-7cd5cb6d4b-nwt8q 1/1 Running 0 2m46s 10.244.133.195 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-s7ccg 1/1 Running 0 2m46s 10.244.133.196 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-wb4v9 1/1 Running 0 2m46s 10.244.226.68 worker-1 <none> <none>
Com isso temos um cluster funcional com duas aplicações em execução. Veremos na seção a seguir como atualizar o cluster de forma a não impactar a execução das aplicações bem como manter a consistência do cluster.
Atualização de um cluster através do kubeadm
Antes de atualizar o cluster, é preciso ter alguns cuidados em mente:
- Verificar a versão atual do cluster
- Identificar qual a versão alvo para atualização
- Ver se é possível fazer a atualização direta ou se vai precisar atualizar para uma versão intermediária
Em nosso cenário, estamos na versão v1.22.0-00
. A versão mais atual do kubernetes no momento em que esse post foi escrito é v.1.23.5-00
. De acordo com a documentação oficial, não é necessário fazer quaquer tipo de atualização intermediária tendo em vista que não estamos pulando alguma versão minor
(estamos indo da v1.22 para 1.23*, se estivéssemos na versão v1.21 isso não seria possível de forma direta).
Os passos para update de um cluster de forma segura é realizar a atualização da versão de forma individual em cada nó, um de cada vez, sendo que durante a atualização do kubelet
e kubectl
, é necessário atualizar o estado do nó para modo de manutenção.
Atualizando o control plane
Para iniciarmos a atualização do control-plane, acesse sua máquina através do comando vagrant ssh control-plane
. Em seguida torne-se root através da diretiva sudo su
.
O primeiro passo para atualizar o cluster é fazer a atualização do kubeadm
. Para tal, desmarque o kubeadm
através da diretiva apt-mark unhold kubeadm
e sem seguida atualize sua lista de pacotes e performe a atualização através do comando apt-mark unhold kubeadm && apt update && apt install kubeadm=1.23.5-00
:
root@control-plane:/home/vagrant# sudo apt install kubeadm=1.23.5-00
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following held packages will be changed:
kubeadm
The following packages will be upgraded:
kubeadm
1 upgraded, 0 newly installed, 0 to remove and 52 not upgraded.
Need to get 8,582 kB of archives.
After this operation, 623 kB disk space will be freed.
Do you want to continue? [Y/n]
Após confirmar com Y
, o gerenciador de pacotes irá realizar o processo de atualização. Após esse processo é possível verificar a versão do kubeadm com a diretiva kubeadm version
root@control-plane:/home/vagrant# kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.5", GitCommit:"c285e781331a3785a7f436042c65c5641ce8a9e9", GitTreeState:"clean", BuildDate:"2022-03-16T15:57:37Z", GoVersion:"go1.17.8", Compiler:"gc", Platform:"linux/amd64"}
Para verificar o plano de atualização do nó, podemos utilizar a diretiva kubeadm upgrade plan
– desta forma irá verificar se há alguma pendência no nó, além de mostrar as possíveis atualizações e as ações necessárias pós atualização:
root@control-plane:/home/vagrant# kubeadm upgrade plan
[upgrade/config] Making sure the configuration is correct:
[upgrade/config] Reading configuration from the cluster...
[upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[preflight] Running pre-flight checks.
[upgrade] Running cluster health checks
[upgrade] Fetching available versions to upgrade to
[upgrade/versions] Cluster version: v1.22.9
[upgrade/versions] kubeadm version: v1.23.5
[upgrade/versions] Target version: v1.23.6
[upgrade/versions] Latest version in the v1.22 series: v1.22.9
Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT TARGET
kubelet 3 x v1.22.0 v1.23.6
Upgrade to the latest stable version:
COMPONENT CURRENT TARGET
kube-apiserver v1.22.9 v1.23.6
kube-controller-manager v1.22.9 v1.23.6
kube-scheduler v1.22.9 v1.23.6
kube-proxy v1.22.9 v1.23.6
CoreDNS v1.8.4 v1.8.6
etcd 3.5.0-0 3.5.1-0
You can now apply the upgrade by executing the following command:
kubeadm upgrade apply v1.23.6
Note: Before you can perform this upgrade, you have to update kubeadm to v1.23.6.
_____________________________________________________________________
The table below shows the current state of component configs as understood by this version of kubeadm.
Configs that have a "yes" mark in the "MANUAL UPGRADE REQUIRED" column require manual config upgrade or
resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually
upgrade to is denoted in the "PREFERRED VERSION" column.
API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED
kubeproxy.config.k8s.io v1alpha1 v1alpha1 no
kubelet.config.k8s.io v1beta1 v1beta1 no
_____________________________________________________________________
Note que durante este processo, foi identificado uma versão mais atualizada – v1.23.6
. E há um aviso importate que, para atualizar para última versão estável, é necessário atualizar o kubeadm
para a versão v1.23.6-00
:
root@control-plane:~/$ apt update && apt install kubeadm=v1.23.6-00
(...)
Após a atualização, podemos verificar novamente se o plano de atualização é plausível com o comando kubeadm upgrade plan
. Desta vez não aparecerá nenhum impedimento direto, inclusive aparecendo a mensagem com o comando a ser executado via kubeadm:
(...)
You can now apply the upgrade by executing the following command:
kubeadm upgrade apply v1.23.6
(...)
Note que há também um aviso sobre o componente kubelet
que deverá ser feita manualmente:
Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT CURRENT TARGET
kubelet 3 x v1.22.0 v1.23.6
Nesse sentido vamos aplicar a seguinte estratégia:
- atualizar o cluster com o kubeadm upgrade apply v1.23.6
- colocar o nó em modo de manutenção através da diretiva
kubectl drain control-plane --ignore-daemonsets
- atualizar o kubelet para versão desejada
- retornar do modo de manutenção através do comando
kubectl uncordon control-plane
.
Para atualizar o cluster utilizamos o comando conforme a saída do comando do kubeadm upgrade plan
:
root@control-plane:/home/vagrant# kubeadm upgrade apply v1.23.6
[upgrade/config] Making sure the configuration is correct:
[upgrade/config] Reading configuration from the cluster...
[upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[preflight] Running pre-flight checks.
[upgrade] Running cluster health checks
[upgrade/version] You have chosen to change the cluster version to "v1.23.6"
[upgrade/versions] Cluster version: v1.22.9
[upgrade/versions] kubeadm version: v1.23.6
[upgrade/confirm] Are you sure you want to proceed with the upgrade? [y/N]: y
[upgrade/prepull] Pulling images required for setting up a Kubernetes cluster
[upgrade/prepull] This might take a minute or two, depending on the speed of your internet connection
[upgrade/prepull] You can also perform this action in beforehand using 'kubeadm config images pull'
[upgrade/apply] Upgrading your Static Pod-hosted control plane to version "v1.23.6"...
Static pod: kube-apiserver-control-plane hash: dbf53049950d64d0d51c2ac8821a8048
Static pod: kube-controller-manager-control-plane hash: 2330aca433980402f4f49d6603f2d898
Static pod: kube-scheduler-control-plane hash: 7fdfa0d609e3fd3c5a02e41c2c025484
[upgrade/etcd] Upgrading to TLS for etcd
Static pod: etcd-control-plane hash: e190aab32386f2b82b392ff88a0c43d9
[upgrade/staticpods] Preparing for "etcd" upgrade
[upgrade/staticpods] Renewing etcd-server certificate
[upgrade/staticpods] Renewing etcd-peer certificate
[upgrade/staticpods] Renewing etcd-healthcheck-client certificate
[upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/etcd.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2022-04-22-17-56-13/etcd.yaml"
[upgrade/staticpods] Waiting for the kubelet to restart the component
[upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s)
Static pod: etcd-control-plane hash: e190aab32386f2b82b392ff88a0c43d9
Static pod: etcd-control-plane hash: 9b5786e55fd0df43b304d665a9ea0e35
[apiclient] Found 1 Pods for label selector component=etcd
[upgrade/staticpods] Component "etcd" upgraded successfully!
[upgrade/etcd] Waiting for etcd to become available
[upgrade/staticpods] Writing new Static Pod manifests to "/etc/kubernetes/tmp/kubeadm-upgraded-manifests324761829"
[upgrade/staticpods] Preparing for "kube-apiserver" upgrade
[upgrade/staticpods] Renewing apiserver certificate
[upgrade/staticpods] Renewing apiserver-kubelet-client certificate
[upgrade/staticpods] Renewing front-proxy-client certificate
[upgrade/staticpods] Renewing apiserver-etcd-client certificate
[upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-apiserver.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2022-04-22-17-56-13/kube-apiserver.yaml"
[upgrade/staticpods] Waiting for the kubelet to restart the component
[upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s)
Static pod: kube-apiserver-control-plane hash: dbf53049950d64d0d51c2ac8821a8048
Static pod: kube-apiserver-control-plane hash: 380f1d7b85b2a93ee6253013a4c90921
[apiclient] Found 1 Pods for label selector component=kube-apiserver
[upgrade/staticpods] Component "kube-apiserver" upgraded successfully!
[upgrade/staticpods] Preparing for "kube-controller-manager" upgrade
[upgrade/staticpods] Renewing controller-manager.conf certificate
[upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-controller-manager.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2022-04-22-17-56-13/kube-controller-manager.yaml"
[upgrade/staticpods] Waiting for the kubelet to restart the component
[upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s)
Static pod: kube-controller-manager-control-plane hash: 2330aca433980402f4f49d6603f2d898
Static pod: kube-controller-manager-control-plane hash: 1006a360e1a440e1c59344829009a790
[apiclient] Found 1 Pods for label selector component=kube-controller-manager
[upgrade/staticpods] Component "kube-controller-manager" upgraded successfully!
[upgrade/staticpods] Preparing for "kube-scheduler" upgrade
[upgrade/staticpods] Renewing scheduler.conf certificate
[upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-scheduler.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2022-04-22-17-56-13/kube-scheduler.yaml"
[upgrade/staticpods] Waiting for the kubelet to restart the component
[upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s)
Static pod: kube-scheduler-control-plane hash: 7fdfa0d609e3fd3c5a02e41c2c025484
Static pod: kube-scheduler-control-plane hash: 11441b8e7cd4bbf5926a2836d512e88f
[apiclient] Found 1 Pods for label selector component=kube-scheduler
[upgrade/staticpods] Component "kube-scheduler" upgraded successfully!
[upgrade/postupgrade] Applying label node-role.kubernetes.io/control-plane='' to Nodes with label node-role.kubernetes.io/master='' (deprecated)
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.23" in namespace kube-system with the configuration for the kubelets in the cluster
NOTE: The "kubelet-config-1.23" naming of the kubelet ConfigMap is deprecated. Once the UnversionedKubeletConfigMap feature gate graduates to Beta the default name will become just "kubelet-config". Kubeadm upgrade will handle this transition transparently.
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
[upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.23.6". Enjoy!
[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.
Note essa etapa pode demorar alguns minutos pois algumas imagens de contêineres atualizadas serão baixadas, e a conexão da sua internet pode interferir no processo.
Com a atualização do cluster, precisamos atualizar o kubelet
. Só que esse é um serviço essencial e pode influenciar no comportamento do cluster, e por isso é necessário aplicar o modo de manutenção no nó em questão através do comando kubectl drain control-plane --ignore-daemonsets
:
root@control-plane:/home/vagrant# kubectl drain control-plane --ignore-daemonsets
node/control-plane cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-xjrhf, kube-system/kube-proxy-kr55r
evicting pod kube-system/calico-kube-controllers-65898446b5-ns9ht
pod/calico-kube-controllers-65898446b5-ns9ht evicted
node/control-plane evicted
Agora é possível atualizar o serviço do kubelet com o gerenciador de pacotes. Como tínhamos sinalizado anteriomente, é preciso desmarcar os pacotes kubelet
e kubectl
:
root@control-plane:/home/vagrant# apt-mark unhold kubelet kubectl
Canceled hold on kubelet.
Canceled hold on kubectl.
Agora é possível atualizar os pacotes normalmente através da diretiva apt-get install
:
root@control-plane:/home/vagrant# apt install kubelet=1.23.6-00 kubectl=1.23.6-00
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages will be upgraded:
kubectl kubelet
2 upgraded, 0 newly installed, 0 to remove and 50 not upgraded.
Need to get 28.4 MB of archives.
After this operation, 29.1 MB disk space will be freed.
Get:1 https://packages.cloud.google.com/apt kubernetes-xenial/main amd64 kubectl amd64 1.23.6-00 [8,933 kB]
Get:2 https://packages.cloud.google.com/apt kubernetes-xenial/main amd64 kubelet amd64 1.23.6-00 [19.5 MB]
Fetched 28.4 MB in 18s (1,538 kB/s)
Reading changelogs... Done
(Reading database ... 37737 files and directories currently installed.)
Preparing to unpack .../kubectl_1.23.6-00_amd64.deb ...
Unpacking kubectl (1.23.6-00) over (1.22.0-00) ...
Preparing to unpack .../kubelet_1.23.6-00_amd64.deb ...
Unpacking kubelet (1.23.6-00) over (1.22.0-00) ...
Setting up kubectl (1.23.6-00) ...
Setting up kubelet (1.23.6-00) ...
Ao final da atualização retornamos o estado com o apt-mark hold kubeadm kubectl kubelet
. Além de impedir a atualização por softwares terceiros, é necessário reinicializar o serviço do kubelet:
root@control-plane:/home/vagrant# systemctl daemon-reload
root@control-plane:/home/vagrant# systemctl restart kubelet
root@control-plane:/home/vagrant# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Fri 2022-04-22 18:05:40 UTC; 59s ago
Docs: https://kubernetes.io/docs/home/
Main PID: 113952 (kubelet)
Tasks: 14 (limit: 2336)
Memory: 32.1M
CPU: 1.721s
Com isso o nó está pronto para retornar ao estado normal. Para tal utilize o comando kubectl uncordon control-plane
:
root@control-plane:/home/vagrant# kubectl uncordon control-plane
node/control-plane uncordoned
root@control-plane:/home/vagrant# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
control-plane Ready control-plane,master 3h7m v1.23.6 10.0.2.15 <none> Debian GNU/Linux 11 (bullseye) 5.10.0-11-amd64 cri-o://1.22.3
worker-1 Ready <none> 138m v1.22.0 10.0.2.15 <none> Debian GNU/Linux 11 (bullseye) 5.10.0-11-amd64 cri-o://1.22.3
worker-2 Ready <none> 97m v1.22.0 10.0.2.15 <none> Debian GNU/Linux 11 (bullseye) 5.10.0-11-amd64 cri-o://1.22.3
Com isso o control-plane foi atualizado. Agora é preciso fazer o mesmo processo nos worker nodes, um de cada vez, como veremos à seguir.
Atualizando Worker nodes
O processo é semelhante ao control-plane, porém é mais simples tendo em vista que há menos componenetes nos workers do que no control-plane.
Acesse em outra aba do seu terminal a máquina worker-1
com o comando vagrant ssh worker-1
.
As etapas serão as mesmas:
- atualizar o kubeadm para a versão alvo
- aplicar a atualização
- colocar o nó worker-1 em modo de manutenção
- atualizar o kubelet
- sair do modo de manutenção
É importante dizer que as configurações de acesso estão restritas ao nó control plane. A criação de kubeconfigs e service accounts estão fora do escopo deste post, e por isso, as diretivas
kubectl
serão executadas na máquina virtual do control-plane.
Na máquina worker node, atualize o kubeadm com o seguinte comando:
root@worker-1:/home/vagrant# sudo apt-mark unhold kubeadm
Canceled hold on kubeadm.
root@worker-1:/home/vagrant# apt update && apt install -y kubeadm=1.23.6-00
Para atualizar o nó com o kubeadm o comando se modifica:
root@worker-1:/home/vagrant# kubeadm upgrade node
[upgrade] Reading configuration from the cluster...
[upgrade] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[preflight] Running pre-flight checks
[preflight] Skipping prepull. Not a control plane node.
[upgrade] Skipping phase. Not a control plane node.
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[upgrade] The configuration for this node was successfully updated!
[upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.
Pronto, agora é necessário colocar o nó em manutenção para poder atualizar o kubelet
. Você pode estar se perguntando o que acontece com as aplicações que estão ativas no nó. O comando kubectl drain
realiza a realocação dos pods
que estão no nó alvo de manutenção, mantendo assim a sua aplicação de pé. podemos ver esse comportamento inspecionando os pods antes e depois:
# antes do modo de manutenção
root@control-plane:/home/vagrant# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx1-deployment-645c6857b7-b4vx6 1/1 Running 0 87m 10.244.226.65 worker-1 <none> <none>
nginx1-deployment-645c6857b7-bm9w7 1/1 Running 0 87m 10.244.133.193 worker-2 <none> <none>
nginx1-deployment-645c6857b7-rtm7m 1/1 Running 0 87m 10.244.133.194 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-bx9ln 1/1 Running 0 72m 10.244.226.67 worker-1 <none> <none>
nginx2-deployment-7cd5cb6d4b-nks2s 1/1 Running 0 72m 10.244.226.66 worker-1 <none> <none>
nginx2-deployment-7cd5cb6d4b-nwt8q 1/1 Running 0 72m 10.244.133.195 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-s7ccg 1/1 Running 0 72m 10.244.133.196 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-wb4v9 1/1 Running 0 72m 10.244.226.68 worker-1 <none> <none>
root@control-plane:/home/vagrant# kubectl drain worker-1 --ignore-daemonsets
node/worker-1 cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-fvxbh, kube-system/kube-proxy-5wqpg
evicting pod default/nginx1-deployment-645c6857b7-b4vx6
evicting pod kube-system/coredns-64897985d-nw2xb
evicting pod default/nginx2-deployment-7cd5cb6d4b-nks2s
evicting pod default/nginx2-deployment-7cd5cb6d4b-bx9ln
evicting pod default/nginx2-deployment-7cd5cb6d4b-wb4v9
evicting pod kube-system/calico-kube-controllers-65898446b5-hfgks
pod/nginx2-deployment-7cd5cb6d4b-nks2s evicted
pod/nginx1-deployment-645c6857b7-b4vx6 evicted
pod/nginx2-deployment-7cd5cb6d4b-bx9ln evicted
pod/calico-kube-controllers-65898446b5-hfgks evicted
pod/nginx2-deployment-7cd5cb6d4b-wb4v9 evicted
pod/coredns-64897985d-nw2xb evicted
node/worker-1 drained
# inspecionando o nós depois do modo drain
root@control-plane:/home/vagrant# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx1-deployment-645c6857b7-7j8f4 1/1 Running 0 43s 10.244.133.202 worker-2 <none> <none>
nginx1-deployment-645c6857b7-bm9w7 1/1 Running 0 88m 10.244.133.193 worker-2 <none> <none>
nginx1-deployment-645c6857b7-rtm7m 1/1 Running 0 88m 10.244.133.194 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-674fp 1/1 Running 0 43s 10.244.133.203 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-c7kfr 1/1 Running 0 43s 10.244.133.201 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-nwt8q 1/1 Running 0 73m 10.244.133.195 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-s7ccg 1/1 Running 0 73m 10.244.133.196 worker-2 <none> <none>
nginx2-deployment-7cd5cb6d4b-z8x22 1/1 Running 0 43s 10.244.133.200 worker-2 <none> <none>
Veja que todos os pods foram direcionados para o nó worker-2
e o estado atual do nó é o seguinte:
NAME STATUS ROLES AGE VERSION
control-plane Ready control-plane,master 3h26m v1.23.6
worker-1 Ready,SchedulingDisabled <none> 156m v1.22.0
worker-2 Ready <none> 115m v1.22.0
Note que o control-plane irá evitar de alocar pods no worker-1
tendo em vista que o scheduling está desabilitado. Com isso conseguimos prosseguir com a atualização do kubelet
:
root@worker-1:/home/vagrant# apt-mark unhold kubelet
Canceled hold on kubelet.
root@worker-1:/home/vagrant# apt install kubelet=1.23.6-00
Reading package lists... Done
(...)
root@worker-1:/home/vagrant# systemctl daemon-reload
root@worker-1:/home/vagrant# systemctl restart kubelet
root@worker-1:/home/vagrant# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Fri 2022-04-22 18:29:22 UTC; 7s ago
Docs: https://kubernetes.io/docs/home/
Main PID: 55547 (kubelet)
Tasks: 12 (limit: 2336)
Memory: 29.3M
CPU: 310ms
root@worker-1:/home/vagrant# apt-mark hold kubeadm kubelet
kubeadm set on hold.
kubelet set on hold.
Após essa etapa podemos retirar o modo manutenção no control-plane:
root@control-plane:/home/vagrant# kubectl uncordon worker-1
node/worker-1 uncordoned
root@control-plane:/home/vagrant# kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane Ready control-plane,master 3h30m v1.23.6
worker-1 Ready <none> 161m v1.23.6
worker-2 Ready <none> 120m v1.22.0
Com isso temos o segundo nó atualizado. Repita os procedimentos no worker-2
e teremos o cluser atualizado:
root@control-plane:/home/vagrant# kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane Ready control-plane,master 3h30m v1.23.6
worker-1 Ready <none> 161m v1.23.6
worker-2 Ready <none> 120m v1.23.6
E assimencerramos esse hands on sobre preparação, instalação e atualização de um cluster Kubernetes através do kubeadm
.
Fique atento ao nosso blog pois mais posts sobre a CKA virão por aí.
Até lá!
Notas
[1]: Ver ementa oficial em: https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/
[3]: O Jeff Geerling ou GeerlingGuy como é conhecido, é um membro ativo da comunidade open source, já fez parte do conselho técnico da ferramenta Ansible da Red Hat. Sobre a box, o motivo de sua escolha é pela curadoria apurada e por ser uma das menores em termos de tamanho em disco, o que facilita no processo de download.
[4]: Para maiores detalhes ver: https://cri-o.io/
[5]: Para saber mais sobre o projeto calico acesse: https://www.tigera.io/project-calico/
Referências
SPENNEBERG, R. Bridgewalling- Using Netfilter in Bridge Mode.
Líder em Treinamento e serviços de Consultoria, Suporte e Implantação para o mundo open source. Conheça nossas soluções:
About author
Você pode gostar também
Guia completo: Como instalar e configurar o OCS Inventory
O OCS Inventory é um software de gerência para inventários de dispositivos em rede, com ele é possível registrar todas as características de um computador incluindo: Versão do sistema operacional;
Prepare sua empresa para 2022 com a Consultoria e Cursos 4Linux
Sua empresa está preparada para 2022? Em um mercado cada vez mais competitivo, e principalmente após uma pandemia, a inovação e tecnologia são fundamentais para a sobrevivência e podem ser
Crie sua própria Wiki: Guia passo a passo para instalação e uso
Uma wiki é uma coleção de páginas da web interconectadas e editáveis colaborativamente. O termo “wiki” é derivado da palavra havaiana “wiki wiki”, que significa “rápido” ou “veloz”. A característica