Skip to content

Commit c7aed7f

Browse files
authored
Tweak to support federated platform (kubeflow#1219)
Signed-off-by: lucferbux <[email protected]>
1 parent d2c04b0 commit c7aed7f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+886
-439
lines changed

.github/workflows/build-and-push-ui-images-standalone.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,6 @@ jobs:
7474
labels: ${{ steps.meta.outputs.labels }}
7575
build-args: |
7676
DEPLOYMENT_MODE=standalone
77+
STYLE_THEME=mui-theme
7778
cache-from: type=gha
7879
cache-to: type=gha,mode=max
Lines changed: 63 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
name: Build and Push UI and BFF Images
1+
name: Build and Push UI Image
2+
# this workflow builds an image to support local testing
23
on:
34
push:
45
branches:
@@ -7,51 +8,72 @@ on:
78
- 'v*'
89
paths:
910
- 'clients/ui/**'
11+
- '!LICENSE*'
12+
- '!DOCKERFILE*'
13+
- '!**.gitignore'
14+
- '!**.md'
15+
- '!**.txt'
1016
env:
1117
IMG_REGISTRY: ghcr.io
1218
IMG_ORG: kubeflow
13-
IMG_UI_REPO: model-registry/ui
14-
PUSH_IMAGE: true
19+
IMG_UI_REPO: model-registry/ui # this image is intended for local development, not production
1520
DOCKER_USER: ${{ github.actor }}
1621
DOCKER_PWD: ${{ secrets.GITHUB_TOKEN }}
1722
jobs:
18-
build-image:
23+
build-and-push:
1924
runs-on: ubuntu-latest
25+
permissions:
26+
contents: read
27+
packages: write
2028
steps:
21-
# Assign context variable for various action contexts (tag, main, CI)
22-
- name: Assigning tag context
23-
if: github.head_ref == '' && startsWith(github.ref, 'refs/tags/v')
24-
run: echo "BUILD_CONTEXT=tag" >> $GITHUB_ENV
25-
# Assign context variable for various action contexts (main, CI)
26-
- name: Assigning main context
27-
if: github.head_ref == '' && github.ref == 'refs/heads/main'
28-
run: echo "BUILD_CONTEXT=main" >> $GITHUB_ENV
29-
# checkout branch
30-
- uses: actions/checkout@v4
31-
# set image version
32-
- name: Set main-branch environment
33-
if: env.BUILD_CONTEXT == 'main'
34-
run: |
35-
commit_sha=${{ github.event.after }}
36-
tag=main-${commit_sha:0:7}
37-
echo "VERSION=${tag}" >> $GITHUB_ENV
38-
- name: Set tag environment
39-
if: env.BUILD_CONTEXT == 'tag'
40-
run: |
41-
echo "VERSION=${{ github.ref_name }}" >> $GITHUB_ENV
42-
- name: Build and Push UI Image
43-
shell: bash
44-
env:
45-
IMG_REPO: ${{ env.IMG_UI_REPO }}
46-
run: ./scripts/build_deploy.sh
47-
- name: Tag Latest UI Image
48-
if: env.BUILD_CONTEXT == 'main'
49-
shell: bash
50-
env:
51-
IMG_REPO: ${{ env.IMG_UI_REPO }}
52-
IMG: "${{ env.IMG_REGISTRY }}/${{ env.IMG_ORG }}/${{ env.IMG_UI_REPO }}"
53-
BUILD_IMAGE: false # image is already built in "Build and Push UI Image" step
54-
run: |
55-
docker tag ${{ env.IMG }}:$VERSION ${{ env.IMG }}:latest
56-
# BUILD_IMAGE=false skip the build, just push the tag made above
57-
VERSION=latest ./scripts/build_deploy.sh
29+
- name: Checkout repository
30+
uses: actions/checkout@v4
31+
32+
- name: Set up Docker Buildx
33+
uses: docker/setup-buildx-action@v3
34+
35+
- name: Log in to the Container registry
36+
uses: docker/login-action@v3
37+
with:
38+
registry: ${{ env.IMG_REGISTRY }}
39+
username: ${{ env.DOCKER_USER }}
40+
password: ${{ env.DOCKER_PWD }}
41+
42+
- name: Set main-branch environment
43+
if: github.ref == 'refs/heads/main'
44+
run: |
45+
commit_sha=${{ github.sha }}
46+
tag=main-${commit_sha:0:7}
47+
echo "VERSION=${tag}" >> $GITHUB_ENV
48+
49+
- name: Set tag environment
50+
if: startsWith(github.ref, 'refs/tags/v')
51+
run: |
52+
echo "VERSION=${{ github.ref_name }}" >> $GITHUB_ENV
53+
54+
- name: Extract metadata (tags, labels) for Docker
55+
id: meta
56+
uses: docker/metadata-action@v5
57+
with:
58+
images: "${{ env.IMG_REGISTRY }}/${{ env.IMG_ORG }}/${{ env.IMG_UI_REPO }}"
59+
tags: |
60+
type=ref,event=branch
61+
type=ref,event=pr
62+
type=semver,pattern={{version}}
63+
type=semver,pattern={{major}}.{{minor}}
64+
type=sha
65+
type=raw,value=${{ env.VERSION }},enable=${{ env.VERSION != '' }}
66+
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
67+
68+
- name: Build and push Docker image
69+
uses: docker/build-push-action@v6
70+
with:
71+
context: ./clients/ui
72+
push: true
73+
tags: ${{ steps.meta.outputs.tags }}
74+
labels: ${{ steps.meta.outputs.labels }}
75+
build-args: |
76+
DEPLOYMENT_MODE=kubeflow
77+
STYLE_THEME=mui-theme
78+
cache-from: type=gha
79+
cache-to: type=gha,mode=max

clients/ui/.env

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
CONTAINER_TOOL=docker
44
IMG_UI=ghcr.io/kubeflow/model-registry/ui:latest
55
IMG_UI_STANDALONE=ghcr.io/kubeflow/model-registry/ui-standalone:latest
6+
IMG_UI_FEDERATED=ghcr.io/kubeflow/model-registry/ui-federated:latest
67
PLATFORM=linux/amd64
8+
STYLE_THEME=mui-theme
9+
DEPLOYMENT_MODE=kubeflow

clients/ui/.env.production

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
APP_ENV=production
2-
DEPLOYMENT_MODE=integrated
3-
STYLE_THEME=mui-theme
2+

clients/ui/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ FROM ${NODE_BASE_IMAGE} AS ui-builder
1212

1313
ARG UI_SOURCE_CODE
1414
ARG DEPLOYMENT_MODE
15+
ARG STYLE_THEME
1516

1617
WORKDIR /usr/src/app
1718

clients/ui/Makefile

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,46 +32,67 @@ dev-install-dependencies:
3232

3333
.PHONY: dev-bff
3434
dev-bff:
35-
cd bff && make run PORT=4000 MOCK_K8S_CLIENT=true MOCK_MR_CLIENT=true DEV_MODE=true STANDALONE_MODE=true
35+
cd bff && make run PORT=4000 MOCK_K8S_CLIENT=true MOCK_MR_CLIENT=true DEV_MODE=true STANDALONE_MODE=true FEDERATED_PLATFORM=false
3636

3737
.PHONY: dev-frontend
3838
dev-frontend:
39-
cd frontend && npm run start:dev
39+
DEPLOYMENT_MODE=standalone && STYLE_THEME=mui-theme cd frontend && npm run start:dev
4040

4141
.PHONY: dev-start
4242
dev-start:
4343
make -j 2 dev-bff dev-frontend
4444

45-
########### Dev Integrated ############
45+
########### Dev Kubeflow ############
4646
.PHONY: dev-start-kubeflow
4747
dev-start-kubeflow:
4848
make -j 2 dev-bff-kubeflow dev-frontend-kubeflow
4949

5050
.PHONY: dev-frontend-kubeflow
5151
dev-frontend-kubeflow:
52-
DEPLOYMENT_MODE=integrated && cd frontend && npm run start:dev
52+
DEPLOYMENT_MODE=kubeflow && STYLE_THEME=mui-theme && cd frontend && npm run start:dev
5353

5454
.PHONY: dev-bff-kubeflow
5555
dev-bff-kubeflow:
56-
cd bff && make run PORT=4000 MOCK_K8S_CLIENT=false MOCK_MR_CLIENT=false DEV_MODE=true STANDALONE_MODE=false DEV_MODE_PORT=8085
56+
cd bff && make run PORT=4000 MOCK_K8S_CLIENT=false MOCK_MR_CLIENT=false DEV_MODE=true STANDALONE_MODE=false FEDERATED_PLATFORM=false DEV_MODE_PORT=8085
57+
58+
########### Dev Federated ############
59+
.PHONY: dev-start-federated
60+
dev-start-federated:
61+
make -j 2 dev-bff-federated dev-frontend-federated
62+
63+
.PHONY: dev-frontend-federated
64+
dev-frontend-federated:
65+
DEPLOYMENT_MODE=federated && STYLE_THEME=patternfly && cd frontend && npm run start:dev
66+
67+
.PHONY: dev-bff-federated
68+
dev-bff-federated:
69+
cd bff && make run PORT=4000 MOCK_K8S_CLIENT=false MOCK_MR_CLIENT=false DEV_MODE=true STANDALONE_MODE=false FEDERATED_PLATFORM=true DEV_MODE_PORT=8085
5770

5871
############ Build ############
5972

6073
.PHONY: docker-build
6174
docker-build:
62-
$(CONTAINER_TOOL) build -t ${IMG_UI} .
75+
$(CONTAINER_TOOL) build --build-arg DEPLOYMENT_MODE=kubeflow --build-arg STYLE_THEME=mui-theme -t ${IMG_UI} .
6376

6477
.PHONY: docker-build-standalone
6578
docker-build-standalone:
66-
$(CONTAINER_TOOL) build --build-arg DEPLOYMENT_MODE=standalone -t ${IMG_UI_STANDALONE} .
79+
$(CONTAINER_TOOL) build --build-arg DEPLOYMENT_MODE=standalone --build-arg STYLE_THEME=mui-theme -t ${IMG_UI_STANDALONE} .
80+
81+
.PHONY: docker-build-federated
82+
docker-build-federated:
83+
$(CONTAINER_TOOL) build --build-arg DEPLOYMENT_MODE=federated --build-arg STYLE_THEME=patternfly -t ${IMG_UI_FEDERATED} .
6784

6885
.PHONY: docker-buildx
6986
docker-buildx:
70-
docker buildx build --platform ${PLATFORM} -t ${IMG_UI} --push .
87+
docker buildx build --build-arg DEPLOYMENT_MODE=kubeflow --build-arg STYLE_THEME=mui-theme --platform ${PLATFORM} -t ${IMG_UI} --push .
7188

7289
.PHONY: docker-buildx-standalone
7390
docker-buildx-standalone:
74-
docker buildx build --build-arg DEPLOYMENT_MODE=standalone --platform ${PLATFORM} -t ${IMG_UI_STANDALONE} --push .
91+
docker buildx build --build-arg DEPLOYMENT_MODE=standalone --build-arg STYLE_THEME=mui-theme --platform ${PLATFORM} -t ${IMG_UI_STANDALONE} --push .
92+
93+
.PHONY: docker-buildx-federated
94+
docker-buildx-federated:
95+
docker buildx build --build-arg DEPLOYMENT_MODE=federated --build-arg STYLE_THEME=patternfly --platform ${PLATFORM} -t ${IMG_UI_FEDERATED} --push .
7596

7697
############ Push ############
7798

@@ -83,6 +104,10 @@ docker-push:
83104
docker-push-standalone:
84105
${CONTAINER_TOOL} push ${IMG_UI_STANDALONE}
85106

107+
.PHONY: docker-push-federated
108+
docker-push-federated:
109+
${CONTAINER_TOOL} push ${IMG_UI_FEDERATED}
110+
86111
############ Deployment ############
87112

88113
.PHONY: kind-deployment
@@ -96,7 +121,7 @@ kubeflow-deployment:
96121
############ Build ############
97122
.PHONY: frontend-build
98123
frontend-build:
99-
cd frontend && npm run build:prod
124+
cd frontend && DEPLOYMENT_MODE=kubeflow && npm run build:prod
100125

101126
.PHONY: frontend-build-standalone
102127
frontend-build-standalone:

clients/ui/README.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ There's two main environments that the Model Registry UI is targeted for:
2424

2525
1. **Standalone**: This is the default environment for local development. The UI is served by the BFF and the BFF is responsible for serving the API requests. The BFF exposes a `/namespace` endpoint that returns all the namespaces in the cluster and the UI sends a user header `kubeflow-user` to authenticate the calls.
2626

27-
2. **Integrated**: This is the environment where the UI is served by the Kubeflow Ingress and the BFF is served by the Kubeflow API Gateway. The BFF is responsible for serving the API requests and namespace selection is leveraged from Kubeflow.
27+
2. **Kubeflow**: This is the environment where the UI is served by the Kubeflow Ingress and the BFF is served by the Kubeflow API Gateway. The BFF is responsible for serving the API requests and namespace selection is leveraged from Kubeflow.
2828

2929
## Environment Variables
3030

@@ -49,6 +49,12 @@ The following environment variables are used to configure the deployment and dev
4949
* **Default Value**: `ghcr.io/kubeflow/model-registry/ui-standalone:latest`
5050
* **Example**: `IMG_UI_STANDALONE=ghcr.io/kubeflow/model-registry/ui-standalone:latest`
5151

52+
### `IMG_UI_FEDERATED`
53+
54+
* **Description**: Specifies the image name and tag for the UI (with BFF) in **federated mode**, used for federated mode outside kubeflow.
55+
* **Default Value**: `ghcr.io/kubeflow/model-registry/ui-federated:latest`
56+
* **Example**: `IMG_UI_FEDERATED=ghcr.io/kubeflow/model-registry/ui-federated:latest`
57+
5258
### `PLATFORM`
5359

5460
* **Description**: Specifies the platform for a **docker buildx** build.
@@ -58,8 +64,17 @@ The following environment variables are used to configure the deployment and dev
5864
### `DEPLOYMENT_MODE`
5965

6066
* **Description**: Specifies the deployment mode for the UI.
61-
* **Default Value**: `standalone` (in dev mode) / `integrated` (in production mode)
62-
* **Possible Values**: `standalone`, `integrated`
67+
* **Default Value**: `standalone`
68+
* **Note**: This variable is used to determine how the UI is built and deployed.
69+
* **Possible Values**: `standalone`, `kubeflow`, `federated`
70+
* **Example**: `DEPLOYMENT_MODE=standalone`
71+
72+
### `STYLE_THEME`
73+
74+
* **Description**: Specifies the theme/styling framework to be used for the UI.
75+
* **Default Value**: `mui-theme`
76+
* **Possible Values**: `mui-theme`, `patternfly-theme`
77+
* **Example**: `STYLE_THEME=mui-theme`
6378

6479
### Example `.env.local` File
6580

clients/ui/bff/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ MOCK_K8S_CLIENT ?= false
33
MOCK_MR_CLIENT ?= false
44
DEV_MODE ?= false
55
DEV_MODE_PORT ?= 8080
6-
STANDALONE_MODE ?= true
6+
DEPLOYMENT_MODE ?= kubeflow
77
AUTH_METHOD ?= internal
88
AUTH_TOKEN_HEADER ?= Authorization
99
AUTH_TOKEN_PREFIX ?= Bearer\
@@ -59,7 +59,7 @@ endif
5959
.PHONY: run
6060
run: fmt vet envtest ## Runs the project.
6161
ENVTEST_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \
62-
go run ./cmd --port=$(PORT) --auth-method=${AUTH_METHOD} --auth-token-header=$(AUTH_TOKEN_HEADER) --auth-token-prefix="$(AUTH_TOKEN_PREFIX)" --static-assets-dir=$(STATIC_ASSETS_DIR) --mock-k8s-client=$(MOCK_K8S_CLIENT) --mock-mr-client=$(MOCK_MR_CLIENT) --dev-mode=$(DEV_MODE) --dev-mode-port=$(DEV_MODE_PORT) --standalone-mode=$(STANDALONE_MODE) --log-level=$(LOG_LEVEL) --allowed-origins=$(ALLOWED_ORIGINS)
62+
go run ./cmd --port=$(PORT) --auth-method=${AUTH_METHOD} --auth-token-header=$(AUTH_TOKEN_HEADER) --auth-token-prefix="$(AUTH_TOKEN_PREFIX)" --static-assets-dir=$(STATIC_ASSETS_DIR) --mock-k8s-client=$(MOCK_K8S_CLIENT) --mock-mr-client=$(MOCK_MR_CLIENT) --dev-mode=$(DEV_MODE) --dev-mode-port=$(DEV_MODE_PORT) --deployment-mode=$(DEPLOYMENT_MODE) --log-level=$(LOG_LEVEL) --allowed-origins=$(ALLOWED_ORIGINS)
6363

6464
##@ Dependencies
6565

clients/ui/bff/cmd/main.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
func main() {
2121
var cfg config.EnvConfig
2222
var certFile, keyFile string
23+
2324
fmt.Println("Starting Model Registry UI BFF!")
2425
flag.IntVar(&cfg.Port, "port", getEnvAsInt("PORT", 8080), "API server port")
2526
flag.StringVar(&certFile, "cert-file", "", "Path to TLS certificate file")
@@ -28,15 +29,34 @@ func main() {
2829
flag.BoolVar(&cfg.MockMRClient, "mock-mr-client", false, "Use mock Model Registry client")
2930
flag.BoolVar(&cfg.DevMode, "dev-mode", false, "Use development mode for access to local K8s cluster")
3031
flag.IntVar(&cfg.DevModePort, "dev-mode-port", getEnvAsInt("DEV_MODE_PORT", 8080), "Use port when in development mode")
31-
flag.BoolVar(&cfg.StandaloneMode, "standalone-mode", false, "Use standalone mode for enabling endpoints in standalone mode")
32+
33+
// New deployment mode flag
34+
flag.Var(&cfg.DeploymentMode, "deployment-mode", "Deployment mode (kubeflow, federated, or standalone)")
35+
3236
flag.StringVar(&cfg.StaticAssetsDir, "static-assets-dir", "./static", "Configure frontend static assets root directory")
3337
flag.TextVar(&cfg.LogLevel, "log-level", parseLevel(getEnvAsString("LOG_LEVEL", "INFO")), "Sets server log level, possible values: error, warn, info, debug")
3438
flag.Func("allowed-origins", "Sets allowed origins for CORS purposes, accepts a comma separated list of origins or * to allow all, default none", newOriginParser(&cfg.AllowedOrigins, getEnvAsString("ALLOWED_ORIGINS", "")))
3539
flag.StringVar(&cfg.AuthMethod, "auth-method", "internal", "Authentication method (internal or user_token)")
3640
flag.StringVar(&cfg.AuthTokenHeader, "auth-token-header", getEnvAsString("AUTH_TOKEN_HEADER", config.DefaultAuthTokenHeader), "Header used to extract the token (e.g., Authorization)")
3741
flag.StringVar(&cfg.AuthTokenPrefix, "auth-token-prefix", getEnvAsString("AUTH_TOKEN_PREFIX", config.DefaultAuthTokenPrefix), "Prefix used in the token header (e.g., 'Bearer ')")
42+
43+
// Deprecated flags - kept for backward compatibility
44+
flag.BoolVar(&cfg.StandaloneMode, "standalone-mode", false, "DEPRECATED: Use -deployment-mode=standalone instead")
45+
flag.BoolVar(&cfg.FederatedPlatform, "federated-platform", false, "DEPRECATED: Use -deployment-mode=federated instead")
46+
3847
flag.Parse()
3948

49+
// Handle backward compatibility: if old flags are used, override deployment mode
50+
if cfg.StandaloneMode {
51+
cfg.DeploymentMode = config.DeploymentModeStandalone
52+
} else if cfg.FederatedPlatform {
53+
cfg.DeploymentMode = config.DeploymentModeFederated
54+
}
55+
56+
// Ensure the deprecated boolean fields are consistent with the new deployment mode
57+
cfg.StandaloneMode = cfg.DeploymentMode.IsStandaloneMode()
58+
cfg.FederatedPlatform = cfg.DeploymentMode.IsFederatedMode()
59+
4060
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
4161
Level: cfg.LogLevel,
4262
}))

clients/ui/bff/internal/api/app.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,10 @@ func (app *App) Routes() http.Handler {
161161
apiRouter.GET(UserPath, app.UserHandler)
162162
apiRouter.GET(ModelRegistryListPath, app.AttachNamespace(app.RequireListServiceAccessInNamespace(app.GetAllModelRegistriesHandler)))
163163

164-
// Standalone "only" routes
165-
if app.config.StandaloneMode {
164+
// Enable these routes in all cases except Kubeflow integration mode
165+
// (Kubeflow integration mode is when DeploymentMode is kubeflow)
166+
isKubeflowIntegrationMode := app.config.DeploymentMode.IsKubeflowMode()
167+
if !isKubeflowIntegrationMode {
166168
// This namespace endpoint is used on standalone mode to simulate
167169
// Kubeflow Central Dashboard namespace selector dropdown on our standalone web app
168170
apiRouter.GET(NamespaceListPath, app.GetNamespacesHandler)

0 commit comments

Comments
 (0)