Alura > Cursos de Dados > Cursos de MLOps e Operacionalização > Conteúdos de MLOps e Operacionalização > Primeiras aulas do curso Kubeflow: construindo pipelines de machine learning em produção

Kubeflow: construindo pipelines de machine learning em produção

Kubernetes para ML Engineers - Introdução

Apresentando o instrutor e realizando audiodescrição

Olá! Meu nome é Fabrício Zilli, serei o instrutor nas próximas aulas do curso de Kubeflow da Alura, conduzindo ao mundo de construção de pipelines (fluxos de processamento) dentro do Kubernetes, utilizando o Kubeflow.

Audiodescrição: Sou um homem branco, com cabelo curto, barba curta e visto um moletom marrom. Atrás de mim há uma parede branca, com uma estante a um lado, algumas luzes e uma planta.

Apresentando a visão geral do curso e a primeira aula

Neste curso, percorreremos todo o ciclo de vida de construção de um modelo de aprendizado de máquina, utilizando componentes do Kubernetes.

Na primeira aula, compreenderemos por que utilizar Kubernetes para modelos de aprendizado de máquina.

Explorando componentes e atividades do curso

Neste projeto, realizaremos a análise exploratória de dados utilizando o Jupyter Notebook, executando-o em nosso cluster de Kubernetes.

Em seguida, veremos nosso primeiro componente do Kubeflow, o KFP (Kubeflow Pipelines), que é um componente voltado à criação de pipelines (fluxos de processamento).

Depois, estudaremos o Katib, outro componente do Kubeflow, voltado à otimização de hiperparâmetros.

Por fim, treinaremos nosso modelo com o Kubeflow Training Operator e disponibilizaremos esse modelo, expondo-o por meio de uma API (interface de programação de aplicações), utilizando o KServe.

Apresentando o projeto de detecção de fraude e convidando para a próxima aula

Ao longo de todo o curso, utilizaremos um projeto como guia, focado em detecção de fraude. Trabalharemos com um conjunto de dados contendo diversos registros de transações de cartão de crédito e treinaremos um modelo para identificar se determinada transação é fraude ou não.

Eu espero você na próxima aula.

Kubernetes para ML Engineers - Por que Kubernetes para ML?

Contextualizando os desafios em aprendizado de máquina

Primeiro, precisamos entender por que discutimos Kubernetes em projetos de aprendizado de máquina.

Quem já trabalhou ou vai trabalhar com aprendizado de máquina provavelmente já passou ou passará por situações como estas:

Definindo as principais dores

Todos esses problemas convergem para três dores principais: reprodutibilidade, escalabilidade e resiliência.

Introduzindo contêineres como solução parcial

A primeira solução que costuma vir à mente para esses problemas é utilizar contêineres. De fato, contêineres resolvem a questão da reprodutibilidade, mas não resolvem os problemas de escalabilidade nem de resiliência.

A reprodutibilidade se resolve porque, com contêineres, nós empacotamos todo o nosso código, variáveis de ambiente e bibliotecas, de forma que possamos enviar esse pacote para qualquer outro dispositivo ou equipamento e obter o mesmo resultado que obtivemos, por exemplo, na nossa máquina.

Explicando o papel do Kubernetes

No entanto, isso não resolverá a questão da escalabilidade nem da resiliência. É nesse ponto que entra o Kubernetes. O Kubernetes funcionará como um grande orquestrador que gerenciará nossos contêineres, quaisquer que sejam, e garantirá que possam ser executados, que sejam recriados se algum deles apresentar falha e, inclusive, que a máquina onde esses contêineres estão sendo executados possa ser escalada. É ele quem desempenhará esse papel de mestre e orquestrará todos esses contêineres e as capacidades que temos.

O Kubernetes é declarativo. Nós não precisamos nos preocupar em definir e arquitetar toda essa estrutura; simplesmente declaramos como queremos que nosso cluster (agrupamento) seja e se comporte. Definimos, por exemplo, que queremos N réplicas desses contêineres, que esses contêineres tenham à disposição uma determinada quantidade de memória RAM e que estejam conectados a determinados serviços. O Kubernetes garantirá e trabalhará de forma contínua para que todas essas definições sejam respeitadas e estejam em vigor dentro do nosso cluster (agrupamento).

O Kubernetes garantirá que nossos contêineres sejam executados quando desejarmos e que nossas máquinas sejam instanciadas com a quantidade de recursos exigidos e necessários para que funcionem. Se algum contêiner ou outro tipo de componente precisar de mais recursos, o Kubernetes se encarregará de oferecer e garantir que esse contêiner tenha o recurso necessário. Se algum contêiner falhar, o Kubernetes o recriará e garantirá que sempre mantenhamos o estado que declaramos anteriormente para nosso cluster (agrupamento).

Apresentando o Kubeflow e próximos passos

