目录
已经很久没有更新博客了,想来最近稍稍有了时间,有必要把之前一直没有时间写完的博客更新了
尽管之前我 基于 GitLab、Docker-Compose 和 Harbor 的 CI/CD 实现 中已经实现了一个 CI/CD 流程。但 Docker 本身并不够强大,CI/CD 实现中也十分不优雅。
因此,从 2022 年 2 月的寒假我就决定将我手上大多数服务器推成一个 Kubernetes 集群,并将服务进行迁移。这个工程量是相当巨大的,因此至今还有一小部分服务没有恢复(鸽精本精
然后整个上学期因为架构设计的一些问题,第一版系统架构有着比较严重的问题。因此我一直拖着没有更新博客。
关于 CI/CD 我们在这里不过多阐述,这篇博文主要聊聊新的基础架构。
虚拟化平台
Proxmox VE 7 的 VirtIO 虚拟网卡存在性能问题,对此我进行了一些尝试但没有解决这个问题。
在一位朋友的推荐下,我的第一版方案选择使用 VMware ESXi。并且通过 PCIe 直通将 RAID 控制器直通到 TrueNAS SCALE 虚拟机中实现 NAS。
但这个方案产生了比较严重的时序问题。我们不得不使用 NFSv4 来利用被直通的磁盘空间建立虚拟机。因此在新版 Proxmox VE 解决了虚拟网卡问题之后我决定转回 Proxmox VE,并基于 Proxmox VE 手动实现 NAS 和运行 Kubernetes。
K3S
为了将我的服务器都纳入管理体系,我们使用 WireGuard 将它们放在一起。
启动好 WireGuard 后,我们需要在 /etc/rancher/k3s/config.yaml
中添加:
node-ip: 这里填写 WireGuard 接口的 IP
这里放上 k3s.service 的启动参数:
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
KillMode=process
Delegate=yes
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s \
server \
'--flannel-backend=none' \
'--disable=traefik,local-storage' \
'--disable-network-policy' \
'--kube-proxy-arg' 'proxy-mode=ipvs' 'masquerade-all=true' \
'--snapshotter' 'native' \
'--container-runtime-endpoint' '/run/containerd/containerd.sock' \
'--node-name' 'ix-truenas' # 这里的 node-name 是因为我先前使用 TrueNAS SCALE 中的 k3s
这里说明一下,我采用基于 eBPF 的 cilium 作为 CNI,因此 Flannel 和默认的 Network Policy 要进行禁用。同时我们也不希望 Traefik 被 k3s 自动安装。
在 Proxmox VE 中,我们可以直接使用自行安装的 containerd,因此需要设置 container-runtime-endpoint
。
同时我使用 ZFS 作为文件系统,因此 snapshotter
要选取 native。
存储后端我选择使用 OpenEBS 提供的 zfs-localpv。部署 YAML 如下:
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
storageclass.kubernetes.io/is-default-class: 默认则 "true"
storageclass.kubesphere.io/allow-clone: "true"
storageclass.kubesphere.io/allow-snapshot: "true"
name: 名称
parameters:
fstype: zfs
poolname: 【ZFS Pool 名】/【数据集】
shared: "yes"
provisioner: zfs.csi.openebs.io
reclaimPolicy: Delete
volumeBindingMode: Immediate
Helm 可以用于安装 Traefik、Cilium、OpenEBS 等。
然后我们可以将更多节点加入 Kubernetes 集群。总之上一张 KubeSphere 面板图。
NAS
作为 HomeLab 的部分,NAS 自然必不可少。先前我的方案也主要出于 NAS 考虑而采用了 TrueNAS SCALE,但其定制性实在不够好,且遇到系统组件有 bug 时很难处理。
因此,我决定在 Proxmox VE 上直接手动搭建所有 NAS 功能。
初始化 ZFS
尽管该部分先前我基本已经在 TrueNAS SCALE 上完成,但为了方便读者,还是简单介绍一下。
ZFS 使用之前我们首先要创建存储池,即 zpool,一个简单的存储池可以像这样创建:
zpool create -R /mnt/flash flash /dev/disk/by-partuuid/f656034c-bffa-462a-8534-db7fc71972a4
其中,-R
参数指定的是挂载点,flash
是 pool 名,后面可以跟数个块设备。这样我们创建的是一个简单的存储池。
然而 ZFS 自带软件 RAID,因此我们也可以创建 RAIDZ 存储池。例如,我们创建类似 RAID 6 的 RAIDZ-2 存储池,它可以允许两块磁盘离线。
zpool create panda raidz2 【vdevs】
这里我们建议使用 /dev/disk/by-partuuid
下映射的虚拟设备,因为这样由分区 UUID 决定路径可以确保设备路径不会因为一些原因发生变化。
Samba
首先是账号体系,为了实现良好的账号体系,我决定采用 Windows Server 来搭建 Active Directory 域。搭建成功后,我们就可以通过使用它来管理账号体系而不是在 Samba 内进行管理。这里略去 Active Directory 的搭建过程,仅介绍 Samba 加入 AD 域的相关配置。
首先我们安装 samba 和 winbindd 组件。
apt install samba-common winbind libnss-winbind libpam-winbind
pam-auth-update
然后配置 /etc/samba/smb.conf
。
[global]
log level = 1
read raw = Yes
write raw = Yes
strict locking = No
oplocks = yes
max xmit = 65535
dead time = 15
getwd cache = yes
aio read size = 16384
aio write size = 16384
use sendfile = true
bind interfaces only = Yes
client ldap sasl wrapping = seal
disable spoolss = Yes
dns proxy = No
domain master = No
kerberos method = secrets and keytab
load printers = No
logging = file
max log size = 5120
obey pam restrictions = Yes
passdb backend = tdbsam:/usr/local/samba/passdb.tdb
preferred master = Yes
local master = yes
printcap name = /dev/null
realm = 这里是域名
registry shares = Yes
map to guest = Bad User
netbios name = 这里是NAS的NetBIOS名称
security = ADS
server min protocol = SMB2
server multi channel support = No
server role = member server
server string = 你的NAS标识信息
template homedir = 用户主目录,例如 /home
template shell = /sbin/nologin
username map = /usr/local/samba/etc/user.map
winbind cache time = 7200
winbind enum groups = Yes
winbind enum users = Yes
winbind max domain connections = 10
winbind use default domain = Yes
workgroup = AD
wins support = yes
idmap config ad : backend = rid
idmap config ad : range = 100000001 - 200000000
idmap config * : range = 90000001 - 100000000
idmap config * : backend = tdb
create mask = 0775
directory mask = 0775
配置完这个之后,我们就可以加入域了。
net ads join -U 【一个有权限加入域的用户】
加入后 wbinfo --ping-dc
返回包含 succeeded 即代表成功。此时使用 getent passwd
应当能看到域用户。
为了实现 Shadow Copy 功能,我们应当给每个用户一个数据集,然后安装 zfs-auto-snapshot
来自动化创建快照。
然后,我们给出一个 Home Share 的示例。
[Home]
ea support = Yes
kernel share modes = No
mangled names = no
path = 这里是家路径,例如 /home
posix locking = No
read only = No
valid users =
vfs objects = catia fruit streams_xattr shadow_copy2 acl_xattr recycle io_uring
map acl inherit = yes
shadow:snapdir = .zfs/snapshot
shadow:sort = desc
shadow:format = zfs-auto-snap_frequent
fruit:aapl = yes
fruit:model = Xserve
recycle:subdir_mode = 0700
recycle:directory_mode = 0777
recycle:touch = True
recycle:versions = True
recycle:keeptree = True
recycle:repository = .recycle
但是,这里存在一个问题,就是如何确保 samba 在 AD 域服务启动后再启动。由于我本来就会运行一个脚本用来每分钟执行一些任务,所以:
if (ping -c 1 -w 1 AD域服务器IP 2> /dev/null); then
systemctl start smbd.service nmbd.service winbind.service && sleep 4
if [ -n "$(getent passwd 某个AD账户)" ]; then
# 这里还可以用来写一些 smb 启动后的操作
fi
NFS 和 iSCSI
NFS 和 iSCSI 就比较简单了,只需要安装以下组件:
apt install nfs-common nfs-kernel-server tgt
NFS 相关的配置在 /etc/exports
中,只需要指定路径和参数即可,十分简单,我们主要说说 iSCSI。
iSCSI 的分享是块设备,正好可以很好地和我们的 ZFS 相适应。ZFS 的 zvol 功能可以提供良好的块设备支持。
若要创建一个 zvol,只需要像这样:
zfs create -V 5gb dataset/myzvol
像这样,即可在 /dev/zvol/dataset/myzvol
找到对应的 zvol 块设备。
对于 iSCSI,有两个重要的概念:target 和 LUN。其中一个 target 可以认为是一个虚拟的 SCSI 控制器,LUN 则是这个 SCSI 控制器下面挂接的磁盘。target 名称结构是这样的 iqn.<四位年份>-<两位月份>.<反转域名>:<标识符>
。
我们可以用 tgtadm
管理我们的 iSCSI,例如创建一个 target:
tgtadm --lld iscsi --op new --mode target --tid 1 --targetname iqn.2018-02.tech.imvictor.iscsi:tgt0
那么这个 target 就在系统中 ID 为 1,并且名称为 iqn.2018-02.tech.imvictor.iscsi:tgt0
。
要将 LUN 加入 target,只需:
tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun 1 --backing-store /dev/zvol/dataset/myzvol
更多配置可以查看 tgtadm
的配置。
本文的内容大概就在这里了,只是一个简单的介绍,更多内容后面再写。