From 3475c2013cad009e5e17be481503537f8a0a5d1d Mon Sep 17 00:00:00 2001 From: Konstantin Renner Date: Fri, 26 Jun 2026 15:07:11 +0200 Subject: [PATCH] opentofu: give the woodpecker-agent LXCs IPv6 (the actual root cause) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The agents are unprivileged Proxmox LXCs whose ip_config had only an ipv4 block — no IPv6 at all. So no matter how Docker/Woodpecker were configured for v6 (daemon.json ip6tables, WOODPECKER_BACKEND_DOCKER_ENABLE_IPV6), the step containers had no v6 uplink to NAT onto, and deploys to v6-only hosts (proxy-1) failed 'Network unreachable'. IPv4 NAT works in these LXCs, so v6 NAT will too once the LXC actually has v6. Add an optional ipv6 block to the proxmox_lxc module (auto/dhcp/static) and set ipv6_address = "auto" (SLAAC off v40srv) for the agents. NOTE: `initialization` is in the module's ignore_changes, so this does NOT apply to running agents on a normal apply — they must be RECREATED to pick up v6 (they're tagged `transient`). Recreate one at a time to keep CI up, then re-run install-woodpecker-agent.yml on each. Co-Authored-By: Claude Opus 4.8 (1M context) --- opentofu/modules/proxmox_lxc/main.tf | 21 ++++++++++++++------- opentofu/modules/proxmox_lxc/variables.tf | 12 ++++++++++++ opentofu/woodpecker_agents.tf | 3 +++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/opentofu/modules/proxmox_lxc/main.tf b/opentofu/modules/proxmox_lxc/main.tf index c379cfcb..b1a78d36 100644 --- a/opentofu/modules/proxmox_lxc/main.tf +++ b/opentofu/modules/proxmox_lxc/main.tf @@ -24,6 +24,13 @@ resource "proxmox_virtual_environment_container" "this" { address = var.ip_address != null ? "${var.ip_address}/24" : "dhcp" gateway = var.ip_address != null ? cidrhost("${var.ip_address}/24", 1) : null } + dynamic "ipv6" { + for_each = var.ipv6_address != null ? [1] : [] + content { + address = var.ipv6_address + gateway = var.ipv6_gateway + } + } } } @@ -97,13 +104,13 @@ resource "proxmox_virtual_environment_container" "this" { lifecycle { ignore_changes = [ - node_name, # HA migrations move containers between nodes - initialization, # Hostname/user changes can cause issues - disk, # Disk changes can be destructive - mount_point, # Mount point changes force replacement - operating_system, # Template changes would require recreation - features, # API token can't modify features on privileged containers (requires root@pam) - network_interface # Network changes can disrupt running services and cause connectivity issues + node_name, # HA migrations move containers between nodes + initialization, # Hostname/user changes can cause issues + disk, # Disk changes can be destructive + mount_point, # Mount point changes force replacement + operating_system, # Template changes would require recreation + features, # API token can't modify features on privileged containers (requires root@pam) + network_interface # Network changes can disrupt running services and cause connectivity issues ] } } diff --git a/opentofu/modules/proxmox_lxc/variables.tf b/opentofu/modules/proxmox_lxc/variables.tf index 2aa93f5e..dd95c221 100644 --- a/opentofu/modules/proxmox_lxc/variables.tf +++ b/opentofu/modules/proxmox_lxc/variables.tf @@ -37,6 +37,18 @@ variable "ip_address" { default = null } +variable "ipv6_address" { + type = string + description = "IPv6 config for the container: \"auto\" (SLAAC), \"dhcp\", or a static CIDR. null disables IPv6." + default = null +} + +variable "ipv6_gateway" { + type = string + description = "IPv6 gateway (only for a static ipv6_address; leave null for auto/dhcp)." + default = null +} + variable "tags" { type = string default = "" diff --git a/opentofu/woodpecker_agents.tf b/opentofu/woodpecker_agents.tf index 7d3b4ba1..7ec92ef6 100644 --- a/opentofu/woodpecker_agents.tf +++ b/opentofu/woodpecker_agents.tf @@ -23,6 +23,9 @@ module "woodpecker_agents" { start = each.value.state == "started" ? true : false network_bridge = each.value.bridge + # CI steps must reach IPv6-only hosts; give the LXC SLAAC v6 off v40srv so + # Docker has a v6 uplink to NAT the pipeline networks onto. + ipv6_address = "auto" features = { nesting = each.value.nesting -- 2.54.0