Reputation: 2019
I have a multi-container app with source code stored on Github. Essentially, there's only one part in active development, and the other containers are either stable (like Nginx with special settings) or external (like redis
).
My question is: how can I use Github Actions for the deployment to Azure App Service?
It's rather well-described for a single-container App, and I'm already able to push my image to the Container Registry with an Action. But then I still have to go to Azure web interface and trigger docker-compose
from there. Or alternatively, I can trigger docker-compose
from the Azure CLI from my local machine.
But the actual problem is to trigger docker-compose
from the Github Action (in order to deploy every time my PR into master
is validated).
Any ideas?
As a reference point: my docker-compose.yml
is like this:
version: '3'
services:
nginx:
image: mycr.azurecr.io/nginx:dev-latest
ports:
- "80:80"
- "2222:2222"
volumes:
- asset-volume/app/static
depends_on:
- app
restart: always
app:
image: mycr.azurecr.io/django:dev-latest
ports:
- "8000:8000"
volumes:
- asset-volume:/app/static
- app-volume:/app
- api-documents:/app/documents/storage
redis:
image: redis:alpine
celery:
restart: always
command: celery -A mainApp worker -l info
image: mycr.azurecr.io/django:dev-latest
volumes:
- app-volume:/app
working_dir: /app
depends_on:
- app
- nginx
- redis
volumes:
asset-volume
app-volume
Upvotes: 5
Views: 3006
Reputation: 2019
The real solution seems to be possible only via Azure CLI, but for the moment I came up with a partial one. That's why I can't mark my own answer as an "accepted solution".
In my action (see below):
Dockerfile
latest
and <date>-<hash>
Then, on Azure: MyApp on AppService > Deployment Center:
docker-compose.yml
And that's it. After that, on every merge validation, the GitHub CI pushes a ready-to-go image to a Container Registry. And I only need to hit the "Restart" button on the GUI to restart my app. Then the new latest
image will be loaded by Docker. Of course, it's still a manual action, but it's better than nothing.
My delpoyment.yml
with the action looks like this (I omit non-essential details):
name: 'Deployment to Azure'
on:
push:
env:
DEV_URL: 'my-dev-app.example.com'
DEV_DBNAME: 'app-dev-db'
PROD_URL: ''my-app.example.com''
PROD_DBNAME: 'app-dev-db'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 'Get the branch name'
id: branch-name
uses: tj-actions/branch-names@v5
- name: 'Set RAW_BRANCH variable'
run: echo "RAW_BRANCH=${{ steps.branch-name.outputs.current_branch }}" >> $GITHUB_ENV
- name: 'Checkout repo'
uses: actions/checkout@v2
- name: 'Sets branch-related variables'
# `main` -> `prod`, `dev` -> `dev`,
# everything else -> `feat`:
run: |
if [[ $RAW_BRANCH == 'main' ]]; then
echo "BRANCH=prod" >> $GITHUB_ENV
elif [[ $RAW_BRANCH == 'dev' ]]; then
echo "BRANCH=$RAW_BRANCH" >> $GITHUB_ENV
echo "DBNAME=${{ env.DEV_DBNAME }}" >> $GITHUB_ENV
echo "URL=${{ env.DEV_URL }}" >> $GITHUB_ENV
else
echo "BRANCH=feat" >> $GITHUB_ENV; fi
echo "DBNAME=${{ env.DEV_DBNAME }}" >> $GITHUB_ENV
echo "URL=${{ env.DEV_URL }}" >> $GITHUB_ENV
- name: 'Set SHA variable'
run: echo "SHA=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: 'Set TAG variable'
run: echo "TAG=${{ env.BRANCH }}-$(date "+%Y.%m.%d")-${{ env.SHA }}" >> $GITHUB_ENV
- name: 'Login via Azure CLI'
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: 'Login to Container Registry'
uses: azure/docker-login@v1
with:
login-server: ${{ secrets.DOCKER_REGISTRY_SERVER_URL }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: 'build and push'
run: |
docker build -t ${{ secrets.DOCKER_REGISTRY_SERVER_URL }}/backend:${{ env.TAG }} \
-t ${{ secrets.DOCKER_REGISTRY_SERVER_URL }}/backend:${{ env.BRANCH }}-latest .
docker push --all-tags ${{ secrets.DOCKER_REGISTRY_SERVER_URL }}/backend
And then my Config for, say, dev
instance in the Deployment Center looks like:
version: '3'
services:
nginx:
image: myacr.azurecr.io/nginx:latest
ports:
- "80:80"
- "2222:2222"
volumes:
- asset-volume-dev:/app/static
depends_on:
- app
restart: always
app:
image: myacr.azurecr.io/backend:dev-latest
ports:
- "8000:8000"
volumes:
- asset-volume-dev:/app/static
- app-volume-dev:/app
redis:
image: redis:alpine
celery:
restart: always
command: celery -A superDuperApp worker -l info
image: myapp.azurecr.io/backend:dev-latest
volumes:
- app-volume-dev:/app
working_dir: /app
depends_on:
- app
- nginx
- redis
volumes:
asset-volume-dev:
app-volume-dev:
⚠️ NB: For some unclear reason, if I leave the docker-compose.yml
in the root directory of the app, then the deployment script will be some weird combination of both that yml
and what it written in the Config in Azure GUI. Therefore I had to remove that docker-compose.yml
from the root folder of the repo.
Upvotes: 2