DEV Community

Poveda
Poveda

Posted on

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

Oldest comments (0)