改由 cloud-init 声明 Ayatori 容器静态地址
- Terraform 写 cloud-init.network-config,地址从 records.yml 读取,与 AD DNS 同源 - 撤销 Ansible 直接改 netplan 的做法;镜像模板只在 create/copy 渲染 seed, 故两台空容器已用 -replace 重建 - 固定指纹已从上游 images: 下架,改从 local: 缓存创建 - sshd -t 前预建 /run/sshd:新装 24.04 只有 ssh.socket 运行,目录尚不存在 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -7,8 +7,8 @@ homelab_dns:
|
|||||||
# RRsets are reconciled; Samba-generated AD/Kerberos records are untouched.
|
# RRsets are reconciled; Samba-generated AD/Kerberos records are untouched.
|
||||||
records:
|
records:
|
||||||
- { zone: ad.ddupan.top, name: incus, type: A, values: [192.168.10.127] }
|
- { zone: ad.ddupan.top, name: incus, type: A, values: [192.168.10.127] }
|
||||||
# Static, outside the NEC IX pool (.128-.250); infrastructure/incus/ansible/containers.yml
|
# Static, outside the NEC IX pool (.128-.250); infrastructure/incus/terraform reads
|
||||||
# reads these same values to pin each container's netplan address.
|
# these same values into each container's cloud-init network-config.
|
||||||
- { zone: ad.ddupan.top, name: ayatori-dev, type: A, values: [192.168.10.11] }
|
- { zone: ad.ddupan.top, name: ayatori-dev, type: A, values: [192.168.10.11] }
|
||||||
- { zone: ad.ddupan.top, name: ayatori-prod, type: A, values: [192.168.10.12] }
|
- { zone: ad.ddupan.top, name: ayatori-prod, type: A, values: [192.168.10.12] }
|
||||||
- { zone: ad.ddupan.top, name: bao, type: A, values: [192.168.10.8] }
|
- { zone: ad.ddupan.top, name: bao, type: A, values: [192.168.10.8] }
|
||||||
|
|||||||
@@ -111,11 +111,11 @@ ANSIBLE_CONFIG=ansible.cfg ANSIBLE_COLLECTIONS_PATH=collections ANSIBLE_LOCAL_TE
|
|||||||
kube-apiserver、controller 或数据库;准备 Prod 空容器不代表生产服务已上线。
|
kube-apiserver、controller 或数据库;准备 Prod 空容器不代表生产服务已上线。
|
||||||
|
|
||||||
网络接入既有 `br0`,固定 MAC 分别为 `02:16:3e:aa:00:01`、`02:16:3e:aa:00:02`。
|
网络接入既有 `br0`,固定 MAC 分别为 `02:16:3e:aa:00:01`、`02:16:3e:aa:00:02`。
|
||||||
首次启动走 DHCP,随后 `ansible/containers.yml` 改为静态地址:Dev `192.168.10.11`、
|
Terraform 通过 `cloud-init.network-config` 配置静态地址:Dev `192.168.10.11`、
|
||||||
Prod `192.168.10.12`(`ayatori-{dev,prod}.ad.ddupan.top`)。地址只在
|
Prod `192.168.10.12`(`ayatori-{dev,prod}.ad.ddupan.top`)。地址只在
|
||||||
`infrastructure/dns/records.yml` 声明一次,netplan 与 AD DNS 均从此读取;须位于
|
`infrastructure/dns/records.yml` 声明一次,Terraform 与 AD DNS 均从此读取;须位于
|
||||||
NEC IX DHCP 池(`.128–.250`)之外。容器内禁用 cloud-init 网络模块,否则每次启动都会
|
NEC IX DHCP 池(`.128–.250`)之外。⚠ 镜像模板只在创建/复制时渲染 cloud-init seed,
|
||||||
重写回 DHCP。
|
对已有实例改地址不会生效(重启、`cloud-init clean` 都不行),只能重建实例。
|
||||||
|
|
||||||
初始账号 `panxiao81`,使用 `ansible/files/panxiao81.pub` 公钥登录,可 sudo;
|
初始账号 `panxiao81`,使用 `ansible/files/panxiao81.pub` 公钥登录,可 sudo;
|
||||||
密码登录关闭。宿主也可使用 `incus exec local:ayatori-dev -- bash`。
|
密码登录关闭。宿主也可使用 `incus exec local:ayatori-dev -- bash`。
|
||||||
@@ -131,7 +131,9 @@ terraform -chdir=infrastructure/incus/terraform plan -detailed-exitcode
|
|||||||
```
|
```
|
||||||
|
|
||||||
provider 固定 1.2.0 并保留 lockfile,镜像固定 Ubuntu 24.04 cloud 构建指纹。
|
provider 固定 1.2.0 并保留 lockfile,镜像固定 Ubuntu 24.04 cloud 构建指纹。
|
||||||
上游滚动镜像不保证永久保存,重建前需确认本机镜像缓存或归档可用。
|
上游滚动镜像不保证永久保存:该指纹在 2026-10-01 已从 `images:` 下架,现从 `local:`
|
||||||
|
缓存创建;缓存闲置超过 `images.remote_cache_expiry`(默认 10 天)会被自动删除,重建前需确认
|
||||||
|
本机缓存或归档可用,否则须改用新指纹。
|
||||||
cloud-init 用户设置主要在首次启动执行,修改声明不能替代后续用户/密钥轮换流程。
|
cloud-init 用户设置主要在首次启动执行,修改声明不能替代后续用户/密钥轮换流程。
|
||||||
|
|
||||||
当前 state 位于 `terraform/terraform.tfstate`(Git 忽略),是本地 backend;
|
当前 state 位于 `terraform/terraform.tfstate`(Git 忽略),是本地 backend;
|
||||||
@@ -144,5 +146,4 @@ cloud-init 用户设置主要在首次启动执行,修改声明不能替代后
|
|||||||
`mkdir ... file exists` 竞争;按上面的串行 apply 执行。失败后先重新 plan,
|
`mkdir ... file exists` 竞争;按上面的串行 apply 执行。失败后先重新 plan,
|
||||||
保留已成功创建的实例,不清理或销毁其资源。
|
保留已成功创建的实例,不清理或销毁其资源。
|
||||||
|
|
||||||
`ansible/containers.yml` 通过本机 Incus exec 幂等固定静态地址,并安装、启用 SSH server;
|
`ansible/containers.yml` 通过本机 Incus exec 幂等安装并启用 SSH server。
|
||||||
走 exec 而非 SSH,切换地址不会切断 Ansible 自身连接。
|
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
---
|
---
|
||||||
- name: 准备 Ayatori 基础容器的网络与 SSH 入口
|
- name: 准备 Ayatori 基础容器的 SSH 入口
|
||||||
hosts: incus_hosts
|
hosts: incus_hosts
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
# 静态地址与 AD DNS 记录同源,避免两处地址漂移。
|
|
||||||
vars_files:
|
|
||||||
- ../../dns/records.yml
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: 按容器协调静态地址
|
|
||||||
ansible.builtin.include_tasks: tasks/container-network.yml
|
|
||||||
loop: [ayatori-dev, ayatori-prod]
|
|
||||||
loop_control:
|
|
||||||
loop_var: incus_container
|
|
||||||
|
|
||||||
- name: 按容器协调 SSH
|
- name: 按容器协调 SSH
|
||||||
ansible.builtin.include_tasks: tasks/container-ssh.yml
|
ansible.builtin.include_tasks: tasks/container-ssh.yml
|
||||||
loop: [ayatori-dev, ayatori-prod]
|
loop: [ayatori-dev, ayatori-prod]
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
---
|
|
||||||
# 地址必须在 NEC IX DHCP 池(.128–.250)之外;池由路由器手工维护,没有 reservation 可声明。
|
|
||||||
# 用 incus exec 而非 SSH 执行,切换地址不会断开 Ansible 自身的连接。
|
|
||||||
- name: 读取容器的 AD DNS 地址
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
container_ipv4: >-
|
|
||||||
{{ (homelab_dns.samba.records
|
|
||||||
| selectattr('zone', 'equalto', 'ad.ddupan.top')
|
|
||||||
| selectattr('name', 'equalto', incus_container)
|
|
||||||
| first)['values'] | first }}
|
|
||||||
|
|
||||||
# cloud-init 网络模块每次启动都会重写 50-cloud-init.yaml,必须先禁用它,静态配置才能持久。
|
|
||||||
# 网关与 resolver 照搬原 DHCP 下发值(.1 网关;Blocky .127 优先、路由器 .1 兜底)。
|
|
||||||
- name: 声明静态网络
|
|
||||||
ansible.builtin.command:
|
|
||||||
argv:
|
|
||||||
- incus
|
|
||||||
- exec
|
|
||||||
- "local:{{ incus_container }}"
|
|
||||||
- --env
|
|
||||||
- "CLOUD_CFG={{ container_cloud_cfg }}"
|
|
||||||
- --env
|
|
||||||
- "NETPLAN={{ container_netplan }}"
|
|
||||||
- --
|
|
||||||
- sh
|
|
||||||
- -euc
|
|
||||||
- |
|
|
||||||
changed=0
|
|
||||||
put() {
|
|
||||||
if [ "$(cat "$1" 2>/dev/null)" != "$2" ]; then
|
|
||||||
printf '%s\n' "$2" > "$1"; chmod 600 "$1"; changed=1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
put /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg "$CLOUD_CFG"
|
|
||||||
put /etc/netplan/60-static.yaml "$NETPLAN"
|
|
||||||
if [ -e /etc/netplan/50-cloud-init.yaml ]; then
|
|
||||||
rm /etc/netplan/50-cloud-init.yaml; changed=1
|
|
||||||
fi
|
|
||||||
if [ "$changed" = 1 ]; then netplan apply; echo CHANGED; fi
|
|
||||||
vars:
|
|
||||||
container_cloud_cfg: "network: {config: disabled}"
|
|
||||||
container_netplan: |-
|
|
||||||
network:
|
|
||||||
version: 2
|
|
||||||
ethernets:
|
|
||||||
eth0:
|
|
||||||
dhcp4: false
|
|
||||||
addresses: [{{ container_ipv4 }}/24]
|
|
||||||
routes: [{to: default, via: 192.168.10.1}]
|
|
||||||
nameservers: {addresses: [192.168.10.127, 192.168.10.1]}
|
|
||||||
register: container_network
|
|
||||||
changed_when: "'CHANGED' in container_network.stdout"
|
|
||||||
@@ -55,9 +55,11 @@
|
|||||||
register: container_sshd_write
|
register: container_sshd_write
|
||||||
changed_when: true
|
changed_when: true
|
||||||
|
|
||||||
|
# 24.04 新装时只有 ssh.socket 运行,/run/sshd 要等 ssh.service 的 RuntimeDirectory 才创建,
|
||||||
|
# 缺它时 sshd -t 直接失败;按同样的 0755 预建(/run 为 tmpfs,不留持久状态)。
|
||||||
- name: 校验 SSH 配置
|
- name: 校验 SSH 配置
|
||||||
ansible.builtin.command:
|
ansible.builtin.command:
|
||||||
argv: [incus, exec, "local:{{ incus_container }}", --, /usr/sbin/sshd, -t]
|
argv: [incus, exec, "local:{{ incus_container }}", --, sh, -c, install -d -m 0755 /run/sshd && exec /usr/sbin/sshd -t]
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: 更新运行中的 SSH 配置
|
- name: 更新运行中的 SSH 配置
|
||||||
|
|||||||
@@ -34,12 +34,24 @@ resource "incus_storage_pool" "ayatori" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 地址只在 records.yml 声明一次,AD DNS(ansible/dns.yml)与此处同源读取;
|
||||||
|
# 须位于 NEC IX DHCP 池(.128–.250)之外,池由路由器手工维护,无法声明 reservation。
|
||||||
|
locals {
|
||||||
|
ayatori_ipv4 = {
|
||||||
|
for r in yamldecode(file("${path.module}/../../dns/records.yml")).homelab_dns.samba.records :
|
||||||
|
trimprefix(r.name, "ayatori-") => r.values[0]
|
||||||
|
if r.zone == "ad.ddupan.top" && startswith(r.name, "ayatori-")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resource "incus_instance" "ayatori" {
|
resource "incus_instance" "ayatori" {
|
||||||
for_each = toset(["dev", "prod"])
|
for_each = toset(["dev", "prod"])
|
||||||
name = "ayatori-${each.key}"
|
name = "ayatori-${each.key}"
|
||||||
description = "Ayatori ${each.key} 基础容器;应用由独立部署流程管理"
|
description = "Ayatori ${each.key} 基础容器;应用由独立部署流程管理"
|
||||||
# Ubuntu 24.04 cloud amd64,20260924_07:42;固定指纹避免重建时静默更换镜像。
|
# Ubuntu 24.04 cloud amd64,20260924_07:42;固定指纹避免重建时静默更换镜像。
|
||||||
image = "images:b39d3d56c30738ad74c507066cc5d410e1c0f1647bdcdff398be1ee51d63862a"
|
# 上游 images: 已不再提供该构建(2026-10-01 重建时 "image couldn't be found"),只能取本机缓存;
|
||||||
|
# ⚠ 缓存镜像闲置超过 images.remote_cache_expiry(默认 10 天)会被 Incus 自动删除。
|
||||||
|
image = "local:b39d3d56c30738ad74c507066cc5d410e1c0f1647bdcdff398be1ee51d63862a"
|
||||||
type = "container"
|
type = "container"
|
||||||
profiles = []
|
profiles = []
|
||||||
running = true
|
running = true
|
||||||
@@ -50,6 +62,19 @@ resource "incus_instance" "ayatori" {
|
|||||||
"limits.cpu" = "2"
|
"limits.cpu" = "2"
|
||||||
"limits.memory" = "2GiB"
|
"limits.memory" = "2GiB"
|
||||||
"limits.memory.swap" = "false"
|
"limits.memory.swap" = "false"
|
||||||
|
# ⚠ 镜像模板只在 create/copy 时渲染 cloud-init seed(when: [create, copy]),
|
||||||
|
# 对已有实例修改此键不会生效,重启或 cloud-init clean 也不会;改地址须重建实例。
|
||||||
|
# 网关与 resolver 沿用 LAN DHCP 下发值:.1 网关;Blocky .127 优先、路由器 .1 兜底。
|
||||||
|
"cloud-init.network-config" = yamlencode({
|
||||||
|
version = 2
|
||||||
|
ethernets = {
|
||||||
|
eth0 = {
|
||||||
|
addresses = ["${local.ayatori_ipv4[each.key]}/24"]
|
||||||
|
routes = [{ to = "default", via = "192.168.10.1" }]
|
||||||
|
nameservers = { addresses = ["192.168.10.127", "192.168.10.1"] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
"cloud-init.user-data" = "#cloud-config\n${yamlencode({
|
"cloud-init.user-data" = "#cloud-config\n${yamlencode({
|
||||||
hostname = "ayatori-${each.key}"
|
hostname = "ayatori-${each.key}"
|
||||||
manage_etc_hosts = true
|
manage_etc_hosts = true
|
||||||
|
|||||||
Reference in New Issue
Block a user