Skip to content

Commit f45a465

Browse files
authored
ci: adopt shared reusable release workflows + pin-at-release OCI publishing (#139)
* operator: make model-downloader init image configurable via LLM_MODEL_DOWNLOADER_IMAGE * chart: decouple image tags from appVersion; add configurable model-downloader image * ci: consume reusable build/release workflows; add categorized changelog config Replace the per-image build steps in build-images.yaml with thin caller jobs that invoke the shared nebari-dev/.github pack-build-image reusable workflow, add a release.yaml caller for pack-release, and add .github/release.yml with changelog categories keyed on this repo's labels. The @feat/pack-release-workflows ref is a bring-up ref and must be re-pinned to v1 before this PR merges. * docs: rewrite release process for pin-at-release OCI publishing * ci: build images on Chart.yaml bump so release-commit shas exist Add charts/nebari-llm-serving/Chart.yaml to the push trigger paths in build-images.yaml so the release commit (a Chart.yaml version bump) produces sha-<commit> images before the release workflow pins the chart to that sha. Update the CI/CD docs to reflect that a release now triggers both workflows in parallel instead of describing this as a known gap. * docs: update README and ui-development image paths to llm-serving-pack Follows the repo rename; only the ghcr.io image paths change (the github.com repo URLs are redirect-handled and left for the repo-rename cleanup). Go module path untouched. * ci: pin reusable release workflows to nebari-dev/.github@v1 Now that nebari-dev/.github#43 is merged and tagged v1, pin the caller refs to the release tag and drop the bring-up TODOs.
1 parent 07592f9 commit f45a465

12 files changed

Lines changed: 201 additions & 206 deletions

File tree

.github/release.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
changelog:
2+
categories:
3+
- title: Features
4+
labels: ["type: enhancement 💅🏼", "type: exploration 🔮"]
5+
- title: Bug Fixes
6+
labels: ["type: bug 🐛"]
7+
- title: Documentation
8+
labels: ["area: documentation 📖"]
9+
- title: Dependencies
10+
labels: ["area: dependencies 📦"]
11+
- title: Maintenance
12+
labels: ["type: maintenance 🛠", "area: ci 👷🏽‍♀️"]
13+
- title: Other Changes
14+
labels: ["*"]
Lines changed: 55 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,156 +1,62 @@
1-
name: Build Images
1+
name: Build Docker Images
22

33
on:
44
push:
55
branches: [main]
6-
tags: ["v*"]
6+
paths:
7+
- "operator/**"
8+
- "key-manager/**"
9+
- "frontend/**"
10+
- "model-downloader/**"
11+
- ".github/workflows/build-images.yaml"
12+
# The release workflow pins images to sha-<release-commit>, so the
13+
# release commit (a Chart.yaml bump) must produce images with that
14+
# sha. Building here on the bump ensures they exist. This runs in
15+
# parallel with the release workflow (no hard gate in v1), so images
16+
# are published around the same time the chart becomes consumable.
17+
- "charts/nebari-llm-serving/Chart.yaml"
18+
pull_request:
19+
paths:
20+
- "operator/**"
21+
- "key-manager/**"
22+
- "frontend/**"
23+
- "model-downloader/**"
724
workflow_dispatch:
825

9-
env:
10-
REGISTRY: ghcr.io
11-
IMAGE_PREFIX: ghcr.io/nebari-dev/nebari-llm-serving-pack
12-
1326
jobs:
14-
build-operator:
15-
name: Build and push operator image
16-
runs-on: ubuntu-latest
17-
permissions:
18-
contents: read
19-
packages: write
20-
steps:
21-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
22-
23-
- name: Log in to GHCR
24-
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
25-
with:
26-
registry: ${{ env.REGISTRY }}
27-
username: ${{ github.actor }}
28-
password: ${{ secrets.GITHUB_TOKEN }}
29-
30-
- name: Extract metadata
31-
id: meta
32-
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
33-
with:
34-
images: ${{ env.IMAGE_PREFIX }}/operator
35-
tags: |
36-
type=sha
37-
type=ref,event=branch
38-
type=semver,pattern=v{{version}}
39-
type=raw,value=latest,enable={{is_default_branch}}
40-
41-
- name: Build and push operator image
42-
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
43-
with:
44-
context: operator/
45-
file: operator/Dockerfile
46-
push: true
47-
tags: ${{ steps.meta.outputs.tags }}
48-
labels: ${{ steps.meta.outputs.labels }}
49-
50-
build-model-downloader:
51-
name: Build and push model-downloader image
52-
runs-on: ubuntu-latest
53-
permissions:
54-
contents: read
55-
packages: write
56-
steps:
57-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
58-
59-
- name: Log in to GHCR
60-
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
61-
with:
62-
registry: ${{ env.REGISTRY }}
63-
username: ${{ github.actor }}
64-
password: ${{ secrets.GITHUB_TOKEN }}
65-
66-
- name: Extract metadata
67-
id: meta
68-
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
69-
with:
70-
images: ${{ env.IMAGE_PREFIX }}/model-downloader
71-
tags: |
72-
type=sha
73-
type=ref,event=branch
74-
type=semver,pattern=v{{version}}
75-
type=raw,value=latest,enable={{is_default_branch}}
76-
77-
- name: Build and push model-downloader image
78-
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
79-
with:
80-
context: model-downloader/
81-
file: model-downloader/Dockerfile
82-
push: true
83-
tags: ${{ steps.meta.outputs.tags }}
84-
labels: ${{ steps.meta.outputs.labels }}
85-
86-
build-key-manager:
87-
name: Build and push key-manager image
88-
runs-on: ubuntu-latest
89-
permissions:
90-
contents: read
91-
packages: write
92-
steps:
93-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
94-
95-
- name: Log in to GHCR
96-
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
97-
with:
98-
registry: ${{ env.REGISTRY }}
99-
username: ${{ github.actor }}
100-
password: ${{ secrets.GITHUB_TOKEN }}
101-
102-
- name: Extract metadata
103-
id: meta
104-
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
105-
with:
106-
images: ${{ env.IMAGE_PREFIX }}/key-manager
107-
tags: |
108-
type=sha
109-
type=ref,event=branch
110-
type=semver,pattern=v{{version}}
111-
type=raw,value=latest,enable={{is_default_branch}}
112-
113-
- name: Build and push key-manager image
114-
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
115-
with:
116-
context: .
117-
file: key-manager/Dockerfile
118-
push: true
119-
tags: ${{ steps.meta.outputs.tags }}
120-
labels: ${{ steps.meta.outputs.labels }}
121-
122-
build-frontend:
123-
name: Build and push frontend image
124-
runs-on: ubuntu-latest
125-
permissions:
126-
contents: read
127-
packages: write
128-
steps:
129-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
130-
131-
- name: Log in to GHCR
132-
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
133-
with:
134-
registry: ${{ env.REGISTRY }}
135-
username: ${{ github.actor }}
136-
password: ${{ secrets.GITHUB_TOKEN }}
137-
138-
- name: Extract metadata
139-
id: meta
140-
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
141-
with:
142-
images: ${{ env.IMAGE_PREFIX }}/frontend
143-
tags: |
144-
type=sha
145-
type=ref,event=branch
146-
type=semver,pattern=v{{version}}
147-
type=raw,value=latest,enable={{is_default_branch}}
148-
149-
- name: Build and push frontend image
150-
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
151-
with:
152-
context: frontend/
153-
file: frontend/Dockerfile
154-
push: true
155-
tags: ${{ steps.meta.outputs.tags }}
156-
labels: ${{ steps.meta.outputs.labels }}
27+
operator:
28+
uses: nebari-dev/.github/.github/workflows/pack-build-image.yaml@v1
29+
with:
30+
image: operator
31+
context: operator/
32+
push: ${{ github.event_name != 'pull_request' }}
33+
secrets:
34+
QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}
35+
36+
model-downloader:
37+
uses: nebari-dev/.github/.github/workflows/pack-build-image.yaml@v1
38+
with:
39+
image: model-downloader
40+
context: model-downloader/
41+
push: ${{ github.event_name != 'pull_request' }}
42+
secrets:
43+
QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}
44+
45+
key-manager:
46+
uses: nebari-dev/.github/.github/workflows/pack-build-image.yaml@v1
47+
with:
48+
image: key-manager
49+
context: "."
50+
dockerfile: key-manager/Dockerfile
51+
push: ${{ github.event_name != 'pull_request' }}
52+
secrets:
53+
QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}
54+
55+
frontend:
56+
uses: nebari-dev/.github/.github/workflows/pack-build-image.yaml@v1
57+
with:
58+
image: frontend
59+
context: frontend/
60+
push: ${{ github.event_name != 'pull_request' }}
61+
secrets:
62+
QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}

