Usando o Kubernets pela primeira vez
Tags: todayilearned, braziliandevs, kubernetes, beginners
Published: 2022-06-17 00:16:56

Já subi uma aplicação para a AWS umas 3 vezes mas todas foram um processo muito manual usando o EC2, hoje pela primeira vez usei o kubernets para automatizar esse processo.

## Kubernets (K8s)

O kubernets é um orquestadror de containers que fica responsável por transformar esses containers em pods e subir esses containers de forma mais automatizada para uma cloud como AWS ou GCP ou outras opções, porem ele não faz só isso, ele também tem o load balancer onde ele tenta distribuir as cargas para não deixar um pod sobrecarregado e também toda a parte de service discovery além de levantar pods novos sempre que os antigos caírem

## Como usar o K8s
Primeiro vamos criar um arquivo do tipo yml

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

```

Nesse arquivo inicial temos:
`apiVersion`: Versão da api do k8s, nesse caso é a v1
`kind`: qual o tipo do recurso a ser criado, nesse caso um pod
`metadata`: dados complementares
- `name`: nome do pod
- `labels`: label do pod então podemos depois filtrar por pods com a label `ngnix` por exemplo
`spec`: especificação do serviço
- `containers`: qual o container dentro daquele pod com seu nome a sua imagem e a sua porta
> Existem casos de termos mais de um pod em um container porem como regra geral geralmente temos um pod por container

Com isso temos já um pod, para testar esse pod podemos usar o [kind](https://kind.sigs.k8s.io/) que serve para rodar o kubernets localmente, no próprio site do kind eles ensinam como instalar em diversos sistemas operacionais. Depois de instalado podemos rodar o comando 
`kind create cluster --name={algo}`

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

e entao o kind vai sugerir rodarmos o comando `kubectl cluster-info --context kind-{algo}` mas para isso vamos precisar do [kubectl](https://kubernetes.io/docs/tasks/tools/) depois de rodarmos o comando do kubectl conseguimos ver que o kubernets já está como ready

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

por padrão o kubernets tem o control-plane que gerencia tudo, e quem é gerenciado são as maquinas que ficam conectadas no control-plane. Para rodar um cluster kubernets é recomendado no minimo 3 maquinas

agora para conectar o pod precisamos rodar `kubectl apply -f {nome_do_yml}` e com o `kubectl get pods` ele vai retornar o pod rodando, e para conectar com o ngnix? temos que dar um port-forward com o comando `kubectl port-forward pod/nginx 9090:80` onde 80 é a porta que declaramos no yml e o 9090 é a porta que disponibilizei no meu computador, então se eu for no meu localhost 9090 vou encontrar o nginx

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32izewh4z854dnu4uo4m.png)
 
#### ReplicaSet

Porem o kubernets ainda não está mantendo o pod online todo o tempo, se rodarmos o comando `kubectl delete pod nginx` o pod vai ficar fora do ar. Para garantir que os pods estejam sempre online precisamos adicionar o Replica set, que fica gerenciando os pods e vendo se algum pod saiu do ar para ele criar um novo. 

O yml do replicaSet ficou assim: 
```yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      name: nginx
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
```

onde ele é do tipo ReplicaSet e ele monitora todos os pods que a label é 'nginx', ele tem também um template igual ao pod que definimos no yaml anterior, para que ele saiba como vai ser o pod que ele vai criar.

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

Podemos ver que agora sempre que eu excluo um pod o replicaSet logo em seguida sobe um novo no lugar, além disso é possivel ver que já está salva a configuração que eu desejo manter apenas uma replica daquele pod.

#### Deployments

Se eu quiser mudar a versão da imagem que estou utilizando o replicaSet não vai fazer essa mudança de forma automática, para isso vou precisar matar o pod para quando subir novamente ele subir com a versão nova, o replicaSet só verifica se o pod caiu e quantos pods eu quero.

Agora imagine essa situação onde eu tenho por exemplo 100 replicas, eu teria que matar os pods para atualizar a versão da imagem. E para isso temos os deployments, que são responsaveis por cuidar dos replicasets.

O Deployment sempre que quisermos mudar a versão da imagem ele vai criar um novo replicaSet, então por exemplo, temos 10 pods na versão 1.0, queremos atualizar para a versão 1.1, o deployment cria um novo replicaset com a versão 1.1 e pedindo 10 pods, enquanto no da versão 1.0 ele pede por 0 pods, e se a versão 1.1 estiver quebrada e precisarmos voltar ele pede por 10 pods na versão 1.0 e 0 pods na versão 1.1
 

> O yml do deployment é igual ao do replicaSet, só muda que no kind ao inves de ReplicaSet vai ser Deployment, porem todo o processo é mesmo, basta dar um apply que vai funcionar

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4drexlqmy38sx47or2qj.png)

Da para ver como ele fica alternando entre os replicaSets conforme a configuração muda 

## Rodando o kubernets com o meu servidor

Para isso criei um servidor bem basico em GO, tudo que ele faz é escrever hello world quando acessamos a porta 9090

```go
package main

import "net/http"

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe(":9090", nil)
}

func hello(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello World!"))
}

```

alem disso vou criar um arquivo docker 

```dockerfile
FROM golang:1.18 as builder

WORKDIR /app
COPY main.go .
COPY go.mod .
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o server main.go

FROM scratch
COPY --from=builder /app/server .
CMD [ "./server" ]
```

vou buildar esse arquivo `docker build -t yansb/goserver:latest .` e se e eu rodar o comando `docker run --rm -p 9090:9090 yansb/goserver:latest` já consigo acessar minha porta 9090 e ver o hello world, depois disso posso dar um push dessa imagem para o meu [dockerhub](https://hub.docker.com/repository/docker/yansb/goserver), agora ja posso criar um novo yaml com o essa imagem e fazer esse novo deployment 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mivm6mm31oa6sj60q6rk.png)

Se eu der um port-forward e for na porta 9090 já consigo ver o meu hello world 

#### Load balancer

Agora com diversas replicas dos pods (10 com o GO e 10 nginx) temos um problema, como K8s vai saber para qual pod mandar a pessoa que está acessando a aplicação

Vamos criar um yaml para o service: 

```yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
```

Esse service vai pegar todos os pods com a label nginx e vai fazer o loadBalance baseado nessa seleção agora qualquer pessoa que internamente procurar pelo nginx-service ou pelo ip dele, vai chegar até um dos nginx.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4aqbn3ml4u93z1dtj7ux.png)

O external ip está como pending pois meu computador não consegue gerar um IP externo, porem se estivesse rodando na aws, já poderíamos acessar esse ip externo e ter acesso ao ngnix


Tudo que fiz hoje com o kubernets está nesse repositório: https://github.com/Yansb/full-cycle-course/tree/master/kubernets