微服务版Hello World之k8s集群部署

一直以来我都有一个小小的梦想,做一个微服务版本的 "Hello World"。终于马上要实现了,所以也有了这一系列的文章。目前暂定 3 - 5 篇文章:

  • 部署 k8s 集群
  • 通过 helm 在 k8s 集群上部署 MySQL 应用
  • 实现微服务版本的 Hello World

这是《K8s三部曲》这一列文章(暂定 3 篇)中的第一篇,这篇文档描述了如何在本地部署一个 k8s 的三节点的集群(一个 Master 节点和两个 Worker 节点)。结构如下:

三个环境的节点的配置如下表:

Node CPU Menory Storage
k8s-master 4 Core 8 GB 20 GB
k8s-worker-1 2 Core 6 GB 20 GB
k8s-worker-2 2 Core 6 GB 20 GB

网络配置如下:

Node IP Subnet mark Gateway
k8s-master 10.211.55.10 255.255.255.0 10.211.55.1
k8s-worker-1 10.211.55.11 255.255.255.0 10.211.55.1
k8s-worker-2 10.211.55.12 255.255.255.0 10.211.55.1

其他的,比如 Linux 发行版,我用的是 Ubuntu 24.04.2 LTS 。

环境初始化

首先,三个节点需要做一些初始化的工作。安装更新必要的依赖:

sql 复制代码
sudo apt update && sudo apt upgrade -y
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common

禁用交换分区:

bash 复制代码
# 临时
sudo swapoff -a
# 永久
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# 验证
free -h

配置内核模块和系统参数:

bash 复制代码
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

解释一下这两个内核模块的作用:

  • overlay : Linux 内核的一个网络驱动模块,主要用于创建 overlay 网络,其在 k8s 中的作用如下:

    • 跨节点 Pod 通信:不同节点上的 Pod 可以直接通信
    • 网络隔离:创建虚拟的二层隔离网络
    • IP 地址管理:为每个 Pod 分配独立的 IP 地址
  • br_netfilter:可以使得通过 Linux 网桥(bridge)的流量能够被 iptables 规则处理,其在 k8s 中的作用如下:

    • Service 的实现:kube-proxy 使用 iptables 规则实现 Service 负载均衡
    • 网络策略:NetworkPolicy 通过 iptables 规则控制流量
    • NAT 和端口转发: NodePort、LoadBalancer 等服务类型的实现

配置其他系统参数:

shell 复制代码
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system

部署前检查

在开始之前,必须要检查每一台服务器(虚拟机的)的 MAC 地址、product_uuid 以及 machine-id 是否是唯一的:

shell 复制代码
# 查看 product_uuid
sudo cat /sys/class/dmi/id/product_uuid
# 查看 MAC 地址
ip link
# 查看 machine-id
cat /etc/machine-id

如果发现 machine-id 是一致的,采用如下方式修复:

shell 复制代码
sudo rm /etc/machine-id
sudo rm /var/lib/dbus/machine-id
sudo systemd-machine-id-setup

如果像我一样,是通过 Parallels Desktop 来 Clone 虚拟机,导致 product-ID 一样,那可能要麻烦一点,参考附录。

务必保证 product-ID、Machine-ID、MAC 地址在集群内都是唯一的。

部署 k8s 服务

接下来就开始正式部署 K8s 的服务了。Step By Step,Come on!

安装 container runtime

K8s 支持 Container Runtime Interface(CRI),只要是支实现了 CRI 的 Runtime 都支持。Kubeadmin 默认选择 Container Runtime。

shell 复制代码
# 安装
sudo apt install -y containerd
# 生成默认配置
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 修改配置,启用 SystemdCgroup
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml
# 重启服务
sudo systemctl restart containerd

kubeadm 是官方提供的一种快速初始化 k8s 集群的方式, 本文采用它来初始化集群。

安装 Kubeadm、Kubelet、Kubectl

这三个工具是 K8s 生态系统中最重要的组件,它们的职责如下表所示:

组件 作用 举例说明
kubeadm 集群初始化和管理 比如我要在集群中加入或者移除一个节点
kubelet 节点代理服务 运行在每个节点上的主要代理程序,负责管理节点上的 Pod 和容器
kubectl 集群客户端工具 基于 CLI 的客户端工具,用于和 API 服务器进行通信,管理集群资源

这三个组件安装的节点也不同,如下表所示:

组件 Master Node Worker Node 管理节点/客户端
kubeadm ✅ 必须安装 ✅ 必须安装 ❌ 不需要
kubelet ✅ 必须安装 ✅ 必须安装 ❌ 不需要
kubectl ✅ 必须安装 ⚠️ 可选安装 ✅ 建议安装

