Photo by CHUTTERSNAP on Unsplash

Kubernetes+Nginx Ingress

Danilo Pedrelli
Artigos Machlab
9 min readMar 28, 2021

--

Kubernetes é uma das principais ferramentas atualmente para desenvolvimento, onde é possível orquestrar contêineres e colocar em produção os modelos de machine learning criados pelos cientistas de dados. No entanto, uma ferramenta tão relevante tem material muito escasso na internet quando consideramos sua aplicação à cientistas de dados, principalmente em português. Pensando nisso, o presente artigo tenta trazer um guia rápido e direto onde você poderá colocar seus modelos em produção, de maneira estável e escalável.

Nginx Ingress Controller é uma das formas mais populares de controlar acesso aos contêineres do Kubernetes. De acordo com o Kubernetes, um Ingress resource é:

An API object that manages external access to the services in a cluster, typically HTTP.

Um objeto de API que organiza o acesso externo aos serviços de um cluster, tipicamente HTTP.

No presente artigo você vai ser conduzido por todos os passos, desde a construção da imagem, até criação de um certificado de segurança. Ao final desse artigo você será capaz de:

  1. Subir uma imagem Docker no Google Container Registry;
  2. Fazer o deployment dessa imagem;
  3. Criar um serviço dessa imagem;
  4. Construir um arquivo .yaml para que um Nginx Ingress Controller resource possa direcionar requisições ao serviço;
  5. Colocar um certificado de segurança no acesso à sua API.

Como vemos acima, é um material um pouco extenso para os padrões do Medium, mas tentaremos ser objetivos de modo que você consiga seguir os passos e colocar seu modelo em produção com certificado de segurança.

Preparando o ambiente

Antes de começarmos, é preciso seguir alguns passos para prepararmos o nosso ambiente:

  1. Instale o Google Cloud SDK:

2. Instale o kubectl do Kubernetes:

gcloud components install kubectl

3. Instale o Docker:

4. Instale o Git:

Pronto, agora que instalamos as principais ferramentas, iremos dar início à construção de nosso projeto.

Construindo a imagem

Primeiramente, definimos o PROJECT_ID, presente na página inicial do seu projeto em console.cloud.google.com:

export PROJECT_ID=myproject-xxxxxxxxxxxxxxxxx

Para verificar que o código do projeto foi salvo fazemos:

echo $PROJECT_ID

Em seguida, criamos uma imagem Docker. Para isso navegamos até a pasta onde está o Dockerfile e rodamos:

docker build -t gcr.io/${PROJECT_ID}/my-app:v1 .

No nosso exemplo acima, criamos uma imagem chamada my-app, versão v1. Para visualizar se a imagem foi construída usamos:

docker images

É uma boa prática sempre testar a imagem localmente antes de subir para o Container Registry do Google. Para isso fazemos:

docker run — rm -d -p 8080:80 gcr.io/${PROJECT_ID}/my-app:v1

onde -d significa detach mode que permite deixar a imagem rodando e continuarmos no mesmo terminal, -p significa porta, sendo 80 a porta interna, enquanto 8080 é a porta externa que permitirá o acesso ao app.

Uma vez finalizado, podemos acessar o app utilizando o curl:

curl http://localhost/8080

Se tudo correr bem podemos seguir para o próximo passo.

Subindo a imagem para o Container Registry

Existem diversas nuvens onde é possível subir um contêiner, Docker Hub, por exemplo, é uma delas. Para a plataforma do Google, subimos no Google Container Registry (GCR). Para habilitar o GCR fazemos:

gcloud services enable containerregistry.googleapis.com

Em seguida, autenticamos nossa certificação

gcloud auth configure-docker

Por fim, subimos a imagem com o comando docker push:

docker push gcr.io/${PROJECT_ID}/my-app:v1

Pronto, você acaba de subir sua imagem para o GCR! Uma vez que a imagem se encontra em GCR, podemos criar o contêiner no cluster do Kubernetes.

Criando o contêiner

Assumindo que você já criou um cluster no Kubernetes, se não criou ainda pode seguir esse tutorial que ensina o passo-a-passo:

