Refactor Argo CD application management by removing noble-kyverno and noble-platform configurations, transitioning to Ansible-driven installations. Update documentation to clarify the optional nature of app-of-apps and the role of kustomization.yaml as an empty resource holder. Ensure users are informed about the need to delete stale Applications when migrating from previous configurations.

This commit is contained in:
Nikholas Pcenicni
2026-03-28 15:17:54 -04:00
parent 207cdca0cf
commit 46cedc965f
40 changed files with 1264 additions and 187 deletions

View File

@@ -0,0 +1,18 @@
---
noble_helm_repos:
- { name: cilium, url: "https://helm.cilium.io/" }
- { name: metallb, url: "https://metallb.github.io/metallb" }
- { name: longhorn, url: "https://charts.longhorn.io" }
- { name: traefik, url: "https://traefik.github.io/charts" }
- { name: jetstack, url: "https://charts.jetstack.io" }
- { name: fossorial, url: "https://charts.fossorial.io" }
- { name: argo, url: "https://argoproj.github.io/argo-helm" }
- { name: metrics-server, url: "https://kubernetes-sigs.github.io/metrics-server/" }
- { name: sealed-secrets, url: "https://bitnami-labs.github.io/sealed-secrets" }
- { name: external-secrets, url: "https://charts.external-secrets.io" }
- { name: hashicorp, url: "https://helm.releases.hashicorp.com" }
- { name: prometheus-community, url: "https://prometheus-community.github.io/helm-charts" }
- { name: grafana, url: "https://grafana.github.io/helm-charts" }
- { name: fluent, url: "https://fluent.github.io/helm-charts" }
- { name: headlamp, url: "https://kubernetes-sigs.github.io/headlamp/" }
- { name: kyverno, url: "https://kyverno.github.io/kyverno/" }

View File

@@ -0,0 +1,16 @@
---
- name: Add Helm repositories
ansible.builtin.command:
cmd: "helm repo add {{ item.name }} {{ item.url }}"
loop: "{{ noble_helm_repos }}"
loop_control:
label: "{{ item.name }}"
register: helm_repo_add
changed_when: helm_repo_add.rc == 0
failed_when: >-
helm_repo_add.rc != 0 and
('already exists' not in (helm_repo_add.stderr | default('')))
- name: helm repo update
ansible.builtin.command: helm repo update
changed_when: true

View File

@@ -0,0 +1,20 @@
---
- name: Install Argo CD
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- argocd
- argo/argo-cd
- --namespace
- argocd
- --create-namespace
- --version
- "9.4.17"
- -f
- "{{ noble_repo_root }}/clusters/noble/bootstrap/argocd/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,65 @@
---
- name: Create cert-manager namespace
ansible.builtin.command:
argv:
- kubectl
- apply
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/cert-manager/namespace.yaml"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install cert-manager
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- cert-manager
- jetstack/cert-manager
- --namespace
- cert-manager
- --version
- v1.20.0
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/cert-manager/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Check Cloudflare DNS API token Secret (required for ClusterIssuers)
ansible.builtin.command:
argv:
- kubectl
- -n
- cert-manager
- get
- secret
- cloudflare-dns-api-token
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
register: noble_cf_secret
failed_when: false
changed_when: false
- name: Warn when Cloudflare Secret is missing
ansible.builtin.debug:
msg: >-
Secret cert-manager/cloudflare-dns-api-token not found.
Create it per clusters/noble/apps/cert-manager/README.md before ClusterIssuers can succeed.
when:
- noble_cert_manager_require_cloudflare_secret | bool
- noble_cf_secret.rc != 0
- name: Apply ClusterIssuers (staging + prod)
ansible.builtin.command:
argv:
- kubectl
- apply
- -k
- "{{ noble_repo_root }}/clusters/noble/apps/cert-manager"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,25 @@
---
- name: Install Cilium (required CNI for Talos cni:none)
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- cilium
- cilium/cilium
- --namespace
- kube-system
- --version
- "1.16.6"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/cilium/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Wait for Cilium DaemonSet
ansible.builtin.command: kubectl -n kube-system rollout status ds/cilium --timeout=300s
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: false

View File

@@ -0,0 +1,11 @@
---
- name: Apply kube-vip (Kubernetes API VIP)
ansible.builtin.command:
argv:
- kubectl
- apply
- -k
- "{{ noble_repo_root }}/clusters/noble/apps/kube-vip"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,32 @@
---
- name: Create Kyverno namespace
ansible.builtin.command:
argv:
- kubectl
- apply
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/kyverno/namespace.yaml"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install Kyverno operator
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- kyverno
- kyverno/kyverno
- -n
- kyverno
- --version
- "3.7.1"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/kyverno/values.yaml"
- --wait
- --timeout
- 15m
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,21 @@
---
- name: Install Kyverno policy chart (PSS baseline, Audit)
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- kyverno-policies
- kyverno/kyverno-policies
- -n
- kyverno
- --version
- "3.7.1"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/kyverno/policies-values.yaml"
- --wait
- --timeout
- 10m
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,29 @@
---
- name: Apply Longhorn namespace (PSA) from kustomization
ansible.builtin.command:
argv:
- kubectl
- apply
- -k
- "{{ noble_repo_root }}/clusters/noble/apps/longhorn"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install Longhorn chart
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- longhorn
- longhorn/longhorn
- -n
- longhorn-system
- --create-namespace
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/longhorn/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,37 @@
---
- name: Apply MetalLB namespace (Pod Security labels)
ansible.builtin.command:
argv:
- kubectl
- apply
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/metallb/namespace.yaml"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install MetalLB chart
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- metallb
- metallb/metallb
- --namespace
- metallb-system
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Apply IPAddressPool and L2Advertisement
ansible.builtin.command:
argv:
- kubectl
- apply
- -k
- "{{ noble_repo_root }}/clusters/noble/apps/metallb"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,19 @@
---
- name: Install metrics-server
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- metrics-server
- metrics-server/metrics-server
- -n
- kube-system
- --version
- "3.13.0"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/metrics-server/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,37 @@
---
- name: Skip Newt when not enabled
ansible.builtin.debug:
msg: "noble_newt_install is false — create newt-pangolin-auth Secret and set noble_newt_install=true to deploy Newt."
when: not (noble_newt_install | bool)
- name: Create Newt namespace
ansible.builtin.command:
argv:
- kubectl
- apply
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/newt/namespace.yaml"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
when: noble_newt_install | bool
changed_when: true
- name: Install Newt chart
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- newt
- fossorial/newt
- --namespace
- newt
- --version
- "1.2.0"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/newt/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
when: noble_newt_install | bool
changed_when: true

View File

@@ -0,0 +1,147 @@
---
# Mirrors former **noble-platform** Argo Application: Helm releases + plain manifests under clusters/noble/apps.
- name: Apply clusters/noble/apps kustomize (namespaces, Grafana Loki datasource, Vault extras)
ansible.builtin.command:
argv:
- kubectl
- apply
- -k
- "{{ noble_repo_root }}/clusters/noble/apps"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install Sealed Secrets
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- sealed-secrets
- sealed-secrets/sealed-secrets
- --namespace
- sealed-secrets
- --version
- "2.18.4"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/sealed-secrets/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install External Secrets Operator
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- external-secrets
- external-secrets/external-secrets
- --namespace
- external-secrets
- --version
- "2.2.0"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/external-secrets/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install Vault
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- vault
- hashicorp/vault
- --namespace
- vault
- --version
- "0.32.0"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/vault/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install kube-prometheus-stack
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- kube-prometheus
- prometheus-community/kube-prometheus-stack
- -n
- monitoring
- --version
- "82.15.1"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/kube-prometheus-stack/values.yaml"
- --wait
- --timeout
- 30m
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install Loki
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- loki
- grafana/loki
- -n
- loki
- --version
- "6.55.0"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/loki/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install Fluent Bit
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- fluent-bit
- fluent/fluent-bit
- -n
- logging
- --version
- "0.56.0"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/fluent-bit/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install Headlamp
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- headlamp
- headlamp/headlamp
- --version
- "0.40.1"
- -n
- headlamp
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/headlamp/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,27 @@
---
- name: Vault — manual steps (not automated)
ansible.builtin.debug:
msg: |
1. kubectl -n vault get pods (wait for Running)
2. kubectl -n vault exec -it vault-0 -- vault operator init (once; save keys)
3. Unseal per clusters/noble/apps/vault/README.md
4. ./clusters/noble/apps/vault/configure-kubernetes-auth.sh
5. kubectl apply -f clusters/noble/apps/external-secrets/examples/vault-cluster-secret-store.yaml
- name: Optional — apply Vault ClusterSecretStore for External Secrets
ansible.builtin.command:
argv:
- kubectl
- apply
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/external-secrets/examples/vault-cluster-secret-store.yaml"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
when: noble_apply_vault_cluster_secret_store | default(false) | bool
changed_when: true
- name: Argo CD optional root Application (empty app-of-apps)
ansible.builtin.debug:
msg: >-
Optional: kubectl apply -f clusters/noble/bootstrap/argocd/root-application.yaml
after editing repoURL. Core workloads are not synced by Argo — see bootstrap/argocd/apps/README.md

