Skip to main content

Kubeadm Instalação

Vamos fazer uma instalação do cluster usando o kubeadm.

A ferramenta kubeadm nos ajuda a montar um cluster de vários nós usando as melhores práticas do Kubernetes.

Só para relembrar, o cluster Kubernetes consiste em vários componentes, incluindo o kube-apiserver, etcd, os controladores, etc.

![alt text](/docs/kubernetes/certifications/cka/Installation Configuration Validation/pics/image.png)

Vimos algumas das exigências em torno da segurança e certificados para permitir a comunicação entre todos os componentes. Instalar todos esses vários componentes individualmente em diferentes nós e modificar todos os arquivos de configuração necessários para garantir que todos os componentes apontem uns para os outros e estabelecer certificados para que funcionem é uma tarefa entediante.

A ferramenta kubeadm nos ajuda, cuidando de todas estas tarefas.

Primeiro, você precisa ter vários sistemas ou VMs provisionados. Portanto, vamos precisar de um par de nós para formar o nosso cluster Kubernetes. Estas podem ser máquinas físicas ou virtuais. Como é um lab vamos criar máquinas virtuais usando o VirtualBox e Vagrant.

Com o Vagrant podemos criar um bootstrap após a máquina subir, colocando os comandos necessários em um script.

Os comandos para os nodes que serão os master são diferentes dos que serão workers, mas o kubeadm nos ajudará também nessa tarefa.

Todos os nodes precisam de um container runtime em execução. O kubeadm subirá os controllers como pods estáticos dentro do nosso cluster.

Procedimento para implantação do Kubernetes Cluster

  1. Provisionamento de Máquinas (ALL): 1.1. Garantir que as máquinas atendam aos requisitos mínimos, incluindo:

    • Update do sistema operacional
    • Desabilitar o uso de swap.
    • Desativar o firewall ou configurá-lo corretamente para permitir o tráfego necessário.
  2. Instalação do Container Runtime (ALL):

    • Instalar o containerd em todas as máquinas conforme as instruções do fabricante.
  3. Instalação do kubeadm (ALL):

  4. Configuração do Master (MASTER1):

    • Em uma das máquinas master vamos inicializar o cluster usando o kubeadm como se fosse single node.
  5. Deploy do CNI para criar a rede do cluster (MASTER1):

    • Vamos implantar uma solução de CNI para conseguir ter a rede do nosso cluster.
  6. Adicionar outros masters:

    • Nas máquinas designadas como master, executar os comandos específicos do kubeadm para que se juntem ao cluster com função de master.
  7. Adição de Workers ao Cluster:

    • Nas máquinas designadas como workers, executar os comandos específicos do kubeadm para que se juntem ao cluster.

Requisitos

Vamos precisar do Vagrant instalado e do VirtualBox. É bom dar uma olhada no link https://github.com/kodekloudhub/certified-kubernetes-administrator-course

Crie uma pasta para o projeto.

mkdir kubeadm-env
cd kubeadm-env

E vamos criar um arquivo chamado Vagrantfile com esse conteúdo:

NUM_EXTRA_MASTER_NODE = 2
NUM_WORKER_NODE = 2

IP_NW = "192.168.56."
MASTER_IP_START = 11
NODE_IP_START = 20

Vagrant.configure("2") do |config|

config.vm.box = "ubuntu/jammy64"
config.vm.boot_timeout = 900

config.vm.box_check_update = false

# Provision Master Nodes
config.vm.define "kubemaster" do |node|
node.vm.provider "virtualbox" do |vb|
vb.name = "kubemaster01"
vb.memory = 2048
vb.cpus = 2
end
node.vm.hostname = "kubemaster01"
node.vm.network :private_network, ip: IP_NW + "#{MASTER_IP_START}"
node.vm.network "forwarded_port", guest: 22, host: "#{2710}"
end

# Provision Extra Masters
(1..NUM_EXTRA_MASTER_NODE).each do |i|
config.vm.define "kubemaster0#{i+1}" do |node|
node.vm.provider "virtualbox" do |vb|
vb.name = "kubemaster0#{i+1}"
vb.memory = 2048
vb.cpus = 2
end
node.vm.hostname = "kubemaster0#{i+1}"
node.vm.network :private_network, ip: IP_NW + "#{MASTER_IP_START + i + 1}"
node.vm.network "forwarded_port", guest: 22, host: "#{2710 + i + 1}"
end
end