Inclusive, muita coisa do que falo aqui é possível encontrar nesse tutorial, aconselho que você o utilize em conjunto com o presente artigo. O mesmo te conduzirá até a criação do serviço para o seu modelo, ou seja, a criação de um IP externo de acesso ao serviço.

Para criar o contêiner no cluster do Kubernetes, que será listado em workloads, é preciso conectar a nossa máquina com o cluster:

gcloud container clusters get-credentials my-cluster — zone compute-zone — project ${PROJECT_ID}

Aqui o nome do nosso contêiner é my-cluster, substitua pelo nome do seu contêiner. Importante aqui saber a compute-zone e PROJECT_ID, mas isso pode ser visto ao clicar em conectar ao Cluster na própria dashboard do Kubernetes. Uma vez conectados, iremos criar o deployment utilizando kubectl:

kubectl create deployment my-app — image=gcr.io/${PROJECT_ID}/my-app:v1

Pronto, agora o contêiner foi construído no cluster, para visualizar os contêineres, faça

kubectl get deployment

Agora seus contêiner está em um cluster do Kubernetes pronto para gerar um serviço!

Expondo o app

Para expor o app a partir de um IP, fazemos:

kubectl expose deployment my-app — name=my-app-svc — type=ClusterIP — port 80 — target-port 8080

Aqui criamos um serviço que será acessado na porta 8080 e direcionado para a 80. No exemplo acima, criamos um IP interno ao escolhermos type ClusterIP, se quiséssemos gerar um IP externo, para essa opção escolheríamos LoadBalancer, e o serviço poderia ser acessado por qualquer pessoa com o IP a partir do browser.

Como vamos criar um Ingress, e gerar uma certificação, é importante deixarmos o IP de acesso interno apenas.

Para visualizar os serviços, fazemos:

kubectl get service

Muito bem, agora seu serviço está na nuvem, prontinho para ser acessado pelo Ingress!

Criando um Ingress

Para gerar um link de acesso para diversos serviços, podemos criar um Ingress. Com ele é possível definir os caminho (paths) de modo rápido e fácil num único documento. Aqui utilizaremos o Helm para instalar o Nginx, se você não possui o Helm, siga o seguinte tutorial:

Um bom tutorial para seguir junto ao nosso artigo é:

Instalando o Nginx Ingress

Para instalar o Nginx é preciso primeiro adicionar o repositório ao Helm:

helm repo add nginx-stable https://helm.nginx.com/stable
helm repo update

Em seguida efetuamos a instalação do Nginx Ingress,

helm install nginx-ingress nginx-stable/nginx-ingress

Para verificar se a instalação foi bem sucedida, rode no terminal:

kubectl get deployment nginx-ingress-nginx-ingress
kubectl get service nginx-ingress-nginx-ingress

Feita a instalação, é possível criar um domínio no Google que direcione os acessos ao IP do Nginx Ingress. Esse passo é importante para que consigamos criar uma certificação fornecida por uma CA (Certificate Authority), e o acesso venha por meio de https, como veremos adiante.

Para entender o melhor o que é um Ingress Controller e como suporte ao nosso material, sugiro o seguinte tutorial:

Supondo que nosso domínio seja myproject.com, podemos criar o arquivo .yaml do Ingress,

nano ingress-resource.yaml

Abaixo segue um modelo:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-resource
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
— host: myproject.com
http:
paths:
— path: /myapp
pathType: Prefix
backend:
service:
name: my-app-svc
port:
number: 8080

Aqui, a annotation rewrite-target refere-se à configuração do nosso Ingress Controller, de modo que myproject.com/myapp direcione para IP:8080, do contrário, sem esse annotation, teríamos um direcionamento para IP:8080/myapp, e dependendo de como foi construído seu app, essa path pode retornar “Not Found”. Se ainda assim você tiver problemas, aconselho a inserir a path “/myapp” no seu aplicativo, por exemplo, se for no Flask, escrevendo

@app.route('/myapp'):

Mas a ideia do rewrite-target é fazer com que isso não seja preciso. Para saber mais sobre annotations no Nginx Ingress Controller, tem esse material:

Olhando para nosso arquivo .yaml, vemos que em host definimos o nosso domínio, e paths direciona a requisição para o serviço que desejamos, no caso, /myapp direciona para my-app-svc na porta 8080. Para adicionar mais serviços, é preciso apenas replicar a última etapa de paths.

