From f844ca85d688e6f381ff5c74c85b65a29ee600ba Mon Sep 17 00:00:00 2001 From: "George G. Vega Yon" Date: Thu, 26 Dec 2024 11:44:00 -0700 Subject: [PATCH] Adding container args as well as improving docs (#9) * Adding container args as well as improving docs * The version cannot be used as an input * Picking a different (easier) package and not pulling image * Using a different version of slurmR for the test * Adding tag as an output * Got the names wrong for the tags * Should put the built info in the second buidl * Removing the container image for test * Renaming SHA to GH_SHA in build context * Wrong names * Re-correcting tag names * Needed to add double quotes to the image * Trying alternative approach * Adding checkout to the second job * Checking if renaming the image works * Trying with other type of labe * Adding makefile and fixing example --- .../test-twostep-container-build.yml | 38 ++++++++++++++++++- twostep-container-build/README.md | 25 +++++++++--- twostep-container-build/action.yml | 27 +++++++++++++ .../examples/Containerfile | 10 +++-- .../examples/Containerfile.dependencies | 5 +-- twostep-container-build/examples/Makefile | 29 ++++++++++++++ 6 files changed, 121 insertions(+), 13 deletions(-) create mode 100644 twostep-container-build/examples/Makefile diff --git a/.github/workflows/test-twostep-container-build.yml b/.github/workflows/test-twostep-container-build.yml index d3839f4..f426ce3 100644 --- a/.github/workflows/test-twostep-container-build.yml +++ b/.github/workflows/test-twostep-container-build.yml @@ -14,7 +14,7 @@ on: workflow_dispatch: jobs: - test: + test-no-args: runs-on: ubuntu-latest permissions: @@ -28,6 +28,7 @@ jobs: - name: Two-step build uses: ./twostep-container-build + id: twostep-1 with: registry: ghcr.io/ username: ${{ github.actor }} @@ -36,3 +37,38 @@ jobs: container-file-2: twostep-container-build/examples/Containerfile first-step-cache-key: ${{ hashFiles('twostep-container-build/examples/Containerfile.dependencies') }} image: cdcgov/cfa-actions + + test-with-args: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + name: Checkout code + + # Testing passing arguments + - name: Two-step build with args + id: twostep-2 + uses: ./twostep-container-build + with: + registry: ghcr.io/ + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + container-file-1: twostep-container-build/examples/Containerfile.dependencies + container-file-2: twostep-container-build/examples/Containerfile + first-step-cache-key: ${{ hashFiles('twostep-container-build/examples/Containerfile.dependencies') }} + image: cdcgov/cfa-actions-with-args + build-args-2: | + GH_SHA=${{ github.sha }} + push-image-1: false + push-image-2: false + + - name: Listing the labels from the image + run: | + docker inspect ghcr.io/cdcgov/cfa-actions-with-args:${{ steps.twostep-2.outputs.tag }} \ + --format='{{json .Config.Labels}}' | jq . + diff --git a/twostep-container-build/README.md b/twostep-container-build/README.md index de343de..d7cb10c 100644 --- a/twostep-container-build/README.md +++ b/twostep-container-build/README.md @@ -9,9 +9,9 @@ flowchart LR Containerfile2-->|Generates|Image2 ``` -Caching is done using the [actions/cache](https://github.com/actions/cache/tree/v4) (lookup only) and [docker/build-push-action](https://github.com/docker/build-push-action) actions. Users have to explicitly provide the cache key for the first step. For example, if you are dealing with an R package, you can cache the dependencies by passing the key `${{ hashFiles('DESCRIPTION') }}` to the `first-step-cache-key` input. That way, the first step will only be executed if the dependencies change. +Caching is done using the [actions/cache](https://github.com/actions/cache/tree/v4) (lookup only) and [docker/build-push-action@v6](https://github.com/docker/build-push-action/tree/v6) actions. Users have to explicitly provide the cache key for the first step. For example, if you are dealing with an R package, you can cache the dependencies by passing the key `${{ hashFiles('DESCRIPTION') }}` to the `first-step-cache-key` input. That way, the first step will only be executed if the dependencies change. -## Inputs +## Inputs and Outputs | Field | Description | Required | Default | |-------|-------------|----------|---------| @@ -24,8 +24,23 @@ Caching is done using the [actions/cache](https://github.com/actions/cache/tree/ | `registry` | Registry to push the image to | true | | | `main-branch-name` | Name of the main branch | false | `'main'` | | `main-branch-tag` | Tag to use for the main branch | false | `'latest'` | + +The following are arguments passed to the [docker/build-push-action@v6](https://github.com/docker/build-push-action/tree/v6) action. + +| Field | Description | Required | Default | +|-------|-------------|----------|---------| | `push-image-1` | Push the image created during the first step | false | `false` | | `push-image-2` | Push the image created during the second step | false | `false` | +| `build-args-1` | Build arguments for the first step | false | | +| `build-args-2` | Build arguments for the second step | false | | + +The action has the following outputs: + +| Field | Description | +|-------|-------------| +| `tag` | Container tag of the built image | +| `branch` | Branch name | + ## Example: Using ghcr.io @@ -56,7 +71,7 @@ jobs: name: Checkout code - name: Two-step build - uses: ./twostep-container-build@v1.0.1 + uses: CDCgov/cfa-actions/twostep-container-build@v1.0.1 with: # Login information registry: ghcr.io/ @@ -91,7 +106,7 @@ CMD ["bash"] [`Containerfile`](examples/Containerfile) ```Containerfile -ARG TAG=latest +ARG TAG=dependencies-latest FROM ghcr.io/cdcgov/cfa-actions:${TAG} @@ -100,4 +115,4 @@ COPY twostep-container-build/example/Containerfile /app/. CMD ["bash"] ``` -Notice the `TAG` argument which is passed to the second container file. During runs of the action, `TAG` takes the value of the branch name or `latest` if the branch is the main branch. \ No newline at end of file +Notice the `TAG` argument which is passed to the second container file. During runs of the action, `TAG` takes the value of the `dependencies-[branch name]` or `dependencies-latest` if the branch is the main branch. \ No newline at end of file diff --git a/twostep-container-build/action.yml b/twostep-container-build/action.yml index 70a1915..ffdd97c 100644 --- a/twostep-container-build/action.yml +++ b/twostep-container-build/action.yml @@ -1,5 +1,11 @@ name: twostep-container-build description: | + This action builds a container image in two steps. The first step + is used to build the dependencies, and the second step is used to + build the main image. The first step is cached to speed up the + process. The action is useful when the dependencies are not + expected to change often, and the main image is expected to change + frequently. inputs: container-file-1: @@ -52,6 +58,24 @@ inputs: Whether to push the second image. For instance, true. required: false default: 'true' + build-args-1: + description: | + The build arguments to use for the first image. + required: false + build-args-2: + description: | + The build arguments to use for the second image. + required: false +outputs: + tag: + description: | + The tag to used for the image. + value: ${{ steps.image-tag.outputs.tag }} + branch: + description: | + The branch name. + value: ${{ steps.branch-name.outputs.branch }} + runs: using: 'composite' @@ -116,6 +140,8 @@ runs: tags: | ${{ inputs.registry }}${{ inputs.image }}:dependencies-${{ steps.image-tag.outputs.tag }} file: ${{ inputs.container-file-1 }} + build-args: ${{ inputs.build-args-1 }} + - name: Build and push the main image id: build_and_push_model_image @@ -127,4 +153,5 @@ runs: ${{ inputs.registry }}${{ inputs.image }}:${{ steps.image-tag.outputs.tag }} file: ${{ inputs.container-file-2 }} build-args: | + ${{ inputs.build-args-2 }} TAG=dependencies-${{ steps.image-tag.outputs.tag }} \ No newline at end of file diff --git a/twostep-container-build/examples/Containerfile b/twostep-container-build/examples/Containerfile index e29589f..7e9d20d 100644 --- a/twostep-container-build/examples/Containerfile +++ b/twostep-container-build/examples/Containerfile @@ -1,7 +1,11 @@ -ARG TAG=latest +ARG TAG=dependencies-latest +ARG IMAGE=ghcr.io/cdcgov/cfa-actions -FROM ghcr.io/cdcgov/cfa-actions:${TAG} +FROM ${IMAGE}:${TAG} -COPY twostep-container-build/examples/Containerfile /app/. +# Notice that ARG are reset after the FROM +ARG GH_SHA=default_var +LABEL GH_SHA=${GH_SHA} +COPY . /app/. CMD ["bash"] \ No newline at end of file diff --git a/twostep-container-build/examples/Containerfile.dependencies b/twostep-container-build/examples/Containerfile.dependencies index ed19008..56511bc 100644 --- a/twostep-container-build/examples/Containerfile.dependencies +++ b/twostep-container-build/examples/Containerfile.dependencies @@ -1,5 +1,2 @@ -FROM rocker/r-base:4.4.0 - -RUN install2.r epiworldR - +FROM python:3.12 CMD ["bash"] \ No newline at end of file diff --git a/twostep-container-build/examples/Makefile b/twostep-container-build/examples/Makefile new file mode 100644 index 0000000..fb49d51 --- /dev/null +++ b/twostep-container-build/examples/Makefile @@ -0,0 +1,29 @@ +ifndef TAG +TAG := latest +endif + +ifndef IMAGE +IMAGE := ghcr.io/cdcgov/cfa-actions +endif + +ifndef ENGINE +ENGINE := podman +endif + +deps: + $(ENGINE) build \ + --no-cache \ + -t $(IMAGE):dependencies-$(TAG) -f Containerfile.dependencies + +build: + cd ../../ && \ + $(ENGINE) build \ + --build-arg TAG=dependencies-$(TAG) \ + --build-arg GH_SHA=example \ + --build-arg IMAGE=$(IMAGE) \ + --no-cache \ + -t $(IMAGE):$(TAG) \ + -f twostep-container-build/examples/Containerfile + +print-sha: + $(ENGINE) inspect $(IMAGE):$(TAG) --format='{{json .Config.Labels}}' | jq . \ No newline at end of file