Skip to content
This repository was archived by the owner on Nov 26, 2025. It is now read-only.

Conversation

@michaelstingl
Copy link
Contributor

Summary

This PR adds comprehensive High Availability (HA) documentation based on the findings and solutions discussed in issue #53.

Changes

  • Added dedicated "High Availability (HA) Configuration" section to README
  • Documented the OC_EXCLUDE_RUN_SERVICES=idp,idm solution provided by @micbar
  • Added external NATS configuration examples
  • Included complete HA deployment example
  • Updated opencloud.replicas parameter description to clarify requirements
  • Added opencloud.excludeServices to the parameter documentation

Key Documentation Added

1. Prerequisites for HA

  • External Identity Provider requirement
  • Shared storage (RWX) requirement
  • External NATS requirement
  • Need to disable embedded services

2. Disabling Embedded Services

  • Clear examples using excludeServices array
  • Alternative environment variable approach

3. Complete HA Example

  • Full configuration showing all required settings
  • External Keycloak, NATS, and S3 configuration

4. Storage Requirements

  • List of recommended storage solutions
  • Clarification that persistence should NOT be disabled

Addresses

Related Issues

Testing

  • Validated YAML syntax in examples
  • Cross-referenced with actual values.yaml parameters
  • Verified links work correctly

cc @Tim-herbie @micbar - This documents the solution you discussed in #53

- Added dedicated High Availability (HA) Configuration section
- Documented OC_EXCLUDE_RUN_SERVICES=idp,idm requirement from issue #53
- Added external NATS configuration for distributed messaging
- Included complete HA example with all required settings
- Updated opencloud.replicas description to clarify RWX storage requirement
- Added opencloud.excludeServices to parameter documentation
- Listed recommended storage solutions (CephFS, GlusterFS, NFS v4)
- Clarified that persistence should NOT be disabled for HA

Addresses action items from issue #53 where @micbar provided the solution
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds comprehensive documentation for High Availability (HA) configuration to the OpenCloud Helm chart README, addressing gaps identified in issue #53. The documentation provides clear guidance on configuring multi-replica deployments with external dependencies.

  • Added dedicated HA configuration section with prerequisites, service exclusion methods, and complete examples
  • Updated parameter descriptions to clarify HA requirements and correct misleading information about persistence
  • Added documentation for the excludeServices parameter that was previously undocumented

@michaelstingl michaelstingl requested review from butonic and micbar July 22, 2025 08:35
### Important Notes
- You need RWX storage or external S3 storage, not disabled persistence.
- Each OpenCloud instance needs access to the same data, which requires either RWX volumes or external S3 storage.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @michaelstingl for the PR!

I think that the requirement is a RWX Volume and an external S3 storage. I will test it.

@Tim-herbie
Copy link
Contributor

I installed the helm-chart in a fresh namespace with the following setup:

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: opencloud
spec:
  releaseName: opencloud
  interval: 12h
  chart:
    spec:
      chart: opencloud
      sourceRef:
        kind: HelmRepository
        name: opencloud
        namespace: opencloud-dev
      version: "0.2.3"
  values:
    global:

      tls:
        enabled: true
        secretName: opencloud-wildcard-tls
        selfSigned: true

      domain:
        keycloak: keycloak-dev.timherbert.de
        opencloud: opencloud-dev.timherbert.de
        wopi: wopiserver-dev.timherbert.de
        collabora: collabora-dev.timherbert.de
        onlyoffice: onlyoffice-dev.timherbert.de
        companion: companion-dev.timherbert.de 

    collabora:
      enabled: true
      ssl:
        enabled: false
        verification: false
    
    onlyoffice:
      enabled: false
    
    opencloud:
      replicas: 3
      logLevel: warn
      excludeServices:
        - "idp"
        - "idm"
      
      persistence:
        enabled: true
        accessMode: ReadWriteMany
        storageClass: "longhorn"

      nats:
        external:
          enabled: true
          endpoint: nats.opencloud-dev.svc.cluster.local:4222
          cluster: opencloud-cluster
          tls:
            enabled: false

P.S: I used the keycloak instance from the helm-chart instead of my own for testing. For sure, it´s absolutely right to require a external (ha) keycloak deployment.

