1. 为什么“配置master节点”是K8S入门里最易被轻视的生死关卡很多人学K8S一上来就猛敲kubeadm init看到控制台刷出绿色Your Kubernetes control-plane has initialized successfully!就以为大功告成——结果第二天kubectl get nodes返回空列表kubectl describe pod卡在Pendingkubelet日志里满屏Failed to load kubeconfig或connection refused。我见过至少7个团队在模拟项目X的第三周集体卡在这一步不是环境没配好而是根本没理解“配置master节点”这六个字背后承载的三重责任它既是集群的调度中枢又是证书签发中心更是所有组件的信任锚点。你配的不是一台服务器而是一套分布式系统的“心脏起搏器”。关键词里虽未明写但所有实操者都绕不开这四个核心词etcd通信、kube-apiserver绑定、CA证书链、kubelet自注册机制。它们像四根钢索任何一根松动整个master就失去心跳。比如某高校实验室曾用默认--apiserver-advertise-address127.0.0.1初始化结果node节点永远连不上master——因为apiserver只监听本地回环对外网络完全封闭又比如某公司运维在离线环境中手动替换/etc/kubernetes/pki/ca.crt后忘记同步ca.key导致kubeadm join时node反复报x509: certificate signed by unknown authority折腾两天才发现证书签名不匹配。这不是配置失误是认知断层。K8S的master节点从来不是“装完就跑”的黑盒它要求你同时具备网络拓扑意识端口、IP、防火墙、PKI体系常识CA、证书签名、SAN扩展、系统服务管理能力systemd、journalctl、socket激活和容器运行时理解CRI接口、pause镜像作用。本文不讲抽象概念只拆解真实操作中每一条命令背后的物理意义、每一个配置项的生效边界、每一处日志报错的根因定位路径。接下来四章我会带你亲手把master节点从“能启动”变成“可信赖”让kubectl cluster-info输出的每一行都经得起推敲。2. 初始化前必须完成的五项硬性检查跳过任意一项后续90%的问题都源于此很多教程把kubeadm init当作起点这是最大的误导。真正的起点是执行这条命令前的系统级校验。我统计过某跨平台系统部署记录83%的master初始化失败根源都在这五项检查被跳过或草率通过。下面逐项说明检查逻辑、验证方法和修复方案全部基于Linux发行版通用实践CentOS 7/Ubuntu 20.04。2.1 网络连通性与端口开放状态不是“能ping通”而是“端口可被目标地址访问”K8S master依赖多个固定端口提供服务但新手常犯的错误是只在本机telnet 127.0.0.1 6443成功就认为OK。实际上node节点需要从外部IP访问master的6443端口而firewalld/ufw可能仅放行了localhost。必须分三层验证本机监听状态sudo ss -tlnp | grep :6443正确输出应包含LISTEN状态及kube-apiserver进程若无输出说明apiserver未启动或绑定失败。本机外网可达性在另一台同网段机器执行nc -zv master-ip 6443若返回Connection refused需检查master节点防火墙# CentOS/RHEL系 sudo firewall-cmd --permanent --add-port6443/tcp sudo firewall-cmd --permanent --add-port10250/tcp # kubelet API sudo firewall-cmd --permanent --add-port2379/tcp # etcd client sudo firewall-cmd --reloadUbuntu系则用sudo ufw allow 6443/tcp等对应命令。路由与NAT穿透若master位于云主机或NAT后需确认安全组/ACL规则已放行6443端口且目标IP为公网可路由地址非内网IP如10.x.x.x、172.16.x.x。某开发者曾将master部署在家庭宽带路由器后用内网IP初始化导致所有node无法加入——因为kubeadm join命令中的master-ip必须是node能直接访问的地址而非master自身的ip addr show输出。提示kubeadm init默认使用--apiserver-advertise-address参数指定对外广播的IP。若不显式指定kubeadm会自动选择第一个非lo网卡的IPv4地址。但该地址未必是node可达的如Docker网桥地址172.17.0.1因此必须显式指定kubeadm init --apiserver-advertise-address192.168.1.100替换为实际可路由IP。2.2 时间同步精度误差超过1秒证书校验即刻失效K8S所有组件间通信依赖TLS双向认证而证书有效期校验严格依赖系统时间。若master与node时间偏差超1秒kubelet将拒绝连接apiserver日志中出现x509: certificate has expired or is not yet valid。这不是警告是硬性拦截。验证方法在master和所有待加入node上执行timedatectl status重点看System clock synchronized: yes和NTP service: active。若为no必须强制同步# 停止NTP服务 sudo systemctl stop chronyd # CentOS sudo systemctl stop systemd-timesyncd # Ubuntu # 强制同步指向可靠NTP源 sudo ntpdate -s time.windows.com # 或使用pool.ntp.org sudo ntpdate -s 0.pool.ntp.org # 重启并启用服务 sudo systemctl start chronyd sudo systemctl enable chronyd注意ntpdate命令在较新系统中可能被移除此时改用chronyc makestepCentOS或sudo timedatectl set-ntp trueUbuntu。关键不是工具而是确保timedatectl status中System clock synchronized为yes且RTC time与Local time误差小于500ms。2.3 容器运行时就绪状态kubelet启动失败的头号元凶kubeadm init本质是引导kubelet启动并注册为master节点而kubelet本身依赖容器运行时如containerd或docker拉取pause镜像。若运行时未就绪kubelet会卡在Container runtime network not ready状态。验证步骤检查运行时服务状态sudo systemctl status containerd推荐或sudo systemctl status docker验证pause镜像是否存在sudo crictl images | grep pausecontainerd或docker images | grep pause若镜像缺失手动拉取sudo crictl pull registry.k8s.io/pause:3.9注意镜像仓库地址随K8S版本变化常见陷阱某公司使用自建Harbor镜像仓库未配置containerd的registry.mirrors导致crictl pull超时失败。解决方案是在/etc/containerd/config.toml中添加[plugins.io.containerd.grpc.v1.cri.registry.mirrors.registry.k8s.io] endpoint [https://your-harbor-domain/k8s]然后重启sudo systemctl restart containerd。2.4 内核模块与系统参数cgroup驱动不一致引发的雪崩K8S 1.24默认要求cgroup v2而多数Linux发行版仍默认cgroup v1。若kubelet与容器运行时使用的cgroup驱动不一致如kubelet用systemdcontainerd用cgroupfs节点将无法注册journalctl -u kubelet中持续报failed to run Kubelet: misconfiguration: cgroup driver: systemd is different from docker。验证方法# 查看kubelet配置的cgroup驱动 ps aux | grep kubelet | grep -o cgroup-driver[^ ]* # 查看containerd配置 sudo cat /etc/containerd/config.toml | grep SystemdCgroup修复方案以containerd为例编辑/etc/containerd/config.toml确保[plugins.io.containerd.grpc.v1.cri.containerd]下有[plugins.io.containerd.grpc.v1.cri.containerd] default_runtime_name runc [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] runtime_type io.containerd.runc.v2 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true # 关键必须为true重启containerdsudo systemctl restart containerd重启kubeletsudo systemctl restart kubelet实测心得SystemdCgroup true是K8S 1.22后稳定运行的黄金配置。若设为false在高负载下可能出现cgroup内存泄漏导致节点OOM。2.5 主机名与DNS解析kubeadm join失败的隐形杀手kubeadm join命令生成的token和discovery信息隐含master节点的主机名hostname。若node节点无法通过DNS或/etc/hosts解析该主机名连接将失败。例如master主机名为k8s-master-01但node执行ping k8s-master-01返回unknown host。解决方案分两步统一主机名规范所有节点执行sudo hostnamectl set-hostname k8s-master-01master或k8s-node-01node避免下划线、大写字母。强制DNS解析在所有node的/etc/hosts中添加192.168.1.100 k8s-master-01其中192.168.1.100为master的实际IP。此法比配置DNS服务器更可靠尤其在离线环境。这五项检查看似琐碎却是master节点稳定的基石。我建议将其写成shell脚本每次初始化前自动执行#!/bin/bash echo Checking Network ss -tlnp | grep :6443 || echo ERROR: 6443 not listening nc -zv 192.168.1.100 6443 || echo ERROR: 6443 not reachable echo Checking Time Sync timedatectl status | grep synchronized: yes || echo ERROR: time not synced echo Checking Container Runtime systemctl is-active containerd | grep active || echo ERROR: containerd not active crictl images | grep pause || echo ERROR: pause image missing echo Checking cgroup crictl info | grep systemd || echo ERROR: cgroup driver mismatch运行./precheck.sh红字即为必须修复项。跳过检查等于在雷区蒙眼奔跑。3.kubeadm init命令的深度拆解每个参数都是对集群未来形态的投票当五项硬性检查全部通过kubeadm init才真正成为可控操作。但绝大多数人只是复制粘贴示例命令从未思考每个参数如何塑造集群的基因。下面我以K8S 1.28版本为基准逐参数解析其物理意义、适用场景及踩坑实录。3.1--control-plane-endpoint为高可用集群埋下的第一颗种子单master场景下此参数常被忽略。但一旦规划多master它就是集群存续的关键。它的作用是为所有control-plane节点master提供一个统一的、可浮动的入口地址VIP或DNS名使node节点无需感知具体master IP变更。例如你计划部署3个master节点IP分别为192.168.1.101、192.168.1.102、192.168.1.103。此时应先配置一个VIP如192.168.1.200或DNS名如k8s-api.internal然后在首个master上执行kubeadm init \ --control-plane-endpointk8s-api.internal:6443 \ --upload-certs--upload-certs参数会将CA证书加密上传至etcd供后续master节点下载。若省略此参数第二个master加入时将无法获取证书只能手动拷贝/etc/kubernetes/pki/目录——这在生产环境是不可接受的。踩坑实录某团队首次部署高可用集群时未使用--control-plane-endpoint而是让每个node直接kubeadm join到不同master IP。结果当master-01宕机部分node因DNS缓存或连接池未刷新持续向失效IP发起请求导致服务中断12分钟。教训是入口地址必须解耦于物理节点。3.2--pod-network-cidr决定你的应用能分配多少IP地址此参数指定Pod网络的CIDR网段直接影响集群最大Pod数量。K8S默认不分配网络插件需后续安装Calico/Flannel等。但--pod-network-cidr必须在init时确定因为它是kube-controller-manager生成Node CIDR的基础。计算公式最大Pod数 2^(32 - prefix_length) - 2减去网络地址和广播地址。例如--pod-network-cidr10.244.0.0/16prefix_length16则2^16 65536个IP扣除2个保留地址理论支持65534个Pod。选择原则小型测试集群10.244.0.0/16Calico默认或10.240.0.0/16Flannel默认中大型生产集群10.100.0.0/14支持262142个Pod避免未来扩容时重装集群关键警告--pod-network-cidr必须与后续网络插件配置严格一致。若init时设为10.244.0.0/16但安装Flannel时kube-flannel.yml中net-conf.json的Network字段写成10.245.0.0/16所有Pod将无法通信kubectl get pods -A显示ContainerCreating状态。修复需删除flannel DaemonSet并重新部署期间集群网络中断。3.3--cri-socket当你的容器运行时不在标准路径时K8S 1.24移除了dockershimkubelet通过CRIContainer Runtime Interface与containerd/docker交互。--cri-socket指定CRI socket文件路径。默认值为containerd:/run/containerd/containerd.sockdocker:/var/run/docker.sock但若你定制了containerd安装路径如/opt/containerd/containerd.sock必须显式指定kubeadm init --cri-socket/opt/containerd/containerd.sock否则kubelet启动失败日志报failed to run Kubelet: failed to get the container runtimes CRI interface: failed to create CRI client: unable to connect to containerd: failed to dial: dial unix /run/containerd/containerd.sock: connect: no such file or directory。3.4--image-repository离线环境的生命线国内网络环境下kubeadm init默认从k8s.gcr.io拉取镜像必然超时。--image-repository参数可指定国内镜像源如阿里云kubeadm init \ --image-repositoryregistry.cn-hangzhou.aliyuncs.com/google_containers \ --kubernetes-versionv1.28.2注意镜像仓库地址必须与K8S版本匹配。阿里云仓库中v1.28.2对应镜像标签为v1.28.2而latest标签可能指向旧版本导致组件版本不兼容。实操技巧提前拉取所有必需镜像避免init过程中网络波动。执行kubeadm config images list --kubernetes-versionv1.28.2 --image-repositoryregistry.cn-hangzhou.aliyuncs.com/google_containers | xargs -n 1 sudo crictl pull此命令列出所有镜像并批量拉取init时将直接使用本地镜像速度提升10倍以上。3.5--ignore-preflight-errors一把双刃剑用错即灾难此参数允许忽略预检错误如Swap、Mem等。新手常加--ignore-preflight-errorsall强行通过却不知swap关闭是K8S硬性要求——开启swap会导致kubelet OOM Killer误杀关键进程。正确做法是精准忽略kubeadm init --ignore-preflight-errorsSwap但前提是已执行sudo swapoff -a并注释/etc/fstab中swap行否则重启后swap自动启用集群随时崩溃。经验总结--ignore-preflight-errors只应用于已知可控的环境限制如测试机内存不足绝不能用于生产环境。真正的稳定性来自满足所有预检条件而非绕过检查。4. 初始化后的七步加固让master节点从“能用”走向“可信”kubeadm init成功输出kubeadm join命令只是万里长征第一步。此时master处于“裸机”状态没有网络插件、没有dashboard、证书未备份、日志无轮转、监控全无。接下来七步是我在多个项目中沉淀的加固清单每一步都直击生产环境痛点。4.1 安装CNI网络插件Calico vs Flannel的抉择逻辑K8S要求所有Pod能跨节点通信这依赖CNIContainer Network Interface插件。Calico和Flannel是两大主流选择选型逻辑如下维度CalicoFlannel性能BGP模式延迟最低适合金融、游戏等低延迟场景VXLAN封装有额外开销延迟略高功能支持NetworkPolicy细粒度策略、BGP路由控制、IPAM管理仅提供基础网络连通NetworkPolicy需额外组件复杂度配置稍复杂需理解BGP概念极简yaml apply即用适用场景中大型生产集群、需策略管控小型测试集群、快速验证实操步骤以Calico 3.26为例# 下载官方manifest curl https://raw.githubusercontent.com/projectcalico/calico/v3.26/manifests/calico.yaml -O # 修改CIDR匹配init时参数关键 sed -i s/192.168.0.0\/16/10.244.0.0\/16/g calico.yaml # 应用 kubectl apply -f calico.yaml验证watch kubectl get pods -n kube-system直到calico-node-xxx状态为Running且calico-kube-controllers-xxx也Running。注意若calico-node卡在Init:0/3大概率是calico.yaml中CALICO_IPV4POOL_CIDR未修改或节点缺少ip_vs内核模块。执行sudo modprobe ip_vs sudo modprobe ip_vs_rr加载即可。4.2 配置kubectl命令补全与别名每天节省15分钟的生产力kubectl命令冗长kubectl get pods -n kube-system要敲28个字符。配置bash补全和常用别名是提升效率的最小成本投资。# 安装bash-completion sudo apt-get install bash-completion # Ubuntu sudo yum install bash-completion # CentOS # 启用kubectl补全 source (kubectl completion bash) echo source (kubectl completion bash) ~/.bashrc # 添加常用别名写入~/.bashrc alias kkubectl alias kgkubectl get alias kgakubectl get all alias kdpkubectl describe pod alias klkubectl logs alias klfkubectl logs -f重启终端或执行source ~/.bashrc输入k g pTab即可自动补全kubectl get pods。4.3 备份与恢复etcd数据集群的“数字保险柜”etcd存储所有集群状态Pod、Service、ConfigMap等一旦损坏整个集群将不可恢复。kubeadm init生成的/etc/kubernetes/pki/etcd/ca.crt和/etc/kubernetes/pki/etcd/ca.key是etcd证书根必须与etcd数据一同备份。备份脚本etcd-backup.sh#!/bin/bash ETCDCTL_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-$(date %Y-%m-%d).db设置定时任务# 每天凌晨2点备份 echo 0 2 * * * /root/etcd-backup.sh | sudo crontab -恢复操作仅在灾难时# 停止kubelet和etcd sudo systemctl stop kubelet etcd # 恢复快照假设备份文件为/backup/etcd-snapshot.db etcdctl snapshot restore /backup/etcd-snapshot.db \ --data-dir/var/lib/etcd-restore \ --nameetcd-restore \ --initial-clusteretcd-restorehttps://127.0.0.1:2380 \ --initial-advertise-peer-urlshttps://127.0.0.1:2380 # 替换etcd数据目录 sudo mv /var/lib/etcd /var/lib/etcd-bak sudo mv /var/lib/etcd-restore /var/lib/etcd # 启动服务 sudo systemctl start etcd kubelet4.4 部署Metrics Server让kubectl top命令活起来kubectl top nodes和kubectl top pods是资源监控的核心命令但K8S默认不安装Metrics Server。它负责收集各节点的CPU、内存指标并暴露给kubectl top调用。部署步骤# 下载官方yaml注意版本匹配 curl -L https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.4/components.yaml -o metrics-server.yaml # 修改镜像仓库国内加速 sed -i s/k8s.gcr.io\/metrics-server/mirrorgooglecontainers/g metrics-server.yaml # 应用 kubectl apply -f metrics-server.yaml验证kubectl top nodes应返回各节点资源使用率。若报error: Metrics API not available检查kubectl get apiservice | grep metrics确保v1beta1.metrics.k8s.io状态为True。4.5 启用审计日志记录谁在何时执行了什么敏感操作K8S审计日志记录所有API请求是安全合规的基石。默认关闭需在/etc/kubernetes/manifests/kube-apiserver.yaml中添加参数spec: containers: - command: - kube-apiserver - --audit-log-path/var/log/kubernetes/audit.log # 日志路径 - --audit-log-maxage30 # 保留30天 - --audit-log-maxbackup3 # 最多3个备份 - --audit-log-maxsize100 # 单个日志100MB - --audit-policy-file/etc/kubernetes/audit-policy.yaml # 策略文件创建审计策略文件/etc/kubernetes/audit-policy.yamlapiVersion: audit.k8s.io/v1 kind: Policy rules: - level: Metadata # 记录所有请求元数据 resources: - group: resources: [secrets, configmaps, serviceaccounts] - level: RequestResponse # 记录敏感资源的完整请求/响应 resources: - group: resources: [secrets]重启kubeletsudo systemctl restart kubelet。日志将输出到/var/log/kubernetes/audit.log可对接ELK或Splunk做分析。4.6 配置日志轮转防止/var/log被占满K8S组件日志kubelet、containerd默认不轮转长期运行后/var/log分区可能被撑爆。需配置logrotate创建/etc/logrotate.d/kubernetes/var/log/kubernetes/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0644 root root sharedscripts postrotate systemctl kill -s USR1 kubelet 2/dev/null || true endscript }此配置每日轮转保留14天压缩归档并在轮转后通知kubelet重新打开日志文件。4.7 验证集群健康度一份可交付的检查清单最后用一份结构化清单验证master是否真正就绪检查项命令期望输出不通过处理API Server可用curl -k https://127.0.0.1:6443/healthzok检查kube-apiserver容器状态、证书有效期etcd健康kubectl get csetcd-0状态为Healthy检查etcd容器日志、磁盘空间网络连通kubectl get pods -A所有coredns、calico-node为Running检查CNI插件配置、节点Ready状态证书有效期kubeadm certs check-expiration所有证书剩余有效期360天执行kubeadm certs renew all更新资源监控kubectl top nodes显示各节点CPU/MEM使用率检查Metrics Server状态、RBAC权限执行此清单每项都通过master节点才算真正“毕业”。此时你才有资格说“我的K8S集群master已就绪。”5. 常见故障的根因定位链路从kubectl get nodes为空开始的完整排查当kubectl get nodes返回空列表这是master配置失败最典型的表征。但原因千差万别我梳理了一条标准化排查链路覆盖95%的场景。按顺序执行每步都有明确判断依据和修复动作。5.1 第一层确认kubelet服务状态与日志kubectl命令本质是调用kubelet的API若kubelet未运行一切皆空。# 检查服务状态 sudo systemctl status kubelet # 查看实时日志关键 sudo journalctl -u kubelet -f典型错误与修复failed to run Kubelet: unable to load bootstrap kubeconfig/etc/kubernetes/bootstrap-kubelet.conf缺失或权限错误。执行sudo kubeadm init phase kubeconfig kubelet重建。failed to run Kubelet: failed to create kubeconfig: open /etc/kubernetes/kubelet.conf: no such file or directorykubeadm init未完成。检查/var/lib/kubelet/config.yaml是否存在若无重新执行init。Container runtime network not readyCNI插件未安装或配置错误。执行kubectl get pods -n kube-system确认calico-node或kube-flannel-ds状态。提示journalctl -u kubelet日志是黄金线索90%的问题答案都在其中。不要跳过这一步直接重装。5.2 第二层验证etcd集群状态kubelet需连接etcd存储节点信息。若etcd异常节点无法注册。# 进入etcd容器若用kubeadm部署 sudo crictl exec -it $(sudo crictl ps -q --name etcd) sh # 检查etcd成员状态 etcdctl --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/peer.crt \ --key/etc/kubernetes/pki/etcd/peer.key \ member list # 检查健康状态 etcdctl --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/peer.crt \ --key/etc/kubernetes/pki/etcd/peer.key \ endpoint health典型错误与修复member xxx is unreachable该etcd成员网络不通。检查防火墙、节点IP变更。context deadline exceededetcd进程卡死。执行sudo systemctl restart etcd。5.3 第三层检查kube-apiserver证书与绑定apiserver是所有请求的入口若其证书无效或绑定地址错误kubelet无法建立TLS连接。# 检查apiserver监听地址 sudo ss -tlnp | grep :6443 # 检查证书有效期 sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | grep -E Not Before|Not After # 检查证书SANSubject Alternative Name是否包含master IP sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | grep -A1 Subject Alternative Name典型错误与修复Not After日期已过证书过期。执行sudo kubeadm certs renew apiserver更新。SAN中无master IP如只有127.0.0.1kubeadm init时未指定--apiserver-advertise-address。需重新init或手动更新证书复杂不推荐。5.4 第四层诊断kubelet与apiserver的TLS握手即使证书有效握手过程也可能失败。用openssl s_client模拟kubelet连接# 模拟kubelet连接apiserver openssl s_client -connect 127.0.0.1:6443 \ -cert /var/lib/kubelet/pki/kubelet-client-current.pem \ -key /var/lib/kubelet/pki/kubelet-client-current.pem \ -CAfile /etc/kubernetes/pki/ca.crt典型错误与修复verify error:num20:unable to get local issuer certificateCA证书路径错误。确认/etc/kubernetes/pki/ca.crt存在且内容正确。SSL routines:ssl3_get_record:wrong version number端口错误可能连到了http端口而非https。确认6443端口对应apiserver非其他服务。5.5 第五层审查kubelet配置文件/var/lib/kubelet/config.yaml是kubelet的运行蓝图任何配置错误都会导致注册失败。# 检查关键字段 sudo grep -E (server:|certificate-authority:|client-certificate:|client-key:) /var/lib/kubelet/config.yaml典型错误与修复server: https://127.0.0.1:6443应为master可被node访问的IP如https://192.168.1.100:6443。编辑文件修改后执行sudo systemctl restart kubelet。client-certificate路径不存在kubeadm init未生成客户端证书。执行sudo kubeadm init phase kubeconfig kubelet。这条链路不是线性的而是树状的。例如journalctl日志中出现x509: certificate signed by unknown authority直接跳到第三层检查证书若日志显示connection refused则回到第一层确认apiserver是否监听。掌握此链路你就能在10分钟内定位90%的master配置问题而不是盲目重装。6. 个人实操经验总结那些文档不会写的细节与取舍作为经历过十余次K8S集群部署的从业者我想分享几个血泪教训换来的经验。它们不写在官方文档里却决定了你能否在凌晨三点从容应对生产事故。6.1 关于kubeadm init的时机选择永远在系统重启后执行我曾在一个CentOS 7服务器上连续三次kubeadm init失败。journal