Skip to content

Commit 1e5c049

Browse files
ci: add container builds and publish workflow (#605)
* ci: add publish workflow for controller This commit adds a GHA workflow to support publishing a container image for the `workspaces/controller` component as well as some updates to the `Makefile` to establish reasonable (but overridable) defaults. Key behavior: - Publishes controller images on any workspaces/ directory change - Builds images with commit SHA tags by default - "release" images with use the tag as defined by the `VERSION` file - a `-dirty` suffix is added to the tag if the codebase is not `porcelain` - no `latest` tag is ever produced on images - Uses `ghcr.io/kubeflow/notebooks` registry with configurable naming example image name from "random" commit: - `ghcr.io/kubeflow/notebooks/workspaces-controller:sha-3fa851ab3173942dbaa1a609468e7f9eadf5f4e4` example image name from release: - `ghcr.io/kubeflow/notebooks/workspaces-controller:v2.0.0` Signed-off-by: Andy Stoneberg <astonebe@redhat.com> * mathew: example rewrite 1 Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com> * fix registry path to include owner and repo name Signed-off-by: Andy Stoneberg <astonebe@redhat.com> * ci: fix ws-publish.yml with.semver_raw has an incorrect reference to version_raw output that results in an empty string always being passed - which prevented semver tags from ever being produced (even when they should be) Signed-off-by: Andy Stoneberg <astonebe@redhat.com> * fix: semver with references needs.check_version stores all its 'interesting data' under the 'outputs' attribute. This was not properly reflected in the 'with' block for images job. Signed-off-by: Andy Stoneberg <astonebe@redhat.com> --------- Signed-off-by: Andy Stoneberg <astonebe@redhat.com> Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com> Co-authored-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>
1 parent df917e6 commit 1e5c049

File tree

8 files changed

+260
-91
lines changed

8 files changed

+260
-91
lines changed

.github/workflows/ws-backend-test.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ jobs:
5252
exit 1
5353
fi
5454
55+
image-build:
56+
needs: build
57+
uses: ./.github/workflows/ws-build-image.yml
58+
with:
59+
image_name: workspaces-backend
60+
build_file: ./workspaces/backend/Dockerfile
61+
## NOTE: we build the backend from the parent folder so it can COPY from controller
62+
build_context: ./workspaces
63+
build_platforms: linux/amd64,linux/ppc64le,linux/arm64/v8
64+
tag_with_sha: true
65+
5566
unit-tests:
5667
runs-on: ubuntu-latest
5768
needs: build
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: Build Image
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
image_name:
7+
required: true
8+
description: "the name of the image"
9+
type: string
10+
11+
tag_with_latest:
12+
default: false
13+
description: "if true, image tags will include 'latest'"
14+
type: boolean
15+
tag_with_semver:
16+
default: false
17+
description: "if true, image tags will include the version (from semver_raw, without 'v' prefix)"
18+
type: boolean
19+
tag_with_sha:
20+
default: false
21+
description: "if true, image tags will include the commit SHA (both short and long)"
22+
type: boolean
23+
24+
semver_raw:
25+
default: "UNSET_SEMVER"
26+
description: "the raw semver version (e.g., from VERSION file), used if tag_with_semver is true"
27+
type: string
28+
29+
build_file:
30+
required: true
31+
description: "path to Dockerfile"
32+
type: string
33+
build_context:
34+
required: true
35+
description: "path to build context folder"
36+
type: string
37+
build_platforms:
38+
required: true
39+
description: "list of target platforms for build, comma separated (e.g., linux/amd64,linux/arm64/v8)"
40+
type: string
41+
42+
push_to_registry:
43+
default: false
44+
description: "if true, push the built image to the registry"
45+
type: boolean
46+
47+
env:
48+
IMAGE_REGISTRY: ghcr.io/${{ github.repository }}
49+
50+
jobs:
51+
build_image:
52+
name: Build '${{ inputs.image_name }}' Image
53+
runs-on: ubuntu-latest
54+
steps:
55+
- name: Checkout
56+
uses: actions/checkout@v5
57+
58+
- name: Install QEMU
59+
uses: docker/setup-qemu-action@v3
60+
61+
- name: Install Docker Buildx
62+
uses: docker/setup-buildx-action@v3
63+
64+
- name: Login to GitHub Container Registry
65+
uses: docker/login-action@v3
66+
if: ${{ inputs.push_to_registry }}
67+
with:
68+
registry: ghcr.io
69+
username: ${{ github.actor }}
70+
password: ${{ secrets.GITHUB_TOKEN }}
71+
72+
- name: Generate Image Metadata
73+
id: meta
74+
uses: docker/metadata-action@v5
75+
with:
76+
images: |
77+
${{ env.IMAGE_REGISTRY }}/${{ inputs.image_name }}
78+
flavor: |
79+
latest=${{ inputs.tag_with_latest }}
80+
tags: |
81+
type=semver,priority=1000,pattern={{version}},enable=${{ inputs.tag_with_semver }},value=${{ inputs.semver_raw }}
82+
type=semver,priority=900,pattern={{major}}.{{minor}},enable=${{ inputs.tag_with_semver }},value=${{ inputs.semver_raw }}
83+
type=sha,priority=200,prefix=sha-,format=short,enable=${{ inputs.tag_with_sha }}
84+
type=sha,priority=100,prefix=sha-,format=long,enable=${{ inputs.tag_with_sha }}
85+
86+
- name: Build and Push Image
87+
uses: docker/build-push-action@v6
88+
with:
89+
annotations: ${{ steps.meta.outputs.annotations }}
90+
context: ${{ inputs.build_context }}
91+
file: ${{ inputs.build_file }}
92+
labels: ${{ steps.meta.outputs.labels }}
93+
platforms: ${{ inputs.build_platforms }}
94+
push: ${{ inputs.push_to_registry }}
95+
tags: ${{ steps.meta.outputs.tags }}

.github/workflows/ws-controller-test.yaml renamed to .github/workflows/ws-controller-test.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ jobs:
5252
exit 1
5353
fi
5454
55+
image-build:
56+
needs: build
57+
uses: ./.github/workflows/ws-build-image.yml
58+
with:
59+
image_name: workspaces-controller
60+
build_file: ./workspaces/controller/Dockerfile
61+
build_context: ./workspaces/controller
62+
build_platforms: linux/amd64,linux/ppc64le,linux/arm64/v8
63+
tag_with_sha: true
64+
5565
unit-tests:
5666
runs-on: ubuntu-latest
5767
needs: build

.github/workflows/ws-frontend-test.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,13 @@ jobs:
8686
echo "Uncommitted file changes detected: $clean"
8787
git diff
8888
exit 1
89-
fi
89+
fi
90+
91+
image-build:
92+
uses: ./.github/workflows/ws-build-image.yml
93+
with:
94+
image_name: workspaces-frontend
95+
build_file: ./workspaces/frontend/Dockerfile
96+
build_context: ./workspaces/frontend
97+
build_platforms: linux/amd64,linux/ppc64le,linux/arm64/v8
98+
tag_with_sha: true

.github/workflows/ws-publish.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Publish
2+
3+
permissions:
4+
contents: read
5+
packages: write
6+
7+
on:
8+
push:
9+
branches:
10+
- main
11+
- notebooks-v2
12+
- v*-branch
13+
paths:
14+
- releasing/version/VERSION
15+
## NOTE: we publish container images on any commit to all components, so the tags are consistent across components
16+
- workspaces/**
17+
18+
jobs:
19+
check_version:
20+
runs-on: ubuntu-latest
21+
outputs:
22+
version_changed: ${{ steps.filter.outputs.version }}
23+
version_raw: ${{ steps.get_version.outputs.version }}
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v4
27+
28+
- uses: dorny/paths-filter@v3
29+
id: filter
30+
with:
31+
base: ${{ github.ref }}
32+
filters: |
33+
version:
34+
- 'releasing/version/VERSION'
35+
36+
- name: Get Version
37+
id: get_version
38+
run: echo "version=$(cat releasing/version/VERSION)" >> $GITHUB_OUTPUT
39+
40+
images:
41+
uses: ./.github/workflows/ws-build-image.yml
42+
needs: check_version
43+
secrets: inherit
44+
strategy:
45+
fail-fast: false
46+
matrix:
47+
include:
48+
- image_name: workspaces-backend
49+
build_file: ./workspaces/backend/Dockerfile
50+
## NOTE: we build the backend from the parent folder so it can COPY from controller
51+
build_context: ./workspaces
52+
53+
- image_name: workspaces-controller
54+
build_file: ./workspaces/controller/Dockerfile
55+
build_context: ./workspaces/controller
56+
57+
- image_name: workspaces-frontend
58+
build_file: ./workspaces/frontend/Dockerfile
59+
build_context: ./workspaces/frontend
60+
with:
61+
image_name: ${{ matrix.image_name }}
62+
tag_with_latest: false # we don't use 'latest' tags for workspace images
63+
tag_with_semver: ${{ needs.check_version.outputs.version_changed == 'true' }}
64+
tag_with_sha: true
65+
semver_raw: ${{ needs.check_version.outputs.version_raw }}
66+
build_file: ${{ matrix.build_file }}
67+
build_context: ${{ matrix.build_context }}
68+
build_platforms: linux/amd64,linux/ppc64le,linux/arm64/v8
69+
push_to_registry: true

workspaces/backend/Makefile

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
GIT_COMMIT := $(shell git rev-parse HEAD)
2+
GIT_TREE_STATE := $(shell test -n "`git status --porcelain`" && echo "-dirty" || echo "")
3+
14
# Image URL to use all building/pushing image targets
2-
IMG ?= nb-backend:latest
3-
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
4-
ENVTEST_K8S_VERSION = 1.31.0
5+
REGISTRY ?= ghcr.io/kubeflow/notebooks
6+
NAME ?= workspaces-backend
7+
TAG ?= sha-$(GIT_COMMIT)$(GIT_TREE_STATE)
8+
IMG ?= $(REGISTRY)/$(NAME):$(TAG)
9+
ARCH ?= linux/arm64/v8,linux/amd64,linux/ppc64le
10+
511

612
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
713
ifeq (,$(shell go env GOBIN))
@@ -13,12 +19,6 @@ endif
1319
# Backend default port
1420
PORT ?= 4000
1521

16-
# CONTAINER_TOOL defines the container tool to be used for building images.
17-
# Be aware that the target commands are only tested with Docker which is
18-
# scaffolded by default. However, you might want to replace it to use other
19-
# tools. (i.e. podman)
20-
CONTAINER_TOOL ?= docker
21-
2222
# Setting SHELL to bash allows bash commands to be executed by recipes.
2323
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
2424
SHELL = /usr/bin/env bash -o pipefail
@@ -86,34 +86,24 @@ build: fmt vet swag ## Build backend binary.
8686
run: fmt vet swag ## Run a backend from your host.
8787
go run ./cmd/main.go --port=$(PORT)
8888

89-
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
90-
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
91-
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
9289
.PHONY: docker-build
93-
docker-build: ## Build docker image with the backend.
94-
$(CONTAINER_TOOL) build -f Dockerfile -t $(IMG) ..
95-
90+
docker-build:
91+
# NOTE: we are building in the context of the parent directory (..)
92+
docker build --tag ${IMG} --file Dockerfile ..
9693

9794
.PHONY: docker-push
98-
docker-push: ## Push docker image with the backend.
99-
$(CONTAINER_TOOL) push ${IMG}
100-
101-
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
102-
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
103-
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
104-
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
105-
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
106-
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
107-
PLATFORMS ?= linux/arm64/v8,linux/amd64,linux/ppc64le
108-
.PHONY: docker-buildx
109-
docker-buildx: ## Build and push docker image for the manager for cross-platform support
110-
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
111-
sed '1,// s/^FROM/FROM --platform=$${BUILDPLATFORM}/' Dockerfile > Dockerfile.cross
112-
- $(CONTAINER_TOOL) buildx create --name project-v3-builder
113-
$(CONTAINER_TOOL) buildx use project-v3-builder
114-
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross ..
115-
- $(CONTAINER_TOOL) buildx rm project-v3-builder
116-
rm Dockerfile.cross
95+
docker-push:
96+
docker push ${IMG}
97+
98+
.PHONY: docker-build-multi-arch
99+
docker-build-multi-arch:
100+
# NOTE: we are building in the context of the parent directory (..)
101+
docker buildx build --platform ${ARCH} --tag ${IMG} --file Dockerfile ..
102+
103+
.PHONY: docker-build-push-multi-arch
104+
docker-build-push-multi-arch:
105+
# NOTE: we are building in the context of the parent directory (..)
106+
docker buildx build --platform ${ARCH} --tag ${IMG} --file Dockerfile --push ..
117107

118108
##@ Dependencies
119109

workspaces/controller/Makefile

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
GIT_COMMIT := $(shell git rev-parse HEAD)
2+
GIT_TREE_STATE := $(shell test -n "`git status --porcelain`" && echo "-dirty" || echo "")
3+
14
# Image URL to use all building/pushing image targets
2-
TAG ?= $(shell git describe --tags --always --dirty)
3-
IMG ?= ghcr.io/kubeflow/notebooks/workspaces-controller:$(TAG)
5+
REGISTRY ?= ghcr.io/kubeflow/notebooks
6+
NAME ?= workspaces-controller
7+
TAG ?= sha-$(GIT_COMMIT)$(GIT_TREE_STATE)
8+
IMG ?= $(REGISTRY)/$(NAME):$(TAG)
9+
ARCH ?= linux/arm64/v8,linux/amd64,linux/ppc64le
410

511

612
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
@@ -13,12 +19,6 @@ else
1319
GOBIN=$(shell go env GOBIN)
1420
endif
1521

16-
# CONTAINER_TOOL defines the container tool to be used for building images.
17-
# Be aware that the target commands are only tested with Docker which is
18-
# scaffolded by default. However, you might want to replace it to use other
19-
# tools. (i.e. podman)
20-
CONTAINER_TOOL ?= docker
21-
2222
# Setting SHELL to bash allows bash commands to be executed by recipes.
2323
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
2424
SHELL = /usr/bin/env bash -o pipefail
@@ -100,33 +100,21 @@ build: manifests generate fmt vet ## Build manager binary.
100100
run: manifests generate fmt vet ## Run a controller from your host.
101101
go run ./cmd/main.go
102102

103-
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
104-
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
105-
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
106103
.PHONY: docker-build
107-
docker-build: ## Build docker image with the manager.
108-
$(CONTAINER_TOOL) build -t ${IMG} .
104+
docker-build:
105+
docker build --tag ${IMG} .
109106

110107
.PHONY: docker-push
111-
docker-push: ## Push docker image with the manager.
112-
$(CONTAINER_TOOL) push ${IMG}
113-
114-
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
115-
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
116-
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
117-
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
118-
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
119-
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
120-
PLATFORMS ?= linux/arm64/v8,linux/amd64,linux/ppc64le
121-
.PHONY: docker-buildx
122-
docker-buildx: ## Build and push docker image for the manager for cross-platform support
123-
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
124-
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
125-
- $(CONTAINER_TOOL) buildx create --name project-v3-builder
126-
$(CONTAINER_TOOL) buildx use project-v3-builder
127-
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
128-
- $(CONTAINER_TOOL) buildx rm project-v3-builder
129-
rm Dockerfile.cross
108+
docker-push:
109+
docker push ${IMG}
110+
111+
.PHONY: docker-build-multi-arch
112+
docker-build-multi-arch:
113+
docker buildx build --platform ${ARCH} --tag ${IMG} .
114+
115+
.PHONY: docker-build-push-multi-arch
116+
docker-build-push-multi-arch:
117+
docker buildx build --platform ${ARCH} --tag ${IMG} --push .
130118

131119
.PHONY: build-installer
132120
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.

0 commit comments

Comments
 (0)