# Como Configurar um Cluster Kubernetes Usando Kubespray

Se você ainda não sabe o que é o Kubernetes, então acesse o artigo que foi preparado para dar esse embasamento inicial. [O que é Kubernetes](https://nilsonvieira.com.br/o-que-e-kubernetes).

Esta é uma receita de bolo sobre como instalar o Kubernetes (k8s) usando Kubespray. Este *how-to* mostrará como instalar o Kubernetes Cluster usando Kubespray em ambientes Linux.

# O que é o Kubespray

É uma ferramenta gratuita e de código aberto que fornece *playbooks* ansible para implantar e gerenciar clusters Kubernetes. Ele foi projetado para simplificar o processo de instalação de clusters Kubernetes em vários nós, permitindo que os usuários implantem e gerenciem um cluster Kubernetes prontos para produção de forma rápida e fácil.

## Sistemas Operacionais suportados

Ele suporta uma variedade de sistemas operacionais, incluindo Ubuntu, CentOS, Rocky Linux e Red Hat Enterprise Linux, e pode implantar o Kubernetes em uma variedade de plataformas, incluindo bare metal, nuvem pública e nuvem privada.

Para este How-to usaremos o seguinte laboratório:

Máquina Física:

Notebook Acer Nitro 32GB RAM, Intel Core i7 (12 Threads), 1TB SSD com Linux PopOS! 22.04 LTS.

Essa máquina será o Ansible Host (Kubespray).

Devemos contar com 5 VMs que serão criadas através de VagrantFile usando VirtualBox que deverão possuir os IPs 192.168.50.11 ao 15 com Sistema Operacional Ubuntu 22.04. Todas devem ser 2x2, ou seja, 2CPU e 2GB RAM.

Dentro do Kubespray vamos organizar o Cluster para ficar dividido da seguinte forma:

* 3 Masters: Nodes 01 ao 03
    
* 3 ETCDs: Nodes 01 ao 03
    
* 5 Nodes: Nodes 01 ao 05
    

# Configurando o Cluster Kubernetes

## Preparação do Ansible Host (Notebook)

Vamos criar uma pasta para organizar toda a estrutura:

No meu caso estou criando dentro da minha pasta Documentos.

```bash
$ mkdir -p /home/nilson/Documentos/lab-k8s/
```

Com os repositórios criados vamos agora preparar a máquina host. Atualizando pacotes e instalando as dependências necessárias.

```bash
$ sudo apt update
$ sudo apt install git python3 python3-pip -y
$ git clone https://github.com/kubernetes-sigs/kubespray.git
$ cd kubespray
$ pip install -r requirements
```

Após isso verifique a versão do Ansible com o comando `ansible --version` . A saída deve ser parecida com a seguinte:

```plaintext
ansible [core 2.14.10]
  config file = None
  configured module search path = ['/home/nilson/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/nilson/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/nilson/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/nilson/.local/bin/ansible
  python version = 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True
```

## Preparação do Kubespray

Vamos agora preparar o ambiente do kubespray, copiando o diretório sample para outro, no meu caso usei mycluster, para trabalhar nele e realizar os ajustes necessários.

Seguindo ainda a documentação do próprio kubespray vamos declarar os IPs adicionando-os em uma variável para em seguida usar um script python para gerar o arquivo hosts.yaml que será a base estrutural do nosso ambiente.

```bash
$ cp -rfp inventory/sample inventory/mycluster
$ declare -a IPS=(192.168.50.11 192.168.50.12 192.168.50.13 192.168.50.14 192.168.50.15)
$ CONFIG_FILE=inventory/mycluster/hosts.yaml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
```

Feito isso, vamos modificar e deixar de acordo como planejamos acima:

```bash
$ vi inventory/mycluster/hosts.yaml
```

O arquivo deve ficar assim:

```yaml
all:
  hosts:
    k8s-node-1:
      ansible_host: 192.168.50.11
      ip: 192.168.50.11
      access_ip: 192.168.50.11
    k8s-node-2:
      ansible_host: 192.168.50.12
      ip: 192.168.50.12
      access_ip: 192.168.50.12
    k8s-node-3:
      ansible_host: 192.168.50.13
      ip: 192.168.50.13
      access_ip: 192.168.50.13
    k8s-node-4:
      ansible_host: 192.168.50.14
      ip: 192.168.50.14
      access_ip: 192.168.50.14
    k8s-node-5:
      ansible_host: 192.168.50.15
      ip: 192.168.50.15
      access_ip: 192.168.50.15
  children:
    kube_control_plane:
      hosts:
        k8s-node-1:
        k8s-node-2:
        k8s-node-3:
    kube_node:
      hosts:
        k8s-node-1:
        k8s-node-2:
        k8s-node-3:
        k8s-node-4:
        k8s-node-5:
    etcd:
      hosts:
        k8s-node-1:
        k8s-node-2:
        k8s-node-3:
    k8s_cluster:
      children:
        kube_control_plane:
        kube_node:
    calico_rr:
      hosts: {}
  vars:
      ansible_ssh_private_key_file: ~/.ssh/id_rsa
```

O arquivo de chave deve ser o par da chave ssh que será enviada às VMs Hosts através do VagrantFile.

Observe também a disposição dos nodes, se ficou como definimos mais acima. Segue novamente:

* 3 Masters: Nodes 01 ao 03
    
* 3 ETCDs: Nodes 01 ao 03
    
* 5 Nodes: Nodes 01 ao 05
    

Eu gosto de trabalhar com Balanceador Externo, então temos que habilitar o mesmo dentro do arquivo `/inventory/mycluster/group_vars/all/all.yml` deixando assim:

```yaml
loadbalancer_apiserver:
  address: 192.168.1.12
  port: 6443
```

Node que o IP 192.168.1.12 é o IP da máquina HOST ANSIBLE, no nosso caso o Notebook.

Pronto, parte do kubespray configurada, agora vamos para o Balanceador.

## Configurando e Iniciando o Balanceador Externo

O balanceador deve estar configurado e UP antes do playbook rodar, pois ele é uma dependência conforme configuramos no kubespray.

No nosso caso como balanceador, vamos usar o haproxy conteinerizado. Vamos aos passos:

Primeiramente vamos criar um diretório para deixar mais organizado. Entao sairemos da pasta do kubespray e criamos a do Haproxy:

```bash
$ cd ../ 
$ mkdir haproxy
cd haproxy
```

Feito isso vamos criar um arquivo de configuração chamado `haproxy.cfg`.

```plaintext
global
        log /dev/log    local0
        log /dev/log    local1 notice
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

defaults
        log     global
        timeout connect 5s  
        timeout client  50s  
        timeout server  50s  

listen stats
        bind *:81
        mode http
        stats enable
        stats refresh 30s
        stats uri /stats
        stats hide-version
        stats auth admin:admin

listen kubernetes-apiserver
        bind *:6443
        mode tcp
        option log-health-checks
        timeout client 300s
        timeout server 300s
        balance roundrobin
        server k8s-master-01 192.168.50.11:6443 check check-ssl verify none
        server k8s-master-02 192.168.50.12:6443 check check-ssl verify none
        server k8s-master-03 192.168.50.13:6443 check check-ssl verify none 
```

Feito isso saímos do diretório e criamos o compose.

```bash
$ cd ../
$ touch docker-compose.yaml
```

Dentro do arquivo deve conter:

```yaml
version: "3.9"
services:
  haproxy:
    container_name: haproxy
    image: haproxy:2.8.3
    volumes:
      - ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
    ports:
      - "81:81"
      - "8081:8081"
      - "6443:6443"
```

Ao finalizar vamos iniciar o container:

```bash
$ docker compose up -d
```

Após isso para validar acesse `http://localhost:81/stats` e use usuário e senha `admin`.

Deve aparecer algo assim:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1696340146823/13dcc5e3-081b-46e4-94e8-29244218a2a3.png align="center")

