<?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: Behnam Shomali</title>
    <description>The latest articles on DEV Community by Behnam Shomali (@behnam).</description>
    <link>https://dev.to/behnam</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%2F254475%2F8f62dd2f-3fd7-4c15-8fe4-a2cc67d13e02.jpeg</url>
      <title>DEV Community: Behnam Shomali</title>
      <link>https://dev.to/behnam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/behnam"/>
    <language>en</language>
    <item>
      <title>AzureDevOps, Elixir, Docker, CI/CD, and the others — Part 2: Release and deploy.</title>
      <dc:creator>Behnam Shomali</dc:creator>
      <pubDate>Fri, 22 Nov 2019 13:01:15 +0000</pubDate>
      <link>https://dev.to/behnam/azuredevops-elixir-docker-ci-cd-and-the-others-part-2-release-and-deploy-3c09</link>
      <guid>https://dev.to/behnam/azuredevops-elixir-docker-ci-cd-and-the-others-part-2-release-and-deploy-3c09</guid>
      <description>&lt;p&gt;In the previous post (&lt;a href="https://dev.to/behnam/azuredevops-elixir-docker-ci-cd-and-the-others-part-1-docker-compose-and-testing-o1m"&gt;part1&lt;/a&gt;) I tried to use docker-compose doing build and test in AzureDevOps. The app is a &lt;a href="https://github.com/benyblack/elixir-phoenix-ci" rel="noopener noreferrer"&gt;hello world&lt;/a&gt; web site written in elixir and phoenix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;p&gt;The goal is to create a &lt;strong&gt;continuous deployment pipeline&lt;/strong&gt; to deploy our web app to an app service in azure by using &lt;strong&gt;releases&lt;/strong&gt; in elixir and a &lt;strong&gt;docker image&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My todo list is to create and config these services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Azure Container Registry&lt;/li&gt;
&lt;li&gt;Azure Postgres SQL Server&lt;/li&gt;
&lt;li&gt;Build &amp;amp; Push pipeline in AzureDevOps&lt;/li&gt;
&lt;li&gt;App service in Azure&lt;/li&gt;
&lt;li&gt;Deploy pipeline in AzureDevOps&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Azure
&lt;/h2&gt;

&lt;p&gt;First thing first, we need a &lt;strong&gt;container registry&lt;/strong&gt;. It will be used to store our Docker images. Let’s make one in the Azure portal.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1hgxupzt5nox6rob7xnj.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1hgxupzt5nox6rob7xnj.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don’t forget to set the &lt;strong&gt;Admin user&lt;/strong&gt; to &lt;strong&gt;Enable&lt;/strong&gt;.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4j7i3hv2zpnf7zgm6s31.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4j7i3hv2zpnf7zgm6s31.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where to put the database? hmmm! since we don’t use docker-compose here then we need to create a &lt;strong&gt;Postgres Server&lt;/strong&gt;:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8azgvihpm4c0xuqd8g2i.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8azgvihpm4c0xuqd8g2i.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to create a database. To be able to connect to your database, your IP has to be added to the &lt;strong&gt;Allowed list&lt;/strong&gt;. Do it in the &lt;strong&gt;Connection Security&lt;/strong&gt; section of your &lt;strong&gt;Postgres Server&lt;/strong&gt; page on &lt;strong&gt;Azure&lt;/strong&gt;. Also, enable &lt;strong&gt;Allow access to Azure services&lt;/strong&gt;, we need it later to be able to connect from our web app. An easy way to connect is by using &lt;strong&gt;pgAdmin&lt;/strong&gt;. Also, you can use psql in bash and connect with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;**&lt;/span&gt;practicing&lt;span class="k"&gt;**&lt;/span&gt;.postgres.database.azure.com &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5432 &lt;span class="nt"&gt;--username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;**&lt;/span&gt;practiceadmin@practicing&lt;span class="k"&gt;**&lt;/span&gt; &lt;span class="nt"&gt;--dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And run the create database command:&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;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;practicingdb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Since the &lt;strong&gt;app service&lt;/strong&gt; needs to be created based on an image, and wedon’t have it now, I’ll do it later.&lt;/p&gt;
&lt;h2&gt;
  
  
  ‌Build &amp;amp; Push
&lt;/h2&gt;

