feat: deploy
This commit is contained in:
parent
560014d0b8
commit
9bbf8a96aa
16 changed files with 542 additions and 292 deletions
55
Makefile
55
Makefile
|
|
@ -7,10 +7,15 @@ BDD_COMPOSE := docker compose -f docker-compose.bdd.yml
|
|||
HELM ?= helm
|
||||
HELM_CHART := deploy/helm/go-guess
|
||||
HELM_RELEASE ?= go-guess
|
||||
HELM_NAMESPACE ?= go-guess
|
||||
KUBECONFIG ?= $(HOME)/.config/kubectl/rancher.urpi.local.yaml
|
||||
HELM_NAMESPACE ?= go-insane
|
||||
KUBECONFIG ?= $(HOME)/.kube/config
|
||||
HELM_KUBECTL := KUBECONFIG="$(KUBECONFIG)" $(HELM)
|
||||
GO_LOOSE_SET ?= --set-string api.goLoose.tenants.nmbs.clientID="$${GO_LOOSE_NMBS_CLIENT_ID:-}" \
|
||||
--set-string api.goLoose.tenants.nmbs.clientSecret="$${GO_LOOSE_NMBS_CLIENT_SECRET:-}" \
|
||||
--set-string api.goLoose.tenants.ypto.clientID="$${GO_LOOSE_YPTO_CLIENT_ID:-}" \
|
||||
--set-string api.goLoose.tenants.ypto.clientSecret="$${GO_LOOSE_YPTO_CLIENT_SECRET:-}"
|
||||
|
||||
.PHONY: help dev db-up db-down migrate migrate-down seed backend frontend frontend-install test test-backend test-frontend test-integration test-bdd test-bdd-down test-env test-env-down lint build rancher-storage helm-lint helm-deploy-development helm-deploy-production helm-down-production helm-down-development
|
||||
.PHONY: help dev db-up db-down migrate migrate-down seed backend frontend frontend-install test test-backend test-frontend test-integration test-bdd test-bdd-down test-env test-env-down lint build rancher-storage ingress-nginx-install cert-manager-install cluster-prepare helm-lint helm-deploy-development helm-deploy-production helm-down-production helm-down-development
|
||||
|
||||
help:
|
||||
@echo "make dev builds the demo docker image"
|
||||
|
|
@ -33,6 +38,9 @@ help:
|
|||
@echo "make lint runs lint on the frontend"
|
||||
@echo "make build builds the entire project"
|
||||
@echo "make rancher-storage installs the persistent local-path StorageClass"
|
||||
@echo "make ingress-nginx-install installs the ingress-nginx controller serving 80/443"
|
||||
@echo "make cert-manager-install installs cert-manager for chart-issued TLS certificates"
|
||||
@echo "make cluster-prepare runs every cluster prerequisite in order"
|
||||
@echo "make helm-lint lints development and production Helm configurations"
|
||||
@echo "make helm-deploy-development deploys the development Helm release"
|
||||
@echo "make helm-deploy-production deploys the production Helm release"
|
||||
|
|
@ -104,6 +112,27 @@ build:
|
|||
rancher-storage:
|
||||
KUBECONFIG="$(KUBECONFIG)" kubectl apply -f deploy/rancher/local-path.yaml
|
||||
|
||||
ingress-nginx-install:
|
||||
$(HELM_KUBECTL) repo add ingress-nginx https://kubernetes.github.io/ingress-nginx --force-update
|
||||
$(HELM_KUBECTL) repo update
|
||||
$(HELM_KUBECTL) upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
|
||||
--namespace ingress-nginx --create-namespace \
|
||||
--set controller.service.type=NodePort \
|
||||
--set controller.hostPort.enabled=true \
|
||||
--set controller.kind=DaemonSet \
|
||||
--set controller.admissionWebhooks.enabled=false \
|
||||
--wait --timeout 10m
|
||||
|
||||
cert-manager-install:
|
||||
$(HELM_KUBECTL) repo add jetstack https://charts.jetstack.io --force-update
|
||||
$(HELM_KUBECTL) repo update
|
||||
$(HELM_KUBECTL) upgrade --install cert-manager jetstack/cert-manager \
|
||||
--namespace cert-manager --create-namespace \
|
||||
--set crds.enabled=true \
|
||||
--wait --timeout 10m
|
||||
|
||||
cluster-prepare: rancher-storage ingress-nginx-install cert-manager-install
|
||||
|
||||
helm-lint:
|
||||
KUBECONFIG="$(KUBECONFIG)" $(HELM) lint $(HELM_CHART) -f $(HELM_CHART)/values-development.yaml
|
||||
KUBECONFIG="$(KUBECONFIG)" $(HELM) lint $(HELM_CHART) -f $(HELM_CHART)/values-production.yaml
|
||||
|
|
@ -113,17 +142,25 @@ helm-lint:
|
|||
-f $(HELM_CHART)/values-production.yaml >/dev/null
|
||||
|
||||
helm-deploy-development:
|
||||
KUBECONFIG="$(KUBECONFIG)" $(HELM) upgrade --install $(HELM_RELEASE) $(HELM_CHART) --namespace $(HELM_NAMESPACE)-development --create-namespace -f $(HELM_CHART)/values-development.yaml --rollback-on-failure --wait --timeout 10m
|
||||
$(HELM_KUBECTL) upgrade --install $(HELM_RELEASE) $(HELM_CHART) \
|
||||
--namespace $(HELM_NAMESPACE)-development --create-namespace \
|
||||
-f $(HELM_CHART)/values-development.yaml \
|
||||
--set secrets.postgresqlPassword="go_guess" \
|
||||
--set secrets.rabbitmqPassword="guest" \
|
||||
$(GO_LOOSE_SET) \
|
||||
--rollback-on-failure --wait --timeout 10m
|
||||
|
||||
helm-deploy-production:
|
||||
KUBECONFIG="$(KUBECONFIG)" $(HELM) upgrade --install $(HELM_RELEASE) $(HELM_CHART) \
|
||||
$(HELM_KUBECTL) upgrade --install $(HELM_RELEASE) $(HELM_CHART) \
|
||||
--namespace $(HELM_NAMESPACE)-production --create-namespace \
|
||||
-f $(HELM_CHART)/values-production.yaml --wait --timeout 10m\
|
||||
-f $(HELM_CHART)/values-production.yaml \
|
||||
--set secrets.postgresqlPassword="go_guess" \
|
||||
--set secrets.rabbitmqPassword="guest"
|
||||
--set secrets.rabbitmqPassword="guest" \
|
||||
$(GO_LOOSE_SET) \
|
||||
--wait --timeout 10m
|
||||
|
||||
helm-down-production:
|
||||
KUBECONFIG="$(KUBECONFIG)" $(HELM) uninstall $(HELM_RELEASE) -n $(HELM_NAMESPACE)-production
|
||||
$(HELM_KUBECTL) uninstall $(HELM_RELEASE) -n $(HELM_NAMESPACE)-production
|
||||
|
||||
helm-down-development:
|
||||
KUBECONFIG="$(KUBECONFIG)" $(HELM) uninstall $(HELM_RELEASE) -n $(HELM_NAMESPACE)-development
|
||||
$(HELM_KUBECTL) uninstall $(HELM_RELEASE) -n $(HELM_NAMESPACE)-development
|
||||
|
|
|
|||
86
README.md
86
README.md
|
|
@ -156,36 +156,56 @@ make test-env-down
|
|||
|
||||
## Production image
|
||||
|
||||
Build the complete application as a single image:
|
||||
Two images are published to the private registry: `go-guess-api:0.0.1` for the Go
|
||||
service and `go-guess-web:0.0.1` for the React front end behind nginx.
|
||||
|
||||
```bash
|
||||
docker build -t go-guess .
|
||||
docker build -t batty1039.startdedicated.net:5000/go-guess-api:0.0.1 ./backend
|
||||
docker build -t batty1039.startdedicated.net:5000/go-guess-web:0.0.1 ./frontend
|
||||
```
|
||||
|
||||
The image serves the frontend and API on port `8080`. It applies database
|
||||
migrations and shared production fixtures before startup. PostgreSQL, RabbitMQ,
|
||||
and these environment variables must be provided:
|
||||
The API image listens on `8080` and applies database migrations and shared
|
||||
fixtures before serving. The web image listens on `80`, serves the built assets,
|
||||
and proxies `/api/` to `http://api:8080`, so both containers must share a
|
||||
network with the API reachable under the DNS name `api`. PostgreSQL, RabbitMQ,
|
||||
and these environment variables must be provided to the API:
|
||||
|
||||
```bash
|
||||
docker run --rm -p 8080:8080 \
|
||||
-e DATABASE_URL='postgres://user:password@postgres:5432/go_guess?sslmode=disable' \
|
||||
-e RABBITMQ_URL='amqp://user:password@rabbitmq:5672/' \
|
||||
-e JWT_SECRET='replace-with-at-least-32-characters' \
|
||||
-e FRONTEND_URL='https://go-guess.example.com' \
|
||||
go-guess
|
||||
-e FRONTEND_URL='https://nmbs.guess.local' \
|
||||
batty1039.startdedicated.net:5000/go-guess-api:0.0.1
|
||||
```
|
||||
|
||||
The `Dockerfile` at the repository root still builds one combined image that
|
||||
serves both halves on port `8080`. It is convenient for local runs and browser
|
||||
BDD tests, while Kubernetes deploys the two images separately.
|
||||
|
||||
Pushes to `master` publish `go-guess:latest` and `go-guess:<commit-sha>` to the
|
||||
private registry configured in `.github/workflows/publish-image.yml`. The
|
||||
repository must provide `REGISTRY_USERNAME` and `REGISTRY_PASSWORD` secrets.
|
||||
|
||||
## Rancher and Helm
|
||||
|
||||
The chart under `deploy/helm/go-guess` deploys the application, PostgreSQL, and
|
||||
RabbitMQ. It works with any Kubernetes cluster managed by Rancher; Rancher's free
|
||||
edition does not restrict Helm or GitHub Actions deployments.
|
||||
The chart under `deploy/helm/go-guess` deploys the API image, the web image, and
|
||||
their PostgreSQL and RabbitMQ. Every tenant gets its own HTTPS host at
|
||||
`https://<tenant>.guess.local`. The chart values are documented in
|
||||
[deploy/helm/go-guess/README.md](deploy/helm/go-guess/README.md).
|
||||
|
||||
Validate or deploy one of the environment profiles:
|
||||
One web deployment serves every tenant host because the API resolves the tenant
|
||||
from the request `Host` header, so a new tenant is one entry in `tenants`.
|
||||
|
||||
Install the cluster prerequisites once per cluster. Storage for persistent
|
||||
volumes, an ingress-nginx controller for the `nginx` ingress class, and
|
||||
cert-manager for the chart-issued certificate:
|
||||
|
||||
```bash
|
||||
make cluster-prepare
|
||||
```
|
||||
|
||||
Then validate or deploy one of the environment profiles:
|
||||
|
||||
```bash
|
||||
make helm-lint
|
||||
|
|
@ -193,25 +213,41 @@ make helm-deploy-development
|
|||
make helm-deploy-production
|
||||
```
|
||||
|
||||
For the repository's single-node Docker Rancher setup, run
|
||||
`make rancher-storage` once before the first production deployment. This
|
||||
installs the default persistent StorageClass documented in
|
||||
`rancher-install.txt`.
|
||||
Development uses `latest` images, development fixtures, and ephemeral database
|
||||
and broker storage in namespace `go-insane-development`. Production uses the
|
||||
released `0.0.1` tags, production fixtures, and persistent volumes in namespace
|
||||
`go-insane-production`.
|
||||
|
||||
Development uses demo fixtures, ephemeral database and message-broker storage,
|
||||
and NodePort `30080`. Production uses production fixtures, persistent volumes,
|
||||
generated secrets that are preserved across upgrades, and larger resource
|
||||
limits. It exposes the application at NodePort `31374` for the dedicated-server
|
||||
Nginx proxy while PostgreSQL and RabbitMQ remain cluster-internal. The public
|
||||
URL is `https://goguess.urpi.be`; one.com DNS, Nginx, Certbot, firewall, and
|
||||
verification instructions are in `deploy/nginx/README.md`.
|
||||
Certificates are self-signed and issued by the chart, so every browser or client
|
||||
that opens a tenant host needs the CA from the release:
|
||||
|
||||
```bash
|
||||
kubectl -n go-insane-production get secret go-guess-web-ca \
|
||||
-o jsonpath='{.data.ca\.crt}' | base64 -d > go-guess-ca.crt
|
||||
```
|
||||
|
||||
Point each tenant host at the ingress controller address, then open
|
||||
`https://nmbs.guess.local` and `https://ypto.guess.local`. Browser sign-in
|
||||
through Go Loose needs the per-tenant client credentials; pass them from the
|
||||
environment to `make helm-deploy-production`:
|
||||
|
||||
```bash
|
||||
export GO_LOOSE_NMBS_CLIENT_ID=... GO_LOOSE_NMBS_CLIENT_SECRET=...
|
||||
export GO_LOOSE_YPTO_CLIENT_ID=... GO_LOOSE_YPTO_CLIENT_SECRET=...
|
||||
```
|
||||
|
||||
Without credentials for a tenant, that host keeps password login. The cluster
|
||||
served by `~/.kube/config` is managed by Rancher at `rancher.urpi.be`, which is
|
||||
the management interface and not the deployment target. One.com DNS, Nginx,
|
||||
Certbot, and firewall instructions for the single-node dedicated server are in
|
||||
`deploy/nginx/README.md`.
|
||||
|
||||
To use external managed services, disable the bundled StatefulSets and provide
|
||||
full connection URLs:
|
||||
|
||||
```bash
|
||||
helm upgrade --install go-guess deploy/helm/go-guess \
|
||||
--namespace go-guess-production --create-namespace \
|
||||
--namespace go-insane-production --create-namespace \
|
||||
-f deploy/helm/go-guess/values-production.yaml \
|
||||
--set postgresql.enabled=false \
|
||||
--set rabbitmq.enabled=false \
|
||||
|
|
@ -229,8 +265,8 @@ workflow succeeds. Create GitHub environments named `development` and
|
|||
- Secrets `REGISTRY_USERNAME`, `REGISTRY_PASSWORD`, and
|
||||
`GO_GUESS_JWT_SECRET`.
|
||||
- Variable `RANCHER_NAMESPACE` for the target namespace.
|
||||
- Optional variable `GO_GUESS_FRONTEND_URL` when overriding an environment's
|
||||
configured public URL.
|
||||
- Optional secrets `GO_LOOSE_NMBS_CLIENT_ID`, `GO_LOOSE_NMBS_CLIENT_SECRET`,
|
||||
`GO_LOOSE_YPTO_CLIENT_ID`, and `GO_LOOSE_YPTO_CLIENT_SECRET`.
|
||||
|
||||
Because the configured image registry uses HTTP, every Rancher cluster node must
|
||||
trust `batty1039.startdedicated.net:5000` as an insecure registry. Use HTTPS for
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -30,6 +31,13 @@ type GoLooseTenant struct {
|
|||
ClientSecret string
|
||||
}
|
||||
|
||||
// GoLooseCredentialEnv returns the environment variable names holding the Go
|
||||
// Loose client credentials of a tenant.
|
||||
func GoLooseCredentialEnv(slug string) (idEnv, secretEnv string) {
|
||||
prefix := "GO_LOOSE_" + strings.ToUpper(slug)
|
||||
return prefix + "_CLIENT_ID", prefix + "_CLIENT_SECRET"
|
||||
}
|
||||
|
||||
func Load() (Config, error) {
|
||||
ttl, err := time.ParseDuration(env("TOKEN_TTL", "8h"))
|
||||
if err != nil {
|
||||
|
|
@ -62,15 +70,16 @@ func loadGoLoose() GoLooseConfig {
|
|||
CAFile: os.Getenv("GO_LOOSE_CA_FILE"),
|
||||
Tenants: map[string]GoLooseTenant{},
|
||||
}
|
||||
add := func(slug, idEnv, secretEnv string) {
|
||||
add := func(slug string) {
|
||||
idEnv, secretEnv := GoLooseCredentialEnv(slug)
|
||||
id, secret := os.Getenv(idEnv), os.Getenv(secretEnv)
|
||||
if id == "" || secret == "" {
|
||||
return
|
||||
}
|
||||
cfg.Tenants[slug] = GoLooseTenant{ClientID: id, ClientSecret: secret}
|
||||
}
|
||||
add("nmbs", "GO_LOOSE_NMBS_CLIENT_ID", "GO_LOOSE_NMBS_CLIENT_SECRET")
|
||||
add("ypto", "GO_LOOSE_YPTO_CLIENT_ID", "GO_LOOSE_YPTO_CLIENT_SECRET")
|
||||
add("nmbs")
|
||||
add("ypto")
|
||||
return cfg
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ package handler
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
goloose "github.com/danyel/go-loose/client"
|
||||
|
||||
"github.com/danyel/go-guess/backend/internal/config"
|
||||
"github.com/danyel/go-guess/backend/internal/golooseauth"
|
||||
webmapper "github.com/danyel/go-guess/backend/internal/web/mapper"
|
||||
webmodel "github.com/danyel/go-guess/backend/internal/web/model"
|
||||
|
|
@ -14,6 +16,8 @@ import (
|
|||
var (
|
||||
errMissingSession = errors.New("missing Go Loose session")
|
||||
errTenantMismatch = errors.New("Go Loose session does not match this tenant")
|
||||
errLoginDisabled = errors.New("Go Loose browser login is not enabled")
|
||||
errNoTenantHost = errors.New("this host does not identify a configured tenant")
|
||||
)
|
||||
|
||||
func (h *Handler) SetBrowserAuth(auth *golooseauth.Registry) {
|
||||
|
|
@ -28,27 +32,27 @@ func (h *Handler) AppDomain() string {
|
|||
}
|
||||
|
||||
func (h *Handler) BeginExternalLogin(w http.ResponseWriter, r *http.Request) {
|
||||
auth, ok := h.externalAuth(r)
|
||||
auth, slug, ok := h.externalAuthWithSlug(r)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
writeExternalAuthError(w, h, slug)
|
||||
return
|
||||
}
|
||||
auth.LoginHandler(w, r)
|
||||
}
|
||||
|
||||
func (h *Handler) CompleteExternalLogin(w http.ResponseWriter, r *http.Request) {
|
||||
auth, ok := h.externalAuth(r)
|
||||
auth, slug, ok := h.externalAuthWithSlug(r)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
writeExternalAuthError(w, h, slug)
|
||||
return
|
||||
}
|
||||
auth.CallbackHandler(w, r)
|
||||
}
|
||||
|
||||
func (h *Handler) ExternalLogout(w http.ResponseWriter, r *http.Request) {
|
||||
auth, ok := h.externalAuth(r)
|
||||
auth, slug, ok := h.externalAuthWithSlug(r)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
writeExternalAuthError(w, h, slug)
|
||||
return
|
||||
}
|
||||
auth.LogoutHandler(w, r)
|
||||
|
|
@ -57,7 +61,7 @@ func (h *Handler) ExternalLogout(w http.ResponseWriter, r *http.Request) {
|
|||
func (h *Handler) ExternalSession(w http.ResponseWriter, r *http.Request) {
|
||||
auth, slug, ok := h.externalAuthWithSlug(r)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
writeExternalAuthError(w, h, slug)
|
||||
return
|
||||
}
|
||||
if _, err := r.Cookie(golooseauth.SessionCookie); err != nil {
|
||||
|
|
@ -90,3 +94,17 @@ func (h *Handler) externalAuthWithSlug(r *http.Request) (*goloose.BrowserAuth, s
|
|||
}
|
||||
return h.browser.ForHost(r.Host)
|
||||
}
|
||||
|
||||
func writeExternalAuthError(w http.ResponseWriter, h *Handler, slug string) {
|
||||
if h.browser == nil {
|
||||
writeError(w, http.StatusNotFound, errLoginDisabled)
|
||||
return
|
||||
}
|
||||
if slug == "" {
|
||||
writeError(w, http.StatusNotFound, errNoTenantHost)
|
||||
return
|
||||
}
|
||||
idEnv, secretEnv := config.GoLooseCredentialEnv(slug)
|
||||
writeError(w, http.StatusServiceUnavailable,
|
||||
fmt.Errorf("Go Loose login is not configured for tenant %q: set %s and %s, then restart the API", slug, idEnv, secretEnv))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,6 +341,52 @@ func TestTenantHostLoginRedirectsToMatchingGoLooseClient(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTenantHostLoginExplainsUnconfiguredGoLooseTenant(t *testing.T) {
|
||||
h := newTestHandler(t, nil)
|
||||
browser, err := golooseauth.New(config.GoLooseConfig{
|
||||
AuthDomain: "auth.dev",
|
||||
AppDomain: "guess.dev",
|
||||
Tenants: map[string]config.GoLooseTenant{"nmbs": {ClientID: "glc_nmbs", ClientSecret: "secret"}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
h.SetBrowserAuth(browser)
|
||||
api := New(h, security.NewTokenManager("01234567890123456789012345678901", time.Hour), "http://localhost:5173")
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/auth/login", nil)
|
||||
request.Host = "ypto.guess.dev"
|
||||
response := httptest.NewRecorder()
|
||||
api.ServeHTTP(response, request)
|
||||
if response.Code != http.StatusServiceUnavailable ||
|
||||
!strings.Contains(response.Body.String(), "GO_LOOSE_YPTO_CLIENT_ID") {
|
||||
t.Fatalf("ypto login = %d %s", response.Code, response.Body.String())
|
||||
}
|
||||
|
||||
request = httptest.NewRequest(http.MethodGet, "/api/auth/login", nil)
|
||||
request.Host = "guess.dev"
|
||||
response = httptest.NewRecorder()
|
||||
api.ServeHTTP(response, request)
|
||||
if response.Code != http.StatusNotFound || !strings.Contains(response.Body.String(), "tenant") {
|
||||
t.Fatalf("apex login = %d %s", response.Code, response.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginWithoutGoLooseRegistryIsNotFound(t *testing.T) {
|
||||
api := New(
|
||||
newTestHandler(t, nil),
|
||||
security.NewTokenManager("01234567890123456789012345678901", time.Hour),
|
||||
"http://localhost:5173",
|
||||
)
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/auth/login", nil)
|
||||
request.Host = "nmbs.guess.dev"
|
||||
response := httptest.NewRecorder()
|
||||
api.ServeHTTP(response, request)
|
||||
if response.Code != http.StatusNotFound || !strings.Contains(response.Body.String(), "not enabled") {
|
||||
t.Fatalf("login without registry = %d %s", response.Code, response.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
type stubDriver struct{}
|
||||
|
||||
func (stubDriver) Open(string) (driver.Conn, error) { return stubConn{}, nil }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
apiVersion: v2
|
||||
name: go-guess
|
||||
description: Go Guess recruitment workspace
|
||||
description: Go Guess recruitment workspace with per-tenant web hosts
|
||||
type: application
|
||||
version: 0.2.0
|
||||
appVersion: "0.2.0"
|
||||
version: 0.3.0
|
||||
appVersion: "0.3.0"
|
||||
|
|
@ -1,17 +1,48 @@
|
|||
Go Guess has been installed in namespace {{ .Release.Namespace }}.
|
||||
{{- if .Values.goLoose.enabled }}
|
||||
Browser sign-in uses Go Loose at https://<tenant>.{{ .Values.goLoose.authDomain }}.
|
||||
{{- else }}
|
||||
Browser sign-in uses the application password login. Enable goLoose to redirect tenant hosts.
|
||||
Go Guess is installed in namespace {{ .Release.Namespace }}.
|
||||
|
||||
Components:
|
||||
API service/{{ include "go-guess.apiServiceName" . }}:{{ .Values.api.service.port }} (cluster-internal)
|
||||
Web service/{{ include "go-guess.webDeploymentName" . }}:{{ .Values.web.service.port }}
|
||||
Ingress {{ if .Values.ingress.enabled }}class {{ if .Values.ingress.className }}{{ .Values.ingress.className }}{{ else }}default{{ end }}{{ else }}disabled{{ end }}
|
||||
{{ if .Values.ingress.enabled }}
|
||||
Tenant URLs:
|
||||
{{- range .Values.tenants }}
|
||||
{{ if $.Values.ingress.tls.enabled }}https{{ else }}http{{ end }}://{{ printf "%s.%s" . $.Values.domain }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.ingress.enabled }}
|
||||
Open {{ .Values.app.frontendURL }}
|
||||
{{- else if eq .Values.service.type "NodePort" }}
|
||||
The application is exposed on cluster node port {{ .Values.service.nodePort }}.
|
||||
Open {{ .Values.app.frontendURL }} through the external reverse proxy.
|
||||
Point every tenant host at the ingress controller address, for example in
|
||||
/etc/hosts:
|
||||
{{- range .Values.tenants }}
|
||||
<ingress-controller-ip> {{ printf "%s.%s" . $.Values.domain }}
|
||||
{{- end }}
|
||||
{{- if and .Values.ingress.tls.enabled .Values.certManager.enabled (not .Values.ingress.tls.existingSecret) }}
|
||||
|
||||
The certificate is self-signed, so trust the chart CA in every browser or client
|
||||
that opens these hosts:
|
||||
kubectl -n {{ .Release.Namespace }} get secret {{ include "go-guess.certManagerCASecretName" . }} \
|
||||
-o jsonpath='{.data.ca\.crt}' | base64 -d > go-guess-ca.crt
|
||||
{{- end }}
|
||||
{{- if .Values.api.goLoose.enabled }}
|
||||
|
||||
Browser sign-in redirects to https://<tenant>.{{ .Values.api.goLoose.authDomain }}:
|
||||
{{- range $tenant, $credentials := .Values.api.goLoose.tenants }}
|
||||
{{- if and $credentials.clientID $credentials.clientSecret }}
|
||||
{{ $tenant }}: Go Loose browser sign-in
|
||||
{{- else }}
|
||||
{{ $tenant }}: no client credentials configured, password login only
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
|
||||
Browser sign-in uses the application password login.
|
||||
{{- end }}
|
||||
{{- else if and (eq .Values.web.service.type "NodePort") .Values.web.service.nodePort }}
|
||||
|
||||
The web Service is exposed on cluster node port {{ .Values.web.service.nodePort }}.
|
||||
{{- else }}
|
||||
|
||||
Run:
|
||||
kubectl -n {{ .Release.Namespace }} port-forward service/{{ include "go-guess.fullname" . }} 8080:{{ .Values.service.port }}
|
||||
kubectl -n {{ .Release.Namespace }} port-forward service/{{ include "go-guess.webDeploymentName" . }} 8080:{{ .Values.web.service.port }}
|
||||
|
||||
Then open http://127.0.0.1:8080.
|
||||
{{- end }}
|
||||
|
|
@ -39,3 +39,72 @@ app.kubernetes.io/instance: {{ .Release.Name }}
|
|||
{{- define "go-guess.rabbitmqName" -}}
|
||||
{{- printf "%s-rabbitmq" (include "go-guess.fullname" .) }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "go-guess.apiDeploymentName" -}}
|
||||
{{- printf "%s-api" (include "go-guess.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "go-guess.webDeploymentName" -}}
|
||||
{{- printf "%s-web" (include "go-guess.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/* DNS name the API is reachable under. The web image hardcodes "api:8080". */}}
|
||||
{{- define "go-guess.apiServiceName" -}}
|
||||
{{- default "api" .Values.api.service.name }}
|
||||
{{- end }}
|
||||
|
||||
{{/* Host serving one tenant, for example nmbs.guess.local. */}}
|
||||
{{- define "go-guess.tenantHost" -}}
|
||||
{{- printf "%s.%s" (index . 0) (index . 1) }}
|
||||
{{- end }}
|
||||
|
||||
{{/* Fallback public URL for invitation and meeting links. */}}
|
||||
{{- define "go-guess.frontendURL" -}}
|
||||
{{- if .Values.api.frontendURL }}
|
||||
{{- .Values.api.frontendURL }}
|
||||
{{- else if .Values.tenants }}
|
||||
{{- printf "https://%s.%s" (first .Values.tenants) .Values.domain }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/* Secret holding the wildcard-per-tenant web certificate. */}}
|
||||
{{- define "go-guess.tlsSecretName" -}}
|
||||
{{- if .Values.ingress.tls.existingSecret }}
|
||||
{{- .Values.ingress.tls.existingSecret }}
|
||||
{{- else if .Values.ingress.tls.secretName }}
|
||||
{{- .Values.ingress.tls.secretName }}
|
||||
{{- else }}
|
||||
{{- printf "%s-web-tls" (include "go-guess.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/* Cluster-scoped by default so one issuer signs every tenant release. */}}
|
||||
{{- define "go-guess.certManagerIssuerRef" -}}
|
||||
{{- if .Values.certManager.issuerRef }}
|
||||
toYaml .Values.certManager.issuerRef
|
||||
{{- else }}
|
||||
name: selfsigned
|
||||
kind: Issuer
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "go-guess.validate" -}}
|
||||
{{- if not .Values.tenants }}
|
||||
{{- fail "tenants must list at least one tenant slug" }}
|
||||
{{- end }}
|
||||
{{- if not .Values.domain }}
|
||||
{{- fail "domain is required" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.ingress.enabled .Values.ingress.tls.enabled (not .Values.certManager.enabled) (not .Values.ingress.tls.existingSecret) }}
|
||||
{{- fail "ingress.tls.enabled requires certManager.enabled or ingress.tls.existingSecret" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/* Secret holding the CA that signs the leaf web certificate. */}}
|
||||
{{- define "go-guess.certManagerCASecretName" -}}
|
||||
{{- if .Values.certManager.caSecretName }}
|
||||
{{- .Values.certManager.caSecretName }}
|
||||
{{- else }}
|
||||
{{- printf "%s-web-ca" (include "go-guess.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "go-guess.fullname" . }}
|
||||
labels:
|
||||
{{- include "go-guess.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
strategy:
|
||||
type: {{ .Values.strategy.type }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "go-guess.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: application
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/secrets: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "go-guess.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: application
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: go-guess
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
env:
|
||||
- name: APP_ENV
|
||||
value: {{ .Values.app.environment | quote }}
|
||||
- name: FRONTEND_URL
|
||||
value: {{ .Values.app.frontendURL | quote }}
|
||||
- name: TOKEN_TTL
|
||||
value: {{ .Values.app.tokenTTL | quote }}
|
||||
- name: MAX_UPLOAD_MB
|
||||
value: {{ .Values.app.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
|
||||
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.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: temporary-files
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- 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 }}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "go-guess.fullname" . }}
|
||||
labels:
|
||||
{{- include "go-guess.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
selector:
|
||||
{{- include "go-guess.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: application
|
||||
ports:
|
||||
- name: http
|
||||
port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
{{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }}
|
||||
nodePort: {{ .Values.service.nodePort }}
|
||||
{{- end }}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
{{- if .Values.ingress.enabled }}
|
||||
{{- $webService := include "go-guess.webDeploymentName" . }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
|
|
@ -13,23 +14,25 @@ spec:
|
|||
{{- with .Values.ingress.className }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
{{- with .Values.ingress.tls }}
|
||||
{{- if .Values.ingress.tls.enabled }}
|
||||
tls:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
- hosts:
|
||||
{{- range .Values.tenants }}
|
||||
- {{ printf "%s.%s" . $.Values.domain | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ include "go-guess.tlsSecretName" . }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
{{- range .Values.tenants }}
|
||||
- host: {{ printf "%s.%s" . $.Values.domain | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
- path: {{ $.Values.ingress.path }}
|
||||
pathType: {{ $.Values.ingress.pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "go-guess.fullname" $ }}
|
||||
name: {{ $webService }}
|
||||
port:
|
||||
number: {{ $.Values.service.port }}
|
||||
{{- end }}
|
||||
number: {{ $.Values.web.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
@ -32,3 +32,14 @@ data:
|
|||
rabbitmq-url: {{ $rabbitmqURL | b64enc | quote }}
|
||||
postgresql-password: {{ $postgresPassword | b64enc | quote }}
|
||||
rabbitmq-password: {{ $rabbitmqPassword | b64enc | quote }}
|
||||
{{- if .Values.api.goLoose.enabled }}
|
||||
{{- range $tenant, $credentials := .Values.api.goLoose.tenants }}
|
||||
{{- $prefix := printf "go-loose-%s" (lower $tenant) }}
|
||||
{{- if $credentials.clientID }}
|
||||
{{ printf "%s-client-id" $prefix }}: {{ $credentials.clientID | b64enc | quote }}
|
||||
{{- end }}
|
||||
{{- if $credentials.clientSecret }}
|
||||
{{ printf "%s-client-secret" $prefix }}: {{ $credentials.clientSecret | b64enc | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
@ -17,4 +17,11 @@ spec:
|
|||
- wget
|
||||
args:
|
||||
- -qO-
|
||||
- "http://{{ include "go-guess.fullname" . }}:{{ .Values.service.port }}/api/health"
|
||||
- "http://{{ include "go-guess.apiServiceName" . }}:{{ .Values.api.service.port }}/api/health"
|
||||
- name: wget-web
|
||||
image: busybox:1.37
|
||||
command:
|
||||
- wget
|
||||
args:
|
||||
- -qO-
|
||||
- "http://{{ include "go-guess.webDeploymentName" . }}:{{ .Values.web.service.port }}/"
|
||||
|
|
@ -1,19 +1,21 @@
|
|||
image:
|
||||
# Development profile: demo fixtures, ephemeral database and broker storage, and
|
||||
# `latest` image tags. TLS still uses the chart's self-signed certificate so
|
||||
# https://<tenant>.guess.local behaves like the production profile.
|
||||
domain: guess.local
|
||||
|
||||
tenants:
|
||||
- nmbs
|
||||
- ypto
|
||||
|
||||
api:
|
||||
environment: development
|
||||
image:
|
||||
tag: latest
|
||||
pullPolicy: Always
|
||||
|
||||
app:
|
||||
environment: development
|
||||
frontendURL: http://localhost:30080
|
||||
|
||||
service:
|
||||
type: NodePort
|
||||
nodePort: 30080
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
resources:
|
||||
goLoose:
|
||||
enabled: true
|
||||
authDomain: auth.dev
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 96Mi
|
||||
|
|
@ -21,6 +23,22 @@ resources:
|
|||
cpu: 300m
|
||||
memory: 384Mi
|
||||
|
||||
web:
|
||||
replicaCount: 1
|
||||
image:
|
||||
tag: latest
|
||||
pullPolicy: Always
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 96Mi
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
|
||||
postgresql:
|
||||
persistence:
|
||||
enabled: false
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
image:
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
# Production profile: production fixtures, persistent volumes, released image
|
||||
# tags, and self-signed certificates served for https://<tenant>.guess.local.
|
||||
domain: guess.local
|
||||
|
||||
app:
|
||||
tenants:
|
||||
- nmbs
|
||||
- ypto
|
||||
|
||||
api:
|
||||
environment: production
|
||||
frontendURL: https://goguess.urpi.be
|
||||
|
||||
service:
|
||||
type: NodePort
|
||||
nodePort: 31374
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
resources:
|
||||
image:
|
||||
tag: "0.0.1"
|
||||
pullPolicy: IfNotPresent
|
||||
goLoose:
|
||||
enabled: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
|
|
@ -21,6 +21,26 @@ resources:
|
|||
cpu: "1"
|
||||
memory: 768Mi
|
||||
|
||||
web:
|
||||
replicaCount: 2
|
||||
image:
|
||||
tag: "0.0.1"
|
||||
pullPolicy: IfNotPresent
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 300m
|
||||
memory: 128Mi
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
|
||||
certManager:
|
||||
enabled: true
|
||||
|
||||
postgresql:
|
||||
persistence:
|
||||
enabled: true
|
||||
|
|
|
|||
|
|
@ -1,30 +1,142 @@
|
|||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
replicaCount: 1
|
||||
# Public application domain. Every tenant is served from https://<tenant>.<domain>.
|
||||
domain: guess.local
|
||||
|
||||
image:
|
||||
repository: batty1039.startdedicated.net:5000/go-guess
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
# Tenant slugs. Each one gets its own ingress host and TLS SAN.
|
||||
tenants:
|
||||
- nmbs
|
||||
- ypto
|
||||
|
||||
imagePullSecrets: []
|
||||
|
||||
app:
|
||||
environment: production
|
||||
frontendURL: http://localhost:8080
|
||||
api:
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: batty1039.startdedicated.net:5000/go-guess-api
|
||||
tag: "0.0.1"
|
||||
pullPolicy: IfNotPresent
|
||||
environment: development
|
||||
# Public base URL used when building invitation and meeting links. Defaults to
|
||||
# https://<first tenant>.<domain> when empty.
|
||||
frontendURL: ""
|
||||
tokenTTL: 8h
|
||||
maxUploadMB: 10
|
||||
|
||||
goLoose:
|
||||
service:
|
||||
# The web image proxies /api/ to the literal upstream name "api:8080", so this
|
||||
# Service name has to stay "api" unless the web image is rebuilt.
|
||||
name: api
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
goLoose:
|
||||
enabled: false
|
||||
authDomain: auth.dev
|
||||
appDomain: guess.dev
|
||||
ca:
|
||||
# Mount an internal CA bundle and point GO_LOOSE_CA_FILE at it.
|
||||
existingSecret: ""
|
||||
key: ca.crt
|
||||
mountPath: /certs/local-ca.crt
|
||||
tenants: []
|
||||
# Per-tenant browser authentication credentials, written to the release secret.
|
||||
tenants:
|
||||
nmbs:
|
||||
clientID: ""
|
||||
clientSecret: ""
|
||||
ypto:
|
||||
clientID: ""
|
||||
clientSecret: ""
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
podAnnotations: {}
|
||||
podLabels: {}
|
||||
# The image runs as its own "app" user (uid 100), so no uid is forced here:
|
||||
# runAsNonRoot then validates whatever the image declares.
|
||||
podSecurityContext: {}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
# The API container applies migrations and seeds before serving, so old pods must
|
||||
# be gone before the new one starts.
|
||||
strategy:
|
||||
type: Recreate
|
||||
|
||||
web:
|
||||
replicaCount: 2
|
||||
image:
|
||||
repository: batty1039.startdedicated.net:5000/go-guess-web
|
||||
tag: "0.0.1"
|
||||
pullPolicy: IfNotPresent
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
nodePort: null
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
cpu: 300m
|
||||
memory: 128Mi
|
||||
podAnnotations: {}
|
||||
podLabels: {}
|
||||
# nginx workers run as uid 101, which the image already declares.
|
||||
podSecurityContext: {}
|
||||
# nginx binds the privileged port 80 and forks workers as the nginx user, so it
|
||||
# needs the root user plus a small capability set and writable scratch paths.
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
add:
|
||||
- CHOWN
|
||||
- SETGID
|
||||
- SETUID
|
||||
- NET_BIND_SERVICE
|
||||
readOnlyRootFilesystem: false
|
||||
runAsNonRoot: false
|
||||
runAsUser: 0
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: 10m
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-buffering: "off"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
enabled: true
|
||||
# Use a certificate you already manage instead of the chart-issued one.
|
||||
existingSecret: ""
|
||||
# Defaults to <fullname>-web-tls when empty and certManager.enabled is true.
|
||||
secretName: ""
|
||||
|
||||
certManager:
|
||||
# Requires cert-manager in the cluster: make cert-manager-install.
|
||||
enabled: true
|
||||
# Reuse an existing cert-manager issuer instead of creating a self-signed one.
|
||||
issuerRef: {}
|
||||
duration: 8760h
|
||||
renewBefore: 720h
|
||||
caSecretName: ""
|
||||
|
||||
secrets:
|
||||
jwtSecret: ""
|
||||
|
|
@ -33,49 +145,6 @@ secrets:
|
|||
postgresqlPassword: ""
|
||||
rabbitmqPassword: ""
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
nodePort: null
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
className: nginx
|
||||
annotations: {}
|
||||
hosts:
|
||||
- host: go-guess.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls: []
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
podAnnotations: {}
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext:
|
||||
fsGroup: 10001
|
||||
fsGroupChangePolicy: OnRootMismatch
|
||||
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
runAsUser: 10001
|
||||
|
||||
strategy:
|
||||
type: Recreate
|
||||
|
||||
postgresql:
|
||||
enabled: true
|
||||
image:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue