微服务版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 大行其道的今天,还是要保留自己查阅文档的能力的。

相关推荐
伤不起bb39 分钟前
NoSQL 之 Redis 配置与优化
linux·运维·数据库·redis·nosql
广东数字化转型1 小时前
nginx怎么使用nginx-rtmp-module模块实现直播间功能
linux·运维·nginx
love530love1 小时前
【笔记】在 MSYS2(MINGW64)中正确安装 Rust
运维·开发语言·人工智能·windows·笔记·python·rust
啵啵学习1 小时前
Linux 里 su 和 sudo 命令这两个有什么不一样?
linux·运维·服务器·单片机·ubuntu·centos·嵌入式
数字芯片实验室2 小时前
寄存器模型生成:从手工到自动化
运维·自动化
云道轩3 小时前
llm-d:面向Kubernetes的高性能分布式LLM推理框架
分布式·容器·kubernetes
冰橙子id3 小时前
linux——磁盘和文件系统管理
linux·运维·服务器
咕噜企业签名分发-淼淼3 小时前
应用app的服务器如何增加高并发
运维·服务器
b***25113 小时前
18650锂电池组点焊机:高效组装锂电池的关键工具|比斯特自动化
运维·自动化
leagsoft_10033 小时前
联软NSPM自动化策略管理 助力上交所加速国产化替代提升运维效率
运维·网络·自动化