From a1ca496e7004e9da48c59af742843bbe12ff3c0c Mon Sep 17 00:00:00 2001 From: chrislu Date: Sat, 6 Dec 2025 11:02:57 -0800 Subject: [PATCH] helm: enhance all-in-one deployment configuration Fixes #7110 This PR addresses multiple issues with the all-in-one Helm chart configuration: ## New Features ### Configurable Replicas - Added `allInOne.replicas` (was hardcoded to 1) ### S3 Gateway Configuration - Added full S3 config under `allInOne.s3`: - port, httpsPort, domainName, allowEmptyFolder - enableAuth, existingConfigSecret, auditLogConfig - createBuckets for declarative bucket creation ### SFTP Server Configuration - Added full SFTP config under `allInOne.sftp`: - port, sshPrivateKey, hostKeysFolder, authMethods - maxAuthTries, bannerMessage, loginGraceTime - clientAliveInterval, clientAliveCountMax, enableAuth ### Command Line Arguments - Added `allInOne.extraArgs` for custom CLI arguments ### Update Strategy - Added `allInOne.updateStrategy.type` (Recreate/RollingUpdate) ### Secret Environment Variables - Added `allInOne.secretExtraEnvironmentVars` for injecting secrets ### Ingress Support - Added `allInOne.ingress` with S3, filer, and master sub-configs ### Storage Options - Enhanced `allInOne.data` with existingClaim support - Added PVC template for persistentVolumeClaim type ## CI Enhancements - Added comprehensive tests for all-in-one configurations - Tests cover replicas, S3, SFTP, extraArgs, strategies, PVC, ingress --- .github/workflows/helm_ci.yml | 172 ++++++++++++++++++ .../all-in-one/all-in-one-deployment.yaml | 112 ++++++++---- .../all-in-one/all-in-one-ingress.yaml | 154 ++++++++++++++++ .../templates/all-in-one/all-in-one-pvc.yaml | 23 ++- .../all-in-one/all-in-one-service.yml | 18 +- .../shared/post-install-bucket-hook.yaml | 66 ++++--- k8s/charts/seaweedfs/values.yaml | 108 ++++++++++- 7 files changed, 573 insertions(+), 80 deletions(-) create mode 100644 k8s/charts/seaweedfs/templates/all-in-one/all-in-one-ingress.yaml diff --git a/.github/workflows/helm_ci.yml b/.github/workflows/helm_ci.yml index ea971aec1..fada3557c 100644 --- a/.github/workflows/helm_ci.yml +++ b/.github/workflows/helm_ci.yml @@ -118,6 +118,178 @@ jobs: echo "" echo "✅ All template rendering tests passed!" + - name: Verify all-in-one template rendering + run: | + set -e + CHART_DIR="k8s/charts/seaweedfs" + + echo "=== Testing all-in-one with custom replicas ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.replicas=2 > /tmp/allinone-replicas.yaml + grep -q "replicas: 2" /tmp/allinone-replicas.yaml + echo "✓ All-in-one replicas configuration works" + + echo "=== Testing all-in-one with S3 enabled ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.s3.enabled=true > /tmp/allinone-s3.yaml + grep -q "\-s3" /tmp/allinone-s3.yaml + grep -q "swfs-s3" /tmp/allinone-s3.yaml + echo "✓ All-in-one S3 configuration works" + + echo "=== Testing all-in-one with custom S3 port ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.s3.enabled=true \ + --set allInOne.s3.port=9000 > /tmp/allinone-s3-port.yaml + grep -q "port: 9000" /tmp/allinone-s3-port.yaml + echo "✓ All-in-one custom S3 port works" + + echo "=== Testing all-in-one with S3 auth ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.s3.enabled=true \ + --set allInOne.s3.enableAuth=true > /tmp/allinone-s3-auth.yaml + grep -q "config-s3-users" /tmp/allinone-s3-auth.yaml + grep -q "s3.config=" /tmp/allinone-s3-auth.yaml + echo "✓ All-in-one S3 auth configuration works" + + echo "=== Testing all-in-one with S3 domainName ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.s3.enabled=true \ + --set allInOne.s3.domainName=s3.example.com > /tmp/allinone-s3-domain.yaml + grep -q "s3.domainName=s3.example.com" /tmp/allinone-s3-domain.yaml + echo "✓ All-in-one S3 domain name configuration works" + + echo "=== Testing all-in-one with SFTP enabled ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.sftp.enabled=true > /tmp/allinone-sftp.yaml + grep -q "\-sftp" /tmp/allinone-sftp.yaml + grep -q "swfs-sftp" /tmp/allinone-sftp.yaml + echo "✓ All-in-one SFTP configuration works" + + echo "=== Testing all-in-one with custom SFTP port ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.sftp.enabled=true \ + --set allInOne.sftp.port=2222 > /tmp/allinone-sftp-port.yaml + grep -q "sftp.port=2222" /tmp/allinone-sftp-port.yaml + echo "✓ All-in-one custom SFTP port works" + + echo "=== Testing all-in-one with extraArgs ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set 'allInOne.extraArgs[0]=-customFlag' \ + --set 'allInOne.extraArgs[1]=customValue' > /tmp/allinone-extraargs.yaml + grep -q "\-customFlag" /tmp/allinone-extraargs.yaml + echo "✓ All-in-one extraArgs configuration works" + + echo "=== Testing all-in-one with RollingUpdate strategy ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.updateStrategy.type=RollingUpdate > /tmp/allinone-strategy.yaml + grep -q "type: RollingUpdate" /tmp/allinone-strategy.yaml + echo "✓ All-in-one update strategy configuration works" + + echo "=== Testing all-in-one with PVC storage ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.data.type=persistentVolumeClaim \ + --set allInOne.data.size=50Gi \ + --set allInOne.data.storageClass=fast > /tmp/allinone-pvc.yaml + grep -q "PersistentVolumeClaim" /tmp/allinone-pvc.yaml + grep -q "storage: 50Gi" /tmp/allinone-pvc.yaml + grep -q "storageClassName: fast" /tmp/allinone-pvc.yaml + echo "✓ All-in-one PVC configuration works" + + echo "=== Testing all-in-one with existing claim ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.data.type=existingClaim \ + --set allInOne.data.claimName=my-existing-pvc > /tmp/allinone-existing-claim.yaml + grep -q "claimName: my-existing-pvc" /tmp/allinone-existing-claim.yaml + echo "✓ All-in-one existing claim configuration works" + + echo "=== Testing all-in-one with hostPath storage ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.data.type=hostPath \ + --set allInOne.data.hostPathPrefix=/mnt/seaweedfs > /tmp/allinone-hostpath.yaml + grep -q "hostPath:" /tmp/allinone-hostpath.yaml + grep -q "/mnt/seaweedfs/seaweedfs-all-in-one-data" /tmp/allinone-hostpath.yaml + echo "✓ All-in-one hostPath configuration works" + + echo "=== Testing all-in-one with ingress (S3) ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.s3.enabled=true \ + --set allInOne.ingress.enabled=true \ + --set allInOne.ingress.s3.enabled=true \ + --set allInOne.ingress.host=seaweedfs.example.com > /tmp/allinone-ingress-s3.yaml + grep -q "kind: Ingress" /tmp/allinone-ingress-s3.yaml + grep -q "seaweedfs-all-in-one-s3" /tmp/allinone-ingress-s3.yaml + echo "✓ All-in-one S3 ingress configuration works" + + echo "=== Testing all-in-one with ingress (filer) ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.ingress.enabled=true \ + --set allInOne.ingress.filer.enabled=true > /tmp/allinone-ingress-filer.yaml + grep -q "seaweedfs-all-in-one-filer" /tmp/allinone-ingress-filer.yaml + echo "✓ All-in-one filer ingress configuration works" + + echo "=== Testing all-in-one with ingress (master) ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.ingress.enabled=true \ + --set allInOne.ingress.master.enabled=true > /tmp/allinone-ingress-master.yaml + grep -q "seaweedfs-all-in-one-master" /tmp/allinone-ingress-master.yaml + echo "✓ All-in-one master ingress configuration works" + + echo "=== Testing all-in-one with secretExtraEnvironmentVars ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set 'allInOne.secretExtraEnvironmentVars.DB_PASSWORD.secretKeyRef.name=db-secret' \ + --set 'allInOne.secretExtraEnvironmentVars.DB_PASSWORD.secretKeyRef.key=password' > /tmp/allinone-secret-env.yaml + grep -q "DB_PASSWORD" /tmp/allinone-secret-env.yaml + grep -q "secretKeyRef" /tmp/allinone-secret-env.yaml + echo "✓ All-in-one secretExtraEnvironmentVars configuration works" + + echo "=== Testing all-in-one with security enabled ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set global.enableSecurity=true > /tmp/allinone-security.yaml + grep -q "security-config" /tmp/allinone-security.yaml + grep -q "ca-cert" /tmp/allinone-security.yaml + echo "✓ All-in-one security configuration works" + + echo "=== Testing all-in-one combined configuration ===" + helm template test $CHART_DIR \ + --set allInOne.enabled=true \ + --set allInOne.replicas=1 \ + --set allInOne.s3.enabled=true \ + --set allInOne.s3.port=9000 \ + --set allInOne.s3.enableAuth=true \ + --set allInOne.sftp.enabled=true \ + --set allInOne.sftp.port=2222 \ + --set allInOne.data.type=persistentVolumeClaim \ + --set allInOne.data.size=100Gi \ + --set allInOne.ingress.enabled=true \ + --set allInOne.ingress.s3.enabled=true \ + --set allInOne.ingress.filer.enabled=true > /tmp/allinone-combined.yaml + grep -q "replicas: 1" /tmp/allinone-combined.yaml + grep -q "s3.port=9000" /tmp/allinone-combined.yaml + grep -q "sftp.port=2222" /tmp/allinone-combined.yaml + grep -q "storage: 100Gi" /tmp/allinone-combined.yaml + grep -q "kind: Ingress" /tmp/allinone-combined.yaml + echo "✓ All-in-one combined configuration works" + + echo "" + echo "✅ All all-in-one template rendering tests passed!" + - name: Create kind cluster uses: helm/kind-action@v1.13.0 diff --git a/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml b/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml index 6f176ae19..decc0bf39 100644 --- a/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml +++ b/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml @@ -15,9 +15,9 @@ metadata: {{- toYaml .Values.allInOne.annotations | nindent 4 }} {{- end }} spec: - replicas: 1 + replicas: {{ .Values.allInOne.replicas | default 1 }} strategy: - type: Recreate + type: {{ .Values.allInOne.updateStrategy.type | default "Recreate" }} selector: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} @@ -130,12 +130,23 @@ spec: value: {{ include "seaweedfs.cluster.masterAddress" . | quote }} - name: {{ $clusterFilerKey }} value: {{ include "seaweedfs.cluster.filerAddress" . | quote }} + {{- if .Values.allInOne.secretExtraEnvironmentVars }} + {{- range $key, $value := .Values.allInOne.secretExtraEnvironmentVars }} + - name: {{ $key }} + valueFrom: + {{ toYaml $value | nindent 16 }} + {{- end }} + {{- end }} command: - "/bin/sh" - "-ec" - | /usr/bin/weed \ + {{- if .Values.allInOne.loggingOverrideLevel }} + -v={{ .Values.allInOne.loggingOverrideLevel }} \ + {{- else }} -v={{ .Values.global.loggingLevel }} \ + {{- end }} server \ -dir=/data \ -master \ @@ -191,6 +202,9 @@ spec: {{- else if .Values.master.metricsPort }} -metricsPort={{ .Values.master.metricsPort }} \ {{- end }} + {{- if .Values.allInOne.metricsIp }} + -metricsIp={{ .Values.allInOne.metricsIp }} \ + {{- end }} -filer \ -filer.port={{ .Values.filer.port }} \ {{- if .Values.filer.disableDirListing }} @@ -219,61 +233,81 @@ spec: {{- end }} {{- if .Values.allInOne.s3.enabled }} -s3 \ - -s3.port={{ .Values.s3.port }} \ - {{- if .Values.s3.domainName }} + -s3.port={{ .Values.allInOne.s3.port | default .Values.s3.port }} \ + {{- if .Values.allInOne.s3.domainName }} + -s3.domainName={{ .Values.allInOne.s3.domainName }} \ + {{- else if .Values.s3.domainName }} -s3.domainName={{ .Values.s3.domainName }} \ {{- end }} {{- if .Values.global.enableSecurity }} - {{- if .Values.s3.httpsPort }} - -s3.port.https={{ .Values.s3.httpsPort }} \ + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} + -s3.port.https={{ $httpsPort }} \ {{- end }} -s3.cert.file=/usr/local/share/ca-certificates/client/tls.crt \ -s3.key.file=/usr/local/share/ca-certificates/client/tls.key \ {{- end }} - {{- if eq (typeOf .Values.s3.allowEmptyFolder) "bool" }} + {{- $s3AllowEmptyFolder := .Values.allInOne.s3.allowEmptyFolder }} + {{- if eq (typeOf $s3AllowEmptyFolder) "bool" }} + -s3.allowEmptyFolder={{ $s3AllowEmptyFolder }} \ + {{- else if eq (typeOf .Values.s3.allowEmptyFolder) "bool" }} -s3.allowEmptyFolder={{ .Values.s3.allowEmptyFolder }} \ {{- end }} - {{- if .Values.s3.enableAuth }} + {{- if or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth }} -s3.config=/etc/sw/s3/seaweedfs_s3_config \ {{- end }} - {{- if .Values.s3.auditLogConfig }} + {{- $auditLogConfig := .Values.allInOne.s3.auditLogConfig | default .Values.s3.auditLogConfig }} + {{- if $auditLogConfig }} -s3.auditLogConfig=/etc/sw/s3/s3_auditLogConfig.json \ {{- end }} {{- end }} {{- if .Values.allInOne.sftp.enabled }} -sftp \ - -sftp.port={{ .Values.sftp.port }} \ - {{- if .Values.sftp.sshPrivateKey }} - -sftp.sshPrivateKey={{ .Values.sftp.sshPrivateKey }} \ + -sftp.port={{ .Values.allInOne.sftp.port | default .Values.sftp.port }} \ + {{- $sshPrivateKey := .Values.allInOne.sftp.sshPrivateKey | default .Values.sftp.sshPrivateKey }} + {{- if $sshPrivateKey }} + -sftp.sshPrivateKey={{ $sshPrivateKey }} \ {{- end }} - {{- if .Values.sftp.hostKeysFolder }} - -sftp.hostKeysFolder={{ .Values.sftp.hostKeysFolder }} \ + {{- $hostKeysFolder := .Values.allInOne.sftp.hostKeysFolder | default .Values.sftp.hostKeysFolder }} + {{- if $hostKeysFolder }} + -sftp.hostKeysFolder={{ $hostKeysFolder }} \ {{- end }} - {{- if .Values.sftp.authMethods }} - -sftp.authMethods={{ .Values.sftp.authMethods }} \ + {{- $authMethods := .Values.allInOne.sftp.authMethods | default .Values.sftp.authMethods }} + {{- if $authMethods }} + -sftp.authMethods={{ $authMethods }} \ {{- end }} - {{- if .Values.sftp.maxAuthTries }} - -sftp.maxAuthTries={{ .Values.sftp.maxAuthTries }} \ + {{- $maxAuthTries := .Values.allInOne.sftp.maxAuthTries | default .Values.sftp.maxAuthTries }} + {{- if $maxAuthTries }} + -sftp.maxAuthTries={{ $maxAuthTries }} \ {{- end }} - {{- if .Values.sftp.bannerMessage }} - -sftp.bannerMessage="{{ .Values.sftp.bannerMessage }}" \ + {{- $bannerMessage := .Values.allInOne.sftp.bannerMessage | default .Values.sftp.bannerMessage }} + {{- if $bannerMessage }} + -sftp.bannerMessage="{{ $bannerMessage }}" \ {{- end }} - {{- if .Values.sftp.loginGraceTime }} - -sftp.loginGraceTime={{ .Values.sftp.loginGraceTime }} \ + {{- $loginGraceTime := .Values.allInOne.sftp.loginGraceTime | default .Values.sftp.loginGraceTime }} + {{- if $loginGraceTime }} + -sftp.loginGraceTime={{ $loginGraceTime }} \ {{- end }} - {{- if .Values.sftp.clientAliveInterval }} - -sftp.clientAliveInterval={{ .Values.sftp.clientAliveInterval }} \ + {{- $clientAliveInterval := .Values.allInOne.sftp.clientAliveInterval | default .Values.sftp.clientAliveInterval }} + {{- if $clientAliveInterval }} + -sftp.clientAliveInterval={{ $clientAliveInterval }} \ {{- end }} - {{- if .Values.sftp.clientAliveCountMax }} - -sftp.clientAliveCountMax={{ .Values.sftp.clientAliveCountMax }} \ + {{- $clientAliveCountMax := .Values.allInOne.sftp.clientAliveCountMax | default .Values.sftp.clientAliveCountMax }} + {{- if $clientAliveCountMax }} + -sftp.clientAliveCountMax={{ $clientAliveCountMax }} \ {{- end }} + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} -sftp.userStoreFile=/etc/sw/sftp/seaweedfs_sftp_config \ {{- end }} + {{- end }} + {{- range .Values.allInOne.extraArgs }} + {{ . }} \ + {{- end }} volumeMounts: - name: data mountPath: /data - {{- if and .Values.allInOne.s3.enabled (or .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} + {{- if and .Values.allInOne.s3.enabled (or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} - name: config-s3-users mountPath: /etc/sw/s3 readOnly: true @@ -282,10 +316,12 @@ spec: - name: config-ssh mountPath: /etc/sw/ssh readOnly: true + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} - mountPath: /etc/sw/sftp name: config-users readOnly: true {{- end }} + {{- end }} {{- if .Values.filer.notificationConfig }} - name: notification-config mountPath: /etc/seaweedfs/notification.toml @@ -332,15 +368,16 @@ spec: - containerPort: {{ .Values.filer.grpcPort }} name: swfs-fil-grpc {{- if .Values.allInOne.s3.enabled }} - - containerPort: {{ .Values.s3.port }} + - containerPort: {{ .Values.allInOne.s3.port | default .Values.s3.port }} name: swfs-s3 - {{- if .Values.s3.httpsPort }} - - containerPort: {{ .Values.s3.httpsPort }} + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} + - containerPort: {{ $httpsPort }} name: swfs-s3-tls {{- end }} {{- end }} {{- if .Values.allInOne.sftp.enabled }} - - containerPort: {{ .Values.sftp.port }} + - containerPort: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} name: swfs-sftp {{- end }} {{- if .Values.allInOne.metricsPort }} @@ -389,26 +426,31 @@ spec: path: {{ .Values.allInOne.data.hostPathPrefix }}/seaweedfs-all-in-one-data/ type: DirectoryOrCreate {{- else if eq .Values.allInOne.data.type "persistentVolumeClaim" }} + persistentVolumeClaim: + claimName: {{ template "seaweedfs.name" . }}-all-in-one-data + {{- else if eq .Values.allInOne.data.type "existingClaim" }} persistentVolumeClaim: claimName: {{ .Values.allInOne.data.claimName }} {{- else if eq .Values.allInOne.data.type "emptyDir" }} emptyDir: {} {{- end }} - {{- if and .Values.allInOne.s3.enabled (or .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} + {{- if and .Values.allInOne.s3.enabled (or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} - name: config-s3-users secret: defaultMode: 420 - secretName: {{ default (printf "%s-s3-secret" (include "seaweedfs.name" .)) (or .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret) }} + secretName: {{ default (printf "%s-s3-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.s3.existingConfigSecret .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret) }} {{- end }} {{- if .Values.allInOne.sftp.enabled }} - name: config-ssh secret: defaultMode: 420 - secretName: {{ default (printf "%s-sftp-ssh-secret" (include "seaweedfs.name" .)) .Values.sftp.existingSshConfigSecret }} + secretName: {{ default (printf "%s-sftp-ssh-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingSshConfigSecret .Values.sftp.existingSshConfigSecret) }} + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} - name: config-users secret: defaultMode: 420 - secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.name" .)) .Values.sftp.existingConfigSecret }} + secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingConfigSecret .Values.sftp.existingConfigSecret) }} + {{- end }} {{- end }} {{- if .Values.filer.notificationConfig }} - name: notification-config diff --git a/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-ingress.yaml b/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-ingress.yaml new file mode 100644 index 000000000..f4b015092 --- /dev/null +++ b/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-ingress.yaml @@ -0,0 +1,154 @@ +{{- if .Values.allInOne.enabled }} +{{- if .Values.allInOne.ingress.enabled }} +{{- $fullName := printf "%s-all-in-one" (include "seaweedfs.name" .) -}} + +{{- /* S3 Ingress */}} +{{- if and .Values.allInOne.s3.enabled .Values.allInOne.ingress.s3.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }}-s3 + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + {{- with .Values.allInOne.ingress.s3.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.allInOne.ingress.className }} + ingressClassName: {{ .Values.allInOne.ingress.className }} + {{- end }} + {{- if .Values.allInOne.ingress.s3.tls }} + tls: + {{- range .Values.allInOne.ingress.s3.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- if .Values.allInOne.ingress.host }} + - host: {{ .Values.allInOne.ingress.host | quote }} + http: + {{- else }} + - http: + {{- end }} + paths: + - path: {{ .Values.allInOne.ingress.s3.path }} + pathType: {{ .Values.allInOne.ingress.s3.pathType }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ .Values.allInOne.s3.port | default .Values.s3.port }} +{{- end }} + +{{- /* Filer Ingress */}} +{{- if .Values.allInOne.ingress.filer.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }}-filer + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + {{- with .Values.allInOne.ingress.filer.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.allInOne.ingress.className }} + ingressClassName: {{ .Values.allInOne.ingress.className }} + {{- end }} + {{- if .Values.allInOne.ingress.filer.tls }} + tls: + {{- range .Values.allInOne.ingress.filer.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- if .Values.allInOne.ingress.host }} + - host: {{ .Values.allInOne.ingress.host | quote }} + http: + {{- else }} + - http: + {{- end }} + paths: + - path: {{ .Values.allInOne.ingress.filer.path }} + pathType: {{ .Values.allInOne.ingress.filer.pathType }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ .Values.filer.port }} +{{- end }} + +{{- /* Master Ingress */}} +{{- if .Values.allInOne.ingress.master.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }}-master + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + {{- with .Values.allInOne.ingress.master.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.allInOne.ingress.className }} + ingressClassName: {{ .Values.allInOne.ingress.className }} + {{- end }} + {{- if .Values.allInOne.ingress.master.tls }} + tls: + {{- range .Values.allInOne.ingress.master.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- if .Values.allInOne.ingress.host }} + - host: {{ .Values.allInOne.ingress.host | quote }} + http: + {{- else }} + - http: + {{- end }} + paths: + - path: {{ .Values.allInOne.ingress.master.path }} + pathType: {{ .Values.allInOne.ingress.master.pathType }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ .Values.master.port }} +{{- end }} + +{{- end }} +{{- end }} + diff --git a/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml b/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml index 49ac20148..ba4477197 100644 --- a/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml +++ b/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml @@ -1,21 +1,28 @@ -{{- if and .Values.allInOne.enabled (eq .Values.allInOne.data.type "persistentVolumeClaim") }} +{{- if .Values.allInOne.enabled }} +{{- if eq .Values.allInOne.data.type "persistentVolumeClaim" }} apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: {{ .Values.allInOne.data.claimName }} + name: {{ template "seaweedfs.name" . }}-all-in-one-data + namespace: {{ .Release.Namespace }} labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: seaweedfs-all-in-one - {{- if .Values.allInOne.annotations }} + {{- with .Values.allInOne.data.annotations }} annotations: - {{- toYaml .Values.allInOne.annotations | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} spec: accessModes: - ReadWriteOnce - resources: - requests: - storage: {{ .Values.allInOne.data.size }} {{- if .Values.allInOne.data.storageClass }} storageClassName: {{ .Values.allInOne.data.storageClass }} {{- end }} -{{- end }} \ No newline at end of file + resources: + requests: + storage: {{ .Values.allInOne.data.size | default "10Gi" }} +{{- end }} +{{- end }} diff --git a/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml b/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml index 14076a9c3..b13f57899 100644 --- a/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml +++ b/k8s/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml @@ -15,6 +15,7 @@ metadata: {{- toYaml .Values.allInOne.service.annotations | nindent 4 }} {{- end }} spec: + type: {{ .Values.allInOne.service.type | default "ClusterIP" }} internalTrafficPolicy: {{ .Values.allInOne.service.internalTrafficPolicy | default "Cluster" }} ports: # Master ports @@ -50,13 +51,14 @@ spec: # S3 ports (if enabled) {{- if .Values.allInOne.s3.enabled }} - name: "swfs-s3" - port: {{ if .Values.allInOne.s3.enabled }}{{ .Values.s3.port }}{{ else }}{{ .Values.filer.s3.port }}{{ end }} - targetPort: {{ if .Values.allInOne.s3.enabled }}{{ .Values.s3.port }}{{ else }}{{ .Values.filer.s3.port }}{{ end }} + port: {{ .Values.allInOne.s3.port | default .Values.s3.port }} + targetPort: {{ .Values.allInOne.s3.port | default .Values.s3.port }} protocol: TCP - {{- if and .Values.allInOne.s3.enabled .Values.s3.httpsPort }} + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} - name: "swfs-s3-tls" - port: {{ .Values.s3.httpsPort }} - targetPort: {{ .Values.s3.httpsPort }} + port: {{ $httpsPort }} + targetPort: {{ $httpsPort }} protocol: TCP {{- end }} {{- end }} @@ -64,8 +66,8 @@ spec: # SFTP ports (if enabled) {{- if .Values.allInOne.sftp.enabled }} - name: "swfs-sftp" - port: {{ .Values.sftp.port }} - targetPort: {{ .Values.sftp.port }} + port: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} + targetPort: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} protocol: TCP {{- end }} @@ -80,4 +82,4 @@ spec: selector: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} app.kubernetes.io/component: seaweedfs-all-in-one -{{- end }} \ No newline at end of file +{{- end }} diff --git a/k8s/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml b/k8s/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml index 44d650898..ce7d61397 100644 --- a/k8s/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml +++ b/k8s/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml @@ -1,6 +1,32 @@ -{{- if .Values.master.enabled }} -{{- if .Values.filer.s3.enabled }} -{{- if .Values.filer.s3.createBuckets }} +{{- /* Support bucket creation for both standalone filer.s3 and allInOne modes */}} +{{- $createBuckets := list }} +{{- $s3Enabled := false }} +{{- $enableAuth := false }} +{{- $existingConfigSecret := "" }} + +{{- /* Check allInOne mode first */}} +{{- if .Values.allInOne.enabled }} + {{- if .Values.allInOne.s3.enabled }} + {{- $s3Enabled = true }} + {{- if .Values.allInOne.s3.createBuckets }} + {{- $createBuckets = .Values.allInOne.s3.createBuckets }} + {{- end }} + {{- $enableAuth = or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth }} + {{- $existingConfigSecret = or .Values.allInOne.s3.existingConfigSecret .Values.s3.existingConfigSecret }} + {{- end }} +{{- else if .Values.master.enabled }} + {{- /* Check standalone filer.s3 mode */}} + {{- if .Values.filer.s3.enabled }} + {{- $s3Enabled = true }} + {{- if .Values.filer.s3.createBuckets }} + {{- $createBuckets = .Values.filer.s3.createBuckets }} + {{- end }} + {{- $enableAuth = .Values.filer.s3.enableAuth }} + {{- $existingConfigSecret = .Values.filer.s3.existingConfigSecret }} + {{- end }} +{{- end }} + +{{- if and $s3Enabled $createBuckets }} --- apiVersion: batch/v1 kind: Job @@ -32,9 +58,9 @@ spec: - name: WEED_CLUSTER_DEFAULT value: "sw" - name: WEED_CLUSTER_SW_MASTER - value: "{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}:{{ .Values.master.port }}" + value: {{ include "seaweedfs.cluster.masterAddress" . | quote }} - name: WEED_CLUSTER_SW_FILER - value: "{{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }}" + value: {{ include "seaweedfs.cluster.filerAddress" . | quote }} - name: POD_IP valueFrom: fieldRef: @@ -71,24 +97,24 @@ spec: echo "Service at $url failed to become ready within 5 minutes" exit 1 } - wait_for_service "http://$WEED_CLUSTER_SW_MASTER{{ .Values.master.readinessProbe.httpGet.path }}" - wait_for_service "http://$WEED_CLUSTER_SW_FILER{{ .Values.filer.readinessProbe.httpGet.path }}" - {{- range $reg, $props := $.Values.filer.s3.createBuckets }} + wait_for_service "http://$WEED_CLUSTER_SW_MASTER/cluster/status" + wait_for_service "http://$WEED_CLUSTER_SW_FILER/" + {{- range $createBuckets }} exec /bin/echo \ - "s3.bucket.create --name {{ $props.name }}" |\ + "s3.bucket.create --name {{ .name }}" |\ /usr/bin/weed shell {{- end }} - {{- range $reg, $props := $.Values.filer.s3.createBuckets }} - {{- if $props.anonymousRead }} + {{- range $createBuckets }} + {{- if .anonymousRead }} exec /bin/echo \ "s3.configure --user anonymous \ - --buckets {{ $props.name }} \ + --buckets {{ .name }} \ --actions Read \ --apply true" |\ /usr/bin/weed shell {{- end }} {{- end }} - {{- if .Values.filer.s3.enableAuth }} + {{- if $enableAuth }} volumeMounts: - name: config-users mountPath: /etc/sw @@ -106,17 +132,15 @@ spec: {{- if .Values.filer.containerSecurityContext.enabled }} securityContext: {{- omit .Values.filer.containerSecurityContext "enabled" | toYaml | nindent 12 }} {{- end }} - {{- if .Values.filer.s3.enableAuth }} + {{- if $enableAuth }} volumes: - name: config-users secret: defaultMode: 420 - {{- if not (empty .Values.filer.s3.existingConfigSecret) }} - secretName: {{ .Values.filer.s3.existingConfigSecret }} + {{- if $existingConfigSecret }} + secretName: {{ $existingConfigSecret }} {{- else }} - secretName: seaweedfs-s3-secret + secretName: {{ template "seaweedfs.name" . }}-s3-secret {{- end }} - {{- end }}{{/** if .Values.filer.s3.enableAuth **/}} -{{- end }}{{/** if .Values.master.enabled **/}} -{{- end }}{{/** if .Values.filer.s3.enabled **/}} -{{- end }}{{/** if .Values.filer.s3.createBuckets **/}} + {{- end }} +{{- end }} diff --git a/k8s/charts/seaweedfs/values.yaml b/k8s/charts/seaweedfs/values.yaml index bddfd622d..97eab5351 100644 --- a/k8s/charts/seaweedfs/values.yaml +++ b/k8s/charts/seaweedfs/values.yaml @@ -1097,6 +1097,7 @@ allInOne: enabled: false imageOverride: null restartPolicy: Always + replicas: 1 # Number of replicas (note: multiple replicas may require shared storage) # Core configuration idleTimeout: 30 # Connection idle seconds @@ -1108,24 +1109,71 @@ allInOne: metricsIp: "" # Metrics listen IP. If empty, defaults to bindAddress loggingOverrideLevel: null # Override logging level - # Service configuration + # Custom command line arguments to add to the server command + # Example to fix IPv6 metrics connectivity issues: + # extraArgs: ["-metricsIp", "0.0.0.0"] + # Example with multiple args: + # extraArgs: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + + # Update strategy configuration + # type: Recreate or RollingUpdate + # For single replica, Recreate is recommended to avoid data conflicts + updateStrategy: + type: Recreate + + # S3 gateway configuration s3: enabled: false # Whether to enable S3 gateway + port: 8333 # S3 gateway port + httpsPort: 0 # S3 gateway HTTPS port (0 to disable) + domainName: "" # Suffix of the host name, {bucket}.{domainName} + allowEmptyFolder: true # Allow empty folders in S3 + enableAuth: false # Enable user & permission to S3 + # Set to the name of an existing kubernetes Secret with the s3 json config file + # should have a secret key called seaweedfs_s3_config with an inline json config + existingConfigSecret: null + auditLogConfig: {} # S3 audit log configuration + # You may specify buckets to be created during the install process. + # Buckets may be exposed publicly by setting `anonymousRead` to `true` + # createBuckets: + # - name: bucket-a + # anonymousRead: true + # - name: bucket-b + # anonymousRead: false + + # SFTP server configuration sftp: enabled: false # Whether to enable SFTP server + port: 2022 # SFTP port + sshPrivateKey: "/etc/sw/seaweedfs_sftp_ssh_private_key" # Path to SSH private key + hostKeysFolder: "/etc/sw/ssh" # Path to SSH host keys folder + authMethods: "password,publickey" # Comma-separated auth methods + maxAuthTries: 6 # Maximum authentication attempts + bannerMessage: "SeaweedFS SFTP Server" # Banner message + loginGraceTime: "2m" # Login grace time + clientAliveInterval: "5s" # Client keep-alive interval + clientAliveCountMax: 3 # Maximum missed keep-alive messages + enableAuth: false # Enable SFTP authentication + # Set to the name of an existing kubernetes Secret with the sftp json config file + existingConfigSecret: null + # Set to the name of an existing kubernetes Secret with the SSH keys + existingSshConfigSecret: null # Service settings service: annotations: {} # Annotations for the service type: ClusterIP # Service type (ClusterIP, NodePort, LoadBalancer) + internalTrafficPolicy: Cluster # Internal traffic policy # Storage configuration data: - type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir" + type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir", "existingClaim" hostPathPrefix: /mnt/data # Path prefix for hostPath volumes - claimName: seaweedfs-data-pvc # Name of the PVC to use - size: "" # Size of the PVC + claimName: seaweedfs-data-pvc # Name of the PVC to use (for existingClaim type) + size: "" # Size of the PVC (for persistentVolumeClaim type) storageClass: "" # Storage class for the PVC + annotations: {} # Annotations for the PVC # Health checks readinessProbe: @@ -1154,6 +1202,18 @@ allInOne: # Additional resources extraEnvironmentVars: {} # Additional environment variables + # Secret environment variables (for database credentials, etc.) + # Example: + # secretExtraEnvironmentVars: + # WEED_POSTGRES_USERNAME: + # secretKeyRef: + # name: postgres-credentials + # key: username + # WEED_POSTGRES_PASSWORD: + # secretKeyRef: + # name: postgres-credentials + # key: password + secretExtraEnvironmentVars: {} extraVolumeMounts: "" # Additional volume mounts extraVolumes: "" # Additional volumes initContainers: "" # Init containers @@ -1173,7 +1233,7 @@ allInOne: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: master + app.kubernetes.io/component: seaweedfs-all-in-one topologyKey: kubernetes.io/hostname # Topology Spread Constraints Settings @@ -1181,16 +1241,16 @@ allInOne: # for a PodSpec. By Default no constraints are set. topologySpreadConstraints: "" - # Toleration Settings for master pods + # Toleration Settings for pods # This should be a multi-line string matching the Toleration array # in a PodSpec. tolerations: "" - # nodeSelector labels for master pod assignment, formatted as a muli-line string. + # nodeSelector labels for pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector nodeSelector: "" - # Used to assign priority to master pods + # Used to assign priority to pods # ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ priorityClassName: "" @@ -1226,6 +1286,38 @@ allInOne: cpu: "500m" memory: "1Gi" + # Ingress configuration + ingress: + enabled: false + className: "" + # host: false for "*" hostname + host: "seaweedfs.cluster.local" + # S3 ingress settings + s3: + enabled: false + path: "/" + pathType: Prefix + annotations: {} + tls: [] + # Filer ingress settings + filer: + enabled: false + path: "/sw-filer/?(.*)" + pathType: ImplementationSpecific + annotations: {} + # nginx.ingress.kubernetes.io/rewrite-target: /$1 + # nginx.ingress.kubernetes.io/use-regex: "true" + tls: [] + # Master ingress settings + master: + enabled: false + path: "/sw-master/?(.*)" + pathType: ImplementationSpecific + annotations: {} + # nginx.ingress.kubernetes.io/rewrite-target: /$1 + # nginx.ingress.kubernetes.io/use-regex: "true" + tls: [] + # Deploy Kubernetes COSI Driver for SeaweedFS # Requires COSI CRDs and controller to be installed in the cluster # For more information, visit: https://container-object-storage-interface.github.io/docs/deployment-guide