Kubernetes – Instalação
À medida que as organizações buscam adotar estratégias modernas de desenvolvimento de software e implantar aplicações de forma escalável e flexível, o Kubernetes tem se destacado como uma solução essencial. Este artigo é um guia detalhado que o levará através dos passos necessários para instalar e configurar um cluster Kubernetes do zero.
Se você está ansioso para criar um ambiente de orquestração de containers robusto e eficaz, continue lendo. Iremos abordar desde a preparação do sistema operacional até a configuração do Kubernetes e da rede, permitindo que você aproveite ao máximo essa poderosa plataforma de administração de containers.
Configuração do OS
O Kubernetes necessita de algumas configurações, para poder trabalhar de forma normal.
Desabilitando a SWAP
O Kubernetes não lida bem com SWAP de memória, necessita de saber a memoria real de cada node para cálculos internos. Como por exemplo saber se o node que tem determinados recursos disponíveis para correr um determinado container. E a SWAP apesar de poder ser usada como memoria, é muito mais lenta e complica nas decisões.
Estes comandos devem ser executados, quer no kube-master como nos kube-node1 e kube-node2, deste Cluster, se adicionaram mais nodes como workers, executem em todos.
Para desabilitar a SWAP temporariamente executamos o seguinte comando:
swapoff -a
Podemos verificar que está desabilitado a SWAP, o seguinte comando mostra a SWAP a zero:
free
total usada livre compart. buff/cache disponível
Mem.: 2014176 221672 1827264 432 81368 1792504
Swap: 0 0 0
No entanto para desabilitar a SWAP definitivamente, precisamos de comentar “#” a linha que tem swap no ficheiro “/etc/fstab”. De momento ele contem o conteúdo:
cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# systemd generates mount units based on this file, see systemd.mount(5).
# Please run 'systemctl daemon-reload' after making changes here.
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda1 during installation
UUID=b7917832-6c99-4b99-9472-9d4accb3248b / ext4 errors=remount-ro 0 1
# swap was on /dev/sda5 during installation
UUID=03e3bdbc-3dae-4993-b31e-9f43415024e0 none swap sw 0 0
/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0
Neste caso temos de colocar o caracter “#” no inicio da linha que começa por “UUID=03e3bdbc” ficando assim:
cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# systemd generates mount units based on this file, see systemd.mount(5).
# Please run 'systemctl daemon-reload' after making changes here.
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda1 during installation
UUID=b7917832-6c99-4b99-9472-9d4accb3248b / ext4 errors=remount-ro 0 1
# swap was on /dev/sda5 during installation
#UUID=03e3bdbc-3dae-4993-b31e-9f43415024e0 none swap sw 0 0
/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0
Podemos editar o ficheiro com o nano, ou outro editor que gostem mais, no entanto o nano já está instalado:
nano /etc/fstab
Este passo é importante, pois com a SWAP ativa não conseguiremos juntar as máquinas ao Cluster.
Neste momento, o sistema já não irá utilizar SWAP.
Habilitando módulos do kernel
O Kubernetes necessita de routear pacotes de rede entre as vários redes, filtrar informações da rede, Criar regras de NAT, a fim de poder trabalhar.
Para configurarmos os módulos necessários e para que eles sejam carregados no boot, executamos o seguinte comando:
tee /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF
Para inicializar os módulos manualmente executamos o seguintes comandos:
modprobe overlay
modprobe br_netfilter
Também necessitamos permitir que o kernel active o “forward” de pacotes e algumas compatibilidades de “bridge”. Para tal corremos o seguinte comando:
tee /etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
Para ativarmos estas opções, coremos o seguinte comando:
sysctl --system
As configurações necessárias no sistema estão feitas e irão ser carregadas sempre que o sistema reiniciar como é esperado. Estas configurações devem ser feitas em todos os nodes, master e workers.
Instalação do Containerd
Neste Cluster vamos usar o Containerd como “containers runtime”. Necessitamos instalar software e também um repositório que contem os pacotes de software que necessitamos.
Estes passos são para ser executados em todas as máquinas, Kube-master e kube-node1 e kube-node2.
Instalar dependências necessárias
Para podermos instalar repositórios, necessitamos dos seguintes softwares instalados no sistema. Para tal executamos o seguinte comando:
apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates
Adicionar o repositório Docker
Para adicionar o repositórios do Docker, corremos os seguintes comandos:
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/debian.gpg
add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/debian $(lsb_release -cs) stable" -y
Instalar o Containerd
Já temos o repositório de onde queremos instalar o containerd configurado no sistema já o podemos instalar. Para tal corremos os seguintes comandos:
apt update
apt install -y containerd.io
Configurar o Containerd
Se tudo correu bem, como esperado temos o Containerd instalado no sistema.
Temos de criar a configuração inicial, para tal corremos os seguintes comandos:
mkdir -p /etc/containerd
containerd config default | tee /etc/containerd/config.toml
Temos de ativar a opção “systemd_cgroup”, no ficheiro de configuração que acabamos de criar, para tal editamos o ficheiro “/etc/containerd/config.toml” e procuramos pelo seguinte texto e alteramos o valor da variável “SystemdCgroup” para “true”:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = false
Terá de ficar assim:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
Corremos o seguinte comando para configurar a versão da imagem “pause”:
sed -i 's/sandbox_image = "registry.k8s.io\/pause:3.6"/sandbox_image = "registry.k8s.io\/pause:3.9"/g' /etc/containerd/config.toml
Reiniciar o Containerd
Agora podemos reiniciar o Containerd e configura lo para iniciar no boot do sistema.
systemctl restart containerd
systemctl enable containerd
Verificar o serviço do Containerd
Podemos verificar se está a correr tudo bem, com o seguinte comando:
systemctl status containerd
Este comando irá devolver o estado do serviço, onde podemos confirmar que não existem erros.
root@kube-master:~# systemctl status containerd
● containerd.service - containerd container runtime
Loaded: loaded (/lib/systemd/system/containerd.service; enabled; preset: enabled)
Active: active (running) since Mon 2023-09-18 21:56:07 WEST; 5min ago
Docs: https://containerd.io
Main PID: 2853 (containerd)
Tasks: 8
Memory: 25.3M
CPU: 171ms
CGroup: /system.slice/containerd.service
└─2853 /usr/bin/containerd
set 18 21:56:07 kube-master containerd[2853]: time="2023-09-18T21:56:07.048035685+01:00" level=info msg=serving... address=/run/containerd>
set 18 21:56:07 kube-master containerd[2853]: time="2023-09-18T21:56:07.048167844+01:00" level=info msg=serving... address=/run/containerd>
set 18 21:56:07 kube-master containerd[2853]: time="2023-09-18T21:56:07.048262822+01:00" level=info msg="Start subscribing containerd even>
Instalar o Kubernetes
Estes passos são para se executados em todas as máquinas, Kube-master e kube-node1 e kube-node2.
Já temos o nosso Containerd instalado, iremos agora dar inicio à instalação do orquestrador Kubernetes.
Para tal necessitamos instalar outro repositório de software.
Instalar repositório
Para instalar o repositório necessitamos de uma chave válida, corremos o seguinte comando, para adicionar a chave:
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmour -o /etc/apt/trusted.gpg.d/cgoogle.gpg
Agora necessitamos configurar o repositório, para tal corremos o seguinte comando:
tee /etc/apt/sources.list.d/kubernetes.list<<EOF
deb http://apt.kubernetes.io/ kubernetes-xenial main
# deb-src http://apt.kubernetes.io/ kubernetes-xenial main
EOF
Agora que temos o repositório do kubernetes instalado, podemos instalar o kubernetes nos sistemas. Para tal corremos os seguintes comandos:
apt update
apt install kubelet kubeadm kubectl -y
apt-mark hold kubelet kubeadm kubectl
Podemos verificar a versão do software instalado, com o seguinte comando:
kubectl version --client && kubeadm version
Que nos irá dar as versões quer do cliente quer do admin.
Client Version: v1.28.2
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
kubeadm version: &version.Info{Major:"1", Minor:"28", GitVersion:"v1.28.2", GitCommit:"89a4ea3e1e4ddd7f7572286090359983e0387b2f", GitTreeState:"clean", BuildDate:"2023-09-13T09:34:32Z", GoVersion:"go1.20.8", Compiler:"gc", Platform:"linux/amd64"}
Neste momento temos o Kubernetes instalado em todas as máquinas do Cluster.
Inicializar o Master Plane
Estes passos destina se apenas à máquina “kube-master”, que será o Master Plane do nosso Cluster Kubernetes.
Descarregar as imagens
Para descarregar as imagens por defeito do Kubernetes, corremos o seguinte comando:
kubeadm config images pull
Inicializar o Master Plane
Para inicializar o Master Plane, corremos o seguinte comando:
kubeadm init --pod-network-cidr=10.244.0.0/16
Este comando demora um pouco, é normal pois ele tem de descarregar e configurar imagens inicialmente. O que dependendo dos recursos das vossas máquinas pode demorar mais ou menos tempo.
Após o comando correr irá nos dar o seguinte resultado, no vosso o token é diferente, no entanto idêntico.
[init] Using Kubernetes version: v1.28.2
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kube-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.16.178]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [kube-master localhost] and IPs [192.168.16.178 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [kube-master localhost] and IPs [192.168.16.178 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 5.503585 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node kube-master as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node kube-master as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: d6aq33.kiwe5cwy3k6g12as
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[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
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
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.16.178:6443 --token d6aq33.kiwe5cwy3k6g12as \
--discovery-token-ca-cert-hash sha256:1cc8f8f5f3d588167a390c063bdc74733b47816daf46981d89287389262081df
Copiar a configuração
Eu mesmo utilizando o utilizador root vou copiar a configuração para a pasta root, para evitar modificar por lapso este ficheiro. Pois se acontecer algo a este ficheiro, posso copia lo novamente mais tarde.
Para tal corro os seguintes comandos:
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
Verificar o nosso Cluster
Para listar tudo o que está no nosso Cluster, em todos os namespaces corremos o seguinte comando:
kubectl get all --all-namespaces
Que nos dará o seguinte resultado:
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod/coredns-5dd5756b68-7hs5c 0/1 Pending 0 10m
kube-system pod/coredns-5dd5756b68-8w64b 0/1 Pending 0 10m
kube-system pod/etcd-kube-master 1/1 Running 1 10m
kube-system pod/kube-apiserver-kube-master 1/1 Running 1 10m
kube-system pod/kube-controller-manager-kube-master 1/1 Running 1 10m
kube-system pod/kube-proxy-jtjsg 1/1 Running 0 10m
kube-system pod/kube-scheduler-kube-master 1/1 Running 1 10m
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10m
kube-system service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 10m
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-system daemonset.apps/kube-proxy 1 1 1 1 1 kubernetes.io/os=linux 10m
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
kube-system deployment.apps/coredns 0/2 2 0 10m
NAMESPACE NAME DESIRED CURRENT READY AGE
kube-system replicaset.apps/coredns-5dd5756b68 2 2 0 10m
Instalar e configurar o Network plugin
Eu vou usar como plugin de network o Flannel network plugin.
No entanto existem outros que podem ser mais adequados aos vossos projetos:
Aplicar o manifesto do Plugin
Para aplicar o manifesto usamos o seguinte comando:
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Verificar o plugin
Devemos verificar se o plugin está a correr, para tal corremos o seguinte comando:
kubectl get pods -n kube-flannel
Deverá mostrar um resultado idêntico ao seguinte:
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-c25tk 1/1 Running 0 108s
Já temos o plugin flannel instalado e configurado para controlar a rede no Cluster.
Verificar se o Master Plane está pronto
Para verificar corremos o seguinte comando:
kubectl get nodes -o wide
Que nos irá dar um resultado idêntico ao seguinte, mostrando o estado com “Ready”:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
kube-master Ready control-plane 11m v1.28.2 192.168.16.178 <none> Debian GNU/Linux 12 (bookworm) 6.1.0-12-amd64 containerd://1.6.24
Adicionar Worker Nodes ao Cluster
Agora, iremos juntar os nossos Worker Nodes ao Cluster. Para isso, necessitamos de correr o comando fornecido quando inicializamos o master.
Este passo, é para ser executado apenas no kube-node1 e kube-node2.
Corremos o seguinte comando nos dois Worker Nodes:
kubeadm join 192.168.16.178:6443 --token d6aq33.kiwe5cwy3k6g12as \
--discovery-token-ca-cert-hash sha256:1cc8f8f5f3d588167a390c063bdc74733b47816daf46981d89287389262081df
Este comando pode demorar um pouco, mas retornará uma mensagem idêntica à seguinte:
[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.
Agora temos os nossos Worker Nodes adicionados no Cluster, para podermos verificar, no kube-master corremos o seguinte comando:
kubectl get nodes -o wide
Este comando deverá retornar algo idêntico ao seguinte:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
kube-master Ready control-plane 38m v1.28.2 192.168.16.178 <none> Debian GNU/Linux 12 (bookworm) 6.1.0-12-amd64 containerd://1.6.24
kube-node1 Ready <none> 11m v1.28.2 192.168.16.207 <none> Debian GNU/Linux 12 (bookworm) 6.1.0-12-amd64 containerd://1.6.24
kube-node2 Ready <none> 10m v1.28.2 192.168.16.203 <none> Debian GNU/Linux 12 (bookworm) 6.1.0-12-amd64 containerd://1.6.24
O importante neste momento é o “STATUS” de cada node, tem de ficar com “Ready”, isto pode levar algum tempo. Se não aparecer com “Ready”, aguardem uns minutos e corram o comando novamente.
Testar o Cluster
Para testarmos o funcionamento, fazemos o deploy de uma simples aplicação, a fim de perceber se o Cluster é capaz de realizar. Para isso corremos o seguinte comando:
kubectl apply -f https://k8s.io/examples/pods/commands.yaml
Para verificar Corremos o seguinte comando:
kubectl get pods
O comando deve retornar um resultado idêntico ao seguinte:
NAME READY STATUS RESTARTS AGE
command-demo 0/1 Completed 0 24s
O importante no resultado é o “STATUS” estar “Completed”
Conclusão
A instalação de um cluster Kubernetes é possível e relativamente simples, desde que siga os passos corretos. Com o Kubernetes configurado e em funcionamento, pode começar a implementar e gerir aplicações em contentores de forma escalável e eficaz.
Lembre-se de que a configuração do Kubernetes é uma etapa crítica, e a segurança é uma preocupação importante. Certifique-se de seguir as melhores práticas de segurança e manter o seu cluster atualizado para evitar vulnerabilidades.
Este tutorial forneceu uma visão geral dos passos envolvidos na configuração de um cluster Kubernetes básico. Para cenários de produção ou configurações mais complexas, poderá ser necessário efetuar ajustes adicionais e personalizações. Consulte a documentação oficial do Kubernetes e outros recursos disponíveis para obter informações mais detalhadas sobre como configurar e gerir o seu cluster.