Criando Um Cluster Kubernetes Local Com O Kind
O que é o Kind - Seja gentil
Desenvolver uma aplicação para rodar em um cluster Kubernetes, embora não seja uma tarefa tão difícil, requer muitos testes e deployments, como em qualquer outro tipo de desenvolvimento mas o desafio se torna um pouco maior e caro quando falamos de Kubernetes.
Nem sempre podemos ter uma série de máquinas disponíveis para criarmos um ou mais clusters para testes de forma simples e rápida, certo?! É claro, hoje temos diversos provedores na nuvem (cloud) que podem nos permitir criar um novo cluster Kubernetes em alguns minutos, mas nem sempre esta opção é viável, pois caso você mantenha o cluster rodando por algumas horas o custo começa a pesar.
Além disso, dificilmente você irá precisar de apenas algumas horas, certo?! Sua aplicação vai receber atualizações, melhorias, correções de bugs, etc. Tudo isto requer mais desenvolvimento, mais testes, mais deployments, o que significa novamente clusters disponíveis para tais tarefas. Uma forma de reduzir os custos na nuvem para este tipo de rotina é você criar e destruir seus clusters cada vez que for parar de desenvolver/testar. Mas se você faz isso diariamente ou algumas vezes por semana, este trabalho se torna complicado e demandará muito de seu tempo, além de ainda assim lhe custar alguns dólares por cada hora que mantém seu cluster funcionando.
Diversas alternativas foram criadas com foco nesta necessidade, visando justamente uma forma eficiente, prática e barata para que possamos rodar clusters Kubernetes localmente sem a necessidade de termos múltiplas máquinas, múltiplas VMs ou mesmo clusters na nuvem, como por exemplo no Google Cloud ou AWS.
Dentre estas alternativas, algumas das mais comuns são o Docker em si, que agora trás uma versão simplificada do Kubernetes com apenas um node (master), o kubeadm, minikube, kind, etc.
Neste post falaremos um pouco mais sobre o Kind. Kind, que na verdade é uma palavra em inglês que significa gentil, também é uma abreviação para Kubernetes in Docker (Kubernetes em Docker).
De acordo com sua página oficial, o Kind é uma ferramenta que lhe permite rodar clusters Kubernetes utilizando-se de Docker containers como nodes. Isso mesmo, cada node do seu cluster, será na verdade um container Docker em sua máquina, o que resultará na verdade em um cluster de containers rodando dentro de outros containers. Parece engraçado e estranho, rodar containers dentro de outros containers, mas lembre-se, o objetivo aqui não é um cluster de produção, e sim uma forma simples e eficiente para testes, desenvolvimento, CI, etc.
De fato, o Kind é uma ferramenta tão eficiente neste sentido que é utilizada oficialmente no desenvolvimento do Kubernetes em si, como plataforma de testes.
Não seria fantástico poder subir ou deletar um novo cluster em segundos? Todos sabemos o quão rápido é criar um novo container no Docker, certo?! Muito mais rápido que criar uma nova máquina virtual. Da mesma forma, se cada node de nosso cluster será um container, podemos apenas esperar que a criação de um novo cluster seja também rápida.
O kind utiliza o Containerd como seu Container Runtime ao invés do Dockershim. Apenas estou citando isto devido a todo o barulho criado com a notícia de o Kubernetes estar abandonando o uso do Docker como seu container runtime. Ou seja, o kind não será afetado em nada com isto.
Diferentemente do Kubernetes que vem em sua instalação Docker, o Kind lhe permitirá facilmente criar múltiplos clusters, com imagens diferentes para os nodes bem como com múltiplos nodes, o que tornará seus testes ainda mais realistas.
Instalação
Aqui assumirei que você já possui o Docker instalado e funcionando, afinal o Kind criará seus nodes com containers Docker.
Além do Docker, assumo que você já possua alguma familiaridade com o Kubernetes e que já possua o kubectl instalado.
OS X
No mac podemos utilizar o gerenciador de pacotes homebrew que cuidará de todas as dependências e configurações de ambiente:
$ brew install kind
Linux
Para diferentes distribuições Linux o pacote poderá ter um nome diferente em seus repositórios ou mesmo não estar presente nos repositórios, portanto utilizaremos o binário oficial para a instalação aqui:
$ curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64
$ chmod +x ./kind
$ mv ./kind /algum-diretório-no-seu-PATH/kind
Windows
Caso você possua o choco ou chocolatey como gerenciador de pacotes, pode instalar o kind apenas utilizando o seguinte comando:
$ choco install kind
Caso não possua este gerenciador de pacotes, pode fazer o download manualmente através do seguinte link: https://kind.sigs.k8s.io/dl/v0.9.0/kind-windows-amd64
Salve o arquivo e lembre-se de renomeá-lo para kind.exe. É importante que ele seja salvo em um diretório que faça parte de seu Path, do contrário você precisará incluir o diretório no seu PATH em suas variáveis de ambiente.
Como utilizar
Antes de mais nada, vejamos se temos algum container rodando em nosso Docker. (Embora isto não seja necessário, queremos ver o que realmente será criado pelo Kind). Para isto utilizaremos o comando docker ps que listará os containers rodando no momento:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Ótimo, nenhum container foi listado. Não temos nada rodando em nosso Docker.
Para criarmos um novo cluster Kubernetes precisamos apenas utilizar o comando kind create cluster –name
$ kind create cluster --name teste
Creating cluster "teste" ...
✓ Ensuring node image (kindest/node:v1.19.1) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-teste"
You can now use your cluster with:
kubectl cluster-info --context kind-teste
Have a nice day! 👋
O kind nos informou que tudo ocorreu bem e que nosso cluster foi criado com sucesso. Além disso, ele nos informou que o nome do contexto criado foi kind-teste.
Repare que ele aparentemente criou apenas o Master node (control-plane), conforme podemos ver na linha ✓ Preparing nodes 📦. (Apenas uma caixa).
Vamos novmaente rodar docker ps para ver o que foi criado:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0c468b4d1574 kindest/node:v1.19.1 "/usr/local/bin/entr…" 3 minutes ago Up 3 minutes 127.0.0.1:65165->6443/tcp teste-control-plane
Podemos ver que de fato apenas um container foi criado, e que se trata de nosso master node ou control-plane.
Como podemos ver se nosso cluster está funcional?
Se você está utilizando o Docker para Desktop que possui Kubernetes nativo e, caso o mesmo esteja com o Kubernetes inicializado, o seu novo cluster provavelmente estará visível na lista de contextos disponíveis em seu docker:
Ao selecionar este contexto kind-teste poderemos a seguir utilizar o kubectl para gerenciar nosso cluster.
Opcionalmente, você também pode exportar o contexto manualmente com o comando export KUBECONFIG=“$(kind get kubeconfig-path –name=“teste”)”.
Com o cluster criado, podemos listar os clusters existentes no kind com o comando kind get clusters:
$ kind get clusters
teste
E também podemos pegar informações importante sobre o nosso cluster com o comando kubectl cluster-info –context kind-teste:
$ kubectl cluster-info --context kind-teste
Kubernetes master is running at https://127.0.0.1:51908
KubeDNS is running at https://127.0.0.1:51908/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Podemos listar nossos nodes com kubectl get nodes e listar todos os pods (inclusive os padrões do sistema kubernetes) com kubectl get pods –all-namespaces:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
teste-control-plane Ready master 12m v1.19.1
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-f9fd979d6-254xj 1/1 Running 0 11m
kube-system coredns-f9fd979d6-s6jlc 1/1 Running 0 11m
kube-system etcd-teste-control-plane 1/1 Running 0 12m
kube-system kindnet-6qnl5 1/1 Running 0 11m
kube-system kube-apiserver-teste-control-plane 1/1 Running 0 12m
kube-system kube-controller-manager-teste-control-plane 1/1 Running 0 12m
kube-system kube-proxy-fbhnf 1/1 Running 0 11m
kube-system kube-scheduler-teste-control-plane 1/1 Running 0 12m
local-path-storage local-path-provisioner-78776bfc44-dfcc8 1/1 Running 0 11m
Como podemos ver, temos todos os pods padrões do Kubernetes, mas nenhum que nós mesmos tenhamos criado.
Para deletar o cluster podemos utilizar o comando *kind delete cluster –name teste**:
$ kind delete cluster --name teste
Deleting cluster "teste" ...
Simples assim o seu cluster foi deletado.
O kind permite diversas configurações e cenários, como por exemplo a utilização de arquivos de configuração para as definições do seu cluster.
No exemplo a seguir criaremos um arquivo chamado cluster-teste.yml com o seguinte conteúdo:
|
|
Em seguida podemos iniciar o nosso cluster com o comando kind create cluster –name teste –config cluster-teste.yml:
$ kind create cluster --name teste --config cluster-teste.yml
Creating cluster "teste" ...
✓ Ensuring node image (kindest/node:v1.19.1) 🖼
✓ Preparing nodes 📦 📦 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
✓ Joining worker nodes 🚜
Set kubectl context to "kind-teste"
You can now use your cluster with:
kubectl cluster-info --context kind-teste
Have a nice day! 👋
Repare que desta vez a saída do comando nos indicou a criação de 3 nodes. Podemos ver que ele nos apresentou 3 caixas na linha: ✓ Preparing nodes 📦 📦 📦
Se executarmos o comando docker ps poderemos ver que agora 3 containers foram criados, um para cada node:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
41f91c9a0e30 kindest/node:v1.19.1 "/usr/local/bin/entr…" 2 minutes ago Up 2 minutes 127.0.0.1:49543->6443/tcp teste-control-plane
5830cff7f4e8 kindest/node:v1.19.1 "/usr/local/bin/entr…" 2 minutes ago Up 2 minutes teste-worker
094a5c181c00 kindest/node:v1.19.1 "/usr/local/bin/entr…" 2 minutes ago Up 2 minutes teste-worker2
Da mesma forma podemos ver nossos nodes no cluster:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
prod1-control-plane Ready master 3m29s v1.19.1
prod1-worker Ready <none> 2m58s v1.19.1
prod1-worker2 Ready <none> 2m58s v1.19.1
O Kind lhe possibilitará uma série de configurações como mapeamento de portas, proxy, ou mesmo versões específicas do Kubernetes, o que é muito útil para fazer testes em sua aplicação antes de realizar uma atualização real do Kubernetes em seu cluster de produção. Todas as configurações podem ser encontradas em detalhes na documentação do projeto.
Para fazermos um teste simples e termos certeza de que nosso cluster está de fato funcional e que poderia receber deployments de aplicações vamos rodar um servidor web em nosso cluster local.
Com o nosso cluster já funcionando com 1 master (control-plane) e 2 workers, vamos criar um deployment e um service para o nosso nginx web server.
Primeiramente criaremos um arquivo chamado nginx-deployment.yml com o seguinte conteúdo:
|
|
Em seguida criaremos o arquivo nginx-service.yml:
|
|
(Não entraremos em detalhes sobre o conteúdo destes arquivos pois o foco do post é o Kind e assumo que você já possui certa familiaridade com o Kubernetes)
Com nossos dois arquivos criados vamos aplicá-los ao nosso cluster, criando assim um deployment do nginx com duas réplicas e um serviço que irá expôr o nosso deployment:
$ kubectl create -f nginx-deployment.yml
deployment.apps/nginx-deployment created
$ kubectl create -f nginx-service.yml
service/nginx-svc created
Podemos confirmar a criação de nosso deployment e de nosso service com os comandos kubectl get deployments e kubectl get services, ou mesmo checar tudo de uma vez com kubectl get all:
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-559d658b74-5klfx 1/1 Running 0 18m
pod/nginx-deployment-559d658b74-zclb2 1/1 Running 0 18m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 22m
service/nginx-svc NodePort 10.96.88.59 <none> 80:30225/TCP 17m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 2/2 2 2 18m
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-559d658b74 2 2 2 18m
Ali podemos ver também que dois pods foram criados rodando o nginx. Isto se dá por termos dito em nosso deployment que queremos 2 replicas do nosso webserver.
Para que possamos de fato testar nosso webserver nos resta agora apenas fazer um redirecionamento de portas para que possamos testar localmente. Como nosso serviço está escutando na porta 80, vamos mapear isso na porta 8000 de nossa máquina local (assumindo que nada em sua máquina está utilizando esta porta): kubectl port-forward service/nginx-svc 8000:80
$ kubectl port-forward service/nginx-svc 8000:80
Forwarding from 127.0.0.1:8000 -> 80
Forwarding from [::1]:8000 -> 80
Handling connection for 8000
Handling connection for 8000
Agora podemos abrir nosso browser e acessar nosso endereço local, na porta 8000: 127.0.0.1:8000
Da mesma forma que fizemos para inserir worker nodes, podemos inserir também múltiplos Master ou control-planes, para um cluster de alta disponibilidade. As possibilidades com o kind são inúmeras e vale muito a pena ler a documentação do projeto e brincar um pouco com ele.