# Provision Worker Nodes
(1..NUM_WORKER_NODE).each do |i|
config.vm.define "kubenode0#{i}" do |node|
node.vm.provider "virtualbox" do |vb|
vb.name = "kubenode0#{i}"
vb.memory = 1024
vb.cpus = 1
end
node.vm.hostname = "kubenode0#{i}"
node.vm.network :private_network, ip: IP_NW + "#{NODE_IP_START + i}"
node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}"
end
end
end

Este arquivo apenas subirá 5 VMs, e não executará nada dentro delas como o bootstrap. Os passos 1, 2 e 3 servem para todos os nodes, então vamos montar um script para fazer um bootstrap geral.

#!/bin/bash

echo "##### Update System #####"
sudo apt-get update
sudo apt-get upgrade -y

## Seguindo a documentação https://kubernetes.io/docs/setup/production-environment/
## https://docs.docker.com/engine/install/ubuntu/container-runtimes/

echo "##### Desativando o swap #####"
sed -i '/swap/d' /etc/fstab
swapoff -a

echo "##### Desativando o firewall #####"
systemctl disable --now ufw >/dev/null 2>&1

echo "##### Ativando módulos do kernel necessários para o containerd #####"
cat >>/etc/modules-load.d/containerd.conf<<EOF
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter

echo "##### Correção de Módulos #####"
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl params required by setup, params persist across reboots
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system

# Verifying
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward

echo "##### Install Containerd #####"

sudo apt-get update
sudo apt-get install ca-certificates curl

echo "##### Install Containerd: Add Docker's official GPG key #####"

sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo "##### Install Containerd: Add the repository to Apt sources #####"

echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

echo "##### Install Containerd: Install Packages #####"

sudo apt-get update
sudo apt-get install containerd.io -y

echo "##### Install Containerd: Verifying Service #####"
systemctl status containerd.service

echo "##### Install Containerd: Fix Cgroups Driver for systemd #####"

sudo mv /etc/containerd/config.toml /etc/containerd/config.toml.default

sudo tee /etc/containerd/config.toml > /dev/null <<EOF
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
EOF

sudo systemctl restart containerd.service
systemctl status containerd.service

#https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
echo "##### Install Kubeadm kubelet and kubectl #####"
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

echo "##### Install Kubeadm kubelet and kubectl: Add Kubernetes's official GPG key"
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

echo "##### Install Kubeadm kubelet and kubectl: Add the repository to Apt sources"
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update

echo "##### Install Kubeadm kubelet and kubectl: Install Packages #####"
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

Fiz todos os comentários necessários nesse script para que entenda o que vamos fazer, agora vamos adicionar esse script em todas as VMs.

Salve esse script na mesma pasta onde está o Vagrantfile com o nome de bootstrap.sh

ls -lha  
total 20K
drwxrwxr-x 3 david-prata david-prata 4,0K fev 25 02:12 .
drwxrwxr-x 3 david-prata david-prata 4,0K fev 24 21:02 ..
-rw-rw-r-- 1 david-prata david-prata 3,0K fev 25 02:15 bootstrap.sh
-rw-rw-r-- 1 david-prata david-prata 1,7K fev 25 02:17 Vagrantfile

Vamos adicionar as linhas abaixo comentadas.

NUM_EXTRA_MASTER_NODE = 2
NUM_WORKER_NODE = 2

IP_NW = "192.168.56."
MASTER_IP_START = 11
NODE_IP_START = 20

Vagrant.configure("2") do |config|

config.vm.box = "ubuntu/jammy64"
config.vm.boot_timeout = 900

config.vm.box_check_update = false

# Provision Master Nodes
config.vm.define "kubemaster" do |node|
# Nome mostrado na interface gráfica
node.vm.provider "virtualbox" do |vb|
vb.name = "kubemaster01"
vb.memory = 2048
vb.cpus = 2
end
node.vm.hostname = "kubemaster01"
node.vm.network :private_network, ip: IP_NW + "#{MASTER_IP_START}"
node.vm.network "forwarded_port", guest: 22, host: "#{2710}"
node.vm.provision "shell", path: "bootstrap.sh" ## ADICIONADO
end