E o Kubeflow? O Kubeflow é construído sobre o Kubernetes; na prática, fornece novos componentes para essa infraestrutura no Kubernetes, porém focados em problemas de aprendizado de máquina. Como o Kubernetes é genérico, o Kubeflow é específico para esses problemas. O vocabulário e as aplicações se voltam a problemas de aprendizado de máquina e não necessariamente à infraestrutura. Mantém total compatibilidade com o Kubernetes, mas oferece módulos e soluções para desafios que enfrentamos em projetos de aprendizado de máquina, como treinar modelos, servir modelos ou criar pipelines (fluxos de processamento).

É isso que veremos durante este curso.

Kubernetes para ML Engineers - Conceitos essencias de Kubernetes

Apresentando os componentes e iniciando pelos pods

Nesta aula, vamos discutir alguns conceitos e componentes essenciais quando falamos de Kubernetes e que são fundamentais para utilizar no Kubeflow. Os componentes que vamos tratar nesta aula são os Pods (Pods), o Deployment (implantação), os Jobs (tarefas), os Namespaces (espaços de nomes), Requests (solicitações), Limits (limites) e os CRDs (definições de recursos personalizados).

O primeiro tema são os Pods (Pods). Os Pods são a menor unidade de Kubernetes. Podemos pensá-los como “envelopes” onde colocamos contêineres, podendo haver um ou mais contêineres dentro de um mesmo Pod. Todos os contêineres no mesmo Pod compartilham a mesma rede e o mesmo volume, sendo iniciados e encerrados conjuntamente. Na prática, geralmente encontramos um único contêiner por Pod; no entanto, podem existir casos com dois, três ou mais contêineres.

Explicando a estrutura declarativa em yaml com exemplo de pod

Na tela, vemos um exemplo de um arquivo YAML. Já comentamos que Kubernetes é declarativo. Declaramos o estado desejado sempre por meio de arquivos YAML, que seguem uma estrutura muito semelhante à exibida. Nesse exemplo, temos apiVersion, kind, metadata e spec. É importante memorizar esses nomes, porque cada elemento de Kubernetes segue esse mesmo formato. O campo kind informa o tipo — neste caso, Pod. O metadata identifica o componente, e o spec descreve o estado esperado desse componente.

Para ilustrar essa estrutura, veja um Pod definido em YAML, com apiVersion, kind, metadata e spec, contendo um contêiner de exemplo:

apiVersion: v1
kind: Pod
metadata:
  name: dataset-loader
  namespace: kubeflow
spec:
  containers:
  - name: loader
    image: busybox:1.37

Esse exemplo mostra um Pod simples no namespace kubeflow, com um único contêiner usando a imagem busybox. Como comentamos, todos os contêineres de um Pod compartilham rede e volumes e são gerenciados em conjunto.

Apresentando deployments para disponibilidade contínua

Há, entretanto, um problema: quando usamos somente o Pod, se ele por acaso cair, o Kubernetes não o recriará. Quando precisamos manter contêineres ativos ou estabelecer alguma regra pela qual esses contêineres devem executar até certo ponto, utilizamos Deployments (implantações) e Jobs (tarefas).

Ao falarmos de Deployment, definimos que esse componente deve permanecer sempre ativo, sempre em execução. Novamente, especificamos o comportamento por meio de arquivos YAML, como no exemplo em tela. Continuamos com as chaves kind, metadata e spec, mas com algumas diferenças. Em kind, indicamos Deployment. Em spec, definimos, por exemplo, quantas réplicas do contêiner que indicamos em template desejamos manter em execução. Nesse Deployment, temos replicas igual a 1. Isso significa que o Kubernetes garantirá que ao menos uma réplica desse contêiner — neste caso, um Jupyter Notebook, um Jupyter Server — esteja em execução no nosso cluster. Se, por acaso, o Pod cair, o Kubernetes garantirá que uma nova réplica, isto é, uma nova instância desse contêiner, seja criada e volte a atender no cluster.

Um exemplo de Deployment que mantém um Jupyter Server sempre disponível, com uma réplica, fica assim:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jupyter
  namespace: kubeflow
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jupyter
  template:
    metadata:
      labels:
        app: jupyter
    spec:
      containers:
      - name: jupyter
        image: quay.io/jupyter/scipy-notebook:latest

Observe que definimos replicas: 1 e descrevemos o Pod template dentro de spec.template, garantindo que o Kubernetes recrie a instância caso ela falhe.

Utilizando jobs para execuções finitas

Diferentemente do Deployment, outro tipo de componente é o Job. O Job executa o contêiner até a conclusão, que pode ser bem-sucedida ou com falha. No YAML que define o comportamento desse componente, há a chave backoffLimit. Esse backoffLimit é a quantidade de vezes que o Job tentará se executar novamente em caso de falha. A chave restartPolicy indica que, se ocorrer uma falha, o contêiner deve ser reiniciado; e quantas vezes isso ocorrerá seguirá exatamente a quantidade configurada em backoffLimit.

Veja um exemplo de Job configurado para tentar novamente até três vezes em caso de falha, reiniciando o contêiner quando necessário:

apiVersion: batch/v1
kind: Job
metadata:
  name: train-fraude
  namespace: kubeflow
spec:
  backoffLimit: 3
  template:
    spec:
      restartPolicy: OnFailure
      containers:
      - name: trainer
        image: fraude-trainer:2.0
        args: ["--segment=low"]

Portanto, em Kubernetes, definimos tudo de forma declarativa.

Declaramos que queremos que esse contêiner seja executado: ele vai iniciar, executar o que for necessário e finalizar. Se, por acaso, encerrar com falha, vamos reiniciá-lo e tentar executar novamente, até um limite de três vezes.

Comparando o uso de jobs, deployments e pods

Quando costumamos usar Job e quando costumamos usar Deployment? Ou, ainda, quando utilizaremos um Pod? Utilizaremos Jobs quando tivermos alguma situação em que queremos que o contêiner inicie e pare por si só. Exemplos: casos de treinamento de modelo, nos quais vamos treinar o modelo, concluir o treinamento e encerrar; realizar algum tipo de processamento de dados, como o que faremos nas pipelines (fluxos de processamento); ou executar a otimização de hiperparâmetros, percorrendo e realizando experimentos em busca dos melhores hiperparâmetros para determinado modelo. Em todos esses cenários, há começo, meio e fim. Para esses casos, utilizaremos Jobs.

Agora, quando quisermos um serviço que esteja sempre online, sempre disponível para ser acessado e utilizado, como no caso de um servidor para Jupyter Notebooks ou mesmo uma página de inferência, utilizaremos o componente do tipo Deployment.

Quanto aos Pods, como comentamos, raramente os utilizamos. Geralmente, vamos utilizar Jobs ou Deployments. Os Pods ficam para casos muito específicos, como Pods temporários, quando precisamos iniciar um contêiner por um curto período de tempo.

Organizando recursos com namespaces

Outra característica dos nossos ambientes são os Namespaces. Podemos pensar neles como uma pasta lógica, isto é, uma forma de organizar os recursos dos nossos clusters de Kubernetes. Assim, todos os componentes que criarmos estarão dentro de algum Namespace. Dessa forma, podemos filtrar e gerenciar esses componentes à medida que formos instanciando novos.

Para exemplificar, a definição de um Namespace chamado kubeflow pode ser feita assim:

apiVersion: v1
kind: Namespace
metadata:
  name: kubeflow
  labels:
    pod-security.kubernetes.io/enforce: privileged

Configurando recursos com requests e limits

Outra característica muito importante em Kubernetes são os recursos. Eles definem quantos recursos de computação o contêiner, o Deployment ou o Job terão disponíveis para execução. Quando utilizamos a chave requests, definimos o mínimo garantido. No exemplo apresentado, cpu: 1 e memory: 2Gi significam que esse contêiner, Deployment ou Job terá, no mínimo, 1 CPU de processamento e 2 GB de RAM disponíveis. Já limits definem o máximo. No exemplo, cpu: 2 e memory: 4Gi indicam que, como mínimo, teremos 1 CPU e, como máximo, 2; como mínimo, 2 GB de memória e, como máximo, 4 GB. Se, por acaso, a memória ultrapassar 4 GB, o contêiner (ou recurso) apresentará o erro out of memory (falta de memória) e provavelmente será interrompido. Em seguida, o Kubernetes iniciará novamente o componente.

No YAML, esses recursos são especificados na seção resources do contêiner (por exemplo, dentro de spec.template.spec.containers em um Deployment ou em um Job), como no trecho abaixo:

resources:
  requests:
    cpu: "1"
    memory: "2Gi"
  limits:
    cpu: "2"
    memory: "4Gi"

Entendendo crds e extensões do kubernetes

Por fim, temos os CRDs, que são as Custom Resource Definitions (Definições Personalizadas de Recursos). Esse é um mecanismo que o Kubernetes oferece para permitir a criação de novos tipos de componentes do Kubernetes. Pods, Jobs e Deployments são incorporados por padrão, ou seja, já vêm no Kubernetes. Todos os demais componentes que utilizaremos no Kubeflow são criados por meio de CRDs. Não precisamos nos preocupar, pois não vamos criar novos CRDs. No entanto, é importante entendermos como o Kubeflow permite novos componentes sobre o Kubernetes — e isso ocorre por meio dos CRDs.

[♪]

Sobre o curso Kubeflow: construindo pipelines de machine learning em produção

O curso Kubeflow: construindo pipelines de machine learning em produção possui 294 minutos de vídeos, em um total de 57 atividades. Gostou? Conheça nossos outros cursos de MLOps e Operacionalização em Dados, ou leia nossos artigos de Dados.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda MLOps e Operacionalização acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas