Files
infrastructure/servers/gcp/k8s/argocd-apps/vault-helm-gke.yaml
T
Will Anderson cebaf44db3 Scale GKE Vault to 1 replica while raft standby deadlock is unresolved
Pods 1 and 2 can't unseal because port 8201 (cluster port) only opens
after barrier initialization, but the barrier key transfer requires 8201
to be reachable — deadlock. Running single-node on pod 0 so
vault.neuralplatform.ai reliably routes to the active, unsealed instance.
2026-05-05 04:37:20 -05:00

176 lines
6.0 KiB
YAML

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: vault-helm-gke
namespace: argocd
annotations:
# Deploys the Vault Helm chart to the GKE cluster via Legion Argo CD.
# The destination.server must be updated after `terraform apply`:
# terraform -chdir=servers/gcp output -raw gke_cluster_endpoint
spec:
project: default
source:
repoURL: https://helm.releases.hashicorp.com
chart: vault
targetRevision: "0.29.1"
helm:
values: |
global:
enabled: true
injector:
enabled: false
ui:
enabled: true
server:
image:
repository: hashicorp/vault
tag: "1.19.2"
# Workload Identity — Vault pod k8s SA impersonates vault-unseal GCP SA
# for KMS auto-unseal. Binding is in servers/gcp/gke.tf.
serviceAccount:
create: true
name: vault
annotations:
iam.gke.io/gcp-service-account: vault-unseal@neuron-785695.iam.gserviceaccount.com
# GKE Autopilot: no privileged containers. Vault doesn't need privilege.
# Request IPC_LOCK so Vault can lock memory (prevents secrets swap).
securityContext:
capabilities:
add:
- IPC_LOCK
# Single replica for now — raft standby unsealing requires the barrier
# key to be shared over port 8201 (cluster port), but 8201 only opens
# after unsealing (deadlock). Running solo on pod 0 until we resolve
# the standby bootstrap path. Scale back to 3 once fixed.
ha:
enabled: true
replicas: 1
raft:
enabled: true
setNodeId: true
config: |
ui = true
listener "tcp" {
tls_disable = 1
address = "[::]:8200"
cluster_address = "[::]:8201"
}
storage "raft" {
path = "/vault/data"
retry_join {
leader_api_addr = "http://vault-helm-gke-0.vault-helm-gke-internal:8200"
}
retry_join {
leader_api_addr = "http://vault-helm-gke-1.vault-helm-gke-internal:8200"
}
retry_join {
leader_api_addr = "http://vault-helm-gke-2.vault-helm-gke-internal:8200"
}
}
seal "gcpckms" {
project = "neuron-785695"
region = "global"
key_ring = "vault"
crypto_key = "vault-unseal"
}
telemetry {
prometheus_retention_time = "30s"
disable_hostname = false
}
# Spread pods across GKE zones
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: vault
component: server
# 10Gi SSD per pod — premium-rwo = pd-ssd on GKE Autopilot
dataStorage:
enabled: true
size: 10Gi
storageClass: standard-rwo
accessMode: ReadWriteOnce
# Annotations on the pod template — bumping rollme triggers a
# StatefulSet rolling restart (pods 2→1→0) to pick up the
# corrected raft retry_join addresses.
podAnnotations:
rollme: "2026-05-05-raft-join-fix"
readinessProbe:
enabled: true
# standbyok=true: standby pods pass (they serve reads).
# sealedok removed: sealed/uninit pods fail readiness so they
# leave the service endpoints and stop receiving external traffic.
path: "/v1/sys/health?standbyok=true"
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
livenessProbe:
enabled: true
# Liveness keeps sealedok=true so sealed pods aren't killed —
# they need time to join raft and auto-unseal.
path: "/v1/sys/health?standbyok=true&sealedok=true&uninitcode=200"
initialDelaySeconds: 60
periodSeconds: 10
failureThreshold: 3
# GKE Autopilot requires resource requests on all containers
resources:
requests:
memory: 256Mi
cpu: 500m
limits:
memory: 512Mi
cpu: 1000m
service:
enabled: true
type: ClusterIP
port: 8200
targetPort: 8200
annotations:
# Container-native NEG for GCP Global HTTPS LB backend cutover.
# GKE will create a zonal NEG named k8s1-<hash>-vault-vault-helm-gke-8200-<hash>
# in each zone where Vault pods are scheduled.
# After this syncs, list NEGs:
# gcloud compute network-endpoint-groups list --filter="name~vault" --project neuron-785695
# Then reference them in servers/gcp/vault-gke-lb.tf.
cloud.google.com/neg: '{"exposed_ports":{"8200":{}}}'
# Ingress disabled — Vault is exposed via GCP HTTPS LB.
# After migration, update the existing LB backend (vault-nodes.tf)
# to target a GKE NEG instead of the GCE instance groups.
# See: https://cloud.google.com/kubernetes-engine/docs/how-to/standalone-neg
ingress:
enabled: false
destination:
# Replace GKE_CLUSTER_ENDPOINT after `terraform apply`:
# terraform -chdir=servers/gcp output -raw gke_cluster_endpoint
server: https://34.63.89.52
namespace: vault
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true