Agora que já instalamos o podman no WSL é hora de começar a briga para fazer o kubernetes usar o podman no lugar do docker. Neste post vou instalar e configurar o minikube pelo fato dele ser a distribuição mais popular de kubernetes para ambiente de desenvolvimento.
Para fazer o podman rodar em conjunto com o minikube, precisaremos instalar 3 ferramentas:
- O próprio minikube
- O kubectl
- Um runtime (escolhi o CRI-O)
Como o post ficou grande e cheio de seções que podem ser puladas dependendo do que já esta instalado a configurado na máquina, julguei necessário colocar um índice.
De nada 😉
Índice
- Índice
- Entendendo os conceitos de driver e runtime
- Instalando o minikube
- Instalando o kubectl
- Instalando o CRI-O
- Rodando o minikube
- Deploy da aplicação
- Criando a service
- Expondo a aplicação para fora do Kubernetes
- Acessando a aplicação fora do WSL
- Alternativa rootless para o minikube
- Impressões e Conclusão
- Referencias
Entendendo os conceitos de driver e runtime
Sessão opcional: se você já entende o que são os conceitos de driver e runtime ou quer ir direto para a instalação pode pular para a instalação do minikube
Antes de começar com o hands on de verdade, primeiro é necessário entender o básico de driver e runtime no mundo de containers.
Runtime
O runtime é responsável por controlar todo o ciclo de vida do container. Isso vai desde baixar um container até rodá-lo.
Este artigo escrito por Nived Velayudhan aprofunda mais sobre o assunto. Também vale mencionar a própria documentação oficial da especificação do runtime
Driver
O driver é responsável por prover o conjunto de apis nas quais o usuário irá interagir com o ecossistema de containers. Em resumo, provê os comandos usados nos CLIs e interfaces gráficas.
Instalando o minikube
Para instalar a minikube não tem muito mistério, vamos seguir a documentação oficial.
Existem 2 formas de instalar para quem usa distribuições baseadas em debian (meu caso): baixando os binários ou baixando o pacote debian. No tutorial vou mostrar como instalar utilizando o pacote debian, pois foi a forma que eu instalei.
O primeiro passo é rodar o comando curl e baixar a última versão:
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb
Em seguida instalar o pacote:
sudo dpkg -i minikube_latest_amd64.deb
Pronto! Minikube instalado
Instalando o kubectl
Não podemos executar nossos comandos kubernetes sem a ferramenta que serve para isso.
Novamente indo para a documentação oficial, basta seguir os passos informados lá. Para o meu caso utilizei o passo-a-passo do Ubuntu.
Primeiro é necessário atualizar o package index e instalar algumas ferramentas necessárias para poder baixar o Kubernetes via apt:
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
Em seguida baixar a chave pública do GCP e adicionar o repositório do Kubernetes ao repositório do apt:
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
Por fim, reatualizar o package index para buscar as informações do novo repositório e instalar o kubectl:
sudo apt-get update
sudo apt-get install -y kubectl
Instalando o CRI-O
De acordo com a documentação do minikube, para utilizar o podman é necessário instalar um runtime. E o runtime recomendado pela própria documentação é o CRI-O.
Para instalá-lo vamos usar a documentação oficial do CRI-O
Assim como no último post, vamos começar importanto o arquivo /etc/os-release para as variáveis de ambiente:
. /etc/os-release
Com essas variáveis importadas, podemos baixar os repositórios necessários:
CRIO_VERSION=1.23
sudo echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x{$Name}_{$VERSION_ID}/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
sudo echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/{$CRIO_VERSION}/x{$Name}_{$VERSION_ID}/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:{$CRIO_VERSION}.list
A variável CRIO_VERSION deve ser preenchida com a versão desejada. Na data desta publicação é a 1.23.
Agora adicionamos as chaves ao apt-key:
sudo curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x{$Name}_{$VERSION_ID}/Release.key | apt-key add -
sudo curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:{$CRIO_VERSION}/x{$Name}_{$VERSION_ID}/Release.key | apt-key add -
E por fim instalamos a nossa última ferramenta necessária para rodar o minikube com o podman:
sudo apt-get update
sudo apt-get install -y cri-o cri-o-runc
Rodando o minikube
Depois dessa pequena odisséia de instalação, é hora de colocar o minikube para rodar com o podman. O comando exige passar as opções de driver e container runtime, porém nada de extraordinário:
minikube start --driver=podman --container-runtime=cri-o
Ao executar o comando recebemos a seguinte mensagem:
😄 minikube v1.25.2 on Ubuntu 20.04 (amd64)
✨ Using the podman driver based on existing profile
💣 Exiting due to PROVIDER_PODMAN_NOT_RUNNING: "sudo -k -n podman version --format " exit status 1: sudo: a password is required
💡 Suggestion: Add your user to the 'sudoers' file: 'myuser ALL=(ALL) NOPASSWD: /usr/bin/podman'
📘 Documentation: https://podman.io
Se o leitor pensou a mesma coisa que eu a primeira vez que viu essa mensagem, certamente deve ter tentado rodar o minikube com sudo e recebeu o erro abaixo:
😄 minikube v1.25.2 on Ubuntu 20.04 (amd64)
✨ Using the podman driver based on user configuration
🛑 The "podman" driver should not be used with root privileges.
💡 If you are running minikube within a VM, consider using --driver=none:
📘 https://minikube.sigs.k8s.io/docs/reference/drivers/none/
❌ Exiting due to DRV_AS_ROOT: The "podman" driver should not be used with root privileges.
O podman por ser construído utilizando a premissa rootless, não permite que o minikube seja rodado como rootfull quando utilizá-o como driver.
A solução é seguir a sugestão dada na primeira execução
Adicionando o Podman ao sudoers
Apesar de ser uma etapa rápida de fazer, vale parar 1 minuto para entender o que é o sudoers e o que ele faz antes de executar o comando.
sudoers é um arquivo utilizado para definir o nível de permissão de execução de comandos no modo super usuário. Neste arquivo é possível definir desde permissão de execução de comandos em um programa em específico até execução total e irrestrita.
Para mais informações e entendimento recomendo a leitura deste post e a leitura do man do arquivo sudoers.
Execute o comando sudo visudo
e adicione a seginte linha no final do arquivo:
myuser ALL=(ALL) NOPASSWD: /usr/bin/podman
Explicando o nível de permissão que estamos atribuindo:
O usuário myuser pode executar qualquer comando dentro do programa /usr/bin/podman sem a necessidade de informar o password.
Com a configuração adicionada podemos rodar o minikube sem grandes problemas.
Erro ao executar o minikube
Ao tentar rodar o minikube pela primeira vez talvez ocorra o erro de download de imagem KIC (perdi o texto certo do erro 😅). Para resolver esse problema é necessário baixar a imagem manualmente com o comando:
minikube start --driver=podman --container-runtime=cri-o --download-only=true
Após o término do download basta executar o minikube novamente
Deploy da aplicação
Com tudo configurado, é hora de criar um deploy e publicar nossa aplicação de teste.
Para isso crie um arquivo .yaml igual ao exemplo abaixo (ou pega ele pronto no repositório 😉)
apiVersion: apps/v1
kind: Deployment
metadata:
name: juridico-deployment
labels:
app: juridico
spec:
replicas: 2
selector:
matchLabels:
app: juridico
template:
metadata:
labels:
app: juridico
spec:
containers:
- name: juridicoapp
image: localhost/juridico:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3001
Com o deployment.yaml criado, execute o comando
kubectl apply -f <path-to-deployment-file>/deployment.yaml
Para ver se o deployment foi feito rode o comando:
kubectl get deployments juridico-deployment
o resultado deve ser algo parecido com:
NAME READY UP-TO-DATE AVAILABLE AGE
juridico-deployment 2/2 2 2 15d
E para ver os pods criados:
kubectl get pods -l app=juridico
A saída deve ser algo parecido com:
NAME READY STATUS RESTARTS AGE
juridico-deployment-86b6b47b6-j5l9n 1/1 Running 4 15d
juridico-deployment-86b6b47b6-lzkjq 1/1 Running 4 15d
Se por ventura no status estiver mensagens do tipo ImagePullBackOff
ou ErrImagePull
, provavelmente você deve possuir a imagem somente no cache do podman. Se esse for o caso, é necessário fazer um dos 3 passos:
- Subir a imagem para algum registry remoto (dockerhub, quay.io)
- Criar um registry local
- Subir a imagem para o cache do minikube
Adicionando a imagem ao cache do minikube
Se você assim como eu está tentando fazer um teste 100% local, sem dependender de registrys externos e subir mais uma aplicação, antes de ter tudo rodando é necessário executar mais esse passo. O processo é tedioso, porém pouco complexo
Primeiro é necessário exportar a imagem para um arquivo .tar com o comando:
podman save -o juridico.tar localhost/juridico:latest
Depois basta importar a imagem no minikube utilizando o comando:
minikube image load juridico.tar
Feito isso, basta reiniciar o minikube que o problema deve estar solucionado.
Criando a service
O próximo passo é criar uma forma de nos comunicarmos com o sistema independente da quantidade de pods instanciados e qual o IP do pod que está rodando no momento.
Para criar a service seguimos o mesmo passo do deployment e criamos um arquivo .yaml conforme abaixo:
apiVersion: v1
kind: Service
metadata:
name: juridico-service
labels:
app: juridico
spec:
type: NodePort
selector:
app: juridico
ports:
- port: 3001
protocol: TCP
nodePort: 30001
Com o service.yaml criado, execute o comando
kubectl apply -f <path-to-service-file>/service.yaml
Para ver se o service foi criado rode o comando:
kubectl get services juridico-service
o resultado deve ser algo parecido com:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
juridico NodePort 10.109.72.98 <none> 3001:30001/TCP 15d
Com a service configurada as outras aplicações já conseguem resolver o nome do sistema independente do scale up ou down dos pods.
Expondo a aplicação para fora do Kubernetes
Mesmo com a service configurada ainda não é possível realizar um acesso de fora do kubernetes. Para isso é necessária a utilização de um componente de rotas para expor a aplicação para fora e rotear as requisições para a aplicação. Nas minhas pesquisas encontrei duas formas de fazer o encaminhamento: usando o próprio minikube e usando o ingress. Aqui irei apresentar somente a primeira.
Minikube Service
O próprio minikube possui um comando que expõe a service para fora do kubernetes de forma simples e direta, podendo expor todas as services ou somente uma em específico. Para expor a aplicação deste post execute o comando abaixo:
minikube service --url juridico-service
O resultado será algo parecido com:
minikube service juridico
🏃 Starting tunnel for service juridico.
🎉 Opening service default/juridico in default browser...
👉 http://192.168.49.2:30001
Rodando o comando curl na url mostrada o valor retornado é a lista de todos os processos presentes no db.
Acessando a aplicação fora do WSL
Até o momento foram realizados inúmeros testes dentro do WSL e tudo tem ocorrido bem. Porém ao tentar chamar a URL a partir da máquina host(Windows) ela não encontrará a rota (404). Isso acontece porque o minikube assume um IP interno acessível somente pelo próprio WSL. Para tornar o sistema acessível é necessário utilizar o comando de port forwarding.
Para habilitar port fowarding para a service execute o comando:
kubectl port-forward service/juridico-deployment 3001:3001
O resultado deve ser algo semelhante ao que segue:
Forwarding from 127.0.0.1:3001 -> 3001
Forwarding from [::1]:3001 -> 3001
Handling connection for 3001
Handling connection for 3001
Infelizmente ao executar o comando de port forward o terminal fica preso e só é liberado ao encerrar o port-forward
Agora sim é possível chamar o sistema utilizando a URL http://localhost:3001 diretamente da máquina host.
Alternativa rootless para o minikube
Como mencionado nesta issue, os drivers do minikube devem executar em modo rootful. O principal risco de rodar o driver em modo root é a chance de ocorrer uma escalada de privilégios até o host. Para evitar este tipo de problema vamos recorrer a uma alternativa rootless: O usernetes
Impressões e Conclusão
Rodar o minikube utilizando o podman como runtime se provou um desafio grande e demandou muito estudo para fazer tudo rodar corretamente. O principal problema foi tornar a aplicação acessível da máquina host.
Um ponto que me chamou atenção é que durante a configuração do ecossistema é a incapacidade que o minikube tem de operar em modo rootless e as alterções necessárias para "forçar" o podman em modo rootful. Isso me levou a começar a estudar como funciona o userneter e quem sabe trazer um post novo para a série.
Por fim, vejo que o podman ainda precisa percorrer algum caminho para se tornar fácil de ser integrado e configurado como driver das distribuições mais populares de kubernetes para desenvolvedores assim como o docker é hoje.
Todos os arquivos e sistemas utilizados nesse post estão disponíveis no meu github no repositório wsl plus podman.
Referencias
- documentação oficial de instalação do minikube
- documentação oficial de instalação do kubectl
- documentação oficial de instalação do CRI-O
- documentação minikube utilizando podman como driver
- post conceitos de driver e runtime. Autor: Nived Velayuhan
- documentação da Spec do runtime pela OCI
- discussão do porque o podman deve rodar em rootful com minikube
- usernetes: alternativa rootless para o minikube
- problema de download das imagens
Top comments (0)