使用Kubeadm搭建K8S集群
这篇博客记录搭建一个 1Master+2Node 的 K8S 集群的过程。所使用的关键软件的版本:
名称 | 版本 |
---|---|
Ubuntu | 22.04 |
kubeadmin | 1.29.0 |
containerd | 1.7.13 |
runc | 1.1.12 |
以下所有 bash 命令都默认在 root 用户权限下执行。
1 准备机器
使用物理机
我使用的物理机为 3 台 Dell 的 Vostro 主机,它采用一颗 Intel(R) Core(TM) i7-10700 CPU,主频 2.90GHz,8 核心,16 线程,并且有 16GB 内存,实机照片如下:
安装 Ubuntu 22.04 live server
只需要安装服务器版本就够了,用不着桌面环境,安装时间可以缩短。
安装过程中记得选上 OpenSSH 服务,默认是不选的。
组网
我使用机器自带的无线网卡组网,安装完系统后,进入
/etc/netplan/
目录,把原来的配置文件移除(重命名):1 2
mv 00-installer-config.yaml 00-installer-config.yaml.bak mv 00-installer-config-wifi.yaml 00-installer-config-wifi.yaml.bak
然后写一个新的配置文件
00-config.yaml
:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
network: version: 2 wifis: wlp4s0: dhcp4: false access-points: MY_SSID: # 填上无线网络名称 password: MY_PASSWORD # 填上无线网络密码 addresses: - 10.42.0.200/24 routes: - to: default via: 10.42.0.1 nameservers: addresses: - 10.42.0.1 - 114.114.114.114
这里我直接分配了固定 IP,方便之后远程连接。
配置 SSH 认证
把自己的公钥添加到
/root/.ssh/authorized_keys
文件中,建议后面的操作都远程进行,相比在物理机上,远程操作可以方便地在主机间拷贝命令行。
使用 Hyper-V 虚拟机
虚拟机的好处就是可以复制,我们先创建一个 Ubuntu 22.04 的虚拟机,然后复制两份,这样就有了 3 台机器。
创建虚拟机并安装 Ubuntu 22.04
这里不再赘述,安装过程和物理机一样。
设置硬件配额
K8S 至少要 2GB 的内存,在 Hyper-V 管理器的虚拟机设置中,把内存最低限制调整到 2GB(如果启用了动态内存)。
复制虚拟机
在 Hyper-V 管理器中,选择“导入虚拟机”,找到上面安装的那个虚拟机的文件夹,记得在导入类型页面选择“复制新虚拟机(创建新的唯一 IO)”,就能实现虚拟机的复制了。
复制的虚拟机和原来的虚拟机具有完全一样的硬件配置,所以不必再修改最低内存限制。
修改复制虚拟机的 hostname、MAC 地址和 product_uuid
安装 K8S 要求这三个值都不能相同。
hostname 在操作系统中修改:
1
hostnamectl set-hostname xxx # 改为新主机名
在物理机上,MAC 地址存储在网卡中,product_uuid 存储在主板的 BIOS 中。Hyper-V 默认会开启随机 MAC 地址,所以只要启动一遍复制的虚拟机,这两个值就会自动变化。
product_uuid 必须手动在虚拟机外面修改。关闭虚拟机,然后在宿主机的管理员 PowerShell 中运行下面的脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
$VMname="填写Hyper-V中的虚拟机名" $vmx = Get-WmiObject -Namespace root\virtualization\v2 -Class msvm_virtualsystemsettingdata #每次操作选择一台虚拟机 $CurrentSettingsData = $vmx | Where-Object { $_.ElementName -eq $VMname } #检查一下老的GUID $CurrentSettingsData.BIOSGUID #生成新GUID $GUID = [System.Guid]::NewGuid() #重新写入GUID,注意要带{},这是非常重要的细节 $CurrentSettingsData.BIOSGUID = "{" + $GUID.Guid.ToUpper() + "}" #生成一个ModifySystemSettings的空对象 $VMMS = Get-WmiObject -Namespace root\virtualization\v2 -Class msvm_virtualsystemmanagementservice $ModifySystemSettingsParams = $VMMS.GetMethodParameters('ModifySystemSettings') #配置这个属性,需要特殊的转换方式 $ModifySystemSettingsParams.SystemSettings = $CurrentSettingsData.GetText([System.Management.TextFormat]::CimDtd20) #写入 $VMMS.InvokeMethod('ModifySystemSettings', $ModifySystemSettingsParams, $null)
配置 SSH 认证
和物理机一样。
2. 配置操作系统环境
从现在开始,所有操作都可以远程进行。
配置 hosts
写一个 hosts 文件,把所有机器的 IP 和 hostname 都写上去,例如:
1 2 3 4 5 6 7 8 9 10 11
127.0.0.1 localhost 10.42.0.200 m0 10.42.0.210 n0 10.42.0.211 n1 # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters
然后用 scp 命令把这个文件拷贝到所有机器上的
/etc/hosts
文件中,这样以后集群内相互访问就不用写 IP 地址了。禁用 swap
K8S 不允许 swap,所以需要禁用 swap:
1
nano /etc/fstab # 注释掉 swap 的那一行
配置网络
我们后面默认安装的 K8S 使用 iptables 作为网络插件,需要启用
br_netfilter
内核模块:1
nano /etc/modules-load.d/modules.conf # 添加一行:br_netfilter
然后配置
sysctl
:1 2 3 4 5
cat > /etc/sysctl.d/k8s.conf << EOF net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 EOF
我安装的 Ubuntu 22.04 live server 版本没有防火墙,如果有的话要关闭,可以用下面的命令:
1
ufw disable
3 安装 containerd 和 runc
安装 containerd
1 2 3 4 5 6 7 8 9 10
export VERSION="1.7.13" apt install -y libseccomp2 wget wget https://github.com/containerd/containerd/releases/download/v${VERSION}/cri-containerd-cni-${VERSION}-linux-amd64.tar.gz wget https://github.com/containerd/containerd/releases/download/v${VERSION}/cri-containerd-cni-${VERSION}-linux-amd64.tar.gz.sha256sum sha256sum --check cri-containerd-cni-${VERSION}-linux-amd64.tar.gz.sha256sum tar --no-overwrite-dir -C / -xzf cri-containerd-cni-${VERSION}-linux-amd64.tar.gz systemctl daemon-reload systemctl enable containerd
配置 containerd
按我这个教程走,到这里的话需要修改 containerd 的一处默认配置。运行下面的命令生成 containerd 的默认配置文件:
1 2
mkdir -p /etc/containerd/ containerd config default > /etc/containerd/config.toml
然后修改一处:
1 2 3 4
# ... [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true # 原本是 false,不改的话容器会间歇性崩溃 # ...
(可选)配置 containerd 使用网络代理
主要是为了访问镜像仓库,例如 Docker Hub,修改/etc/systemd/system/containerd.service:
1 2 3 4 5 6 7
[Service] # 在这个段落下添加 Environment="http_proxy=http://10.42.0.1:7890" Environment="https_proxy=http://10.42.0.1:7890" Environment="HTTP_PROXY=http://10.42.0.1:7890" Environment="HTTPS_PROXY=http://10.42.0.1:7890" ExecStartPre=-/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd
安装 runc
1 2
wget https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64 install -m 755 runc.amd64 /usr/local/sbin/runc
重启机器
上面的操作都需要重启机器才能生效:
1
reboot
验证 containerd 和 runc
拉取一个 helloworld 镜像运行看看:
1 2
ctr image pull docker.io/library/hello-world:latest ctr run --rm docker.io/library/hello-world:latest hello-world
4 安装 Kubernetes
安装 CNI 插件
这个插件用来使能容器间的网络通讯。
1 2 3
wget https://github.com/containernetworking/plugins/releases/download/v1.4.0/cni-plugins-linux-amd64-v1.4.0.tgz mkdir -p /opt/cni/bin tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.4.0.tgz
下载
kubeadm
1 2 3 4 5 6 7 8 9 10 11
sudo apt-get update # apt-transport-https 可能是一个虚拟包(dummy package);如果是的话,你可以跳过安装这个包 sudo apt-get install -y apt-transport-https ca-certificates curl gpg # 如果 `/etc/apt/keyrings` 目录不存在,则应在 curl 命令之前创建它,请阅读下面的注释。 # sudo mkdir -p -m 755 /etc/apt/keyrings curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg # 此操作会覆盖 /etc/apt/sources.list.d/kubernetes.list 中现存的所有配置。 echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl
5 组建集群
2~4 的步骤需要在所有机器上执行,都成功之后,设定一个机器为 Master,其它两台为 Node。
Master 节点
运行
kubeadm init
成功的话会显示如下的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config Alternatively, if you are the root user, you can run: export KUBECONFIG=/etc/kubernetes/admin.conf You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 172.17.211.1:6443 --token 41as75.eo1kvp6s6osjnevr \ --discovery-token-ca-cert-hash sha256:e1370957613cd3a32232eabe303f4e7ca06aacd77fb06c84046226928f024cd8
注意最后一行,这是用来加入 Node 的命令。
Node 节点
运行
kubeadm join
运行上面打印出来的命令:
1 2
kubeadm join 172.17.211.1:6443 --token 41as75.eo1kvp6s6osjnevr \ --discovery-token-ca-cert-hash sha256:e1370957613cd3a32232eabe303f4e7ca06aacd77fb06c84046226928f024cd8
注意这个命令里的 token 有时限(好像是一个小时?),如果失效了,需要在 Master 生成新的 token,具体怎么做到网上再找资料吧。
完成
如果 kubeadm 运行出错,使用 kubeadm reset
重置集群。
成功后,测试一下组件的集群能不能用。建一个 test.yaml
文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloworld
spec:
replicas: 3
selector:
matchLabels:
app: helloworld
template:
metadata:
labels:
app: helloworld
spec:
containers:
- name: helloworld
image: docker.io/library/hello-world:latest
ports:
- containerPort: 8080
使用 kubectl get pods
查看创建了哪些 Pod,然后使用 kubectl logs <pod_name>
查看 Pod 的输出,最后使用 kubectl delete deployment helloworld
删除这个 Deployment。