&lt;p&gt;Let’s back to our beloved AzureDevOps. I am going to deploy on &lt;strong&gt;Azure&lt;/strong&gt;, then I need to add &lt;strong&gt;Azure Container Registry&lt;/strong&gt; service connection in &lt;strong&gt;Project Setting&lt;/strong&gt;.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6ekn0fi4xmlwnonkv1xv.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6ekn0fi4xmlwnonkv1xv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, I need a Dockerfile to build our production image. This is a &lt;strong&gt;multistage&lt;/strong&gt; build docker file that uses the new &lt;strong&gt;Release&lt;/strong&gt; feature of ELixir 1.9. It results in a very smaller image, something like 35 MB vs 1.2 GB if we use &lt;strong&gt;Release&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Create a new pipeline and in the &lt;strong&gt;Configure&lt;/strong&gt; step, select Docker. In the &lt;strong&gt;Review&lt;/strong&gt; step, go to the Docker task and hit &lt;strong&gt;Settings&lt;/strong&gt;. Make sure that your config is like this:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fy3dsbbof9fu1vriwf5a1.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fy3dsbbof9fu1vriwf5a1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit &lt;strong&gt;Save and run&lt;/strong&gt;. When it got finished, check &lt;strong&gt;Repositories&lt;/strong&gt; in the Container Registry. You should see a new one there:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzi9ojua6tgsbdzp9g2t8.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzi9ojua6tgsbdzp9g2t8.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok. It’s time to back to Azure Portal and create a new App Service.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbmwylw9c7ovupzidf3w1.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbmwylw9c7ovupzidf3w1.png" alt="Alt Text"&gt;&lt;/a&gt;&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fv93299qbo5miw7b7o7bf.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fv93299qbo5miw7b7o7bf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then go to &lt;strong&gt;Review + create&lt;/strong&gt; and hit &lt;strong&gt;Create&lt;/strong&gt; button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;p&gt;Before going further, there is something in the app that should be adjusted before going to deploy it. Let’s take a look at &lt;strong&gt;prod.exs&lt;/strong&gt; at the &lt;strong&gt;config&lt;/strong&gt; folder. It has a reference to &lt;strong&gt;prod.secret.exs&lt;/strong&gt; which contains the &lt;strong&gt;connection string&lt;/strong&gt; and &lt;strong&gt;secret_key_base&lt;/strong&gt;. Also, this file is excluded by &lt;strong&gt;.gitignore&lt;/strong&gt;. It is not a good idea to put this file in the source control. Instead, we can feed this data by &lt;strong&gt;Environment Variables&lt;/strong&gt;. First, replace the last import_config line of &lt;strong&gt;prod.exs&lt;/strong&gt; by this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:hello_world_ci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;HelloWorldCiWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="ss"&gt;secret_key_base:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;SECRET_BASE_KEY&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Configure your database&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:hello_world_ci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;HelloWorldCi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="ss"&gt;username:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DB_USERNAME"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="ss"&gt;password:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DB_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="ss"&gt;database:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DB_NAME"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="ss"&gt;hostname:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DB_HOST"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="ss"&gt;pool_size:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Go to your App Service page and find Configuration in Settings. Add the above keys and needed values. Database related values can be found in the Postgres page in the portal. Don’t forget to hit the save button.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fw61ksruun8zk84q0bakw.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fw61ksruun8zk84q0bakw.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Please read this section carefully. There are some tricks for using &lt;strong&gt;elixir releases&lt;/strong&gt;). Everything looks good but if you deploy your web app now you would realize that the app is unable to read the environment variables! No kidding! The reason is when the release build is used, it evaluates env variables for the prod config file at &lt;strong&gt;build time&lt;/strong&gt; and never calls them again at &lt;strong&gt;run time&lt;/strong&gt;. There is a good solution for it. You can add a file in the config folder named releases.exs and it will be used in the release build and will be able to read environment variables at runtime. Remove config items, like DB connection string and secret key from &lt;strong&gt;prod.exs&lt;/strong&gt; and move them to &lt;strong&gt;releases.exs&lt;/strong&gt;. Then you will be able to use &lt;strong&gt;System.fetch_env!&lt;/strong&gt; as normal.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;If you didn’t commit and push your last changes, do it and let the pipeline build it. When finished, click on &lt;strong&gt;Release&lt;/strong&gt;. Here we go for the release pipeline.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flaaduvmdkbb1xl82cdry.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flaaduvmdkbb1xl82cdry.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the right pan, select &lt;strong&gt;Azure App Service deployment&lt;/strong&gt; and &lt;strong&gt;Apply&lt;/strong&gt;:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fud30t4fnxfwqza438y4c.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fud30t4fnxfwqza438y4c.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, go on Tasks tab, Select &lt;strong&gt;Stage 1&lt;/strong&gt; and in the right panel click on &lt;strong&gt;Unlink all&lt;/strong&gt;.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2r98jrqmrs4pbg4npg65.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2r98jrqmrs4pbg4npg65.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on Deploy Azure App Service in the left and fill the right panel as shown in this (some values may be different in your account):&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Frawoid27aoo4pn5n9n3z.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Frawoid27aoo4pn5n9n3z.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking on the &lt;strong&gt;Save&lt;/strong&gt; button, hit the &lt;strong&gt;Create Release&lt;/strong&gt;.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fybtp4j1zpz6zycxkz01i.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fybtp4j1zpz6zycxkz01i.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill it like above and hit &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this step, I am going to change a file and then see the result on the website. Go to &lt;strong&gt;lib&amp;gt;hello_world_ci_web&amp;gt;templates&amp;gt;page&amp;gt;index.html.eex&lt;/strong&gt; and add this line somewhere to be seen later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;MIX_ENV: &lt;span class="nt"&gt;&amp;lt;b&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;System.get_env&lt;/span&gt;&lt;span class="err"&gt;(“&lt;/span&gt;&lt;span class="na"&gt;MIX_ENV&lt;/span&gt;&lt;span class="err"&gt;”)&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit and push it and wait until the Build pipeline finishes its work. Immediately, the Release pipeline should start.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9qrmg2ajtbu6pj1lkvu6.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9qrmg2ajtbu6pj1lkvu6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait until it finishes its job.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7ay9hjza7n46jqw22y5k.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7ay9hjza7n46jqw22y5k.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait a bit and refresh the website:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxuj94ucpxdtcdazxd2l1.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxuj94ucpxdtcdazxd2l1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome! That’s it. It may seem complicated but trust me, it’s easier than it seems. What about the next part? In the next post, I will try to deploy the app on Kubernetes.&lt;/p&gt;

