Creating container images for migrations
To integrate schema migrations into pipelines that deploy to container management systems (such as Kubernetes, AWS ECS, Google Cloud Run, etc.) it is recommended to create a dedicated container image per version that contains the migration tool (such as Atlas) and the relevant migration files.
In this guide we will demonstrate how to build a dedicated Docker image that includes Atlas and the relevant migrations files. We will demonstrate how to build this image as a GitHub Actions Workflow, but the same result can be achieved in any CI system.
Defining the Dockerfile
Suppose our project structure looks something like:
.
├── main.go
└── migrations
├── 20221031125934_init.sql
├── 20221031125940_add_users_table.sql
├── 20221031125948_add_products_table.sql
└── atlas.sum
Our goal is to build an image that contains:
- The
migrations
directory - The Atlas binary
To do this we can build our container image with the official Atlas Docker image as the base layer.
To do this, our Dockerfile should be placed in the directory containing the migrations
directory and will look something like this:
FROM arigaio/atlas:latest
COPY migrations /migrations
Verify our image
To test our new Dockerfile run:
docker build -t my-image .
Docker will build our image:
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 36B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/arigaio/atlas:latest 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 252B 0.0s
=> [1/2] FROM docker.io/arigaio/atlas:latest 0.0s
=> CACHED [2/2] COPY migrations /migrations 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:c928104de31fc4c99d114d40ea849ade917beae3df7ffe9326113b289939878e 0.0s
=> => naming to docker.io/library/my-image 0.0s
To verify Atlas can find your migrations directory and that its integrity is intact run:
docker run --rm my-image migrate validate
If no issues are found, no errors will be printed out.
Defining the GitHub Actions Workflow
Next, we define a GitHub Actions workflow that will build our container image and push it to the GitHub container repo (ghcr.io) on every push to our mainline branch:
name: Push Docker
on:
push:
branches:
- master
jobs:
docker-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v3
with:
push: true
file: ${{ matrix.file }}
tags: ghcr.io/ariga/<repo name>:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
Save this file in your GitHub repository under the .github/workflows
directory.
After you push it to your mainline branch, you will see a run of the new
workflow in the Actions
tab of the repository.