PF-02 · GCP · IaC
GCP Terraform GKE platform
A module set that keeps capacity during GKE node pool upgrades with SURGE, and opens only what a VPN needs through a firewall baseline, all as code.
- Role
- Design and implementation
- Period
- Personal project · released Nov 2026
- Cloud
- GCP
- Scale
- 22 modules · 3 examples
- Key tech
- Terraform · GCP · GKE · Cloud Logging · Cloud Monitoring
- 22
- Terraform modules
- 5
- Extra nodes first (max_surge)
- 0
- Nodes down at once (max_unavailable)
At a glance
Problem
A GKE node upgrade must not reduce serving capacity, and management ports should open only from a VPN.
Approach
The node pool upgrades with SURGE: five new nodes come up first and unavailable stays at zero. The c2sfirewall module opens management ports from the VPN at priority 1000 and denies other tcp and udp outbound at priority 65534.
Result
Old nodes leave only after replacements are ready. Host errors flow from the hostError audit log to a log-based metric, an alert policy, and a Slack channel.
Up close
Node pool SURGE settings
What this code does: Brings new nodes up first so no node is unavailable during an upgrade.
node_pool = {
game = {
autoscaling_enable = true
min_node_count = 3
max_node_count = 12
location_policy = "BALANCED"
node_count = null
pool_version = "1.31"
machine_type = "e2-standard-4"
tags = ["gke-node"]
# Five extra nodes come up first, and no node is taken away until its replacement is ready.
strategy = ["SURGE"]
max_surge = 5
max_unavailable = 0
# Soak time is read only when the strategy is switched to BLUE_GREEN.
node_pool_soak_duration = "3600s"
}
}
A VPN-only firewall baseline
What this code does: Opens management ports only from VPN ranges, at priority 1000.
locals {
firewall_rules = {
c2s-inbound-vpn = {
direction = "INGRESS"
action = "allow"
ranges = var.vpn_source_ranges
sources = null
targets = null
use_service_accounts = false
enable_logging = false
priority = "1000"
rules = [
{
protocol = "tcp"
ports = var.management_ports
}
]
}What I learned
A setting name alone can mislead. The soak time is read only under BLUE_GREEN, so the SURGE example leaves it out.
What I would improve
This repository defines GKE with Terraform and stops there. CI validates the examples but does not apply them.