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:
- Azure Container Registry
- Azure Postgres SQL Server
- Build & Push pipeline in AzureDevOps
- App service in Azure
- Deploy pipeline in AzureDevOps
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.
Don’t forget to set the Admin user to Enable.
Where to put the database? hmmm! since we don’t use docker-compose here then we need to create a Postgres Server:
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.
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.
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:
Hit Save and run. When it got finished, check Repositories in the Container Registry. You should see a new one there:
Ok. It’s time to back to Azure Portal and create a new App Service.
Then go to Review + create and hit Create button.
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.
(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.
From the right pan, select Azure App Service deployment and Apply:
Next, go on Tasks tab, Select Stage 1 and in the right panel click on Unlink all.
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):
After clicking on the Save button, hit the Create Release.
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.
Wait until it finishes its job.
Wait a bit and refresh the website:
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.