DEV Community

Poveda
Poveda

Posted on

8 2

Podman + minikube

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

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
Enter fullscreen mode Exit fullscreen mode

Em seguida instalar o pacote:

sudo dpkg -i minikube_latest_amd64.deb
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 -
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Com o deployment.yaml criado, execute o comando

kubectl apply -f <path-to-deployment-file>/deployment.yaml
Enter fullscreen mode Exit fullscreen mode

Para ver se o deployment foi feito rode o comando:

kubectl get deployments juridico-deployment
Enter fullscreen mode Exit fullscreen mode

o resultado deve ser algo parecido com:

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
juridico-deployment   2/2     2            2           15d
Enter fullscreen mode Exit fullscreen mode

E para ver os pods criados:

kubectl get pods -l app=juridico
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Depois basta importar a imagem no minikube utilizando o comando:

minikube image load juridico.tar
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Com o service.yaml criado, execute o comando

kubectl apply -f <path-to-service-file>/service.yaml
Enter fullscreen mode Exit fullscreen mode

Para ver se o service foi criado rode o comando:

kubectl get services juridico-service
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay