From f44df94cb03b2137514600e356902f7a6a1d4df2 Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Sat, 21 Mar 2026 10:20:20 -0400 Subject: [PATCH 1/4] fix(helm): pass GITHUB_CLIENTID to front for OAuth flow The front service needs the GitHub App Client ID to build the OAuth authorization URL. Without it, the redirect has client_id= (empty) and GitHub returns 404. Signed-off-by: Daniel Kendall Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Don Kendall --- helm/huly/templates/front/deployment.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/helm/huly/templates/front/deployment.yaml b/helm/huly/templates/front/deployment.yaml index bb8c4b0..7b5e3c7 100644 --- a/helm/huly/templates/front/deployment.yaml +++ b/helm/huly/templates/front/deployment.yaml @@ -47,6 +47,7 @@ spec: {{- include "huly.envConfig" (dict "name" "LOVE_ENDPOINT" "key" "LOVE_ENDPOINT" "root" .) | nindent 12 }} {{- if .Values.githubIntegration.enabled }} {{- include "huly.envConfig" (dict "name" "GITHUB_URL" "key" "GITHUB_URL" "root" .) | nindent 12 }} + {{- include "huly.envSecret" (dict "name" "GITHUB_CLIENTID" "key" "GITHUB_APP_CLIENT_ID" "root" .) | nindent 12 }} {{- end }} {{- if .Values.aibot.enabled }} {{- include "huly.envConfig" (dict "name" "AI_URL" "key" "AI_URL" "root" .) | nindent 12 }} From a79943e6d7b7f8e5c6e1e46bddc74a56fb202de7 Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Sat, 21 Mar 2026 14:05:01 -0400 Subject: [PATCH 2/4] fix(helm): pass GITHUB_APP slug to front for installation flow The front service needs GITHUB_APP (app slug) to build the GitHub App installation URL. Without it, the URL becomes /apps//installations/new which returns 404. Signed-off-by: Daniel Kendall Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Don Kendall --- helm/huly/templates/front/deployment.yaml | 2 ++ helm/huly/values.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/helm/huly/templates/front/deployment.yaml b/helm/huly/templates/front/deployment.yaml index 7b5e3c7..371f129 100644 --- a/helm/huly/templates/front/deployment.yaml +++ b/helm/huly/templates/front/deployment.yaml @@ -48,6 +48,8 @@ spec: {{- if .Values.githubIntegration.enabled }} {{- include "huly.envConfig" (dict "name" "GITHUB_URL" "key" "GITHUB_URL" "root" .) | nindent 12 }} {{- include "huly.envSecret" (dict "name" "GITHUB_CLIENTID" "key" "GITHUB_APP_CLIENT_ID" "root" .) | nindent 12 }} + - name: GITHUB_APP + value: {{ .Values.githubIntegration.appSlug | quote }} {{- end }} {{- if .Values.aibot.enabled }} {{- include "huly.envConfig" (dict "name" "AI_URL" "key" "AI_URL" "root" .) | nindent 12 }} diff --git a/helm/huly/values.yaml b/helm/huly/values.yaml index 9e770f1..6ab7185 100644 --- a/helm/huly/values.yaml +++ b/helm/huly/values.yaml @@ -236,6 +236,8 @@ githubIntegration: replicas: 1 # Bot name shown on GitHub (must match the GitHub App's slug + [bot]) botName: "" + # GitHub App slug (from the app URL: github.com/apps/) + appSlug: "" # GitHub App credentials (stored in the shared secret) appId: "" clientId: "" From 31d413a297730138213f4c176dc91cd35608a422 Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Mon, 9 Mar 2026 11:10:08 -0400 Subject: [PATCH 3/4] feat(kube): replace broken kube/ with working Kustomize manifests Replace the existing flat kube/ manifests (broken for v7, see #181) with a battle-tested Kustomize-based deployment structure. Structure: kube/base/ - config, infra, app, ingress layers kube/overlays/ - example overlay users copy & customize kube/deploy.sh - one-liner deploy script Key design decisions: - Path-based routing (/_accounts, /_transactor, etc.) matching compose.yml - Elasticsearch 7.14.2 (not OpenSearch) - Huly's elasticsearch-js rejects non-ES backends - Explicit env vars on backend services (no bulk envFrom leaking external URLs) - Init containers for startup ordering (busybox wait loops) - Readiness probes on all services (TCP for WS/POST-only, HTTP for REST) - Imperative secret creation (no secret YAML in repo) - huly.example placeholder domain - users must customize via overlay Tested on K3s with v0.7.382. Renders 34 resources: 12 Deployments, 11 Services, 6 Ingresses, 4 PVCs, 1 ConfigMap. Closes #181 Addresses #20 Supersedes #215 Co-Authored-By: Claude Opus 4.6 --- kube/QUICKSTART.md | 101 ---------- kube/README.md | 186 ++++++++++++++++-- kube/account/account-ingress.yaml | 21 -- kube/account/account-service.yaml | 12 -- kube/base/app/account/deployment.yaml | 109 ++++++++++ kube/base/app/account/service.yaml | 14 ++ kube/base/app/collaborator/deployment.yaml | 57 ++++++ kube/base/app/collaborator/service.yaml | 14 ++ kube/base/app/front/deployment.yaml | 51 +++++ kube/base/app/front/service.yaml | 14 ++ kube/base/app/fulltext/deployment.yaml | 90 +++++++++ kube/base/app/fulltext/service.yaml | 14 ++ kube/base/app/kustomization.yaml | 18 ++ kube/base/app/rekoni/deployment.yaml | 40 ++++ kube/base/app/rekoni/service.yaml | 14 ++ kube/base/app/stats/deployment.yaml | 42 ++++ kube/base/app/stats/service.yaml | 14 ++ kube/base/app/transactor/deployment.yaml | 89 +++++++++ kube/base/app/transactor/service.yaml | 14 ++ .../app/workspace/deployment.yaml} | 82 ++++---- kube/base/config/configmap.yaml | 32 +++ kube/base/config/kustomization.yaml | 4 + kube/base/infra/cockroach/deployment.yaml | 51 +++++ kube/base/infra/cockroach/pvc.yaml | 13 ++ kube/base/infra/cockroach/service.yaml | 18 ++ kube/base/infra/elastic/deployment.yaml | 71 +++++++ .../infra/elastic/pvc.yaml} | 7 +- kube/base/infra/elastic/service.yaml | 14 ++ kube/base/infra/kustomization.yaml | 15 ++ kube/base/infra/minio/deployment.yaml | 48 +++++ .../infra/minio/pvc.yaml} | 7 +- kube/base/infra/minio/service.yaml | 17 ++ kube/base/infra/redpanda/deployment.yaml | 74 +++++++ .../infra/redpanda/pvc.yaml} | 7 +- kube/base/infra/redpanda/service.yaml | 17 ++ kube/base/ingress/ingress-accounts.yaml | 27 +++ kube/base/ingress/ingress-collaborator.yaml | 30 +++ .../ingress/ingress-front.yaml} | 20 +- kube/base/ingress/ingress-rekoni.yaml | 27 +++ kube/base/ingress/ingress-stats.yaml | 27 +++ kube/base/ingress/ingress-transactor.yaml | 30 +++ kube/base/ingress/kustomization.yaml | 9 + kube/base/kustomization.yaml | 7 + kube/cockroach/cockroach-deployment.yaml | 52 ----- .../cockroach-persistentvolumeclaim.yaml | 21 -- kube/cockroach/cockroach-service.yaml | 17 -- .../collaborator/collaborator-deployment.yaml | 42 ---- kube/collaborator/collaborator-ingress.yaml | 21 -- kube/collaborator/collaborator-service.yaml | 12 -- kube/config/config.yaml | 15 -- kube/config/secret.yaml | 11 -- kube/deploy.sh | 131 ++++++++++++ kube/elastic/elastic-deployment.yaml | 66 ------- kube/elastic/elastic-service.yaml | 14 -- kube/front/front-deployment.yaml | 78 -------- kube/front/front-service.yaml | 12 -- kube/fulltext/fulltext-deployment.yaml | 61 ------ kube/fulltext/fulltext-service.yaml | 12 -- kube/minio/minio-deployment.yaml | 43 ---- kube/minio/minio-service.yaml | 16 -- kube/overlays/example/kustomization.yaml | 79 ++++++++ kube/redpanda/redpanda-deployment.yaml | 58 ------ kube/redpanda/redpanda-service.yaml | 16 -- kube/rekoni/rekoni-deployment.yaml | 33 ---- kube/rekoni/rekoni-ingress.yaml | 21 -- kube/rekoni/rekoni-service.yaml | 12 -- kube/stats/stats-deployment.yaml | 35 ---- kube/stats/stats-ingress.yaml | 21 -- kube/stats/stats-service.yaml | 12 -- kube/transactor/transactor-deployment.yaml | 62 ------ kube/transactor/transactor-ingress.yaml | 21 -- kube/transactor/transactor-service.yaml | 13 -- kube/workspace/workspace-deployment.yaml | 57 ------ 73 files changed, 1578 insertions(+), 1054 deletions(-) delete mode 100644 kube/QUICKSTART.md delete mode 100644 kube/account/account-ingress.yaml delete mode 100644 kube/account/account-service.yaml create mode 100644 kube/base/app/account/deployment.yaml create mode 100644 kube/base/app/account/service.yaml create mode 100644 kube/base/app/collaborator/deployment.yaml create mode 100644 kube/base/app/collaborator/service.yaml create mode 100644 kube/base/app/front/deployment.yaml create mode 100644 kube/base/app/front/service.yaml create mode 100644 kube/base/app/fulltext/deployment.yaml create mode 100644 kube/base/app/fulltext/service.yaml create mode 100644 kube/base/app/kustomization.yaml create mode 100644 kube/base/app/rekoni/deployment.yaml create mode 100644 kube/base/app/rekoni/service.yaml create mode 100644 kube/base/app/stats/deployment.yaml create mode 100644 kube/base/app/stats/service.yaml create mode 100644 kube/base/app/transactor/deployment.yaml create mode 100644 kube/base/app/transactor/service.yaml rename kube/{account/account-deployment.yaml => base/app/workspace/deployment.yaml} (52%) create mode 100644 kube/base/config/configmap.yaml create mode 100644 kube/base/config/kustomization.yaml create mode 100644 kube/base/infra/cockroach/deployment.yaml create mode 100644 kube/base/infra/cockroach/pvc.yaml create mode 100644 kube/base/infra/cockroach/service.yaml create mode 100644 kube/base/infra/elastic/deployment.yaml rename kube/{redpanda/redpanda-persistentvolumeclaim.yaml => base/infra/elastic/pvc.yaml} (53%) create mode 100644 kube/base/infra/elastic/service.yaml create mode 100644 kube/base/infra/kustomization.yaml create mode 100644 kube/base/infra/minio/deployment.yaml rename kube/{minio/files-persistentvolumeclaim.yaml => base/infra/minio/pvc.yaml} (54%) create mode 100644 kube/base/infra/minio/service.yaml create mode 100644 kube/base/infra/redpanda/deployment.yaml rename kube/{elastic/elastic-persistentvolumeclaim.yaml => base/infra/redpanda/pvc.yaml} (53%) create mode 100644 kube/base/infra/redpanda/service.yaml create mode 100644 kube/base/ingress/ingress-accounts.yaml create mode 100644 kube/base/ingress/ingress-collaborator.yaml rename kube/{front/front-ingress.yaml => base/ingress/ingress-front.yaml} (52%) create mode 100644 kube/base/ingress/ingress-rekoni.yaml create mode 100644 kube/base/ingress/ingress-stats.yaml create mode 100644 kube/base/ingress/ingress-transactor.yaml create mode 100644 kube/base/ingress/kustomization.yaml create mode 100644 kube/base/kustomization.yaml delete mode 100644 kube/cockroach/cockroach-deployment.yaml delete mode 100644 kube/cockroach/cockroach-persistentvolumeclaim.yaml delete mode 100644 kube/cockroach/cockroach-service.yaml delete mode 100644 kube/collaborator/collaborator-deployment.yaml delete mode 100644 kube/collaborator/collaborator-ingress.yaml delete mode 100644 kube/collaborator/collaborator-service.yaml delete mode 100644 kube/config/config.yaml delete mode 100644 kube/config/secret.yaml create mode 100755 kube/deploy.sh delete mode 100644 kube/elastic/elastic-deployment.yaml delete mode 100644 kube/elastic/elastic-service.yaml delete mode 100644 kube/front/front-deployment.yaml delete mode 100644 kube/front/front-service.yaml delete mode 100644 kube/fulltext/fulltext-deployment.yaml delete mode 100644 kube/fulltext/fulltext-service.yaml delete mode 100644 kube/minio/minio-deployment.yaml delete mode 100644 kube/minio/minio-service.yaml create mode 100644 kube/overlays/example/kustomization.yaml delete mode 100644 kube/redpanda/redpanda-deployment.yaml delete mode 100644 kube/redpanda/redpanda-service.yaml delete mode 100644 kube/rekoni/rekoni-deployment.yaml delete mode 100644 kube/rekoni/rekoni-ingress.yaml delete mode 100644 kube/rekoni/rekoni-service.yaml delete mode 100644 kube/stats/stats-deployment.yaml delete mode 100644 kube/stats/stats-ingress.yaml delete mode 100644 kube/stats/stats-service.yaml delete mode 100644 kube/transactor/transactor-deployment.yaml delete mode 100644 kube/transactor/transactor-ingress.yaml delete mode 100644 kube/transactor/transactor-service.yaml delete mode 100644 kube/workspace/workspace-deployment.yaml diff --git a/kube/QUICKSTART.md b/kube/QUICKSTART.md deleted file mode 100644 index 839995f..0000000 --- a/kube/QUICKSTART.md +++ /dev/null @@ -1,101 +0,0 @@ -# Quick Start with Kind -> [!NOTE] -> kind does not require kubectl, but you will not be able to perform some of the examples in our docs without it. To install kubectl see the upstream kubectl installation docs. - -## Install - -**macOS:** -```bash -# For Intel Macs -[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.26.0/kind-darwin-amd64 -# For M1 / ARM Macs -[ $(uname -m) = arm64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.26.0/kind-darwin-arm64 -chmod +x ./kind -mv ./kind /some-dir-in-your-PATH/kind -``` - -**Linux:** -```bash -# For AMD64 / x86_64 -[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.26.0/kind-linux-amd64 -# For ARM64 -[ $(uname -m) = aarch64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.26.0/kind-linux-arm64 -chmod +x ./kind -sudo mv ./kind /usr/local/bin/kind -``` - -## Setup cluster with port forwarding - -> [!NOTE] -> On the host computer, `localhost:80` should be accessible. - -```bash -cat < **Note:** Elasticsearch 7.14.2 is used (not OpenSearch) because Huly's +> fulltext service bundles `elasticsearch-js` which rejects non-Elasticsearch backends. -If you don't have any k8s cluster, consider using the [kind setup](QUICKSTART.md). +## Directory layout -## Check and update configuration +``` +kube/ + base/ + config/ # ConfigMap with URLs and app settings + infra/ # CockroachDB, Redpanda, Elasticsearch, MinIO + app/ # 8 Huly services + ingress/ # 6 nginx Ingress resources (path-based routing) + overlays/ + example/ # Copy this, set your domain + image tags +``` -Huly deployment configuration is located in [config.yaml](config/config.yaml) and [secret.yaml](config/secret.yaml) files. -The sample configuration assume that Huly is available on huly.example hostname with dedicated hostname per service. +## Prerequisites -## Deploy Huly to Kubernetes +- Kubernetes cluster with: + - [ingress-nginx](https://kubernetes.github.io/ingress-nginx/) + - [cert-manager](https://cert-manager.io/) with a `ClusterIssuer` named `letsencrypt-prod` +- `kubectl` configured for your cluster +- DNS A record pointing your domain to the ingress load-balancer IP +- (Optional) Google OAuth credentials for login -Deploy Huly with `kubectl`. +## Quick start ```bash -kubectl create namespace huly-v7 +# 1. Create your overlay (copy the example) +cp -r kube/overlays/example kube/overlays/my-site +# Edit kube/overlays/my-site/kustomization.yaml: +# - Uncomment the patches section +# - Replace huly.yourdomain.com with your actual domain +# - Replace you@yourdomain.com with your admin email +# - Pin image tags to a specific version (e.g., v0.7.382) + +# 2. Create namespace +kubectl create namespace huly -kubectl apply -R -f . --namespace huly-v7 +# 3. Create secrets +SERVER_SECRET=$(openssl rand -hex 32) +CR_PASS=$(openssl rand -hex 16) +RP_PASS=$(openssl rand -hex 16) + +kubectl -n huly create secret generic huly-secret \ + --from-literal=SERVER_SECRET="$SERVER_SECRET" \ + --from-literal=STORAGE_CONFIG='minio|minio?accessKey=minioadmin&secretKey=minioadmin' \ + --from-literal=COCKROACH_PASSWORD="$CR_PASS" \ + --from-literal=REDPANDA_SUPERUSER_PASSWORD="$RP_PASS" \ + --from-literal=CR_DB_URL='postgres://root@cockroach:26257/defaultdb?sslmode=disable' \ + --from-literal=GOOGLE_CLIENT_ID='' \ + --from-literal=GOOGLE_CLIENT_SECRET='' + +# 4. Deploy +kubectl apply -k kube/overlays/my-site/ + +# 5. Watch pods come up +kubectl -n huly get pods -w ``` -Now, launch your web browser and enjoy Huly! +## One-liner deploy + +If you have `envsubst` available, you can deploy with a single command after +creating the namespace and secret above: + +```bash +HULY_DOMAIN=huly.yourdomain.com \ +ADMIN_EMAIL=you@yourdomain.com \ +HULY_VERSION=v0.7.382 \ + bash kube/deploy.sh +``` + +> See the [deploy.sh script](#deploy-script) section below for details. + +## Authentication + +### Google OAuth + +1. Go to [Google Cloud Console](https://console.cloud.google.com/apis/credentials) +2. Create an OAuth 2.0 Client ID (Web application) +3. Add authorized redirect URI: `https:///_accounts/auth/google/callback` +4. Set `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` in `huly-secret` + +### Admin bootstrap + +The first user to sign up creates their workspace and becomes the workspace owner. +Set `ADMIN_EMAILS` in the ConfigMap to grant system-wide admin privileges (comma-separated). + +### Restricting sign-ups + +After creating admin accounts, add `DISABLE_SIGNUP=true` to the account and +front deployments. New users can then only join via workspace invites. + +## Upgrading + +Edit your overlay's `kustomization.yaml` — change all `newTag` values, then: + +```bash +kubectl apply -k kube/overlays/my-site/ +``` + +## Verify + +```bash +# All 12 pods should be Running +kubectl -n huly get pods + +# Front responds +curl -I https:/// + +# Account responds (405 = healthy, POST-only API) +curl -I https:///_accounts + +# CockroachDB admin UI (port-forward) +kubectl -n huly port-forward svc/cockroach 8080:8080 +``` + +## Troubleshooting + +| Symptom | Check | +|---------|-------| +| Pod stuck in `Init` | Infra not ready — `kubectl -n huly logs -c wait-cockroach` | +| Account CrashLoop | DB auth — `kubectl -n huly logs deploy/account` | +| Front CrashLoop | Missing env — check logs for `please provide ` | +| Redpanda won't start | Needs ≥1Gi memory limit | +| Elasticsearch permission denied | Pod spec needs `securityContext.fsGroup: 1000` | +| Fulltext `ProductNotSupportedError` | Must use ES 7.14.2, not OpenSearch | +| WebSocket 502 | Check ingress `proxy-read-timeout: "3600"` annotation | + +## Services + +| Service | Port | Protocol | Needs DB | Needs Redpanda | +|---------|------|----------|----------|----------------| +| front | 8080 | HTTP | - | - | +| account | 3000 | HTTP | yes | yes | +| transactor | 3333 | WebSocket | yes | yes | +| collaborator | 3078 | WebSocket | - | - | +| workspace | - | background | yes | yes | +| fulltext | 4700 | HTTP | yes | yes | +| rekoni | 4004 | HTTP | - | - | +| stats | 4900 | HTTP | - | - | + +## Teardown + +```bash +kubectl delete -k kube/overlays/my-site/ +kubectl -n huly delete secret huly-secret +kubectl delete namespace huly +# PVCs are retained — delete manually if needed: +kubectl -n huly delete pvc --all +``` diff --git a/kube/account/account-ingress.yaml b/kube/account/account-ingress.yaml deleted file mode 100644 index 93a82ce..0000000 --- a/kube/account/account-ingress.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - kubernetes.io/ingress.class: nginx - labels: - app: account - name: account -spec: - ingressClassName: nginx - rules: - - host: account.huly.example - http: - paths: - - backend: - service: - name: account - port: - number: 80 - path: / - pathType: Prefix diff --git a/kube/account/account-service.yaml b/kube/account/account-service.yaml deleted file mode 100644 index 031cca7..0000000 --- a/kube/account/account-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: account - name: account -spec: - ports: - - port: 80 - targetPort: 3000 - selector: - app: account diff --git a/kube/base/app/account/deployment.yaml b/kube/base/app/account/deployment.yaml new file mode 100644 index 0000000..cdbb4a6 --- /dev/null +++ b/kube/base/app/account/deployment.yaml @@ -0,0 +1,109 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: account + labels: + app.kubernetes.io/name: account + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: account + template: + metadata: + labels: + app.kubernetes.io/name: account + spec: + initContainers: + - name: wait-cockroach + image: busybox:1.36 + command: ["sh", "-c", "until nc -z cockroach 26257; do echo waiting for cockroach; sleep 2; done"] + - name: wait-redpanda + image: busybox:1.36 + command: ["sh", "-c", "until nc -z redpanda 9092; do echo waiting for redpanda; sleep 2; done"] + containers: + - name: account + image: hardcoreeng/account:latest + ports: + - name: http + containerPort: 3000 + env: + - name: SERVER_PORT + value: "3000" + - name: ACCOUNT_PORT + value: "3000" + - name: SERVER_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: SERVER_SECRET + - name: DB_URL + valueFrom: + secretKeyRef: + name: huly-secret + key: CR_DB_URL + - name: STORAGE_CONFIG + valueFrom: + secretKeyRef: + name: huly-secret + key: STORAGE_CONFIG + - name: TRANSACTOR_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: TRANSACTOR_URL + - name: FRONT_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: FRONT_URL + - name: ACCOUNTS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: ACCOUNTS_URL + - name: STATS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: STATS_URL + - name: QUEUE_CONFIG + valueFrom: + configMapKeyRef: + name: huly-config + key: QUEUE_CONFIG + - name: MODEL_ENABLED + valueFrom: + configMapKeyRef: + name: huly-config + key: MODEL_ENABLED + - name: GOOGLE_CLIENT_ID + valueFrom: + secretKeyRef: + name: huly-secret + key: GOOGLE_CLIENT_ID + optional: true + - name: GOOGLE_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: GOOGLE_CLIENT_SECRET + optional: true + - name: ADMIN_EMAILS + valueFrom: + configMapKeyRef: + name: huly-config + key: ADMIN_EMAILS + optional: true + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 512Mi + readinessProbe: + tcpSocket: + port: http + initialDelaySeconds: 15 + periodSeconds: 10 diff --git a/kube/base/app/account/service.yaml b/kube/base/app/account/service.yaml new file mode 100644 index 0000000..2b4a92b --- /dev/null +++ b/kube/base/app/account/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: account + labels: + app.kubernetes.io/name: account + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: account + ports: + - name: http + port: 3000 + targetPort: http diff --git a/kube/base/app/collaborator/deployment.yaml b/kube/base/app/collaborator/deployment.yaml new file mode 100644 index 0000000..856678d --- /dev/null +++ b/kube/base/app/collaborator/deployment.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: collaborator + labels: + app.kubernetes.io/name: collaborator + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: collaborator + template: + metadata: + labels: + app.kubernetes.io/name: collaborator + spec: + containers: + - name: collaborator + image: hardcoreeng/collaborator:latest + ports: + - name: ws + containerPort: 3078 + env: + - name: COLLABORATOR_PORT + value: "3078" + - name: SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: SERVER_SECRET + - name: ACCOUNTS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: ACCOUNTS_URL_INTERNAL + - name: STATS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: STATS_URL_INTERNAL + - name: STORAGE_CONFIG + valueFrom: + secretKeyRef: + name: huly-secret + key: STORAGE_CONFIG + readinessProbe: + tcpSocket: + port: ws + initialDelaySeconds: 15 + periodSeconds: 10 + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 512Mi diff --git a/kube/base/app/collaborator/service.yaml b/kube/base/app/collaborator/service.yaml new file mode 100644 index 0000000..6a0f079 --- /dev/null +++ b/kube/base/app/collaborator/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: collaborator + labels: + app.kubernetes.io/name: collaborator + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: collaborator + ports: + - name: ws + port: 3078 + targetPort: ws diff --git a/kube/base/app/front/deployment.yaml b/kube/base/app/front/deployment.yaml new file mode 100644 index 0000000..04b365b --- /dev/null +++ b/kube/base/app/front/deployment.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: front + labels: + app.kubernetes.io/name: front + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: front + template: + metadata: + labels: + app.kubernetes.io/name: front + spec: + containers: + - name: front + image: hardcoreeng/front:latest + ports: + - name: http + containerPort: 8080 + env: + - name: SERVER_PORT + value: "8080" + - name: SERVER_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: SERVER_SECRET + - name: STORAGE_CONFIG + valueFrom: + secretKeyRef: + name: huly-secret + key: STORAGE_CONFIG + envFrom: + - configMapRef: + name: huly-config + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 512Mi + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 diff --git a/kube/base/app/front/service.yaml b/kube/base/app/front/service.yaml new file mode 100644 index 0000000..1425ce6 --- /dev/null +++ b/kube/base/app/front/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: front + labels: + app.kubernetes.io/name: front + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: front + ports: + - name: http + port: 8080 + targetPort: http diff --git a/kube/base/app/fulltext/deployment.yaml b/kube/base/app/fulltext/deployment.yaml new file mode 100644 index 0000000..25a148e --- /dev/null +++ b/kube/base/app/fulltext/deployment.yaml @@ -0,0 +1,90 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fulltext + labels: + app.kubernetes.io/name: fulltext + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: fulltext + template: + metadata: + labels: + app.kubernetes.io/name: fulltext + spec: + initContainers: + - name: wait-cockroach + image: busybox:1.36 + command: ["sh", "-c", "until nc -z cockroach 26257; do echo waiting for cockroach; sleep 2; done"] + - name: wait-redpanda + image: busybox:1.36 + command: ["sh", "-c", "until nc -z redpanda 9092; do echo waiting for redpanda; sleep 2; done"] + - name: wait-elastic + image: busybox:1.36 + command: ["sh", "-c", "until nc -z elastic 9200; do echo waiting for elastic; sleep 2; done"] + containers: + - name: fulltext + image: hardcoreeng/fulltext:latest + ports: + - name: http + containerPort: 4700 + env: + - name: SERVER_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: SERVER_SECRET + - name: DB_URL + valueFrom: + secretKeyRef: + name: huly-secret + key: CR_DB_URL + - name: FULLTEXT_DB_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: ELASTIC_URL + - name: ELASTIC_INDEX_NAME + valueFrom: + configMapKeyRef: + name: huly-config + key: ELASTIC_INDEX_NAME + - name: STORAGE_CONFIG + valueFrom: + secretKeyRef: + name: huly-secret + key: STORAGE_CONFIG + - name: REKONI_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: REKONI_URL_INTERNAL + - name: ACCOUNTS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: ACCOUNTS_URL_INTERNAL + - name: STATS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: STATS_URL_INTERNAL + - name: QUEUE_CONFIG + valueFrom: + configMapKeyRef: + name: huly-config + key: QUEUE_CONFIG + readinessProbe: + tcpSocket: + port: http + initialDelaySeconds: 15 + periodSeconds: 10 + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 512Mi diff --git a/kube/base/app/fulltext/service.yaml b/kube/base/app/fulltext/service.yaml new file mode 100644 index 0000000..5829885 --- /dev/null +++ b/kube/base/app/fulltext/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: fulltext + labels: + app.kubernetes.io/name: fulltext + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: fulltext + ports: + - name: http + port: 4700 + targetPort: http diff --git a/kube/base/app/kustomization.yaml b/kube/base/app/kustomization.yaml new file mode 100644 index 0000000..10ab7e2 --- /dev/null +++ b/kube/base/app/kustomization.yaml @@ -0,0 +1,18 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - front/deployment.yaml + - front/service.yaml + - account/deployment.yaml + - account/service.yaml + - transactor/deployment.yaml + - transactor/service.yaml + - collaborator/deployment.yaml + - collaborator/service.yaml + - workspace/deployment.yaml + - fulltext/deployment.yaml + - fulltext/service.yaml + - rekoni/deployment.yaml + - rekoni/service.yaml + - stats/deployment.yaml + - stats/service.yaml diff --git a/kube/base/app/rekoni/deployment.yaml b/kube/base/app/rekoni/deployment.yaml new file mode 100644 index 0000000..bf41a9b --- /dev/null +++ b/kube/base/app/rekoni/deployment.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: rekoni + labels: + app.kubernetes.io/name: rekoni + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: rekoni + template: + metadata: + labels: + app.kubernetes.io/name: rekoni + spec: + containers: + - name: rekoni + image: hardcoreeng/rekoni-service:latest + ports: + - name: http + containerPort: 4004 + env: + - name: SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: SERVER_SECRET + readinessProbe: + tcpSocket: + port: http + initialDelaySeconds: 15 + periodSeconds: 10 + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 512Mi diff --git a/kube/base/app/rekoni/service.yaml b/kube/base/app/rekoni/service.yaml new file mode 100644 index 0000000..c6f0367 --- /dev/null +++ b/kube/base/app/rekoni/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: rekoni + labels: + app.kubernetes.io/name: rekoni + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: rekoni + ports: + - name: http + port: 4004 + targetPort: http diff --git a/kube/base/app/stats/deployment.yaml b/kube/base/app/stats/deployment.yaml new file mode 100644 index 0000000..7667eab --- /dev/null +++ b/kube/base/app/stats/deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: stats + labels: + app.kubernetes.io/name: stats + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: stats + template: + metadata: + labels: + app.kubernetes.io/name: stats + spec: + containers: + - name: stats + image: hardcoreeng/stats:latest + ports: + - name: http + containerPort: 4900 + env: + - name: PORT + value: "4900" + - name: SERVER_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: SERVER_SECRET + readinessProbe: + tcpSocket: + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + memory: 256Mi diff --git a/kube/base/app/stats/service.yaml b/kube/base/app/stats/service.yaml new file mode 100644 index 0000000..d93af65 --- /dev/null +++ b/kube/base/app/stats/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: stats + labels: + app.kubernetes.io/name: stats + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: stats + ports: + - name: http + port: 4900 + targetPort: http diff --git a/kube/base/app/transactor/deployment.yaml b/kube/base/app/transactor/deployment.yaml new file mode 100644 index 0000000..bca2133 --- /dev/null +++ b/kube/base/app/transactor/deployment.yaml @@ -0,0 +1,89 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: transactor + labels: + app.kubernetes.io/name: transactor + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: transactor + template: + metadata: + labels: + app.kubernetes.io/name: transactor + spec: + initContainers: + - name: wait-cockroach + image: busybox:1.36 + command: ["sh", "-c", "until nc -z cockroach 26257; do echo waiting for cockroach; sleep 2; done"] + - name: wait-redpanda + image: busybox:1.36 + command: ["sh", "-c", "until nc -z redpanda 9092; do echo waiting for redpanda; sleep 2; done"] + containers: + - name: transactor + image: hardcoreeng/transactor:latest + ports: + - name: ws + containerPort: 3333 + env: + - name: SERVER_PORT + value: "3333" + - name: SERVER_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: SERVER_SECRET + - name: DB_URL + valueFrom: + secretKeyRef: + name: huly-secret + key: CR_DB_URL + - name: STORAGE_CONFIG + valueFrom: + secretKeyRef: + name: huly-secret + key: STORAGE_CONFIG + - name: ACCOUNTS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: ACCOUNTS_URL_INTERNAL + - name: FULLTEXT_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: FULLTEXT_URL + - name: STATS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: STATS_URL_INTERNAL + - name: FRONT_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: FRONT_URL + - name: QUEUE_CONFIG + valueFrom: + configMapKeyRef: + name: huly-config + key: QUEUE_CONFIG + - name: LAST_NAME_FIRST + valueFrom: + configMapKeyRef: + name: huly-config + key: LAST_NAME_FIRST + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + memory: 1Gi + readinessProbe: + tcpSocket: + port: ws + initialDelaySeconds: 15 + periodSeconds: 10 diff --git a/kube/base/app/transactor/service.yaml b/kube/base/app/transactor/service.yaml new file mode 100644 index 0000000..d2c8a0d --- /dev/null +++ b/kube/base/app/transactor/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: transactor + labels: + app.kubernetes.io/name: transactor + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: transactor + ports: + - name: ws + port: 3333 + targetPort: ws diff --git a/kube/account/account-deployment.yaml b/kube/base/app/workspace/deployment.yaml similarity index 52% rename from kube/account/account-deployment.yaml rename to kube/base/app/workspace/deployment.yaml index 3d10ebd..6a55b53 100644 --- a/kube/account/account-deployment.yaml +++ b/kube/base/app/workspace/deployment.yaml @@ -1,69 +1,79 @@ apiVersion: apps/v1 kind: Deployment metadata: + name: workspace labels: - app: account - name: account + app.kubernetes.io/name: workspace + app.kubernetes.io/part-of: huly spec: replicas: 1 selector: matchLabels: - app: account + app.kubernetes.io/name: workspace template: metadata: labels: - app: account + app.kubernetes.io/name: workspace spec: + initContainers: + - name: wait-cockroach + image: busybox:1.36 + command: ["sh", "-c", "until nc -z cockroach 26257; do echo waiting for cockroach; sleep 2; done"] + - name: wait-redpanda + image: busybox:1.36 + command: ["sh", "-c", "until nc -z redpanda 9092; do echo waiting for redpanda; sleep 2; done"] containers: - - env: - - name: ACCOUNTS_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: ACCOUNTS_URL - - name: ACCOUNT_PORT - value: '3000' - - name: FRONT_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: FRONT_URL - - name: STATS_URL - value: http://stats - - name: STORAGE_CONFIG + - name: workspace + image: hardcoreeng/workspace:latest + env: + - name: SERVER_SECRET valueFrom: secretKeyRef: name: huly-secret - key: STORAGE_CONFIG - - name: MODEL_ENABLED - value: '*' + key: SERVER_SECRET - name: DB_URL valueFrom: secretKeyRef: name: huly-secret key: CR_DB_URL - - name: MONGO_URL + - name: ACCOUNTS_DB_URL valueFrom: - configMapKeyRef: - name: huly-config - key: MONGO_URL - - name: SERVER_SECRET + secretKeyRef: + name: huly-secret + key: CR_DB_URL + - name: STORAGE_CONFIG valueFrom: secretKeyRef: name: huly-secret - key: SERVER_SECRET + key: STORAGE_CONFIG + - name: ACCOUNTS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: ACCOUNTS_URL_INTERNAL + - name: STATS_URL + valueFrom: + configMapKeyRef: + name: huly-config + key: STATS_URL_INTERNAL - name: TRANSACTOR_URL valueFrom: configMapKeyRef: name: huly-config key: TRANSACTOR_URL - name: QUEUE_CONFIG - value: redpanda:9092 - image: hardcoreeng/account:v0.7.382 - name: account - ports: - - containerPort: 3000 + valueFrom: + configMapKeyRef: + name: huly-config + key: QUEUE_CONFIG + - name: MODEL_ENABLED + valueFrom: + configMapKeyRef: + name: huly-config + key: MODEL_ENABLED resources: + requests: + cpu: 50m + memory: 128Mi limits: - memory: "512M" - restartPolicy: Always + memory: 512Mi diff --git a/kube/base/config/configmap.yaml b/kube/base/config/configmap.yaml new file mode 100644 index 0000000..4d56756 --- /dev/null +++ b/kube/base/config/configmap.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: huly-config +data: + # External URLs — override these in your overlay + ACCOUNTS_URL: "https://huly.example/_accounts" + COLLABORATOR_URL: "wss://huly.example/_collaborator" + FRONT_URL: "https://huly.example" + REKONI_URL: "https://huly.example/_rekoni" + STATS_URL: "https://huly.example/_stats" + TRANSACTOR_URL: "ws://transactor:3333;wss://huly.example/_transactor" + # Internal URLs (no need to override) + ELASTIC_URL: "http://elastic:9200" + ELASTIC_INDEX_NAME: "huly_storage_index" + FULLTEXT_URL: "http://fulltext:4700" + ACCOUNTS_URL_INTERNAL: "http://account:3000" + REKONI_URL_INTERNAL: "http://rekoni:4004" + STATS_URL_INTERNAL: "http://stats:4900" + QUEUE_CONFIG: "redpanda:9092" + # App settings + MODEL_ENABLED: "*" + LAST_NAME_FIRST: "true" + TITLE: "Huly Self Host" + DEFAULT_LANGUAGE: "en" + UPLOAD_URL: "/files" + ADMIN_EMAILS: "admin@example.com" + # Optional integration URLs (required by front even if unused) + GMAIL_URL: "https://huly.example/_gmail" + TELEGRAM_URL: "https://huly.example/_telegram" + CALENDAR_URL: "https://huly.example/_calendar" + LOVE_ENDPOINT: "https://huly.example/_love" diff --git a/kube/base/config/kustomization.yaml b/kube/base/config/kustomization.yaml new file mode 100644 index 0000000..9fb65fa --- /dev/null +++ b/kube/base/config/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - configmap.yaml diff --git a/kube/base/infra/cockroach/deployment.yaml b/kube/base/infra/cockroach/deployment.yaml new file mode 100644 index 0000000..5623964 --- /dev/null +++ b/kube/base/infra/cockroach/deployment.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cockroach + labels: + app.kubernetes.io/name: cockroach + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: cockroach + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/name: cockroach + spec: + containers: + - name: cockroach + image: cockroachdb/cockroach:latest-v24.2 + command: ["cockroach"] + args: ["start-single-node", "--insecure"] + ports: + - name: sql + containerPort: 26257 + - name: http + containerPort: 8080 + env: + - name: COCKROACH_DATABASE + value: "defaultdb" + volumeMounts: + - name: data + mountPath: /cockroach/cockroach-data + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + memory: 2Gi + readinessProbe: + httpGet: + path: /health?ready=1 + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + volumes: + - name: data + persistentVolumeClaim: + claimName: cockroach-data diff --git a/kube/base/infra/cockroach/pvc.yaml b/kube/base/infra/cockroach/pvc.yaml new file mode 100644 index 0000000..edad5d5 --- /dev/null +++ b/kube/base/infra/cockroach/pvc.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: cockroach-data + labels: + app.kubernetes.io/name: cockroach + app.kubernetes.io/part-of: huly +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/kube/base/infra/cockroach/service.yaml b/kube/base/infra/cockroach/service.yaml new file mode 100644 index 0000000..60471ed --- /dev/null +++ b/kube/base/infra/cockroach/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: cockroach + labels: + app.kubernetes.io/name: cockroach + app.kubernetes.io/part-of: huly +spec: + clusterIP: None + selector: + app.kubernetes.io/name: cockroach + ports: + - name: sql + port: 26257 + targetPort: sql + - name: http + port: 8080 + targetPort: http diff --git a/kube/base/infra/elastic/deployment.yaml b/kube/base/infra/elastic/deployment.yaml new file mode 100644 index 0000000..add95b1 --- /dev/null +++ b/kube/base/infra/elastic/deployment.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: elastic + labels: + app.kubernetes.io/name: elastic + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: elastic + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/name: elastic + spec: + initContainers: + - name: sysctl + image: busybox:1.36 + command: ["sh", "-c", "sysctl -w vm.max_map_count=262144 || true"] + securityContext: + privileged: true + securityContext: + fsGroup: 1000 + runAsUser: 1000 + runAsGroup: 1000 + containers: + - name: elasticsearch + image: elasticsearch:7.14.2 + command: + - sh + - -c + - | + if ! /usr/share/elasticsearch/bin/elasticsearch-plugin list | grep -q ingest-attachment; then + /usr/share/elasticsearch/bin/elasticsearch-plugin install --batch ingest-attachment + fi + exec /usr/local/bin/docker-entrypoint.sh eswrapper + ports: + - name: http + containerPort: 9200 + env: + - name: discovery.type + value: "single-node" + - name: ES_JAVA_OPTS + value: "-Xms512m -Xmx512m" + - name: http.cors.enabled + value: "true" + - name: http.cors.allow-origin + value: "*" + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data + resources: + requests: + cpu: 200m + memory: 768Mi + limits: + memory: 1536Mi + readinessProbe: + httpGet: + path: /_cluster/health + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + volumes: + - name: data + persistentVolumeClaim: + claimName: elastic-data diff --git a/kube/redpanda/redpanda-persistentvolumeclaim.yaml b/kube/base/infra/elastic/pvc.yaml similarity index 53% rename from kube/redpanda/redpanda-persistentvolumeclaim.yaml rename to kube/base/infra/elastic/pvc.yaml index fa24440..32f339a 100644 --- a/kube/redpanda/redpanda-persistentvolumeclaim.yaml +++ b/kube/base/infra/elastic/pvc.yaml @@ -1,12 +1,13 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: + name: elastic-data labels: - app: redpanda - name: redpanda + app.kubernetes.io/name: elastic + app.kubernetes.io/part-of: huly spec: accessModes: - ReadWriteOnce resources: requests: - storage: 100Mi + storage: 10Gi diff --git a/kube/base/infra/elastic/service.yaml b/kube/base/infra/elastic/service.yaml new file mode 100644 index 0000000..b4d8074 --- /dev/null +++ b/kube/base/infra/elastic/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: elastic + labels: + app.kubernetes.io/name: elastic + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: elastic + ports: + - name: http + port: 9200 + targetPort: http diff --git a/kube/base/infra/kustomization.yaml b/kube/base/infra/kustomization.yaml new file mode 100644 index 0000000..6435bd5 --- /dev/null +++ b/kube/base/infra/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - cockroach/deployment.yaml + - cockroach/service.yaml + - cockroach/pvc.yaml + - redpanda/deployment.yaml + - redpanda/service.yaml + - redpanda/pvc.yaml + - elastic/deployment.yaml + - elastic/service.yaml + - elastic/pvc.yaml + - minio/deployment.yaml + - minio/service.yaml + - minio/pvc.yaml diff --git a/kube/base/infra/minio/deployment.yaml b/kube/base/infra/minio/deployment.yaml new file mode 100644 index 0000000..a7dcc47 --- /dev/null +++ b/kube/base/infra/minio/deployment.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: minio + labels: + app.kubernetes.io/name: minio + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: minio + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/name: minio + spec: + containers: + - name: minio + image: minio/minio:latest + command: ["minio"] + args: ["server", "/data", "--address", ":9000", "--console-address", ":9001"] + ports: + - name: api + containerPort: 9000 + - name: console + containerPort: 9001 + volumeMounts: + - name: data + mountPath: /data + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + memory: 512Mi + readinessProbe: + httpGet: + path: /minio/health/ready + port: api + initialDelaySeconds: 10 + periodSeconds: 10 + volumes: + - name: data + persistentVolumeClaim: + claimName: minio-data diff --git a/kube/minio/files-persistentvolumeclaim.yaml b/kube/base/infra/minio/pvc.yaml similarity index 54% rename from kube/minio/files-persistentvolumeclaim.yaml rename to kube/base/infra/minio/pvc.yaml index af0754d..b37a842 100644 --- a/kube/minio/files-persistentvolumeclaim.yaml +++ b/kube/base/infra/minio/pvc.yaml @@ -1,12 +1,13 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: + name: minio-data labels: - app: files - name: files + app.kubernetes.io/name: minio + app.kubernetes.io/part-of: huly spec: accessModes: - ReadWriteOnce resources: requests: - storage: 100Mi + storage: 10Gi diff --git a/kube/base/infra/minio/service.yaml b/kube/base/infra/minio/service.yaml new file mode 100644 index 0000000..9568bab --- /dev/null +++ b/kube/base/infra/minio/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: minio + labels: + app.kubernetes.io/name: minio + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: minio + ports: + - name: api + port: 9000 + targetPort: api + - name: console + port: 9001 + targetPort: console diff --git a/kube/base/infra/redpanda/deployment.yaml b/kube/base/infra/redpanda/deployment.yaml new file mode 100644 index 0000000..8f3c4bd --- /dev/null +++ b/kube/base/infra/redpanda/deployment.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redpanda + labels: + app.kubernetes.io/name: redpanda + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: redpanda + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/name: redpanda + spec: + securityContext: + fsGroup: 101 + runAsUser: 101 + runAsGroup: 101 + containers: + - name: redpanda + image: docker.redpanda.com/redpandadata/redpanda:v24.3.6 + command: ["rpk"] + args: + - "redpanda" + - "start" + - "--kafka-addr" + - "internal://0.0.0.0:9092" + - "--advertise-kafka-addr" + - "internal://redpanda:9092" + - "--rpc-addr" + - "0.0.0.0:33145" + - "--advertise-rpc-addr" + - "redpanda:33145" + - "--mode" + - "dev-container" + - "--smp" + - "1" + - "--default-log-level=info" + ports: + - name: kafka + containerPort: 9092 + - name: rpc + containerPort: 33145 + env: + - name: REDPANDA_SUPERUSER_USERNAME + value: "admin" + - name: REDPANDA_SUPERUSER_PASSWORD + valueFrom: + secretKeyRef: + name: huly-secret + key: REDPANDA_SUPERUSER_PASSWORD + volumeMounts: + - name: data + mountPath: /var/lib/redpanda/data + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + memory: 1536Mi + readinessProbe: + exec: + command: ["rpk", "cluster", "info"] + initialDelaySeconds: 15 + periodSeconds: 10 + volumes: + - name: data + persistentVolumeClaim: + claimName: redpanda-data diff --git a/kube/elastic/elastic-persistentvolumeclaim.yaml b/kube/base/infra/redpanda/pvc.yaml similarity index 53% rename from kube/elastic/elastic-persistentvolumeclaim.yaml rename to kube/base/infra/redpanda/pvc.yaml index 54049c0..a28acd6 100644 --- a/kube/elastic/elastic-persistentvolumeclaim.yaml +++ b/kube/base/infra/redpanda/pvc.yaml @@ -1,12 +1,13 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: + name: redpanda-data labels: - app: elastic - name: elastic + app.kubernetes.io/name: redpanda + app.kubernetes.io/part-of: huly spec: accessModes: - ReadWriteOnce resources: requests: - storage: 100Mi + storage: 5Gi diff --git a/kube/base/infra/redpanda/service.yaml b/kube/base/infra/redpanda/service.yaml new file mode 100644 index 0000000..ae92ffe --- /dev/null +++ b/kube/base/infra/redpanda/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: redpanda + labels: + app.kubernetes.io/name: redpanda + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: redpanda + ports: + - name: kafka + port: 9092 + targetPort: kafka + - name: rpc + port: 33145 + targetPort: rpc diff --git a/kube/base/ingress/ingress-accounts.yaml b/kube/base/ingress/ingress-accounts.yaml new file mode 100644 index 0000000..7b5012f --- /dev/null +++ b/kube/base/ingress/ingress-accounts.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: huly-accounts + labels: + app.kubernetes.io/part-of: huly + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$2 +spec: + ingressClassName: nginx + tls: + - hosts: + - huly.example + secretName: huly-tls + rules: + - host: huly.example + http: + paths: + - path: /_accounts(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: account + port: + number: 3000 diff --git a/kube/base/ingress/ingress-collaborator.yaml b/kube/base/ingress/ingress-collaborator.yaml new file mode 100644 index 0000000..5795a3c --- /dev/null +++ b/kube/base/ingress/ingress-collaborator.yaml @@ -0,0 +1,30 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: huly-collaborator + labels: + app.kubernetes.io/part-of: huly + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$2 + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-http-version: "1.1" +spec: + ingressClassName: nginx + tls: + - hosts: + - huly.example + secretName: huly-tls + rules: + - host: huly.example + http: + paths: + - path: /_collaborator(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: collaborator + port: + number: 3078 diff --git a/kube/front/front-ingress.yaml b/kube/base/ingress/ingress-front.yaml similarity index 52% rename from kube/front/front-ingress.yaml rename to kube/base/ingress/ingress-front.yaml index 675de0b..6a973d1 100644 --- a/kube/front/front-ingress.yaml +++ b/kube/base/ingress/ingress-front.yaml @@ -1,21 +1,25 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - annotations: - kubernetes.io/ingress.class: nginx + name: huly-front labels: - app: front - name: front + app.kubernetes.io/part-of: huly + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: nginx + tls: + - hosts: + - huly.example + secretName: huly-tls rules: - host: huly.example http: paths: - - backend: + - path: / + pathType: Prefix + backend: service: name: front port: - number: 80 - path: / - pathType: Prefix + number: 8080 diff --git a/kube/base/ingress/ingress-rekoni.yaml b/kube/base/ingress/ingress-rekoni.yaml new file mode 100644 index 0000000..714b177 --- /dev/null +++ b/kube/base/ingress/ingress-rekoni.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: huly-rekoni + labels: + app.kubernetes.io/part-of: huly + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$2 +spec: + ingressClassName: nginx + tls: + - hosts: + - huly.example + secretName: huly-tls + rules: + - host: huly.example + http: + paths: + - path: /_rekoni(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: rekoni + port: + number: 4004 diff --git a/kube/base/ingress/ingress-stats.yaml b/kube/base/ingress/ingress-stats.yaml new file mode 100644 index 0000000..69ae0e1 --- /dev/null +++ b/kube/base/ingress/ingress-stats.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: huly-stats + labels: + app.kubernetes.io/part-of: huly + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$2 +spec: + ingressClassName: nginx + tls: + - hosts: + - huly.example + secretName: huly-tls + rules: + - host: huly.example + http: + paths: + - path: /_stats(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: stats + port: + number: 4900 diff --git a/kube/base/ingress/ingress-transactor.yaml b/kube/base/ingress/ingress-transactor.yaml new file mode 100644 index 0000000..8459ba1 --- /dev/null +++ b/kube/base/ingress/ingress-transactor.yaml @@ -0,0 +1,30 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: huly-transactor + labels: + app.kubernetes.io/part-of: huly + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$2 + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-http-version: "1.1" +spec: + ingressClassName: nginx + tls: + - hosts: + - huly.example + secretName: huly-tls + rules: + - host: huly.example + http: + paths: + - path: /_transactor(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: transactor + port: + number: 3333 diff --git a/kube/base/ingress/kustomization.yaml b/kube/base/ingress/kustomization.yaml new file mode 100644 index 0000000..bf46078 --- /dev/null +++ b/kube/base/ingress/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ingress-front.yaml + - ingress-accounts.yaml + - ingress-transactor.yaml + - ingress-collaborator.yaml + - ingress-rekoni.yaml + - ingress-stats.yaml diff --git a/kube/base/kustomization.yaml b/kube/base/kustomization.yaml new file mode 100644 index 0000000..cec20a7 --- /dev/null +++ b/kube/base/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - config/ + - infra/ + - app/ + - ingress/ diff --git a/kube/cockroach/cockroach-deployment.yaml b/kube/cockroach/cockroach-deployment.yaml deleted file mode 100644 index b761991..0000000 --- a/kube/cockroach/cockroach-deployment.yaml +++ /dev/null @@ -1,52 +0,0 @@ - apiVersion: apps/v1 - kind: Deployment - metadata: - name: cockroachdb-single-node - spec: - replicas: 1 - selector: - matchLabels: - app: cockroach - template: - metadata: - labels: - app: cockroach - spec: - # initContainers: - # - name: init-certs-dir - # image: busybox - # command: ['sh', '-c', 'mkdir -p /cockroach/cockroach-certs && chmod -R 700 /cockroach'] - # volumeMounts: - # - name: certs - # mountPath: /cockroach/certs - containers: - - name: cockroachdb - image: cockroachdb/cockroach:latest-v24.2 - args: - - start-single-node - - --accept-sql-without-tls - env: - - name: COCKROACH_DATABASE - value: "defaultdb" - - name: COCKROACH_USER - value: "selfhost" - - name: COCKROACH_PASSWORD - valueFrom: - secretKeyRef: - name: huly-secret - key: COCKROACH_PASSWORD - ports: - - containerPort: 26257 - - containerPort: 8080 - volumeMounts: - - name: cockroachdb-data - mountPath: /cockroach/cockroach-data - - name: cockroachdb-certs - mountPath: /cockroach/certs - volumes: - - name: cockroachdb-data - persistentVolumeClaim: - claimName: cockroachdb-data - - name: cockroachdb-certs - persistentVolumeClaim: - claimName: cockroachdb-certs \ No newline at end of file diff --git a/kube/cockroach/cockroach-persistentvolumeclaim.yaml b/kube/cockroach/cockroach-persistentvolumeclaim.yaml deleted file mode 100644 index 1f02264..0000000 --- a/kube/cockroach/cockroach-persistentvolumeclaim.yaml +++ /dev/null @@ -1,21 +0,0 @@ - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: cockroachdb-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi ---- - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: cockroachdb-certs - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Mi \ No newline at end of file diff --git a/kube/cockroach/cockroach-service.yaml b/kube/cockroach/cockroach-service.yaml deleted file mode 100644 index 51edf28..0000000 --- a/kube/cockroach/cockroach-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ - apiVersion: v1 - kind: Service - metadata: - labels: - app: cockroach - name: cockroach - spec: - selector: - app: cockroach - ports: - - name: grpc - port: 26257 - targetPort: 26257 - - name: http - port: 8080 - targetPort: 8080 - clusterIP: None \ No newline at end of file diff --git a/kube/collaborator/collaborator-deployment.yaml b/kube/collaborator/collaborator-deployment.yaml deleted file mode 100644 index 2bc9293..0000000 --- a/kube/collaborator/collaborator-deployment.yaml +++ /dev/null @@ -1,42 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: collaborator - name: collaborator -spec: - replicas: 1 - selector: - matchLabels: - app: collaborator - template: - metadata: - labels: - app: collaborator - spec: - containers: - - env: - - name: ACCOUNTS_URL - value: http://account - - name: STATS_URL - value: http://stats - - name: COLLABORATOR_PORT - value: "3078" - - name: STORAGE_CONFIG - valueFrom: - secretKeyRef: - name: huly-secret - key: STORAGE_CONFIG - - name: SECRET - valueFrom: - secretKeyRef: - name: huly-secret - key: SERVER_SECRET - image: hardcoreeng/collaborator:v0.7.382 - name: collaborator - ports: - - containerPort: 3078 - resources: - limits: - memory: '512M' - restartPolicy: Always diff --git a/kube/collaborator/collaborator-ingress.yaml b/kube/collaborator/collaborator-ingress.yaml deleted file mode 100644 index 2091140..0000000 --- a/kube/collaborator/collaborator-ingress.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - kubernetes.io/ingress.class: nginx - labels: - app: collaborator - name: collaborator -spec: - ingressClassName: nginx - rules: - - host: collaborator.huly.example - http: - paths: - - backend: - service: - name: collaborator - port: - number: 80 - path: / - pathType: Prefix diff --git a/kube/collaborator/collaborator-service.yaml b/kube/collaborator/collaborator-service.yaml deleted file mode 100644 index cb5db83..0000000 --- a/kube/collaborator/collaborator-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: collaborator - name: collaborator -spec: - ports: - - port: 80 - targetPort: 3078 - selector: - app: collaborator diff --git a/kube/config/config.yaml b/kube/config/config.yaml deleted file mode 100644 index 257e28d..0000000 --- a/kube/config/config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: huly-config -data: - ACCOUNTS_URL: 'http://account.huly.example/' - COLLABORATOR_URL: 'ws://collaborator.huly.example/' - FRONT_URL: 'http://huly.example' - REKONI_URL: 'http://rekoni.huly.example/' - STATS_URL: 'http://stats.huly.example/' - TRANSACTOR_URL: 'ws://transactor;ws://transactor.huly.example/' - MINIO_ENDPOINT: 'minio' - MONGO_URL: 'mongodb://mongodb:27017' - ELASTIC_URL: 'http://elastic:9200' - ELASTIC_INDEX_NAME: 'huly_storage_index' diff --git a/kube/config/secret.yaml b/kube/config/secret.yaml deleted file mode 100644 index e95e3cf..0000000 --- a/kube/config/secret.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: huly-secret -type: Opaque -stringData: - SERVER_SECRET: secret - STORAGE_CONFIG: minio|minio?accessKey=minioadmin&secretKey=minioadmin - COCKROACH_PASSWORD: cockroach_user_secret - REDPANDA_SUPERUSER_PASSWORD: superpassword - CR_DB_URL: postgres://selfhost:cockroach_user_secret@cockroach:26257/defaultdb \ No newline at end of file diff --git a/kube/deploy.sh b/kube/deploy.sh new file mode 100755 index 0000000..06250fb --- /dev/null +++ b/kube/deploy.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash +# Quick deploy script for Huly on Kubernetes. +# +# Prerequisites: kubectl, kustomize (or kubectl >= 1.14), cert-manager, +# ingress-nginx, DNS A record for $HULY_DOMAIN +# +# Usage: +# HULY_DOMAIN=huly.yourdomain.com \ +# ADMIN_EMAIL=you@yourdomain.com \ +# HULY_VERSION=v0.7.382 \ +# GOOGLE_CLIENT_ID=xxx \ +# GOOGLE_CLIENT_SECRET=yyy \ +# bash kube/deploy.sh +# +# Optional: +# HULY_NAMESPACE (default: huly) +# HULY_VERSION (default: latest) + +set -euo pipefail + +: "${HULY_DOMAIN:?Set HULY_DOMAIN to your Huly hostname (e.g. huly.yourdomain.com)}" +: "${ADMIN_EMAIL:=admin@example.com}" +: "${HULY_VERSION:=latest}" +: "${HULY_NAMESPACE:=huly}" +: "${GOOGLE_CLIENT_ID:=}" +: "${GOOGLE_CLIENT_SECRET:=}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TMPDIR="$(mktemp -d)" +trap 'rm -rf "$TMPDIR"' EXIT + +echo "==> Deploying Huly to namespace '$HULY_NAMESPACE' at https://$HULY_DOMAIN" + +# 1. Create namespace +kubectl create namespace "$HULY_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - + +# 2. Create/update secret +SERVER_SECRET=$(openssl rand -hex 32) +CR_PASS=$(openssl rand -hex 16) +RP_PASS=$(openssl rand -hex 16) + +kubectl -n "$HULY_NAMESPACE" create secret generic huly-secret \ + --from-literal=SERVER_SECRET="$SERVER_SECRET" \ + --from-literal=STORAGE_CONFIG='minio|minio?accessKey=minioadmin&secretKey=minioadmin' \ + --from-literal=COCKROACH_PASSWORD="$CR_PASS" \ + --from-literal=REDPANDA_SUPERUSER_PASSWORD="$RP_PASS" \ + --from-literal=CR_DB_URL='postgres://root@cockroach:26257/defaultdb?sslmode=disable' \ + --from-literal=GOOGLE_CLIENT_ID="$GOOGLE_CLIENT_ID" \ + --from-literal=GOOGLE_CLIENT_SECRET="$GOOGLE_CLIENT_SECRET" \ + --dry-run=client -o yaml | kubectl apply -f - + +# 3. Generate overlay with user's domain +cat > "$TMPDIR/kustomization.yaml" < Huly deployed! Waiting for pods..." +kubectl -n "$HULY_NAMESPACE" get pods +echo "" +echo "Visit https://$HULY_DOMAIN once all pods are Running." diff --git a/kube/elastic/elastic-deployment.yaml b/kube/elastic/elastic-deployment.yaml deleted file mode 100644 index 45651ff..0000000 --- a/kube/elastic/elastic-deployment.yaml +++ /dev/null @@ -1,66 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: elastic - name: elastic -spec: - replicas: 1 - selector: - matchLabels: - app: elastic - strategy: - type: Recreate - template: - metadata: - labels: - app: elastic - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - containers: - - args: - - /bin/sh - - -c - - |- - chown -R 1000:1000 /usr/share/elasticsearch/data; - apt-get update && apt-get install -y curl; - ./bin/elasticsearch-plugin list | grep -q ingest-attachment || yes | ./bin/elasticsearch-plugin install --silent ingest-attachment; - /usr/local/bin/docker-entrypoint.sh eswrapper - env: - - name: BITNAMI_DEBUG - value: "true" - - name: ELASTICSEARCH_PORT_NUMBER - value: "9200" - - name: ES_JAVA_OPTS - value: -Xms1024m -Xmx1024m - - name: discovery.type - value: single-node - - name: http.cors.allow-origin - value: http://localhost:8082 - - name: http.cors.enabled - value: "true" - image: elasticsearch:7.14.2 - livenessProbe: - exec: - command: - - /bin/sh - - -c - - curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"' - initialDelaySeconds: 60 - periodSeconds: 20 - failureThreshold: 10 - name: elastic - ports: - - containerPort: 9200 - protocol: TCP - volumeMounts: - - mountPath: /usr/share/elasticsearch/data - name: elastic - restartPolicy: Always - volumes: - - name: elastic - persistentVolumeClaim: - claimName: elastic diff --git a/kube/elastic/elastic-service.yaml b/kube/elastic/elastic-service.yaml deleted file mode 100644 index 656d7be..0000000 --- a/kube/elastic/elastic-service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - annotations: - labels: - app: elastic - name: elastic -spec: - ports: - - name: "9200" - port: 9200 - targetPort: 9200 - selector: - app: elastic diff --git a/kube/front/front-deployment.yaml b/kube/front/front-deployment.yaml deleted file mode 100644 index 52a7f30..0000000 --- a/kube/front/front-deployment.yaml +++ /dev/null @@ -1,78 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: front - name: front -spec: - replicas: 1 - selector: - matchLabels: - app: front - template: - metadata: - labels: - app: front - spec: - containers: - - env: - - name: ACCOUNTS_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: ACCOUNTS_URL - - name: ACCOUNTS_URL_INTERNAL - value: http://account - - name: CALENDAR_URL - value: http://calendar - - name: COLLABORATOR_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: COLLABORATOR_URL - - name: DEFAULT_LANGUAGE - value: en - - name: ELASTIC_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: ELASTIC_URL - - name: GMAIL_URL - value: http://gmail:8088 - - name: STORAGE_CONFIG - valueFrom: - secretKeyRef: - name: huly-secret - key: STORAGE_CONFIG - - name: MONGO_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: MONGO_URL - - name: REKONI_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: REKONI_URL - - name: SERVER_PORT - value: "8080" - - name: SERVER_SECRET - valueFrom: - secretKeyRef: - name: huly-secret - key: SERVER_SECRET - - name: TELEGRAM_URL - value: http://telegram:8086 - - name: TITLE - value: Huly Self Hosted - - name: UPLOAD_URL - value: /files - - name: STATS_URL - value: http://stats - - name: DESKTOP_UPDATES_CHANNEL - value: selfhost - image: hardcoreeng/front:v0.7.382 - name: front - ports: - - containerPort: 8080 - restartPolicy: Always diff --git a/kube/front/front-service.yaml b/kube/front/front-service.yaml deleted file mode 100644 index e9a6a0c..0000000 --- a/kube/front/front-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: front - name: front -spec: - ports: - - port: 80 - targetPort: 8080 - selector: - app: front diff --git a/kube/fulltext/fulltext-deployment.yaml b/kube/fulltext/fulltext-deployment.yaml deleted file mode 100644 index 19d1369..0000000 --- a/kube/fulltext/fulltext-deployment.yaml +++ /dev/null @@ -1,61 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: fulltext - name: fulltext -spec: - replicas: 1 - selector: - matchLabels: - app: fulltext - template: - metadata: - labels: - app: fulltext - spec: - containers: - - env: - - name: SERVER_SECRET - valueFrom: - secretKeyRef: - name: huly-secret - key: SERVER_SECRET - - name: DB_URL - valueFrom: - secretKeyRef: - name: huly-secret - key: CR_DB_URL - - name: FULLTEXT_DB_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: ELASTIC_URL - - name: ELASTIC_INDEX_NAME - valueFrom: - configMapKeyRef: - name: huly-config - key: ELASTIC_INDEX_NAME - - name: STORAGE_CONFIG - valueFrom: - secretKeyRef: - name: huly-secret - key: STORAGE_CONFIG - - name: REKONI_URL - value: http://rekoni - - name: ACCOUNTS_URL - value: http://account - - name: STATS_URL - value: http://stats - - name: QUEUE_CONFIG - value: redpanda:9092 - image: hardcoreeng/fulltext:v0.7.382 - name: fulltext - ports: - - containerPort: 4700 - hostPort: 4700 - protocol: TCP - resources: - limits: - memory: "512M" - restartPolicy: Always diff --git a/kube/fulltext/fulltext-service.yaml b/kube/fulltext/fulltext-service.yaml deleted file mode 100644 index c05a877..0000000 --- a/kube/fulltext/fulltext-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: fulltext - name: fulltext -spec: - ports: - - port: 80 - targetPort: 4700 - selector: - app: fulltext diff --git a/kube/minio/minio-deployment.yaml b/kube/minio/minio-deployment.yaml deleted file mode 100644 index 604dcbd..0000000 --- a/kube/minio/minio-deployment.yaml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: minio - name: minio -spec: - replicas: 1 - selector: - matchLabels: - app: minio - strategy: - type: Recreate - template: - metadata: - labels: - app: minio - spec: - containers: - - args: - - server - - /data - - --address - - :9000 - - --console-address - - :9001 - image: minio/minio - name: minio - ports: - - containerPort: 9000 - hostPort: 9000 - protocol: TCP - - containerPort: 9001 - hostPort: 9001 - protocol: TCP - volumeMounts: - - mountPath: /data - name: files - restartPolicy: Always - volumes: - - name: files - persistentVolumeClaim: - claimName: files diff --git a/kube/minio/minio-service.yaml b/kube/minio/minio-service.yaml deleted file mode 100644 index bbbc269..0000000 --- a/kube/minio/minio-service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: minio - name: minio -spec: - ports: - - name: "9000" - port: 9000 - targetPort: 9000 - - name: "9001" - port: 9001 - targetPort: 9001 - selector: - app: minio diff --git a/kube/overlays/example/kustomization.yaml b/kube/overlays/example/kustomization.yaml new file mode 100644 index 0000000..8192ba4 --- /dev/null +++ b/kube/overlays/example/kustomization.yaml @@ -0,0 +1,79 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +# Set your namespace +namespace: huly + +resources: + - ../../base + +# Pin all Huly images to a specific version. +# Find the latest tag at https://hub.docker.com/u/hardcoreeng +images: + - name: hardcoreeng/front + newTag: latest + - name: hardcoreeng/account + newTag: latest + - name: hardcoreeng/transactor + newTag: latest + - name: hardcoreeng/collaborator + newTag: latest + - name: hardcoreeng/workspace + newTag: latest + - name: hardcoreeng/fulltext + newTag: latest + - name: hardcoreeng/rekoni-service + newTag: latest + - name: hardcoreeng/stats + newTag: latest + +# Uncomment and set your domain to override the placeholder (huly.example). +# This replaces the ConfigMap values and Ingress hosts/TLS. +# +# patches: +# - target: +# kind: ConfigMap +# name: huly-config +# patch: | +# - op: replace +# path: /data/FRONT_URL +# value: "https://huly.yourdomain.com" +# - op: replace +# path: /data/ACCOUNTS_URL +# value: "https://huly.yourdomain.com/_accounts" +# - op: replace +# path: /data/COLLABORATOR_URL +# value: "wss://huly.yourdomain.com/_collaborator" +# - op: replace +# path: /data/REKONI_URL +# value: "https://huly.yourdomain.com/_rekoni" +# - op: replace +# path: /data/STATS_URL +# value: "https://huly.yourdomain.com/_stats" +# - op: replace +# path: /data/TRANSACTOR_URL +# value: "ws://transactor:3333;wss://huly.yourdomain.com/_transactor" +# - op: replace +# path: /data/GMAIL_URL +# value: "https://huly.yourdomain.com/_gmail" +# - op: replace +# path: /data/TELEGRAM_URL +# value: "https://huly.yourdomain.com/_telegram" +# - op: replace +# path: /data/CALENDAR_URL +# value: "https://huly.yourdomain.com/_calendar" +# - op: replace +# path: /data/LOVE_ENDPOINT +# value: "https://huly.yourdomain.com/_love" +# - op: replace +# path: /data/ADMIN_EMAILS +# value: "you@yourdomain.com" +# - target: +# kind: Ingress +# patch: | +# - op: replace +# path: /spec/tls/0/hosts/0 +# value: huly.yourdomain.com +# - op: replace +# path: /spec/rules/0/host +# value: huly.yourdomain.com diff --git a/kube/redpanda/redpanda-deployment.yaml b/kube/redpanda/redpanda-deployment.yaml deleted file mode 100644 index 3d58ef8..0000000 --- a/kube/redpanda/redpanda-deployment.yaml +++ /dev/null @@ -1,58 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: redpanda - name: redpanda -spec: - replicas: 1 - selector: - matchLabels: - app: redpanda - template: - metadata: - labels: - app: redpanda - spec: - containers: - - env: - - name: REDPANDA_SUPERUSER_USERNAME - value: superuser - - name: REDPANDA_SUPERUSER_PASSWORD - valueFrom: - secretKeyRef: - name: huly-secret - key: REDPANDA_SUPERUSER_PASSWORD - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - image: docker.redpanda.com/redpandadata/redpanda:v24.3.6 - args: - - redpanda - - start - - --kafka-addr internal://0.0.0.0:9092,external://0.0.0.0:19092 - - --advertise-kafka-addr internal://redpanda:9092,external://localhost:19092 - - --pandaproxy-addr internal://0.0.0.0:8082,external://0.0.0.0:18082 - - --advertise-pandaproxy-addr internal://redpanda:8082,external://localhost:18082 - - --schema-registry-addr internal://0.0.0.0:8081,external://0.0.0.0:18081 - - --rpc-addr 0.0.0.0:33145 - - --advertise-rpc-addr redpanda:33145 - - --mode dev-container - - --smp 1 - - --default-log-level=info - name: redpanda - ports: - - containerPort: 9092 - - containerPort: 33145 - volumeMounts: - - mountPath: /var/lib/redpanda/data - name: redpanda - resources: - limits: - memory: "512M" - restartPolicy: Always - volumes: - - name: redpanda - persistentVolumeClaim: - claimName: redpanda diff --git a/kube/redpanda/redpanda-service.yaml b/kube/redpanda/redpanda-service.yaml deleted file mode 100644 index c548fef..0000000 --- a/kube/redpanda/redpanda-service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: redpanda - name: redpanda -spec: - ports: - - port: 9092 - targetPort: 9092 - name: kafka - - port: 33145 - targetPort: 33145 - name: rpc - selector: - app: redpanda diff --git a/kube/rekoni/rekoni-deployment.yaml b/kube/rekoni/rekoni-deployment.yaml deleted file mode 100644 index feee5a4..0000000 --- a/kube/rekoni/rekoni-deployment.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: rekoni - name: rekoni -spec: - replicas: 1 - selector: - matchLabels: - app: rekoni - template: - metadata: - labels: - app: rekoni - spec: - containers: - - image: hardcoreeng/rekoni-service:v0.7.382 - name: rekoni - env: - - name: SECRET - valueFrom: - secretKeyRef: - name: huly-secret - key: SERVER_SECRET - ports: - - containerPort: 4004 - hostPort: 4004 - protocol: TCP - resources: - limits: - memory: "500M" - restartPolicy: Always diff --git a/kube/rekoni/rekoni-ingress.yaml b/kube/rekoni/rekoni-ingress.yaml deleted file mode 100644 index bb598be..0000000 --- a/kube/rekoni/rekoni-ingress.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - kubernetes.io/ingress.class: nginx - labels: - app: rekoni - name: rekoni -spec: - ingressClassName: nginx - rules: - - host: rekoni.huly.example - http: - paths: - - backend: - service: - name: rekoni - port: - number: 80 - path: / - pathType: Prefix diff --git a/kube/rekoni/rekoni-service.yaml b/kube/rekoni/rekoni-service.yaml deleted file mode 100644 index 0995308..0000000 --- a/kube/rekoni/rekoni-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: rekoni - name: rekoni -spec: - ports: - - port: 80 - targetPort: 4004 - selector: - app: rekoni diff --git a/kube/stats/stats-deployment.yaml b/kube/stats/stats-deployment.yaml deleted file mode 100644 index 661545a..0000000 --- a/kube/stats/stats-deployment.yaml +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: stats - name: stats -spec: - replicas: 1 - selector: - matchLabels: - app: stats - template: - metadata: - labels: - app: stats - spec: - containers: - - image: hardcoreeng/stats:v0.7.382 - name: stats - env: - - name: PORT - value: "4900" - - name: SERVER_SECRET - valueFrom: - secretKeyRef: - name: huly-secret - key: SERVER_SECRET - ports: - - containerPort: 4900 - hostPort: 4900 - protocol: TCP - resources: - limits: - memory: "500M" - restartPolicy: Always diff --git a/kube/stats/stats-ingress.yaml b/kube/stats/stats-ingress.yaml deleted file mode 100644 index e7088fe..0000000 --- a/kube/stats/stats-ingress.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - kubernetes.io/ingress.class: nginx - labels: - app: stats - name: stats -spec: - ingressClassName: nginx - rules: - - host: stats.huly.example - http: - paths: - - backend: - service: - name: stats - port: - number: 80 - path: / - pathType: Prefix diff --git a/kube/stats/stats-service.yaml b/kube/stats/stats-service.yaml deleted file mode 100644 index 28b321b..0000000 --- a/kube/stats/stats-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: stats - name: stats -spec: - ports: - - port: 80 - targetPort: 4900 - selector: - app: stats diff --git a/kube/transactor/transactor-deployment.yaml b/kube/transactor/transactor-deployment.yaml deleted file mode 100644 index 6677e1f..0000000 --- a/kube/transactor/transactor-deployment.yaml +++ /dev/null @@ -1,62 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: transactor - name: transactor -spec: - replicas: 1 - selector: - matchLabels: - app: transactor - template: - metadata: - labels: - app: transactor - spec: - containers: - - env: - - name: ACCOUNTS_URL - value: http://account - - name: FULLTEXT_URL - value: http://fulltext - - name: FRONT_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: FRONT_URL - - name: STATS_URL - value: http://stats - - name: STORAGE_CONFIG - valueFrom: - secretKeyRef: - name: huly-secret - key: STORAGE_CONFIG - - name: MONGO_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: MONGO_URL - - name: DB_URL - valueFrom: - secretKeyRef: - name: huly-secret - key: CR_DB_URL - - name: SERVER_CURSOR_MAXTIMEMS - value: "30000" - - name: SERVER_PORT - value: "3333" - - name: SERVER_SECRET - valueFrom: - secretKeyRef: - name: huly-secret - key: SERVER_SECRET - - name: QUEUE_CONFIG - value: redpanda:9092 - image: hardcoreeng/transactor:v0.7.382 - name: transactor - ports: - - containerPort: 3333 - hostPort: 3333 - protocol: TCP - restartPolicy: Always diff --git a/kube/transactor/transactor-ingress.yaml b/kube/transactor/transactor-ingress.yaml deleted file mode 100644 index 84bfc33..0000000 --- a/kube/transactor/transactor-ingress.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - kubernetes.io/ingress.class: nginx - labels: - app: transactor - name: transactor -spec: - ingressClassName: nginx - rules: - - host: transactor.huly.example - http: - paths: - - backend: - service: - name: transactor - port: - number: 80 - path: / - pathType: Prefix diff --git a/kube/transactor/transactor-service.yaml b/kube/transactor/transactor-service.yaml deleted file mode 100644 index bb14e3b..0000000 --- a/kube/transactor/transactor-service.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: transactor - name: transactor -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 3333 - selector: - app: transactor diff --git a/kube/workspace/workspace-deployment.yaml b/kube/workspace/workspace-deployment.yaml deleted file mode 100644 index 9d53939..0000000 --- a/kube/workspace/workspace-deployment.yaml +++ /dev/null @@ -1,57 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: workspace - name: workspace -spec: - replicas: 1 - selector: - matchLabels: - app: workspace - template: - metadata: - labels: - app: workspace - spec: - containers: - - env: - - name: ACCOUNTS_URL - value: http://account - - name: STATS_URL - value: http://stats - - name: TRANSACTOR_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: TRANSACTOR_URL - - name: STORAGE_CONFIG - valueFrom: - secretKeyRef: - name: huly-secret - key: STORAGE_CONFIG - - name: MODEL_ENABLED - value: '*' - - name: DB_URL - valueFrom: - secretKeyRef: - name: huly-secret - key: CR_DB_URL - - name: MONGO_URL - valueFrom: - configMapKeyRef: - name: huly-config - key: MONGO_URL - - name: SERVER_SECRET - valueFrom: - secretKeyRef: - name: huly-secret - key: SERVER_SECRET - - name: QUEUE_CONFIG - value: redpanda:9092 - image: hardcoreeng/workspace:v0.7.382 - name: workspace - resources: - limits: - memory: "512M" - restartPolicy: Always From 81b22b973f9b0e72d133dcb40e72eec322134194 Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Sun, 22 Mar 2026 11:28:01 -0400 Subject: [PATCH 4/4] feat(kube): align Kustomize manifests with merged Helm chart - Add KVS service (deployment + service, pinned to s0.7.392 since hulykvs does not publish a :latest tag) - Add liveness probes to all services, align readiness initialDelaySeconds with Helm defaults - Fix CI workflow: use kubectl apply -k, correct deployment names, path-based routing, namespaced commands - Add optional auth env vars to account (GitHub OAuth, OIDC, DISABLE_SIGNUP) - Add SERVER_CURSOR_MAXTIMEMS to transactor - Add DESKTOP_UPDATES_CHANNEL to configmap - Align Redpanda args with Helm (pandaproxy, schema-registry, external listeners), fix superuser username, use init container for data dir - Align Elasticsearch with Helm (1024m heap, exec readiness probe, BITNAMI_DEBUG, remove sysctl init container) - Add MinIO liveness probe, increase PVC to 50Gi - Fix CockroachDB: use root user for --insecure mode (no password auth) - Fix deploy.sh and README secret creation to match Tested on Hetzner cluster: 13/13 pods running, 0 restarts, all endpoints verified including account creation. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Don Kendall --- .github/workflows/main.yaml | 27 ++++++----- kube/README.md | 18 +++++-- kube/base/app/account/deployment.yaml | 43 ++++++++++++++++- kube/base/app/collaborator/deployment.yaml | 7 ++- kube/base/app/front/deployment.yaml | 8 +++- kube/base/app/fulltext/deployment.yaml | 7 ++- kube/base/app/kustomization.yaml | 2 + kube/base/app/kvs/deployment.yaml | 55 ++++++++++++++++++++++ kube/base/app/kvs/service.yaml | 14 ++++++ kube/base/app/rekoni/deployment.yaml | 7 ++- kube/base/app/stats/deployment.yaml | 7 ++- kube/base/app/transactor/deployment.yaml | 9 +++- kube/base/config/configmap.yaml | 1 + kube/base/infra/cockroach/deployment.yaml | 6 +++ kube/base/infra/elastic/deployment.yaml | 31 +++++++----- kube/base/infra/minio/deployment.yaml | 6 +++ kube/base/infra/minio/pvc.yaml | 2 +- kube/base/infra/redpanda/deployment.yaml | 23 ++++++--- kube/deploy.sh | 4 +- kube/overlays/example/kustomization.yaml | 3 ++ 20 files changed, 237 insertions(+), 43 deletions(-) create mode 100644 kube/base/app/kvs/deployment.yaml create mode 100644 kube/base/app/kvs/service.yaml diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index f829b57..48e700b 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -24,7 +24,7 @@ jobs: [ $(uname -m) = aarch64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.26.0/kind-linux-arm64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind - + - name: "Setup k8s cluster" run: | cat <' \ @@ -116,6 +114,19 @@ HULY_VERSION=v0.7.382 \ 3. Add authorized redirect URI: `https:///_accounts/auth/google/callback` 4. Set `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` in `huly-secret` +### GitHub OAuth (optional) + +1. Create a GitHub OAuth App at https://github.com/settings/developers +2. Set callback URL: `https:///_accounts/auth/github/callback` +3. Add `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET` to `huly-secret` + +### OpenID Connect (optional) + +Add the following keys to `huly-secret`: +- `OPENID_CLIENT_ID` +- `OPENID_CLIENT_SECRET` +- `OPENID_ISSUER` (e.g. `https://accounts.google.com`) + ### Admin bootstrap The first user to sign up creates their workspace and becomes the workspace owner. @@ -137,7 +148,7 @@ kubectl apply -k kube/overlays/my-site/ ## Verify ```bash -# All 12 pods should be Running +# All 13 pods should be Running (including kvs) kubectl -n huly get pods # Front responds @@ -172,6 +183,7 @@ kubectl -n huly port-forward svc/cockroach 8080:8080 | collaborator | 3078 | WebSocket | - | - | | workspace | - | background | yes | yes | | fulltext | 4700 | HTTP | yes | yes | +| kvs | 8094 | HTTP | yes | - | | rekoni | 4004 | HTTP | - | - | | stats | 4900 | HTTP | - | - | diff --git a/kube/base/app/account/deployment.yaml b/kube/base/app/account/deployment.yaml index cdbb4a6..cec11a4 100644 --- a/kube/base/app/account/deployment.yaml +++ b/kube/base/app/account/deployment.yaml @@ -96,6 +96,42 @@ spec: name: huly-config key: ADMIN_EMAILS optional: true + - name: GITHUB_CLIENT_ID + valueFrom: + secretKeyRef: + name: huly-secret + key: GITHUB_CLIENT_ID + optional: true + - name: GITHUB_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: GITHUB_CLIENT_SECRET + optional: true + - name: OPENID_CLIENT_ID + valueFrom: + secretKeyRef: + name: huly-secret + key: OPENID_CLIENT_ID + optional: true + - name: OPENID_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: OPENID_CLIENT_SECRET + optional: true + - name: OPENID_ISSUER + valueFrom: + secretKeyRef: + name: huly-secret + key: OPENID_ISSUER + optional: true + - name: DISABLE_SIGNUP + valueFrom: + configMapKeyRef: + name: huly-config + key: DISABLE_SIGNUP + optional: true resources: requests: cpu: 50m @@ -105,5 +141,10 @@ spec: readinessProbe: tcpSocket: port: http - initialDelaySeconds: 15 + initialDelaySeconds: 5 periodSeconds: 10 + livenessProbe: + tcpSocket: + port: http + initialDelaySeconds: 30 + periodSeconds: 30 diff --git a/kube/base/app/collaborator/deployment.yaml b/kube/base/app/collaborator/deployment.yaml index 856678d..21849f2 100644 --- a/kube/base/app/collaborator/deployment.yaml +++ b/kube/base/app/collaborator/deployment.yaml @@ -47,8 +47,13 @@ spec: readinessProbe: tcpSocket: port: ws - initialDelaySeconds: 15 + initialDelaySeconds: 5 periodSeconds: 10 + livenessProbe: + tcpSocket: + port: ws + initialDelaySeconds: 30 + periodSeconds: 30 resources: requests: cpu: 50m diff --git a/kube/base/app/front/deployment.yaml b/kube/base/app/front/deployment.yaml index 04b365b..da1cca1 100644 --- a/kube/base/app/front/deployment.yaml +++ b/kube/base/app/front/deployment.yaml @@ -47,5 +47,11 @@ spec: httpGet: path: / port: http - initialDelaySeconds: 10 + initialDelaySeconds: 5 periodSeconds: 10 + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 15 + periodSeconds: 30 diff --git a/kube/base/app/fulltext/deployment.yaml b/kube/base/app/fulltext/deployment.yaml index 25a148e..80b22cd 100644 --- a/kube/base/app/fulltext/deployment.yaml +++ b/kube/base/app/fulltext/deployment.yaml @@ -80,8 +80,13 @@ spec: readinessProbe: tcpSocket: port: http - initialDelaySeconds: 15 + initialDelaySeconds: 5 periodSeconds: 10 + livenessProbe: + tcpSocket: + port: http + initialDelaySeconds: 30 + periodSeconds: 30 resources: requests: cpu: 50m diff --git a/kube/base/app/kustomization.yaml b/kube/base/app/kustomization.yaml index 10ab7e2..0337c73 100644 --- a/kube/base/app/kustomization.yaml +++ b/kube/base/app/kustomization.yaml @@ -16,3 +16,5 @@ resources: - rekoni/service.yaml - stats/deployment.yaml - stats/service.yaml + - kvs/deployment.yaml + - kvs/service.yaml diff --git a/kube/base/app/kvs/deployment.yaml b/kube/base/app/kvs/deployment.yaml new file mode 100644 index 0000000..905705a --- /dev/null +++ b/kube/base/app/kvs/deployment.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kvs + labels: + app.kubernetes.io/name: kvs + app.kubernetes.io/part-of: huly +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: kvs + template: + metadata: + labels: + app.kubernetes.io/name: kvs + spec: + initContainers: + - name: wait-cockroach + image: busybox:1.36 + command: ["sh", "-c", "until nc -z cockroach 26257; do echo waiting for cockroach; sleep 2; done"] + containers: + - name: kvs + # hulykvs does not publish a :latest tag — pin explicitly + image: hardcoreeng/hulykvs:s0.7.392 + ports: + - name: http + containerPort: 8094 + env: + - name: HULY_DB_CONNECTION + valueFrom: + secretKeyRef: + name: huly-secret + key: CR_DB_URL + - name: HULY_TOKEN_SECRET + valueFrom: + secretKeyRef: + name: huly-secret + key: SERVER_SECRET + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 512Mi + readinessProbe: + tcpSocket: + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + tcpSocket: + port: http + initialDelaySeconds: 30 + periodSeconds: 30 diff --git a/kube/base/app/kvs/service.yaml b/kube/base/app/kvs/service.yaml new file mode 100644 index 0000000..288a7ba --- /dev/null +++ b/kube/base/app/kvs/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: kvs + labels: + app.kubernetes.io/name: kvs + app.kubernetes.io/part-of: huly +spec: + selector: + app.kubernetes.io/name: kvs + ports: + - name: http + port: 8094 + targetPort: http diff --git a/kube/base/app/rekoni/deployment.yaml b/kube/base/app/rekoni/deployment.yaml index bf41a9b..f489d2f 100644 --- a/kube/base/app/rekoni/deployment.yaml +++ b/kube/base/app/rekoni/deployment.yaml @@ -30,8 +30,13 @@ spec: readinessProbe: tcpSocket: port: http - initialDelaySeconds: 15 + initialDelaySeconds: 5 periodSeconds: 10 + livenessProbe: + tcpSocket: + port: http + initialDelaySeconds: 15 + periodSeconds: 30 resources: requests: cpu: 50m diff --git a/kube/base/app/stats/deployment.yaml b/kube/base/app/stats/deployment.yaml index 7667eab..db9d6b3 100644 --- a/kube/base/app/stats/deployment.yaml +++ b/kube/base/app/stats/deployment.yaml @@ -32,8 +32,13 @@ spec: readinessProbe: tcpSocket: port: http - initialDelaySeconds: 10 + initialDelaySeconds: 5 periodSeconds: 10 + livenessProbe: + tcpSocket: + port: http + initialDelaySeconds: 15 + periodSeconds: 30 resources: requests: cpu: 50m diff --git a/kube/base/app/transactor/deployment.yaml b/kube/base/app/transactor/deployment.yaml index bca2133..b78f9f8 100644 --- a/kube/base/app/transactor/deployment.yaml +++ b/kube/base/app/transactor/deployment.yaml @@ -76,6 +76,8 @@ spec: configMapKeyRef: name: huly-config key: LAST_NAME_FIRST + - name: SERVER_CURSOR_MAXTIMEMS + value: "30000" resources: requests: cpu: 100m @@ -85,5 +87,10 @@ spec: readinessProbe: tcpSocket: port: ws - initialDelaySeconds: 15 + initialDelaySeconds: 5 periodSeconds: 10 + livenessProbe: + tcpSocket: + port: ws + initialDelaySeconds: 30 + periodSeconds: 30 diff --git a/kube/base/config/configmap.yaml b/kube/base/config/configmap.yaml index 4d56756..7a64648 100644 --- a/kube/base/config/configmap.yaml +++ b/kube/base/config/configmap.yaml @@ -30,3 +30,4 @@ data: TELEGRAM_URL: "https://huly.example/_telegram" CALENDAR_URL: "https://huly.example/_calendar" LOVE_ENDPOINT: "https://huly.example/_love" + DESKTOP_UPDATES_CHANNEL: "selfhost" diff --git a/kube/base/infra/cockroach/deployment.yaml b/kube/base/infra/cockroach/deployment.yaml index 5623964..9103bd8 100644 --- a/kube/base/infra/cockroach/deployment.yaml +++ b/kube/base/infra/cockroach/deployment.yaml @@ -45,6 +45,12 @@ spec: port: http initialDelaySeconds: 10 periodSeconds: 10 + livenessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 30 + periodSeconds: 30 volumes: - name: data persistentVolumeClaim: diff --git a/kube/base/infra/elastic/deployment.yaml b/kube/base/infra/elastic/deployment.yaml index add95b1..88414e0 100644 --- a/kube/base/infra/elastic/deployment.yaml +++ b/kube/base/infra/elastic/deployment.yaml @@ -17,12 +17,6 @@ spec: labels: app.kubernetes.io/name: elastic spec: - initContainers: - - name: sysctl - image: busybox:1.36 - command: ["sh", "-c", "sysctl -w vm.max_map_count=262144 || true"] - securityContext: - privileged: true securityContext: fsGroup: 1000 runAsUser: 1000 @@ -45,11 +39,15 @@ spec: - name: discovery.type value: "single-node" - name: ES_JAVA_OPTS - value: "-Xms512m -Xmx512m" + value: "-Xms1024m -Xmx1024m" - name: http.cors.enabled value: "true" - name: http.cors.allow-origin - value: "*" + value: "http://localhost:8082" + - name: BITNAMI_DEBUG + value: "true" + - name: ELASTICSEARCH_PORT_NUMBER + value: "9200" volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data @@ -60,11 +58,22 @@ spec: limits: memory: 1536Mi readinessProbe: - httpGet: - path: /_cluster/health - port: http + exec: + command: + - sh + - -c + - 'curl -sf http://localhost:9200/_cluster/health | grep -vq ''"status":"red"''' initialDelaySeconds: 30 periodSeconds: 10 + livenessProbe: + exec: + command: + - sh + - -c + - 'curl -sf http://localhost:9200/_cluster/health | grep -vq ''"status":"red"''' + initialDelaySeconds: 60 + periodSeconds: 20 + failureThreshold: 10 volumes: - name: data persistentVolumeClaim: diff --git a/kube/base/infra/minio/deployment.yaml b/kube/base/infra/minio/deployment.yaml index a7dcc47..3d78088 100644 --- a/kube/base/infra/minio/deployment.yaml +++ b/kube/base/infra/minio/deployment.yaml @@ -42,6 +42,12 @@ spec: port: api initialDelaySeconds: 10 periodSeconds: 10 + livenessProbe: + httpGet: + path: /minio/health/live + port: api + initialDelaySeconds: 30 + periodSeconds: 20 volumes: - name: data persistentVolumeClaim: diff --git a/kube/base/infra/minio/pvc.yaml b/kube/base/infra/minio/pvc.yaml index b37a842..28f8d51 100644 --- a/kube/base/infra/minio/pvc.yaml +++ b/kube/base/infra/minio/pvc.yaml @@ -10,4 +10,4 @@ spec: - ReadWriteOnce resources: requests: - storage: 10Gi + storage: 50Gi diff --git a/kube/base/infra/redpanda/deployment.yaml b/kube/base/infra/redpanda/deployment.yaml index 8f3c4bd..2b5562b 100644 --- a/kube/base/infra/redpanda/deployment.yaml +++ b/kube/base/infra/redpanda/deployment.yaml @@ -17,10 +17,13 @@ spec: labels: app.kubernetes.io/name: redpanda spec: - securityContext: - fsGroup: 101 - runAsUser: 101 - runAsGroup: 101 + initContainers: + - name: set-datadir-ownership + image: busybox:1.36 + command: ["sh", "-c", "chown 101:101 /var/lib/redpanda/data"] + volumeMounts: + - name: data + mountPath: /var/lib/redpanda/data containers: - name: redpanda image: docker.redpanda.com/redpandadata/redpanda:v24.3.6 @@ -29,9 +32,15 @@ spec: - "redpanda" - "start" - "--kafka-addr" - - "internal://0.0.0.0:9092" + - "internal://0.0.0.0:9092,external://0.0.0.0:19092" - "--advertise-kafka-addr" - - "internal://redpanda:9092" + - "internal://redpanda:9092,external://localhost:19092" + - "--pandaproxy-addr" + - "internal://0.0.0.0:8082,external://0.0.0.0:18082" + - "--advertise-pandaproxy-addr" + - "internal://redpanda:8082,external://localhost:18082" + - "--schema-registry-addr" + - "internal://0.0.0.0:8081,external://0.0.0.0:18081" - "--rpc-addr" - "0.0.0.0:33145" - "--advertise-rpc-addr" @@ -48,7 +57,7 @@ spec: containerPort: 33145 env: - name: REDPANDA_SUPERUSER_USERNAME - value: "admin" + value: "superuser" - name: REDPANDA_SUPERUSER_PASSWORD valueFrom: secretKeyRef: diff --git a/kube/deploy.sh b/kube/deploy.sh index 06250fb..5439619 100755 --- a/kube/deploy.sh +++ b/kube/deploy.sh @@ -36,13 +36,11 @@ kubectl create namespace "$HULY_NAMESPACE" --dry-run=client -o yaml | kubectl ap # 2. Create/update secret SERVER_SECRET=$(openssl rand -hex 32) -CR_PASS=$(openssl rand -hex 16) RP_PASS=$(openssl rand -hex 16) kubectl -n "$HULY_NAMESPACE" create secret generic huly-secret \ --from-literal=SERVER_SECRET="$SERVER_SECRET" \ --from-literal=STORAGE_CONFIG='minio|minio?accessKey=minioadmin&secretKey=minioadmin' \ - --from-literal=COCKROACH_PASSWORD="$CR_PASS" \ --from-literal=REDPANDA_SUPERUSER_PASSWORD="$RP_PASS" \ --from-literal=CR_DB_URL='postgres://root@cockroach:26257/defaultdb?sslmode=disable' \ --from-literal=GOOGLE_CLIENT_ID="$GOOGLE_CLIENT_ID" \ @@ -73,6 +71,8 @@ images: newTag: "$HULY_VERSION" - name: hardcoreeng/stats newTag: "$HULY_VERSION" + - name: hardcoreeng/hulykvs + newTag: "$HULY_VERSION" patches: - target: kind: ConfigMap diff --git a/kube/overlays/example/kustomization.yaml b/kube/overlays/example/kustomization.yaml index 8192ba4..18f78c9 100644 --- a/kube/overlays/example/kustomization.yaml +++ b/kube/overlays/example/kustomization.yaml @@ -26,6 +26,9 @@ images: newTag: latest - name: hardcoreeng/stats newTag: latest + # hulykvs does not publish a :latest tag — pin explicitly + - name: hardcoreeng/hulykvs + newTag: s0.7.392 # Uncomment and set your domain to override the placeholder (huly.example). # This replaces the ConfigMap values and Ingress hosts/TLS.