Em seguida, aplique as configurações para gerar o Ingress:

kubectl apply -f ingress-resource.yaml

E verifique se o ingress está funcionando corretamente:

kubectl get ingress ingress-resource

Para acessar o serviço utilize o curl:

curl http://myproject.com/hello

Nosso próximo passo é inserir uma certificação TLS com o cert-manager para o nosso Ingress.

Cert-Manager — LetsEncrypt

Para gerarmos um certificado de segurança iremos utilizar o cert-manager, cuja instalação será feita com o Helm. Para um tutorial mais completo, sugiro estudar a documentação:

Instalação

Primeiro, criamos um namespace:

kubectl create namespace cert-manager

Depois adicionamos o Jetstack ao repositório,

helm repo add jetstack https://charts.jetstack.io

e fazemos o update do Helm,

helm repo update

Em seguida realizamos a instalação via Helm

helm install \
cert-manager jetstack/cert-manager \
— namespace cert-manager \
— version v1.2.0 \
— set installCRDs=true

Verifique se a instalação ocorreu corretamente

kubectl get pods — namespace cert-manager

Você deve ver três pods (unidade mínima no Kubernetes) rodando.

Teste

Para testar o Issuer, crie um certificado auto-assinado digitando no terminal:

$ cat <<EOF > test-resources.yaml
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-test
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: test-selfsigned
namespace: cert-manager-test
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: selfsigned-cert
namespace: cert-manager-test
spec:
dnsNames:
- example.com
secretName: selfsigned-cert-tls
issuerRef:
name: test-selfsigned
EOF

E aplique a configuração,

kubectl apply -f test-resources.yaml

Cheque agora o status da certificação:

kubectl describe certificate -n cert-manager-test

Você deve ver uma mensagem dizendo Certificate issued successfully, isso significa que o cert-manager foi instalado corretamente e você pode atribuir certificações aos seus serviços. Agora delete o resource:

kubectl delete -f test-resources.yaml

Criando nossa certificação

Crie um production issuer, que no fundo é um fornecedor do seu certificado, para adicionar o certificado ao Ingress:

nano production_issuer.yaml

E escreva:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# Coloque aqui seu e-mail para registro no ACME
email: name@email.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Defina nome para salvar o secret
name: letsencrypt-prod-private-key
# Adicione um desafio a ser resolvido pelo nginx
solvers:
- http01:
ingress:
class: nginx

Substitua seu e-mail para receber notificações do certificado. Em seguida, aplique a configuração do certificado de segurança,

kubectl create -f production_issuer.yaml

E adicione o certificado ao ingress-resource.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-resource
annotations:
kubernetes.io/ingress.class: nginx
# Os annotations abaixo são muito importantes
acme.cert-manager.io/http01-edit-in-place: “true”
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
rules:
— host: myproject.com
http:
paths:
— path: /myapp
pathType: Prefix
backend:
service:
name: my-app-svc
port:
number: 8080
tls:
- hosts:
- myproject.com
secretName: app-web-cert

Aqui é importante frisar os annotations:

acme.cert-manager.io/http01-edit-in-place: “true”
cert-manager.io/cluster-issuer: letsencrypt-prod

Eles permitem uma unificação do certificado com o Ingress e definir qual o Issuer de certificação, respectivamente.

O próximo passo é simplesmente aplicar a nova configuração:

kubectl apply -f ingress-resource.yaml

Para verificar o estado do certificado, faça:

kubectl describe certificate app-web-cert

Novamente, você deve ver Certificate issued successfully.

Conclusão

Pronto, você agora já sabe como subir os contêineres no Container Registry, criar serviços, administrar via Ingress e aplicar o certificado de segurança! Espero que esse pequeno tutorial te ajude a subir seus modelos utilizando uma ferramenta super importante no mercado e que pode ser seu diferencial na busca por um emprego ou se destacar no seu dia-a-dia numa empresa. E acima de tudo, que assim você consiga solucionar problemas, porque ciência de dados é para isso!!! Qualquer dúvida que você tiver ou bug que encontrar, só comentar que será um prazer ajudar e fazer os ajustes no material!

--

--