From 04818af0de1e371d4cc6508548ad407474e75ea8 Mon Sep 17 00:00:00 2001 From: Paul Bruno <15909838+thetoolsmith@users.noreply.github.com> Date: Fri, 27 Dec 2024 14:05:22 -0500 Subject: [PATCH] build and publish core images (#34) * uncomment for PR test * create workflows dir * add scheduled run every sunday 5am * add unique image tagging, update contributing doc * keep publishing the latest image tags in addition to the build specific one. Switch unique tagging to use native github github.run_attempt property * add push to verify access to ghcr and see default visability * cannot set pub/priv at the tag level * add delete step to remove test package * add delete step to remove test package * env var syntax debug * env var syntax debug * env var syntax debug * add notes about deleting the test package * change latest to semantic versioning to make immutable * notes about immutable packages * typo * remove redundant build, change tagging strategy, notes * fix markdown --- .github/build_and_publish_images.yml | 47 --------------- .github/build_images.yml | 47 --------------- .../workflows/build_and_publish_images.yml | 60 +++++++++++++++++++ .github/workflows/build_images.yml | 57 ++++++++++++++++++ images/contributing.md | 52 +++++++++++++++- 5 files changed, 167 insertions(+), 96 deletions(-) delete mode 100644 .github/build_and_publish_images.yml delete mode 100644 .github/build_images.yml create mode 100644 .github/workflows/build_and_publish_images.yml create mode 100644 .github/workflows/build_images.yml diff --git a/.github/build_and_publish_images.yml b/.github/build_and_publish_images.yml deleted file mode 100644 index b8ef613..0000000 --- a/.github/build_and_publish_images.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Build and Publish Base Images - -on: - push: - branches: - - main -#jobs: -# build-publish-image: -# runs-on: ubuntu-latest -# defaults: -# run: -# working-directory: './images' -# steps: -# - name: 'Checkout GitHub Action' -# uses: actions/checkout@main -# -# - name: 'Login to GitHub Container Registry' -# uses: docker/login-action@v1 -# with: -# registry: ghcr.io -# username: ${{github.actor}} -# password: ${{secrets.GITHUB_TOKEN}} - -# - name: 'Build and Publish alpine image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/alpine:3.18 -f Dockerfile-alpine . -# docker push ghcr.io/cfpb/regtech/sbl/alpine:3.18 - -# - name: 'Build and Publish python-alpine image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/python-alpine:3.12 -f Dockerfile-python-alpine . -# docker push ghcr.io/cfpb/regtech/sbl/python-alpine:3.12 - -# - name: 'Build and Publish nginx-alpine image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/nginx-alpine:1.27 -f Dockerfile-nginx-alpine . -# docker push ghcr.io/cfpb/regtech/sbl/nginx-alpine:1.27 - -# - name: 'Build and Publish node-js-alpine image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/node-js-alpine:3.20 -f Dockerfile-node-js-alpine . -# docker push ghcr.io/cfpb/regtech/sbl/node-js-alpine:3.20 - -# - name: 'Build and Publish python-ubi8 image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/python-ubi8:3.12 -f Dockerfile-python-ubi8 . -# docker push ghcr.io/cfpb/regtech/sbl/python-ubi8:3.12 diff --git a/.github/build_images.yml b/.github/build_images.yml deleted file mode 100644 index b1fcab0..0000000 --- a/.github/build_images.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Build Base Images - -on: - push: - branches: - - main - -# pull_request: -# branches: [main] -# workflow_dispatch: - -#jobs: -# build-images: -# runs-on: ubuntu-latest -# defaults: -# run: -# working-directory: './images' -# steps: -# - name: 'Checkout GitHub Action' -# uses: actions/checkout@main -# -# - name: 'Login to GitHub Container Registry' -# uses: docker/login-action@v1 -# with: -# registry: ghcr.io -# username: ${{github.actor}} -# password: ${{secrets.GITHUB_TOKEN}} -# -# - name: 'Build alpine image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/alpine:3.18 -f Dockerfile-alpine . - -# - name: 'Build python-alpine image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/python-alpine:3.12 -f Dockerfile-python-alpine . - -# - name: 'Build nginx-alpine image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/nginx-alpine:1.27 -f Dockerfile-nginx-alpine. - -# - name: 'Build node-js-alpine image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/node-js-alpine:3.20 -f Dockerfile-node-js-alpine . - -# - name: 'Build python-ubi8 image' -# run: | -# docker build -t ghcr.io/cfpb/regtech/sbl/python-ubi8:3.12 -f Dockerfile-python-ubi8 . diff --git a/.github/workflows/build_and_publish_images.yml b/.github/workflows/build_and_publish_images.yml new file mode 100644 index 0000000..45079dc --- /dev/null +++ b/.github/workflows/build_and_publish_images.yml @@ -0,0 +1,60 @@ +name: Build and Publish Base Images + +on: + push: + branches: + - main + schedule: + - cron: "0 5 * * Sun" + +jobs: + build-publish-image: + runs-on: ubuntu-latest + defaults: + run: + working-directory: './images' + steps: + - name: 'Checkout GitHub Action' + uses: actions/checkout@v4 + + - name: 'Login to GitHub Container Registry' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{github.actor}} + password: ${{secrets.GITHUB_TOKEN}} + + - name: 'Build and Publish alpine image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/alpine:v3.18.0 -f Dockerfile-alpine . + docker tag ghcr.io/cfpb/regtech/sbl/alpine:v3.18.0 ghcr.io/cfpb/regtech/sbl/alpine:v3.18.0_${{github.run_attempt}} + docker tag ghcr.io/cfpb/regtech/sbl/alpine:v3.18.0 ghcr.io/cfpb/regtech/sbl/alpine:latest + docker push ghcr.io/cfpb/regtech/sbl/alpine --all-tags + + - name: 'Build and Publish python-alpine image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/python-alpine:v3.12.0 -f Dockerfile-python-alpine . + docker tag ghcr.io/cfpb/regtech/sbl/python-alpine:v3.12.0 ghcr.io/cfpb/regtech/sbl/python-alpine:v3.12.0_${{github.run_attempt}} + docker tag ghcr.io/cfpb/regtech/sbl/python-alpine:v3.12.0 ghcr.io/cfpb/regtech/sbl/python-alpine:latest + docker push ghcr.io/cfpb/regtech/sbl/python-alpine --all-tags + + - name: 'Build and Publish nginx-alpine image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/nginx-alpine:v1.27.0 -f Dockerfile-nginx-alpine . + docker tag ghcr.io/cfpb/regtech/sbl/nginx-alpine:v1.27.0 ghcr.io/cfpb/regtech/sbl/nginx-alpine:v1.27.0_${{github.run_attempt}} + docker tag ghcr.io/cfpb/regtech/sbl/nginx-alpine:v1.27.0 ghcr.io/cfpb/regtech/sbl/nginx-alpine:latest + docker push ghcr.io/cfpb/regtech/sbl/nginx-alpine --all-tags + + - name: 'Build and Publish node-js-alpine image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/node-js-alpine:v3.20.0 -f Dockerfile-node-js-alpine . + docker tag ghcr.io/cfpb/regtech/sbl/node-js-alpine:v3.20.0 ghcr.io/cfpb/regtech/sbl/node-js-alpine:v3.20.0_${{github.run_attempt}} + docker tag ghcr.io/cfpb/regtech/sbl/node-js-alpine:v3.20.0 ghcr.io/cfpb/regtech/sbl/node-js-alpine:latest + docker push ghcr.io/cfpb/regtech/sbl/node-js-alpine --all-tags + + - name: 'Build and Publish python-ubi8 image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/python-ubi8:v3.12.0 -f Dockerfile-python-ubi8 . + docker tag ghcr.io/cfpb/regtech/sbl/python-ubi8:v3.12.0 ghcr.io/cfpb/regtech/sbl/python-ubi8:v3.12.0_${{github.run_attempt}} + docker tag ghcr.io/cfpb/regtech/sbl/python-ubi8:v3.12.0 ghcr.io/cfpb/regtech/sbl/python-ubi8:latest + docker push ghcr.io/cfpb/regtech/sbl/python-ubi8 --all-tags diff --git a/.github/workflows/build_images.yml b/.github/workflows/build_images.yml new file mode 100644 index 0000000..75da106 --- /dev/null +++ b/.github/workflows/build_images.yml @@ -0,0 +1,57 @@ +name: Build Base Images + +on: + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + build-images: + runs-on: ubuntu-latest + defaults: + run: + working-directory: './images' + steps: + - name: 'Checkout GitHub Action' + uses: actions/checkout@v4 + + - name: 'Login to GitHub Container Registry' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{github.actor}} + password: ${{secrets.GITHUB_TOKEN}} + + - name: 'Build test image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/test:do_not_use -f Dockerfile-alpine . + docker push ghcr.io/cfpb/regtech/sbl/test:do_not_use + + - name: 'Build alpine image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/alpine:3.18_${{github.run_attempt}} -f Dockerfile-alpine . + + - name: 'Build python-alpine image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/python-alpine:3.12_${{github.run_attempt}} -f Dockerfile-python-alpine . + + - name: 'Build nginx-alpine image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/nginx-alpine:1.27_${{github.run_attempt}} -f Dockerfile-nginx-alpine . + + - name: 'Build node-js-alpine image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/node-js-alpine:3.20_${{github.run_attempt}} -f Dockerfile-node-js-alpine . + + - name: 'Build python-ubi8 image' + run: | + docker build -t ghcr.io/cfpb/regtech/sbl/python-ubi8:3.12_${{github.run_attempt}} -f Dockerfile-python-ubi8 . + +# Github api reference only. +# We would need to use a dedicted user PAT since auto-generated GITHUB_TOKEN is not org admin which is required for delete + +# - name: 'Delete test package' +# run: | +# curl -L -X DELETE -H "Accept: application/vnd.github+json" -H "Authorization: $GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/orgs/cfpb/packages/container/regtech%2Fsbl%2Ftest +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/images/contributing.md b/images/contributing.md index bd5ab4c..1a2caa9 100644 --- a/images/contributing.md +++ b/images/contributing.md @@ -2,7 +2,55 @@ Reference [Github's documentation](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) as needed. -## Authenticating with GHCR + +## Pipeline Build and Publish Core Images +We now have a GHA pipeline to build and publish these base images to the GHCR. + +#### On Pull Requests +[build_images](../.github/workflows/build_images.yml) - runs on Pull Requests to test the image build only. + +#### On Merge to Main +[build_and_publish_images](../.github/workflows/build_and_publish_images.yml) - runs on Merge to Main. This workflow will build and publish the images to Github Container Registry (GHCR). + +> **NOTE** The `build_and_publish_images` workflow is also scheduled to run weekly every Sunday at 5 AM to help keep the base images up-to-date with the latest security patches and such. + +#### Core Image tagging +We now add a unique tag to each published set of images that are included in the `build_and_publish_images` workflow. +Tagging is using github builtin property `github.run_attempt` and appended to the image tag. + +Example image with new tag format: `ghcr.io/cfpb/regtech/sbl/python-alpine:3.12_xx` + +This will allow applications to pin to specific builds in the event a new change is introduced to latest that doesn't play nice with the application. +The standard build image tag is still available to support apps pinning to the latest. + +### Test package +We build and push a duplicate alpine test package during the `build_image` workflow that runs on PR. This is to assure proper permission are available before we merge code changes to main and build and publish all the images. + +That package is named `regtech/sbl/test:do_not_use`. It is set to private and thus not available to public. +It is not immutable, so each workflow run with build and push the same tag. This is for GHA to GHCR access testing only. + +> ***Note*** `GITHIB_TOKEN` is autogenerated by GHA during each workflow execution and use to access the container registry. Due to limitations on this token, the workflow is not able to delete the test package. [Reference](https://docs.github.com/en/rest/packages/packages?apiVersion=2022-11-28#delete-a-package-for-an-organization). Even with GHA having admin to the package, since packages live at the ORG level, Github requires ORG level admin permissions to delete a package. Since `GITHUB_TOKEN` is generated and use for workflow run only, it's not possible (or desirable) to grant this access at the ORG level. +> If it's important to delete this test package, we would need to create a dedicated user PAT, grant Org Admin level and use it in the workflow step to delete the package. + +### Immutable Packages +[Publish immutable action reference](https://github.com/actions/publish-immutable-action/pkgs/container/publish-immutable-action) +[Immutable Actions reference](https://github.com/features/preview/immutable-actions) + +> ***Note*** This ↑ is `Public Preview` as of `12/26/24` + +### Image Tagging +We now publish 3 tagged versions of each core image during in the GHA workflow for all main branch merges. +They are as follows + +- *image_name*:vMAJ.MIN.PATCH +- *image_name*:vMAJ.MIN.PATCH_*unique_build* +- *image_name*:latest + +--- + +## Local Machine build and push core images (old depracated method) + +#### Authenticating with GHCR Generate a classic PAT token with the `read:packages`, `write:packages`, and `delete:packages` permissions. @@ -13,7 +61,7 @@ $ echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin > Login Succeeded ``` -## Build and push to GCR +#### Build and push to GCR ```bash $ docker build -t ghcr.io/cfpb/regtech/sbl/alpine:3.18 -f Dockerfile-alpine .