From b4ecd6a85e08eabd8760e8c1d57f7e5ee07f0f8a Mon Sep 17 00:00:00 2001 From: Braden Mars Date: Mon, 30 Sep 2024 10:42:56 -0500 Subject: [PATCH 1/7] feat(k8s.construct.api): increase wsgi cpu requests Signed-off-by: Braden Mars --- packages/k8s/construct/api/src/api.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/k8s/construct/api/src/api.ts b/packages/k8s/construct/api/src/api.ts index c1b5eda..51cc58e 100644 --- a/packages/k8s/construct/api/src/api.ts +++ b/packages/k8s/construct/api/src/api.ts @@ -220,8 +220,11 @@ export class ApiWSGI '--timeout=90', ], ...(props.probes ?? this.createHttpProbes(this.httpProbePath)), + // todo: allow config via configs schema resources: { - cpu: this.props.containerDefaults!.resources!.cpu!, + cpu: { + request: kplus.Cpu.millis(900), + }, memory: { request: Size.mebibytes(1200), limit: Size.mebibytes(1200), From 6738e5b9880bc902539a1bb9db7b5f73e7044b4e Mon Sep 17 00:00:00 2001 From: Braden Mars Date: Mon, 30 Sep 2024 10:57:45 -0500 Subject: [PATCH 2/7] feat(k8s.construct.api): adjust asgi/wsgi resource requests/limits Signed-off-by: Braden Mars --- packages/k8s/construct/api/src/api.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/k8s/construct/api/src/api.ts b/packages/k8s/construct/api/src/api.ts index 51cc58e..c18c0ef 100644 --- a/packages/k8s/construct/api/src/api.ts +++ b/packages/k8s/construct/api/src/api.ts @@ -223,7 +223,8 @@ export class ApiWSGI // todo: allow config via configs schema resources: { cpu: { - request: kplus.Cpu.millis(900), + request: kplus.Cpu.millis(1000), + limit: kplus.Cpu.millis(1800), }, memory: { request: Size.mebibytes(1200), @@ -345,6 +346,14 @@ export class ApiASGI user: 1000, group: 1000, }, + resources: { + // todo: properly expose via configs + memory: this.props.containerDefaults!.resources!.memory!, + cpu: { + request: kplus.Cpu.millis(500), + limit: kplus.Cpu.millis(1500), + }, + }, }) // rag channels stateful set @@ -395,7 +404,7 @@ export class ApiASGI }, resources: { cpu: { - limit: kplus.Cpu.units(3), + //limit: kplus.Cpu.units(3), request: kplus.Cpu.millis(200), }, memory: { From ab17c6d494b3c56b6189401a9f98b34091b830cb Mon Sep 17 00:00:00 2001 From: Braden Mars Date: Mon, 30 Sep 2024 10:57:59 -0500 Subject: [PATCH 3/7] test: update snapshots Signed-off-by: Braden Mars --- .../test/__snapshots__/main.spec.ts.snap | 21 +++++++++++-------- .../api/test/__snapshots__/main.spec.ts.snap | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/charts/crisiscleanup/test/__snapshots__/main.spec.ts.snap b/packages/charts/crisiscleanup/test/__snapshots__/main.spec.ts.snap index 3480d0d..74a7eaa 100644 --- a/packages/charts/crisiscleanup/test/__snapshots__/main.spec.ts.snap +++ b/packages/charts/crisiscleanup/test/__snapshots__/main.spec.ts.snap @@ -87,10 +87,11 @@ exports[`CrisisCleanupChart: 'defaults' > api matches snapshot > defaults-api 1` }, "resources": { "limits": { + "cpu": "1800m", "memory": "1200Mi", }, "requests": { - "cpu": "100m", + "cpu": "1000m", "memory": "1200Mi", }, }, @@ -491,10 +492,11 @@ exports[`CrisisCleanupChart: 'defaults' > api matches snapshot > defaults-api 1` }, "resources": { "limits": { + "cpu": "1500m", "memory": "1024Mi", }, "requests": { - "cpu": "100m", + "cpu": "500m", "memory": "1024Mi", }, }, @@ -650,7 +652,6 @@ exports[`CrisisCleanupChart: 'defaults' > api matches snapshot > defaults-api 1` "name": "rag-channels", "resources": { "limits": { - "cpu": "3", "memory": "4096Mi", }, "requests": { @@ -1641,10 +1642,11 @@ exports[`CrisisCleanupChart: 'with spread' > api matches snapshot > with spread- }, "resources": { "limits": { + "cpu": "1800m", "memory": "1200Mi", }, "requests": { - "cpu": "100m", + "cpu": "1000m", "memory": "1200Mi", }, }, @@ -2006,10 +2008,11 @@ exports[`CrisisCleanupChart: 'with spread' > api matches snapshot > with spread- }, "resources": { "limits": { + "cpu": "1500m", "memory": "1024Mi", }, "requests": { - "cpu": "100m", + "cpu": "500m", "memory": "1024Mi", }, }, @@ -2177,7 +2180,6 @@ exports[`CrisisCleanupChart: 'with spread' > api matches snapshot > with spread- "name": "rag-channels", "resources": { "limits": { - "cpu": "3", "memory": "4096Mi", }, "requests": { @@ -3115,10 +3117,11 @@ exports[`CrisisCleanupChart: 'with sync' > api matches snapshot > with sync-api }, "resources": { "limits": { + "cpu": "1800m", "memory": "1200Mi", }, "requests": { - "cpu": "100m", + "cpu": "1000m", "memory": "1200Mi", }, }, @@ -3519,10 +3522,11 @@ exports[`CrisisCleanupChart: 'with sync' > api matches snapshot > with sync-api }, "resources": { "limits": { + "cpu": "1500m", "memory": "1024Mi", }, "requests": { - "cpu": "100m", + "cpu": "500m", "memory": "1024Mi", }, }, @@ -3678,7 +3682,6 @@ exports[`CrisisCleanupChart: 'with sync' > api matches snapshot > with sync-api "name": "rag-channels", "resources": { "limits": { - "cpu": "3", "memory": "4096Mi", }, "requests": { diff --git a/packages/stacks/api/test/__snapshots__/main.spec.ts.snap b/packages/stacks/api/test/__snapshots__/main.spec.ts.snap index 08bb6a6..dccddc5 100644 --- a/packages/stacks/api/test/__snapshots__/main.spec.ts.snap +++ b/packages/stacks/api/test/__snapshots__/main.spec.ts.snap @@ -1283,7 +1283,7 @@ exports[`Snapshot 1`] = ` "ClusterName": { "Ref": "teststackF0A1F222", }, - "Manifest": "[{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/name\\":\\"wsgi\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"minReadySeconds\\":0,\\"progressDeadlineSeconds\\":600,\\"selector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-c83e828d\\"}},\\"strategy\\":{\\"rollingUpdate\\":{\\"maxSurge\\":\\"25%\\",\\"maxUnavailable\\":\\"25%\\"},\\"type\\":\\"RollingUpdate\\"},\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-c83e828d\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"/serve.sh\\",\\"wsgi\\",\\"--workers=2\\",\\"--threads=4\\",\\"--worker-class=gthread\\",\\"--worker-tmp-dir=/worker-tmp\\",\\"--timeout=90\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"livenessProbe\\":{\\"failureThreshold\\":6,\\"httpGet\\":{\\"path\\":\\"/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"initialDelaySeconds\\":20,\\"periodSeconds\\":10,\\"timeoutSeconds\\":6},\\"name\\":\\"gunicorn\\",\\"ports\\":[{\\"containerPort\\":5000}],\\"readinessProbe\\":{\\"failureThreshold\\":6,\\"httpGet\\":{\\"path\\":\\"/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"initialDelaySeconds\\":20,\\"periodSeconds\\":10,\\"timeoutSeconds\\":6},\\"resources\\":{\\"limits\\":{\\"memory\\":\\"1200Mi\\"},\\"requests\\":{\\"cpu\\":\\"100m\\",\\"memory\\":\\"1200Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"startupProbe\\":{\\"failureThreshold\\":30,\\"httpGet\\":{\\"path\\":\\"/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"periodSeconds\\":15},\\"volumeMounts\\":[{\\"mountPath\\":\\"/app/staticfiles\\",\\"name\\":\\"staticfiles\\"},{\\"mountPath\\":\\"/worker-tmp\\",\\"name\\":\\"worker-tmp\\"},{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Always\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsNonRoot\\":true},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":30,\\"volumes\\":[{\\"emptyDir\\":{},\\"name\\":\\"staticfiles\\"},{\\"emptyDir\\":{\\"medium\\":\\"Memory\\"},\\"name\\":\\"worker-tmp\\"},{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}}}},{\\"apiVersion\\":\\"batch/v1\\",\\"kind\\":\\"Job\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi-migrate\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"activeDeadlineSeconds\\":1800,\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-migrate-c8890c80\\",\\"component\\":\\"api-migrate\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"python\\",\\"manage.py\\",\\"migrate\\",\\"--noinput\\",\\"--verbosity=1\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"migrate\\",\\"resources\\":{\\"limits\\":{\\"memory\\":\\"3072Mi\\"},\\"requests\\":{\\"cpu\\":\\"100m\\",\\"memory\\":\\"1024Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"volumeMounts\\":[{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Never\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":300,\\"volumes\\":[{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}},\\"ttlSecondsAfterFinished\\":120}},{\\"apiVersion\\":\\"batch/v1\\",\\"kind\\":\\"Job\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi-collectstatic\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"activeDeadlineSeconds\\":1800,\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-collectstatic-c871685d\\",\\"component\\":\\"api-static\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"python\\",\\"manage.py\\",\\"collectstatic\\",\\"--no-post-process\\",\\"--noinput\\",\\"--verbosity=2\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"collectstatic\\",\\"resources\\":{\\"limits\\":{\\"memory\\":\\"3072Mi\\"},\\"requests\\":{\\"cpu\\":\\"100m\\",\\"memory\\":\\"1024Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"volumeMounts\\":[{\\"mountPath\\":\\"/app/staticfiles\\",\\"name\\":\\"staticfiles\\"},{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Never\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":300,\\"volumes\\":[{\\"emptyDir\\":{},\\"name\\":\\"staticfiles\\"},{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}},\\"ttlSecondsAfterFinished\\":120}},{\\"apiVersion\\":\\"v1\\",\\"kind\\":\\"Service\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi-service\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"externalIPs\\":[],\\"ports\\":[{\\"port\\":5000,\\"targetPort\\":5000}],\\"selector\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-c83e828d\\"},\\"type\\":\\"ClusterIP\\"}},{\\"apiVersion\\":\\"autoscaling/v2\\",\\"kind\\":\\"HorizontalPodAutoscaler\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi-hpa\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"behavior\\":{\\"scaleDown\\":{\\"policies\\":[{\\"periodSeconds\\":300,\\"type\\":\\"Pods\\",\\"value\\":1}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":300},\\"scaleUp\\":{\\"policies\\":[{\\"periodSeconds\\":60,\\"type\\":\\"Pods\\",\\"value\\":4},{\\"periodSeconds\\":60,\\"type\\":\\"Percent\\",\\"value\\":200}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":0}},\\"maxReplicas\\":3,\\"metrics\\":[{\\"resource\\":{\\"name\\":\\"cpu\\",\\"target\\":{\\"averageUtilization\\":70,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"},{\\"resource\\":{\\"name\\":\\"memory\\",\\"target\\":{\\"averageUtilization\\":85,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"}],\\"minReplicas\\":1,\\"scaleTargetRef\\":{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"name\\":\\"crisiscleanup-api-wsgi\\"}}},{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/name\\":\\"asgi\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"minReadySeconds\\":0,\\"progressDeadlineSeconds\\":600,\\"selector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-c818ff7e\\"}},\\"strategy\\":{\\"rollingUpdate\\":{\\"maxSurge\\":\\"25%\\",\\"maxUnavailable\\":\\"25%\\"},\\"type\\":\\"RollingUpdate\\"},\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-c818ff7e\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"/serve.sh\\",\\"asgi\\",\\"--workers=2\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"livenessProbe\\":{\\"failureThreshold\\":6,\\"httpGet\\":{\\"path\\":\\"/ws/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"initialDelaySeconds\\":20,\\"periodSeconds\\":10,\\"timeoutSeconds\\":6},\\"name\\":\\"hypercorn\\",\\"ports\\":[{\\"containerPort\\":5000}],\\"readinessProbe\\":{\\"failureThreshold\\":6,\\"httpGet\\":{\\"path\\":\\"/ws/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"initialDelaySeconds\\":20,\\"periodSeconds\\":10,\\"timeoutSeconds\\":6},\\"resources\\":{\\"limits\\":{\\"memory\\":\\"1024Mi\\"},\\"requests\\":{\\"cpu\\":\\"100m\\",\\"memory\\":\\"1024Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"startupProbe\\":{\\"failureThreshold\\":30,\\"httpGet\\":{\\"path\\":\\"/ws/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"periodSeconds\\":15},\\"volumeMounts\\":[{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Always\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsNonRoot\\":true},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":30,\\"volumes\\":[{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}}}},{\\"apiVersion\\":\\"storage.k8s.io/v1\\",\\"kind\\":\\"StorageClass\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"rag-models\\",\\"namespace\\":\\"local\\"},\\"parameters\\":{\\"allowAutoIOPSPerGBIncrease\\":\\"true\\",\\"iops\\":\\"1000\\",\\"type\\":\\"io2\\"},\\"provisioner\\":\\"ebs.csi.aws.com\\",\\"volumeBindingMode\\":\\"WaitForFirstConsumer\\"},{\\"apiVersion\\":\\"v1\\",\\"kind\\":\\"Service\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-asgi-rag-service\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"clusterIP\\":\\"None\\",\\"externalIPs\\":[],\\"ports\\":[{\\"name\\":\\"channels\\",\\"port\\":5000}],\\"selector\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"},\\"type\\":\\"ClusterIP\\"}},{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"StatefulSet\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-rag\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"minReadySeconds\\":0,\\"podManagementPolicy\\":\\"OrderedReady\\",\\"selector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"}},\\"serviceName\\":\\"crisiscleanup-api-asgi-asgi-rag-service\\",\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"}},\\"spec\\":{\\"affinity\\":{\\"podAntiAffinity\\":{\\"requiredDuringSchedulingIgnoredDuringExecution\\":[{\\"labelSelector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"}},\\"namespaces\\":[\\"local\\"],\\"topologyKey\\":\\"kubernetes.io/hostname\\"},{\\"labelSelector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"}},\\"namespaces\\":[\\"local\\"],\\"topologyKey\\":\\"topology.kubernetes.io/zone\\"}]}},\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"/serve.sh\\",\\"channelsworker\\",\\"rag-document\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"rag-channels\\",\\"resources\\":{\\"limits\\":{\\"cpu\\":\\"3\\",\\"memory\\":\\"4096Mi\\"},\\"requests\\":{\\"cpu\\":\\"200m\\",\\"memory\\":\\"1024Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"volumeMounts\\":[{\\"mountPath\\":\\"/ccu/nltk_data\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"nltk_data\\"},{\\"mountPath\\":\\"/ccu/.cache/huggingface\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"hf_data\\"},{\\"mountPath\\":\\"/ccu/.cache/matplotlib\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"mp_data\\"}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"initContainers\\":[{\\"command\\":[\\"sh\\",\\"-x\\",\\"-c\\",\\"mkdir -p /ccu && chown -R 1000:1000 /ccu\\"],\\"image\\":\\"public.ecr.aws/docker/library/busybox:stable\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"host-mounts-init\\",\\"resources\\":{\\"limits\\":{\\"cpu\\":\\"30m\\",\\"memory\\":\\"50Mi\\"},\\"requests\\":{\\"cpu\\":\\"20m\\",\\"memory\\":\\"20Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":0,\\"runAsNonRoot\\":false,\\"runAsUser\\":0},\\"volumeMounts\\":[{\\"mountPath\\":\\"/ccu/nltk_data\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"nltk_data\\"},{\\"mountPath\\":\\"/ccu/.cache/huggingface\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"hf_data\\"},{\\"mountPath\\":\\"/ccu/.cache/matplotlib\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"mp_data\\"}]}],\\"restartPolicy\\":\\"Always\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsNonRoot\\":true},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":30,\\"volumes\\":[{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}},\\"updateStrategy\\":{\\"rollingUpdate\\":{\\"partition\\":0},\\"type\\":\\"RollingUpdate\\"},\\"volumeClaimTemplates\\":[{\\"metadata\\":{\\"name\\":\\"rag-volume\\"},\\"spec\\":{\\"accessModes\\":[\\"ReadWriteOnce\\"],\\"storageClassName\\":\\"rag-models\\",\\"resources\\":{\\"requests\\":{\\"storage\\":\\"10Gi\\"}}}}]}},{\\"apiVersion\\":\\"autoscaling/v2\\",\\"kind\\":\\"HorizontalPodAutoscaler\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-rag-scaling-hpa\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"behavior\\":{\\"scaleDown\\":{\\"policies\\":[{\\"periodSeconds\\":300,\\"type\\":\\"Pods\\",\\"value\\":1}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":300},\\"scaleUp\\":{\\"policies\\":[{\\"periodSeconds\\":60,\\"type\\":\\"Pods\\",\\"value\\":4},{\\"periodSeconds\\":60,\\"type\\":\\"Percent\\",\\"value\\":200}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":0}},\\"maxReplicas\\":6,\\"metrics\\":[{\\"resource\\":{\\"name\\":\\"cpu\\",\\"target\\":{\\"averageUtilization\\":50,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"},{\\"resource\\":{\\"name\\":\\"memory\\",\\"target\\":{\\"averageUtilization\\":80,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"}],\\"minReplicas\\":1,\\"scaleTargetRef\\":{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"StatefulSet\\",\\"name\\":\\"crisiscleanup-api-asgi-rag\\"}}},{\\"apiVersion\\":\\"v1\\",\\"kind\\":\\"Service\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-service\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"externalIPs\\":[],\\"ports\\":[{\\"port\\":5000,\\"targetPort\\":5000}],\\"selector\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-c818ff7e\\"},\\"type\\":\\"ClusterIP\\"}},{\\"apiVersion\\":\\"autoscaling/v2\\",\\"kind\\":\\"HorizontalPodAutoscaler\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-hpa\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"behavior\\":{\\"scaleDown\\":{\\"policies\\":[{\\"periodSeconds\\":300,\\"type\\":\\"Pods\\",\\"value\\":1}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":300},\\"scaleUp\\":{\\"policies\\":[{\\"periodSeconds\\":60,\\"type\\":\\"Pods\\",\\"value\\":4},{\\"periodSeconds\\":60,\\"type\\":\\"Percent\\",\\"value\\":200}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":0}},\\"maxReplicas\\":2,\\"metrics\\":[{\\"resource\\":{\\"name\\":\\"cpu\\",\\"target\\":{\\"averageUtilization\\":70,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"},{\\"resource\\":{\\"name\\":\\"memory\\",\\"target\\":{\\"averageUtilization\\":85,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"}],\\"minReplicas\\":1,\\"scaleTargetRef\\":{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"name\\":\\"crisiscleanup-api-asgi\\"}}},{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/name\\":\\"adminwebsocket\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-admin-websocket\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"minReadySeconds\\":0,\\"progressDeadlineSeconds\\":600,\\"replicas\\":1,\\"selector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-admin-websocket-c879d9e4\\"}},\\"strategy\\":{\\"rollingUpdate\\":{\\"maxSurge\\":\\"25%\\",\\"maxUnavailable\\":\\"25%\\"},\\"type\\":\\"RollingUpdate\\"},\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-admin-websocket-c879d9e4\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"/serve.sh\\",\\"adminwebsocket\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"adminwebsocket\\",\\"resources\\":{\\"limits\\":{\\"memory\\":\\"250Mi\\"},\\"requests\\":{\\"cpu\\":\\"3m\\",\\"memory\\":\\"250Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"volumeMounts\\":[{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Always\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsNonRoot\\":true},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":30,\\"volumes\\":[{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}}}}]", + "Manifest": "[{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/name\\":\\"wsgi\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"minReadySeconds\\":0,\\"progressDeadlineSeconds\\":600,\\"selector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-c83e828d\\"}},\\"strategy\\":{\\"rollingUpdate\\":{\\"maxSurge\\":\\"25%\\",\\"maxUnavailable\\":\\"25%\\"},\\"type\\":\\"RollingUpdate\\"},\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-c83e828d\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"/serve.sh\\",\\"wsgi\\",\\"--workers=2\\",\\"--threads=4\\",\\"--worker-class=gthread\\",\\"--worker-tmp-dir=/worker-tmp\\",\\"--timeout=90\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"livenessProbe\\":{\\"failureThreshold\\":6,\\"httpGet\\":{\\"path\\":\\"/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"initialDelaySeconds\\":20,\\"periodSeconds\\":10,\\"timeoutSeconds\\":6},\\"name\\":\\"gunicorn\\",\\"ports\\":[{\\"containerPort\\":5000}],\\"readinessProbe\\":{\\"failureThreshold\\":6,\\"httpGet\\":{\\"path\\":\\"/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"initialDelaySeconds\\":20,\\"periodSeconds\\":10,\\"timeoutSeconds\\":6},\\"resources\\":{\\"limits\\":{\\"cpu\\":\\"1800m\\",\\"memory\\":\\"1200Mi\\"},\\"requests\\":{\\"cpu\\":\\"1000m\\",\\"memory\\":\\"1200Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"startupProbe\\":{\\"failureThreshold\\":30,\\"httpGet\\":{\\"path\\":\\"/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"periodSeconds\\":15},\\"volumeMounts\\":[{\\"mountPath\\":\\"/app/staticfiles\\",\\"name\\":\\"staticfiles\\"},{\\"mountPath\\":\\"/worker-tmp\\",\\"name\\":\\"worker-tmp\\"},{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Always\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsNonRoot\\":true},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":30,\\"volumes\\":[{\\"emptyDir\\":{},\\"name\\":\\"staticfiles\\"},{\\"emptyDir\\":{\\"medium\\":\\"Memory\\"},\\"name\\":\\"worker-tmp\\"},{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}}}},{\\"apiVersion\\":\\"batch/v1\\",\\"kind\\":\\"Job\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi-migrate\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"activeDeadlineSeconds\\":1800,\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-migrate-c8890c80\\",\\"component\\":\\"api-migrate\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"python\\",\\"manage.py\\",\\"migrate\\",\\"--noinput\\",\\"--verbosity=1\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"migrate\\",\\"resources\\":{\\"limits\\":{\\"memory\\":\\"3072Mi\\"},\\"requests\\":{\\"cpu\\":\\"100m\\",\\"memory\\":\\"1024Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"volumeMounts\\":[{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Never\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":300,\\"volumes\\":[{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}},\\"ttlSecondsAfterFinished\\":120}},{\\"apiVersion\\":\\"batch/v1\\",\\"kind\\":\\"Job\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi-collectstatic\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"activeDeadlineSeconds\\":1800,\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-collectstatic-c871685d\\",\\"component\\":\\"api-static\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"python\\",\\"manage.py\\",\\"collectstatic\\",\\"--no-post-process\\",\\"--noinput\\",\\"--verbosity=2\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"collectstatic\\",\\"resources\\":{\\"limits\\":{\\"memory\\":\\"3072Mi\\"},\\"requests\\":{\\"cpu\\":\\"100m\\",\\"memory\\":\\"1024Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"volumeMounts\\":[{\\"mountPath\\":\\"/app/staticfiles\\",\\"name\\":\\"staticfiles\\"},{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Never\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":300,\\"volumes\\":[{\\"emptyDir\\":{},\\"name\\":\\"staticfiles\\"},{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}},\\"ttlSecondsAfterFinished\\":120}},{\\"apiVersion\\":\\"v1\\",\\"kind\\":\\"Service\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi-service\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"externalIPs\\":[],\\"ports\\":[{\\"port\\":5000,\\"targetPort\\":5000}],\\"selector\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-wsgi-c83e828d\\"},\\"type\\":\\"ClusterIP\\"}},{\\"apiVersion\\":\\"autoscaling/v2\\",\\"kind\\":\\"HorizontalPodAutoscaler\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-wsgi-hpa\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"behavior\\":{\\"scaleDown\\":{\\"policies\\":[{\\"periodSeconds\\":300,\\"type\\":\\"Pods\\",\\"value\\":1}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":300},\\"scaleUp\\":{\\"policies\\":[{\\"periodSeconds\\":60,\\"type\\":\\"Pods\\",\\"value\\":4},{\\"periodSeconds\\":60,\\"type\\":\\"Percent\\",\\"value\\":200}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":0}},\\"maxReplicas\\":3,\\"metrics\\":[{\\"resource\\":{\\"name\\":\\"cpu\\",\\"target\\":{\\"averageUtilization\\":70,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"},{\\"resource\\":{\\"name\\":\\"memory\\",\\"target\\":{\\"averageUtilization\\":85,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"}],\\"minReplicas\\":1,\\"scaleTargetRef\\":{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"name\\":\\"crisiscleanup-api-wsgi\\"}}},{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/name\\":\\"asgi\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"minReadySeconds\\":0,\\"progressDeadlineSeconds\\":600,\\"selector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-c818ff7e\\"}},\\"strategy\\":{\\"rollingUpdate\\":{\\"maxSurge\\":\\"25%\\",\\"maxUnavailable\\":\\"25%\\"},\\"type\\":\\"RollingUpdate\\"},\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-c818ff7e\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"/serve.sh\\",\\"asgi\\",\\"--workers=2\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"livenessProbe\\":{\\"failureThreshold\\":6,\\"httpGet\\":{\\"path\\":\\"/ws/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"initialDelaySeconds\\":20,\\"periodSeconds\\":10,\\"timeoutSeconds\\":6},\\"name\\":\\"hypercorn\\",\\"ports\\":[{\\"containerPort\\":5000}],\\"readinessProbe\\":{\\"failureThreshold\\":6,\\"httpGet\\":{\\"path\\":\\"/ws/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"initialDelaySeconds\\":20,\\"periodSeconds\\":10,\\"timeoutSeconds\\":6},\\"resources\\":{\\"limits\\":{\\"cpu\\":\\"1500m\\",\\"memory\\":\\"1024Mi\\"},\\"requests\\":{\\"cpu\\":\\"500m\\",\\"memory\\":\\"1024Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"startupProbe\\":{\\"failureThreshold\\":30,\\"httpGet\\":{\\"path\\":\\"/ws/health\\",\\"port\\":5000,\\"scheme\\":\\"HTTP\\"},\\"periodSeconds\\":15},\\"volumeMounts\\":[{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Always\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsNonRoot\\":true},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":30,\\"volumes\\":[{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}}}},{\\"apiVersion\\":\\"storage.k8s.io/v1\\",\\"kind\\":\\"StorageClass\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"rag-models\\",\\"namespace\\":\\"local\\"},\\"parameters\\":{\\"allowAutoIOPSPerGBIncrease\\":\\"true\\",\\"iops\\":\\"1000\\",\\"type\\":\\"io2\\"},\\"provisioner\\":\\"ebs.csi.aws.com\\",\\"volumeBindingMode\\":\\"WaitForFirstConsumer\\"},{\\"apiVersion\\":\\"v1\\",\\"kind\\":\\"Service\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-asgi-rag-service\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"clusterIP\\":\\"None\\",\\"externalIPs\\":[],\\"ports\\":[{\\"name\\":\\"channels\\",\\"port\\":5000}],\\"selector\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"},\\"type\\":\\"ClusterIP\\"}},{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"StatefulSet\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-rag\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"minReadySeconds\\":0,\\"podManagementPolicy\\":\\"OrderedReady\\",\\"selector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"}},\\"serviceName\\":\\"crisiscleanup-api-asgi-asgi-rag-service\\",\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"}},\\"spec\\":{\\"affinity\\":{\\"podAntiAffinity\\":{\\"requiredDuringSchedulingIgnoredDuringExecution\\":[{\\"labelSelector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"}},\\"namespaces\\":[\\"local\\"],\\"topologyKey\\":\\"kubernetes.io/hostname\\"},{\\"labelSelector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-rag-c86cf6a6\\"}},\\"namespaces\\":[\\"local\\"],\\"topologyKey\\":\\"topology.kubernetes.io/zone\\"}]}},\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"/serve.sh\\",\\"channelsworker\\",\\"rag-document\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"rag-channels\\",\\"resources\\":{\\"limits\\":{\\"memory\\":\\"4096Mi\\"},\\"requests\\":{\\"cpu\\":\\"200m\\",\\"memory\\":\\"1024Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"volumeMounts\\":[{\\"mountPath\\":\\"/ccu/nltk_data\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"nltk_data\\"},{\\"mountPath\\":\\"/ccu/.cache/huggingface\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"hf_data\\"},{\\"mountPath\\":\\"/ccu/.cache/matplotlib\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"mp_data\\"}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"initContainers\\":[{\\"command\\":[\\"sh\\",\\"-x\\",\\"-c\\",\\"mkdir -p /ccu && chown -R 1000:1000 /ccu\\"],\\"image\\":\\"public.ecr.aws/docker/library/busybox:stable\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"host-mounts-init\\",\\"resources\\":{\\"limits\\":{\\"cpu\\":\\"30m\\",\\"memory\\":\\"50Mi\\"},\\"requests\\":{\\"cpu\\":\\"20m\\",\\"memory\\":\\"20Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":0,\\"runAsNonRoot\\":false,\\"runAsUser\\":0},\\"volumeMounts\\":[{\\"mountPath\\":\\"/ccu/nltk_data\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"nltk_data\\"},{\\"mountPath\\":\\"/ccu/.cache/huggingface\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"hf_data\\"},{\\"mountPath\\":\\"/ccu/.cache/matplotlib\\",\\"name\\":\\"rag-volume\\",\\"subPath\\":\\"mp_data\\"}]}],\\"restartPolicy\\":\\"Always\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsNonRoot\\":true},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":30,\\"volumes\\":[{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}},\\"updateStrategy\\":{\\"rollingUpdate\\":{\\"partition\\":0},\\"type\\":\\"RollingUpdate\\"},\\"volumeClaimTemplates\\":[{\\"metadata\\":{\\"name\\":\\"rag-volume\\"},\\"spec\\":{\\"accessModes\\":[\\"ReadWriteOnce\\"],\\"storageClassName\\":\\"rag-models\\",\\"resources\\":{\\"requests\\":{\\"storage\\":\\"10Gi\\"}}}}]}},{\\"apiVersion\\":\\"autoscaling/v2\\",\\"kind\\":\\"HorizontalPodAutoscaler\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-rag-scaling-hpa\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"behavior\\":{\\"scaleDown\\":{\\"policies\\":[{\\"periodSeconds\\":300,\\"type\\":\\"Pods\\",\\"value\\":1}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":300},\\"scaleUp\\":{\\"policies\\":[{\\"periodSeconds\\":60,\\"type\\":\\"Pods\\",\\"value\\":4},{\\"periodSeconds\\":60,\\"type\\":\\"Percent\\",\\"value\\":200}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":0}},\\"maxReplicas\\":6,\\"metrics\\":[{\\"resource\\":{\\"name\\":\\"cpu\\",\\"target\\":{\\"averageUtilization\\":50,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"},{\\"resource\\":{\\"name\\":\\"memory\\",\\"target\\":{\\"averageUtilization\\":80,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"}],\\"minReplicas\\":1,\\"scaleTargetRef\\":{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"StatefulSet\\",\\"name\\":\\"crisiscleanup-api-asgi-rag\\"}}},{\\"apiVersion\\":\\"v1\\",\\"kind\\":\\"Service\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-service\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"externalIPs\\":[],\\"ports\\":[{\\"port\\":5000,\\"targetPort\\":5000}],\\"selector\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-asgi-c818ff7e\\"},\\"type\\":\\"ClusterIP\\"}},{\\"apiVersion\\":\\"autoscaling/v2\\",\\"kind\\":\\"HorizontalPodAutoscaler\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-asgi-hpa\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"behavior\\":{\\"scaleDown\\":{\\"policies\\":[{\\"periodSeconds\\":300,\\"type\\":\\"Pods\\",\\"value\\":1}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":300},\\"scaleUp\\":{\\"policies\\":[{\\"periodSeconds\\":60,\\"type\\":\\"Pods\\",\\"value\\":4},{\\"periodSeconds\\":60,\\"type\\":\\"Percent\\",\\"value\\":200}],\\"selectPolicy\\":\\"Max\\",\\"stabilizationWindowSeconds\\":0}},\\"maxReplicas\\":2,\\"metrics\\":[{\\"resource\\":{\\"name\\":\\"cpu\\",\\"target\\":{\\"averageUtilization\\":70,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"},{\\"resource\\":{\\"name\\":\\"memory\\",\\"target\\":{\\"averageUtilization\\":85,\\"type\\":\\"Utilization\\"}},\\"type\\":\\"Resource\\"}],\\"minReplicas\\":1,\\"scaleTargetRef\\":{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"name\\":\\"crisiscleanup-api-asgi\\"}}},{\\"apiVersion\\":\\"apps/v1\\",\\"kind\\":\\"Deployment\\",\\"metadata\\":{\\"labels\\":{\\"aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b\\":\\"\\",\\"app.kubernetes.io/component\\":\\"api\\",\\"app.kubernetes.io/name\\":\\"adminwebsocket\\",\\"app.kubernetes.io/part-of\\":\\"crisiscleanup\\"},\\"name\\":\\"crisiscleanup-api-admin-websocket\\",\\"namespace\\":\\"local\\"},\\"spec\\":{\\"minReadySeconds\\":0,\\"progressDeadlineSeconds\\":600,\\"replicas\\":1,\\"selector\\":{\\"matchLabels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-admin-websocket-c879d9e4\\"}},\\"strategy\\":{\\"rollingUpdate\\":{\\"maxSurge\\":\\"25%\\",\\"maxUnavailable\\":\\"25%\\"},\\"type\\":\\"RollingUpdate\\"},\\"template\\":{\\"metadata\\":{\\"labels\\":{\\"cdk8s.io/metadata.addr\\":\\"crisiscleanup-api-admin-websocket-c879d9e4\\"}},\\"spec\\":{\\"automountServiceAccountToken\\":false,\\"containers\\":[{\\"command\\":[\\"/serve.sh\\",\\"adminwebsocket\\"],\\"env\\":[{\\"name\\":\\"POSTGRES_USER\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_USER\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_PASSWORD\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_PASSWORD\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}},{\\"name\\":\\"POSTGRES_HOST\\",\\"valueFrom\\":{\\"secretKeyRef\\":{\\"key\\":\\"POSTGRES_HOST\\",\\"name\\":\\"crisiscleanup-db-secrets\\"}}}],\\"envFrom\\":[{\\"configMapRef\\":{\\"name\\":\\"crisiscleanup-config-api-config\\"}}],\\"image\\":\\"crisiscleanup-api:latest\\",\\"imagePullPolicy\\":\\"IfNotPresent\\",\\"name\\":\\"adminwebsocket\\",\\"resources\\":{\\"limits\\":{\\"memory\\":\\"250Mi\\"},\\"requests\\":{\\"cpu\\":\\"3m\\",\\"memory\\":\\"250Mi\\"}},\\"securityContext\\":{\\"allowPrivilegeEscalation\\":false,\\"privileged\\":false,\\"readOnlyRootFilesystem\\":false,\\"runAsGroup\\":1000,\\"runAsNonRoot\\":true,\\"runAsUser\\":1000},\\"volumeMounts\\":[{\\"mountPath\\":\\"/mnt/secrets-store\\",\\"name\\":\\"secrets-store-inline\\",\\"readOnly\\":true}]}],\\"dnsPolicy\\":\\"ClusterFirst\\",\\"hostNetwork\\":false,\\"restartPolicy\\":\\"Always\\",\\"securityContext\\":{\\"fsGroupChangePolicy\\":\\"Always\\",\\"runAsNonRoot\\":true},\\"serviceAccountName\\":\\"crisiscleanup-api\\",\\"setHostnameAsFQDN\\":false,\\"terminationGracePeriodSeconds\\":30,\\"volumes\\":[{\\"csi\\":{\\"driver\\":\\"secrets-store.csi.k8s.io\\",\\"readOnly\\":true,\\"volumeAttributes\\":{\\"secretProviderClass\\":\\"crisiscleanup-api\\"}},\\"name\\":\\"secrets-store-inline\\"}]}}}}]", "PruneLabel": "aws.cdk.eks/prune-c82f78fa5f1261be46ff61475603c88ab5fa680f3b", "RoleArn": { "Fn::GetAtt": [ From b870e562388cc7fae57f6c73caad300081007723 Mon Sep 17 00:00:00 2001 From: Braden Mars Date: Mon, 30 Sep 2024 12:35:58 -0500 Subject: [PATCH 4/7] feat(charts.crisiscleanup): implement `resources` schema into deployment schema Signed-off-by: Braden Mars --- packages/charts/crisiscleanup/src/schema.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/charts/crisiscleanup/src/schema.ts b/packages/charts/crisiscleanup/src/schema.ts index 640982b..8f3b378 100644 --- a/packages/charts/crisiscleanup/src/schema.ts +++ b/packages/charts/crisiscleanup/src/schema.ts @@ -12,6 +12,23 @@ const containerImageSchema = z const metricPercent = z.number().min(0).max(100) +const K8sMillicores = z.number().describe('Kubernetes CPU Millicores') +const K8sMemoryMebibytes = z.number().describe('Kubernetes Memory Mebibytes') + +const resourcesSchema = z + .object({ + cpu: z.object({ + limit: K8sMillicores.optional(), + request: K8sMillicores.optional(), + }), + memory: z.object({ + limit: K8sMemoryMebibytes.optional(), + request: K8sMemoryMebibytes.optional(), + }), + }) + .describe('Kubernetes resource limits/requests') + .deepPartial() + const scalingSchema = z .object({ minReplicas: z.number().optional(), @@ -32,6 +49,7 @@ const scalingSchema = z const deploymentSchema = z.object({ image: containerImageSchema.optional(), spread: z.boolean().default(false), + resources: resourcesSchema.optional(), }) const withScaling = (inSchema: T) => From 578116dc5569edb9a529a079edde2d6fa6aa8d6a Mon Sep 17 00:00:00 2001 From: Braden Mars Date: Mon, 30 Sep 2024 12:36:37 -0500 Subject: [PATCH 5/7] feat(k8s.construct.component): add zod dependency Signed-off-by: Braden Mars --- .projenrc.ts | 2 +- packages/k8s/construct/component/.projen/deps.json | 4 ++++ packages/k8s/construct/component/.projen/tasks.json | 4 ++-- packages/k8s/construct/component/package.json | 3 ++- pnpm-lock.yaml | 11 +++++++---- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.projenrc.ts b/.projenrc.ts index ad3adc7..635c03b 100644 --- a/.projenrc.ts +++ b/.projenrc.ts @@ -365,7 +365,7 @@ const Cdk8sConstructBuilder = new ProjectBuilder(cdk8s.ConstructLibraryCdk8s) // K8s Constructs const k8sComponentConstruct = Cdk8sConstructBuilder.build({ name: 'k8s.construct.component', - deps: ['debug', 'defu', 'js-yaml'], + deps: ['debug', 'defu', 'js-yaml', 'zod'], devDeps: ['@types/debug'], jest: false, }) diff --git a/packages/k8s/construct/component/.projen/deps.json b/packages/k8s/construct/component/.projen/deps.json index 7c85a68..fce0efe 100644 --- a/packages/k8s/construct/component/.projen/deps.json +++ b/packages/k8s/construct/component/.projen/deps.json @@ -113,6 +113,10 @@ { "name": "js-yaml", "type": "runtime" + }, + { + "name": "zod", + "type": "runtime" } ], "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." diff --git a/packages/k8s/construct/component/.projen/tasks.json b/packages/k8s/construct/component/.projen/tasks.json index 2414573..2f2e2d7 100644 --- a/packages/k8s/construct/component/.projen/tasks.json +++ b/packages/k8s/construct/component/.projen/tasks.json @@ -163,13 +163,13 @@ }, "steps": [ { - "exec": "pnpm dlx npm-check-updates@16 --upgrade --target=minor --peer --dep=dev,peer,prod,optional --filter=@arroyodev-llc/utils.unbuild-composite-preset,@types/debug,cdk8s-plus-27,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-prettier,jsii-diff,jsii-docgen,jsii-pacmak,lint-staged,prettier,unbuild,debug,defu,js-yaml" + "exec": "pnpm dlx npm-check-updates@16 --upgrade --target=minor --peer --dep=dev,peer,prod,optional --filter=@arroyodev-llc/utils.unbuild-composite-preset,@types/debug,cdk8s-plus-27,eslint-config-prettier,eslint-import-resolver-typescript,eslint-plugin-import,eslint-plugin-prettier,jsii-diff,jsii-docgen,jsii-pacmak,lint-staged,prettier,unbuild,debug,defu,js-yaml,zod" }, { "exec": "pnpm i --no-frozen-lockfile" }, { - "exec": "pnpm update @arroyodev-llc/utils.unbuild-composite-preset @types/debug @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser cdk8s-plus-27 eslint-config-prettier eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-prettier eslint jsii-diff jsii-docgen jsii-pacmak jsii-rosetta jsii lint-staged prettier typescript unbuild cdk8s constructs debug defu js-yaml" + "exec": "pnpm update @arroyodev-llc/utils.unbuild-composite-preset @types/debug @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser cdk8s-plus-27 eslint-config-prettier eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-prettier eslint jsii-diff jsii-docgen jsii-pacmak jsii-rosetta jsii lint-staged prettier typescript unbuild cdk8s constructs debug defu js-yaml zod" }, { "exec": "npx projen" diff --git a/packages/k8s/construct/component/package.json b/packages/k8s/construct/component/package.json index 0910041..f29f0b5 100644 --- a/packages/k8s/construct/component/package.json +++ b/packages/k8s/construct/component/package.json @@ -59,7 +59,8 @@ "dependencies": { "debug": "^4.3.4", "defu": "^6.1.2", - "js-yaml": "^4.1.0" + "js-yaml": "^4.1.0", + "zod": "^3.23.8" }, "keywords": [ "cdk" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ebe4cb..9c58df4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -669,6 +669,9 @@ importers: js-yaml: specifier: ^4.1.0 version: 4.1.0 + zod: + specifier: ^3.23.8 + version: 3.23.8 devDependencies: '@arroyodev-llc/utils.unbuild-composite-preset': specifier: ^0.1.6 @@ -11791,10 +11794,10 @@ packages: engines: { node: '>=14.17' } hasBin: true - typescript@5.7.0-dev.20240927: + typescript@5.7.0-dev.20240930: resolution: { - integrity: sha512-IWKZHTHAlS8BglLp8iM4rUHhy0h79B9r9vj6b6zpa8U38ofctFS1fLiKY7okZ3JYeG15kUHuOwsLwOmvc5+e1Q==, + integrity: sha512-mGW96cpbwcYuc264UPqGpKBLNebFFtVEXRLPwSwxVEub9tSyMI+XGFGxsznop7pU8E1ntx4OC4cN1n5MnzO0+Q==, } engines: { node: '>=14.17' } hasBin: true @@ -17122,7 +17125,7 @@ snapshots: dependencies: semver: 7.5.4 shelljs: 0.8.5 - typescript: 5.7.0-dev.20240927 + typescript: 5.7.0-dev.20240930 duplexer@0.1.2: {} @@ -20514,7 +20517,7 @@ snapshots: typescript@5.2.2: {} - typescript@5.7.0-dev.20240927: {} + typescript@5.7.0-dev.20240930: {} ufo@1.1.2: {} From 50a19843fe471f14c780cf5f6e91760a3eec2787 Mon Sep 17 00:00:00 2001 From: Braden Mars Date: Mon, 30 Sep 2024 12:38:57 -0500 Subject: [PATCH 6/7] feat(k8s.construct.component): implement `getResources` for parsing and merging container resources from configs/container defaults/overrides Signed-off-by: Braden Mars --- .../k8s/construct/component/src/component.ts | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/packages/k8s/construct/component/src/component.ts b/packages/k8s/construct/component/src/component.ts index aeaa398..8576ccb 100644 --- a/packages/k8s/construct/component/src/component.ts +++ b/packages/k8s/construct/component/src/component.ts @@ -3,6 +3,7 @@ import * as kplus from 'cdk8s-plus-27' import { type Construct, type Node } from 'constructs' import createDebug from 'debug' import defu from 'defu' +import { z } from 'zod' import { ContainerImage, type ContainerImageProps } from './container-image' import { Label } from './labels' import { PodDisruptionBudget, type PodDisruptionBudgetProps } from './pdb' @@ -10,12 +11,59 @@ import { ComponentScaling, type ComponentScalingProps } from './scaling' const debug = createDebug('@crisiscleanup:k8s.construct.component') +export interface ContainerResources { + cpu?: kplus.CpuResources + memory?: kplus.MemoryResources +} + +export interface ContainerResourceProps { + cpu?: { + request?: number + limit?: number + } + memory?: { + request?: number + limit?: number + } +} + +const K8sMillicores = z + .number() + .describe('Kubernetes CPU Millicores') + .transform((v) => kplus.Cpu.millis(v)) +const K8sMemoryMebibytes = z + .number() + .describe('Kubernetes Memory Mebibytes') + .transform((v) => Size.mebibytes(v)) + +const K8sCpuToMillicores = z.string().transform((v) => { + if (v.endsWith('m')) { + return parseInt(v.slice(0, -1)) + } + return parseInt(v) * 1000 +}) + +const resourcesSchema = z + .object({ + cpu: z.object({ + limit: K8sMillicores.optional(), + request: K8sMillicores.optional(), + }), + memory: z.object({ + limit: K8sMemoryMebibytes.optional(), + request: K8sMemoryMebibytes.optional(), + }), + }) + .describe('Kubernetes resource limits/requests') + .partial() + export interface DeploymentProps extends kplus.WorkloadProps { replicaCount?: number image?: ContainerImageProps probes?: Pick scaling?: ComponentScalingProps containerDefaults?: Partial + resources?: ContainerResourceProps } export type ComponentContainerProps = Omit & { @@ -68,6 +116,45 @@ export class Component { return new Map(this.#containers) } + protected getResources( + defaults?: ContainerResourceProps, + ): ContainerResources { + const { cpu: cpuDefaults, memory: memoryDefaults } = + this.props.containerDefaults?.resources ?? {} + const containerDefaults = { + ...(cpuDefaults + ? { + cpu: { + limit: cpuDefaults.limit + ? K8sCpuToMillicores.parse(cpuDefaults.limit.amount) + : undefined, + request: cpuDefaults.request + ? K8sCpuToMillicores.parse(cpuDefaults.request.amount) + : undefined, + }, + } + : {}), + ...(memoryDefaults + ? { + memory: { + limit: memoryDefaults.limit + ? memoryDefaults.limit.toMebibytes() + : undefined, + request: memoryDefaults.request + ? memoryDefaults.request.toMebibytes() + : undefined, + }, + } + : {}), + } + const resourcesIn = defu( + this.props.resources ?? {}, + defaults ?? {}, + containerDefaults, + ) + return resourcesSchema.parse(resourcesIn) + } + protected createDeploymentProps(): kplus.DeploymentProps { return {} } From c42069f92a4d6f1a4e25c7bd916ad930216e8b14 Mon Sep 17 00:00:00 2001 From: Braden Mars Date: Mon, 30 Sep 2024 12:39:25 -0500 Subject: [PATCH 7/7] feat(k8s.construct.api): utilize `getResources` to merge resources for each component Signed-off-by: Braden Mars --- packages/k8s/construct/api/src/api.ts | 76 ++++++++++++++------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/packages/k8s/construct/api/src/api.ts b/packages/k8s/construct/api/src/api.ts index c18c0ef..47ef04f 100644 --- a/packages/k8s/construct/api/src/api.ts +++ b/packages/k8s/construct/api/src/api.ts @@ -205,6 +205,17 @@ export class ApiWSGI }) as ApiWSGIProps super(scope, id, propsWithDefaults) + const resources = this.getResources({ + cpu: { + request: 1000, + limit: 1800, + }, + memory: { + request: 1200, + limit: 1200, + }, + }) + const backend = this.addContainer({ name: 'gunicorn', portNumber: 5000, @@ -220,17 +231,7 @@ export class ApiWSGI '--timeout=90', ], ...(props.probes ?? this.createHttpProbes(this.httpProbePath)), - // todo: allow config via configs schema - resources: { - cpu: { - request: kplus.Cpu.millis(1000), - limit: kplus.Cpu.millis(1800), - }, - memory: { - request: Size.mebibytes(1200), - limit: Size.mebibytes(1200), - }, - }, + resources, }) const staticVolume = kplus.Volume.fromEmptyDir( @@ -526,6 +527,15 @@ export class CeleryBeat extends ApiComponent { constructor(scope: Construct, id: string, props: ApiProps) { super(scope, id, props) + const resources = this.getResources({ + cpu: { + request: 20, + }, + memory: { + request: 400, + limit: 400, + }, + }) this.addContainer({ name: 'celerybeat', command: ['/serve.sh', 'celerybeat'], @@ -536,15 +546,7 @@ export class CeleryBeat extends ApiComponent { user: 1000, group: 1000, }, - resources: { - cpu: { - request: kplus.Cpu.millis(20), - }, - memory: { - request: Size.mebibytes(400), - limit: Size.mebibytes(400), - }, - }, + resources, }) } @@ -564,6 +566,13 @@ export class CeleryWorker extends ApiComponent { const queues = [...new Set(props.queues)] + const resources = this.getResources({ + memory: { + limit: 900, + request: 900, + }, + }) + this.addContainer({ name, command: [ @@ -583,13 +592,7 @@ export class CeleryWorker extends ApiComponent { user: 1000, group: 1000, }, - resources: { - cpu: this.props.containerDefaults!.resources!.cpu!, - memory: { - limit: Size.mebibytes(900), - request: Size.mebibytes(900), - }, - }, + resources, }) } } @@ -599,6 +602,15 @@ export class AdminWebSocket extends ApiComponent { constructor(scope: Construct, id: string, props: ApiProps) { super(scope, id, props) + const resources = this.getResources({ + cpu: { + request: 3, + }, + memory: { + request: 250, + limit: 250, + }, + }) this.addContainer({ name: 'adminwebsocket', command: ['/serve.sh', 'adminwebsocket'], @@ -609,15 +621,7 @@ export class AdminWebSocket extends ApiComponent { user: 1000, group: 1000, }, - resources: { - cpu: { - request: kplus.Cpu.millis(3), - }, - memory: { - request: Size.mebibytes(250), - limit: Size.mebibytes(250), - }, - }, + resources, }) } }