接下来就按照上比啊来安装吧,最简单的做法就是在 Master 和 Worker 节点全部安装上:

shell 复制代码
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/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://pkgs.k8s.io/core:/stable:/v1.32/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
sudo systemctl enable --now kubelet

在完成安装之后,通过查看版本号来验证是否安装成功:

初始化 Master 节点

接下来是使用 kubeadm init 命令来初始化 Master 节点。在初始化前,我们需要一份默认的初始化配置,可以通过如下命令输出:

shell 复制代码
kubeadm config print init-defaults

我输出的内容如下,加了注释:

yaml 复制代码
# kubeadm 初始化配置文件 - 详细注释版本
# 基于 kubeadm.k8s.io/v1beta4 API 版本

# ============================================================================
# InitConfiguration - 初始化配置部分
# 用于配置 kubeadm init 命令的行为和初始化过程中的各种参数
# ============================================================================
apiVersion: kubeadm.k8s.io/v1beta4  # kubeadm 配置 API 版本,v1beta4 是较新版本

# Bootstrap Tokens - 引导令牌配置
# 用于 Worker 节点加入集群时的身份验证
bootstrapTokens:
- groups:  # 令牌关联的用户组
  - system:bootstrappers:kubeadm:default-node-token  # 默认节点令牌组,允许节点加入集群
  token: abcdef.0123456789abcdef  # 令牌值,格式:[a-z0-9]{6}.[a-z0-9]{16},用于节点认证
  ttl: 24h0m0s  # 令牌生存时间 (Time To Live),24小时后自动过期
  usages:  # 令牌用途
  - signing  # 用于签名,验证令牌的合法性
  - authentication  # 用于身份验证,允许节点通过此令牌加入集群

kind: InitConfiguration  # 配置类型:初始化配置

# Local API Endpoint - 本地 API 服务器端点配置
# 定义 Master 节点上 API Server 的监听地址和端口
localAPIEndpoint:
  advertiseAddress: 1.2.3.4  # Master 节点对外广播的 IP 地址,需要修改为实际 Master IP
  bindPort: 6443  # API Server 监听端口,Kubernetes 默认端口

# Node Registration - 节点注册配置
# 定义节点如何注册到集群中
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock  # 容器运行时接口 (CRI) Socket 路径
  imagePullPolicy: IfNotPresent  # 镜像拉取策略:如果本地不存在才拉取
  imagePullSerial: true  # 是否串行拉取镜像,true 表示一次只拉取一个镜像
  name: node  # 节点名称,需要修改为实际主机名
  taints: null  # 节点污点,null 表示 Master 节点可以调度 Pod(默认情况下 Master 有 NoSchedule 污点)

# Timeouts - 超时配置
# 定义各种操作的超时时间,防止操作无限期等待
timeouts:
  controlPlaneComponentHealthCheck: 4m0s  # 控制平面组件健康检查超时时间
  discovery: 5m0s  # 服务发现超时时间
  etcdAPICall: 2m0s  # etcd API 调用超时时间
  kubeletHealthCheck: 4m0s  # kubelet 健康检查超时时间
  kubernetesAPICall: 1m0s  # Kubernetes API 调用超时时间
  tlsBootstrap: 5m0s  # TLS 引导超时时间
  upgradeManifests: 5m0s  # 升级清单文件超时时间

---  # YAML 文档分隔符,分隔不同的配置部分

# ============================================================================
# ClusterConfiguration - 集群配置部分
# 用于配置整个 Kubernetes 集群的全局设置
# ============================================================================

# API Server Configuration - API 服务器配置
apiServer: {}  # 空配置,使用默认设置
# 可配置项包括:
# - extraArgs: 额外的命令行参数
# - extraVolumes: 额外的卷挂载
# - certSANs: 证书主题备用名称
# - timeoutForControlPlane: 控制平面超时时间

apiVersion: kubeadm.k8s.io/v1beta4  # 重复声明 API 版本

# Certificate Validity Periods - 证书有效期配置
caCertificateValidityPeriod: 87600h0m0s  # CA 证书有效期:10年 (87600小时)
certificateValidityPeriod: 8760h0m0s  # 其他证书有效期:1年 (8760小时)

# Certificates Directory - 证书存储目录
certificatesDir: /etc/kubernetes/pki  # 集群证书文件存储路径

# Cluster Name - 集群名称
clusterName: kubernetes  # 集群标识名称,用于区分不同的集群