</description>
      <category>continuousdeployment</category>
      <category>azure</category>
      <category>docker</category>
      <category>elixir</category>
    </item>
    <item>
      <title>AzureDevOps, Elixir, Docker, CI/CD, and the others - Part 1: docker-compose and testing.</title>
      <dc:creator>Behnam Shomali</dc:creator>
      <pubDate>Fri, 08 Nov 2019 13:49:47 +0000</pubDate>
      <link>https://dev.to/behnam/azuredevops-elixir-docker-ci-cd-and-the-others-part-1-docker-compose-and-testing-o1m</link>
      <guid>https://dev.to/behnam/azuredevops-elixir-docker-ci-cd-and-the-others-part-1-docker-compose-and-testing-o1m</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Elixir is a new player in the market, and the tooling is not as comprehensive as the others like C# and Java. When I started learning Elixir, I had some questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where to host it?&lt;/li&gt;
&lt;li&gt;How to build and test it in a CI style?&lt;/li&gt;
&lt;li&gt;How to deploy it on Azure?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The immediate answer was to have a VM on Azure, but that's not an affordable solution. Fortunately, nowadays the main problem is solved by using docker for development and deployment. In this post, I will share a simple solution to using AzureDevOps for the CI part of the development and in a follow-up article, I will cover the CD part. If you want to check out the code, here is the repo: &lt;a href="https://github.com/benyblack/elixir-phoenix-ci"&gt;https://github.com/benyblack/elixir-phoenix-ci&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One of the most popular approaches to website creation in Elixir is by using Phoenix. To set it up using &lt;a href="https://gist.github.com/benyblack/f3c0e44fa8f796e95644da0bfbb4c6ff"&gt;this&lt;/a&gt; gist. The credentials for the &lt;strong&gt;Postgres server&lt;/strong&gt; exist in &lt;strong&gt;dev.exs&lt;/strong&gt; in the config folder. If your credentials are different, you can change them in the script Have a look at the final result in the following:&lt;/p&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;


&lt;p&gt;Navigate to &lt;a href="http://localhost:4000"&gt;http://localhost:4000&lt;/a&gt;, and you will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LUAGktP0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bz53zxq5xtoifat4f67f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LUAGktP0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bz53zxq5xtoifat4f67f.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have a working code, then we can think about the build and test part. To begin, let's try to do it locally with Docker. &lt;/p&gt;

&lt;p&gt;First, we need a docker file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Build and run it by these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; benyblack/helloworldci &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 4000:4000 benyblack/helloworldci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Navigate to &lt;a href="http://localhost:4000"&gt;http://localhost:4000&lt;/a&gt;, and you should get see a working web site, albeit one with lots of connection errors in the console. It's time to use docker-compose magic. The config file for docker-compose is rather simple:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Furthermore, we need to change the database &lt;strong&gt;hostname&lt;/strong&gt; in &lt;strong&gt;test.exs&lt;/strong&gt;. Change the &lt;strong&gt;hostname&lt;/strong&gt; to &lt;strong&gt;database&lt;/strong&gt;. Then run this command to build and run our tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;--abort-on-container-exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There we have it! You should see the result at the end of the console messages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_X1CQvHp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h3lh6oal8joywz6bahgy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_X1CQvHp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h3lh6oal8joywz6bahgy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Integration
&lt;/h2&gt;

