Validando uma ideia com o MicroK8s

Dia a dia

Num dia normal de trabalho de um Sysadmin/DevOps/SRE eles/elas realizam tarefas de suporte, manutenção, atualização e monitoração de sistemas, respondem chamados de incidentes, acompanha o canal do #Slack, responder no grupo de whatsapp entre muitas outras atividades, também faz parte de suas atribuições realizar Provas de Conceitos as famosas (POC).

Conhece aquela expressão “Works on my machine!”? Para quem não conhece ela pode ser explicada com a seguinte cena pode ter ocorrido em qualquer empresa desse nosso país :). O desenvolvedor teve uma brilhante ideia, codifica essa ideia e chega para a equipe de suporte/implantação e fala assim:

Desenvolvedor: - Tive uma ideia nova para o produto, já codifiquei e esse binário tá funcionando na minha máquina pode subir para produção? 

Suporte/Implantação: - Você tem certeza que está funcionando? Você testou? Estou perguntando só pra garantir, sabe como é né?!

Desenvolvedor: Sim!! Sim!! Testei na minha máquina e tá funcionando perfeito! Pode instalar! Vai com fé!!

Não é preciso dizer mais nada né? Já dá para imaginar o resultado dessa história. Situações como essa e muitas outras foram os gatilhos para adoção da cultura DevOps em muitos lugares.

Se analisarmos por um outro ângulo o Desenvolvedor e o “Works on my machine” não são os vilões dessa história. O “Works on my machine” traz um ponto importante, que é o ímpeto e a vontade de fazer o mais rápido possível, fazer a ideia sair da mente e ter o código instalado em Produção se materializando na saída de um GET ou de um POST. Esse ímpeto deve ser cultivado e não penalizado por que quebrou a Produção. Para tirar proveito dessa situação a saída é mudar o processo para proporcionar um “Works on my machine” “tunadão” à prova de erros sem deixar de validar uma ideia.

Conhecendo o MicroK8s e tal da POC

