K8S集群搭建
K8S的集群大体上分为两类:一主多从与多主多从。
- 一主多从: 存在单机故障风险,搭建简单,适用于测试环境
- 多主多从: 搭建麻烦,安全性高,适用于生产环境
安装: 有三种安装方式:minkube(快速单间单节点k8s的工具), kubeadm快速搭建k8s集群的工具, 二进制包(从官网一个一个下,比较麻烦但是理解的更深刻)
咱就是说坑踩多了就老老实实的跟着教程走:
- 关闭swap, 关闭防火墙(ufw), 写入主机名, 设置时戳:
(Tips: swap 指允许我们使用虚存, 必须禁用放置性能抖动。主要是k8s这么要求的)
sudo nano /etc/hosts # 设置主机名
sudo ufw disable # 关闭防火墙
sudo nano /etc/fstab # 关闭swap
sudo timedatectl set-timezone Asia/Shanghai # 设置时间戳保持相同
# 关于为什么centos需要关闭selinux而ubuntu不需要,,兄弟你确定你装selinux了么
- 安装docker, 按照官方文档来就行,或者https://docs.docker.com/engine/install/ubuntu/
- 安装kubeadm, kubectl, kubelet:
# 更新并与允许 curl HTTPs的访问,没装过的装一下
# sudo apt-get update && sudo apt-get install -y apt-transport-https
# 去阿里云去搞一个密钥。 注,这句话只能由root运行,不也能使用sudo。畏怯一般来说都要运行这句话的
curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
#新增源
sudo tee /etc/apt/sources.list.d/kubernetes.list <<EOF
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
# 更新并安装三组件: kubelet, kubeadm, kubectl
sudo apt-get install -y kubelet kubeadm kubectl
# 遇到的问题1:缺少依赖,缺少啥咱就安啥
The following packages have unmet dependencies:
kubelet : Depends: ebtables but it is not going to be installed
E: Unable to correct problems, you have held broken packages.
sudo apt-get install ebtables
# 遇到问题二,版本不兼容
kubelet : Depends: iptables (>= 1.4.21)
E: Unable to correct problems, you have held broken packages.
# 升级, 核心包版本不兼容
apt-get upgrade iptables
iptables : Depends: libip4tc0 (= 1.6.1-2ubuntu2) but it is not going to be installed
Depends: libip6tc0 (= 1.6.1-2ubuntu2) but it is not going to be installed
Depends: libiptc0 (= 1.6.1-2ubuntu2) but it is not going to be installed
Depends: libxtables12 (= 1.6.1-2ubuntu2) but 1.8.4-3ubuntu2 is to be installed
# 这里报错更高版本的包已经装过了,坑点,不要卸载这个更高版本的包(笔者的一时手欠加忘拍快照直接报废了一个系统),直接安装需要的版本的包即可,不然系统直接挂了
apt-get install libxtables12=1.6.1-2ubuntu2
# 之后递归向上更新即可
apt-get upgrade iptables
sudo apt-get install -y kubelet kubeadm kubectl
- 初始化:
# 这里本来可以设置apiserver和版本,但是我的版本是一样的再加上设不设置都一样我就没管
kubeadm init \
# 设置镜像源。如果不设置就需要翻墙
--image-repository registry.aliyuncs.com/google_containers \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
# 这里坑点巨多,我接下来讲解我遇到的坑
- 如果你想在公网搭建,并且有一台有公网IP的机子,你首先要明确:
- 是别人家的云服务器?恭喜你,现在市面上的云服务器多半是虚拟网卡的。什么意思呢,就是说你去解析127.0.0.1的时候,它找不到对应的公网地址。在init初识化状态中,你定义了apiserver他会尝试去解析127.0.0.1 与你apiserver的关系。但最后很遗憾的它连不上,然后就会卡死,超时,初识化失败。这里有一篇应对的方法,但是我是没复现出来,放在这里https://zhuanlan.zhihu.com/p/74134318。毕竟集群这玩应就是和私网搭建
- 如果是你自己的有公网IP的机子,恭喜你不会遇到上面的问题。由于我没有遮掩的机子,会遇到什么问题我不知道,需要你自行探索
- 初始化后又重新搭建:
会发现有一堆要关掉的占用端口的进程和要删除的文件。这个时候用下面的命令即可。主节点和从节点都要运行这个命令
kubeadm reset
值得注意的是,如果你已经构建到了最后一步,即运行了如下三条命令。那么你还需要将新创建的文件夹删除。否则表面上看没什么影响。实际在其他节点加入集群的时候回产生证书问题
# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config'''
rm -r $HOME/.kube
- 单节点k8s集群。
对于单纯想了解学习k8s的搭建丹姐点的同学请运行如下命令,确包此节点允许单节点运行pod.否则之后部署查询的时候会在日志里见到相关的warning, 同时pod的状态也会一直 ready 0/1
# 这句语句请在至少部署一个service 与 pod 后运行
kubectl taint nodes --all node-role.kubernetes.io/master-
- K8s中的插件部署。K8s的网络是使用插件的方式安装的。比较流行的插件网络有flannel, calico等。 我们只需要在master网络安装插件即可。以flannel为例:
# 直接找改过仓库的版本:
kubectl apply -f flannel.yml
# 这一段是运行的结果
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/psp.flannel.unprivileged configured
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel unchanged
configmap/kube-flannel-cfg unchanged
daemonset.apps/kube-flannel-ds created
#获取node状态,变成ready, 成功
kubectl get nodes
NAME STATUS ROLES AGE VERSION
vm-0-13-ubuntu Ready control-plane,master 8m45s v1.23.5
vm-4-9-ubuntu Ready <none> 3m36s v1.23.5
至此,k8s的基本环境就搭建的该一段落了。接下来我们开始我们的第一个deemo 部署
K8S 部署项目1:Nginx
# 先下载镜像
kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
# 准备暴漏端口。我我想放在80端口上,先查一下80端口是否占用:
netstat -tunlp| grep :80
# 暴漏端口,port直容器暴漏给外部的端口
kubectl expose deploy nginx --port=80 --type=NodePort
service/nginx exposed
# 查看状态
kubectl get pods,svc
# Ready 1/1就说明搭建成功
NAME READY STATUS RESTARTS AGE
pod/nginx-85b98978db-4ffg9 1/1 Running 0 4m46s
# svc 指先在运行的service.我们访问的时候都是访问主节点,主节点分发给到响应路由
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24m
service/nginx NodePort 10.99.177.13 <none> 80:31524/TCP 37s
# 访问一下, 我靠超时,怎么肥事,我们排查在哪台node上运行,
curl http://10.0.0.13:31254
# 超时无反应
kubectl get pod -A -owide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
default nginx-85b98978db-5npc5 1/1 Running 0 2m41s 10.244.1.2 vm-0-2-ubuntu <none> <none>
# 我们找一下另一台节点, 是成功的。。
curl http://10.0.0.2:31254
<!DOCTYPE html>
Nginx
</html>
这说明转发失败,我们来回溯一下,按照这篇博客排查 :
- 查看网络插件:
netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
# 存在网络插件
10.244.0.0 10.244.0.0 255.255.255.0 UG 0 0 0 flannel.1
- 查看是否允许转发
iptables -L -n
# 果然,不允许(我的master节点)
Chain FORWARD (policy DROP)
# 设置允许
echo "net.ipv4.ip_forward = 1" >> /usr/lib/sysctl.d/50-default.conf
sysctl -p
reboot
- 但是当我们满心欢喜的等待重启后发现,wtf还是连不上。等等我知道问什么了。 机器A 访问不到机器B 的docker 内网环境10.244.1.2。 那接下来的问题就是跨机器容器互联了。本来这是flannel的活,为啥flannel没起作用就是我们需要探究的东西了。
kubectl get pod -A -owide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
default nginx-85b98978db-9mv8d 1/1 Running 0 18m 10.244.1.2 vm-0-2-ubuntu <none> <none>
- 好吧,原因是因为版本不兼容,我之前一直把warnning当成屁是我的问题.那我们退回
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
# 我退回到1.18的版本,再重来一边的时候发现又变成0/1 了
# 找找原因
kubectl describe pod nginx-f89759699-zftx6 -n kube-system
# 原来是网络插件没删干净。因为我中间尝试了calico也不行,如果你们没有尝试就不用看这条
关于flannel没有卸干净:
关于calico没 卸载干净:
- 还是不行,这是咋回事。。我又海查了资料,发现,最终找到了这一条:腾讯云的机子由于虚拟网卡的问题,想要使用flannel就要打开端口,udp的8472端口。由于我只打开了TCP端口。所以不行。害,这次定位完之后终于成功了
root@VM-0-13-ubuntu:~# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-f89759699-vwjnl 1/1 Running 0 53m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 55m
service/nginx NodePort 10.96.22.96 <none> 80:32532/TCP 53m
root@VM-0-13-ubuntu:~# curl 127.0.0.1:32532
<!DOCTYPE html>
Nginx
</html>