<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Murilo Menezes Mendonça</title>
    <description>The latest articles on Forem by Murilo Menezes Mendonça (@murilommen).</description>
    <link>https://forem.com/murilommen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F428161%2F2c840302-2dae-4d78-abab-1bb5e4ce17be.jpg</url>
      <title>Forem: Murilo Menezes Mendonça</title>
      <link>https://forem.com/murilommen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/murilommen"/>
    <language>en</language>
    <item>
      <title>Customizando modelos de MLFlow com PyFuncs</title>
      <dc:creator>Murilo Menezes Mendonça</dc:creator>
      <pubDate>Thu, 03 Feb 2022 20:53:25 +0000</pubDate>
      <link>https://forem.com/murilommen/customizando-modelos-de-mlflow-com-pyfuncs-5cb4</link>
      <guid>https://forem.com/murilommen/customizando-modelos-de-mlflow-com-pyfuncs-5cb4</guid>
      <description>&lt;p&gt;Se você estuda ou trabalha com ciência de dados e aprendizado de máquina, já deve ter se deparado com alguns problemas de &lt;em&gt;reproducibilidade&lt;/em&gt;. Tipo assim, você não consegue treinar de novo um modelo que seja tão bom quanto o que você fez 3 meses atrás. Seja porque em algum momento você usou algum hiperparâmetro diferente, ou porque você não anotou em nenhum lugar qual foi a métrica que você conseguiu com aquele treino aquele dia. &lt;/p&gt;

&lt;p&gt;Pode ser que você também tenha tentado serializar um modelo com um framework específico que aplicava sempre o método &lt;code&gt;transform&lt;/code&gt; para realizar predições, e aí depois você decidiu mudar de framework e o método de predição era &lt;code&gt;predict&lt;/code&gt; e isso acabou quebrando um pouco o fluxo de servir o modelo em produção. &lt;/p&gt;

&lt;p&gt;Se isso te parece familiar, a boa notícia é que tem uma ferramenta &lt;strong&gt;maravilhosa&lt;/strong&gt; que ajuda bastante nessa gestão do seu modelo. O Mlflow se define como uma “plataforma de código aberto para o ciclo de vida de Machine Learning”. &lt;/p&gt;

&lt;h2&gt;
  
  
  Componentes do Mlflow
&lt;/h2&gt;

&lt;p&gt;São 4 os principais componentes do Mlflow, cada um com uma responsabilidade e um benefício próprio. O legal é que você define na sua estrutura o que mais faz sentido utilizar dentre esses componentes, não sendo necessária uma adoção completa de todos. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mlflow Tracking: uma ferramenta web que te auxilia a registrar os parâmetros, artefatos e métricas de cada execução de treino realizada. &lt;/li&gt;
&lt;li&gt;Mlflow Projects: define como criar um ambiente virtual, com a ajuda do Anaconda e executar todos os passos (entry-points) para reproduzir a pipeline da sua execução. &lt;/li&gt;
&lt;li&gt;Mlflow Models: “empacota” todos os modelos em um formato único. Também é usado para servir os modelos em produção, construindo uma imagem e subindo um servidor baseado em APIs REST.&lt;/li&gt;
&lt;li&gt;Mlflow Registry: Faz a gestão das diferentes versões e estágios do seu modelo, entre Staging até Production ou Arquivado. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Mlflow Models
&lt;/h2&gt;

&lt;p&gt;Existem vários artigos que te ensinam como treinar e registrar um modelo “simples” de Mlflow, usando frameworks conhecidos. Seu código fica mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.datasets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_iris&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.ensemble&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RandomForestClassifier&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;

        &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sklearn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;autolog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;load_iris&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;feature_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="n"&gt;clf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RandomForestClassifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_estimators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;clf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Percebe que modificamos um código “usual” de treino em 3 linhas? Quando a gente executar esse pedaço de código, o mlflow irá registrar todos os &lt;strong&gt;hiperparâmetros&lt;/strong&gt;, uma série de &lt;strong&gt;métricas&lt;/strong&gt; de aprendizado e também o &lt;strong&gt;modelo&lt;/strong&gt; serializado como um &lt;code&gt;pickle&lt;/code&gt; usando o formato padronizado de um modelo de MLflow. Tudo isso vai ficar armazenado no seu servidor de Mlflow Tracking e pronto para ser “empacotado” pra produção. Legal, né? &lt;/p&gt;

&lt;p&gt;Mas essa postagem aqui não apareceu pra te ensinar a usar o Mlflow base. Parto do princípio que você pelo menos já mexeu um pouquinho e já adotou, mas precisa saber como construir um modelo &lt;strong&gt;customizado&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Customizar um modelo pode ser interessante se você:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quer que o seu método predict retorne algo além da coluna de predições&lt;/li&gt;
&lt;li&gt;Precisa tratar os dados com outros métodos antes de fazer as predições&lt;/li&gt;
&lt;li&gt;Quer servir um &lt;em&gt;stack&lt;/em&gt; de modelos como um único modelo&lt;/li&gt;
&lt;li&gt;Está utilizando algum framework desconhecido pelo Mlflow&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Estrutura de PyFuncs
&lt;/h2&gt;

&lt;p&gt;Para construir um modelo customizado, você terá que utilizar o "sabor" &lt;code&gt;pyfunc&lt;/code&gt;. Ele é basicamente um &lt;em&gt;wrapper&lt;/em&gt; que pode pegar qualquer modelo genérico e transformar em um modelo de MLflow. É importante também destacar que &lt;strong&gt;todos os modelos de MLflow herdam a mesma classe base&lt;/strong&gt;. Ou seja, você, ao trabalhar com PyFuncs, está estendendo as funcionalidades que já foram pré-determinadas no &lt;code&gt;mlflow.sklearn&lt;/code&gt;, por exemplo. Mas no fim das contas, o modelo vai seguir o mesmo padrão de encapsulamento. &lt;/p&gt;

&lt;p&gt;Isso já garante pra gente uma uniformidade em como realizar as tuas predições. Mesmo que o seu framework utilize o método &lt;code&gt;transform&lt;/code&gt;, todos os modelos de Mlflow irão implementar um método &lt;code&gt;predict&lt;/code&gt; por padrão.&lt;/p&gt;

&lt;p&gt;Para construir uma PyFunc, os imports no começo do código ficam:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cloudpickle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você vai precisar conhecer um pouco de Programação Orientada a Objetos para poder criar o seu próprio modelo, mas não é difícil. Você vai herdar a classe &lt;code&gt;PythonModel&lt;/code&gt; e também vai precisar informar algumas coisas extras, que os frameworks padronizados pelo MLflow e o autologging abstraíam pra você antes.&lt;/p&gt;

&lt;p&gt;Vamos começar com um exemplo de como você define um modelo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModelWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pyfunc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PythonModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os dois métodos acima são necessários no seu &lt;em&gt;wrapper&lt;/em&gt; para que você consiga registrar com sucesso seu modelo. Você basicamente irá dizer para o MLflow como carregar o modelo treinado (onde ele está, qual é nome dele) e como realizar as predições. &lt;/p&gt;

&lt;p&gt;Imagine que você precisasse carregar um preprocessador antes, chamá-lo para transformar seus dados e só depois realizar as predições. O seu código ficaria assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModelWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pyfunc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PythonModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preprocessor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preprocessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;transformed_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preprocessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transformed_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Percebe como é flexível? Você precisa basicamente declarar o que muda de uma estrutura padrão de modelo para a sua necessidade. Nesse caso, você pode combinar múltiplos modelos treinados em um único modelo de MLflow, ou como fiz ali em cima, um pre-processador serializado junto com o estimador. Tudo isso vai ser entendido pelo seu "pacote" de modelos de MLflow em um único &lt;code&gt;predict&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Mas... pera! Tá faltando alguma coisa. Como você treina esse modelo? De onde sai esse &lt;code&gt;context.artifacts&lt;/code&gt;? 😨 &lt;/p&gt;

&lt;h2&gt;
  
  
  Treinando seu modelo como uma PyFunc
&lt;/h2&gt;

&lt;p&gt;Bom, como você tem mais flexibilidade, você vai ter um trabalinho maior também pra definir seu treino. Apesar de não ser estritamente necessário, recomendo &lt;strong&gt;fortemente&lt;/strong&gt; que você inclua na sua classe &lt;code&gt;MyModelWrapper&lt;/code&gt; o médoto &lt;code&gt;fit&lt;/code&gt;. Aí você vai conseguir empacotar tudo em um fluxo de trabalho só, e vamos mostrar um exemplo de como fazer. Perceba que no nosso construtor estamos incluindo o &lt;strong&gt;preprocessador&lt;/strong&gt; e o &lt;strong&gt;estimador&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModelWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pyfunc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PythonModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preprocessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MinMaxScaler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SVC&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preprocessor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;estimator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Making the splits
&lt;/span&gt;        &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Training the transformer and scaling the data
&lt;/span&gt;        &lt;span class="n"&gt;X_scaled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preprocessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_scaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Training your model Pipeline
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Evaluating and logging metric with MLFlow
&lt;/span&gt;        &lt;span class="n"&gt;y_pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;accuracy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;accuracy_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log_metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accuracy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accuracy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Dumping the fitted objects
&lt;/span&gt;        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fitted_processor.pkl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cloudpickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preprocessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fitted_model.pkl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cloudpickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;transformed_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preprocessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transformed_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bom, primeira coisa que eu gostaria de pontuar é que estou utilizando o &lt;code&gt;cloudpickle&lt;/code&gt; para persistir os modelos treinados. O MLflow se dá muito bem com esse serializador, e depois você pode usar o &lt;code&gt;pickle&lt;/code&gt; para desserializar numa boa. Mas, caso necessário, você pode utilizar o serializador de sua escolha, desde que você ajuste depois o método &lt;code&gt;load_context&lt;/code&gt; de acordo. Além disso, mesmo antes de termos definido a nossa execução, já podemos dizer qual métrica queremos acompanhar com o MLFlow.&lt;/p&gt;

&lt;p&gt;Pra treinar o algoritmo, você vai precisar definir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O ambiente de Anaconda para replicar seu experimento&lt;/li&gt;
&lt;li&gt;Definir a classe do seu modelo&lt;/li&gt;
&lt;li&gt;Definir um dicionário de artefatos&lt;/li&gt;
&lt;li&gt;Definir o nome do diretório que contém os artefatos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos ver o código então:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;

    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyModelWrapper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;conda_env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conda.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;artifacts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preprocessor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fitted_processor.pkl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fitted_model.pkl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pyfunc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;artifact_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;artifacts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;python_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;conda_env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conda_env&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse &lt;code&gt;conda.yaml&lt;/code&gt; é um arquivo que precisa estar na sua estrutura de execução, na mesma organização de pastas em que você executará o seu módulo de treino. &lt;/p&gt;

&lt;p&gt;Além disso, o método &lt;code&gt;fit&lt;/code&gt; faz o &lt;em&gt;dump&lt;/em&gt; dos objetos serializados no seu diretório local. Então você abre um dicionário chamado &lt;code&gt;artifacts&lt;/code&gt; e dá o nome das chaves de cada artefato que você está logando. Perceba que no &lt;code&gt;load_context&lt;/code&gt; pegamos justamente os valores das chaves &lt;code&gt;preprocessor&lt;/code&gt; e &lt;code&gt;estimator&lt;/code&gt; do dicionário &lt;code&gt;artifact&lt;/code&gt;. Você também pode adicionar a esse dicionário um plot de gráfico em JPEG ou até mesmo um arquivo CSV com as perdas em cada época da sua rede neural, por exemplo. &lt;/p&gt;

&lt;p&gt;Enfim, artefatos servem para que você &lt;strong&gt;carregue informação junto com a sua execução de treino&lt;/strong&gt; lá pro servidor do Mlflow Tracking. Ou mesmo modelos treinados, que precisarão aparecer no seu &lt;code&gt;load_context&lt;/code&gt; depois 😄&lt;/p&gt;

&lt;h2&gt;
  
  
  Fazendo predições
&lt;/h2&gt;

&lt;p&gt;Como comentei mais cedo, todos os modelos que forem registrados como modelos de MLflow terão a mesma estrutura. Seja ele um modelo “padrão”, utilizando frameworks conhecidos, ou mesmo o customizado, como acabamos de ver. &lt;/p&gt;

&lt;p&gt;Pra fazer as predições, pra qualquer modelo de MLflow, a gente vai precisar fazer o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;logged_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;runs:/&amp;lt;run_id&amp;gt;/&amp;lt;artifact_directory&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;loaded_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pyfunc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logged_model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;loaded_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então, só trocando a &lt;code&gt;run_id&lt;/code&gt; você já pode usar o mesmo método de predição. Percebe o valor disso? O que a gente fez foi basicamente editar e estender tanto o que carregar quando eu chamar &lt;code&gt;mlflow.pyfunc.load_model&lt;/code&gt;, como também como exatamente realizar as predições, chamando o método &lt;strong&gt;padronizado&lt;/strong&gt; &lt;code&gt;predict&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Parabéns, você agora já sabe como montar um modelo customizado com uma ferramenta mega poderosa 🥳&lt;/p&gt;

&lt;h2&gt;
  
  
  O que mais?
&lt;/h2&gt;

&lt;p&gt;Se você se interessou por esse tópico e quer explorar ainda mais o MLflow Models, não deixe de conferir a &lt;a href="https://www.mlflow.org/docs/latest/python_api/mlflow.pyfunc.html" rel="noopener noreferrer"&gt;documentação das PyFuncs&lt;/a&gt;, pois isso poderá te ajudar bastante no seu desenvolvimento.&lt;/p&gt;

&lt;p&gt;De verdade, espero que esse tutorial seja útil pra você.  &lt;/p&gt;

&lt;p&gt;Tem dúvidas? Deixe seu comentário 😃&lt;/p&gt;

</description>
      <category>mlflow</category>
      <category>machinelearning</category>
      <category>model</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Configurando o Windows para trabalhar com Python no WSL 2</title>
      <dc:creator>Murilo Menezes Mendonça</dc:creator>
      <pubDate>Mon, 27 Sep 2021 17:10:51 +0000</pubDate>
      <link>https://forem.com/murilommen/configurando-o-windows-para-trabalhar-com-python-no-wsl-2-44ea</link>
      <guid>https://forem.com/murilommen/configurando-o-windows-para-trabalhar-com-python-no-wsl-2-44ea</guid>
      <description>&lt;p&gt;Se você trabalha com desenvolvimento ou está começando a aprender Python no Windows, talvez você já tenha tido alguma dificuldade com gestão de dependências, variáveis de ambiente e até mesmo permissão pra fazer as coisas porque não abriu seu &lt;em&gt;Prompt&lt;/em&gt; de Comando como administrador. Esse post pode te dar um ganho de produtividade &lt;strong&gt;gigante&lt;/strong&gt;, sem precisar abandonar esse tão famoso sistema operacional! &lt;/p&gt;

&lt;p&gt;O que vamos fazer aqui é configurar um terminal de Ubuntu, uma distribuição de Linux mega popular, dentro do Windows, usando o WSL, ou Windows Subsystem for Linux. Sem a necessidade de ter dois Sistemas Operacionais instalados no seu PC, sem precisar de máquina virtual e nem nada. Tudo integrado e facinho 🤓. Aí além disso, vamos também rodar uma IDE super famosa de dentro desse terminal e garantir que você já consiga "sair jogando" pra desenvolver teu código Python (ou qualquer outra linguagem do seu interesse) depois de ler essa postagem.&lt;/p&gt;

&lt;p&gt;Dividi em algumas pequenas etapas e vou colocar algumas capturas de tela pra você se guiar. Se tiver qualquer dúvida, pode comentar aqui que eu respondo se souber. Vamos nessa?&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalando o WSL
&lt;/h2&gt;

&lt;p&gt;O primeiro passo então é instalar e habilitar o WSL na sua máquina. Pra isso, abra &lt;strong&gt;como administrador&lt;/strong&gt; o Powershell&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9l6zu3htt2jn32l8zoz2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9l6zu3htt2jn32l8zoz2.jpg" alt="pwsh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E então execute o comando:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;wsl &lt;span class="nt"&gt;--install&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Esse processo vai demorar alguns minutos, dependendo da velocidade da sua internet e também do seu processador. Pra mim aqui foi em torno de 10 minutos. Uma vez que tiver tido sucesso ao instalar, reinicie seu computador.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurando o Ubuntu
&lt;/h2&gt;

