From 842f8b727e44184e88a82eb699a5cd42e62eed21 Mon Sep 17 00:00:00 2001 From: Daniel Noulet Date: Sat, 3 Oct 2026 04:39:27 +0200 Subject: [PATCH] feat: deploy --- deploy/helm/go-guess/README.md | 272 ++++++++++++++++++ .../go-guess/templates/api-deployment.yaml | 148 ++++++++++ .../helm/go-guess/templates/api-service.yaml | 18 ++ .../helm/go-guess/templates/certificate.yaml | 76 +++++ .../go-guess/templates/web-deployment.yaml | 89 ++++++ .../helm/go-guess/templates/web-service.yaml | 17 ++ 6 files changed, 620 insertions(+) create mode 100644 deploy/helm/go-guess/README.md create mode 100644 deploy/helm/go-guess/templates/api-deployment.yaml create mode 100644 deploy/helm/go-guess/templates/api-service.yaml create mode 100644 deploy/helm/go-guess/templates/certificate.yaml create mode 100644 deploy/helm/go-guess/templates/web-deployment.yaml create mode 100644 deploy/helm/go-guess/templates/web-service.yaml diff --git a/deploy/helm/go-guess/README.md b/deploy/helm/go-guess/README.md new file mode 100644 index 0000000..857d159 --- /dev/null +++ b/deploy/helm/go-guess/README.md @@ -0,0 +1,272 @@ +# Go Guess Helm chart + +This chart deploys Go Guess as two images, an API and a web front end, plus its +own PostgreSQL and RabbitMQ, and publishes one HTTPS host per tenant under +`https://.guess.local`. + +## 1. What the chart creates + +| Resource | Name | Purpose | +|---|---|---| +| Deployment | `go-guess-api` | Go API, runs migrations and seeds before serving | +| Deployment | `go-guess-web` | nginx serving the built React application | +| Service | `api` | Cluster-internal API, proxied by the web image | +| Service | `go-guess-web` | Cluster-internal web front end, ingress backend | +| Ingress | `go-guess` | One rule and one TLS SAN per tenant host | +| Issuer | `go-guess-selfsigned` | cert-manager self-signed issuer | +| Certificate | `go-guess-web-ca` | Chart CA that signs the leaf certificate | +| Certificate | `go-guess-web` | Leaf certificate covering every tenant host | +| StatefulSet | `go-guess-postgresql` | PostgreSQL, `emptyDir` or persistent volume | +| StatefulSet | `go-guess-rabbitmq` | RabbitMQ, `emptyDir` or persistent volume | +| Secret | `go-guess-secrets` | JWT secret, connection URLs, broker credentials | + +A single web deployment serves every tenant host. The API resolves the tenant +from the request `Host` header, so adding a tenant means adding one entry to +`tenants`, not deploying another stack. + +## 2. Prerequisites + +- A Kubernetes cluster reachable through `KUBECONFIG`. +- A `StorageClass` when `postgresql.persistence.enabled` or + `rabbitmq.persistence.enabled` is `true`. +- ingress-nginx with the `nginx` ingress class: `make ingress-nginx-install`. +- cert-manager when `ingress.tls.enabled` is `true`: `make cert-manager-install`. +- Cluster nodes trusting `batty1039.startdedicated.net:5000` as an insecure + registry, or an HTTPS registry. + +Run everything the chart depends on in one step: + +```bash +make cluster-prepare +``` + +## 3. Deploy + +```bash +make helm-lint +make helm-deploy-development +``` + +The development profile uses `latest` images, development fixtures, ephemeral +storage, and namespace `go-insane-development`. Production uses released tags, +production fixtures, persistent volumes, and namespace `go-insane-production`: + +```bash +make helm-deploy-production +``` + +Both targets accept per-tenant Go Loose credentials from the environment: + +```bash +export GO_LOOSE_NMBS_CLIENT_ID=... +export GO_LOOSE_NMBS_CLIENT_SECRET=... +export GO_LOOSE_YPTO_CLIENT_ID=... +export GO_LOOSE_YPTO_CLIENT_SECRET=... +make helm-deploy-production +``` + +After a successful install the release notes list every tenant URL and the +command that exports the CA certificate. With the local platform, prefer +`docs/KUBERNETES-DEPLOYMENTS.md` in the infrastructure repository, which covers +`/etc/hosts` entries and CA trust for the whole platform. + +## 4. Tenants and hosts + +`tenants` is the list of slugs and `domain` is the shared parent domain: + +```yaml +domain: guess.local +tenants: + - nmbs + - ypto +``` + +The chart derives, without any extra configuration: + +- `GO_LOOSE_APP_DOMAIN=guess.local`, so the API accepts `nmbs.guess.local` and + `ypto.guess.local` as tenant hosts. +- One ingress rule per tenant, all pointing at `go-guess-web`. +- One certificate SAN per tenant, so a single secret covers every host. +- `FRONTEND_URL`, when `api.frontendURL` is empty, as + `https://.`. This is the fallback used to build + invitation and meeting links, so the first entry is the tenant that receives + shareable links. + +A slug must be a single DNS label. The API rejects slugs containing a dot, and +the certificate would not match a two-level host. + +Adding a tenant therefore requires three things: the slug in `tenants`, a DNS +record pointing at the ingress controller, and a Go Loose client when browser +sign-in is used. + +## 5. Values + +### Top level + +| Key | Default | Description | +|---|---|---| +| `nameOverride` | `""` | Overrides the chart name in resource names and labels | +| `fullnameOverride` | `""` | Replaces the generated resource name prefix | +| `domain` | `guess.local` | Parent domain of every tenant host | +| `tenants` | `[nmbs, ypto]` | Tenant slugs served by the release | +| `imagePullSecrets` | `[]` | Pull secrets added to both pods | + +### api + +| Key | Default | Description | +|---|---|---| +| `api.replicaCount` | `1` | API replicas, keep at `1` while migrations run on startup | +| `api.image.repository` | `batty1039.startdedicated.net:5000/go-guess-api` | API image | +| `api.image.tag` | `0.0.1` | API image tag | +| `api.image.pullPolicy` | `IfNotPresent` | API pull policy | +| `api.environment` | `development` | `APP_ENV`, `production` seeds production fixtures only | +| `api.frontendURL` | `""` | Fallback public URL for invitation and meeting links | +| `api.tokenTTL` | `8h` | `TOKEN_TTL` for issued API tokens | +| `api.maxUploadMB` | `10` | `MAX_UPLOAD_MB` upload limit, match `proxy-body-size` | +| `api.service.name` | `api` | Service DNS name, fixed by the web image | +| `api.service.type` | `ClusterIP` | API service type | +| `api.service.port` | `8080` | API service port | +| `api.goLoose.enabled` | `false` | Enables Go Loose browser sign-in | +| `api.goLoose.authDomain` | `auth.dev` | Tenant login host `https://.` | +| `api.goLoose.ca.existingSecret` | `""` | Secret holding the Go Loose CA bundle | +| `api.goLoose.ca.key` | `ca.crt` | Key projected from that secret | +| `api.goLoose.ca.mountPath` | `/certs/local-ca.crt` | `GO_LOOSE_CA_FILE` target | +| `api.goLoose.tenants..clientID` | `""` | Go Loose client ID for that tenant | +| `api.goLoose.tenants..clientSecret` | `""` | Go Loose client secret for that tenant | +| `api.resources` | `50m`/`128Mi` to `500m`/`512Mi` | API requests and limits | +| `api.podAnnotations`, `api.podLabels` | `{}` | Extra pod metadata | +| `api.podSecurityContext` | `{}` | Pod security context | +| `api.securityContext` | non-root, read-only root filesystem | Container security context | +| `api.strategy.type` | `Recreate` | Old pod exits before migrations run again | + +### web + +| Key | Default | Description | +|---|---|---| +| `web.replicaCount` | `2` | nginx replicas, safe to scale because nginx is stateless | +| `web.image.repository` | `batty1039.startdedicated.net:5000/go-guess-web` | Web image | +| `web.image.tag` | `0.0.1` | Web image tag | +| `web.image.pullPolicy` | `IfNotPresent` | Web pull policy | +| `web.service.type` | `ClusterIP` | Web service type | +| `web.service.port` | `80` | Web service port | +| `web.service.nodePort` | `null` | Node port when the type is `NodePort` | +| `web.resources` | `25m`/`32Mi` to `300m`/`128Mi` | Web requests and limits | +| `web.podAnnotations`, `web.podLabels` | `{}` | Extra pod metadata | +| `web.podSecurityContext` | `{}` | Pod security context | +| `web.securityContext` | root, `NET_BIND_SERVICE` only | Container security context | +| `web.strategy` | rolling, `maxUnavailable: 0` | Keeps the ingress backed up during rollout | + +Neither container has a forced uid. Both images declare their own user, the API +as `app` and nginx as `nginx`, and `runAsNonRoot` validates it. + +The web security context differs from the API one on purpose. nginx binds the +privileged port `80` and forks workers as the `nginx` user, so the pod runs as +root with `CHOWN`, `SETGID`, `SETUID`, and `NET_BIND_SERVICE`, and mounts +writable `emptyDir` volumes at `/var/cache/nginx`, `/var/run`, and `/tmp`. + +### ingress + +| Key | Default | Description | +|---|---|---| +| `ingress.enabled` | `true` | Creates the multi-host ingress | +| `ingress.className` | `nginx` | Ingress class of the controller | +| `ingress.annotations` | body size `10m`, timeouts `3600`, buffering off, TLS redirect | Controller annotations | +| `ingress.path` | `/` | Path routed to the web service | +| `ingress.pathType` | `Prefix` | Path type of that route | +| `ingress.tls.enabled` | `true` | Terminates TLS on the controller | +| `ingress.tls.secretName` | `""` | Defaults to `-web-tls` | +| `ingress.tls.existingSecret` | `""` | Uses a certificate managed outside the chart | + +The proxy annotations matter for the interview feature: the API streams events +over server-sent events and accepts video uploads, so buffering off, a one-hour +read timeout, and a body size at least as large as `api.maxUploadMB` are +required, otherwise streams stall and uploads fail with `413`. + +### certManager + +| Key | Default | Description | +|---|---|---| +| `certManager.enabled` | `true` | Chart creates the certificates | +| `certManager.issuerRef` | `{}` | Uses an existing issuer instead of the chart CA | +| `certManager.duration` | `8760h` | Certificate lifetime | +| `certManager.renewBefore` | `720h` | Renewal window | +| `certManager.caSecretName` | `""` | Defaults to `-web-ca` | + +Three certificate objects are created in order: a self-signed `Issuer`, a CA +`Certificate` stored in `caSecretName`, and the leaf `Certificate` stored in the +ingress TLS secret with one `dnsNames` entry per tenant. Set `issuerRef` to sign +with a cluster issuer instead, for example an internal ACME issuer: + +```yaml +certManager: + issuerRef: + name: internal-acme + kind: ClusterIssuer + group: cert-manager.io +``` + +Set `ingress.tls.existingSecret` to use a certificate the chart does not own, +and `certManager.enabled: false` to stop emitting cert-manager objects. + +### Secrets, storage, and scheduling + +| Key | Default | Description | +|---|---|---| +| `secrets.jwtSecret` | `""` | Generated and preserved across upgrades when empty | +| `secrets.databaseURL` | derived | Full URL, required when PostgreSQL is disabled | +| `secrets.rabbitmqURL` | derived | Full URL, required when RabbitMQ is disabled | +| `secrets.postgresqlPassword` | generated | PostgreSQL user password | +| `secrets.rabbitmqPassword` | generated | RabbitMQ user password | +| `postgresql.enabled` | `true` | Bundled PostgreSQL | +| `postgresql.persistence.enabled` | `true` | Persistent volume instead of `emptyDir` | +| `postgresql.persistence.size` | `8Gi` | Volume size | +| `postgresql.auth.username` | `go_guess` | Database user | +| `rabbitmq.enabled` | `true` | Bundled RabbitMQ | +| `rabbitmq.persistence.enabled` | `true` | Persistent volume instead of `emptyDir` | +| `rabbitmq.persistence.size` | `4Gi` | Volume size | +| `nodeSelector`, `tolerations`, `affinity` | empty | Applied to both deployments | + +Generated secrets are read back with `lookup` on upgrade, so leaving them empty +rotates nothing and keeps sessions valid across releases. + +## 6. External services + +Disable the bundled StatefulSets and pass full connection URLs to use managed +PostgreSQL and RabbitMQ: + +```bash +helm upgrade --install go-guess deploy/helm/go-guess \ + --namespace go-insane-production --create-namespace \ + -f deploy/helm/go-guess/values-production.yaml \ + --set postgresql.enabled=false \ + --set rabbitmq.enabled=false \ + --set-string secrets.databaseURL="$DATABASE_URL" \ + --set-string secrets.rabbitmqURL="$RABBITMQ_URL" +``` + +## 7. Upgrade and remove + +```bash +make helm-deploy-production +helm -n go-insane-production history go-guess +helm -n go-insane-production rollback go-guess 1 +make helm-down-production +``` + +Uninstalling removes the release secrets, so store `secrets.jwtSecret` and the +two connection URLs outside the cluster before deleting a release whose database +must survive. + +## 8. Verify + +```bash +kubectl -n go-insane-production get ingress go-guess +kubectl -n go-insane-production get certificate +kubectl -n go-insane-production rollout status deployment/go-guess-api +kubectl -n go-insane-production rollout status deployment/go-guess-web +curl --resolve nmbs.guess.local:443:127.0.0.1 --cacert go-guess-ca.crt \ + https://nmbs.guess.local/api/health +``` + +The test pod installed by `helm test` checks the API health endpoint and the web +root from inside the cluster. \ No newline at end of file diff --git a/deploy/helm/go-guess/templates/api-deployment.yaml b/deploy/helm/go-guess/templates/api-deployment.yaml new file mode 100644 index 0000000..25623f7 --- /dev/null +++ b/deploy/helm/go-guess/templates/api-deployment.yaml @@ -0,0 +1,148 @@ +{{- include "go-guess.validate" . -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "go-guess.apiDeploymentName" . }} + labels: + {{- include "go-guess.labels" . | nindent 4 }} + app.kubernetes.io/component: api +spec: + replicas: {{ .Values.api.replicaCount }} + strategy: + type: {{ .Values.api.strategy.type }} + selector: + matchLabels: + {{- include "go-guess.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: api + template: + metadata: + annotations: + checksum/secrets: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- with .Values.api.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "go-guess.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: api + {{- with .Values.api.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + automountServiceAccountToken: false + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.api.podSecurityContext | nindent 8 }} + containers: + - name: api + image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}" + imagePullPolicy: {{ .Values.api.image.pullPolicy }} + securityContext: + {{- toYaml .Values.api.securityContext | nindent 12 }} + env: + - name: APP_ENV + value: {{ .Values.api.environment | quote }} + - name: FRONTEND_URL + value: {{ include "go-guess.frontendURL" . | quote }} + - name: TOKEN_TTL + value: {{ .Values.api.tokenTTL | quote }} + - name: MAX_UPLOAD_MB + value: {{ .Values.api.maxUploadMB | quote }} + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: {{ include "go-guess.secretName" . }} + key: database-url + - name: RABBITMQ_URL + valueFrom: + secretKeyRef: + name: {{ include "go-guess.secretName" . }} + key: rabbitmq-url + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: {{ include "go-guess.secretName" . }} + key: jwt-secret + {{- if .Values.api.goLoose.enabled }} + - name: GO_LOOSE_AUTH_DOMAIN + value: {{ .Values.api.goLoose.authDomain | quote }} + - name: GO_LOOSE_APP_DOMAIN + value: {{ .Values.domain | quote }} + {{- if .Values.api.goLoose.ca.existingSecret }} + - name: GO_LOOSE_CA_FILE + value: {{ .Values.api.goLoose.ca.mountPath | quote }} + {{- end }} + {{- range $tenant, $credentials := .Values.api.goLoose.tenants }} + {{- $envPrefix := printf "GO_LOOSE_%s" (upper $tenant) }} + {{- $keyPrefix := printf "go-loose-%s" (lower $tenant) }} + {{- if $credentials.clientID }} + - name: {{ $envPrefix }}_CLIENT_ID + valueFrom: + secretKeyRef: + name: {{ include "go-guess.secretName" $ }} + key: {{ $keyPrefix }}-client-id + {{- end }} + {{- if $credentials.clientSecret }} + - name: {{ $envPrefix }}_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: {{ include "go-guess.secretName" $ }} + key: {{ $keyPrefix }}-client-secret + {{- end }} + {{- end }} + {{- end }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + readinessProbe: + httpGet: + path: /api/health + port: http + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 12 + livenessProbe: + httpGet: + path: /api/health + port: http + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 3 + resources: + {{- toYaml .Values.api.resources | nindent 12 }} + volumeMounts: + - name: temporary-files + mountPath: /tmp + {{- if and .Values.api.goLoose.enabled .Values.api.goLoose.ca.existingSecret }} + - name: go-loose-ca + mountPath: {{ dir .Values.api.goLoose.ca.mountPath }} + readOnly: true + {{- end }} + volumes: + - name: temporary-files + emptyDir: {} + {{- if and .Values.api.goLoose.enabled .Values.api.goLoose.ca.existingSecret }} + - name: go-loose-ca + secret: + secretName: {{ .Values.api.goLoose.ca.existingSecret }} + items: + - key: {{ .Values.api.goLoose.ca.key }} + path: {{ base .Values.api.goLoose.ca.mountPath }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deploy/helm/go-guess/templates/api-service.yaml b/deploy/helm/go-guess/templates/api-service.yaml new file mode 100644 index 0000000..ad7431f --- /dev/null +++ b/deploy/helm/go-guess/templates/api-service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + # Kept as the literal name "api": the web image proxies /api/ to api:8080. + name: {{ include "go-guess.apiServiceName" . }} + labels: + {{- include "go-guess.labels" . | nindent 4 }} + app.kubernetes.io/component: api +spec: + type: {{ .Values.api.service.type }} + selector: + {{- include "go-guess.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: api + ports: + - name: http + port: {{ .Values.api.service.port }} + targetPort: http + protocol: TCP \ No newline at end of file diff --git a/deploy/helm/go-guess/templates/certificate.yaml b/deploy/helm/go-guess/templates/certificate.yaml new file mode 100644 index 0000000..e0cb1c7 --- /dev/null +++ b/deploy/helm/go-guess/templates/certificate.yaml @@ -0,0 +1,76 @@ +{{- if and .Values.ingress.enabled .Values.ingress.tls.enabled .Values.certManager.enabled }} +{{- $fullname := include "go-guess.fullname" . }} +{{- $caSecret := include "go-guess.certManagerCASecretName" . }} +{{- $tlsSecret := include "go-guess.tlsSecretName" . }} +{{- if not .Values.certManager.issuerRef }} +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ $fullname }}-selfsigned + labels: + {{- include "go-guess.labels" . | nindent 4 }} + app.kubernetes.io/component: certificate +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ $fullname }}-web-ca + labels: + {{- include "go-guess.labels" . | nindent 4 }} + app.kubernetes.io/component: certificate +spec: + secretName: {{ $caSecret }} + commonName: {{ printf "%s-ca" $fullname }} + duration: {{ .Values.certManager.duration }} + renewBefore: {{ .Values.certManager.renewBefore }} + privateKey: + algorithm: ECDSA + size: 256 + issuerRef: + name: {{ $fullname }}-selfsigned + kind: Issuer + group: cert-manager.io +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ $fullname }}-web-ca + labels: + {{- include "go-guess.labels" . | nindent 4 }} + app.kubernetes.io/component: certificate +spec: + ca: + secretName: {{ $caSecret }} +--- +{{- end }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ $fullname }}-web + labels: + {{- include "go-guess.labels" . | nindent 4 }} + app.kubernetes.io/component: certificate +spec: + secretName: {{ $tlsSecret }} + duration: {{ .Values.certManager.duration }} + renewBefore: {{ .Values.certManager.renewBefore }} + privateKey: + algorithm: ECDSA + size: 256 + usages: + - server auth + dnsNames: + {{- range .Values.tenants }} + - {{ printf "%s.%s" . $.Values.domain | quote }} + {{- end }} + issuerRef: + {{- if .Values.certManager.issuerRef }} + {{- include "go-guess.certManagerIssuerRef" . | nindent 4 }} + {{- else }} + name: {{ $fullname }}-web-ca + kind: Issuer + group: cert-manager.io + {{- end }} +{{- end }} \ No newline at end of file diff --git a/deploy/helm/go-guess/templates/web-deployment.yaml b/deploy/helm/go-guess/templates/web-deployment.yaml new file mode 100644 index 0000000..552078f --- /dev/null +++ b/deploy/helm/go-guess/templates/web-deployment.yaml @@ -0,0 +1,89 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "go-guess.webDeploymentName" . }} + labels: + {{- include "go-guess.labels" . | nindent 4 }} + app.kubernetes.io/component: web +spec: + replicas: {{ .Values.web.replicaCount }} + strategy: + {{- toYaml .Values.web.strategy | nindent 4 }} + selector: + matchLabels: + {{- include "go-guess.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: web + template: + metadata: + {{- with .Values.web.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "go-guess.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: web + {{- with .Values.web.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + automountServiceAccountToken: false + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.web.podSecurityContext | nindent 8 }} + containers: + - name: web + image: "{{ .Values.web.image.repository }}:{{ .Values.web.image.tag }}" + imagePullPolicy: {{ .Values.web.image.pullPolicy }} + securityContext: + {{- toYaml .Values.web.securityContext | nindent 12 }} + ports: + - name: http + containerPort: 80 + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 3 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 6 + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 3 + resources: + {{- toYaml .Values.web.resources | nindent 12 }} + volumeMounts: + - name: nginx-cache + mountPath: /var/cache/nginx + - name: nginx-run + mountPath: /var/run + - name: temporary-files + mountPath: /tmp + volumes: + - name: nginx-cache + emptyDir: {} + - name: nginx-run + emptyDir: {} + - name: temporary-files + emptyDir: {} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deploy/helm/go-guess/templates/web-service.yaml b/deploy/helm/go-guess/templates/web-service.yaml new file mode 100644 index 0000000..a8eb8eb --- /dev/null +++ b/deploy/helm/go-guess/templates/web-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "go-guess.webDeploymentName" . }} + labels: + {{- include "go-guess.labels" . | nindent 4 }} + app.kubernetes.io/component: web +spec: + type: {{ .Values.web.service.type }} + selector: + {{- include "go-guess.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: web + ports: + - name: http + port: {{ .Values.web.service.port }} + targetPort: http + protocol: TCP \ No newline at end of file