I added also the nats and nack deployment from butonic´s last PR from here: https://github.com/opencloud-eu/helm/tree/main/deployments/nats

With the following setup, the opencloud pods can´t start and I see the following:

Pod overview:

Every 2.0s: kubectl get pods -o wide                                                                                           MacBook-Air-von-Tim.local: Wed Jul 23 10:15:12 2025

NAME                                       READY   STATUS             RESTARTS      AGE     IP              NODE               NOMINATED NODE   READINESS GATES
nack-5b8fd86d8d-r5ftt                      1/1     Running            0             3m37s   10.42.117.223   k8s-node3-worker   <none>           <none>
nats-0                                     2/2     Running            0             3m37s   10.42.117.227   k8s-node3-worker   <none>           <none>
nats-1                                     1/2     CrashLoopBackOff   5 (22s ago)   3m37s   10.42.135.54    k8s-node4-worker   <none>           <none>
nats-2                                     2/2     Running            0             3m37s   10.42.161.100   k8s-node1-worker   <none>           <none>
nats-box-7795cd6f95-7ncv6                  1/1     Running            0             3m37s   10.42.117.229   k8s-node3-worker   <none>           <none>
opencloud-collabora-5ccbd49d4c-x5fhw       1/1     Running            0             3m35s   10.42.117.225   k8s-node3-worker   <none>           <none>
opencloud-collaboration-6b4f84547b-4dt5m   0/1     CrashLoopBackOff   4 (65s ago)   3m35s   10.42.117.239   k8s-node3-worker   <none>           <none>
opencloud-keycloak-8496fcc74d-j8nd7        1/1     Running            0             3m35s   10.42.117.217   k8s-node3-worker   <none>           <none>
opencloud-minio-748b5d5454-945gc           1/1     Running            0             3m35s   10.42.117.215   k8s-node3-worker   <none>           <none>
opencloud-opencloud-b78ccfb6c-9g6sc        0/1     CrashLoopBackOff   4 (38s ago)   3m35s   10.42.117.214   k8s-node3-worker   <none>           <none>
opencloud-opencloud-b78ccfb6c-fvp8w        0/1     CrashLoopBackOff   4 (33s ago)   3m35s   10.42.161.101   k8s-node1-worker   <none>           <none>
opencloud-opencloud-b78ccfb6c-fwzqv        0/1     CrashLoopBackOff   4 (42s ago)   3m35s   10.42.135.59    k8s-node4-worker   <none>           <none>
opencloud-postgres-7b867c67ff-w72tm        1/1     Running            0             3m35s   10.42.117.203   k8s-node3-worker   <none>           <none>
opencloud-tika-6b585c6f4c-d8b6n            1/1     Running            0             3m35s   10.42.117.199   k8s-node3-worker   <none>           <none>

Logs from opencloud pods

kubectl logs opencloud-opencloud-b78ccfb6c-9g6sc 

