资讯动态

Kubernetes集群部署实践:基于kubeadm、Calico与Harbor的完整方案

发布时间:2026/10/20 7:38:39 来源:尧图企业网站定制
1. 环境规划与版本选型1.1 硬件与操作系统要求先说点实际的很多人第一次搭Kubernetes集群上来就急着敲命令结果装到一半发现资源不够、内核版本不对、容器运行时起不来各种返工。我个人的建议是动手之前先把硬件和系统版本规划清楚这一步省下的时间绝对比你想象的要多。以我常用的这套三节点环境为例大致配置如下角色主机名配置操作系统Mastermaster014C / 8G / 50G磁盘CentOS 7.9 / Ubuntu 22.04Workerworker014C / 8G / 50G磁盘同上Workerworker024C / 8G / 50G磁盘同上如果是纯测试环境比如用虚拟机模拟Master节点2C / 4G也能跑但你还要部署Dashboard、Harbor这些组件内存不够的话会很吃力。这里建议Master至少4G内存Worker根据实际业务负载决定一般来说2~4G起步比较稳妥。另外磁盘方面Docker镜像和Harbor存储都会吃空间能给大就给大。操作系统方面CentOS 7.9和Ubuntu 22.04都是我实际验证过的只要内核版本达到要求3.10以上基本可以4.x更稳配合较新的Kubernetes版本都没有问题。这里多说一句尽量别用太老的操作系统版本比如CentOS 6这种早就EOL的坑会非常多。1.2 版本选型的考量Kubernetes的版本迭代速度很快但并不是越新越好。选版本的时候我一般遵循以下原则看社区稳定版本优先选择当前处于GA状态的稳定版本而非beta或RC版本。匹配kubeadm版本kubeadm的版本与Kubernetes版本必须一致例如你安装1.28.x的kubeadm对应的Kubernetes集群版本也是1.28.x。考虑容器运行时兼容性这里要重点说Kubernetes 1.24版本之后移除了对DockerShim的支持也就是说不再默认支持直接使用Docker作为容器运行时而是推荐使用containerd或是CRI-O。如果你还在用Docker或者计划用Docker那么要么选择1.23及以下版本要么就改用containerd。对于新项目我强烈建议直接上containerd配置不复杂而且官方支持到位。我这篇文章的操作过程基于Kubernetes 1.28.x containerd 1.7.x Calico 3.26.x这套组合这是一套经过大量生产环境验证的稳定搭配。如果是其他小版本操作流程大同小异只要注意版本配套关系即可。2. 基础环境初始化所有节点2.1 主机名与hosts解析集群节点之间通信需要解析主机名这一步比较简单但也容易被忽略。假如你的主机名还叫localhost或者随意取的名称后面的kubeadm init和join操作都会遇到麻烦。首先给每台机器设置一个有意义的主机名# 在master节点上执行 hostnamectl set-hostname master01 # 在worker节点上分别执行 hostnamectl set-hostname worker01 hostnamectl set-hostname worker02然后修改每台机器的/etc/hosts把几个节点的IP和主机名对应关系写进去。假设三个节点的IP分别是192.168.1.10、192.168.1.11、192.168.1.12那么在每台机器的hosts文件里追加192.168.1.10 master01 192.168.1.11 worker01 192.168.1.12 worker02这里有个小技巧虽然kubeadm在初始化时会在/etc/hosts里写入一些信息但在初始化之前先把主机名解析配好可以避免不少莫名其妙的问题。特别是当你有多网卡的时候Kubernetes组件对节点IP的识别非常敏感提前规划好IP和主机名对应关系后续排查会轻松很多。2.2 系统参数调优与依赖安装接下来需要做一些系统层面的调整。这步做得不到位后续容器运行时起不来、网络插件异常都会有连带反应。先关闭交换分区swap。Kubernetes官方要求每个节点必须关闭swap否则kubelet无法正常工作swapoff -a # 永久关闭注释掉 /etc/fstab 中的 swap 行 sed -i s/.*swap.*/#/ /etc/fstab然后是加载内核模块和调整网络参数。这里直接给出一套常规配置cat EOF | tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF modprobe overlay modprobe br_netfilter cat EOF | 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 sysctl --system这几个参数的作用overlay模块是container存储驱动所需br_netfilter让iptables能够处理桥接流量并确保Kubernetes的Service转发和网络策略可以正常工作ip_forward则开启IPv4转发。这些都是kubeadm安装的标准前置条件缺一个后面都会产生连锁问题。另外如果你的操作系统版本比较老可能还需要关闭firewalld或者放行相应端口。这里我的做法是在测试环境直接关闭防火墙systemctl stop firewalld systemctl disable firewalld生产环境建议使用安全组规则或firewalld精确放行但这里不展开细说。SELinux也建议先设为permissive或disabled否则容器挂载目录和网络命名空间的限制很容易导致权限错误。2.3 容器运行时安装containerd前面我提到新版本Kubernetes直接使用containerd作为容器运行时。这里把安装和配置过程演示一遍。以CentOS环境为例先配置Docker的yum源containerd也在这个源里然后安装yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install -y containerd.io安装完之后containerd会生成一个默认配置但我们需要修改它的SystemdCgroup参数。因为Kubernetes的kubelet默认使用cgroupfs或systemd cgroup驱动而containerd需要与其保持一致否则kubelet和容器运行时会各自为政轻则日志刷警告重则节点状态异常。直接生成默认配置然后手动修改containerd config default /etc/containerd/config.toml编辑/etc/containerd/config.toml找到SystemdCgroup这行将其改为true[plugins.io.containerd.grpc.v1.cri] systemd_cgroup true另外由于在国内拉取gcr.io镜像很容易超时推荐设置一个镜像加速器地址。在config.toml中找到sandbox_image把默认的pause镜像地址替换为国内可用的源例如sandbox_image registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.9这一步可以避免后续初始化集群时因为pause镜像拉取失败而整体卡住。改完之后重启containerd并设置开机自启systemctl daemon-reload systemctl restart containerd systemctl enable containerd提示containerd安装好之后ctr命令可以用来测试拉取镜像但Kubernetes使用的是containerd的CRI插件所以测试请使用crictl安装方法可参照kubernetes官方工具也可以通过crictl的静态二进制覆盖安装。注意crictl的配置文件与containerd的endpoint路径要一致否则也会出现连接不上运行时的情况。3. 使用Kubeadm部署Kubernetes控制平面3.1 配置yum源并安装kubeadm / kubelet / kubectl这里以国内的镜像源为例按Google官方源配置也可以但国内环境太容易超时所以通常建议直接用阿里云镜像源cat EOF /etc/yum.repos.d/kubernetes.repo [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled1 gpgcheck1 repo_gpgcheck1 gpgkeyhttps://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF然后安装指定版本的kubeadm、kubelet、kubectlyum install -y kubeadm-1.28.* kubelet-1.28.* kubectl-1.28.*安装完成后把kubelet设置为开机自启注意暂时不要启动因为还没有集群配置systemctl enable kubelet有一点要提前说明kubelet是集群中每个节点都会运行的组件它负责启动容器、挂载存储、上报节点状态等。kubectl只是管理工具安装在Master即可。kubeadm则是初始化集群和加入节点的命令工具。3.2 初始化Master节点一切准备就绪后在master01上执行kubeadm init。这里需要指定Pod网络的CIDR因为后面的CNI插件Calico要使用这段IP段来分配Pod IP。kubeadm init \ --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \ --kubernetes-version v1.28.2 \ --pod-network-cidr192.168.0.0/16 \ --apiserver-advertise-address192.168.1.10参数解释--image-repository指定镜像仓库地址默认是registry.k8s.io在国内环境很难拉取改成国内镜像仓库会快很多。--kubernetes-version必须与你要安装的版本一致这里写成v1.28.2你可以根据实际kubeadm版本调整。--pod-network-cidrPod网络的网段Calico默认使用192.168.0.0/16。这个网段要提前规划好不要和你的业务网段、Service网段冲突。--apiserver-advertise-addressMaster节点对外提供API服务的IP。如果机器只有一张网卡可以不指定kubeadm会自动识别但如果有多网卡强烈建议显式指定否则后面kubectl和所有组件连接API Server都可能连错地址。整个过程会经过拉取镜像、生成证书、生成配置文件、启动控制平面组件etcd、apiserver、scheduler、controller-manager这些步骤。看到以下输出说明Master初始化成功Your Kubernetes control-plane has initialized successfully! ...根据输出的提示配置kubectl访问集群mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config然后执行kubectl get node你会看到master节点状态是NotReady这是正常的因为CNI网络插件还没有部署。不过控制平面组件应该都是Running你可以通过kubectl get pods -n kube-system查看。3.3 加入Worker节点Master初始化成功后kubeadm会在输出末尾给你一长串kubeadm join命令里面包含一个token和一个ca证书哈希。在worker01和worker02上分别执行这条命令kubeadm join 192.168.1.10:6443 --token token \ --discovery-token-ca-cert-hash sha256:hash如果token过期了也不用重新初始化集群。在master节点上执行以下命令重新生成kubeadm token create --print-join-command执行结束后分别在worker节点上确认加入成功。几条常用的查看命令kubectl get nodes kubectl get pods -n kube-system -o wide提示如果执行kubeadm join时提示token无效先检查Master节点和Worker节点的时间是否同步时间偏差大会导致证书校验失败。4. 网络插件部署与验证4.1 选择CNI插件Kubernetes本身不负责Pod网络的实现需要借助CNI插件来打通节点之间的网络。市面上常见的有Flannel、Calico、Weave、Cilium等选型上的讲究也多说两句Flannel配置简单功能基础性能一般适合快速测试。Calico支持NetworkPolicy性能较好功能丰富是目前生产环境使用最广的方案。我强烈推荐Calico。Cilium基于eBPF的高性能方案功能强大但上手门槛较高如果你的团队对网络和安全策略有较高要求可以尝试。4.2 部署CalicoCalico的部署方式很简单直接应用它的manifests文件即可。先下载Calico提供的yaml文件curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml注意检查一下文件中的CALICO_IPV4POOL_CIDR变量是否和kubeadm初始化时指定的Pod网段一致。默认情况下如果kubeadm使用了192.168.0.0/16在Calico的yaml中搜到下面这一段- name: CALICO_IPV4POOL_CIDR value: 192.168.0.0/16假如不一致就改成你自己的Pod网段。然后应用kubectl apply -f calico.yaml等待Pod状态变为Runningkubectl get pods -n kube-system -l k8s-appcalico-node全部Running之后再等一下然后看看节点的状态kubectl get nodes这个时候三个节点应该都处于Ready状态了。如果你用了多网卡Calico可能出现探测网卡选错的情况一个常见的解决方式是在calico-node的DaemonSet环境变量里指定IP_AUTODETECTION_METHODinterfaceeth.*让Calico选以eth开头的网卡。首次搭建集群看到所有节点都变成Ready的那一刻心情还是很舒服的。不过别高兴太早接下来还有Dashboard和Harbor等着我们。5. Dashboard部署与访问5.1 部署DashboardDashboard是Kubernetes官方提供的Web UI管理工具通过它可以直观查看工作负载、服务、存储等资源的状态。虽然命令行更灵活但可视化面板在排查问题时确实能节省不少时间。部署Dashboard的方式有好几种最简单的是直接使用官方yamlkubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml查看Dashboard相关Pod是否正常运行kubectl get pods -n kubernetes-dashboard5.2 创建访问账号并获取Token默认情况下Dashboard的ServiceAccount只有很基础的权限直接访问时页面会提示找不到资源。我们需要自己创建一个管理员账号# dashboard-admin.yaml apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard应用并获取Tokenkubectl apply -f dashboard-admin.yaml kubectl -n kubernetes-dashboard create token admin-user输出来的就是用于登录Dashboard的Token。5.3 访问方式的配置Dashboard默认通过ClusterIP提供服务外部无法直接访问。我一般把Dashboard的Service改成NodePort或直接使用kubectl proxy。方案一使用NodePort方式。编辑kubernetes-dashboard这个Servicekubectl edit svc -n kubernetes-dashboard kubernetes-dashboard把type从ClusterIP改为NodePortspec: type: NodePort ports: - port: 443 targetPort: 8443 nodePort: 30000然后通过任意节点IP:30000访问Dashboard。方案二使用kubectl proxy临时转发kubectl proxy然后访问http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/。需要注意的是方案一暴露的端口是HTTPS的浏览器访问时会有证书警告这属于正常现象。如果想彻底解决证书问题可以给Dashboard配置正式证书或自建CA证书这里不展开讲。提示生产环境建议通过Ingress网关暴露Dashboard并配合OIDC或LDAP做身份认证不要直接把NodePort暴露到公网。6. Harbor镜像仓库部署与集成6.1 Harbor是什么为什么需要它在真实的开发流程中我们构建好镜像后不可能都在本地直接使用通常需要推送到一个统一的镜像仓库里然后让Kubernetes从仓库拉取镜像。Harbor就是一个企业级的镜像仓库方案功能很全包括镜像存储、镜像复制、漏洞扫描、权限控制等。之前有不少朋友问我直接用Docker Hub不行吗行是行但企业内网环境里无论是效率还是安全都难以保证Harbor私有化部署可控性高而且它和Kubernetes的集成并不复杂。6.2 部署HarborHarbor的部署有两种主流方式一种是基于Docker Compose适合快速测试另一种是基于Helm适合Kubernetes内部署。这里介绍更常见的Docker Compose方式毕竟很多人是先建好K8S集群再单独拿一台机器或直接在Worker上部署Harbor。首先准备Harbor的离线安装包选择最新的stable版本比如v2.9.x。解压后有install.sh和harbor.yml配置文件。编辑harbor.yml重点关注几个关键项hostname: harbor.example.com # 实际上可用IP或域名 http: port: 80 harbor_admin_password: Harbor12345 # 管理员密码 data_volume: /data/harbor # 数据存储目录如果计划通过HTTPS访问还需要配置证书和https段。但如果我们只是内网使用先走HTTP反而省事注意后面配置K8S拉取私有镜像时需要处理一下insecure-registries。然后在Harbor解压目录下执行./install.sh这个过程会拉取多个Harbor组件镜像并启动包括nginx负责外部网关和TLS终止portalHarbor的Web界面core核心API服务registry镜像存储服务redis缓存database元数据存储启动完成后浏览器访问http://harbor-ip就可以打开Harbor管理界面用配置的admin账户登录。如果是在Kubernetes节点上直接部署Harbor注意服务占用的端口不要和Kubernetes的NodePort区间默认30000-32767冲突。不过由于Harbor默认使用80端口一般没有问题。6.3 配置Kubernetes访问Harbor私有仓库这其实就是配置kubelet拉取私有镜像的能力。Kubernetes中从私有仓库拉取镜像的方式一般是创建imagePullSecret然后将其关联到Deployment或ServiceAccount上。首先在Docker客户端登录Harbor生成认证信息docker login http://harbor-ip然后在Kubernetes里创建Secretkubectl create secret docker-registry harbor-secret \ --namespacedefault \ --docker-serverharbor-ip \ --docker-usernameadmin \ --docker-passwordpassword \ --docker-emailadminexample.com在编写Deployment时直接在Pod模板中指定imagePullSecretsapiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 2 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: imagePullSecrets: - name: harbor-secret containers: - name: my-app image: harbor-ip/library/my-app:latest这里有个细节所有Worker节点上的容器运行时含containerd也必须信任Harbor的HTTP地址。也就是说需要在每个节点的/etc/containerd/config.toml中添加Harbor到registry.mirrors或registry.configs的配置里。对于containerd配置方式如下[plugins.io.containerd.grpc.v1.cri.registry] [plugins.io.containerd.grpc.v1.cri.registry.mirrors] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.harbor-ip] endpoint [http://harbor-ip] [plugins.io.containerd.grpc.v1.cri.registry.configs] [plugins.io.containerd.grpc.v1.cri.registry.configs.harbor-ip.auth] username admin password password修改完在每台节点上重启containerdsystemctl restart containerd到此为止整个部署链路就完整了kubeadm部署集群Calico提供网络Dashboard做可视化管理Harbor负责镜像的存储和分发。7. 常见问题与排查经验部署过程中我踩过的坑不少这里挑几个典型问题整理成速查表希望能帮大家少走弯路。现象可能原因解决思路kubeadm init卡在拉取pause镜像网络原因无法访问默认镜像仓库使用--image-repository参数或手动ctr -n k8s.io pull预拉取节点显示NotReadyCNI插件未部署或Calico网段与Pod网段不一致检查calico-system命名空间下的Pod日志确认CALICO_IPV4POOL_CIDRkubectl get nodes显示No resourceskubeconfig文件没配置或配置错误检查$HOME/.kube/config是否存在确认admin.conf内容Dashboard访问时提示ForbiddenServiceAccount权限不足创建ClusterRoleBinding绑定cluster-admin从Harbor拉取镜像失败提示x509证书未配置insecure-registries或containerd trust在containerd配置中增加对应Harbor的mirrors和configskubelet反复启动失败没有关闭swap或cgroup驱动不一致执行swapoff -a修改containerd的SystemdCgrouptrue并重启Node加入集群后一直NotReady且kubelet日志报错找不到CNI配置网络插件未安装或安装顺序错误确保先部署Calico/Flannel后再检查节点状态查看/var/lib/kubelet/kubelet.log再分享两个我实际调试过程中总结的思路第一日志永远是第一排查入口。kubelet日志看journalctl -u kubelet -fPod状态异常看kubectl describe pod name -n namespaceContainer Runtime状态看crictl ps -a。这些命令组合起来基本上90%的问题都能定位。第二版本配合问题最隐蔽。很多人喜欢把各组件都升级到“最新版本”但kubeadm、kubelet、kubectl以及containerd、CNI插件这些工具版本之间是有配套关系的。比如Kubernetes 1.28要求containerd不低于1.7.x如果你的containerd是1.6甚至更低节点就会经常出现起不来或者RT超时。建议按官方发布的版本兼容矩阵来选型别一味追求新。还有一个经常被忽略的点如果你使用云服务器安全组防火墙一定要放行所需端口包括Master的6443、10250以及各节点之间的TCP/UDP端口。如果在本地虚拟机上测试确认VMware或VirtualBox的网卡网络类型是桥接模式否则节点之间网络不通集群初始化也会失败。写在最后的经验整套东西搭建下来流程并算不上复杂真正需要花精力的是理解每个组件的角色和它们之间的协作关系。kubeadm把控制平面从0到1拉起简化了证书、etcd等繁琐步骤Calico打理Pod网络Dashboard提供一个不错的可视化入口Harbor则把镜像的构建、分发和拉取闭环打通。四者配合好了一套可用的Kubernetes集群运维基础设施也就成型了。我自己的体会是第一次搭建时不要追求一步到位先顺手部署一遍理解每一步在做什么之后如果有余力再去研究高可用例如kubeadm部署多个控制平面节点、Ingress接入、监控告警等进阶方向。希望这篇文章能让你少踩一点坑一次把集群搭起来。

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

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

免费获取报价 →
↑