Article
Use Docker Compose with Phoenix Framework
Docker Compose aloows us to start together some services inside a project. How to use it with Phoenix Framework ? Let's see that together !
Vous avez une image Docker avec votre application Elixir et vous voulez utiliser Docker Compose pour gérer les services associés (PostgreSQL par exemple). Si ce n'est pas le cas, mes précédents articles sur le sujet sont un bon point de départ.
This article is part of a serie about releasing and deploying a Phoenix Framework app. You can find our other articles on the blog.
Use Docker Compose locally
The point of Docker is to share the same environment between your work stations. It's as useful in production as in local development. In that first case, let's use Docker Compose to start the project's associated services without putting our Phoenix Framework app into a container.
Why? Because your locale app (mix
) is not the same as the production one (release
), because the programming experience is better with asdf
, because no online tutorial will remind you to go inside your container before executing the commands the give you, and to avoid modifications of your dev Dockerfile in order to add dependancies.
Let's create a compose.local.yml
file.
services:
db:
image: postgres:14
restart: always
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_USER=postgres
ports:
- 5432:5432
volumes:
- db:/var/lib/postgresql/data
volumes:
db:
driver: local
We will simply ask it to start a postgres service, with the user and password included, available on the port 5432
with persistent data storage.
To start it, we will use docker compose
. By default, the file we are looking for is compose.yml
, but we will use it for our production image.
docker compose -f compose.local.yml up
If you prefer, you can call that file compose.yml
and the production one compose.prod.yml
.
Use Docker Compose in production
To use Docker Compose in production, we will mainly have to add the Phoenix Framework server as a service.
services:
phoenix:
image: MY_REGISTRY/MY_NAMESPACE/MY_PROJECT
env_file:
- .env
ports:
- '4000:4000'
depends_on:
- db
volumes:
- files:/uploads
db:
image: postgres:14
env_file:
- .env
environment:
PGDATA: /var/lib/postgresql/data/pgdata
restart: always
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
files:
pgdata:
Besides our server, I replaced the environment variables by a env_file
. This allows us to hide the passwords from a file that will be on our Github or Sourcehut repository. This file must be on our host when we do the docker compose and the content will be turned into environment variables inside our containers.
Other solutions exist to handle secrets with Docker. In the case of the postgres image, it is possible to use Docker secrets
with the POSTGRES_PASSWORD_FILE
, POSTGRES_USER_FILE
and POSTGRES_DB_FILE
variables. If we want the same to happen with our Phoenix server, we have to modify our config/runtime.exs
file to read the values inside a file instead of a environment variable.
Edit : I added a volume example linking to a /uploads
folder for the files uploaded on the server. The name is free as Phoenix doesn't choose for us. This won't work with our priv
folder as its position changes at each new version from your project. It's then easier to choose an arbitrary path.