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

421 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kubernetes
## 安装 Kubernetes
### 更新系统并安装依赖
```bash
# 更新系统并安装依赖
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
```bash
# 清理旧的配置
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
```
### 将镜像文件保存到指定的路径(可选)
```bash
# 停止服务
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
```
### 配置镜像加速
```bash
# 注意:配置镜像加速器
# 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 集群
```bash
# 拉取镜像
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
```
### 设置集群单节点可以使用
```bash
# 重要:设置集群单节点可以使用,否则服务由于不能分配到资源,不能正常启动
kubectl describe node arno | grep Taints
# 你可以直接使用節點的角色來移除,或者指定節點名稱
# --all 會對所有擁有該角色的節點生效,在單節點環境中很方便
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
# 再次检查
kubectl describe node arno | grep Taints
```
### 测试功能
```bash
# 测试
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 以指定组的权限来运行
```bash
# 让 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 的区别
`Deployment``StatefulSet``DaemonSet` 是三种最常用的应用部署控制器,但它们的设计目标和适用场景完全不同。
简单来说:
- **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 使用所在节点的网络,通常配置 `hostPort``hostNetwork`。 |
| **存储** | 通常使用共享存储(如 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)<br>- API 网关<br>- 无状态的微服务 | - 数据库 (MySQL, PostgreSQL, MongoDB)<br>- 消息队列 (Kafka, RabbitMQ)<br>- 分布式文件系统 (Zookeeper) | - 日志收集器 (Fluentd, Logstash)<br>- 监控代理 (Prometheus Node Exporter, Datadog Agent)<br>- 网络插件 (Calico, Flannel)<br>- 存储插件 (Ceph, GlusterFS) |
---
### 如何选择?
你可以通过问自己以下几个问题来决定使用哪一个:
- **我的应用需要在集群的每个节点上都运行一个实例吗?**
- **是** -> 使用 **DaemonSet**。 (例如,为了从每个节点收集日志)
- **我的应用需要稳定的网络标识(固定的DNS名)或每个实例需要独立的持久化数据吗?**
- **是** -> 使用 **StatefulSet**。 (例如,部署一个主从复制的数据库,每个节点的数据都不能丢失)
- **以上都不是?我的应用是无状态的,可以随意创建和销毁,而不用担心数据丢失或实例身份吗?**
- **是** -> 使用 **Deployment**。 (这是最常见的情况,例如部署一个网站后端服务)
掌握这三者的区别,你就掌握了在 Kubernetes 中部署不同类型应用的核心武器。