前言
昨天晚上回宿舍后看到了那个视频,这不就是我想要的效果吗,于是就尝试着复现。
安装 PVE
是的,我还是选择 pve 了。
esxi 的 api 是只读的,也就是说不支持直接用 terraform 去操控,如果需要使用 terraform 操控 exsi 平台的话,需要上到 vsphere。先不说这玩意巨贵我不会买就是了,还吃资源,我就一台机器也搞 vCenter 着实没必要。虽然也有 方案 使用 ssh 去直接提供类似的 terraform 的 api,但是我看了,不支持 cdrom,所以只能作罢。(其实我在后台安装了一天的 vCenter)
然后,换虚拟化平台的话,就。懒,不想换,换平台好麻烦的。我 esxi 和我洋垃圾服务器主板超配的好不好,用的也很稳,很爽,干嘛换掉。
于是,那就在 exsi 里面安装 pve 吧。😁
熟练的下载 iso,熟练的创建虚拟机,选择 iso,下一步,下一步,下一步。就安装好了。
然后 开启嵌套虚拟化,就可以愉快的玩耍了。
方案选择
主要参考的教程是 这个
首先,我想了好几个方案
- 一是,用了 pve 了,之前在 esxi 上面设置不了的 serial number 可以随意设置了,那我就可以实现我的“完美”方案了(见本系列第一篇)
- 二是,可以用 terraform 渲染 cloud init 的配置,然后再调用命令生成 iso,把 iso 挂载到镜像上面就可以啦。这个方案就通用的一点,如果 vmware 家的平台可以用的话,迁移过去也不会有有很大的成本
不过,后来发现,pve 自带 cloudinit 了,甚至简单的配置项都可以直接在 ui 上面完成,配置文件都不用写了。
接着仔细研读了 pve 的 terraform provider 文档,发现,人家专门有一个叫做**Cloud Init Disk
** 的 Resource。你只要给配置文件,他能够自动生成符合 cloudinit 规范的 iso,然后使用 nocloud 这个 datasource 的方式挂载上去,就能自己按照你给的 yaml 进行配置了。
再想想,也是哦,我是用户诶。我干嘛去管 要怎么搞让实例读到配置 等细节,我是平台的用户,平台给了这个接口,我干嘛不用,还想着自己造轮子?
于是乎,就改变策略,我就只把要的实例的信息和配置告诉 terraform,然后剩下的就让它帮我去做吧。
构建模板
首先,需要构建实例的模板。模板是镜像文件和配置的组合,我们把基础配置提前在模板里面配置好,接下来使用的时候直接克隆预先配置好的模板,就可以省很多事。
创建模板可以参考这个 官方文档。注意可以的话,尽量选择 virtio 的设备,性能会高一些。
这里真的踩了好多坑,先是 providers 版本不够,我用的 pve 太新了。升级之后 providers 的语法又改了,又要改配置文件。然后改完之后出现了克隆出来的硬盘用不了的情况,测试了好久,最后在 issue 里面了解到要加一个选项才能正常克隆。
怎么说呢。我确实不是很懂 pve,也不是很懂 terraform,可能折磨我几个小时的问题在行家的眼里就是基本操作吧。就好比看到别人学 c 语言犯的常见错误一样吧。
反正不管怎么说,我还是搞成功了,就这样吧,能用就行,反正我也不是搞这个的专家。
tf 配置文件在下面给出来了,记得改成你自己的参数。
简单的来说就是传入自己的 cloudinit 的配置文件,创建一个 cloud_init_disk。然后把这个 disk 挂载到从模板克隆出来的虚拟机上。这样虚拟机启动的时候就会自动读取配置文件了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
terraform {
required_providers {
proxmox = {
source = "Telmate/proxmox"
version = "3.0.1-rc3"
}
}
}
provider "proxmox" {
pm_tls_insecure = true
pm_api_url = "https://10.21.22.14:8006/api2/json"
pm_api_token_id = "root@pam!ewq1"
pm_api_token_secret = "d3e5ec16-cb34-4417-9f5e-06315c7090ac"
pm_debug = true
}
locals {
vm_name = "ubuntu"
pve_node = "pve"
iso_storage_pool = "local"
}
resource "proxmox_cloud_init_disk" "ci" {
name = local.vm_name
pve_node = local.pve_node
storage = local.iso_storage_pool
meta_data = yamlencode({
instance_id = sha1(local.vm_name)
local-hostname = local.vm_name
})
user_data = file("user-data.yaml")
network_config = file("network-config.yaml")
}
resource "proxmox_vm_qemu" "proxmox-ubuntu" {
name = local.vm_name
desc = "Ubuntu develop environment"
# 节点名
target_node = "pve"
# cloud-init template
clone = "ubuntu-2404-cloudinit-template"
full_clone = false
# 关机 guest agent
agent = 0
os_type = "ubuntu"
onboot = false
# CPU
cores = 4
sockets = 1
cpu = "host"
# 内存
memory = 4096
scsihw = "virtio-scsi-pci"
bootdisk = "virtio0"
# boot = "order=virtio0" # 不能用这个,用这个启动不了
disks {
virtio {
virtio0 {
disk {
# 硬盘设置,因计算的方式 101580M 代替 100G
size = "101580M"
storage = "local-lvm"
replicate = true
# 这个 replicate 必须要加,不然识别不了克隆出来的硬盘
}
}
}
scsi {
scsi0 {
cdrom {
iso = "${local.iso_storage_pool}:${proxmox_cloud_init_disk.ci.id}"
}
}
}
}
# 网络
network {
model = "virtio"
bridge = "vmbr0"
}
lifecycle {
ignore_changes = [
network,
]
}
}
|
Cloud init 配置文件
这个就因人而异了,自己想配置啥就写啥
给出我的作为参考吧,是打算练习安装 k8s 的初始配置,自用,写得很烂
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
#cloud-config
# 判断是否运行
bootcmd:
- echo "Hello World. The time is now $(date -R)!" | tee /userdata_bootcmd
# 换源
apt:
primary:
- arches: [default]
uri: https://mirrors.tuna.tsinghua.edu.cn/ubuntu/
# 时区
timezone: Asia/Shanghai
# ntp 服务
ntp:
enabled: true
servers:
- ntp1.aliyun.com
# 安装软件
# package_update: true
# package_upgrade: true
# hostname
hostname: ubuntu
# ssh 公钥
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5E3GWFRw0aQrLNDIZ3E6b5VmvzXgFI5DOhnxCDtLqqYDhJ8WQIVnPvXqDJu0ZIhSLudMX5Fng/WPO5ES7OnmZOLqla5Tq26leV4MrvIWgHlZfJuBJNc2smFLf68yxZYm0QFjqsxOK3tg0Mc2Hb+93maOCDGUY/+IkiXtgCrHNUqvA3NlaMYmNUARDoUX/eAiGCn/M7nrEN7XAM885/GXAkdyMQxIiLJpj6HrTSXalTj8G6sPap/5IHb0+Jbx+NW8W69UDkOYDEy17yyJzb6jv3TU3Qm1mCHO4R4LMA/LxQOxsSxqXQMzyNRZyHPO2UI6zPlWojlcucsLHrpZ0RhsK8UmDeyRW9zN1J9TRngLykvC6TnkBPtKdQ5jx1kgN6KG4UUCPgqjncc1f7kF30V4kX+dXUDWggM1wd8ICH1BRgbTIvZdbl/X9OnVRbqSzMF6soTdNIEbTZMvPSfFrTEmt0G44ZLqWk8NKXeFSCQKey103KNyD4pKBCTLcpQHg7qE= suyiiyii@PC-5950x
# 写入文件
write_files:
# 欢迎信息
- path: /etc/issue
content: |
\ Welcome to \S, customized by suyiiyii.
\ Hostname: \n
\ IP Address: \4
\ IP Address: \6
\ \t
append: true
- path: /etc/motd
content: The OS image is customized by suyiiyii.
append: true
- path: /etc/ssh/sshd_config
content: |
PermitRootLogin yes
append: true
# 用户
user:
name: suyiiyii
chpasswd:
expire: False
users:
- name: root
password: $6$As3IUoJEdk6ep5xx$mlgkdV4lSIUDqn6SqdghuIYT/dOIg4C038DdqCIRrEFRKvmIpKjN4MGZry0wSQ8RoKcwa6qjkUR6gDhc0I2W/.
- name: suyiiyii
password: $6$As3IUoJEdk6ep5xx$mlgkdV4lSIUDqn6SqdghuIYT/dOIg4C038DdqCIRrEFRKvmIpKjN4MGZry0wSQ8RoKcwa6qjkUR6gDhc0I2W/.
final_message: |
cloud-init has finished
version: $version
timestamp: $timestamp
datasource: $datasource
uptime: $uptime
runcmd:
# 禁用 swap
- swapoff -a
- sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# 关闭 selinux
- setenforce 0
- sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
# 关闭防火墙
- systemctl stop ufw
- systemctl disable ufw
# 使用官方命令和清华源安装 docker
- for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do apt-get remove $pkg; done
- apt-get update -y
- apt-get install ca-certificates curl gnupg -y
- install -m 0755 -d /etc/apt/keyrings
- curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
- sudo chmod a+r /etc/apt/keyrings/docker.gpg
- |
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
# - apt-get update -y
# - apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
# 使用 ubuntu 源安装 docker
- apt-get install docker.io -y
# 给用户组添加权限
- usermod -aG docker suyiiyii
# 导入 k8s 源
- curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/kubernetes/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
- echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/kubernetes/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
- apt-get update -y
- apt-get install -y kubelet kubeadm kubectl
- apt-mark hold kubelet kubeadm kubectl
# 安装 neofetch
- apt-get install neofetch -y
|
配置文件的渲染
这里才算是重头戏。当我们同时创建多台机器的时候,如果使用同样的配置文件,那么他们将会有同样的 hostname,同样的 ip。着并不是我们所期望的。
所以需要对机器的配置文件进行一定的个性化,这里我是使用 tf 对 ci 的配置文件进行一定的模板替换。
user-data 内,将变量设置为被 ${}
的占位符
1
2
|
# hostname
hostname: ${hostname}
|
然后在 tf,通过 templatefile 命令进行模板替换
1
|
user_data = templatefile("user-data.yaml", { "hostname" = local.vm_name })
|
最后系统中的 hostname
就会和local.vm_name
保持一致了,非常愉快。
目前只会这个最简单的替换,更多的不会了,先这样吧。😁
总结
这几天搞了这么久,终于爽了一把了。敲一行命令就可以部署一台可以直接使用的机器,不想要了也是敲一行命令就可以销毁,并且想要多少条就可以创建多少台,不喜欢还可以进一步自定义,实在是太有幸福感了。
可以在家开 IDC 了,再加个界面就可以躺着赚钱了。
目前还是有很多不足的,例如 ip 地址的分配问题。这个要再研究研究 tf 的配置文件要怎么写。
还有 apt,几台机器都去源下载同样的文件太浪费了,docker 也是,还要再搞个本地的缓存加速。
果然,,挖坑容易填坑难,我就想快速方便的创建机器,怎么要这么多事情。