<?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>DEV Community: Espoir Murhabazi</title>
    <description>The latest articles on DEV Community by Espoir Murhabazi (@espoir).</description>
    <link>https://dev.to/espoir</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%2F9206%2F8159a728-621b-4f37-9ba3-b9bff6bdb6b4.jpg</url>
      <title>DEV Community: Espoir Murhabazi</title>
      <link>https://dev.to/espoir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/espoir"/>
    <language>en</language>
    <item>
      <title>Batch Vector Search with PgVector and PostgreSQL Using Cross Lateral Joins</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Mon, 15 Sep 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/espoir/supercharge-postgres-vector-search-cross-join-lateral-for-bacth-vector-search-2e48</link>
      <guid>https://dev.to/espoir/supercharge-postgres-vector-search-cross-join-lateral-for-bacth-vector-search-2e48</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F465jrln3ysbck9bzfs10.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F465jrln3ysbck9bzfs10.jpg" alt="Needle in a Haystack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last week, while working on a project, I needed to perform a batch vector search in Postgres—sending multiple embedding vectors at once to avoid using a for-loop.&lt;/p&gt;

&lt;p&gt;I started googling online and found an old answer on StackOverflow using a query with &lt;code&gt;UNION&lt;/code&gt;s. When I asked Deepseek how to improve the query, it recommended I use a &lt;code&gt;CROSS JOIN LATERAL&lt;/code&gt;, which seemed to be faster than a normal union.&lt;/p&gt;

&lt;p&gt;Then I started digging a little bit deeper to understand what cross lateral joins are. Unfortunately, I couldn’t find any blog online that was explaining them in the context of a vector database, which is why I decided to put this guide together.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Let’s say you have a list of questions and you need to perform an embedding search for all of them at once. This can happen when you need to evaluate how an embedding model performs on a set of queries. For each query, you want to retrieve the top 10 relevant chunks. In this post, we will work with a document table of this form for simplicity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document
--
doc_id: int
embedding: vector(1024)
content: Text

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

&lt;/div&gt;

&lt;h3&gt;
  
  
  Recap on Similarity Search
&lt;/h3&gt;

&lt;p&gt;You have a query text that has been embedded into a vector using an embedding model. You want to query your vector database to retrieve similar text to your query using the embedding and cosine similarity as a distance measure.&lt;/p&gt;

&lt;p&gt;Here is how you will perform the query using Postgres with the pgvector extension installed. You would perform something along these lines:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"embedding"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_embedding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&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;similarity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"url"&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"documents"&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you have been working with RAG, that query is familiar to you.&lt;/p&gt;
&lt;h2&gt;
  
  
  Different Approaches to Solve the Problem:
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Similarity search with multiple queries
&lt;/h3&gt;

&lt;p&gt;Assuming now that you have 100 or 1000 queries that you want to send to the database and for each query you want to retrieve the corresponding documents.&lt;/p&gt;

&lt;p&gt;A naive Python code would look like this:&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="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;SELECT (1 - (&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &amp;lt;=&amp;gt; %({query_embedding})s::vector)) as similarity, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; FROM &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; ORDER BY similarity desc LIMIT 5&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;question_embedding&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;db_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;question_embedding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;With this approach, you can see for each question you will be performing a round trip to the database and retrieve the results. If your database is hosted in a remote server that round trip can be costly for the performance of your application.&lt;/p&gt;

&lt;p&gt;That can be inefficient when you are dealing with hundreds or thousands of vectors. This is why I started thinking that there could be a better way to do this.&lt;/p&gt;
&lt;h3&gt;
  
  
  First Improvement: The UNION ALL Approach
&lt;/h3&gt;

&lt;p&gt;One way that came to my mind was to use the union query. With the union query, our query will look like this.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"embedding"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;query_embedding_1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&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;similarity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"url"&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"documents"&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;UNION&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"embedding"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;query_embedding_2&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&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;similarity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"url"&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"documents"&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;UNION&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"embedding"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;query_embedding_n&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&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;similarity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"url"&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"documents"&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;A Python code to generate that query would be something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;base_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"&lt;/span&gt;&lt;span class="se"&gt;""&lt;/span&gt;&lt;span class="nv"&gt;SELECT (1 - ("&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="nv"&gt;" &amp;lt;=&amp;gt; %(query_embedding_{index})s::vector)) as similarity, "&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="nv"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="nv"&gt;" FROM "&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="nv"&gt;" ORDER BY similarity desc LIMIT 5&lt;/span&gt;&lt;span class="se"&gt;""&lt;/span&gt;&lt;span class="nv"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;all_queries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;formatted_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;all_queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formatted_query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;final_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;" UNION ALL "&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_queries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="k"&gt;execute&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will give better performance than the previous one, but there is still room for improvement. And that is when the cross lateral join comes in.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Superior Solution: Cross Join Lateral
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Cross lateral join&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Before diving deep into the SQL aspect of cross lateral join, let’s recap a concept from high school algebra.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Cartesian Product&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The Cartesian product of two sets &lt;em&gt;&lt;em&gt;A&lt;/em&gt;&lt;/em&gt; and &lt;em&gt;&lt;em&gt;B&lt;/em&gt;&lt;/em&gt;, written &lt;em&gt;&lt;em&gt;A x B&lt;/em&gt;&lt;/em&gt;, is the set of all ordered pairs in which the first element belongs to &lt;em&gt;&lt;em&gt;A&lt;/em&gt;&lt;/em&gt; and the second belongs to &lt;em&gt;&lt;em&gt;B&lt;/em&gt;&lt;/em&gt;: 

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;A×B=(a,b)∣a∈A and b∈BA \times B = {(a, b) \mid a \in A \text{ and } b \in B}&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;A&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;b&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;∣&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;∈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;A&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt; and &lt;/span&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;b&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;∈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Let’s assume we have &lt;/p&gt;

&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;A=1,2,3A = {1, 2, 3}&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;A&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;and &lt;/p&gt;

&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;B=A,B,CB = {A, B, C}&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;A&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;, the Cartesian product of (A) and (B) will be the following: &lt;/p&gt;

&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;A×B=(1,A),(1,B),(1,C),(2,A),(2,B),(2,C),(3,A),(3,B),(3,C)A \times B = {(1,A), (1, B), (1,C), (2,A), (2, B), (2,C), (3,A), (3, B), (3,C)}&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;A&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;A&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;A&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;3&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;A&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;3&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;B&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;3&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;.&lt;/p&gt;

&lt;p&gt;We can also note that the cardinality of &lt;em&gt;&lt;em&gt;A x B = |A| x |B|&lt;/em&gt;&lt;/em&gt;. In our example, we will have the cardinality equal to nine.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;From Cartesian Product to Cross Join&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;With the Cartesian product in mind, let’s define the cross join:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The CROSS JOIN is used to generate a paired combination of each row of the first table with each row of the second table.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is an example of two tables and the resulting table from a cross join:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fu2oimhiv66wjynzi0ey2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fu2oimhiv66wjynzi0ey2.png" alt="Cross Join in SQL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cross Join in SQL&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It was taken from this &lt;a href="https://www.sqlshack.com/sql-cross-join-with-examples/" rel="noopener noreferrer"&gt;site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is the syntax of the cross join. Given two tables &lt;code&gt;Meals&lt;/code&gt; and &lt;code&gt;Drinks&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Meals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Drinks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Meals&lt;/span&gt;
&lt;span class="k"&gt;CROSS&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;Drinks&lt;/span&gt;

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  On To Cross Lateral Join
&lt;/h4&gt;

&lt;p&gt;What if we found a way to do better? As we have a list of vectors, how can we run the select against each vector in the list of vectors? This is where cross lateral join comes in handy.&lt;/p&gt;

&lt;p&gt;In the Postgres documentation, here is what is said about that query:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;LATERAL:&lt;/p&gt;

