diff --git a/Makefile b/Makefile index 737cbb136..8e4e69367 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,9 @@ TEST_IMAGE_FOLDERS := autocalibration controller manager mapping cluster_analyti TEST_IMAGES := $(addsuffix -test, camcalibration controller manager mapping cluster_analytics) DEPLOYMENT_TEST ?= 0 +# Kubernetes demo variables +DEMO_K8S_MODE ?= core + # Observability variables CONTROLLER_ENABLE_METRICS ?= false CONTROLLER_METRICS_ENDPOINT ?= otel-collector.scenescape.intel.com:4317 @@ -68,6 +71,9 @@ build-core: init-secrets build-core-images install-models .PHONY: build-all build-all: init-secrets build-all-images install-models +.PHONY: build-experimental +build-experimental: build-experimental-images + # ============================== Help ================================ .PHONY: help @@ -78,8 +84,10 @@ help: @echo "Available targets:" @echo " build-core (default) Build secrets, core images (excluding mapping and cluster_analytics), and install models" @echo " build-all Build secrets, all images, and install models" + @echo " build-experimental Build experimental images only (mapping and cluster_analytics)" @echo " build-core-images Build core microservice images (excluding mapping and cluster_analytics) in parallel" @echo " build-all-images Build all microservice images in parallel" + @echo " build-experimental-images Build experimental microservice images (mapping and cluster_analytics) in parallel" @echo " init-secrets Generate secrets and certificates" @echo " Build a specific microservice image (autocalibration, controller, etc.)" @echo "" @@ -87,7 +95,7 @@ help: @echo " demo-all Start the SceneScape demo with all services using Docker Compose" @echo " (the demo targets require the SUPASS environment variable to be set" @echo " as the super user password for logging into Intel® SceneScape)" - @echo " demo-k8s Start the SceneScape demo using Kubernetes" + @echo " demo-k8s Start the SceneScape demo using Kubernetes (DEMO_K8S_MODE=core|all, default: core)" @echo "" @echo " list-dependencies List all apt/pip dependencies for all microservices" @echo " build-sources-image Build the image with 3rd party sources" @@ -133,7 +141,7 @@ help: @echo "" @echo "Usage:" @echo " - Use 'SUPASS= make build-all demo' to build Intel® SceneScape and run demo using Docker Compose." - @echo " - Use 'make build-all demo-k8s' to build Intel® SceneScape and run demo using Kubernetes." + @echo " - Use 'make build-all demo-k8s DEMO_K8S_MODE=all' to build Intel® SceneScape and run demo using Kubernetes with all services." @echo "" @echo "Tips:" @echo " - Use 'make BUILD_DIR=' to change build output folder (default is './build')." @@ -199,11 +207,6 @@ endef build-all-images: $(BUILD_DIR) $(call parallel-build, $(IMAGE_FOLDERS)) -# Parallel wrapper for core images (excluding mapping and cluster_analytics) -.PHONY: build-core-images -build-core-images: $(BUILD_DIR) - $(call parallel-build, $(CORE_IMAGE_FOLDERS)) - # Parallel wrapper for core images (excluding mapping and cluster_analytics) .PHONY: build-core-images build-core-images: $(BUILD_DIR) @@ -213,6 +216,14 @@ build-core-images: $(BUILD_DIR) $(MAKE) -j$(JOBS) $(CORE_IMAGE_FOLDERS) @echo "DONE ==> Parallel builds of core folders: $(CORE_IMAGE_FOLDERS)" +# Parallel wrapper for experimental images (mapping and cluster_analytics) +.PHONY: build-experimental-images +build-experimental-images: $(BUILD_DIR) + @echo "==> Running parallel builds of experimental folders: mapping cluster_analytics" + @set -e; trap 'grep --color=auto -i -r --include="*.log" "^error" $(BUILD_DIR) || true' EXIT; \ + $(MAKE) -j$(JOBS) mapping cluster_analytics + @echo "DONE ==> Parallel builds of experimental folders: mapping cluster_analytics" + # ===================== Cleaning and Rebuilding ======================= .PHONY: rebuild-core-images rebuild-core-images: clean-core-images build-core-images @@ -575,7 +586,7 @@ demo-all: build-all init-sample-data .PHONY: demo-k8s demo-k8s: - $(MAKE) -C kubernetes DEPLOYMENT_TEST=$(DEPLOYMENT_TEST) + $(MAKE) -C kubernetes DEPLOYMENT_TEST=$(DEPLOYMENT_TEST) DEMO_K8S_MODE=$(DEMO_K8S_MODE) .PHONY: docker-compose.yml docker-compose.yml: diff --git a/kubernetes/Makefile b/kubernetes/Makefile index b79d83169..627479d88 100644 --- a/kubernetes/Makefile +++ b/kubernetes/Makefile @@ -4,8 +4,13 @@ MANAGERIMAGE=scenescape-manager CAMCALIBIMAGE=scenescape-camcalibration CONTROLLERIMAGE=scenescape-controller -# optional image for cluster analytics component CLUSTERANALYTICSIMAGE=scenescape-cluster-analytics +MAPPINGIMAGE=scenescape-mapping + +# Image groupings for flexible builds +CORE_IMAGES=$(MANAGERIMAGE) $(CAMCALIBIMAGE) $(CONTROLLERIMAGE) +EXPERIMENTAL_IMAGES=$(CLUSTERANALYTICSIMAGE) $(MAPPINGIMAGE) +ALL_IMAGES=$(CORE_IMAGES) $(EXPERIMENTAL_IMAGES) VERSION:=$(shell cat ../version.txt) NAMESPACE=scenescape @@ -38,18 +43,36 @@ RELEASE=scenescape-release-1 FORCE_VAAPI?=0 CHART_DEBUG?=0 +# Demo mode variable for Kubernetes deployments (core or all) +DEMO_K8S_MODE?=core + # Proxy settings: if http_proxy, https_proxy, or no_proxy environment variables are set, # they will be automatically passed to the Helm chart during installation # Chart debug: set CHART_DEBUG=1 to enable chartdebug=true in Helm deployment # start kind, then install SceneScape with helm -default: install-deps clean-kind kind build-all install +default: install-deps clean-kind kind build-demo install + +# Helper target to select build based on DEMO_K8S_MODE +.PHONY: build-demo +build-demo: + @if [ "$(DEMO_K8S_MODE)" = "all" ]; then \ + $(MAKE) build-all; \ + else \ + $(MAKE) build-core; \ + fi # publish to ITEP by building, packaging, then pushing -build-and-package: build-all package +build-and-package: build-core package # build scenescape images and push everything to a registry, then generate Chart.yaml -build-all: build push +build: build-core + +build-core: docker-build-core push-core + +build-all: build-core build-experimental + +build-experimental: docker-build-experimental push-experimental kind: generate-kind-yaml start-kind install-cert-manager @@ -135,10 +158,13 @@ install-cert-manager: # build scenescape docker images, download models for init-models # note, will make unneeded secrets in secrets/ as well -build: +docker-build-core: make -C .. CERTPASS=$(CERTPASS) FORCE_VAAPI=$(FORCE_VAAPI) -push: +docker-build-experimental: + make -C .. build-experimental CERTPASS=$(CERTPASS) FORCE_VAAPI=$(FORCE_VAAPI) + +push-core: docker tag $(MANAGERIMAGE):$(VERSION) $(REGISTRY)/$(ORGANIZATION)/$(MANAGERIMAGE):$(VERSION) docker push $(REGISTRY)/$(ORGANIZATION)/$(MANAGERIMAGE):$(VERSION) docker tag $(CAMCALIBIMAGE):$(VERSION) $(REGISTRY)/$(ORGANIZATION)/$(CAMCALIBIMAGE):$(VERSION) @@ -146,9 +172,14 @@ push: docker tag $(CONTROLLERIMAGE):$(VERSION) $(REGISTRY)/$(ORGANIZATION)/$(CONTROLLERIMAGE):$(VERSION) docker push $(REGISTRY)/$(ORGANIZATION)/$(CONTROLLERIMAGE):$(VERSION) -push-all: push +push-experimental: + # optional images for cluster analytics and mapping components docker tag $(CLUSTERANALYTICSIMAGE):$(VERSION) $(REGISTRY)/$(ORGANIZATION)/$(CLUSTERANALYTICSIMAGE):$(VERSION) docker push $(REGISTRY)/$(ORGANIZATION)/$(CLUSTERANALYTICSIMAGE):$(VERSION) + docker tag $(MAPPINGIMAGE):$(VERSION) $(REGISTRY)/$(ORGANIZATION)/$(MAPPINGIMAGE):$(VERSION) + docker push $(REGISTRY)/$(ORGANIZATION)/$(MAPPINGIMAGE):$(VERSION) + +push-all: push-core push-experimental # generate Chart.yaml with appropriate version.txt chart.yaml: @@ -211,8 +242,12 @@ install: copy-files if [ "$(DEPLOYMENT_TEST)" = "1" ]; then \ docker system prune --all --force --volumes; \ fi; \ + MODE_ARG=""; \ + if [ "$(DEMO_K8S_MODE)" = "all" ]; then \ + MODE_ARG="--set mapping.enabled=true --set clusterAnalytics.enabled=true"; \ + fi; \ REPOSITORY_ARG="--set repository=$(REGISTRY)"; \ - helm upgrade $(RELEASE) --install scenescape-chart/ -n $(NAMESPACE) --create-namespace --timeout $(INSTALL_TIMEOUT) $${DEBUG_ARGS} $${REPOSITORY_ARG} $${SUPASS_ARG} $${PGPASS_ARG} $${VALUES_FILE} $(VALIDATION_FLAG) $(TEST_FLAGS); + helm upgrade $(RELEASE) --install scenescape-chart/ -n $(NAMESPACE) --create-namespace --timeout $(INSTALL_TIMEOUT) $${DEBUG_ARGS} $${REPOSITORY_ARG} $${SUPASS_ARG} $${PGPASS_ARG} $${MODE_ARG} $${VALUES_FILE} $(VALIDATION_FLAG) $(TEST_FLAGS); @if [ -f "/tmp/scenescape-proxy-values.yaml" ]; then \ rm -f /tmp/scenescape-proxy-values.yaml; \ fi @@ -233,7 +268,28 @@ wait-for-ready: # below targets work if registry and kind are already running # building and reinstalling (during development) -rebuild: uninstall delete-namespace build-all-tests install +rebuild: rebuild-demo + +rebuild-demo: + @if [ "$(DEMO_K8S_MODE)" = "all" ]; then \ + $(MAKE) rebuild-all; \ + else \ + $(MAKE) rebuild-core; \ + fi + +rebuild-core: uninstall delete-namespace build-core install + +rebuild-all: uninstall delete-namespace build-all install + +build-validation: build-validation-demo + +build-validation-demo: + @if [ "$(DEMO_K8S_MODE)" = "all" ]; then \ + $(MAKE) build-validation-all; \ + else \ + $(MAKE) build-validation-core; \ + fi + +build-validation-core: delete-namespace build-core install wait-for-ready -# validation build (blocks until scenescape is ready) -build-validation: delete-namespace build-all-tests install wait-for-ready +build-validation-all: delete-namespace build-all install wait-for-ready diff --git a/kubernetes/scenescape-chart/templates/_helpers.tpl b/kubernetes/scenescape-chart/templates/_helpers.tpl index cc0934e39..124384cac 100644 --- a/kubernetes/scenescape-chart/templates/_helpers.tpl +++ b/kubernetes/scenescape-chart/templates/_helpers.tpl @@ -55,6 +55,13 @@ path: scenescape-camcalibration.key - key: tls.crt path: scenescape-camcalibration.crt + - secret: + name: {{ .Release.Name }}-mapping-tls + items: + - key: tls.key + path: scenescape-mapping.key + - key: tls.crt + path: scenescape-mapping.crt - secret: name: {{ .Release.Name }}-scenescape-ca.pem items: diff --git a/kubernetes/scenescape-chart/templates/cluster-analytics/deployment.yaml b/kubernetes/scenescape-chart/templates/cluster-analytics/deployment.yaml index 1b4870084..f4a3a1afb 100644 --- a/kubernetes/scenescape-chart/templates/cluster-analytics/deployment.yaml +++ b/kubernetes/scenescape-chart/templates/cluster-analytics/deployment.yaml @@ -26,7 +26,7 @@ spec: containers: - name: cluster-analytics image: {{ .Values.repository }}/{{ .Values.clusterAnalytics.image }}:{{ .Chart.AppVersion }} - pullPolicy: {{ .Values.clusterAnalytics.pullPolicy }} + imagePullPolicy: {{ .Values.clusterAnalytics.pullPolicy }} args: - "--broker" - "broker.{{ .Release.Namespace }}.svc.cluster.local" diff --git a/kubernetes/scenescape-chart/templates/mapping/certificate.yaml b/kubernetes/scenescape-chart/templates/mapping/certificate.yaml new file mode 100644 index 000000000..60f90225f --- /dev/null +++ b/kubernetes/scenescape-chart/templates/mapping/certificate.yaml @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ .Release.Name }}-mapping-cert +spec: + secretName: {{ .Release.Name }}-mapping-tls + issuerRef: + name: {{ .Release.Name }}-ca-issuer + kind: Issuer + commonName: "mapping.scenescape.intel.com" + dnsNames: + - "mapping.scenescape.intel.com" + - "mapping" + - "mapping.{{ .Release.Namespace }}" + - "mapping.{{ .Release.Namespace }}.svc.cluster.local" + duration: 8760h + renewBefore: 720h diff --git a/kubernetes/scenescape-chart/templates/mapping/deployment.yaml b/kubernetes/scenescape-chart/templates/mapping/deployment.yaml new file mode 100644 index 000000000..84e8524c1 --- /dev/null +++ b/kubernetes/scenescape-chart/templates/mapping/deployment.yaml @@ -0,0 +1,84 @@ +# SPDX-FileCopyrightText: (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +--- +{{- if .Values.mapping.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-mapping + labels: + app: {{ .Release.Name }}-mapping +spec: + replicas: 1 + selector: + matchLabels: + app: {{ .Release.Name }}-mapping + template: + metadata: + labels: + app: {{ .Release.Name }}-mapping + spec: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + containers: + - name: mapping + image: {{ .Values.repository }}/{{ .Values.mapping.image }}:{{ .Chart.AppVersion }} + imagePullPolicy: {{ .Values.mapping.pullPolicy }} + env: + - name: PYTHONDONTWRITEBYTECODE + value: "1" + {{ include "proxy_envs" . | indent 10 }} + ports: + - containerPort: 8444 + securityContext: + {{ include "defaultContainerSecurityContext" . | indent 12 }} + runAsUser: 1000 + runAsGroup: 1000 + readinessProbe: + exec: + command: + - sh + - -c + - curl -k -s https://localhost:8444/health + periodSeconds: 10 + timeoutSeconds: 60 + failureThreshold: 5 + initialDelaySeconds: 10 + volumeMounts: + - mountPath: /run/secrets/certs/scenescape-ca.pem + subPath: scenescape-ca.pem + name: certs + readOnly: true + - mountPath: /run/secrets/certs/scenescape-mapping.crt + subPath: scenescape-mapping.crt + name: certs + readOnly: true + - mountPath: /run/secrets/certs/scenescape-mapping.key + subPath: scenescape-mapping.key + name: certs + readOnly: true + - mountPath: /tmp + name: model-storage + - mountPath: /workspace/.cache/huggingface + name: huggingface-cache + - mountPath: /workspace/.cache/torch + name: torch-cache + - mountPath: /workspace/model_weights + name: model-weights + volumes: + {{- include "certs_volume" . | nindent 8 }} + - name: model-storage + emptyDir: + sizeLimit: "1Gi" + - name: huggingface-cache + emptyDir: + sizeLimit: "5Gi" + - name: torch-cache + emptyDir: + sizeLimit: "2Gi" + - name: model-weights + emptyDir: + sizeLimit: "1Gi" +{{- end }} diff --git a/kubernetes/scenescape-chart/templates/mapping/service.yaml b/kubernetes/scenescape-chart/templates/mapping/service.yaml new file mode 100644 index 000000000..03ffb9186 --- /dev/null +++ b/kubernetes/scenescape-chart/templates/mapping/service.yaml @@ -0,0 +1,40 @@ +# SPDX-FileCopyrightText: (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +--- +{{- if .Values.mapping.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: mapping + annotations: {{- toYaml .Values.service.annotations | nindent 4 }} +spec: + selector: + app: {{ .Release.Name }}-mapping + ports: + - name: "8444" + protocol: TCP + port: 8444 + targetPort: 8444 +{{- if .Values.loadBalancer.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: mapping-lb + annotations: {{- toYaml .Values.loadBalancer.annotations | nindent 4 }} +spec: + type: LoadBalancer + selector: + app: {{ .Release.Name }}-mapping + ports: + - name: "8444" + protocol: TCP + port: 8444 + targetPort: 8444 + externalTrafficPolicy: {{ .Values.loadBalancer.externalTrafficPolicy }} + {{- if (default .Values.loadBalancer.loadBalancerIP false) }} + loadBalancerIP: {{ .Values.loadBalancer.loadBalancerIP }} + {{- end }} +{{- end }} +{{- end }} diff --git a/kubernetes/scenescape-chart/templates/web-app/deployment.yaml b/kubernetes/scenescape-chart/templates/web-app/deployment.yaml index 79a442a11..95be062d4 100644 --- a/kubernetes/scenescape-chart/templates/web-app/deployment.yaml +++ b/kubernetes/scenescape-chart/templates/web-app/deployment.yaml @@ -66,6 +66,10 @@ spec: - --camcalibration - camcalibration.{{ .Release.Namespace }}.svc.cluster.local:8443 env: + {{- if .Values.mapping.enabled }} + - name: MAPPING_SERVICE_URL + value: https://mapping.{{ .Release.Namespace }}.svc.cluster.local:8444 + {{- end }} - name: WEBSERVER_URL value: https://web.scenescape.svc.cluster.local - name: MODEL_CONFIGS_FOLDER diff --git a/kubernetes/scenescape-chart/values.yaml b/kubernetes/scenescape-chart/values.yaml index cad951ee0..e597141d1 100644 --- a/kubernetes/scenescape-chart/values.yaml +++ b/kubernetes/scenescape-chart/values.yaml @@ -132,6 +132,11 @@ clusterAnalytics: webUI: enabled: false +mapping: + enabled: false + image: intel/scenescape-mapping + pullPolicy: IfNotPresent + # Used as init container in some deployments to wait for dependent services busyboxImage: repository: docker.io