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:
- Subir uma imagem Docker no Google Container Registry;
- Fazer o deployment dessa imagem;
- Criar um serviço dessa imagem;
- Construir um arquivo .yaml para que um Nginx Ingress Controller resource possa direcionar requisições ao serviço;
- 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:
- Instale o Google Cloud SDK:
Guia de início rápido: instalar a Google Cloud CLI | Documentação da CLI do Google Cloud
2. Instale o kubectl do Kubernetes:
gcloud components install kubectl
3. Instale o Docker:
Install Docker Engine | Docker Documentation
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:
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:
Como implantar um aplicativo da Web em contêiner | Kubernetes Engine | Google Cloud
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 seu 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 caminhos (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 é:
Ingress with NGINX controller on Google Kubernetes Engine | Google Cloud Platform Community
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:
Annotations – NGINX Ingress Controller (kubernetes.github.io)
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:
cert-manager – cert-manager Documentation
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: [email protected]
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!