Kubernetes集群完整搭建步骤
kubernetes集群完整搭建步骤
使用Ubuntu搭建k8s集群的完整步骤,包含常见错误解决办法
前言
k8s介绍
用于自动部署、扩展和管理“容器化应用程序”的开源系统
kubernetes,是一个全新的基于容器技术的分布式架构领先方案,是谷歌严格保密十几年的秘密武器—-Borg系统的一个开源版本,于2014年9月发布第一个版本,2015年7月发布第一个正式版本。
kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:
- 自我修复:一旦某一个容器崩溃,能够在1秒中左右迅速启动新的容器
- 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
- 服务发现:服务可以通过自动发现的形式找到它所依赖的服务,想要什么服务就自动去寻找
- 负载均衡:如果一个服务启动了多个容器,能够自动实现请求的负载均衡
- 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
- 存储编排:可以根据容器自身的需求自动创建存储卷
从上图中可以看出k8s的整体结构,一个k8s集群主要分为两类节点,一类是master节点,一类是工作节点,也就是主节点和从节点,具体的区别如下:
- 主节点主要用来管理集群,接受客户端的请求,安排容器的执行并且运行控制循环
- 从节点主要用来部署应用,听从主节点的调度
环境规划
集群类型
kubernetes集群大体上分为两类:一主多从和多主多从
- 一主多从:一台master,多台node,搭建简单,但是master出现错误,整个集群不再可用
- 多主多从:多台master,多台node,搭建麻烦,但是容错率高
为了简单,本文中使用一主两从
安装方式
目前生产部署Kubernetes 集群主要有两种方式:
1.kubeadm(本文中采用)
Kubeadm 是一个K8s 部署工具,提供kubeadm init 和kubeadm join,用于快速部署Kubernetes 集群。
官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/
2.二进制包
从github 下载发行版的二进制包,手动部署每个组件,组成Kubernetes 集群。
Kubeadm 降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易可控,推荐使用二进制包部署Kubernetes 集群,虽然手动部署麻烦点,期间可以学习很多工作原理,利于后期维护。
主机规划
服务器ip | 主机名 | 备注 |
---|---|---|
222.27.255.211 | master | master node |
222.27.255.211 | node1 | work node |
222.27.255.211 | node2 | work node |
上面三台主机对外暴露端口不一样
安装步骤
连接服务器
为了部署一个kubernetes集群,首先需要通过远程工具连接集群中的每一个主机,下面提供master节点的连接方式,工作节点的连接方式类似:
- 新建连接
按照服务器配置中的ip和端口号进行配置,之后点击用户身份验证
- 配置用户名和密码
按照自己主机的用户名和密码连接到master主机上
- 配置xshell
按照如图方式配置xshell之后,实现左键选中,右键自动粘贴,提升效率
- 连接成功
提示未知主机秘钥,点击"接受并保存"
出现如图效果,证明连接成功
- 配置主机名,方便辨认
至此master节点的基本配置完成,两个工作节点按照以上操作连接并修改自己的主机名
批量操作
为了简化操作步骤,避免重复输入,xshell提供了批量操作功能,实现一处输入,多处运行
- 连接所有想要批量操作的主机
- 批量操作
>
选择将发送键入到已连接的会话,此时可以批量管理k8s集群
- 测试
将窗口垂直和水平分割之后,三个窗口可以显示在同一个屏幕中
确保所有主机的状态都是
off
,之后输入hostname
查看之前的主机名配置是否生效,出现如图状态说明配置成功
- 查看三台主机ip,输入
ifconfig
即可
可以看到三台主机处于同一个网段,子网掩码一致,后期节点通信时就是用下面的ip
主机名 | 主机ip | 子网掩码 |
---|---|---|
master | 192.168.1.24 | 255.255.255.0 |
node1 | 192.168.1.25 | 255.255.255.0 |
node2 | 192.168.1.27 | 255.255.255.0 |
环境初始化
为了安装k8s集群,将三台主机配置好后,还需要进行环境初始化
为了操作方便,以下操作全部都在root用户下进行,切换root用户的命令为:
su root
,之后按照提示输入root用户的密码即可
- 查看ubuntu版本
本次实验中采用
ubuntu 22.04.2 LTS
版本
配置主机名解析,配置之后按照主机名即可访问对应主机
主机的hosts文件路径在
/etc/hosts
中
|
|
以上操作要确保hosts有写入权限
如果没有写入权限,执行
sudo chmod +w /etc/hosts
添加写入权限,或者直接切换到root用户,命令为su root
,之后输入root用户的密码即可在node1和node2中ping master出现下图中的效果说明配置成功
- 同步系统时间,k8s要求集群中的节点时间必须一致,所以这里使用
chronyd
服务从网络同步时间
|
|
禁用
iptables
和firewall
服务禁用iptables服务的原因是因为k8s和docker在运行的过程中会产生大量的iptables规则实现转发,为了不让这些规则与系统规则混淆,直接关闭iptables服务
禁用firewall服务是为了节点之间通信时不会产生一些莫名其妙的错误
|
|
- 禁用selinux服务
|
|
出现下图中的状态说明配置生效
禁用swap分区
启用swap分区会对系统的性能产生负面的影响,所以k8s要求禁用swap分区
|
|
出现下图效果说明配置生效
- 修改linux的内核参数
|
|
出现以下效果说明配置成功
配置ipvs功能
在k8s中有两种代理模型,这里选择性能更高的ipvs
|
|
重启服务器
重启服务器查看selinux和swap配置是否生效
|
|
出现下面的效果说明配置生效:
安装必备组件
安装docker
- 切换镜像源
|
|
|
|
添加一个配置文件
docker默认使用cgroupfs作为Cgroup Drive,但是k8s推荐使用systemd,所以这里修改配置
|
|
使用docker info | grep -i "Cgroup Driver"
查看配置是否生效
使用docker -v
查看docker版本
测试docker
安装k8s组件
- 切换镜像源
|
|
- 安装kubuadm、kubulet、kubuctl
|
|
- 配置kubulet的cgroup
|
|
上面的步骤三台主机都需要操作
上面的步骤三台主机都需要操作
上面的步骤三台主机都需要操作
集群初始化
使用kubeadm init
对集群初始化,kubeadm会自动下载apiserver,controller-manager等镜像,但是由于网络原因可能下载失败,所以提供一个其他的方法:
- 从阿里云下载对应镜像
- 集群初始化(master节点操作)
|
|
出现如下效果证明集群初始化成功:
执行制定指令
1 2 3
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
查看集群状态
配置主节点网络
由于github需要外网访问,所以手动下载,之后上传到服务器中
将文件放在/目录下即可
提供修改之后的文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
apiVersion: v1 kind: Namespace metadata: labels: k8s-app: flannel pod-security.kubernetes.io/enforce: privileged name: kube-flannel --- apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-app: flannel name: flannel namespace: kube-flannel --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: k8s-app: flannel name: flannel rules: - apiGroups: - "" resources: - pods verbs: - get - apiGroups: - "" resources: - nodes verbs: - get - list - watch - apiGroups: - "" resources: - nodes/status verbs: - patch - apiGroups: - networking.k8s.io resources: - clustercidrs verbs: - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: k8s-app: flannel name: flannel roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: flannel subjects: - kind: ServiceAccount name: flannel namespace: kube-flannel --- apiVersion: v1 data: cni-conf.json: | { "name": "cbr0", "cniVersion": "0.3.1", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": { "portMappings": true } } ] } net-conf.json: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan" } } kind: ConfigMap metadata: labels: app: flannel k8s-app: flannel tier: node name: kube-flannel-cfg namespace: kube-flannel --- apiVersion: apps/v1 kind: DaemonSet metadata: labels: app: flannel k8s-app: flannel tier: node name: kube-flannel-ds namespace: kube-flannel spec: selector: matchLabels: app: flannel k8s-app: flannel template: metadata: labels: app: flannel k8s-app: flannel tier: node spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/os operator: In values: - linux containers: - args: - --ip-masq - --kube-subnet-mgr - --iface=eno2 # master的ip在哪就写哪个 command: - /opt/bin/flanneld env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: EVENT_QUEUE_DEPTH value: "5000" image: docker.io/flannel/flannel:v0.22.0 name: kube-flannel resources: requests: cpu: 100m memory: 50Mi securityContext: capabilities: add: - NET_ADMIN - NET_RAW privileged: false volumeMounts: - mountPath: /run/flannel name: run - mountPath: /etc/kube-flannel/ name: flannel-cfg - mountPath: /run/xtables.lock name: xtables-lock hostNetwork: true initContainers: - args: - -f - /flannel - /opt/cni/bin/flannel command: - cp image: docker.io/flannel/flannel-cni-plugin:v1.1.2 name: install-cni-plugin volumeMounts: - mountPath: /opt/cni/bin name: cni-plugin - args: - -f - /etc/kube-flannel/cni-conf.json - /etc/cni/net.d/10-flannel.conflist command: - cp image: docker.io/flannel/flannel:v0.22.0 name: install-cni volumeMounts: - mountPath: /etc/cni/net.d name: cni - mountPath: /etc/kube-flannel/ name: flannel-cfg priorityClassName: system-node-critical serviceAccountName: flannel tolerations: - effect: NoSchedule operator: Exists volumes: - hostPath: path: /run/flannel name: run - hostPath: path: /opt/cni/bin name: cni-plugin - hostPath: path: /etc/cni/net.d name: cni - configMap: name: kube-flannel-cfg name: flannel-cfg - hostPath: path: /run/xtables.lock type: FileOrCreate name: xtables-lock
运行下面的命令配置集群
1
kubectl apply -f kube-flannel.yml
显示created和configured即可
监控应用的进度
1
watch kubectl get pods --all-namespaces
显示如下效果说明网络配置成功
将工作节点加入集群
|
|
显示如下效果证明节点加入成功
看到节点的状态为NotReady,等待节点自动加载完毕,会显示Ready,约三分钟后,显示如下效果:
环境测试
- 部署nginx
在集群中部署一个nginx,查看集群是否安装成功
操作时,只需要通过master执行即可,k8s自动管理工作节点
|
|
- 查看nginx部署情况
|
|
查看nginx被部署到了node2节点上
可以看到集群的变化,对外暴露端口为32737,也就是说,使用node2
的ip+32737就可以访问到节点内部80端口对应的nginx,测试如下:
至此k8s集群部署完毕
错误解决方法
同步节点时间时使用chronyd服务显示以下错误
|
|
查看selinux状态出现以下错误:
直接按照提示安装
selinux-utils
即可运行ipvs.modules脚本显示下面的错误
版本出了问题,此时将脚本中的
nf_conntrack_ipv4
改成nf_conntrack
即可
- 集群初始化安装镜像时出现以下错误
确保当前用户是root,如果还是出现错误,重启docker服务即可:
systemctl restart docker
集群初始化使用kubeadm init出现以下错误
更换
kubernetes-version
的版本如果kubeadm init提示如下信息
说明docker版本不兼容,需要安装指定版本docker
- kubeadm初始化时显示如下错误
依次执行下面的命令
|
|
- kubeadm init出现以下问题
|
|
- kubeadm init出现以下问题
直接删除对应的文件即可
k8s的多网卡节点之间通信出现问题
存在多个网卡时,k8s不知道以哪个网卡进行通信,需要手动指定,在网卡配置时,需要在配置文件中更改参数,配置文件的下载地址 点这里
iface指定通信的网卡
kubeadm init出现以下问题
运行以下命令之后重新运行kubeadm init
|
|
如果还是不行,尝试重装k8s,确保之前的版本完全卸载,卸载教程 点这里
- apt update一直连接的是google镜像源
进入/etc/apt/sources.list.d目录下
查看目录结构
只保留上面两个文件即可
- 安装docker报错
1.查看系统版本
- 发现系统的codename为jammy,此时下载的docker版本也需要有jammy后缀
上述操作保证docker被完全卸载
13.初始化k8s集群报错,首先检查docker与k8s的版本 对应关系 ,例如,以k8s v1.21为例:
发现支持的最新docker版本为20.10,所以不要超过这个版本
安装docker指定不了版本,提供一个笨办法
- 先安装docker-ce并指定版本,此时docker-ce-cli为最新版本
- 之后使用aptitude降级
kubeadm join时卡在
master的6443端口未开放,打开master的6443端口即可正常加入
kubectl get cs显示unhealthy
需要修改配置文件,文件路径为:
/etc/kubernetes/manifests
分别将kube-scheduler.yaml kube-controller-manager.yaml
文件中的port=0
注释掉即可
无法通过ip+端口的方式访问部署的应用
先查看部署的应用在哪个节点上,之后通过节点ip+端口的方式访问
以nginx为例,
查看nginx的名称(nginx-65c4bffcb6-zphwj)
找到nginx部署在哪个节点上(node2)
访问(192.168.1.27:32737),这个端口号为集群内部端口号
可以通过
kubectl get service
获得
总结
k8s部署过程中存在诸多问题,最常见的问题如下:
- docker无法指定版本,k8s与docker之间有版本对应关系
- k8s节点之间通信对于多网卡设备来说需要指定网卡
- k8s部署时卡在某一步不动
以上问题按照教程还不能完美解决,建议重装对应组件