&lt;p&gt;Após reiniciar seu computador, procure por "Ubuntu" na barra de tarefas e abra a aplicação. Ele vai pedir pra você configurar um usuário e senha, que são as credenciais que você vai colocar pra configurar o seu terminal. Essa senha vai ser usada em muitas ocasiões que você precise de acesso como administrador, mas, por ser Linux (❤️), você consegue fazer isso sem a necessidade de reabrir o terminal e pra um comando específico, com &lt;code&gt;sudo nome-do-comando&lt;/code&gt;. Enfim, escolha uma senha fácil de digitar e termine de configurar. Depois, feche a aplicação.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F454i1uhhcd5uf3y7d6bp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F454i1uhhcd5uf3y7d6bp.jpg" alt="configuring"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ajustando a versão do WSL
&lt;/h2&gt;

&lt;p&gt;Agora, abra de novo o Powershell como administrador e garanta que você está configurado na versão 2 do WSL, com o seguinte comando:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;wsl &lt;span class="nt"&gt;--set-default-version&lt;/span&gt; 2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Instalando o VS Code e habilitando a extensão do WSL
&lt;/h2&gt;

&lt;p&gt;Último mas não menos importante, &lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;baixe o Visual Studio Code&lt;/a&gt; e instale na sua máquina. Certifique-se de que você adiciona o comando "code" no seu $PATH (que por padrão já é habilitado).&lt;/p&gt;

&lt;p&gt;Uma vez feito isso, procure e baixe uma extensão chamada Remote - WSL, clicando no ícone de blocos na aba esquerda do seu VS Code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbh7bbs80xek1edrkcpo8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbh7bbs80xek1edrkcpo8.jpg" alt="remote-wsl"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feito isso, feche o VS Code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Executando seu "olá mundo" de dentro do WSL
&lt;/h2&gt;

&lt;p&gt;Agora pra etapa final, reabra o Ubuntu, crie uma pasta e inicie o VS Code de dentro do WSL, da seguinte forma:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foshi6kj718btcdpkzhxh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foshi6kj718btcdpkzhxh.jpg" alt="criar-pasta-iniciar-vs-code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Isso vai abrir a janela do VS Code e a partir daí você já consegue criar seu primeiro código &lt;code&gt;hello-world.py&lt;/code&gt; com Python. Note que você está executando o VS Code de dentro do ambiente Ubuntu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbwfmonw6loh66vlvur6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbwfmonw6loh66vlvur6.jpg" alt="hello-world"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Então clique em "New Terminal" na aba de cima e execute o seu código dando o comando:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;python3 hello-world.py

OLHA EU AQUI MUNDO!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uhuuul! 🥳&lt;/p&gt;

&lt;h2&gt;
  
  
  Concluindo
&lt;/h2&gt;

&lt;p&gt;Essa postagem foi bem curtinha, porque esse é um processo muito simples. Espero que ela seja útil pra você e se algo não ficou claro, me avisa aqui nos comentários! &lt;/p&gt;

&lt;p&gt;Um abraço e até a próxima 🍻&lt;/p&gt;

</description>
      <category>python</category>
      <category>windows</category>
      <category>wsl</category>
      <category>configuration</category>
    </item>
    <item>
      <title>Deploy do Airflow 2.0 no Kubernetes com Helm</title>
      <dc:creator>Murilo Menezes Mendonça</dc:creator>
      <pubDate>Fri, 18 Jun 2021 21:58:58 +0000</pubDate>
      <link>https://forem.com/murilommen/deploy-do-airflow-2-0-no-kubernetes-com-helm-1a96</link>
      <guid>https://forem.com/murilommen/deploy-do-airflow-2-0-no-kubernetes-com-helm-1a96</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A foto é do &lt;a href="https://unsplash.com/@loik_marras?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Loik Marras&lt;/a&gt; no &lt;a href="https://unsplash.com/s/photos/helm?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Olá! Se você trabalha com &lt;em&gt;pipelines&lt;/em&gt; de dados ou &lt;em&gt;Jobs&lt;/em&gt; que precisam de uma resiliência maior do que um simples agendador de tarefas, como o &lt;code&gt;cron&lt;/code&gt;, o Airflow pode ser uma excelente solução! Ele foi desenvolvido pelo time de dados do Airbnb, mas hoje pertence à fundação de software Apache. E claro, é um software de código aberto, mas você ainda vai precisar se preocupar com a infraestrutura pra mantê-lo de pé. Se você tem interesse em saber como subir uma instância de Airflow no Kubernetes, acho que esse post pode ser bem útil para você. &lt;/p&gt;

&lt;h2&gt;
  
  
  O que vamos fazer aqui?
&lt;/h2&gt;

&lt;p&gt;Vou tentar trazer aqui um passo-a-passo super breve pra você conseguir fazer o deploy do Airflow na sua instância de Kubernetes com a ajuda do Helm. Não sabe do que se trata? Vou riscar a superfície sobre eles no próximo tópico, só pra que você não fique tãão perdido(a). Mas, como em muitas coisas relacionadas à tecnologia, faça seu dever de casa, procure outras postagens, faça cursos e se aprofunde. E claro, se alguma dúvida surgir, pode comentar aqui que eu tento ajudar com o que puder 😄   &lt;/p&gt;

&lt;p&gt;O Airflow pode funcionar em uma máquina virtual no seu provedor de nuvem ou mesmo na sua máquina local, como mostra &lt;a href="https://airflow.apache.org/docs/apache-airflow/stable/start/docker.html" rel="noopener noreferrer"&gt;esse tutorial&lt;/a&gt; do próprio time do Airflow.  O que vamos utilizar nesse post é o Kubernetes, por se tratar de uma infraestrutura computacional bastante resiliente, performática e escalável.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes
&lt;/h3&gt;

&lt;p&gt;Em um resumo MEGA resumido, o Kubernetes é um serviço de gerenciamento de containers para garantir que sua aplicação sempre esteja de pé. Ele se baseia na sua &lt;strong&gt;declaração&lt;/strong&gt; de como sua aplicação deve funcionar. Para isso, você faz uso de arquivos YAML, que vão dizer exatamente como sua aplicação fica de pé e como ela escala, e o serviço do Kubernetes garante que essas declarações irão se manter ao longo do tempo. Se no meio do caminho um container desliga, o Kubernetes provisiona um novo container. Se existirem muitos usuários, o Kubernetes consegue escalar o número de nós do seu cluster de máquinas, para que sua aplicação se mantenha sempre estável. E aí quando o número de usuários diminuir, ele também desliga as máquinas que não forem necessárias. Doido, né? &lt;/p&gt;

&lt;h3&gt;
  
  
  E o Helm? Pra que serve?
&lt;/h3&gt;

&lt;p&gt;Bom, trabalhar com Kubernetes tem uma curva de aprendizado bastante inclinada. E você também pode demorar um pouco até que tudo funcione como você deseja, afinal, dependendo da complexidade da sua aplicação, o número de arquivos de configuração pode crescer consideravelmente. Pra tentar tornar esse processo mais amigável e fácil de manter, o projeto do Helm surgiu. Ele tenta &lt;em&gt;templatear&lt;/em&gt; a maior parte "estática" das suas declarações, deixando as partes móveis em um único arquivo, comumente chamado &lt;code&gt;values.yaml&lt;/code&gt;. E aí só com ele, você consegue declarar tudo o que você precisa pra subir sua aplicação. &lt;/p&gt;

&lt;blockquote&gt;

&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvciojsrcekmu5b2f2us9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvciojsrcekmu5b2f2us9.png" alt="AirflowLogo" width="800" height="309"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Falar só sobre Airflow dá uma postagem bastante extensa. Mas vamos repassar o básico só pra gente se situar. Se você quiser, recomendo bastante que leia as &lt;a href="https://airflow.apache.org/" rel="noopener noreferrer"&gt;documentações&lt;/a&gt; no site oficial. &lt;/p&gt;

