diff --git a/.github/linters/actionlint.yaml b/.github/linters/actionlint.yaml new file mode 100644 index 0000000..df9a254 --- /dev/null +++ b/.github/linters/actionlint.yaml @@ -0,0 +1,2 @@ +config-variables: + - SLACK_CHANNEL_ID \ No newline at end of file diff --git a/.github/workflows/call-local-docker-build-promotion.yaml b/.github/workflows/call-local-docker-build-promotion.yaml deleted file mode 100644 index e817031..0000000 --- a/.github/workflows/call-local-docker-build-promotion.yaml +++ /dev/null @@ -1,61 +0,0 @@ ---- -# THIS IS NOT A TEMPLATE. -# This is just for testing the repo itself. -# This calls the reusable workflow from its local file path. -name: Docker Build with Promotion - -on: - push: - branches: - - main - paths-ignore: - - 'README.md' - - '.github/linters/**' - pull_request: - paths-ignore: - - 'README.md' - - '.github/linters/**' - -# cancel any previously-started, yet still active runs of this workflow on the same branch -concurrency: - group: ${{ github.ref }}-${{ github.workflow }} - cancel-in-progress: true - -permissions: - contents: read - packages: write - pull-requests: write - -jobs: - - # run this job on every push to a PR - # it will push images to GHCR, but not DockerHub - docker-build-pr: - name: Call Build on PR - if: github.event_name == 'pull_request' - uses: ./.github/workflows/reusable-docker-build.yaml - with: - dockerhub-enable: false - ghcr-enable: true - push: true - image-names: | - ghcr.io/${{ github.repository }} - - # run this job on every push to the default branch (including merges and tags) - # it will push images to GHCR and DockerHub - # tags will also include ones like `stable--` and `latest` - docker-build-merge: - name: Call Build on Push - # this if is filtered to only the main branch push event (see events at top) - if: github.event_name == 'push' - uses: ./.github/workflows/reusable-docker-build.yaml - secrets: - dockerhub-username: ${{ secrets.DOCKERHUB_USERNAME }} - dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }} - with: - dockerhub-enable: true - ghcr-enable: true - push: true - image-names: | - docker.io/${{ github.repository }} - ghcr.io/${{ github.repository }} diff --git a/.github/workflows/reusable-docker-build.yaml b/.github/workflows/reusable-docker-build.yaml index d9bcaa3..e373834 100644 --- a/.github/workflows/reusable-docker-build.yaml +++ b/.github/workflows/reusable-docker-build.yaml @@ -92,7 +92,6 @@ on: description: Build stage to target required: false type: string - secrets: dockerhub-username: @@ -103,10 +102,9 @@ on: required: false outputs: - ghcr-tag: - description: "single-use tag for ghcr.io" - value: ${{ jobs.build-image.outputs.ghcr-tag }} - + image-tag: + description: "single-use image tag for GHA runs" + value: ${{ jobs.build-image.outputs.image-tag }} # permissions: GITHUB_TOKEN are better set by the **calling** workflow # but we'll set defaults here for reference @@ -126,36 +124,36 @@ jobs: outputs: # only outputs the unique gha- image tag that's unique to each GHA run - ghcr-tag: ${{ steps.ghcr-tag.outputs.tag }} + image-tag: ${{ steps.image-tag.outputs.image-tag }} steps: - - + # we need qemu and buildx so we can build multiple platforms later - name: Set up QEMU + - name: Set up QEMU id: qemu uses: docker/setup-qemu-action@v2.1.0 - - + # BuildKit (used with `docker buildx`) is the best way to build images - name: Set up Docker Buildx + - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v2.5.0 - - - name: Login to DockerHub + + - name: Login to DockerHub if: inputs.dockerhub-enable uses: docker/login-action@v2.1.0 with: username: ${{ secrets.dockerhub-username }} password: ${{ secrets.dockerhub-token }} - - - name: Login to GHCR + + - name: Login to GHCR if: inputs.ghcr-enable uses: docker/login-action@v2.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - - name: Docker meta + + - name: Docker meta id: docker_meta uses: docker/metadata-action@v4.3.0 with: @@ -163,12 +161,12 @@ jobs: images: ${{ inputs.image-names }} flavor: ${{ inputs.flavor-rules }} tags: ${{ inputs.tag-rules }} - - + # this will build the images, once per platform, # then push to one or more registries (based on image list above in docker_meta) # NOTE: this will not push if a PR is from a fork, where secrets are not available # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ - name: Docker Build and Push + - name: Docker Build and Push id: build_image uses: docker/build-push-action@v4.0.0 with: @@ -189,10 +187,10 @@ jobs: # https://docs.docker.com/build/attestations/attestation-storage/ provenance: true sbom: true - - + # If PR, put image tags in the PR comments # from https://github.com/marketplace/actions/create-or-update-comment - name: Find comment for image tags + - name: Find comment for image tags uses: peter-evans/find-comment@v2.3.0 if: github.event_name == 'pull_request' && inputs.comment-enable id: fc @@ -220,8 +218,13 @@ jobs: ``` edit-mode: replace - - name: Find the gha-run-based image tag we just pushed to ghcr.io - id: ghcr-tag + # for dependent jobs, we need to output the unique tag for this GHA run + # based on the docker_meta tag priority rules, the highest priority tag + # will be sent to this output + # this step output is sent to job output, which is sent to workflow output + # use this tag in another job with needs..outputs.image-tag + - name: Find the primary image tag we just pushed, and output it + id: image-tag run: | # shellcheck disable=SC2086 - echo "tag=gha-${{ github.run_id }}" >> $GITHUB_OUTPUT + echo "image-tag=${{ steps.docker_meta.outputs.version }}" >> $GITHUB_OUTPUT diff --git a/README.md b/README.md index ffb16a3..509043b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# Template Repo: Docker Build and Push GitHub Actions Workflow +# Template: Docker Build and Push GitHub Actions Workflow [![Lint Code Base](https://github.com/BretFisher/docker-build-workflow/actions/workflows/call-super-linter.yaml/badge.svg)](https://github.com/BretFisher/docker-build-workflow/actions/workflows/call-super-linter.yaml) [![Docker Build](https://github.com/BretFisher/docker-build-workflow/actions/workflows/call-local-docker-build.yaml/badge.svg)](https://github.com/BretFisher/docker-build-workflow/actions/workflows/call-local-docker-build.yaml) A Reusable Workflow of the Docker GitHub Actions steps. Enhanced with learnings from production use. -> ⚠️ **DO NOT call this workflow directly**, rather, use it as a template repo and fork it for your own reusable workflow. I might change this workflow at anytime, based on new GHA features or learnings, and your calling workflow might break. ⚠️ +> ⚠️ **DO NOT call this workflow directly**, rather, use it as a template repository and fork it for your own reusable workflow. I might change this workflow at anytime, based on new GHA features or learnings, and your calling workflow might break. ⚠️ ## Reasons to use this workflow @@ -13,29 +13,40 @@ A Reusable Workflow of the Docker GitHub Actions steps. Enhanced with learnings 2. Provides inline docs based on real-world usage of this workflow. 3. Gives you inputs so you can reuse this workflow across many repositories and only needing the full workflow stored in a central repository. 4. New in 2023: Adds [SBOM and Provenance](https://docs.docker.com/build/attestations/) metadata to your images. -5. New in 2023: [Example template](./templates/call-docker-build-promote.yaml) to use the reusable workflow twice, in a "image promotion" style of dual registries (one for devs and PRs, one for production after PR merges) +5. New in 2023: [Example template](./templates/call-docker-build-promote.yaml) to use the reusable workflow twice, in an "image promotion" style of dual registries (one for devs and PRs, one for production after PR merges) ## Steps to adopt this workflow 1. Fork this repository and tweak the reusable workflow to your liking: [.github/workflows/reusable-docker-build.yaml](.github/workflows/reusable-docker-build.yaml) -2. Copy my "calling" workflow [`templates/call-docker-build.yaml`](templates/call-docker-build.yaml) to all the repos you want to build images in, and change it to point to the forked workflow above. +2. Copy my "calling" workflow [`templates/call-docker-build.yaml`](templates/call-docker-build.yaml) to all the repositories you want to build images in and change it to point to the forked workflow above. ## "But what does this workflow really do beyond just `docker build`?" 1. Clone the repository -2. Setup QEMU for multi-platform building (buildx) via docker/setup-qemu-action +2. Setup QEMU for multi-platform building (via buildx) via docker/setup-qemu-action 3. Setup buildx for awesome and fast building via docker/setup-buildx-action 4. Log into Docker Hub and/or GHCR 5. Add labels and tags via docker/metadata-action 6. Build and push image via docker/build-push-action with GitHub-based layer caching 7. Reports tags and labels in the PR comments -## This repository is part of my example DevOps repos on GitHub Actions +## What other ways can I use this workflow? + +I have a more advanced example of using this reusable workflow to do a "promotion" style workflow of: + +1. On PR creation, build and push to a "dev" registry (GHCR) +2. On PR merge, build and push to a "prod" registry (Docker Hub) +3. Create a GitOps YAML update PR to update image tags +4. Notify of GitOps PR creation in Slack + +I've added that example to my [github-actions-templates](https://github.com/BretFisher/github-actions-templates) repository. It calls the reusable `reusable-docker-build.yaml` file in this repository. + +## This repository is part of my example DevOps repositories on GitHub Actions - [bretfisher/github-actions-templates](https://github.com/BretFisher/github-actions-templates) - Main reusable templates repository - [bretfisher/super-linter-workflow](https://github.com/BretFisher/super-linter-workflow) - Reusable linter workflow - (you are here) [bretfisher/docker-build-workflow](https://github.com/BretFisher/docker-build-workflow)- Reusable docker build workflow -- [bretfisher/docker-ci-automation](https://github.com/BretFisher/docker-ci-automation) - Step by step video and example of a Docker CI workflow +- [bretfisher/docker-ci-automation](https://github.com/BretFisher/docker-ci-automation) - Step-by-step video and example of a Docker CI workflow - [My full list of container examples and tools](https://github.com/bretfisher) ## More reading