&lt;p&gt;The LATERAL key word can precede a sub-SELECT FROM item. This allows the sub-SELECT to refer to columns of FROM items that appear before it in the FROM list. (Without LATERAL, each sub-SELECT is evaluated independently and so cannot cross-reference any other FROM item.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a little bit convoluted and hard to explain.&lt;/p&gt;

&lt;p&gt;Let’s see how it works.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;em&gt;The Query:&lt;/em&gt;
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;vector_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;query_index&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
  &lt;span class="k"&gt;unnest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;ORDINALITY&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;vector_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;CROSS&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="k"&gt;LATERAL&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"embedding"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vector_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_vector&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;similarity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;"url"&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
      &lt;span class="nv"&gt;"documents"&lt;/span&gt;
    &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
      &lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt;
    &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&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;results&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;vector_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;

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

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;em&gt;Deconstructing the Magic Query&lt;/em&gt;
&lt;/h5&gt;

&lt;p&gt;Let’s now dissect the query and see how it works. It has two parts.&lt;/p&gt;

&lt;p&gt;Let’s look at the &lt;strong&gt;first one&lt;/strong&gt;. The left part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;  &lt;span class="k"&gt;unnest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;ORDINALITY&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;vector_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This part is the temporary table creation where a table is created and has each embedding vector as a row. So our table will have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector_0&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector_1&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector_2&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector_n&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ordinality&lt;/code&gt; keyword adds an index starting from 1 to each row in the returned value of the first part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then the second&lt;/strong&gt; part is a cross join. The table on the left is cross-joined with the table on the right. The LATERAL keyword helps to use the left table in the cross join clause. &lt;em&gt;Without it, each sub-SELECT is evaluated independently and so cannot cross-reference any other FROM item.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is why in the second item, we were able to reference the results of the first select as &lt;code&gt;vector_table.query_vector&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The subquery is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;    &lt;span class="k"&gt;SELECT&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"embedding"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vector_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_vector&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;similarity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;"url"&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
      &lt;span class="nv"&gt;"documents"&lt;/span&gt;
    &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
      &lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt;
    &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The documentation explains the execution perfectly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a FROM item contains LATERAL cross-references, evaluation proceeds as follows: for each row of the FROM item providing the cross-referenced column(s)… the LATERAL item is evaluated using that row or row set’s values of the columns. The resulting row(s) are joined as usual with the rows they were computed from. This is repeated for each row or set of rows from the column source table(s).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Benchmarks
&lt;/h3&gt;

&lt;p&gt;Let us benchmark the 3 approaches and find out which one is the fastest.&lt;/p&gt;

&lt;p&gt;We are running the query in a small setting where we have around 10k documents in our database each document has string content and embedding vector of size &lt;code&gt;1024&lt;/code&gt;. The database table is indexed on the embedding column using a &lt;code&gt;hnsw&lt;/code&gt; index. The database and the code where both running on my local machine a Mac M1 with 16GB of CPU.&lt;/p&gt;

&lt;p&gt;Later I will benchmark the three queries in a setting where the code run on a different machine than the database and I will update this section with the performance of the code in those settings.&lt;/p&gt;

&lt;p&gt;After benchmarking and performing an analyzis on the answer with my table I found a small gain of performance on a small table.&lt;/p&gt;

&lt;p&gt;In the upcoming version of this blog I replicate the setting in a table of millions documents and vector and report the performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this post we explained how cross lateral join works with PGVectors. In the next post I will run a benchmark of the cross lateral and compare it with. a normal for loop for batch vector search.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>pgvectorvectorsearch</category>
      <category>ai</category>
      <category>rag</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Mon, 26 May 2025 15:01:40 +0000</pubDate>
      <link>https://dev.to/espoir/-184e</link>
      <guid>https://dev.to/espoir/-184e</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/espoir/evaluation-metrics-for-summarization-3amo" class="crayons-story__hidden-navigation-link"&gt;Evaluation Metrics for Summarization&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/espoir" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F9206%2F8159a728-621b-4f37-9ba3-b9bff6bdb6b4.jpg" alt="espoir profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/espoir" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Espoir Murhabazi
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Espoir Murhabazi
                
              
              &lt;div id="story-author-preview-content-2520213" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/espoir" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F9206%2F8159a728-621b-4f37-9ba3-b9bff6bdb6b4.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Espoir Murhabazi&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/espoir/evaluation-metrics-for-summarization-3amo" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 26 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/espoir/evaluation-metrics-for-summarization-3amo" id="article-link-2520213"&gt;
          Evaluation Metrics for Summarization
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/summarization"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;summarization&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/evaluation"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;evaluation&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nlp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nlp&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/espoir/evaluation-metrics-for-summarization-3amo" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/espoir/evaluation-metrics-for-summarization-3amo#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>summarization</category>
      <category>evaluation</category>
      <category>ai</category>
      <category>nlp</category>
    </item>
    <item>
      <title>Evaluation Metrics for Summarization</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Thu, 22 May 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/espoir/evaluation-metrics-for-summarization-3amo</link>
      <guid>https://dev.to/espoir/evaluation-metrics-for-summarization-3amo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Everyone wants GenAI, but no one wants to spend time on evaluation or generating reference texts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I worked on a summarization project recently, but I have never spent time evaluating the summarization output. My summarizer &lt;a href="https://balobi.info/" rel="noopener noreferrer"&gt;balobi.info&lt;/a&gt; makes a lot of mistakes: sometimes it generates news in English, other times it confuses Congo and Rwanda, or sometimes it makes up stuff. Those errors could have been avoided if I had spent time evaluating the metrics and deciding which metrics I could use for my model.&lt;/p&gt;

&lt;p&gt;Recently, I documented myself on summarization metrics, and I found a load of them online. I decided to summarize them for the reader in this post.&lt;/p&gt;

&lt;h1&gt;
  
  
  Definition
&lt;/h1&gt;

&lt;p&gt;Text summarization is the process of producing a concise and coherent summary while preserving key information and meaning of the source text. There are two major approaches to automatic text summarization: &lt;em&gt;extractive&lt;/em&gt; and &lt;em&gt;abstractive&lt;/em&gt; summarization. _ Extractive summarization_ involves selecting important sentences or phrases from the original document. On the other hand, &lt;em&gt;abstractive summarization&lt;/em&gt; generates the summary with sentences that are different from those in the original text while not changing the ideas. In most cases, when you prompt a Large Language Model (LLM), it generates an abstractive summary of the text.&lt;/p&gt;

&lt;h1&gt;
  
  
  Evaluation
&lt;/h1&gt;

&lt;p&gt;Evaluation is the process of evaluating the quality of a summarization output. Evaluation of a summarization can be done in two ways: by using a &lt;em&gt;human evaluator&lt;/em&gt; or using &lt;em&gt;automated metrics._Human evaluation is more accurate but it is time-consuming and requires a lot of effort._Automatic evaluation&lt;/em&gt; is simple, easy to scale, but sometimes less accurate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human Evaluation:
&lt;/h2&gt;

&lt;p&gt;In most cases, humans are tasked to evaluate the model outputs using four criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coherence&lt;/strong&gt; : It evaluates how good the sentences are.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt; : The factual alignment between the summary and the summarized source. A factually consistent summary contains only statements that are entailed by the source document. Annotators were also asked to penalize summaries that contained hallucinated facts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fluency&lt;/strong&gt; : The quality of individual sentences. Drawing again from the DUC quality guidelines, sentences in the summary ‘‘should have no formatting problems, capitalization errors or obviously ungrammatical sentences (e.g., fragments, missing components) that make the text difficult to read.’’&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relevance&lt;/strong&gt; : Selection of important content from the source. The summary should include only important information from the source document. Annotators were instructed to penalize summaries that contained redundancies and excess information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A final score is computed by averaging the scores of all these criteria.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic Evaluation:
&lt;/h2&gt;

&lt;p&gt;In term of automatic evaluation we have two types of metrics, &lt;strong&gt;references based metrics&lt;/strong&gt; and &lt;strong&gt;non reference metrics.&lt;/strong&gt; or references free metrics.&lt;/p&gt;

&lt;p&gt;References metrics involves a human annotator who will give a reference summary to compare the generated summary against. For non references metrics there is no references and the generated summary is compared against the original text.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Metrics for References Evaluation:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F4w1bd3uyfnd7g5lby08t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F4w1bd3uyfnd7g5lby08t.png" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;reference based summary&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here are the metrics for automated summarization evaluation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ROUGE:&lt;/strong&gt; (Recall-Oriented Understudy for Gisting Evaluation), measures the number of overlapping textual units (n-grams, word sequences) between the generated summary and a set of gold reference summaries. Many papers have suggested that ROUGE metrics is the one that correlates the most with human juggement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ROUGE-WE:&lt;/strong&gt; extends ROUGE by using soft lexical matching based on the cosine similarity of Word2Vec embeddings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BertScore:&lt;/strong&gt; computes the semantic similarity scores by aligning generated and reference summaries on a token-level. Token alignments are computed greedily to maximize the cosine similarity between contextualized token embeddings from BERT.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BLEU:&lt;/strong&gt; is a corpus level precision-focused metric that calculates n-gram overlap between a candidate and reference utterance and includes a brevity penalty. It is the primary evaluation metric for machine translation. &lt;strong&gt;CIDER:&lt;/strong&gt;   computes {1–4}-gram cooccurrences between the candidate and reference texts, down weighting common n-grams and calculating cosine similarity between the n-grams of the candidate and reference texts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reference Free Metrics:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fwjhnorchhvhl45p7mybp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fwjhnorchhvhl45p7mybp.png" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reference free summaries&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Reference-free metrics are metrics that are based on the matching between the generated summary and the original document.&lt;/p&gt;

&lt;p&gt;They are faster to implement as they don’t require any human annotator.&lt;/p&gt;

&lt;p&gt;All the methods of reference metrics can be used to build reference-free metrics. We can do that by considering the original document as the summary and comparing the generated summary with it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ROUGE-C&lt;/strong&gt; : is a modification to ROUGE: Instead of comparing to a reference summary, the generated summary is compared to the source document. We can go further with ROUGE-C and create metrics that will down-weight common terms in the text. Up-weight important terms that are present in the summary.&lt;em&gt;Researchers found that ROUGE-C correlated well with methods that depend on reference summaries, including human judgments.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SUPERT&lt;/strong&gt; : Rate the quality of a summary by measuring it semantic similarity with a pseudo reference summary. The pseudo references are generated by selecting salient sentences from the source document using contextualized embedding and soft token alignment techniques. Compared to the state-of-the-art unsupervised evaluation metrics, SUPERT correlates better with human ratings by 18- 39%.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Entailment Metrics Based on NLI Tasks&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Entailment metrics&lt;/strong&gt; are based on the &lt;strong&gt;natural language inference (NLI) task&lt;/strong&gt; where a hypothesis sentence is classified as entailed by, neutral, or contradicting a premise sentence. To evaluate abstractive summarization for consistency, we check if the summary is entailed by the source document. In the scientific literature the metric used is called SummaC.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How does SummaC works?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It split the original document in block of text(sentences, or paragraph), the generated summary by the sentences. Then use a NLI model such as BERT to compute the entailment score for each sentence of generated summary vs each sentence in the original document. Those scores are saved in a matrix which is called entailment matrix. For SummaCZS, they reduce the entailment matrix into a one-dimensional vector by taking the maximum value in each column. Intuitively, this results in retaining the score for the document sentence that provides the strongest support for each summary sentence. Then, to get a single score for the entire summary, they simply compute the mean of the vector. There are other sophisticated approaches of the entailment matrix using a convolutional layer. The bellow picture describes how the entailment matrix works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Flbyfecb0tvviglgs7pjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Flbyfecb0tvviglgs7pjd.png" width="800" height="932"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SummaC summarization&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  LLM as a Judge for summaries Evaluation
&lt;/h2&gt;

&lt;p&gt;With the rise of LLM, we have seen case in the literature where we are using LLM as a judge to evaluate the LLM summary.  With this approach we let the LLM is trying to replicate the work a human evaluator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluating using a Language Model
&lt;/h2&gt;

&lt;p&gt;Unlike metrics like &lt;code&gt;ROUGE&lt;/code&gt; or &lt;code&gt;BERTScore&lt;/code&gt; that rely on comparison to reference summaries, the &lt;code&gt;gpt-4&lt;/code&gt; based evaluator assesses the quality of generated content based solely on the input prompt and text, without any ground truth references. This makes it applicable to new datasets and tasks where human references are not available.&lt;/p&gt;

&lt;p&gt;Here’s an overview of this method:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using the four criteria used by human, coherence, consistency, fluency, and relevance.&lt;/li&gt;
&lt;li&gt;Create a prompt that will ask the LLM to generate a score form 1 to 5 for each of those criteria using chain of thought generation.&lt;/li&gt;
&lt;li&gt;We generate scores from  the language model with the defined prompts, comparing them across summaries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that LLM-based metrics could have a bias towards preferring LLM-generated texts over human-written texts. Additionally LLM based metrics are sensitive to system messages/prompts. Sometimes you don’t have an LLM available for evaluation and you need to stick to traditional metrics.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this post, we highlight evaluation methods for summarization, discuss the different types of summarization evaluation, and show the pros and cons of each method. The right metrics for your summarization project depend on the engagement of your stakeholders. When they are engaged, ask them for reference summaries and fine-tune your prompts to obtain good metrics using the reference texts. Alternatively, you can ask them to evaluate different summaries generated by various prompts and different LLMs. If there is no engagement from the stakeholders from the beginning, prefer reference-free metrics.&lt;/p&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Liu Y, Iter D, Xu Y, Wang S, Xu R, Zhu C. (2023). &lt;a href="https://arxiv.org/pdf/2303.16634.pdf" rel="noopener noreferrer"&gt;G-EVAL: NLG Evaluation Using GPT-4 with Better Human Alignment&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Zhang T, Kishore V, Wu F, Weinberger KQ, Artzi Y. (2020). &lt;a href="https://arxiv.org/abs/1904.09675" rel="noopener noreferrer"&gt;BERTScore: Evaluating Text Generation with BERT&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Lin CY. (2004). &lt;a href="https://aclanthology.org/W04-1013/" rel="noopener noreferrer"&gt;ROUGE: A Package for Automatic Evaluation of Summaries&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Fabbri A, et al. (2021). &lt;a href="https://aclanthology.org/2021.tacl-1.24" rel="noopener noreferrer"&gt;SummEval: Re-evaluating Summarization Evaluation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Yan, Ziyou. (2023). &lt;a href="https://eugeneyan.com/writing/abstractive/" rel="noopener noreferrer"&gt;Evaluation &amp;amp; Hallucination Detection for Abstractive Summaries&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;He T, et al. (2008). ROUGE-C: A fully automated evaluation method for multi-document summarization. 2008 IEEE International Conference on Granular Computing, Hangzhou, China, pp. 269-274. doi: &lt;a href="https://doi.org/10.1109/GRC.2008.4664680" rel="noopener noreferrer"&gt;10.1109/GRC.2008.4664680&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sbert.net/examples/sentence_transformer/training/nli/README.html" rel="noopener noreferrer"&gt;Natural Language Inference with Sentence Transformer&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>summarization</category>
      <category>evaluation</category>
      <category>ai</category>
      <category>nlp</category>
    </item>
    <item>
      <title>Deploy your language models to production using the ONNX runtime and the Triton inference server</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Sun, 07 Apr 2024 22:12:57 +0000</pubDate>
      <link>https://dev.to/espoir/deploy-your-language-models-to-production-using-the-onnx-runtime-and-the-triton-inference-server-28p</link>
      <guid>https://dev.to/espoir/deploy-your-language-models-to-production-using-the-onnx-runtime-and-the-triton-inference-server-28p</guid>
      <description>&lt;center&gt;Cover: Lac Kivu in East DRC&lt;/center&gt;

&lt;p&gt;You are a Data Scientist who has finally trained a language model and it works in a jupyter notebook and you are happy with your results. Now you want to expose it to the users so that they can interact with it.&lt;/p&gt;

&lt;p&gt;You have different options to serve your model to your users. You can use the jupyter notebook directly in production 🤣. You can wrap the model in a pickle file and serve it using an API 🤪. Both options work, but can they handle millions of requests per second in a production environment? In this post, I will show how you can use modern tools to deploy a language model in a scalable way. We will use the ONNX runtime, Triton inference server, Docker, and Kubernetes. These tools will help us to deploy a production-ready language model.&lt;/p&gt;

&lt;p&gt;This guide is addressed to Data scientists, Machine Learning Engineers and researchers aiming to use their Language Models in Production. It discusses the engineering principles of scalable language models APIs.&lt;/p&gt;

&lt;p&gt;It will be divided into multiple parts. In the first part, we will prepare the model for a production setting. We will use the ONNX runtime and Docker container to achieve that goal. Finally, in the second part, we will learn how to scale our Apis using Kubernetes.&lt;/p&gt;

&lt;p&gt;If I have time later, I’ll explain how to use the embedding API in a downstream app like a Retrieval Augmentation Generation (RAG).&lt;/p&gt;

&lt;p&gt;Before we dive into the deployment bits of this application, let us first review some theories about language models.&lt;/p&gt;

&lt;p&gt;We will be deploying an embedding model, so let's start by defining a language model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8nUDSZVT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://murhabazi.com/assets/posts/2024-04-07-deploying-language-model-with-onnx-runtime-on-triton-inference-server/gorilla.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8nUDSZVT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://murhabazi.com/assets/posts/2024-04-07-deploying-language-model-with-onnx-runtime-on-triton-inference-server/gorilla.png" alt="_Mountain Gorilla, one our similar cousin." width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt; Mountain Gorilla, one of our similar cousins. &lt;/center&gt;

&lt;h2&gt;
  
  
  Embeddings.
&lt;/h2&gt;

&lt;p&gt;Embedding models are the backbone of generative AI, they are representations of words in a vector space. They capture word semantics such as, with them similar vectors represent similar words.&lt;/p&gt;

&lt;p&gt;Contextual embeddings are embeddings such as each word is represented with a vector given its context.&lt;/p&gt;

&lt;p&gt;Let’s look at those two examples:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The bank of the river Thames is located in South London.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I am going to withdraw cash at Lloyds Bank.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In those two sentences the word &lt;code&gt;bank&lt;/code&gt; has two different meanings. In the first, bank means &lt;em&gt;the land alongside or sloping down to a river or lake.&lt;/em&gt; In the second sentence, it means &lt;em&gt;a place where you save money.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Embedding models can capture those differences and represent words with two different vectors according to the context.&lt;/p&gt;

&lt;p&gt;This is not a post to explain how embedding models are built, if you want to learn more about them refer to &lt;a href="https://mccormickml.com/2019/05/14/BERT-word-embeddings-tutorial/"&gt;this post.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But one thing to know is that embedding models are built with language models or Large language models for the majority of cases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HwYYGkZ4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://murhabazi.com/assets/posts/2024-04-07-deploying-language-model-with-onnx-runtime-on-triton-inference-server/word-embeddings-representation.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HwYYGkZ4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://murhabazi.com/assets/posts/2024-04-07-deploying-language-model-with-onnx-runtime-on-triton-inference-server/word-embeddings-representation.webp" alt="_Words Representation in 2D vector Space._" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt; Words Representation in 2D vector Space. &lt;/center&gt;

&lt;h2&gt;
  
  
  Large Language Model.
&lt;/h2&gt;

&lt;p&gt;Large language models are neural networks or probabilistic models that can predict the next word given the previous words.&lt;/p&gt;

&lt;p&gt;One of the most common neural network architectures that power language models is the Transformer model. It was introduced in 2017 by Google researchers. Those models have a powerful capacity when it comes to understanding words and their meanings because they are trained on a large corpus of documents.&lt;/p&gt;

&lt;p&gt;During their training, transformers’ models can learn contextual word embeddings. Those embeddings are useful in downstream applications such as chatbots, document classification, topic modeling, document clustering et consort.&lt;/p&gt;

&lt;p&gt;Again, this post is not about language models, there are legions on the internet, my favorite one is the &lt;a href="https://jalammar.github.io/illustrated-transformer/"&gt;illustrated trasnfomer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If this post is not about word embedding theory, or large language model theory what is it about?&lt;/p&gt;

&lt;p&gt;Nice question, this post is about deploying a large language model. We assume that you have a model trained on how you want to deploy it. We will learn how to create an embedding service, an API that developers can query to generate document embeddings.&lt;/p&gt;

&lt;p&gt;We will build a scalable API that developers can query it to get word embeddings of their sentences. They can use the embeddings in downstream applications. This API can be part of a chatbot, or a Retrieval Augmented Generation application.&lt;/p&gt;

&lt;p&gt;I made it for educational purposes while learning how to deploy a language model using Kubernetes. If you want a production-ready application that can support multiple embedding models &lt;a href="https://github.com/jina-ai/clip-as-service"&gt;check out this repository.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enough talking let’s show us the code!&lt;/p&gt;

&lt;h2&gt;
  
  
  The embedding models.
&lt;/h2&gt;

&lt;p&gt;In this post, we will explore the embedding model generated by the BioLinkBert. The BioLinkBert model is a model from the BERT family but it was fine-tuned on documents from the medical domain. The reason I used the Biolink model is that I wanted to build a chatbot application for the medical domain in the future.&lt;/p&gt;

&lt;p&gt;The embedding of words is the last hidden state of a transformer model where the input is the word encoded as text. Let us see how it works in practice. We will be using a custom Bert model which inherits the base Bert model from Huggingface.&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;torch&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderedDict&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers.onnx&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OnnxConfig&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ModelOutput&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BertModel&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmbeddingOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelOutput&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;last_hidden_state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FloatTensor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomEmbeddingBertModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BertModel&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;forward&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;input_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;head_mask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;inputs_embeds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;EmbeddingOutput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="n"&gt;head_mask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;head_mask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="n"&gt;inputs_embeds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;inputs_embeds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="n"&gt;output_attentions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="n"&gt;output_hidden_states&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="n"&gt;return_dict&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mean_embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_hidden_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&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;embedding_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EmbeddingOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_hidden_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mean_embedding&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;embedding_output&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Our custom embedding is a wrapper around the Bert embedding model. It takes the input ids and returns the embedding of a sentence. The input IDs are the tokenized version of a sentence. The embeddings of the sentence are the average of the embedding of all words in a sentence.&lt;/p&gt;

&lt;p&gt;Here is how that works in practice.&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="n"&gt;embedding_model_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;michiyasunaga/BioLinkBERT-large&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;base_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CustomEmbeddingBertModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding_model_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Before passing the text to the embedding, it needs to be transformed in a tokenizer.&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;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;

&lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding_model_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;test_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is the cause of Covid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;encoded_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;test_input&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                          &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;truncation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With our encoded_input and the base model, we can generate the text embedding for our text input.&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="n"&gt;encoded_input&lt;/span&gt;


&lt;span class="n"&gt;encoded_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;token_type_ids&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;embedding_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;encoded_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;text_embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embedding_output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_hidden_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detach&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;numpy&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text_embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The text embedding is the embedding representation of the sentence in text_input. It can be used in downstream applications in different ways.&lt;/p&gt;

&lt;p&gt;The next step is to save the model in the format we can use to deploy it in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exporting the Model to Onnx format.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the ONNX format?
&lt;/h3&gt;

&lt;p&gt;ONNX stands for Open Neural Network Exchange. It is an open format built to represent machine learning models in a framework and language-agnostic way.&lt;/p&gt;

&lt;p&gt;As you may know, neural networks are computation graphs with input, weights, and operations. ONNX format is a way of saving neural networks as computation graphs. That computational graph represents the flow of data through the neural network.&lt;/p&gt;

&lt;p&gt;The key benefits of saving neural networks in the ONNX format are interoperability and hardware access. Any deep learning platform can read a neural network saved in the ONNX format. For example, a model trained in Pytorch can be exported to ONNX format and imported in Tensorflow and vice versa.&lt;/p&gt;

&lt;p&gt;You don’t need to use Python to read a model saved as ONNX. You can use any programming language of your choice, such as Javascript, C, or C++.&lt;/p&gt;

&lt;p&gt;ONNX makes the model easier to access hardware optimizations. You can apply other optimizations, such as quantization, to your ONNX model.&lt;/p&gt;

&lt;p&gt;Let us see how we can convert our model to ONNX format to use the full benefits of it.&lt;/p&gt;

&lt;p&gt;Let’s see how we can achieve that with the code.&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;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="n"&gt;model_repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;models_repository&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;embedding_model_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieval&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;embedding_model&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;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;model_path&lt;/span&gt;


&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;


&lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoded_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;torch.onnx&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;torch_onnx_export&lt;/span&gt;

&lt;span class="nf"&gt;torch_onnx_export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoded_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bio-bert-embedder.onnx&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;input_names&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;input_ids&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;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;dynamic_axes&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;input_ids&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;batch_size&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sequence&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;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;batch_size&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sequence&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;last_hidden_state&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;batch_size&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sequence&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
    &lt;span class="n"&gt;do_constant_folding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;opset_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With the above code, we have our model exported into ONNX format and ready to be deployed in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model deployment on Docker with the ONNX Runtime.
&lt;/h2&gt;

&lt;p&gt;In this section, we will learn how to use the model in a docker container.&lt;/p&gt;

&lt;p&gt;One of the most obvious solutions is to deploy a model and wrap it in with Flask or Fastapi. While this solution can work in practice, it has some latency due to the fact that the API is written in Python. For this blog I will try a different approach, I will deploy the model using the onnx runtime which is a C++ backend. We will leverage the fact that our model in ONNX format is platform agnostic and we can deploy on any language backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Triton Server
&lt;/h3&gt;

&lt;p&gt;Triton is a software tool for deploying machine learning models for inference. It is designed to produce high-quality inference across different hardware platforms, either GPU or CPU. It also supports inference across cloud, data center, and embedded devices.&lt;/p&gt;

&lt;p&gt;One of the advantages of the triton server is that it supports dynamic batching and concurrent model execution.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic batching:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For models that support batching, which is the case for deep learning models, triton implements scheduling and batching algorithms. That approach combines individual requests to improve inference throughput.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Concurrency model execution is the capacity to run simultaneously multiple models on the same GPU or various GPUs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Triton Server Backend
&lt;/h3&gt;

&lt;p&gt;Triton supports different backends to execute the model. A backend is a wrapper around a deep learning framework like Pytorch, TensorFlow, TensorRT, or ONNX Runtime.&lt;/p&gt;

&lt;p&gt;Two backend types interested us for this post: the Python Backend and the ONNX runtime backend.&lt;/p&gt;

&lt;p&gt;The ONNX runtime backend executes ONNX models, and the Python backend allows the writing of the model logic in Python.&lt;/p&gt;

&lt;p&gt;In this post, we will be focused on the ONNX and the Python backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Triton Server
&lt;/h3&gt;

&lt;p&gt;Let us set up the model repository for the triton inference server.&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="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbtxt&lt;/span&gt;

&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ensemble_model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ensemble_model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbtxt&lt;/span&gt;

&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&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;py&lt;/span&gt;

&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbtxt&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This bash script will create the model repository for our embedding model. The next section will set up the files in that model repository to run our models.&lt;/p&gt;

&lt;p&gt;The model repository should have three components, the tokenizer, the embedding model, and the ensemble model. The tokenizer is the configuration of our tokenizer model, it uses the Python backend and handles the tokenization of our text input. The tokenizer repository should have the files from our tokenizer, the model code, and the model configuration.&lt;/p&gt;

&lt;p&gt;It should have the following layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;└── tokenizer
    ├── 1
    │ ├── __pycache__
    │ ├── config.json
    │ ├── model.py
    │ ├── special_tokens_map.json
    │ ├── tokenizer.json
    │ ├── tokenizer_config.json
    │ └── vocab.txt
    └── config.pbtxt

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

&lt;/div&gt;



&lt;p&gt;To create the tokenizer file, we will have to save our tokenizer to the tokenizer repository, we will use the following code.&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="n"&gt;model_repository&lt;/span&gt;



&lt;span class="n"&gt;tokenizer_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieval&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;tokenizer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tokenizer_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenizer_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;From that tokenizer, we will create the &lt;code&gt;model.py&lt;/code&gt; file, which will handle the tokenization part.&lt;/p&gt;

&lt;p&gt;Here is what the model should look like&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="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;writefile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&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;py&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;triton_python_backend_utils&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pb_utils&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PreTrainedTokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TensorType&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TritonPythonModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PreTrainedTokenizer&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&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;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Initialize the tokenization process
        :param args: arguments from Triton config file
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="c1"&gt;# more variables in https://github.com/triton-inference-server/python_backend/blob/main/src/python.cc
&lt;/span&gt;        &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model_repository&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model_version&lt;/span&gt;&lt;span class="sh"&gt;"&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;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;execute&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;requests&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;List[List[pb_utils.Tensor]]&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;
        Parse and tokenize each request
        :param requests: 1 or more requests received by Triton server.
        :return: text as input tensors
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="c1"&gt;# for loop for batch requests (disabled in our case)
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# binary data typed back to string
&lt;/span&gt;            &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UTF-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pb_utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_input_tensor_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TEXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_numpy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TensorType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NUMPY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;truncation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# tensorrt uses int32 as input type, ort uses int64
&lt;/span&gt;            &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
            &lt;span class="c1"&gt;# communicate the tokenization results to Triton server
&lt;/span&gt;            &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;input_name&lt;/span&gt; &lt;span class="ow"&gt;in&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;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model_input_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;tensor_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pb_utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;input_name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tensor_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;inference_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pb_utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InferenceResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;output_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inference_response&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;responses&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;initialize&lt;/code&gt; method from this class will create our tokenizer from this folder. All our tokenizer files will be initialized from it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;execute&lt;/code&gt; method is the one that handles the request. It can take multiple requests and parse them. Finally, create the query from the text, and return the tokenized text.&lt;/p&gt;

&lt;p&gt;With our tokenizer setup, let us configure the Python server to use it.&lt;/p&gt;

&lt;p&gt;The content of the &lt;code&gt;tokenizer/config.pbxt&lt;/code&gt; should look like this.&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="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;writefile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbtxt&lt;/span&gt;

&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tokenizer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;max_batch_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TEXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TYPE_STRING&lt;/span&gt;
    &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TYPE_INT64&lt;/span&gt;
    &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&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="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="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TYPE_INT64&lt;/span&gt;
    &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&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="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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;instance_group&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;KIND_CPU&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this file, we specify that our backend is a Python backend. It will take an input named text, with dimension -1. The dimension -1 means dynamic or it can be of any size. It returns the inputs_ids, and the attention_mask and will run on a CPU.&lt;/p&gt;

&lt;p&gt;The second component of our model is the embedding model itself, it has the following layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── embedding_model
│ ├── 1
│ │ ├── bio-bert-embedder.onnx
│ │ └── config.json
│ └── config.pbtxt

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

&lt;/div&gt;



&lt;p&gt;Let's look at the &lt;code&gt;config.pbtxt&lt;/code&gt; for the embedding model&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="n"&gt;embedding_model_path&lt;/span&gt;


&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;writefile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbtxt&lt;/span&gt;

&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding_model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;onnxruntime_onnx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;onnxruntime&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;default_model_filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bio-bert-embedder.onnx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;max_batch_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TYPE_INT64&lt;/span&gt;
    &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&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="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="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TYPE_INT64&lt;/span&gt;
    &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&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="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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3391&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# not sure why this is name 3391, need to double check
&lt;/span&gt;    &lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TYPE_FP32&lt;/span&gt;
    &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&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="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;instance_group&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;KIND_CPU&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;It is the configuration file for our embedding model, we can see that it takes the output from our tokenizer model and produces the embedding vector of shape, -1, 1024. With -1 meaning the dynamic shape, and 1024 is our embedding size.&lt;/p&gt;

&lt;p&gt;Note: for some reason, the model output is named &lt;code&gt;3391&lt;/code&gt; I don’t know why it is named like that.&lt;/p&gt;

&lt;p&gt;We can connect our embedding model and the tokenizer’s input and output with the ensemble model. It should have the following layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── ensemble_model
│ ├── 1
│ └── config.pbtxt

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

&lt;/div&gt;



&lt;p&gt;And the content of the &lt;code&gt;config.pbtxt&lt;/code&gt; file in the ensemble model should be like this:&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="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;writefile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_model_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;__str__ &lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ensemble_model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbtxt&lt;/span&gt;
&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ensemble_model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="c1"&gt;# maximum batch size 
&lt;/span&gt;&lt;span class="n"&gt;max_batch_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; 
&lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ensemble&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;#input to the model 
&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TEXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TYPE_STRING&lt;/span&gt;
    &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&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="c1"&gt;# -1 means dynamic axis, aka this dimension may change 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;#output of the model 
&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3391&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TYPE_FP32&lt;/span&gt;
    &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&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="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="c1"&gt;# two dimensional tensor, where 1st dimension: batch-size, 2nd dimension: #classes, not sure why name is 3391.
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;#Type of scheduler to be used
&lt;/span&gt;&lt;span class="n"&gt;ensemble_scheduling&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tokenizer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;model_version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;input_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TEXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TEXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;output_map&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding_model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;model_version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;input_map&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;output_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3391&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3391&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In a nutshell, this config connects our tokenizer and the embedding model. The output of the tokenizer model is passed to the embedding model to produce the embedding vector.&lt;/p&gt;

&lt;p&gt;If the three components were configured correctly we should have the following layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
models_repository/retrieval
├── embedding_model
│ ├── 1
│ │ ├── bio-bert-embedder.onnx
│ │ └── config.json
│ └── config.pbtxt
├── ensemble_model
│ ├── 1
│ └── config.pbtxt
└── tokenizer
    ├── 1
    │ ├── __pycache__
    │ ├── config.json
    │ ├── model.py
    │ ├── special_tokens_map.json
    │ ├── tokenizer.json
    │ ├── tokenizer_config.json
    │ └── vocab.txt
    └── config.pbtxt

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

&lt;/div&gt;



&lt;p&gt;If you have all the following components we can go to the next stage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the triton Inference server image.
&lt;/h3&gt;

&lt;p&gt;In this section, we will see how to build the triton inference server image. The base triton inference server docker image is huge and can weigh up to 10 GB. In the triton inference server there is a way to build a Cpu only image for triton. I wasn’t able to build it from my Macbook.&lt;/p&gt;

&lt;p&gt;We will be using the image &lt;a href="https://github.com/Jackiexiao"&gt;Jackie Xiao&lt;/a&gt; built for that purpose.&lt;/p&gt;

&lt;p&gt;It is a CPU-only image, hence the small size of 500Mb. If you are deploying the model in an infrastructure with a GPU, you will need to use the full Triton Image which is huge.&lt;/p&gt;

&lt;p&gt;Here is the docker file used to build this image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%%writefile {Path.cwd().parent. __str__ ()}/Dockerfile

# Use the base image
FROM jackiexiao/tritonserver:23.12-onnx-py-cpu

# Install the required Python packages
RUN pip install transformers==4.27.1 sacremoses==0.1.1

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

&lt;/div&gt;



&lt;p&gt;You can see that we are pulling the base image and install in it the transformer and the Moses tokenizer.&lt;/p&gt;

&lt;p&gt;With that docker image, we can build the docker image.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker build -t espymur/triton-onnx-cpu:dev -f Dockerfile .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If the image was successfully built we push it to the docker image repository:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker push espymur/triton-onnx-cpu:dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After pushing the image to the repository, you can start your docker container with the triton server in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 docker run --rm -p 8000:8000 -p 8001:8001 -p 8002:8002 -v ${PWD}/models_repository/retrieval:/models espymur/triton-onnx-cpu:dev tritonserver --model-repository=/models

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

&lt;/div&gt;



&lt;p&gt;This command does the following:&lt;/p&gt;

&lt;p&gt;It starts the docker container with the triton-onnx-cpu:dev image.&lt;/p&gt;

&lt;p&gt;It exposes the different ports from the container to the external environment:&lt;/p&gt;

&lt;p&gt;For HTTP connection, it maps the port 8000 from the container to the port 8000 of the external environment.&lt;/p&gt;

&lt;p&gt;For GRPC, it maps the port 8001 to the port 8001.&lt;/p&gt;

&lt;p&gt;For the metric server, it maps the port 8002 to the port 8002&lt;/p&gt;

&lt;p&gt;It maps the local directory, named &lt;code&gt;model_repository&lt;/code&gt; to the folder named &lt;code&gt;/models&lt;/code&gt; in the docker container by using volumes.&lt;/p&gt;

&lt;p&gt;We specify that the triton server should use the model folder as the model repository.&lt;/p&gt;

&lt;p&gt;If everything goes well with that command you should be able to see the following output which tells us which port is used by the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
I0329 18:42:18.452806 1 grpc_server.cc:2495] Started GRPCInferenceService at 0.0.0.0:8001