Validar uma ideia numa infraestrutura baseada em Kubernetes nunca deve ser testada no cluster de Produção, como alternativa as equipes de infraestrutura e de desenvolvimento podem utilizar o [MicroK8s] (https://microk8s.io) como ferramenta para simular o seu ambiente de produtivo. O [MicroK8s] (https://microk8s.io) tem como proposta principal ser o Kubernetes mais fácil de ser instalado, consumindo uma quantidade mínima de 4GB RAM e 20GB de espaço em disco.

Vamos ver se isso funciona mesmo! Os passos de instalação podem ser encontrados na [documentação oficial] (https://microk8s.io/docs), esse passos foram automatizados em um [Vagrantfile](LINK GITHUB) que cria duas máquinas virtuais e em um playbook do [Ansible](LINK GITHUB) para fazer uma instalção básica, o cenário de testes ficou assim:

HOST SO MEMÓRIA IP SSH ID SSH PORT
iac-microk8s-m bento/ubuntu-20.04 4096 10.10.100.200 iack8s 2270
iac-microk8s-w bento/ubuntu-20.04 2048 10.10.100.201 iack8s 2271

Criando o ambiente Kubernetes com o Microk8s

O ponto de partida é um Vagrantfile com todas especificações do ambiente Vagrantfile e um Ansibile Playbook com algumas poucas rotinas para fazer um setup básico

Vagrantfile

 1  # -*- mode: ruby -*-
 2# vi: set ft=ruby :
 3
 4vhosts =[
 5 { :hostname => "iac-microk8s-m",
 6  :fssh_port => "2270",
 7  :fweb_port => "8070",
 8  :box => "bento/ubuntu-20.04",
 9  :ip =>"10.10.100.200",
10  :profile => "microk8",
11  :memory => "4096"},
12  { :hostname => "iac-microk8s-w",
13  :fssh_port => "2271",
14  :fweb_port => "8071",
15  :box => "bento/ubuntu-20.04",
16  :ip =>"10.10.100.201",
17  :profile => "microk8",
18  :memory => "2048"},
19]
20
21Vagrant.configure("2") do |config|
22
23 vhosts.each do |vhost|
24
25  config.vm.define vhost[:hostname] do |node|
26   node.vm.box = vhost[:box]
27   node.vm.hostname = vhost[:hostname]
28   node.vm.box_url = vhost[:box]
29   node.vm.boot_timeout = 3600
30   node.vm.network :private_network, ip: vhost[:ip], virtualbox__intnet: true
31   node.vm.network :forwarded_port, id:"microk8 01", guest:22, host: vhost[:fssh_port], host_ip: "127.0.0.1", auto_correct: true
32   node.vm.network :forwarded_port, id:"microk8 02", guest:80, host: vhost[:fweb_port], host_ip: "127.0.0.1", auto_correct: true
33
34   node.vm.provider :virtualbox do |v|
35    v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
36    v.customize ["modifyvm", :id, "--memory", vhost[:memory]]
37    v.customize ["modifyvm", :id, "--name", vhost[:hostname]]
38    v.customize ["modifyvm", :id, "--cpus", 2]
39   end
40   node.vm.provision :shell, inline: "sudo apt-get update ; sudo apt-get install python3-pip -y; sudo pip3 install ansible"
41   node.vm.provision :shell, inline: "sudo ansible-playbook -i localhost /vagrant/playbook.yaml"
42  end
43 end
44
45end

Ansible playbook

 1---
 2- hosts: localhost,all
 3 remote_user: vagrant
 4 become: true
 5 vars:
 6  iac_user: "iack8s"
 7  k8s_user_homedir: "/home/iack8s"
 8
 9  hosts_list:
10   - "10.10.100.200  iac-microk8s-m"
11   - "10.10.100.201  iac-microk8s-w"
12
13 tasks:
14
15 - name: Configura /etc/hosts
16  lineinfile:
17   dest: /etc/hosts
18   state: present
19   line: "{{ item }}"
20  with_items:
21   - "{{ hosts_list }}"
22
23 - name: Remove swapfile from /etc/fstab
24  mount:
25   name: "{{ item }}"
26   fstype: swap
27   state: absent
28  with_items:
29    - swap
30    - none
31
32 - name: Install basic packages
33  snap:
34   name: "microk8s"
35   state: present
36   classic: yes
37   channel: 1.18/stable
38
39 - name: Disable swap
40  command: swapoff -a
41  when: ansible_swaptotal_mb > 0
42
43 - name: "Add user management {{ iac_user }}"
44  user:
45   name: '{{ iac_user }}'
46   password: $6$WpA1Fzrw/OTU$V5uXr0Zf1dVV44g5wDySvKxdlktXveuqYSudh1ykUQmj6E3HX7BNi9cD4Rz4wCm/Fi6jcZmG.nJcDsQwnV6qp1
47   shell: '/bin/bash'
48   state: 'present'
49   groups: 'microk8s'
50
51 - name: Create a directory if it does not exist
52  file:
53   path: "{{ k8s_user_homedir }}/.kube"
54   state: directory
55   mode: '0750'
56   owner: "{{ iac_user }}"
57   group: "{{ iac_user }}"
58
59 - name: Adding featureflag into /etc/sudoers
60  lineinfile:
61   dest: '/etc/sudoers.d/99_{{ item }}'
62   regexp: '^{{ item }}'
63   line: '{{ item }} ALL=(ALL:ALL) NOPASSWD: ALL'
64   create: yes
65  with_items:
66   - "{{ iac_user }}"
67
68#EOF

Logando no master

Para facilitar o login e senha estão definidos como “iack8s”.

ssh iack8s@localhost -p 2270 

Verificando a saúde do Kubernetes

Não se surpreenda, o Kubernetes já está instalado!!! Na primeira vez que testei eu pensei “é sério que é só isso!?”. Se você não acredita então vamos ver para crer!!

iack8s@iac-microk8s-m:~$ microk8s status --wait-ready
microk8s is running
addons:
cilium: disabled
dashboard: disabled
dns: disabled
fluentd: disabled
gpu: disabled
helm: disabled
helm3: disabled
ingress: disabled
istio: disabled
jaeger: disabled
knative: disabled
kubeflow: disabled
linkerd: disabled
metallb: disabled
metrics-server: disabled
prometheus: disabled
rbac: disabled
registry: disabled
storage: disabled

Criando um namespace

iack8s@iac-microk8s-m:~$ microk8s.kubectl create ns iac
namespace/iac created
iack8s@iac-microk8s-m:~$ microk8s.kubectl get ns
NAME       STATUS  AGE
default      Active  41m
iac        Active  10s
kube-node-lease  Active  41m
kube-public    Active  41m
kube-system    Active  41m

Criando um pod

iack8s@iac-microk8s-m:~$ microk8s.kubectl run pod-iac --image=nginx --restart=Never --port=80 --dry-run=client -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod-iac
name: pod-iac
spec:
containers:
- image: nginx
name: pod-iac
 ports:
	- containerPort: 80
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Never
status: {}

iack8s@iac-microk8s-m:~$ microk8s.kubectl run pod-iac --image=nginx --restart=Never --port=80 --dry-run=client -o yaml >pod-iac.yaml
iack8s@iac-microk8s-m:~$ microk8s.kubectl apply -f yaml -n iac

iack8s@iac-microk8s-m:~$ microk8s.kubectl get pods  -n iac
NAME   READY  STATUS       RESTARTS  AGE
pod-iac  0/1   ContainerCreating  0     14s

Referência: Pod-iac

Criando um deployment

iack8s@iac-microk8s-m:~$ microk8s.kubectl create deployment deploy-iac --image=nginx  --dry-run=client -o yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
	app: deploy-iac
name: deploy-iac
	spec:
replicas: 1
selector:
	matchLabels:
	app: deploy-iac
strategy: {}
template:
	metadata:
	creationTimestamp: null
	labels:
		app: deploy-iac
	spec:
	containers:
	- image: nginx
		name: nginx
		resources: {}
	status: {}

iack8s@iac-microk8s-m:~$ microk8s.kubectl create deployment deploy-iac --image=nginx  --dry-run=client -o yaml >deploy-iac.yaml

iack8s@iac-microk8s-m:~$ microk8s.kubectl apply -f deploy-iac.yaml -n iac
deployment.apps/deploy-iac created

iack8s@iac-microk8s-m:~$ microk8s.kubectl get deploy -n iac
NAME     READY  UP-TO-DATE  AVAILABLE  AGE
deploy-iac  1/1   1      1      32s

iack8s@iac-microk8s-m:~$ microk8s.kubectl get pod -n iac
NAME             READY  STATUS  RESTARTS  AGE
deploy-iac-76df8948fb-8jwnj  1/1   Running  0     39s
pod-iac            1/1   Running  0     2m18s

Referência: deployment-iac

Adicionando mais um nó

iack8s@iac-microk8s-m:~$ microk8s kubectl get no
NAME       STATUS  ROLES  AGE  VERSION
iac-microk8s-m  Ready  <none>  74m  v1.18.8
iack8s@iac-microk8s-m:~$

iack8s@iac-microk8s-m:~$ microk8s add-node
Join node with: microk8s join 10.0.2.15:25000/WLQuGldxsaUlUGbLUBtccbtAULqCTqYX

If the node you are adding is not reachable through the default interface you can use one of the following:
microk8s join 10.0.2.15:25000/WLQuGldxsaUlUGbLUBtccbtAULqCTqYX
microk8s join 10.10.100.200:25000/WLQuGldxsaUlUGbLUBtccbtAULqCTqYX
microk8s join 10.1.62.0:25000/WLQuGldxsaUlUGbLUBtccbtAULqCTqYX

Após gerar os comando de join, é necessário logar no servidor iac-microk8s-w e executar o seguinte comando:

iack8s@iac-microk8s-m:~$ ssh iack8s@iac-microk8s-w
iack8s@iac-microk8s-w: microk8s join 10.10.100.200:25000/WLQuGldxsaUlUGbLUBtccbtAULqCTqYX

O resultado esperado dever ser semelhante a seguinte saída:

iack8s@iac-microk8s-m:~$ microk8s kubectl get no
NAME       STATUS  ROLES  AGE  VERSION
iac-microk8s-m  Ready  <none>  74m  v1.18.8
iac-microk8s-w  Ready  <none>  19s  v1.18.8
iack8s@iac-microk8s-m:~$

Conclusão

Para uma ambiente pequeno e local o [MicroK8s] (https://microk8s.io/docs) mostrou ser a forma mais simples de instalação do Kubernetes que eu já testei até o momento, é realmente muito fácil de instalar, após a VM subir já está pronto. Montar um cluster é outra atividade bem simples de realizar conforme foi visto ao adicionar um novo nó ao cluster. Além de fácil de instalar é muito simples criar Pods, deployment e outros objetos dentro do Kubernetes.

Depois de realizar esses testes é possível afirmar o grande valor ter o [MicroK8s] (https://microk8s.io) instalado em seu laptop e dar a possibilidade de qualquer membro da equipe validar uma ideia, um deploy de uma nova APP ou uma nova configuração que possa afetar o funcionamento do cluster. Assim quem sabe expressão “Works on my machine!” ganha mais credibilidade na sua empresa ;) ;).

Por fim, é claro que em um único post não dá para explorar todas as funcionalidades de [MicroK8s] (https://microk8s.io), esse post serve apenas para chamar sua atenção para essa ferramenta e dispertar a sua curiosidade para explorar um pouco as configurações mais avançadas!!!

Boa Sorte!!

Referências


Eu adoraria ouvir suas outras histórias e situações semelhantes ao que acabei de escrever neste post, você pode me encontrar em @infraascode_br ou linkedin.com/in/leonardoml/ .

Te convido a ver os outros posts do blog Infra-as-Code garanto que tem coisas legais lá!!


--- --- IMPORTANTE --- ---
As opiniões aqui expressas são pessoais e de responsabilidade única e exclusiva do autor, elas não refletem necessariamente a posição das empresas que eu trabalho(ei) e/ou presto(ei) serviço.