&lt;p&gt;Como eu comentei ali em cima, o Airflow é um serviço que vai te ajudar a "programaticamente criar, orquestrar e monitorar fluxos de trabalho". Para isso, você define sua sequência de tarefas com arquivos Python, que o Airflow irá entender e  construir &lt;a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph" rel="noopener noreferrer"&gt;DAGs&lt;/a&gt; através deles. &lt;/p&gt;

&lt;p&gt;É bem importante frisar que o papel do Airflow deve ser majoritariamente &lt;strong&gt;chamar outros serviços para realizar a computação pesada&lt;/strong&gt;, porque é aí que ele brilha. A execução e paralelização de atividades em si vai ser mais bem executada quando feita por um cluster de Spark ou de PrestoSQL, por exemplo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web UI
&lt;/h3&gt;

&lt;p&gt;A interface web é um componente que te permite visualizar todas as suas DAGs, o tempo de duração médio delas, a quantidade de falhas, o log de cada atividade. Com ela você também consegue ativar e pausar as suas DAGs, o que irá ser identificado pelo Scheduler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduler
&lt;/h3&gt;

&lt;p&gt;O Scheduler (orquestrador) é o coração do Airflow, pois ele é quem irá identificar comandos da Web UI, como quando você ativa uma DAG manualmente, e também definições de periodicidade para ativar os seus pipelines. Mas quem irá realmente executar o comando que chama outras aplicações são os Workers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worker
&lt;/h3&gt;

&lt;p&gt;O worker é o componente que de fato irá executar a tarefa. Se por exemplo você possui uma tarefa que vai chamar um executor externo, o comando que ativa isso é dado pelo worker.&lt;/p&gt;

&lt;h3&gt;
  
  
  Banco de dados
&lt;/h3&gt;

&lt;p&gt;O Airflow precisa armazenar informações, como credenciais de usuários, strings de conexão e também logs de DAGs e isso tudo fica armazenado em um banco de dados relacional. Por padrão se utiliza o Postgres, mas é possível conectar a um banco MySQL caso necessário.&lt;/p&gt;

&lt;p&gt;Depois dessa introdução talvez longa demais, vamos pro que interessa!&lt;/p&gt;

&lt;blockquote&gt;

&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Requisitos necessários
&lt;/h2&gt;

&lt;p&gt;Pra não ficar tão extenso por aqui, vou assumir aqui que você já tenha instalado e configurado na sua máquina:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kubectl&lt;/li&gt;
&lt;li&gt;helm&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Se estiver trabalhando com o MacOS, basta instalar ambas as ferramentas com o homebrew! 🍺&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Também vou partir do princípio que você possui acesso a um cluster de Kubernetes no seu provedor de nuvem. Caso você esteja estudando e queira ter a experiência do Kubernetes na máquina local, dê uma olhada no &lt;a href="https://kind.sigs.k8s.io/docs/user/quick-start/" rel="noopener noreferrer"&gt;Kind&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy inicial
&lt;/h2&gt;

&lt;p&gt;Para esse deploy, iremos utilizar o Helm chart oficial do Airflow. Para fazer a instalação padrão, basta você adicionar o repositório ao seu helm local com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm repo add apache-airflow https://airflow.apache.org
&lt;span class="nv"&gt;$ &lt;/span&gt;helm repo update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então, crie um &lt;em&gt;namespace&lt;/em&gt; que seja declarativo. Iremos utilizar aqui &lt;code&gt;airflow-dev&lt;/code&gt;, para representar que essa é a instância de airflow em desenvolvimento. Defina também um nome para sua &lt;em&gt;release&lt;/em&gt;. Normalmente se chama de &lt;code&gt;airflow&lt;/code&gt; mesmo. Rode então os seguinte comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create namespace airflow-dev
&lt;span class="nv"&gt;$ &lt;/span&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;airflow apache-airflow/airflow &lt;span class="nt"&gt;--namespace&lt;/span&gt; airflow-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boa! 🤩 Com isso, você acaba de fazer a instalação padrão da sua primeira instância de Airflow. Mas em cenários reais, quase nunca essa instalação vai atender suas necessidades. &lt;/p&gt;

&lt;h2&gt;
  
  
  Customizando o chart do Helm
&lt;/h2&gt;

&lt;p&gt;Como comentei, precisamos então acessar o arquivo &lt;code&gt;values.yaml&lt;/code&gt; para que façamos as nossas alterações. Gosto bastante de começar criando um arquivo vazio, com esse mesmo nome, e ir customizando aos poucos, de acordo com o &lt;a href="https://github.com/apache/airflow/blob/main/chart/values.yaml" rel="noopener noreferrer"&gt;arquivo completo do repositório&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Vamos lá? Crie um arquivo vazio e comece a editá-lo com seu editor de texto preferido. Aqui eu to usando o VS Code, mas não importa muito.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;airflow-deploy &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;touch &lt;/span&gt;airflow-deploy/values.yaml
&lt;span class="nv"&gt;$ &lt;/span&gt;code airflow-deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Definindo uma Fernet Key
&lt;/h3&gt;

&lt;p&gt;Essa chave é super simples de gerar e, caso você não a defina, o Airflow irá definir uma por você. Ela serve para criptografar as informações que você armazenará no Banco de Dados, como chaves de acesso a outros serviços, então é bem importante utilizá-la. Vale lembrar que é importante ter esse valor no momento de instalação, e não de atualização da sua &lt;em&gt;release&lt;/em&gt;. Então caso queira customizá-la, basta rodar o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from cryptography.fernet import Fernet; FERNET_KEY = Fernet.generate_key().decode(); print(FERNET_KEY)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aí você copia o valor que aparecer no seu bash e coloca no &lt;code&gt;values.yaml&lt;/code&gt; como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;fernetKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;sua-chave-hasheada&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Banco de dados externo
&lt;/h3&gt;

&lt;p&gt;Se você verificar, o deploy que você fez com o Helm ali em cima acabou de subir um Postgres no seu Kubernetes. Mas nem sempre é o desejável, principalmente se você já possui um banco de dados de pé para outras aplicações. Pra conectar com esse outro banco de dados, você vai precisar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desabilitar o Postgresql padrão&lt;/li&gt;
&lt;li&gt;Criptografar sua string de conexão&lt;/li&gt;
&lt;li&gt;Criar um secret no Kubernetes com a sua string de conexão&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para criptografar uma string, você vai executar esse comando no seu terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'sua-string-aqui'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para desencriptar e conferir, adicione o argumento &lt;code&gt;-d&lt;/code&gt; após &lt;code&gt;base64&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;O secret pode então ser criado se você criar um arquivo com o nome &lt;code&gt;airflow-db-secret.yaml&lt;/code&gt; e preencher com sua string criptografada no arquivo abaixo. Perceba que colocamos ali o namespace que você usou para seu deployment. Isso é importante para que a sua aplicação enxergue esse secret depois.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;airflow-secret&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;airflow-dev&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;sua-connection-string-criptografada&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aí você sobe esse secret pro seu Kubernetes com o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; airflow-db-secret.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Existe uma alternativa com o &lt;code&gt;kubectl&lt;/code&gt; que você consegue criar um segredo e não precisa criptografar essa string na mão. Sabe qual? 🤔 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seu &lt;code&gt;values.yaml&lt;/code&gt; vai ficar assim, por enquanto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;postgresql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;metadataSecretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;airflow-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sincronizando suas DAGs
&lt;/h3&gt;

&lt;p&gt;Agora que você já setou a conexão com o banco, precisamos pensar em como colocar suas DAGs (arquivos Python) pra dentro do Airflow. Uma opção bem fácil seria copiar os arquivos pra dentro da imagem de Docker antes de realizar o deploy. Mas isso não é uma boa prática, pois, a cada modificação ou mesmo nova DAG que seu time fizer, você vai precisar fazer uma atualização do seu deploy. E aí isso pode afetar algum pipeline que esteja rodando ou demorar um pouco mais pra acontecer. Ao invés disso, vamos usar um serviço bastante conveniente, chamado &lt;a href="https://github.com/kubernetes/git-sync" rel="noopener noreferrer"&gt;git-sync&lt;/a&gt;. &lt;br&gt;
Ele funciona como um container extra, que fica presente em todos os Pods do Airflow. E o que ele faz é sincronizar com uma periodicidade que você definir com o seu repositório remoto. Aí todas as suas DAGs ficam alocadas no Github/Gitlab e você pode fazer o controle do que é sincronizado com um processo de Gitflow, por exemplo.&lt;/p&gt;

