Fix: readme #37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |