From a195cc10c6a62c431a1c92791b703090541b28e6 Mon Sep 17 00:00:00 2001 From: prymax10 Date: Tue, 28 Apr 2026 09:55:46 -0300 Subject: [PATCH 1/4] feat(go-boilerplate-ddd): add Helm chart for Go Boilerplate DDD reference service Adds production-ready Helm chart following the single-component pattern (tracer reference). Includes Deployment, Service, Ingress, ConfigMap, Secret (stringData/AVP-safe), PDB, HPA, ServiceAccount, and an idempotent PostgreSQL bootstrap job. Key characteristics: - Liveness: GET /health, Readiness: GET /ready - distroless nonroot (UID/GID 65532), readOnlyRootFilesystem - Image: ghcr.io/lerianstudio/go-boilerplate-ddd - OTel HOST_IP injection when ENABLE_TELEMETRY=true - values-template.yaml with AVP placeholders for Vault secrets --- charts/go-boilerplate-ddd/Chart.yaml | 29 +++ .../go-boilerplate-ddd/templates/_helpers.tpl | 75 ++++++ .../templates/bootstrap-postgres.yaml | 131 ++++++++++ .../templates/configmap.yaml | 60 +++++ .../templates/deployment.yaml | 94 +++++++ charts/go-boilerplate-ddd/templates/hpa.yaml | 33 +++ .../go-boilerplate-ddd/templates/ingress.yaml | 42 ++++ charts/go-boilerplate-ddd/templates/pdb.yaml | 23 ++ .../go-boilerplate-ddd/templates/secrets.yaml | 14 ++ .../go-boilerplate-ddd/templates/service.yaml | 22 ++ .../templates/serviceaccount.yaml | 13 + .../go-boilerplate-ddd/values-template.yaml | 93 +++++++ charts/go-boilerplate-ddd/values.yaml | 237 ++++++++++++++++++ 13 files changed, 866 insertions(+) create mode 100644 charts/go-boilerplate-ddd/Chart.yaml create mode 100644 charts/go-boilerplate-ddd/templates/_helpers.tpl create mode 100644 charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml create mode 100644 charts/go-boilerplate-ddd/templates/configmap.yaml create mode 100644 charts/go-boilerplate-ddd/templates/deployment.yaml create mode 100644 charts/go-boilerplate-ddd/templates/hpa.yaml create mode 100644 charts/go-boilerplate-ddd/templates/ingress.yaml create mode 100644 charts/go-boilerplate-ddd/templates/pdb.yaml create mode 100644 charts/go-boilerplate-ddd/templates/secrets.yaml create mode 100644 charts/go-boilerplate-ddd/templates/service.yaml create mode 100644 charts/go-boilerplate-ddd/templates/serviceaccount.yaml create mode 100644 charts/go-boilerplate-ddd/values-template.yaml create mode 100644 charts/go-boilerplate-ddd/values.yaml diff --git a/charts/go-boilerplate-ddd/Chart.yaml b/charts/go-boilerplate-ddd/Chart.yaml new file mode 100644 index 00000000..928884ba --- /dev/null +++ b/charts/go-boilerplate-ddd/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: go-boilerplate-ddd-helm +description: A Helm chart for Go Boilerplate DDD - Lerian reference service template + +type: application + +home: https://github.com/LerianStudio/helm + +sources: + - https://github.com/LerianStudio/helm/tree/main/charts/go-boilerplate-ddd + - https://github.com/LerianStudio/go-boilerplate-ddd + +maintainers: + - name: "Lerian Studio" + email: "support@lerian.studio" + +version: 1.0.0 + +appVersion: "1.0.0" + +keywords: + - boilerplate + - reference + - template + - lerian + - ddd + - hexagonal + +icon: https://avatars.githubusercontent.com/u/148895005?s=200&v=4 diff --git a/charts/go-boilerplate-ddd/templates/_helpers.tpl b/charts/go-boilerplate-ddd/templates/_helpers.tpl new file mode 100644 index 00000000..46985880 --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/_helpers.tpl @@ -0,0 +1,75 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "boilerplate.name" -}} +{{- default (default "go-boilerplate-ddd" .Values.nameOverride) | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name for go-boilerplate-ddd. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "boilerplate.fullname" -}} +{{- default (include "boilerplate.name" .) .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "boilerplate.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create go-boilerplate-ddd app version +*/}} +{{- define "boilerplate.defaultTag" -}} +{{- default .Chart.AppVersion .Values.boilerplate.image.tag }} +{{- end -}} + +{{/* +Return valid go-boilerplate-ddd version label +*/}} +{{- define "boilerplate.versionLabelValue" -}} +{{ regexReplaceAll "[^-A-Za-z0-9_.]" (include "boilerplate.defaultTag" .) "-" | trunc 63 | trimAll "-" | trimAll "_" | trimAll "." | quote }} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "boilerplate.labels" -}} +helm.sh/chart: {{ include "boilerplate.chart" .context }} +{{ include "boilerplate.selectorLabels" (dict "context" .context "component" .component "name" .name) }} +app.kubernetes.io/version: {{ include "boilerplate.versionLabelValue" .context }} +app.kubernetes.io/managed-by: {{ .context.Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "boilerplate.selectorLabels" -}} +app.kubernetes.io/name: {{ include "boilerplate.name" .context }} +app.kubernetes.io/instance: {{ .context.Release.Name }} +{{- if .component }} +app.kubernetes.io/component: {{ .component }} +{{- end }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "boilerplate.serviceAccountName" -}} +{{- if .Values.boilerplate.serviceAccount.create }} +{{- default (include "boilerplate.fullname" .) .Values.boilerplate.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.boilerplate.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Expand the namespace of the release. +Allows overriding it for multi-namespace deployments in combined charts. +*/}} +{{- define "global.namespace" -}} +{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml b/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml new file mode 100644 index 00000000..f097faa6 --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml @@ -0,0 +1,131 @@ +{{- if .Values.global.externalPostgresDefinitions.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "boilerplate.fullname" . }}-bootstrap-postgres + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" "bootstrap" "name" "postgres") | nindent 4 }} +spec: + ttlSecondsAfterFinished: 300 + completions: 1 + parallelism: 1 + backoffLimit: 3 + template: + spec: + restartPolicy: Never + initContainers: + - name: wait-for-dependencies + image: busybox:1.37 + env: + - name: DB_HOST + value: {{ .Values.global.externalPostgresDefinitions.connection.host | quote }} + - name: DB_PORT + value: {{ .Values.global.externalPostgresDefinitions.connection.port | quote }} + command: + - /bin/sh + - -c + - > + TIMEOUT=300; + ELAPSED=0; + echo "Checking $DB_HOST:$DB_PORT..."; + while ! nc -z "$DB_HOST" "$DB_PORT"; do + if [ $ELAPSED -ge $TIMEOUT ]; then + echo "Timeout waiting for $DB_HOST:$DB_PORT after ${TIMEOUT}s"; + exit 1; + fi; + echo "$DB_HOST:$DB_PORT is not ready yet, waiting... (${ELAPSED}s/${TIMEOUT}s)"; + sleep 5; + ELAPSED=$((ELAPSED + 5)); + done; + echo "$DB_HOST:$DB_PORT is ready!"; + containers: + - name: psql + image: postgres:17 + env: + - name: DB_HOST + value: {{ .Values.global.externalPostgresDefinitions.connection.host | quote }} + - name: DB_PORT + value: {{ .Values.global.externalPostgresDefinitions.connection.port | quote }} + - name: DB_USER_ADMIN + {{- if .Values.global.externalPostgresDefinitions.postgresAdminLogin.useExistingSecret.name }} + valueFrom: + secretKeyRef: + name: {{ .Values.global.externalPostgresDefinitions.postgresAdminLogin.useExistingSecret.name | quote }} + key: DB_USER_ADMIN + {{- else }} + value: {{ .Values.global.externalPostgresDefinitions.postgresAdminLogin.username | quote }} + {{- end }} + - name: DB_ADMIN_PASSWORD + {{- if .Values.global.externalPostgresDefinitions.postgresAdminLogin.useExistingSecret.name }} + valueFrom: + secretKeyRef: + name: {{ .Values.global.externalPostgresDefinitions.postgresAdminLogin.useExistingSecret.name | quote }} + key: DB_ADMIN_PASSWORD + {{- else }} + value: {{ .Values.global.externalPostgresDefinitions.postgresAdminLogin.password | quote }} + {{- end }} + - name: DB_PASSWORD_BOILERPLATE + {{- if .Values.global.externalPostgresDefinitions.boilerplateCredentials.useExistingSecret.name }} + valueFrom: + secretKeyRef: + name: {{ .Values.global.externalPostgresDefinitions.boilerplateCredentials.useExistingSecret.name | quote }} + key: DB_PASSWORD_BOILERPLATE + {{- else }} + value: {{ .Values.global.externalPostgresDefinitions.boilerplateCredentials.password | quote }} + {{- end }} + - name: DB_DATABASE + value: postgres + command: + - /bin/sh + - -c + - | + set -euo pipefail + echo "=== Go Boilerplate DDD PostgreSQL Bootstrap ===" + echo "Host: $DB_HOST:$DB_PORT" + echo "" + + echo "Checking existing PostgreSQL objects..." + DB_EXISTS=0 + ROLE_EXISTS=0 + + if PGPASSWORD="$DB_ADMIN_PASSWORD" psql -At -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" -c "SELECT 1 FROM pg_database WHERE datname='go-boilerplate-ddd'" | grep -q 1; then + DB_EXISTS=1 + fi + if PGPASSWORD="$DB_ADMIN_PASSWORD" psql -At -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" -c "SELECT 1 FROM pg_roles WHERE rolname='go-boilerplate-ddd'" | grep -q 1; then + ROLE_EXISTS=1 + fi + + if [ "$DB_EXISTS" = "1" ] && [ "$ROLE_EXISTS" = "1" ]; then + echo "PostgreSQL bootstrap already complete (database 'go-boilerplate-ddd' and role 'go-boilerplate-ddd' exist). Skipping creation." + else + # Create role if not exists + if [ "$ROLE_EXISTS" = "1" ]; then + echo "Role 'go-boilerplate-ddd' already exists. Skipping creation." + else + echo "Creating role 'go-boilerplate-ddd'..." + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" -c "CREATE ROLE \"go-boilerplate-ddd\" LOGIN PASSWORD '$DB_PASSWORD_BOILERPLATE'" + fi + + # Create database if not exists + if [ "$DB_EXISTS" = "1" ]; then + echo "Database 'go-boilerplate-ddd' already exists. Skipping creation." + else + echo "Creating database 'go-boilerplate-ddd'..." + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" -c "CREATE DATABASE \"go-boilerplate-ddd\" OWNER \"go-boilerplate-ddd\"" + fi + fi + + # Privileges (safe to run repeatedly) + echo "Ensuring privileges and schema permissions..." + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" -c "ALTER USER \"go-boilerplate-ddd\" CREATEDB" || true + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" -c "GRANT ALL PRIVILEGES ON DATABASE \"go-boilerplate-ddd\" TO \"go-boilerplate-ddd\"" + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "go-boilerplate-ddd" -c "GRANT ALL ON SCHEMA public TO \"go-boilerplate-ddd\"" + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "go-boilerplate-ddd" -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"go-boilerplate-ddd\"" + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "go-boilerplate-ddd" -c "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO \"go-boilerplate-ddd\"" + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "go-boilerplate-ddd" -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO \"go-boilerplate-ddd\"" + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "go-boilerplate-ddd" -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO \"go-boilerplate-ddd\"" + + echo "" + echo "=== Go Boilerplate DDD PostgreSQL Bootstrap completed successfully ===" +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/configmap.yaml b/charts/go-boilerplate-ddd/templates/configmap.yaml new file mode 100644 index 00000000..94b0f37d --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/configmap.yaml @@ -0,0 +1,60 @@ +{{- if .Values.boilerplate.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "boilerplate.fullname" . }} + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} +data: + # Application Settings + ENV_NAME: {{ .Values.boilerplate.configmap.ENV_NAME | default "production" | quote }} + LOG_LEVEL: {{ .Values.boilerplate.configmap.LOG_LEVEL | default "info" | quote }} + SERVER_ADDRESS: {{ .Values.boilerplate.configmap.SERVER_ADDRESS | default ":8080" | quote }} + + # CORS + CORS_ALLOWED_ORIGINS: {{ .Values.boilerplate.configmap.CORS_ALLOWED_ORIGINS | default "*" | quote }} + + # Auth Plugin (Access Manager) + PLUGIN_AUTH_ENABLED: {{ .Values.boilerplate.configmap.PLUGIN_AUTH_ENABLED | default "false" | quote }} + PLUGIN_AUTH_HOST: {{ .Values.boilerplate.configmap.PLUGIN_AUTH_HOST | default "http://plugin-auth:4000" | quote }} + + # PostgreSQL Database + POSTGRES_HOST: {{ .Values.boilerplate.configmap.POSTGRES_HOST | default "go-boilerplate-ddd-postgresql" | quote }} + POSTGRES_PORT: {{ .Values.boilerplate.configmap.POSTGRES_PORT | default "5432" | quote }} + POSTGRES_USER: {{ .Values.boilerplate.configmap.POSTGRES_USER | default "go-boilerplate-ddd" | quote }} + POSTGRES_NAME: {{ .Values.boilerplate.configmap.POSTGRES_NAME | default "go-boilerplate-ddd" | quote }} + POSTGRES_SSLMODE: {{ .Values.boilerplate.configmap.POSTGRES_SSLMODE | default "disable" | quote }} + MIGRATIONS_PATH: {{ .Values.boilerplate.configmap.MIGRATIONS_PATH | default "migrations" | quote }} + + # Redis + REDIS_HOST: {{ .Values.boilerplate.configmap.REDIS_HOST | default "go-boilerplate-ddd-redis:6379" | quote }} + REDIS_DB: {{ .Values.boilerplate.configmap.REDIS_DB | default "0" | quote }} + REDIS_TLS: {{ .Values.boilerplate.configmap.REDIS_TLS | default "false" | quote }} + + # OpenTelemetry (Observability) + ENABLE_TELEMETRY: {{ .Values.boilerplate.configmap.ENABLE_TELEMETRY | default "false" | quote }} + OTEL_RESOURCE_SERVICE_NAME: {{ .Values.boilerplate.configmap.OTEL_RESOURCE_SERVICE_NAME | default "go-boilerplate-ddd" | quote }} + OTEL_LIBRARY_NAME: {{ .Values.boilerplate.configmap.OTEL_LIBRARY_NAME | default "github.com/LerianStudio/go-boilerplate-ddd" | quote }} + OTEL_EXPORTER_OTLP_ENDPOINT: {{ .Values.boilerplate.configmap.OTEL_EXPORTER_OTLP_ENDPOINT | default "" | quote }} + OTEL_RESOURCE_DEPLOYMENT_ENVIRONMENT: {{ .Values.boilerplate.configmap.OTEL_RESOURCE_DEPLOYMENT_ENVIRONMENT | default "production" | quote }} + + # Rate Limiting + RATE_LIMIT_ENABLED: {{ .Values.boilerplate.configmap.RATE_LIMIT_ENABLED | default "true" | quote }} + RATE_LIMIT_MAX: {{ .Values.boilerplate.configmap.RATE_LIMIT_MAX | default "500" | quote }} + RATE_LIMIT_WINDOW_SEC: {{ .Values.boilerplate.configmap.RATE_LIMIT_WINDOW_SEC | default "60" | quote }} + + # Swagger Documentation + SWAGGER_ENABLED: {{ .Values.boilerplate.configmap.SWAGGER_ENABLED | default "true" | quote }} + SWAGGER_TITLE: {{ .Values.boilerplate.configmap.SWAGGER_TITLE | default "Go Boilerplate DDD" | quote }} + + # Multi-tenant (disabled by default) + MULTI_TENANT_ENABLED: {{ .Values.boilerplate.configmap.MULTI_TENANT_ENABLED | default "false" | quote }} + + # Extra Env Vars + {{- with .Values.boilerplate.extraEnvVars }} + {{- range . }} + {{ .name }}: {{ .value | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/deployment.yaml b/charts/go-boilerplate-ddd/templates/deployment.yaml new file mode 100644 index 00000000..533d66af --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/deployment.yaml @@ -0,0 +1,94 @@ +{{- if .Values.boilerplate.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "boilerplate.fullname" . }} + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} +spec: + revisionHistoryLimit: {{ .Values.boilerplate.revisionHistoryLimit | default 10 }} + strategy: + type: {{ .Values.boilerplate.deploymentUpdate.type }} + {{- if eq .Values.boilerplate.deploymentUpdate.type "RollingUpdate" }} + rollingUpdate: + maxSurge: {{ .Values.boilerplate.deploymentUpdate.maxSurge }} + maxUnavailable: {{ .Values.boilerplate.deploymentUpdate.maxUnavailable }} + {{- end }} + {{- if not .Values.boilerplate.autoscaling.enabled }} + replicas: {{ .Values.boilerplate.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "boilerplate.selectorLabels" (dict "context" . "name" .Values.boilerplate.name) | nindent 6 }} + template: + metadata: + {{- with .Values.boilerplate.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 8 }} + spec: + {{- with .Values.boilerplate.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "boilerplate.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.boilerplate.podSecurityContext | nindent 8 }} + containers: + - name: {{ include "boilerplate.fullname" . }} + securityContext: + {{- toYaml .Values.boilerplate.securityContext | nindent 12 }} + image: "{{ .Values.boilerplate.image.repository }}:{{ .Values.boilerplate.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.boilerplate.image.pullPolicy }} + envFrom: + - secretRef: + name: {{ if .Values.boilerplate.useExistingSecret }}{{ .Values.boilerplate.existingSecretName }}{{ else }}{{ include "boilerplate.fullname" . }}{{ end }} + - configMapRef: + name: {{ include "boilerplate.fullname" . }} + {{- if eq (toString .Values.boilerplate.configmap.ENABLE_TELEMETRY) "true" }} + env: + - name: "HOST_IP" + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: "OTEL_EXPORTER_OTLP_ENDPOINT" + value: "$(HOST_IP):4317" + {{- end }} + ports: + - name: http + containerPort: {{ .Values.boilerplate.service.port }} + protocol: TCP + livenessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 15 + periodSeconds: 20 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /ready + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + resources: + {{- toYaml .Values.boilerplate.resources | nindent 12 }} + {{- with .Values.boilerplate.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.boilerplate.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.boilerplate.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/hpa.yaml b/charts/go-boilerplate-ddd/templates/hpa.yaml new file mode 100644 index 00000000..97685d67 --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/hpa.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.boilerplate.enabled .Values.boilerplate.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "boilerplate.fullname" . }} + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "boilerplate.fullname" . }} + minReplicas: {{ .Values.boilerplate.autoscaling.minReplicas }} + maxReplicas: {{ .Values.boilerplate.autoscaling.maxReplicas }} + metrics: + {{- if .Values.boilerplate.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.boilerplate.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.boilerplate.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.boilerplate.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/ingress.yaml b/charts/go-boilerplate-ddd/templates/ingress.yaml new file mode 100644 index 00000000..47c20a77 --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/ingress.yaml @@ -0,0 +1,42 @@ +{{- if and .Values.boilerplate.enabled .Values.boilerplate.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "boilerplate.fullname" . }} + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} + {{- with .Values.boilerplate.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.boilerplate.ingress.className }} + ingressClassName: {{ .Values.boilerplate.ingress.className }} + {{- end }} + {{- if .Values.boilerplate.ingress.tls }} + tls: + {{- range .Values.boilerplate.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.boilerplate.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "boilerplate.fullname" $ }} + port: + number: {{ $.Values.boilerplate.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/pdb.yaml b/charts/go-boilerplate-ddd/templates/pdb.yaml new file mode 100644 index 00000000..a01458de --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/pdb.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.boilerplate.enabled .Values.boilerplate.pdb.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "boilerplate.fullname" . }} + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} + {{- with .Values.boilerplate.pdb.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.boilerplate.pdb.minAvailable }} + minAvailable: {{ .Values.boilerplate.pdb.minAvailable }} + {{- end }} + {{- if .Values.boilerplate.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.boilerplate.pdb.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- include "boilerplate.selectorLabels" (dict "context" . "name" .Values.boilerplate.name) | nindent 6 }} +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/secrets.yaml b/charts/go-boilerplate-ddd/templates/secrets.yaml new file mode 100644 index 00000000..5ba2f752 --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/secrets.yaml @@ -0,0 +1,14 @@ +{{- if and .Values.boilerplate.enabled (not .Values.boilerplate.useExistingSecret) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "boilerplate.fullname" . }} + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} +type: Opaque +stringData: + {{- range $key, $value := .Values.boilerplate.secrets }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/service.yaml b/charts/go-boilerplate-ddd/templates/service.yaml new file mode 100644 index 00000000..f419c8f6 --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/service.yaml @@ -0,0 +1,22 @@ +{{- if .Values.boilerplate.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "boilerplate.fullname" . }} + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} + {{- with .Values.boilerplate.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.boilerplate.service.type }} + ports: + - port: {{ .Values.boilerplate.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "boilerplate.selectorLabels" (dict "context" . "name" .Values.boilerplate.name) | nindent 4 }} +{{- end }} diff --git a/charts/go-boilerplate-ddd/templates/serviceaccount.yaml b/charts/go-boilerplate-ddd/templates/serviceaccount.yaml new file mode 100644 index 00000000..39071abd --- /dev/null +++ b/charts/go-boilerplate-ddd/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.boilerplate.enabled .Values.boilerplate.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "boilerplate.serviceAccountName" . }} + namespace: {{ include "global.namespace" . }} + labels: + {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} + {{- with .Values.boilerplate.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/go-boilerplate-ddd/values-template.yaml b/charts/go-boilerplate-ddd/values-template.yaml new file mode 100644 index 00000000..79ba1303 --- /dev/null +++ b/charts/go-boilerplate-ddd/values-template.yaml @@ -0,0 +1,93 @@ +# Template values for go-boilerplate-ddd deployment +# Copy this file and customize for your environment + +namespaceOverride: "go-boilerplate-ddd" + +global: + externalPostgresDefinitions: + enabled: false + connection: + host: "" + port: "5432" + postgresAdminLogin: + useExistingSecret: + name: "" + username: "" + password: "" + boilerplateCredentials: + useExistingSecret: + name: "" + password: "" + +boilerplate: + enabled: true + replicaCount: 1 + + image: + repository: ghcr.io/lerianstudio/go-boilerplate-ddd + pullPolicy: IfNotPresent + tag: "" + + imagePullSecrets: + - name: ghcr-credential + + ingress: + enabled: true + className: "nginx" + annotations: {} + hosts: + - host: "" + paths: + - path: / + pathType: Prefix + tls: [] + + resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 50m + memory: 64Mi + + autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 5 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + + configmap: + ENV_NAME: "" + LOG_LEVEL: "info" + SERVER_ADDRESS: ":8080" + CORS_ALLOWED_ORIGINS: "" + PLUGIN_AUTH_ENABLED: "false" + PLUGIN_AUTH_HOST: "" + POSTGRES_HOST: "" + POSTGRES_PORT: "5432" + POSTGRES_USER: "go-boilerplate-ddd" + POSTGRES_NAME: "go-boilerplate-ddd" + POSTGRES_SSLMODE: "disable" + MIGRATIONS_PATH: "migrations" + REDIS_HOST: "" + REDIS_DB: "0" + REDIS_TLS: "false" + ENABLE_TELEMETRY: "false" + OTEL_RESOURCE_SERVICE_NAME: "go-boilerplate-ddd" + OTEL_LIBRARY_NAME: "github.com/LerianStudio/go-boilerplate-ddd" + OTEL_EXPORTER_OTLP_ENDPOINT: "" + OTEL_RESOURCE_DEPLOYMENT_ENVIRONMENT: "" + RATE_LIMIT_ENABLED: "true" + RATE_LIMIT_MAX: "500" + RATE_LIMIT_WINDOW_SEC: "60" + SWAGGER_ENABLED: "true" + SWAGGER_TITLE: "Go Boilerplate DDD" + MULTI_TENANT_ENABLED: "false" + + secrets: + POSTGRES_PASSWORD: "" + REDIS_PASSWORD: "" + + useExistingSecret: false + existingSecretName: "" diff --git a/charts/go-boilerplate-ddd/values.yaml b/charts/go-boilerplate-ddd/values.yaml new file mode 100644 index 00000000..563d22ab --- /dev/null +++ b/charts/go-boilerplate-ddd/values.yaml @@ -0,0 +1,237 @@ +# Default values for go-boilerplate-ddd. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +nameOverride: "go-boilerplate-ddd" +fullnameOverride: "" +namespaceOverride: "go-boilerplate-ddd" + +global: + # -- Bootstrap job for external PostgreSQL: creates databases, roles, and grants privileges + externalPostgresDefinitions: + # -- Enable or disable the PostgreSQL bootstrap job + enabled: false + # -- PostgreSQL connection settings + connection: + # -- PostgreSQL host + host: "go-boilerplate-ddd-postgresql" + # -- PostgreSQL port + port: "5432" + # -- Admin credentials for PostgreSQL + postgresAdminLogin: + useExistingSecret: + # -- Name of existing secret containing DB_USER_ADMIN and DB_ADMIN_PASSWORD keys + name: "" + # -- Admin username (ignored if useExistingSecret.name is set) + username: "postgres" + # -- Admin password (ignored if useExistingSecret.name is set) + password: "lerian" + # -- Credentials for go-boilerplate-ddd role created by the job + boilerplateCredentials: + useExistingSecret: + # -- Name of existing secret containing DB_PASSWORD_BOILERPLATE key + name: "" + # -- Password for go-boilerplate-ddd role (ignored if useExistingSecret.name is set) + password: "lerian" + +boilerplate: + # -- Service name + name: go-boilerplate-ddd + + # -- Service description + description: "Lerian reference service template following DDD and Hexagonal Architecture" + + # -- Enable or disable the service + enabled: true + + # -- Number of replicas + replicaCount: 1 + + # -- Number of old ReplicaSets to retain for deployment rollback + revisionHistoryLimit: 10 + + image: + # -- Repository for the container image + repository: ghcr.io/lerianstudio/go-boilerplate-ddd + # -- Image pull policy + pullPolicy: IfNotPresent + # -- Image tag used for deployment + tag: "latest" + + # -- Secrets for pulling images from a private registry + imagePullSecrets: + - name: ghcr-credential + + # -- Overrides the default generated name by Helm + nameOverride: "" + # -- Overrides the full name generated by Helm + fullnameOverride: "" + + # -- Pod annotations for additional metadata + podAnnotations: {} + + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: + # -- Defines the group ID for the user running the process inside the container (distroless nonroot) + runAsGroup: 65532 + # -- Defines the user ID for the process running inside the container (distroless nonroot) + runAsUser: 65532 + # -- Ensures the process does not run as root + runAsNonRoot: true + capabilities: + drop: + - ALL + # -- Defines the root filesystem as read-only + readOnlyRootFilesystem: true + + # -- PodDisruptionBudget configuration + pdb: + # -- Enable or disable PodDisruptionBudget + enabled: true + # -- Minimum number of available pods + minAvailable: 1 + # -- Maximum number of unavailable pods + maxUnavailable: 1 + # -- Annotations for the PodDisruptionBudget + annotations: {} + + # -- Deployment update strategy + deploymentUpdate: + # -- Type of deployment strategy + type: RollingUpdate + # -- Maximum number of pods that can be created over the desired number of pods + maxSurge: 1 + # -- Maximum number of pods that can be unavailable during the update + maxUnavailable: 1 + + service: + # -- Kubernetes service type + type: ClusterIP + # -- Port for the HTTP API + port: 8080 + annotations: {} + + ingress: + # -- Enable or disable ingress + enabled: true + # -- Ingress class name + className: "nginx" + # -- Additional ingress annotations + annotations: {} + hosts: + - host: "" + paths: + - path: / + pathType: Prefix + # -- TLS configuration for ingress + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + resources: + # -- CPU and memory limits for pods + limits: + cpu: 200m + memory: 256Mi + # -- Minimum CPU and memory requests + requests: + cpu: 50m + memory: 64Mi + + autoscaling: + # -- Enable or disable horizontal pod autoscaling + enabled: false + # -- Minimum number of replicas + minReplicas: 1 + # -- Maximum number of replicas + maxReplicas: 5 + # -- Target CPU utilization percentage for autoscaling + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + + # -- Node selector for scheduling pods on specific nodes + nodeSelector: {} + + # -- Tolerations for scheduling on tainted nodes + tolerations: {} + + # -- Affinity rules for pod scheduling + affinity: {} + + # -- ConfigMap for environment variables and configurations + # @default -- templates/configmap.yaml + configmap: + # Application Settings + ENV_NAME: "production" + LOG_LEVEL: "info" + SERVER_ADDRESS: ":8080" + + # CORS Configuration + CORS_ALLOWED_ORIGINS: "*" + + # Auth Plugin (Access Manager) + PLUGIN_AUTH_ENABLED: "false" + PLUGIN_AUTH_HOST: "http://plugin-access-manager-auth.midaz-plugins.svc.cluster.local.:4000" + + # PostgreSQL Database + POSTGRES_HOST: "go-boilerplate-ddd-postgresql.go-boilerplate-ddd.svc.cluster.local." + POSTGRES_PORT: "5432" + POSTGRES_USER: "go-boilerplate-ddd" + POSTGRES_NAME: "go-boilerplate-ddd" + POSTGRES_SSLMODE: "disable" + MIGRATIONS_PATH: "migrations" + + # Redis + REDIS_HOST: "go-boilerplate-ddd-redis.go-boilerplate-ddd.svc.cluster.local.:6379" + REDIS_DB: "0" + REDIS_TLS: "false" + + # OpenTelemetry + # -- Enable telemetry collection (when true, OTEL_EXPORTER_OTLP_ENDPOINT is overridden with HOST_IP:4317) + ENABLE_TELEMETRY: "false" + # -- OTEL resource service name for traces/metrics + OTEL_RESOURCE_SERVICE_NAME: "go-boilerplate-ddd" + # -- OTEL library name for instrumentation + OTEL_LIBRARY_NAME: "github.com/LerianStudio/go-boilerplate-ddd" + # -- OTEL exporter endpoint (empty when disabled; overridden by HOST_IP:4317 when ENABLE_TELEMETRY=true) + OTEL_EXPORTER_OTLP_ENDPOINT: "" + # -- Deployment environment for OTEL resource attributes + OTEL_RESOURCE_DEPLOYMENT_ENVIRONMENT: "production" + + # Rate Limiting + RATE_LIMIT_ENABLED: "true" + RATE_LIMIT_MAX: "500" + RATE_LIMIT_WINDOW_SEC: "60" + + # Swagger Documentation + SWAGGER_ENABLED: "true" + SWAGGER_TITLE: "Go Boilerplate DDD" + + # Multi-tenant (disabled by default) + MULTI_TENANT_ENABLED: "false" + + # -- Secrets for storing sensitive data + # @default -- templates/secrets.yaml + secrets: + # -- PostgreSQL password + POSTGRES_PASSWORD: "lerian" + # -- Redis password + REDIS_PASSWORD: "" + + # -- Existing secrets name + useExistingSecret: false + existingSecretName: "" + + # -- Extra environment variables + extraEnvVars: [] + + serviceAccount: + # -- Specifies whether a ServiceAccount should be created + create: true + # -- Annotations for the ServiceAccount + annotations: {} + # -- Name of the service account + # @default -- `boilerplate.fullname` + name: "" From c0eae5b8ca6de835c4921cd579660c033a26b547 Mon Sep 17 00:00:00 2001 From: prymax10 Date: Tue, 28 Apr 2026 10:10:41 -0300 Subject: [PATCH 2/4] fix(go-boilerplate-ddd): address CodeRabbit review findings - Fix SQL injection in bootstrap-postgres: use psql -v variable binding instead of direct string interpolation for DB_PASSWORD_BOILERPLATE - Add secure defaults to values.yaml: podSecurityContext with fsGroup, seccompProfile RuntimeDefault and securityContext with allowPrivilegeEscalation: false - Fix HPA template: wrap metrics block in conditional to avoid invalid manifest when no utilization targets are configured - Fix PDB template: add mutual exclusion fail guard for minAvailable and maxUnavailable - Fix values.yaml: remove duplicate PDB field (maxUnavailable removed, minAvailable kept as the active default) --- .../templates/bootstrap-postgres.yaml | 4 ++- charts/go-boilerplate-ddd/templates/hpa.yaml | 2 ++ charts/go-boilerplate-ddd/templates/pdb.yaml | 6 +++++ charts/go-boilerplate-ddd/values.yaml | 26 ++++++++++++------- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml b/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml index f097faa6..7b0dae1b 100644 --- a/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml +++ b/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml @@ -104,7 +104,9 @@ spec: echo "Role 'go-boilerplate-ddd' already exists. Skipping creation." else echo "Creating role 'go-boilerplate-ddd'..." - PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" -c "CREATE ROLE \"go-boilerplate-ddd\" LOGIN PASSWORD '$DB_PASSWORD_BOILERPLATE'" + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" \ + -v pwd="$DB_PASSWORD_BOILERPLATE" \ + -c "CREATE ROLE \"go-boilerplate-ddd\" LOGIN PASSWORD :'pwd'" fi # Create database if not exists diff --git a/charts/go-boilerplate-ddd/templates/hpa.yaml b/charts/go-boilerplate-ddd/templates/hpa.yaml index 97685d67..81a34eca 100644 --- a/charts/go-boilerplate-ddd/templates/hpa.yaml +++ b/charts/go-boilerplate-ddd/templates/hpa.yaml @@ -13,6 +13,7 @@ spec: name: {{ include "boilerplate.fullname" . }} minReplicas: {{ .Values.boilerplate.autoscaling.minReplicas }} maxReplicas: {{ .Values.boilerplate.autoscaling.maxReplicas }} + {{- if or .Values.boilerplate.autoscaling.targetCPUUtilizationPercentage .Values.boilerplate.autoscaling.targetMemoryUtilizationPercentage }} metrics: {{- if .Values.boilerplate.autoscaling.targetCPUUtilizationPercentage }} - type: Resource @@ -30,4 +31,5 @@ spec: type: Utilization averageUtilization: {{ .Values.boilerplate.autoscaling.targetMemoryUtilizationPercentage }} {{- end }} + {{- end }} {{- end }} diff --git a/charts/go-boilerplate-ddd/templates/pdb.yaml b/charts/go-boilerplate-ddd/templates/pdb.yaml index a01458de..264b6043 100644 --- a/charts/go-boilerplate-ddd/templates/pdb.yaml +++ b/charts/go-boilerplate-ddd/templates/pdb.yaml @@ -1,4 +1,10 @@ {{- if and .Values.boilerplate.enabled .Values.boilerplate.pdb.enabled }} +{{- if and .Values.boilerplate.pdb.minAvailable .Values.boilerplate.pdb.maxUnavailable }} + {{- fail "pdb: set either minAvailable or maxUnavailable, not both" }} +{{- end }} +{{- if and (not .Values.boilerplate.pdb.minAvailable) (not .Values.boilerplate.pdb.maxUnavailable) }} + {{- fail "pdb: at least one of minAvailable or maxUnavailable must be set" }} +{{- end }} apiVersion: policy/v1 kind: PodDisruptionBudget metadata: diff --git a/charts/go-boilerplate-ddd/values.yaml b/charts/go-boilerplate-ddd/values.yaml index 563d22ab..45cc753b 100644 --- a/charts/go-boilerplate-ddd/values.yaml +++ b/charts/go-boilerplate-ddd/values.yaml @@ -69,21 +69,27 @@ boilerplate: # -- Pod annotations for additional metadata podAnnotations: {} - podSecurityContext: {} - # fsGroup: 2000 + podSecurityContext: + runAsNonRoot: true + runAsUser: 65532 + runAsGroup: 65532 + fsGroup: 65532 + seccompProfile: + type: RuntimeDefault securityContext: - # -- Defines the group ID for the user running the process inside the container (distroless nonroot) - runAsGroup: 65532 - # -- Defines the user ID for the process running inside the container (distroless nonroot) - runAsUser: 65532 + allowPrivilegeEscalation: false + # -- Defines the root filesystem as read-only + readOnlyRootFilesystem: true # -- Ensures the process does not run as root runAsNonRoot: true + # -- Defines the user ID for the process running inside the container (distroless nonroot) + runAsUser: 65532 + # -- Defines the group ID for the user running the process inside the container (distroless nonroot) + runAsGroup: 65532 capabilities: drop: - ALL - # -- Defines the root filesystem as read-only - readOnlyRootFilesystem: true # -- PodDisruptionBudget configuration pdb: @@ -91,8 +97,8 @@ boilerplate: enabled: true # -- Minimum number of available pods minAvailable: 1 - # -- Maximum number of unavailable pods - maxUnavailable: 1 + # -- Maximum number of unavailable pods (set this instead of minAvailable if preferred) + # maxUnavailable: 1 # -- Annotations for the PodDisruptionBudget annotations: {} From 08f4215bed1917f2946040e5ed658bf6e63c7193 Mon Sep 17 00:00:00 2001 From: prymax10 Date: Tue, 28 Apr 2026 10:25:25 -0300 Subject: [PATCH 3/4] refactor(go-boilerplate-ddd): rewrite chart using underwriter+plugin-fees as canonical references - Rebase entire chart on underwriter (single-component, prod-proven pattern) - PDB uses with/else priority pattern (maxUnavailable > minAvailable fallback) - podSecurityContext: {} intentionally empty per Lerian standard - bootstrap-postgres uses direct password interpolation per Lerian standard - Add multi-tenant conditional block from plugin-fees pattern: MULTI_TENANT_ENABLED=true gates required vars with helm required() validation - Readiness probe: /ready (unique to boilerplate, liveness stays /health) - Port: 8080, image: ghcr.io/lerianstudio/go-boilerplate-ddd --- charts/go-boilerplate-ddd/Chart.yaml | 10 +- .../go-boilerplate-ddd/templates/_helpers.tpl | 6 +- .../templates/bootstrap-postgres.yaml | 4 +- .../templates/configmap.yaml | 69 +++++++++++-- charts/go-boilerplate-ddd/templates/hpa.yaml | 2 - charts/go-boilerplate-ddd/templates/pdb.yaml | 15 +-- .../go-boilerplate-ddd/values-template.yaml | 23 ++--- charts/go-boilerplate-ddd/values.yaml | 99 +++++++++++-------- 8 files changed, 133 insertions(+), 95 deletions(-) diff --git a/charts/go-boilerplate-ddd/Chart.yaml b/charts/go-boilerplate-ddd/Chart.yaml index 928884ba..0565fe6f 100644 --- a/charts/go-boilerplate-ddd/Chart.yaml +++ b/charts/go-boilerplate-ddd/Chart.yaml @@ -1,23 +1,16 @@ apiVersion: v2 name: go-boilerplate-ddd-helm description: A Helm chart for Go Boilerplate DDD - Lerian reference service template - type: application - -home: https://github.com/LerianStudio/helm - +home: https://github.com/LerianStudio/go-boilerplate-ddd sources: - https://github.com/LerianStudio/helm/tree/main/charts/go-boilerplate-ddd - https://github.com/LerianStudio/go-boilerplate-ddd - maintainers: - name: "Lerian Studio" email: "support@lerian.studio" - version: 1.0.0 - appVersion: "1.0.0" - keywords: - boilerplate - reference @@ -25,5 +18,4 @@ keywords: - lerian - ddd - hexagonal - icon: https://avatars.githubusercontent.com/u/148895005?s=200&v=4 diff --git a/charts/go-boilerplate-ddd/templates/_helpers.tpl b/charts/go-boilerplate-ddd/templates/_helpers.tpl index 46985880..b3db70b1 100644 --- a/charts/go-boilerplate-ddd/templates/_helpers.tpl +++ b/charts/go-boilerplate-ddd/templates/_helpers.tpl @@ -6,7 +6,7 @@ Expand the name of the chart. {{- end }} {{/* -Create a default fully qualified app name for go-boilerplate-ddd. +Create a default fully qualified app name for boilerplate. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). */}} {{- define "boilerplate.fullname" -}} @@ -21,14 +21,14 @@ Create chart name and version as used by the chart label. {{- end }} {{/* -Create go-boilerplate-ddd app version +Create boilerplate app version */}} {{- define "boilerplate.defaultTag" -}} {{- default .Chart.AppVersion .Values.boilerplate.image.tag }} {{- end -}} {{/* -Return valid go-boilerplate-ddd version label +Return valid boilerplate version label */}} {{- define "boilerplate.versionLabelValue" -}} {{ regexReplaceAll "[^-A-Za-z0-9_.]" (include "boilerplate.defaultTag" .) "-" | trunc 63 | trimAll "-" | trimAll "_" | trimAll "." | quote }} diff --git a/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml b/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml index 7b0dae1b..f097faa6 100644 --- a/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml +++ b/charts/go-boilerplate-ddd/templates/bootstrap-postgres.yaml @@ -104,9 +104,7 @@ spec: echo "Role 'go-boilerplate-ddd' already exists. Skipping creation." else echo "Creating role 'go-boilerplate-ddd'..." - PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" \ - -v pwd="$DB_PASSWORD_BOILERPLATE" \ - -c "CREATE ROLE \"go-boilerplate-ddd\" LOGIN PASSWORD :'pwd'" + PGPASSWORD="$DB_ADMIN_PASSWORD" psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER_ADMIN" -d "$DB_DATABASE" -c "CREATE ROLE \"go-boilerplate-ddd\" LOGIN PASSWORD '$DB_PASSWORD_BOILERPLATE'" fi # Create database if not exists diff --git a/charts/go-boilerplate-ddd/templates/configmap.yaml b/charts/go-boilerplate-ddd/templates/configmap.yaml index 94b0f37d..26fcb4f5 100644 --- a/charts/go-boilerplate-ddd/templates/configmap.yaml +++ b/charts/go-boilerplate-ddd/templates/configmap.yaml @@ -7,35 +7,60 @@ metadata: labels: {{- include "boilerplate.labels" (dict "context" . "component" .Values.boilerplate.name "name" .Values.boilerplate.name) | nindent 4 }} data: - # Application Settings + # Application ENV_NAME: {{ .Values.boilerplate.configmap.ENV_NAME | default "production" | quote }} LOG_LEVEL: {{ .Values.boilerplate.configmap.LOG_LEVEL | default "info" | quote }} SERVER_ADDRESS: {{ .Values.boilerplate.configmap.SERVER_ADDRESS | default ":8080" | quote }} + HTTP_BODY_LIMIT_BYTES: {{ .Values.boilerplate.configmap.HTTP_BODY_LIMIT_BYTES | default "104857600" | quote }} - # CORS + # CORS Configuration CORS_ALLOWED_ORIGINS: {{ .Values.boilerplate.configmap.CORS_ALLOWED_ORIGINS | default "*" | quote }} + CORS_ALLOWED_METHODS: {{ .Values.boilerplate.configmap.CORS_ALLOWED_METHODS | default "GET,POST,PUT,PATCH,DELETE,OPTIONS" | quote }} + CORS_ALLOWED_HEADERS: {{ .Values.boilerplate.configmap.CORS_ALLOWED_HEADERS | default "Origin,Content-Type,Accept,Authorization,X-Request-ID" | quote }} - # Auth Plugin (Access Manager) - PLUGIN_AUTH_ENABLED: {{ .Values.boilerplate.configmap.PLUGIN_AUTH_ENABLED | default "false" | quote }} - PLUGIN_AUTH_HOST: {{ .Values.boilerplate.configmap.PLUGIN_AUTH_HOST | default "http://plugin-auth:4000" | quote }} + # TLS Configuration + TLS_TERMINATED_UPSTREAM: {{ .Values.boilerplate.configmap.TLS_TERMINATED_UPSTREAM | default "true" | quote }} + + # Tenancy + DEFAULT_TENANT_ID: {{ .Values.boilerplate.configmap.DEFAULT_TENANT_ID | default "11111111-1111-1111-1111-111111111111" | quote }} # PostgreSQL Database - POSTGRES_HOST: {{ .Values.boilerplate.configmap.POSTGRES_HOST | default "go-boilerplate-ddd-postgresql" | quote }} + POSTGRES_HOST: {{ .Values.boilerplate.configmap.POSTGRES_HOST | default "localhost" | quote }} POSTGRES_PORT: {{ .Values.boilerplate.configmap.POSTGRES_PORT | default "5432" | quote }} POSTGRES_USER: {{ .Values.boilerplate.configmap.POSTGRES_USER | default "go-boilerplate-ddd" | quote }} POSTGRES_NAME: {{ .Values.boilerplate.configmap.POSTGRES_NAME | default "go-boilerplate-ddd" | quote }} POSTGRES_SSLMODE: {{ .Values.boilerplate.configmap.POSTGRES_SSLMODE | default "disable" | quote }} MIGRATIONS_PATH: {{ .Values.boilerplate.configmap.MIGRATIONS_PATH | default "migrations" | quote }} + # PostgreSQL Connection Pool + POSTGRES_MAX_OPEN_CONNS: {{ .Values.boilerplate.configmap.POSTGRES_MAX_OPEN_CONNS | default "25" | quote }} + POSTGRES_MAX_IDLE_CONNS: {{ .Values.boilerplate.configmap.POSTGRES_MAX_IDLE_CONNS | default "5" | quote }} + POSTGRES_CONN_MAX_LIFETIME_MINS: {{ .Values.boilerplate.configmap.POSTGRES_CONN_MAX_LIFETIME_MINS | default "30" | quote }} + POSTGRES_CONN_MAX_IDLE_TIME_MINS: {{ .Values.boilerplate.configmap.POSTGRES_CONN_MAX_IDLE_TIME_MINS | default "5" | quote }} + POSTGRES_CONNECT_TIMEOUT_SEC: {{ .Values.boilerplate.configmap.POSTGRES_CONNECT_TIMEOUT_SEC | default "10" | quote }} + # Redis - REDIS_HOST: {{ .Values.boilerplate.configmap.REDIS_HOST | default "go-boilerplate-ddd-redis:6379" | quote }} + REDIS_HOST: {{ .Values.boilerplate.configmap.REDIS_HOST | default "localhost:6379" | quote }} REDIS_DB: {{ .Values.boilerplate.configmap.REDIS_DB | default "0" | quote }} - REDIS_TLS: {{ .Values.boilerplate.configmap.REDIS_TLS | default "false" | quote }} + REDIS_PROTOCOL: {{ .Values.boilerplate.configmap.REDIS_PROTOCOL | default "3" | quote }} + REDIS_POOL_SIZE: {{ .Values.boilerplate.configmap.REDIS_POOL_SIZE | default "10" | quote }} + REDIS_MIN_IDLE_CONNS: {{ .Values.boilerplate.configmap.REDIS_MIN_IDLE_CONNS | default "2" | quote }} + REDIS_READ_TIMEOUT_MS: {{ .Values.boilerplate.configmap.REDIS_READ_TIMEOUT_MS | default "3000" | quote }} + REDIS_WRITE_TIMEOUT_MS: {{ .Values.boilerplate.configmap.REDIS_WRITE_TIMEOUT_MS | default "3000" | quote }} + REDIS_DIAL_TIMEOUT_MS: {{ .Values.boilerplate.configmap.REDIS_DIAL_TIMEOUT_MS | default "5000" | quote }} + + # Authentication + PLUGIN_AUTH_ENABLED: {{ .Values.boilerplate.configmap.PLUGIN_AUTH_ENABLED | default "false" | quote }} + PLUGIN_AUTH_HOST: {{ .Values.boilerplate.configmap.PLUGIN_AUTH_HOST | default "http://plugin-access-manager-auth:4000" | quote }} + + # Infrastructure Boot Timeout + INFRA_CONNECT_TIMEOUT_SEC: {{ .Values.boilerplate.configmap.INFRA_CONNECT_TIMEOUT_SEC | default "30" | quote }} # OpenTelemetry (Observability) ENABLE_TELEMETRY: {{ .Values.boilerplate.configmap.ENABLE_TELEMETRY | default "false" | quote }} - OTEL_RESOURCE_SERVICE_NAME: {{ .Values.boilerplate.configmap.OTEL_RESOURCE_SERVICE_NAME | default "go-boilerplate-ddd" | quote }} OTEL_LIBRARY_NAME: {{ .Values.boilerplate.configmap.OTEL_LIBRARY_NAME | default "github.com/LerianStudio/go-boilerplate-ddd" | quote }} + OTEL_RESOURCE_SERVICE_NAME: {{ .Values.boilerplate.configmap.OTEL_RESOURCE_SERVICE_NAME | default "go-boilerplate-ddd" | quote }} + OTEL_RESOURCE_SERVICE_VERSION: {{ .Values.boilerplate.image.tag | default .Chart.AppVersion | quote }} OTEL_EXPORTER_OTLP_ENDPOINT: {{ .Values.boilerplate.configmap.OTEL_EXPORTER_OTLP_ENDPOINT | default "" | quote }} OTEL_RESOURCE_DEPLOYMENT_ENVIRONMENT: {{ .Values.boilerplate.configmap.OTEL_RESOURCE_DEPLOYMENT_ENVIRONMENT | default "production" | quote }} @@ -48,8 +73,32 @@ data: SWAGGER_ENABLED: {{ .Values.boilerplate.configmap.SWAGGER_ENABLED | default "true" | quote }} SWAGGER_TITLE: {{ .Values.boilerplate.configmap.SWAGGER_TITLE | default "Go Boilerplate DDD" | quote }} - # Multi-tenant (disabled by default) + # Observability & Metrics + DB_METRICS_INTERVAL_SEC: {{ .Values.boilerplate.configmap.DB_METRICS_INTERVAL_SEC | default "15" | quote }} + + # Idempotency + IDEMPOTENCY_RETRY_WINDOW_SEC: {{ .Values.boilerplate.configmap.IDEMPOTENCY_RETRY_WINDOW_SEC | default "300" | quote }} + + # Auto-generated version + VERSION: {{ .Values.boilerplate.image.tag | default .Chart.AppVersion | quote }} + + # Multi-Tenant MULTI_TENANT_ENABLED: {{ .Values.boilerplate.configmap.MULTI_TENANT_ENABLED | default "false" | quote }} + {{- if eq (.Values.boilerplate.configmap.MULTI_TENANT_ENABLED | default "false" | toString) "true" }} + MULTI_TENANT_URL: {{ required "boilerplate.configmap.MULTI_TENANT_URL is required when MULTI_TENANT_ENABLED=true" .Values.boilerplate.configmap.MULTI_TENANT_URL | quote }} + MULTI_TENANT_REDIS_HOST: {{ required "boilerplate.configmap.MULTI_TENANT_REDIS_HOST is required when MULTI_TENANT_ENABLED=true" .Values.boilerplate.configmap.MULTI_TENANT_REDIS_HOST | quote }} + MULTI_TENANT_REDIS_PORT: {{ .Values.boilerplate.configmap.MULTI_TENANT_REDIS_PORT | default "6379" | quote }} + MULTI_TENANT_REDIS_TLS: {{ .Values.boilerplate.configmap.MULTI_TENANT_REDIS_TLS | default "false" | quote }} + MULTI_TENANT_REDIS_PASSWORD: {{ .Values.boilerplate.configmap.MULTI_TENANT_REDIS_PASSWORD | default "" | quote }} + MULTI_TENANT_MAX_TENANT_POOLS: {{ .Values.boilerplate.configmap.MULTI_TENANT_MAX_TENANT_POOLS | default "100" | quote }} + MULTI_TENANT_IDLE_TIMEOUT_SEC: {{ .Values.boilerplate.configmap.MULTI_TENANT_IDLE_TIMEOUT_SEC | default "300" | quote }} + MULTI_TENANT_TIMEOUT: {{ .Values.boilerplate.configmap.MULTI_TENANT_TIMEOUT | default "30" | quote }} + MULTI_TENANT_CIRCUIT_BREAKER_THRESHOLD: {{ .Values.boilerplate.configmap.MULTI_TENANT_CIRCUIT_BREAKER_THRESHOLD | default "5" | quote }} + MULTI_TENANT_CIRCUIT_BREAKER_TIMEOUT_SEC: {{ .Values.boilerplate.configmap.MULTI_TENANT_CIRCUIT_BREAKER_TIMEOUT_SEC | default "30" | quote }} + MULTI_TENANT_CACHE_TTL_SEC: {{ .Values.boilerplate.configmap.MULTI_TENANT_CACHE_TTL_SEC | default "120" | quote }} + MULTI_TENANT_CONNECTIONS_CHECK_INTERVAL_SEC: {{ .Values.boilerplate.configmap.MULTI_TENANT_CONNECTIONS_CHECK_INTERVAL_SEC | default "30" | quote }} + MULTI_TENANT_SERVICE_API_KEY: {{ required "boilerplate.configmap.MULTI_TENANT_SERVICE_API_KEY is required when MULTI_TENANT_ENABLED=true" .Values.boilerplate.configmap.MULTI_TENANT_SERVICE_API_KEY | quote }} + {{- end }} # Extra Env Vars {{- with .Values.boilerplate.extraEnvVars }} diff --git a/charts/go-boilerplate-ddd/templates/hpa.yaml b/charts/go-boilerplate-ddd/templates/hpa.yaml index 81a34eca..97685d67 100644 --- a/charts/go-boilerplate-ddd/templates/hpa.yaml +++ b/charts/go-boilerplate-ddd/templates/hpa.yaml @@ -13,7 +13,6 @@ spec: name: {{ include "boilerplate.fullname" . }} minReplicas: {{ .Values.boilerplate.autoscaling.minReplicas }} maxReplicas: {{ .Values.boilerplate.autoscaling.maxReplicas }} - {{- if or .Values.boilerplate.autoscaling.targetCPUUtilizationPercentage .Values.boilerplate.autoscaling.targetMemoryUtilizationPercentage }} metrics: {{- if .Values.boilerplate.autoscaling.targetCPUUtilizationPercentage }} - type: Resource @@ -31,5 +30,4 @@ spec: type: Utilization averageUtilization: {{ .Values.boilerplate.autoscaling.targetMemoryUtilizationPercentage }} {{- end }} - {{- end }} {{- end }} diff --git a/charts/go-boilerplate-ddd/templates/pdb.yaml b/charts/go-boilerplate-ddd/templates/pdb.yaml index 264b6043..ba651437 100644 --- a/charts/go-boilerplate-ddd/templates/pdb.yaml +++ b/charts/go-boilerplate-ddd/templates/pdb.yaml @@ -1,10 +1,4 @@ {{- if and .Values.boilerplate.enabled .Values.boilerplate.pdb.enabled }} -{{- if and .Values.boilerplate.pdb.minAvailable .Values.boilerplate.pdb.maxUnavailable }} - {{- fail "pdb: set either minAvailable or maxUnavailable, not both" }} -{{- end }} -{{- if and (not .Values.boilerplate.pdb.minAvailable) (not .Values.boilerplate.pdb.maxUnavailable) }} - {{- fail "pdb: at least one of minAvailable or maxUnavailable must be set" }} -{{- end }} apiVersion: policy/v1 kind: PodDisruptionBudget metadata: @@ -17,11 +11,10 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} spec: - {{- if .Values.boilerplate.pdb.minAvailable }} - minAvailable: {{ .Values.boilerplate.pdb.minAvailable }} - {{- end }} - {{- if .Values.boilerplate.pdb.maxUnavailable }} - maxUnavailable: {{ .Values.boilerplate.pdb.maxUnavailable }} + {{- with .Values.boilerplate.pdb.maxUnavailable }} + maxUnavailable: {{ . }} + {{- else }} + minAvailable: {{ .Values.boilerplate.pdb.minAvailable | default 1 }} {{- end }} selector: matchLabels: diff --git a/charts/go-boilerplate-ddd/values-template.yaml b/charts/go-boilerplate-ddd/values-template.yaml index 79ba1303..76eafa71 100644 --- a/charts/go-boilerplate-ddd/values-template.yaml +++ b/charts/go-boilerplate-ddd/values-template.yaml @@ -51,7 +51,7 @@ boilerplate: memory: 64Mi autoscaling: - enabled: false + enabled: true minReplicas: 1 maxReplicas: 5 targetCPUUtilizationPercentage: 80 @@ -59,35 +59,24 @@ boilerplate: configmap: ENV_NAME: "" - LOG_LEVEL: "info" SERVER_ADDRESS: ":8080" - CORS_ALLOWED_ORIGINS: "" - PLUGIN_AUTH_ENABLED: "false" - PLUGIN_AUTH_HOST: "" + LOG_LEVEL: "info" POSTGRES_HOST: "" POSTGRES_PORT: "5432" POSTGRES_USER: "go-boilerplate-ddd" POSTGRES_NAME: "go-boilerplate-ddd" POSTGRES_SSLMODE: "disable" - MIGRATIONS_PATH: "migrations" REDIS_HOST: "" REDIS_DB: "0" - REDIS_TLS: "false" + PLUGIN_AUTH_ENABLED: "false" + PLUGIN_AUTH_HOST: "" ENABLE_TELEMETRY: "false" - OTEL_RESOURCE_SERVICE_NAME: "go-boilerplate-ddd" - OTEL_LIBRARY_NAME: "github.com/LerianStudio/go-boilerplate-ddd" OTEL_EXPORTER_OTLP_ENDPOINT: "" - OTEL_RESOURCE_DEPLOYMENT_ENVIRONMENT: "" - RATE_LIMIT_ENABLED: "true" - RATE_LIMIT_MAX: "500" - RATE_LIMIT_WINDOW_SEC: "60" - SWAGGER_ENABLED: "true" - SWAGGER_TITLE: "Go Boilerplate DDD" MULTI_TENANT_ENABLED: "false" secrets: - POSTGRES_PASSWORD: "" - REDIS_PASSWORD: "" + POSTGRES_PASSWORD: "" + REDIS_PASSWORD: "" useExistingSecret: false existingSecretName: "" diff --git a/charts/go-boilerplate-ddd/values.yaml b/charts/go-boilerplate-ddd/values.yaml index 45cc753b..dc92bcce 100644 --- a/charts/go-boilerplate-ddd/values.yaml +++ b/charts/go-boilerplate-ddd/values.yaml @@ -1,4 +1,4 @@ -# Default values for go-boilerplate-ddd. +# Default values for go-boilerplate-ddd components. # This is a YAML-formatted file. # Declare variables to be passed into your templates. nameOverride: "go-boilerplate-ddd" @@ -38,19 +38,19 @@ boilerplate: name: go-boilerplate-ddd # -- Service description - description: "Lerian reference service template following DDD and Hexagonal Architecture" + description: "Lerian Go service reference template" - # -- Enable or disable the service + # -- Enable or disable the boilerplate service enabled: true - # -- Number of replicas + # -- Number of replicas for the boilerplate service replicaCount: 1 # -- Number of old ReplicaSets to retain for deployment rollback revisionHistoryLimit: 10 image: - # -- Repository for the container image + # -- Repository for the boilerplate service container image repository: ghcr.io/lerianstudio/go-boilerplate-ddd # -- Image pull policy pullPolicy: IfNotPresent @@ -61,35 +61,24 @@ boilerplate: imagePullSecrets: - name: ghcr-credential - # -- Overrides the default generated name by Helm - nameOverride: "" - # -- Overrides the full name generated by Helm - fullnameOverride: "" - # -- Pod annotations for additional metadata podAnnotations: {} - podSecurityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - fsGroup: 65532 - seccompProfile: - type: RuntimeDefault + podSecurityContext: {} + # fsGroup: 2000 securityContext: - allowPrivilegeEscalation: false - # -- Defines the root filesystem as read-only - readOnlyRootFilesystem: true + # -- Defines the group ID for the user running the process inside the container + runAsGroup: 65532 + # -- Defines the user ID for the process running inside the container + runAsUser: 65532 # -- Ensures the process does not run as root runAsNonRoot: true - # -- Defines the user ID for the process running inside the container (distroless nonroot) - runAsUser: 65532 - # -- Defines the group ID for the user running the process inside the container (distroless nonroot) - runAsGroup: 65532 capabilities: drop: - ALL + # -- Defines the root filesystem as read-only + readOnlyRootFilesystem: true # -- PodDisruptionBudget configuration pdb: @@ -97,8 +86,8 @@ boilerplate: enabled: true # -- Minimum number of available pods minAvailable: 1 - # -- Maximum number of unavailable pods (set this instead of minAvailable if preferred) - # maxUnavailable: 1 + # -- Maximum number of unavailable pods + maxUnavailable: 1 # -- Annotations for the PodDisruptionBudget annotations: {} @@ -126,7 +115,7 @@ boilerplate: # -- Additional ingress annotations annotations: {} hosts: - - host: "" + - host: "go-boilerplate-ddd.lerian.net" paths: - path: / pathType: Prefix @@ -148,7 +137,7 @@ boilerplate: autoscaling: # -- Enable or disable horizontal pod autoscaling - enabled: false + enabled: true # -- Minimum number of replicas minReplicas: 1 # -- Maximum number of replicas @@ -173,37 +162,61 @@ boilerplate: ENV_NAME: "production" LOG_LEVEL: "info" SERVER_ADDRESS: ":8080" + HTTP_BODY_LIMIT_BYTES: "104857600" # CORS Configuration CORS_ALLOWED_ORIGINS: "*" + CORS_ALLOWED_METHODS: "GET,POST,PUT,PATCH,DELETE,OPTIONS" + CORS_ALLOWED_HEADERS: "Origin,Content-Type,Accept,Authorization,X-Request-ID" - # Auth Plugin (Access Manager) - PLUGIN_AUTH_ENABLED: "false" - PLUGIN_AUTH_HOST: "http://plugin-access-manager-auth.midaz-plugins.svc.cluster.local.:4000" + # TLS Configuration + TLS_TERMINATED_UPSTREAM: "true" + + # Tenancy + DEFAULT_TENANT_ID: "11111111-1111-1111-1111-111111111111" # PostgreSQL Database - POSTGRES_HOST: "go-boilerplate-ddd-postgresql.go-boilerplate-ddd.svc.cluster.local." + POSTGRES_HOST: "postgres.firmino.lerian.net" POSTGRES_PORT: "5432" POSTGRES_USER: "go-boilerplate-ddd" POSTGRES_NAME: "go-boilerplate-ddd" POSTGRES_SSLMODE: "disable" MIGRATIONS_PATH: "migrations" - # Redis - REDIS_HOST: "go-boilerplate-ddd-redis.go-boilerplate-ddd.svc.cluster.local.:6379" + # PostgreSQL Connection Pool + POSTGRES_MAX_OPEN_CONNS: "25" + POSTGRES_MAX_IDLE_CONNS: "5" + POSTGRES_CONN_MAX_LIFETIME_MINS: "30" + POSTGRES_CONN_MAX_IDLE_TIME_MINS: "5" + POSTGRES_CONNECT_TIMEOUT_SEC: "10" + + # Redis / Valkey + REDIS_HOST: "valkey.firmino.lerian.net:6379" REDIS_DB: "0" - REDIS_TLS: "false" + REDIS_PROTOCOL: "3" + REDIS_POOL_SIZE: "10" + REDIS_MIN_IDLE_CONNS: "2" + REDIS_READ_TIMEOUT_MS: "3000" + REDIS_WRITE_TIMEOUT_MS: "3000" + REDIS_DIAL_TIMEOUT_MS: "5000" + + # Authentication + PLUGIN_AUTH_ENABLED: "false" + PLUGIN_AUTH_HOST: "http://plugin-access-manager-auth:4000" + + # Infrastructure Boot Timeout + INFRA_CONNECT_TIMEOUT_SEC: "30" # OpenTelemetry # -- Enable telemetry collection (when true, OTEL_EXPORTER_OTLP_ENDPOINT is overridden with HOST_IP:4317) ENABLE_TELEMETRY: "false" - # -- OTEL resource service name for traces/metrics - OTEL_RESOURCE_SERVICE_NAME: "go-boilerplate-ddd" # -- OTEL library name for instrumentation OTEL_LIBRARY_NAME: "github.com/LerianStudio/go-boilerplate-ddd" + # -- OTEL resource service name for traces/metrics + OTEL_RESOURCE_SERVICE_NAME: "go-boilerplate-ddd" # -- OTEL exporter endpoint (empty when disabled; overridden by HOST_IP:4317 when ENABLE_TELEMETRY=true) OTEL_EXPORTER_OTLP_ENDPOINT: "" - # -- Deployment environment for OTEL resource attributes + # -- OTEL deployment environment OTEL_RESOURCE_DEPLOYMENT_ENVIRONMENT: "production" # Rate Limiting @@ -215,7 +228,13 @@ boilerplate: SWAGGER_ENABLED: "true" SWAGGER_TITLE: "Go Boilerplate DDD" - # Multi-tenant (disabled by default) + # Observability & Metrics + DB_METRICS_INTERVAL_SEC: "15" + + # Idempotency + IDEMPOTENCY_RETRY_WINDOW_SEC: "300" + + # Multi-Tenant MULTI_TENANT_ENABLED: "false" # -- Secrets for storing sensitive data @@ -223,7 +242,7 @@ boilerplate: secrets: # -- PostgreSQL password POSTGRES_PASSWORD: "lerian" - # -- Redis password + # -- Redis password (empty if auth disabled) REDIS_PASSWORD: "" # -- Existing secrets name From 049f0391120dafa5b44b07a07d9b7766dd0f926e Mon Sep 17 00:00:00 2001 From: prymax10 Date: Tue, 28 Apr 2026 11:11:54 -0300 Subject: [PATCH 4/4] fix(go-boilerplate-ddd): move MULTI_TENANT_SERVICE_API_KEY from ConfigMap to Secret API keys must not be exposed in ConfigMaps. Moved to secrets map so it is rendered in the Secret via the existing stringData range. --- charts/go-boilerplate-ddd/templates/configmap.yaml | 1 - charts/go-boilerplate-ddd/values.yaml | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/charts/go-boilerplate-ddd/templates/configmap.yaml b/charts/go-boilerplate-ddd/templates/configmap.yaml index 26fcb4f5..1cf24f59 100644 --- a/charts/go-boilerplate-ddd/templates/configmap.yaml +++ b/charts/go-boilerplate-ddd/templates/configmap.yaml @@ -97,7 +97,6 @@ data: MULTI_TENANT_CIRCUIT_BREAKER_TIMEOUT_SEC: {{ .Values.boilerplate.configmap.MULTI_TENANT_CIRCUIT_BREAKER_TIMEOUT_SEC | default "30" | quote }} MULTI_TENANT_CACHE_TTL_SEC: {{ .Values.boilerplate.configmap.MULTI_TENANT_CACHE_TTL_SEC | default "120" | quote }} MULTI_TENANT_CONNECTIONS_CHECK_INTERVAL_SEC: {{ .Values.boilerplate.configmap.MULTI_TENANT_CONNECTIONS_CHECK_INTERVAL_SEC | default "30" | quote }} - MULTI_TENANT_SERVICE_API_KEY: {{ required "boilerplate.configmap.MULTI_TENANT_SERVICE_API_KEY is required when MULTI_TENANT_ENABLED=true" .Values.boilerplate.configmap.MULTI_TENANT_SERVICE_API_KEY | quote }} {{- end }} # Extra Env Vars diff --git a/charts/go-boilerplate-ddd/values.yaml b/charts/go-boilerplate-ddd/values.yaml index dc92bcce..dfaec74f 100644 --- a/charts/go-boilerplate-ddd/values.yaml +++ b/charts/go-boilerplate-ddd/values.yaml @@ -244,6 +244,8 @@ boilerplate: POSTGRES_PASSWORD: "lerian" # -- Redis password (empty if auth disabled) REDIS_PASSWORD: "" + # -- Multi-tenant service API key (required when MULTI_TENANT_ENABLED=true) + MULTI_TENANT_SERVICE_API_KEY: "" # -- Existing secrets name useExistingSecret: false