Unverified Commit 8b1f2ded authored by julienmancuso's avatar julienmancuso Committed by GitHub
Browse files

fix: add steps to install using published helm charts (#1623)

parent 9f2f95af
......@@ -14,10 +14,6 @@
# limitations under the License.
dynamo-operator:
natsAddr: "nats://${RELEASE_NAME}-nats:4222"
etcdAddr: "${RELEASE_NAME}-etcd:2379"
namespaceRestriction:
targetNamespace: ${NAMESPACE}
controllerManager:
manager:
image:
......@@ -28,28 +24,20 @@ dynamo-operator:
dynamo:
enableLWS: ${ENABLE_LWS}
apiStore:
endpoint: http://${RELEASE_NAME}-dynamo-api-store
ingress:
enabled: ${INGRESS_ENABLED}
className: ${INGRESS_CLASS}
tlsSecretName: my-tls-secret
istio:
enabled: ${ISTIO_ENABLED}
gateway: ${ISTIO_GATEWAY}
ingressHostSuffix: ${DYNAMO_INGRESS_SUFFIX}
dockerRegistry:
useKubernetesSecret: true
server: ${PIPELINES_DOCKER_SERVER}
username: ${PIPELINES_DOCKER_USERNAME}
password: ${PIPELINES_DOCKER_PASSWORD}
imageBuildEngine: buildkit
virtualServiceSupportsHTTPS: ${VIRTUAL_SERVICE_SUPPORTS_HTTPS}
dynamo-api-store:
namespaceRestriction:
enabled: true
targetNamespace: ${NAMESPACE}
istio:
enabled: ${ISTIO_ENABLED}
gateway: ${ISTIO_GATEWAY}
......@@ -57,7 +45,6 @@ dynamo-api-store:
image:
repository: ${DOCKER_SERVER}/dynamo-api-store
tag: ${IMAGE_TAG}
pullPolicy: IfNotPresent
imagePullSecrets:
- name: ${DOCKER_SECRET_NAME}
ingress:
......@@ -68,28 +55,3 @@ dynamo-api-store:
paths:
- path: /
pathType: Prefix
postgresql:
enabled: true
minio:
enabled: true
etcd:
enabled: true
persistence:
enabled: true
storageClass: ""
size: 1Gi
preUpgrade:
enabled: false
nats:
enabled: true
config:
jetstream:
enabled: true
fileStore:
pvc:
size: 1Gi
storageClassName: ""
......@@ -21,7 +21,7 @@ kind: ClusterRole
metadata:
name: {{ include "helm.fullname" . }}-role
{{- if .Values.namespaceRestriction.enabled }}
namespace: {{ .Values.namespaceRestriction.targetNamespace }}
namespace: {{ default .Release.Namespace .Values.namespaceRestriction.targetNamespace }}
{{- end }}
rules:
- apiGroups: [""]
......@@ -49,7 +49,7 @@ kind: ClusterRoleBinding
metadata:
name: {{ include "helm.fullname" . }}-role-binding
{{- if .Values.namespaceRestriction.enabled }}
namespace: {{ .Values.namespaceRestriction.targetNamespace }}
namespace: {{ default .Release.Namespace .Values.namespaceRestriction.targetNamespace }}
{{- end }}
subjects:
- kind: ServiceAccount
......
......@@ -82,51 +82,29 @@ Create the name of the service account to use
{{/*
Generate docker config json for registry credentials
Supports both direct credentials and existing secrets
*/}}
{{- define "dynamo-operator.dockerconfig" -}}
{{- $server := .Values.dynamo.dockerRegistry.server -}}
{{- $server := required "docker registry server is required" .Values.dynamo.dockerRegistry.server -}}
{{- if or (eq $server "docker.io") (hasPrefix "docker.io/" $server) -}}
{{- $server = "https://index.docker.io/v1/" -}}
{{- end -}}
{{- $username := .Values.dynamo.dockerRegistry.username -}}
{{- $password := .Values.dynamo.dockerRegistry.password -}}
{{- if .Values.dynamo.dockerRegistry.passwordExistingSecretName -}}
{{- $secretName := .Values.dynamo.dockerRegistry.passwordExistingSecretName -}}
{{- $secretKey := .Values.dynamo.dockerRegistry.passwordExistingSecretKey -}}
{{- $dockerconfigjson := lookup "v1" "Secret" .Release.Namespace $secretName }}
{{- if $dockerconfigjson -}}
{{- if eq $dockerconfigjson.type "kubernetes.io/dockerconfigjson" -}}
{{/* If the secret is already of type kubernetes.io/dockerconfigjson, use its .dockerconfigjson value directly */}}
{{- index $dockerconfigjson.data ".dockerconfigjson" | b64dec }}
{{- else -}}
{{/* If the secret is not of the correct type, extract password from the secret and build a new one */}}
{{- $password = index $dockerconfigjson.data $secretKey | b64dec }}
{
"auths": {
"{{ $server }}": {
"username": "{{ $username }}",
"password": "{{ $password }}",
"auth": "{{ printf "%s:%s" $username $password | b64enc }}"
}
}
}
{{- end -}}
{{- else -}}
{{/* If no secret is found, use the default password */}}
{{- $password = .Values.dynamo.dockerRegistry.password }}
{
"auths": {
"{{ $server }}": {
"username": "{{ $username }}",
"password": "{{ $password }}",
"auth": "{{ printf "%s:%s" $username $password | b64enc }}"
}
}
}
{{- if .Values.dynamo.dockerRegistry.existingSecretName -}}
{{/* Use existing secret */}}
{{- $secretName := .Values.dynamo.dockerRegistry.existingSecretName -}}
{{- $secret := lookup "v1" "Secret" .Release.Namespace $secretName -}}
{{- if not $secret -}}
{{- fail (printf "Secret %s not found in namespace %s" $secretName .Release.Namespace) -}}
{{- end -}}
{{- if ne $secret.type "kubernetes.io/dockerconfigjson" -}}
{{- fail (printf "Secret %s in namespace %s is not of type kubernetes.io/dockerconfigjson" $secretName .Release.Namespace) -}}
{{- end -}}
{{- index $secret.data ".dockerconfigjson" | b64dec -}}
{{- else -}}
{{/* Build a new dockerconfigjson if passwordExistingSecretName is not set */}}
{{/* Use direct credentials */}}
{{- $username := required "docker registry username is required when not using existing secret" .Values.dynamo.dockerRegistry.username -}}
{{- $password := required "docker registry password is required when not using existing secret" .Values.dynamo.dockerRegistry.password -}}
{
"auths": {
"{{ $server }}": {
......@@ -137,4 +115,39 @@ Generate docker config json for registry credentials
}
}
{{- end -}}
{{- end -}}
{{/*
Validate docker config secret has auth for server (extracted from full repository path)
Usage:
{{ include "dynamo-operator.validateDockerConfigSecret" (dict "secretName" "my-secret" "namespace" .Release.Namespace "repository" "myserver.com/myrepo") }}
Returns: Error if invalid or missing auth, empty string if valid
*/}}
{{- define "dynamo-operator.validateDockerConfigSecret" -}}
{{- $server := regexSplit "/" .repository 2 | first -}}
{{- $secret := lookup "v1" "Secret" .namespace .secretName -}}
{{- if not $secret -}}
{{- fail (printf "Secret %s not found in namespace %s" .secretName .namespace) -}}
{{- end -}}
{{- if ne $secret.type "kubernetes.io/dockerconfigjson" -}}
{{- fail (printf "Secret %s in namespace %s is not of type kubernetes.io/dockerconfigjson" .secretName .namespace) -}}
{{- end -}}
{{- $dockerConfig := index $secret.data ".dockerconfigjson" | b64dec | fromJson -}}
{{- if not (hasKey $dockerConfig "auths") -}}
{{- fail (printf "Secret %s in namespace %s does not contain auths field" .secretName .namespace) -}}
{{- end -}}
{{- if not (hasKey $dockerConfig.auths $server) -}}
{{- fail (printf "Secret %s in namespace %s does not contain auth for server %s (extracted from %s)" .secretName .namespace $server .repository) -}}
{{- end -}}
{{- end -}}
{{/*
Retrieve components docker registry secret name
*/}}
{{- define "dynamo-operator.componentsDockerRegistrySecretName" -}}
{{- if .Values.dynamo.dockerRegistry.existingSecretName -}}
{{- .Values.dynamo.dockerRegistry.existingSecretName -}}
{{- else -}}
{{- printf "%s-regcred" (include "dynamo-operator.fullname" .) -}}
{{- end -}}
{{- end -}}
\ No newline at end of file
......@@ -26,5 +26,5 @@ metadata:
{{- toYaml .Values.dynamo.components.serviceAccount.annotations | nindent 4 }}
{{- if .Values.dynamo.dockerRegistry.useKubernetesSecret }}
imagePullSecrets:
- name: dynamo-regcred
- name: {{ include "dynamo-operator.componentsDockerRegistrySecretName" . }}
{{- end }}
......@@ -72,9 +72,13 @@ spec:
{{- end }}
{{- if .Values.natsAddr }}
- --natsAddr={{ .Values.natsAddr }}
{{- else }}
- --natsAddr=nats://{{ .Release.Name }}-nats:4222
{{- end }}
{{- if .Values.etcdAddr }}
- --etcdAddr={{ .Values.etcdAddr }}
{{- else }}
- --etcdAddr={{ .Release.Name }}-etcd:2379
{{- end }}
{{- if and .Values.dynamo.istio.enabled .Values.dynamo.istio.gateway }}
- --istio-virtual-service-gateway={{ .Values.dynamo.istio.gateway }}
......@@ -135,7 +139,7 @@ spec:
volumes:
- name: docker-config
secret:
secretName: dynamo-regcred
secretName: {{ include "dynamo-operator.componentsDockerRegistrySecretName" . }}
items:
- key: .dockerconfigjson
path: config.json
......
......@@ -20,7 +20,7 @@ metadata:
namespace: {{ .Values.namespace }}
{{- if .Values.dynamo.dockerRegistry.useKubernetesSecret }}
imagePullSecrets:
- name: dynamo-regcred
- name: {{ include "dynamo-operator.componentsDockerRegistrySecretName" . }}
{{- end }}
---
apiVersion: rbac.authorization.k8s.io/v1
......
......@@ -21,7 +21,7 @@ kind: ClusterRole
metadata:
name: {{ include "dynamo-operator.fullname" . }}-proxy-role
{{- if .Values.namespaceRestriction.enabled }}
namespace: {{ .Values.namespaceRestriction.targetNamespace }}
namespace: {{ default .Release.Namespace .Values.namespaceRestriction.targetNamespace }}
{{- end }}
labels:
app.kubernetes.io/component: kube-rbac-proxy
......@@ -51,7 +51,7 @@ kind: ClusterRoleBinding
metadata:
name: {{ include "dynamo-operator.fullname" . }}-proxy-rolebinding
{{- if .Values.namespaceRestriction.enabled }}
namespace: {{ .Values.namespaceRestriction.targetNamespace }}
namespace: {{ default .Release.Namespace .Values.namespaceRestriction.targetNamespace }}
{{- end }}
labels:
app.kubernetes.io/component: kube-rbac-proxy
......
......@@ -13,13 +13,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
{{- if .Values.dynamo.dockerRegistry.useKubernetesSecret }}
{{- /* if we need to use a kubernetes secret to authenticate with the components docker registry */}}
{{- if .Values.dynamo.dockerRegistry.existingSecretName }}
{{- /* if we re-use an existing secret to authenticate with the components docker registry, let's validate it */}}
{{- include "dynamo-operator.validateDockerConfigSecret" (dict "secretName" .Values.dynamo.dockerRegistry.existingSecretName "namespace" .Release.Namespace "repository" .Values.dynamo.dockerRegistry.server) }}
{{- else }}
{{- /* otherwise, we need to create a new secret to authenticate with the components docker registry */}}
---
apiVersion: v1
kind: Secret
metadata:
name: dynamo-regcred
name: {{ include "dynamo-operator.componentsDockerRegistrySecretName" . }}
labels:
{{- include "dynamo-operator.labels" . | nindent 4 }}
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ include "dynamo-operator.dockerconfig" . | b64enc }}
{{- end }}
\ No newline at end of file
{{- end }}
{{- end }}
......@@ -21,7 +21,11 @@ metadata:
{{- include "dynamo-operator.labels" . | nindent 4 }}
type: Opaque
stringData:
{{- if .Values.dynamo.apiStore.endpoint }}
API_STORE_ENDPOINT : {{ .Values.dynamo.apiStore.endpoint | quote }}
{{- else }}
API_STORE_ENDPOINT : http://{{ .Release.Name }}-dynamo-api-store
{{- end }}
API_STORE_CLUSTER_NAME: {{ .Values.dynamo.apiStore.clusterName | quote }}
DYNAMO_SYSTEM_NAMESPACE: {{ .Release.Namespace }}
DYNAMO_DEPLOYMENT_NAMESPACE: {{ .Release.Namespace }}
......@@ -37,9 +41,9 @@ stringData:
DYNAMO_INGRESS_SUFFIX: {{ .Values.dynamo.dynamoIngressSuffix | quote }}
{{- end }}
DOCKER_REGISTRY_SERVER: {{ .Values.dynamo.dockerRegistry.server | quote }}
DOCKER_REGISTRY_SERVER: {{ required "docker registry server is required" .Values.dynamo.dockerRegistry.server | quote }}
{{- if .Values.dynamo.dockerRegistry.useKubernetesSecret }}
DOCKER_REGISTRY_SECRET_NAME: "dynamo-regcred"
DOCKER_REGISTRY_SECRET_NAME: {{ include "dynamo-operator.componentsDockerRegistrySecretName" . }}
{{- end }}
DOCKER_REGISTRY_SECURE: {{ .Values.dynamo.dockerRegistry.secure | quote }}
DOCKER_REGISTRY_DYNAMO_COMPONENTS_REPOSITORY_NAME: {{ .Values.dynamo.dockerRegistry.dynamoComponentsRepositoryName | quote }}
......
......@@ -95,14 +95,13 @@ dynamo:
enableRestrictedSecurityContext: false
dockerRegistry:
server: 'nvcr.io/nvidian/nim-llm-dev'
server: ''
# set to true if you want to use the kubernetes secret for the registry credentials
# if false, no secret will be created and used. Allows to use cloud provider mechanisms for authentication (e.g. Workload Identity for GKE, ...)
useKubernetesSecret: false
username: '$oauthtoken'
password: ""
passwordExistingSecretName: ''
passwordExistingSecretKey: ''
existingSecretName: ''
secure: true
dynamoComponentsRepositoryName: dynamo-pipelines
......
......@@ -21,19 +21,21 @@ dynamo-operator:
etcdAddr: ""
namespaceRestriction:
enabled: true
targetNamespace: ""
targetNamespace:
controllerManager:
manager:
image:
repository: ""
tag: "latest"
pullPolicy: IfNotPresent
args:
- --health-probe-bind-address=:8081
- --metrics-bind-address=127.0.0.1:8080
imagePullSecrets: []
dynamo:
enableLWS: false
apiStore:
endpoint: http://dynamo-store
endpoint:
clusterName: default
internalImages:
dynamoComponentsDownloader: rapidfort/curl:latest
......@@ -43,10 +45,11 @@ dynamo-operator:
debugger: python:3.12-slim
enableRestrictedSecurityContext: false
dockerRegistry:
useKubernetesSecret: false
server: ""
username: ""
password: ""
useKubernetesSecret: true
server:
username:
password:
existingSecretName:
secure: true
dynamoComponentsRepositoryName: dynamo-pipelines
imageBuildEngine: buildkit
......@@ -56,12 +59,21 @@ dynamo-operator:
kaniko:
cacheRepo: ""
snapshotMode: ""
ingress:
enabled: false
className:
tlsSecretName: my-tls-secret
istio:
enabled: false
gateway:
ingressHostSuffix: ""
virtualServiceSupportsHTTPS: false
dynamo-api-store:
enabled: true
namespaceRestriction:
enabled: true
targetNamespace: ""
targetNamespace:
istio:
enabled: false
host: ""
......@@ -73,6 +85,7 @@ dynamo-api-store:
repository: ""
tag: "latest"
pullPolicy: IfNotPresent
imagePullSecrets: []
ingress:
enabled: false
className: nginx
......@@ -88,7 +101,7 @@ dynamo-api-store:
## @param minio.apiIngress.ingressClassName IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+)
## @param minio.apiIngress.hostname Default host for the ingress resource
minio:
enabled: false
enabled: true
mode: standalone
auth:
rootUser: minioadmin
......@@ -96,7 +109,8 @@ minio:
persistence:
enabled: true
size: 10Gi
storageClass: ""
# Use the cluster default storage-class or override with a named class
storageClass: null
mountPath: /data
annotations:
helm.sh/resource-policy: keep
......@@ -134,7 +148,7 @@ minio:
console: 9001
postgresql:
enabled: false
enabled: true
auth:
existingSecret: ""
postgresPassword: ""
......@@ -146,7 +160,14 @@ postgresql:
enabled: false
etcd:
enabled: false
enabled: true
persistence:
enabled: true
# Use the cluster default storage-class or override with a named class
storageClass: null
size: 1Gi
preUpgrade:
enabled: false
replicaCount: 1
# Explicitly remove authentication
auth:
......@@ -160,7 +181,7 @@ etcd:
enabled: false
nats:
enabled: false
enabled: true
# reference a common CA Certificate or Bundle in all nats config `tls` blocks and nats-box contexts
# note: `tls.verify` still must be set in the appropriate nats config `tls` blocks to require mTLS
tlsCA:
......
......@@ -190,3 +190,108 @@ After deploying the Dynamo cloud platform, you can:
3. Manage your deployments using the Dynamo CLI
For more detailed information about deploying inference graphs, see the [Dynamo Deploy Guide](README.md).
### Installation using published helm chart
To install Dynamo Cloud using the published Helm chart, you'll need to configure Docker registry credentials and image settings. The chart supports both direct credential configuration and existing Kubernetes secrets.
#### Configuration Options
You have two options for providing Docker registry credentials:
**Option 1: Direct Credentials** (Simpler for testing)
- Provide username and password directly via Helm values
- Credentials are stored in a Kubernetes secret created by the chart
**Option 2: Existing Secret** (Recommended for production)
- Use an existing Kubernetes secret containing Docker registry credentials
- More secure and follows Kubernetes best practices
#### Environment Setup
Set the required environment variables:
```bash
# Docker registry configuration
export DOCKER_SERVER="your-registry.com" # Docker registry server where images of dynamo cloud services (api-server and operator) are available
export IMAGE_TAG="v1.0.0" # Image tag to deploy
export NAMESPACE="dynamo-cloud" # Target namespace
# Pipeline-specific Docker registry (can be different from DOCKER_SERVER)
export PIPELINES_DOCKER_SERVER="your-pipeline-registry.com" # Registry for pipeline images
# Option 1: Direct credentials
export PIPELINES_DOCKER_USERNAME="your-username"
export PIPELINES_DOCKER_PASSWORD="your-password"
# Option 2: Existing secret (recommended)
export PIPELINES_DOCKER_CREDS_SECRET="my-docker-secret" # Name of existing secret
# Note: If not specified, the chart will look for a secret named "dynamo-regcred"
# Image pull secret for the operator itself
export DOCKER_SECRET_NAME="my-pull-secret" # Secret for pulling images of dynamo cloud services (api-server and operator) operator images
```
you can easily create an image pull secret with the following command :
```bash
kubectl create secret docker-registry ${DOCKER_SECRET_NAME} \
--docker-server=${DOCKER_SERVER} \
--docker-username=${DOCKER_USERNAME} \
--docker-password=${DOCKER_PASSWORD} \
--namespace=${NAMESPACE}
```
#### Installation Commands
**Step 1: Install Custom Resource Definitions (CRDs)**
```bash
helm install dynamo-crds dynamo-crds-helm-chart.tgz \
--namespace default \
--wait \
--atomic
```
**Step 2: Install Dynamo Platform**
Choose one of the following approaches based on your credential configuration:
**Using Direct Credentials:**
```bash
helm install dynamo-platform dynamo-platform-helm-chart.tgz \
--namespace ${NAMESPACE} \
--create-namespace \
--set "dynamo-operator.controllerManager.manager.image.repository=${DOCKER_SERVER}/dynamo-operator" \
--set "dynamo-operator.controllerManager.manager.image.tag=${IMAGE_TAG}" \
--set "dynamo-operator.imagePullSecrets[0].name=${DOCKER_SECRET_NAME}" \
--set "dynamo-operator.dynamo.dockerRegistry.server=${PIPELINES_DOCKER_SERVER:-$DOCKER_SERVER}" \
--set "dynamo-operator.dynamo.dockerRegistry.username=${PIPELINES_DOCKER_USERNAME}" \
--set "dynamo-operator.dynamo.dockerRegistry.password=${PIPELINES_DOCKER_PASSWORD}" \
--set "dynamo-api-store.image.repository=${DOCKER_SERVER}/dynamo-api-store" \
--set "dynamo-api-store.image.tag=${IMAGE_TAG}" \
--set "dynamo-api-store.imagePullSecrets[0].name=${DOCKER_SECRET_NAME}"
```
**Using Existing Secret (Recommended):**
```bash
helm install dynamo-platform dynamo-platform-helm-chart.tgz \
--namespace ${NAMESPACE} \
--create-namespace \
--set "dynamo-operator.controllerManager.manager.image.repository=${DOCKER_SERVER}/dynamo-operator" \
--set "dynamo-operator.controllerManager.manager.image.tag=${IMAGE_TAG}" \
--set "dynamo-operator.imagePullSecrets[0].name=${DOCKER_SECRET_NAME}" \
--set "dynamo-operator.dynamo.dockerRegistry.server=${PIPELINES_DOCKER_SERVER:-$DOCKER_SERVER}" \
--set "dynamo-operator.dynamo.dockerRegistry.existingSecretName=${PIPELINES_DOCKER_CREDS_SECRET:-dynamo-regcred}" \
--set "dynamo-api-store.image.repository=${DOCKER_SERVER}/dynamo-api-store" \
--set "dynamo-api-store.image.tag=${IMAGE_TAG}" \
--set "dynamo-api-store.imagePullSecrets[0].name=${DOCKER_SECRET_NAME}"
```
[!Note]
- If `PIPELINES_DOCKER_SERVER` is not set, it defaults to `DOCKER_SERVER`
- If `PIPELINES_DOCKER_CREDS_SECRET` is not set, the chart will look for a secret named `dynamo-regcred`
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment