Skip to content

Fix: readme

Fix: readme #37

name: Build, push, and deploy images
# Builds all 7 Rodan images, pushes them to the private GitHub Container Registry, and
# (on manual dispatch or version tags) deploys the app tier to the k3s cluster.
# Replaces the DockerHub autobuild hooks (hooks/build, hooks/push).
#
# Tags:
# git tag v* -> ghcr.io/ddmal/<name>:<version> (+ deploy)
# push to develop -> ghcr.io/ddmal/<name>:nightly
# pull_request -> build only, no push (validates Dockerfiles)
# workflow_dispatch -> optional tag input (defaults to "nightly") (+ deploy)
# Every pushed build also gets an immutable ghcr.io/ddmal/<name>:sha-<gitsha> tag,
# which the deploy job pins so the rollout is guaranteed to pull the new image.
on:
push:
branches: [develop]
tags: ['v*']
workflow_dispatch:
inputs:
tag:
description: "Image tag to build/push (e.g. v3.4.0 or nightly)"
required: false
default: "nightly"
permissions:
contents: read
packages: write
concurrency:
group: build-and-deploy-${{ github.ref }}
cancel-in-progress: true
env:
REGISTRY: ghcr.io
OWNER: ddmal
jobs:
setup:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.meta.outputs.tag }}
push: ${{ steps.meta.outputs.push }}
short_sha: ${{ steps.meta.outputs.short_sha }}
steps:
- id: meta
env:
EVENT: ${{ github.event_name }}
REF_TYPE: ${{ github.ref_type }}
REF_NAME: ${{ github.ref_name }}
INPUT_TAG: ${{ github.event.inputs.tag }}
PR_NUMBER: ${{ github.event.number }}
run: |
set -euo pipefail
if [ "$EVENT" = "workflow_dispatch" ] && [ -n "$INPUT_TAG" ]; then
TAG="$INPUT_TAG"; PUSH=true
elif [ "$REF_TYPE" = "tag" ]; then
TAG="$REF_NAME"; PUSH=true # e.g. v3.4.0
elif [ "$EVENT" = "pull_request" ]; then
TAG="pr-$PR_NUMBER"; PUSH=false # build only, never push
elif [ "$REF_NAME" = "develop" ]; then
TAG="nightly"; PUSH=true
else
TAG="$REF_NAME"; PUSH=true
fi
# Docker tags cannot contain "/"
TAG="$(printf '%s' "$TAG" | tr '/' '-')"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "push=$PUSH" >> "$GITHUB_OUTPUT"
echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
echo "Resolved tag=$TAG push=$PUSH sha=${GITHUB_SHA::7} (event=$EVENT ref_type=$REF_TYPE ref=$REF_NAME)"
# Ordered dependency chain on ONE runner so the hardcoded
# `FROM ddmal/<base>:${VERSION}` lines resolve to the locally-built images.
chain:
needs: setup
runs-on: ubuntu-latest
env:
TAG: ${{ needs.setup.outputs.tag }}
PUSH: ${{ needs.setup.outputs.push }}
SHA_TAG: sha-${{ needs.setup.outputs.short_sha }}
steps:
- uses: actions/checkout@v4
- name: Free disk space
# Reclaims ~25-35 GB on ubuntu-latest.
uses: jlumbroso/free-disk-space@v1.3.1
with:
tool-cache: true
large-packages: false
docker-images: false
- name: Log in to GHCR
if: env.PUSH == 'true'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build rodan-python3-celery (base)
run: |
docker build \
--build-arg BRANCHES=develop \
--build-arg VERSION="$TAG" \
-t "$REGISTRY/$OWNER/rodan-python3-celery:$TAG" \
-t "$REGISTRY/$OWNER/rodan-python3-celery:$SHA_TAG" \
-t "ddmal/rodan-python3-celery:$TAG" \
-f python3-celery/Dockerfile \
.
- name: Build rodan-main (FROM rodan-python3-celery)
run: |
docker build \
--build-arg BRANCHES=develop \
--build-arg VERSION="$TAG" \
--build-arg build_hash="${{ github.sha }}" \
-t "$REGISTRY/$OWNER/rodan-main:$TAG" \
-t "$REGISTRY/$OWNER/rodan-main:$SHA_TAG" \
-t "ddmal/rodan-main:$TAG" \
-f rodan-main/Dockerfile \
.
- name: Build nginx (FROM rodan-main, bakes static files)
run: |
docker build \
--build-arg VERSION="$TAG" \
-t "$REGISTRY/$OWNER/nginx:$TAG" \
-t "$REGISTRY/$OWNER/nginx:$SHA_TAG" \
./nginx
- name: Push chain images
if: env.PUSH == 'true'
run: |
docker push "$REGISTRY/$OWNER/rodan-python3-celery:$TAG"
docker push "$REGISTRY/$OWNER/rodan-python3-celery:$SHA_TAG"
docker push "$REGISTRY/$OWNER/rodan-main:$TAG"
docker push "$REGISTRY/$OWNER/rodan-main:$SHA_TAG"
docker push "$REGISTRY/$OWNER/nginx:$TAG"
docker push "$REGISTRY/$OWNER/nginx:$SHA_TAG"
# Independent images — each on its own runner, in parallel.
independent:
needs: setup
runs-on: ubuntu-latest
env:
TAG: ${{ needs.setup.outputs.tag }}
PUSH: ${{ needs.setup.outputs.push }}
SHA_TAG: sha-${{ needs.setup.outputs.short_sha }}
strategy:
fail-fast: false
matrix:
include:
- name: rodan-client
dockerfile: rodan-client/Dockerfile
context: ./rodan-client
args: "--build-arg BRANCHES=develop"
- name: rodan-gpu-celery
dockerfile: gpu-celery/Dockerfile
context: .
args: "--build-arg BRANCHES=develop"
- name: postgres-plpython
dockerfile: postgres/Dockerfile
context: .
args: ""
- name: iipsrv
dockerfile: iipsrv/Dockerfile
context: ./iipsrv
args: ""
steps:
- uses: actions/checkout@v4
- name: Free disk space
uses: jlumbroso/free-disk-space@v1.3.1
with:
tool-cache: true
large-packages: false
docker-images: false
- name: Log in to GHCR
if: env.PUSH == 'true'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build ${{ matrix.name }}
run: |
docker build ${{ matrix.args }} \
--build-arg VERSION="$TAG" \
-t "$REGISTRY/$OWNER/${{ matrix.name }}:$TAG" \
-t "$REGISTRY/$OWNER/${{ matrix.name }}:$SHA_TAG" \
-f "${{ matrix.dockerfile }}" \
"${{ matrix.context }}"
- name: Push ${{ matrix.name }}
if: env.PUSH == 'true'
run: |
docker push "$REGISTRY/$OWNER/${{ matrix.name }}:$TAG"
docker push "$REGISTRY/$OWNER/${{ matrix.name }}:$SHA_TAG"
# Deploy the app tier by pinning the immutable sha-<gitsha> tag (guarantees a fresh pull +
# gives `kubectl rollout undo` rollback). Runs only on manual dispatch or version tags.
# postgres / redis / rabbitmq are intentionally left alone (don't bounce the DB on every deploy).
deploy:
needs: [setup, chain, independent]
if: needs.setup.outputs.push == 'true' && (github.event_name == 'workflow_dispatch' || github.ref_type == 'tag')
runs-on: ubuntu-latest
env:
NS: rodan
REG: ghcr.io/ddmal
SHA_TAG: sha-${{ needs.setup.outputs.short_sha }}
steps:
- name: Install kubectl
uses: azure/setup-kubectl@v4
- name: Configure kubeconfig from secret
env:
KUBECONFIG_DATA: ${{ secrets.KUBECONFIG }}
run: |
set -euo pipefail
printf '%s' "$KUBECONFIG_DATA" > "$RUNNER_TEMP/kubeconfig"
chmod 600 "$RUNNER_TEMP/kubeconfig"
echo "KUBECONFIG=$RUNNER_TEMP/kubeconfig" >> "$GITHUB_ENV"
- name: Roll app-tier images to the immutable SHA tag
run: |
set -euo pipefail
kubectl -n "$NS" set image deployment/rodan-main rodan-main="$REG/rodan-main:$SHA_TAG"
kubectl -n "$NS" set image deployment/celery celery="$REG/rodan-main:$SHA_TAG"
kubectl -n "$NS" set image deployment/py3-celery py3-celery="$REG/rodan-python3-celery:$SHA_TAG"
kubectl -n "$NS" set image deployment/gpu-celery gpu-celery="$REG/rodan-gpu-celery:$SHA_TAG"
kubectl -n "$NS" set image deployment/iipsrv iipsrv="$REG/iipsrv:$SHA_TAG"
kubectl -n "$NS" set image deployment/rodan-client rodan-client="$REG/rodan-client:$SHA_TAG"
kubectl -n "$NS" set image deployment/nginx nginx="$REG/nginx:$SHA_TAG"
- name: Wait for rollouts
run: |
set -euo pipefail
for d in rodan-main celery py3-celery gpu-celery iipsrv rodan-client nginx; do
kubectl -n "$NS" rollout status deployment/"$d" --timeout=600s
done