&lt;p&gt;That's it! It's now ready to be used in AzureDevOps. We need to connect our GitHub and DockerHub account to the project in the AzureDevOps project settings section. Go to the &lt;strong&gt;Project Settings&lt;/strong&gt; at the bottom left side of the page and then select &lt;strong&gt;Service connections&lt;/strong&gt; and hit "&lt;strong&gt;+ New service connection&lt;/strong&gt;". From the list select &lt;strong&gt;Github&lt;/strong&gt;. It is necessary to give access to our code on Github.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tLioZn-A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/im0g12oktytyszhzd8aa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tLioZn-A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/im0g12oktytyszhzd8aa.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kBwlLddi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/carvus2f98y2i4msqgw8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kBwlLddi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/carvus2f98y2i4msqgw8.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do the same for DockerHub to connect your public repositories to the project, except select &lt;strong&gt;Docker Registery&lt;/strong&gt; this time. We'll use it later for using docker-compose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vjOt3g2H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1iqhmawdw934auyae4cs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vjOt3g2H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1iqhmawdw934auyae4cs.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aQhXrEeY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/d2mafy1nhal8dqu74ou3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aQhXrEeY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/d2mafy1nhal8dqu74ou3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to create a Pipeline. Go to &lt;strong&gt;Pipelines&lt;/strong&gt; from the main menu. Select &lt;strong&gt;Github&lt;/strong&gt; from the list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RPyyjy5p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7nt3sdv2k1fvxlryyriy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RPyyjy5p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7nt3sdv2k1fvxlryyriy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit &lt;strong&gt;Next&lt;/strong&gt; and select &lt;strong&gt;Existing Azure pipelines YAML file&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7trCC4YF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/n4en6tw77hyzr1robn88.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7trCC4YF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/n4en6tw77hyzr1robn88.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A popup should appear from the right. Select the config file we have created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NBO9bHgo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/eamk6ewk0i0ny5rhyn2p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NBO9bHgo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/eamk6ewk0i0ny5rhyn2p.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, you can adjust the config by hitting the setting link or editing it manually. If your DockerHub connection name is not the same as mine, you'll have to change it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G70iA94X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5idpe5chc6flgznxpl2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G70iA94X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5idpe5chc6flgznxpl2m.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--62jupz4_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8zuxvupqucbkc9oslegz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--62jupz4_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8zuxvupqucbkc9oslegz.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, hit the &lt;strong&gt;Run&lt;/strong&gt; button at the top left of the page.&lt;/p&gt;

&lt;p&gt;You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RYpI2Lxo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5c5z87qz8dp11j3arx6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RYpI2Lxo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5c5z87qz8dp11j3arx6x.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At long last, we have to have some green lights. However, there is one more step; publishing the test result. The problem is that AzureDevOps can't parse the test result from the &lt;strong&gt;mix test&lt;/strong&gt;. The solution is to apply a &lt;strong&gt;Formatter&lt;/strong&gt; for the test result. In this case, I chose to use &lt;a href="https://github.com/victorolinasc/junit-formatter"&gt;JUnitFormatter&lt;/a&gt;. It exports the result to an XML file. Using the library is pretty straightforward. I appended this section in my &lt;strong&gt;test.exs&lt;/strong&gt; in the config folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Configure publishing test result&lt;/span&gt;
&lt;span class="s"&gt;config :junit_formatter,&lt;/span&gt;
&lt;span class="na"&gt;report_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;“report_file_test.xml”,&lt;/span&gt;
&lt;span class="na"&gt;report_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;“./”,&lt;/span&gt;
&lt;span class="na"&gt;print_report_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;prepend_project_name?&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moreover, we need to add a test publishing step to our pipeline. Go to the build menu and select Edit to edit the pipelines. From the right panel, select &lt;strong&gt;Publish Test Result&lt;/strong&gt; and set the &lt;strong&gt;testResultsFiles&lt;/strong&gt; to '&lt;strong&gt;**/hello_world_ci-report_file_test.xml&lt;/strong&gt;'. Click &lt;strong&gt;Add&lt;/strong&gt;. It should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--moSYoFAH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ojk8zif7bljf41j00vvb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--moSYoFAH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ojk8zif7bljf41j00vvb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save it and run it again. You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SXrbmJks--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/mcetvol54e04pmld87te.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SXrbmJks--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/mcetvol54e04pmld87te.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to the &lt;strong&gt;Tests&lt;/strong&gt; tab. Your Tests tab should be the same as mine:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SU14TOg---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/suzuuhm8pp1aoiitty0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SU14TOg---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/suzuuhm8pp1aoiitty0e.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voilà! That's it! Pretty simple. In an &lt;a href="https://dev.to/behnam/azuredevops-elixir-docker-ci-cd-and-the-others-part-2-release-and-deploy-3c09"&gt;upcoming post&lt;/a&gt;, I am going to do the &lt;strong&gt;CD&lt;/strong&gt; part.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>cicd</category>
      <category>azuredevops</category>
    </item>
  </channel>
</rss>