I0329 18:42:18.460674 1 http_server.cc:4619] Started HTTPService at 0.0.0.0:8000

I0329 18:42:18.520315 1 http_server.cc:282] Started Metrics Service at 0.0.0.0:8002

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

&lt;/div&gt;



&lt;p&gt;With that code, we have our embedding API running and we can now send requests to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making Request to the inference Server.
&lt;/h3&gt;

&lt;p&gt;We have now built our model, the next step is to make an inference request to it and analyze the response.&lt;/p&gt;

&lt;p&gt;Since the model is deployed as a REST API you can make inference requests to it using any client of your choice in any language&lt;/p&gt;

&lt;p&gt;. The inference server is very strict in terms of what it expects as input, and how to interact with it. Fortunately, they have described different clients to use to build the inputs.&lt;/p&gt;

&lt;p&gt;For demonstration purposes, I will be using the Python HTTP client to make the inference requests.&lt;/p&gt;

&lt;p&gt;But nothing restricted you from using your language of choice to make HTTP requests to the API.&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;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tritonclient.http&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;httpclient&lt;/span&gt;
&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost:8000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;http_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpclient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InferenceServerClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;The above code creates the HTTP client, with our server url, let us define the input and output of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text_input = httpclient.InferInput('TEXT', shape=[1], datatype='BYTES')

embedding_output = httpclient.InferRequestedOutput("3391", binary_data=False)

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

&lt;/div&gt;



&lt;p&gt;Those are the placeholder for our inputs and output, let us fill them now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sentences = ["what cause covid"]
np_input_data = np.asarray([sentences], dtype=object)


np_input_data.reshape(-1)


text_input.set_data_from_numpy(np_input_data.reshape(-1))


results = http_client.infer(model_name="ensemble_model", inputs=[text_input], outputs=[embedding_output])


results

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

&lt;/div&gt;



&lt;p&gt;We can now convert back the output to numpy using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inference_output = results.as_numpy('3391')
print(inference_output.shape)

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

&lt;/div&gt;



&lt;p&gt;That is all we have our embedding API, which takes the text and produces the embedding vector.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this post, we have learned how to deploy an embedding model as an API using the triton inference server. The knowledge learned in this post can be used to deploy any transformer model with an encoder or decoder using the triton inference server. Any model from the BERT, or GPT family. It can slightly be adapted to use with encoder-decoder models such as T5 or M2M.&lt;/p&gt;

&lt;p&gt;Once we deploy the model to the production server it will grow with users and need to scale. In the second part of this series, we will learn how to scale the model using Kubernetes.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>mlops</category>
      <category>llm</category>
    </item>
    <item>
      <title>A Letter to LinkedIn Recruiters</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Mon, 11 Apr 2022 23:02:11 +0000</pubDate>
      <link>https://dev.to/espoir/letter-to-linkedin-recruiters-d3j</link>
      <guid>https://dev.to/espoir/letter-to-linkedin-recruiters-d3j</guid>
      <description>&lt;p&gt;Dear LinkedIn Hiring Managers and Aka Tech Recruiters, &lt;/p&gt;

&lt;p&gt;I am writing to you people on behalf of my fellow developers.&lt;/p&gt;

&lt;p&gt;Thank you for always trying to reach out to us, even if we mentioned that we are not looking for opportunities on our LinkedIn profiles. We appreciate the courage. We know what it takes for a man to try to date a woman who is in a relationship or married.&lt;/p&gt;

&lt;p&gt;First, where were you when we were still based in the South? Africa, South America, or Asia? Why did you wait for us to be in Europe or America to start sending us your emails? Don't you know that the future of work is remote and that relocation exists? &lt;em&gt;Brilliance is evenly distributed but opportunities are not. Please give opportunities to everyone.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Please, next time, if you are reaching out to us, please take some time to go over our profiles and read them carefully. Take some time to go over our Github pages as well. Most of the time, googling our name will take you to our portfolios. Don’t just copy-paste an email and send it to a list of people. This is how some of you requested a creator of a framework with four years of experience in the framework he created three years ago. Please do your research. &lt;/p&gt;

&lt;p&gt;If we have agreed to discuss this with you, please, first of all, show up. We know the whole feeling of being ghosted and how it hurts. If we are talking on the phone, please make sure you read our CV/resume before; we don’t want to be asked questions about the technologies we are familiar with or proficient with. Learn our jargon. If we told you that we are proficient with the PyData Stack, why do you keep asking us if we know Pandas and Numpy? If we told you that we have worked with SpringBoot, why keep asking us if we know Java?&lt;/p&gt;

&lt;p&gt;More importantly, never ask us for our salary expectations on the first call, tell us about the budget you have for the role, and that will be enough. Or even worse, asking us for our current salary. If we are currently underpaid, why try to continue with the same schema?&lt;/p&gt;

&lt;p&gt;If you keep doing things like this and don’t change your practices, we will run away from your Linkedin and start posting our CV in JSON format to allow only people who can read them. &lt;/p&gt;

&lt;p&gt;Regards.&lt;/p&gt;

&lt;p&gt;Sincerely Busy Developers.&lt;/p&gt;

&lt;p&gt;PS: I am not looking for work. I am happy with my current role, don’t try to reach out to me again after reading this message. &lt;/p&gt;

</description>
      <category>recruiters</category>
      <category>jokes</category>
      <category>career</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>How I break up with pip and fall in love with poetry my new girlfriend.</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Sun, 17 Oct 2021 15:33:42 +0000</pubDate>
      <link>https://dev.to/espoir/how-i-break-up-with-pip-and-fall-in-love-with-poetry-my-new-girlfriend-4465</link>
      <guid>https://dev.to/espoir/how-i-break-up-with-pip-and-fall-in-love-with-poetry-my-new-girlfriend-4465</guid>
      <description>&lt;p&gt;I have recently stumbled across &lt;a href="https://python-poetry.org/"&gt;poetry&lt;/a&gt; new dependency management for python and decided to give it a try.&lt;/p&gt;

&lt;p&gt;I have been a die hard fan of pip and had used it in most of my projects before I discovered poetry. Furthermore, I had heard about pyenv in the past but was reluctant to use it in my projects for preference reasons. Since Python dependency management is an interesting topic, I would like to explain the difference in another article such as &lt;a href="https://github.com/pypa/pip"&gt;pip&lt;/a&gt; vs &lt;a href="https://github.com/pyenv/pyenv"&gt;pyenv&lt;/a&gt; vs &lt;a href="https://github.com/python-poetry/poetry"&gt;petry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When I discovered poetry and tested it, I fell in love with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is poetry?
&lt;/h2&gt;

&lt;p&gt;Although I will be talking about girlfriends, falling in love , and breakups in this article, the poetry I am talking about is not about love, prose, poems, or Shakespeare.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Poetry is a tool for &lt;strong&gt;dependency management&lt;/strong&gt; and &lt;strong&gt;packaging&lt;/strong&gt; in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.&lt;/em&gt; It supports Python 2.7 and 3.5+&lt;/p&gt;

&lt;p&gt;If you work with python and install packages you should be familiar with &lt;code&gt;pip&lt;/code&gt; my old girlfriend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we should use poetry in lieu of pip?
&lt;/h2&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%2Fhsc472csl1450be5tqvb.jpeg" 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%2Fhsc472csl1450be5tqvb.jpeg" alt="Image description" width="750" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After 2 weeks of usages and successful migration of five personal projects from &lt;code&gt;pip&lt;/code&gt; to &lt;code&gt;poetry&lt;/code&gt;, I can choose poetry because :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has a good dependency resolver. It does the job better than PIP. Read the interesting article &lt;a href="https://www.activestate.com/resources/quick-reads/python-dependencies-everything-you-need-to-know/"&gt;www.activestate.com&lt;/a&gt;. The author explicitly said&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Unfortunately, pip makes no attempt to resolve dependency conflicts. For example, if you install two packages, package A may require a different version of a dependency than package B requires.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;And another advantage I found is that anytime you add a new dependency to the project poetry update for you the &lt;code&gt;pyproject.toml&lt;/code&gt; with the new top-level dependency, it, therefore, avoid you to do &lt;code&gt;pip freeze&lt;/code&gt; to generate a new requirement file for your project.&lt;/li&gt;
&lt;li&gt;You can use the same tool to build and publish your packages. And it is easy to do so. I my opinion this is why I think &lt;code&gt;poetry&lt;/code&gt; outweighed &lt;code&gt;pip&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On one hand, I think &lt;code&gt;poetry&lt;/code&gt; outweigh &lt;code&gt;pip&lt;/code&gt; in many aspects. On the other hand, I view it as &lt;code&gt;pip&lt;/code&gt; on &lt;code&gt;steroids&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the following sections, I will guide you on how to migrate an existing project from pip to poetry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Poetry in your system
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q8A62fYE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh5.googleusercontent.com/prDFZYFCdhOvTIpSpv8fItqiZ3GHrHEypuEhY0J2IyORNHoOwd6JlneUEUEGlcE-yRR0xVGkOUlwIeDWc5DfSCMrpJqX5m_CQxcERZ2fUzLmmOeV-dF-OYUbMAAg0t0uvxhAN-o%3Ds0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q8A62fYE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh5.googleusercontent.com/prDFZYFCdhOvTIpSpv8fItqiZ3GHrHEypuEhY0J2IyORNHoOwd6JlneUEUEGlcE-yRR0xVGkOUlwIeDWc5DfSCMrpJqX5m_CQxcERZ2fUzLmmOeV-dF-OYUbMAAg0t0uvxhAN-o%3Ds0" width="768" height="776"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installing poetry is very straightforward, if you have python installed and &lt;code&gt;curl&lt;/code&gt; you can easily install it by running :&lt;/p&gt;

&lt;h4&gt;
  
  
  osx / linux / bashonwindows install instructions
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  windows powershell install instructions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | python -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt; : The previous &lt;code&gt;get-poetry.py&lt;/code&gt; installer is now deprecated, if you are currently using it you should migrate to the new, supported, &lt;code&gt;install-poetry.py&lt;/code&gt; installer.&lt;/p&gt;

&lt;p&gt;The installer installs the &lt;code&gt;poetry&lt;/code&gt; tool to Poetry’s &lt;code&gt;bin&lt;/code&gt; directory. This location depends on your system:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$HOME/.local/bin&lt;/code&gt; for Unix&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%APPDATA%\Python\Scripts&lt;/code&gt; on Windows&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If this directory is not on your &lt;code&gt;PATH&lt;/code&gt;, you will need to add it manually if you want to invoke Poetry with simply &lt;code&gt;poetry&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Alternatively, you can use the full path to &lt;code&gt;poetry&lt;/code&gt; to use it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is also another version of installing it with &lt;code&gt;pip&lt;/code&gt; but why would you use your ex to attract your new girlfriend? 🤔🤪&lt;/p&gt;

&lt;p&gt;Once everything is installed you can restart your terminal and run the following command to check the poetry version:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;poetry --version&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If installation is unsuccessfully or encountering incompatibility issues. Please heads up to &lt;a href="https://github.com/python-poetry/poetry"&gt;Github Poetry&lt;/a&gt; to get a help, to learn more or to fire an issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C3EVx49P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh4.googleusercontent.com/S09PZBBBn_Q9Vx8vpxLNP67_9HmU-JEM50KpnZZaZavhqS3y2tzfDFuvHlL59CJo_UKhtRtYyWofhx5zlUtvUbk3yO5HHsMM4rqs6xH0fCKaGWZsjlBX7T3j_R0WdPjvf1gG3U0%3Ds0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C3EVx49P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh4.googleusercontent.com/S09PZBBBn_Q9Vx8vpxLNP67_9HmU-JEM50KpnZZaZavhqS3y2tzfDFuvHlL59CJo_UKhtRtYyWofhx5zlUtvUbk3yO5HHsMM4rqs6xH0fCKaGWZsjlBX7T3j_R0WdPjvf1gG3U0%3Ds0" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate top-level dependencies
&lt;/h3&gt;

&lt;p&gt;Before moving to the next step you need to make sure you can generate the top-level dependencies for your project, to do that you will need a package called &lt;a href="https://pypi.org/project/pipdeptree/"&gt;pipdeptree&lt;/a&gt; . For context, the top-level dependencies are the root of your dependencies tree. What is even the dependency tree? Each package you install using &lt;code&gt;pip&lt;/code&gt; has the other dependencies that rely on it. And before installing a new package it installs his top-level dependencies. For example, pandas is a package but &lt;code&gt;pandas&lt;/code&gt; depends on &lt;code&gt;numpy&lt;/code&gt;, if you install pandas it install also numpy as a dependent.&lt;/p&gt;

&lt;p&gt;The following command will generate only the top-level dependencies, so if you have installed pandas, it will just generate pandas and not numpy as a requirement.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why is this important? :&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This should be filled&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pipdeptree --warn silence | grep -E '^\w+' &amp;gt; requirements-new.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once you have generated the top-level dependencies, I would suggest you deactivate your virtual environment and delete it to make the break-up complete before moving to the next steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding poetry to an existing project.
&lt;/h3&gt;

&lt;p&gt;If you have a new project where you are using &lt;code&gt;pip&lt;/code&gt; and have the &lt;code&gt;requirements.txt&lt;/code&gt; file inside you can run the following command to initialize poetry in the project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;poetry init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will prompt you to set up poetry to your existing project and asked you to give some details about your project such as the project name, the python version you want to use, and the description. It will consequently generate the &lt;code&gt;pyproject.toml&lt;/code&gt; file which will contain all the details about your project as well as the top-level projects requirement and their versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating virtual environment
&lt;/h3&gt;

&lt;p&gt;Poetry creates by default virtual environment in a folder called &lt;code&gt;~/Library/Application Support/pypoetry&lt;/code&gt; but you can change those settings by using the following command :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;poetry config virtualenvs.in-project true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After running that command you can run the following :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;poetry shell&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It will activate the project’s virtual environment and create a new one if the project does not have one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the requirements for your projects.
&lt;/h3&gt;

&lt;p&gt;If you have the &lt;code&gt;requirements-news.txt&lt;/code&gt; file resulting from the command you run on the first step, you can install all the packages in that and their corresponding version by running the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;for item in $(sed -n 's/==/@/p' requirements-new.txt); do poetry add "${item}" ; done&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This will work only on Linux and Mac, still trying to find the exact version of it for Windows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What does that command do? I loop over every line of the &lt;code&gt;requirement-new.txt&lt;/code&gt; file take the dependency, and just replace the &lt;code&gt;==&lt;/code&gt; in the dependency with &lt;code&gt;@&lt;/code&gt; and then add it with poetry.&lt;/p&gt;

&lt;p&gt;If for example in the file you have pandas==1.1.1, it will install the following with poetry &lt;code&gt;poetry add pandas@1.11&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If everything goes well you should have the all the top-level packages installed with their dependencies.&lt;/p&gt;

&lt;p&gt;Once the command has successfully run and you have everything installed, you should check if your &lt;code&gt;pyproject.toml&lt;/code&gt; file contains all the packages and their top-level dependencies.&lt;/p&gt;

&lt;p&gt;You can now remove the old &lt;code&gt;requirements.txt&lt;/code&gt; file and the newly create &lt;code&gt;requirement-new.txt&lt;/code&gt;file by running.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rm -f requirements.*&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A section about using poetry with conda enviroment
&lt;/h3&gt;

&lt;p&gt;Some people like to have multiples girlfriend and may like to keep their old conda or pip environment. I haven’t tried this approach yet , but according to&lt;a href="https://github.com/python-poetry/poetry/issues/105#issuecomment-498042062"&gt;this issue&lt;/a&gt; it is possible to use poetry to install packages in a python environment.&lt;/p&gt;

&lt;p&gt;You just have to configure poetry to not create a virtual environment in a project and install your packages in the conda or pip environment.&lt;/p&gt;

&lt;p&gt;I think you can try it and let us know in comment how it goes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus, the Dockerfile.
&lt;/h3&gt;

&lt;p&gt;If you have a dockerfile you can edit it and use the following docker images which use multi-stage build to install all your requirement with poetry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.7.5 AS base
LABEL maintainer="Espoir Murhabazi &amp;lt; first_name.second_name[:3] on gmail.com&amp;gt;"

ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
POETRY_HOME="/opt/poetry" \
POETRY_VIRTUALENVS_IN_PROJECT=true \
POETRY_NO_INTERACTION=1 \
PYSETUP_PATH="/opt/pysetup" \
VENV_PATH="/opt/pysetup/.venv"

ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"

FROM base AS python-deps

RUN apt-get update \

&amp;amp;&amp;amp; apt-get install --no-install-recommends -y \

curl \

build-essential
# Install Poetry - respects $POETRY_VERSION &amp;amp; $POETRY_HOME
ENV POETRY_VERSION=1.1.7

RUN curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python
WORKDIR $PYSETUP_PATH

COPY ./poetry.lock ./pyproject.toml ./
RUN poetry install --no-dev
FROM base AS runtime
COPY --from=python-deps $POETRY_HOME $POETRY_HOME
COPY --from=python-deps $PYSETUP_PATH $PYSETUP_PATH
RUN useradd -ms /bin/bash espy
COPY . /home/espy
WORKDIR /home/espy
USER espy
CMD [" you command "]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically, what the docker file does, it uses a multi-stage build to first install the packages in the first step and copy only the packages installed in the second as well as the project repository. One of the advantages of the multi-stage build is that it uses only the necessary files your project needs and therefore reduce the memory of your docker container.&lt;/p&gt;

&lt;p&gt;You can learn more about multi-stage build using the &lt;a href="%5Bhttps://pythonspeed.com/articles/multi-stage-docker-python/%5D(https://pythonspeed.com/articles/multi-stage-docker-python/)"&gt;following tutorial.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And the story of my break up comes to an end. As you may know, all separations are not smooth, sometimes the daemons of your old girlfriend come and start causing troubles in your new relationship. So if you find any issue during this break-up, feel free to let me know in the comment I will try to help you as much as I can 🤔.&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>My books recommendations to enhance your Soft Skills as a developer</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Sat, 05 Jun 2021 12:57:09 +0000</pubDate>
      <link>https://dev.to/espoir/my-books-recommendations-to-enhance-your-soft-skills-as-a-developer-4k3o</link>
      <guid>https://dev.to/espoir/my-books-recommendations-to-enhance-your-soft-skills-as-a-developer-4k3o</guid>
      <description>&lt;p&gt;Three years ago, I decided to part ways with my Facebook account, and I decided to replace the time spent on Facebook with reading developers’ blogs. During that time, I stumbled across &lt;a href="https://dev.to/"&gt;dev&lt;/a&gt;, medium, and quora. These sites and publications have contributed a lot to the developer I am today. I decided to dig deeper in my social media detox. Last year, I decided to block WhatsApp status unless Man-City qualified for the Champions League final and spent the time reading books about soft skills to improve my softs skills as a developer.&lt;/p&gt;

&lt;p&gt;I am not planning to talk about the pros and cons of not having a social media account here; instead, I will talk about a few books I read recently, which improved my soft skills as a developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.amazon.com/How-Win-Friends-Influence-People/dp/0671027034" rel="noopener noreferrer"&gt;Dale Carnegie, How to Win Friends &amp;amp; Influence People, 1998 Edition&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;After the Bible, this is the best and essential book in my life. It has improved my life, not only as a developer but also as a person in general. It helps me improve my communication skills, communicate with anyone, avoid arguments, and be a good leader.&lt;/p&gt;

&lt;p&gt;The first aspect I appreciate from this book comes from the introduction, where the author explains how we should read the book to gain most of it. Those pieces of advice were very useful for every other book I read after this one.&lt;/p&gt;

&lt;p&gt;After reading this book, my communication skills got better, and I was able to land a job with a triple of my previous salary.&lt;/p&gt;

&lt;p&gt;My favorite quote from the book is :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;The highest-paid personnel in engineering are frequently not those who know the most about engineering. The person who has technical knowledge plus the ability to express ideas, assume leadership, and arouse enthusiasm among people – that person is headed for higher earning power.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you would like to improve your soft skills and be better at communication, I recommend this book.&lt;/p&gt;

&lt;p&gt;There are numerous benefits of reading this book; I remember in the third chapter where the author wrote: “the best way to win your friend into your way of thinking is to talk about the other person’s interest.” Later in the chapter about arguments when the author said : &lt;strong&gt;" you can’t win an argument. A man convinced against his will is of the same opinion still”.&lt;/strong&gt; _&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.amazon.com/Atomic-Habits-Proven-Build-Break/dp/0735211299" rel="noopener noreferrer"&gt;James Clear, Atomic Habits: An Easy &amp;amp; Proven Way to Build Good Habits &amp;amp; Break Bad Ones, 2018 Edition&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The second book is a recent bestseller, and it is not about communication but rather about building good habits. Have you ever found yourself in the bad habit of checking social media every time you are working? Are you constantly failing to start a habit of something you care about and know is essential for your health, such as reading a book or exercising every day? Do you need to improve your productivity as an Engineer ? I recommend the book Atomic Habits by James Clear.&lt;/p&gt;

&lt;p&gt;The book explains how getting 1% better every day can be beneficial over time. From the first chapter, I learned how small habits compound over time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As you can see in the picture below :&lt;/em&gt;&lt;a href="/static/5d119b52bfe58a0227d4baf5181e0ec1/cb5f6/atomic_habits_effects.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.murhabazi.com%2Fstatic%2F5d119b52bfe58a0227d4baf5181e0ec1%2F799d3%2Fatomic_habits_effects.png" title="atomic habits effects" alt="atomic habits effects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“The effects of small habits compound over time. For example, if you can get just 1 percent better each day, you’ll end up with results that are nearly 37 times better after one year.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The book’s backbone is a four-step model of habits - cue, craving, response, reward, and the four laws of behavior change that evolve out of these steps. The mastery of those four laws is an essential step for everyone who wants to build better habits.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Make it obvious, Make it attractive, Make it easy and Make it satisfying.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By understanding those laws, on the one hand, you will learn how addictive products such as video games or social media applications are built. On the other hand, you can learn how to use the same psychological tips in those products to your favor when building solid habits. Lessons learned from that book can easily be applied to a software development career, especially if you want to develop strong habits within your software development team.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.amazon.com/Rich-Dad-Poor-Teach-Middle/dp/1612680194" rel="noopener noreferrer"&gt;Robert Kiyosaki, Rich Dad Poor Dad: What the Rich Teach Their Kids About Money That the Poor and Middle Class Do Not 2017 Edition&lt;/a&gt;.
&lt;/h2&gt;

&lt;p&gt;The third book is neither on leadership nor habits, but it is a financial best-seller Rich Dad, Poor Dad. Do you want to be financially free, never to be broke again? This book is for you. The author of the book exposes two contrasting views about money from his two dads; the one he called poor dad, his real dad who was working for the government and taught him to work for money, and his rich dad, who was his best friend’s dad who taught him how to let the money work for him. From the book, I learned the difference between assets and liability and why we should buy assets instead of liabilities.&lt;/p&gt;

&lt;p&gt;There are numerous lessons I learned from the book, but here is the most important one :&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The cone of learning&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/50473b9d729f28bc279a5691e89360cf/4bad3/cone_of_learnings.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.murhabazi.com%2Fstatic%2F50473b9d729f28bc279a5691e89360cf%2F799d3%2Fcone_of_learnings.png" title="cones of learning" alt="cones of learning"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Rich don’t work for money. They work to learn how to let money work for them one day&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The ability to sell—to communicate to another human being, be it a customer, employee, boss, spouse, or child—is the base skill of personal success.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Never Say I can’t afford it, or I can do it, instead ask yourself how I can afford it or do it&lt;/em&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By completing this book, I realized how important it is to be financially free, and I decided to start thinking about building my own company.&lt;/p&gt;

&lt;h2&gt;
  
  
  Napoleon Hill, &lt;em&gt;Think and Grow Rich,&lt;/em&gt; 1937.
&lt;/h2&gt;

&lt;p&gt;Another interesting book I read which is similar to the previous one is: Think and Grow Rich by Napoleon Hill.&lt;/p&gt;

&lt;p&gt;I haven’t yet finished the book, but it has numerous lessons on how to get rich from what I am reading. And from the author’s perspective, the book is not only about being rich in terms of money but being rich in other aspects of your life such as marriage, health, or studies. The book highlighted 14 key success factors. The book contains stories and extracts of the most successful person on the planet bibliographies such as T. Edinson, H.Ford or Andrew Carnegie. The key concept from the book is that the rich start from someone’s mind. The author gives six key steps in which desires of riches can be transmuted to this physical equivalent. I think those steps are easy to apply, and I have started seeing their benefits in my current life.&lt;/p&gt;

&lt;p&gt;Here is my favorite quote from the book :&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“If you think you are beaten, you are&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you think you dare not, you don’t,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you like to win, but you think you can’t&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It is almost certain you won’t.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you think you’ll lose, you’re lost&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For out of the world we find,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Success begins with a fellow’s will&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It’s all in the state of mind.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you think you are outclassed, you are&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You’ve got to think high to rise,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You’ve got to be sure of yourself before&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can ever win a prize.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Life’s battles don’t always go&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;To the stronger or faster man,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But soon or late the man who wins&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Is the man WHO THINKS HE CAN!”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I haven’t yet finished the book, but the lessons in my life are enormous.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.amazon.com/Clean-Coder-Conduct-Professional-Programmers/dp/0137081073" rel="noopener noreferrer"&gt;Robert C. Martin, Clean Coder, The: A Code of Conduct for Professional Programmers, 2011.&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Last but not least is the book I am currently reading and the book I wish I read when I started my software development career—the Clean Coder.&lt;/p&gt;

&lt;p&gt;The book’s author is Uncle Bob, an experienced programmer with more than 42 years of coding experience. The book is all about professionalism for software developers. It describes the actions and disciplines you should consider to be a professional developer. Most of the lessons you find from the book came from his experience and are very useful for today’s developers. From the book, you can learn how to say No and say Yes in your day-to-day job as a software engineer. How testing can help you become a professional developer. It talks about work ethics and how you should keep learning to stay updated on your skills. How to become a better team player. How to handle meetings at work and avoid working overtime and, more importantly, improving your productivity as a developer. I haven’t yet completed the book, but after reading the first two chapters of this book, I had concluded that this is the book I wish I had read when I started coding. I recommend it for every teacher who is teaching software engineering to school. It is the handbook for professionalism as a Software Engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;That is all about books I read last year. They are not enough in comparison with books that humans have written on this earth, but in one year it is a lot, and the most important was not to read the book but to put into practice what you read from them. When I get old, I will have a large library like this one, and I can brag about them to my friends.&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/251d73690d3594470ca125a66a69eb8d/f094d/book_shelf.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.murhabazi.com%2Fstatic%2F251d73690d3594470ca125a66a69eb8d%2F799d3%2Fbook_shelf.png" title="book shelve" alt="book shelve"&gt;&lt;/a&gt;How do I manage to find time to read and work full time with endless bugs in a world full of distractions? The secret came from the book Atomic habits. I have made it easy for me. I have a ritual, my morning routine. I know that I have to do two things in the morning; my fitness routine, brushing my teeth, and reading for at least 30 minutes. And as a reward for this routine, I can open my phone and check if I have important emails or any notification that will boost my dopamine.&lt;/p&gt;

&lt;p&gt;And as I said in the introduction, I learned how to gain time from social media and WhatsApp status by making the habits of checking them hard by blocking access to my contacts to WhatsApp and just deleting my Facebook account. I also use Twitter for 10 minutes per day on my laptop and from 7 pm to 10 pm on my phone and only in read-only mode.&lt;/p&gt;

&lt;p&gt;I hope you learned something from this, and I can guarantee that you will learn more from the book I shared.&lt;/p&gt;

&lt;p&gt;Do you have similar books to recommend to me? Feel free to leave them as a comment. Otherwise, take care and enjoy life. Cheers.&lt;/p&gt;

</description>
      <category>career</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>books</category>
    </item>
    <item>
      <title>Shipping Python Code to AWS ECS using Github Actions</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Mon, 05 Apr 2021 13:33:07 +0000</pubDate>
      <link>https://dev.to/espoir/shipping-python-code-to-aws-ecs-using-github-actions-3f3j</link>
      <guid>https://dev.to/espoir/shipping-python-code-to-aws-ecs-using-github-actions-3f3j</guid>
      <description>&lt;p&gt;This is the last post of this series. &lt;a href="https://dev.to/espoir/how-to-use-the-aws-python-cdk-to-create-an-infrastructure-on-ecs-3lcc"&gt;In the first post&lt;/a&gt; we learned how to build the ship for our boatload: The CloudFormation Stack and its different objects); &lt;a href="https://dev.to/espoir/converting-a-docker-compose-file-to-an-aws-task-definition-3poc"&gt;in The second&lt;/a&gt; we learned how to build containers; finally, in this one, we will find how to ship those containers to our boat using Github Actions.&lt;/p&gt;