View File

@@ -0,0 +1,30 @@
---
- name: Create Traefik namespace
ansible.builtin.command:
argv:
- kubectl
- apply
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/traefik/namespace.yaml"
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true
- name: Install Traefik
ansible.builtin.command:
argv:
- helm
- upgrade
- --install
- traefik
- traefik/traefik
- --namespace
- traefik
- --version
- "39.0.6"
- -f
- "{{ noble_repo_root }}/clusters/noble/apps/traefik/values.yaml"
- --wait
environment:
KUBECONFIG: "{{ noble_kubeconfig }}"
changed_when: true

View File

@@ -0,0 +1,3 @@
---
# Set **true** to run `talhelper genconfig -o out` under **talos/** (requires talhelper + talconfig).
noble_talos_genconfig: false

View File

@@ -0,0 +1,36 @@
---
- name: Generate Talos machine configs (talhelper genconfig)
when: noble_talos_genconfig | bool
block:
- name: Validate talconfig
ansible.builtin.command:
argv:
- talhelper
- validate
- talconfig
- talconfig.yaml
args:
chdir: "{{ noble_repo_root }}/talos"
changed_when: false
- name: Generate Talos configs (out/)
ansible.builtin.command:
argv:
- talhelper
- genconfig
- -o
- out
args:
chdir: "{{ noble_repo_root }}/talos"
changed_when: true
- name: Post genconfig — next steps
ansible.builtin.debug:
msg: >-
Configs are in talos/out/. Apply to nodes, bootstrap, and kubeconfig per talos/README.md
before running playbooks/noble.yml.
- name: Skip when noble_talos_genconfig is false
ansible.builtin.debug:
msg: "No-op: pass -e noble_talos_genconfig=true to run talhelper genconfig."
when: not (noble_talos_genconfig | bool)

View File

@@ -0,0 +1,38 @@
---
# **noble_repo_root** and **noble_talos_dir** are set by **playbooks/talos_phase_a.yml** (repo root and **talos/**).
# Run **talhelper genconfig -o out** before apply (needs talhelper + talsecret per talos/README.md §1).
noble_talos_genconfig: true
# **auto** — probe nodes (maintenance vs joined TLS); **insecure** — always **--insecure**; **secure** — always **TALOSCONFIG** (Phase A already done / talos/README §2 B).
noble_talos_apply_mode: auto
# Skip if cluster is already bootstrapped (re-run playbook safely).
noble_talos_skip_bootstrap: false
# After **apply-config**, nodes often reboot — wait for Talos **apid** (:50000) before **bootstrap** / **kubeconfig**.
noble_talos_wait_for_apid: true
noble_talos_apid_wait_delay: 20
noble_talos_apid_wait_timeout: 900
# **talosctl bootstrap -n** — first control plane (neon).
noble_talos_bootstrap_node_ip: "192.168.50.20"
# **talosctl kubeconfig -n** (node that answers Talos/K8s for cert fetch).
noble_talos_kubeconfig_node: "192.168.50.20"
# **talosctl kubeconfig -e** — Talos endpoint (node IP before VIP is reachable; VIP when LAN works).
noble_talos_kubeconfig_endpoint: "192.168.50.20"
# After kubeconfig, patch **kubectl** server if VIP in file is unreachable (**group_vars** / same as noble.yml).
# noble_k8s_api_server_override: ""
# Must match **cluster.name** / kubeconfig cluster entry (often **noble**).
noble_talos_kubectl_cluster_name: noble
# Inventory: IP + filename under **talos/out/** — align with **talos/talconfig.yaml**.
noble_talos_nodes:
- { ip: "192.168.50.20", machine: "noble-neon.yaml" }
- { ip: "192.168.50.30", machine: "noble-argon.yaml" }
- { ip: "192.168.50.40", machine: "noble-krypton.yaml" }
- { ip: "192.168.50.10", machine: "noble-helium.yaml" }