# Provision Extra Masters
(1..NUM_EXTRA_MASTER_NODE).each do |i|
config.vm.define "kubemaster0#{i+1}" do |node|
node.vm.provider "virtualbox" do |vb|
vb.name = "kubemaster0#{i+1}"
vb.memory = 2048
vb.cpus = 2
end
node.vm.hostname = "kubemaster0#{i+1}"
node.vm.network :private_network, ip: IP_NW + "#{MASTER_IP_START + i + 1}"
node.vm.network "forwarded_port", guest: 22, host: "#{2710 + i + 1}"
node.vm.provision "shell", path: "bootstrap.sh" ## ADICIONADO
end
end

# Provision Worker Nodes
(1..NUM_WORKER_NODE).each do |i|
config.vm.define "kubenode0#{i}" do |node|
node.vm.provider "virtualbox" do |vb|
vb.name = "kubenode0#{i}"
vb.memory = 1024
vb.cpus = 1
end
node.vm.hostname = "kubenode0#{i}"
node.vm.network :private_network, ip: IP_NW + "#{NODE_IP_START + i}"
node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}"
node.vm.provision "shell", path: "bootstrap.sh" ## ADICIONADO
end
end
end

Em cada nó então estaremos preparados para montar o cluster.

No primeiro nó master precisamos inicializar o cluster.

kubeadm init --apiserver-advertise-address=<IP DO MASTER> --pod-network-cidr=<REDE QUE OS PODS TERÃO>

Nós já sabemos qual é o IP dos masters. Definimos no Vagrantfile os IPs de forma automática.

IPSNODE
kubemaster01192.168.56.11
kubemaster02192.168.56.12
kubemaster03192.168.56.13
kubemaster01192.168.56.21
kubemaster01192.168.56.22

Vamos definir a rede que será usada pelos pods para 10.244.0.0/16, poderia ser outra, claro.

Então o comando seria: kubeadm init --apiserver-advertise-address=192.168.56.11 --pod-network-cidr=10.244.0.0/16

Podemos automatizar isso.

IP_ADDR=`ip -4 address show enp0s8 | grep inet | awk '{print $2}' | cut -d/ -f1`
POD_CIDR="10.244.0.0/16"

echo "##### Inicializando o cluster #####"
sudo kubeadm init --apiserver-advertise-address=$IP_ADDR --pod-network-cidr=$POD_CIDR

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Vamos falar um pouco sobre esse comando. Não temos aqui um load balancer na frente do nosso cluster. Se tivéssemos deveríamos passar alguns parâmetros a mais nesse comando --control-plane-endpoint=<IP_LB:6443> --upload-certs.

O comando init faz pull de algumas imagens que serão usadas automaticamente. Se quiser fazer o pull dessas imagens antes de rodar o comando init para ser mais rápido é possível, mas não é obrigatório. kubeadm config images pull.

Executando o script acima temos o cluster com um único node master. No console ele mostra os comandos necessários que demos continuar executando, veja a saída.

###
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.11:6443 --token 9n1vty.afan7eb99kaxltcj \
--discovery-token-ca-cert-hash sha256:6ebd7fd44972113263b6e85e8bdddd841774a39db9a48bd04d575c034c188247

O kubeconfig gerado fica em /etc/kubernetes/admin.conf. Precisamos dele para que o kubectl funcione, logo vamos colocar os comandos acima dentro do nosso script. Outra coisa que precisamos fazer é instalar um CNI no cluster. Já vamos também aplicá-lo no cluster usando o kubectl que acabamos de fazer funcionar. Poderíamos usar outras opções de CNI, mas vamos escolher o Weavenet.

IP_ADDR=`ip -4 address show enp0s8 | grep inet | awk '{print $2}' | cut -d/ -f1`
POD_CIDR="10.244.0.0/16"

echo "##### Init Cluster #####"
sudo kubeadm init --apiserver-advertise-address=$IP_ADDR --pod-network-cidr=$POD_CIDR

echo "##### Copy kubeconfig #####"
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

##https://github.com/weaveworks/weave?tab=readme-ov-file
echo "##### Deploy CNI weavenet #####"
kubectl apply -f https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n') >/dev/null 2>&1

kubeadm token create --certificate-key $(kubeadm init phase upload-certs --upload-certs | tail -1 ) --print-join-command > /join_masters.sh