首页 / 资讯中心 / 文章详情

从零搭建K8s与KubeSphere容器编排环境实战指南

从零搭建K8s与KubeSphere容器编排环境实战指南 ★ FEATURED ARTICLE
1. 从零搭建容器编排环境为什么选择这条技术路线很多团队在业务初期用几台云主机跑Docker Compose就能撑住可一旦服务数量超过十个、需要滚动更新、要做灰度发布、要按CPU和内存自动扩缩容裸Docker的短板就暴露得非常彻底。容器编排这件事Kubernetes下称K8s几乎是绕不开的选项但原生K8s的安装门槛和日常运维复杂度又让不少中小团队望而却步。我所在的团队大概在两年前也面临同样的抉择是硬啃原生K8s还是找一个带图形化管理面板的发行版来降低日常操作成本。最终我们选的是KubeSphere作为上层管理平台底层依然是标准K8s这样既保留了K8s的生态兼容性又让日常的部署、监控、日志查看变得对普通开发同学友好很多。这篇文章想聊的不是K8s是什么这种概念科普而是把一套可复现的部署路径完整讲清楚从机器规划、系统初始化、容器运行时选型到K8s集群拉起再到KubeSphere的安装与最小可用配置。中间会穿插大量我在实际部署中踩过的坑比如内核参数没调导致Pod频繁重启、镜像拉取超时、存储类没配好导致有状态服务起不来等等。适合的读者是有一定Linux基础、用过Docker、准备把业务往容器编排平台上迁移的运维或后端同学。如果你完全没接触过容器建议先把Docker的基本操作过一遍再来看这篇否则中间很多步骤会知其然不知其所以然。需要先说明一点本文的部署方案基于常见的生产实践总结具体版本号和参数需要根据你实际的硬件和网络环境做调整。我不会给出某个特定云厂商的绑定操作所有步骤都尽量做到环境无关你在自建机房、私有云或者公有云的裸金属实例上都能照着走。2. 部署前的机器规划与系统底座准备2.1 节点角色划分与最低配置推算K8s集群的节点分为控制平面节点Control Plane旧称Master和工作节点Worker。控制平面负责调度、API服务、etcd存储等核心职能工作节点负责实际跑业务容器。小规模场景下很多人会把控制平面和工作节点混部在一台机器上这在测试环境没问题但生产环境强烈建议分离原因后面会讲。配置方面我按经验给一个可落地的参考节点角色数量最低配置推荐配置说明控制平面1测试/ 3生产2C4G4C8G生产环境3节点保证etcd高可用工作节点2起4C8G8C16G起按业务容器实际资源需求叠加负载均衡12C2G2C4G生产环境需要测试可省略这里有个容易忽略的点etcd对磁盘IO非常敏感控制平面节点的系统盘一定要用SSD机械盘会导致etcd写入延迟飙升进而拖垮整个集群的API响应。我见过一个团队用普通云盘做控制平面结果每次创建Pod都要等十几秒排查了半天才发现是etcd的锅。操作系统我一般选Ubuntu 20.04/22.04 LTS或者CentOS 7.9CentOS 8已停止维护不建议新装。内核版本建议5.4以上低版本内核在cgroup v2和网络转发上会有兼容性问题。2.2 系统初始化那些不调就会出事的参数机器装好系统后别急着装容器运行时先把下面这些基础配置做掉。这些操作在每台节点上都要执行。关闭Swap。K8s的设计假设是节点内存可预测Swap会让内存统计失真导致调度器做出错误决策。执行swapoff -a sed -i /swap/s/^/#/ /etc/fstab加载内核模块并调整网络参数。容器网络依赖网桥转发和iptables默认内核参数下流量可能被丢弃cat /etc/modules-load.d/k8s.conf EOF overlay br_netfilter EOF modprobe overlay modprobe br_netfilter 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设置主机名和hosts解析。每台机器的主机名要唯一且所有节点能通过主机名互相解析。我习惯在/etc/hosts里写死避免依赖内网DNShostnamectl set-hostname k8s-master-01 # 在每台机器的/etc/hosts追加所有节点的IP和主机名映射时间同步。集群内证书校验、日志排序都依赖时间一致用chrony或systemd-timesyncd都行确保所有节点时间偏差在秒级以内。提示做完这些之后重启一次机器确认Swap确实没挂载、内核参数生效再进入下一步。我遇到过改完参数没重启结果br_netfilter模块没加载Calico网络插件起不来的情况。2.3 容器运行时选型containerd还是DockerK8s从1.24版本开始移除了对Dockershim的支持也就是说原生Docker作为容器运行时已经不被官方推荐了。现在主流选择是containerd或者CRI-O。containerd本身就是Docker底层的运行时剥离了Docker的镜像构建等上层功能更轻量也是目前社区最主流的选择。安装containerd以Ubuntu为例apt update apt install -y containerd mkdir -p /etc/containerd containerd config default /etc/containerd/config.toml关键一步修改config.toml里的SystemdCgroup参数。默认是false但K8s的kubelet默认用systemd管理cgroup两边不一致会导致Pod反复重启[plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true改完重启containerd并设为开机自启systemctl restart containerd systemctl enable containerd如果你之前习惯用Docker命令装完containerd后可以用crictl来调试容器命令和docker类似只是前缀换成crictl。需要配置/etc/crictl.yaml指向containerd的socket。3. K8s集群的拉起与网络插件落地3.1 kubeadm初始化控制平面安装kubeadm、kubelet、kubectl三件套。这里要注意版本锁定三个组件的版本必须一致否则会出现兼容问题apt install -y apt-transport-https ca-certificates curl curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | 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.28/deb/ / /etc/apt/sources.list.d/kubernetes.list apt update apt install -y kubelet1.28.0-1.1 kubeadm1.28.0-1.1 kubectl1.28.0-1.1 apt-mark hold kubelet kubeadm kubectlapt-mark hold这步很重要防止系统自动升级导致版本漂移。初始化控制平面。这里需要指定Pod网段要和后面网络插件的网段一致kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --pod-network-cidr10.244.0.0/16 \ --kubernetes-versionv1.28.0初始化成功后按提示配置kubectlmkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config3.2 网络插件选型Calico与Flannel的取舍网络插件是K8s集群里最容易出问题的组件之一。常见选择有Flannel和Calico。Flannel配置简单适合小规模集群但不支持网络策略NetworkPolicyCalico功能完整支持网络策略、BGP路由生产环境更推荐。我选Calico用它的operator模式安装kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yamlcustom-resources.yaml里的CIDR要和kubeadm init时指定的pod-network-cidr一致否则Pod之间无法通信。这个坑我踩过初始化时写10.244.0.0/16Calico默认配置是192.168.0.0/16结果Pod全部处于Pending状态排查了半天才发现是网段不匹配。安装完成后用下面命令确认所有Pod都是Runningkubectl get pods -n calico-system kubectl get nodes节点状态从NotReady变成Ready说明网络插件生效了。3.3 工作节点加入与集群验证在工作节点上执行kubeadm init输出的join命令格式类似kubeadm join 192.168.1.10:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxxtoken默认24小时过期如果过期了可以在控制平面用kubeadm token create --print-join-command重新生成。加入后回到控制平面执行kubectl get nodes确认所有节点Ready。然后跑一个测试Pod验证跨节点通信kubectl run test-nginx --imagenginx --replicas2 kubectl get pods -o wide如果两个Pod分布在不同节点且都能Running说明集群网络基本正常。这时候可以删掉测试Pod准备装KubeSphere。注意如果节点一直NotReady先看kubelet日志journalctl -u kubelet -f八成是容器运行时配置或者网络插件的问题。别急着重装日志里基本都能找到线索。4. KubeSphere的安装与最小可用配置4.1 为什么在K8s之上再套一层KubeSphere原生K8s的Dashboard功能比较基础日常运维中我们经常需要查看Pod的实时日志、监控CPU和内存曲线、配置告警规则、管理多租户权限、可视化CI/CD流水线。这些在原生K8s里要么没有要么需要额外装一堆组件。KubeSphere把这些能力整合到一个控制台里对团队里不熟悉kubectl的开发同学特别友好。KubeSphere的定位是以K8s为内核的分布式操作系统它本身不替代K8s而是在K8s之上提供管理界面和扩展功能。安装方式有All-in-One单节点测试和多节点生产部署两种。生产环境推荐用KubeKey工具来装它能同时处理K8s和KubeSphere的安装省去手动配K8s的步骤。但如果你已经有现成的K8s集群也可以直接在集群上装KubeSphere。4.2 在已有K8s集群上安装KubeSphere前置条件集群里要有默认StorageClass因为KubeSphere的很多组件需要持久化存储。如果没有可以先装一个本地存储方案测试环境用kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.24/deploy/local-path-storage.yaml kubectl patch storageclass local-path -p {metadata: {annotations:{storageclass.kubernetes.io/is-default-class:true}}}然后安装KubeSphere的核心组件。官方提供了ks-installer通过应用一个ClusterConfiguration来触发安装kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.4.1/kubesphere-installer.yaml kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.4.1/cluster-configuration.yaml安装过程会拉取大量镜像国内环境建议提前配置镜像加速。可以通过修改cluster-configuration.yaml里的spec.local_registry或者给containerd配置registry mirror来加速。查看安装进度kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l appks-install -o jsonpath{.items[0].metadata.name}) -f看到Installation is complete就说明装好了。然后查看控制台服务kubectl get svc -n kubesphere-system找到ks-console的NodePort用浏览器访问http://节点IP:端口默认账号admin密码P88w0rd。首次登录会要求改密码。4.3 安装后必做的几项配置开启常用组件。KubeSphere默认只装核心很多功能需要手动开启。编辑cluster-configuration.yaml把需要的组件设为true比如spec: monitoring: enabled: true logging: enabled: true alerting: enabled: true devops: enabled: true改完重新applyks-installer会检测到变更并安装对应组件。这个过程可能比较久取决于网络。配置多租户。KubeSphere的权限模型是企业空间-项目-用户三层。建议按团队划分企业空间按业务线划分项目然后给不同用户分配角色。别所有东西都塞在admin账号下后期权限管理会很乱。对接外部存储。生产环境一定要把默认StorageClass换成NFS、Ceph或者云厂商的块存储local-path只适合测试节点挂了数据就没了。提示KubeSphere的DevOps组件依赖Jenkins资源消耗比较大。如果集群规模小可以先不开等需要CI/CD的时候再启用。5. 部署过程中那些让人抓狂的坑5.1 镜像拉取失败最常见的拦路虎K8s和KubeSphere的组件镜像大多托管在海外仓库国内环境直接拉大概率超时。表现是Pod一直ImagePullBackOff。解决办法有两个一是给containerd配置registry mirror二是提前把镜像拉到本地再打tag。配置containerd mirror[plugins.io.containerd.grpc.v1.cri.registry.mirrors] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.docker.io] endpoint [https://你的镜像加速地址]改完重启containerd。注意K8s系统组件的镜像地址是k8s.gcr.io或registry.k8s.io这些也需要单独配mirror或者用kubeadm init时加--image-repository参数指定替代仓库。5.2 Pod一直Pending资源与调度问题Pending状态说明Pod没有被调度到任何节点。用kubectl describe pod看Events常见原因有节点资源不足CPU/内存请求超过节点可分配量、节点有污点Taint而Pod没有对应容忍Toleration、PVC没绑定成功。控制平面节点默认有污点不允许普通Pod调度上去。测试环境如果只有一台机器可以去掉污点kubectl taint nodes --all node-role.kubernetes.io/control-plane-生产环境别这么干控制平面就让它专心做控制平面的事。5.3 有状态服务起不来存储类没配对部署MySQL、Redis这类有状态服务时如果PVC一直Pending基本是StorageClass的问题。用kubectl get sc确认有没有默认存储类没有的话PVC不会自动绑定。另外要注意有些存储方案只支持ReadWriteOnce如果你多个Pod要同时挂同一个卷得用支持ReadWriteMany的方案比如NFS。5.4 节点NotReady从kubelet日志找答案节点突然NotReady先看kubelet状态systemctl status kubelet journalctl -u kubelet -n 100 --no-pager常见原因容器运行时挂了、磁盘满了kubelet有磁盘压力驱逐机制、证书过期。证书过期在集群运行一年后特别常见用kubeadm certs check-expiration检查kubeadm certs renew all续期。6. 集群跑起来之后的日常维护心得6.1 资源配额与限制别让一个Pod拖垮整个节点K8s默认不限制Pod的资源使用一个内存泄漏的容器能把节点内存吃光导致其他Pod被驱逐。所以每个工作负载都要配requests和limitsresources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mirequests影响调度调度器按requests找节点limits是硬上限。经验值是limits设为requests的2到4倍留出突发空间。但别设太大否则节点超卖严重高峰期会互相抢资源。6.2 监控告警提前发现比事后救火强KubeSphere自带的监控能看集群、节点、工作负载三个层级的指标。建议至少配几条告警节点CPU持续5分钟超过80%、节点内存超过85%、Pod重启次数超过5次、PVC使用率超过90%。这些告警通过邮件或webhook发出来能在用户投诉之前发现问题。6.3 备份etcd集群的命根子etcd存着整个集群的状态它挂了集群就没了。生产环境一定要定期备份ETCDCTL_API3 etcdctl snapshot save 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备份文件要传到集群外的存储别放本地。恢复的时候用etcdctl snapshot restore具体步骤官方文档写得很清楚但建议在测试环境先演练一遍真出事的时候才不会手忙脚乱。6.4 版本升级小步走别跳版K8s的版本升级不支持跨大版本比如1.26不能直接升到1.28得先升1.27。升级前先看官方Release Notes里的废弃API列表很多老的工作负载YAML在新版本里会报错。升级顺序是先控制平面再工作节点每升一个节点确认Ready再升下一个。KubeSphere的升级相对独立但也要注意和K8s版本的兼容矩阵。我在实际运维中的体会是容器编排平台的价值不在于装起来那一刻而在于日复一日的稳定运行。前期把节点规划、存储、监控、备份这些基础打牢后面能省掉大量救火时间。反过来如果为了快速上线跳过这些步骤后面迟早要还债。最后分享一个小技巧把集群的初始化脚本和所有配置都放进Git仓库管理新节点加入或者灾难恢复的时候照着仓库里的文档走一遍就能重建比凭记忆操作靠谱得多。
阅读完成 · 觉得有帮助?
咨询建站