View File

@@ -0,0 +1,209 @@
---
# Order matches talos/README.md: genconfig → apply all nodes → bootstrap → kubeconfig.
- name: Validate talconfig and generate **out/** (talhelper genconfig)
when: noble_talos_genconfig | bool
block:
- name: talhelper validate
ansible.builtin.command:
argv:
- talhelper
- validate
- talconfig
- talconfig.yaml
args:
chdir: "{{ noble_talos_dir }}"
changed_when: false
- name: talhelper genconfig -o out
ansible.builtin.command:
argv:
- talhelper
- genconfig
- -o
- out
args:
chdir: "{{ noble_talos_dir }}"
changed_when: true
- name: Stat talos/out/talosconfig
ansible.builtin.stat:
path: "{{ noble_talos_dir }}/out/talosconfig"
register: noble_talos_talosconfig
- name: Require talos/out/talosconfig
ansible.builtin.assert:
that:
- noble_talos_talosconfig.stat.exists | default(false)
fail_msg: >-
Missing {{ noble_talos_dir }}/out/talosconfig. Run **talhelper genconfig -o out** in **talos/** (talsecret per talos/README.md §1),
or set **noble_talos_genconfig=true** on this playbook.
# Maintenance API (**--insecure**) vs joined cluster (**tls: certificate required**) — talos/README §2 A vs B.
- name: Set apply path from noble_talos_apply_mode (manual)
ansible.builtin.set_fact:
noble_talos_apply_insecure: "{{ noble_talos_apply_mode == 'insecure' }}"
when: noble_talos_apply_mode | default('auto') in ['insecure', 'secure']
- name: Probe Talos API — apply-config dry-run (insecure / maintenance)
ansible.builtin.command:
argv:
- talosctl
- apply-config
- --insecure
- -n
- "{{ noble_talos_nodes[0].ip }}"
- -f
- "{{ noble_talos_dir }}/out/{{ noble_talos_nodes[0].machine }}"
- --dry-run
register: noble_talos_probe_insecure
failed_when: false
changed_when: false
when: noble_talos_apply_mode | default('auto') == 'auto'
- name: Probe Talos API — apply-config dry-run (TLS / joined)
ansible.builtin.command:
argv:
- talosctl
- apply-config
- -n
- "{{ noble_talos_nodes[0].ip }}"
- -f
- "{{ noble_talos_dir }}/out/{{ noble_talos_nodes[0].machine }}"
- --dry-run
environment:
TALOSCONFIG: "{{ noble_talos_dir }}/out/talosconfig"
register: noble_talos_probe_secure
failed_when: false
changed_when: false
when:
- noble_talos_apply_mode | default('auto') == 'auto'
- noble_talos_probe_insecure.rc != 0
- name: Resolve apply mode — maintenance (insecure)
ansible.builtin.set_fact:
noble_talos_apply_insecure: true
when:
- noble_talos_apply_mode | default('auto') == 'auto'
- noble_talos_probe_insecure.rc == 0
- name: Resolve apply mode — joined (TALOSCONFIG, no insecure)
ansible.builtin.set_fact:
noble_talos_apply_insecure: false
when:
- noble_talos_apply_mode | default('auto') == 'auto'
- noble_talos_probe_insecure.rc != 0
- noble_talos_probe_secure.rc == 0
- name: Fail when Talos API mode cannot be determined
ansible.builtin.fail:
msg: >-
Cannot run **talosctl apply-config --dry-run** on {{ noble_talos_nodes[0].ip }}.
Insecure: rc={{ noble_talos_probe_insecure.rc }} {{ noble_talos_probe_insecure.stderr | default('') }}.
TLS: rc={{ noble_talos_probe_secure.rc | default('n/a') }} {{ noble_talos_probe_secure.stderr | default('') }}.
Check LAN to :50000, node power, and that **out/talosconfig** matches these nodes.
Override: **-e noble_talos_apply_mode=secure** (joined) or **insecure** (maintenance ISO).
when:
- noble_talos_apply_mode | default('auto') == 'auto'
- noble_talos_probe_insecure.rc != 0
- noble_talos_probe_secure is not defined or noble_talos_probe_secure.rc != 0
- name: Show resolved Talos apply-config mode
ansible.builtin.debug:
msg: >-
apply-config: {{ 'maintenance (--insecure)' if noble_talos_apply_insecure | bool else 'joined (TALOSCONFIG)' }}
(noble_talos_apply_mode={{ noble_talos_apply_mode | default('auto') }})
- name: Apply machine config to each node (first install — insecure)
ansible.builtin.command:
argv:
- talosctl
- apply-config
- --insecure
- -n
- "{{ item.ip }}"
- --file
- "{{ noble_talos_dir }}/out/{{ item.machine }}"
loop: "{{ noble_talos_nodes }}"
loop_control:
label: "{{ item.ip }}"
when: noble_talos_apply_insecure | bool
changed_when: true
- name: Apply machine config to each node (cluster already has TLS — no insecure)
ansible.builtin.command:
argv:
- talosctl
- apply-config
- -n
- "{{ item.ip }}"
- --file
- "{{ noble_talos_dir }}/out/{{ item.machine }}"
environment:
TALOSCONFIG: "{{ noble_talos_dir }}/out/talosconfig"
loop: "{{ noble_talos_nodes }}"
loop_control:
label: "{{ item.ip }}"
when: not (noble_talos_apply_insecure | bool)
changed_when: true
# apply-config triggers reboots; apid on :50000 must accept connections before talosctl bootstrap / kubeconfig.
- name: Wait for Talos machine API (apid) on bootstrap node
ansible.builtin.wait_for:
host: "{{ noble_talos_bootstrap_node_ip }}"
port: 50000
delay: "{{ noble_talos_apid_wait_delay | int }}"
timeout: "{{ noble_talos_apid_wait_timeout | int }}"
state: started
when: noble_talos_wait_for_apid | default(true) | bool
- name: Bootstrap cluster (once per cluster)
ansible.builtin.command:
argv:
- talosctl
- bootstrap
- -n
- "{{ noble_talos_bootstrap_node_ip }}"
environment:
TALOSCONFIG: "{{ noble_talos_dir }}/out/talosconfig"
register: noble_talos_bootstrap_cmd
when: not (noble_talos_skip_bootstrap | bool)
changed_when: noble_talos_bootstrap_cmd.rc == 0
failed_when: >-
noble_talos_bootstrap_cmd.rc != 0 and
('etcd data directory is not empty' not in (noble_talos_bootstrap_cmd.stderr | default('')))
- name: Write Kubernetes admin kubeconfig
ansible.builtin.command:
argv:
- talosctl
- kubeconfig
- "{{ noble_talos_kubeconfig_out }}"
- --force
- -n
- "{{ noble_talos_kubeconfig_node }}"
- -e
- "{{ noble_talos_kubeconfig_endpoint }}"
- --merge=false
environment:
TALOSCONFIG: "{{ noble_talos_dir }}/out/talosconfig"
changed_when: true
- name: Optional — set kubectl cluster server to reachable API (VIP unreachable from this host)
ansible.builtin.command:
argv:
- kubectl
- config
- set-cluster
- "{{ noble_talos_kubectl_cluster_name }}"
- --server={{ noble_k8s_api_server_override }}
- --kubeconfig={{ noble_talos_kubeconfig_out }}
when: noble_k8s_api_server_override | default('') | length > 0
changed_when: true
- name: Next — platform stack
ansible.builtin.debug:
msg: >-
Kubeconfig written to {{ noble_talos_kubeconfig_out }}.
Export KUBECONFIG={{ noble_talos_kubeconfig_out }} and run: ansible-playbook playbooks/noble.yml
(or: ansible-playbook playbooks/deploy.yml for the full pipeline).