Defaulted container "opencloud" out of: opencloud, init-config (init), init-drawio (init), init-externalsites (init), init-importer (init), init-jsonviewer (init), init-progressbars (init), init-unzip (init), init-web-extensions (init)
2025/07/23 08:16:04 Could not create config: config file already exists, use --force-overwrite to overwrite or --diff to show diff
{"level":"warn","service":"storage-system","pkg":"rhttp","time":"2025-07-23T08:16:04Z","message":"missing or incomplete nats configuration. Events will not be published."}
{"level":"warn","service":"ocm","pkg":"rhttp","time":"2025-07-23T08:16:05Z","message":"missing or incomplete nats configuration. Events will not be published."}
{"level":"warn","service":"ocm","pkg":"rhttp","traceid":"62028f07a6d96f85e2fe451968a9e81c","time":"2025-07-23T08:16:05Z","message":"core access token not set"}
{"level":"warn","service":"ocm","pkg":"rhttp","traceid":"62028f07a6d96f85e2fe451968a9e81c","host":"127.0.0.1","method":"GET","uri":"/","url":"/","proto":"HTTP/1.1","status":404,"size":19,"start":"23/Jul/2025:08:16:05 +0000","end":"23/Jul/2025:08:16:05 +0000","time_ns":127977,"time":"2025-07-23T08:16:05Z","message":"http"}
{"level":"warn","service":"ocm","pkg":"rhttp","traceid":"fedde19460ace89ceb03285d06f19aba","time":"2025-07-23T08:16:05Z","message":"core access token not set"}
{"level":"warn","service":"ocm","pkg":"rhttp","traceid":"fedde19460ace89ceb03285d06f19aba","host":"127.0.0.1","method":"GET","uri":"/","url":"/","proto":"HTTP/1.1","status":404,"size":19,"start":"23/Jul/2025:08:16:05 +0000","end":"23/Jul/2025:08:16:05 +0000","time_ns":121707,"time":"2025-07-23T08:16:05Z","message":"http"}
{"level":"warn","service":"frontend","pkg":"rhttp","traceid":"3fb4814577e797139ca87fa1e60fac72","time":"2025-07-23T08:16:06Z","message":"core access token not set"}
{"level":"warn","service":"frontend","pkg":"rhttp","traceid":"3fb4814577e797139ca87fa1e60fac72","host":"127.0.0.1","method":"GET","uri":"/","url":"/","proto":"HTTP/1.1","status":401,"size":0,"start":"23/Jul/2025:08:16:06 +0000","end":"23/Jul/2025:08:16:06 +0000","time_ns":179770,"time":"2025-07-23T08:16:06Z","message":"http"}
{"level":"warn","service":"auth-basic","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:06Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"warn","service":"graph","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:06Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"warn","service":"users","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:06Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"warn","service":"groups","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:06Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"warn","service":"auth-basic","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:08Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"warn","service":"graph","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:08Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"warn","service":"users","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:08Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"warn","service":"groups","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:08Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"warn","service":"auth-basic","LDAP CACert":"/var/lib/opencloud/idm/ldap.crt","time":"2025-07-23T08:16:10Z","message":"CA cert file is not ready yet. Waiting 2 seconds for it to appear."}
{"level":"error","service":"auth-basic","error":"unable to register services: rgrpc: grpc service authprovider could not be started,: Error reading LDAP CA Cert '/var/lib/opencloud/idm/ldap.crt.': open /var/lib/opencloud/idm/ldap.crt: no such file or directory","time":"2025-07-23T08:16:10Z","message":"error starting the grpc server"}

Here is the openclod deployment:

kubectl get deploy opencloud-opencloud -o yaml           

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
    meta.helm.sh/release-name: opencloud
    meta.helm.sh/release-namespace: opencloud-dev
    reloader.stakater.com/auto: "true"
  creationTimestamp: "2025-07-23T08:11:37Z"
  generation: 1
  labels:
    app.kubernetes.io/component: opencloud
    app.kubernetes.io/instance: opencloud
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: opencloud
    app.kubernetes.io/version: latest
    helm.sh/chart: opencloud-0.2.3
    helm.toolkit.fluxcd.io/name: opencloud
    helm.toolkit.fluxcd.io/namespace: opencloud-dev
  name: opencloud-opencloud
  namespace: opencloud-dev
  resourceVersion: "589463411"
  uid: e415f20c-47af-4ca2-9a85-b0df25e407f1
