Compare commits

...
Author SHA1 Message Date
claude-botandClaude Fable 5.1 1d21196060 feat(netbird): deploy the reverse-proxy-services controller
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
Deployment for the controller of the previous commit: openbao namespace
like the rotators (its default-deny already allows OpenBao, DNS, the
apiserver and world), own ServiceAccount with a read-only ClusterRole
(Ingresses list/watch, Services get), one replica, Recreate. The image tag
is the branch build that pushed this exact code.

The OpenBao role is applied once by hand (policies/netbird-proxy-services
.hcl); until then the pod logs an auth error per minute and changes nothing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 12:11:14 +02:00
k.renner 57b2485487 Merge pull request 'fix(ceph): state the cluster CIDR — host-device leaves Rook's canary no NIC' (#807) from ceph-address-ranges into master
ci/woodpecker/cron/issue-fix Pipeline was successful
ci/woodpecker/cron/alert-monitor Pipeline was successful
Reviewed-on: k.renner/homelab#807
2026-09-07 05:22:30 +00:00
claude-botandClaude Fable 5.1 49c33b9b0f fix(ceph): state the cluster CIDR — host-device leaves the canary no NIC
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
Since the host-device rollout (#801) Rook cannot finish a CephCluster
reconcile: it runs a canary pod with OSD placement to read the cluster
CIDR off the attachment, the OSD on that node already holds the NIC, and
the canary fails "error adding container to network ceph-san" until the
15-minute discovery timeout, then the next reconcile repeats it. Under
macvlan the canary could sit beside the OSD; a whole-device attachment has
exactly one consumer per node.

Discovery is skipped when addressRanges.cluster is set (Rook: "if user
specifies CIDRs in the network config, that is the definitive source of
truth"). The value is what discovery produced and what ceph config already
holds, so no daemon changes. The old comment claiming addressRanges is
honoured only under provider: host was wrong — the CRD documents it for
host and multus.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:21:36 +02:00
k.renner cbd47596bf Merge pull request 'fix(talos): answer ARP only on the link that owns the address' (#804) from fix/arp-flux-second-nic into master
Reviewed-on: k.renner/homelab#804
2026-09-07 05:17:09 +00:00
k.renner 99827fb776 Merge pull request 'fix(ceph): OSD raw volume label must not contain "ceph" (ceph-volume rejects it)' (#803) from osd-partlabel-no-ceph into master
ci/woodpecker/cron/alert-monitor Pipeline was successful
Reviewed-on: k.renner/homelab#803
2026-09-07 05:15:17 +00:00
k.renner 19f8d5bc51 Merge pull request 'fix(infrastructure): LAPI ServersTransport behind the Traefik CRDs (phase 1/2, add)' (#802) from lapi-transport-post-crds into master
Reviewed-on: k.renner/homelab#802
2026-09-07 05:00:59 +00:00
k.renner a88d3cd224 Merge pull request 'feat(ceph): hand the SAN NIC to the OSD pod (rollout 2/2, maintenance window)' (#801) from san-host-device-nad into master
ci/woodpecker/cron/e2e Pipeline is running
ci/woodpecker/cron/update-audit Pipeline is running
ci/woodpecker/cron/alert-monitor Pipeline was successful
Reviewed-on: k.renner/homelab#801
2026-09-07 04:51:00 +00:00
claude-botandClaude Fable 5.1 4d629bfd66 fix(talos): answer ARP only on the link that owns the address
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
Every node has a second, address-less NIC (enp87s0) up on the untagged
fallback network, which shares the mgmt VLAN's broadcast domain. With
the Linux default arp_ignore=0 the host answers ARP for the node IP from
that NIC too, so the UDM can learn 10.2.40.x against enp87s0's MAC.
Inbound IPv4 then arrives on a device Cilium is not attached to, never
reaches cil_from_netdev, and is routed straight back to the UDM by the
default route — a loop that made every IPv4 LoadBalancer VIP on the
affected node unreachable for 13.5 hours. IPv6 was untouched because
NDP only answers on the interface that owns the address.

The flux was measurable on all three nodes: an ARP request for a node
IP from a neighbour returned replies from two MACs. Which node's entry
had actually flipped at the UDM was a race, and it moved during the
diagnosis.

arp_ignore=1 answers only when the target address is configured on the
receiving interface; arp_announce=2 stops the host from sourcing ARP
from an interface that does not own the address. Applied live with
talosctl on all three nodes before this commit and verified with
enp87s0 up: each node now answers from its mgmt0 MAC only.

A node property, so it lives next to the existing enp87s0 sysctls in
each machine patch rather than in the site patch.

Refs #793, #576

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 23:46:51 +02:00
claude-botandClaude Fable 5.1 93c0e33dac fix(ceph): OSD raw volume label must not contain "ceph"
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
All three OSD prepare jobs on the Hetzner rehearsal finished with zero
OSDs:

  cephosd: skipping device "sdb1": ["Used by ceph-disk"]

The partition is exactly what the machine config asked for (PARTLABEL
r-ceph-osd, plain Linux partition type). ceph-volume rejects it anyway —
its ceph-disk-member test is `"ceph" in PARTLABEL or PARTTYPE in
ceph_disk_guids` (ceph_volume/util/device.py) — so any label containing
"ceph" reads as a legacy ceph-disk partition and is never provisioned.

Talos derives the label from the RawVolumeConfig name (r-<name>), so the
name changes: ceph-osd -> osd-data, label r-osd-data. This is why the
rebuild branch called it osd-data; the #798 review renamed it back for
symmetry with the node label without this failure being known.

Production is unaffected today: the MS-01 OSDs match on the by-id half of
devicePathFilter and no r-ceph-osd partition exists there. The partlabel
half is the migration target and would have failed on the first
repartitioned drive.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 23:43:25 +02:00
k.renner 078b250fbd Merge pull request 'feat(talos): name the SAN NIC by its role on every site (rollout 1/2, inert)' (#800) from san-role-rename into master
ci/woodpecker/cron/issue-fix Pipeline was successful
ci/woodpecker/cron/alert-monitor Pipeline was successful
Reviewed-on: k.renner/homelab#800
2026-09-06 21:11:47 +00:00
claude-botandClaude Fable 5.1 d31d07ef87 feat(ceph): hand the SAN NIC to the OSD pod (host-device)
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
The NetworkAttachmentDefinition switches from a macvlan on a kernel
interface name to host-device on the role name `ceph-san`. The NIC is
dedicated to Ceph and has exactly one consumer per node, so it is moved
into the OSD pod whole — real MAC, real MTU — and returns to the host when
the pod goes away. No hardware name appears in this file any more; every
machine renames its own link at boot (previous commit).

ROLLOUT — not atomic with the machine config. Between this flip and a
node's reboot, an OSD restart on that node fails: the NAD asks for
ceph-san and the running node only has the old name. Merge only inside a
maintenance window, then drain + noout + reboot k8s-1/2/3 back to back.
Running OSD pods keep their existing attachment until restarted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 22:54:39 +02:00
claude-botandClaude Fable 5.1 05b20ec74c feat(talos): name the SAN NIC by its role on every site
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
Only the Talos machine config knows hardware. Each machine renames its own
Ceph cluster-network link to `ceph-san` at boot, so shared manifests can
address the role and no kernel interface name leaves this directory:

- k8s-1/2/3 (MS-01): a udev rule matches the X710 port 1 by burned-in MAC
  and renames it before the network stack opens links. The LinkConfig then
  names ceph-san (up, mtu 9000). A rule applied to a RUNNING node cannot
  rename (Resource busy) and takes effect at the next reboot, so this
  change is inert on production until each node is rebooted — that is the
  planned rollout, node by node.
- vm-1..4 (qemu site): one NIC only, so the segment is VLAN 30 named
  ceph-san directly. The DHCPv4Config on the parent is load-bearing:
  declaring any network document stops the implicit DHCP that addresses
  the node.
- hcloud-1/2/3 already carry the same shape (udev by PCI bus path) since
  the rebuild-tooling merge.

Validated on Hetzner with the host-device attachment: OSD pods held the
real fabric MACs, Ceph reached HEALTH_OK.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 22:54:19 +02:00
16 changed files with 258 additions and 67 deletions
+2 -2
View File
@@ -1379,8 +1379,8 @@ EOF
vm_addr="${NODE_ADDRS[$idx]}"
vols=$(talosctl -n "$vm_addr" -e "$vm_addr" get discoveredvolumes 2>&1) \
|| fail "could not read volumes from $vm_node ($vm_addr): ${vols//$'\n'/ | }"
awk '$NF == "r-ceph-osd" {found=1} END {exit !found}' <<<"$vols" \
|| fail "$vm_node has no r-ceph-osd partition — RawVolumeConfig did not take"
awk '$NF == "r-osd-data" {found=1} END {exit !found}' <<<"$vols" \
|| fail "$vm_node has no r-osd-data partition — RawVolumeConfig did not take"
kubectl get node "$vm_node" \
-o jsonpath='{.metadata.labels.storage\.renner\.uno/ceph-osd}' \
| grep -q true \
@@ -18,6 +18,7 @@ resources:
- cloudnative-pg/
- mariadb-operator/
- netbird-ingress/
- netbird-proxy-services/
- coredns-config/
- k8s-gateway/
- external-dns-unifi/
@@ -0,0 +1,99 @@
# Reconciles NetBird reverse-proxy services from Ingresses that carry
# dns.renner.uno/public: one TLS-passthrough service per host on :443,
# targeting Traefik's ClusterIP through a subnet resource over the service
# CIDR (ci/images/netbird-proxy-services/controller.py).
#
# openbao namespace, like the rotators: its default-deny already allows egress
# to OpenBao, DNS, the apiserver and `world` (netbird.renner.uno), and the
# NetBird PAT is read from OpenBao on every pass through the
# netbird-proxy-services role — policies/netbird-proxy-services.hcl, applied
# once by hand like the rotator roles. Until that role exists the pod logs an
# auth error each minute and does nothing.
apiVersion: v1
kind: ServiceAccount
metadata:
name: netbird-proxy-services
namespace: openbao
labels:
app.kubernetes.io/name: netbird-proxy-services
---
# Read-only, cluster-wide: public Ingresses live in many namespaces, the
# Traefik Service in ingress/.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: netbird-proxy-services-read
rules:
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: netbird-proxy-services-read
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: netbird-proxy-services-read
subjects:
- kind: ServiceAccount
name: netbird-proxy-services
namespace: openbao
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: netbird-proxy-services
namespace: openbao
labels:
app.kubernetes.io/name: netbird-proxy-services
spec:
replicas: 1
# One writer against the management API at a time.
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: netbird-proxy-services
template:
metadata:
labels:
app.kubernetes.io/name: netbird-proxy-services
spec:
serviceAccountName: netbird-proxy-services
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: controller
image: gitea.renner.uno/gitea_admin/netbird-proxy-services:2026-09-07
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
env:
- name: NB_MANAGEMENT_URL
value: https://netbird.renner.uno
- name: BAO_ADDR
value: http://openbao.openbao.svc.cluster.local:8200
- name: BAO_ROLE
value: netbird-proxy-services
# Must match cluster.network.serviceSubnets in talos/patches/cluster.yaml.
- name: SERVICE_CIDR
value: "10.96.0.0/12"
- name: TRAEFIK_SERVICE
value: ingress/traefik
- name: INTERVAL_SECONDS
value: "60"
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
memory: 64Mi
@@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
@@ -95,12 +95,18 @@ spec:
# Dedicated Ceph cluster network on VLAN 49, attached to the OSDs through
# Multus. The attachment is san-network-attachment.yaml.
#
# Only `cluster` is selected. Do not add `public`, and do not reach for
# `addressRanges` — that is honoured only under provider: host, which puts
# every daemon including the mons on host networking. A mon's address then
# becomes the node's DHCP lease, and when a lease moves the mon crash-loops
# on "Cannot assign requested address" with no node free to fail over to,
# because all three already hold the mon host ports.
# Only `cluster` is selected. Do not add `public`: under provider: host
# that puts every daemon including the mons on host networking. A mon's
# address then becomes the node's DHCP lease, and when a lease moves the mon
# crash-loops on "Cannot assign requested address" with no node free to
# fail over to, because all three already hold the mon host ports.
#
# addressRanges.cluster is stated, not discovered. Without it Rook runs a
# canary pod on an OSD node to read the CIDR off the attachment on EVERY
# reconcile; the attachment is host-device, so the OSD on that node already
# holds the NIC and the canary can never attach — the reconcile blocks for
# 15 minutes, fails, and repeats. The value must equal the whereabouts range
# in san-network-attachment.yaml.
#
# With `public` unset, client traffic stays on the pod network and VLAN 49
# carries Ceph-internal traffic only — which is also why Rook's Multus
@@ -117,6 +123,9 @@ spec:
provider: multus
selectors:
cluster: rook-ceph/ceph-san
addressRanges:
cluster:
- 10.99.0.0/29
# Nodes listed explicitly, not useAllNodes: under useAllNodes the operator
# re-provisions an OSD on any node whose device still carries a BlueStore
# signature, so purging an OSD before pulling its drive is impossible — it
@@ -144,10 +153,12 @@ spec:
useAllDevices: false
# Two forms while the production drives are migrated:
#
# by-partlabel/r-ceph-osd the target. Talos names the drive in the
# machine config (RawVolumeConfig ceph-osd), so
# by-partlabel/r-osd-data the target. Talos names the drive in the
# machine config (RawVolumeConfig osd-data), so
# this file needs to know nothing about models,
# serials or hostnames.
# serials or hostnames. The label must not
# contain "ceph": ceph-volume rejects any such
# partition as a legacy ceph-disk member.
# by-id/nvme-SAMSUNG… the three MS-01 drives as they are today:
# bluestore written straight onto the raw disk,
# with no partition table and therefore no
@@ -159,7 +170,7 @@ spec:
#
# The second half goes when those three are repartitioned, one node at a
# time. Until then it is what keeps the running OSDs claimed.
devicePathFilter: "^/dev/disk/by-(partlabel/r-ceph-osd|id/nvme-SAMSUNG_MZQLB960HAJR)"
devicePathFilter: "^/dev/disk/by-(partlabel/r-osd-data|id/nvme-SAMSUNG_MZQLB960HAJR)"
config:
osdsPerDevice: "1"
# Highest built-in class: kubelet evicts these last and the kernel gives
@@ -3,33 +3,26 @@
# without every Ceph daemon landing on host networking to get there. The
# alternative and why it was rejected is in cephcluster.yaml.
#
# host-device: the SAN NIC is dedicated to Ceph and has exactly one consumer
# per node — the OSD pod — so it is handed to that pod whole, not virtualised
# under it. The device keeps its identity (MAC, MTU) and moves back to the
# host when the pod goes away.
#
# `device` names the role, not hardware: every machine renames its own SAN
# interface to ceph-san at boot (udev rule in its Talos patch). No kernel
# interface name appears in this file.
#
# ISOLATION
#
# VLAN 49 carries Ceph-internal traffic and nothing else. Two consequences
# are deliberate:
# VLAN 49 carries Ceph-internal traffic and nothing else. No gateway and no
# routes: there is no router on this segment and there must not be one.
# whereabouts adds neither unless asked, so nothing here can leak onto or off
# the SAN.
#
# No gateway and no routes. There is no router on this segment and there
# must not be one. whereabouts adds neither unless asked, so nothing here
# can leak onto or off the SAN. This also means no `sbr` chaining is
# needed — unlike the v30iot attachments, there is no DHCP-supplied default
# route to confine, because there is no DHCP and no default route.
#
# The pool is the whole usable /29, .1 through .6. It was .4-.6 while the
# migration ran, because the nodes still held .1-.3 for as long as Ceph
# needed host networking to reach this link — three addresses for three
# OSDs, no spare. The nodes have since given those up (the link is only a
# macvlan parent now and needs no address of its own), so the reservation
# has nothing left to avoid.
#
# Keeping the pool inside the /29 rather than moving it elsewhere on the
# segment is not cosmetic. There is no router here, so an address outside
# the /29 would be unreachable from anything still using one inside it —
# which is exactly what would break a future rolling change, where migrated
# and un-migrated OSDs have to keep talking to each other.
#
# Six addresses for three OSDs is the headroom the migration could not
# afford: room for a leaked allocation to sit until the reconciler collects
# it, and room to add a second OSD per node without touching this file.
# The pool is the whole usable /29, .1 through .6 — headroom for a leaked
# allocation to sit until the reconciler collects it. One address per node is
# in use; a second OSD on a node would need a second SAN interface, which is a
# hardware change, not a config one.
#
# IPAM
#
@@ -37,29 +30,18 @@
# a server that must not exist here, and host-local keeps its state per node
# with no cluster-wide coordination, so two nodes would hand out the same
# address on shared L2. See infrastructure/multus/whereabouts-daemonset.yaml.
#
# MTU 9000 matches the link. macvlan children inherit the master's MTU, but
# it is stated so that a change to the parent does not silently halve
# replication throughput without anything in the tree recording the
# expectation.
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: ceph-san
namespace: rook-ceph
spec:
# `master` is an interface name. enp2s0f1np1 is the second X710 SFP+ port,
# a busPath-derived predictable name (net.ifnames=1 via the Image Factory
# schematic) that is identical on k8s-1/2/3 and cannot shuffle across
# reboots.
config: |
{
"cniVersion": "0.3.1",
"name": "ceph-san",
"type": "macvlan",
"master": "enp2s0f1np1",
"mode": "bridge",
"mtu": 9000,
"type": "host-device",
"device": "ceph-san",
"ipam": {
"type": "whereabouts",
"range": "10.99.0.0/29",
+1 -1
View File
@@ -57,7 +57,7 @@ up: true
---
apiVersion: v1alpha1
kind: RawVolumeConfig
name: ceph-osd
name: osd-data
provisioning:
diskSelector:
# Two disks: the system disk and the attached volume. Matching on transport
+1 -1
View File
@@ -42,7 +42,7 @@ up: true
---
apiVersion: v1alpha1
kind: RawVolumeConfig
name: ceph-osd
name: osd-data
provisioning:
diskSelector:
match: '!system_disk'
+1 -1
View File
@@ -42,7 +42,7 @@ up: true
---
apiVersion: v1alpha1
kind: RawVolumeConfig
name: ceph-osd
name: osd-data
provisioning:
diskSelector:
match: '!system_disk'
+21 -6
View File
@@ -14,6 +14,13 @@ machine:
# Disabling v6 on a VLAN parent does not affect the VLAN child.
net.ipv6.conf.enp2s0f0np0.disable_ipv6: "1"
net.ipv6.conf.enp87s0.disable_ipv6: "1"
# That network also carries the mgmt VLAN's ARP. Answer ARP only on the
# link that owns the address, or the UDM learns the node IP against
# enp87s0's MAC and delivers IPv4 to a NIC Cilium is not attached to (#793).
net.ipv4.conf.all.arp_ignore: "1"
net.ipv4.conf.default.arp_ignore: "1"
net.ipv4.conf.all.arp_announce: "2"
net.ipv4.conf.default.arp_announce: "2"
install:
# Select disks by serial only. A broad selector such as
# `disk.transport == 'nvme'` matches every drive in the machine, and the
@@ -28,6 +35,13 @@ machine:
# this label instead of listing hostnames, so which boxes carry storage is
# stated once, here, by the machine that knows.
storage.renner.uno/ceph-osd: "true"
udev:
# Renames the SAN port (X710 port 1, matched by its burned-in MAC) to the
# role name at boot, before the network stack opens links — a rule applied
# to a RUNNING node cannot rename (Resource busy) and takes effect at the
# next reboot.
rules:
- SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="58:47:ca:74:70:28", NAME="ceph-san"
cluster:
allowSchedulingOnControlPlanes: true
---
@@ -124,14 +138,15 @@ parent: enp2s0f0np0
up: true
---
# Dedicated Ceph cluster network on X710 port 1, VLAN 49, untagged on the
# wire. OSD-to-OSD replication and nothing else.
# wire. OSD-to-OSD replication and nothing else. The udev rule in the machine
# section above renames the port to ceph-san at boot, so shared manifests name
# the role and only this file knows the hardware.
#
# The node holds NO address here on purpose. Rook attaches the link to the OSD
# pods through a Multus macvlan, and a macvlan parent only needs to be up.
# Giving the node an address would put it on a segment reserved for
# Ceph-internal traffic.
# The node holds NO address here on purpose: the link is handed whole to the
# OSD pod (host-device attachment). Giving the node an address would put it on
# a segment reserved for Ceph-internal traffic.
apiVersion: v1alpha1
kind: LinkConfig
name: enp2s0f1np1
name: ceph-san
up: true
mtu: 9000
+13 -3
View File
@@ -12,6 +12,11 @@ machine:
# cluster IPv6 egress.
net.ipv6.conf.enp2s0f0np0.disable_ipv6: "1"
net.ipv6.conf.enp87s0.disable_ipv6: "1"
# Answer ARP only on the link that owns the address — see k8s-1.yaml (#793).
net.ipv4.conf.all.arp_ignore: "1"
net.ipv4.conf.default.arp_ignore: "1"
net.ipv4.conf.all.arp_announce: "2"
net.ipv4.conf.default.arp_announce: "2"
install:
# Select the installer target by serial so it cannot land on the OSD drive
# or on EPHEMERAL, whatever order the kernel enumerates them in.
@@ -23,6 +28,10 @@ machine:
topology.kubernetes.io/zone: saturn
# Holds a Ceph OSD drive — see k8s-1.yaml.
storage.renner.uno/ceph-osd: "true"
udev:
# Renames the SAN port to the role name at boot — see k8s-1.yaml.
rules:
- SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="58:47:ca:76:6f:74", NAME="ceph-san"
cluster:
allowSchedulingOnControlPlanes: true
---
@@ -95,11 +104,12 @@ up: true
---
# Dedicated Ceph cluster network on X710 port 1, VLAN 49, untagged on the
# wire. OSD-to-OSD replication only, not routed off its own segment.
# Renamed to the role name by the udev rule above — see k8s-1.yaml.
#
# The node holds NO address here on purpose. Rook attaches the link to the OSD
# pods through a Multus macvlan, and a macvlan parent only needs to be up.
# The node holds NO address here on purpose: the link is handed whole to the
# OSD pod (host-device attachment).
apiVersion: v1alpha1
kind: LinkConfig
name: enp2s0f1np1
name: ceph-san
up: true
mtu: 9000
+11 -2
View File
@@ -8,6 +8,11 @@ machine:
# k8s-1.yaml.
net.ipv6.conf.enp2s0f0np0.disable_ipv6: "1"
net.ipv6.conf.enp87s0.disable_ipv6: "1"
# Answer ARP only on the link that owns the address — see k8s-1.yaml (#793).
net.ipv4.conf.all.arp_ignore: "1"
net.ipv4.conf.default.arp_ignore: "1"
net.ipv4.conf.all.arp_announce: "2"
net.ipv4.conf.default.arp_announce: "2"
install:
# Select the installer target by serial so it cannot land on the OSD drive
# or on EPHEMERAL, whatever order the kernel enumerates them in.
@@ -19,6 +24,10 @@ machine:
topology.kubernetes.io/zone: neptune
# Holds a Ceph OSD drive — see k8s-1.yaml.
storage.renner.uno/ceph-osd: "true"
udev:
# Renames the SAN port to the role name at boot — see k8s-1.yaml.
rules:
- SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="58:47:ca:74:72:d4", NAME="ceph-san"
cluster:
allowSchedulingOnControlPlanes: true
---
@@ -78,9 +87,9 @@ parent: enp2s0f0np0
up: true
---
# Dedicated Ceph cluster network — see k8s-1.yaml. The node holds NO address
# here on purpose; the link is only a macvlan parent for the OSD pods.
# here on purpose; the link is handed whole to the OSD pod (host-device).
apiVersion: v1alpha1
kind: LinkConfig
name: enp2s0f1np1
name: ceph-san
up: true
mtu: 9000
+12
View File
@@ -43,3 +43,15 @@ apiVersion: v1alpha1
kind: HostnameConfig
auto: off
hostname: vm-1
---
# Ceph cluster network — see vm-2.yaml for why this is a VLAN, and why the
# DHCPv4Config below is load-bearing.
apiVersion: v1alpha1
kind: VLANConfig
name: ceph-san
parent: enp0s2
vlanID: 30
---
apiVersion: v1alpha1
kind: DHCPv4Config
name: enp0s2
+26 -2
View File
@@ -21,7 +21,7 @@ auto: off
hostname: vm-2
---
# The OSD device, named by the machine that has it. Ceph then consumes
# /dev/disk/by-partlabel/r-ceph-osd and needs to know nothing about models,
# /dev/disk/by-partlabel/r-osd-data and needs to know nothing about models,
# serials or hostnames — the same CephCluster works here and on the MS-01s.
#
# The selector is a CEL expression, so each machine says whatever identifies its
@@ -29,9 +29,33 @@ hostname: vm-2
# real nodes it will name the Samsung.
apiVersion: v1alpha1
kind: RawVolumeConfig
name: ceph-osd
name: osd-data
provisioning:
diskSelector:
match: disk.transport == "virtio" && !system_disk
minSize: 5GiB
grow: true
---
# The Ceph cluster network link. Production gives it a second physical port;
# this machine has one NIC, so the segment is a VLAN on it.
#
# A dummy link would be simpler and worthless — no traffic between nodes, so
# Ceph would replicate over an interface going nowhere and the test would pass
# having proven nothing. A VLAN rides the provisioner's bridge that every VM is
# on, so the SAN carries real frames on its own tag.
#
# No MTU, unlike production's 9000: the qemu NIC is created with host_mtu=1500.
apiVersion: v1alpha1
kind: VLANConfig
name: ceph-san
parent: enp0s2
vlanID: 30
---
# Load-bearing. Declaring any network document makes Talos configure this link
# explicitly, and the implicit DHCP that gives the node its address stops. A
# first attempt with only the VLANConfig took vm-4 off the network — NotReady,
# unreachable over the Talos API. Verified on a second throwaway node that this
# document keeps the parent addressed.
apiVersion: v1alpha1
kind: DHCPv4Config
name: enp0s2
+13 -1
View File
@@ -15,9 +15,21 @@ hostname: vm-3
---
apiVersion: v1alpha1
kind: RawVolumeConfig
name: ceph-osd
name: osd-data
provisioning:
diskSelector:
match: disk.transport == "virtio" && !system_disk
minSize: 5GiB
grow: true
---
# Ceph cluster network — see vm-2.yaml for why this is a VLAN, and why the
# DHCPv4Config below is load-bearing.
apiVersion: v1alpha1
kind: VLANConfig
name: ceph-san
parent: enp0s2
vlanID: 30
---
apiVersion: v1alpha1
kind: DHCPv4Config
name: enp0s2
+13 -1
View File
@@ -19,9 +19,21 @@ hostname: vm-4
---
apiVersion: v1alpha1
kind: RawVolumeConfig
name: ceph-osd
name: osd-data
provisioning:
diskSelector:
match: disk.transport == "virtio" && !system_disk
minSize: 5GiB
grow: true
---
# Ceph cluster network — see vm-2.yaml for why this is a VLAN, and why the
# DHCPv4Config below is load-bearing.
apiVersion: v1alpha1
kind: VLANConfig
name: ceph-san
parent: enp0s2
vlanID: 30
---
apiVersion: v1alpha1
kind: DHCPv4Config
name: enp0s2