.github/workflows/release.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Release Chart
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "charts/nebari-llm-serving/Chart.yaml"
8+
9+
jobs:
10+
release:
11+
uses: nebari-dev/.github/.github/workflows/pack-release.yaml@v1
12+
with:
13+
chart-path: charts/nebari-llm-serving
14+
chart-name: nebari-llm-serving
15+
tag-paths: |
16+
operator.image.tag
17+
keyManager.image.tag
18+
frontend.image.tag
19+
modelDownloader.image.tag
20+
secrets:
21+
NEBARI_HELM_REPO_TOKEN: ${{ secrets.NEBARI_HELM_REPO_TOKEN }}

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,10 @@ Admin applies LLMModel CR
236236
237237
| Image | Description |
238238
|-------|-------------|
239-
| `ghcr.io/nebari-dev/nebari-llm-serving-pack/operator` | LLM operator - reconciles LLMModel CRDs |
240-
| `ghcr.io/nebari-dev/nebari-llm-serving-pack/key-manager` | Key manager REST API |
241-
| `ghcr.io/nebari-dev/nebari-llm-serving-pack/frontend` | LLM serving pack React UI (nginx) |
242-
| `ghcr.io/nebari-dev/nebari-llm-serving-pack/model-downloader` | Model download init container (distroless, pixi-managed) |
239+
| `ghcr.io/nebari-dev/llm-serving-pack/operator` | LLM operator - reconciles LLMModel CRDs |
240+
| `ghcr.io/nebari-dev/llm-serving-pack/key-manager` | Key manager REST API |
241+
| `ghcr.io/nebari-dev/llm-serving-pack/frontend` | LLM serving pack React UI (nginx) |
242+
| `ghcr.io/nebari-dev/llm-serving-pack/model-downloader` | Model download init container (distroless, pixi-managed) |
243243
244244
### Infrastructure requirements
245245
@@ -281,7 +281,7 @@ make teardown
281281

282282
### Key manager UI
283283

284-
The key manager web UI is a [React](https://react.dev) + TypeScript app (Vite, Tailwind, shadcn/ui) in [`frontend/`](frontend/). In production it ships as its own nginx image (`ghcr.io/nebari-dev/nebari-llm-serving-pack/frontend`) that serves the SPA and proxies `/api` to the API-only key-manager; it is not embedded in the Go binary. For a one-command dev loop that needs **no Keycloak**:
284+
The key manager web UI is a [React](https://react.dev) + TypeScript app (Vite, Tailwind, shadcn/ui) in [`frontend/`](frontend/). In production it ships as its own nginx image (`ghcr.io/nebari-dev/llm-serving-pack/frontend`) that serves the SPA and proxies `/api` to the API-only key-manager; it is not embedded in the Go binary. For a one-command dev loop that needs **no Keycloak**:
285285

286286
```bash
287287
# One-time: copy dev/.env.example to dev/.env and set OPENROUTER_API_KEY

charts/nebari-llm-serving/templates/frontend-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ spec:
3434
# ClusterIP. This is the service the NebariApp targets; auth is handled
3535
# client-side by keycloak-js (PKCE/S256) and validated by the key-manager.
3636
- name: frontend
37-
image: {{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag | default .Chart.AppVersion }}
37+
image: {{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}
3838
imagePullPolicy: {{ .Values.frontend.image.pullPolicy | default "IfNotPresent" }}
3939
ports:
4040
- name: http

charts/nebari-llm-serving/templates/key-manager-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ spec:
2020
serviceAccountName: {{ include "nebari-llm-serving.fullname" . }}-key-manager
2121
containers:
2222
- name: key-manager
23-
image: {{ .Values.keyManager.image.repository }}:{{ .Values.keyManager.image.tag | default .Chart.AppVersion }}
23+
image: {{ .Values.keyManager.image.repository }}:{{ .Values.keyManager.image.tag }}
2424
imagePullPolicy: {{ .Values.keyManager.image.pullPolicy | default "IfNotPresent" }}
2525
ports:
2626
- containerPort: 8080

charts/nebari-llm-serving/templates/operator-deployment.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ spec:
1919
serviceAccountName: {{ include "nebari-llm-serving.fullname" . }}-operator
2020
containers:
2121
- name: manager
22-
image: {{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag | default .Chart.AppVersion }}
22+
image: {{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag }}
2323
imagePullPolicy: {{ .Values.operator.image.pullPolicy | default "IfNotPresent" }}
2424
env:
2525
- name: LLM_BASE_DOMAIN
@@ -48,6 +48,8 @@ spec:
4848
value: {{ .Values.defaults.serving.image | quote }}
4949
- name: LLM_DEFAULT_EPP_IMAGE
5050
value: {{ .Values.defaults.epp.image | quote }}
51+
- name: LLM_MODEL_DOWNLOADER_IMAGE
52+
value: "{{ .Values.modelDownloader.image.repository }}:{{ .Values.modelDownloader.image.tag }}"
5153
- name: LLM_DEFAULT_STORAGE_CLASS_NAME
5254
value: {{ .Values.defaults.storage.storageClassName | quote }}
5355
- name: LLM_CLUSTER_ISSUER_NAME

charts/nebari-llm-serving/values.yaml

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,9 @@ keyManager:
7272
groups:
7373
- llm
7474
image:
75-
repository: ghcr.io/nebari-dev/nebari-llm-serving-pack/key-manager
76-
# tag defaults to .Chart.AppVersion when empty so the chart version and
77-
# the image version always move together. Override only when testing a
78-
# specific image build (e.g. tag: 0.1.0-alpha.2 or tag: sha-abc1234).
79-
tag: ""
75+
repository: ghcr.io/nebari-dev/llm-serving-pack/key-manager
76+
# Floating on main; pinned to a build sha at release time (see cicd-and-releasing).
77+
tag: "latest"
8078
pullPolicy: Always
8179
auditInterval: 5m
8280
oidcUserinfoURL: ""
@@ -176,10 +174,9 @@ frontend:
176174
# Set enabled=false to skip the frontend (e.g. an API-only test install).
177175
enabled: true
178176
image:
179-
repository: ghcr.io/nebari-dev/nebari-llm-serving-pack/frontend
180-
# tag defaults to .Chart.AppVersion when empty so the chart and image
181-
# versions move together. Override to pull a specific build.
182-
tag: ""
177+
repository: ghcr.io/nebari-dev/llm-serving-pack/frontend
178+
# Floating on main; pinned to a build sha at release time (see cicd-and-releasing).
179+
tag: "latest"
183180
pullPolicy: Always
184181
# port nginx listens on. Must be > 1024 - the container runs as non-root
185182
# (UID 101) with all capabilities dropped and cannot bind privileged ports.
@@ -202,13 +199,20 @@ frontend:
202199

203200
operator:
204201
image:
205-
repository: ghcr.io/nebari-dev/nebari-llm-serving-pack/operator
206-
# tag defaults to .Chart.AppVersion when empty so the chart version and
207-
# the image version always move together. Override only when testing a
208-
# specific image build (e.g. tag: 0.1.0-alpha.2 or tag: sha-abc1234).
209-
tag: ""
202+
repository: ghcr.io/nebari-dev/llm-serving-pack/operator
203+
# Floating on main; pinned to a build sha at release time (see cicd-and-releasing).
204+
tag: "latest"
210205
pullPolicy: Always
211206

207+
# modelDownloader - the init/job image the operator uses to fetch model
208+
# weights before a serving Deployment starts. Rendered into the operator's
209+
# LLM_MODEL_DOWNLOADER_IMAGE env var (operator-deployment.yaml) rather than
210+
# hardcoded, so it can be re-pinned without rebuilding the operator image.
211+
modelDownloader:
212+
image:
213+
repository: ghcr.io/nebari-dev/llm-serving-pack/model-downloader
214+
# Floating on main; pinned to a build sha at release time (see cicd-and-releasing).
215+
tag: "latest"
212216

213217
defaults:
214218
serving:

0 commit comments

Comments
 (0)