资讯动态

Ubuntu 18.04 部署 Kubernetes 1.18 全流程实战与避坑指南

发布时间:2026/10/21 21:21:26 来源:尧图企业网站定制
1. 为什么这个组合值得单独拿出来讲Ubuntu 18.04 加 Kubernetes 1.18这个组合放在今天来看确实有点“考古”的味道但我可以很负责任地说现在仍然有不少团队在内部测试环境、离线机房、教学实验室里跑着类似的技术栈。原因很实在老服务器的内核版本卡在那里业务依赖的容器运行时还没做新版本适配或者干脆就是一套跑了很久的私有集群没人敢轻易动它。所以把这两个版本凑在一起部署不是猎奇而是真实存在的需求。这个内容适合谁看一类是手里有 Ubuntu 18.04 机器、想从零搭一套 Kubernetes 练手或做内部验证的运维和开发人员另一类是在离线或半离线环境里需要快速复现一套可用集群的工程师。它解决的核心问题就一个在系统版本和容器编排版本都偏旧的前提下怎么把集群稳稳当当地拉起来并且知道每一步为什么这么做。我自己前前后后在不同环境里装过不下十次踩过的坑包括镜像拉不下来、kubelet 反复重启、节点 NotReady、网络插件和内核模块打架等等。下面我把整套流程拆开从设计思路到实操细节再到问题排查尽量讲透。你照着做大概率能少走很多弯路。2. 整体部署思路与方案选型拆解2.1 为什么选 kubeadm 而不是二进制手工部署Kubernetes 的部署方式大致分三类二进制手工部署、kubeadm 工具部署、以及各种发行版封装好的方案。在这个场景下我强烈建议用 kubeadm理由有三条。第一Ubuntu 18.04 的系统环境相对干净kubeadm 对它的支持在 1.18 这个版本上已经相当成熟官方文档里明确把它列为验证过的平台。第二kubeadm 把证书生成、组件配置、启动参数这些容易出错的环节都做了标准化你不需要去背每个组件的 flag 含义。第三出问题的时候kubeadm 的报错信息相对明确排查路径清晰不像手工部署那样一个参数写错就找半天。当然kubeadm 也不是万能的。它默认不帮你装网络插件也不管你用什么容器运行时这些需要你自己补上。但这恰恰是好事因为你可以根据实际环境选择最合适的方案而不是被某个发行版绑死。2.2 容器运行时为什么选 Docker 而不是 containerdKubernetes 1.18 这个时间点Docker 还是最主流的选择containerd 虽然已经在后面追但生态和文档丰富度还差一截。更重要的是很多老环境的镜像仓库里只有 Docker 格式的镜像用 containerd 还得额外处理命名空间和配置徒增复杂度。这里有个关键点要注意Kubernetes 1.18 对 Docker 的版本有要求太新的 Docker 反而可能不兼容。我实测下来Docker 19.03 这个系列和 Kubernetes 1.18 配合最稳。如果你用的是 Ubuntu 18.04 自带的 Docker 版本大概率太旧需要手动升级或指定版本安装。2.3 网络插件选型Calico 还是 Flannel网络插件这块Flannel 和 Calico 是两个最常见的选项。Flannel 配置简单适合快速验证Calico 功能更强支持网络策略适合对隔离有要求的场景。在 Ubuntu 18.04 加 Kubernetes 1.18 这个组合里我倾向于先用 Flannel 把集群跑通确认基础功能没问题之后如果确实需要网络策略再换成 Calico。原因很简单Flannel 的故障点少出问题容易定位Calico 依赖 BGP 和 iptables 的配合在老内核上偶尔会有兼容性小毛病排查起来更费时间。提示不管你选哪个插件都要确保所有节点的内核模块加载正确尤其是 br_netfilter 和 overlay这两个是容器网络的基础。2.4 版本锁定与离线镜像准备这一步很多人会忽略但恰恰是最影响成功率的。Kubernetes 1.18 对应的组件版本必须锁死不能让它自动升级。具体来说kubeadm、kubelet、kubectl 三个包的版本要完全一致都是 1.18.x。如果你用 apt 安装一定要用 apt-mark hold 把它们锁住否则某次系统更新可能就把 kubelet 升到不兼容的版本集群直接挂掉。离线环境的话需要提前把所需镜像全部拉下来打包成 tar 文件再传到目标机器上加载。镜像列表可以用 kubeadm config images list 命令生成这个后面实操部分会详细讲。3. 系统环境准备与核心参数配置3.1 主机名与 hosts 解析的规范做法集群里每台机器的主机名必须唯一而且要和 hosts 文件里的解析一致。我见过太多因为主机名重复或者解析不对导致节点注册失败的案例。具体操作上用 hostnamectl set-hostname 设置主机名然后在 /etc/hosts 里把每个节点的 IP 和主机名对应写进去。注意不要只写 master 的所有节点都要互相能解析。如果你有内部 DNS那更好但 hosts 文件是最稳妥的兜底方案。# 在每台机器上执行替换为实际主机名 hostnamectl set-hostname k8s-master # 编辑 /etc/hosts加入所有节点的映射 cat /etc/hosts EOF 192.168.1.10 k8s-master 192.168.1.11 k8s-node1 192.168.1.12 k8s-node2 EOF3.2 关闭 swap 的必要性与操作细节Kubernetes 要求关闭 swap这不是随便定的规矩。kubelet 在计算节点资源的时候如果 swap 开着内存的可用量计算会不准可能导致调度决策出错。所以这一步必须做而且要做彻底。临时关闭用 swapoff -a但重启后会失效。永久关闭需要编辑 /etc/fstab把 swap 那一行注释掉。注意有些云主机的 swap 不是通过 fstab 管理的那就需要检查 systemd 的 swap 单元用 systemctl mask 把它屏蔽掉。# 临时关闭 swapoff -a # 永久关闭注释掉 fstab 中的 swap 行 sed -i /swap/s/^/#/ /etc/fstab # 验证 free -h3.3 内核模块加载与 sysctl 参数调优容器网络依赖几个内核模块必须确保它们在开机时自动加载。br_netfilter 负责网桥的流量过滤overlay 是 OverlayFS 文件系统的基础这两个缺一不可。sysctl 参数方面最核心的是 net.bridge.bridge-nf-call-iptables 和 net.ipv4.ip_forward。前者让网桥流量经过 iptables 处理后者开启 IP 转发。这两个如果不对Pod 之间可能通但 Pod 到外网就不通或者反过来。# 加载内核模块 cat /etc/modules-load.d/k8s.conf EOF br_netfilter overlay EOF modprobe br_netfilter modprobe overlay # 设置 sysctl 参数 cat /etc/sysctl.d/k8s.conf EOF net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sysctl --system注意有些 Ubuntu 18.04 的镜像里br_netfilter 模块可能被黑名单了需要检查 /etc/modprobe.d/ 下有没有相关配置有的话要移除或覆盖。3.4 防火墙与 SELinux 的处理策略Ubuntu 默认用的是 ufw不是 firewalld。在集群环境里我建议直接把 ufw 关掉因为 Kubernetes 自己会管理 iptables 规则ufw 的规则可能和它冲突。关掉之后用安全组或者网络 ACL 来做外层防护。SELinux 在 Ubuntu 上默认是不启用的所以不用像 CentOS 那样去 setenforce 0。但如果你手动装过 SELinux那还是要检查一下状态确保它是 disabled 或 permissive。# 关闭 ufw systemctl stop ufw systemctl disable ufw # 检查 SELinux 状态 sestatus 2/dev/null || echo SELinux not installed4. Docker 安装与 Kubernetes 组件部署实操4.1 Docker 版本选择与安装步骤前面说了Docker 19.03 和 Kubernetes 1.18 配合最稳。安装的时候不要直接用 apt install docker.io那个版本太旧。要用 Docker 官方的仓库来装。具体步骤是先装依赖包然后添加 Docker 的 GPG 密钥和仓库地址最后指定版本安装。安装完之后要配置 daemon.json把 cgroup driver 改成 systemd这一点非常关键因为 kubelet 默认也用 systemd两者不一致会导致 kubelet 启动失败。# 安装依赖 apt-get update apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common # 添加 Docker 官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - # 添加仓库 add-apt-repository deb [archamd64] https://download.docker.com/linux/ubuntu bionic stable # 安装指定版本 apt-get update apt-get install -y docker-ce5:19.03.15~3-0~ubuntu-bionic docker-ce-cli5:19.03.15~3-0~ubuntu-bionic containerd.io # 配置 daemon.json cat /etc/docker/daemon.json EOF { exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m }, storage-driver: overlay2 } EOF systemctl daemon-reload systemctl restart docker systemctl enable docker4.2 kubeadm、kubelet、kubectl 的安装与版本锁定这三个组件的版本必须一致都是 1.18.x。安装源用 Kubernetes 官方的 apt 仓库。装完之后立刻用 apt-mark hold 锁住防止意外升级。# 添加 Kubernetes 仓库 curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - cat /etc/apt/sources.list.d/kubernetes.list EOF deb https://apt.kubernetes.io/ kubernetes-xenial main EOF apt-get update apt-get install -y kubelet1.18.20-00 kubeadm1.18.20-00 kubectl1.18.20-00 # 锁定版本 apt-mark hold kubelet kubeadm kubectl # 验证版本 kubeadm version kubelet --version提示如果你的环境访问不了官方源可以提前把 deb 包下载好用 dpkg -i 安装效果一样。4.3 初始化 master 节点的完整命令与参数解读初始化 master 用 kubeadm init但直接跑默认参数可能会因为镜像拉不下来而卡住。所以要先指定镜像仓库国内环境可以用阿里云的镜像地址。命令里的参数逐个解释一下--image-repository 指定镜像仓库--kubernetes-version 锁定版本--pod-network-cidr 指定 Pod 网段这个要和后面网络插件的配置一致--apiserver-advertise-address 指定 API Server 对外通告的地址多网卡机器上必须指定否则可能选错网卡。kubeadm init \ --image-repositoryregistry.aliyuncs.com/google_containers \ --kubernetes-versionv1.18.20 \ --pod-network-cidr10.244.0.0/16 \ --apiserver-advertise-address192.168.1.10 \ --service-cidr10.96.0.0/12初始化成功后会输出一段 join 命令这个要保存好后面加节点要用。同时按照提示配置 kubectl 的 kubeconfig。mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config4.4 网络插件部署与节点加入Flannel 的部署很简单直接 apply 一个 yaml 就行。但要注意如果你的 Pod 网段不是默认的 10.244.0.0/16需要先下载 yaml 修改里面的网段配置再 apply。# 下载并修改网段如果需要 curl -O https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml # 编辑 kube-flannel.yml把 Network 字段改成你的 pod-network-cidr kubectl apply -f kube-flannel.yml节点加入用之前保存的 join 命令在 node 节点上执行。执行前确保 node 节点也完成了前面所有的系统准备工作。kubeadm join 192.168.1.10:6443 --token xxxxxx.xxxxxxxxxxxx \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx加入之后在 master 上执行 kubectl get nodes看到节点状态变成 Ready 就说明成功了。如果一直是 NotReady大概率是网络插件还没完全启动等一两分钟再查。5. 常见故障排查与避坑经验实录5.1 镜像拉取失败的排查路径镜像拉不下来是最常见的问题表现就是 kubeadm init 卡在某个步骤不动或者 kubelet 一直报 ImagePullBackOff。排查思路分三步先确认网络能不能通到镜像仓库再确认镜像名称和 tag 对不对最后检查 Docker 的配置有没有问题。如果是离线环境需要提前在有网的机器上把镜像拉下来用 docker save 导出成 tar传到目标机器后用 docker load 导入。kubeadm config images list 可以列出所有需要的镜像照着这个列表准备就行。# 列出所需镜像 kubeadm config images list --kubernetes-versionv1.18.20 # 导出镜像 docker save -o k8s-images.tar k8s.gcr.io/kube-apiserver:v1.18.20 ... # 导入镜像 docker load -i k8s-images.tar5.2 kubelet 启动失败的典型原因kubelet 起不来九成以上是 cgroup driver 不一致导致的。Docker 用 systemdkubelet 默认也用 systemd但如果 Docker 的 daemon.json 没配好它可能用的是 cgroupfs这时候 kubelet 就会报错。另一个常见原因是 swap 没关干净。有时候 fstab 注释了但 systemd 的 swap 单元还在需要额外 mask 掉。排查的时候用 journalctl -u kubelet -f 看日志报错信息一般都很明确。# 查看 kubelet 日志 journalctl -u kubelet -f # 检查 cgroup driver docker info | grep -i cgroup5.3 节点 NotReady 的排查顺序节点 NotReady 的原因很多我一般按这个顺序排查先看网络插件 Pod 是不是 Running再看节点上的 kube-proxy 有没有正常启动然后检查内核模块和 sysctl 参数最后看证书有没有过期。网络插件没起来是最常见的用 kubectl get pods -n kube-system 看一下 flannel 或 calico 的 Pod 状态。如果是 CrashLoopBackOff看日志找具体原因多半是网段配置不对或者内核模块没加载。现象可能原因排查命令节点 NotReady网络插件未就绪kubectl get pods -n kube-systemkubelet 反复重启cgroup driver 不一致journalctl -u kubeletPod 无法跨节点通信内核模块未加载lsmod | grep br_netfilter镜像拉取失败仓库地址不可达docker pull 测试证书错误证书过期或时间不同步kubeadm certs check-expiration5.4 时间同步与证书问题的隐藏坑这个问题很隐蔽但一旦出现就很难查。Kubernetes 的证书对时间敏感如果节点之间时间差太大证书验证会失败表现为节点加入不了或者 API 调用报 x509 错误。Ubuntu 18.04 默认用 systemd-timesyncd 做时间同步但有些环境里这个服务没启用或者 NTP 服务器配得不对。部署前一定要确认所有节点时间一致用 timedatectl 检查。# 检查时间同步状态 timedatectl status # 如果没同步手动配置 NTP apt-get install -y chrony systemctl enable chrony systemctl start chrony注意证书问题在集群跑了一段时间后才会暴露所以部署时最好把证书有效期检查加到日常巡检里。kubeadm 提供了 certs check-expiration 命令定期跑一下没坏处。6. 集群验证与日常维护要点6.1 部署一个测试应用验证集群功能集群搭好之后别急着上业务先跑一个简单的测试应用确认基础功能正常。我一般用 nginx 或者 busybox 做验证创建一个 Deployment 和一个 Service然后从不同节点访问看网络是否通。# 创建测试 Deployment kubectl create deployment nginx-test --imagenginx:1.18 # 暴露 Service kubectl expose deployment nginx-test --port80 --typeNodePort # 查看状态 kubectl get pods,svc -o wide如果 Pod 能正常 RunningService 能访问跨节点通信也没问题那这套集群的基础功能就算通了。接下来再根据实际需求去配置存储、Ingress、监控这些。6.2 版本锁定与升级的注意事项前面反复强调版本锁定这里再展开说一下。Kubernetes 的版本升级不是小事尤其是跨小版本升级必须按照官方推荐的顺序来。1.18 升 1.19 可以但 1.18 直接升 1.20 就可能出问题。升级前一定要备份 etcd 数据这个是最关键的。etcd 备份用 etcdctl snapshot save 命令备份文件要存到安全的地方。升级过程用 kubeadm upgrade plan 先看计划再按步骤执行。# 备份 etcd ETCDCTL_API3 etcdctl snapshot save /backup/etcd-snapshot.db \ --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 # 查看升级计划 kubeadm upgrade plan6.3 资源监控与日志收集的简易方案集群跑起来之后至少要有个基本的监控。资源占用用 kubectl top 就能看但需要先装 metrics-server。日志方面如果不想上 EFK 那套重家伙可以先用 kubectl logs 和 journalctl 顶着等业务量上来了再考虑集中式日志方案。metrics-server 的部署要注意版本兼容性1.18 对应的 metrics-server 版本不能太新。装好之后等几分钟kubectl top nodes 和 kubectl top pods 就能用了。# 部署 metrics-server kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml # 验证 kubectl top nodes提示metrics-server 默认需要证书验证如果集群用的是自签证书可能需要在启动参数里加 --kubelet-insecure-tls测试环境可以这么干生产环境还是要配好证书。6.4 我踩过的几个印象深刻的坑第一个坑是主机名大小写问题。有次我把主机名设成 K8s-Master结果 kubelet 注册的时候变成小写和 hosts 里的解析对不上节点一直 NotReady。后来统一用全小写问题解决。第二个坑是 Docker 的 storage-driver。Ubuntu 18.04 默认可能用 overlay2但如果内核版本太低overlay2 可能不支持需要降级到 overlay。这个用 docker info 看 Storage Driver 那一行就能确认。第三个坑是 Flannel 的网段和 Docker 默认网段冲突。Docker 默认用 172.17.0.0/16如果 Flannel 也配成这个网段就会打架。所以 Pod 网段最好避开 172.17用 10.244 这种。第四个坑是节点加入时 token 过期。kubeadm 生成的 token 默认 24 小时有效过期了就得重新生成。用 kubeadm token create 可以生成新的然后配合 --discovery-token-ca-cert-hash 重新加入。# 重新生成 token kubeadm token create --print-join-command这套东西说起来不复杂但每个环节都有细节一个不注意就可能卡住。我的建议是第一次部署的时候把每一步的输出都记下来形成自己的检查清单后面再装就快了。集群跑稳之后定期做健康检查证书有效期、etcd 状态、节点资源这些都要关注别等出问题了才去查。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