Skip to content

Fix: Kustomize Patch Failures vs Helm Rendering Errors on EKS

In a production AWS EKS environment, the choice between Helm (templating) and Kustomize (overlaying) often becomes a source of deployment failure when a “small service” evolves. Architects frequently encounter the “Patch Merge Failure” in Kustomize or the “Missing Required Value” error in Helm when the tool choice does not match the environment’s complexity.

This guide addresses the architectural friction when a service’s configuration becomes too complex for simple overlays or too rigid for templates.

The Issue: Configuration Drift in Small Services

Section titled “The Issue: Configuration Drift in Small Services”

You have a microservice deployed via Kustomize on AWS EKS. As you add AWS Load Balancer Controller annotations or EKS-specific IAM Roles for Service Accounts (IRSA), your kustomization.yaml becomes a nest of patchesStrategicMerge errors. Conversely, you might be using Helm for a service with zero variability, leading to “Tiller-less” orphan resources.

  • Cloud Provider: AWS (EKS v1.27+)
  • CI/CD: GitHub Actions or GitLab CI
  • Provisioning: Terraform (providing the OIDC provider for IRSA)
  • Infrastructure: Fargate or Managed Node Groups

When Kustomize fails to find a matching target for a patch in a small service:

Terminal window
error: failure in merge of patches:
failed to find target for patch [Group: apps, Version: v1, Kind: Deployment, Name: small-service-api]
in [kustomization.yaml]:
patch: '{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"small-service-api"},"spec":{"template":{"spec":{"containers":[{"name":"app","image":"...","env":[{"name":"DB_URL","value":"..."}]}]}}}}'

Or, when Helm fails due to a missing environment-specific key in a rigid chart:

Terminal window
Error: execution error at (small-service/templates/deployment.yaml:15:20):
A valid 'aws_account_id' is required for the IRSA annotation in the 'production' environment.
  1. Complexity Factor: Does the service require logic (if/else, loops)? If yes, Kustomize patches will become unmaintainable.
  2. Infrastructure Dependency: Does the service rely on environment-specific AWS ARNs (IAM Roles)?
  3. Schema Validation: Are you patching fields that do not exist in the base kustomization.yaml?
  4. Dry-run Validation: Run the following to see where the output diverges:
    Terminal window
    # For Kustomize
    kubectl kustomize ./overlays/production
    # For Helm
    helm install --debug --dry-run small-service ./charts/small-service -f values-prod.yaml

Scenario A: Use Kustomize when the service is static

Section titled “Scenario A: Use Kustomize when the service is static”

If the service only changes by environment (e.g., cpu: 100m vs cpu: 500m), stick to Kustomize but fix the “Target Not Found” by aligning your base and overlays.

Base Deployment (base/deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
name: small-service
spec:
template:
spec:
containers:
- name: web
image: my-repo/small-service:latest

Production Overlay (overlays/production/kustomization.yaml):

resources:
- ../../base
patches:
- target:
kind: Deployment
name: small-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: my-repo/small-service:stable

Scenario B: Switch to Helm when AWS Integration grows

Section titled “Scenario B: Switch to Helm when AWS Integration grows”

When you need to inject AWS-specific configurations (like ALB annotations or IRSA) that vary wildly across dev, staging, and prod, Kustomize overlays become “Wall of YAML.” Switch to a Helm template to handle the EKS OIDC provider dynamically.

Template (templates/serviceaccount.yaml):

apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "small-service.fullname" . }}
annotations:
# Injecting AWS IAM Role dynamically based on environment
eks.amazonaws.com/role-arn: arn:aws:iam::{{ .Values.global.awsAccountId }}:role/{{ .Values.serviceAccount.roleName }}

Values Configuration (values-prod.yaml):

global:
awsAccountId: "123456789012"
serviceAccount:
roleName: "prod-small-service-irsa"
  • Reach for Kustomize if you are the sole consumer of the manifest and the service is “boring” (few dependencies, no logic). It is native to kubectl and requires no package management.
  • Reach for Helm if the service is a “product” consumed by other teams or requires complex AWS resource mapping (S3 buckets, RDS endpoints, IAM roles) that change based on the AWS Account ID or Region.