spec:
  progressDeadlineSeconds: 600
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/component: opencloud
      app.kubernetes.io/instance: opencloud
      app.kubernetes.io/name: opencloud
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
  template:
    metadata:
      annotations:
        checksum/config-json: 08528cc036f4b3c68b615049abf60228240d67fa736aa58d11d0408fe2714cd9
        checksum/configmap: 79f85ef7dd0baf2b2f8e5925d2f64b3463ba13a081c97d24260fcf9ac2f33750
        checksum/web-extensions-init: 84ae401f0b3d9a84d276357fb000add33060db05142b1987f00c3337145e9308
      creationTimestamp: null
      labels:
        app.kubernetes.io/component: opencloud
        app.kubernetes.io/instance: opencloud
        app.kubernetes.io/name: opencloud
    spec:
      containers:
      - args:
        - -c
        - opencloud init || true; opencloud server
        command:
        - /bin/sh
        env:
        - name: OC_URL
          value: https://opencloud-dev.timherbert.de
        - name: GRAPH_AVAILABLE_ROLES
          value: b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5,a8d5fe5e-96e3-418d-825b-534dbdf22b99,fb6c3e19-e378-47e5-b277-9732f9de6e21,58c63c02-1d89-4572-916a-870abc5a1b7d,2d00ce52-1fc2-4dbc-8b95-a73b73395f5a,1c996275-f1c9-4e71-abdf-a42f6495e960,312c0871-5ef7-4b3a-85b6-0e4074c64049,aa97fe03-7980-45ac-9e50-b325749fd7e6
        - name: OC_LOG_LEVEL
          value: warn
        - name: OC_LOG_COLOR
          value: "false"
        - name: OC_LOG_PRETTY
          value: "false"
        - name: OC_EXCLUDE_RUN_SERVICES
          value: idp,idm,nats
        - name: PROXY_TLS
          value: "false"
        - name: GATEWAY_GRPC_ADDR
          value: 0.0.0.0:9142
        - name: OC_INSECURE
          value: "true"
        - name: PROXY_ENABLE_BASIC_AUTH
          value: "false"
        - name: ONLYOFFICE_DOMAIN
          value: onlyoffice-dev.timherbert.de
        - name: COMPANION_DOMAIN
          value: companion-dev.timherbert.de
        - name: OC_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD
          value: "false"
        - name: OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST
          value: banned-password-list.txt
        - name: SEARCH_EXTRACTOR_TYPE
          value: tika
        - name: SEARCH_EXTRACTOR_TIKA_TIKA_URL
          value: http://opencloud-tika:9998
        - name: OC_GRPC_MAX_RECEIVED_MESSAGE_SIZE
          value: "102400000"
        - name: PROXY_AUTOPROVISION_ACCOUNTS
          value: "true"
        - name: FRONTEND_READONLY_USER_ATTRIBUTES
          value: user.onPremisesSamAccountName,user.displayName,user.mail,user.passwordProfile,user.accountEnabled,user.appRoleAssignments
        - name: PROXY_ROLE_ASSIGNMENT_DRIVER
          value: oidc
        - name: OC_OIDC_ISSUER
          value: https://keycloak-dev.timherbert.de/realms/openCloud
        - name: WEB_OPTION_ACCOUNT_EDIT_LINK_HREF
          value: https://keycloak-dev.timherbert.de/realms/openCloud/account
        - name: PROXY_OIDC_REWRITE_WELLKNOWN
          value: "true"
        - name: WEB_OIDC_CLIENT_ID
          value: web
        - name: PROXY_USER_OIDC_CLAIM
          value: preferred_username
        - name: PROXY_USER_CS3_CLAIM
          value: username
        - name: OC_ADMIN_USER_ID
        - name: GRAPH_ASSIGN_DEFAULT_USER_ROLE
          value: "false"
        - name: GRAPH_USERNAME_MATCH
          value: none
        - name: PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM
          value: roles
        - name: PROXY_OIDC_ACCESS_TOKEN_VERIFY_METHOD
          value: jwt
        - name: WEB_OIDC_METADATA_URL
          value: https://keycloak-dev.timherbert.de/realms/openCloud/.well-known/openid-configuration
        - name: WEB_OIDC_SCOPE
          value: openid profile email groups roles
        - name: IDM_ADMIN_PASSWORD
          valueFrom:
            secretKeyRef:
              key: adminPassword
              name: opencloud-opencloud
        - name: IDM_CREATE_DEMO_USERS
          value: "false"
        - name: MICRO_REGISTRY_ADDRESS
          value: nats.opencloud-dev.svc.cluster.local:4222
        - name: OC_CACHE_STORE_NODES
          value: nats.opencloud-dev.svc.cluster.local:4222
        - name: OC_PERSISTENT_STORE_NODES
          value: nats.opencloud-dev.svc.cluster.local:4222
        - name: OC_EVENTS_ENDPOINT
          value: nats.opencloud-dev.svc.cluster.local:4222
        - name: OC_EVENTS_CLUSTER
          value: opencloud-cluster
        - name: OC_EVENTS_ENABLE_TLS
          value: "false"
        - name: OC_EVENTS_TLS_INSECURE
          value: "false"
        - name: PROXY_CSP_CONFIG_FILE_LOCATION
          value: /etc/opencloud/csp.yaml
        - name: STORAGE_USERS_DRIVER
          value: decomposeds3
        - name: STORAGE_SYSTEM_DRIVER
          value: decomposed
        - name: STORAGE_USERS_DECOMPOSEDS3_ENDPOINT
          value: http://opencloud-minio:9000
        - name: STORAGE_USERS_DECOMPOSEDS3_REGION
          value: default
        - name: STORAGE_USERS_DECOMPOSEDS3_BUCKET
          value: opencloud-bucket
        - name: STORAGE_USERS_DECOMPOSEDS3_CREATE_BUCKET
          value: "true"
        - name: STORAGE_USERS_DECOMPOSEDS3_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              key: rootUser
              name: opencloud-minio
        - name: STORAGE_USERS_DECOMPOSEDS3_SECRET_KEY
          valueFrom:
            secretKeyRef:
              key: rootPassword
              name: opencloud-minio
        image: docker.io/opencloudeu/opencloud-rolling:2.1.0
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /health
            port: 9200
            scheme: HTTP
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        name: opencloud
        ports:
        - containerPort: 9200
          name: http
          protocol: TCP
        - containerPort: 9233
          name: nats
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /health
            port: 9200
            scheme: HTTP
          periodSeconds: 5
          successThreshold: 1
          timeoutSeconds: 5
        resources:
          limits:
            memory: 20Gi
          requests:
            cpu: 128m
            memory: 128Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
        startupProbe:
          failureThreshold: 60
          httpGet:
            path: /health
            port: 9200
            scheme: HTTP
          periodSeconds: 2
          successThreshold: 1
          timeoutSeconds: 5
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /etc/opencloud
          name: config
        - mountPath: /var/lib/opencloud
          name: data
        - mountPath: /var/lib/opencloud/config.json
          name: config-json
          subPath: config.json
        - mountPath: /etc/opencloud/search.yaml
          name: config-files
          subPath: search.yaml
        - mountPath: /etc/opencloud/csp.yaml
          name: config-files
          subPath: csp.yaml
        - mountPath: /etc/opencloud/banned-password-list.txt
          name: config-files
          subPath: banned-password-list.txt
      dnsPolicy: ClusterFirst
      initContainers:
      - command:
        - sh
        - -c
        - mkdir -p /etc/opencloud /var/lib/opencloud
        image: docker.io/library/busybox:1.36
        imagePullPolicy: IfNotPresent
        name: init-config
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /etc/opencloud
          name: config
        - mountPath: /var/lib/opencloud
          name: data
      - command:
        - sh
        - -c
        - mkdir -p /extensions/draw-io && cp -R /usr/share/nginx/html/draw-io/ /extensions/
        image: docker.io/opencloudeu/web-extensions:draw-io-1.0.0
        imagePullPolicy: IfNotPresent
        name: init-drawio
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /extensions
          name: extensions
      - command:
        - sh
        - -c
        - mkdir -p /extensions/external-sites && cp -R /usr/share/nginx/html/external-sites/
          /extensions/
        image: docker.io/opencloudeu/web-extensions:external-sites-1.0.0
        imagePullPolicy: IfNotPresent
        name: init-externalsites
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /extensions
          name: extensions
      - command:
        - sh
        - -c
        - mkdir -p /extensions/importer && cp -R /usr/share/nginx/html/importer/ /extensions/
        image: docker.io/opencloudeu/web-extensions:importer-1.0.0
        imagePullPolicy: IfNotPresent
        name: init-importer
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /extensions
          name: extensions
      - command:
        - sh
        - -c
        - mkdir -p /extensions/json-viewer && cp -R /usr/share/nginx/html/json-viewer/
          /extensions/
        image: docker.io/opencloudeu/web-extensions:json-viewer-1.0.0
        imagePullPolicy: IfNotPresent
        name: init-jsonviewer
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /extensions
          name: extensions
      - command:
        - sh
        - -c
        - mkdir -p /extensions/progress-bars && cp -R /usr/share/nginx/html/progress-bars/
          /extensions/
        image: docker.io/opencloudeu/web-extensions:progress-bars-1.0.0
        imagePullPolicy: IfNotPresent
        name: init-progressbars
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /extensions
          name: extensions
      - command:
        - sh
        - -c
        - mkdir -p /extensions/unzip && cp -R /usr/share/nginx/html/unzip/ /extensions/
        image: docker.io/opencloudeu/web-extensions:unzip-1.0.0
        imagePullPolicy: IfNotPresent
        name: init-unzip
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /extensions
          name: extensions
      - command:
        - sh
        - /scripts/init-web-extensions.sh
        image: docker.io/library/busybox:1.36
        imagePullPolicy: IfNotPresent
        name: init-web-extensions
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /extensions
          name: extensions
        - mountPath: /var/lib/opencloud
          name: data
        - mountPath: /scripts
          name: web-extensions-init-script
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext:
        fsGroup: 1000
      terminationGracePeriodSeconds: 30
      volumes:
      - name: config
        persistentVolumeClaim:
          claimName: opencloud-opencloud-config
      - name: data
        persistentVolumeClaim:
          claimName: opencloud-opencloud-data
      - configMap:
          defaultMode: 420
          name: opencloud-opencloud-config-json
        name: config-json
      - configMap:
          defaultMode: 420
          name: opencloud-opencloud-config
        name: config-files
      - configMap:
          defaultMode: 420
          name: opencloud-opencloud-proxy-config
        name: proxy-config
      - emptyDir: {}
        name: extensions
      - configMap:
          defaultMode: 420
          name: opencloud-opencloud-web-extensions-init
        name: web-extensions-init-script
status:
  conditions:
  - lastTransitionTime: "2025-07-23T08:11:37Z"
    lastUpdateTime: "2025-07-23T08:12:35Z"
    message: ReplicaSet "opencloud-opencloud-b78ccfb6c" has successfully progressed.
    reason: NewReplicaSetAvailable
    status: "True"
    type: Progressing
  - lastTransitionTime: "2025-07-23T08:12:37Z"
    lastUpdateTime: "2025-07-23T08:12:37Z"
    message: Deployment does not have minimum availability.
    reason: MinimumReplicasUnavailable
    status: "False"
    type: Available
  observedGeneration: 1
  replicas: 3
  unavailableReplicas: 3
  updatedReplicas: 3

I am not sure, if I did a mistake in a deployment or there is a parameter or something missing.

@Tim-herbie
Copy link
Contributor

Maybe @micbar can help?

- Add auth-basic to excludeServices to prevent LDAP cert lookup errors
- Fix duplicate YAML keys in HA example (storage config under opencloud)
- Clarify that BOTH RWX and S3 storage are required for HA
- Add note about auth-basic exclusion for external authentication
@michaelstingl
Copy link
Contributor Author

michaelstingl commented Jul 24, 2025

@Tim-herbie Thank you for testing the HA configuration! I think I found the issue with your setup.

