前言:为什么要 “手动搭” K8s?

你可能听过 kubeadm init 一行命令就能拉起 K8s 集群,甚至 Minikube 能一键部署测试环境。但这些自动化工具就像 “黑盒”—— 它们帮你省去了配置细节,却也让你错过了最核心的 “组件协作逻辑”。

手动搭建的价值在于:

  • 看清 kube-apiserverkubeletcontainerd 之间的依赖关系
  • 理解证书、配置文件、启动参数的作用(后续排障的核心)
  • 摆脱 “只会用工具,不懂原理” 的尴尬

这篇文章会带你用 “笨办法” 从零搭建单节点 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 → 通过bootstrapapiserver注册 → apiserveretcd交互存储数据 → 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,更重要的是理解了:

  1. K8s 组件的协作逻辑:apiserver是核心,kubelet是节点代理,containerd是容器运行时,Flannel是网络基础
  2. 证书的作用:TLS 加密是集群安全的基础,所有组件通信都依赖证书
  3. 配置文件的意义:每个组件的核心参数都在配置文件中,排障时先查配置

回顾学习路径:Linux 内核 → 容器原理 → K8s 组件 → 手动搭建,你已经为后续学习企业级集群部署、故障排查打下了坚实的基础。

        如果在实操中遇到问题,或者想了解后续内容(比如高可用集群搭建、K8s 核心概念深入解析、故障排查实战),欢迎在评论区留言交流!

        这就是本文的全部内容,也感谢耐心看到这里的读者,我会持续更新,希望你能够多多关注,如果本文有帮组到你的话,还请三连加关注,你的支持就是我创作的最大动力!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