## Configurando o Vagrant e Subindo as VMs

Configurado o Balanceador Externo, vamos agora trabalhar nas máquinas virtuais. Vamos criar um arquivo nomeado Vagrantfile.

```bash
$ touch Vagrantfile
```

Dentro dele adicionamos o seguinte:

```ruby
IMAGE_NAME = "bento/ubuntu-22.04"
NODES = 5
NET_IP="192.168.50."
INIT_IP=1

Vagrant.configure(2) do |config|
        config.vm.provision "file", source: "./.ssh/id_rsa.pub", destination: "~/.ssh/me.pub"
        config.vm.provision "shell", env:{"NET_IP" => NET_IP, "INIT_IP" => INIT_IP}, inline: <<-SCRIPT
        apt-get update -y && apt install -y vim net-tools telnet git nfs-common
        cat /home/vagrant/.ssh/me.pub >> /home/vagrant/.ssh/authorized_keys
        SCRIPT

    config.vm.box = IMAGE_NAME
    config.vm.box_check_update = true

    (1..NODES).each do |i|
        config.vm.define "node-#{i}" do |node|
            node.vm.hostname = "k8s-node-#{i}"
            node.vm.network "private_network", ip: NET_IP + "#{i + 10}"
            node.vm.provider "virtualbox" do |vb|
                vb.name = "k8s-node-#{i}"
                vb.memory = 2048
                vb.cpus = 2
            end
        end
    end
end
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Antes de executar lembre-se de criar uma pasta <code>.ssh</code> e copie a sua chave pública para dentro</div>
</div>

Para rodar basta executar:

```bash
vagrant up
```

Pronto! Agora vamos configurar nosso cluster Kubernetes.

## Executando o Playbook

Antes de tudo recomendo deixar a chave salva no *bash* pra evitar que fique solicitando autorização e digitação da senha a todo momento.

```bash
eval `ssh-agent`
ssh-add
```

Pronto! Podemos rodar o playbook.

```bash
$ cd kubespray
$ ansible-playbook -i inventory/mycluster/hosts.yaml -u vagrant --become --become-user=root cluster.yml
```

Ao final, sem erros você pode copiar o texto do arquivo `/etc/kubernetes/admin.conf` de dentro de uma das VMS Master (nodes 01 ao 03) e colar em um Gerenciador como o Lens, por exemplo.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1696341137746/f781e504-2351-47a3-a9ea-aa2c6f5b5b4a.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1696341150865/27661eed-2be2-4266-866a-85bba2abd633.png align="center")

Cluster ponto para uso! :)

# Referências

KUBESPRAY. **Kubernetes Sigs:** Kubespray: Disponível em: &lt;[kubernetes-sigs/kubespray: Deploy a Production Ready Kubernetes Cluster (](https://github.com/kubernetes-sigs/kubespray)[github.com](http://github.com)[)](https://github.com/kubernetes-sigs/kubespray)\&gt;. Acessado em: &lt;02/10/2023&gt;
