kubeadm安装Kubernetes 1.37并集成Docker运行时教程

📅 发布时间:2026/9/7 12:38:31
kubeadm安装Kubernetes 1.37并集成Docker运行时教程
这次我们来看一个用 kubeadm 安装最新 Kubernetes 集群的完整过程目标版本是 k8s 1.37.x并且让底层容器运行时真正走 Docker。这里需要先把背景说清楚Kubernetes 从 1.24 开始移除了内置 dockershimK8s 高版本不再直接内置 Docker 支持。如果想在 1.37.x 继续使用 Docker Engine正确做法是安装 cri-dockerd 适配器让 kubelet 通过 CRI 接口与 Docker 通信。整篇文章会给出从环境准备到集群验证的完整命令同时对这个方案背后的原理做说明方便你判断哪种运行时更适合自己的项目。适用读者主要是这几类第一公司服务器上已经大量使用 Docker想把业务平滑迁移到 Kubernetes第二正在学习 K8s想对比 containerd 与 Docker 在集群中的行为差异第三需要一个可复现的 kubeadm 安装步骤把集群搭出来给开发或测试环境用。本文不会花太多篇幅讲 Kubernetes 基础概念而是直接围绕部署链路展开所以如果你已经知道 Deployment、Service、Pod 的基本含义理解起来会更快。对完全没接触过 K8s 的读者先把这套安装跑通再回来看概念文档效果也会比空谈概念好很多。部署细节上我会以 Ubuntu 22.04 作为示例系统过程中会同步给出 Rocky Linux / CentOS 等发行版的差异说明。硬件方面测试环境建议至少两个节点master 2 核 4Gworker 2 核 4G系统盘 40G 以上。如果只是单机学习也可以把 master 和 worker 放在同一台机器但需要处理 master 节点的 taint这部分我会在功能验证时提到。下面先从整体能力开始给出一张快速判断表。1. 核心能力速览能力项说明集群安装工具kubeadm、kubelet、kubectl底层容器运行时Docker Engine通过 cri-dockerd 适配 CRI目标版本Kubernetes 1.37.x具体以官方软件仓库实际提供为准节点组成至少 1 个 master 和 1 个 worker单机测试时可合并推荐硬件Master 2C4G 以上Worker 按业务负载评估操作系统Ubuntu 22.04/24.04、Rocky Linux 9、CentOS 7/9 等主流 Linux 发行版网络方案Flannel、Calico、Cilium 等 CNI 插件任选一种API 能力kube-apiserver 提供完整 REST APIkubectl 和 HTTP 客户端都能调用批量任务原生支持 Deployment、StatefulSet、Job、CronJob 等工作负载适用场景生产集群搭建、容器化应用迁移、Docker 生态兼容性验证、K8s 学习上表最需要关注的是“底层容器运行时”这一行。Docker 并不是一个能直接接入 Kubernetes 高版本的 CRI 实现因此一旦你决定“底层走 Docker”就等于在 kubelet 和 Docker Engine 之间增加了一个适配组件 cri-dockerd。这个组件会带来少量额外管理和资源开销但能让你继续使用熟悉的 docker ps、docker logs、docker exec 等命令排查集群里的容器这是很多从 Docker 迁移过来的运维团队比较看重的一点。2. 为什么 K8s 与 Docker 之间多了一层适配在 Kubernetes 的设计里每个节点上的 kubelet 只通过 CRIContainer Runtime Interface与容器运行时通信。早期版本内置了 dockershim让 kubelet 可以直接操作 Docker但在 1.24 版本后这个 shim 被彻底移除官方推荐直接使用 containerd 或 CRI-O。很多用户还想继续使用 Docker主要原因是团队已有的镜像仓库里可能全是 Docker 构建的镜像或者从 Docker Compose 迁移到 Kubernetes 的过程中希望底层行为和 Docker 保持一致方便对照排查。cri-dockerd 就是为这个场景准备的适配器。它实现了 Kubernetes 的 CRI 接口把 kubelet 发出的请求转换成 Docker API 调用最终由 Docker Engine 完成容器生命周期管理。数据链路大致是这样的kubelet - CRI 调用 - cri-dockerd - Docker API - dockerd - containerd - runc - 容器进程安装 cri-dockerd 之后kubelet 通过unix:///var/run/cri-dockerd.sock这个 socket 与它通信而不是默认的unix:///var/run/containerd/containerd.sock。kubeadm init 和 kubeadm join 时需要显式指定 cri socket这一点非常关键否则 kubeadm 会优先去寻找 containerd导致集群虽然装好了但底层还是 containerd和你预想的不一致。还有一个必须处理的点是 cgroup 驱动。Kubernetes 控制面和 kubelet 默认倾向于使用 systemd cgroup driver而 Docker 安装后默认可能是 cgroupfs。如果两者不一致节点会一直处于 NotReady 状态或者 Pod 调度后报错。下文安装 Docker 时会直接修改 daemon.json把 Docker 的 cgroup driver 固定为 systemd。这也意味着这套方案并不是“装完就能跑”需要在配置层面做好对齐。3. 节点规划与环境准备3.1 节点规划开始安装前先确认节点和网络条件。这里给出一个两节点测试环境作为示例生产环境可根据业务规模扩展。节点角色主机名IP 示例配置建议masterk8s-master192.168.1.102C4G 以上workerk8s-worker1192.168.1.112C4G 以上按业务评估所有节点都需要有固定的主机名并且/etc/hosts中最好写入包含其他节点的 IP 映射避免 DNS 解析问题。3.2 关闭 swap 与加载内核模块kubelet 默认不允许节点使用 swap。测试环境直接关掉最省事避免后续参数不一致sudo swapoff -a sudo sed -i / swap / s/^/#/ /etc/fstab然后加载 Kubernetes 需要的内核模块并调整网络转发参数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如果不加载br_netfilter常见的现象是 Flannel 或 Calico 容器启动后网络策略和流量转发异常节点状态倒是 Ready但跨节点 Pod 通信不通。所以这步不要跳过。3.3 防火墙与端口规划各节点之间需要放行 Kubernetes 组件通信端口。如果使用云厂商安全组或者本机启用 firewalld / ufw需要按下面这张表精确放行端口协议用途6443TCPkube-apiserver所有节点访问10250TCPkubelet 指标、日志、exec10259TCPkube-scheduler10257TCPkube-controller-manager2379/2380TCPetcd 客户端和集群通信30000-32767TCP/UDPNodePort 服务访问内网测试环境如果节点彼此信任可以临时关闭防火墙来减少变量但生产环境建议精确放行端口不要直接关闭防火墙。3.4 设置主机名在 master 节点执行sudo hostnamectl set-hostname k8s-master在 worker 节点执行sudo hostnamectl set-hostname k8s-worker1同时在所有节点的/etc/hosts中加入192.168.1.10 k8s-master 192.168.1.11 k8s-worker14. 安装 Docker 与 cri-dockerd4.1 安装 Docker Engine以 Ubuntu 22.04 为例安装 Docker 官方源的常用步骤是sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release echo $VERSION_CODENAME) stable | \ sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin安装完成后创建一个/etc/docker/daemon.json把 cgroup driver 固定为 systemd同时设置日志轮转避免容器日志无限增长sudo mkdir -p /etc/docker cat EOF | sudo tee /etc/docker/daemon.json { exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m }, storage-driver: overlay2 } EOF sudo systemctl enable docker sudo systemctl restart docker这里必须确认 docker 服务正常sudo systemctl status docker docker info | grep -i cgroup输出应该能看到Cgroup Driver: systemd。4.2 安装 cri-dockerdcri-dockerd 是 Mirantis 维护的开源适配器GitHub 仓库名为Mirantis/cri-dockerd。安装方式是下载 release 二进制放到/usr/local/bin再注册 systemd 服务。版本以官方 Releases 页面为准我这里以 v0.3.16 作为示例版本号wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.16/cri-dockerd-0.3.16.amd64.tgz tar -xvf cri-dockerd-0.3.16.amd64.tgz sudo install -o root -g root -m 0755 cri-dockerd /usr/local/bin/cri-dockerd然后创建两个 systemd 文件。第一个是 cri-docker.socketsudo tee /etc/systemd/system/cri-docker.socket EOF [Unit] DescriptionCRI Docker Socket for the API PartOfcri-docker.service [Socket] ListenStream%t/cri-dockerd.sock SocketMode0660 SocketUserroot SocketGrouproot [Install] WantedBysockets.target EOF第二个是 cri-docker.servicesudo tee /etc/systemd/system/cri-docker.service EOF [Unit] DescriptionCRI Interface for Docker Application Container Engine Documentationhttps://docs.mirantis.com Afterdocker.service Requiresdocker.service [Service] Typenotify ExecStart/usr/local/bin/cri-dockerd --container-runtime-endpoint fd:// Restartalways RestartSec10 StartLimitInterval0 StartLimitBurst5 [Install] WantedBymulti-user.target EOF启动并设置开机自启sudo systemctl daemon-reload sudo systemctl enable cri-docker.socket cri-docker.service sudo systemctl start cri-docker.socket cri-docker.service验证 socket 是否存在ls -l /var/run/cri-dockerd.sock sudo systemctl status cri-docker.socket cri-docker.service到这里Docker 底层已经通过 cri-dockerd 暴露出了 CRI 接口。kubelet 使用这个 socket 就能把 Pod 的创建请求交给 Docker Engine 处理。5. 安装 kubeadm、kubelet、kubectl安装 kubeadm、kubelet、kubectl 的方式通常通过官方软件仓库。以 Ubuntu/Debian 为例使用 pkgs.k8s.io 的 v1.37 仓库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.37/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.37/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如果你的仓库里还没有提供 1.37.x 的完整版本可以用下面的命令查看可安装的版本列表apt-cache madison kubeadmRHEL/Rocky/CentOS 的仓库写法稍有不同cat EOF | sudo tee /etc/yum.repos.d/kubernetes.repo [kubernetes] nameKubernetes baseurlhttps://pkgs.k8s.io/core:/stable:/v1.37/rpm/ enabled1 gpgcheck1 gpgkeyhttps://pkgs.k8s.io/core:/stable:/v1.37/rpm/repodata/repomd.xml.key excludekubelet kubeadm kubectl EOF sudo setenforce 0 sudo sed -i s/^SELINUXenforcing$/SELINUXpermissive/ /etc/selinux/config sudo yum install -y kubelet kubeadm kubectl --disableexcludeskubernetesRHEL 系列需要把 SELinux 设成 permissive否则 CNI 插件创建 veth 口时会受到限制。安装完成后三个组件会自动注册 systemd 服务但kubelet现在先不要启动因为集群还没初始化kubelet 启动后只会反复报错等待配置文件。等 kubeadm init 结束后再启动。6. 初始化 Master 节点6.1 准备初始化参数到了最关键的一步。由于我们要让底层运行时走 Dockerkubeadm init必须带上--cri-socketunix:///var/run/cri-dockerd.sock否则 kubeadm 自动探测 CRI 时很可能找到 containerd导致后续集群虽然能用但容器实际由 containerd 管理。下面给出两种初始化方式。第一种直接用命令行参数sudo kubeadm init \ --kubernetes-versionv1.37.x \ --apiserver-advertise-address192.168.1.10 \ --pod-network-cidr10.244.0.0/16 \ --cri-socketunix:///var/run/cri-dockerd.sock \ --image-repository registry.aliyuncs.com/google_containers注意v1.37.x要替换成你仓库里看到的实际版本号比如v1.37.2。如果网络能正常访问 K8s 官方镜像仓库可以不加--image-repository如果拉镜像比较慢或失败再考虑使用国内镜像仓库。第二种方式把参数写入 kubeadm 配置文件。以 kubeadm.k8s.io/v1beta4 为例部分实际版本字段需要按你的 kubeadm 版本调整apiVersion: kubeadm.k8s.io/v1beta4 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.10 bindPort: 6443 nodeRegistration: criSocket: unix:///var/run/cri-dockerd.sock name: k8s-master --- apiVersion: kubeadm.k8s.io/v1beta4 kind: ClusterConfiguration kubernetesVersion: 1.37.x networking: podSubnet: 10.244.0.0/16保存为kubeadm-config.yaml后执行sudo kubeadm init --configkubeadm-config.yaml6.2 配置 kubectl初始化成功后末尾会输出一段配置 kubectl 的命令。复制到 shell 里执行mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config然后确认集群组件状态kubectl get nodes kubectl get pods -A这里会遇到一个正常的现象Node 可能是 NotReady很多系统 PodCoreDNS显示 Pending。原因不是集群坏了而是还没有安装 CNI 网络插件。6.3 安装 CNI 网络插件CNI 负责 Pod 网络不装的话节点无法变成 Ready。这里以 Flannel 为例因为它对 Pod CIDR 的默认配置正好是10.244.0.0/16和上面的初始化参数匹配kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml如果使用 Calico则把--pod-network-cidr192.168.0.0/16写入初始化参数再应用 Calico 的 manifest。安装后等待 1-2 分钟kubectl get nodes -o wide kubectl get pods -A | grep -E flannel|calico当 master 节点状态变成 Ready并且 CNI Pod 都处于 Running说明集群控制面已经可用。7. 加入 Worker 节点kubeadm init成功时终端会输出一条 join 命令类似sudo kubeadm join 192.168.1.10:6443 --token token \ --discovery-token-ca-cert-hash sha256:hash \ --cri-socketunix:///var/run/cri-dockerd.sock这里必须把--cri-socket补上否则 worker 节点的 kubelet 会去找 containerd和 master 使用的运行时不一致虽然也可能加入成功但后续排查时会多一层问题。如果当时没复制 join 命令可以在 master 节点重新生成 tokensudo kubeadm token create --print-join-command拿到 token 后在 worker 节点执行 join 命令。执行完毕后回到 master 节点查看kubectl get nodes -o wide正常情况下master 和 worker 都应该是 Ready 状态。如果 worker 一直 NotReady先看 worker 节点 kubelet 状态systemctl status kubelet journalctl -u kubelet -f8. 功能测试与效果验证8.1 验证节点和系统 Pod集群搭建完成后第一件事是确认所有节点 Ready并且所有kube-system命名空间下的 Pod 都处于 Runningkubectl get nodes kubectl get pods -A这个步骤能判断集群组件是否健康。如果某个 system Pod 反复重启优先看它的日志kubectl logs -n kube-system pod-name8.2 部署一个测试应用为了验证业务调度和 Service 暴露创建一个简单的 Nginx DeploymentapiVersion: apps/v1 kind: Deployment metadata: name: nginx-test spec: replicas: 2 selector: matchLabels: app: nginx-test template: metadata: labels: app: nginx-test spec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-test-svc spec: type: NodePort selector: app: nginx-test ports: - port: 80 targetPort: 80 nodePort: 30080保存为nginx-test.yaml并应用kubectl apply -f nginx-test.yaml kubectl get deployment nginx-test kubectl get pods -o wide kubectl get svc nginx-test-svc然后通过任意节点的30080端口访问测试服务。如果访问不到先查 Service 和 Endpointskubectl describe svc nginx-test-svc kubectl get endpoints nginx-test-svc8.3 验证底层确实走 Docker这是本文方案的关键验证点。在任意节点上执行docker ps --format table {{.Names}}\t{{.Image}}\t{{.Status}} | grep k8s_只要看到容器名带k8s_前缀就说明这个节点的 Pod 容器确实由 Docker 创建和管理。再用 crictl 验证同一个视图cat EOF | sudo tee /etc/crictl.yaml runtime-endpoint: unix:///var/run/cri-dockerd.sock image-endpoint: unix:///var/run/cri-dockerd.sock EOF sudo crictl pscrictl ps会列出 Kubernetes 视角下的容器列表。如果 Docker 和 crictl 都能看到相同容器说明这层适配链路是通的kubelet - cri-dockerd - Docker Engine - 容器如果 crictl 报错找不到 socket多半是 cri-dockerd 服务没起来或者/etc/crictl.yaml的配置没有生效。8.4 验证扩容和滚动更新Kubernetes 的日常操作验证可以先扩容看 Pod 分布kubectl scale deployment nginx-test --replicas5 kubectl get pods -o wide再做一个原地滚动更新镜像标签kubectl set image deployment/nginx-test nginxnginx:1.27-alpine kubectl rollout status deployment/nginx-test最后看日志是否能正常输出kubectl logs -l appnginx-test --tail109. 接口 API 与批量任务示例9.1 通过 kubectl proxy 调用 APIKubernetes 的 kube-apiserver 暴露了一整套 REST API日常看到的是 kubectl 封装。你可以开启一个本地代理直接用 curl 调用kubectl proxy --port8080 然后请求 APIcurl http://127.0.0.1:8080/api/v1/namespaces/default/pods返回结果是 JSON 格式的 Pod 列表。这里可以用一个小脚本提取 Pod 名称curl -s http://127.0.0.1:8080/api/v1/namespaces/default/pods | \ python3 -c import sys, json; datajson.load(sys.stdin); print(\n.join([item[metadata][name] for item in data[items]]))如果需要更完整的授权方式推荐使用 ServiceAccount token。这就涉及到 RBAC 配置生产环境不建议直接使用kubectl proxy给外部系统调用只适合本地调试。9.2 用 CronJob 做批量任务Kubernetes 原生支持 Job 和 CronJob适合批量处理和定时任务。下面这个示例每天凌晨两点执行一次归档操作apiVersion: batch/v1 kind: CronJob metadata: name: batch-archive-job spec: schedule: 0 2 * * * jobTemplate: spec: template: spec: containers: - name: archive image: busybox:1.36 command: [/bin/sh, -c, echo batch job at $(date); ls /data] restartPolicy: OnFailure应用并查看执行记录kubectl apply -f cronjob.yaml kubectl get cronjob kubectl get jobs --watch批量任务的重点是给容器配置足够的资源限制和超时避免某个异常任务一直占住节点资源。生产级批量框架还可以搭配 Argo Workflows 或 Volcano但基础的 CronJob 对很多运维场景已经够用。10. 资源占用与性能观察10.1 控制面组件资源占用master 节点部署了 kube-apiserver、etcd、kube-controller-manager、kube-scheduler再加上 kubelet 和 Docker / cri-dockerd即使不跑业务也会占一部分内存。从低负载测试集群的经验看空闲状态下这些组件常驻内存加起来在 1.5GB 到 2.5GB 之间具体数值与集群规模、日志量、etcd 数据量有关实际以你的环境为准。建议 master 节点不要低于 4G 内存否则初始化过程中容易出现一次拉起多个镜像失败的情况。观察命令如下free -h docker stats --no-stream crictl stats kubectl top node注意kubectl top node需要先安装 metrics-server。如果是临时查看节点资源直接在节点上执行free -h和docker stats更直接。10.2 Docker cri-dockerd 与 containerd 的差异相比直接在节点上使用 containerd这套方案多了一层 cri-dockerd 适配器因此 CPU 和内存占用会略高一些。优势是运维习惯不变你可以用 docker exec 进入任意容器排查用 docker logs 拉取标准输出镜像构建和 Docker Compose 迁移也更顺畅。劣势是容器的创建路径更长大规模高并发创建 Pod 时性能会有轻微损耗。如果集群规模在几十个节点以内这个差异通常感知不明显。如果集群会扩展到几百个节点或者对 Pod 启动速度和资源占用有极致要求建议考虑 containerd 作为运行时。选择哪种运行时本质上是运维习惯和性能效率之间的取舍。10.3 与网络插件配合时的资源观察CNI 组件同样会占用节点资源。以 Flannel 为例每个节点都会运行一个 flanneld 进程负责维护 vxlan 网络。如果节点数量很多或者 Pod 流量很大可以观察 flannel 进程的 CPU 和内存ps aux | grep flanneld如果发现 CNI 组件异常消耗内存优先检查节点是否出现了大量 Pod 重建以及网络策略是否过于复杂。11. 常见问题与排查方法问题现象可能原因排查方式解决方案kubeadm init 拉镜像失败网络无法访问镜像仓库或镜像仓库地址不通查看 init 输出日志确认镜像名称使用--image-repository指定可访问的镜像仓库节点一直 NotReadyCNI 未安装或 kubelet 与运行时通信异常kubectl get nodesjournalctl -u kubelet -f安装 Flannel/Calico检查 cri socket 配置CoreDNS Pod 反复 CrashLoopBackOff网络插件未就绪或容器运行时异常kubectl logs -n kube-system coredns-pod等待网络插件就绪重启 CoreDNS DeploymentPod 调度后容器创建失败cgroup driver 不一致docker info | grep Cgroupkubelet 配置统一为 systemd修改 daemon.json 后重启 dockercri-dockerd.sock 不存在cri-dockerd 服务没启动systemctl status cri-docker.socket cri-docker.service启动服务检查 ExecStart 路径是否正确kubeadm join 找不到 K8s API Servertoken 过期或端口不通在 master 执行kubeadm token list检查 6443 端口重新生成 token或放行防火墙端口NodePort 无法访问Service 类型不是 NodePort或防火墙未放行 30000-32767kubectl get svcss -lntp | grep 30080修改 Service 类型或在安全组放行 NodePort 段kubectl logs卡住无输出kubelet 与 apiserver 网络异常或容器已退出kubectl describe pod检查节点 10250 端口确认节点间网络排查 kubelet 状态集群 Pod IP 在不同节点间不通CNI 插件异常或 bridge-nf-call-iptables 未开启sysctl net.bridge.bridge-nf-call-iptables查看 CNI 日志重新执行 sysctl 配置重启 CNI Pod业务容器重启频率很高资源限制过低或健康检查失败kubectl describe pod查看 OOMKilled 状态调高资源 limits或调整 liveness/readiness 探针排查 Kubernetes 问题时最重要的两个命令是kubectl describe和日志查看。很多表面现象比如 Pod 一直 Pending、Node 状态 NotReady、Service 不通最后都能在 describe 输出和系统组件日志里找到直接原因。12. 最佳实践与使用建议12.1 第一次部署先小参数验证不要一上来就铺几十个节点。先在两个节点上跑通整套流程确认 Docker、cri-dockerd、kubeadm 的版本匹配关系再逐步增加节点。尤其是 cri-dockerd 版本和 Docker 版本之间最好以官方 Release 说明为准。没有验证过的新版本先在小环境里跑几天再考虑上生产。12.2 模型文件、镜像、配置文件分目录管理集群运维中建议把 kubeadm 配置、CNI manifest、业务 YAML 分目录存放。比如/opt/k8s/ └── manifests/ ├── kubeadm-config.yaml ├── cni/ └── apps/这样升级集群、排查配置差异时能快速找到对应文件也方便用 git 做版本管理。12.3 批量任务要加日志和失败重试Kubernetes 原生 Job 的重试策略有限。如果是重要批量任务建议在应用层实现失败重试并把日志写入持久化存储。CronJob 也建议设置startingDeadlineSeconds避免调度堆积时产生大量并发 Job。12.4 安全与合规提醒部署 Kubernetes 集群时组件和镜像应该只从官方或可信来源获取不要使用来路不明的二进制和容器镜像尤其是涉及生产数据和用户隐私时。集群中如果运行人脸、声音、版权素材等敏感数据的处理任务必须先确认数据来源合法、已获得授权并按照企业内部安全规范设置网络策略和访问控制。kube-apiserver 的 6443 端口不要直接暴露到公网建议放在内网或通过堡垒机访问启用 RBAC 并配置认证插件避免未授权访问。12.5 定期备份 etcdetcd 是整个集群状态的核心。生产环境要配置 etcd 的定期快照备份到独立存储。备份命令可以直接使用 etcdctlETCDCTL_API3 etcdctl --endpointshttps://127.0.0.1:2379 \ --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/server.crt \ --key/etc/kubernetes/pki/etcd/server.key \ snapshot save /backup/etcd-snapshot.db出现节点恢复、集群扩容等场景时这份备份就是最后的兜底。13. 总结与下一步这套 kubeadm 安装 K8s 1.37.x 并让底层走 Docker 的方案最值得尝试的点在于它保留了 Docker 的运维习惯同时让你拿到一个可用的多节点 Kubernetes 集群。安装完成后最应该先验证三件事第一节点是否为 Ready系统 Pod 是否 Running第二docker ps 能否看到带k8s_前缀的容器第三部署一个 Nginx Service 并确认 NodePort 能正常访问。这三步通过说明 kubelet、cri-dockerd、Docker Engine 整条链路是通的。最容易踩的坑有两个一个是没有在kubeadm init和kubeadm join中显式指定 cri socket导致集群底层实际变成 containerd另一个是 Docker 的 cgroup driver 和 Kubernetes 不一致导致节点状态异常。提前把这两点处理好整个安装过程会顺畅很多。后续可以继续扩展的方向包括接入 Cilium 或 Calico 实现更精细的网络策略安装 metrics-server 或 Prometheus 做监控告警通过 Ingress Controller 替代 NodePort 暴露服务把现有 Docker Compose 服务逐步改写成 Deployment 和 StatefulSet。等这一套集群稳定运行一段时间后再评估是否需要切换到底层 containerd对比两者的资源占用和管理成本。建议收藏备用尤其是准备在多台机器上复现这个部署流程的时候。