Build Docker Image #117
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 Docker Image | |
| on: | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| IMAGE: ${{ github.repository }} | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-latest | |
| arch: amd64 | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| arch: arm64 | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v6 | |
| - name: Get version from package.json | |
| id: version | |
| run: echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT" | |
| - name: Setup Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata (tags, labels) for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| ghcr.io/${{ env.IMAGE }} | |
| docker.io/${{ env.IMAGE }} | |
| tags: | | |
| type=sha,prefix=sha-,suffix=-${{ matrix.arch }} | |
| - name: Build and Push by Digest | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| sbom: true | |
| push: true | |
| provenance: mode=max | |
| platforms: ${{ matrix.platform }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| annotations: ${{ steps.meta.outputs.annotations }} | |
| cache-from: type=gha,scope=${{ env.IMAGE }}-${{ matrix.arch }} | |
| cache-to: type=gha,mode=max,scope=${{ env.IMAGE }}-${{ matrix.arch }} | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: digests-${{ matrix.arch }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge: | |
| needs: build | |
| timeout-minutes: 30 | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@v6 | |
| with: | |
| sparse-checkout: package.json | |
| sparse-checkout-cone-mode: false | |
| - name: Get version from package.json | |
| id: version | |
| run: echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT" | |
| - name: Download digests | |
| uses: actions/download-artifact@v7 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - name: Setup Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Parse version components | |
| id: semver | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| MAJOR=$(echo "$VERSION" | cut -d. -f1) | |
| MINOR=$(echo "$VERSION" | cut -d. -f2) | |
| echo "major=$MAJOR" >> "$GITHUB_OUTPUT" | |
| echo "minor=$MINOR" >> "$GITHUB_OUTPUT" | |
| - name: Extract metadata for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| ghcr.io/${{ env.IMAGE }} | |
| docker.io/${{ env.IMAGE }} | |
| tags: | | |
| type=sha,prefix=sha- | |
| type=raw,value=latest | |
| type=raw,value=v${{ steps.version.outputs.version }} | |
| type=raw,value=v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }} | |
| type=raw,value=v${{ steps.semver.outputs.major }} | |
| - name: Create manifest list and push | |
| id: manifest | |
| working-directory: /tmp/digests | |
| run: | | |
| set -euo pipefail | |
| docker buildx imagetools create \ | |
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| --annotation "index:org.opencontainers.image.licenses=MIT" \ | |
| --annotation "index:org.opencontainers.image.title=Reactive Resume" \ | |
| --annotation "index:org.opencontainers.image.description=A free and open-source resume builder." \ | |
| --annotation "index:org.opencontainers.image.vendor=Amruth Pillai" \ | |
| --annotation "index:org.opencontainers.image.url=https://rxresu.me" \ | |
| --annotation "index:org.opencontainers.image.documentation=https://docs.rxresu.me" \ | |
| --annotation "index:org.opencontainers.image.source=https://github.com/amruthpillai/reactive-resume" \ | |
| --annotation "index:org.opencontainers.image.version=${{ steps.version.outputs.version }}" \ | |
| $(printf 'ghcr.io/${{ env.IMAGE }}@sha256:%s ' *) \ | |
| $(printf 'docker.io/${{ env.IMAGE }}@sha256:%s ' *) | |
| # Get the digest of the multi-arch manifest | |
| GHCR_DIGEST=$(docker buildx imagetools inspect ghcr.io/${{ env.IMAGE }}:v${{ steps.version.outputs.version }} --format '{{json .Manifest.Digest}}' | tr -d '"') | |
| DOCKER_DIGEST=$(docker buildx imagetools inspect docker.io/${{ env.IMAGE }}:v${{ steps.version.outputs.version }} --format '{{json .Manifest.Digest}}' | tr -d '"') | |
| echo "ghcr_digest=$GHCR_DIGEST" >> "$GITHUB_OUTPUT" | |
| echo "docker_digest=$DOCKER_DIGEST" >> "$GITHUB_OUTPUT" | |
| - name: Install Cosign | |
| uses: sigstore/cosign-installer@v3 | |
| - name: Sign images with Cosign | |
| run: | | |
| # Sign GHCR image | |
| cosign sign --yes ghcr.io/${{ env.IMAGE }}@${{ steps.manifest.outputs.ghcr_digest }} | |
| # Sign Docker Hub image | |
| cosign sign --yes docker.io/${{ env.IMAGE }}@${{ steps.manifest.outputs.docker_digest }} | |
| - name: Inspect image | |
| run: | | |
| docker buildx imagetools inspect ghcr.io/${{ env.IMAGE }}:v${{ steps.version.outputs.version }} | |
| docker buildx imagetools inspect docker.io/${{ env.IMAGE }}:v${{ steps.version.outputs.version }} | |
| - name: Redeploy Stack | |
| uses: appleboy/ssh-action@v1 | |
| with: | |
| key: ${{ secrets.SSH_KEY }} | |
| host: ${{ secrets.SSH_HOST }} | |
| username: ${{ secrets.SSH_USER }} | |
| script: | | |
| cd docker | |
| ./manage_stack.sh up reactive_resume |