&lt;p&gt;This is not a post about Github Actions or CI/CD, to get started with those concepts there are a tremendous amount of tutorials online for that. &lt;/p&gt;

&lt;p&gt;If by any chance you are not familiar with CI/CD or Github actions in general refer to &lt;a href="https://dev.to/michaelcurrin/intro-tutorial-to-ci-cd-with-github-actions-2ba8"&gt;this guide&lt;/a&gt; and &lt;a href="https://docs.github.com/en/actions/guides/about-continuous-integration" rel="noopener noreferrer"&gt;this one&lt;/a&gt; to get started. &lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started
&lt;/h3&gt;

&lt;p&gt;To get started download a sample project we will be using by running the following command in your cmd.  I hope you have git installed in your machine.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git clone https://github.com/espoirMur/deploy_python_to_aws_github_actions.git&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As you can see this is just a dummy project which runs with run four docker containers.&lt;/p&gt;

&lt;p&gt;You can follow the readme to get the project running for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  What we will accomplish and the tools we will use:
&lt;/h3&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%2Fwww.murhabazi.com%2Fstatic%2F416046a7ad233f3cdd57171f273a55c2%2F799d3%2Faws_architecture.png" 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%2Fwww.murhabazi.com%2Fstatic%2F416046a7ad233f3cdd57171f273a55c2%2F799d3%2Faws_architecture.png" alt=""&gt;&lt;/a&gt;
&lt;/p&gt;


&lt;p&gt;&lt;br&gt;
    &lt;em&gt;Our architecture and workflow in  a nutshell &lt;em&gt;&lt;br&gt;
&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the picture our actions, on every push to the master branch, will build a docker image for our application, log in to ECR, push the image to the ECR, update the task definition with the new image pushed URL, and start the service with the associated task definition in the AWS Cluster.&lt;/p&gt;

&lt;p&gt;Here is a list of the GitHub actions we will be using :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://github.com/aws-actions/configure-aws-credentials" rel="noopener noreferrer"&gt;Configure-aws-credentials&lt;/a&gt;: This will help to configure AWS credential and region environment variables for use in other GitHub Actions. &lt;/li&gt;
&lt;li&gt;
&lt;a href="http://github.com/aws-actions/amazon-ecr-login" rel="noopener noreferrer"&gt;Amazon-ecr-login&lt;/a&gt;:  This will enable us to log in to the local Docker client to one or more Amazon Elastic Container Registry (ECR) registries. After logging, we can therefore push our docker images to the registry. &lt;/li&gt;
&lt;li&gt;
&lt;a href="http://github.com/aws-actions/amazon-ecs-render-task-definition" rel="noopener noreferrer"&gt;Amazon ECS-render-task-definition&lt;/a&gt;:  This will help us to render the docker image URI to the task definition.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://github.com/aws-actions/amazon-ecs-deploy-task-definition" rel="noopener noreferrer"&gt;Amazon ECS-deploy-task-definition&lt;/a&gt;: This is the action that does the real deploy for us. It will register the AWS task definition to ECS and then deploys it to an Amazon ECS service.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/docker/setup-buildx-action" rel="noopener noreferrer"&gt;Docker Buildx&lt;/a&gt;: This action will help us to set up the most recent version of the docker build: buildx which support caching. It is not mandatory if you don’t need to use caching you can skip it. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Back To the Business: The code we want to deploy.
&lt;/h3&gt;

&lt;p&gt;Let go back to the project I introduced in the beginning and we will work from it. From your command line move to the project directory :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd deploy_python_to_aws_github_actions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Activate your virtual enviroment with :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;source .venv/bin/activate&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Creating the Github actions:
&lt;/h4&gt;

&lt;p&gt;To create Github Actions we can add them from the Github UI or do it from the command line. To perform that operation via command line you need to have a folder called &lt;code&gt;.github/workflows&lt;/code&gt; in your project directory and add your action &lt;code&gt;.yml&lt;/code&gt; file within it.&lt;/p&gt;

&lt;p&gt;Let us create the folder:&lt;code&gt;mkdir .github &amp;amp;&amp;amp; mkdir .github/workflows&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then we can create our action file with &lt;br&gt;
&lt;code&gt;touch .github/workflows/deploy_aws.yml&lt;/code&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Setting up
&lt;/h5&gt;

&lt;p&gt;In the deploy to AWS action we add the following code :&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;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

 &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&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;Deploy to Amazon ECS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this line we are only specifying the event that will trigger our action, this action will be triggered on a push to master.&lt;/p&gt;

&lt;p&gt;Next, let us specify the set of job that our actions will run:&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

 &lt;span class="na"&gt;deploy&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;Deploy&lt;/span&gt;

  &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells our job to run on the ubuntu instance. The job has the following steps&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&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;Checkout&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This action checks-out your repository under &lt;code&gt;$GITHUB_WORKSPACE&lt;/code&gt;, so your workflow can access it.&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="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="n"&gt;Python&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;

  &lt;span class="n"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="nd"&gt;@v1&lt;/span&gt;

  &lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

   &lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This action set up the python version to use for our application.&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="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;Set up QEMU&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-qemu-action@v1&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;Set up Docker Buildx&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-buildx-action@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one set up the docker build tools we will be using.&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="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;create docker cache&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

   &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.workspace }}/cache&lt;/span&gt;

   &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-docker-${{ hashfiles('cache/**') }}&lt;/span&gt;

   &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;${{ runner.os }}-docker-&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one creates the cache we will be using in the build phase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: generating the config files

run: |

echo '''${{ secrets.CONFIGURATION_FILE }}''' &amp;gt;&amp;gt; .env

echo "done creating the configuration file"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one generates our configuration file, so basically if you have environment variables in a .env file, these actions will generate them back.&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="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;Configure AWS credentials&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v1&lt;/span&gt;

&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;

&lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;

&lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the name stated this action will configure your AWS credentials so that you can easily log in to the ECR. &lt;br&gt;
&lt;strong&gt;Don’t forget to add your credentials to your Github repository secrets.&lt;/strong&gt; If you are not familiar with how to add secrets to GitHub refer to &lt;a href="https://bloggie.io/@_junrong/using-environment-variables-secrets-in-github-actions" rel="noopener noreferrer"&gt;this guide&lt;/a&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="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;Login to Amazon ECR&lt;/span&gt;

  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;login-ecr&lt;/span&gt;

  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/amazon-ecr-login@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the name stated this use the credentials set up in the previous steg to login to the container registry.&lt;/p&gt;

&lt;p&gt;Once we are login we can now build the container and push it to the container registry.&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="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;Build, tag, and push the image to Amazon ECR&lt;/span&gt;

  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build-image&lt;/span&gt;

  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

   &lt;span class="na"&gt;ECR_REGISTRY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.login-ecr.outputs.registry }}&lt;/span&gt;

   &lt;span class="na"&gt;ECR_REPOSITORY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ecs-devops-repository&lt;/span&gt;

   &lt;span class="na"&gt;IMAGE_TAG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.sha }}&lt;/span&gt;

&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;

&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="s"&gt;ocker buildx build -f Dockerfile --cache-from "type=local,src=$GITHUB_WORKSPACE/cache" --cache-to "type=local,dest=$GITHUB_WORKSPACE/cache" --output "type=image, name=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG,push=true" .&lt;/span&gt;

&lt;span class="err"&gt;e&lt;/span&gt;&lt;span class="s"&gt;cho "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This builds the container and pushes the container registry. Note that the output of this step is the image URI or image name, we will need it in the next step.&lt;/p&gt;

&lt;p&gt;In the next step, we will fill the image name in each container definition in our task-definition file so that the docker container will be pulling the newly built docker image.&lt;/p&gt;

&lt;p&gt;There are 3 steps in sequence. The output of one step is used in the next step.&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="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;Fill in the new image ID in the Amazon ECS task definition of the beat container&lt;/span&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;render-beat-container&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/amazon-ecs-render-task-definition@v1&lt;/span&gt;

&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;task-definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./.aws/task-definition.json&lt;/span&gt;

&lt;span class="na"&gt;container-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;celery-beat&lt;/span&gt;

&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.build-image.outputs.image }}&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;Fill in the new image ID in the Amazon ECS task definition of the flower container&lt;/span&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;render-flower-container&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/amazon-ecs-render-task-definition@v1&lt;/span&gt;

&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;task-definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.render-beat-container.outputs.task-definition }}&lt;/span&gt;

&lt;span class="na"&gt;container-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flower&lt;/span&gt;

&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.build-image.outputs.image }}&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;Fill in the new image ID in the Amazon ECS task definition of the worker container&lt;/span&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;render-worker-container&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/amazon-ecs-render-task-definition@v1&lt;/span&gt;

&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;task-definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.render-flower-container.outputs.task-definition }}&lt;/span&gt;

&lt;span class="na"&gt;container-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;celery-worker&lt;/span&gt;

&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.build-image.outputs.image }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the task definition updated we can now push the task definitions to the service and start running the service.&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="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;Deploy Amazon ECS task definition&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/amazon-ecs-deploy-task-definition@v1&lt;/span&gt;

&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;task-definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.render-worker-container.outputs.task-definition }}&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ecs-devops-service&lt;/span&gt;

&lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ecs-devops-cluster&lt;/span&gt;

&lt;span class="na"&gt;wait-for-service-stability&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;p&gt;This is the step that does the actual deployment, it pushes the task definitions to the service which starts the tasks.&lt;/p&gt;

&lt;p&gt;With this added we can make sure we have the following content in our &lt;code&gt;.github/workflows/deploy_aws.yml&lt;/code&gt; file.&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;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&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;Deploy to Amazon ECS&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;deploy&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;Deploy&lt;/span&gt;

&lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&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;Checkout&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&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;Set up Python python-version&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v1&lt;/span&gt;

&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3.7&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;Set up QEMU&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-qemu-action@v1&lt;/span&gt;

&lt;span class="c1"&gt;# https://github.com/docker/setup-buildx-action&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;Set up Docker Buildx&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/setup-buildx-action@v1&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;create docker cache&lt;/span&gt;

&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v1&lt;/span&gt;

&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.workspace }}/cache&lt;/span&gt;

&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-docker-${{ hashfiles('cache/**') }}&lt;/span&gt;

&lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;

&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="s"&gt;{{ runner.os }}-docker-&lt;/span&gt;

&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="s"&gt; name: generating the config files&lt;/span&gt;

&lt;span class="err"&gt;r&lt;/span&gt;&lt;span class="s"&gt;un: |&lt;/span&gt;

&lt;span class="err"&gt;e&lt;/span&gt;&lt;span class="s"&gt;cho '''${{ secrets.CONFIGURATION_FILE }}''' &amp;gt;&amp;gt; .env&lt;/span&gt;

&lt;span class="err"&gt;e&lt;/span&gt;&lt;span class="s"&gt;cho "done creating the configuration file"&lt;/span&gt;

&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="s"&gt; name: Configure AWS credentials&lt;/span&gt;

&lt;span class="err"&gt;u&lt;/span&gt;&lt;span class="s"&gt;ses: ws-actions/configure-aws-credentials@v1&lt;/span&gt;

&lt;span class="err"&gt;w&lt;/span&gt;&lt;span class="s"&gt;ith:&lt;/span&gt;

&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="s"&gt;ws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;

&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="s"&gt;ws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;

&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="s"&gt;ws-region: us-east-2&lt;/span&gt;

&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="s"&gt; name: Login to Amazon ECR&lt;/span&gt;

&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="s"&gt;d: login-ecr&lt;/span&gt;

&lt;span class="err"&gt;u&lt;/span&gt;&lt;span class="s"&gt;ses: aws-actions/amazon-ecr-login@v1&lt;/span&gt;



&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="s"&gt; name: Build, tag, and push the image to Amazon ECR&lt;/span&gt;

&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="s"&gt;d: build-image&lt;/span&gt;

&lt;span class="err"&gt;e&lt;/span&gt;&lt;span class="s"&gt;nv:&lt;/span&gt;

&lt;span class="err"&gt;E&lt;/span&gt;&lt;span class="s"&gt;CR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}&lt;/span&gt;

&lt;span class="err"&gt;E&lt;/span&gt;&lt;span class="s"&gt;CR_REPOSITORY: ecs-devops-repository&lt;/span&gt;

&lt;span class="err"&gt;I&lt;/span&gt;&lt;span class="s"&gt;MAGE_TAG: ${{ github.sha }}&lt;/span&gt;

&lt;span class="err"&gt;r&lt;/span&gt;&lt;span class="s"&gt;un: |&lt;/span&gt;

&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="s"&gt;ocker buildx build -f Dockerfile --cache-from "type=local,src=$GITHUB_WORKSPACE/cache" --cache-to "type=local,dest=$GITHUB_WORKSPACE/cache" --output "type=image, name=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG,push=true" .&lt;/span&gt;

&lt;span class="err"&gt;e&lt;/span&gt;&lt;span class="s"&gt;cho "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"&lt;/span&gt;

&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="s"&gt; name: Fill in the new image ID in the Amazon ECS task definition of the beat container&lt;/span&gt;

&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="s"&gt;d: render-beat-container&lt;/span&gt;

&lt;span class="err"&gt;u&lt;/span&gt;&lt;span class="s"&gt;ses: aws-actions/amazon-ecs-render-task-definition@v1&lt;/span&gt;

&lt;span class="err"&gt;w&lt;/span&gt;&lt;span class="s"&gt;ith:&lt;/span&gt;

&lt;span class="err"&gt;t&lt;/span&gt;&lt;span class="s"&gt;ask-definition: ./.aws/task-definition.json&lt;/span&gt;

&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="s"&gt;ontainer-name: celery-beat&lt;/span&gt;

&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="s"&gt;mage: ${{ steps.build-image.outputs.image }}&lt;/span&gt;

&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="s"&gt; name: Fill in the new image ID in the Amazon ECS task definition of the flower container&lt;/span&gt;

&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="s"&gt;d: render-flower-container&lt;/span&gt;

&lt;span class="err"&gt;u&lt;/span&gt;&lt;span class="s"&gt;ses: aws-actions/amazon-ecs-render-task-definition@v1&lt;/span&gt;

&lt;span class="err"&gt;w&lt;/span&gt;&lt;span class="s"&gt;ith:&lt;/span&gt;

&lt;span class="err"&gt;t&lt;/span&gt;&lt;span class="s"&gt;ask-definition: ${{ steps.render-beat-container.outputs.task-definition }}&lt;/span&gt;

&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="s"&gt;ontainer-name: flower&lt;/span&gt;

&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="s"&gt;mage: ${{ steps.build-image.outputs.image }}&lt;/span&gt;

&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="s"&gt; name: Fill in the new image ID in the Amazon ECS task definition of the worker container&lt;/span&gt;

&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="s"&gt;d: render-worker-container&lt;/span&gt;

&lt;span class="err"&gt;u&lt;/span&gt;&lt;span class="s"&gt;ses: aws-actions/amazon-ecs-render-task-definition@v1&lt;/span&gt;

&lt;span class="err"&gt;w&lt;/span&gt;&lt;span class="s"&gt;ith:&lt;/span&gt;

&lt;span class="err"&gt;t&lt;/span&gt;&lt;span class="s"&gt;ask-definition: ${{ steps.render-flower-container.outputs.task-definition }}&lt;/span&gt;

&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="s"&gt;ontainer-name: celery-worker&lt;/span&gt;

&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="s"&gt;mage: ${{ steps.build-image.outputs.image }}&lt;/span&gt;
&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="s"&gt; name: Deploy Amazon ECS task definition&lt;/span&gt;
&lt;span class="err"&gt;u&lt;/span&gt;&lt;span class="s"&gt;ses: aws-actions/amazon-ecs-deploy-task-definition@v1&lt;/span&gt;

&lt;span class="err"&gt;w&lt;/span&gt;&lt;span class="s"&gt;ith:&lt;/span&gt;

&lt;span class="err"&gt;t&lt;/span&gt;&lt;span class="s"&gt;ask-definition: ${{ steps.render-worker-container.outputs.task-definition }}&lt;/span&gt;

&lt;span class="err"&gt;s&lt;/span&gt;&lt;span class="s"&gt;ervice: ecs-devops-service&lt;/span&gt;

&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="s"&gt;luster: ecs-devops-cluster&lt;/span&gt;

&lt;span class="err"&gt;w&lt;/span&gt;&lt;span class="s"&gt;ait-for-service-stability: false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, we can now commit the code and see how the application will start the pipeline and get deployed to AWS. Run the following to deploy.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git commit -am 'setup the ci cd pipeline'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;`git push origin master&lt;/p&gt;

&lt;p&gt;We can check if our GitHub actions are running&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%2Frf39hmnr9ii2ib4dlk5c.png" 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%2Frf39hmnr9ii2ib4dlk5c.png" alt="github actions running"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything goes well you can visualize the deployment &lt;a href="https://us-east-2.console.aws.amazon.com/ecs/v2/clusters/ecs-devops-cluster/services/ecs-devops-service/deployments?region=us-east-2" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please change your service and cluster with your cluster name and service name in the URL.&lt;/p&gt;

&lt;p&gt;If everything in your deployment goes well you can check the logs for your worker to see what is happening &lt;a href="https://us-east-2.console.aws.amazon.com/cloudwatch/home?region=us-east-2#logsV2:log-groups/log-group/ecs-devops-service-logs" rel="noopener noreferrer"&gt;there&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting:
&lt;/h3&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%2Fi.redd.it%2Fyh1zhpezbwr61.png" 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%2Fi.redd.it%2Fyh1zhpezbwr61.png" alt=""&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Let me quote Albert Einstein here: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Theory is when you know everything but nothing works. Practice is when everything works but no one knows why. In our lab, theory and practice are combined: nothing works and no one knows why. 🤪&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In theory, things should go as expected and everything should work in the first place, but in practice that is not always the case.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In case you got some issue making this work, first, make sure that in your GitHub actions and the task definition you put the correct name of the objects you created with the cdk. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In case you are using an application that connects to a managed database, make sure you have a security group attached to your instance that is allowed to make connections to the database. Security groups and networking is beyond the scope of this blog, maybe in the fourth part of the series I can talk a little about it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If after deploying nothing is running you can check the status of your tasks using the following code: &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;aws ecs list-tasks --cluster ecs-devops-cluster  --region us-east-2  --desired-status STOPPED&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;to get the task stopped ARN. &lt;br&gt;
And then use the following ARN in this code to check the reason why it has stopped : &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;aws ecs describe-tasks --cluster ecs-devops-cluster --tasks task_arn_from_previous_step  --region us-east-2 --debug&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you are lucky enough you should see why your tasks are not working here. &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;In these three-part series we learned how to create a scalable architecture to deploy our python application to AWS, we learned also how to use Github actions to deploy a simple application to AWS. And to sum up we add some useful commands you can use to troubleshoot an AWS service and tasks. I hope you enjoy reading this tutorial. If you encountered any issues while working on this, feel free to let us know in the comments. &lt;/p&gt;

&lt;p&gt;In meantime take care of yourself and happy coding. &lt;/p&gt;

&lt;h3&gt;
  
  
  Ressources
&lt;/h3&gt;

&lt;p&gt;Here is a non-exhaustive list of resources I used in this blog post : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/containers/create-a-ci-cd-pipeline-for-amazon-ecs-with-github-actions-and-aws-codebuild-tests/" rel="noopener noreferrer"&gt;The first one from AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://towardsdatascience.com/how-to-deploy-apache-airflow-with-celery-on-aws-ce2518dbf631" rel="noopener noreferrer"&gt;The second one&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/raphaelmansuy/deploy-a-docker-app-to-aws-using-ecs-3i1g"&gt;The third one&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>githubactions</category>
      <category>python</category>
    </item>
    <item>
      <title>Converting a docker-compose file to an AWS task definition</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Thu, 25 Mar 2021 10:03:25 +0000</pubDate>
      <link>https://dev.to/espoir/converting-a-docker-compose-file-to-an-aws-task-definition-3poc</link>
      <guid>https://dev.to/espoir/converting-a-docker-compose-file-to-an-aws-task-definition-3poc</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/espoir/how-to-use-the-aws-python-cdk-to-create-an-infrastructure-on-ecs-3lcc"&gt;previous post&lt;/a&gt;, we learned how to create an AWS Architecture to support our Python Application . In this post, we will learn how to create a task-definition from a docker-compose file.&lt;/p&gt;

&lt;p&gt;Before diving deep into the tutorial, let us define what is a docker-compose file and recall from the previous tutorial what is a task-definition.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is docker-compose?:
&lt;/h3&gt;

&lt;p&gt;From this &lt;a href="https://adamtheautomator.com/docker-compose-tutorial/#What_is_Docker_Compose" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;, docker-compose is defined as :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Docker Compose is a way to create reproducible Docker containers using a config file instead of extremely long Docker commands. By using a structured config file, mistakes are easier to pick up and container interactions are easier to define.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What is a task definition:
&lt;/h3&gt;

&lt;p&gt;Let’s recall what a task-definition is: it is just a specification. You use it to define one or more containers that you want to run together, along with other details such as environment variables, CPU/memory requirements, etc.&lt;/p&gt;

&lt;p&gt;From the two definitions, we can see that a task definition role is similar to that of a docker-compose file.&lt;/p&gt;

&lt;p&gt;We will therefore use the docker-compose file to generate the task-definition.&lt;/p&gt;

&lt;h3&gt;
  
  
  The real stuff, the transformation :
&lt;/h3&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%2F0aiqnuqbyz80yavbkotm.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%2F0aiqnuqbyz80yavbkotm.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make our transformation, we can go back to &lt;a href="https://github.com/espoirMur/deploy_python_to_aws_github_actions.git" rel="noopener noreferrer"&gt;the project&lt;/a&gt; we introduced in the first part and &lt;code&gt;cd&lt;/code&gt; to the project directory.&lt;/p&gt;

&lt;p&gt;We will leverage a python tool called &lt;a href="https://github.com/micahhausler/container-transform" rel="noopener noreferrer"&gt;container-transform&lt;/a&gt; to accomplish our transformation.&lt;/p&gt;

&lt;p&gt;You can install it in your project virtual environment with :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install container-transform&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With the tool installed we can now use it to generate the task definition file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cat docker-compose.yml | container-transform -v &amp;gt; .aws/task-definition.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The output of this command is sent to the file &lt;code&gt;.aws/task-definition.json&lt;/code&gt; , if everything went well you will have something like this :&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"containerDefinitions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"celery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"-A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"celery_factory:celery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"beat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"-S"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"redbeat.RedBeatScheduler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"--loglevel=info"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task_runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"redis"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celery-beat"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"celery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"worker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"-A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"celery_factory:celery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"--loglevel=info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"-E"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task_runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"redis"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celery-worker"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"./start_flower"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FLOWER_PORT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5556"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task_runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"redis"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"flower"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"portMappings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"containerPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5556&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"hostPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5556&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"volumes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



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

&lt;/div&gt;

&lt;p&gt;What to note here; all services we have in the docker-compose file are now in the &lt;code&gt;containerDefinitions&lt;/code&gt; sections of our task definition. However, that file is not yet fully complete. We will have to update it with other keys such as the network mode, resources, execution role we created before, and the logging option for sending logs to Cloudwatch. Let’s edit the file by adding the following. We also need to remove the &lt;code&gt;link&lt;/code&gt; key from each container definition.&lt;/p&gt;

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


"requiresCompatibilities": [



"FARGATE"



],



"inferenceAccelerators": [],

"volumes": [],



"networkMode": "awsvpc",



"memory": "512",



"cpu": "256",



"executionRoleArn": "arn:aws:iam::Your-id-from-aws:role/ecs-devops-execution-role",



"family": "ecs-devops-task-definition",



"taskRoleArn": "",



"placementConstraints": []



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

&lt;/div&gt;

&lt;p&gt;What are those elements?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;requiresCompatibilities&lt;/code&gt;: here, we are specifying that our launch type is of Fargate type.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;networkMode&lt;/code&gt;: this is the Docker networking mode to use for containers in the task. AWS offers the following network modes: &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;bridge&lt;/code&gt;, &lt;code&gt;awsvpc&lt;/code&gt;, and &lt;code&gt;host&lt;/code&gt;. In the Fargate launch type, the &lt;code&gt;awsvpc&lt;/code&gt; network mode is required. With this setting, the task is allocated its own elastic network interface (ENI) and a primary private IPv4 address. This gives the task the same networking properties as Amazon EC2 instances. Learn more about networking mode &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;memory&lt;/code&gt;: is the amount of RAM to allocate to containers, if your cluster does not have any registered container instances with the requested memory available, the task will fail.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cpu&lt;/code&gt;: The number of CPU units that the Amazon ECS container agent will reserve for the container.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;executionRoleArn&lt;/code&gt;: The Amazon Resource Name (ARN) of the task execution role that grants Amazon ECS container agent permission to make AWS API calls on your behalf. As you can see it is the IAM role we created in our Cloudformation stack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;family&lt;/code&gt;: is the name of the task definition we created on the Cloudformation stack.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In each container definition, we need to add this code to send container logs to Cloudwatch.&lt;/p&gt;

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


"logConfiguration": {



"logDriver": "awslogs",



"options": {



"awslogs-group": "ecs-devops-service-logs-groups",



"awslogs-region": "us-east-2",



"awslogs-stream-prefix": "celery-beat"



}



},



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

&lt;/div&gt;

&lt;p&gt;Add those lines to each AWS service and change the &lt;code&gt;awslogs-stream-prefix&lt;/code&gt; key and put the container name. To learn more about task definitions parameters, check &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With those parameters edited we end up with the following task-definition.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"containerDefinitions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"celery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"-A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"celery_factory:celery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"beat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"--scheduler=redbeat.RedBeatScheduler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"--loglevel=debug"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task_runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CELERY_BROKER_URL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis://127.0.0.1:6379"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celery-beat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"logConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"logDriver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"awslogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecs-devops-service-logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-stream-prefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celery-beat"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"celery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"-A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"celery_factory:celery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"worker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"--loglevel=error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s2"&gt;"-E"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task_runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celery-worker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CELERY_BROKER_URL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis://127.0.0.1:6379"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"logConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"logDriver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"awslogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecs-devops-service-logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-stream-prefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celery-worker"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./start_flower"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FLOWER_PORT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5556"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CELERY_BROKER_URL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis://127.0.0.1:6379"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task_runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"logConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"logDriver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"awslogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecs-devops-service-logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-stream-prefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celery-flower"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"flower"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"portMappings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"containerPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5556&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"hostPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5556&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"portMappings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"containerPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"logConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"logDriver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"awslogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecs-devops-service-logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;span class="nl"&gt;"awslogs-stream-prefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celery-redis"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"requiresCompatibilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"FARGATE"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;span class="nl"&gt;"inferenceAccelerators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"volumes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"networkMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"awsvpc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"memory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"512"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"cpu"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"executionRoleArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::****youraws id*****:role/ecs-devops-execution-role"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecs-devops-task-definition"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"taskRoleArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"placementConstraints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



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

&lt;/div&gt;

&lt;p&gt;In this tutorial, we learned how to use the container-transform tool to convert a docker-compose file to an AWS task-definition.&lt;/p&gt;

&lt;p&gt;With our task definition in place, we can now move to the third part of this tutorial where we will use the task-definition to deploy our containers to our Cloudformation stack, created in part one, using Github actions.&lt;/p&gt;

&lt;p&gt;See you then.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to use the AWS Python CDK to create an infrastructure on ECS.</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Fri, 26 Feb 2021 12:14:07 +0000</pubDate>
      <link>https://dev.to/espoir/how-to-use-the-aws-python-cdk-to-create-an-infrastructure-on-ecs-3lcc</link>
      <guid>https://dev.to/espoir/how-to-use-the-aws-python-cdk-to-create-an-infrastructure-on-ecs-3lcc</guid>
      <description>&lt;p&gt;Recently at work, we decided to build a CI/CD pipeline that deploys our application directly to AWS. I had never worked with AWS, and it was a missing point on my CV which demonstrates that I have some DevOps skills. I decided to search for some tutorials online and I was not lucky to get what we needed at work. I decided to write this guide by getting something working from various tutorials I found online.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you will learn from this series.
&lt;/h3&gt;

&lt;p&gt;In this 3 parts tutorial, we will learn how to Create an AWS architecture where you can deploy an application, how to convert a docker-compose file in a Task Definition and how to deploy a Task Definition to an AWS Architecture using GitHub Actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who is this series for ?
&lt;/h3&gt;

&lt;p&gt;This tutorial is for developers who are familiar with docker and have an application with docker-compose. Although the series was written by a Python developer and using Python, the concepts can be applied to other programming languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which application will we deploy?
&lt;/h3&gt;

&lt;p&gt;In this tutorial, we will deploy a Python application that has a celery worker, a celery scheduler, and a Redis database for task messaging and task queues.&lt;/p&gt;

&lt;p&gt;I will not talk about celery and task queues and how to use those tools but you can get start with them &lt;a href="[https://medium.com/analytics-vidhya/python-celery-distributed-task-queue-demystified-for-beginners-to-professionals-part-1-b27030912fea](https://medium.com/analytics-vidhya/python-celery-distributed-task-queue-demystified-for-beginners-to-professionals-part-1-b27030912fea)"&gt;here&lt;/a&gt;, and to get started with docker you can use &lt;a href="https://dev.to/javascriptcoff1/what-is-docker-3be2"&gt;this one&lt;/a&gt; ,and &lt;a href="https://adamtheautomator.com/docker-compose-tutorial/" rel="noopener noreferrer"&gt;this one&lt;/a&gt; to be familiar with docker-compose.&lt;/p&gt;

&lt;p&gt;This series is not based on any popular Python web framework such as Django, Flask, or FastAPi but you can adapt this tutorial to them and I am sure it will work like a charm.&lt;/p&gt;

&lt;p&gt;The application skeleton can be downloaded from &lt;a href="https://github.com/espoirMur/deploy_python_to_aws_github_actions" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to get started.&lt;/p&gt;

&lt;p&gt;In this first part of the tutorial, we will learn how to create the Cloudformation stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is AWS CloudFormation?
&lt;/h3&gt;

&lt;p&gt;From &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html" rel="noopener noreferrer"&gt;the official documentation&lt;/a&gt;, Cloudformation is defined as :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AWS CloudFormation is a service that helps you model and set up your Amazon Web Services resources so that you can spend less time managing those resources and more time focusing on your applications that run in AWS. You create a template that describes all the AWS resources that you want (like Amazon EC2 instances or Amazon RDS DB instances), and CloudFormation takes care of provisioning and configuring those resources for you. You don't need to individually create and configure AWS resources and figure out what's dependent on what; CloudFormation handles all of that.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Creating the AWS Architecture
&lt;/h3&gt;

&lt;p&gt;Make sure that you have created an AWS account and you have your credentials; the access key, and the application secret key.&lt;/p&gt;

&lt;p&gt;Most of the services used in this tutorial are available within an AWS free tier.&lt;/p&gt;

&lt;p&gt;We will deploy our application using the AWS ECS Fargate launch type which will pull docker images from the Elastic Container Registry aka ECR.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why Fargate and not EC2?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3o7btPCcdNniyf0ArS/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3o7btPCcdNniyf0ArS/giphy.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS provides us basically two launch types which are the Fargate launch type and the EC2.&lt;/p&gt;

&lt;p&gt;Amazon Elastic Compute Cloud (Amazon EC2) provides scalable computing capacity in the Amazon Web Services (AWS) Cloud. Using Amazon EC2 eliminates the need to invest in hardware upfront, so you can develop and deploy applications faster. You can use Amazon EC2 to launch as many or as few virtual servers as you need. It allows you to configure security and networking, and manage storage yourself. With EC2 you don’t have to worry about the hardware, the hardware is managed by AWS.&lt;/p&gt;

&lt;p&gt;AWS Fargate is a technology that you can use with Amazon ECS to run &lt;a href="https://aws.amazon.com/what-are-containers" rel="noopener noreferrer"&gt;containers&lt;/a&gt; without having to manage servers or clusters of Amazon EC2 instances. The advantage of Fargate over EC2 is the fact that you don’t have to configure, provision, or scale cluster instances and don't have to worry about the virtual machines.&lt;/p&gt;

&lt;p&gt;In a nutshell :&lt;/p&gt;

&lt;p&gt;With a virtual machine, someone still has to manage the hardware, but with EC2 that someone is AWS and you never even see the hardware.&lt;/p&gt;

&lt;p&gt;With ECS on EC2, someone still has to manage the instances, but with ECS on Fargate that someone is AWS and you never even see the EC2 instances.&lt;/p&gt;

&lt;p&gt;ECS has a “launch type” of either EC2 (if you want to manage the instances yourself) or Fargate (if you want AWS to manage the instances). &lt;a href="https://www.reddit.com/r/aws/comments/dvl601/eli5_aws_fargate/f7ddkup?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3" rel="noopener noreferrer"&gt;Source&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  The objects we need :
&lt;/h4&gt;

&lt;p&gt;To deploy the application we need the following objects: a cluster, a service, a task definition with containers definition, cloud watch for logging, and IAM roles. The below picture illustrates how those AWS objects interact with each other.&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%2Fk5bcp5zjq6ssob06mgyt.png" 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%2Fk5bcp5zjq6ssob06mgyt.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us define some of those objects and then we will investigate how to create a stack, containing them, using Python cdk.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A cluster&lt;/strong&gt;: It is a logical group of container instances that ECS can use for deploying Docker containers. It provides computing power to run application container instances. In practice, a cluster is usually attached to an AWS Instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A service&lt;/strong&gt;: It enables us to run and maintain a specified number of instances of a task definition simultaneously in an Amazon ECS cluster. ie. It helps us run single or multiple containers all using the same Task Definition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The task definition&lt;/strong&gt;: A task definition is a specification. You use it to define one or more containers (with image URIs) that you want to run together, along with other details such as environment variables, CPU/memory requirements, etc. The task definition doesn’t actually run anything, it's a description of how things will be set up when something does run. The task definition shares some similarities with the docker-compose file. In the second part of this tutorial, we will convert a docker-compose file into a task definition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A task&lt;/strong&gt;: A task is an actual thing that is running. ECS uses the task definition to run the task; it downloads the container images, configures the runtime environment based on other details in the task definition. You can run one or many tasks for any given task definition. Each running task is a set of one or more running containers - containers in a task all run on the same instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;cloudwatch&lt;/strong&gt;: CloudWatch is a monitoring service, we are using it in this stack to get and visualize logs from the docker containers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all the objects described, we can now learn how to create them using the Python CDK.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating the architecture:
&lt;/h4&gt;

&lt;p&gt;To build the infrastructure, we will leverage the &lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;AWS Cloud Development Kit (CDK)&lt;/a&gt;. If you are new to CDK, see &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html" rel="noopener noreferrer"&gt;Getting Started with AWS CDK&lt;/a&gt;, it is simple and straightforward to install. In this post, we will be using the CDK with Python 3.7. Another alternative to the CDK is to create the application via the AWS console. However, I found the CDK to be the simplest approach because it allows you to have control over the code you are writing.&lt;/p&gt;

&lt;p&gt;After installing the CDK check if it is working with the following command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cdk --version&lt;/code&gt; should output your CDK version.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Initializing the AWS CLI :
&lt;/h5&gt;

&lt;p&gt;Make sure you have AWS CLI installed on your computer. &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html" rel="noopener noreferrer"&gt;Configure your AWS CLI&lt;/a&gt; with an IAM user that has permissions to create the resources (VPC, ECS, ECR, IAM Role) described in the template below. After the configuration you should have the AWS keys stored in your computer at the following location :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;~/.aws/credentials&lt;/code&gt;: if you are using Mac or Linux&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;C:\Users\&lt;/code&gt;USERNAME&lt;code&gt;\.aws\config&lt;/code&gt;: if you are on Windows&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The content of that file should look like this one:&lt;/p&gt;

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


[default]

region=your region

aws_access_key_id = *********************************

aws_secret_access_key = ******************************



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

&lt;/div&gt;

&lt;p&gt;With the credentials, the cli client and the CDK installed let us move to the second step about creating the architecture.&lt;/p&gt;

&lt;h4&gt;
  
  
  Initializing The CDK Project :
&lt;/h4&gt;

&lt;p&gt;To initialize the CDK we will create a new Python project which will contain the code to create the architecture.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Step 1&lt;/em&gt;: Creating the project&lt;/p&gt;

&lt;p&gt;Run the following command to create a new CDK project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir ecs-devops-cdk&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Enter the project using:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd ecs-devops-cdk&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or if you are using VSCode you can open the project with vs code using:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;code ecs-devops-cdk&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Step 2&lt;/em&gt;: Initialize the python CDK project :&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To initialize the CDK project run the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cdk init --language python&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The command will create a new python CDK project and we will be editing it in the next step to build our stack.&lt;/p&gt;

&lt;p&gt;After a quick look you should see a structure like this in your project:&lt;/p&gt;

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


&lt;span class="nb"&gt;.&lt;/span&gt;

├── README.md

├── app.py

├── cdk.json

├── ecs_devops_cdk

│ ├── __init__.py

│ └── ecs_devops_cdk_stack.py

├── requirements.txt

├── setup.py

└── source.bat



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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Step 3&lt;/em&gt;: activate virtual environment :&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can activate your virtual environment using the following command :&lt;/p&gt;

&lt;p&gt;On mac and linux : &lt;code&gt;source .env/bin/activate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For windows : &lt;code&gt;.env\Scripts\activate.bat&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;step 4&lt;/em&gt;: Installing dependencies:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the virtual environment created we can now install the dependencies :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install -r requirements.txt&lt;/code&gt;and&lt;code&gt;pip install aws_cdk.aws_ec2 aws_cdk.aws_ecs aws_cdk.aws_ecr aws_cdk.aws_iam&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With the project initialized we can now move to the next step where we will be creating our components.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating the objects :
&lt;/h4&gt;

&lt;p&gt;We can now move to the stack creation step&lt;/p&gt;

&lt;p&gt;If you open the file under &lt;code&gt;ecs_devops_cdk/ecs_devops_cdk_stack.py&lt;/code&gt; you should be able to see the followings :&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;from&lt;/span&gt; &lt;span class="n"&gt;aws_cdk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EcsDevopsCdkStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stack&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;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;construct_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&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="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&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;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;construct_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;It is basically a class that will contain the code defining our stack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;step 1&lt;/strong&gt;: Import the core functionality&lt;/p&gt;

&lt;p&gt;Edit the first line to import the code we need to create the following stack:&lt;/p&gt;

&lt;p&gt;`python&lt;/p&gt;

&lt;p&gt;from aws_cdk import (core, aws_ecs as ecs, aws_ecr as ecr, aws_ec2 as ec2, aws_iam as iam, aws_logs)`&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;step 2&lt;/strong&gt;: Create the container repository&lt;/p&gt;

&lt;p&gt;To create a container repository you can use the following command :&lt;/p&gt;

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


&lt;span class="n"&gt;ecr_repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Repository&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-repository&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repository_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-repository&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;step 3&lt;/strong&gt;: Creating the VPC :&lt;/p&gt;

&lt;p&gt;We can either create a vpc or use an existing vpc. To create a vpc use can add the following code the &lt;code&gt;__init__&lt;/code&gt; method.&lt;/p&gt;

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


&lt;span class="n"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-vpc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_azs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;You can also use an existing vpc , if that is the case for you use the following lines:&lt;/p&gt;

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


&lt;span class="n"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_lookup&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-vpc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;vpc_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;vpc-number&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;For this, you need the vpc name and the corresponding id.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;step 4:&lt;/em&gt; Cluster Creation :&lt;/p&gt;

&lt;p&gt;With the vpc created we can attach the cluster to it . To create the cluster we can use the following code :&lt;/p&gt;

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


&lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Cluster&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-cluster&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;cluster_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-cluster&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;vpc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;step 5:&lt;/em&gt; Creating the Role:&lt;/p&gt;

&lt;p&gt;Let us create the role, the role will give the service permission to perform tasks.&lt;/p&gt;

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


&lt;span class="n"&gt;execution_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Role&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-execution-role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;assumed_by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ServicePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-tasks.amazonaws.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;role_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-execution-role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;With the execution role created we can attach policy to it to give it the permission it needs.&lt;/p&gt;

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


&lt;span class="n"&gt;execution_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_to_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resources&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;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;actions&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;ecr:GetAuthorizationToken&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;ecr:BatchCheckLayerAvailability&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;ecr:GetDownloadUrlForLayer&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;ecr:BatchGetImage&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;logs:CreateLogStream&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;logs:PutLogEvents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;With the IAM role created we can attach a task definition to it&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Step 6&lt;/em&gt;: Creating the task definition :&lt;/p&gt;

&lt;p&gt;Here is the code we used to create the task definition ;&lt;/p&gt;

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


&lt;span class="n"&gt;task_definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateTaskDefinition&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-task-definition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;execution_role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;execution_role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-task-definition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;And the container :&lt;/p&gt;

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


&lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task_definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-sandbox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContainerImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_registry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon/amazon-ecs-sample&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;In the code above, we are initially specifying the Task Definition to run with an example container from a public AWS sample registry. This sample container is replaced with our application container when our CI/CD pipeline updates the Task Definition. We are using the container from the sample registry to allow the Service to stabilize before any application container images are added to our ECR repository.&lt;/p&gt;

&lt;p&gt;With the task definition created we can attach a service that will be running it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;step 7:&lt;/em&gt; Creating the service :&lt;/p&gt;

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


&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateService&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;task_definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;The service uses the task definition and you can see it is attached to our created cluster.&lt;/p&gt;

&lt;p&gt;PS: When your AWS instance is in a public subnet , you need to auto-assign public IP addresses to the containers to grant them internet access. This will help your service to download a docker image from a public repository. In that case, you can use the following code when creating the service. :&lt;/p&gt;

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


&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateService&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service-name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;task_definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;task_definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service-name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;assign_public_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# this is important
&lt;/span&gt;
&lt;span class="n"&gt;security_groups&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;security&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;also&lt;/span&gt; &lt;span class="n"&gt;important&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

&lt;span class="n"&gt;vpc_subnets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Note the assign_public_ip , the security group and the VPC subnets.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Step 8&lt;/em&gt;: Creating the cloudwatch Log group:&lt;/p&gt;

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


&lt;span class="n"&gt;log_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws_logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LogGroup&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-service-logs-groups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;



&lt;span class="n"&gt;log_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-service-logs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;As stated before we will be transferring the docker logs to our log group created in Cloudwatch.&lt;/p&gt;

&lt;p&gt;With all the objects created let us make sure that we have all the ingredients for our stack in the following updated file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ecs_devops_cdk/ecs_devops_cdk_stack.py&lt;/code&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;from&lt;/span&gt; &lt;span class="n"&gt;aws_cdk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aws_ecs&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aws_ecr&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ecr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aws_ec2&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aws_iam&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aws_logs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EcsDevopsCdkStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stack&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;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;construct_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&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="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&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;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;construct_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ecr_repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Repository&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-repository&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repository_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-repository&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-vpc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_azs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Cluster&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-cluster&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cluster_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-cluster&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vpc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;execution_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Role&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-execution-role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;assumed_by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ServicePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-tasks.amazonaws.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;role_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-execution-role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;execution_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_to_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;

&lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resources&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;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

&lt;span class="n"&gt;actions&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;ecr:GetAuthorizationToken&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;ecr:BatchCheckLayerAvailability&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;ecr:GetDownloadUrlForLayer&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;ecr:BatchGetImage&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;logs:CreateLogStream&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;logs:PutLogEvents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;



&lt;span class="n"&gt;task_definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateTaskDefinition&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-task-definition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;execution_role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;execution_role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-task-definition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task_definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-sandbox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContainerImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_registry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon/amazon-ecs-sample&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateService&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;task_definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;log_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws_logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LogGroup&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-service-logs-groups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-service-logs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Before creating the stack open the file &lt;code&gt;app.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see something like this :&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;from&lt;/span&gt; &lt;span class="n"&gt;aws_cdk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ecs_devops_cdk.ecs_devops_cdk_stack&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EcsDevopsCdkStack&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;



&lt;span class="nc"&gt;EcsDevopsCdkStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-cdk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;synth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Replace the line where your stack is instantiated, 4th line, with the following :&lt;/p&gt;

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


&lt;span class="nc"&gt;EcsDevopsCdkStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ecs-devops-cdk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&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;account&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; **************&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;region&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;your region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;



&lt;span class="p"&gt;})&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;With this set; you can now create your stack. With the code created we can now run the following command to create our stack.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cdk deploy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If everything goes well you should have your stack created. As a result, you will have a cluster, running a service that deploys a task definition, and a Cloudwatch log group created.&lt;/p&gt;

&lt;p&gt;You can check your stack from the AWS console by navigating to the following &lt;a href="https://us-east-2.console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks?filteringStatus=active&amp;amp;filteringText=&amp;amp;viewNested=true&amp;amp;hideStacks=false" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want, you can check this project on GitHub &lt;a href="https://github.com/espoirMur/ecs-devops-cdk" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That is all for this first part, we managed to build our ship and added the most important objects to it.&lt;/p&gt;

&lt;p&gt;We are now ready to pack containers and deliver our content to our client.&lt;/p&gt;

&lt;p&gt;In the second part of this series, we will learn how to convert our docker-compose file to a task definition described in this tutorial. See you then!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>Hacktoberfest is almost there, Python developers here are some venues for parties.</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Wed, 30 Sep 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/espoir/hacktoberfest-is-almost-there-python-developers-here-are-some-venues-for-parties-4cen</link>
      <guid>https://dev.to/espoir/hacktoberfest-is-almost-there-python-developers-here-are-some-venues-for-parties-4cen</guid>
      <description>&lt;p&gt;This year has been fantastic because I contributed to some open-source projects and had my pull request merged on amazing projects with many stars. It helps me to put some green dots on my GitHub profile…&lt;/p&gt;

&lt;p&gt;I don’t want to brag about my open source contributions, which are very small compared to what has been done in the open-source community. Instead, I want to show &lt;em&gt;you&lt;/em&gt; which open source project &lt;em&gt;you&lt;/em&gt; can contribute to during this period. They are not the biggest parties at the festival, but they can train &lt;em&gt;you&lt;/em&gt; to drink beers, dress, and dance before attending the most prominent venues.&lt;/p&gt;

&lt;p&gt;By contributing to those projects, &lt;em&gt;you&lt;/em&gt; can get those green dots on &lt;em&gt;your GitHub profile&lt;/em&gt; so that when a recruiter asks you for some sample of your work, &lt;em&gt;you&lt;/em&gt; can have something to show them.&lt;/p&gt;

&lt;h2&gt;
  
  
  But why October?
&lt;/h2&gt;

&lt;p&gt;The reason why I wrote this post today, it’s because we are in October, which is the open-source month. DigitalOcean, in partnership with dev.to, organizes &lt;a href="https://hacktoberfest.digitalocean.com/"&gt;Hacktoberfest&lt;/a&gt;. During the most exciting open-source festival, people get the opportunity to contribute to open sources and get some swags and other awards for recognition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you tell us about the venues? :
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0QQgD4-w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/3a1de513ba937ccdedfea8b22642f861/88218/festival.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0QQgD4-w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/3a1de513ba937ccdedfea8b22642f861/88218/festival.jpg" alt="hackotobest" width="590" height="392"&gt;&lt;/a&gt;&lt;br&gt;
The venues are on Github. Here are some links with topics and descriptions of each venue I collected for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/karec/cookiecutter-flask-restful"&gt;Kratec flask restful cookie-cutter&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This project is a cookie-cutter, a template for creating flask applications.&lt;/p&gt;

&lt;p&gt;It has a structured way to make flask-restful applications. It is a good starting point for building flask applications. It has some basic features all applications have in common such as token-based authentication and user management system.&lt;/p&gt;

&lt;p&gt;It also has all the settings needed for a flask backend, such as database setup, celery configurations, docker-compose, etc.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;The project is built using Flask and Python 3.6. If you are familiar with that stack, this can be a good start for you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How You can contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;As for all the software projects, this one is not yet completed. It needs some improvements. You can make it &lt;a href="https://realpython.com/python-pep8/"&gt;PEP8&lt;/a&gt; compliant by setting up linter to make sure it follows all the styles included in pep8. It has some open issues you can look to.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/masakhane-io/masakhane-mt"&gt;Masakhane&lt;/a&gt; :
&lt;/h3&gt;

&lt;p&gt;This is my favorite project; it aims to apply the modern neural machine translation techniques to African languages. With this, we are building the next google translator for African languages. If you are an African, you care for African languages, and you are an NLP enthusiast, I will recommend to look at this project. It has a good opening community. You should join this project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech stack used&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Python, Keras, PyTorch&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How to Contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;The project is well documented; you can go to &lt;a href="https://github.com/masakhane-io/masakhane-mt#how-can-i-contribute"&gt;this&lt;/a&gt; section in the readme; you will find different ways to contribute.&lt;/p&gt;

&lt;p&gt;We have a &lt;a href="https://github.com/masakhane-io/masakhane-mt/blob/master/starter_notebook.ipynb"&gt;starter notebook&lt;/a&gt;, you can grab it, it is self-explanatory, and by running it for your local language, you can have the first benchmark for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/nficano/pytube"&gt;PyTube&lt;/a&gt; :
&lt;/h3&gt;

&lt;p&gt;This is a fantastic tool, and by contributing to it, you will be helping many developers around.From the project readme, you can read that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PyTube is a very serious, lightweight, dependency-free Python library (and command-line utility) for downloading YouTube Videos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simple terms, this project helps you to download a Youtube video or a full Youtube playlist video by providing its URL using python code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech stack used&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How to contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;The project is looking for contributors. It has around 30 open issues as of now; you can pick one and start investigating it.I have opened &lt;a href="https://github.com/nficano/pytube/issues/593"&gt;this issue&lt;/a&gt; on the project. You can look at it. It is beginner-friendly, and if you have a beginner to intermediate knowledge in Python, you are good to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/MasterScrat/Chatistics"&gt;Chatistics&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The project name is a concatenation of chat and statistics.It is a python3 project that converts chat logs from various messaging platforms into pandas DataFrames. It can also generate histograms and word clouds from the chat logs.Suppose you are an intermediate python developer who is interested in data, NLP, and text analysis. In that case, this can help you to forge your knowledge in those topics.It can help you find the most active users and get the most topics your friends discuss in a Whatsapp group or a telegram channel.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech stack used&lt;/strong&gt;&lt;/em&gt;: Python&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How to contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;The project has 18 open issues, and you can think about other features you can add. I have opened a &lt;a href="https://github.com/MasterScrat/Chatistics/issues/64"&gt;issue about&lt;/a&gt; a feature some may need. You can look at it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/kenessajr/speed-rw"&gt;Speed Rwanda&lt;/a&gt;:
&lt;/h3&gt;

&lt;p&gt;A few months ago, a friend of mine &lt;a href="https://twitter.com/kenessajr?lang=en"&gt;Remy Muhire&lt;/a&gt; started a twitter thread where Rwandans users could post their internet speed in text format and a screenshot of from fast.com.&lt;/p&gt;

&lt;p&gt;We collected more than two hundred tweets from Rwandans.&lt;/p&gt;

&lt;p&gt;They shared their network provider, their internet speed (in text and as a screenshot), and some shared their location.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Python, Tweepy, Pandas&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How to contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;There are different ways to contribute to:&lt;/p&gt;

&lt;p&gt;suppose you want to dive into optical character recognition. In that case, you can help us get the internet speed from the fast.com network speed screenshot.&lt;/p&gt;

&lt;p&gt;If you want to get into data analysis, I have collected many questions you can answer using data visualization or simple pandas queries. You can check the project readme to learn more about it.&lt;/p&gt;

&lt;p&gt;If you want to play with regex, you can also help us extract the tweets’ speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/pindoio/pindo-cli"&gt;Pindo&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Pindo is the communication platform for humans and machines. It helps to send messages, emails, and text in bulk. It’s similar to Nexmo or Twillo.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How to contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;The project is actively looking for contributors. If you are a beginner and want to work on a CLI project, you can reach out to &lt;a href="https://twitter.com/kenessajr?lang=en"&gt;Remy Muhire&lt;/a&gt;. He can tell you how you can help.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/jpadilla/django-dotenv"&gt;Django-dotenv&lt;/a&gt;:
&lt;/h3&gt;

&lt;p&gt;This project is a tool that helps to read .env files in a Django project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Python and Django&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How to contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;I have opened &lt;a href="https://github.com/jpadilla/django-dotenv/issues/46"&gt;an issue&lt;/a&gt;. You can have a look at it to get started with the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python and Django Conferences website (DjangoConf and EuroPython)
&lt;/h3&gt;

&lt;p&gt;Other projects that can give you exposure are Django conference websites. The projects are written in Python and are maintained with the best Django developers in the world. Working on those projects can give you a kickstart in your Django learning path.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Python and Django&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How to contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Here is the link to &lt;a href="https://github.com/djangocon"&gt;the site&lt;/a&gt; also the &lt;a href="https://github.com/EuroPython"&gt;EuroPython website&lt;/a&gt;, you can pick one project and see how you can help.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Projects
&lt;/h3&gt;

&lt;p&gt;I also have two open-source projects. I always hack on Github. Feel free to have a look at them, &lt;a href="https://github.com/espoirMur/balobi_nini"&gt;balobi nini&lt;/a&gt;, &lt;a href="https://github.com/kisanola/nzembo"&gt;nzembo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Python, NLTK, Django, and soon Vue Js or React for frontend&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;How to contribute&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Reach out to me, and I will tell you how you can contribute.&lt;/p&gt;

&lt;h3&gt;
  
  
  StackOverflow Questions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://stackexchange.com/users/5957993"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p7IiJaKz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://stackexchange.com/users/flair/5957993.png%3Ftheme%3Ddark" title="profile for Espoir Murhabazi on Stack Exchange, a network of free, community-driven Q&amp;amp;A sites" alt="profile for Espoir Murhabazi on Stack Exchange, a network of free, community-driven Q&amp;amp;A sites" width="208" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another way of contributing to open source is by answering questions on stack overflow. You will be surprised by the number of topics you can learn in a short period. I tried two years ago, and I was surprised by the number of people I have helped on the platform. Even today, people are still coming back to me to ask one or two questions about the answers I put there a long time ago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Tech Stack&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;You decide and choose what is familiar to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;How to contribute&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;I know most of you have never seen the &lt;a href="https://stackoverflow.com/"&gt;stackOverflow&lt;/a&gt; home page; this is the chance to go and see it.&lt;/p&gt;

&lt;p&gt;There are always beginners who ask for help. You can filter new questions according to the language and tech stack you are familiar with and provide service to people.&lt;/p&gt;

&lt;h2&gt;
  
  
  I don’t know how to dress and how to drink. Can you give us some links to get started?
&lt;/h2&gt;

&lt;p&gt;You are not alone, we have all been there looking for how to take our first short. Luckily,  we wrote some blogs post on how to get started. &lt;br&gt;
I know someone who gave &lt;a href="https://isabelcosta.github.io/talks/"&gt;talks&lt;/a&gt; about opens source contributions.  I would recommend to check out her  &lt;a class="mentioned-user" href="https://dev.to/isabelcmdcosta"&gt;@isabelcmdcosta&lt;/a&gt;. She wrote an amazing blog on &lt;a href="https://isabelcosta.github.io/posts/overcoming-blockers-about-contributing-to-open-source/"&gt;how to overcome blockers while contributing to open sources projects&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are other resources you can use : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/codesandboxio/how-to-make-your-first-open-source-contribution-2oim"&gt;How to make your first OS contribution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cockroachlabs/answering-your-frequently-asked-questions-about-hacktoberfest-4p6i"&gt;FAQ about Hacktoberfest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/surajv/5-mistakes-that-can-be-avoided-as-a-beginner-in-foss-contribution-22gc"&gt;Mistakes to avoid when contributing to open source &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://opensource.guide/"&gt;Open Source guides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorial_series/an-introduction-to-open-source"&gt;An introduction to open source from digital ocean&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hackernoon.com/45-github-issues-dos-and-donts-dfec9ab4b612"&gt;Github issues do and don't &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/dailydotdev/how-to-contribute-to-open-source-projects-as-a-beginner-2h43"&gt;How to contribute to open source for beginners&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How being drunk with pull requests and merge requests will help us?
&lt;/h2&gt;

&lt;p&gt;We know that contributing to open source can play an instrumental role in your tech career. I could write a full blog post explaining its benefits, but that is for next time. And since we got a lot from the open-source community, contributing to open sources is an excellent way to give back to the community.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“&lt;em&gt;YOU received free, give free.&lt;/em&gt;” &lt;em&gt;Matthew 10:8&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  I have a not listed venue. How can I get people joining my stand?
&lt;/h2&gt;

&lt;p&gt;If you have any other open-source project you know a beginner may be interested in, please share it with us.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>hacktoberfest</category>
      <category>beginners</category>
      <category>python</category>
    </item>
    <item>
      <title>Quelques meilleurs conseils pour un travail efficace à distance: une réalité africaine</title>
      <dc:creator>Espoir Murhabazi</dc:creator>
      <pubDate>Thu, 26 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/espoir/quelques-meilleurs-conseils-pour-un-travail-efficace-a-distance-une-realite-africaine-3np1</link>
      <guid>https://dev.to/espoir/quelques-meilleurs-conseils-pour-un-travail-efficace-a-distance-une-realite-africaine-3np1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Qc5By4OY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/895691833b55b2e32f249a454da05c48/88218/cover_picture_bkv_home.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qc5By4OY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/895691833b55b2e32f249a454da05c48/88218/cover_picture_bkv_home.jpg" title="Photo Aeriènne de Goma Crédit Clarice Butsapu Twitter" alt="Photo Aeriènne de Goma Crédit Clarice Butsapu Twitter" width="590" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo Aeriènne de Goma, Crédit : &lt;a href="https://twitter.com/clarice_butsapu"&gt;Clarice Butsapu Twitter&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;De nos jours travailler à la maison est devenue une nécessité, étant développeurs c'est la seule façon de travailler en cette période de crise de la pandémie. &lt;/p&gt;

&lt;p&gt;En parcourant l’internet, je n’ai pas pu trouver un bon article donnant certaines astuces pour le travail à distance dans le contexte Africain et précisément Congolais.En Afrique dans certains pays, avoir un bon internet et un courant stable est un dilemme de tout le jour.&lt;/p&gt;

&lt;p&gt;Une idée, une motivation qui m’a poussé à rédiger cet article enfin de partage avec vous.&lt;/p&gt;

&lt;p&gt;Dans cet article je partagerai mon expérience ainsi que les différentes leçons apprises durant mes quatre années de travail à la maison et j’espère pouvoir aider certains amis et petits frères et sœurs qui ont les mêmes problèmes.&lt;/p&gt;

&lt;p&gt;Mais avant tout, laissez-moi me présenter : Je suis Espoir Murhabazi développeur FullStack indépendant avec une expérience de travail à distance que les anglais appelé “Remote work”.&lt;/p&gt;

&lt;p&gt;Je vais d’abord, en premier lieu, dans cet article définir le terme &lt;strong&gt;télétravail&lt;/strong&gt; ou &lt;strong&gt;Remote Work&lt;/strong&gt; et après, présenter ses avantages.Le télétravail est une combinaison de deux mot télé et travail. Télé comme dans télévision, téléphone veut dire à distance; En terme plus simple le télétravail veut dire travailler à distance.&lt;/p&gt;

&lt;p&gt;Wikipédia définit comme : &lt;em&gt;Le télétravail, ou telecommuting en anglais, est une activité professionnelle effectuée en tout ou partie à distance du lieu où le résultat du travail est attendu. Il s’oppose au travail sur site, à savoir le travail effectué dans les locaux de son employeur. Le télétravail peut s’effectuer depuis le domicile, un télécentre, un bureau satellite ou de manière nomade (lieux de travail différents selon l’activité à réaliser), dans le cadre du travail salarié, mais aussi depuis des espaces partagés (coworking), dans le cadre du télétravail indépendant.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Les professionnels ne devraient pas attendre COVID-19 pour constater les avantages du télétravail, L’indépendance, Un gain de temps, Hausse de la qualité de vie, Une meilleure conciliation entre le travail et la vie de famille, Réduction de frais pour l’entreprise, Personnes handicapées.&lt;/p&gt;

&lt;p&gt;Mais aussi le télétravail est trop lucratif pour les développeurs qui travaillent depuis les pays africains car il nous permet d’être rémunéré aux standards internationaux tout en vivant dans nos pays africains où le coût de la vie reste relativement faible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comment cela est-il possible ?
&lt;/h2&gt;

&lt;p&gt;Actuellement avec internet et téléphonie nous pouvons être en contact avec des personnes de l’autre bout du monde dans un clic.Le monde professionnel utilise les outils comme Slack, Zoom, Skype pour nous permettre de créer des bureaux virtuels où d’espace de travail collaboratif qui ne nécessite pas la présence physique.Nous avons compris au moins l’apport de télétravail, passons maintenant à sur quelques astuces pour survivre dans le monde de travail à distance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Astuces pour survivre
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Avoir toujours une bonne connexion internet
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KSks9M2l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/656a84f4e62a961eea871e7a6449f527/88218/vendeurs_megas_rdc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KSks9M2l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/656a84f4e62a961eea871e7a6449f527/88218/vendeurs_megas_rdc.jpg" title="Vendeur des Megas Kinshasa Source : rfi.fr" alt="Vendeur des Megas Kinshasa Source : rfi.fr" width="590" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vendeur des Megas à Kinshasa Source :  &lt;a href="www.rfi.fr"&gt;RFI&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Comme pour télétravailler nous avons besoin d’une bonne connection internet , c’est donc la première chose que nous devons nous rassurer de ne pas manquer. Ce n’est pas professionnel de donner à ses collègues des prétextes de manque de connexion internet, ou de la lenteur de la connexion pour n’avoir pas fini le travail à faire. Toutes ces excuses n’ont pas leur place dans le monde professionnel. C’est du bulshit.&lt;/p&gt;

&lt;p&gt;Le meilleur moyen de contourner cela, c’est de se préparer en avance en calculant avec exactitude la quantité des forfaits internet que l’on dépense mensuellement afin cherchez un fournisseur d’accès Internet avec la meilleure offre qualité-prix.&lt;/p&gt;

&lt;p&gt;Il est également conseillé d’avoir au moins 2 ou 3 fournisseurs de relaie, car en cas d’urgence il est possible d’utiliser toutes les connexions en même temps. J’ai moi-même l’expérience d’avoir été contraint d’utiliser à la fois les connexions Airtel, Orange, MTN Rwanda et Airtel Rwanda.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accès à l’électricité
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dk0kzE5m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/46e8070822e3b14d36486ed3c9b3a5a5/88218/delestage_afrique.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dk0kzE5m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/46e8070822e3b14d36486ed3c9b3a5a5/88218/delestage_afrique.jpg" title="Delestage En Afrique" alt="Delestage En Afrique" width="590" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Delestages en Afrique&lt;/p&gt;



&lt;p&gt;Dans certains pays, l’électricité n’est plus du tout un problème sérieux; la population a facilement de l’électricité 24 heures sur 24; dans d’autres pourtant cela reste encore un sérieux problème d’actualité.Tout comme pour l’internet, il est évident que vos collègues ne prendront jamais en compte des excuses de délestage ou de manque d’énergie pour cause du retard de travail.&lt;/p&gt;

&lt;p&gt;Voici donc quelques astuces pour palier à ce problème :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Investir dans un laptop ayant une bonne autonomie de la batterie. Il n’est pas nécessaire d’avoir le tout dernier macbook pro pour bien travailler, les chinois nous ont facilité la tâche avec de très bonnes batteries performantes à moindre coût.&lt;/li&gt;
&lt;li&gt;Comme pour l’accès à internet, il faut avoir des alternatifs pour les sources d’électricité, l’investissement dans un kit solaire avec batteries pourrait rassurer quelques heures d’autonomie. Nos amis Nigérians utilisent des groupes électrogènes et ça marche bien chez eux.&lt;/li&gt;
&lt;li&gt;Repérer des endroits calmes dans son entourage où l’on peut facilement avoir accès au courant et à internet, telle qu’une bibliothèque, un cyber café, un resto ou bar, etc. L’endroit peut ne pas être fancy ou chic mais juste une place où l’on peut s’asseoir confortablement et travailler calmement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Une fois que les problèmes d’électricité et d’internet seront résolus, la moitié des problèmes que les jeunes africains rencontrent pour le remote work aura été résolu.Le reste d’astuces sont valables peu importe le pays où l’on travaille :&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoir un endroit confortable où l’on peut s’asseoir tranquillement et coder :
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MAm9Cf4k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/e98031b102dbe112acfb8dec1a232a78/88218/Me_working.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MAm9Cf4k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/e98031b102dbe112acfb8dec1a232a78/88218/Me_working.jpg" title="Me working At Klab" alt="Me working At Klab" width="590" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Me Working from Somewhere in Kigali&lt;/p&gt;



&lt;p&gt;Le télétravail donne la flexibilité de travailler n’importe où , mais tous les endroit ne favorisent pas la productivité .Personnellement j’ai tendance à somnoler si je travaille sur mon lit ou sur le fauteuil de mon salon, mais je me concentre beaucoup plus si je suis assis confortablement sur ma table de bureau .Nous n’avons pas besoin d’exigence pour ce qui est de la marque de la chaise ou de son prix pour travailler, il nous faut tout simplement un espace qui nous facilite de travailler convenablement; nous avons des très bons menuisiers qui peuvent nous fabriquer des chaises confortable à moins de 50 USD.&lt;/p&gt;

&lt;h3&gt;
  
  
  Éviter les distractions inutiles de la maison
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VMculjkV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.murhabazi.com/6dc229b2458222b561bb2fa437b8ca05/working-from-home.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VMculjkV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.murhabazi.com/6dc229b2458222b561bb2fa437b8ca05/working-from-home.gif" alt="Working from home and having a family life." width="540" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Working from home and having family life. &lt;br&gt;
Source :  &lt;a href="www.bbc.com"&gt;Bbc&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Je pense que c’est la partie la plus difficile à gérer surtout lorsque l’on travaille à la maison et que des enfants ou de petits frères veuillent tout le temps s’amuser avec nous pendant que nous sommes disponible à tout moment.&lt;/p&gt;

&lt;p&gt;La solution réside dans l’anticipation, informer les gens que tu es occupé et les éduquer à respecter tes heures de travail.&lt;/p&gt;

&lt;p&gt;Au départ ils prendront sûrement du temps pour s’adapter mais après un bon moment ils s’habitueront à votre horaire, ainsi ils sauront qu’à tel ou tel autre moment de la journée, le papa ou le frère ou encore la soeur travaille et il ne veut pas être dérangé.&lt;/p&gt;

&lt;h3&gt;
  
  
  Investir dans de bons equipments audio:
&lt;/h3&gt;

&lt;p&gt;Comme le travail à distance demande de passer la plupart du ton temps à appeler des collègues via Skype, Zoom ou autre application, un tres bon equipement audio s’avère important.&lt;/p&gt;

&lt;p&gt;Des très bons écouteurs avec un bon micro aideront à bien parler avec ses collègues et toujours être professionnel lors des appels.Elles aideront également à s’isoler dans un endroit où il y a trop de monde et à éviter les dérangements inutiles.&lt;/p&gt;

&lt;p&gt;Nous n’avons pas besoin d’avoir le tout dernier Airpods pro ou les derniers écouteurs Bose, à moins de 10 ou 20 $, nous pouvons obtenir des très bons écouteurs avec un bon microphone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoir une vie Sociale
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r1TsxrMq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/4ddfbc99f85a09d7e3d1968e9469a0cb/88218/me_having_life.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r1TsxrMq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/4ddfbc99f85a09d7e3d1968e9469a0cb/88218/me_having_life.jpg" title="Me Having Life" alt="Me Having Life" width="590" height="659"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Me having a life at Gisenyi Beach&lt;/p&gt;



&lt;p&gt;Un très grand problème avec le remote work est l’isolement social. A force de passer la plupart du temps à travailler à la maison, il y’a risque d’oublier la vie sociale. Une conséquence à long terme est la dépression. Croyez moi la dépression est réelle, je me rappelle avoir quitté mon remote work parce que je me suis retrouvé seul sans collègues et déprimé.&lt;/p&gt;

&lt;p&gt;Pour pallier à cela voici certains astuces que je vous suggère:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mettre des limites entre les heures de travail et les heures de repos, d’habitude si je commence à travailler à 9h je m’efforce à tout finir à 21h . Car je sais que mon cerveaux ne se concentre pas au delà de 21 même les grands bugs savent qu’ils ne peuvent pas être résolus à cette heure.&lt;/li&gt;
&lt;li&gt;Trouve toi une activité extra professionnelle : personnellement j’aime le foot et la première league, mes week-ends sont pour le football et ainsi je vais dans la ville et je m’amuse avec les amis.&lt;/li&gt;
&lt;li&gt;C’est aussi bien de trouver un club qui peut être de lecture ou de n’importe quoi mais ou les gens se retrouvent régulièrement physiquement pour discuter des sujets qui importent pour eux.Personnellement l’Église et la Religion m’aident car je sais que mes dimanches sont réservés à Dieu, je pars au culte, j’ai des amis, on rigole un peu et on oublie les soucis de la vie.&lt;/li&gt;
&lt;li&gt;Avoir une petite amie peut aussi aider, comme soutien émotionnel&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prend soin de ton corps.
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Un esprit sain dans un corps sain.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Les media et les films nous ont vendu l’idée que le geek c’est une personne qui es gros et qui passe sont temps à coder, manger la pizza et boire du coca. Mes chers amis, c’est juste une idée reçu et dans la plupart du temps, c’est faux.&lt;/p&gt;

&lt;p&gt;Aie une bonne hygiène de vie, moi personnellement je commence ma journée par 30 push ups et 30 abdominaux. L’important n’est pas le nombre mais la répétition et la constance dans ces habitudes.A me voir je suis aussi slim que Wizzy Calipha mais ça m’aide à garder la forme.&lt;/p&gt;

&lt;p&gt;Selon ton programme, prends le temps de préparer un bon petit déjeuner et un bon dîner ou si tu vis avec la famille, prends le temps de savourer la nourriture de maman ou de ton partenaire.&lt;/p&gt;

&lt;p&gt;Rappelle toi: &lt;em&gt;ventre creux n’a point d’oreil&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t2lNSLXZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/7fac11e7171b974d47b7d6e2fe55b366/88218/home_food.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t2lNSLXZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.murhabazi.com/static/7fac11e7171b974d47b7d6e2fe55b366/88218/home_food.jpg" title="Local Food" alt="Local Food" width="590" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Local Food Credit:  &lt;a href="https://twitter.com/Ensapu1"&gt; Esther Nsapu&lt;/a&gt; on Twitter&lt;/p&gt;



&lt;h3&gt;
  
  
  Les autres astuces en rapport au professionnalisme dans le monde réel reste aussi valable en remote work :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;La ponctualité a toujours sa place, toujours bon de se connecter 10 minutes dans un appel zoom pour éviter les soucis technique et être toujours la personne qu’on attend dans un call.&lt;/li&gt;
&lt;li&gt;Comme la communication se passe par écrit, c’est toujours bon d’éviter de faire des fautes d’orthographe, d’être clair et concis dans ses communications écrites (mails ou slack messages).&lt;/li&gt;
&lt;li&gt;Etc…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Celles-là ne sont que quelques astuces que j’ai pu trouvé. Vous n’êtes pas obligé(e) de les suivre à la lettre, ils ont marché pour moi mais ne marcheront peut être pas pour vous, avec quelques révisions et ajustements vous pouvez avoir une version valide pour vous.Mais je suis sur qu’il y en a plein qui marchent avec vous , n’hésitez pas à nous le faire savoir en commentaire.&lt;/p&gt;

&lt;p&gt;Big thanks à tous le monde qui a participé de pret ou de loin à la rédaction cet article : Ma petite soeur &lt;a href="https://twitter.com/JosephineNdeze"&gt;Ndeze Josephine&lt;/a&gt;, mon grand &lt;a href="https://twitter.com/BBasabana"&gt;Bosco B&lt;/a&gt;, Karl Musingo, Brian pour les corrections et suggestions.&lt;/p&gt;

&lt;p&gt;In meantime: Take care, Stay Home, Stay Safe, and don't forget to always wash your hands...&lt;/p&gt;

</description>
      <category>remote</category>
      <category>beginners</category>
      <category>french</category>
      <category>career</category>
    </item>
  </channel>
</rss>
