feat(apps): deploy Mattermost Team Edition for team communications #330

Open
jesus wants to merge 3 commits from jesus/infra-core:feat/mattermost into live
Contributor

What

Deploy self-hosted Mattermost Team Edition using the upstream Mattermost Operator instead of a hand-rolled Deployment chart.

Source: https://github.com/mattermost/mattermost

Why

  • The upstream mattermost-team-edition Helm chart is deprecated; the Mattermost Operator is the supported deployment path.
  • We only maintain custom app charts when no operator exists.
  • CNPG clusters are already deployed as separate cnpg-cluster-* ArgoCD Applications, so the database should not be embedded in the app chart.

Changes

Platform operator

  • New base values: core/charts/platform/mattermost-operator/values.yaml
    • Chart: mattermost/mattermost-operator from https://helm.mattermost.com
    • Disables operator-managed ingress (we use Cilium Gateway API).

App chart (core/charts/apps/mattermost/)

  • templates/mattermost.yaml: installation.mattermost.com/v1beta1 Mattermost CR.
  • templates/httproute.yaml: Gateway API route for mattermost.aaron.reynoza.org.
  • templates/minio.yaml: optional bundled MinIO for file uploads (disabled via fileStore.minio.enabled=false to use external S3).
  • templates/secret.yaml: OIDC client credentials secret for Zitadel integration.
  • Removed: Deployment, Service, PVC, ConfigMap, embedded CNPG cluster, and DB connection secret templates.

Required prod overlay

1. Operator Application

prod/apps/mattermost-operator.yaml ArgoCD Application (sync-wave ~5):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: mattermost-operator
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://helm.mattermost.com
    chart: mattermost-operator
    targetRevision: <chart-version>
    helm:
      valueFiles:
        - values.yaml
        - ../../../../prod/values/mattermost-operator/values.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: mattermost-operator
  syncPolicy:
    syncOptions:
      - CreateNamespace=true

2. CNPG cluster

prod/apps/cnpg-cluster-mattermost.yaml using core/charts/platform/cnpg-cluster/:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cnpg-cluster-mattermost
  namespace: argocd
spec:
  project: default
  source:
    repoURL: http://forgejo.aaron.reynoza.org/aaron/infra-core.git
    targetRevision: live
    path: core/charts/platform/cnpg-cluster
    helm:
      valueFiles:
        - values.yaml
        - ../../../../prod/values/cnpg-cluster-mattermost/values.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: mattermost

3. Mattermost Application

prod/apps/mattermost.yaml using core/charts/apps/mattermost/:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: mattermost
  namespace: argocd
spec:
  project: default
  source:
    repoURL: http://forgejo.aaron.reynoza.org/aaron/infra-core.git
    targetRevision: live
    path: core/charts/apps/mattermost
    helm:
      valueFiles:
        - values.yaml
        - ../../../../prod/values/mattermost/values.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: mattermost

4. Environment-specific values (prod/values/mattermost/values.yaml)

mattermost:
  siteUrl: "https://mattermost.aaron.reynoza.org"

database:
  # CNPG generates secret <cluster-name>-app with key `uri`.
  # The operator expects `DB_CONNECTION_STRING`; set useUriKey=true if the
  # CNPG secret does not provide that key.
  secretName: cnpg-cluster-mattermost-app
  useUriKey: true

fileStore:
  minio:
    enabled: true
    rootPassword: "<random-password>"

oidc:
  enabled: true
  clientId: "<zitadel-client-id>"
  clientSecret: "<zitadel-client-secret>"
  discoveryUrl: "https://zitadel.aaron.reynoza.org/.well-known/openid-configuration"
  authUri: "https://zitadel.aaron.reynoza.org/oauth/v2/authorize"
  tokenUri: "https://zitadel.aaron.reynoza.org/oauth/v2/token"
  userinfoUri: "https://zitadel.aaron.reynoza.org/oidc/v1/userinfo"
  logoutUri: "https://zitadel.aaron.reynoza.org/oidc/v1/end_session"

