Repository: BretFisher/docker-ci-automation Branch: main Commit: 0608ac3f115b Files: 24 Total size: 48.8 KB Directory structure: gitextract_w2qc27yx/ ├── .dockerignore ├── .github/ │ ├── dependabot.yml │ ├── linters/ │ │ ├── .hadolint.yaml │ │ ├── .markdown-lint.yml │ │ └── .yaml-lint.yml │ └── workflows/ │ ├── 01-basic-docker-build.yaml │ ├── 02-add-buildkit-cache.yaml │ ├── 03-add-multi-platform.yaml │ ├── 04-add-metadata.yaml │ ├── 05-add-comment.yaml │ ├── 06-add-cve-scanning.yaml │ ├── 07-add-cve-scanning-adv.yaml │ ├── 08-add-unit-test.yaml │ ├── 09-add-integration-test.yaml │ ├── 10-add-k8s-test.yaml │ ├── 99-parallelize-jobs.yaml │ └── call-super-linter.yaml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── docker-compose.test.yml ├── healthchecks/ │ └── postgres-healthcheck └── manifests/ └── deployment.yaml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ .git ================================================ FILE: .github/dependabot.yml ================================================ --- # To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: # Maintain dependencies for GitHub Actions - package-ecosystem: "github-actions" directory: "/" cooldown: default-days: 7 schedule: interval: "daily" # Add this section for each directory with a Dockerfile, K8s manifest, or Helm chart # They must use a semver tag, and Dependabot must be able to access the registry # You can give it access to private ones: # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#configuration-options-for-private-registries # follow along on a feature request to support multiple directories in one package-ecosystem # https://github.com/dependabot/dependabot-core/issues/2178 - package-ecosystem: "docker" directory: "/" cooldown: default-days: 7 schedule: interval: "weekly" commit-message: # Prefix all commit messages with "[docker] " prefix: "[docker] " ================================================ FILE: .github/linters/.hadolint.yaml ================================================ --- # README: https://github.com/hadolint/hadolint # Often it's a good idea to do inline disables rather that repo-wide in this file. # Example of inline Dockerfile rules: # hadolint ignore=DL3018 #RUN apk add --no-cache git # or just ignore rules repo-wide ignored: - DL3003 #ignore that we use cd sometimes - DL3006 #image pin versions - DL3008 #apt pin versions - DL3018 #apk add pin versions - DL3022 #bad rule for COPY --from - DL3028 #gem install pin versions - DL3059 #multiple consecutive runs # FULL TEMPLATE # failure-threshold: string # name of threshold level (error | warning | info | style | ignore | none) # format: string # Output format (tty | json | checkstyle | codeclimate | gitlab_codeclimate | gnu | codacy) # ignored: [string] # list of rules # label-schema: # See Linting Labels below for specific label-schema details # author: string # Your name # contact: string # email address # created: timestamp # rfc3339 datetime # version: string # semver # documentation: string # url # git-revision: string # hash # license: string # spdx # no-color: boolean # true | false # no-fail: boolean # true | false # override: # error: [string] # list of rules # warning: [string] # list of rules # info: [string] # list of rules # style: [string] # list of rules # strict-labels: boolean # true | false # disable-ignore-pragma: boolean # true | false # trustedRegistries: string | [string] # registry or list of registries ================================================ FILE: .github/linters/.markdown-lint.yml ================================================ --- # MD013/line-length - Line length MD013: # Number of characters, default is 80 # I'm OK with long lines. All editors now have wordwrap line_length: 9999 # Number of characters for headings heading_line_length: 100 # check code blocks? code_blocks: false ================================================ FILE: .github/linters/.yaml-lint.yml ================================================ --- ########################################### # These are the rules used for # # linting all the yaml files in the stack # # NOTE: # # You can disable line with: # # # yamllint disable-line # ########################################### rules: braces: level: warning min-spaces-inside: 0 max-spaces-inside: 0 min-spaces-inside-empty: 1 max-spaces-inside-empty: 5 brackets: level: warning min-spaces-inside: 0 max-spaces-inside: 0 min-spaces-inside-empty: 1 max-spaces-inside-empty: 5 colons: level: warning max-spaces-before: 0 max-spaces-after: 1 commas: level: warning max-spaces-before: 0 min-spaces-after: 1 max-spaces-after: 1 comments: disable comments-indentation: disable document-end: disable document-start: disable empty-lines: level: warning max: 2 max-start: 0 max-end: 0 hyphens: level: warning max-spaces-after: 1 indentation: level: warning spaces: consistent indent-sequences: true check-multi-line-strings: false key-duplicates: enable line-length: disable new-line-at-end-of-file: disable new-lines: type: unix trailing-spaces: disable truthy: disable ================================================ FILE: .github/workflows/01-basic-docker-build.yaml ================================================ --- name: 01 Basic Docker Build # simplest workflow possible on: push: branches: - main pull_request: jobs: build-image: name: Build Image runs-on: ubuntu-latest steps: - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Docker build uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: ${{ github.event_name != 'pull_request' }} tags: bretfisher/docker-ci-automation:latest,bretfisher/docker-ci-automation:01 ================================================ FILE: .github/workflows/02-add-buildkit-cache.yaml ================================================ --- name: 02 Build with BuildKit Cache on: push: branches: - main pull_request: jobs: build-image: name: Build Image runs-on: ubuntu-latest steps: #NEW: (START) ########################################################## - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 #NEW: (END) ############################################################ - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Docker build uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: ${{ github.event_name != 'pull_request' }} tags: bretfisher/docker-ci-automation:02 #NEW: (START) ########################################################## cache-from: type=gha cache-to: type=gha,mode=max #NEW: (END) ############################################################ ================================================ FILE: .github/workflows/03-add-multi-platform.yaml ================================================ --- name: 03 Build with Multi-Platform on: push: branches: - main pull_request: jobs: build-image: name: Build Images runs-on: ubuntu-latest steps: #NEW: (START) ########################################################## - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 #NEW: (END) ############################################################ - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Docker build uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: ${{ github.event_name != 'pull_request' }} tags: bretfisher/docker-ci-automation:03 cache-from: type=gha cache-to: type=gha,mode=max #NEW: (START) ########################################################## platforms: linux/amd64,linux/arm64,linux/arm/v7 #NEW: (END) ############################################################ ================================================ FILE: .github/workflows/04-add-metadata.yaml ================================================ --- name: 04 Build with Metadata on: push: branches: - main pull_request: jobs: build-image: name: Build Images runs-on: ubuntu-latest steps: - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} #NEW: (START) ########################################################## - name: Docker meta id: docker_meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf #v6.0.0 with: images: bretfisher/docker-ci-automation flavor: | latest=false tags: | type=raw,value=04 type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} type=ref,event=pr type=ref,event=branch type=semver,pattern={{version}} #NEW: (END) ############################################################ - name: Docker build uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: #NEW: (START) ########################################################## push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} #NEW: (END) ############################################################ cache-from: type=gha cache-to: type=gha,mode=max # comma seperated list of what OS and architechtures to build for (in parallel) # default is linux/amd64 (the OS of the runner) but you can add more # adding linux/arm64 is recommended for Apple Silicon, Raspberry Pi, AWS Graviton, etc. # linux/arm/v7 is for 32-bit ARM devices like Raspberry Pi 2/3 platforms: linux/amd64,linux/arm64 ================================================ FILE: .github/workflows/05-add-comment.yaml ================================================ --- name: 05 Build and Comment on: push: branches: - main pull_request: jobs: build-image: name: Build Images runs-on: ubuntu-latest #NEW: (START) ########################################################## permissions: pull-requests: write # needed to create and update comments in PRs #NEW: (END) ############################################################ steps: - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Docker meta id: docker_meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf #v6.0.0 with: images: bretfisher/docker-ci-automation flavor: | latest=false tags: | type=raw,value=05 type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} type=ref,event=pr type=ref,event=branch type=semver,pattern={{version}} - name: Docker build uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: false # false for this demo to prevent overwriting image tags of other examples tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # comma seperated list of what OS and architechtures to build for (in parallel) # default is linux/amd64 (the OS of the runner) but you can add more # adding linux/arm64 is recommended for Apple Silicon, Raspberry Pi, AWS Graviton, etc. # linux/arm/v7 is for 32-bit ARM devices like Raspberry Pi 2/3 platforms: linux/amd64,linux/arm64 #NEW: (START) ########################################################## # 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 uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e #v3.1.0 if: github.event_name == 'pull_request' id: fc with: issue-number: ${{ github.event.pull_request.number }} comment-author: 'github-actions[bot]' body-includes: Docker image tag(s) pushed # If PR, put image tags in the PR comments - name: Create or update comment for image tags uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 #v4.0.0 if: github.event_name == 'pull_request' with: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} body: | Docker image tag(s) pushed: ```text ${{ steps.docker_meta.outputs.tags }} ``` Labels added to images: ```text ${{ steps.docker_meta.outputs.labels }} ``` edit-mode: replace #NEW: (END) ############################################################ ================================================ FILE: .github/workflows/06-add-cve-scanning.yaml ================================================ --- name: 06 Build and Scan on: push: branches: - main pull_request: jobs: build-image: name: Build Images runs-on: ubuntu-latest steps: - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and export to Docker uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: false load: true # Export to Docker Engine rather than pushing to a registry tags: ${{ github.run_id }} target: test cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64 #NEW: (START) ########################################################## - name: Run Trivy for all CVEs (non-blocking) uses: aquasecurity/trivy-action@264c9c5e188ea085e7377fd77abd17bfbd4e5926 #master with: image-ref: ${{ github.run_id }} exit-code: 0 format: table #NEW: (END) ############################################################ - name: Docker Metadata for Final Image Build id: docker_meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf #v6.0.0 with: images: bretfisher/docker-ci-automation flavor: | latest=false tags: | type=raw,value=06 # comment these out on all but 04-add-metadata.yaml to avoid overwriting image tags # type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} # type=ref,event=pr # type=ref,event=branch # type=semver,pattern={{version}} - name: Docker Build and Push to Docker Hub uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # comma seperated list of what OS and architechtures to build for (in parallel) # default is linux/amd64 (the OS of the runner) but you can add more # adding linux/arm64 is recommended for Apple Silicon, Raspberry Pi, AWS Graviton, etc. # linux/arm/v7 is for 32-bit ARM devices like Raspberry Pi 2/3 platforms: linux/amd64,linux/arm64 ================================================ FILE: .github/workflows/07-add-cve-scanning-adv.yaml ================================================ --- name: 07 Build and Scan + Report on: push: branches: - main pull_request: jobs: build-image: name: Build Images runs-on: ubuntu-latest #NEW: (START) ########################################################## permissions: contents: read # for actions/checkout to fetch code security-events: write # for github/codeql-action/upload-sarif to upload SARIF results #NEW: (END) ############################################################ steps: #NEW: (START) ########################################################## - name: Checkout git repo uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 #NEW: (END) ############################################################ - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and export to Docker uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: false load: true # Export to Docker Engine rather than pushing to a registry tags: ${{ github.run_id }} target: test cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64 - name: Run Trivy for all CVEs (non-blocking) uses: aquasecurity/trivy-action@264c9c5e188ea085e7377fd77abd17bfbd4e5926 #master with: image-ref: ${{ github.run_id }} format: table exit-code: 0 #NEW: (START) ########################################################## - name: Run Trivy for HIGH,CRITICAL CVEs and report (blocking) uses: aquasecurity/trivy-action@264c9c5e188ea085e7377fd77abd17bfbd4e5926 #master with: image-ref: ${{ github.run_id }} exit-code: 1 ignore-unfixed: true vuln-type: 'os,library' severity: 'HIGH,CRITICAL' format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@5c8a8a642e79153f5d047b10ec1cba1d1cc65699 #v3.35.1 if: always() with: sarif_file: 'trivy-results.sarif' #NEW: (END) ############################################################ - name: Docker Metadata for Final Image Build id: docker_meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf #v6.0.0 with: images: bretfisher/docker-ci-automation flavor: | latest=false tags: | type=raw,value=07 # comment these out on all but 04-add-metadata.yaml to avoid overwriting image tags # type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} # type=ref,event=pr # type=ref,event=branch # type=semver,pattern={{version}} - name: Docker Build and Push to Docker Hub uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # comma seperated list of what OS and architechtures to build for (in parallel) # default is linux/amd64 (the OS of the runner) but you can add more # adding linux/arm64 is recommended for Apple Silicon, Raspberry Pi, AWS Graviton, etc. # linux/arm/v7 is for 32-bit ARM devices like Raspberry Pi 2/3 platforms: linux/amd64,linux/arm64 ================================================ FILE: .github/workflows/08-add-unit-test.yaml ================================================ --- name: 08 Build and Unit Test on: push: branches: - main pull_request: jobs: build-image: name: Build Images runs-on: ubuntu-latest steps: - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} #NEW: (START) ########################################################## - name: Build and export to Docker uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: false load: true # Export to Docker Engine rather than pushing to a registry tags: ${{ github.run_id }} target: test cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64 # for simple tests (npm test, etc.) just run a local image in docker - name: Unit Testing in Docker run: | docker run --rm ${{ github.run_id }} echo "run test commands here" #NEW: (END) ############################################################ - name: Docker Metadata for Final Image Build id: docker_meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf #v6.0.0 with: images: bretfisher/docker-ci-automation flavor: | latest=false tags: | type=raw,value=08 # comment these out on all but 04-add-metadata.yaml to avoid overwriting image tags # type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} # type=ref,event=pr # type=ref,event=branch # type=semver,pattern={{version}} - name: Docker Build and Push to Docker Hub uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # comma seperated list of what OS and architechtures to build for (in parallel) # default is linux/amd64 (the OS of the runner) but you can add more # adding linux/arm64 is recommended for Apple Silicon, Raspberry Pi, AWS Graviton, etc. # linux/arm/v7 is for 32-bit ARM devices like Raspberry Pi 2/3 platforms: linux/amd64,linux/arm64 ================================================ FILE: .github/workflows/09-add-integration-test.yaml ================================================ --- name: 09 Build and Integration Test on: push: branches: - main pull_request: jobs: build-image: name: Build Images runs-on: ubuntu-latest steps: - name: Checkout git repo uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and export to Docker uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: false load: true # Export to Docker Engine rather than pushing to a registry tags: ${{ github.run_id }} target: test cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64 #NEW: (START) ############################################################ # for more advanced tests, use docker compose with `depends_on` # NOTE: GHA and other CIs can also run dependency containers on their own # GHA `services:` can do this if you're trying to avoid docker compose - name: Test healthcheck in Docker Compose run: | export TESTING_IMAGE="${{ github.run_id }}" docker compose -f docker-compose.test.yml up --exit-code-from sut #NEW: (END) ############################################################ - name: Docker Metadata for Final Image Build id: docker_meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf #v6.0.0 with: images: bretfisher/docker-ci-automation flavor: | latest=false tags: | type=raw,value=09 # comment these out on all but 04-add-metadata.yaml to avoid overwriting image tags # type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} # type=ref,event=pr # type=ref,event=branch # type=semver,pattern={{version}} - name: Docker Build and Push to Docker Hub uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # comma seperated list of what OS and architechtures to build for (in parallel) # default is linux/amd64 (the OS of the runner) but you can add more # adding linux/arm64 is recommended for Apple Silicon, Raspberry Pi, AWS Graviton, etc. # linux/arm/v7 is for 32-bit ARM devices like Raspberry Pi 2/3 platforms: linux/amd64,linux/arm64 ================================================ FILE: .github/workflows/10-add-k8s-test.yaml ================================================ --- name: 10 Build and Smoke Test on: push: branches: - main pull_request: jobs: build-image: name: Build Images runs-on: ubuntu-latest permissions: packages: write # needed to push docker image to ghcr.io steps: - name: Checkout git repo uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} #NEW: (START) ############################################################ - name: Login to ghcr.io registry uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and Push to GHCR uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: true tags: ghcr.io/bretfisher/docker-ci-automation:${{ github.run_id }} target: test cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64 - uses: AbsaOSS/k3d-action@4e8b3239042be1dc0aed6c5eb80c13b18200fc79 #v2.4.0 with: cluster-name: "test-cluster-1" args: >- --agents 1 --no-lb --k3s-arg "--no-deploy=traefik,servicelb,metrics-server@server:*" - name: Smoke test deployment in k3d Kubernetes run: | kubectl create secret docker-registry regcred \ --docker-server=https://ghcr.io \ --docker-username=${{ github.actor }} \ --docker-password=${{ secrets.GITHUB_TOKEN }} export TESTING_IMAGE=ghcr.io/bretfisher/docker-ci-automation:"$GITHUB_RUN_ID" envsubst < manifests/deployment.yaml | kubectl apply -f - kubectl rollout status deployment myapp kubectl exec deploy/myapp -- curl --fail localhost #NEW: (END) ############################################################ - name: Docker Metadata for Final Image Build id: docker_meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf #v6.0.0 with: images: bretfisher/docker-ci-automation,ghcr.io/bretfisher/docker-ci-automation flavor: | latest=false tags: | type=raw,value=10 # comment these out on all but 04-add-metadata.yaml to avoid overwriting image tags # type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} # type=ref,event=pr # type=ref,event=branch # type=semver,pattern={{version}} - name: Docker Build and Push to Docker Hub uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # comma seperated list of what OS and architechtures to build for (in parallel) # default is linux/amd64 (the OS of the runner) but you can add more # adding linux/arm64 is recommended for Apple Silicon, Raspberry Pi, AWS Graviton, etc. # linux/arm/v7 is for 32-bit ARM devices like Raspberry Pi 2/3 platforms: linux/amd64,linux/arm64 ================================================ FILE: .github/workflows/99-parallelize-jobs.yaml ================================================ --- name: 99 Parallelize Jobs on: push: branches: - main pull_request: jobs: # FIRST JOB ####################################################################### build-test-image: name: Build Image for Testing runs-on: ubuntu-latest permissions: packages: write # needed to push docker image to ghcr.io steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to ghcr.io registry uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and Push to GHCR uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: true tags: ghcr.io/bretfisher/docker-ci-automation:${{ github.run_id }} target: test cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64 # NEXT JOB ####################################################################### test-unit: name: Unit tests in Docker needs: [build-test-image] runs-on: ubuntu-latest permissions: packages: read steps: - name: Login to ghcr.io registry uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Unit Testing in Docker run: docker run --rm ghcr.io/bretfisher/docker-ci-automation:"$GITHUB_RUN_ID" echo "run test commands here" # NEXT JOB ####################################################################### test-integration: name: Integration tests in Compose needs: [build-test-image] runs-on: ubuntu-latest permissions: packages: read steps: - name: Checkout git repo uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to ghcr.io registry uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Test healthcheck in Docker Compose run: | export TESTING_IMAGE=ghcr.io/bretfisher/docker-ci-automation:"$GITHUB_RUN_ID" echo Testing image: "$TESTING_IMAGE" docker compose -f docker-compose.test.yml up --exit-code-from sut # NEXT JOB ####################################################################### test-k3d: name: Test Deployment in Kubernetes needs: [build-test-image] runs-on: ubuntu-latest permissions: packages: read steps: - name: Checkout git repo uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to ghcr.io registry uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - uses: AbsaOSS/k3d-action@4e8b3239042be1dc0aed6c5eb80c13b18200fc79 #v2.4.0 with: cluster-name: "test-cluster-1" args: >- --agents 1 --no-lb --k3s-arg "--no-deploy=traefik,servicelb,metrics-server@server:*" - name: Smoke test deployment in k3d Kubernetes run: | kubectl create secret docker-registry regcred \ --docker-server=https://ghcr.io \ --docker-username=${{ github.actor }} \ --docker-password=${{ secrets.GITHUB_TOKEN }} export TESTING_IMAGE=ghcr.io/bretfisher/docker-ci-automation:"$GITHUB_RUN_ID" envsubst < manifests/deployment.yaml | kubectl apply -f - kubectl rollout status deployment myapp kubectl exec deploy/myapp -- curl --fail localhost # NEXT JOB ####################################################################### scan-image: name: Scan Image with Trivy needs: [build-test-image] runs-on: ubuntu-latest permissions: contents: read # for actions/checkout to fetch code packages: read # needed to pull docker image to ghcr.io security-events: write # for github/codeql-action/upload-sarif to upload SARIF results steps: - name: Checkout git repo uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to ghcr.io registry uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Pull image to scan run: docker pull ghcr.io/bretfisher/docker-ci-automation:"$GITHUB_RUN_ID" - name: Run Trivy for all CVEs (non-blocking) uses: aquasecurity/trivy-action@264c9c5e188ea085e7377fd77abd17bfbd4e5926 #master with: image-ref: ghcr.io/bretfisher/docker-ci-automation:${{ github.run_id }} format: table exit-code: 0 # NOTE: disabled to avoid running twice and overwriting 07-add-cve-scanning-adv.yaml # - name: Run Trivy for HIGH,CRITICAL CVEs and report (blocking) # uses: aquasecurity/trivy-action@master # with: # image-ref: ghcr.io/bretfisher/docker-ci-automation:${{ github.run_id }} # exit-code: 1 # ignore-unfixed: true # vuln-type: 'os,library' # severity: 'HIGH,CRITICAL' # format: 'sarif' # output: 'trivy-results.sarif' # - name: Upload Trivy scan results to GitHub Security tab # uses: github/codeql-action/upload-sarif@v1 # if: always() # with: # sarif_file: 'trivy-results.sarif' # NEXT JOB ####################################################################### build-final-image: name: Build Final Image needs: [test-unit, test-integration, test-k3d, scan-image] runs-on: ubuntu-latest permissions: packages: write # needed to push docker image to ghcr.io pull-requests: write # needed to create and update comments in PRs steps: - name: Set up QEMU uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a #v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0 - name: Login to Docker Hub uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to ghcr.io registry uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Docker Metadata for Final Image Build id: docker_meta uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf #v6.0.0 with: images: bretfisher/docker-ci-automation,ghcr.io/bretfisher/docker-ci-automation flavor: | latest=false tags: | type=raw,value=99 # comment these out on all but 04-add-metadata.yaml to avoid overwriting image tags # type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} # type=ref,event=pr # type=ref,event=branch # type=semver,pattern={{version}} - name: Docker Build and Push to GHCR and Docker Hub uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f #v7.1.0 with: push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # comma seperated list of what OS and architechtures to build for (in parallel) # default is linux/amd64 (the OS of the runner) but you can add more # adding linux/arm64 is recommended for Apple Silicon, Raspberry Pi, AWS Graviton, etc. # linux/arm/v7 is for 32-bit ARM devices like Raspberry Pi 2/3 platforms: linux/amd64,linux/arm64 # If PR, put image tags in the PR comments # from https://github.com/marketplace/actions/create-or-update-comment # These are commented out to avoid conflicting with 05-add-comments.yaml example # - name: Find comment for image tags # uses: peter-evans/find-comment@v1 # if: github.event_name == 'pull_request' # id: fc # with: # issue-number: ${{ github.event.pull_request.number }} # comment-author: 'github-actions[bot]' # body-includes: Docker image tag(s) pushed # # If PR, put image tags in the PR comments # - name: Create or update comment for image tags # uses: peter-evans/create-or-update-comment@v1 # if: github.event_name == 'pull_request' # with: # comment-id: ${{ steps.fc.outputs.comment-id }} # issue-number: ${{ github.event.pull_request.number }} # body: | # Docker image tag(s) pushed: # ```text # ${{ steps.docker_meta.outputs.tags }} # ``` # Labels added to images: # ```text # ${{ steps.docker_meta.outputs.labels }} # ``` # edit-mode: replace ================================================ FILE: .github/workflows/call-super-linter.yaml ================================================ --- # template source: https://github.com/bretfisher/super-linter-workflow/blob/main/templates/call-super-linter.yaml name: Lint Code Base on: # run anytime a PR is merged to main or a direct push to main push: branches: [main] # run on any push to a PR branch pull_request: # 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 # reset permissions to none at the workflow level # we'll set them at the job level below permissions: {} jobs: call-super-linter: name: Call Super-Linter permissions: contents: read # clone the repository to lint pull-requests: write # create a summary comment in PR statuses: write # read/write to repository custom statuses ### use Reusable Workflows to call my workflow remotely ### https://docs.github.com/en/actions/learn-github-actions/reusing-workflows ### you can also call workflows from inside the same repository via file path # FIXME: customize uri to point to your own reusable linter repository # NOTE: zizmor scanner rule ignore added because we control sha pins via reusable workflow, not calling workflow uses: bretfisher/super-linter-workflow/.github/workflows/reusable-super-linter.yaml@main # zizmor: ignore[unpinned-uses] ### Optional settings examples # with: ### 1. Remember .github/super-linter.env is injected for setting linter on/off ### 2. For a DevOps-focused repository. Prevents some code-language linters from running ### defaults to false # devops-only: false ### 3. A regex to exclude files from linting ### defaults to empty # filter-regex-exclude: html/.* # ### 4. Additional environment variables to pass to super-linter (one per line) # extra-envs: | # VALIDATE_DOCKERFILE=false # VALIDATE_JSCPD=false # VALIDATE_TRIVY=false ================================================ FILE: .gitignore ================================================ TODO-*.yaml ================================================ FILE: Dockerfile ================================================ # sample dockerfile for testing docker builds FROM nginx:1.20-alpine as base RUN apk add --no-cache curl WORKDIR /test COPY . . ######################### FROM base as test #layer test tools and assets on top as optional test stage RUN apk add --no-cache apache2-utils ######################### FROM base as final # this layer gets built by default unless you set target to test ================================================ FILE: LICENSE ================================================ This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to ================================================ FILE: README.md ================================================ # Automation with Docker for CI Workflows [![Lint Code Base](https://github.com/bretfisher/docker-ci-automation/actions/workflows/call-super-linter.yaml/badge.svg)](https://github.com/bretfisher/docker-ci-automation/actions/workflows/call-super-linter.yaml) > For Docker Community All Hands 2022 [![All-Hands Automation with Docker](https://user-images.githubusercontent.com/792287/160971371-0ae75c14-1ea4-4a11-82dc-f35f96184fa3.gif)](https://www.youtube.com/watch?v=aZzV6X7XhyI) Watch the walkthrough of this repo: [https://www.youtube.com/watch?v=aZzV6X7XhyI](https://www.youtube.com/watch?v=aZzV6X7XhyI) See this repositories' [`.github/workflows`](.github/workflows) directory for the below example workflows, ordered by number, simple to complex. These examples are focused on five of Docker's [official GitHub Actions](https://github.com/marketplace?type=actions&query=publisher%3Adocker+). These examples are based on three workflow diagrams on progressively more complex automation pipelines: 1. [Basic code PR automation workflow](diagrams/basic-code-pr.png) 2. [Intermediate code PR automation workflow](diagrams/intermediate-code-pr.png) 3. [Advanced code PR automation workflow](diagrams/advanced-code-pr.png) I also have a [LIVE course on learning GitHub Actions for DevOps automation and Argo CD](https://bret.courses/autodeploy) for GitOps-style deployments. ## Example Workflows 1. Basic Docker build 2. Adding BuildKit cache 3. Adding multi-platform builds 4. Adding metadata to images 5. Adding comments with image tags to PRs 6. Adding CVE scanning 7. Adding CVE security reporting 8. Adding unit testing 9. Adding integration testing 10. Adding Kubernetes smoke tests 11. Adding job parallelizing for mucho speed ## GitHub Actions shown in these examples - [Docker Login](https://github.com/marketplace/actions/docker-login) - [Docker Setup Buildx](https://github.com/marketplace/actions/docker-setup-buildx) - [Docker Setup QEMU](https://github.com/marketplace/actions/docker-setup-qemu) - [Docker Metadata](https://github.com/marketplace/actions/docker-metadata-action) - [Docker Build and Push](https://github.com/marketplace/actions/build-and-push-docker-images) - [Aqua Security Trivy CVE Scan](https://github.com/marketplace/actions/aqua-security-trivy) - [Super-Linter](https://github.com/marketplace/actions/super-linter) - [Setup k3d](https://github.com/marketplace/actions/absaoss-k3d-action) - [Find Comment](https://github.com/marketplace/actions/find-comment) - [Create or Update Comment](https://github.com/marketplace/actions/create-or-update-comment) ## This repository is part of my example DevOps repos 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 - [bretfisher/docker-build-workflow](https://github.com/BretFisher/docker-build-workflow)- Reusable docker build workflow - (you are here) [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 [Docker Build/Push Action advanced examples](https://github.com/docker/build-push-action/tree/master/docs/advanced) [My full list of container examples and tools](https://github.com/bretfisher) ## 🎉🎉🎉 Join my container DevOps community 🎉🎉🎉 - [My "Vital DevOps" Discord server](https://devops.fan) - [My weekly YouTube Live show](https://bret.live) - [My courses and coupons](https://www.bretfisher.com/courses) ================================================ FILE: docker-compose.test.yml ================================================ services: allhands22: image: "${TESTING_IMAGE}" postgres: image: postgres environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres volumes: - ./healthchecks:/healthchecks healthcheck: test: /healthchecks/postgres-healthcheck interval: "5s" sut: image: "${TESTING_IMAGE}" depends_on: allhands22: condition: service_started postgres: condition: service_healthy # run all your tests here against the allhands22 service command: curl --fail http://allhands22:80 || exit 1 ================================================ FILE: healthchecks/postgres-healthcheck ================================================ #!/bin/bash set -eo pipefail host="$(hostname -i || echo '127.0.0.1')" user="${POSTGRES_USER:-postgres}" db="${POSTGRES_DB:-$POSTGRES_USER}" export PGPASSWORD="${POSTGRES_PASSWORD:-}" args=( # force postgres to not use the local unix socket (test "external" connectibility) --host "$host" --username "$user" --dbname "$db" --quiet --no-align --tuples-only ) if select="$(echo 'SELECT 1' | psql "${args[@]}")" && [ "$select" = '1' ]; then exit 0 fi exit 1 ================================================ FILE: manifests/deployment.yaml ================================================ # kubernetes deployment --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp labels: app: myapp spec: replicas: 1 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: imagePullSecrets: - name: regcred containers: - name: myapp image: "${TESTING_IMAGE}" imagePullPolicy: IfNotPresent