# Controller Manager Configuration - 控制器管理器配置
controllerManager: {}  # 空配置,使用默认设置
# 可配置项包括:
# - extraArgs: 额外的命令行参数
# - extraVolumes: 额外的卷挂载

# DNS Configuration - DNS 配置
dns: {}  # 空配置,使用默认 CoreDNS 设置
# 可配置项包括:
# - type: DNS 服务类型 (CoreDNS)
# - imageRepository: DNS 镜像仓库
# - imageTag: DNS 镜像标签

# Encryption Algorithm - 加密算法
encryptionAlgorithm: RSA-2048  # 证书加密算法,RSA-2048 位

# etcd Configuration - etcd 数据库配置
etcd:
  local:  # 本地 etcd 配置(非外部 etcd 集群)
    dataDir: /var/lib/etcd  # etcd 数据存储目录

# Image Repository - 镜像仓库
imageRepository: registry.k8s.io  # Kubernetes 组件镜像仓库地址

kind: ClusterConfiguration  # 配置类型:集群配置

# Kubernetes Version - Kubernetes 版本
kubernetesVersion: 1.32.0  # 要安装的 Kubernetes 版本

# Networking Configuration - 网络配置
networking:
  dnsDomain: cluster.local  # 集群内部 DNS 域名后缀
  serviceSubnet: 10.96.0.0/12  # Service 网络 CIDR,用于 ClusterIP 分配
  # 注意:缺少 podSubnet 配置,需要添加 Pod 网络 CIDR

# Proxy Configuration - 代理配置
proxy: {}  # 空配置,使用默认 kube-proxy 设置
# 可配置项包括:
# - mode: 代理模式 (iptables, ipvs)
# - config: 代理配置参数

# Scheduler Configuration - 调度器配置
scheduler: {}  # 空配置,使用默认调度器设置
# 可配置项包括:
# - extraArgs: 额外的命令行参数
# - extraVolumes: 额外的卷挂载

上面的内容很多,着重修改下面这几项配置就行:

配置项目 描述 如何获取
localAPIEndpoint.advertiseAddress 修改为实际的 Master 节点 IP 通过 ip add show 命令查看
nodeRegistration.name 修改为 Master 节点的主机名 通过 hostname 命令查看
networking.podSubnet 定义集群内 Pod 可用的 IP 范围(CIDR 网段) 例如 10.244.0.0/16

另外添加如下配置:

yaml 复制代码
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  imagePullPolicy: IfNotPresent
  imagePullSerial: true
  name: 你的主机名
  taints: null
  # 添加下面两行配置
	kubeletExtraArgs:
	- name: "cgroup-driver"
	  value: "systemd"
	- name: "container-runtime-endpoint"
	  value: "unix:///var/run/containerd/containerd.sock"

配置完了之后,执行下面的命令:

shell 复制代码
sudo kubeadm init --config kubeadm-init-defaults.yaml

如果你看到类似如下输出,则表明初始化成功了:

那么按照提示进行下一步:

bash 复制代码
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 如果你是 root 用户的话
export KUBECONFIG=/etc/kubernetes/admin.conf

然后执行如下命令,验证是否初始化成功:

安装网络插件

接下来安装网络插件,应用如下配置文件:

shell 复制代码
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

如果看到如下输出,则表明没有问题:

shell 复制代码
namespace/kube-flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

然后进一步验证 pod 已经 Running:

shell 复制代码
$ kubectl get pods -n kube-flannel
NAME                    READY   STATUS    RESTARTS   AGE
kube-flannel-ds-5zzvm   1/1     Running   0          110s

加入 Worker 节点

接下来,就开始初始化 Worker 节点了。首先通过如下命令生成 join 的命令,包含了鉴权的 token:

shell 复制代码
$ kubeadm token create --print-join-command
kubeadm join 10.211.55.10:6443 --token 4tg13t.14co8uefbx6jdjr8 --discovery-token-ca-cert-hash sha256:88d916c90ea239f3f6a369dcbc303c7ebd435fccb12707c1e13087d23dff8678

确保 Worker 节点的服务以及防火墙状态都正常:

shell 复制代码
sudo systemctl status containerd
# 先关闭
sudo systemctl stop kubelet
sudo ufw status

然后执行 kubeadm join 命令,直接复制之前通过 kubeadm token create 生成的命令就可以。如果出现如下错误:

需要关闭 Swap 以及启用 ip forward:

shell 复制代码
# 临时
sudo sysctl -w net.ipv4.ip_forward=1
# 永久配置
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
# 生效
sudo sysctl -p
# 验证输出是否为 1
cat /proc/sys/net/ipv4/ip_forward

# 临时
sudo swapoff -a
# 永久配置
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# 验证输出 Swap 是否全部为 0
free -h
               total        used        free      shared  buff/cache   available
Mem:           3.8Gi       716Mi       1.9Gi        33Mi       1.4Gi       3.1Gi
Swap:             0B          0B          0B

看到类似如下输出,则证明已经 Joined 了集群:

最后, Worker 2 节点也执行相同的步骤即可。通过在 Master 节点上运行 kubectl get nodes 可以查看所有节点的状态:

shell 复制代码
$ kubectl get nodes
NAME           STATUS   ROLES           AGE     VERSION
k8s-master     Ready    control-plane   29m     v1.32.5
k8s-worker-1   Ready    <none>          2m55s   v1.32.5
k8s-worker-2   Ready    <none>          29s     v1.32.5

来一张所有集群初始化成功的全家福:

总结

这篇文章从 0 到 1 完成了 K8s 的三节点的搭建,对于学习开发测试而言就已经足够了。但是如果是生产环境的话可能需要更多的节点,从小规模到大规模可能需要 3 到 5 个 Master 节点,也对应更多的 Worker 节点。

整个搭建的过程,虽然步骤比较多,中间也可能会出现一些小问题。但是使用 kubeadm 也不算复杂。这个过程和其他分布式应用都差不多。耐下心,一步一步来,遇到问题解决问题就行了。

附录:Parallels Desktop 中 VM 如何重新生成 product-ID

在日常的开发中,经常需要使用虚拟机或者容器,或者在虚拟机中部署容器。我现在使用的是 MacBook Pro,使用 M4 Pro 芯片。所以虚拟机使用 Parallels Desktop,能够保证最少的性能损耗。

我在部署 K8s 集群的过程中,Clone 了几台 VM,但是发现这几台机器的 product-id 是一致的,而 K8s 集群通过这个 product-id 来区分不同的机器。

但是很遗憾的是,没有办法通过虚拟机中的命令行来重新生成 product-id。通过查阅官方文档,发现了如下的说明:

可以通过 Unregister 后在此 Register ,附加 --regenerate-src-uuid 来重新生成 product ID。

具体过程如下:

bash 复制代码
# 假设我的虚拟机名称为 "K8s-Master"
# 首先需要查找起 Path
prlctl list -a -i "K8s-Master" | grep "Home:"
# 上面命令输出: Home: /Users/user/Parallels/K8s-Master.pvm/
# Unregister
prlctl unregister "K8s-Master"
# Re-Register
prlctl register "/Users/sujinzhi/Parallels/K8s-Master.pvm/" --regenerate-src-uuid

然后重新启动 VM 后查看重新生成 product-ID:

bash 复制代码
sudo cat /sys/class/dmi/id/product_uuid
[sudo] password for parallels: 
dddcef29-de5b-4244-8c66-e285f1d41d87

主要注意,Re-Register 之后,例如端口转发之类的配置会删除,需要重新配置。

话说,我本来是问 AI 如何来解决这个问题的,AI 的回答告诉了我可以通过 prlctl 命令来重新生成,只是它搞错了具体的子命令和参数。看起来,在 AI 大行其道的今天,还是要保留自己查阅文档的能力的。

相关推荐
河码匠4 分钟前
Kubernests YAML 详细之卷(PV、PVC、StorageClass)
云原生·容器·kubernetes
LilySesy4 分钟前
【案例总结】震撼巨作——SAP连接钉钉WEBHOOK
运维·人工智能·ai·钉钉·sap·abap·webhook
仰泳之鹅5 分钟前
【MQTT】详解MQTT协议
运维·服务器·网络
wanhengidc36 分钟前
BGP服务器网络安全如何
运维·服务器·web安全
码上上班41 分钟前
k8s控制器,daemonset
云原生·容器·kubernetes
码上上班44 分钟前
k8s中安装metrics,实现hpa
容器·kubernetes·excel
云飞云共享云桌面1 小时前
精密机械制造工厂10个SolidWorks研发共享一台服务器设计办公
运维·服务器·网络·云计算·电脑
babytiger1 小时前
Windows 11 下格式化 Linux 分区 TF 卡(DiskPart 完整教程)
linux·运维·windows
renhongxia11 小时前
生产线数智化质量可靠性管控与安全风险感知
运维·人工智能·安全·机器学习·架构·自动化
H_老邪1 小时前
Docker 学习之路-从入门到放弃:2
学习·docker·容器