&lt;p&gt;Pra isso, você precisará colocar os seguintes valores no seu &lt;code&gt;values.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;persistence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="na"&gt;gitSync&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git@github.com:&amp;lt;sua-organizacao&amp;gt;/&amp;lt;seu-repo&amp;gt;.git&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HEAD&lt;/span&gt;
    &lt;span class="na"&gt;depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;subPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/dags"&lt;/span&gt;
    &lt;span class="na"&gt;sshKeySecret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;airflow-ssh-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O primeiro argumento irá indicar que você não vai alocar suas DAGs em um Storage padrão, e na sequência já aparecem os argumentos do git-sync. Veja que você pode definir uma branch e até mesmo uma pasta dentro do seu repositório que você deseja que o Airflow enxergue as DAGs, definida no argumento &lt;code&gt;subPath&lt;/code&gt;. Por último ali eu defini a minha chave SSH como um segredo do Kubernetes. &lt;/p&gt;

&lt;p&gt;Você pode fazer isso com o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create secret generic airflow-ssh-key &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;id_rsa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/path/das/chaves-ssh-locais &lt;span class="nt"&gt;-n&lt;/span&gt; airflow-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Customizando a imagem base
&lt;/h3&gt;

&lt;p&gt;Se você estiver com as DAGs sendo sincronizadas via git-sync, customizar a imagem base pode não ser estritamente necessário. No entanto, caso você esteja trabalhando com algum &lt;a href="https://airflow.apache.org/docs/apache-airflow-providers/index.html" rel="noopener noreferrer"&gt;&lt;em&gt;provider&lt;/em&gt;&lt;/a&gt;, você vai precisar editar sua imagem. &lt;/p&gt;

&lt;p&gt;Crie uma Dockerfile e estenda com o que você precisar. Eu vou instalar o pacote extra do Databricks aqui, pois é bastante relevante para meus pipelines de dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; apache/airflow:2.1.0&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; apache-airflow-providers-databricks&lt;span class="o"&gt;==&lt;/span&gt;1.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beleza, aí você vai precisar &lt;em&gt;buildar&lt;/em&gt; essa imagem e subir no seu repositório de preferência. Caso queria saber exatamente como fazer isso, confira as documentações do &lt;a href="https://docs.docker.com/docker-hub/" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;. Seu &lt;code&gt;values.yaml&lt;/code&gt; vai ficar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;airflow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;sua-organizacao&amp;gt;/&amp;lt;sua-imagem&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;

&lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;airflow-registry&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui eu também criei um secret para armazenar as minhas credenciais de login no meu repositório privado. Isso é bem importante caso esteja colocando customizações que não podem ser expostas. Pra isso, basta executar o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create secret &lt;span class="nt"&gt;-n&lt;/span&gt; airflow-dev docker-registry airflow-registry &lt;span class="nt"&gt;--docker-server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;seu-servidor-docker&amp;gt; &lt;span class="nt"&gt;--docker-username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;seu-usuario&amp;gt; &lt;span class="nt"&gt;--docker-password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;sua-senha&amp;gt; &lt;span class="nt"&gt;--docker-email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;seu-email&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exportando logs
&lt;/h3&gt;

&lt;p&gt;Essa é uma das principais customizações, porque pela arquitetura padrão do Airflow no Kubernetes, as tarefas são executadas pelos Pods com os Workers. Esses Pods sobem quando a tarefa é demandada pelo Scheduler, executam e desligam. Só que ao desligar, os logs dessa execução são apagados junto do container. &lt;/p&gt;

&lt;p&gt;Existem duas soluções principais pra isso: criar um Persistent Volume no Kubernetes e exportar os logs pra lá ou conectar-se a um Storage de nuvem, como por exemplo o s3. Nesse caso, vou mostrar como eu fiz para me conectar ao Blob Storage da Azure, que foi um pouco mais chato (de achar referência ou documentação, mas não de configurar) do que teria sido com o s3 ou GCS. &lt;/p&gt;

&lt;p&gt;Basta você incluir o seguinte no seu &lt;code&gt;values.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;core&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;logging_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG"&lt;/span&gt;
    &lt;span class="na"&gt;fab_logging_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG"&lt;/span&gt;
  &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;remote_logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;remote_base_log_folder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wasb-airflow-logs"&lt;/span&gt;
    &lt;span class="na"&gt;remote_log_conn_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wasb_default"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, você está setando o nível de log das tarefas para "DEBUG". Você diz que os logs irão para uma pasta chamada &lt;code&gt;wasb-airflow-logs&lt;/code&gt;. É bem importante que o nome da sua pasta comece com &lt;code&gt;wasb-&lt;/code&gt;, caso contrário os templates não funcionarão (pelo menos não funcionaram pra mim). &lt;br&gt;
Além disso, você precisa dizer o id da conexão que você fará com o Blob. No meu caso, chamei de &lt;code&gt;wasb_default&lt;/code&gt;. Vou colocar um tópico para como setar essa conexão depois de subir as customizações ali em baixo, tá?&lt;/p&gt;

&lt;p&gt;Agora quando você executar uma DAG, os logs das tarefas devem cair dentro do Blob, nessa localização. E você também consegue acessar diretamente da UI do Airflow, navegando pelas DAGs. &lt;/p&gt;
&lt;h3&gt;
  
  
  Exportando métricas para o Datadog
&lt;/h3&gt;

&lt;p&gt;As documentações do Datadog no dia dessa postagem não contemplam exemplos com o Helm chart oficial do Airflow. E foi por essa dificuldade que resolvi escrever. É, como muita coisa na vida, ridiculamente simples. Mas por algum motivo as documentações do Datadog apontam pra um chart mantido pela comunidade e usam annotations ao invés do que o que é necessário. Estranho. &lt;/p&gt;

&lt;p&gt;Enfim, temos aqui no nosso cluster a nossa instância de Datadog configurada com DaemonSets, que irão sempre ter Pods atrelados a todos os nós, para pegar métricas dos containers e Pods que subirem e monitorar o nosso cluster como um todo. No entanto, você consegue também exportar métricas específicas do Airflow para esse serviço através do StatsD. Pra não me alongar muito, o que você vai precisar fazer no &lt;code&gt;values.yaml&lt;/code&gt; é o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;statsd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;statsd_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;statsd_port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8125&lt;/span&gt;

&lt;span class="na"&gt;extraEnv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;- name: AIRFLOW__METRICS__STATSD_HOST&lt;/span&gt;
    &lt;span class="s"&gt;valueFrom:&lt;/span&gt;
      &lt;span class="s"&gt;fieldRef:&lt;/span&gt;
        &lt;span class="s"&gt;fieldPath: status.hostIP&lt;/span&gt;
  &lt;span class="s"&gt;- name: DD_AGENT_HOST&lt;/span&gt;
    &lt;span class="s"&gt;valueFrom:&lt;/span&gt;
      &lt;span class="s"&gt;fieldRef:&lt;/span&gt;
          &lt;span class="s"&gt;fieldPath: status.hostIP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A definição desses valores irá:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criar um pod para onde irão ser direcionadas as métricas do Airflow&lt;/li&gt;
&lt;li&gt;Mudar a porta padrão do StatsD para a 8125 (requerida pelo Datadog por padrão)&lt;/li&gt;
&lt;li&gt;Apontar o host do StatsD do Airflow para o nó do Kubernetes onde ele está instalado &lt;/li&gt;
&lt;li&gt;Apontar para o mesmo host onde está o Agent do Datadog &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Parece muita coisa, mas são apenas essas as configurações que eu precisei pra fazer funcionar a conexão na minha instalação. Aí com isso posso criar um belíssimo dashboard para acompanhar a saúde da minha aplicação. Legal demais 😃 &lt;/p&gt;

&lt;h3&gt;
  
  
  Outros
&lt;/h3&gt;

&lt;p&gt;O que eu fiz foi não subir um componente de mensageria (Redis), que aumentaria bastante a complexidade da instalação nesse primeiro momento. Por isso, também desabilitei o Flower UI, que é uma interface gráfica para acompanhar esse serviço. Vamos ver então como ficou o arquivo &lt;code&gt;values.yaml&lt;/code&gt; final?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Fernet Key&lt;/span&gt;
&lt;span class="na"&gt;fernetKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;sua-chave-hasheada&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;# Imagem customizada&lt;/span&gt;
&lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;airflow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;sua-organizacao&amp;gt;/&amp;lt;sua-imagem&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;

&lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;airflow-registry&lt;/span&gt;


&lt;span class="c1"&gt;# Executor de Kubernetes&lt;/span&gt;
&lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KubernetesExecutor"&lt;/span&gt;

&lt;span class="c1"&gt;# StatsD&lt;/span&gt;
&lt;span class="na"&gt;statsd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;extraEnv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;- name: AIRFLOW__METRICS__STATSD_HOST&lt;/span&gt;
    &lt;span class="s"&gt;valueFrom:&lt;/span&gt;
      &lt;span class="s"&gt;fieldRef:&lt;/span&gt;
        &lt;span class="s"&gt;fieldPath: status.hostIP&lt;/span&gt;
  &lt;span class="s"&gt;- name: DD_AGENT_HOST&lt;/span&gt;
    &lt;span class="s"&gt;valueFrom:&lt;/span&gt;
      &lt;span class="s"&gt;fieldRef:&lt;/span&gt;
          &lt;span class="s"&gt;fieldPath: status.hostIP&lt;/span&gt;

&lt;span class="c1"&gt;# Redis e Flower&lt;/span&gt;
&lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;flower&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="c1"&gt;# Banco de Dados&lt;/span&gt;
&lt;span class="na"&gt;postgresql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;metadataSecretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;airflow-secret&lt;/span&gt;

&lt;span class="c1"&gt;# Git Sync&lt;/span&gt;
&lt;span class="na"&gt;dags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;persistence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;gitSync&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git@github.com:&amp;lt;sua-organizacao&amp;gt;/&amp;lt;seu-repo&amp;gt;.git&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HEAD&lt;/span&gt;
    &lt;span class="na"&gt;depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;subPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/dags"&lt;/span&gt;
    &lt;span class="na"&gt;sshKeySecret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;airflow-ssh-key&lt;/span&gt;

&lt;span class="c1"&gt;# Logs e StatsD&lt;/span&gt;
&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;core&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;logging_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG"&lt;/span&gt;
    &lt;span class="na"&gt;fab_logging_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG"&lt;/span&gt;
  &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;remote_logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;remote_base_log_folder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wasb-airflow-logs"&lt;/span&gt;
    &lt;span class="na"&gt;remote_log_conn_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wasb_default"&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;statsd_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;statsd_port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8125&lt;/span&gt;

&lt;span class="na"&gt;logs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;persistence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Subindo suas alterações
&lt;/h3&gt;

&lt;p&gt;Para subir todas essas customizações, basta você rodar o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm upgrade airflow apache-airflow/airflow &lt;span class="nt"&gt;-n&lt;/span&gt; airflow-dev &lt;span class="nt"&gt;-f&lt;/span&gt; airflow-deploy/values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E é isso! Agora você tem uma aplicação super massa com muita coisa customizada de pé. Comemore! 🚀 &lt;/p&gt;

&lt;h3&gt;
  
  
  Extra: Criando uma conexão com o seu Storage
&lt;/h3&gt;

&lt;p&gt;Como comentei durante o tópico anterior, vamos ver como fazer para autenticar suas credenciais no Storage Account da Azure. A forma mais fácil de fazer isso é pela Web UI. Como você provavelmente ainda não setou um Ingress, para que você possa visualizar a web UI, faça um &lt;code&gt;port-forward&lt;/code&gt; no container da web. Você pode fazer isso com o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl port-forward svc/airflow-webserver 8080:8080 &lt;span class="nt"&gt;--namespace&lt;/span&gt; airflow-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, vá ao seu &lt;code&gt;localhost:8080&lt;/code&gt; no seu navegador, logue com &lt;code&gt;admin/admin&lt;/code&gt; e faça o seguinte caminho:&lt;br&gt;
&lt;code&gt;Admin &amp;gt; Connections &amp;gt; +&lt;/code&gt; &lt;br&gt;
Aí defina o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Conn Type: Azure Blob Storage
Blob Storage Login: &amp;lt;seu-storage-account&amp;gt;
Blob Storage Shared Access Key: &amp;lt;sua-chave-de-acesso&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa é uma das formas de se autenticar no Blob, a outra pode ser a própria string de conexão. Por padrão os logs irão para o seu Storage em um container chamado "airflow-logs", dentro da pasta que você definiu ali em cima.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concluindo
&lt;/h2&gt;

&lt;p&gt;Se você conseguiu acompanhar até aqui, ótimo. Acho que esse post pode ser muito útil para muitas pessoas que, como eu, podem ficar por dias travadas em alguns pontos que deveriam ser simples. &lt;/p&gt;

&lt;p&gt;Ainda existem algumas coisas bem importantes para você fazer antes de considerar que possui uma instância em produção, como, por exemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configurar o Ingress e acessar a web UI através de um DNS&lt;/li&gt;
&lt;li&gt;Configurar o PgBouncer para controlar o número de conexões abertas no seu banco de dados pelo Airflow&lt;/li&gt;
&lt;li&gt;Dimensionar corretamente o seu cluster &lt;/li&gt;
&lt;li&gt;Alocar os componentes em diferentes nós através de &lt;code&gt;nodeSelectors&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Criar a mesma instância em um ambiente isolado e vincular as DAGs a uma branch diferente no seu repositório&lt;/li&gt;
&lt;li&gt;Construir pipelines de dados que entreguem muito valor para o seu negócio =)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deletando os recursos
&lt;/h3&gt;

&lt;p&gt;Se você quer fazer o deploy com uma fernetKey diferente, ou mesmo pausar a utilização de recursos, você pode deletar tudo o que foi feito com um simples comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm delete airflow &lt;span class="nt"&gt;-n&lt;/span&gt; airflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Espero que tenha sido uma boa leitura e, caso tenha alguma dúvida, me avisa aqui nos comentários. &lt;/p&gt;

&lt;p&gt;Um abraço!&lt;/p&gt;

</description>
      <category>airflow</category>
      <category>kubernetes</category>
      <category>helm</category>
      <category>deploy</category>
    </item>
    <item>
      <title>Git para Ciência de Dados</title>
      <dc:creator>Murilo Menezes Mendonça</dc:creator>
      <pubDate>Fri, 20 Nov 2020 13:00:03 +0000</pubDate>
      <link>https://forem.com/murilommen/git-para-ciencia-de-dados-442a</link>
      <guid>https://forem.com/murilommen/git-para-ciencia-de-dados-442a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A foto de cima é do Yancy Min, do &lt;a href="https://unsplash.com/photos/842ofHC6MaI?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditShareLink" rel="noopener noreferrer"&gt;Unplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Olá! Esse post é a minha estreia aqui e eu vou tentar deixar um pouco mais claro os conceitos de Git, o porquê que é bom de usar, as boas práticas que eu adoto no meu dia-a-dia e também alguns macetes pra você não ter problemas lá na frente - ou ter menos problemas, pelo menos. Eu to assumindo que você trabalha com Ciência de Dados, mas só pra tentar trazer alguns exemplos pra nossa realidade. Se você não é um DS, ainda acho que tem bastante coisa aqui pra aproveitar. Bora? 😄&lt;/p&gt;

&lt;h1&gt;
  
  
  O que é Git?
&lt;/h1&gt;

&lt;p&gt;Pra colocar em uma frase: Git é uma ferramenta gratuita e de código aberto para controle de versão de código-fonte. O troço é tão relevante, que foi criado pelo Linus Torvalds, criador do Linux, justamente pra controlar as versões do &lt;em&gt;kernel&lt;/em&gt;. Doido, né?&lt;/p&gt;

&lt;h3&gt;
  
  
  O básico
&lt;/h3&gt;

&lt;p&gt;O que isso significa é que ele vai gerenciar pra você cada modificação que você fizer no seu modelo, alguma variável nova que você está calculando, enfim, tudo o que for modificado vai ser controlado por ele, através de cópias e chaves. Se quiser ler as documentações mais a fundo depois, dá uma olhada no &lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;site oficial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Então imagina que você hoje tenha essa estrutura em uma pasta:&lt;/p&gt;

