diff --git a/charts/polymorphic-app/Chart.yaml b/charts/polymorphic-app/Chart.yaml index 07257ddc..dc6b74e3 100644 --- a/charts/polymorphic-app/Chart.yaml +++ b/charts/polymorphic-app/Chart.yaml @@ -4,5 +4,5 @@ description: A Helm chart for deploying any custom applications, specifically po maintainers: - name: improwised type: application -version: 2.7.0 +version: 3.0.0 appVersion: 1.0.0 diff --git a/charts/polymorphic-app/Readme.md b/charts/polymorphic-app/README.md similarity index 82% rename from charts/polymorphic-app/Readme.md rename to charts/polymorphic-app/README.md index 0837590b..e2ab016d 100644 --- a/charts/polymorphic-app/Readme.md +++ b/charts/polymorphic-app/README.md @@ -11,4 +11,5 @@ This chart is ideal for deploying applications that support polymorphic containe * Worker: Consists of a kubernetes `Deployment` and optionally a `HorizontalPodAutoscaler`. Typically used to deploy long-running services that are not consumed through a TCP/HTTP server. e.g. Queue Workers and Stream Processors * Jobs: Typically used to run one-off jobs, mostly helm hooks, to be run when installing/uninstalling/upgrading the helm deployment. Used to run database migrations by default. Backed by Kubernetes `Job`. * CronJobs: Typically used to run scheduled jobs. Used for triggering events and batch processing jobs at a regular interval. Backed by Kubernetes `CronJob`. +* **Multi-Container Support**: Deploy multiple containers in a single pod for both Deployments and StatefulSets. This enables sidecar patterns, log collection, monitoring agents, and more. Each service must define a `containers` array, supporting both single and multiple containers with a consistent structure. See [MULTI_CONTAINER.md](./MULTI_CONTAINER.md) for detailed documentation. * Designed to be used with [Flux Helm Controller](https://github.com/fluxcd/helm-controller), [Helmfile](https://github.com/roboll/helmfile), and any other mechanism that is backed by helm values-file override. diff --git a/charts/polymorphic-app/ci/override-values.yaml b/charts/polymorphic-app/ci/override-values.yaml index cc2f014f..a0b4cbac 100644 --- a/charts/polymorphic-app/ci/override-values.yaml +++ b/charts/polymorphic-app/ci/override-values.yaml @@ -1,3 +1,6 @@ +# Comprehensive test values for polymorphic-app chart +# This file contains all test cases including services and workers with multi-container support + serviceTemplate: healthcheck: enabled: true @@ -6,35 +9,60 @@ serviceTemplate: path: / initialDelaySeconds: 5 periodSeconds: 5 + +# Services with various configurations services: - - name: demo-1 - image: - repository: nginx - tag: "latest" - ports: - - name: http - containerPort: 80 + # ======================================== + # Single Container Services + # ======================================== + + - name: single-container + containers: + - name: single-container + image: + repository: nginx + tag: "1.20" + env: + - name: ENV_VAR + value: "test" + ports: + - name: http + containerPort: 80 + healthcheck: + enabled: true + type: httpGet + path: /health + port: 80 service: + enabled: true + type: ClusterIP ports: - name: http port: 80 targetPort: http - - name: demo-2 + + # ======================================== + # StatefulSet with Single Container + # ======================================== + + - name: statefulset-single type: StatefulSet - image: - repository: nginx - tag: latest - healthcheck: - enabled: true - type: tcpSocket - port: 80 - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 3 - volumeMounts: - - name: data - mountPath: /data + containers: + - name: statefulset-single + image: + repository: nginx + tag: latest + healthcheck: + enabled: true + type: tcpSocket + port: 80 + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 5 + failureThreshold: 3 + volumeMounts: + - name: data + mountPath: /data volumeClaimTemplates: - metadata: name: data @@ -43,77 +71,464 @@ services: resources: requests: storage: 1Gi - - name: demo-3 - image: - repository: nginx - tag: latest - healthcheck: + + # ======================================== + # Service with Autoscaling + # ======================================== + + - name: autoscaling-test + containers: + - name: autoscaling-test + image: + repository: nginx + tag: latest + ports: + - name: http + containerPort: 80 + resources: + requests: + cpu: 100m + memory: 128Mi + autoscaling: true + minReplicaCount: 2 + maxReplicaCount: 5 + averageUtilization: 70 + service: + enabled: true + ports: + - port: 80 + targetPort: http + + # ======================================== + # Health Check Types + # ======================================== + + - name: http-healthcheck + containers: + - name: http-healthcheck + image: + repository: nginx + tag: latest + ports: + - name: http + containerPort: 80 + healthcheck: + enabled: true + type: httpGet + path: / + port: 80 + service: enabled: true - type: exec - command: - - cat - - /usr/share/nginx/html/index.html - - name: demo-4 - image: - repository: nginx - tag: "latest" - ports: - - name: http - containerPort: 80 - healthcheck: + ports: + - port: 80 + targetPort: http + + - name: exec-healthcheck + containers: + - name: exec-healthcheck + image: + repository: nginx + tag: latest + healthcheck: + enabled: true + type: exec + command: + - cat + - /usr/share/nginx/html/index.html + + - name: separate-probes + containers: + - name: separate-probes + image: + repository: nginx + tag: latest + ports: + - name: http + containerPort: 80 + healthcheck: + enabled: true + type: exec + liveness: + command: + - cat + - /usr/share/nginx/html/index.html + initialDelaySeconds: 5 + periodSeconds: 5 + readiness: + command: + - cat + - /usr/share/nginx/html/50x.html + + # ======================================== + # Multi-Container Services + # ======================================== + + - name: multi-container-app + containers: + - name: main-app + image: + repository: nginx + tag: "latest" + ports: + - name: http + containerPort: 80 + protocol: TCP + healthcheck: + enabled: true + type: httpGet + path: / + port: 80 + initialDelaySeconds: 10 + periodSeconds: 10 + resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + - name: sidecar + image: + repository: busybox + tag: "latest" + command: ["/bin/sh"] + args: ["-c", "while true; do sleep 30; done"] + resources: + limits: + cpu: 50m + memory: 64Mi + requests: + cpu: 25m + memory: 32Mi + service: enabled: true - type: exec - liveness: + type: ClusterIP + ports: + - name: http + port: 80 + targetPort: http + protocol: TCP + + - name: multi-container-statefulset + type: StatefulSet + containers: + - name: database + image: + repository: postgres + tag: "15" + ports: + - name: postgres + containerPort: 5432 + protocol: TCP + env: + - name: POSTGRES_DB + value: testdb + - name: POSTGRES_USER + value: testuser + healthcheck: + enabled: true + type: tcpSocket + port: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + - name: backup-agent + image: + repository: busybox + tag: "latest" + command: ["/bin/sh"] + args: ["-c", "while true; do sleep 300; done"] + volumeMounts: + - name: data + mountPath: /backup + readOnly: true + resources: + limits: + cpu: 100m + memory: 128Mi + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 5Gi + + # ======================================== + # Edge Cases + # ======================================== + + - name: minimal-container + containers: + - name: minimal + image: + repository: nginx + tag: latest + + - name: mixed-health-checks + containers: + - name: http-health + image: + repository: nginx + tag: latest + ports: + - name: http + containerPort: 80 + healthcheck: + enabled: true + type: httpGet + path: / + port: 80 + - name: tcp-health + image: + repository: redis + tag: alpine + ports: + - name: redis + containerPort: 6379 + healthcheck: + enabled: true + type: tcpSocket + port: 6379 + - name: exec-health + image: + repository: busybox + tag: latest + command: ["/bin/sh", "-c", "sleep 3600"] + healthcheck: + enabled: true + type: exec + command: + - /bin/true + + - name: mixed-env + containers: + - name: app + image: + repository: nginx + tag: latest + env: + - name: APP_SPECIFIC + value: app-value + ports: + - name: http + containerPort: 80 + - name: sidecar + image: + repository: busybox + tag: latest + env: + - name: SIDECAR_SPECIFIC + value: sidecar-value + command: ["/bin/sh", "-c", "sleep 3600"] + env: + - name: SHARED_ENV + value: shared-value + + - name: complex-volumes + containers: + - name: writer + image: + repository: busybox + tag: latest command: - - cat - - /usr/share/nginx/html/index.html - initialDelaySeconds: 5 - periodSeconds: 5 - readiness: + [ + "/bin/sh", + "-c", + "while true; do echo 'data' > /shared/data.txt; sleep 10; done", + ] + volumeMounts: + - name: shared-data + mountPath: /shared + - name: writer-only + mountPath: /writer-data + - name: reader + image: + repository: busybox + tag: latest command: - - cat - - /usr/share/nginx/html/50x.html - - - name: demo-5 - image: - repository: nginx - tag: "latest" - ports: - - name: http - containerPort: 80 - healthcheck: - enabled: true - type: httpGet - path: / - port: 80 - liveness: - port: 80 - initialDelaySeconds: 5 - periodSeconds: 5 - failureThreshold: 5 - timeoutSeconds: 5 - path: /live - readiness: - initialDelaySeconds: 10 - periodSeconds: 10 - failureThreshold: 10 - timeoutSeconds: 10 - - name: demo-6 - image: - repository: nginx - tag: "latest" - healthcheck: - enabled: false - type: httpGet - path: / - port: 80 - - name: demo-7 - image: - repository: nginx - tag: "latest" - healthcheck: - enabled: true - type: httpGet - liveness: - path: /live - port: 80 + [ + "/bin/sh", + "-c", + "while true; do cat /shared/data.txt; sleep 10; done", + ] + volumeMounts: + - name: shared-data + mountPath: /shared + readOnly: true + - name: reader-only + mountPath: /reader-data + volumes: + - name: shared-data + emptyDir: {} + - name: writer-only + emptyDir: {} + - name: reader-only + emptyDir: {} + + - name: lifecycle-hooks + containers: + - name: app + image: + repository: nginx + tag: latest + lifecycleHooks: + postStart: + exec: + command: + - /bin/sh + - -c + - echo "Container started" + preStop: + exec: + command: + - /bin/sh + - -c + - echo "Container stopping" + ports: + - name: http + containerPort: 80 + + - name: init-and-multi + initContainers: + - name: init-1 + image: busybox + command: ["sh", "-c", 'echo "Init 1"'] + - name: init-2 + image: busybox + command: ["sh", "-c", 'echo "Init 2"'] + containers: + - name: main + image: + repository: nginx + tag: latest + ports: + - name: http + containerPort: 80 + - name: helper + image: + repository: busybox + tag: latest + command: ["/bin/sh", "-c", "sleep 3600"] + +# Workers with multi-container support +workers: + # ======================================== + # Single Container Workers + # ======================================== + + - name: single-worker + containers: + - name: worker + image: + repository: busybox + tag: latest + command: ["/bin/sh", "-c"] + args: ["while true; do echo 'working'; sleep 30; done"] + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + + # ======================================== + # Multi-Container Workers + # ======================================== + + - name: multi-container-worker + containers: + - name: main-worker + image: + repository: busybox + tag: latest + command: ["/bin/sh", "-c"] + args: ["while true; do echo 'data' > /shared/work.log; sleep 10; done"] + volumeMounts: + - name: shared-data + mountPath: /shared + resources: + limits: + cpu: 200m + memory: 256Mi + - name: log-collector + image: + repository: busybox + tag: latest + command: ["/bin/sh", "-c"] + args: ["while true; do cat /logs/work.log; sleep 15; done"] + volumeMounts: + - name: shared-data + mountPath: /logs + readOnly: true + volumes: + - name: shared-data + emptyDir: {} + + # ======================================== + # Worker with Health Check + # ======================================== + + - name: worker-with-healthcheck + containers: + - name: worker + image: + repository: busybox + tag: latest + command: ["/bin/sh", "-c"] + args: ["touch /tmp/healthy && while true; do sleep 30; done"] + healthcheck: + enabled: true + type: exec + command: + - cat + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 10 + + # ======================================== + # Worker with Autoscaling + # ======================================== + + - name: autoscaling-worker + containers: + - name: worker + image: + repository: busybox + tag: latest + command: ["/bin/sh", "-c"] + args: ["while true; do sleep 30; done"] + resources: + requests: + cpu: 100m + memory: 128Mi + autoscaling: true + minReplicaCount: 2 + maxReplicaCount: 5 + averageUtilization: 70 + + # ======================================== + # Worker with Init Container + # ======================================== + + - name: worker-with-init + initContainers: + - name: init-setup + image: busybox + command: ["sh", "-c", "echo 'Initializing...' && sleep 2"] + containers: + - name: worker + image: + repository: busybox + tag: latest + command: ["/bin/sh", "-c"] + args: ["while true; do sleep 30; done"] diff --git a/charts/polymorphic-app/templates/_helpers.tpl b/charts/polymorphic-app/templates/_helpers.tpl index fad18c0c..704e1bcf 100644 --- a/charts/polymorphic-app/templates/_helpers.tpl +++ b/charts/polymorphic-app/templates/_helpers.tpl @@ -234,3 +234,238 @@ readinessProbe: {{- end -}} {{- end -}} {{- end -}} + +{{/* +Container spec template - generates a single container definition +Context: { + container: container definition, + root: root values, + defaultImage: default image repository and tag, + defaultEnv: default env vars, + defaultEnvFrom: default envFrom, + defaultVolumeMounts: default volume mounts +} +*/}} +{{- define "polymorphic-app.container" -}} +name: {{ .container.name | required "Container name is required" }} + {{- if .container.image }} +image: "{{ .container.image.repository }}:{{ .container.image.tag }}" + {{- else if .defaultImage }} +image: "{{ .defaultImage.repository }}:{{ .defaultImage.tag }}" + {{- else }} +image: "{{ .root.Values.image.repository }}:{{ .root.Values.image.tag }}" + {{- end }} +imagePullPolicy: {{ .root.Values.image.pullPolicy }} + {{- if or .container.env .defaultEnv .root.Values.env }} +env: + {{- if .container.env }} +{{ toYaml .container.env | indent 2 }} + {{- end }} + {{- if .defaultEnv }} +{{ toYaml .defaultEnv | indent 2 }} + {{- end }} + {{- if .root.Values.env }} +{{ toYaml .root.Values.env | indent 2 }} + {{- end }} + {{- end }} + {{- if or .container.envFrom .defaultEnvFrom .root.Values.envFrom }} +envFrom: + {{- if .container.envFrom }} +{{ toYaml .container.envFrom | indent 2 }} + {{- end }} + {{- if .defaultEnvFrom }} +{{ toYaml .defaultEnvFrom | indent 2 }} + {{- end }} + {{- if .root.Values.envFrom }} +{{ toYaml .root.Values.envFrom | indent 2 }} + {{- end }} + {{- end }} + {{- if .container.command }} +command: +{{ toYaml .container.command | indent 2 }} + {{- end }} + {{- if .container.args }} +args: +{{ toYaml .container.args | indent 2 }} + {{- end }} + {{- with .container.ports }} +ports: +{{ toYaml . | indent 2 }} + {{- end }} + {{- with .container.resources }} +resources: +{{ toYaml . | indent 2 }} + {{- end }} + {{- with .container.containerSecurityContext }} +securityContext: +{{ toYaml . | indent 2 }} + {{- end }} + {{- if .container.lifecycleHooks }} +lifecycle: +{{ toYaml .container.lifecycleHooks | indent 2 }} + {{- end }} + {{- if or .container.volumeMounts .defaultVolumeMounts .root.Values.volumeMounts }} +volumeMounts: + {{- if .container.volumeMounts }} +{{ toYaml .container.volumeMounts | indent 2 }} + {{- end }} + {{- if .defaultVolumeMounts }} +{{ toYaml .defaultVolumeMounts | indent 2 }} + {{- end }} + {{- if .root.Values.volumeMounts }} +{{ toYaml .root.Values.volumeMounts | indent 2 }} + {{- end }} + {{- end }} + {{- $health := .container.healthcheck -}} + {{- if and $health (ne $health.enabled false) }} +{{- include "polymorphic-app.healthchecks" $health | nindent 0 }} + {{- end }} +{{- end -}} + +{{/* +Pod spec template - generates the full pod spec (without initial 'spec:' key) +Context: { + item: service/worker item definition, + root: root context ($), + template: template defaults (serviceTemplate or workerTemplate), + type: "service" or "worker" +} +*/}} +{{- define "polymorphic-app.podSpec" -}} +{{- if .item.imagePullSecrets }} +imagePullSecrets: +{{ toYaml .item.imagePullSecrets | indent 2 }} +{{- else if .template.imagePullSecrets }} +imagePullSecrets: +{{ toYaml .template.imagePullSecrets | indent 2 }} +{{- else if .root.Values.imagePullSecrets }} +imagePullSecrets: +{{ toYaml .root.Values.imagePullSecrets | indent 2 }} +{{- end }} +terminationGracePeriodSeconds: {{ .item.terminationGracePeriodSeconds | default .template.terminationGracePeriodSeconds }} +{{- if or .template.initContainers .item.initContainers }} + {{- with .item.initContainers | default .template.initContainers }} +initContainers: +{{ toYaml . | indent 2 }} + {{- end }} +{{- end }} +containers: +{{- $containers := .item.containers -}} +{{- if not $containers -}} + {{- fail "containers array is required. Please define containers for your deployment." -}} +{{- end -}} +{{- range $container := $containers }} + - name: {{ $container.name | required "Container name is required" }} + {{- if $container.image }} + image: "{{ $container.image.repository }}:{{ $container.image.tag }}" + {{- else if $.template.image }} + image: "{{ $.template.image.repository }}:{{ $.template.image.tag }}" + {{- else }} + image: "{{ $.root.Values.image.repository }}:{{ $.root.Values.image.tag }}" + {{- end }} + imagePullPolicy: {{ $.root.Values.image.pullPolicy }} + {{- if or $container.env $.template.env $.root.Values.env }} + env: + {{- if $container.env }} +{{ toYaml $container.env | indent 6 }} + {{- end }} + {{- if $.template.env }} +{{ toYaml $.template.env | indent 6 }} + {{- end }} + {{- if $.root.Values.env }} +{{ toYaml $.root.Values.env | indent 6 }} + {{- end }} + {{- end }} + {{- if or $container.envFrom $.template.envFrom $.root.Values.envFrom }} + envFrom: + {{- if $container.envFrom }} +{{ toYaml $container.envFrom | indent 6 }} + {{- end }} + {{- if $.template.envFrom }} +{{ toYaml $.template.envFrom | indent 6 }} + {{- end }} + {{- if $.root.Values.envFrom }} +{{ toYaml $.root.Values.envFrom | indent 6 }} + {{- end }} + {{- end }} + {{- if $container.command }} + command: +{{ toYaml $container.command | indent 6 }} + {{- end }} + {{- if $container.args }} + args: +{{ toYaml $container.args | indent 6 }} + {{- end }} + {{- with $container.ports }} + ports: +{{ toYaml . | indent 6 }} + {{- end }} + {{- with $container.resources }} + resources: +{{ toYaml . | indent 6 }} + {{- end }} + {{- with $container.containerSecurityContext }} + securityContext: +{{ toYaml . | indent 6 }} + {{- end }} + {{- if $container.lifecycleHooks }} + lifecycle: +{{ toYaml $container.lifecycleHooks | indent 6 }} + {{- end }} + {{- if or $container.volumeMounts $.template.volumeMounts $.root.Values.volumeMounts }} + volumeMounts: + {{- if $container.volumeMounts }} +{{ toYaml $container.volumeMounts | indent 6 }} + {{- end }} + {{- if $.template.volumeMounts }} +{{ toYaml $.template.volumeMounts | indent 6 }} + {{- end }} + {{- if $.root.Values.volumeMounts }} +{{ toYaml $.root.Values.volumeMounts | indent 6 }} + {{- end }} + {{- end }} + {{- $health := $container.healthcheck -}} + {{- if and $health (ne $health.enabled false) }} +{{- include "polymorphic-app.healthchecks" $health | nindent 4 }} + {{- end }} +{{- end }} +{{- with .item.dnsConfig | default .template.dnsConfig }} +dnsConfig: +{{ toYaml . | indent 2 }} +{{- end }} +{{- with .item.securityContext | default .template.securityContext }} +securityContext: +{{ toYaml . | indent 2 }} +{{- end }} +volumes: +{{- if .item.volumes }} +{{ toYaml .item.volumes | indent 2 }} +{{- end }} +{{- if .root.Values.volumes }} +{{ toYaml .root.Values.volumes | indent 2 }} +{{- end }} +{{- if .template.volumes }} +{{ toYaml .template.volumes | indent 2 }} +{{- end }} +{{- with .item.nodeSelector | default .template.nodeSelector }} +nodeSelector: +{{ toYaml . | indent 2 }} +{{- end }} +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + {{- include "polymorphic-app.labels" $.root | nindent 12 }} + app.kubernetes.io/component: "{{ .item.name | default .template.name }}" +{{- with .item.affinity | default .template.affinity }} +{{ toYaml . | indent 2 }} +{{- end }} +{{- with .item.tolerations | default .template.tolerations }} +tolerations: +{{ toYaml . | indent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/polymorphic-app/templates/service.yaml b/charts/polymorphic-app/templates/service.yaml index ce016b5f..dd3d2a35 100644 --- a/charts/polymorphic-app/templates/service.yaml +++ b/charts/polymorphic-app/templates/service.yaml @@ -46,142 +46,7 @@ spec: {{ toYaml .podAnnotations | indent 8 }} {{- end }} spec: - {{- if .imagePullSecrets }} - imagePullSecrets: -{{ toYaml .imagePullSecrets | indent 8 }} - {{- else if $.Values.serviceTemplate.imagePullSecrets }} - imagePullSecrets: -{{ toYaml $.Values.serviceTemplate.imagePullSecrets | indent 8 }} - {{- else }} - {{- if $.Values.imagePullSecrets }} - imagePullSecrets: -{{ toYaml $.Values.imagePullSecrets | indent 8 }} - {{- end }} - {{- end }} - terminationGracePeriodSeconds: {{ .terminationGracePeriodSeconds | default $.Values.serviceTemplate.terminationGracePeriodSeconds }} - {{- if or ($.Values.serviceTemplate.initContainers) (.initContainers) }} - {{- with .initContainers | default $.Values.serviceTemplate.initContainers }} - initContainers: -{{ toYaml . | indent 8 }} - {{- end }} - {{- end }} - containers: - {{- if $.Values.prefixWithReleaseName.enabled }} - - name: "{{ $.Release.Name }}-{{ .name | default $.Values.serviceTemplate.name }}" - {{- else}} - - name: "{{ .name | default $.Values.serviceTemplate.name }}" - {{- end }} - {{- if .image }} - image: "{{ .image.repository }}:{{ .image.tag }}" - {{- else if $.Values.serviceTemplate.image }} - image: "{{ $.Values.serviceTemplate.image.repository }}:{{ $.Values.serviceTemplate.image.tag }}" - {{- else }} - image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag }}" - {{- end }} - imagePullPolicy: {{ $.Values.image.pullPolicy }} - env: - {{- if .env }} -{{ toYaml .env | indent 12 }} - {{- end }} - {{- if $.Values.env }} -{{ toYaml $.Values.env | indent 12 }} - {{- end }} - {{- if $.Values.serviceTemplate.env }} -{{ toYaml $.Values.serviceTemplate.env | indent 12 }} - {{- end }} - envFrom: - {{- if .envFrom }} -{{ toYaml .envFrom | indent 12 }} - {{- end }} - {{- if $.Values.envFrom }} -{{ toYaml $.Values.envFrom | indent 12 }} - {{- end }} - {{- if $.Values.serviceTemplate.envFrom }} -{{ toYaml $.Values.serviceTemplate.envFrom | indent 12 }} - {{- end }} - {{- if .command }} - {{- with .command | default $.Values.serviceTemplate.command }} - command: -{{ toYaml . | indent 12 }} - {{- end }} - {{- end }} - {{- if .args }} - {{- with .args | default $.Values.serviceTemplate.args }} - args: -{{ toYaml . | indent 12 }} - {{- end }} - {{- end }} - {{- with .ports | default $.Values.serviceTemplate.ports }} - ports: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with .resources | default $.Values.serviceTemplate.resources }} - resources: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with .containerSecurityContext | default $.Values.serviceTemplate.containerSecurityContext }} - securityContext: -{{ toYaml . | indent 12 }} - {{- end }} - {{- if or ($.Values.serviceTemplate.lifecycleHooks) (.lifecycleHooks) }} - {{- with .lifecycleHooks | default $.Values.serviceTemplate.lifecycleHooks }} - lifecycle: -{{ toYaml . | indent 12 }} - {{- end }} - {{- end }} - volumeMounts: - {{- if .volumeMounts }} -{{ toYaml .volumeMounts | indent 10 }} - {{- end }} - {{- if $.Values.volumeMounts }} -{{ toYaml $.Values.volumeMounts | indent 10 }} - {{- end }} - {{- if $.Values.serviceTemplate.volumeMounts }} -{{ toYaml $.Values.serviceTemplate.volumeMounts | indent 10 }} - {{- end }} - {{- $health := .healthcheck | default $.Values.serviceTemplate.healthcheck -}} - {{- if and $health (ne $health.enabled false) }} - {{- include "polymorphic-app.healthchecks" $health | nindent 10 }} - {{- end }} - {{- with .dnsConfig | default $.Values.workerTemplate.dnsConfig }} - dnsConfig: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .securityContext | default $.Values.serviceTemplate.securityContext }} - securityContext: -{{ toYaml . | indent 8 }} - {{- end }} - volumes: - {{- if .volumes }} -{{ toYaml .volumes | indent 8 }} - {{- end }} - {{- if $.Values.volumes }} -{{ toYaml $.Values.volumes | indent 8 }} - {{- end }} - {{- if $.Values.serviceTemplate.volumes }} -{{ toYaml $.Values.serviceTemplate.volumes | indent 8 }} - {{- end }} - {{- with .nodeSelector | default $.Values.serviceTemplate.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 1 - podAffinityTerm: - topologyKey: kubernetes.io/hostname - labelSelector: - matchLabels: - {{- include "polymorphic-app.labels" $ | nindent 18 }} - app.kubernetes.io/component: "{{ .name | default $.Values.serviceTemplate.name }}" - {{- with .affinity | default $.Values.serviceTemplate.affinity }} -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .tolerations | default $.Values.serviceTemplate.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} +{{- include "polymorphic-app.podSpec" (dict "item" . "root" $ "template" $.Values.serviceTemplate "type" "service") | indent 6 }} {{- if .volumeClaimTemplates }} volumeClaimTemplates: @@ -224,12 +89,6 @@ spec: target: type: Utilization averageUtilization: {{ .averageUtilization | default $.Values.serviceTemplate.averageUtilization }} - # - type: Resource - # resource: - # name: memory - # target: - # type: AverageValue - # averageValue: 100Mi {{- end }} {{- if .service}} {{- if or ( .service.enabled ) ($.Values.serviceTemplate.service.enabled) }} diff --git a/charts/polymorphic-app/templates/worker.yaml b/charts/polymorphic-app/templates/worker.yaml index d78bf2d1..920e64cd 100644 --- a/charts/polymorphic-app/templates/worker.yaml +++ b/charts/polymorphic-app/templates/worker.yaml @@ -32,172 +32,18 @@ spec: {{- include "polymorphic-app.labels" $ | nindent 8 }} app.kubernetes.io/component: "{{ .name | default $.Values.workerTemplate.name }}" spec: - {{- if .imagePullSecrets }} - imagePullSecrets: -{{ toYaml .imagePullSecrets | indent 8 }} - {{- else if $.Values.workerTemplate.imagePullSecrets }} - imagePullSecrets: -{{ toYaml $.Values.workerTemplate.imagePullSecrets | indent 8 }} - {{- else }} - {{- if $.Values.imagePullSecrets }} - imagePullSecrets: -{{ toYaml $.Values.imagePullSecrets | indent 8 }} - {{- end }} - {{- end }} - terminationGracePeriodSeconds: {{ .terminationGracePeriodSeconds | default $.Values.workerTemplate.terminationGracePeriodSeconds }} - containers: - {{- if $.Values.prefixWithReleaseName.enabled }} - - name: "{{ $.Release.Name }}-{{ .name | default $.Values.workerTemplate.name }}" - {{- else }} - - name: "{{ .name | default $.Values.workerTemplate.name }}" - {{- end }} - {{- if .image }} - image: "{{ .image.repository }}:{{ .image.tag }}" - {{- else if $.Values.workerTemplate.image }} - image: "{{ $.Values.workerTemplate.image.repository }}:{{ $.Values.workerTemplate.image.tag }}" - {{- else }} - image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag }}" - {{- end }} - imagePullPolicy: {{ $.Values.image.pullPolicy }} - env: - {{- if .env }} -{{ toYaml .env | indent 12 }} - {{- end }} - {{- if $.Values.env }} -{{ toYaml $.Values.env | indent 12 }} - {{- end }} - {{- if $.Values.workerTemplate.env }} -{{ toYaml $.Values.workerTemplate.env | indent 12 }} - {{- end }} - envFrom: - {{- if .envFrom }} -{{ toYaml .envFrom | indent 12 }} - {{- end }} - {{- if $.Values.envFrom }} -{{ toYaml $.Values.envFrom | indent 12 }} - {{- end }} - {{- if $.Values.workerTemplate.envFrom }} -{{ toYaml $.Values.workerTemplate.envFrom | indent 12 }} - {{- end }} - {{- if .command }} - {{- with .command | default $.Values.workerTemplate.command }} - command: -{{ toYaml . | indent 12 }} - {{- end }} - {{- end }} - {{- if .args }} - {{- with .args | default $.Values.workerTemplate.args }} - args: -{{ toYaml . | indent 12 }} - {{- end }} - {{- end }} - {{- with .resources | default $.Values.workerTemplate.resources }} - resources: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with .containerSecurityContext | default $.Values.workerTemplate.containerSecurityContext }} - securityContext: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with .lifecycleHooks | default $.Values.workerTemplate.lifecycleHooks }} - lifecycle: -{{ toYaml . | indent 12 }} - {{- end }} - volumeMounts: - {{- if .volumeMounts }} -{{ toYaml .volumeMounts | indent 10 }} - {{- end }} - {{- if $.Values.volumeMounts }} -{{ toYaml $.Values.volumeMounts | indent 10 }} - {{- end }} - {{- if $.Values.workerTemplate.volumeMounts }} -{{ toYaml $.Values.workerTemplate.volumeMounts | indent 10 }} - {{- end }} - {{- if or ($.Values.workerTemplate.probe) (.probe) }} - livenessProbe: - exec: - {{- if $.Values.workerTemplate.probe }} - {{- with $.Values.workerTemplate.probe.aliveCommand }} - command: -{{ toYaml . | indent 14 }} - {{- end }} - {{- else }} - {{- with .probe.aliveCommand }} - command: -{{ toYaml . | indent 14 }} - {{- end }} - {{- end }} - initialDelaySeconds: 10 - periodSeconds: 20 - {{- if $.Values.workerTemplate.probe }} - timeoutSeconds: {{ $.Values.workerTemplate.probe.timeoutSeconds }} - {{- else }} - timeoutSeconds: {{ .probe.timeoutSeconds }} - {{- end }} - successThreshold: 1 - readinessProbe: - exec: - {{- if $.Values.workerTemplate.probe }} - {{- with $.Values.workerTemplate.probe.aliveCommand }} - command: -{{ toYaml . | indent 14 }} - {{- end }} - {{- else }} - {{- with .probe.aliveCommand }} - command: -{{ toYaml . | indent 14 }} - {{- end }} - {{- end }} - initialDelaySeconds: 10 - periodSeconds: 20 - {{- if $.Values.workerTemplate.probe }} - timeoutSeconds: {{ $.Values.workerTemplate.probe.timeoutSeconds }} - {{- else }} - timeoutSeconds: {{ .probe.timeoutSeconds }} - {{- end }} - successThreshold: 1 - {{- end }} - {{- with .dnsConfig | default $.Values.workerTemplate.dnsConfig }} - dnsConfig: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .securityContext | default $.Values.workerTemplate.securityContext }} - securityContext: -{{ toYaml . | indent 8 }} - {{- end }} - volumes: - {{- if .volumes }} -{{ toYaml .volumes | indent 8 }} - {{- end }} - {{- if $.Values.volumes }} -{{ toYaml $.Values.volumes | indent 8 }} - {{- end }} - {{- if $.Values.workerTemplate.volumes }} -{{ toYaml $.Values.workerTemplate.volumes | indent 8 }} - {{- end }} - {{- with .nodeSelector | default $.Values.workerTemplate.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .affinity | default $.Values.workerTemplate.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .tolerations | default $.Values.workerTemplate.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} +{{- include "polymorphic-app.podSpec" (dict "item" . "root" $ "template" $.Values.workerTemplate "type" "worker") | indent 6 }} {{- if .autoscaling | default $.Values.workerTemplate.autoscaling }} --- apiVersion: {{ include "hpa.apiVersion" $ }} kind: HorizontalPodAutoscaler metadata: -{{- if $.Values.prefixWithReleaseName.enabled }} + {{- if $.Values.prefixWithReleaseName.enabled }} name: "{{ $.Release.Name }}-{{ .name | default $.Values.workerTemplate.name }}" -{{- else }} + {{- else }} name: "{{ .name | default $.Values.workerTemplate.name }}" -{{- end }} + {{- end }} labels: {{- include "polymorphic-app.labels" $ | nindent 4 }} app.kubernetes.io/component: "{{ .name | default $.Values.workerTemplate.name }}" @@ -218,6 +64,6 @@ spec: name: cpu target: type: Utilization - averageUtilization: {{ .averageUtilization | default $.Values.serviceTemplate.averageUtilization }} + averageUtilization: {{ .averageUtilization | default $.Values.workerTemplate.averageUtilization }} {{- end }} {{- end }} diff --git a/charts/polymorphic-app/values.yaml b/charts/polymorphic-app/values.yaml index c1a2fc99..a246951e 100644 --- a/charts/polymorphic-app/values.yaml +++ b/charts/polymorphic-app/values.yaml @@ -134,6 +134,62 @@ serviceTemplate: volumeMounts: [] volumes: [] + # Container definitions (required) + # Each service must define a containers array with at least one container + # Each container supports the following fields: + # - name (required): Container name + # - image: Image repository and tag + # - env: Container-specific environment variables + # - envFrom: Environment variables from ConfigMaps/Secrets + # - command: Container command + # - args: Container arguments + # - ports: Container ports + # - resources: CPU and memory resources + # - containerSecurityContext: Security context for the container + # - lifecycleHooks: Lifecycle hooks (postStart, preStop) + # - volumeMounts: Container-specific volume mounts + # - healthcheck: Container-specific health check configuration + containers: [] + # Example: Single container + # - name: main-app + # image: + # repository: nginx + # tag: latest + # ports: + # - name: http + # containerPort: 80 + # protocol: TCP + # healthcheck: + # enabled: true + # type: httpGet + # path: /healthz + # port: 80 + + # Example: Multiple containers + # - name: main-app + # image: + # repository: nginx + # tag: latest + # ports: + # - name: http + # containerPort: 80 + # protocol: TCP + # healthcheck: + # enabled: true + # type: httpGet + # path: /healthz + # port: 80 + # - name: sidecar + # image: + # repository: busybox + # tag: latest + # command: ["/bin/sh"] + # args: ["-c", "while true; do sleep 30; done"] + # resources: + # limits: + # cpu: 50m + # memory: 64Mi + service: enabled: true # className: nginx @@ -237,6 +293,54 @@ workerTemplate: annotations: {} + # Container definitions (required) + # Each worker must define a containers array with at least one container + # Each container supports the following fields: + # - name (required): Container name + # - image: Image repository and tag + # - env: Container-specific environment variables + # - envFrom: Environment variables from ConfigMaps/Secrets + # - command: Container command + # - args: Container arguments + # - ports: Container ports (optional for workers) + # - resources: CPU and memory resources + # - containerSecurityContext: Security context for the container + # - lifecycleHooks: Lifecycle hooks (postStart, preStop) + # - volumeMounts: Container-specific volume mounts + # - healthcheck: Container-specific health check configuration + containers: [] + # Example: Single container worker + # - name: worker + # image: + # repository: my-worker + # tag: latest + # command: ["/app/worker"] + # args: ["--queue", "default"] + # healthcheck: + # enabled: true + # type: exec + # command: + # - /app/health-check + + # Example: Multi-container worker with sidecar + # - name: worker + # image: + # repository: my-worker + # tag: latest + # command: ["/app/worker"] + # resources: + # limits: + # cpu: 500m + # memory: 512Mi + # - name: log-collector + # image: + # repository: busybox + # tag: latest + # command: ["/bin/sh", "-c", "tail -f /var/log/worker.log"] + # volumeMounts: + # - name: logs + # mountPath: /var/log + workers: ####################################### # pulsar-billing-service