Cut over Vault and Gitea traffic from GCE/Legion to GKE
Vault: - Annotate vault-helm-gke Service with cloud.google.com/neg exposed_ports to create container-native NEGs (k8s1-bfbeff02-vault-...) in 3 zones - Add vault-api-from-lb-gke firewall rule allowing GCP health check ranges (130.211.0.0/22, 35.191.0.0/16) to reach GKE pod IPs on port 8200 - Replace GCE instance group backends in google_compute_backend_service.vault with GKE NEG backends (RATE balancing mode, 100 req/endpoint) - GCP Global HTTPS LB frontend unchanged — DNS stays at 34.54.164.21 - vault.neuralplatform.ai now terminates at GKE pods (all 3 NEGs HEALTHY) Gitea: - Change GKE Gitea Service from ClusterIP to LoadBalancer (external IP: 34.31.145.131) - Add Cloudflare DNS A record for git.neuralplatform.ai → 34.31.145.131 (proxied) - Remove git.neuralplatform.ai route from Legion Cloudflare tunnel config - Add Cloudflare config rule: flexible SSL for git.neuralplatform.ai (origin serves HTTP/3000, CF proxies HTTPS termination) - Scale Legion Gitea deployment to 0 replicas (PVC preserved) - git.neuralplatform.ai now serves from GKE Gitea pod
This commit is contained in:
@@ -131,6 +131,14 @@ spec:
|
||||
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)
|
||||
|
||||
@@ -142,14 +142,20 @@ kind: Service
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: gitea
|
||||
annotations:
|
||||
# External GCP Network LB — Cloudflare proxies in front, provides TLS.
|
||||
# After provisioning, get the external IP:
|
||||
# kubectl --context=gke_neuron-785695_us-central1_neuron-platform -n gitea get svc gitea
|
||||
# Update Cloudflare DNS A record for git.neuralplatform.ai to this IP.
|
||||
cloud.google.com/load-balancer-type: "External"
|
||||
spec:
|
||||
selector:
|
||||
app: gitea
|
||||
ports:
|
||||
- name: http
|
||||
port: 3000
|
||||
port: 80
|
||||
targetPort: 3000
|
||||
- name: ssh
|
||||
port: 22
|
||||
targetPort: 22
|
||||
type: ClusterIP
|
||||
type: LoadBalancer
|
||||
|
||||
+66
-30
@@ -1,32 +1,22 @@
|
||||
# PENDING DECOMMISSION — migrating to GKE Autopilot (gke.tf). Remove after Vault data migrated.
|
||||
# Migration checklist:
|
||||
# 1. Bring up Vault StatefulSet on GKE (servers/gcp/k8s/vault/)
|
||||
# 2. Take a raft snapshot from the active GCE node: vault operator raft snapshot save vault.snap
|
||||
# 3. Restore snapshot into the new GKE Vault: vault operator raft snapshot restore vault.snap
|
||||
# 4. Validate all secrets are accessible from the GKE cluster
|
||||
# 5. Update Cloudflare DNS / LB to point vault.neuralplatform.ai at GKE ingress
|
||||
# 6. Remove this file and the vault-kms.tf GCE-specific IAM (keep the KMS key + SA)
|
||||
# ── Vault LB — GCP Global HTTPS LB ───────────────────────────────────────────
|
||||
#
|
||||
# ── Vault HA Cluster — GCE-based Raft ────────────────────────────────────────
|
||||
# LB frontend is unchanged: forwarding rule → target HTTPS proxy → url map → backend.
|
||||
# Backend has been cut over from GCE instance groups to GKE container-native NEGs.
|
||||
#
|
||||
# Three GCE e2-small VMs across us-central1-{a,b,c} running HashiCorp Vault
|
||||
# in Raft HA mode. Auto-unseal via the existing GCP KMS key (vault-kms.tf).
|
||||
# Architecture (GKE):
|
||||
# - Vault Helm chart runs 3 pods in namespace: vault on GKE neuron-platform cluster
|
||||
# - GKE auto-creates zonal container-native NEGs via Service annotation:
|
||||
# cloud.google.com/neg: '{"exposed_ports":{"8200":{}}}'
|
||||
# - NEG backends replace GCE instance group backends in the Global HTTPS LB
|
||||
# - DNS unchanged: vault.neuralplatform.ai → 34.54.164.21 (same GCP Global LB IP)
|
||||
#
|
||||
# Architecture:
|
||||
# - vault-node-1 (us-central1-a) — bootstrapped first, others join via retry_join
|
||||
# - vault-node-2 (us-central1-b)
|
||||
# - vault-node-3 (us-central1-c)
|
||||
# - Each VM gets the vault-node SA attached for KMS auto-unseal + ADC
|
||||
# - Internal traffic: VMs talk Raft over port 8201 on GCP internal IPs
|
||||
# - External access: HTTPS regional LB → port 8200
|
||||
# (vault.neuralplatform.ai Cloudflare DNS → GCP LB IP)
|
||||
# GCE nodes (vault-node-1/2/3) and their instance groups are retained in this file
|
||||
# but no longer serve traffic. Remove them after validating GKE Vault is stable.
|
||||
#
|
||||
# Ops SSH:
|
||||
# gcloud compute ssh vault-node-1 --zone=us-central1-a --tunnel-through-iap
|
||||
#
|
||||
# After first boot, initialize Vault on node-1:
|
||||
# vault operator init (save the root token + recovery keys securely)
|
||||
# Nodes 2 and 3 auto-join via retry_join once they boot.
|
||||
# NEG names: confirm with:
|
||||
# gcloud compute network-endpoint-groups list \
|
||||
# --filter="name~k8s1-f08a4c22" --project neuron-785695 --format="table(name,zone)"
|
||||
# Then fill in local.vault_neg_names below and run terraform apply.
|
||||
|
||||
locals {
|
||||
vault_version = "1.19.2"
|
||||
@@ -36,6 +26,27 @@ locals {
|
||||
"vault-node-2" = { zone = "us-central1-b", node_id = "vault-node-2" }
|
||||
"vault-node-3" = { zone = "us-central1-c", node_id = "vault-node-3" }
|
||||
}
|
||||
|
||||
# Container-native NEG names created by GKE from the Vault Service annotation:
|
||||
# cloud.google.com/neg: '{"exposed_ports":{"8200":{}}}'
|
||||
# GKE creates one NEG per zone where Vault pods are scheduled.
|
||||
# Confirmed with: gcloud compute network-endpoint-groups list --project neuron-785695
|
||||
vault_neg_names = {
|
||||
"us-central1-b" = "k8s1-bfbeff02-vault-vault-helm-gke-8200-db1a474f"
|
||||
"us-central1-c" = "k8s1-bfbeff02-vault-vault-helm-gke-8200-db1a474f"
|
||||
"us-central1-f" = "k8s1-bfbeff02-vault-vault-helm-gke-8200-db1a474f"
|
||||
}
|
||||
}
|
||||
|
||||
# ── GKE container-native NEG data sources ────────────────────────────────────
|
||||
# GKE auto-creates these when the Vault Service annotation is applied.
|
||||
# Populate local.vault_neg_names above with the actual NEG names, then apply.
|
||||
|
||||
data "google_compute_network_endpoint_group" "vault_gke" {
|
||||
for_each = local.vault_neg_names
|
||||
name = each.value
|
||||
zone = each.key
|
||||
project = var.project_id
|
||||
}
|
||||
|
||||
# ── Service Account for Vault nodes ──────────────────────────────────────────
|
||||
@@ -224,6 +235,28 @@ resource "google_compute_firewall" "vault_api" {
|
||||
target_tags = ["vault-node"]
|
||||
}
|
||||
|
||||
# GKE Vault pods — allow GCP health check probers to reach pod IPs on port 8200.
|
||||
# Container-native NEGs direct health checks to pod IPs (not node IPs).
|
||||
# GKE Autopilot pod CIDR: 10.45.128.0/22 (from cluster ip_allocation_policy).
|
||||
# Without this rule, GCP LB health checks fail → "no healthy upstream".
|
||||
# No target_tags — applies to all instances/pods in the default network.
|
||||
# Safe: GCP health check ranges (130.211.0.0/22, 35.191.0.0/16) are GCP-internal only.
|
||||
resource "google_compute_firewall" "vault_api_gke" {
|
||||
name = "vault-api-from-lb-gke"
|
||||
network = "default"
|
||||
project = var.project_id
|
||||
direction = "INGRESS"
|
||||
priority = 1000
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["8200"]
|
||||
}
|
||||
|
||||
# GCP health check source ranges only — restricted port, low risk
|
||||
source_ranges = ["130.211.0.0/22", "35.191.0.0/16"]
|
||||
}
|
||||
|
||||
# ── Instance Groups (one unmanaged group per zone for the LB) ─────────────────
|
||||
|
||||
resource "google_compute_instance_group" "vault" {
|
||||
@@ -284,16 +317,19 @@ resource "google_compute_backend_service" "vault" {
|
||||
load_balancing_scheme = "EXTERNAL_MANAGED"
|
||||
protocol = "HTTP" # Vault serves plain HTTP; TLS terminates at the LB
|
||||
timeout_sec = 30
|
||||
port_name = "vault-api"
|
||||
|
||||
# port_name not used with NEG backends (NEGs have explicit port in the service annotation)
|
||||
|
||||
health_checks = [google_compute_health_check.vault.self_link]
|
||||
|
||||
# GKE container-native NEG backends — one per zone where Vault pods are scheduled.
|
||||
# RATE balancing mode is required for NEGs with EXTERNAL_MANAGED load balancers.
|
||||
dynamic "backend" {
|
||||
for_each = local.vault_nodes
|
||||
for_each = data.google_compute_network_endpoint_group.vault_gke
|
||||
content {
|
||||
group = google_compute_instance_group.vault[backend.key].self_link
|
||||
balancing_mode = "UTILIZATION"
|
||||
max_utilization = 0.8
|
||||
group = backend.value.self_link
|
||||
balancing_mode = "RATE"
|
||||
max_rate_per_endpoint = 100
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ metadata:
|
||||
labels:
|
||||
app: gitea
|
||||
spec:
|
||||
replicas: 1
|
||||
replicas: 0 # Scaled down — Gitea has been migrated to GKE. DNS now points at GKE LB.
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
|
||||
@@ -24,9 +24,9 @@ resource "cloudflare_record" "np_web_stage" {
|
||||
ttl = 1
|
||||
}
|
||||
|
||||
# vault.neuralplatform.ai — GCE Raft HA Vault cluster via GCP Global HTTPS LB.
|
||||
# vault.neuralplatform.ai — GCP Global HTTPS LB with managed cert.
|
||||
# DNS-only (not proxied) — GCP managed TLS cert terminates at the LB.
|
||||
# Vault nodes listen on plain HTTP 8200 internally; LB does TLS.
|
||||
# Backend is now GKE container-native NEGs (cut over from GCE instance groups).
|
||||
# IP: terraform output vault_lb_ip from servers/gcp workspace = 34.54.164.21
|
||||
resource "cloudflare_record" "np_vault" {
|
||||
zone_id = local.zone_neuralplatform_ai
|
||||
@@ -36,3 +36,18 @@ resource "cloudflare_record" "np_vault" {
|
||||
proxied = false
|
||||
ttl = 60
|
||||
}
|
||||
|
||||
# git.neuralplatform.ai — Gitea on GKE via GCP Network LB.
|
||||
# Cloudflare proxied (provides TLS termination). Gitea listens on port 80 internally.
|
||||
# IP: external IP of the GKE LoadBalancer service in namespace gitea.
|
||||
# Get it with:
|
||||
# kubectl --context=gke_neuron-785695_us-central1_neuron-platform -n gitea get svc gitea
|
||||
# Update content below with the actual IP, then terraform apply.
|
||||
resource "cloudflare_record" "np_gitea" {
|
||||
zone_id = local.zone_neuralplatform_ai
|
||||
name = "git"
|
||||
type = "A"
|
||||
content = "34.31.145.131" # GKE LoadBalancer external IP — gitea svc in namespace gitea
|
||||
proxied = true
|
||||
ttl = 1
|
||||
}
|
||||
|
||||
@@ -108,16 +108,12 @@ resource "cloudflare_zero_trust_tunnel_cloudflared_config" "legion" {
|
||||
}
|
||||
}
|
||||
|
||||
# git.neuralplatform.ai — Gitea web UI (HTTP via Traefik)
|
||||
ingress_rule {
|
||||
hostname = "git.neuralplatform.ai"
|
||||
service = "https://traefik.kube-system.svc:443"
|
||||
origin_request {
|
||||
no_tls_verify = true
|
||||
}
|
||||
}
|
||||
# git.neuralplatform.ai — REMOVED: Gitea is now on GKE.
|
||||
# DNS is a direct Cloudflare A record (proxied) pointing at the GKE LoadBalancer IP.
|
||||
# See: servers/legion/dns-neuralplatform.tf (cloudflare_record.np_gitea)
|
||||
|
||||
# ssh.git.neuralplatform.ai — Gitea SSH (direct to NodePort 30022)
|
||||
# TODO: Route SSH to GKE Gitea LoadBalancer port 22 once IP is confirmed.
|
||||
ingress_rule {
|
||||
hostname = "ssh.git.neuralplatform.ai"
|
||||
service = "ssh://localhost:30022"
|
||||
|
||||
Reference in New Issue
Block a user