Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions .github/workflows/talos-boot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,17 +256,10 @@ jobs:
YAML
# webhook が受け付けるようになるまで断られる
until kubectl apply -f /tmp/issuer.yaml 2>/dev/null; do sleep 5; done
# nodeport.yaml は ArgoCD の PostSync 用(VM では下で直に patch する)なので当てない
until kubectl apply -f bootstrap/gateway/gateway.yaml -f bootstrap/gateway/redirect-https.yaml -f bootstrap/argocd/httproute.yaml; do sleep 5; done
kubectl -n kube-system wait --for=condition=Ready certificate --all --timeout=3m
kubectl -n kube-system wait --for=condition=Programmed gateway/doany --timeout=3m
# bootstrap/gateway/nodeport.yaml と同じ手当て(本番では ArgoCD の PostSync)。nodePort が 80/443 でないと L7LB に入らない(bootstrap/cilium/values.yaml)
until kubectl -n kube-system get svc cilium-gateway-doany >/dev/null 2>&1; do sleep 5; done
kubectl -n kube-system patch svc cilium-gateway-doany --type=json -p '[
{"op":"replace","path":"/spec/ports/0/nodePort","value":80},
{"op":"replace","path":"/spec/ports/1/nodePort","value":443}
]'
# 公開経路を実際に通す。http は https への 301、https は argocd-server まで
# 公開経路を実際に通す。Service の nodePort はランダムなまま(bootstrap/cilium/values.yaml の `nodePort`)。http は https への 301、https は argocd-server まで
code() { curl -s -o /dev/null -w '%{http_code}' --max-time 10 "$@" || true; }
for i in $(seq 36); do
H=$(code -H 'Host: ac.doany.io' http://127.0.0.1:18080/)
Expand Down
2 changes: 1 addition & 1 deletion apps/forgejo/node-access.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ノード自身(containerd)が fj.doany.io に届くための口。
#
# **ホストからノードの 80/443 には繋がらない**(bootstrap/cilium/values.yaml の nodePort の説明の 3)。
# **ホストからノードの 80/443 には繋がらなかった**(k3s の頃。bootstrap/cilium/values.yaml の `nodePort`。今も要るかは未確認)。
# 公開経路は Gateway なので、containerd が fj.doany.io のイメージを取ろうとすると
# 接続がタイムアウトする(2026-09-15 に shadai で踏んだ)。レジストリはトークンの取得先(realm)も
# `https://fj.doany.io/v2/token` を返すので、IP だけ差し替えるミラーでは足りない。
Expand Down
3 changes: 1 addition & 2 deletions apps/k8up/etcd-snapshot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
#
# **戻すときの主経路ではない。** 主経路は「git から Argo CD で建て直して PV を k8up で戻す」
# (recovery/README.md。2026-10-17 に実機で通した)。こちらは git に無い状態
# (Argo CD が作った Application の同期状態、cert-manager の発行済み証明書、
# API サーバが割り当てた nodePort など)まで含めて**一瞬で戻したいとき**の近道。
# (Argo CD が作った Application の同期状態、cert-manager の発行済み証明書など)まで含めて**一瞬で戻したいとき**の近道。
# 戻し方は docs/talos.md「etcd スナップショットからの復旧」の `bootstrap --recover-from`。
#
# Talos API への権限は `os:etcd:backup` だけ(talos/patches/etcd-backup.yaml)。
Expand Down
47 changes: 13 additions & 34 deletions bootstrap/cilium/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# machine config の inlineManifest にする(更新は render.sh → apply-config → upgrade-k8s。
# talos/README.md「上げ方 / 当て直し方」)。`cilium-config` の ConfigMap を直接いじらない ──
# 次の upgrade-k8s で黙って戻る(2026-09-07 まで値が git に無く、`node-port-range: "80,443"` が
# ConfigMap 直いじりでしか入っていなかった。戻ると公開している Web が全部落ちる)。
# ConfigMap 直いじりでしか入っていなかった。当時は、戻ると公開している Web が全部落ちた)。

# kube-proxy は使わない(Talos 側は talos/patches/cni.yaml で止めている)。
kubeProxyReplacement: true
Expand Down Expand Up @@ -46,34 +46,20 @@ externalIPs:
enabled: true
nodePort:
enabled: true
# 80 と 443 だけ。Gateway の Service がこの 2 つを nodePort として握っている。
# 範囲を広げると、その中に入る hostPort を Cilium が張らなくなる
# (AdGuard の 853、Mattermost calls の 8443(いまは LiveKit)、3proxy の 3129 が一斉に落ちた)。
# 範囲は既定(30000-32767)。Gateway の Service の nodePort は API サーバが割り当てるランダムな値のままでよい。
# 外からの 80/443 は Envoy が hostNetwork で掴んだソケットに直接届く(下の gatewayAPI.hostNetwork)。
#
# hostNetwork にしても外せない。Service は NodePort 型のまま残り(下の
# gatewayAPI.hostNetwork のコメント)、この 2 つの NodePort フロントエンドが
# 経路そのものになっている。2026-09-08 に実測した。
# 2026-09-08〜10-17(k3s の頃)は違った。nodePort 80/443 の L7LB リダイレクトが経路そのもので、port-80 の nodePort を
# 30080 にずらすと 80 番が全部死んだ。そのため範囲を `"80,443"`、API サーバの `service-node-port-range` を `80-32767` にし、
# nodePort を 80/443 に揃える Job を置いていた。副作用として、ノード自身から 80/443 に繋ぐと応答が返らなかった
# (apps/netbird/routing-peer.yaml、apps/forgejo/node-access.yaml)。
#
# `cilium-dbg bpf lb list` にはこう出る:
# 2026-10-18 に Talos で確かめ直した。VM では範囲を既定に戻し nodePort をランダム(32399/32657)にしても、外からも、
# ノード自身(hostNetwork の Pod)からも、Pod からも http 301 / https 200。本番でも port-80 の nodePort を 30080 に
# ずらして 301 / 200 のままだった。それで 3 つとも外した。
#
# 10.0.0.2:80/TCP 0.0.0.0:0 (1189) [NodePort, l7-load-balancer] (L7LB Proxy Port: 80)
#
# Envoy は確かにホストの `0.0.0.0:80` を LISTEN しているが、そのソケットに
# 直接来た接続は通らない。実通信は L7LB リダイレクト経由で Envoy に入る。
# 試しに port-80 の nodePort だけ 30080 に振り直したところ、外部・LAN・Pod・ホストの
# すべてから 80 番が死んだ(443 は無事。すぐ戻した)。
#
# 帰結が 3 つある:
#
# 1. ここと API サーバの `service-node-port-range=80-32767`(talos/patches/apiserver.yaml)は外せない
# 2. 復元では当て直しが要る。Cilium が Service を作り直すと API サーバが
# 範囲内のランダムな値を割り当てる。`bootstrap/gateway/nodeport.yaml`(ArgoCD の PostSync)がパッチを当てる
# 3. 副作用として、ノード自身からノードの 80/443 に繋ぐと応答が返らない。
# これは実害を出した(2026-09-08)。hostNetwork の Pod も「ノード自身」で、netbird のルーティングピアが
# `nb.doany.io:443` に繋げず `Management: Disconnected` で止まった
# (VPN 越しの DNS も LAN への RDP も落ちる)。あちらを hostNetwork から外して直した
# (apps/netbird/routing-peer.yaml)。hostNetwork の Pod を足すときは必ずこれを思い出すこと。
range: "80,443"
# **範囲を広げないこと。** 範囲に入る hostPort を Cilium は張らない(`80-32767` にしたとき
# AdGuard の 853、LiveKit の 8443、3proxy の 3129 が一斉に落ちた)。

# Gateway API。CRD は v1.6.1 が要る(v1.5.1 だと GatewayClass が無言で止まる)。
gatewayAPI:
Expand All @@ -91,14 +77,7 @@ gatewayAPI:
# Service は消えず NodePort になる(`operator/pkg/model/translation/gateway-api/translator.go`
# の `toServiceType`: `if HostNetworkConfig.Enabled { return ServiceTypeNodePort }`)。
#
# nodePort の手当ては消えなかった(2026-09-08 訂正)
#
# この変更は当初「手で当てていた nodePort 80/443 が要らなくなる」つもりで入れた。
# それは誤りだった。Envoy はホストの `0.0.0.0:80` を LISTEN するが、
# そこに直接来た接続は通らない。実通信は Cilium の L7LB リダイレクト経由で入る。
# 詳しくは上の `nodePort.range` のコメント(実測つき)。
#
# したがって nodePort の当て直し(bootstrap/gateway/nodeport.yaml)は今も要る(#91 で消したが戻した)。
# nodePort の値は経路に関係しない(上の `nodePort` のコメント。k3s の頃は関係していた)。
#
# ポートの指定は無い。Gateway のリスナー(80 / 443)がそのままホストに bind される。
# `httpPort` / `httpsPort` / `sharedListenerPort` は `ingressController.hostNetwork`
Expand Down
74 changes: 0 additions & 74 deletions bootstrap/gateway/nodeport.yaml

This file was deleted.

8 changes: 4 additions & 4 deletions docs/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ Talos には helm-controller が無く、inlineManifests は Helm を実行で
- **平文の残りは ArgoCD(2026-10-17 まで GitHub Actions の `bootstrap-apply.yml`)。** 鶏と卵にならない ──
ArgoCD が動くのに要るもの(本体・repo の資格情報・入口の `apps`)は全部 machine config にあり、この層に頼っていない。
この層が要る CRD も machine config が入れる(`InfisicalSecret` の CRD だけ `apps/` から来るので、最初の何回かは retry)。
唯一 git に書けない Gateway の nodePort 80/443 は PostSync の Job([bootstrap/gateway/nodeport.yaml](../bootstrap/gateway/nodeport.yaml))
- **SOPS の Secret を machine config に入れる。** 復号鍵はクラスタにも CI にも渡さないので、ArgoCD からは当てられない。
machine config の入力(`talos/secrets.yaml`)もクラスタ CA の秘密鍵を含む SOPS なので信頼水準は変わらず、起動時点で存在する
- **Helm を実行する場所はクラスタの外(手元の生成時)だけ。** Cilium は CNI なので inlineManifests 以外に置きようがなく、
Expand Down Expand Up @@ -153,7 +152,8 @@ bootstrap のあとに `helm install` する案は、再構築のたびに「CNI
| 認証 | oauth2-proxy を前段のプロキシに(下記) | — |

- **Cilium 1.20 は Gateway API v1.6.1 の CRD を要求する。** 古いと GatewayClass が `Waiting for controller` のまま止まる
- **ノード自身からは 80/443 に届かない。** Gateway の nodePort が L7LB リダイレクトとして載っているため(外から来る通信の経路そのもの)
- **ノード自身からは 80/443 に届かなかった(k3s の頃)。** Gateway の nodePort 80/443 が L7LB リダイレクトとして載っていたため。
2026-10-18 に nodePort を既定の範囲に戻した(`bootstrap/cilium/values.yaml` の `nodePort`)
- **`terminationGracePeriodSeconds` が長い Pod**(denpa と tuner-agent、6 時間)は Recreate と組むと入れ替わらない。`--grace-period=0 --force` で消す

### LoadBalancer をどう置き換えるか(2026-09-06 決定・実施済み)
Expand All @@ -164,7 +164,7 @@ hostPort ならノードの全アドレスで受けられ、送信元 IP も保

| 対象 | hostPort |
| --- | --- |
| Gateway(`cilium-gateway-doany`) | 80 / 443。Envoy が hostNetwork で bind するが、**実通信は nodePort の L7LB リダイレクト経由**(`bootstrap/cilium/values.yaml` の `nodePort`)。nodePort 80/443 は `bootstrap/gateway/nodeport.yaml`(ArgoCD の PostSync)が当て直す |
| Gateway(`cilium-gateway-doany`) | 80 / 443。Envoy が hostNetwork で bind し、外からの通信はそこに直接届く。Service の nodePort はランダムなままでよい(`bootstrap/cilium/values.yaml` の `nodePort`。k3s の頃は 80/443 に揃える必要があった) |
| adguardhome | 53 UDP・53 TCP・853 TCP |
| matrix の LiveKit | 8443 UDP・8443 TCP |
| 3proxy(tls-terminator サイドカー) | 3129 TCP |
Expand All @@ -173,7 +173,7 @@ hostPort ならノードの全アドレスで受けられ、送信元 IP も保
`ss` には出ないので確認は `cilium-dbg service list | grep HostPort`
- **hostPort と RollingUpdate は両立しない**(新しい Pod が Pending で止まる)。AdGuard と 3proxy は `strategy: Recreate`
- **Gateway はアドレスが付くまで `Programmed=False`。** `gatewayAPI.hostNetwork` でノードの IP が `status.addresses` に入る
- **`nodePort.range` は `80,443` の 2 つだけ。** Cilium は nodePort の範囲に入る hostPort を張らない(`80-32767` にしたら 853・8443・3129 が一斉に落ちた)。
- **`nodePort.range` を広げない(既定の 30000-32767)。** Cilium は nodePort の範囲に入る hostPort を張らない(`80-32767` にしたら 853・8443・3129 が一斉に落ちた)。
前段を入れ替えるときは、自分で配っている chart の入口(denpa の `httpRoute`)も数えること

### 3proxy と AdGuard の DoH はサイドカーで TLS を終端する
Expand Down
2 changes: 1 addition & 1 deletion docs/talos.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ PSA のラベルまで戻った。**PV の中身は戻らない**(etcd は「PVC
このあと PV データを k8up で戻す。順序は etcd が先(PV オブジェクトが無いと戻す先が決まらない)。

**主経路ではない。** 主経路は git から建て直すほう([recovery/README.md](../recovery/README.md)。スナップショットの鮮度に左右されない)。
こちらは git に無い状態(Application の同期状態、発行済みの証明書、API サーバが割り当てた nodePort など)まで一度に戻したいときの近道。
こちらは git に無い状態(Application の同期状態、発行済みの証明書など)まで一度に戻したいときの近道。
日次で取っているのは [apps/k8up/etcd-snapshot.yaml](../apps/k8up/etcd-snapshot.yaml)(restic の `--host etcd`)。取り出しは:

```shell
Expand Down
7 changes: 3 additions & 4 deletions recovery/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,15 @@ kubectl get gatewayclass # cilium が Accepted(無いと Gateway が `Waiting
## 5. 残りの bootstrap/ が入るのを見る(ArgoCD)

手ですることは無い。ArgoCD の Application `bootstrap`([../bootstrap/argocd/repos.yaml](../bootstrap/argocd/repos.yaml))が
`ClusterIssuer`・Gateway・auth・`InfisicalSecret` を当て、最後に Gateway の Service の nodePort を 80/443 に揃える
([../bootstrap/gateway/nodeport.yaml](../bootstrap/gateway/nodeport.yaml) の PostSync の Job)。
`ClusterIssuer`・Gateway・auth・`InfisicalSecret` を当てる。

```shell
kubectl -n argocd get application bootstrap # InfisicalSecret の CRD が来るまでは何度か落ちて retry で戻る
kubectl -n kube-system get svc cilium-gateway-doany # 80:80 / 443:443。違えば ArgoCD で bootstrap を Sync し直す
kubectl get certificate -A # Gateway に証明書が付く
```

ここが 80/443 でないと公開経路が全部死ぬ([../bootstrap/cilium/values.yaml](../bootstrap/cilium/values.yaml) の `nodePort`)。
Gateway の Service の nodePort はランダムな値のままでよい(2026-10-18 まではここで 80/443 に揃えていた。
[../bootstrap/cilium/values.yaml](../bootstrap/cilium/values.yaml) の `nodePort`)。

Argo CD はこの間に `apps/` と各リポジトリの `deploy/` を同期しはじめる。**中身はまだ空**なので、
Infisical の Secret を待つアプリと、Forgejo から来る非公開アプリ(`repos-forgejo` が `ErrorOccurred`)は上がらない。想定どおり。
Expand Down
7 changes: 1 addition & 6 deletions talos/patches/apiserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@ kind: KubeAPIServerConfig
# Talos はマシンのアドレス・ホスト名・Kubernetes の名前は自動で入れるが、公開名は入らない。
certExtraSANs:
- ks.doany.io
extraArgs:
# Gateway の Service は nodePort 80/443 を持っていて、そこが公開経路そのもの
# (Cilium の L7LB リダイレクト。bootstrap/cilium/values.yaml の `nodePort` に実測あり)。
# 既定の 30000-32767 のままだと 80/443 を Service に入れられず、復元後の
# 当て直しが `provided port is not in the valid range` で弾かれる。
service-node-port-range: 80-32767
# `service-node-port-range` は既定に戻した(2026-10-18。bootstrap/cilium/values.yaml の `nodePort`)。
---
apiVersion: v1alpha1
kind: KubeAuthenticationConfig
Expand Down
2 changes: 1 addition & 1 deletion talos/patches/cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ nameservers:
- address: 1.0.0.1
---
# ノード(containerd)から fj.doany.io のイメージを取るため、名前を中継の ClusterIP に向ける。
# ノード自身からは Gateway の 443 に繋がらない(bootstrap/cilium/values.yaml の nodePort の 3)。
# ノード自身からは Gateway の 443 に繋がらなかった(k3s の頃。bootstrap/cilium/values.yaml の `nodePort`。今も要るかは未確認)。
# 中継は apps/forgejo/node-access.yaml(2026-09-15)
apiVersion: v1alpha1
kind: StaticHostConfig
Expand Down
Loading