Files
tech/知识/Kubernetes.md
T
arno 68e22c5386 docs: 初始化技术知识库和资料目录
- 添加金鹏、containerd、声纹模型等技术知识文档
- 添加相关参考资料和图片素材
2026-04-09 09:23:16 +08:00

18 KiB
Raw Blame History

Kubernetes

安装 Kubernetes

更新系统并安装依赖

# 更新系统并安装依赖
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg

# 临时关闭
sudo swapoff -a

# 永久禁用:编辑 /etc/fstab 文件,注释掉 swap 相关的行
# 找到类似下面这行,在行首加上 #
# /swap.img      none    swap    sw      0       0
sudo sed -i 's/\/swap.img/#\/swap.img/g' /etc/fstab

# 关闭防火墙(生产环境建议配置规则)
sudo ufw disable

# 禁用 SELinux(如已安装)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

# 配置主机名和 hosts 文件 (可选,但强烈推荐)
sudo hostnamectl set-hostname k8s-master

# 配置系统参数
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# 设置网络参数
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

安装 Kubernetes 依赖的 containerd

# 清理旧的配置
sudo rm /etc/apt/sources.list.d/kubernetes.list

# 创建用于存放密钥的目录
sudo mkdir -p /etc/apt/keyrings

# 下载阿里云的 Kubernetes GPG 密钥并保存
curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg

# 添加 Kubernetes 的阿里云软件源,并指定使用我们刚刚下载的密钥
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list > /dev/null

# 安装kubelet/kubeadm/kubectl
sudo apt update

# 取消保持状态
sudo apt-mark unhold kubelet kubeadm kubectl

# 安装最新版本
sudo apt install -y kubelet kubeadm kubectl

# 锁定版本(避免自动升级)
sudo apt-mark hold kubelet kubeadm kubectl

将镜像文件保存到指定的路径(可选)

# 停止服务
sudo systemctl stop containerd
sudo systemctl stop kubelet

# Generate default containerd config
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml

# Edit the config to enable SystemdCgroup
sudo mkdir -p /data/containerd/root

# 修改 containerd 服务的默认存储路径
sudo sed -i 's/root = "\/var\/lib\/containerd"/root = "\/data\/containerd\/root"/' /etc/containerd/config.toml

# 迁移现有数据
sudo rsync -avz /var/lib/containerd/ /data/containerd/root/
sudo mv /var/lib/containerd /var/lib/containerd-bak

sudo systemctl daemon-reload
sudo systemctl start containerd
sudo systemctl enable containerd
sudo systemctl start kubelet
sudo systemctl status containerd

配置镜像加速

# 注意:配置镜像加速器
# k8s、crictl 可以使用 config.toml 中的镜像配置
# ctr 需要指定 --hosts-dir
# config_path 和 plugins."io.containerd.grpc.v1.cri".registry.mirrors 是互斥的,只能配置一个,优先使用 config_path

# 配置镜像加速器配置文件路径
#   [plugins."io.containerd.grpc.v1.cri".registry]
#     config_path = "
#     ...
#      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
#        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
#          endpoint = ["https://docker.m.daocloud.io"]

# 启用 SystemdCgroup
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# 配置镜像加速器配置文件路径
sudo sed -i 's/registry.k8s.io\/pause:3.8/registry.aliyuncs.com\/google_containers\/pause:3.9/' /etc/containerd/config.toml

# 创建配置文件
sudo mkdir -p /etc/containerd/certs.d/docker.io
sudo tee /etc/containerd/certs.d/docker.io/hosts.toml << EOF
server = "https://docker.io"

[host."https://docker.m.daocloud.io"]
  capabilities = ["pull", "resolve"]

[host."https://docker.m.daocloud.io/library"]
  capabilities = ["pull", "resolve"] 
EOF
sudo mkdir -p /etc/containerd/certs.d/registry.k8s.io
sudo tee /etc/containerd/certs.d/registry.k8s.io/hosts.toml << EOF
server = "https://registry.k8s.io"

[host."https://k8s.m.daocloud.io"]
  capabilities = ["pull", "resolve"]
EOF

