五、“笨办法” 学 K8s:亲手组装一个 Kubernetes 节点,彻底理解集群启动
《手动搭建单节点K8s集群:从零到精通的实践指南》 摘要:本文详细介绍了手动搭建单节点Kubernetes集群的全过程,强调通过"笨办法"深入理解K8s核心组件协作原理。内容包括:环境准备(系统配置、依赖安装)、五大核心步骤(二进制组件安装、TLS证书生成、containerd配置、K8s组件启动、Flannel网络部署),以及常见问题排查方法。重点讲解了kubelet、api
前言:为什么要 “手动搭” K8s?
你可能听过 kubeadm init 一行命令就能拉起 K8s 集群,甚至 Minikube 能一键部署测试环境。但这些自动化工具就像 “黑盒”—— 它们帮你省去了配置细节,却也让你错过了最核心的 “组件协作逻辑”。
手动搭建的价值在于:
- 看清
kube-apiserver、kubelet、containerd之间的依赖关系 - 理解证书、配置文件、启动参数的作用(后续排障的核心)
- 摆脱 “只会用工具,不懂原理” 的尴尬
这篇文章会带你用 “笨办法” 从零搭建单节点 K8s,全程不依赖任何自动化脚本,每一步都讲清 “为什么” 和 “怎么做”。
前置准备:环境与前提条件
🔧 硬件配置(最低要求)
| 资源类型 | 配置要求 | 说明 |
|---|---|---|
| CPU | 2 核及以上 | K8s 核心组件(apiserver、etcd)需要独立 CPU |
| 内存 | 4GB 及以上 | 单节点最小内存,否则组件会因 OOM 崩溃 |
| 存储 | 20GB 空闲空间 | 用于存放镜像、日志、配置文件 |
| 操作系统 | CentOS 7.9 / Ubuntu 20.04 | 推荐这两个稳定版本,兼容性最好 |
🚫 环境预处理(必做!)
手动搭建的坑大多来自环境冲突,先执行以下命令清理环境:
bash
# 1. 关闭防火墙(生产环境需配置规则,测试环境直接关闭)
systemctl stop firewalld && systemctl disable firewalld
# 2. 关闭SELinux(避免权限拦截)
setenforce 0 && sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
# 3. 关闭Swap(K8s要求禁用Swap,否则会影响调度)
swapoff -a && sed -i '/swap/s/^/#/' /etc/fstab
# 4. 配置内核参数(开启IP转发和模块)
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
sysctl --system # 生效配置
# 5. 安装依赖工具
yum install -y wget curl vim tar socat conntrack # CentOS
# apt install -y wget curl vim tar socat conntrack # Ubuntu
正文:5 步手动搭建单节点 K8s
🔍 先看整体架构(一张图看懂组件关系)
(提示:核心组件协作流程:kubelet → 通过bootstrap向apiserver注册 → apiserver与etcd交互存储数据 → kube-proxy配置网络规则 → Flannel提供 Pod 网络)
步骤 1:安装核心二进制组件
K8s 单节点需要的核心组件:kubelet(节点代理)、kube-apiserver(集群入口)、kube-controller-manager(控制器)、kube-scheduler(调度器)、kube-proxy(网络代理)、containerd(容器运行时)、kubectl(命令行工具)。
1.1 下载二进制文件(指定版本,避免兼容性问题)
bash
# 创建工作目录
mkdir -p /opt/k8s/{bin,cfg,ssl,logs} && cd /opt/k8s
# 下载K8s组件(v1.24.0,稳定版)
wget https://dl.k8s.io/v1.24.0/kubernetes-server-linux-amd64.tar.gz
tar zxf kubernetes-server-linux-amd64.tar.gz
# 复制核心组件到/usr/local/bin(系统PATH路径)
cd kubernetes/server/bin
cp kubelet kube-apiserver kube-controller-manager kube-scheduler kube-proxy kubectl /usr/local/bin/
# 下载containerd(v1.6.6,与K8s 1.24兼容)
wget https://github.com/containerd/containerd/releases/download/v1.6.6/containerd-1.6.6-linux-amd64.tar.gz
tar zxf containerd-1.6.6-linux-amd64.tar.gz -C /usr/local/
1.2 验证组件安装
bash
kubelet --version # 输出:Kubernetes v1.24.0
containerd --version # 输出:containerd github.com/containerd/containerd v1.6.6 ...
步骤 2:生成 TLS 安全证书(集群通信加密)
K8s 组件间通信需要 TLS 加密,这里用cfssl工具生成证书(最常用的 K8s 证书工具)。
2.1 安装 cfssl 工具
bash
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl_1.6.3_linux_amd64 -O /usr/local/bin/cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssljson_1.6.3_linux_amd64 -O /usr/local/bin/cfssljson
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl-certinfo_1.6.3_linux_amd64 -O /usr/local/bin/cfssl-certinfo
chmod +x /usr/local/bin/cfssl*
2.2 生成 CA 根证书(所有证书的签发者)
bash
# 创建证书目录
mkdir -p /opt/k8s/ssl && cd /opt/k8s/ssl
# 编写CA配置文件
cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "8760h" # 证书有效期1年
},
"profiles": {
"kubernetes": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "8760h"
}
}
}
}
EOF
# 编写CA证书请求文件
cat > ca-csr.json << EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "k8s",
"OU": "study"
}
]
}
EOF
# 生成CA证书和私钥
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2.3 生成 apiserver 证书(核心组件通信证书)
bash
# 编写apiserver证书请求文件(替换IP为你的节点IP)
NODE_IP="192.168.1.100" # 改成你的服务器IP
cat > apiserver-csr.json << EOF
{
"CN": "kube-apiserver",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "k8s",
"OU": "study"
}
],
"hosts": [
"127.0.0.1",
"${NODE_IP}",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster.local"
]
}
EOF
# 生成apiserver证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes apiserver-csr.json | cfssljson -bare apiserver
2.4 证书验证(确保生成成功)
bash
ls /opt/k8s/ssl # 应包含:ca.pem、ca-key.pem、apiserver.pem、apiserver-key.pem等文件
步骤 3:配置 containerd(容器运行时)
K8s 从 1.24 版本开始不再默认依赖 Docker,而是直接使用 containerd 作为容器运行时,需要配置 CRI(容器运行时接口)。
3.1 生成 containerd 默认配置
bash
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
3.2 修改关键配置(3 处核心修改)
bash
vim /etc/containerd/config.toml
# 1. 配置镜像仓库镜像(加速拉取K8s镜像)
找到 [plugins."io.containerd.grpc.v1.cri".registry.mirrors],添加:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://registry.docker-cn.com", "https://hub-mirror.c.163.com"]
# 2. 配置cgroup驱动为systemd(与K8s兼容)
找到 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options],修改:
SystemdCgroup = true # 默认为false,改为true
# 3. 配置sandbox镜像(K8s的Pause容器,版本要与K8s匹配)
找到 [plugins."io.containerd.grpc.v1.cri".sandbox_image],修改:
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.7" # 替换为国内镜像
3.3 启动 containerd 并设置开机自启
bash
# 创建systemd服务文件
cat > /etc/systemd/system/containerd.service << EOF
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target
[Service]
ExecStart=/usr/local/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
[Install]
WantedBy=multi-user.target
EOF
# 启动服务
systemctl daemon-reload
systemctl start containerd
systemctl enable containerd
# 验证containerd状态
systemctl status containerd # 应显示active (running)
步骤 4:启动 K8s 核心组件(apiserver + kubelet 等)
4.1 启动 kube-apiserver(集群 “大脑”)
bash
# 创建apiserver配置文件
cat > /etc/kubernetes/apiserver.conf << EOF
KUBE_APISERVER_OPTS="--logtostderr=false \
--v=2 \
--log-dir=/opt/k8s/logs \
--bind-address=192.168.1.100 \ # 你的节点IP
--secure-port=6443 \
--insecure-port=0 \
--advertise-address=192.168.1.100 \ # 你的节点IP
--allow-privileged=true \
--service-cluster-ip-range=10.96.0.0/12 \ # 服务网段
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
--authorization-mode=Node,RBAC \
--kubelet-https=true \
--enable-bootstrap-token-auth \
--token-auth-file=/etc/kubernetes/token.csv \
--service-account-key-file=/opt/k8s/ssl/ca-key.pem \
--tls-cert-file=/opt/k8s/ssl/apiserver.pem \
--tls-private-key-file=/opt/k8s/ssl/apiserver-key.pem \
--client-ca-file=/opt/k8s/ssl/ca.pem \
--etcd-cafile=/opt/k8s/ssl/ca.pem \
--etcd-certfile=/opt/k8s/ssl/apiserver.pem \
--etcd-keyfile=/opt/k8s/ssl/apiserver-key.pem \
--etcd-servers=https://192.168.1.100:2379" # etcd地址(单节点本地)
EOF
# 创建token文件(用于kubelet bootstrap注册)
cat > /etc/kubernetes/token.csv << EOF
$(head -c 16 /dev/urandom | od -An -t x | tr -d ' '),kubelet-bootstrap,10001,"system:node-bootstrapper"
EOF
# 创建apiserver systemd服务
cat > /etc/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
EnvironmentFile=/etc/kubernetes/apiserver.conf
ExecStart=/usr/local/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# 启动apiserver
systemctl daemon-reload
systemctl start kube-apiserver
systemctl enable kube-apiserver
# 验证apiserver(访问6443端口)
curl -k https://192.168.1.100:6443/healthz # 输出:ok
4.2 启动 kubelet(节点 “代理”)
bash
# 生成kubelet bootstrap配置文件
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/k8s/ssl/ca.pem \
--server=https://192.168.1.100:6443 \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
kubectl config set-credentials kubelet-bootstrap \
--token=$(cat /etc/kubernetes/token.csv | cut -d ',' -f1) \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
kubectl config set-context default \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
kubectl config use-context default --kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
# 创建kubelet配置文件
cat > /var/lib/kubelet/config.yaml << EOF
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: 192.168.1.100
port: 10250
readOnlyPort: 10255
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
failSwapOn: false
authentication:
anonymous:
enabled: false
webhook:
enabled: true
authorization:
mode: Webhook
EOF
# 创建kubelet systemd服务(用户提供的配置文件)
cat > /etc/systemd/system/kubelet.service.d/10-config.conf << EOF
[Service]
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
ExecStart=
ExecStart=/usr/local/bin/kubelet \$KUBELET_CONFIG_ARGS
EOF
# 创建kubelet主服务文件
cat > /etc/systemd/system/kubelet.service << EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service
[Service]
Restart=on-failure
RestartSec=5
EnvironmentFile=-/etc/kubernetes/kubelet.env
ExecStart=/usr/local/bin/kubelet \$KUBELET_CONFIG_ARGS
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
# 启动kubelet
systemctl daemon-reload
systemctl start kubelet
systemctl enable kubelet
4.3 批准 kubelet 证书请求(关键步骤)
kubelet 启动后会向 apiserver 发送证书请求,需要手动批准:
bash
# 查看证书请求
kubectl get csr
# 输出类似:NAME AGE SIGNERNAME REQUESTOR CONDITION
# csr-xxxx 10s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Pending
# 批准请求(替换csr-xxxx为实际名称)
kubectl certificate approve csr-xxxx
# 验证节点状态(此时节点应处于Ready状态)
kubectl get nodes # 输出:NAME STATUS ROLES AGE VERSION
# node-1 Ready <none> 1m v1.24.0
步骤 5:部署网络插件(Flannel)
K8s 集群必须部署网络插件才能让 Pod 之间通信,这里选择最常用的 Flannel。
bash
# 下载Flannel配置文件(国内镜像)
wget https://raw.githubusercontent.com/flannel-io/flannel/v0.20.2/Documentation/kube-flannel.yml
# 修改镜像地址(替换为国内镜像,加速下载)
sed -i 's|quay.io/coreos/flannel:v0.20.2|registry.aliyuncs.com/google_containers/flannel:v0.20.2|g' kube-flannel.yml
# 部署Flannel
kubectl apply -f kube-flannel.yml
# 验证Flannel部署(查看kube-system命名空间下的Pod)
kubectl get pods -n kube-system
# 输出应包含:kube-flannel-ds-xxxx Running 0 2m
# 测试Pod网络(创建一个测试Pod)
kubectl run nginx-test --image=nginx:alpine
kubectl get pods # 确保Pod处于Running状态
kubectl exec -it nginx-test -- ping 8.8.8.8 # 测试网络连通性
关键配置文件汇总(方便查阅)
| 组件 | 配置文件路径 | 核心作用 |
|---|---|---|
| containerd | /etc/containerd/config.toml | 容器运行时配置(镜像、cgroup) |
| apiserver | /etc/kubernetes/apiserver.conf | 集群入口配置(端口、证书、etcd) |
| kubelet | /var/lib/kubelet/config.yaml | 节点代理配置(IP、DNS、认证) |
| kubelet | /etc/systemd/system/kubelet.service.d/10-config.conf | kubelet 启动参数 |
| Flannel | kube-flannel.yml | 网络插件配置(Pod 网段) |
常见问题排查(避坑指南)
| 问题现象 | 排查方向 | 解决方案 |
|---|---|---|
| kubelet 启动失败,日志显示 “connection refused” | apiserver 未启动或端口不通 | 检查 apiserver 状态:systemctl status kube-apiserver |
| 节点一直处于 NotReady 状态 | Flannel 未部署或部署失败 | 查看 Flannel 日志:kubectl logs -n kube-system kube-flannel-ds-xxxx |
| Pod 无法创建,提示 “network plugin is not ready” | Flannel 未就绪 | 等待 Flannel 启动完成,或重新部署 Flannel |
| 证书生成失败 | cfssl 工具未安装或配置文件格式错误 | 重新安装 cfssl,检查 json 配置文件语法 |
总结:手动搭建的核心收获
通过这篇 “笨办法” 教程,你不仅搭建了一个可运行的单节点 K8s,更重要的是理解了:
- K8s 组件的协作逻辑:
apiserver是核心,kubelet是节点代理,containerd是容器运行时,Flannel是网络基础 - 证书的作用:TLS 加密是集群安全的基础,所有组件通信都依赖证书
- 配置文件的意义:每个组件的核心参数都在配置文件中,排障时先查配置
回顾学习路径:Linux 内核 → 容器原理 → K8s 组件 → 手动搭建,你已经为后续学习企业级集群部署、故障排查打下了坚实的基础。
如果在实操中遇到问题,或者想了解后续内容(比如高可用集群搭建、K8s 核心概念深入解析、故障排查实战),欢迎在评论区留言交流!
这就是本文的全部内容,也感谢耐心看到这里的读者,我会持续更新,希望你能够多多关注,如果本文有帮组到你的话,还请三连加关注,你的支持就是我创作的最大动力!
更多推荐



所有评论(0)