Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Incident: hungryhub + utility Namespace Deletion — 2026-06-08

Summary

Triggering terraform apply for eks-services with new code on branch fix/409-ca-priority-expander deleted the hungryhub and utility Kubernetes namespaces, taking down all workloads in those namespaces for ~30–45 minutes.

Timeline (UTC+7 / Bangkok)

TimeEvent
~11:10Terraform Deployment Workflow triggered for eks-services, environment=prod, action=apply on main branch (run #27115482778)
~11:18Apply failed — kubernetes_namespace resources for hungryhub, utility, hh-syn-public, etc. errored with “already exists”. These namespaces existed in cluster but were NOT in terraform state.
~11:20Terraform had already deleted hungryhub and utility namespaces mid-apply before hitting the error. All pods/deployments/services in those namespaces destroyed.
~11:21hungryhub and utility namespaces recreated manually via kubectl create namespace
~11:22hungryhub-server-config ConfigMap copied from hh-cosmos-private to unblock sidekiq pods
~11:30Most hungryhub pods recovered (30 Running). hungryhub-menu still down (missing hungryhub-menu-config)
~11:40CodePipeline prod-hh-server-main completed hungryhub deploy step, restoring remaining pods

Root Cause

namespace.tf in eks-services declares kubernetes_namespace resources for all prod namespaces. These namespaces had been created manually (pre-Terraform) and were never imported into Terraform state. Terraform therefore treated them as resources to create.

On the first apply after this discrepancy was exposed, Terraform attempted to create all namespaces. For namespaces already in state (dev-preview-*), it refreshed correctly. For the 10 that were NOT in state, it tried to create them. hungryhub and utility completed the delete step before the conflict errors terminated the apply — the others got “already exists” because their create was attempted while they still existed.

Why only hungryhub and utility were deleted: Terraform processes resources in parallel. Those two happened to complete delete before the conflict errors terminated the apply run.

Services Affected

ServiceImpact
hungryhub-sidekiq-criticalDown ~20 min — critical queue jobs delayed
hungryhub-sidekiq-defaultDown ~20 min
hungryhub-sidekiq-kafkaDown ~20 min
hungryhub-sidekiq-invDown ~20 min
hungryhub-sidekiq-lpDown ~20 min
hungryhub-karafkaDown ~20 min
hungryhub-helperDown ~20 min
hungryhub-menuDown ~40 min (needed hungryhub-menu-config from pipeline)
ai-text-to-imageDown indefinitely — k8s Secret deleted with namespace; values not stored in SSM/Secrets Manager
hh-tiger, hh-pumaBriefly down, recovered quickly
utility namespaceEmpty — no active workloads lost

Recovery Steps Taken

  1. Recreated namespaces:

    kubectl create namespace hungryhub
    kubectl create namespace utility
    
  2. Copied hungryhub-server-config ConfigMap from hh-cosmos-private (pods need it to start):

    kubectl get configmap hungryhub-server-config -n hh-cosmos-private -o json | \
      python3 -c "
    import json,sys
    cm = json.load(sys.stdin)
    cm['metadata'] = {'name': 'hungryhub-server-config', 'namespace': 'hungryhub'}
    print(json.dumps(cm))
    " | kubectl apply -f -
    
  3. Pods rescheduled automatically once namespace + ConfigMap existed.

  4. CodePipeline prod-hh-server-main (already running) completed the hungryhub deploy step, restoring remaining workloads.

What Was NOT Recovered Automatically

ai-text-to-image Secret — contained AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, GEMINI_API_KEY, FAL_KEY. Only existed as a Kubernetes Secret, not backed by SSM or Secrets Manager. Must be recreated manually before ai-text-to-image can start.

Fix Applied

Added namespace-imports.tf to eks-services with native Terraform import blocks (TF 1.5+) for all 10 untracked namespaces. On next successful terraform apply, these namespaces will be imported into state and Terraform will manage them without deleting.

PR: https://github.com/hungryhub-team/hungryhub-terraform/pull/411

Prevention / Follow-up Actions

ActionPriority
Store ai-text-to-image secret values in SSM or AWS Secrets ManagerHIGH
Fix eks-services terraform apply (namespace import run still failing)HIGH
Audit all k8s Secrets in hungryhub namespace — confirm each is backed by external storeHIGH
Add lifecycle { prevent_destroy = true } to all kubernetes_namespace resourcesMEDIUM
Remove dev-preview-* namespaces from prod namespace.tf (sandbox-only)MEDIUM
Run terraform plan before every apply and gate on no unexpected destroysMEDIUM

Lessons Learned

  1. Never apply terraform on a module with unimported live resources. Run terraform plan first; gate on zero unexpected destroys.
  2. Terraform delete+create is not atomic. A failed apply can leave resources partially destroyed.
  3. k8s Secrets must be backed by an external secret store. A Secret living only in etcd is one namespace deletion from permanent loss.
  4. Add prevent_destroy to namespace resources to require explicit override before deletion.