# 在 config.toml 中启用镜像加速器
# 源站 --> 替换为
# https://github.com/DaoCloud/public-image-mirror
# docker.elastic.co --> elastic.m.daocloud.io
# docker.io --> docker.m.daocloud.io
# gcr.io --> gcr.m.daocloud.io
# ghcr.io --> ghcr.m.daocloud.io
# k8s.gcr.io --> k8s-gcr.m.daocloud.io # k8s.gcr.io 已被迁移到 registry.k8s.io
# registry.k8s.io --> k8s.m.daocloud.io
# mcr.microsoft.com --> mcr.m.daocloud.io
# nvcr.io --> nvcr.m.daocloud.io
# quay.io --> quay.m.daocloud.io
# registry.ollama.ai --> ollama.m.daocloud.io # 实验内测中
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.elastic.co"]
    endpoint = ["https://elastic.m.daocloud.io"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
    endpoint = ["https://docker.m.daocloud.io"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io/library"]
    endpoint = ["https://docker.m.daocloud.io/library"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
    endpoint = ["https://gcr.m.daocloud.io"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]
    endpoint = ["https://ghcr.m.daocloud.io"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
    endpoint = ["https://k8s-gcr.m.daocloud.io"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
    endpoint = ["https://k8s.m.daocloud.io"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."mcr.microsoft.com"]
    endpoint = ["https://mcr.m.daocloud.io"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."nvcr.io"]
    endpoint = ["https://nvcr.m.daocloud.io"]

  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
    endpoint = ["https://quay.m.daocloud.io"]

# 检查配置是否生效
sudo systemctl restart containerd
sudo systemctl status containerd
sudo containerd config dump | grep -A 5 'plugins."io.containerd.grpc.v1.cri".registry'
sudo ctr plugins ls | grep -i cri
# io.containerd.grpc.v1    cri    linux/amd64    ok

初始化 Kubernetes 集群

# 拉取镜像
sudo kubeadm config images pull \
  --image-repository=registry.aliyuncs.com/google_containers \
  --kubernetes-version=v1.28.15

sudo ctr -n k8s.io image ls

# # 拉取一个测试镜像
# sudo ctr images pull --hosts-dir "/etc/containerd/certs.d" docker.io/calico/cni:v3.28.0
# sudo ctr -n k8s.io image pull --hosts-dir "/etc/containerd/certs.d" registry.k8s.io/pause:3.9
# # 检查新目录的磁盘使用情况
# sudo du -sh /data/containerd

# Restart containerd
sudo systemctl restart containerd

sudo ctr version

# 通过阿里云获取镜像文件
sudo ctr images pull registry.aliyuncs.com/google_containers/coredns:v1.10.1
sudo ctr images tag registry.aliyuncs.com/google_containers/coredns:v1.10.1 registry.k8s.io/coredns/coredns:v1.10.1

sudo ctr images pull registry.aliyuncs.com/google_containers/etcd:3.5.9-0
sudo ctr images tag registry.aliyuncs.com/google_containers/etcd:3.5.9-0 registry.k8s.io/etcd:3.5.9-0

sudo ctr images pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.15
sudo ctr images tag registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.15 registry.k8s.io/kube-apiserver:v1.28.15

sudo ctr images pull registry.aliyuncs.com/google_containers/kube-controller-manager:v1.28.15
sudo ctr images tag registry.aliyuncs.com/google_containers/kube-controller-manager:v1.28.15 registry.k8s.io/kube-controller-manager:v1.28.15

sudo ctr images pull registry.aliyuncs.com/google_containers/kube-proxy:v1.28.15
sudo ctr images tag registry.aliyuncs.com/google_containers/kube-proxy:v1.28.15 registry.k8s.io/kube-proxy:v1.28.15

sudo ctr images pull registry.aliyuncs.com/google_containers/kube-scheduler:v1.28.15
sudo ctr images tag registry.aliyuncs.com/google_containers/kube-scheduler:v1.28.15 registry.k8s.io/kube-scheduler:v1.28.15

sudo ctr images pull registry.aliyuncs.com/google_containers/registry.k8s.io/pause:3.9
sudo ctr images tag registry.aliyuncs.com/google_containers/registry.k8s.io/pause:3.9 registry.k8s.io/pause:3.9

#获取本机内网IP
ip addr show eth0
# 192.168.0.196

# 初始化集群
sudo kubeadm init \
  --apiserver-advertise-address=192.168.0.196 \
  --image-repository=registry.aliyuncs.com/google_containers \
  --pod-network-cidr=192.168.0.0/16 \
  --kubernetes-version=v1.28.15

# 配置kubectl(普通用户)
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 设置环境变量(永久设置)
echo "export KUBECONFIG=$HOME/.kube/config" >> ~/.bashrc
source ~/.bashrc

# 检查节点状态
kubectl get nodes
kubectl get pods -A
kubectl get pods --all-namespaces
# 如果你還沒有安裝 CNI,你很可能會看到 coredns 的 Pods 處於 Pending (等待中) 狀態。
kubectl cluster-info

# Then install a CNI plugin (e.g., Calico):
sudo ctr images pull --hosts-dir "/etc/containerd/certs.d" docker.io/calico/cni:v3.27.0
sudo ctr images pull --hosts-dir "/etc/containerd/certs.d" docker.io/calico/node:v3.27.0
sudo ctr images pull --hosts-dir "/etc/containerd/certs.d" docker.io/calico/kube-controllers:v3.27.0

# 安装 Calico 网络插件
# 方式一:
wget https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml
wget https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/custom-resources.yaml

kubectl create -f ./tigera-operator.yaml
kubectl create -f ./custom-resources.yaml

# 方式二:
wget https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
kubectl apply -f ./calico.yaml

# 查看 Calico 插件的 Pods 是否正常运行
watch -n 1 kubectl get pods -A
kubectl describe pod calico-node-4q9kh -n kube-system

# 配置 crictl 让其使用 containerd 作为运行时
sudo tee /etc/crictl.yaml << EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF

# 检查配置是否生效
sudo crictl info
sudo crictl pull docker.io/library/mysql:8
sudo crictl images

# 通过 crictl 获取镜像文件
sudo crictl pull registry.k8s.io/coredns/coredns:v1.10.1
sudo crictl pull registry.k8s.io/etcd:3.5.9-0
sudo crictl pull registry.k8s.io/kube-apiserver:v1.28.15
sudo crictl pull registry.k8s.io/kube-controller-manager:v1.28.15
sudo crictl pull registry.k8s.io/kube-proxy:v1.28.15
sudo crictl pull registry.k8s.io/kube-scheduler:v1.28.15
sudo crictl pull registry.k8s.io/pause:3.9

设置集群单节点可以使用

# 重要:设置集群单节点可以使用,否则服务由于不能分配到资源,不能正常启动
kubectl describe node arno | grep Taints
# 你可以直接使用節點的角色來移除,或者指定節點名稱
# --all 會對所有擁有該角色的節點生效,在單節點環境中很方便
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
# 再次检查
kubectl describe node arno | grep Taints

测试功能

# 测试
kubectl create deployment nginx-test --image=nginx
kubectl get pods
kubectl expose deployment nginx-test --type=NodePort --port=80
kubectl get services
curl http://localhost:30209

修改 containerd 以指定组的权限来运行

# 让 containerd 以指定组的权限来运行
sudo groupadd containerd
sudo usermod -aG containerd $USER
getent group containerd
# containerd:x:1002:arno

# 修改 /etc/containerd/config.toml 以下内容
[grpc]
  address = "/run/containerd/containerd.sock"
  uid = 0
  gid = 1002

# 重启服务
sudo systemctl restart containerd

# 查看是否生效
newgrp containerd
ls -l /run/containerd/containerd.sock
crictl images

Deployment、StatefulSet 和 DaemonSet 的区别

DeploymentStatefulSetDaemonSet 是三种最常用的应用部署控制器,但它们的设计目标和适用场景完全不同。

简单来说:

  • Deployment:用于部署无状态应用,核心是“随意扩缩、随意替换”。
  • StatefulSet:用于部署有状态应用,核心是“身份唯一、顺序稳定”。
  • DaemonSet:用于确保每个节点上都运行一个副本,核心是“节点覆盖、常驻运行”。

下面我们用一个更生动的比喻,然后进行详细的技术对比。

核心比喻:公司员工安排

想象一下你要为一个新公司安排三种不同类型的员工:

  • Deployment (客服团队)

    • 特点:团队里有10个客服人员。他们每个人都做完全一样的工作,没有名字,只有工号(比如 客服-A, 客服-B)。客户打进电话,随便接给谁都行。
    • 扩缩容:业务忙了,老板说:“客服加到20人!” 于是就新招10个一模一样的人。业务闲了,就随便裁掉几个,剩下的继续工作,不受影响。
    • 替换:某个客服(Pod)生病请假了(挂了),公司会立刻招一个新人来顶替他的位置,保证总人数不变。这个新人是全新的,和之前那个没任何关系。
    • 核心:员工之间可随意替换,不关心具体是哪个人,只关心总人数。
  • StatefulSet (管理层团队)

    • 特点:公司有CEO、CTO、CFO三位高管。他们每个人都有唯一的身份和职责。CEO的位子只能是CEO,不能随便换成CTO。
    • 身份和顺序:他们的职位是固定的 (ceo-0, cto-1, cfo-2)。招聘时必须按顺序来:先招CEO,CEO到位了再招CTO,最后招CFO。离职时也得按相反顺序来,保证权力平稳交接。
    • 专属资源:每个人都有自己专属的办公室和电脑(稳定的存储和网络标识)。即使CEO离职了,新来的CEO也会接管原来的办公室和电脑,里面的文件资料都在。
    • 核心:每个成员身份唯一、不可替代,并且有严格的顺序和专属资源。
  • DaemonSet (安保/保洁团队)

    • 特点:公司有3层楼,老板要求每一层楼都必须有一个保安和一个保洁员
    • 节点绑定:公司新租了一层楼(增加一个Node),就必须自动为这层楼配一个保安和保洁(自动部署一个Pod)。如果退租一层楼(移除一个Node),这层楼的保安和保洁也就自动撤离了。
    • 数量:团队总人数不固定,取决于楼层(Node)的数量。你不能说“我要5个保安”,你只能说“每层楼都要有保安”。
    • 核心:确保每个单元(Node)上都有一个副本,用于执行该单元的特定任务(如监控、日志收集)。

详细技术对比表

特性 Deployment StatefulSet DaemonSet
核心用途 管理无状态应用。 管理有状态应用。 在集群中每个(或部分)节点上运行一个 Pod 副本。
Pod 身份 Pod 是可互换的(Fungible,没有唯一身份。Pod 名称是随机的,如 myapp-deploy-random-string Pod 拥有稳定且唯一的身份。Pod 名称是有序且可预测的,如 web-0, web-1 Pod 名称包含节点名,如 fluentd-abc12,但身份不重要,重要的是它所在的节点。
网络 所有 Pod 共享一个 Service IP。Pod 自身的 IP 和主机名在重启后会改变。 每个 Pod 拥有稳定的、唯一的网络标识DNS 条目),如 web-0.svc.cluster.local。重启后不变。 Pod 使用所在节点的网络,通常配置 hostPorthostNetwork
存储 通常使用共享存储(如 ReadWriteMany)或不使用持久化存储。所有副本共享同一个 PVC。 每个 Pod 副本拥有自己独立的、持久化的存储卷(PVC。Pod web-0 始终绑定 pvc-web-0 通常直接访问节点的文件系统,或使用 hostPath 卷来读写节点上的数据。
伸缩与部署 并行、无序。可以一次性创建或删除多个副本。支持滚动更新(Rolling Update)。 有序、串行。部署、扩容、缩容、更新都按 Pod 序号(0, 1, 2...顺序执行 自动。当一个新节点加入集群时,DaemonSet 会自动在该节点上部署一个 Pod。节点移除时,Pod 也被回收。
replicas 字段 需要。用户明确指定需要运行的 Pod 数量。 需要。用户明确指定需要运行的 Pod 数量。 不需要。Pod 的数量由匹配 nodeSelector 的节点数量决定。
适用场景 - Web 服务器 (Nginx, Apache)
- API 网关
- 无状态的微服务
- 数据库 (MySQL, PostgreSQL, MongoDB)
- 消息队列 (Kafka, RabbitMQ)
- 分布式文件系统 (Zookeeper)
- 日志收集器 (Fluentd, Logstash)
- 监控代理 (Prometheus Node Exporter, Datadog Agent)
- 网络插件 (Calico, Flannel)
- 存储插件 (Ceph, GlusterFS)

如何选择?

你可以通过问自己以下几个问题来决定使用哪一个:

  • 我的应用需要在集群的每个节点上都运行一个实例吗?

    • -> 使用 DaemonSet。 (例如,为了从每个节点收集日志)
  • 我的应用需要稳定的网络标识(固定的DNS名)或每个实例需要独立的持久化数据吗?

    • -> 使用 StatefulSet。 (例如,部署一个主从复制的数据库,每个节点的数据都不能丢失)
  • 以上都不是?我的应用是无状态的,可以随意创建和销毁,而不用担心数据丢失或实例身份吗?

    • -> 使用 Deployment。 (这是最常见的情况,例如部署一个网站后端服务)

掌握这三者的区别,你就掌握了在 Kubernetes 中部署不同类型应用的核心武器。