&lt;pre&gt;
notebooks/
├── meu_modelo_v1.ipynb     
├── meu_modelo_v2.ipynb
├── meu_modelo_v2_27062021.ipynb
├── meu_modelo_final.ipynb
├── meu_modelo_final2.ipynb
&lt;/pre&gt;

&lt;p&gt;E você vai passar a ter uma estrutura assim, quando começar a usar Git:&lt;/p&gt;

&lt;pre&gt;
notebooks/
├── meu_modelo.ipynb     
&lt;/pre&gt;

&lt;p&gt;Ué, mas que bruxaria é essa? 🧙&lt;/p&gt;

&lt;h3&gt;
  
  
  Versões através de chaves
&lt;/h3&gt;

&lt;p&gt;Com esse desenho lindo aqui em baixo (risos) eu tentei mostrar como fica o seu código ao longo do tempo, da direita pra esquerda. O que acontece é que cada versão do seu código vai ser copiada pelo Git e atribuída a uma chave identificadora única. Isso acontece toda vez que você salvar o seu trabalho, ou, quando você der um &lt;em&gt;commit&lt;/em&gt; - eu vou explicar esse jargão um pouco mais pra frente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhnp66ah6zz9cq5eozh4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhnp66ah6zz9cq5eozh4i.png" alt="Alt Text" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Qual a diferença entre Git e Github?
&lt;/h3&gt;

&lt;p&gt;Se a gente controlar as versões do nosso trabalho localmente, isso já dá uma aliviada muito grande. Mas se a gente pensa em trabalhar em equipe ou até mesmo em não depender do nosso computador funcionando sempre, é muito importante que isso vá pra algum lugar na nuvem, em um &lt;em&gt;servidor remoto&lt;/em&gt;, para que a gente possa acessar depois. O Github é esse lugar. &lt;/p&gt;

&lt;p&gt;Além de armazenar nosso código e arquivos, ele também possibilita a gente controlar algumas coisas através da sua interface gráfica, facilitando bastante o trabalho no dia-a-dia. Além do Github, existem outros servidores remotos de Git, como Gitlab e Bitbucket. Escolhi falar sobre o Github porque é gratuito, o mais popular e, na minha opinião, muito completo. &lt;/p&gt;

&lt;h1&gt;
  
  
  Trabalhando com Git no dia-a-dia
&lt;/h1&gt;

&lt;p&gt;Dando um salto para o fluxo de trabalho, vamos falar um pouco agora sobre como a gente trabalha com Git no dia-a-dia. Essa é a parte mais densa dessa postagem, mas vamo junto que isso vai ser muito útil para você! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTA:&lt;/em&gt;&lt;/strong&gt; Estou aqui partindo do pressuposto que você já baixou o Git na sua máquina e também tem uma conta no Github. Caso contrário, pesquise sobre como fazer e volte aqui depois!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Estrutura do Git e comandos principais
&lt;/h3&gt;

&lt;p&gt;Um pouco mais abaixo eu resolvi deixar mais uma obra de arte para tentar visualmente caminhar pelos comandos mais importantes - não todos - e até entender como e porque a gente usa eles. &lt;/p&gt;

&lt;p&gt;O primeiro e talvez mais frequente comando que você vai utilizar é o&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com ele, você consegue saber o que tá acontecendo na sua pasta. Quais arquivos você tá e não tá controlando, se a sua versão do código está atualizada de acordo com o seu repositório e assim por diante. Sempre que você quiser conferir se deu certo o que você fez, mande um &lt;code&gt;git status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiwdks64pvy4rr4q1jpru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiwdks64pvy4rr4q1jpru.png" alt="Alt Text" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando você fizer as modificações no seu código, você vai mandá-lo pra uma área de &lt;em&gt;staging&lt;/em&gt;, que vai basicamente indicar pro Git que esse código é um arquivo que você quer controlar a versão. Você faz isso através do comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git add meu_arquivo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim, o &lt;code&gt;meu_arquivo.py&lt;/code&gt; irá ser indexado para que entre no seu próximo &lt;em&gt;commit&lt;/em&gt; realizado. Se você quiser mandar para a área de indexação todos os seus arquivos de uma vez, use um &lt;em&gt;wildcard&lt;/em&gt;, como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas tenha &lt;strong&gt;cuidado&lt;/strong&gt;! É muito fácil mandar algum arquivo ou diretório indesejado utilizando um &lt;em&gt;wildcard&lt;/em&gt;. Então depois de adicionar os arquivos para a indexação, lembre-se de rodar um &lt;code&gt;git status&lt;/code&gt; para saber o que está sendo indexado para ser versionado, tá? &lt;/p&gt;

&lt;p&gt;Uma vez indexado, seu código poderá ser salvo no repositório local através do comando &lt;code&gt;commit&lt;/code&gt;. Essa etapa também é super importante, pois aqui você terá a possibilidade de dar um resumo sobre quais foram as alterações feitas nessa nova versão do código, de uma forma breve e objetiva. Para isso, use o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"modelo com média de preços para treino"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O argumento &lt;code&gt;-m&lt;/code&gt; possibilita que você escreva uma frase para representar esse &lt;em&gt;commit&lt;/em&gt;. Essa parte é tão crítica, que existem alguns &lt;a href="https://code.likeagirl.io/antes-e-depois-das-minhas-mensagens-de-commit-1ad8cc288d05" rel="noopener noreferrer"&gt;posts&lt;/a&gt; sobre como escrever uma boa mensagem no &lt;em&gt;commit&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Uma vez que seu repositório local conhece as modificações que foram indexadas para esse &lt;em&gt;commit&lt;/em&gt;, ta na hora de "empurrar" isso pra nuvem, com o comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependendo de como você estruturou sua conexão, isso pode mandar as modificações direto para o seu repositório no Github ou te pedir o login e senha. De todo modo, tá salvo!&lt;/p&gt;

&lt;p&gt;Os comandos &lt;code&gt;checkout&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt; e &lt;code&gt;fetch&lt;/code&gt; eu vou cobrir no próximo tópico.&lt;/p&gt;

&lt;h3&gt;
  
  
  Aproveite sua IDE!
&lt;/h3&gt;

&lt;p&gt;Se você tá acostumado a trabalhar em uma IDE ou Editor de Texto, aproveite as funcionalidades que eles trazem para controle de versão de código. No PyCharm, por exemplo, as linhas que você modifica, apaga ou adiciona, criam marcadores específicos, que te indicam o que foi feito ali em relação ao código original.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwv1i7jcgjcsc8z9qqeyk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwv1i7jcgjcsc8z9qqeyk.png" alt="Alt Text" width="203" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Além disso, os arquivos modificados também ficam com cores diferentes. E não só você pode acompanhar visualmente as modificações, como também pode realizar &lt;em&gt;add&lt;/em&gt;, &lt;em&gt;commit&lt;/em&gt; e &lt;em&gt;push&lt;/em&gt; com apenas alguns cliques. Eu gosto muito de fazer tudo em um lugar só, então vale muito a pena explorar isso. Confia! 🤞&lt;/p&gt;

&lt;h1&gt;
  
  
  Trabalhando em equipe
&lt;/h1&gt;

&lt;p&gt;Bom, agora que você já tem uma ideia de como controlar as versões do código, chegou a hora de falar um pouco sobre como você faz pra utilizar isso na vida real, trabalhando com mais pessoas. E não ache que porque você é o único Cientista de Dados do seu projeto você está sozinho nessa. &lt;br&gt;
&lt;strong&gt;O seu eu do futuro também é o seu colega de trabalho&lt;/strong&gt;. Parece meio louco pensar nisso, mas se você passar alguns meses sem mexer com um projeto, vai ser muito difícil olhar pra trás e saber o que foi feito sem existir uma boa documentação e cuidado com o trabalho realizado. &lt;/p&gt;
&lt;h3&gt;
  
  
  Branches
&lt;/h3&gt;

&lt;p&gt;Pensando em trabalhar com mais pessoas, é fundamental que exista um código principal e que sejam criadas versões espelhadas do seu projeto, para que você possa fazer quaisquer mudanças sem afetar o código principal. &lt;/p&gt;

