html
我抵制为我的家庭实验室设置自动化很长一段时间,部分原因是我想手动重复这个过程,以便加深记忆,帮助学习。这意味着我错过了那些方便的命令行工具来进行一行修复,但我专注于设置的错误方面。如果我能重新来过,我会从一开始就学习像Terraform、Ansible和Packer这样的自动化工具,因为将基础设施视为代码(IaC)的范式转变,如果你已经陷入某种工作方式,会花费更长的时间。
现在我正在深入学习自动化所需的符文(抱歉,YAML和Jinja),并设置文本文件的文件夹,将它们串联成一个最终命令,只需几次按键就能重现我的家庭实验室。老实说,这种力量令人陶醉,但也有点令人畏惧,这就是为什么我一直在逐步进行。我离这个目标越来越近,使用Ansible,但还没有完全实现。
为什么Ansible是正确的答案
也许这些年我问错了问题
我老实说。我的家庭实验室在最好的时候几乎是无序的混乱。目前,它分布在两台运行Proxmox的迷你PC上,彼此差异巨大:一台有大量存储和低功耗CPU,另一台则配备Strix Halo、128GB内存和2TB存储。它还有一个NAS,里面仍然有我曾经使用但尚未完全替换(还在等待替换)的程序残余,以及一台Threadripper机器,由于我在等待一些部件到货,尚未完全配置。
在网络方面,它也是一个混合的组合,主要是Zyxel的设备,但有一些Firewalla设备在轮换使用。Firewalla路由器和接入点将很快成为未被触动的家庭网络,而家庭实验室即将进行一次重大升级,增加一些Unifi设备的机架。
关键不在于硬件;而是我需要一个多功能的解决方案,能够处理每个设备,平台无关且易于管理。我本可以选择Terraform(也许在玩了一段时间后我应该选择它),但我不喜欢中途放弃,所以Ansible有更多的时间来证明自己,而我在努力克服困难。
我的最终目标是用一行命令重现我的家庭实验室,ansible-playbook site.yml --vault-password-file ~/.vault_password
. 这个过程进展缓慢,但我希望只需做一次,因为我将最终拥有一个完全记录的家庭实验室,包含虚拟机、秘密管理、网络及其他一切。
这不是Proxmox管理的最佳解决方案
虽然Ansible可以用于许多任务,但它需要一些调整才能与Proxmox配合使用。 Proxmox主机需要安装一些工具,以便能够利用Proxmox Rest API,主要是Proxmoxer及其所需的Python依赖。
apt install build-essential python3-dev libguestfs-tools -y
apt install python3 virtualenv
apt install python3 proxmoxer
与任何其他外部工具一样,我还需要一个API令牌,以便Ansible能够在我的主机上运行剧本。我决定不使用root用户,因为我想正确地做事,所以ansible@pam应运而生,我取消选中特权分离框,以避免后续的ACL问题。
这其实不是最难的部分,因为我需要在Ansible中使用community.general.proxmox_kvm模块,而不是更新的community.proxmox.proxmox.lxc模块。这意味着每个虚拟机剧本看起来像这样(但我的秘密和其他信息已被替换):
- name: 从定义中配置虚拟机
community.general.proxmox_kvm:
proxmox_default_behavior: "{{ proxmox_behavior | default('no_defaults') }}"
node: "{{ item.node }}"
vmid: "{{ item.vmid }}"
name: "{{ item.name }}"
memory: "{{ item.memory | default(2048) }}"
cores: "{{ item.cores | default(2) }}"
sockets: "{{ item.sockets | default(1) }}"
disk: "{{ item.disk | default('100') }}"
storage: "{{ item.storage | default('local-lvm') }}"
ostype: l26 # Linux 2.6+
osimage: "{{ item.osimage | default('ubuntu-20.04-standard') }}" # 操作系统镜像
netif: # 网络接口
net0: "virtio,bridge=vmbr{{ item.vlan | default('0') }}" # 网络配置
ipconfig0: "{{ item.ip_config | default('dhcp') }}" # IP配置
sshkeys: "{{ lookup('file', '~/.ssh/ansible_homelab.pub') }}" # SSH密钥
state: present # 状态
proxmox_default_behavior: no_defaults # Proxmox默认行为
loop: "{{ vms_to_create | default([]) }}" # 循环创建虚拟机
when: vms_to_create is defined # 当虚拟机列表已定义时
tags: vm_creation # 标签: 虚拟机创建
- name: 启动虚拟机 (Start VMs)
command: "qm start {{ item.vmid }}" # 启动指定的虚拟机
changed_when: false # 状态未改变
loop: "{{ vms_to_create | default([]) }}" # 循环创建虚拟机
when:
- vms_to_create is defined # 当虚拟机列表已定义时
- item.state | default('started') == 'started' # 如果状态为启动
- name: 等待虚拟机启动并获取IP地址
uri:
url: "{{ proxmox_url }}/api2/json/nodes/{{ item.node }}/qemu/{{ item.vmid }}/status/current" # API请求的URL
user: "{{ proxmox_user }}" # 用户名
password: "{{ proxmox_password }}" # 密码
validate_certs: no # 不验证证书
register: vm_status # 注册虚拟机状态
until: vm_status.json.data.status == 'running' # 直到虚拟机状态为运行中
重试次数:30
延迟:2
循环: "{{ vms_to_create | default([]) }}"
条件:vms_to_create 已定义
我们的 CMS 经常会提取 Ansible playbook 所需的缩进格式。大多数 IDE 都知道缩进的规则,而我现在很高兴使用 Cursor 进行开发。
记录所有内容是需要时间的
尤其是因为在设置过程中我什么都没记录
最终的目标是建立一个遵循最佳实践的完整项目结构,每个方面都细分为更小的角色:
homelab-infra/
├── ansible.cfg # 全局 Ansible 配置
├── site.yml # 主要入口 playbook
├── requirements.yml # Ansible 集合和角色
├── inventory/
│ ├── 00-static.yml # 手动定义主机和组
│ ├── 01-proxmox-dynamic.yml # 动态 Proxmox 插件配置
│ └── 02-constructed.yml # 组的后处理
├── group_vars/
│ ├── all.yml # 全局变量
│ ├── proxmox.yml # Proxmox 特定配置
│ ├── networking.yml # VLAN、DNS、NTP 配置
│ └── vault.yml # 加密的秘密(Ansible Vault)
├── host_vars/ # 主机特定的变量(如有需要)
├── roles/
│ ├── bootstrap/ # SSH 密钥的设置和初始访问
│ ├── proxmox_baseline/ # Proxmox 节点配置
│ ├── networking/ # VLAN、路由、防火墙
│ ├── vm_provisioning/ # 虚拟机的创建与销毁
│ ├── services/ # Docker, K3s, 监控
│ └── security/ # 安全加固, 备份
├── playbooks/
│ ├── bootstrap.yml # Ansible 初始化设置
│ └── configure.yml # 主要配置
├── roles/common/
│ ├── tasks/
│ │ └── main.yml
│ ├── handlers/
│ │ └── main.yml
│ ├── templates/
│ ├── vars/
│ │ └── main.yml
│ └── defaults/
│ └── main.yml
└── .gitignore # 排除 vault.yml, secrets 等
目前,我已经将网络部分规划并处理完毕,并使从 Proxmox 主机获取动态库存的功能正常运作。这个计划中的一些内容目前在我的实验室中还没有实现,比如 K3s,但它们随时可能成为功能,所以趁着我脑子里还在想着 Ansible 语法,干脆把这项工作做了。
我可不能忘了秘密管理
我最近开始使用 Bitwarden 来存储我在 Docker 文件中使用的秘密,我也想为我的 Ansible 剧本做同样的事。Ansible Vault 在使用时会创建加密字符串或文本文件,然后你可以在剧本中引用这些加密文件,让你的秘密,嗯……保持秘密。
ansible-vault create group_vars/vault.yml
这会让你创建一个 vault 密码,Ansible 会为你打开一个窗口,以便你添加 API 密钥、密码和其他秘密。我的文件里只有几个项目,因为我的家庭实验室比较简单,但随着我的需求增加,我可以在这个文件中添加更多内容。
# Proxmox API 凭证
vault_proxmox_user: automation@pve
vault_proxmox_password: "
# 服务凭证
vault_docker_registry_username: 我的用户名
vault_docker_registry_password: 我的密码
# 数据库凭据
vault_postgres_root_password: "(请填写密码)"
vault_postgres_replication_password: "(请填写密码)"
# TLS 证书
vault_tailscale_auth_key: "tskey-XXXXXXX"
然后,每个使用秘密的剧本都需要引用这个保管库,具体如下:
- name: 配置 Proxmox API 访问
set_fact:
proxmox_user: "{{ vault_proxmox_user }}"
proxmox_password: "{{ vault_proxmox_password }}"
- name: 用秘密来部署服务
docker_container:
name: postgres
image: postgres:14
env:
POSTGRES 密码: "{{ vault_postgres_root_password }}"
POSTGRES 复制密码: "{{ vault_postgres_replication_password }}"
老实说,这确实有点麻烦,但我更希望我的密码和 API 密钥能够被加密,尤其是因为我打算把剧本存储在自托管的 Git 实例里进行版本控制。而且我可不能忘了在那些任务里加上no_log: true,因为没人想在日志文件里泄露自己的秘密。
Ansible 是我脑子里需要的活文档工具
我很享受学习 Ansible 和它的语法。我知道我不会主动做文档,除非被迫,而把自动化工具当作文档,这种脑力黑客我很能接受。我期待有一天能用一行代码重建我的家庭实验室,无论我把它搞得多糟糕。当然,前提是我弄坏的东西不是实物,这可是完全不同的事情要处理。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.