From 7f56a3db56311d7e3f1be6ba157006ebfdadea0f Mon Sep 17 00:00:00 2001
From: Peter Kurfer <peter@icb4dc0.de>
Date: Wed, 12 Feb 2025 08:20:01 +0100
Subject: [PATCH] feat: custom postgres images

---
 .github/workflows/postgres.yml                |  64 ++
 .github/workflows/test-e2e.yml                |   5 +
 Tiltfile                                      |  12 +-
 api/v1alpha1/apigateway_types.go              |   2 +-
 api/v1alpha1/common_types.go                  |  60 +-
 api/v1alpha1/core_types.go                    |  16 +-
 api/v1alpha1/dashboard_types.go               |   4 +-
 api/v1alpha1/storage_types.go                 |   4 +-
 api/v1alpha1/zz_generated.deepcopy.go         |  50 +-
 .../10000000000000_demote-postgres.sql        |  19 -
 ...0529180330_alter_api_roles_for_inherit.sql |   2 -
 .../supabase.k8s.icb4dc0.de_apigateways.yaml  | 486 ++++-----
 .../bases/supabase.k8s.icb4dc0.de_cores.yaml  | 972 +++++++++---------
 .../supabase.k8s.icb4dc0.de_dashboards.yaml   | 972 +++++++++---------
 .../supabase.k8s.icb4dc0.de_storages.yaml     | 972 +++++++++---------
 config/dev/apigateway.yaml                    |   2 +
 config/dev/cnpg-cluster.yaml                  |   9 +-
 config/dev/kustomization.yaml                 |   3 +
 docs/api/supabase.k8s.icb4dc0.de.md           |  20 +-
 internal/controller/apigateway_controller.go  |  18 +-
 internal/controller/core_gotrue_controller.go |   2 +-
 .../controller/core_postgrest_controller.go   |  22 +-
 .../dashboard_pg-meta_controller.go           |  22 +-
 .../controller/dashboard_studio_controller.go |  22 +-
 internal/controller/storage_api_controller.go |  24 +-
 .../controller/storage_imgproxy_controller.go |  24 +-
 internal/db/migrator.go                       |   4 +
 internal/supabase/images.go                   |   2 +-
 magefiles/generate.go                         |  13 +-
 postgres/Dockerfile                           | 178 ++++
 30 files changed, 2131 insertions(+), 1874 deletions(-)
 create mode 100644 .github/workflows/postgres.yml
 delete mode 100644 assets/migrations/migrations/10000000000000_demote-postgres.sql
 create mode 100644 postgres/Dockerfile

diff --git a/.github/workflows/postgres.yml b/.github/workflows/postgres.yml
new file mode 100644
index 0000000..0b9596d
--- /dev/null
+++ b/.github/workflows/postgres.yml
@@ -0,0 +1,64 @@
+name: Postgres image
+on:
+  push:
+    branches:
+      - main
+    tags:
+      - "v*"
+
+env:
+  MINOR_VERSIONS: '{"15": "10","17": "2"}'
+
+jobs:
+  build:
+    strategy:
+      matrix:
+        arch:
+          - arm64
+          - amd64
+        postgres_major:
+          - "15"
+          - "17"
+    runs-on: ubuntu-latest-${{ matrix.arch }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Login to container registry
+        uses: docker/login-action@v3
+        with:
+          registry: code.icb4dc0.de
+          username: prskr
+          password: ${{ secrets.RELEASE_TOKEN }}
+
+      - name: Build and push
+        uses: docker/build-push-action@v6
+        with:
+          file: postgres/Dockerfile
+          push: true
+          tags: code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-${{ matrix.arch }}
+          build-args: |
+            POSTGRES_MAJOR=${{ matrix.postgres_major }}
+            POSTGRES_MINOR=${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}
+
+  manifest:
+    strategy:
+      matrix:
+        postgres_major:
+          - "15"
+          - "17"
+    runs-on: ubuntu-latest
+    needs:
+      - build
+    steps:
+      - name: Login to container registry
+        uses: docker/login-action@v3
+        with:
+          registry: code.icb4dc0.de
+          username: prskr
+          password: ${{ secrets.RELEASE_TOKEN }}
+
+      - name: Create manifest
+        run: |
+          docker buildx imagetools create -t code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }} \
+              code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-arm64 \
+              code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-amd64
diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml
index e059ade..3b5c44b 100644
--- a/.github/workflows/test-e2e.yml
+++ b/.github/workflows/test-e2e.yml
@@ -43,3 +43,8 @@ jobs:
         run: |
           go mod tidy
           make test-e2e
+
+      - name: Cleanup kind cluster
+        if: always()
+        run: |
+          kind delete cluster
diff --git a/Tiltfile b/Tiltfile
index 63d5292..adaed2b 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -7,6 +7,13 @@ k8s_yaml(kustomize('config/dev'))
 
 compile_cmd = 'CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o out/supabase-operator ./cmd/'
 
