diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..b7a2035 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(helm template:*)" + ] + } +} diff --git a/helm/payouts/Chart.yaml b/helm/payouts/Chart.yaml index 9a3ba7c..f0e52bb 100644 --- a/helm/payouts/Chart.yaml +++ b/helm/payouts/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: payouts -description: A Helm chart for payouts service +description: Payouts service Helm chart type: application version: 0.1.0 -appVersion: "1.0.0" \ No newline at end of file +appVersion: "1.0.0" diff --git a/helm/payouts/README.md b/helm/payouts/README.md index f021077..652446d 100644 --- a/helm/payouts/README.md +++ b/helm/payouts/README.md @@ -1,130 +1,203 @@ -# Payouts Helm Chart +# payouts Helm Chart -This chart deploys the payouts service to a Kubernetes cluster. - -## Introduction - -This chart bootstraps a payouts deployment on a Kubernetes cluster using the Helm package manager. +Helm chart for deploying the **payouts** service to Kubernetes. ## Prerequisites -- Kubernetes 1.19+ -- Helm 3.0+ +- Kubernetes 1.21+ +- Helm 3.2+ ## Installing the Chart -To install the chart with the release name `my-release`: +```bash +helm install payouts ./helm +``` + +To install into a specific namespace: ```bash -helm install my-release helm/payouts +helm install payouts ./helm --namespace payouts --create-namespace ``` ## Uninstalling the Chart -To uninstall the chart: - ```bash -helm uninstall my-release +helm uninstall payouts ``` ## Configuration -The following table lists the configurable parameters of the payouts chart and their default values. +All parameters are set via `values.yaml` or `--set` flags. -### Global parameters +### Image | Parameter | Description | Default | |-----------|-------------|---------| -| `replicaCount` | Number of replicas | `1` | -| `image.repository` | Image repository | `payouts` | -| `image.tag` | Image tag | `latest` | +| `image.repository` | Container image repository | `payouts` | +| `image.tag` | Container image tag | `latest` | | `image.pullPolicy` | Image pull policy | `IfNotPresent` | -### Service parameters +### Service | Parameter | Description | Default | |-----------|-------------|---------| -| `service.type` | Service type | `ClusterIP` | +| `service.type` | Kubernetes service type | `ClusterIP` | | `service.port` | Service port | `8080` | -### Ingress parameters +### Ingress | Parameter | Description | Default | |-----------|-------------|---------| | `ingress.enabled` | Enable ingress | `false` | +| `ingress.className` | IngressClass name | `""` | | `ingress.annotations` | Ingress annotations | `{}` | -| `ingress.hosts` | Ingress hosts | `[{ host: payouts.local, paths: [] }]` | -| `ingress.tls` | Ingress TLS | `[]` | +| `ingress.host` | Ingress hostname | `payouts.example.com` | +| `ingress.path` | Ingress path | `/` | +| `ingress.pathType` | Ingress path type | `Prefix` | +| `ingress.tls` | TLS configuration | `[]` | -### ConfigMap parameters +### TLS (application-level) + +When `config.Server.Tls.Enabled` is `true` the chart mounts a TLS secret as +files into the pod at the paths defined by `config.Server.Tls.CertFile` and +`config.Server.Tls.KeyFile`. + +Two modes are supported: + +**Option A — use an existing secret** (type `kubernetes.io/tls`): + +```yaml +config: + Server: + Tls: + Enabled: true +tls: + existingSecret: "my-tls-secret" +``` + +**Option B — let the chart create the secret** (supply PEM values, do not commit to VCS): + +```yaml +config: + Server: + Tls: + Enabled: true +tls: + cert: | + -----BEGIN CERTIFICATE----- + ... + key: | + -----BEGIN PRIVATE KEY----- + ... +``` | Parameter | Description | Default | |-----------|-------------|---------| -| `config.Server.Port` | Server port | `:8080` | -| `config.Server.WriteTimeout` | Write timeout | `35s` | -| `config.Server.ReadTimeout` | Read timeout | `35s` | -| `config.Server.EnablePProfEndpoints` | Enable pprof endpoints | `false` | -| `config.Server.Tls.Enabled` | Enable TLS | `false` | -| `config.Server.Tls.CertFile` | TLS certificate file path | `""` | -| `config.Server.Tls.KeyFile` | TLS key file path | `""` | -| `config.Socket.MaxHttpBufferSize` | Max HTTP buffer size | `2097152` | -| `config.Socket.PingInterval` | Ping interval | `25s` | -| `config.Socket.PingTimeout` | Ping timeout | `20s` | -| `config.Socket.Debug` | Enable debug | `false` | -| `config.Metrics.Endpoint` | Metrics endpoint | `/metrics` | -| `config.Metrics.HistogramBuckets` | Histogram buckets | `0.001,0.002,0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10` | -| `config.Metrics.Http.HistogramEnabled` | Enable HTTP histogram | `true` | -| `config.Metrics.Http.Buckets` | HTTP buckets | `0.001,0.002,0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10` | +| `config.Server.Tls.Enabled` | Enable TLS on the HTTP server | `false` | +| `config.Server.Tls.CertFile` | Path to the certificate file inside the pod | `/etc/payouts/tls/tls.crt` | +| `config.Server.Tls.KeyFile` | Path to the private key file inside the pod | `/etc/payouts/tls/tls.key` | +| `tls.existingSecret` | Name of an existing `kubernetes.io/tls` secret to use | `""` | +| `tls.cert` | PEM-encoded certificate (used when `existingSecret` is empty) | `""` | +| `tls.key` | PEM-encoded private key (used when `existingSecret` is empty) | `""` | + +> When TLS is enabled, either `tls.existingSecret` or both `tls.cert` and `tls.key` must be provided — the chart will fail with a descriptive error otherwise. + +### Application Config + +Non-secret application parameters are stored in a ConfigMap and mounted as +`/etc/payouts/config.yaml` inside the pod. The path is passed to the application +via the `CONFIG_PATH` environment variable. + +All keys preserve the exact casing from `config/payouts.properties`. + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `config.Server.Port` | HTTP listen address | `:8080` | +| `config.Server.WriteTimeout` | HTTP write timeout | `35s` | +| `config.Server.ReadTimeout` | HTTP read timeout | `35s` | +| `config.Server.EnablePProfEndpoints` | Expose pprof endpoints | `false` | +| `config.Socket.MaxHttpBufferSize` | Max HTTP buffer size for socket | `2097152` | +| `config.Socket.PingInterval` | Socket ping interval | `25s` | +| `config.Socket.PingTimeout` | Socket ping timeout | `20s` | +| `config.Socket.Debug` | Enable socket debug logging | `false` | +| `config.Metrics.Endpoint` | Prometheus metrics endpoint | `/metrics` | +| `config.Metrics.HistogramBuckets` | Global histogram buckets | `0.001,...,10` | +| `config.Metrics.Http.HistogramEnabled` | Enable HTTP latency histogram | `true` | +| `config.Metrics.Http.Buckets` | HTTP histogram buckets | `0.001,...,10` | | `config.Log.Level` | Log level | `DEBUG` | | `config.Log.FilePath` | Log file path | `./logs/payouts.log` | -| `config.Log.TextOutput` | Enable text output | `false` | -| `config.Log.StdoutEnabled` | Enable stdout logging | `true` | -| `config.Log.FileEnabled` | Enable file logging | `false` | -| `config.Database.Type` | Database type | `""` | -| `config.Database.Connection` | Database connection string | `""` | -| `config.Database.LogLevel` | Database log level | `Info` | -| `config.Database.TraceRequests` | Trace database requests | `false` | -| `config.Cache.TTL` | Cache TTL | `24h` | -| `config.YooKassa.BaseUrl` | YooKassa base URL | `https://api.yookassa.ru/v3` | -| `config.YooKassa.Timeout` | YooKassa timeout | `2s` | -| `config.YooKassa.Retry.Enabled` | Enable YooKassa retry | `false` | -| `config.YooKassa.Retry.Count` | Retry count | `3` | +| `config.Log.TextOutput` | Use plain-text log format | `false` | +| `config.Log.StdoutEnabled` | Log to stdout | `true` | +| `config.Log.FileEnabled` | Log to file | `false` | +| `config.Database.Type` | Database type (`sqlite` or `postgres`) | `""` | +| `config.Database.LogLevel` | Database query log level | `Info` | +| `config.Database.TraceRequests` | Trace all DB requests | `false` | +| `config.Cache.TTL` | Session cache TTL | `24h` | +| `config.YooKassa.BaseUrl` | YooKassa API base URL | `https://api.yookassa.ru/v3` | +| `config.YooKassa.Timeout` | YooKassa request timeout | `2s` | +| `config.YooKassa.Retry.Enabled` | Enable request retries | `false` | +| `config.YooKassa.Retry.Count` | Retry count (incl. initial) | `3` | | `config.YooKassa.Retry.WaitTime` | Wait time between retries | `200ms` | -| `config.YooKassa.Retry.MaxWaitTime` | Max wait time | `5s` | -| `config.YooKassa.Test` | Test mode | `false` | -| `config.YooKassa.CheckAllowedCallbackAddress` | Check allowed callback address | `true` | -| `config.YooKassa.AllowedCallbackSubnets` | Allowed callback subnets | `185.71.76.0/27,185.71.77.0/27,77.75.153.0/25,77.75.156.11/32,77.75.156.35/32,77.75.154.128/25,2a02:5180::/32` | -| `config.YooKassa.ApiBaseKey` | YooKassa base API key | `""` | -| `config.YooKassa.ApiBaseSecret` | YooKassa base API secret | `""` | -| `config.YooKassa.ApiPaymentKey` | YooKassa payment API key | `""` | -| `config.YooKassa.ApiPaymentSecret` | YooKassa payment API secret | `""` | -| `config.YooKassa.CallbackProcessTimeout` | Callback process timeout | `1s` | +| `config.YooKassa.Retry.MaxWaitTime` | Max wait time (exponential backoff) | `5s` | +| `config.YooKassa.Test` | Enable YooKassa test mode | `false` | +| `config.YooKassa.CheckAllowedCallbackAddress` | Validate callback source IP | `true` | +| `config.YooKassa.AllowedCallbackSubnets` | Allowed callback CIDR list | YooKassa subnets | +| `config.YooKassa.CallbackProcessTimeout` | Timeout to process callback | `1s` | -### Secret parameters +### Secrets -| Parameter | Description | Default | -|-----------|-------------|---------| -| `secrets.yookassa.apiBaseKey` | YooKassa base API key | `""` | -| `secrets.yookassa.apiBaseSecret` | YooKassa base API secret | `""` | -| `secrets.yookassa.apiPaymentKey` | YooKassa payment API key | `""` | -| `secrets.yookassa.apiPaymentSecret` | YooKassa payment API secret | `""` | +Secret values are stored in a Kubernetes Secret and injected as environment +variables. Variable names are the uppercased property key with `.` replaced by `_`. -## TLS Configuration +> **These values are empty by default and must be supplied before deploying to production.** -To enable TLS, set `config.Server.Tls.Enabled` to `true` and provide either: +| Env variable | Original property | +|---|---| +| `DATABASE_CONNECTION` | `Database.Connection` | +| `YOOKASSA_APIBASEKEY` | `YooKassa.ApiBaseKey` | +| `YOOKASSA_APIBASESECRET` | `YooKassa.ApiBaseSecret` | +| `YOOKASSA_APIPAYMENTKEY` | `YooKassa.ApiPaymentKey` | +| `YOOKASSA_APIPAYMENTSECRET` | `YooKassa.ApiPaymentSecret` | -1. **Create new TLS secret**: Set `tls.createSecret` to `true` and provide certificate and key data -2. **Use existing TLS secret**: Set `tls.existingSecret` to the name of existing secret - -When TLS is enabled, the following environment variables will be set: -- `SERVER_TLS_CERTFILE` - path to certificate file -- `SERVER_TLS_KEYFILE` - path to key file - -## Example usage +Provide secrets at install/upgrade time: ```bash -helm install my-release helm/payouts \ - --set config.Server.Tls.Enabled=true \ - --set tls.createSecret=true \ - --set tls.certData="-----BEGIN CERTIFICATE-----\n..." \ - --set tls.keyData="-----BEGIN PRIVATE KEY-----\n..." \ No newline at end of file +helm install payouts ./helm \ + --set secrets.DATABASE_CONNECTION="host=127.0.0.1 user=app password=s3cr3t dbname=payouts port=5432 sslmode=disable" \ + --set secrets.YOOKASSA_APIBASEKEY="" \ + --set secrets.YOOKASSA_APIBASESECRET="" \ + --set secrets.YOOKASSA_APIPAYMENTKEY="" \ + --set secrets.YOOKASSA_APIPAYMENTSECRET="" +``` + +Or keep them in a separate values file that is **not committed to version control**: + +```bash +helm install payouts ./helm -f secrets.values.yaml +``` + +Example `secrets.values.yaml`: + +```yaml +secrets: + DATABASE_CONNECTION: "host=127.0.0.1 user=app password=s3cr3t dbname=payouts port=5432 sslmode=disable" + YOOKASSA_APIBASEKEY: "" + YOOKASSA_APIBASESECRET: "" + YOOKASSA_APIPAYMENTKEY: "" + YOOKASSA_APIPAYMENTSECRET: "" +``` + +### Ingress example + +```yaml +ingress: + enabled: true + className: nginx + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + host: payouts.example.com + tls: + - secretName: payouts-tls + hosts: + - payouts.example.com +``` diff --git a/helm/payouts/templates/NOTES.txt b/helm/payouts/templates/NOTES.txt index 1f304ea..009fe4f 100644 --- a/helm/payouts/templates/NOTES.txt +++ b/helm/payouts/templates/NOTES.txt @@ -1,39 +1,45 @@ -Payouts service has been installed successfully! - +1. Get the application URL: {{- if .Values.ingress.enabled }} -{{- range .Values.ingress.hosts }} -Visit the following URL to access the service: - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}{{ (index .paths 0).path }} -{{- end }} + http{{ if .Values.ingress.tls }}s{{ end }}://{{ .Values.ingress.host }}{{ .Values.ingress.path }} +{{- else if eq .Values.service.type "NodePort" }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "payouts.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "http://$NODE_IP:$NODE_PORT" +{{- else if eq .Values.service.type "LoadBalancer" }} + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "payouts.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo "http://$SERVICE_IP:{{ .Values.service.port }}" {{- else }} -Get the service URL by running these commands: - export SERVICE_PORT=$(kubectl get svc {{ include "payouts.fullname" . }} -o jsonpath='{.spec.ports[0].port}') - export SERVICE_HOST=$(kubectl get svc {{ include "payouts.fullname" . }} -o jsonpath='{.spec.clusterIP}') - echo "Service URL: http://$SERVICE_HOST:$SERVICE_PORT" + kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "payouts.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }} + echo "http://127.0.0.1:{{ .Values.service.port }}" {{- end }} +2. Configuration is mounted at $CONFIG_PATH inside the pod: + /etc/payouts/config.yaml (from ConfigMap {{ include "payouts.fullname" . }}) + {{- if .Values.config.Server.Tls.Enabled }} -TLS is enabled for the service. -{{- if .Values.tls.createSecret }} -A new TLS secret "{{ include "payouts.fullname" . }}-tls" has been created. -{{- else if .Values.tls.existingSecret }} -Using existing TLS secret "{{ .Values.tls.existingSecret }}". -{{- end }} +3. TLS is ENABLED. Certificate and key are mounted from Secret {{ include "payouts.tlsSecretName" . }}: + {{ .Values.config.Server.Tls.CertFile }} + {{ .Values.config.Server.Tls.KeyFile }} +{{- if not .Values.tls.existingSecret }} + The chart created the TLS secret. To rotate the certificate, update tls.cert / tls.key and run helm upgrade. +{{- else }} + Using existing secret: {{ .Values.tls.existingSecret }} {{- end }} -{{- if .Values.secrets.yookassa.apiBaseKey }} -YooKassa API base key is configured. +4. Secret environment variables are injected from Secret {{ include "payouts.fullname" . }}: +{{- else }} +3. Secret environment variables are injected from Secret {{ include "payouts.fullname" . }}: {{- end }} + DATABASE_CONNECTION, YOOKASSA_APIBASEKEY, YOOKASSA_APIBASESECRET, + YOOKASSA_APIPAYMENTKEY, YOOKASSA_APIPAYMENTSECRET -{{- if .Values.secrets.yookassa.apiPaymentKey }} -YooKassa API payment key is configured. -{{- end }} + Before deploying to production, populate these values: + helm upgrade {{ .Release.Name }} ./helm \ + --set secrets.DATABASE_CONNECTION="host=... dbname=..." \ + --set secrets.YOOKASSA_APIBASEKEY="" \ + --set secrets.YOOKASSA_APIBASESECRET="" \ + --set secrets.YOOKASSA_APIPAYMENTKEY="" \ + --set secrets.YOOKASSA_APIPAYMENTSECRET="" -{{- if .Values.config.Server.Tls.Enabled }} -The service will use the following TLS certificate and key files: -- Certificate file: {{ .Values.config.Server.Tls.CertFile | default "/etc/tls/cert.pem" }} -- Key file: {{ .Values.config.Server.Tls.KeyFile | default "/etc/tls/key.pem" }} -{{- end }} - -To view the logs of the deployed pods, run: - kubectl logs -l app.kubernetes.io/name={{ include "payouts.name" . }} \ No newline at end of file + Or use a separate values file that is not committed to version control: + helm upgrade {{ .Release.Name }} ./helm -f secrets.values.yaml diff --git a/helm/payouts/templates/_helpers.tpl b/helm/payouts/templates/_helpers.tpl index c096acc..ab6cbfb 100644 --- a/helm/payouts/templates/_helpers.tpl +++ b/helm/payouts/templates/_helpers.tpl @@ -1,7 +1,13 @@ +{{/* +Expand the name of the chart. +*/}} {{- define "payouts.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} +{{/* +Create a default fully qualified app name. +*/}} {{- define "payouts.fullname" -}} {{- if .Values.fullnameOverride }} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} @@ -15,26 +21,42 @@ {{- end }} {{- end }} -{{- define "payouts.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - +{{/* +Common labels +*/}} {{- define "payouts.labels" -}} -app.kubernetes.io/name: {{ include "payouts.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} +helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{ include "payouts.selectorLabels" . }} app.kubernetes.io/managed-by: {{ .Release.Service }} -helm.sh/chart: {{ include "payouts.chart" . }} {{- end }} +{{/* +Selector labels +*/}} {{- define "payouts.selectorLabels" -}} app.kubernetes.io/name: {{ include "payouts.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} -{{- define "payouts.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "payouts.fullname" .) .Values.serviceAccount.name }} +{{/* +Name of the TLS secret to mount. +Returns tls.existingSecret when set, otherwise the chart-managed secret name. +*/}} +{{- define "payouts.tlsSecretName" -}} +{{- if .Values.tls.existingSecret }} +{{- .Values.tls.existingSecret }} {{- else }} -{{- default "default" .Values.serviceAccount.name }} +{{- printf "%s-tls" (include "payouts.fullname" .) }} +{{- end }} +{{- end }} + +{{/* +Validate TLS configuration. +*/}} +{{- define "payouts.validateTls" -}} +{{- if .Values.config.Server.Tls.Enabled }} +{{- if and (not .Values.tls.existingSecret) (or (not .Values.tls.cert) (not .Values.tls.key)) }} +{{- fail "TLS is enabled: either set tls.existingSecret or provide both tls.cert and tls.key" }} +{{- end }} {{- end }} {{- end }} diff --git a/helm/payouts/templates/configmap.yaml b/helm/payouts/templates/configmap.yaml index 430cc64..6d78afa 100644 --- a/helm/payouts/templates/configmap.yaml +++ b/helm/payouts/templates/configmap.yaml @@ -1,18 +1,9 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ include "payouts.fullname" . }}-config + name: {{ include "payouts.fullname" . }} labels: {{- include "payouts.labels" . | nindent 4 }} data: - payouts.yaml: | -{{- range $key, $value := .Values.config }} -{{ $key }}: -{{- if eq (kindOf $value) "map" }} -{{- range $subkey, $subvalue := $value }} - {{ $subkey }}: {{ $subvalue | quote }} -{{- end }} -{{- else }} - {{ $value | quote }} -{{- end }} -{{- end }} + config.yaml: | + {{- .Values.config | toYaml | nindent 4 }} diff --git a/helm/payouts/templates/deployment.yaml b/helm/payouts/templates/deployment.yaml index 526416f..0e457ca 100644 --- a/helm/payouts/templates/deployment.yaml +++ b/helm/payouts/templates/deployment.yaml @@ -11,102 +11,58 @@ spec: {{- include "payouts.selectorLabels" . | nindent 6 }} template: metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} labels: - {{- include "payouts.labels" . | nindent 8 }} + {{- include "payouts.selectorLabels" . | nindent 8 }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- if .Values.config.Server.Tls.Enabled }} + checksum/tls: {{ include (print $.Template.BasePath "/tls-secret.yaml") . | sha256sum }} + {{- end }} spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - name: http - containerPort: 8080 - protocol: TCP - livenessProbe: - httpGet: - path: /health - port: http - readinessProbe: - httpGet: - path: /health - port: http env: - name: CONFIG_PATH - value: "/app/config/payouts.yaml" - - name: YOOKASSA_APIBASEKEY + value: /etc/payouts/config.yaml + {{- range $key, $value := .Values.secrets }} + - name: {{ $key }} valueFrom: secretKeyRef: - name: {{ include "payouts.fullname" . }}-secret - key: yookassa.apiBaseKey - - name: YOOKASSA_APIBASESECRET - valueFrom: - secretKeyRef: - name: {{ include "payouts.fullname" . }}-secret - key: yookassa.apiBaseSecret - - name: YOOKASSA_APIPAYMENTKEY - valueFrom: - secretKeyRef: - name: {{ include "payouts.fullname" . }}-secret - key: yookassa.apiPaymentKey - - name: YOOKASSA_APIPAYMENTSECRET - valueFrom: - secretKeyRef: - name: {{ include "payouts.fullname" . }}-secret - key: yookassa.apiPaymentSecret - {{- if .Values.config.Server.Tls.Enabled }} - - name: SERVER_TLS_CERTFILE - value: {{ .Values.config.Server.Tls.CertFile | quote }} - - name: SERVER_TLS_KEYFILE - value: {{ .Values.config.Server.Tls.KeyFile | quote }} + name: {{ include "payouts.fullname" $ }} + key: {{ $key }} {{- end }} + ports: + - name: http + containerPort: {{ trimPrefix ":" .Values.config.Server.Port | int }} + protocol: TCP volumeMounts: - - name: config-volume - mountPath: /app/config + - name: config + mountPath: /etc/payouts + readOnly: true {{- if .Values.config.Server.Tls.Enabled }} - {{- if .Values.tls.createSecret }} - - name: tls-certs - mountPath: /etc/tls + - name: tls + mountPath: /etc/payouts/tls readOnly: true - {{- else if .Values.tls.existingSecret }} - - name: tls-certs - mountPath: /etc/tls - readOnly: true - {{- end }} {{- end }} resources: {{- toYaml .Values.resources | nindent 12 }} - {{- if .Values.config.Server.Tls.Enabled }} volumes: - - name: config-volume + - name: config configMap: - name: {{ include "payouts.fullname" . }}-config - {{- if .Values.tls.createSecret }} - - name: tls-certs + name: {{ include "payouts.fullname" . }} + {{- if .Values.config.Server.Tls.Enabled }} + - name: tls secret: - secretName: {{ include "payouts.fullname" . }}-tls - {{- else if .Values.tls.existingSecret }} - - name: tls-certs - secret: - secretName: {{ .Values.tls.existingSecret }} + secretName: {{ include "payouts.tlsSecretName" . }} + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key {{- end }} - {{- else }} - volumes: - - name: config-volume - configMap: - name: {{ include "payouts.fullname" . }}-config - {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -118,4 +74,4 @@ spec: {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file + {{- end }} diff --git a/helm/payouts/templates/ingress.yaml b/helm/payouts/templates/ingress.yaml index cc5857c..238f67a 100644 --- a/helm/payouts/templates/ingress.yaml +++ b/helm/payouts/templates/ingress.yaml @@ -1,4 +1,4 @@ -{{- if .Values.ingress.enabled -}} +{{- if .Values.ingress.enabled }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: @@ -10,29 +10,22 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} {{- if .Values.ingress.tls }} tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} + {{- toYaml .Values.ingress.tls | nindent 4 }} {{- end }} rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} + - host: {{ .Values.ingress.host }} http: paths: - {{- range .paths }} - - path: {{ .path }} - pathType: {{ .pathType }} + - path: {{ .Values.ingress.path }} + pathType: {{ .Values.ingress.pathType }} backend: service: - name: {{ include "payouts.fullname" $ }} + name: {{ include "payouts.fullname" . }} port: - number: {{ $.Values.service.port }} - {{- end }} - {{- end }} -{{- end -}} \ No newline at end of file + name: http +{{- end }} diff --git a/helm/payouts/templates/secret.yaml b/helm/payouts/templates/secret.yaml index c305b93..cff73b7 100644 --- a/helm/payouts/templates/secret.yaml +++ b/helm/payouts/templates/secret.yaml @@ -1,34 +1,11 @@ apiVersion: v1 kind: Secret metadata: - name: {{ include "payouts.fullname" . }}-secret + name: {{ include "payouts.fullname" . }} labels: {{- include "payouts.labels" . | nindent 4 }} type: Opaque data: -{{- if .Values.secrets.yookassa.apiBaseKey }} - yookassa.apiBaseKey: {{ .Values.secrets.yookassa.apiBaseKey | toString | b64enc | quote }} -{{- end }} -{{- if .Values.secrets.yookassa.apiBaseSecret }} - yookassa.apiBaseSecret: {{ .Values.secrets.yookassa.apiBaseSecret | toString | b64enc | quote }} -{{- end }} -{{- if .Values.secrets.yookassa.apiPaymentKey }} - yookassa.apiPaymentKey: {{ .Values.secrets.yookassa.apiPaymentKey | toString | b64enc | quote }} -{{- end }} -{{- if .Values.secrets.yookassa.apiPaymentSecret }} - yookassa.apiPaymentSecret: {{ .Values.secrets.yookassa.apiPaymentSecret | toString | b64enc | quote }} -{{- end }} - -{{- if and .Values.config.Server.Tls.Enabled .Values.tls.createSecret }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "payouts.fullname" . }}-tls - labels: - {{- include "payouts.labels" . | nindent 4 }} -type: kubernetes.io/tls -data: - tls.crt: {{ .Values.tls.certData | b64enc | quote }} - tls.key: {{ .Values.tls.keyData | b64enc | quote }} -{{- end }} \ No newline at end of file + {{- range $key, $value := .Values.secrets }} + {{ $key }}: {{ $value | toString | b64enc | quote }} + {{- end }} diff --git a/helm/payouts/templates/service.yaml b/helm/payouts/templates/service.yaml index fc8e81a..5add6fa 100644 --- a/helm/payouts/templates/service.yaml +++ b/helm/payouts/templates/service.yaml @@ -12,4 +12,4 @@ spec: protocol: TCP name: http selector: - {{- include "payouts.selectorLabels" . | nindent 4 }} \ No newline at end of file + {{- include "payouts.selectorLabels" . | nindent 4 }} diff --git a/helm/payouts/templates/tls-secret.yaml b/helm/payouts/templates/tls-secret.yaml new file mode 100644 index 0000000..671d2e6 --- /dev/null +++ b/helm/payouts/templates/tls-secret.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.config.Server.Tls.Enabled (not .Values.tls.existingSecret) }} +{{- include "payouts.validateTls" . }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-tls" (include "payouts.fullname" .) }} + labels: + {{- include "payouts.labels" . | nindent 4 }} +type: kubernetes.io/tls +data: + tls.crt: {{ .Values.tls.cert | toString | b64enc }} + tls.key: {{ .Values.tls.key | toString | b64enc }} +{{- end }} diff --git a/helm/payouts/values.yaml b/helm/payouts/values.yaml index fb18d09..76469c6 100644 --- a/helm/payouts/values.yaml +++ b/helm/payouts/values.yaml @@ -1,7 +1,3 @@ -# Default values for payouts chart -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - replicaCount: 1 image: @@ -15,93 +11,95 @@ service: ingress: enabled: false + className: "" annotations: {} - hosts: - - host: payouts.local - paths: [] + host: payouts.example.com + path: / + pathType: Prefix tls: [] -# TLS configuration -tls: - createSecret: false - existingSecret: "" - certData: "" - keyData: "" - resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi nodeSelector: {} - tolerations: [] - affinity: {} -# ConfigMap values (YAML format) +# Non-secret application config — rendered as /etc/payouts/config.yaml inside the pod config: Server: Port: ":8080" - WriteTimeout: "35s" - ReadTimeout: "35s" + WriteTimeout: 35s + ReadTimeout: 35s EnablePProfEndpoints: false Tls: Enabled: false - CertFile: "/etc/tls/cert.pem" - KeyFile: "/etc/tls/key.pem" + CertFile: /etc/payouts/tls/tls.crt + KeyFile: /etc/payouts/tls/tls.key + Socket: - MaxHttpBufferSize: "2097152" - PingInterval: "25s" - PingTimeout: "20s" + MaxHttpBufferSize: 2097152 + PingInterval: 25s + PingTimeout: 20s Debug: false + Metrics: - Endpoint: "/metrics" + Endpoint: /metrics HistogramBuckets: "0.001,0.002,0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10" Http: HistogramEnabled: true Buckets: "0.001,0.002,0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10" + Log: - Level: "DEBUG" - FilePath: "./logs/payouts.log" + Level: DEBUG + FilePath: ./logs/payouts.log TextOutput: false StdoutEnabled: true FileEnabled: false + Database: Type: "" - Connection: "" - LogLevel: "Info" + LogLevel: Info TraceRequests: false + Cache: - TTL: "24h" + TTL: 24h + YooKassa: - BaseUrl: "https://api.yookassa.ru/v3" - Timeout: "2s" + BaseUrl: https://api.yookassa.ru/v3 + Timeout: 2s Retry: Enabled: false - Count: "3" - WaitTime: "200ms" - MaxWaitTime: "5s" + Count: 3 + WaitTime: 200ms + MaxWaitTime: 5s Test: false CheckAllowedCallbackAddress: true AllowedCallbackSubnets: "185.71.76.0/27,185.71.77.0/27,77.75.153.0/25,77.75.156.11/32,77.75.156.35/32,77.75.154.128/25,2a02:5180::/32" - ApiBaseKey: "" - ApiBaseSecret: "" - ApiPaymentKey: "" - ApiPaymentSecret: "" - CallbackProcessTimeout: "1s" + CallbackProcessTimeout: 1s -# Secret values (secrets that should not be in ConfigMap) +# TLS for the application server +# When config.Server.Tls.Enabled is true, a volume with the cert and key is mounted +# into the pod at the paths defined by config.Server.Tls.CertFile / KeyFile. +# +# Option A — bring your own secret (must be type kubernetes.io/tls): +# tls.existingSecret: "my-tls-secret" +# +# Option B — supply PEM values and let the chart create the secret: +# tls.cert: | +# -----BEGIN CERTIFICATE----- +# ... +# tls.key: | +# -----BEGIN PRIVATE KEY----- +# ... +tls: + existingSecret: "" + cert: "" + key: "" + +# Secret values — injected as env vars (uppercase, dots → underscores) secrets: - yookassa: - apiBaseKey: "" - apiBaseSecret: "" - apiPaymentKey: "" - apiPaymentSecret: "" + DATABASE_CONNECTION: "" + YOOKASSA_APIBASEKEY: "" + YOOKASSA_APIBASESECRET: "" + YOOKASSA_APIPAYMENTKEY: "" + YOOKASSA_APIPAYMENTSECRET: ""