Verify

  • mattermost-operator ArgoCD Application is healthy
  • cnpg-cluster-mattermost ArgoCD Application is healthy and secret cnpg-cluster-mattermost-app exists
  • mattermost ArgoCD Application is healthy and serves the setup wizard
  • mattermost.aaron.reynoza.org resolves and is reachable via HTTPS
  • File uploads work (MinIO bucket created, PVC bound)
  • OIDC login with Zitadel works (optional)
## What Deploy self-hosted **Mattermost Team Edition** using the upstream **Mattermost Operator** instead of a hand-rolled Deployment chart. Source: https://github.com/mattermost/mattermost ## Why - The upstream `mattermost-team-edition` Helm chart is deprecated; the Mattermost Operator is the supported deployment path. - We only maintain custom app charts when no operator exists. - CNPG clusters are already deployed as separate `cnpg-cluster-*` ArgoCD Applications, so the database should not be embedded in the app chart. ## Changes ### Platform operator - New base values: `core/charts/platform/mattermost-operator/values.yaml` - Chart: `mattermost/mattermost-operator` from `https://helm.mattermost.com` - Disables operator-managed ingress (we use Cilium Gateway API). ### App chart (`core/charts/apps/mattermost/`) - `templates/mattermost.yaml`: `installation.mattermost.com/v1beta1` `Mattermost` CR. - `templates/httproute.yaml`: Gateway API route for `mattermost.aaron.reynoza.org`. - `templates/minio.yaml`: optional bundled MinIO for file uploads (disabled via `fileStore.minio.enabled=false` to use external S3). - `templates/secret.yaml`: OIDC client credentials secret for Zitadel integration. - Removed: Deployment, Service, PVC, ConfigMap, embedded CNPG cluster, and DB connection secret templates. ## Required prod overlay ### 1. Operator Application `prod/apps/mattermost-operator.yaml` ArgoCD Application (sync-wave ~5): ```yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: mattermost-operator namespace: argocd spec: project: default source: repoURL: https://helm.mattermost.com chart: mattermost-operator targetRevision: <chart-version> helm: valueFiles: - values.yaml - ../../../../prod/values/mattermost-operator/values.yaml destination: server: https://kubernetes.default.svc namespace: mattermost-operator syncPolicy: syncOptions: - CreateNamespace=true ``` ### 2. CNPG cluster `prod/apps/cnpg-cluster-mattermost.yaml` using `core/charts/platform/cnpg-cluster/`: ```yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: cnpg-cluster-mattermost namespace: argocd spec: project: default source: repoURL: http://forgejo.aaron.reynoza.org/aaron/infra-core.git targetRevision: live path: core/charts/platform/cnpg-cluster helm: valueFiles: - values.yaml - ../../../../prod/values/cnpg-cluster-mattermost/values.yaml destination: server: https://kubernetes.default.svc namespace: mattermost ``` ### 3. Mattermost Application `prod/apps/mattermost.yaml` using `core/charts/apps/mattermost/`: ```yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: mattermost namespace: argocd spec: project: default source: repoURL: http://forgejo.aaron.reynoza.org/aaron/infra-core.git targetRevision: live path: core/charts/apps/mattermost helm: valueFiles: - values.yaml - ../../../../prod/values/mattermost/values.yaml destination: server: https://kubernetes.default.svc namespace: mattermost ``` ### 4. Environment-specific values (`prod/values/mattermost/values.yaml`) ```yaml mattermost: siteUrl: "https://mattermost.aaron.reynoza.org" database: # CNPG generates secret <cluster-name>-app with key `uri`. # The operator expects `DB_CONNECTION_STRING`; set useUriKey=true if the # CNPG secret does not provide that key. secretName: cnpg-cluster-mattermost-app useUriKey: true fileStore: minio: enabled: true rootPassword: "<random-password>" oidc: enabled: true clientId: "<zitadel-client-id>" clientSecret: "<zitadel-client-secret>" discoveryUrl: "https://zitadel.aaron.reynoza.org/.well-known/openid-configuration" authUri: "https://zitadel.aaron.reynoza.org/oauth/v2/authorize" tokenUri: "https://zitadel.aaron.reynoza.org/oauth/v2/token" userinfoUri: "https://zitadel.aaron.reynoza.org/oidc/v1/userinfo" logoutUri: "https://zitadel.aaron.reynoza.org/oidc/v1/end_session" ``` ## Verify - [ ] `mattermost-operator` ArgoCD Application is healthy - [ ] `cnpg-cluster-mattermost` ArgoCD Application is healthy and secret `cnpg-cluster-mattermost-app` exists - [ ] `mattermost` ArgoCD Application is healthy and serves the setup wizard - [ ] `mattermost.aaron.reynoza.org` resolves and is reachable via HTTPS - [ ] File uploads work (MinIO bucket created, PVC bound) - [ ] OIDC login with Zitadel works (optional)
Deploy self-hosted Mattermost (https://github.com/mattermost/mattermost)
on the homelab cluster with:
- Custom Helm chart under core/charts/apps/mattermost/
- CNPG PostgreSQL cluster for persistence
- HTTPRoute for mattermost.aaron.reynoza.org
- OIDC placeholders for future Zitadel SSO integration

Base values are reusable; environment-specific config (domain,
secrets, SSO) belongs in prod/values/mattermost/.
fix(mattermost): align CNPG cluster name with app secret and move at-rest key to secret
Some checks failed
CI Review / pr-title (pull_request) Failing after 0s
CI Review / helm-validate (pull_request) Failing after 20s
CI Review / ai-review (pull_request) Failing after 4s
Lint & Validate / terraform-validate (pull_request) Failing after 54s
Lint & Validate / yaml-lint (pull_request) Failing after 4s
Lint & Validate / shellcheck (pull_request) Failing after 3s
be9cf3d10b
- Default CNPG cluster name to cnpg-cluster-mattermost so the generated
  secret matches database.secretName (cnpg-cluster-mattermost-app).
- Remove redundant managed.roles block from CNPG Cluster.
- Move MM_SQLSETTINGS_ATRESTENCRYPTKEY from ConfigMap to Secret.
Owner

Review: prefer Mattermost Operator instead of custom chart

Thanks for putting this together — the chart is well-structured and follows our patterns for labels, CNPG, and HTTPRoute. The issue isn't quality; it's that Mattermost already has an official Kubernetes operator, so a hand-rolled Deployment/Service/PVC chart duplicates concerns the operator handles better.

Why this should change

  • The upstream mattermost-team-edition Helm chart is officially deprecated; the Mattermost Operator is the supported deployment path.
  • We only maintain custom app charts when no operator exists. outline is custom because Outline has no operator. Mattermost does.
  • This PR adds ~10 templates (Deployment, Service, PVC, Secret, ConfigMap, probes, env vars, etc.) that the operator would manage and keep up to date for us.
  • CNPG shouldn't be embedded in the app chart; we already deploy clusters as separate cnpg-cluster-* ArgoCD Applications.

Replace the full custom chart with:

  1. Platform operator

    • core/charts/platform/mattermost-operator/values.yaml
    • prod/apps/mattermost-operator.yaml (ArgoCD Application, sync-wave ~5)
    • Source: mattermost/mattermost-operator from https://helm.mattermost.com
  2. Minimal app deployment

    • core/charts/apps/mattermost/ containing just:
      • Mattermost CR (installation.mattermost.com/v1beta1)
      • Gateway API HTTPRoute for mattermost.aaron.reynoza.org
      • (Disable the operator's Ingress creation since we use Cilium Gateway API.)
    • prod/apps/mattermost.yaml ArgoCD Application
  3. Database

    • prod/apps/cnpg-cluster-mattermost.yaml following the existing cnpg-cluster-outline pattern.
    • Reference the CNPG-generated secret in the Mattermost CR database.external.secret.
  4. File storage

    • Use external S3/MinIO (we already bundle MinIO for Outline) or local PVC via the CR's file store options.
**Review: prefer Mattermost Operator instead of custom chart** Thanks for putting this together — the chart is well-structured and follows our patterns for labels, CNPG, and HTTPRoute. The issue isn't quality; it's that **Mattermost already has an official Kubernetes operator**, so a hand-rolled Deployment/Service/PVC chart duplicates concerns the operator handles better. ### Why this should change - The upstream `mattermost-team-edition` Helm chart is **officially deprecated**; the [Mattermost Operator](https://docs.mattermost.com/deployment-guide/server/deploy-kubernetes.html#itab--Mattermost-Operator--3_1-step-2-install-the-mattermost-operator) is the supported deployment path. - We only maintain custom app charts when no operator exists. `outline` is custom because Outline has no operator. Mattermost does. - This PR adds ~10 templates (Deployment, Service, PVC, Secret, ConfigMap, probes, env vars, etc.) that the operator would manage and keep up to date for us. - CNPG shouldn't be embedded in the app chart; we already deploy clusters as separate `cnpg-cluster-*` ArgoCD Applications. ### Recommended approach Replace the full custom chart with: 1. **Platform operator** - `core/charts/platform/mattermost-operator/values.yaml` - `prod/apps/mattermost-operator.yaml` (ArgoCD Application, sync-wave ~5) - Source: `mattermost/mattermost-operator` from `https://helm.mattermost.com` 2. **Minimal app deployment** - `core/charts/apps/mattermost/` containing just: - `Mattermost` CR (`installation.mattermost.com/v1beta1`) - Gateway API `HTTPRoute` for `mattermost.aaron.reynoza.org` - (Disable the operator's Ingress creation since we use Cilium Gateway API.) - `prod/apps/mattermost.yaml` ArgoCD Application 3. **Database** - `prod/apps/cnpg-cluster-mattermost.yaml` following the existing `cnpg-cluster-outline` pattern. - Reference the CNPG-generated secret in the `Mattermost` CR `database.external.secret`. 4. **File storage** - Use external S3/MinIO (we already bundle MinIO for Outline) or local PVC via the CR's file store options.
aaron left a comment
Owner

Needs refactoring into external operator

Needs refactoring into external operator
refactor(mattermost): use Mattermost Operator instead of custom Deployment chart
Some checks failed
CI Review / pr-title (pull_request) Failing after 0s
CI Review / helm-validate (pull_request) Failing after 7s
CI Review / ai-review (pull_request) Failing after 3s
Lint & Validate / terraform-validate (pull_request) Failing after 49s
Lint & Validate / yaml-lint (pull_request) Failing after 3s
Lint & Validate / shellcheck (pull_request) Failing after 2s
1702bcf88f
Per review feedback:
- Remove hand-rolled Deployment/Service/PVC/ConfigMap/Secret/CNPG templates.
- Add platform operator values: core/charts/platform/mattermost-operator/values.yaml
- Refactor app chart to deploy a Mattermost CR
  (installation.mattermost.com/v1beta1) plus HTTPRoute and optional
  bundled MinIO.
- External database is now expected from a separate CNPG cluster app
  (prod/apps/cnpg-cluster-mattermost.yaml) using the generated *-app secret.
- Disable operator ingress; traffic enters through Cilium Gateway API.
- Keep OIDC placeholders for future Zitadel integration.
Some checks failed
CI Review / pr-title (pull_request) Failing after 0s
Required
Details
CI Review / helm-validate (pull_request) Failing after 7s
Required
Details
CI Review / ai-review (pull_request) Failing after 3s
Lint & Validate / terraform-validate (pull_request) Failing after 49s
Required
Details
Lint & Validate / yaml-lint (pull_request) Failing after 3s
Required
Details
Lint & Validate / shellcheck (pull_request) Failing after 2s
Required
Details
Some required checks were not successful.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u feat/mattermost:jesus-feat/mattermost
git switch jesus-feat/mattermost
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aaron/infra-core!330
No description provided.