&lt;p&gt;Pensando nisso, criou-se o conceito de &lt;em&gt;branch&lt;/em&gt; (em inglês, galho de árvore), que são ramificações do código principal. Para criar uma &lt;em&gt;branch&lt;/em&gt;, você pode utilizar a interface gráfica do Github, clicando onde estiver escrito &lt;em&gt;master&lt;/em&gt; (ou &lt;em&gt;main&lt;/em&gt;), como mostra a figura:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhpbe0s2h5hsrjwvpi6hn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhpbe0s2h5hsrjwvpi6hn.png" alt="Alt Text" width="392" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feito isso, mude para a branch criada no seu local de trabalho, utilizando os seguintes comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git fetch
&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout my_new_branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como vimos na figura da seção anterior, o &lt;code&gt;git fetch&lt;/code&gt; irá pegar as modificações do repositório remoto e trazê-las para o repositório local. Isso faz com que o Git local possa identificar que uma nova branch chamada &lt;code&gt;my_new_branch&lt;/code&gt; foi criada. Com o comando &lt;code&gt;checkout&lt;/code&gt;, você irá passar a trabalhar nela.&lt;/p&gt;

&lt;p&gt;A partir daqui, todas as suas modificações irão ser contempladas e realizadas na sua própria &lt;em&gt;branch&lt;/em&gt;, sem afetar o código principal. Uma vez que você estiver satisfeito com as suas modificações, você poderá abrir uma &lt;em&gt;Pull Request&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pull Requests
&lt;/h3&gt;

&lt;p&gt;Se você estiver trabalhando no seu código em uma &lt;em&gt;branch&lt;/em&gt; específica, a versão principal ficará desatualizada em relação às suas modificações, certo? Por isso, quando você julgar que essas modificações podem fazer parte do código principal, abra uma Pull Request (PR). Pra fazer isso pelo Github, basta você abrir a aba de PR's, clicar em &lt;em&gt;New Pull Request&lt;/em&gt; e seguir as instruções.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa5pz0c2nhxljs7v03k06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa5pz0c2nhxljs7v03k06.png" alt="Alt Text" width="800" height="83"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vale ressaltar aqui que é &lt;strong&gt;muito importante&lt;/strong&gt; que alguém revise suas modificações. Para isso, indique alguém do seu time para ser um "Reviewer" do lado direito da janela principal da PR. Isso faz com que a pessoa veja com clareza as modificações realizadas no seu código, escreva mensagens específicas, aprove ou até faça a requisição de modificações.&lt;/p&gt;

&lt;p&gt;Uma vez aprovada a PR, o código principal irá contemplar as suas alterações e você contribuiu para o projeto de uma forma controlada e responsável! &lt;/p&gt;

&lt;p&gt;Tendo em vista que outras pessoas podem ter feito PRs e modificações na &lt;em&gt;branch&lt;/em&gt; principal, é importante periodicamente rodar o comando &lt;code&gt;git fetch&lt;/code&gt;. Existe uma opção no VS Code que ele faz isso pra você! &lt;/p&gt;

&lt;p&gt;Se você desejar que as alterações do código feitas venham diretamente para o seu local de trabalho, você também pode utilizar o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git pull
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalizando assim a lista de comandos que eu tinha prometido anteriormente. &lt;/p&gt;

&lt;h3&gt;
  
  
  Motivos para pensarmos em Gitflow
&lt;/h3&gt;

&lt;p&gt;Esse tópico pode até ser considerado um pouco mais avançado, mas a filosofia dele é extremamente importante e eu estou colocando nessa postagem porque eu queria que alguém tivesse me dito isso quando eu estava começando.&lt;/p&gt;

&lt;p&gt;Se você já trabalhou com desenvolvimento ou pelo menos foi em algum &lt;em&gt;meetup&lt;/em&gt;, muito provavelmente você já ouviu a seguinte frase, entoada a plenos pulmões:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"NUNCA DÊ COMMIT NA MASTER"&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mas... por que?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Primeiro que, se você fizer um &lt;em&gt;commit&lt;/em&gt; no código principal que esteja com algum pequeno &lt;em&gt;bug&lt;/em&gt;, outras pessoas vão deixar de ter um código que funciona para trabalhar, e isso por si só já pode ser um baita problema. &lt;/p&gt;

&lt;p&gt;Mas vamos pensar mais além, se temos uma aplicação em produção, como um modelo de Análise de Crédito, por exemplo, ele provavelmente vai estar sendo consumido por uma &lt;em&gt;pipeline&lt;/em&gt; de Integração e &lt;em&gt;Deploy&lt;/em&gt; contínuos (CI/CD). Isso significa que a aplicação se baseia na &lt;em&gt;branch&lt;/em&gt; principal para funcionar. Se você der um &lt;em&gt;commit&lt;/em&gt; diretamente nela, a aplicação vai ser automaticamente atualizada.&lt;/p&gt;

&lt;p&gt;Se seu código possui erros, no melhor dos cenários ela para de funcionar. No pior dos cenários, ela irá entregar análises de crédito erradas e até trazer um grande prejuízo pra empresa. Chato, né? Então por isso que é muito importante sempre pensar em trabalhar em &lt;em&gt;branches&lt;/em&gt; e realizar PR's. Essa é a mensagem.&lt;/p&gt;

&lt;p&gt;O termo "Gitflow" é utilizado baseando-se numa metodologia que padroniza a nomenclatura de &lt;em&gt;branches&lt;/em&gt; e também parte do princípio que o ciclo de vida de uma branch é bem curto - no máximo 3 dias. Isso faz com que o código seja constantemente revisado, que as modificações nele sejam incrementais e que exista uma política de governança bem estabelecida para o trabalho. Se quiser ler mais sobre, veja &lt;a href="https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow" rel="noopener noreferrer"&gt;essa postagem&lt;/a&gt; em inglês da Atlassian.&lt;/p&gt;

&lt;h3&gt;
  
  
  Não versione dados com Git
&lt;/h3&gt;

&lt;p&gt;"Bom, se é importante eu salvar meu trabalho e as versões dele, então fica mais fácil já colocar junto também os dados em CSV que eu tô utilizando, certo?"&lt;/p&gt;

&lt;p&gt;E aqui vai um grande &lt;strong&gt;NÃO&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O Git foi feito para controlar inúmeras versões dos códigos escritos justamente porque são arquivos extremamente leves e fáceis de serem controlados. Se você trabalha com dados locais, como arquivos em CSV ou XLSX, crie um arquivo no seu repositório chamado &lt;code&gt;.gitignore&lt;/code&gt;. Com ele, você vai poder dizer o que o Git não deve olhar quando verificar alterações. Um template que eu uso pode ser escrito assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Python secondary files
__pycache__/
*.py[cod]
*$py.class
.ipynb_checkpoints/

# VS Code config file
.vscode/

# Datasets
*.csv
*.xlsx

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/


# Other files
.idea/
.idea/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Existem ferramentas específicas para versionamento de dados, como o &lt;a href="https://dvc.org/" rel="noopener noreferrer"&gt;DVC&lt;/a&gt;, mas que fogem do escopo desse artigo.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resumão
&lt;/h1&gt;

&lt;p&gt;Nesse meu primeiro artigo, quis trazer um "curso relâmpago" de Git, com algumas especificidades de Data Science pra te ajudar a trilhar essa jornada e estabelecer conhecimentos fundamentais do Desenvolvimento de Software para o seu dia-a-dia.&lt;/p&gt;

&lt;p&gt;Sei que se você nunca mexeu com Git essa postagem pode ter sido cheia de jargões ou conceitos que ainda estão um pouco obscuros pra você. Ao mesmo tempo em que é apaixonante, também pode ser exaustivo trabalhar com tecnologia. Não se desespere! Pesquise mais, leia mais e exercite sua curiosidade, que eu garanto que isso tudo vai se esclarecer aos poucos pra você. &lt;/p&gt;

&lt;p&gt;Se mesmo assim tem algum conceito que eu falei aqui e que ainda não tá claro, me manda uma mensagem, comenta aqui em baixo e me ajude a tornar essa postagem ainda mais acessível. &lt;/p&gt;

&lt;p&gt;Um abraço e boa caminhada! 🚀&lt;/p&gt;

</description>
      <category>git</category>
      <category>data</category>
      <category>datascience</category>
      <category>github</category>
    </item>
  </channel>
</rss>