The Problem

The auth-basic service is still running and looking for the IDM's LDAP certificate at /var/lib/opencloud/idm/ldap.crt, even though you've excluded IDM. This causes the crash you're seeing.

The Solution

You need to also exclude the auth-basic service in your configuration:

opencloud:
  excludeServices:
    - "idp"
    - "idm"
    - "auth-basic"  # Add this!

Why This Works

When using external authentication (Keycloak in your case):

  • The proxy service handles basic authentication directly using PROXY_ENABLE_BASIC_AUTH
  • The proxy uses the main OpenCloud LDAP configuration (OC_LDAP_*)
  • The standalone auth-basic service is not needed and can cause conflicts

This is how opencloud-compose handles external authentication - they don't use the auth-basic service at all.

Updated PR

I've updated this PR to:

  1. Add auth-basic to the exclude list in all examples
  2. Clarified that BOTH RWX storage AND external S3 are needed for HA (not either/or)
  3. Fixed the duplicate YAML keys that Copilot identified
  4. Added a note about excluding auth-basic when using external authentication

Could you please test again with auth-basic added to your excludeServices list? This should resolve the LDAP certificate errors you're seeing.


Update: I've also created an OpenCloud issue to improve this behavior: opencloud-eu/opencloud#1271

The auth-basic service should handle IDM exclusion more intelligently instead of requiring manual exclusion.

@michaelstingl
Copy link
Contributor Author

Based on @micbar's feedback in opencloud-eu/opencloud#1271 (comment), I'm converting this PR to a Draft for now.

He questions whether auth-basic actually accesses the IDM certificate, suggesting that services should be cleanly separated. We need to clarify this before proceeding with the documentation update.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants