loading...

AzureDevOps, Elixir, Docker, CI/CD, and the others — Part 2: Release and deploy.

behnam profile image Behnam Shomali ・5 min read

In the previous post (part1) I tried to use docker-compose doing build and test in AzureDevOps. The app is a hello world web site written in elixir and phoenix.

Goal

The goal is to create a continuous deployment pipeline to deploy our web app to an app service in azure by using releases in elixir and a docker image.

My todo list is to create and config these services:

  1. Azure Container Registry
  2. Azure Postgres SQL Server
  3. Build & Push pipeline in AzureDevOps
  4. App service in Azure
  5. Deploy pipeline in AzureDevOps

Azure

First thing first, we need a container registry. It will be used to store our Docker images. Let’s make one in the Azure portal.

Alt Text

Don’t forget to set the Admin user to Enable.

Alt Text

Where to put the database? hmmm! since we don’t use docker-compose here then we need to create a Postgres Server:

Alt Text

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

psql --host=**practicing**.postgres.database.azure.com --port=5432 --username=**practiceadmin@practicing** --dbname=postgres

And run the create database command:

CREATE DATABASE practicingdb;

Since the app service needs to be created based on an image, and wedon’t have it now, I’ll do it later.

‌Build & Push

Let’s back to our beloved AzureDevOps. I am going to deploy on Azure, then I need to add Azure Container Registry service connection in Project Setting.

Alt Text

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

Create a new pipeline and in the Configure step, select Docker. In the Review step, go to the Docker task and hit Settings. Make sure that your config is like this:

Alt Text

Hit Save and run. When it got finished, check Repositories in the Container Registry. You should see a new one there:

Alt Text

Ok. It’s time to back to Azure Portal and create a new App Service.

Alt Text

Alt Text

Then go to Review + create and hit Create button.

Environment Variables

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

config :hello_world_ci, HelloWorldCiWeb.Endpoint,  
    secret_key_base: System.get_env(SECRET_BASE_KEY)
# Configure your database
config :hello_world_ci, HelloWorldCi.Repo, 
    username: System.get_env("DB_USERNAME"), 
    password: System.get_env("DB_PASSWORD"), 
    database: System.get_env("DB_NAME"), 
    hostname: System.get_env("DB_HOST"), 
    pool_size: 15

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.

Alt Text

(Please read this section carefully. There are some tricks for using elixir releases). 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 build time and never calls them again at run time. 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 prod.exs and move them to releases.exs. Then you will be able to use System.fetch_env! as normal.

If you didn’t commit and push your last changes, do it and let the pipeline build it. When finished, click on Release. Here we go for the release pipeline.

Alt Text

From the right pan, select Azure App Service deployment and Apply:

Alt Text

Next, go on Tasks tab, Select Stage 1 and in the right panel click on Unlink all.

Alt Text

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):

Alt Text

After clicking on the Save button, hit the Create Release.

Alt Text

Fill it like above and hit Create.

In this step, I am going to change a file and then see the result on the website. Go to lib>hello_world_ci_web>templates>page>index.html.eex and add this line somewhere to be seen later:

<p>MIX_ENV: <b><%= System.get_env(“MIX_ENV”) %></b></p>

Commit and push it and wait until the Build pipeline finishes its work. Immediately, the Release pipeline should start.

Alt Text

Wait until it finishes its job.

Alt Text

Wait a bit and refresh the website:

Alt Text

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.

Discussion

pic
Editor guide