#K8S01: Criando Cluster Kubernetes para Fins Didáticos
Tags: kubernetes, devops, sre, microservices
Published: 2021-12-11 21:01:00

## Introdução

O Kubernetes é um sistema de orquestração de contêineres que automatiza a implantação, o dimensionamento e a gestão de aplicações. Por esses e outros motivos, se tornou uma referência no mercado.

Empresas dos mais variados tamanhos estão empregando o Kubernetes para implantar as suas aplicações na nuvem. Além disso, a academia também está utilizando o Kubernetes no desenvolvimento de novas aplicações. Sendo assim, é fundamental conhecer essa ferramenta nos dias de hoje.

No presente tutorial é descrito como instalar e configurar um cluster Kubernetes com três `Nodes` (um _master_ e dois _workers_) utilizando o Virtualbox. Cada um desses `Nodes` será uma máquina virtual criada através do Virtualbox e rodando o sistema operacional Ubuntu Server 22.04.

Obs.: Esse cluster deve ser utilizado apenas para fins didáticos.

## Criando e Configurando as Máquinas Virtuais

Em primeiro lugar, para seguir esse tutorial é necessário a criação de 3 máquinas virtuais com as características descritas na tabela abaixo:

| host        | user | ip            | cpus | RAM | configuração de rede |
|-------------|------|---------------|------|-----|----------------------|
| k8s_01.contro_plane.net  | k8s  | 192.168.0.100 | 2    | 2   | placa em modo bridge |
| k8s_02.worker_01.net | k8s  | 192.168.0.101 | 2    | 2   | placa em modo bridge |
| k8s_03.worker_03.net | k8s  | 192.168.0.102 | 2    | 2   | placa em modo bridge |

Em todas as máquinas é recomendada a instalação do Ubuntu Server 22.04. Quanto aos recursos relacionados ao hardware, a quantidade de cpu e memória RAM definidas seguem as recomendações mínimas. Além disso, foi definido 20 GB de capacidade de armazenamento para cada nó.

Após a instalação do Ubuntu Server 22.04, altere as configurações de rede (tipo de adaptador) de cada uma das máquinas para o modo bridge. A ideia aqui é que você seja capaz de acessar via ssh os nós do seu cluster por qualquer dispositivo conectado na sua rede local.

Dica: Para acelerar a instalação, crie uma máquina virtual e instale o Ubuntu. Após terminar a instalação faça duas cópias dessa máquina (na opção de cópia selecione a opção de gerar um novo endereço MAC) e as utilize como nós _worker_. Para deixar tudo organizado, mude o nome das máquinas clonadas editando o arquivo `\etc\hostname` como no exemplo abaixo:

```bash
k8s_01.control_plane.net
#Faça isso em todos os nós
```

Além disso, configure a resolução de nome entre os `Nodes` do seu cluster adicionando o nome e o ip das máquinas no arquivo `/etc/hosts`, veja o exemplo abaixo:

```bash
127.0.0.1 localhost
127.0.1.1 ubuntu

#Inicio do conteúdo adicionado
192.168.0.100   k8s_01.control_plane.net k8s_01
192.168.0.101   k8s_02.worker_01.net k8s_02
192.168.0.102   k8s_03.worker_02.net k8s_03
#fim do conteúdo adicionado

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
```

Para evitar problemas de mudança de `ip` dos `Nodes` do cluster (coisa que pode acontecer caso seja o endereçamento seja configurado via DHCP), na configuração de rede defina `ips` estáticos. Essa configuração deve ser realizada via [netplan](https://netplan.io/examples/). A configuração é simples, por exemplo, considerando a rede local 192.168.0.0, máscara de sub-rede 255.255.255.0 (/24) e gateway 192.168.0.1 o conteúdo do arquivo referente ao netplan deve conter o seguinte conteúdo:

```yml
network:
  ethernets:
    enp0s3:
      addresses:
         - 192.168.0.100/24
      nameservers:
        addresses: [1.1.1.1, 8.8.8.8]
      routes:
        - to: default
          via: 192.168.0.1
  version: 2
```

Os demais `Nodes` podem ser configurados de forma semelhante, alterando apenas o campo referente ao `ip`. Caso seja necessário, consulte os exemplos do [netplan](https://netplan.io/examples/).

Após realizar a configuração de rede verifique se todos os `Nodes`:
- estão respondendo no endereço `ip` configurado;
- possuem acesso a rede para baixar todos os pacotes necessários.

Se os seus `Nodes` passaram nessa verificação chegou o momento de iniciarmos a instalação do Kubernetes.

## Instalando o Kubernetes 

A instalação é relativamente simples, atualize o seu sistema com os comandos abaixo e siga cada um dos passos descritos a seguir:

```shell
sudo apt update
sudo apt upgrade -y
```

### Passo 1: Desative o `swap` e adicione as configurações de kernel necessárias:

:warning: **Esse passo deve ser realizado em todos os Nodes.**

```shell
#Desativando o swap
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
```

Agora vamos carregar os módulos do kernel necessários em todos nos `Nodes`:

```shell
sudo tee /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
```

Após carregar os módulos, vamos configurar parâmetros do Kernel para o Kubernetes:

```shell
sudo 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 finalizar, execute o comando abaixo para que as modificações tenham efeito:

```shell
sudo sysctl --system
```

### Passo 2: Instalando e configurando o containerd runtime

:warning: **Esse passo deve ser realizado em todos os Nodes.**

Execute o comando abaixo para instalar as dependências:

```shell
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates
```

Ative o repositório do Docker:

```shell
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
```

Agora podemos instalar o **containerd**:

```shell
sudo apt update
sudo apt install -y containerd.io
```

Após a instalação, vamos configurar o **containerd** para que ele inicie usando o `systemd` como `cgroup`:

```shell
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml
```

Para finalizar esse passo, reinicie e ative o serviço do **continerd**:

```shell
sudo systemctl restart containerd
sudo systemctl enable containerd
```

### Passo 3: Adicionando o repositório apt do Kubernetes e instalando os componentes Kubectl, kubeadm e kubelet:

:warning: **Esse passo deve ser realizado em todos os Nodes.**

Faça Download da chave pública do Google:

```shell
sudo curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
```
Adicione o repositório apt do Kubernetes:

```shell
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
```

Download a Google Cloud public signing key:

```bash
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | \ 
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg
```

Atualize o apt:

```shell
sudo apt-get update
```

Agora podemos finalizar esse passo instalando os componentes:

```shell
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
```

### Passo 4: Configurando o control plane e obtendo informações importantes

:warning: **Esse passo deve ser realizado apenas no nó que será responsável pelo control plane.**

Para iniciar, entre no `Node` que será responsável pelo control plane (o principal `Node`) e execute o comando abaixo:

```shell
sudo kubeadm init
```

Exemplo de saída do comando se estiver tudo certo:

```shel
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.0.100:6443 --token jfri31.ofryjs5y52dqkqc3 \
        --discovery-token-ca-cert-hash sha256:c7a20a2be5c2adb091f9657166a416aaff60f7b89b9bfc68016c165c129112a1
```

Essa saída é muito importante, ela contém as informações para realizar a configuração que vai possibilitar o acesso, adição de nós e etc. Na Figura abaixo, foi destacado o que devemos observar com mais cuidado: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/047kje527r6fmfktjxla.PNG)

Logo, observando a figura será necessário executar o comando abaixo como usuário "normal" ou sem privilégios para gerenciar o seu novo cluster:

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

Após essa configuração, vamos adicionar os nós.

### Passo 5: Adicionando os nós _workers_ 

:warning: **Esse passo deve ser realizado nos Nodes que vão ser adicionados ao cluster.**

Na última figura foi apresentada a saída do comando `kubeadm init` onde foi indicado onde está o comando para adicionar um novo nó. Esse comando deve ser executado nos `Nodes` que vão ser adicionados ao cluster e é semelhante ao apresentado abaixo:

```shell
kubeadm join 192.168.0.100:6443 --token jfri31.ofryjs5y52dqkqc3 \
        --discovery-token-ca-cert-hash sha256:c7a20a2be5c2adb091f9657166a416aaff60f7b89b9bfc68016c165c129112a1
```

Obs.: Será necessário executar o comando com permissão de administrador (sudo) no Node _worker_ para adiciona-lo ao cluster!

Se tudo correu bem você verá uma mensagem de sucesso semelhante a apresentada abaixo:

```shell
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.
```

Pronto, agora podemos verificar o STATUS dos `Nodes` adicionados com o comando abaixo:

```shell
kubectl get nodes
```

A saída esperada para 3 `Nodes` vai ser semelhante a apresentada abaixo:

```shell
NAME                     STATUS     ROLES           AGE     VERSION
k8s01.controlplane.net   NotReady   control-plane   10m     v1.26.0
k8s02.worker01.net       NotReady   <none>          4m14s   v1.26.0
k8s03.worker02.net       NotReady   <none>          2m56s   v1.26.0
```

Analisando a saída, você provavelmente viu que tem algo errado, os `Nodes` do nosso cluster estão com o STATUS `NotReady`. Para que esses `Nodes` fiquem "prontos" ainda precisamos instalar e configurar um componente, a "rede" do Kubernetes. 

### Passo 6: Calico Pod Network Add-on:

:warning: **Esse passo deve ser realizado apenas no nó que será responsável pelo control plane.**

Existem várias opções de **pod network**, mas nesse tutorial vamos instalar o [Calico Pod Network](https://projectcalico.docs.tigera.io/getting-started/kubernetes/).

Para instalar o Calico execute os comandos abaixo no seu principal `Node`:

```shell
curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml -O
kubectl apply -f calico.yaml
```

Após a instalação, verifique o status dos pods no namespace kube-system com o comando `kubectl get pods -n kube-system`. Observe se os pods do Calico estão com o `STATUS` Running como na figura abaixo:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/itlpibkam7a6mxcq359h.PNG)

Após checar os pods, aguarde uns segundos e verifique se os `Nodes` do seu cluster estão com o status Ready como apresentado abaixo:

```shell
NAME                     STATUS   ROLES           AGE     VERSION
k8s01.controlplane.net   Ready    control-plane   3h11m   v1.26.0
k8s02.worker01.net       Ready    <none>          3h5m    v1.26.0
k8s03.worker02.net       Ready    <none>          3h3m    v1.26.0
```

Se sua saída for semelhante a apresentada acima, está tudo certo, já pode começar a quebradeira!

## Extra

Aqui no extra vou descrever de maneira breve como você pode criar o seu primeiro pod e trabalhar com mais de uma interface de rede (não recomendo).

### Criando nosso primeiro pod

É possível criar um pod de diversas maneiras, a minha preferida é escrevendo o arquivo de manifesto. Sendo assim, crie um arquivo com o nome `pod.yaml` contendo o conteúdo abaixo:

```yml
apiVersion: v1
kind: Pod
metadata:
  name: meu-pod
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
```

Após salvar o arquivo execute o comando `kubectl apply -f pod.yaml` para criar o pod.

Verifique se o pod está sendo executado com o comando `kubectl get po`. Caso esse pod estaja com o STATUS `Running` você acaba de criar o seu primeiro pod.

### Trabalhando com mais de uma interface de rede

Caso você tenha configurado mais de uma interface de rede, você pode verificar se o ip interno do nó do seu cluster corresponde ao ip da interface esperada com o seguinte comando:

```shell
kubectl describe node k8s_01 | grep InternalIP
```

Caso o endereço ip não corresponda ao da interface de rede escolhida, você pode ir até o arquivo localizado em /etc/systemd/system/kubelet.service.d/10-kubeadm.conf com o editor da sua preferência, procurar por KUBELET_CONFIG_ARGS e adicionar no final a instrução –node-ip=. O trecho alterado será semelhante abaixo:

```shell
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml --node-ip=192.168.0.101"
```

Salve o arquivo e execute os comandos abaixo para reiniciar a configuração e consequentemente o kubelet.

```shell
sudo systemctl daemon-reload
sudo systemctl restart kubelet
```

É isso, espero que esse conteúdo tenha sido útil para você, abraço :) 

## Referências

[Livro Descomplicando o Kubernetes](https://livro.descomplicandokubernetes.com.br/pt/)

[Curso Descomplicando o Kubernetes](https://www.linuxtips.io/products/descomplicando-o-kubernetes)

[O que é Kubernetes](https://www.redhat.com/pt-br/topics/containers/what-is-kubernetes)

[Orquestração de contêineres prontos para produção](https://kubernetes.io/pt-br/)

[How to Install Kubernetes Cluster on Ubuntu 22.04](https://www.linuxtechi.com/install-kubernetes-on-ubuntu-22-04/)

[Install Calico networking and network policy for on-premises deployments](https://docs.tigera.io/calico/latest/getting-started/kubernetes/self-managed-onprem/onpremises)