+update_settings(suppress_unused_image_warnings=["localhost:5005/cnpg-postgres:17.2"])
+custom_build(
+    'localhost:5005/cnpg-postgres:17.2',
+    'docker build -t $EXPECTED_REF --push -f postgres/Dockerfile --build-arg POSTGRES_MAJOR=17 --build-arg=POSTGRES_MINOR=2 .',
+    ['postgres/Dockerfile']
+)
+
 local_resource(
   'manager-go-compile',
   compile_cmd,
@@ -22,6 +29,8 @@ local_resource(
   resource_deps=[]
 )
 
+k8s_kind('Cluster', api_version='postgresql.cnpg.io/v1')
+
 docker_build_with_restart(
   'supabase-operator',
   '.',
@@ -39,10 +48,11 @@ k8s_resource('supabase-controller-manager')
 k8s_resource(
     workload='supabase-control-plane',
     port_forwards=18000,
+    resource_deps=[]
 )
 
 k8s_resource(
-    objects=["cluster-example:Cluster:supabase-demo"],
+    workload='cluster-example',
     new_name='Postgres cluster',
     port_forwards=5432
 )
diff --git a/api/v1alpha1/apigateway_types.go b/api/v1alpha1/apigateway_types.go
index 2bedf7c..57de576 100644
--- a/api/v1alpha1/apigateway_types.go
+++ b/api/v1alpha1/apigateway_types.go
@@ -80,7 +80,7 @@ type EnvoySpec struct {
 	// ControlPlane - configure the control plane where Envoy will retrieve its configuration from
 	ControlPlane *ControlPlaneSpec `json:"controlPlane"`
 	// WorkloadTemplate - customize the Envoy deployment
-	WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
+	WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
 	// DisableIPv6 - disable IPv6 for the Envoy instance
 	// this will force Envoy to use IPv4 for upstream hosts (mostly for the OAuth2 token endpoint)
 	DisableIPv6 bool                   `json:"disableIPv6,omitempty"`
diff --git a/api/v1alpha1/common_types.go b/api/v1alpha1/common_types.go
index 0db17fd..bbba08d 100644
--- a/api/v1alpha1/common_types.go
+++ b/api/v1alpha1/common_types.go
@@ -91,16 +91,16 @@ type ContainerTemplate struct {
 	AdditionalEnv   []corev1.EnvVar             `json:"additionalEnv,omitempty"`
 }
 
-type WorkloadTemplate struct {
+type WorkloadSpec struct {
 	Replicas         *int32                     `json:"replicas,omitempty"`
 	SecurityContext  *corev1.PodSecurityContext `json:"securityContext,omitempty"`
 	AdditionalLabels map[string]string          `json:"additionalLabels,omitempty"`
-	// Workload - customize the container template of the workload
-	Workload          *ContainerTemplate `json:"workload,omitempty"`
+	// ContainerSpec - customize the container template of the workload
+	ContainerSpec     *ContainerTemplate `json:"container,omitempty"`
 	AdditionalVolumes []corev1.Volume    `json:"additionalVolumes,omitempty"`
 }
 
-func (t *WorkloadTemplate) ReplicaCount() *int32 {
+func (t *WorkloadSpec) ReplicaCount() *int32 {
 	if t != nil && t.Replicas != nil {
 		return t.Replicas
 	}
@@ -108,20 +108,20 @@ func (t *WorkloadTemplate) ReplicaCount() *int32 {
 	return nil
 }
 
-func (t *WorkloadTemplate) MergeEnv(basicEnv []corev1.EnvVar) []corev1.EnvVar {
-	if t == nil || t.Workload == nil || len(t.Workload.AdditionalEnv) == 0 {
+func (t *WorkloadSpec) MergeEnv(basicEnv []corev1.EnvVar) []corev1.EnvVar {
+	if t == nil || t.ContainerSpec == nil || len(t.ContainerSpec.AdditionalEnv) == 0 {
 		return basicEnv
 	}
 
-	existingKeys := make(map[string]bool, len(basicEnv)+len(t.Workload.AdditionalEnv))
+	existingKeys := make(map[string]bool, len(basicEnv)+len(t.ContainerSpec.AdditionalEnv))
 
-	merged := append(make([]corev1.EnvVar, 0, len(basicEnv)+len(t.Workload.AdditionalEnv)), basicEnv...)
+	merged := append(make([]corev1.EnvVar, 0, len(basicEnv)+len(t.ContainerSpec.AdditionalEnv)), basicEnv...)
 
 	for _, v := range basicEnv {
 		existingKeys[v.Name] = true
 	}
 
-	for _, v := range t.Workload.AdditionalEnv {
+	for _, v := range t.ContainerSpec.AdditionalEnv {
 		if _, alreadyPresent := existingKeys[v.Name]; alreadyPresent {
 			continue
 		}
@@ -132,7 +132,7 @@ func (t *WorkloadTemplate) MergeEnv(basicEnv []corev1.EnvVar) []corev1.EnvVar {
 	return merged
 }
 
-func (t *WorkloadTemplate) MergeLabels(initial map[string]string, toAppend ...map[string]string) map[string]string {
+func (t *WorkloadSpec) MergeLabels(initial map[string]string, toAppend ...map[string]string) map[string]string {
 	result := make(map[string]string)
 
 	maps.Copy(result, initial)
@@ -156,47 +156,47 @@ func (t *WorkloadTemplate) MergeLabels(initial map[string]string, toAppend ...ma
 	return result
 }
 
-func (t *WorkloadTemplate) Image(defaultImage string) string {
-	if t != nil && t.Workload != nil && t.Workload.Image != "" {
-		return t.Workload.Image
+func (t *WorkloadSpec) Image(defaultImage string) string {
+	if t != nil && t.ContainerSpec != nil && t.ContainerSpec.Image != "" {
+		return t.ContainerSpec.Image
 	}
 
 	return defaultImage
 }
 
-func (t *WorkloadTemplate) ImagePullPolicy() corev1.PullPolicy {
-	if t != nil && t.Workload != nil && t.Workload.PullPolicy != "" {
-		return t.Workload.PullPolicy
+func (t *WorkloadSpec) ImagePullPolicy() corev1.PullPolicy {
+	if t != nil && t.ContainerSpec != nil && t.ContainerSpec.PullPolicy != "" {
+		return t.ContainerSpec.PullPolicy
 	}
 
 	return corev1.PullIfNotPresent
 }
 
-func (t *WorkloadTemplate) PullSecrets() []corev1.LocalObjectReference {
-	if t != nil && t.Workload != nil && len(t.Workload.ImagePullSecrets) > 0 {
-		return t.Workload.ImagePullSecrets
+func (t *WorkloadSpec) PullSecrets() []corev1.LocalObjectReference {
+	if t != nil && t.ContainerSpec != nil && len(t.ContainerSpec.ImagePullSecrets) > 0 {
+		return t.ContainerSpec.ImagePullSecrets
 	}
 
 	return nil
 }
 
-func (t *WorkloadTemplate) Resources() corev1.ResourceRequirements {
-	if t != nil && t.Workload != nil {
-		return t.Workload.Resources
+func (t *WorkloadSpec) Resources() corev1.ResourceRequirements {
+	if t != nil && t.ContainerSpec != nil {
+		return t.ContainerSpec.Resources
 	}
 
 	return corev1.ResourceRequirements{}
 }
 
-func (t *WorkloadTemplate) AdditionalVolumeMounts(defaultMounts ...corev1.VolumeMount) []corev1.VolumeMount {
-	if t != nil && t.Workload != nil {
-		return append(defaultMounts, t.Workload.VolumeMounts...)
+func (t *WorkloadSpec) AdditionalVolumeMounts(defaultMounts ...corev1.VolumeMount) []corev1.VolumeMount {
+	if t != nil && t.ContainerSpec != nil {
+		return append(defaultMounts, t.ContainerSpec.VolumeMounts...)
 	}
 
 	return defaultMounts
 }
 
-func (t *WorkloadTemplate) Volumes(defaultVolumes ...corev1.Volume) []corev1.Volume {
+func (t *WorkloadSpec) Volumes(defaultVolumes ...corev1.Volume) []corev1.Volume {
 	if t == nil {
 		return defaultVolumes
 	}
@@ -204,7 +204,7 @@ func (t *WorkloadTemplate) Volumes(defaultVolumes ...corev1.Volume) []corev1.Vol
 	return append(defaultVolumes, t.AdditionalVolumes...)
 }
 
-func (t *WorkloadTemplate) PodSecurityContext() *corev1.PodSecurityContext {
+func (t *WorkloadSpec) PodSecurityContext() *corev1.PodSecurityContext {
 	if t != nil && t.SecurityContext != nil {
 		return t.SecurityContext
 	}
@@ -214,9 +214,9 @@ func (t *WorkloadTemplate) PodSecurityContext() *corev1.PodSecurityContext {
 	}
 }
 
-func (t *WorkloadTemplate) ContainerSecurityContext(uid, gid int64) *corev1.SecurityContext {
-	if t != nil && t.Workload != nil && t.Workload.SecurityContext != nil {
-		return t.Workload.SecurityContext
+func (t *WorkloadSpec) ContainerSecurityContext(uid, gid int64) *corev1.SecurityContext {
+	if t != nil && t.ContainerSpec != nil && t.ContainerSpec.SecurityContext != nil {
+		return t.ContainerSpec.SecurityContext
 	}
 
 	return &corev1.SecurityContext{
diff --git a/api/v1alpha1/core_types.go b/api/v1alpha1/core_types.go
index e4d4e18..cd20586 100644
--- a/api/v1alpha1/core_types.go
+++ b/api/v1alpha1/core_types.go
@@ -167,8 +167,8 @@ type PostgrestSpec struct {
 	// MaxRows - maximum number of rows PostgREST will load at a time
 	// +kubebuilder:default=1000
 	MaxRows int `json:"maxRows,omitempty"`
-	// WorkloadTemplate - customize the PostgREST workload
-	WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
+	// WorkloadSpec - customize the PostgREST workload
+	WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
 }
 
 type AuthProviderMeta struct {
@@ -365,12 +365,12 @@ func (p *AuthProviders) Vars(apiExternalURL string) []corev1.EnvVar {
 }
 
 type AuthSpec struct {
-	AdditionalRedirectUrls []string          `json:"additionalRedirectUrls,omitempty"`
-	DisableSignup          *bool             `json:"disableSignup,omitempty"`
-	AnonymousUsersEnabled  *bool             `json:"anonymousUsersEnabled,omitempty"`
-	Providers              *AuthProviders    `json:"providers,omitempty"`
-	WorkloadTemplate       *WorkloadTemplate `json:"workloadTemplate,omitempty"`
-	EmailSignupDisabled    *bool             `json:"emailSignupDisabled,omitempty"`
+	AdditionalRedirectUrls []string       `json:"additionalRedirectUrls,omitempty"`
+	DisableSignup          *bool          `json:"disableSignup,omitempty"`
+	AnonymousUsersEnabled  *bool          `json:"anonymousUsersEnabled,omitempty"`
+	Providers              *AuthProviders `json:"providers,omitempty"`
+	WorkloadTemplate       *WorkloadSpec  `json:"workloadTemplate,omitempty"`
+	EmailSignupDisabled    *bool          `json:"emailSignupDisabled,omitempty"`
 }
 
 // CoreSpec defines the desired state of Core.
diff --git a/api/v1alpha1/dashboard_types.go b/api/v1alpha1/dashboard_types.go
index 2b4cd29..66d1a30 100644
--- a/api/v1alpha1/dashboard_types.go
+++ b/api/v1alpha1/dashboard_types.go
@@ -24,7 +24,7 @@ import (
 type StudioSpec struct {
 	JWT *JwtSpec `json:"jwt,omitempty"`
 	// WorkloadTemplate - customize the studio deployment
-	WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
+	WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
 	// GatewayServiceSelector - selector to find the service for the API gateway
 	// Required to configure the API URL in the studio deployment
 	// If you don't run multiple APIGateway instances in the same namespaces, the default will be fine
@@ -37,7 +37,7 @@ type StudioSpec struct {
 
 type PGMetaSpec struct {
 	// WorkloadTemplate - customize the pg-meta deployment
-	WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
+	WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
 }
 
 type DbCredentialsReference struct {
diff --git a/api/v1alpha1/storage_types.go b/api/v1alpha1/storage_types.go
index 09e719d..45c9099 100644
--- a/api/v1alpha1/storage_types.go
+++ b/api/v1alpha1/storage_types.go
@@ -191,7 +191,7 @@ type StorageApiSpec struct {
 	// UploadTemp - configure the emptyDir for storing intermediate files during uploads
 	UploadTemp *UploadTempSpec `json:"uploadTemp,omitempty"`
 	// WorkloadTemplate - customize the Storage API workload
-	WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
+	WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
 }
 
 type ImageProxySpec struct {
@@ -199,7 +199,7 @@ type ImageProxySpec struct {
 	Enable               bool `json:"enable,omitempty"`
 	EnabledWebPDetection bool `json:"enableWebPDetection,omitempty"`
 	// WorkloadTemplate - customize the image proxy workload
-	WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
+	WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
 }
 
 // StorageSpec defines the desired state of Storage.
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index f58f780..f3d6a98 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -252,7 +252,7 @@ func (in *AuthSpec) DeepCopyInto(out *AuthSpec) {
 	}
 	if in.WorkloadTemplate != nil {
 		in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
-		*out = new(WorkloadTemplate)
+		*out = new(WorkloadSpec)
 		(*in).DeepCopyInto(*out)
 	}
 	if in.EmailSignupDisabled != nil {
@@ -921,9 +921,9 @@ func (in *EnvoySpec) DeepCopyInto(out *EnvoySpec) {
 		*out = new(ControlPlaneSpec)
 		**out = **in
 	}
-	if in.WorkloadTemplate != nil {
-		in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
-		*out = new(WorkloadTemplate)
+	if in.WorkloadSpec != nil {
+		in, out := &in.WorkloadSpec, &out.WorkloadSpec
+		*out = new(WorkloadSpec)
 		(*in).DeepCopyInto(*out)
 	}
 	if in.Debugging != nil {
@@ -998,9 +998,9 @@ func (in *GithubAuthProvider) DeepCopy() *GithubAuthProvider {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ImageProxySpec) DeepCopyInto(out *ImageProxySpec) {
 	*out = *in
-	if in.WorkloadTemplate != nil {
-		in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
-		*out = new(WorkloadTemplate)
+	if in.WorkloadSpec != nil {
+		in, out := &in.WorkloadSpec, &out.WorkloadSpec
+		*out = new(WorkloadSpec)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -1089,9 +1089,9 @@ func (in *OAuthProvider) DeepCopy() *OAuthProvider {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *PGMetaSpec) DeepCopyInto(out *PGMetaSpec) {
 	*out = *in
-	if in.WorkloadTemplate != nil {
-		in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
-		*out = new(WorkloadTemplate)
+	if in.WorkloadSpec != nil {
+		in, out := &in.WorkloadSpec, &out.WorkloadSpec
+		*out = new(WorkloadSpec)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -1135,9 +1135,9 @@ func (in *PostgrestSpec) DeepCopyInto(out *PostgrestSpec) {
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
-	if in.WorkloadTemplate != nil {
-		in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
-		*out = new(WorkloadTemplate)
+	if in.WorkloadSpec != nil {
+		in, out := &in.WorkloadSpec, &out.WorkloadSpec
+		*out = new(WorkloadSpec)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -1294,9 +1294,9 @@ func (in *StorageApiSpec) DeepCopyInto(out *StorageApiSpec) {
 		*out = new(UploadTempSpec)
 		(*in).DeepCopyInto(*out)
 	}
-	if in.WorkloadTemplate != nil {
-		in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
-		*out = new(WorkloadTemplate)
+	if in.WorkloadSpec != nil {
+		in, out := &in.WorkloadSpec, &out.WorkloadSpec
+		*out = new(WorkloadSpec)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -1387,9 +1387,9 @@ func (in *StudioSpec) DeepCopyInto(out *StudioSpec) {
 		*out = new(JwtSpec)
 		**out = **in
 	}
-	if in.WorkloadTemplate != nil {
-		in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
-		*out = new(WorkloadTemplate)
+	if in.WorkloadSpec != nil {
+		in, out := &in.WorkloadSpec, &out.WorkloadSpec
+		*out = new(WorkloadSpec)
 		(*in).DeepCopyInto(*out)
 	}
 	if in.GatewayServiceMatchLabels != nil {
@@ -1447,7 +1447,7 @@ func (in *UploadTempSpec) DeepCopy() *UploadTempSpec {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *WorkloadTemplate) DeepCopyInto(out *WorkloadTemplate) {
+func (in *WorkloadSpec) DeepCopyInto(out *WorkloadSpec) {
 	*out = *in
 	if in.Replicas != nil {
 		in, out := &in.Replicas, &out.Replicas
@@ -1466,8 +1466,8 @@ func (in *WorkloadTemplate) DeepCopyInto(out *WorkloadTemplate) {
 			(*out)[key] = val
 		}
 	}
-	if in.Workload != nil {
-		in, out := &in.Workload, &out.Workload
+	if in.ContainerSpec != nil {
+		in, out := &in.ContainerSpec, &out.ContainerSpec
 		*out = new(ContainerTemplate)
 		(*in).DeepCopyInto(*out)
 	}
@@ -1480,12 +1480,12 @@ func (in *WorkloadTemplate) DeepCopyInto(out *WorkloadTemplate) {
 	}
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadTemplate.
-func (in *WorkloadTemplate) DeepCopy() *WorkloadTemplate {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadSpec.
+func (in *WorkloadSpec) DeepCopy() *WorkloadSpec {
 	if in == nil {
 		return nil
 	}
-	out := new(WorkloadTemplate)
+	out := new(WorkloadSpec)
 	in.DeepCopyInto(out)
 	return out
 }
diff --git a/assets/migrations/migrations/10000000000000_demote-postgres.sql b/assets/migrations/migrations/10000000000000_demote-postgres.sql
deleted file mode 100644
index 1f7e2e2..0000000
--- a/assets/migrations/migrations/10000000000000_demote-postgres.sql
+++ /dev/null
@@ -1,19 +0,0 @@
--- migrate:up
-
--- demote postgres user
-GRANT ALL ON DATABASE postgres TO postgres;
-GRANT ALL ON SCHEMA auth TO postgres;
-GRANT ALL ON SCHEMA extensions TO postgres;
-GRANT ALL ON SCHEMA storage TO postgres;
-GRANT ALL ON ALL TABLES IN SCHEMA auth TO postgres;
-GRANT ALL ON ALL TABLES IN SCHEMA storage TO postgres;
-GRANT ALL ON ALL TABLES IN SCHEMA extensions TO postgres;
-GRANT ALL ON ALL SEQUENCES IN SCHEMA auth TO postgres;
-GRANT ALL ON ALL SEQUENCES IN SCHEMA storage TO postgres;
-GRANT ALL ON ALL SEQUENCES IN SCHEMA extensions TO postgres;
-GRANT ALL ON ALL ROUTINES IN SCHEMA auth TO postgres;
-GRANT ALL ON ALL ROUTINES IN SCHEMA storage TO postgres;
-GRANT ALL ON ALL ROUTINES IN SCHEMA extensions TO postgres;
-ALTER ROLE postgres NOSUPERUSER CREATEDB CREATEROLE LOGIN REPLICATION BYPASSRLS;
-
--- migrate:down
diff --git a/assets/migrations/migrations/20230529180330_alter_api_roles_for_inherit.sql b/assets/migrations/migrations/20230529180330_alter_api_roles_for_inherit.sql
index 4df82e3..013a074 100644
--- a/assets/migrations/migrations/20230529180330_alter_api_roles_for_inherit.sql
+++ b/assets/migrations/migrations/20230529180330_alter_api_roles_for_inherit.sql
@@ -4,7 +4,5 @@ ALTER ROLE authenticated inherit;
 ALTER ROLE anon inherit;
 ALTER ROLE service_role inherit;
 
-GRANT pgsodium_keyholder to service_role;
-
 -- migrate:down
 
diff --git a/config/crd/bases/supabase.k8s.icb4dc0.de_apigateways.yaml b/config/crd/bases/supabase.k8s.icb4dc0.de_apigateways.yaml
index 39ac679..e6a8085 100644
--- a/config/crd/bases/supabase.k8s.icb4dc0.de_apigateways.yaml
+++ b/config/crd/bases/supabase.k8s.icb4dc0.de_apigateways.yaml
@@ -295,7 +295,7 @@ spec:
                       if not set, the name of the APIGateway resource will be used
                       The primary use case is to make the assignment of multiple supabase instances in a single namespace explicit.
                     type: string
-                  workloadTemplate:
+                  workloadSpec:
                     description: WorkloadTemplate - customize the Envoy deployment
                     properties:
                       additionalLabels:
@@ -2102,248 +2102,9 @@ spec:
                           - name
                           type: object
                         type: array
-                      replicas:
-                        format: int32
-                        type: integer
-                      securityContext:
-                        description: |-
-                          PodSecurityContext holds pod-level security attributes and common container settings.
-                          Some fields are also present in container.securityContext.  Field values of
-                          container.securityContext take precedence over field values of PodSecurityContext.
-                        properties:
-                          appArmorProfile:
-                            description: |-
-                              appArmorProfile is the AppArmor options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile loaded on the node that should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must match the loaded name of the profile.
-                                  Must be set if and only if type is "Localhost".
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of AppArmor profile will be applied.
-                                  Valid options are:
-                                    Localhost - a profile pre-loaded on the node.
-                                    RuntimeDefault - the container runtime's default profile.
-                                    Unconfined - no AppArmor enforcement.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          fsGroup:
-                            description: |-
-                              A special supplemental group that applies to all containers in a pod.
-                              Some volume types allow the Kubelet to change the ownership of that volume
-                              to be owned by the pod:
-
-                              1. The owning GID will be the FSGroup
-                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
-                              3. The permission bits are OR'd with rw-rw----
-
-                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          fsGroupChangePolicy:
-                            description: |-
-                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
-                              before being exposed inside Pod. This field will only apply to
-                              volume types which support fsGroup based ownership(and permissions).
-                              It will have no effect on ephemeral volume types such as: secret, configmaps
-                              and emptydir.
-                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          runAsGroup:
-                            description: |-
-                              The GID to run the entrypoint of the container process.
-                              Uses runtime default if unset.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          runAsNonRoot:
-                            description: |-
-                              Indicates that the container must run as a non-root user.
-                              If true, the Kubelet will validate the image at runtime to ensure that it
-                              does not run as UID 0 (root) and fail to start the container if it does.
-                              If unset or false, no such validation will be performed.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence.
-                            type: boolean
-                          runAsUser:
-                            description: |-
-                              The UID to run the entrypoint of the container process.
-                              Defaults to user specified in image metadata if unspecified.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          seLinuxChangePolicy:
-                            description: |-
-                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
-                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
-                              Valid values are "MountOption" and "Recursive".
-
-                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
-                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
-
-                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
-                              This requires all Pods that share the same volume to use the same SELinux label.
-                              It is not possible to share the same volume among privileged and unprivileged Pods.
-                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
-                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
-                              CSIDriver instance. Other volumes are always re-labelled recursively.
-                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
-
-                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
-                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
-                              and "Recursive" for all other volumes.
-
-                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
-
-                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          seLinuxOptions:
-                            description: |-
-                              The SELinux context to be applied to all containers.
-                              If unspecified, the container runtime will allocate a random SELinux context for each
-                              container.  May also be set in SecurityContext.  If set in
-                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
-                              takes precedence for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              level:
-                                description: Level is SELinux level label that applies
-                                  to the container.
-                                type: string
-                              role:
-                                description: Role is a SELinux role label that applies
-                                  to the container.
-                                type: string
-                              type:
-                                description: Type is a SELinux type label that applies
-                                  to the container.
-                                type: string
-                              user:
-                                description: User is a SELinux user label that applies
-                                  to the container.
-                                type: string
-                            type: object
-                          seccompProfile:
-                            description: |-
-                              The seccomp options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile defined in a file on the node should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
-                                  Must be set if type is "Localhost". Must NOT be set for any other type.
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of seccomp profile will be applied.
-                                  Valid options are:
-
-                                  Localhost - a profile defined in a file on the node should be used.
-                                  RuntimeDefault - the container runtime default profile should be used.
-                                  Unconfined - no profile should be applied.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          supplementalGroups:
-                            description: |-
-                              A list of groups applied to the first process run in each container, in
-                              addition to the container's primary GID and fsGroup (if specified).  If
-                              the SupplementalGroupsPolicy feature is enabled, the
-                              supplementalGroupsPolicy field determines whether these are in addition
-                              to or instead of any group memberships defined in the container image.
-                              If unspecified, no additional groups are added, though group memberships
-                              defined in the container image may still be used, depending on the
-                              supplementalGroupsPolicy field.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              format: int64
-                              type: integer
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          supplementalGroupsPolicy:
-                            description: |-
-                              Defines how supplemental groups of the first container processes are calculated.
-                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
-                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
-                              and the container runtime must implement support for this feature.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          sysctls:
-                            description: |-
-                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
-                              sysctls (by the container runtime) might fail to launch.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              description: Sysctl defines a kernel parameter to be
-                                set
-                              properties:
-                                name:
-                                  description: Name of a property to set
-                                  type: string
-                                value:
-                                  description: Value of a property to set
-                                  type: string
-                              required:
-                              - name
-                              - value
-                              type: object
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          windowsOptions:
-                            description: |-
-                              The Windows specific settings applied to all containers.
-                              If unspecified, the options within a container's SecurityContext will be used.
-                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
-                              Note that this field cannot be set when spec.os.name is linux.
-                            properties:
-                              gmsaCredentialSpec:
-                                description: |-
-                                  GMSACredentialSpec is where the GMSA admission webhook
-                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
-                                  GMSA credential spec named by the GMSACredentialSpecName field.
-                                type: string
-                              gmsaCredentialSpecName:
-                                description: GMSACredentialSpecName is the name of
-                                  the GMSA credential spec to use.
-                                type: string
-                              hostProcess:
-                                description: |-
-                                  HostProcess determines if a container should be run as a 'Host Process' container.
-                                  All of a Pod's containers must have the same effective HostProcess value
-                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
-                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
-                                type: boolean
-                              runAsUserName:
-                                description: |-
-                                  The UserName in Windows to run the entrypoint of the container process.
-                                  Defaults to the user specified in image metadata if unspecified.
-                                  May also be set in PodSecurityContext. If set in both SecurityContext and
-                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
-                                type: string
-                            type: object
-                        type: object
-                      workload:
-                        description: Workload - customize the container template of
-                          the workload
+                      container:
+                        description: ContainerSpec - customize the container template
+                          of the workload
                         properties:
                           additionalEnv:
                             items:
@@ -2808,6 +2569,245 @@ spec:
                               type: object
                             type: array
                         type: object
+                      replicas:
+                        format: int32
+                        type: integer
+                      securityContext:
+                        description: |-
+                          PodSecurityContext holds pod-level security attributes and common container settings.
+                          Some fields are also present in container.securityContext.  Field values of
+                          container.securityContext take precedence over field values of PodSecurityContext.
+                        properties:
+                          appArmorProfile:
+                            description: |-
+                              appArmorProfile is the AppArmor options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile loaded on the node that should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must match the loaded name of the profile.
+                                  Must be set if and only if type is "Localhost".
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of AppArmor profile will be applied.
+                                  Valid options are:
+                                    Localhost - a profile pre-loaded on the node.
+                                    RuntimeDefault - the container runtime's default profile.
+                                    Unconfined - no AppArmor enforcement.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          fsGroup:
+                            description: |-
+                              A special supplemental group that applies to all containers in a pod.
+                              Some volume types allow the Kubelet to change the ownership of that volume
+                              to be owned by the pod:
+
+                              1. The owning GID will be the FSGroup
+                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
+                              3. The permission bits are OR'd with rw-rw----
+
+                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          fsGroupChangePolicy:
+                            description: |-
+                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
+                              before being exposed inside Pod. This field will only apply to
+                              volume types which support fsGroup based ownership(and permissions).
+                              It will have no effect on ephemeral volume types such as: secret, configmaps
+                              and emptydir.
+                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          runAsGroup:
+                            description: |-
+                              The GID to run the entrypoint of the container process.
+                              Uses runtime default if unset.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          runAsNonRoot:
+                            description: |-
+                              Indicates that the container must run as a non-root user.
+                              If true, the Kubelet will validate the image at runtime to ensure that it
+                              does not run as UID 0 (root) and fail to start the container if it does.
+                              If unset or false, no such validation will be performed.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence.
+                            type: boolean
+                          runAsUser:
+                            description: |-
+                              The UID to run the entrypoint of the container process.
+                              Defaults to user specified in image metadata if unspecified.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          seLinuxChangePolicy:
+                            description: |-
+                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
+                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
+                              Valid values are "MountOption" and "Recursive".
+
+                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
+                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
+
+                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
+                              This requires all Pods that share the same volume to use the same SELinux label.
+                              It is not possible to share the same volume among privileged and unprivileged Pods.
+                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
+                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
+                              CSIDriver instance. Other volumes are always re-labelled recursively.
+                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
+
+                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
+                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
+                              and "Recursive" for all other volumes.
+
+                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
+
+                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          seLinuxOptions:
+                            description: |-
+                              The SELinux context to be applied to all containers.
+                              If unspecified, the container runtime will allocate a random SELinux context for each
+                              container.  May also be set in SecurityContext.  If set in
+                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
+                              takes precedence for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              level:
+                                description: Level is SELinux level label that applies
+                                  to the container.
+                                type: string
+                              role:
+                                description: Role is a SELinux role label that applies
+                                  to the container.
+                                type: string
+                              type:
+                                description: Type is a SELinux type label that applies
+                                  to the container.
+                                type: string
+                              user:
+                                description: User is a SELinux user label that applies
+                                  to the container.
+                                type: string
+                            type: object
+                          seccompProfile:
+                            description: |-
+                              The seccomp options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile defined in a file on the node should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
+                                  Must be set if type is "Localhost". Must NOT be set for any other type.
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of seccomp profile will be applied.
+                                  Valid options are:
+
+                                  Localhost - a profile defined in a file on the node should be used.
+                                  RuntimeDefault - the container runtime default profile should be used.
+                                  Unconfined - no profile should be applied.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          supplementalGroups:
+                            description: |-
+                              A list of groups applied to the first process run in each container, in
+                              addition to the container's primary GID and fsGroup (if specified).  If
+                              the SupplementalGroupsPolicy feature is enabled, the
+                              supplementalGroupsPolicy field determines whether these are in addition
+                              to or instead of any group memberships defined in the container image.
+                              If unspecified, no additional groups are added, though group memberships
+                              defined in the container image may still be used, depending on the
+                              supplementalGroupsPolicy field.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              format: int64
+                              type: integer
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          supplementalGroupsPolicy:
+                            description: |-
+                              Defines how supplemental groups of the first container processes are calculated.
+                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
+                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
+                              and the container runtime must implement support for this feature.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          sysctls:
+                            description: |-
+                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
+                              sysctls (by the container runtime) might fail to launch.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              description: Sysctl defines a kernel parameter to be
+                                set
+                              properties:
+                                name:
+                                  description: Name of a property to set
+                                  type: string
+                                value:
+                                  description: Value of a property to set
+                                  type: string
+                              required:
+                              - name
+                              - value
+                              type: object
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          windowsOptions:
+                            description: |-
+                              The Windows specific settings applied to all containers.
+                              If unspecified, the options within a container's SecurityContext will be used.
+                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
+                              Note that this field cannot be set when spec.os.name is linux.
+                            properties:
+                              gmsaCredentialSpec:
+                                description: |-
+                                  GMSACredentialSpec is where the GMSA admission webhook
+                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
+                                  GMSA credential spec named by the GMSACredentialSpecName field.
+                                type: string
+                              gmsaCredentialSpecName:
+                                description: GMSACredentialSpecName is the name of
+                                  the GMSA credential spec to use.
+                                type: string
+                              hostProcess:
+                                description: |-
+                                  HostProcess determines if a container should be run as a 'Host Process' container.
+                                  All of a Pod's containers must have the same effective HostProcess value
+                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
+                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
+                                type: boolean
+                              runAsUserName:
+                                description: |-
+                                  The UserName in Windows to run the entrypoint of the container process.
+                                  Defaults to the user specified in image metadata if unspecified.
+                                  May also be set in PodSecurityContext. If set in both SecurityContext and
+                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
+                                type: string
+                            type: object
+                        type: object
                     type: object
                 required:
                 - controlPlane
diff --git a/config/crd/bases/supabase.k8s.icb4dc0.de_cores.yaml b/config/crd/bases/supabase.k8s.icb4dc0.de_cores.yaml
index ce862ae..2fd79ef 100644
--- a/config/crd/bases/supabase.k8s.icb4dc0.de_cores.yaml
+++ b/config/crd/bases/supabase.k8s.icb4dc0.de_cores.yaml
@@ -1993,248 +1993,9 @@ spec:
                           - name
                           type: object
                         type: array
-                      replicas:
-                        format: int32
-                        type: integer
-                      securityContext:
-                        description: |-
-                          PodSecurityContext holds pod-level security attributes and common container settings.
-                          Some fields are also present in container.securityContext.  Field values of
-                          container.securityContext take precedence over field values of PodSecurityContext.
-                        properties:
-                          appArmorProfile:
-                            description: |-
-                              appArmorProfile is the AppArmor options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile loaded on the node that should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must match the loaded name of the profile.
-                                  Must be set if and only if type is "Localhost".
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of AppArmor profile will be applied.
-                                  Valid options are:
-                                    Localhost - a profile pre-loaded on the node.
-                                    RuntimeDefault - the container runtime's default profile.
-                                    Unconfined - no AppArmor enforcement.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          fsGroup:
-                            description: |-
-                              A special supplemental group that applies to all containers in a pod.
-                              Some volume types allow the Kubelet to change the ownership of that volume
-                              to be owned by the pod:
-
-                              1. The owning GID will be the FSGroup
-                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
-                              3. The permission bits are OR'd with rw-rw----
-
-                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          fsGroupChangePolicy:
-                            description: |-
-                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
-                              before being exposed inside Pod. This field will only apply to
-                              volume types which support fsGroup based ownership(and permissions).
-                              It will have no effect on ephemeral volume types such as: secret, configmaps
-                              and emptydir.
-                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          runAsGroup:
-                            description: |-
-                              The GID to run the entrypoint of the container process.
-                              Uses runtime default if unset.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          runAsNonRoot:
-                            description: |-
-                              Indicates that the container must run as a non-root user.
-                              If true, the Kubelet will validate the image at runtime to ensure that it
-                              does not run as UID 0 (root) and fail to start the container if it does.
-                              If unset or false, no such validation will be performed.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence.
-                            type: boolean
-                          runAsUser:
-                            description: |-
-                              The UID to run the entrypoint of the container process.
-                              Defaults to user specified in image metadata if unspecified.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          seLinuxChangePolicy:
-                            description: |-
-                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
-                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
-                              Valid values are "MountOption" and "Recursive".
-
-                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
-                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
-
-                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
-                              This requires all Pods that share the same volume to use the same SELinux label.
-                              It is not possible to share the same volume among privileged and unprivileged Pods.
-                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
-                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
-                              CSIDriver instance. Other volumes are always re-labelled recursively.
-                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
-
-                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
-                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
-                              and "Recursive" for all other volumes.
-
-                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
-
-                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          seLinuxOptions:
-                            description: |-
-                              The SELinux context to be applied to all containers.
-                              If unspecified, the container runtime will allocate a random SELinux context for each
-                              container.  May also be set in SecurityContext.  If set in
-                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
-                              takes precedence for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              level:
-                                description: Level is SELinux level label that applies
-                                  to the container.
-                                type: string
-                              role:
-                                description: Role is a SELinux role label that applies
-                                  to the container.
-                                type: string
-                              type:
-                                description: Type is a SELinux type label that applies
-                                  to the container.
-                                type: string
-                              user:
-                                description: User is a SELinux user label that applies
-                                  to the container.
-                                type: string
-                            type: object
-                          seccompProfile:
-                            description: |-
-                              The seccomp options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile defined in a file on the node should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
-                                  Must be set if type is "Localhost". Must NOT be set for any other type.
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of seccomp profile will be applied.
-                                  Valid options are:
-
-                                  Localhost - a profile defined in a file on the node should be used.
-                                  RuntimeDefault - the container runtime default profile should be used.
-                                  Unconfined - no profile should be applied.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          supplementalGroups:
-                            description: |-
-                              A list of groups applied to the first process run in each container, in
-                              addition to the container's primary GID and fsGroup (if specified).  If
-                              the SupplementalGroupsPolicy feature is enabled, the
-                              supplementalGroupsPolicy field determines whether these are in addition
-                              to or instead of any group memberships defined in the container image.
-                              If unspecified, no additional groups are added, though group memberships
-                              defined in the container image may still be used, depending on the
-                              supplementalGroupsPolicy field.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              format: int64
-                              type: integer
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          supplementalGroupsPolicy:
-                            description: |-
-                              Defines how supplemental groups of the first container processes are calculated.
-                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
-                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
-                              and the container runtime must implement support for this feature.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          sysctls:
-                            description: |-
-                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
-                              sysctls (by the container runtime) might fail to launch.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              description: Sysctl defines a kernel parameter to be
-                                set
-                              properties:
-                                name:
-                                  description: Name of a property to set
-                                  type: string
-                                value:
-                                  description: Value of a property to set
-                                  type: string
-                              required:
-                              - name
-                              - value
-                              type: object
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          windowsOptions:
-                            description: |-
-                              The Windows specific settings applied to all containers.
-                              If unspecified, the options within a container's SecurityContext will be used.
-                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
-                              Note that this field cannot be set when spec.os.name is linux.
-                            properties:
-                              gmsaCredentialSpec:
-                                description: |-
-                                  GMSACredentialSpec is where the GMSA admission webhook
-                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
-                                  GMSA credential spec named by the GMSACredentialSpecName field.
-                                type: string
-                              gmsaCredentialSpecName:
-                                description: GMSACredentialSpecName is the name of
-                                  the GMSA credential spec to use.
-                                type: string
-                              hostProcess:
-                                description: |-
-                                  HostProcess determines if a container should be run as a 'Host Process' container.
-                                  All of a Pod's containers must have the same effective HostProcess value
-                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
-                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
-                                type: boolean
-                              runAsUserName:
-                                description: |-
-                                  The UserName in Windows to run the entrypoint of the container process.
-                                  Defaults to the user specified in image metadata if unspecified.
-                                  May also be set in PodSecurityContext. If set in both SecurityContext and
-                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
-                                type: string
-                            type: object
-                        type: object
-                      workload:
-                        description: Workload - customize the container template of
-                          the workload
+                      container:
+                        description: ContainerSpec - customize the container template
+                          of the workload
                         properties:
                           additionalEnv:
                             items:
@@ -2699,6 +2460,245 @@ spec:
                               type: object
                             type: array
                         type: object
+                      replicas:
+                        format: int32
+                        type: integer
+                      securityContext:
+                        description: |-
+                          PodSecurityContext holds pod-level security attributes and common container settings.
+                          Some fields are also present in container.securityContext.  Field values of
+                          container.securityContext take precedence over field values of PodSecurityContext.
+                        properties:
+                          appArmorProfile:
+                            description: |-
+                              appArmorProfile is the AppArmor options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile loaded on the node that should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must match the loaded name of the profile.
+                                  Must be set if and only if type is "Localhost".
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of AppArmor profile will be applied.
+                                  Valid options are:
+                                    Localhost - a profile pre-loaded on the node.
+                                    RuntimeDefault - the container runtime's default profile.
+                                    Unconfined - no AppArmor enforcement.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          fsGroup:
+                            description: |-
+                              A special supplemental group that applies to all containers in a pod.
+                              Some volume types allow the Kubelet to change the ownership of that volume
+                              to be owned by the pod:
+
+                              1. The owning GID will be the FSGroup
+                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
+                              3. The permission bits are OR'd with rw-rw----
+
+                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          fsGroupChangePolicy:
+                            description: |-
+                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
+                              before being exposed inside Pod. This field will only apply to
+                              volume types which support fsGroup based ownership(and permissions).
+                              It will have no effect on ephemeral volume types such as: secret, configmaps
+                              and emptydir.
+                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          runAsGroup:
+                            description: |-
+                              The GID to run the entrypoint of the container process.
+                              Uses runtime default if unset.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          runAsNonRoot:
+                            description: |-
+                              Indicates that the container must run as a non-root user.
+                              If true, the Kubelet will validate the image at runtime to ensure that it
+                              does not run as UID 0 (root) and fail to start the container if it does.
+                              If unset or false, no such validation will be performed.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence.
+                            type: boolean
+                          runAsUser:
+                            description: |-
+                              The UID to run the entrypoint of the container process.
+                              Defaults to user specified in image metadata if unspecified.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          seLinuxChangePolicy:
+                            description: |-
+                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
+                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
+                              Valid values are "MountOption" and "Recursive".
+
+                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
+                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
+
+                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
+                              This requires all Pods that share the same volume to use the same SELinux label.
+                              It is not possible to share the same volume among privileged and unprivileged Pods.
+                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
+                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
+                              CSIDriver instance. Other volumes are always re-labelled recursively.
+                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
+
+                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
+                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
+                              and "Recursive" for all other volumes.
+
+                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
+
+                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          seLinuxOptions:
+                            description: |-
+                              The SELinux context to be applied to all containers.
+                              If unspecified, the container runtime will allocate a random SELinux context for each
+                              container.  May also be set in SecurityContext.  If set in
+                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
+                              takes precedence for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              level:
+                                description: Level is SELinux level label that applies
+                                  to the container.
+                                type: string
+                              role:
+                                description: Role is a SELinux role label that applies
+                                  to the container.
+                                type: string
+                              type:
+                                description: Type is a SELinux type label that applies
+                                  to the container.
+                                type: string
+                              user:
+                                description: User is a SELinux user label that applies
+                                  to the container.
+                                type: string
+                            type: object
+                          seccompProfile:
+                            description: |-
+                              The seccomp options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile defined in a file on the node should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
+                                  Must be set if type is "Localhost". Must NOT be set for any other type.
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of seccomp profile will be applied.
+                                  Valid options are:
+
+                                  Localhost - a profile defined in a file on the node should be used.
+                                  RuntimeDefault - the container runtime default profile should be used.
+                                  Unconfined - no profile should be applied.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          supplementalGroups:
+                            description: |-
+                              A list of groups applied to the first process run in each container, in
+                              addition to the container's primary GID and fsGroup (if specified).  If
+                              the SupplementalGroupsPolicy feature is enabled, the
+                              supplementalGroupsPolicy field determines whether these are in addition
+                              to or instead of any group memberships defined in the container image.
+                              If unspecified, no additional groups are added, though group memberships
+                              defined in the container image may still be used, depending on the
+                              supplementalGroupsPolicy field.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              format: int64
+                              type: integer
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          supplementalGroupsPolicy:
+                            description: |-
+                              Defines how supplemental groups of the first container processes are calculated.
+                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
+                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
+                              and the container runtime must implement support for this feature.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          sysctls:
+                            description: |-
+                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
+                              sysctls (by the container runtime) might fail to launch.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              description: Sysctl defines a kernel parameter to be
+                                set
+                              properties:
+                                name:
+                                  description: Name of a property to set
+                                  type: string
+                                value:
+                                  description: Value of a property to set
+                                  type: string
+                              required:
+                              - name
+                              - value
+                              type: object
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          windowsOptions:
+                            description: |-
+                              The Windows specific settings applied to all containers.
+                              If unspecified, the options within a container's SecurityContext will be used.
+                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
+                              Note that this field cannot be set when spec.os.name is linux.
+                            properties:
+                              gmsaCredentialSpec:
+                                description: |-
+                                  GMSACredentialSpec is where the GMSA admission webhook
+                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
+                                  GMSA credential spec named by the GMSACredentialSpecName field.
+                                type: string
+                              gmsaCredentialSpecName:
+                                description: GMSACredentialSpecName is the name of
+                                  the GMSA credential spec to use.
+                                type: string
+                              hostProcess:
+                                description: |-
+                                  HostProcess determines if a container should be run as a 'Host Process' container.
+                                  All of a Pod's containers must have the same effective HostProcess value
+                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
+                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
+                                type: boolean
+                              runAsUserName:
+                                description: |-
+                                  The UserName in Windows to run the entrypoint of the container process.
+                                  Defaults to the user specified in image metadata if unspecified.
+                                  May also be set in PodSecurityContext. If set in both SecurityContext and
+                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
+                                type: string
+                            type: object
+                        type: object
                     type: object
                 type: object
               database:
@@ -2824,8 +2824,8 @@ spec:
                     items:
                       type: string
                     type: array
-                  workloadTemplate:
-                    description: WorkloadTemplate - customize the PostgREST workload
+                  workloadSpec:
+                    description: WorkloadSpec - customize the PostgREST workload
                     properties:
                       additionalLabels:
                         additionalProperties:
@@ -4631,248 +4631,9 @@ spec:
                           - name
                           type: object
                         type: array
-                      replicas:
-                        format: int32
-                        type: integer
-                      securityContext:
-                        description: |-
-                          PodSecurityContext holds pod-level security attributes and common container settings.
-                          Some fields are also present in container.securityContext.  Field values of
-                          container.securityContext take precedence over field values of PodSecurityContext.
-                        properties:
-                          appArmorProfile:
-                            description: |-
-                              appArmorProfile is the AppArmor options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile loaded on the node that should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must match the loaded name of the profile.
-                                  Must be set if and only if type is "Localhost".
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of AppArmor profile will be applied.
-                                  Valid options are:
-                                    Localhost - a profile pre-loaded on the node.
-                                    RuntimeDefault - the container runtime's default profile.
-                                    Unconfined - no AppArmor enforcement.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          fsGroup:
-                            description: |-
-                              A special supplemental group that applies to all containers in a pod.
-                              Some volume types allow the Kubelet to change the ownership of that volume
-                              to be owned by the pod:
-
-                              1. The owning GID will be the FSGroup
-                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
-                              3. The permission bits are OR'd with rw-rw----
-
-                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          fsGroupChangePolicy:
-                            description: |-
-                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
-                              before being exposed inside Pod. This field will only apply to
-                              volume types which support fsGroup based ownership(and permissions).
-                              It will have no effect on ephemeral volume types such as: secret, configmaps
-                              and emptydir.
-                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          runAsGroup:
-                            description: |-
-                              The GID to run the entrypoint of the container process.
-                              Uses runtime default if unset.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          runAsNonRoot:
-                            description: |-
-                              Indicates that the container must run as a non-root user.
-                              If true, the Kubelet will validate the image at runtime to ensure that it
-                              does not run as UID 0 (root) and fail to start the container if it does.
-                              If unset or false, no such validation will be performed.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence.
-                            type: boolean
-                          runAsUser:
-                            description: |-
-                              The UID to run the entrypoint of the container process.
-                              Defaults to user specified in image metadata if unspecified.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          seLinuxChangePolicy:
-                            description: |-
-                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
-                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
-                              Valid values are "MountOption" and "Recursive".
-
-                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
-                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
-
-                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
-                              This requires all Pods that share the same volume to use the same SELinux label.
-                              It is not possible to share the same volume among privileged and unprivileged Pods.
-                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
-                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
-                              CSIDriver instance. Other volumes are always re-labelled recursively.
-                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
-
-                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
-                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
-                              and "Recursive" for all other volumes.
-
-                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
-
-                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          seLinuxOptions:
-                            description: |-
-                              The SELinux context to be applied to all containers.
-                              If unspecified, the container runtime will allocate a random SELinux context for each
-                              container.  May also be set in SecurityContext.  If set in
-                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
-                              takes precedence for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              level:
-                                description: Level is SELinux level label that applies
-                                  to the container.
-                                type: string
-                              role:
-                                description: Role is a SELinux role label that applies
-                                  to the container.
-                                type: string
-                              type:
-                                description: Type is a SELinux type label that applies
-                                  to the container.
-                                type: string
-                              user:
-                                description: User is a SELinux user label that applies
-                                  to the container.
-                                type: string
-                            type: object
-                          seccompProfile:
-                            description: |-
-                              The seccomp options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile defined in a file on the node should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
-                                  Must be set if type is "Localhost". Must NOT be set for any other type.
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of seccomp profile will be applied.
-                                  Valid options are:
-
-                                  Localhost - a profile defined in a file on the node should be used.
-                                  RuntimeDefault - the container runtime default profile should be used.
-                                  Unconfined - no profile should be applied.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          supplementalGroups:
-                            description: |-
-                              A list of groups applied to the first process run in each container, in
-                              addition to the container's primary GID and fsGroup (if specified).  If
-                              the SupplementalGroupsPolicy feature is enabled, the
-                              supplementalGroupsPolicy field determines whether these are in addition
-                              to or instead of any group memberships defined in the container image.
-                              If unspecified, no additional groups are added, though group memberships
-                              defined in the container image may still be used, depending on the
-                              supplementalGroupsPolicy field.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              format: int64
-                              type: integer
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          supplementalGroupsPolicy:
-                            description: |-
-                              Defines how supplemental groups of the first container processes are calculated.
-                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
-                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
-                              and the container runtime must implement support for this feature.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          sysctls:
-                            description: |-
-                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
-                              sysctls (by the container runtime) might fail to launch.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              description: Sysctl defines a kernel parameter to be
-                                set
-                              properties:
-                                name:
-                                  description: Name of a property to set
-                                  type: string
-                                value:
-                                  description: Value of a property to set
-                                  type: string
-                              required:
-                              - name
-                              - value
-                              type: object
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          windowsOptions:
-                            description: |-
-                              The Windows specific settings applied to all containers.
-                              If unspecified, the options within a container's SecurityContext will be used.
-                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
-                              Note that this field cannot be set when spec.os.name is linux.
-                            properties:
-                              gmsaCredentialSpec:
-                                description: |-
-                                  GMSACredentialSpec is where the GMSA admission webhook
-                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
-                                  GMSA credential spec named by the GMSACredentialSpecName field.
-                                type: string
-                              gmsaCredentialSpecName:
-                                description: GMSACredentialSpecName is the name of
-                                  the GMSA credential spec to use.
-                                type: string
-                              hostProcess:
-                                description: |-
-                                  HostProcess determines if a container should be run as a 'Host Process' container.
-                                  All of a Pod's containers must have the same effective HostProcess value
-                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
-                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
-                                type: boolean
-                              runAsUserName:
-                                description: |-
-                                  The UserName in Windows to run the entrypoint of the container process.
-                                  Defaults to the user specified in image metadata if unspecified.
-                                  May also be set in PodSecurityContext. If set in both SecurityContext and
-                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
-                                type: string
-                            type: object
-                        type: object
-                      workload:
-                        description: Workload - customize the container template of
-                          the workload
+                      container:
+                        description: ContainerSpec - customize the container template
+                          of the workload
                         properties:
                           additionalEnv:
                             items:
@@ -5337,6 +5098,245 @@ spec:
                               type: object
                             type: array
                         type: object
+                      replicas:
+                        format: int32
+                        type: integer
+                      securityContext:
+                        description: |-
+                          PodSecurityContext holds pod-level security attributes and common container settings.
+                          Some fields are also present in container.securityContext.  Field values of
+                          container.securityContext take precedence over field values of PodSecurityContext.
+                        properties:
+                          appArmorProfile:
+                            description: |-
+                              appArmorProfile is the AppArmor options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile loaded on the node that should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must match the loaded name of the profile.
+                                  Must be set if and only if type is "Localhost".
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of AppArmor profile will be applied.
+                                  Valid options are:
+                                    Localhost - a profile pre-loaded on the node.
+                                    RuntimeDefault - the container runtime's default profile.
+                                    Unconfined - no AppArmor enforcement.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          fsGroup:
+                            description: |-
+                              A special supplemental group that applies to all containers in a pod.
+                              Some volume types allow the Kubelet to change the ownership of that volume
+                              to be owned by the pod:
+
+                              1. The owning GID will be the FSGroup
+                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
+                              3. The permission bits are OR'd with rw-rw----
+
+                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          fsGroupChangePolicy:
+                            description: |-
+                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
+                              before being exposed inside Pod. This field will only apply to
+                              volume types which support fsGroup based ownership(and permissions).
+                              It will have no effect on ephemeral volume types such as: secret, configmaps
+                              and emptydir.
+                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          runAsGroup:
+                            description: |-
+                              The GID to run the entrypoint of the container process.
+                              Uses runtime default if unset.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          runAsNonRoot:
+                            description: |-
+                              Indicates that the container must run as a non-root user.
+                              If true, the Kubelet will validate the image at runtime to ensure that it
+                              does not run as UID 0 (root) and fail to start the container if it does.
+                              If unset or false, no such validation will be performed.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence.
+                            type: boolean
+                          runAsUser:
+                            description: |-
+                              The UID to run the entrypoint of the container process.
+                              Defaults to user specified in image metadata if unspecified.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          seLinuxChangePolicy:
+                            description: |-
+                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
+                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
+                              Valid values are "MountOption" and "Recursive".
+
+                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
+                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
+
+                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
+                              This requires all Pods that share the same volume to use the same SELinux label.
+                              It is not possible to share the same volume among privileged and unprivileged Pods.
+                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
+                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
+                              CSIDriver instance. Other volumes are always re-labelled recursively.
+                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
+
+                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
+                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
+                              and "Recursive" for all other volumes.
+
+                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
+
+                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          seLinuxOptions:
+                            description: |-
+                              The SELinux context to be applied to all containers.
+                              If unspecified, the container runtime will allocate a random SELinux context for each
+                              container.  May also be set in SecurityContext.  If set in
+                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
+                              takes precedence for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              level:
+                                description: Level is SELinux level label that applies
+                                  to the container.
+                                type: string
+                              role:
+                                description: Role is a SELinux role label that applies
+                                  to the container.
+                                type: string
+                              type:
+                                description: Type is a SELinux type label that applies
+                                  to the container.
+                                type: string
+                              user:
+                                description: User is a SELinux user label that applies
+                                  to the container.
+                                type: string
+                            type: object
+                          seccompProfile:
+                            description: |-
+                              The seccomp options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile defined in a file on the node should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
+                                  Must be set if type is "Localhost". Must NOT be set for any other type.
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of seccomp profile will be applied.
+                                  Valid options are:
+
+                                  Localhost - a profile defined in a file on the node should be used.
+                                  RuntimeDefault - the container runtime default profile should be used.
+                                  Unconfined - no profile should be applied.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          supplementalGroups:
+                            description: |-
+                              A list of groups applied to the first process run in each container, in
+                              addition to the container's primary GID and fsGroup (if specified).  If
+                              the SupplementalGroupsPolicy feature is enabled, the
+                              supplementalGroupsPolicy field determines whether these are in addition
+                              to or instead of any group memberships defined in the container image.
+                              If unspecified, no additional groups are added, though group memberships
+                              defined in the container image may still be used, depending on the
+                              supplementalGroupsPolicy field.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              format: int64
+                              type: integer
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          supplementalGroupsPolicy:
+                            description: |-
+                              Defines how supplemental groups of the first container processes are calculated.
+                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
+                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
+                              and the container runtime must implement support for this feature.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          sysctls:
+                            description: |-
+                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
+                              sysctls (by the container runtime) might fail to launch.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              description: Sysctl defines a kernel parameter to be
+                                set
+                              properties:
+                                name:
+                                  description: Name of a property to set
+                                  type: string
+                                value:
+                                  description: Value of a property to set
+                                  type: string
+                              required:
+                              - name
+                              - value
+                              type: object
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          windowsOptions:
+                            description: |-
+                              The Windows specific settings applied to all containers.
+                              If unspecified, the options within a container's SecurityContext will be used.
+                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
+                              Note that this field cannot be set when spec.os.name is linux.
+                            properties:
+                              gmsaCredentialSpec:
+                                description: |-
+                                  GMSACredentialSpec is where the GMSA admission webhook
+                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
+                                  GMSA credential spec named by the GMSACredentialSpecName field.
+                                type: string
+                              gmsaCredentialSpecName:
+                                description: GMSACredentialSpecName is the name of
+                                  the GMSA credential spec to use.
+                                type: string
+                              hostProcess:
+                                description: |-
+                                  HostProcess determines if a container should be run as a 'Host Process' container.
+                                  All of a Pod's containers must have the same effective HostProcess value
+                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
+                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
+                                type: boolean
+                              runAsUserName:
+                                description: |-
+                                  The UserName in Windows to run the entrypoint of the container process.
+                                  Defaults to the user specified in image metadata if unspecified.
+                                  May also be set in PodSecurityContext. If set in both SecurityContext and
+                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
+                                type: string
+                            type: object
+                        type: object
                     type: object
                 type: object
               siteUrl:
diff --git a/config/crd/bases/supabase.k8s.icb4dc0.de_dashboards.yaml b/config/crd/bases/supabase.k8s.icb4dc0.de_dashboards.yaml
index 2913ec5..555c8fb 100644
--- a/config/crd/bases/supabase.k8s.icb4dc0.de_dashboards.yaml
+++ b/config/crd/bases/supabase.k8s.icb4dc0.de_dashboards.yaml
@@ -75,7 +75,7 @@ spec:
               pgMeta:
                 description: PGMeta
                 properties:
-                  workloadTemplate:
+                  workloadSpec:
                     description: WorkloadTemplate - customize the pg-meta deployment
                     properties:
                       additionalLabels:
@@ -1882,248 +1882,9 @@ spec:
                           - name
                           type: object
                         type: array
-                      replicas:
-                        format: int32
-                        type: integer
-                      securityContext:
-                        description: |-
-                          PodSecurityContext holds pod-level security attributes and common container settings.
-                          Some fields are also present in container.securityContext.  Field values of
-                          container.securityContext take precedence over field values of PodSecurityContext.
-                        properties:
-                          appArmorProfile:
-                            description: |-
-                              appArmorProfile is the AppArmor options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile loaded on the node that should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must match the loaded name of the profile.
-                                  Must be set if and only if type is "Localhost".
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of AppArmor profile will be applied.
-                                  Valid options are:
-                                    Localhost - a profile pre-loaded on the node.
-                                    RuntimeDefault - the container runtime's default profile.
-                                    Unconfined - no AppArmor enforcement.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          fsGroup:
-                            description: |-
-                              A special supplemental group that applies to all containers in a pod.
-                              Some volume types allow the Kubelet to change the ownership of that volume
-                              to be owned by the pod:
-
-                              1. The owning GID will be the FSGroup
-                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
-                              3. The permission bits are OR'd with rw-rw----
-
-                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          fsGroupChangePolicy:
-                            description: |-
-                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
-                              before being exposed inside Pod. This field will only apply to
-                              volume types which support fsGroup based ownership(and permissions).
-                              It will have no effect on ephemeral volume types such as: secret, configmaps
-                              and emptydir.
-                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          runAsGroup:
-                            description: |-
-                              The GID to run the entrypoint of the container process.
-                              Uses runtime default if unset.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          runAsNonRoot:
-                            description: |-
-                              Indicates that the container must run as a non-root user.
-                              If true, the Kubelet will validate the image at runtime to ensure that it
-                              does not run as UID 0 (root) and fail to start the container if it does.
-                              If unset or false, no such validation will be performed.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence.
-                            type: boolean
-                          runAsUser:
-                            description: |-
-                              The UID to run the entrypoint of the container process.
-                              Defaults to user specified in image metadata if unspecified.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          seLinuxChangePolicy:
-                            description: |-
-                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
-                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
-                              Valid values are "MountOption" and "Recursive".
-
-                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
-                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
-
-                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
-                              This requires all Pods that share the same volume to use the same SELinux label.
-                              It is not possible to share the same volume among privileged and unprivileged Pods.
-                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
-                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
-                              CSIDriver instance. Other volumes are always re-labelled recursively.
-                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
-
-                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
-                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
-                              and "Recursive" for all other volumes.
-
-                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
-
-                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          seLinuxOptions:
-                            description: |-
-                              The SELinux context to be applied to all containers.
-                              If unspecified, the container runtime will allocate a random SELinux context for each
-                              container.  May also be set in SecurityContext.  If set in
-                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
-                              takes precedence for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              level:
-                                description: Level is SELinux level label that applies
-                                  to the container.
-                                type: string
-                              role:
-                                description: Role is a SELinux role label that applies
-                                  to the container.
-                                type: string
-                              type:
-                                description: Type is a SELinux type label that applies
-                                  to the container.
-                                type: string
-                              user:
-                                description: User is a SELinux user label that applies
-                                  to the container.
-                                type: string
-                            type: object
-                          seccompProfile:
-                            description: |-
-                              The seccomp options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile defined in a file on the node should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
-                                  Must be set if type is "Localhost". Must NOT be set for any other type.
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of seccomp profile will be applied.
-                                  Valid options are:
-
-                                  Localhost - a profile defined in a file on the node should be used.
-                                  RuntimeDefault - the container runtime default profile should be used.
-                                  Unconfined - no profile should be applied.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          supplementalGroups:
-                            description: |-
-                              A list of groups applied to the first process run in each container, in
-                              addition to the container's primary GID and fsGroup (if specified).  If
-                              the SupplementalGroupsPolicy feature is enabled, the
-                              supplementalGroupsPolicy field determines whether these are in addition
-                              to or instead of any group memberships defined in the container image.
-                              If unspecified, no additional groups are added, though group memberships
-                              defined in the container image may still be used, depending on the
-                              supplementalGroupsPolicy field.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              format: int64
-                              type: integer
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          supplementalGroupsPolicy:
-                            description: |-
-                              Defines how supplemental groups of the first container processes are calculated.
-                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
-                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
-                              and the container runtime must implement support for this feature.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          sysctls:
-                            description: |-
-                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
-                              sysctls (by the container runtime) might fail to launch.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              description: Sysctl defines a kernel parameter to be
-                                set
-                              properties:
-                                name:
-                                  description: Name of a property to set
-                                  type: string
-                                value:
-                                  description: Value of a property to set
-                                  type: string
-                              required:
-                              - name
-                              - value
-                              type: object
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          windowsOptions:
-                            description: |-
-                              The Windows specific settings applied to all containers.
-                              If unspecified, the options within a container's SecurityContext will be used.
-                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
-                              Note that this field cannot be set when spec.os.name is linux.
-                            properties:
-                              gmsaCredentialSpec:
-                                description: |-
-                                  GMSACredentialSpec is where the GMSA admission webhook
-                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
-                                  GMSA credential spec named by the GMSACredentialSpecName field.
-                                type: string
-                              gmsaCredentialSpecName:
-                                description: GMSACredentialSpecName is the name of
-                                  the GMSA credential spec to use.
-                                type: string
-                              hostProcess:
-                                description: |-
-                                  HostProcess determines if a container should be run as a 'Host Process' container.
-                                  All of a Pod's containers must have the same effective HostProcess value
-                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
-                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
-                                type: boolean
-                              runAsUserName:
-                                description: |-
-                                  The UserName in Windows to run the entrypoint of the container process.
-                                  Defaults to the user specified in image metadata if unspecified.
-                                  May also be set in PodSecurityContext. If set in both SecurityContext and
-                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
-                                type: string
-                            type: object
-                        type: object
-                      workload:
-                        description: Workload - customize the container template of
-                          the workload
+                      container:
+                        description: ContainerSpec - customize the container template
+                          of the workload
                         properties:
                           additionalEnv:
                             items:
@@ -2588,6 +2349,245 @@ spec:
                               type: object
                             type: array
                         type: object
+                      replicas:
+                        format: int32
+                        type: integer
+                      securityContext:
+                        description: |-
+                          PodSecurityContext holds pod-level security attributes and common container settings.
+                          Some fields are also present in container.securityContext.  Field values of
+                          container.securityContext take precedence over field values of PodSecurityContext.
+                        properties:
+                          appArmorProfile:
+                            description: |-
+                              appArmorProfile is the AppArmor options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile loaded on the node that should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must match the loaded name of the profile.
+                                  Must be set if and only if type is "Localhost".
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of AppArmor profile will be applied.
+                                  Valid options are:
+                                    Localhost - a profile pre-loaded on the node.
+                                    RuntimeDefault - the container runtime's default profile.
+                                    Unconfined - no AppArmor enforcement.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          fsGroup:
+                            description: |-
+                              A special supplemental group that applies to all containers in a pod.
+                              Some volume types allow the Kubelet to change the ownership of that volume
+                              to be owned by the pod:
+
+                              1. The owning GID will be the FSGroup
+                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
+                              3. The permission bits are OR'd with rw-rw----
+
+                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          fsGroupChangePolicy:
+                            description: |-
+                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
+                              before being exposed inside Pod. This field will only apply to
+                              volume types which support fsGroup based ownership(and permissions).
+                              It will have no effect on ephemeral volume types such as: secret, configmaps
+                              and emptydir.
+                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          runAsGroup:
+                            description: |-
+                              The GID to run the entrypoint of the container process.
+                              Uses runtime default if unset.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          runAsNonRoot:
+                            description: |-
+                              Indicates that the container must run as a non-root user.
+                              If true, the Kubelet will validate the image at runtime to ensure that it
+                              does not run as UID 0 (root) and fail to start the container if it does.
+                              If unset or false, no such validation will be performed.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence.
+                            type: boolean
+                          runAsUser:
+                            description: |-
+                              The UID to run the entrypoint of the container process.
+                              Defaults to user specified in image metadata if unspecified.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          seLinuxChangePolicy:
+                            description: |-
+                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
+                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
+                              Valid values are "MountOption" and "Recursive".
+
+                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
+                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
+
+                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
+                              This requires all Pods that share the same volume to use the same SELinux label.
+                              It is not possible to share the same volume among privileged and unprivileged Pods.
+                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
+                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
+                              CSIDriver instance. Other volumes are always re-labelled recursively.
+                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
+
+                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
+                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
+                              and "Recursive" for all other volumes.
+
+                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
+
+                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          seLinuxOptions:
+                            description: |-
+                              The SELinux context to be applied to all containers.
+                              If unspecified, the container runtime will allocate a random SELinux context for each
+                              container.  May also be set in SecurityContext.  If set in
+                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
+                              takes precedence for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              level:
+                                description: Level is SELinux level label that applies
+                                  to the container.
+                                type: string
+                              role:
+                                description: Role is a SELinux role label that applies
+                                  to the container.
+                                type: string
+                              type:
+                                description: Type is a SELinux type label that applies
+                                  to the container.
+                                type: string
+                              user:
+                                description: User is a SELinux user label that applies
+                                  to the container.
+                                type: string
+                            type: object
+                          seccompProfile:
+                            description: |-
+                              The seccomp options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile defined in a file on the node should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
+                                  Must be set if type is "Localhost". Must NOT be set for any other type.
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of seccomp profile will be applied.
+                                  Valid options are:
+
+                                  Localhost - a profile defined in a file on the node should be used.
+                                  RuntimeDefault - the container runtime default profile should be used.
+                                  Unconfined - no profile should be applied.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          supplementalGroups:
+                            description: |-
+                              A list of groups applied to the first process run in each container, in
+                              addition to the container's primary GID and fsGroup (if specified).  If
+                              the SupplementalGroupsPolicy feature is enabled, the
+                              supplementalGroupsPolicy field determines whether these are in addition
+                              to or instead of any group memberships defined in the container image.
+                              If unspecified, no additional groups are added, though group memberships
+                              defined in the container image may still be used, depending on the
+                              supplementalGroupsPolicy field.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              format: int64
+                              type: integer
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          supplementalGroupsPolicy:
+                            description: |-
+                              Defines how supplemental groups of the first container processes are calculated.
+                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
+                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
+                              and the container runtime must implement support for this feature.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          sysctls:
+                            description: |-
+                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
+                              sysctls (by the container runtime) might fail to launch.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              description: Sysctl defines a kernel parameter to be
+                                set
+                              properties:
+                                name:
+                                  description: Name of a property to set
+                                  type: string
+                                value:
+                                  description: Value of a property to set
+                                  type: string
+                              required:
+                              - name
+                              - value
+                              type: object
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          windowsOptions:
+                            description: |-
+                              The Windows specific settings applied to all containers.
+                              If unspecified, the options within a container's SecurityContext will be used.
+                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
+                              Note that this field cannot be set when spec.os.name is linux.
+                            properties:
+                              gmsaCredentialSpec:
+                                description: |-
+                                  GMSACredentialSpec is where the GMSA admission webhook
+                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
+                                  GMSA credential spec named by the GMSACredentialSpecName field.
+                                type: string
+                              gmsaCredentialSpecName:
+                                description: GMSACredentialSpecName is the name of
+                                  the GMSA credential spec to use.
+                                type: string
+                              hostProcess:
+                                description: |-
+                                  HostProcess determines if a container should be run as a 'Host Process' container.
+                                  All of a Pod's containers must have the same effective HostProcess value
+                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
+                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
+                                type: boolean
+                              runAsUserName:
+                                description: |-
+                                  The UserName in Windows to run the entrypoint of the container process.
+                                  Defaults to the user specified in image metadata if unspecified.
+                                  May also be set in PodSecurityContext. If set in both SecurityContext and
+                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
+                                type: string
+                            type: object
+                        type: object
                     type: object
                 type: object
               studio:
@@ -2636,7 +2636,7 @@ spec:
                           service JWT from
                         type: string
                     type: object
-                  workloadTemplate:
+                  workloadSpec:
                     description: WorkloadTemplate - customize the studio deployment
                     properties:
                       additionalLabels:
@@ -4443,248 +4443,9 @@ spec:
                           - name
                           type: object
                         type: array
-                      replicas:
-                        format: int32
-                        type: integer
-                      securityContext:
-                        description: |-
-                          PodSecurityContext holds pod-level security attributes and common container settings.
-                          Some fields are also present in container.securityContext.  Field values of
-                          container.securityContext take precedence over field values of PodSecurityContext.
-                        properties:
-                          appArmorProfile:
-                            description: |-
-                              appArmorProfile is the AppArmor options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile loaded on the node that should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must match the loaded name of the profile.
-                                  Must be set if and only if type is "Localhost".
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of AppArmor profile will be applied.
-                                  Valid options are:
-                                    Localhost - a profile pre-loaded on the node.
-                                    RuntimeDefault - the container runtime's default profile.
-                                    Unconfined - no AppArmor enforcement.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          fsGroup:
-                            description: |-
-                              A special supplemental group that applies to all containers in a pod.
-                              Some volume types allow the Kubelet to change the ownership of that volume
-                              to be owned by the pod:
-
-                              1. The owning GID will be the FSGroup
-                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
-                              3. The permission bits are OR'd with rw-rw----
-
-                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          fsGroupChangePolicy:
-                            description: |-
-                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
-                              before being exposed inside Pod. This field will only apply to
-                              volume types which support fsGroup based ownership(and permissions).
-                              It will have no effect on ephemeral volume types such as: secret, configmaps
-                              and emptydir.
-                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          runAsGroup:
-                            description: |-
-                              The GID to run the entrypoint of the container process.
-                              Uses runtime default if unset.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          runAsNonRoot:
-                            description: |-
-                              Indicates that the container must run as a non-root user.
-                              If true, the Kubelet will validate the image at runtime to ensure that it
-                              does not run as UID 0 (root) and fail to start the container if it does.
-                              If unset or false, no such validation will be performed.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence.
-                            type: boolean
-                          runAsUser:
-                            description: |-
-                              The UID to run the entrypoint of the container process.
-                              Defaults to user specified in image metadata if unspecified.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          seLinuxChangePolicy:
-                            description: |-
-                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
-                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
-                              Valid values are "MountOption" and "Recursive".
-
-                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
-                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
-
-                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
-                              This requires all Pods that share the same volume to use the same SELinux label.
-                              It is not possible to share the same volume among privileged and unprivileged Pods.
-                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
-                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
-                              CSIDriver instance. Other volumes are always re-labelled recursively.
-                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
-
-                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
-                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
-                              and "Recursive" for all other volumes.
-
-                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
-
-                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          seLinuxOptions:
-                            description: |-
-                              The SELinux context to be applied to all containers.
-                              If unspecified, the container runtime will allocate a random SELinux context for each
-                              container.  May also be set in SecurityContext.  If set in
-                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
-                              takes precedence for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              level:
-                                description: Level is SELinux level label that applies
-                                  to the container.
-                                type: string
-                              role:
-                                description: Role is a SELinux role label that applies
-                                  to the container.
-                                type: string
-                              type:
-                                description: Type is a SELinux type label that applies
-                                  to the container.
-                                type: string
-                              user:
-                                description: User is a SELinux user label that applies
-                                  to the container.
-                                type: string
-                            type: object
-                          seccompProfile:
-                            description: |-
-                              The seccomp options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile defined in a file on the node should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
-                                  Must be set if type is "Localhost". Must NOT be set for any other type.
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of seccomp profile will be applied.
-                                  Valid options are:
-
-                                  Localhost - a profile defined in a file on the node should be used.
-                                  RuntimeDefault - the container runtime default profile should be used.
-                                  Unconfined - no profile should be applied.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          supplementalGroups:
-                            description: |-
-                              A list of groups applied to the first process run in each container, in
-                              addition to the container's primary GID and fsGroup (if specified).  If
-                              the SupplementalGroupsPolicy feature is enabled, the
-                              supplementalGroupsPolicy field determines whether these are in addition
-                              to or instead of any group memberships defined in the container image.
-                              If unspecified, no additional groups are added, though group memberships
-                              defined in the container image may still be used, depending on the
-                              supplementalGroupsPolicy field.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              format: int64
-                              type: integer
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          supplementalGroupsPolicy:
-                            description: |-
-                              Defines how supplemental groups of the first container processes are calculated.
-                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
-                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
-                              and the container runtime must implement support for this feature.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          sysctls:
-                            description: |-
-                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
-                              sysctls (by the container runtime) might fail to launch.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              description: Sysctl defines a kernel parameter to be
-                                set
-                              properties:
-                                name:
-                                  description: Name of a property to set
-                                  type: string
-                                value:
-                                  description: Value of a property to set
-                                  type: string
-                              required:
-                              - name
-                              - value
-                              type: object
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          windowsOptions:
-                            description: |-
-                              The Windows specific settings applied to all containers.
-                              If unspecified, the options within a container's SecurityContext will be used.
-                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
-                              Note that this field cannot be set when spec.os.name is linux.
-                            properties:
-                              gmsaCredentialSpec:
-                                description: |-
-                                  GMSACredentialSpec is where the GMSA admission webhook
-                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
-                                  GMSA credential spec named by the GMSACredentialSpecName field.
-                                type: string
-                              gmsaCredentialSpecName:
-                                description: GMSACredentialSpecName is the name of
-                                  the GMSA credential spec to use.
-                                type: string
-                              hostProcess:
-                                description: |-
-                                  HostProcess determines if a container should be run as a 'Host Process' container.
-                                  All of a Pod's containers must have the same effective HostProcess value
-                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
-                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
-                                type: boolean
-                              runAsUserName:
-                                description: |-
-                                  The UserName in Windows to run the entrypoint of the container process.
-                                  Defaults to the user specified in image metadata if unspecified.
-                                  May also be set in PodSecurityContext. If set in both SecurityContext and
-                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
-                                type: string
-                            type: object
-                        type: object
-                      workload:
-                        description: Workload - customize the container template of
-                          the workload
+                      container:
+                        description: ContainerSpec - customize the container template
+                          of the workload
                         properties:
                           additionalEnv:
                             items:
@@ -5149,6 +4910,245 @@ spec:
                               type: object
                             type: array
                         type: object
+                      replicas:
+                        format: int32
+                        type: integer
+                      securityContext:
+                        description: |-
+                          PodSecurityContext holds pod-level security attributes and common container settings.
+                          Some fields are also present in container.securityContext.  Field values of
+                          container.securityContext take precedence over field values of PodSecurityContext.
+                        properties:
+                          appArmorProfile:
+                            description: |-
+                              appArmorProfile is the AppArmor options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile loaded on the node that should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must match the loaded name of the profile.
+                                  Must be set if and only if type is "Localhost".
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of AppArmor profile will be applied.
+                                  Valid options are:
+                                    Localhost - a profile pre-loaded on the node.
+                                    RuntimeDefault - the container runtime's default profile.
+                                    Unconfined - no AppArmor enforcement.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          fsGroup:
+                            description: |-
+                              A special supplemental group that applies to all containers in a pod.
+                              Some volume types allow the Kubelet to change the ownership of that volume
+                              to be owned by the pod:
+
+                              1. The owning GID will be the FSGroup
+                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
+                              3. The permission bits are OR'd with rw-rw----
+
+                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          fsGroupChangePolicy:
+                            description: |-
+                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
+                              before being exposed inside Pod. This field will only apply to
+                              volume types which support fsGroup based ownership(and permissions).
+                              It will have no effect on ephemeral volume types such as: secret, configmaps
+                              and emptydir.
+                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          runAsGroup:
+                            description: |-
+                              The GID to run the entrypoint of the container process.
+                              Uses runtime default if unset.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          runAsNonRoot:
+                            description: |-
+                              Indicates that the container must run as a non-root user.
+                              If true, the Kubelet will validate the image at runtime to ensure that it
+                              does not run as UID 0 (root) and fail to start the container if it does.
+                              If unset or false, no such validation will be performed.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence.
+                            type: boolean
+                          runAsUser:
+                            description: |-
+                              The UID to run the entrypoint of the container process.
+                              Defaults to user specified in image metadata if unspecified.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          seLinuxChangePolicy:
+                            description: |-
+                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
+                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
+                              Valid values are "MountOption" and "Recursive".
+
+                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
+                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
+
+                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
+                              This requires all Pods that share the same volume to use the same SELinux label.
+                              It is not possible to share the same volume among privileged and unprivileged Pods.
+                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
+                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
+                              CSIDriver instance. Other volumes are always re-labelled recursively.
+                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
+
+                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
+                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
+                              and "Recursive" for all other volumes.
+
+                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
+
+                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          seLinuxOptions:
+                            description: |-
+                              The SELinux context to be applied to all containers.
+                              If unspecified, the container runtime will allocate a random SELinux context for each
+                              container.  May also be set in SecurityContext.  If set in
+                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
+                              takes precedence for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              level:
+                                description: Level is SELinux level label that applies
+                                  to the container.
+                                type: string
+                              role:
+                                description: Role is a SELinux role label that applies
+                                  to the container.
+                                type: string
+                              type:
+                                description: Type is a SELinux type label that applies
+                                  to the container.
+                                type: string
+                              user:
+                                description: User is a SELinux user label that applies
+                                  to the container.
+                                type: string
+                            type: object
+                          seccompProfile:
+                            description: |-
+                              The seccomp options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile defined in a file on the node should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
+                                  Must be set if type is "Localhost". Must NOT be set for any other type.
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of seccomp profile will be applied.
+                                  Valid options are:
+
+                                  Localhost - a profile defined in a file on the node should be used.
+                                  RuntimeDefault - the container runtime default profile should be used.
+                                  Unconfined - no profile should be applied.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          supplementalGroups:
+                            description: |-
+                              A list of groups applied to the first process run in each container, in
+                              addition to the container's primary GID and fsGroup (if specified).  If
+                              the SupplementalGroupsPolicy feature is enabled, the
+                              supplementalGroupsPolicy field determines whether these are in addition
+                              to or instead of any group memberships defined in the container image.
+                              If unspecified, no additional groups are added, though group memberships
+                              defined in the container image may still be used, depending on the
+                              supplementalGroupsPolicy field.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              format: int64
+                              type: integer
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          supplementalGroupsPolicy:
+                            description: |-
+                              Defines how supplemental groups of the first container processes are calculated.
+                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
+                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
+                              and the container runtime must implement support for this feature.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          sysctls:
+                            description: |-
+                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
+                              sysctls (by the container runtime) might fail to launch.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              description: Sysctl defines a kernel parameter to be
+                                set
+                              properties:
+                                name:
+                                  description: Name of a property to set
+                                  type: string
+                                value:
+                                  description: Value of a property to set
+                                  type: string
+                              required:
+                              - name
+                              - value
+                              type: object
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          windowsOptions:
+                            description: |-
+                              The Windows specific settings applied to all containers.
+                              If unspecified, the options within a container's SecurityContext will be used.
+                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
+                              Note that this field cannot be set when spec.os.name is linux.
+                            properties:
+                              gmsaCredentialSpec:
+                                description: |-
+                                  GMSACredentialSpec is where the GMSA admission webhook
+                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
+                                  GMSA credential spec named by the GMSACredentialSpecName field.
+                                type: string
+                              gmsaCredentialSpecName:
+                                description: GMSACredentialSpecName is the name of
+                                  the GMSA credential spec to use.
+                                type: string
+                              hostProcess:
+                                description: |-
+                                  HostProcess determines if a container should be run as a 'Host Process' container.
+                                  All of a Pod's containers must have the same effective HostProcess value
+                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
+                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
+                                type: boolean
+                              runAsUserName:
+                                description: |-
+                                  The UserName in Windows to run the entrypoint of the container process.
+                                  Defaults to the user specified in image metadata if unspecified.
+                                  May also be set in PodSecurityContext. If set in both SecurityContext and
+                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
+                                type: string
+                            type: object
+                        type: object
                     type: object
                 required:
                 - externalUrl
diff --git a/config/crd/bases/supabase.k8s.icb4dc0.de_storages.yaml b/config/crd/bases/supabase.k8s.icb4dc0.de_storages.yaml
index 22a7a80..32a2b94 100644
--- a/config/crd/bases/supabase.k8s.icb4dc0.de_storages.yaml
+++ b/config/crd/bases/supabase.k8s.icb4dc0.de_storages.yaml
@@ -210,7 +210,7 @@ spec:
                         pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                         x-kubernetes-int-or-string: true
                     type: object
-                  workloadTemplate:
+                  workloadSpec:
                     description: WorkloadTemplate - customize the Storage API workload
                     properties:
                       additionalLabels:
@@ -2017,248 +2017,9 @@ spec:
                           - name
                           type: object
                         type: array
-                      replicas:
-                        format: int32
-                        type: integer
-                      securityContext:
-                        description: |-
-                          PodSecurityContext holds pod-level security attributes and common container settings.
-                          Some fields are also present in container.securityContext.  Field values of
-                          container.securityContext take precedence over field values of PodSecurityContext.
-                        properties:
-                          appArmorProfile:
-                            description: |-
-                              appArmorProfile is the AppArmor options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile loaded on the node that should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must match the loaded name of the profile.
-                                  Must be set if and only if type is "Localhost".
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of AppArmor profile will be applied.
-                                  Valid options are:
-                                    Localhost - a profile pre-loaded on the node.
-                                    RuntimeDefault - the container runtime's default profile.
-                                    Unconfined - no AppArmor enforcement.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          fsGroup:
-                            description: |-
-                              A special supplemental group that applies to all containers in a pod.
-                              Some volume types allow the Kubelet to change the ownership of that volume
-                              to be owned by the pod:
-
-                              1. The owning GID will be the FSGroup
-                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
-                              3. The permission bits are OR'd with rw-rw----
-
-                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          fsGroupChangePolicy:
-                            description: |-
-                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
-                              before being exposed inside Pod. This field will only apply to
-                              volume types which support fsGroup based ownership(and permissions).
-                              It will have no effect on ephemeral volume types such as: secret, configmaps
-                              and emptydir.
-                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          runAsGroup:
-                            description: |-
-                              The GID to run the entrypoint of the container process.
-                              Uses runtime default if unset.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          runAsNonRoot:
-                            description: |-
-                              Indicates that the container must run as a non-root user.
-                              If true, the Kubelet will validate the image at runtime to ensure that it
-                              does not run as UID 0 (root) and fail to start the container if it does.
-                              If unset or false, no such validation will be performed.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence.
-                            type: boolean
-                          runAsUser:
-                            description: |-
-                              The UID to run the entrypoint of the container process.
-                              Defaults to user specified in image metadata if unspecified.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          seLinuxChangePolicy:
-                            description: |-
-                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
-                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
-                              Valid values are "MountOption" and "Recursive".
-
-                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
-                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
-
-                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
-                              This requires all Pods that share the same volume to use the same SELinux label.
-                              It is not possible to share the same volume among privileged and unprivileged Pods.
-                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
-                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
-                              CSIDriver instance. Other volumes are always re-labelled recursively.
-                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
-
-                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
-                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
-                              and "Recursive" for all other volumes.
-
-                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
-
-                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          seLinuxOptions:
-                            description: |-
-                              The SELinux context to be applied to all containers.
-                              If unspecified, the container runtime will allocate a random SELinux context for each
-                              container.  May also be set in SecurityContext.  If set in
-                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
-                              takes precedence for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              level:
-                                description: Level is SELinux level label that applies
-                                  to the container.
-                                type: string
-                              role:
-                                description: Role is a SELinux role label that applies
-                                  to the container.
-                                type: string
-                              type:
-                                description: Type is a SELinux type label that applies
-                                  to the container.
-                                type: string
-                              user:
-                                description: User is a SELinux user label that applies
-                                  to the container.
-                                type: string
-                            type: object
-                          seccompProfile:
-                            description: |-
-                              The seccomp options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile defined in a file on the node should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
-                                  Must be set if type is "Localhost". Must NOT be set for any other type.
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of seccomp profile will be applied.
-                                  Valid options are:
-
-                                  Localhost - a profile defined in a file on the node should be used.
-                                  RuntimeDefault - the container runtime default profile should be used.
-                                  Unconfined - no profile should be applied.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          supplementalGroups:
-                            description: |-
-                              A list of groups applied to the first process run in each container, in
-                              addition to the container's primary GID and fsGroup (if specified).  If
-                              the SupplementalGroupsPolicy feature is enabled, the
-                              supplementalGroupsPolicy field determines whether these are in addition
-                              to or instead of any group memberships defined in the container image.
-                              If unspecified, no additional groups are added, though group memberships
-                              defined in the container image may still be used, depending on the
-                              supplementalGroupsPolicy field.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              format: int64
-                              type: integer
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          supplementalGroupsPolicy:
-                            description: |-
-                              Defines how supplemental groups of the first container processes are calculated.
-                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
-                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
-                              and the container runtime must implement support for this feature.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          sysctls:
-                            description: |-
-                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
-                              sysctls (by the container runtime) might fail to launch.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              description: Sysctl defines a kernel parameter to be
-                                set
-                              properties:
-                                name:
-                                  description: Name of a property to set
-                                  type: string
-                                value:
-                                  description: Value of a property to set
-                                  type: string
-                              required:
-                              - name
-                              - value
-                              type: object
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          windowsOptions:
-                            description: |-
-                              The Windows specific settings applied to all containers.
-                              If unspecified, the options within a container's SecurityContext will be used.
-                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
-                              Note that this field cannot be set when spec.os.name is linux.
-                            properties:
-                              gmsaCredentialSpec:
-                                description: |-
-                                  GMSACredentialSpec is where the GMSA admission webhook
-                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
-                                  GMSA credential spec named by the GMSACredentialSpecName field.
-                                type: string
-                              gmsaCredentialSpecName:
-                                description: GMSACredentialSpecName is the name of
-                                  the GMSA credential spec to use.
-                                type: string
-                              hostProcess:
-                                description: |-
-                                  HostProcess determines if a container should be run as a 'Host Process' container.
-                                  All of a Pod's containers must have the same effective HostProcess value
-                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
-                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
-                                type: boolean
-                              runAsUserName:
-                                description: |-
-                                  The UserName in Windows to run the entrypoint of the container process.
-                                  Defaults to the user specified in image metadata if unspecified.
-                                  May also be set in PodSecurityContext. If set in both SecurityContext and
-                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
-                                type: string
-                            type: object
-                        type: object
-                      workload:
-                        description: Workload - customize the container template of
-                          the workload
+                      container:
+                        description: ContainerSpec - customize the container template
+                          of the workload
                         properties:
                           additionalEnv:
                             items:
@@ -2723,6 +2484,245 @@ spec:
                               type: object
                             type: array
                         type: object
+                      replicas:
+                        format: int32
+                        type: integer
+                      securityContext:
+                        description: |-
+                          PodSecurityContext holds pod-level security attributes and common container settings.
+                          Some fields are also present in container.securityContext.  Field values of
+                          container.securityContext take precedence over field values of PodSecurityContext.
+                        properties:
+                          appArmorProfile:
+                            description: |-
+                              appArmorProfile is the AppArmor options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile loaded on the node that should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must match the loaded name of the profile.
+                                  Must be set if and only if type is "Localhost".
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of AppArmor profile will be applied.
+                                  Valid options are:
+                                    Localhost - a profile pre-loaded on the node.
+                                    RuntimeDefault - the container runtime's default profile.
+                                    Unconfined - no AppArmor enforcement.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          fsGroup:
+                            description: |-
+                              A special supplemental group that applies to all containers in a pod.
+                              Some volume types allow the Kubelet to change the ownership of that volume
+                              to be owned by the pod:
+
+                              1. The owning GID will be the FSGroup
+                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
+                              3. The permission bits are OR'd with rw-rw----
+
+                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          fsGroupChangePolicy:
+                            description: |-
+                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
+                              before being exposed inside Pod. This field will only apply to
+                              volume types which support fsGroup based ownership(and permissions).
+                              It will have no effect on ephemeral volume types such as: secret, configmaps
+                              and emptydir.
+                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          runAsGroup:
+                            description: |-
+                              The GID to run the entrypoint of the container process.
+                              Uses runtime default if unset.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          runAsNonRoot:
+                            description: |-
+                              Indicates that the container must run as a non-root user.
+                              If true, the Kubelet will validate the image at runtime to ensure that it
+                              does not run as UID 0 (root) and fail to start the container if it does.
+                              If unset or false, no such validation will be performed.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence.
+                            type: boolean
+                          runAsUser:
+                            description: |-
+                              The UID to run the entrypoint of the container process.
+                              Defaults to user specified in image metadata if unspecified.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          seLinuxChangePolicy:
+                            description: |-
+                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
+                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
+                              Valid values are "MountOption" and "Recursive".
+
+                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
+                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
+
+                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
+                              This requires all Pods that share the same volume to use the same SELinux label.
+                              It is not possible to share the same volume among privileged and unprivileged Pods.
+                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
+                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
+                              CSIDriver instance. Other volumes are always re-labelled recursively.
+                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
+
+                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
+                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
+                              and "Recursive" for all other volumes.
+
+                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
+
+                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          seLinuxOptions:
+                            description: |-
+                              The SELinux context to be applied to all containers.
+                              If unspecified, the container runtime will allocate a random SELinux context for each
+                              container.  May also be set in SecurityContext.  If set in
+                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
+                              takes precedence for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              level:
+                                description: Level is SELinux level label that applies
+                                  to the container.
+                                type: string
+                              role:
+                                description: Role is a SELinux role label that applies
+                                  to the container.
+                                type: string
+                              type:
+                                description: Type is a SELinux type label that applies
+                                  to the container.
+                                type: string
+                              user:
+                                description: User is a SELinux user label that applies
+                                  to the container.
+                                type: string
+                            type: object
+                          seccompProfile:
+                            description: |-
+                              The seccomp options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile defined in a file on the node should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
+                                  Must be set if type is "Localhost". Must NOT be set for any other type.
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of seccomp profile will be applied.
+                                  Valid options are:
+
+                                  Localhost - a profile defined in a file on the node should be used.
+                                  RuntimeDefault - the container runtime default profile should be used.
+                                  Unconfined - no profile should be applied.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          supplementalGroups:
+                            description: |-
+                              A list of groups applied to the first process run in each container, in
+                              addition to the container's primary GID and fsGroup (if specified).  If
+                              the SupplementalGroupsPolicy feature is enabled, the
+                              supplementalGroupsPolicy field determines whether these are in addition
+                              to or instead of any group memberships defined in the container image.
+                              If unspecified, no additional groups are added, though group memberships
+                              defined in the container image may still be used, depending on the
+                              supplementalGroupsPolicy field.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              format: int64
+                              type: integer
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          supplementalGroupsPolicy:
+                            description: |-
+                              Defines how supplemental groups of the first container processes are calculated.
+                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
+                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
+                              and the container runtime must implement support for this feature.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          sysctls:
+                            description: |-
+                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
+                              sysctls (by the container runtime) might fail to launch.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              description: Sysctl defines a kernel parameter to be
+                                set
+                              properties:
+                                name:
+                                  description: Name of a property to set
+                                  type: string
+                                value:
+                                  description: Value of a property to set
+                                  type: string
+                              required:
+                              - name
+                              - value
+                              type: object
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          windowsOptions:
+                            description: |-
+                              The Windows specific settings applied to all containers.
+                              If unspecified, the options within a container's SecurityContext will be used.
+                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
+                              Note that this field cannot be set when spec.os.name is linux.
+                            properties:
+                              gmsaCredentialSpec:
+                                description: |-
+                                  GMSACredentialSpec is where the GMSA admission webhook
+                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
+                                  GMSA credential spec named by the GMSACredentialSpecName field.
+                                type: string
+                              gmsaCredentialSpecName:
+                                description: GMSACredentialSpecName is the name of
+                                  the GMSA credential spec to use.
+                                type: string
+                              hostProcess:
+                                description: |-
+                                  HostProcess determines if a container should be run as a 'Host Process' container.
+                                  All of a Pod's containers must have the same effective HostProcess value
+                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
+                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
+                                type: boolean
+                              runAsUserName:
+                                description: |-
+                                  The UserName in Windows to run the entrypoint of the container process.
+                                  Defaults to the user specified in image metadata if unspecified.
+                                  May also be set in PodSecurityContext. If set in both SecurityContext and
+                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
+                                type: string
+                            type: object
+                        type: object
                     type: object
                 required:
                 - db
@@ -2738,7 +2738,7 @@ spec:
                     type: boolean
                   enableWebPDetection:
                     type: boolean
-                  workloadTemplate:
+                  workloadSpec:
                     description: WorkloadTemplate - customize the image proxy workload
                     properties:
                       additionalLabels:
@@ -4545,248 +4545,9 @@ spec:
                           - name
                           type: object
                         type: array
-                      replicas:
-                        format: int32
-                        type: integer
-                      securityContext:
-                        description: |-
-                          PodSecurityContext holds pod-level security attributes and common container settings.
-                          Some fields are also present in container.securityContext.  Field values of
-                          container.securityContext take precedence over field values of PodSecurityContext.
-                        properties:
-                          appArmorProfile:
-                            description: |-
-                              appArmorProfile is the AppArmor options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile loaded on the node that should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must match the loaded name of the profile.
-                                  Must be set if and only if type is "Localhost".
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of AppArmor profile will be applied.
-                                  Valid options are:
-                                    Localhost - a profile pre-loaded on the node.
-                                    RuntimeDefault - the container runtime's default profile.
-                                    Unconfined - no AppArmor enforcement.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          fsGroup:
-                            description: |-
-                              A special supplemental group that applies to all containers in a pod.
-                              Some volume types allow the Kubelet to change the ownership of that volume
-                              to be owned by the pod:
-
-                              1. The owning GID will be the FSGroup
-                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
-                              3. The permission bits are OR'd with rw-rw----
-
-                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          fsGroupChangePolicy:
-                            description: |-
-                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
-                              before being exposed inside Pod. This field will only apply to
-                              volume types which support fsGroup based ownership(and permissions).
-                              It will have no effect on ephemeral volume types such as: secret, configmaps
-                              and emptydir.
-                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          runAsGroup:
-                            description: |-
-                              The GID to run the entrypoint of the container process.
-                              Uses runtime default if unset.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          runAsNonRoot:
-                            description: |-
-                              Indicates that the container must run as a non-root user.
-                              If true, the Kubelet will validate the image at runtime to ensure that it
-                              does not run as UID 0 (root) and fail to start the container if it does.
-                              If unset or false, no such validation will be performed.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence.
-                            type: boolean
-                          runAsUser:
-                            description: |-
-                              The UID to run the entrypoint of the container process.
-                              Defaults to user specified in image metadata if unspecified.
-                              May also be set in SecurityContext.  If set in both SecurityContext and
-                              PodSecurityContext, the value specified in SecurityContext takes precedence
-                              for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            format: int64
-                            type: integer
-                          seLinuxChangePolicy:
-                            description: |-
-                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
-                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
-                              Valid values are "MountOption" and "Recursive".
-
-                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
-                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
-
-                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
-                              This requires all Pods that share the same volume to use the same SELinux label.
-                              It is not possible to share the same volume among privileged and unprivileged Pods.
-                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
-                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
-                              CSIDriver instance. Other volumes are always re-labelled recursively.
-                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
-
-                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
-                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
-                              and "Recursive" for all other volumes.
-
-                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
-
-                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          seLinuxOptions:
-                            description: |-
-                              The SELinux context to be applied to all containers.
-                              If unspecified, the container runtime will allocate a random SELinux context for each
-                              container.  May also be set in SecurityContext.  If set in
-                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
-                              takes precedence for that container.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              level:
-                                description: Level is SELinux level label that applies
-                                  to the container.
-                                type: string
-                              role:
-                                description: Role is a SELinux role label that applies
-                                  to the container.
-                                type: string
-                              type:
-                                description: Type is a SELinux type label that applies
-                                  to the container.
-                                type: string
-                              user:
-                                description: User is a SELinux user label that applies
-                                  to the container.
-                                type: string
-                            type: object
-                          seccompProfile:
-                            description: |-
-                              The seccomp options to use by the containers in this pod.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            properties:
-                              localhostProfile:
-                                description: |-
-                                  localhostProfile indicates a profile defined in a file on the node should be used.
-                                  The profile must be preconfigured on the node to work.
-                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
-                                  Must be set if type is "Localhost". Must NOT be set for any other type.
-                                type: string
-                              type:
-                                description: |-
-                                  type indicates which kind of seccomp profile will be applied.
-                                  Valid options are:
-
-                                  Localhost - a profile defined in a file on the node should be used.
-                                  RuntimeDefault - the container runtime default profile should be used.
-                                  Unconfined - no profile should be applied.
-                                type: string
-                            required:
-                            - type
-                            type: object
-                          supplementalGroups:
-                            description: |-
-                              A list of groups applied to the first process run in each container, in
-                              addition to the container's primary GID and fsGroup (if specified).  If
-                              the SupplementalGroupsPolicy feature is enabled, the
-                              supplementalGroupsPolicy field determines whether these are in addition
-                              to or instead of any group memberships defined in the container image.
-                              If unspecified, no additional groups are added, though group memberships
-                              defined in the container image may still be used, depending on the
-                              supplementalGroupsPolicy field.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              format: int64
-                              type: integer
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          supplementalGroupsPolicy:
-                            description: |-
-                              Defines how supplemental groups of the first container processes are calculated.
-                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
-                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
-                              and the container runtime must implement support for this feature.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            type: string
-                          sysctls:
-                            description: |-
-                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
-                              sysctls (by the container runtime) might fail to launch.
-                              Note that this field cannot be set when spec.os.name is windows.
-                            items:
-                              description: Sysctl defines a kernel parameter to be
-                                set
-                              properties:
-                                name:
-                                  description: Name of a property to set
-                                  type: string
-                                value:
-                                  description: Value of a property to set
-                                  type: string
-                              required:
-                              - name
-                              - value
-                              type: object
-                            type: array
-                            x-kubernetes-list-type: atomic
-                          windowsOptions:
-                            description: |-
-                              The Windows specific settings applied to all containers.
-                              If unspecified, the options within a container's SecurityContext will be used.
-                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
-                              Note that this field cannot be set when spec.os.name is linux.
-                            properties:
-                              gmsaCredentialSpec:
-                                description: |-
-                                  GMSACredentialSpec is where the GMSA admission webhook
-                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
-                                  GMSA credential spec named by the GMSACredentialSpecName field.
-                                type: string
-                              gmsaCredentialSpecName:
-                                description: GMSACredentialSpecName is the name of
-                                  the GMSA credential spec to use.
-                                type: string
-                              hostProcess:
-                                description: |-
-                                  HostProcess determines if a container should be run as a 'Host Process' container.
-                                  All of a Pod's containers must have the same effective HostProcess value
-                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
-                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
-                                type: boolean
-                              runAsUserName:
-                                description: |-
-                                  The UserName in Windows to run the entrypoint of the container process.
-                                  Defaults to the user specified in image metadata if unspecified.
-                                  May also be set in PodSecurityContext. If set in both SecurityContext and
-                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
-                                type: string
-                            type: object
-                        type: object
-                      workload:
-                        description: Workload - customize the container template of
-                          the workload
+                      container:
+                        description: ContainerSpec - customize the container template
+                          of the workload
                         properties:
                           additionalEnv:
                             items:
@@ -5251,6 +5012,245 @@ spec:
                               type: object
                             type: array
                         type: object
+                      replicas:
+                        format: int32
+                        type: integer
+                      securityContext:
+                        description: |-
+                          PodSecurityContext holds pod-level security attributes and common container settings.
+                          Some fields are also present in container.securityContext.  Field values of
+                          container.securityContext take precedence over field values of PodSecurityContext.
+                        properties:
+                          appArmorProfile:
+                            description: |-
+                              appArmorProfile is the AppArmor options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile loaded on the node that should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must match the loaded name of the profile.
+                                  Must be set if and only if type is "Localhost".
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of AppArmor profile will be applied.
+                                  Valid options are:
+                                    Localhost - a profile pre-loaded on the node.
+                                    RuntimeDefault - the container runtime's default profile.
+                                    Unconfined - no AppArmor enforcement.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          fsGroup:
+                            description: |-
+                              A special supplemental group that applies to all containers in a pod.
+                              Some volume types allow the Kubelet to change the ownership of that volume
+                              to be owned by the pod:
+
+                              1. The owning GID will be the FSGroup
+                              2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
+                              3. The permission bits are OR'd with rw-rw----
+
+                              If unset, the Kubelet will not modify the ownership and permissions of any volume.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          fsGroupChangePolicy:
+                            description: |-
+                              fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
+                              before being exposed inside Pod. This field will only apply to
+                              volume types which support fsGroup based ownership(and permissions).
+                              It will have no effect on ephemeral volume types such as: secret, configmaps
+                              and emptydir.
+                              Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          runAsGroup:
+                            description: |-
+                              The GID to run the entrypoint of the container process.
+                              Uses runtime default if unset.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          runAsNonRoot:
+                            description: |-
+                              Indicates that the container must run as a non-root user.
+                              If true, the Kubelet will validate the image at runtime to ensure that it
+                              does not run as UID 0 (root) and fail to start the container if it does.
+                              If unset or false, no such validation will be performed.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence.
+                            type: boolean
+                          runAsUser:
+                            description: |-
+                              The UID to run the entrypoint of the container process.
+                              Defaults to user specified in image metadata if unspecified.
+                              May also be set in SecurityContext.  If set in both SecurityContext and
+                              PodSecurityContext, the value specified in SecurityContext takes precedence
+                              for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            format: int64
+                            type: integer
+                          seLinuxChangePolicy:
+                            description: |-
+                              seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
+                              It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
+                              Valid values are "MountOption" and "Recursive".
+
+                              "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
+                              This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
+
+                              "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
+                              This requires all Pods that share the same volume to use the same SELinux label.
+                              It is not possible to share the same volume among privileged and unprivileged Pods.
+                              Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
+                              whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
+                              CSIDriver instance. Other volumes are always re-labelled recursively.
+                              "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
+
+                              If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
+                              If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
+                              and "Recursive" for all other volumes.
+
+                              This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
+
+                              All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          seLinuxOptions:
+                            description: |-
+                              The SELinux context to be applied to all containers.
+                              If unspecified, the container runtime will allocate a random SELinux context for each
+                              container.  May also be set in SecurityContext.  If set in
+                              both SecurityContext and PodSecurityContext, the value specified in SecurityContext
+                              takes precedence for that container.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              level:
+                                description: Level is SELinux level label that applies
+                                  to the container.
+                                type: string
+                              role:
+                                description: Role is a SELinux role label that applies
+                                  to the container.
+                                type: string
+                              type:
+                                description: Type is a SELinux type label that applies
+                                  to the container.
+                                type: string
+                              user:
+                                description: User is a SELinux user label that applies
+                                  to the container.
+                                type: string
+                            type: object
+                          seccompProfile:
+                            description: |-
+                              The seccomp options to use by the containers in this pod.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            properties:
+                              localhostProfile:
+                                description: |-
+                                  localhostProfile indicates a profile defined in a file on the node should be used.
+                                  The profile must be preconfigured on the node to work.
+                                  Must be a descending path, relative to the kubelet's configured seccomp profile location.
+                                  Must be set if type is "Localhost". Must NOT be set for any other type.
+                                type: string
+                              type:
+                                description: |-
+                                  type indicates which kind of seccomp profile will be applied.
+                                  Valid options are:
+
+                                  Localhost - a profile defined in a file on the node should be used.
+                                  RuntimeDefault - the container runtime default profile should be used.
+                                  Unconfined - no profile should be applied.
+                                type: string
+                            required:
+                            - type
+                            type: object
+                          supplementalGroups:
+                            description: |-
+                              A list of groups applied to the first process run in each container, in
+                              addition to the container's primary GID and fsGroup (if specified).  If
+                              the SupplementalGroupsPolicy feature is enabled, the
+                              supplementalGroupsPolicy field determines whether these are in addition
+                              to or instead of any group memberships defined in the container image.
+                              If unspecified, no additional groups are added, though group memberships
+                              defined in the container image may still be used, depending on the
+                              supplementalGroupsPolicy field.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              format: int64
+                              type: integer
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          supplementalGroupsPolicy:
+                            description: |-
+                              Defines how supplemental groups of the first container processes are calculated.
+                              Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
+                              (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
+                              and the container runtime must implement support for this feature.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            type: string
+                          sysctls:
+                            description: |-
+                              Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
+                              sysctls (by the container runtime) might fail to launch.
+                              Note that this field cannot be set when spec.os.name is windows.
+                            items:
+                              description: Sysctl defines a kernel parameter to be
+                                set
+                              properties:
+                                name:
+                                  description: Name of a property to set
+                                  type: string
+                                value:
+                                  description: Value of a property to set
+                                  type: string
+                              required:
+                              - name
+                              - value
+                              type: object
+                            type: array
+                            x-kubernetes-list-type: atomic
+                          windowsOptions:
+                            description: |-
+                              The Windows specific settings applied to all containers.
+                              If unspecified, the options within a container's SecurityContext will be used.
+                              If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
+                              Note that this field cannot be set when spec.os.name is linux.
+                            properties:
+                              gmsaCredentialSpec:
+                                description: |-
+                                  GMSACredentialSpec is where the GMSA admission webhook
+                                  (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
+                                  GMSA credential spec named by the GMSACredentialSpecName field.
+                                type: string
+                              gmsaCredentialSpecName:
+                                description: GMSACredentialSpecName is the name of
+                                  the GMSA credential spec to use.
+                                type: string
+                              hostProcess:
+                                description: |-
+                                  HostProcess determines if a container should be run as a 'Host Process' container.
+                                  All of a Pod's containers must have the same effective HostProcess value
+                                  (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
+                                  In addition, if HostProcess is true then HostNetwork must also be set to true.
+                                type: boolean
+                              runAsUserName:
+                                description: |-
+                                  The UserName in Windows to run the entrypoint of the container process.
+                                  Defaults to the user specified in image metadata if unspecified.
+                                  May also be set in PodSecurityContext. If set in both SecurityContext and
+                                  PodSecurityContext, the value specified in SecurityContext takes precedence.
+                                type: string
+                            type: object
+                        type: object
                     type: object
                 type: object
             type: object
diff --git a/config/dev/apigateway.yaml b/config/dev/apigateway.yaml
index b2b9ae1..578d218 100644
--- a/config/dev/apigateway.yaml
+++ b/config/dev/apigateway.yaml
@@ -10,6 +10,8 @@ metadata:
 spec:
   envoy:
     disableIPv6: true
+    workloadSpec:
+      replicas: 2
   apiEndpoint:
     jwks:
       name: core-sample-jwt
diff --git a/config/dev/cnpg-cluster.yaml b/config/dev/cnpg-cluster.yaml
index cdbd22e..089167f 100644
--- a/config/dev/cnpg-cluster.yaml
+++ b/config/dev/cnpg-cluster.yaml
@@ -44,14 +44,15 @@ metadata:
   namespace: supabase-demo
 spec:
   instances: 1
-  imageName: ghcr.io/supabase/postgres:15.8.1.021
-  postgresUID: 105
-  postgresGID: 106
+  imageName: localhost:5005/cnpg-postgres:17.2
+  imagePullPolicy: Always
+  postgresUID: 26
+  postgresGID: 102
 
   bootstrap:
     initdb:
       database: app
-      owner: setup
+      owner: supabase_admin
       postInitSQL:
         - drop publication if exists supabase_realtime;
 
diff --git a/config/dev/kustomization.yaml b/config/dev/kustomization.yaml
index 67cedd5..1343889 100644
--- a/config/dev/kustomization.yaml
+++ b/config/dev/kustomization.yaml
@@ -25,3 +25,6 @@ patches:
     target:
       kind: Deployment
       labelSelector: app.kubernetes.io/name=control-plane
+
+configurations:
+  - kustomizeconfig/cnpg-cluster.yaml
diff --git a/docs/api/supabase.k8s.icb4dc0.de.md b/docs/api/supabase.k8s.icb4dc0.de.md
index d8e83e7..a017fa6 100644
--- a/docs/api/supabase.k8s.icb4dc0.de.md
+++ b/docs/api/supabase.k8s.icb4dc0.de.md
@@ -151,7 +151,7 @@ _Appears in:_
 | `disableSignup` _boolean_ |  |  |  |
 | `anonymousUsersEnabled` _boolean_ |  |  |  |
 | `providers` _[AuthProviders](#authproviders)_ |  |  |  |
-| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ |  |  |  |
+| `workloadTemplate` _[WorkloadSpec](#workloadspec)_ |  |  |  |
 | `emailSignupDisabled` _boolean_ |  |  |  |
 
 
@@ -185,7 +185,7 @@ _Appears in:_
 
 
 _Appears in:_
-- [WorkloadTemplate](#workloadtemplate)
+- [WorkloadSpec](#workloadspec)
 
 | Field | Description | Default | Validation |
 | --- | --- | --- | --- |
@@ -660,7 +660,7 @@ _Appears in:_
 | --- | --- | --- | --- |
 | `nodeName` _string_ | NodeName - identifies the Envoy cluster within the current namespace<br />if not set, the name of the APIGateway resource will be used<br />The primary use case is to make the assignment of multiple supabase instances in a single namespace explicit. |  |  |
 | `controlPlane` _[ControlPlaneSpec](#controlplanespec)_ | ControlPlane - configure the control plane where Envoy will retrieve its configuration from |  |  |
-| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the Envoy deployment |  |  |
+| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the Envoy deployment |  |  |
 | `disableIPv6` _boolean_ | DisableIPv6 - disable IPv6 for the Envoy instance<br />this will force Envoy to use IPv4 for upstream hosts (mostly for the OAuth2 token endpoint) |  |  |
 | `debugging` _[EnvoyDebuggingOptions](#envoydebuggingoptions)_ |  |  |  |
 
@@ -731,7 +731,7 @@ _Appears in:_
 | --- | --- | --- | --- |
 | `enable` _boolean_ | Enable - whether to deploy the image proxy or not |  |  |
 | `enableWebPDetection` _boolean_ |  |  |  |
-| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the image proxy workload |  |  |
+| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the image proxy workload |  |  |
 
 
 #### ImageSpec
@@ -818,7 +818,7 @@ _Appears in:_
 
 | Field | Description | Default | Validation |
 | --- | --- | --- | --- |
-| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the pg-meta deployment |  |  |
+| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the pg-meta deployment |  |  |
 
 
 #### PhoneAuthProvider
@@ -854,7 +854,7 @@ _Appears in:_
 | `extraSearchPath` _string array_ | ExtraSearchPath - Extra schemas to add to the search_path of every request.<br />These schemas tables, views and functions don’t get API endpoints, they can only be referred from the database objects inside your db-schemas. | [public extensions] |  |
 | `anonRole` _string_ | AnonRole - name of the anon role | anon |  |
 | `maxRows` _integer_ | MaxRows - maximum number of rows PostgREST will load at a time | 1000 |  |
-| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the PostgREST workload |  |  |
+| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadSpec - customize the PostgREST workload |  |  |
 
 
 #### S3BackendSpec
@@ -989,7 +989,7 @@ _Appears in:_
 | `db` _[StorageApiDbSpec](#storageapidbspec)_ | DBSpec - Configure access to the Postgres database<br />In most cases this will reference the supabase-storage-admin credentials secret provided by the Core resource |  |  |
 | `s3` _[S3ProtocolSpec](#s3protocolspec)_ | S3Protocol - Configure S3 access to the Storage API allowing clients to use any S3 client |  |  |
 | `uploadTemp` _[UploadTempSpec](#uploadtempspec)_ | UploadTemp - configure the emptyDir for storing intermediate files during uploads |  |  |
-| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the Storage API workload |  |  |
+| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the Storage API workload |  |  |
 
 
 #### StorageList
@@ -1043,7 +1043,7 @@ _Appears in:_
 | Field | Description | Default | Validation |
 | --- | --- | --- | --- |
 | `jwt` _[JwtSpec](#jwtspec)_ |  |  |  |
-| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the studio deployment |  |  |
+| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the studio deployment |  |  |
 | `gatewayServiceSelector` _object (keys:string, values:string)_ | GatewayServiceSelector - selector to find the service for the API gateway<br />Required to configure the API URL in the studio deployment<br />If you don't run multiple APIGateway instances in the same namespaces, the default will be fine | \{ app.kubernetes.io/component:api-gateway app.kubernetes.io/name:envoy \} |  |
 | `externalUrl` _string_ | APIExternalURL is referring to the URL where Supabase API will be available<br />Typically this is the ingress of the API gateway |  |  |
 
@@ -1084,7 +1084,7 @@ _Appears in:_
 | `sizeLimit` _[Quantity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#quantity-resource-api)_ |  |  |  |
 
 
-#### WorkloadTemplate
+#### WorkloadSpec
 
 
 
@@ -1106,7 +1106,7 @@ _Appears in:_
 | `replicas` _integer_ |  |  |  |
 | `securityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#podsecuritycontext-v1-core)_ |  |  |  |
 | `additionalLabels` _object (keys:string, values:string)_ |  |  |  |
-| `workload` _[ContainerTemplate](#containertemplate)_ | Workload - customize the container template of the workload |  |  |
+| `container` _[ContainerTemplate](#containertemplate)_ | ContainerSpec - customize the container template of the workload |  |  |
 | `additionalVolumes` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#volume-v1-core) array_ |  |  |  |
 
 
diff --git a/internal/controller/apigateway_controller.go b/internal/controller/apigateway_controller.go
index 0b7807e..1de83fb 100644
--- a/internal/controller/apigateway_controller.go
+++ b/internal/controller/apigateway_controller.go
@@ -436,7 +436,7 @@ func (r *APIGatewayReconciler) reconileEnvoyDeployment(
 	)
 
 	_, err := controllerutil.CreateOrUpdate(ctx, r.Client, envoyDeployment, func() error {
-		envoyDeployment.Labels = envoySpec.WorkloadTemplate.MergeLabels(
+		envoyDeployment.Labels = envoySpec.WorkloadSpec.MergeLabels(
 			objectLabels(gateway, "envoy", "api-gateway", supabase.Images.Envoy.Tag),
 			gateway.Labels,
 		)
@@ -447,7 +447,7 @@ func (r *APIGatewayReconciler) reconileEnvoyDeployment(
 			}
 		}
 
-		envoyDeployment.Spec.Replicas = envoySpec.WorkloadTemplate.ReplicaCount()
+		envoyDeployment.Spec.Replicas = envoySpec.WorkloadSpec.ReplicaCount()
 
 		envoyArgs := []string{"-c /etc/envoy/config.yaml"}
 
@@ -464,13 +464,13 @@ func (r *APIGatewayReconciler) reconileEnvoyDeployment(
 				Labels: objectLabels(gateway, "envoy", "api-gateway", supabase.Images.Envoy.Tag),
 			},
 			Spec: corev1.PodSpec{
-				ImagePullSecrets:             envoySpec.WorkloadTemplate.PullSecrets(),
+				ImagePullSecrets:             envoySpec.WorkloadSpec.PullSecrets(),
 				AutomountServiceAccountToken: ptrOf(false),
 				Containers: []corev1.Container{
 					{
 						Name:            "envoy-proxy",
-						Image:           envoySpec.WorkloadTemplate.Image(supabase.Images.Envoy.String()),
-						ImagePullPolicy: envoySpec.WorkloadTemplate.ImagePullPolicy(),
+						Image:           envoySpec.WorkloadSpec.Image(supabase.Images.Envoy.String()),
+						ImagePullPolicy: envoySpec.WorkloadSpec.ImagePullPolicy(),
 						Args:            envoyArgs,
 						Ports: []corev1.ContainerPort{
 							{
@@ -512,16 +512,16 @@ func (r *APIGatewayReconciler) reconileEnvoyDeployment(
 								},
 							},
 						},
-						SecurityContext: envoySpec.WorkloadTemplate.ContainerSecurityContext(serviceCfg.Defaults.UID, serviceCfg.Defaults.GID),
-						Resources:       envoySpec.WorkloadTemplate.Resources(),
-						VolumeMounts: envoySpec.WorkloadTemplate.AdditionalVolumeMounts(corev1.VolumeMount{
+						SecurityContext: envoySpec.WorkloadSpec.ContainerSecurityContext(serviceCfg.Defaults.UID, serviceCfg.Defaults.GID),
+						Resources:       envoySpec.WorkloadSpec.Resources(),
+						VolumeMounts: envoySpec.WorkloadSpec.AdditionalVolumeMounts(corev1.VolumeMount{
 							Name:      configVolumeName,
 							ReadOnly:  true,
 							MountPath: "/etc/envoy",
 						}),
 					},
 				},
-				SecurityContext: envoySpec.WorkloadTemplate.PodSecurityContext(),
+				SecurityContext: envoySpec.WorkloadSpec.PodSecurityContext(),
 				Volumes: []corev1.Volume{
 					{
 						Name: configVolumeName,
diff --git a/internal/controller/core_gotrue_controller.go b/internal/controller/core_gotrue_controller.go
index 95b358b..cd60edd 100644
--- a/internal/controller/core_gotrue_controller.go
+++ b/internal/controller/core_gotrue_controller.go
@@ -232,7 +232,7 @@ func (r *CoreAuthReconciler) reconcileAuthService(
 	}
 
 	_, err := controllerutil.CreateOrUpdate(ctx, r.Client, authService, func() error {
-		authService.Labels = core.Spec.Postgrest.WorkloadTemplate.MergeLabels(
+		authService.Labels = core.Spec.Postgrest.WorkloadSpec.MergeLabels(
 			objectLabels(core, "auth", "core", supabase.Images.Gotrue.Tag),
 			core.Labels,
 		)
diff --git a/internal/controller/core_postgrest_controller.go b/internal/controller/core_postgrest_controller.go
index e9e3811..ebea924 100644
--- a/internal/controller/core_postgrest_controller.go
+++ b/internal/controller/core_postgrest_controller.go
@@ -115,7 +115,7 @@ func (r *CorePostgrestReconiler) reconilePostgrestDeployment(
 	}
 
 	_, err = controllerutil.CreateOrUpdate(ctx, r.Client, postgrestDeployment, func() error {
-		postgrestDeployment.Labels = postgrestSpec.WorkloadTemplate.MergeLabels(
+		postgrestDeployment.Labels = postgrestSpec.WorkloadSpec.MergeLabels(
 			objectLabels(core, serviceCfg.Name, "core", supabase.Images.Postgrest.Tag),
 			core.Labels,
 		)
@@ -155,7 +155,7 @@ func (r *CorePostgrestReconiler) reconilePostgrestDeployment(
 			}
 		}
 
-		postgrestDeployment.Spec.Replicas = postgrestSpec.WorkloadTemplate.ReplicaCount()
+		postgrestDeployment.Spec.Replicas = postgrestSpec.WorkloadSpec.ReplicaCount()
 
 		postgrestDeployment.Spec.Template = corev1.PodTemplateSpec{
 			ObjectMeta: metav1.ObjectMeta{
@@ -165,14 +165,14 @@ func (r *CorePostgrestReconiler) reconilePostgrestDeployment(
 				Labels: objectLabels(core, serviceCfg.Name, "core", supabase.Images.Postgrest.Tag),
 			},
 			Spec: corev1.PodSpec{
-				ImagePullSecrets: postgrestSpec.WorkloadTemplate.PullSecrets(),
+				ImagePullSecrets: postgrestSpec.WorkloadSpec.PullSecrets(),
 				Containers: []corev1.Container{
 					{
 						Name:            "supabase-rest",
-						Image:           postgrestSpec.WorkloadTemplate.Image(supabase.Images.Postgrest.String()),
-						ImagePullPolicy: postgrestSpec.WorkloadTemplate.ImagePullPolicy(),
+						Image:           postgrestSpec.WorkloadSpec.Image(supabase.Images.Postgrest.String()),
+						ImagePullPolicy: postgrestSpec.WorkloadSpec.ImagePullPolicy(),
 						Args:            []string{"postgrest"},
-						Env:             postgrestSpec.WorkloadTemplate.MergeEnv(postgrestEnv),
+						Env:             postgrestSpec.WorkloadSpec.MergeEnv(postgrestEnv),
 						Ports: []corev1.ContainerPort{
 							{
 								Name:          serviceCfg.Defaults.ServerPortName,
@@ -185,9 +185,9 @@ func (r *CorePostgrestReconiler) reconilePostgrestDeployment(
 								Protocol:      corev1.ProtocolTCP,
 							},
 						},
-						SecurityContext: postgrestSpec.WorkloadTemplate.ContainerSecurityContext(serviceCfg.Defaults.UID, serviceCfg.Defaults.GID),
-						Resources:       postgrestSpec.WorkloadTemplate.Resources(),
-						VolumeMounts:    postgrestSpec.WorkloadTemplate.AdditionalVolumeMounts(),
+						SecurityContext: postgrestSpec.WorkloadSpec.ContainerSecurityContext(serviceCfg.Defaults.UID, serviceCfg.Defaults.GID),
+						Resources:       postgrestSpec.WorkloadSpec.Resources(),
+						VolumeMounts:    postgrestSpec.WorkloadSpec.AdditionalVolumeMounts(),
 						ReadinessProbe: &corev1.Probe{
 							InitialDelaySeconds: 5,
 							PeriodSeconds:       3,
@@ -213,7 +213,7 @@ func (r *CorePostgrestReconiler) reconilePostgrestDeployment(
 						},
 					},
 				},
-				SecurityContext: postgrestSpec.WorkloadTemplate.PodSecurityContext(),
+				SecurityContext: postgrestSpec.WorkloadSpec.PodSecurityContext(),
 			},
 		}
 
@@ -239,7 +239,7 @@ func (r *CorePostgrestReconiler) reconcilePostgrestService(
 	)
 
 	_, err := controllerutil.CreateOrUpdate(ctx, r.Client, postgrestService, func() error {
-		postgrestService.Labels = core.Spec.Postgrest.WorkloadTemplate.MergeLabels(
+		postgrestService.Labels = core.Spec.Postgrest.WorkloadSpec.MergeLabels(
 			objectLabels(core, serviceCfg.Name, "core", supabase.Images.Postgrest.Tag),
 			core.Labels,
 		)
diff --git a/internal/controller/dashboard_pg-meta_controller.go b/internal/controller/dashboard_pg-meta_controller.go
index 6ca7540..9fdf851 100644
--- a/internal/controller/dashboard_pg-meta_controller.go
+++ b/internal/controller/dashboard_pg-meta_controller.go
@@ -99,7 +99,7 @@ func (r *DashboardPGMetaReconciler) reconcilePGMetaDeployment(
 	}
 
 	_, err := controllerutil.CreateOrUpdate(ctx, r.Client, pgMetaDeployment, func() error {
-		pgMetaDeployment.Labels = pgMetaSpec.WorkloadTemplate.MergeLabels(
+		pgMetaDeployment.Labels = pgMetaSpec.WorkloadSpec.MergeLabels(
 			objectLabels(dashboard, serviceCfg.Name, "dashboard", supabase.Images.PostgresMeta.Tag),
 			dashboard.Labels,
 		)
@@ -110,7 +110,7 @@ func (r *DashboardPGMetaReconciler) reconcilePGMetaDeployment(
 			}
 		}
 
-		pgMetaDeployment.Spec.Replicas = pgMetaSpec.WorkloadTemplate.ReplicaCount()
+		pgMetaDeployment.Spec.Replicas = pgMetaSpec.WorkloadSpec.ReplicaCount()
 
 		pgMetaEnv := []corev1.EnvVar{
 			serviceCfg.EnvKeys.APIPort.Var(serviceCfg.Defaults.APIPort),
@@ -126,20 +126,20 @@ func (r *DashboardPGMetaReconciler) reconcilePGMetaDeployment(
 				Labels: objectLabels(dashboard, serviceCfg.Name, "dashboard", supabase.Images.PostgresMeta.Tag),
 			},
 			Spec: corev1.PodSpec{
-				ImagePullSecrets: pgMetaSpec.WorkloadTemplate.PullSecrets(),
+				ImagePullSecrets: pgMetaSpec.WorkloadSpec.PullSecrets(),
 				Containers: []corev1.Container{{
 					Name:            "supabase-meta",
-					Image:           pgMetaSpec.WorkloadTemplate.Image(supabase.Images.PostgresMeta.String()),
-					ImagePullPolicy: pgMetaSpec.WorkloadTemplate.ImagePullPolicy(),
-					Env:             pgMetaSpec.WorkloadTemplate.MergeEnv(pgMetaEnv),
+					Image:           pgMetaSpec.WorkloadSpec.Image(supabase.Images.PostgresMeta.String()),
+					ImagePullPolicy: pgMetaSpec.WorkloadSpec.ImagePullPolicy(),
+					Env:             pgMetaSpec.WorkloadSpec.MergeEnv(pgMetaEnv),
 					Ports: []corev1.ContainerPort{{
 						Name:          "api",
 						ContainerPort: serviceCfg.Defaults.APIPort,
 						Protocol:      corev1.ProtocolTCP,
 					}},
-					SecurityContext: pgMetaSpec.WorkloadTemplate.ContainerSecurityContext(serviceCfg.Defaults.NodeUID, serviceCfg.Defaults.NodeGID),
-					Resources:       pgMetaSpec.WorkloadTemplate.Resources(),
-					VolumeMounts:    pgMetaSpec.WorkloadTemplate.AdditionalVolumeMounts(),
+					SecurityContext: pgMetaSpec.WorkloadSpec.ContainerSecurityContext(serviceCfg.Defaults.NodeUID, serviceCfg.Defaults.NodeGID),
+					Resources:       pgMetaSpec.WorkloadSpec.Resources(),
+					VolumeMounts:    pgMetaSpec.WorkloadSpec.AdditionalVolumeMounts(),
 					ReadinessProbe: &corev1.Probe{
 						InitialDelaySeconds: 5,
 						PeriodSeconds:       3,
@@ -164,7 +164,7 @@ func (r *DashboardPGMetaReconciler) reconcilePGMetaDeployment(
 						},
 					},
 				}},
-				SecurityContext: pgMetaSpec.WorkloadTemplate.PodSecurityContext(),
+				SecurityContext: pgMetaSpec.WorkloadSpec.PodSecurityContext(),
 			},
 		}
 
@@ -191,7 +191,7 @@ func (r *DashboardPGMetaReconciler) reconcilePGMetaService(
 	}
 
 	_, err := controllerutil.CreateOrPatch(ctx, r.Client, pgMetaService, func() error {
-		pgMetaService.Labels = dashboard.Spec.PGMeta.WorkloadTemplate.MergeLabels(
+		pgMetaService.Labels = dashboard.Spec.PGMeta.WorkloadSpec.MergeLabels(
 			objectLabels(dashboard, supabase.ServiceConfig.PGMeta.Name, "dashboard", supabase.Images.PostgresMeta.Tag),
 			dashboard.Labels,
 		)
diff --git a/internal/controller/dashboard_studio_controller.go b/internal/controller/dashboard_studio_controller.go
index 453c1f2..17f1f51 100644
--- a/internal/controller/dashboard_studio_controller.go
+++ b/internal/controller/dashboard_studio_controller.go
@@ -107,7 +107,7 @@ func (r *DashboardStudioReconciler) reconcileStudioDeployment(
 	gatewayService := gatewayServiceList.Items[0]
 
 	_, err = controllerutil.CreateOrUpdate(ctx, r.Client, studioDeployment, func() error {
-		studioDeployment.Labels = studioSpec.WorkloadTemplate.MergeLabels(
+		studioDeployment.Labels = studioSpec.WorkloadSpec.MergeLabels(
 			objectLabels(dashboard, serviceCfg.Name, "dashboard", supabase.Images.Studio.Tag),
 			dashboard.Labels,
 		)
@@ -118,7 +118,7 @@ func (r *DashboardStudioReconciler) reconcileStudioDeployment(
 			}
 		}
 
-		studioDeployment.Spec.Replicas = studioSpec.WorkloadTemplate.ReplicaCount()
+		studioDeployment.Spec.Replicas = studioSpec.WorkloadSpec.ReplicaCount()
 
 		studioEnv := []corev1.EnvVar{
 			serviceCfg.EnvKeys.PGMetaURL.Var(fmt.Sprintf("http://%s.%s.svc:%d", supabase.ServiceConfig.PGMeta.ObjectName(dashboard), dashboard.Namespace, supabase.ServiceConfig.PGMeta.Defaults.APIPort)),
@@ -137,20 +137,20 @@ func (r *DashboardStudioReconciler) reconcileStudioDeployment(
 				Labels: objectLabels(dashboard, serviceCfg.Name, "dashboard", supabase.Images.Studio.Tag),
 			},
 			Spec: corev1.PodSpec{
-				ImagePullSecrets: studioSpec.WorkloadTemplate.PullSecrets(),
+				ImagePullSecrets: studioSpec.WorkloadSpec.PullSecrets(),
 				Containers: []corev1.Container{{
 					Name:            "supabase-studio",
-					Image:           studioSpec.WorkloadTemplate.Image(supabase.Images.Studio.String()),
-					ImagePullPolicy: studioSpec.WorkloadTemplate.ImagePullPolicy(),
-					Env:             studioSpec.WorkloadTemplate.MergeEnv(studioEnv),
+					Image:           studioSpec.WorkloadSpec.Image(supabase.Images.Studio.String()),
+					ImagePullPolicy: studioSpec.WorkloadSpec.ImagePullPolicy(),
+					Env:             studioSpec.WorkloadSpec.MergeEnv(studioEnv),
 					Ports: []corev1.ContainerPort{{
 						Name:          "studio",
 						ContainerPort: serviceCfg.Defaults.APIPort,
 						Protocol:      corev1.ProtocolTCP,
 					}},
-					SecurityContext: studioSpec.WorkloadTemplate.ContainerSecurityContext(serviceCfg.Defaults.NodeUID, serviceCfg.Defaults.NodeGID),
-					Resources:       studioSpec.WorkloadTemplate.Resources(),
-					VolumeMounts: studioSpec.WorkloadTemplate.AdditionalVolumeMounts(corev1.VolumeMount{
+					SecurityContext: studioSpec.WorkloadSpec.ContainerSecurityContext(serviceCfg.Defaults.NodeUID, serviceCfg.Defaults.NodeGID),
+					Resources:       studioSpec.WorkloadSpec.Resources(),
+					VolumeMounts: studioSpec.WorkloadSpec.AdditionalVolumeMounts(corev1.VolumeMount{
 						Name:      "next-cache",
 						MountPath: "/app/apps/studio/.next/cache",
 					}),
@@ -178,7 +178,7 @@ func (r *DashboardStudioReconciler) reconcileStudioDeployment(
 						},
 					},
 				}},
-				SecurityContext: studioSpec.WorkloadTemplate.PodSecurityContext(),
+				SecurityContext: studioSpec.WorkloadSpec.PodSecurityContext(),
 				Volumes: []corev1.Volume{{
 					Name: "next-cache",
 					VolumeSource: corev1.VolumeSource{
@@ -214,7 +214,7 @@ func (r *DashboardStudioReconciler) reconcileStudioService(
 	}
 
 	_, err := controllerutil.CreateOrPatch(ctx, r.Client, studioService, func() error {
-		studioService.Labels = dashboard.Spec.Studio.WorkloadTemplate.MergeLabels(
+		studioService.Labels = dashboard.Spec.Studio.WorkloadSpec.MergeLabels(
 			objectLabels(dashboard, supabase.ServiceConfig.Studio.Name, "dashboard", supabase.Images.Studio.Tag),
 			dashboard.Labels,
 		)
diff --git a/internal/controller/storage_api_controller.go b/internal/controller/storage_api_controller.go
index c46155b..0c081c2 100644
--- a/internal/controller/storage_api_controller.go
+++ b/internal/controller/storage_api_controller.go
@@ -133,7 +133,7 @@ func (r *StorageApiReconciler) reconcileStorageApiDeployment(
 	))
 
 	_, err := controllerutil.CreateOrUpdate(ctx, r.Client, storageApiDeployment, func() error {
-		storageApiDeployment.Labels = apiSpec.WorkloadTemplate.MergeLabels(
+		storageApiDeployment.Labels = apiSpec.WorkloadSpec.MergeLabels(
 			objectLabels(storage, serviceCfg.Name, "storage", supabase.Images.Storage.Tag),
 			storage.Labels,
 		)
@@ -188,7 +188,7 @@ func (r *StorageApiReconciler) reconcileStorageApiDeployment(
 			}
 		}
 
-		storageApiDeployment.Spec.Replicas = apiSpec.WorkloadTemplate.ReplicaCount()
+		storageApiDeployment.Spec.Replicas = apiSpec.WorkloadSpec.ReplicaCount()
 
 		storageApiDeployment.Spec.Template = corev1.PodTemplateSpec{
 			ObjectMeta: metav1.ObjectMeta{
@@ -199,20 +199,20 @@ func (r *StorageApiReconciler) reconcileStorageApiDeployment(
 				Labels: objectLabels(storage, serviceCfg.Name, "storage", supabase.Images.Storage.Tag),
 			},
 			Spec: corev1.PodSpec{
-				ImagePullSecrets: apiSpec.WorkloadTemplate.PullSecrets(),
+				ImagePullSecrets: apiSpec.WorkloadSpec.PullSecrets(),
 				Containers: []corev1.Container{{
 					Name:            "supabase-storage",
-					Image:           apiSpec.WorkloadTemplate.Image(supabase.Images.Storage.String()),
-					ImagePullPolicy: apiSpec.WorkloadTemplate.ImagePullPolicy(),
-					Env:             apiSpec.WorkloadTemplate.MergeEnv(append(storagApiEnv, slices.Concat(apiSpec.FileBackend.Env(), apiSpec.S3Backend.Env())...)),
+					Image:           apiSpec.WorkloadSpec.Image(supabase.Images.Storage.String()),
+					ImagePullPolicy: apiSpec.WorkloadSpec.ImagePullPolicy(),
+					Env:             apiSpec.WorkloadSpec.MergeEnv(append(storagApiEnv, slices.Concat(apiSpec.FileBackend.Env(), apiSpec.S3Backend.Env())...)),
 					Ports: []corev1.ContainerPort{{
 						Name:          serviceCfg.Defaults.ApiPortName,
 						ContainerPort: serviceCfg.Defaults.ApiPort,
 						Protocol:      corev1.ProtocolTCP,
 					}},
-					SecurityContext: apiSpec.WorkloadTemplate.ContainerSecurityContext(serviceCfg.Defaults.UID, serviceCfg.Defaults.GID),
-					Resources:       apiSpec.WorkloadTemplate.Resources(),
-					VolumeMounts: apiSpec.WorkloadTemplate.AdditionalVolumeMounts(
+					SecurityContext: apiSpec.WorkloadSpec.ContainerSecurityContext(serviceCfg.Defaults.UID, serviceCfg.Defaults.GID),
+					Resources:       apiSpec.WorkloadSpec.Resources(),
+					VolumeMounts: apiSpec.WorkloadSpec.AdditionalVolumeMounts(
 						corev1.VolumeMount{
 							Name:      "tmp",
 							MountPath: "/tmp",
@@ -242,8 +242,8 @@ func (r *StorageApiReconciler) reconcileStorageApiDeployment(
 						},
 					},
 				}},
-				SecurityContext: apiSpec.WorkloadTemplate.PodSecurityContext(),
-				Volumes: apiSpec.WorkloadTemplate.Volumes(
+				SecurityContext: apiSpec.WorkloadSpec.PodSecurityContext(),
+				Volumes: apiSpec.WorkloadSpec.Volumes(
 					corev1.Volume{
 						Name: "tmp",
 						VolumeSource: corev1.VolumeSource{
@@ -276,7 +276,7 @@ func (r *StorageApiReconciler) reconcileStorageApiService(
 	)
 
 	_, err := controllerutil.CreateOrUpdate(ctx, r.Client, storageApiService, func() error {
-		storageApiService.Labels = storage.Spec.Api.WorkloadTemplate.MergeLabels(
+		storageApiService.Labels = storage.Spec.Api.WorkloadSpec.MergeLabels(
 			objectLabels(storage, serviceCfg.Name, "storage", supabase.Images.Storage.Tag),
 			storage.Labels,
 		)
diff --git a/internal/controller/storage_imgproxy_controller.go b/internal/controller/storage_imgproxy_controller.go
index e197574..12f4ee3 100644
--- a/internal/controller/storage_imgproxy_controller.go
+++ b/internal/controller/storage_imgproxy_controller.go
@@ -98,7 +98,7 @@ func (r *StorageImgProxyReconciler) reconcileImgProxyDeployment(
 	)
 
 	_, err := controllerutil.CreateOrUpdate(ctx, r.Client, imgProxyDeployment, func() error {
-		imgProxyDeployment.Labels = imgProxySpec.WorkloadTemplate.MergeLabels(
+		imgProxyDeployment.Labels = imgProxySpec.WorkloadSpec.MergeLabels(
 			objectLabels(storage, serviceCfg.Name, "storage", supabase.Images.ImgProxy.Tag),
 			storage.Labels,
 		)
@@ -119,27 +119,27 @@ func (r *StorageImgProxyReconciler) reconcileImgProxyDeployment(
 			}
 		}
 
-		imgProxyDeployment.Spec.Replicas = imgProxySpec.WorkloadTemplate.ReplicaCount()
+		imgProxyDeployment.Spec.Replicas = imgProxySpec.WorkloadSpec.ReplicaCount()
 
 		imgProxyDeployment.Spec.Template = corev1.PodTemplateSpec{
 			ObjectMeta: metav1.ObjectMeta{
 				Labels: objectLabels(storage, serviceCfg.Name, "storage", supabase.Images.ImgProxy.Tag),
 			},
 			Spec: corev1.PodSpec{
-				ImagePullSecrets: imgProxySpec.WorkloadTemplate.PullSecrets(),
+				ImagePullSecrets: imgProxySpec.WorkloadSpec.PullSecrets(),
 				Containers: []corev1.Container{{
 					Name:            "supabase-imgproxy",
-					Image:           imgProxySpec.WorkloadTemplate.Image(supabase.Images.ImgProxy.String()),
-					ImagePullPolicy: imgProxySpec.WorkloadTemplate.ImagePullPolicy(),
-					Env:             imgProxySpec.WorkloadTemplate.MergeEnv(imgProxyEnv),
+					Image:           imgProxySpec.WorkloadSpec.Image(supabase.Images.ImgProxy.String()),
+					ImagePullPolicy: imgProxySpec.WorkloadSpec.ImagePullPolicy(),
+					Env:             imgProxySpec.WorkloadSpec.MergeEnv(imgProxyEnv),
 					Ports: []corev1.ContainerPort{{
 						Name:          serviceCfg.Defaults.ApiPortName,
 						ContainerPort: serviceCfg.Defaults.ApiPort,
 						Protocol:      corev1.ProtocolTCP,
 					}},
-					SecurityContext: imgProxySpec.WorkloadTemplate.ContainerSecurityContext(serviceCfg.Defaults.UID, serviceCfg.Defaults.GID),
-					Resources:       imgProxySpec.WorkloadTemplate.Resources(),
-					VolumeMounts:    imgProxySpec.WorkloadTemplate.AdditionalVolumeMounts(),
+					SecurityContext: imgProxySpec.WorkloadSpec.ContainerSecurityContext(serviceCfg.Defaults.UID, serviceCfg.Defaults.GID),
+					Resources:       imgProxySpec.WorkloadSpec.Resources(),
+					VolumeMounts:    imgProxySpec.WorkloadSpec.AdditionalVolumeMounts(),
 					ReadinessProbe: &corev1.Probe{
 						InitialDelaySeconds: 5,
 						PeriodSeconds:       3,
@@ -162,8 +162,8 @@ func (r *StorageImgProxyReconciler) reconcileImgProxyDeployment(
 						},
 					},
 				}},
-				SecurityContext: imgProxySpec.WorkloadTemplate.PodSecurityContext(),
-				Volumes:         imgProxySpec.WorkloadTemplate.Volumes(),
+				SecurityContext: imgProxySpec.WorkloadSpec.PodSecurityContext(),
+				Volumes:         imgProxySpec.WorkloadSpec.Volumes(),
 			},
 		}
 
@@ -189,7 +189,7 @@ func (r *StorageImgProxyReconciler) reconcileImgProxyService(
 	)
 
 	_, err := controllerutil.CreateOrPatch(ctx, r.Client, imgProxyService, func() error {
-		imgProxyService.Labels = storage.Spec.Api.WorkloadTemplate.MergeLabels(
+		imgProxyService.Labels = storage.Spec.Api.WorkloadSpec.MergeLabels(
 			objectLabels(storage, serviceCfg.Name, "storage", supabase.Images.ImgProxy.Tag),
 			storage.Labels,
 		)
diff --git a/internal/db/migrator.go b/internal/db/migrator.go
index b1eeafa..d0535b3 100644
--- a/internal/db/migrator.go
+++ b/internal/db/migrator.go
@@ -22,6 +22,7 @@ import (
 	"iter"
 
 	"github.com/jackc/pgx/v5"
+	"sigs.k8s.io/controller-runtime/pkg/log"
 
 	supabasev1alpha1 "code.icb4dc0.de/prskr/supabase-operator/api/v1alpha1"
 	"code.icb4dc0.de/prskr/supabase-operator/assets/migrations"
@@ -32,6 +33,8 @@ type Migrator struct {
 }
 
 func (m Migrator) ApplyAll(ctx context.Context, status supabasev1alpha1.MigrationStatus, seq iter.Seq2[migrations.Script, error]) (appliedSomething bool, err error) {
+	logger := log.FromContext(ctx)
+
 	for s, err := range seq {
 		if err != nil {
 			return false, err
@@ -41,6 +44,7 @@ func (m Migrator) ApplyAll(ctx context.Context, status supabasev1alpha1.Migratio
 			continue
 		}
 
+		logger.Info("Applying missing migration", "filename", s.FileName)
 		if err := m.Apply(ctx, s.Content); err != nil {
 			return false, err
 		}
diff --git a/internal/supabase/images.go b/internal/supabase/images.go
index ad0b0d4..28cf4bd 100644
--- a/internal/supabase/images.go
+++ b/internal/supabase/images.go
@@ -42,7 +42,7 @@ var Images = struct {
 }{
 	EdgeRuntime: ImageRef{
 		Repository: "supabase/edge-runtime",
-		Tag:        "v1.66.5",
+		Tag:        "v1.67.0",
 	},
 	Envoy: ImageRef{
 		Repository: "envoyproxy/envoy",
diff --git a/magefiles/generate.go b/magefiles/generate.go
index 2213a30..da0bfc3 100644
--- a/magefiles/generate.go
+++ b/magefiles/generate.go
@@ -28,6 +28,7 @@ import (
 	"os"
 	"path"
 	"path/filepath"
+	"slices"
 	"strings"
 	"time"
 
@@ -41,6 +42,10 @@ const (
 	composeFileUrl = "https://raw.githubusercontent.com/supabase/supabase/refs/heads/master/docker/docker-compose.yml"
 )
 
+var ignoredMigrations = []string{
+	"10000000000000_demote-postgres.sql",
+}
+
 func GenerateAll(ctx context.Context) {
 	mg.CtxDeps(ctx, FetchImageMeta, FetchMigrations, CRDs, CRDDocs)
 }
@@ -204,7 +209,13 @@ func FetchMigrations(ctx context.Context) (err error) {
 		if strings.HasPrefix(fileName, migrationsDirPath) {
 			fileName = strings.TrimPrefix(fileName, migrationsDirPath)
 
-			dir, _ := path.Split(fileName)
+			dir, migrationFileName := path.Split(fileName)
+
+			if slices.Contains(ignoredMigrations, migrationFileName) {
+				slog.Info("Skipping migration file", slog.String("name", migrationFileName))
+				continue
+			}
+
 			outDir := filepath.Join(workingDir, "assets", "migrations", filepath.FromSlash(dir))
 			if err := os.MkdirAll(outDir, 0o750); err != nil {
 				return err
diff --git a/postgres/Dockerfile b/postgres/Dockerfile
new file mode 100644
index 0000000..4bf9830
--- /dev/null
+++ b/postgres/Dockerfile
@@ -0,0 +1,178 @@
+# syntax=docker/dockerfile:1.13
+
+ARG POSTGRES_MAJOR=17
+ARG POSTGRES_MINOR=2
+ARG IMAGE_FLAVOR=standard
+ARG DISTRO=bookworm
+ARG IMAGE_BASE=ghcr.io/cloudnative-pg/postgresql:${POSTGRES_MAJOR}.${POSTGRES_MINOR}-${IMAGE_FLAVOR}-${DISTRO}
+
+FROM ${IMAGE_BASE} AS base
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+ARG POSTGRES_MAJOR
+
+USER root
+
+RUN apt-get update && \
+    apt-get install --yes --no-install-recommends \
+    libsodium23 \
+    postgresql-${POSTGRES_MAJOR}-cron \
+    postgresql-${POSTGRES_MAJOR}-http \
+    postgresql-${POSTGRES_MAJOR}-hypopg \
+    postgresql-${POSTGRES_MAJOR}-pgrouting \
+    postgresql-${POSTGRES_MAJOR}-pgtap \
+    postgresql-${POSTGRES_MAJOR}-plpgsql-check \
+    postgresql-${POSTGRES_MAJOR}-postgis-3 \
+    postgresql-${POSTGRES_MAJOR}-wal2json \
+    postgresql-${POSTGRES_MAJOR}-rum \
+    postgresql-${POSTGRES_MAJOR}-repack \
+    postgresql-${POSTGRES_MAJOR}-timescaledb && \
+    rm -rf /var/lib/apt/lists/*
+
+USER 26
+
+FROM ${IMAGE_BASE} AS builder
+
+ARG POSTGRES_MAJOR
+ARG PG_SAFEUPDATE_VERSION=1.5
+ARG PG_NET_VERSION=v0.9.1
+ARG PGSODIUM_VERSION=v3.1.9
+ARG PG_HASHIDS_VERSION=v1.2.1
+ARG PG_TLE_VERSION=v1.4.0
+ARG PG_GRAPHQL_VERSION=v1.5.9
+ARG PG_SUPABASE_VAULT_VERSION=v0.3.1
+ARG SUPABASE_WRAPPER_VERSION=v0.4.4
+ARG INDEX_ADVISOR_VERSION=v0.2.0
+ARG PG_JSONSCHEMA_VERSION=v0.3.3
+ARG PG_PLAN_FILTER_REVISION=5081a7b
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+USER root
+
+RUN apt-get update && \
+    apt-get install --yes --no-install-recommends \
+    curl \
+    pkg-config \
+    ca-certificates \
+    postgresql-server-dev-${POSTGRES_MAJOR} \
+    libcurl4-openssl-dev \
+    libsodium-dev \
+    git \
+    build-essential \
+    flex \
+    libkrb5-dev
+
+RUN curl -sSf https://sh.rustup.rs | sh -s -- -y && \
+    export PATH="/root/.cargo/bin:$PATH" && \
+    export "PG${POSTGRES_MAJOR}_PG_CONFIG=/usr/lib/postgresql/${POSTGRES_MAJOR}/bin/pg_config" && \
+    cargo install cargo-pgrx --version 0.12.6 --locked && \
+    cargo pgrx init
+
+WORKDIR /postgres/extensions
+
+ENV PATH="/root/.cargo/bin:$PATH"
+
+# Install pgjwt
+RUN git clone https://github.com/michelp/pgjwt.git && \
+    make -C pgjwt && make -C pgjwt install
+
+# Install pg_hashids
+RUN git clone --branch ${PG_HASHIDS_VERSION} --depth 1 https://github.com/iCyberon/pg_hashids.git && \
+    make -C pg_hashids && make -C pg_hashids install
+
+# Install pg-safeupdate
+RUN git clone --branch ${PG_SAFEUPDATE_VERSION} --depth 1 https://github.com/eradman/pg-safeupdate.git && \
+    make -C pg-safeupdate && make -C pg-safeupdate install
+
+# install pg_net
+RUN git clone --branch ${PG_NET_VERSION} --depth 1 https://github.com/supabase/pg_net.git && \
+    make -C pg_net && make -C pg_net install
+
+# install pg_graphql
+RUN git clone --branch ${PG_GRAPHQL_VERSION} --depth 1 https://github.com/supabase/pg_graphql.git && \
+    cd pg_graphql && \
+    cargo pgrx install --release
+
+# install supabase vault
+RUN git clone --branch ${PG_SUPABASE_VAULT_VERSION} --depth 1 https://github.com/supabase/vault.git && \
+    make -C vault && make -C vault install
+
+# install pg_jsonschema
+RUN git clone --branch ${PG_JSONSCHEMA_VERSION} --depth 1 https://github.com/supabase/pg_jsonschema.git && \
+    cd pg_jsonschema && \
+    cargo pgrx install --release
+
+# install supabase wrappers
+RUN git clone --branch ${SUPABASE_WRAPPER_VERSION} --depth 1 https://github.com/supabase/wrappers.git && \
+    cd wrappers/wrappers && \
+    cargo pgrx install --release --features "pg${POSTGRES_MAJOR},all_fdws"
+
+# install index_advisor
+RUN git clone --branch ${INDEX_ADVISOR_VERSION} --depth 1 https://github.com/supabase/index_advisor.git && \
+    make -C index_advisor && make -C index_advisor install
+
+# install pgsodium
+RUN git clone --branch ${PGSODIUM_VERSION} --depth 1 https://github.com/michelp/pgsodium.git && \
+    make -C pgsodium && make -C pgsodium install
+
+# install pg_tle
+RUN git clone --branch ${PG_TLE_VERSION} --depth 1 https://github.com/aws/pg_tle.git && \
+    make -C pg_tle && make -C pg_tle install
+
+# install pg_plan_filter
+RUN git clone https://github.com/pgexperts/pg_plan_filter.git && \
+    git -C pg_plan_filter checkout ${PG_PLAN_FILTER_REVISION} && \
+    make -C pg_plan_filter && make -C pg_plan_filter install
+
+FROM base AS final
+
+ARG POSTGRES_MAJOR
+
+# Copy all bitcode additions
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/bitcode /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/bitcode
+
+# pgjwt
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/pgjwt* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# pg-safeupdate
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/safeupdate.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+
+# pg_hashids
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/pg_hashids.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/pg_hashids* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# pg_net
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/pg_net.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/pg_net* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# pg_graphql
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/pg_graphql.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/pg_graphql* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# supabase vault
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/supabase_vault.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/supabase_vault* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# pg_jsonschema
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/pg_jsonschema.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/pg_jsonschema* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# Supabase wrappers
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/wrappers-*.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/wrappers* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# pgsodium
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/pgsodium.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/pgsodium* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# pg_tle
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/pg_tle.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/pg_tle* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/
+
+# pg_plan_filter
+COPY --from=builder /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/plan_filter.so /usr/lib/postgresql/${POSTGRES_MAJOR}/lib/
+
+# index_advisor
+COPY --from=builder /usr/share/postgresql/${POSTGRES_MAJOR}/extension/index_advisor* /usr/share/postgresql/${POSTGRES_MAJOR}/extension/