mirror of
https://github.com/immich-app/yucca-o11y.git
synced 2026-09-30 13:23:23 +08:00
refactor: make tf outputs the single source of operational facts (#104)
Signed-off-by: Devin Buhl <devin@buhl.casa>
This commit is contained in:
+15
-7
@@ -31,23 +31,31 @@ ENVIRONMENT_SHORT = "{% set e = get_env(name='ENVIRONMENT', default='development
|
||||
# Control planes need the image uploaded to OVH glance (talos:{dl,ul}:cp); workers
|
||||
# are OVH BYOI, so OVH fetches their raw from the Factory at order time (no upload).
|
||||
|
||||
# Image facts (schematic, version, glance name, regions) come from the ovh/account
|
||||
# cp_image output — one source, no must-match with the module.
|
||||
[tasks."talos:dl:cp"]
|
||||
run = """
|
||||
: "${ENVIRONMENT:?set ENVIRONMENT=staging (or production) first}"
|
||||
mkdir -p {{config_root}}/.private/dist
|
||||
wget https://factory.talos.dev/image/bbfcb7053b1609712a977830952455432825890922cb6bac23cea34b980970f1/v1.13.5/openstack-amd64.raw.xz -O {{config_root}}/.private/dist/talos.1.13.5-qemu-netbird.raw.xz
|
||||
unxz {{config_root}}/.private/dist/talos.1.13.5-qemu-netbird.raw.xz --force
|
||||
CP_IMAGE=$(mise run tg run --working-dir deployment/modules/ovh/account output -- -json cp_image)
|
||||
NAME=$(echo "$CP_IMAGE" | jq -r .glance_name)
|
||||
wget "$(echo "$CP_IMAGE" | jq -r .download_url)" -O {{config_root}}/.private/dist/${NAME}.raw.xz
|
||||
unxz {{config_root}}/.private/dist/${NAME}.raw.xz --force
|
||||
"""
|
||||
description = "Download the control-plane Talos image (OpenStack, qemu-guest-agent + netbird schematic)"
|
||||
description = "Download the control-plane Talos image (OpenStack, from the ovh/account cp_image output)"
|
||||
dir = "{{cwd}}"
|
||||
|
||||
[tasks."talos:ul:cp"]
|
||||
run = """
|
||||
for region in "RBX-A" "GRA9" "EU-WEST-PAR"; do
|
||||
echo "Uploading to region ${region}..."
|
||||
: "${ENVIRONMENT:?set ENVIRONMENT=staging (or production) first}"
|
||||
CP_IMAGE=$(mise run tg run --working-dir deployment/modules/ovh/account output -- -json cp_image)
|
||||
NAME=$(echo "$CP_IMAGE" | jq -r .glance_name)
|
||||
for region in $(echo "$CP_IMAGE" | jq -r '.regions[]'); do
|
||||
echo "Uploading ${NAME} to region ${region}..."
|
||||
source {{config_root}}/.private/openstack/${ENVIRONMENT}/openrc.sh
|
||||
openstack image create "talos-1.13.5-qemu-netbird" \
|
||||
openstack image create "${NAME}" \
|
||||
--os-region "${region}" \
|
||||
--file {{config_root}}/.private/dist/talos.1.13.5-qemu-netbird.raw \
|
||||
--file {{config_root}}/.private/dist/${NAME}.raw \
|
||||
--disk-format raw \
|
||||
--container-format bare \
|
||||
--property hw_qemu_guest_agent=yes \
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
output "flux_operator_status" {
|
||||
value = helm_release.flux_operator.status
|
||||
}
|
||||
|
||||
output "flux_instance_status" {
|
||||
value = helm_release.flux_instance.status
|
||||
}
|
||||
@@ -17,10 +17,7 @@ dependency "talos" {
|
||||
# Cert mocks must be valid base64 — providers.tf base64-decodes on every plan.
|
||||
mock_outputs = {
|
||||
cluster = {
|
||||
name = "mock"
|
||||
endpoint = "https://mock:6443"
|
||||
operator_endpoint = "https://mock:6443"
|
||||
vip = "10.0.0.5"
|
||||
client_certificate = "bW9jaw=="
|
||||
client_key = "bW9jaw=="
|
||||
ca_certificate = "bW9jaw=="
|
||||
|
||||
@@ -9,10 +9,7 @@ variable "tf_state_s3_endpoint" {}
|
||||
|
||||
variable "cluster" {
|
||||
type = object({
|
||||
name = string
|
||||
endpoint = string
|
||||
operator_endpoint = string
|
||||
vip = string
|
||||
client_certificate = string
|
||||
client_key = string
|
||||
ca_certificate = string
|
||||
|
||||
@@ -20,10 +20,6 @@ output "worker_nodes" {
|
||||
}
|
||||
}
|
||||
|
||||
output "loadbalancer_ip" {
|
||||
value = ovh_iploadbalancing.envoy.ipv4
|
||||
}
|
||||
|
||||
# bare_metal for workers, public_cloud for CPs — sharing breaks upgrade on
|
||||
# the other. Openstack URL is hand-built because the talos provider's
|
||||
# data source returns null for platform = "openstack".
|
||||
@@ -37,3 +33,13 @@ output "talos_installer_images" {
|
||||
output "private_network_cidr" {
|
||||
value = var.private_network_cidr
|
||||
}
|
||||
|
||||
# Consumed by the talos:dl:cp / talos:ul:cp mise tasks, so the CP image facts
|
||||
# (schematic, version, glance name, regions) live only in this module.
|
||||
output "cp_image" {
|
||||
value = {
|
||||
download_url = "https://factory.talos.dev/image/${var.talos_schematic_id}/${var.talos_version}/openstack-amd64.raw.xz"
|
||||
glance_name = var.talos_public_cloud_image_name
|
||||
regions = distinct([for n in var.controlplane_nodes : n.region])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# Exactly what downstream providers (kubernetes/helm) need to reach the cluster.
|
||||
output "cluster" {
|
||||
sensitive = true
|
||||
value = {
|
||||
name = local.cluster_name
|
||||
endpoint = local.cluster_endpoint
|
||||
operator_endpoint = local.operator_endpoint
|
||||
vip = local.controlplane_vip
|
||||
client_certificate = talos_cluster_kubeconfig.this.kubernetes_client_configuration.client_certificate
|
||||
client_key = talos_cluster_kubeconfig.this.kubernetes_client_configuration.client_key
|
||||
ca_certificate = talos_cluster_kubeconfig.this.kubernetes_client_configuration.ca_certificate
|
||||
@@ -16,14 +14,49 @@ output "talos_client_configuration" {
|
||||
value = data.talos_client_configuration.this.talos_config
|
||||
}
|
||||
|
||||
# Server rewritten from the (in-cluster-only) VIP to the HA mesh endpoint, so the zone
|
||||
# special-case lives only in netbird/cluster's mesh_dns_zone. Break-glass for bootstrap/DR
|
||||
# before the gateway exists: kubectl --server=https://<cp-private-ip>:6443 (all cert SANs).
|
||||
# TF-authored kubeconfig with two contexts: the HA mesh endpoint (default) and a
|
||||
# direct-CP break-glass for bootstrap/DR before the gateway exists
|
||||
# (kubectl --context <cluster>-direct). Both endpoints are apiserver cert SANs.
|
||||
output "kubeconfig" {
|
||||
sensitive = true
|
||||
value = replace(
|
||||
talos_cluster_kubeconfig.this.kubeconfig_raw,
|
||||
"server: ${local.cluster_endpoint}",
|
||||
"server: https://kube.${var.mesh_dns_zone}:6443",
|
||||
)
|
||||
value = yamlencode({
|
||||
apiVersion = "v1"
|
||||
kind = "Config"
|
||||
"current-context" = local.cluster_name
|
||||
clusters = [
|
||||
{
|
||||
name = local.cluster_name
|
||||
cluster = {
|
||||
server = "https://kube.${var.mesh_dns_zone}:6443"
|
||||
"certificate-authority-data" = talos_cluster_kubeconfig.this.kubernetes_client_configuration.ca_certificate
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "${local.cluster_name}-direct"
|
||||
cluster = {
|
||||
server = local.operator_endpoint
|
||||
"certificate-authority-data" = talos_cluster_kubeconfig.this.kubernetes_client_configuration.ca_certificate
|
||||
}
|
||||
},
|
||||
]
|
||||
users = [
|
||||
{
|
||||
name = "admin@${local.cluster_name}"
|
||||
user = {
|
||||
"client-certificate-data" = talos_cluster_kubeconfig.this.kubernetes_client_configuration.client_certificate
|
||||
"client-key-data" = talos_cluster_kubeconfig.this.kubernetes_client_configuration.client_key
|
||||
}
|
||||
},
|
||||
]
|
||||
contexts = [
|
||||
{
|
||||
name = local.cluster_name
|
||||
context = { cluster = local.cluster_name, user = "admin@${local.cluster_name}" }
|
||||
},
|
||||
{
|
||||
name = "${local.cluster_name}-direct"
|
||||
context = { cluster = "${local.cluster_name}-direct", user = "admin@${local.cluster_name}" }
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
@@ -84,9 +84,10 @@ mise run talos:kubeconfig # for kubectl
|
||||
mise run talos:talosconfig # for talosctl
|
||||
```
|
||||
|
||||
Each writes to `.private/$ENVIRONMENT/` (mode 600) from the Talos module's Terraform outputs. `talos:kubeconfig` also repoints the kubeconfig `server:` from the floating VIP (`10.150.200.5`) to a control-plane private IP (`10.150.200.10`) — the VIP doesn't ARP reliably across DCs over the NetBird network, and every CP IP is in the apiserver cert SANs so TLS still validates.
|
||||
Each writes to `.private/$ENVIRONMENT/` (mode 600) from the Talos module's Terraform outputs. The kubeconfig is TF-authored with two contexts:
|
||||
|
||||
> **A highly-available operator API endpoint is TBD.** `kubectl` is pinned to a single control-plane IP, so if that CP is down you currently repoint to another by hand (any CP IP works — they're all cert SANs). The floating VIP is HA *inside* the cluster (kubelet and in-cluster clients use it) but doesn't ARP across DCs over the NetBird network, so there's no HA endpoint for operators yet.
|
||||
* **`o11y-<env>`** (default) — the HA endpoint `kube.<mesh-zone>:6443`, fronted by the Envoy mesh gateway (TLS passthrough to every apiserver). Survives any single CP being down and never hairpins through a NetBird routing peer.
|
||||
* **`o11y-<env>-direct`** — a control-plane private IP, for bootstrap/DR before the mesh gateway exists: `kubectl --context o11y-<env>-direct`. Every CP IP is an apiserver cert SAN, so TLS validates on both paths. (The floating VIP `.5` is in-cluster-only — it doesn't ARP across DCs.)
|
||||
|
||||
**Point your tools at them:**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user