运维相关:死磕K3S和Rancher

发布于 2022-01-08  6014 次阅读


前言:最近在公司完成了一个C端产品的小版本研发,实际体验了一下有大量用户的产品上线的流程。其中,有幸接触到了运维部署工具K8S和管理工具Rancher。趁着元旦放假开始好好学习了下,下面是踩坑记录。这个真的很难,中途有想过放弃,但最终我还是坚持下来了。作为开发,而不是专业运维人员,了解下面这些已经足够了。

0、准备

知识准备:阅读rancher官方文档:https://www.rancher.cn/

硬件准备:

  • 树莓派4c4g一台
  • 阿里云1c2g服务器一台,一个ipv4的IP linux
  • 腾讯云2c4g服务器一台,一个ipv4的IP windows
  • 华为云1c1g服务器一台,一个ipv4的IP linux
  • thestack 1c256m服务器一台,一个ipv4的IP linux

初步构建思路:

因为官网上介绍到配置要求最低内存是512M,所以 thestack 的服务器不能使用

K3S要求CPU 和内存

  • CPU: 最低 1
  • 内存: 最低 512MB(建议至少为 1GB)

K3s 高可用安装Rancher的 CPU 和 内存要求

这些要求适用于安装了 Rancher Server 的 K3s Kubernetes 集群中的每个主机。

部署规模集群节点vCPUs内存数据库规模
最多 150 个最多 1500 个28 GB2 cores, 4GB + 1000 IOPS
最多 300 个最多 3000 个416 GB2 cores, 4GB + 1000 IOPS
最多 500 个最多 5000 个832 GB2 cores, 4GB + 1000 IOPS
特大最多 1000 个最多 10,000 个1664 GB2 cores, 4GB + 1000 IOPS
超大最多 2000 个最多 20,000 个32128 GB2 cores, 4GB + 1000 IOPS

所以初步构想使用树莓派4b来跑rancher服务, 内网穿透给外部访问 。

华为的1C1G作为节点安装

行动参考:https://zhuanlan.zhihu.com/p/384328373

最开始使用的Docker安装的Rancher,因为现在的版本Rancher都是安装在容器上面的,所以安装好后会有一个本地local集群。我想把另一台主机加入到这个集群。尝试很久发现并不行,嫌麻烦就放弃了这个方案。端口开放见下表。

Rancher Server 节点的入站规则

协议端口来源描述
TCP80Load balancer/proxy,做外部 SSL 终端使用外部 SSL 终止时的 Rancher UI/API
TCP443server 节点agent 节点托管/注册的 Kubernetes任何需要能够使用 Rancher UI 或 API 的源Rancher agent, Rancher UI/API, kubectl
TCP6443K3s server 节点Kubernetes API
UDP8472K3s server 和 agent 节点Flannel VXLAN 需要
TCP10250K3s server 和 agent 节点kubelet

Rancher 节点出站规则

协议端口目的地描述
TCP22来自使用 Node Driver 程序创建的节点的任何节点 IP使用 Node Driver 程序 SSH 配置节点
TCP443git.rancher.ioRancher catalog
TCP2376Any node IP from a node created using Node driverDocker Machine 使用的 Docker daemon TLS 端口
TCP6443托管/导入的 Kubernetes APIKubernetes API server

更多信息参考:https://docs.rancher.cn/docs/rancher2/installation/requirements/ports/_index

并且一开始穿透方案一直无法转发流量,认为是部署问题,重试了几遍也是。所以我的树莓派内网穿透方案失败!!

2022年1月24日更新:内网穿透方案失败的原因是穿透工具使用了4层网络协议。后改用7层网络协议,直接穿https成功。

1、在线服务器方案Master节点

重装腾讯云2C4G服务器为Linux,部署Rancher服务器,这次选择不使用docker镜像,使用官网的高可用安装方式。

注意:Rancher是部署在容器中的

所以需要先安装K3S集群,参考链接:https://docs.rancher.cn/docs/k3s/installation/_index

Master节点安装

master节点安装最简单, INSTALL_K3S_VERSION 指定版本号,经过N多次安装尝试, v1.19.13+k3s1 最稳定,后面节点也安装此版本

curl -sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn INSTALL_K3S_VERSION=v1.19.13+k3s1 sh -s

K3S卸载

/usr/local/bin/  //目录下
./k3s-uninstall.sh  //maser执行
./k3s-agent-uninstall.sh   //节点执行

K3S的Master启动

需要配置服务,这些配置直接在启动的时候指定也是可以的

一次性指定参数可以参考我的另一篇文章的安装:

vim /etc/systemd/system/multi-user.target.wants/k3s.service

修改启动参数${MASTER_IP}替换为当前节点的公网IP,目的是为了给子节点注册时能访问。

ExecStart=/usr/local/bin/k3s server --kube-apiserver-arg advertise-address=${MASTER_IP} --kube-apiserver-arg external-hostname=${MASTER_IP} --tls-san ${MASTER_IP}
  • --tls-san 参数是为了增加 tls 证书的ip
  • --docker 使用docker而不是 containerd,看个人喜好了
  • --no-deploy traefik 不部署 traefik,看个人喜好

然后重启服务

sudo systemctl daemon-reload
sudo systemctl restart k3s 

高可用安装Rancher

下面参考链接是安装Rancher的方式,必读

高可用安装方式服务器配置最小为4c8g,否则即使安装成功也会心跳检测失败

参考地址:https://docs.rancher.cn/docs/rancher2/installation/install-rancher-on-k8s/_index/

我的部署命令:

helm install rancher rancher-stable/rancher \
 --namespace cattle-system \
 --set hostname=www.hostname.com \
 --set replicas=3 \
 --version 2.5.11

首先配置一下环境变量,否则会出现Error: Kubernetes cluster unreachable: Get "http://localhost:8080/version?timeout=32s": dial tcp [::1]:8080: connect: connection refused的错误:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

如果出现cannot re-use a name that is still in use错误,执行以下命令,会删除命名空间,谨慎操作。

helm ls --all-namespaces
kubectl delete namespace cattle-system
kubectl create namespace cattle-system

这个安装需要安装heml,heml国内镜像地址:https://mirrors.huaweicloud.com/helm/v3.6.3/ 后面的版本号可以手动修改。 v3.6.3 可任意修改已存在的版本号。

不知道heml是什么?简单介绍一下

很多人都使用过Ubuntu下的ap-get或者CentOS下的yum, 这两者都是Linux系统下的包管理工具。采用apt-get/yum,应用开发者可以管理应用包之间的依赖关系,发布应用;用户则可以以简单的方式查找、安装、升级、卸载应用程序。

我们可以将Helm看作Kubernetes下的apt-get/yum。Helm是Deis (https://deis.com/) 开发的一个用于kubernetes的包管理器。

对于应用发布者而言,可以通过Helm打包应用,管理应用依赖关系,管理应用版本并发布应用到软件仓库。

对于使用者而言,使用Helm后不用需要了解Kubernetes的Yaml语法并编写应用部署文件,可以通过Helm下载并在kubernetes上安装需要的应用。

除此以外,Helm还提供了kubernetes上的软件部署,删除,升级,回滚应用的强大功能。

严格按照官网1-7步骤安装好后,Rancher就可以使用了。

2、Worker/Node节点配置和启动

部署子节点需要master节点的token,用于添加到集群

在master节点上执行以下代码:

# cat /var/lib/rancher/k3s/server/node-token

得到一个这个格式的token:K1082501c0eaxxxxxxxx77059a4fff524a8a589b9::server:1f2d8a347xxxxxxxa75efd06

在worker节点上执行以下代码:

  1. 然后把这个获取到的token替换下面的${TOKEN}
  2. ${ K3S_URL } 替换为master节点的ip加端口,例子:12.23.34.56:6443,默认端口是6443
  3. ${NODE_IP} 为当前节点的公网ip,设置公网ip是应为我的集群是跨云的,如果内网ip是可以相互访问的,可以不设置
curl -sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn K3S_TOKEN=${TOKEN} K3S_URL=${K3S_URL} INSTALL_K3S_VERSION=v1.19.13+k3s1 sh -s - agent --node-external-ip ${NODE_IP}

3、不配置上面公网IP会出现的问题和解决方案

参考:https://blog.csdn.net/qq_33996921/article/details/103529312

参考:https://docs.rancher.cn/docs/rancher2/faq/install/_index/#error-httpsranchermyorgping-is-not-accessible-could-not-resolve-host-ranchermyorg

参考:https://github.com/k3s-io/k3s/issues/882

问题:子节点在通过master的复制添加节点的时候会load banlance 主节点的内网ip去连接主节点,这样因为不在同一个局域网内,所以不能加入到集群。

临时解决方案:子节点直接映射主节点的内网ip到主节点的公网ip,这样子节点拿到的虽然是内网ip,也会重定向到公网ip去。

iptables -t nat -A OUTPUT -d 192.168.0.1 -j DNAT --to-destination 152.132.125.96

注:第一个ip是master节点的内网ip,后一个ip是外网Ip

其他解决方案:

I also had the same problem, and finally found a solution. You can start your server with --node-external-ip, like this sudo k3s server --node-external-ip 49.xx.xx.xx, and agent need config env or start with sudo k3s agent --server https://49.xx.xx.xx:6443 --token ${K3S_TOKEN}, then your local device (edge node) from private IP can connect public cloud .

https://stackoverflow.com/questions/58834434/how-to-change-set-k8s-master-node-internal-ip-or-public-ip

设置coreDNS

kubectl -n cattle-system patch  deployments cattle-cluster-agent --patch '{
​    "spec": {
​        "template": {
​            "spec": {
​                "hostAliases": [
​                    {
​                      "hostnames":
​                      [
​                        "www.hostname.com"
​                      ],
​                      "ip": "101.35.XX.XX"
​                    }
​                ]
​            }
​        }
​    }
}'

kubectl -n cattle-system patch  daemonsets cattle-node-agent --patch '{
 "spec": {
​     "template": {
​         "spec": {
​             "hostAliases": [
​                 {
​                    "hostnames":
​                      [
​                        "www.hostname.com"
​                      ],
​                    "ip": "101.35.XX.XX"
​                 }
​             ]
​         }
​     }
 }
}'

4、集群配置

配置好集群后不代表部署服务没有问题,下面介绍节点间的IP配置。

1、保证集群内部服务转发正常

节点配置

k3s.io/external-ip填公网IP
flannel.alpha.coreos.com/public-ip填公网IP,会自动建立虚拟局域网
k3s.io/internal-ip内网IP

关闭防火墙

2、保证集群外部端口开放

查看云服务商的防火墙,具体开放端口见最上面表格

3、节点端口和负载均衡的区别和配置

节点端口:https://docs.rancher.cn/docs/rancher2.5/quick-start-guide/workload/quickstart-deploy-workload-nodeport/_index

负载均衡:https://docs.rancher.cn/docs/rancher2.5/quick-start-guide/workload/quickstart-deploy-workload-ingress/_index

5、问题汇总

1、在子节点中由于K3S server启动了,导致不能启动agent。

子节点需要安装K3S server的,但是不用启动,会由agent自动去调度。

问题描述:cannot run k3s server

解决方案:

stop a k3s service. (systemctl stop k3s)
run k3s agent (sudo k3s agent --server ${K3S_URL} --token ${K3S_TOKEN})

参考链接:https://github.com/k3s-io/k3s/issues/60

2、节点password注册失败

问题描述:因为我多次加入节点失败后,重置了云服务器,导致之前的密码,已经存在了master端。导致新的系统生成的密码和已存在的不匹配。

level=error msg="Node password rejected, duplicate hostname or contents of '/etc/rancher/node/password' may not match server nod

解决方案:

# agent
$ cat /etc/rancher/node/password
47211f28f469622cccf893071dbda698
$ hostname
xxxxxxx

# server
cat /var/lib/rancher/k3s/server/cred/node-passwd
31567be88e5408a31cbd036fc9b37975,ip-172-31-13-54,ip-172-31-13-54,
cf3f4f37042c05c631e07b0c0abc528f,xxxxx,xxxxxx,

Agent node对应的passwd和server中存储的hostname对应的passwd不一致,按照我们前面说的基本原理,就会出现403的错误日志。

具体解决方案:

为什么会出现passwd不一致呢?正常来说如果用k3s-agent-uninstall.sh来清理安装过的agent node,并不会删除password文件(/etc/rancher/node/password),那么问题很可能是VM重建或者手动操作删除的这个文件。因为agent上删除了password,agent再次注册时会重新生成password,就导致了新的password和server上原先存储的不一致。

解决办法可以有三种:

  • 手动在agent上创建password,内容和server中存储保持一致
  • 修改了server中的原始内容,让password和agent上新生成的保持一致
  • 可以试试agent注册时使用--with-node-id,这样server中认为这完全是新node,不会用原始信息比对

参考链接:https://cloud.tencent.com/developer/article/1594895

参考链接:https://github.com/k3s-io/k3s/issues/802#issuecomment-841748960 (刪除密码方式)

3、节点没有角色,显示 <none>

kubectl label nodes  k8s-node1 node-role.kubernetes.io/worker=worker

还有就是设置节点的标签键值对

node-role.kubernetes.io/worker = yes 就是worker角色

node-role.kubernetes.io/master = yes 就是master 角色

参考链接:https://cloud.tencent.com/developer/article/1659636

6、K3S常用命令

kubectl get pods --all-namespaces //获取所有pod

kubectl get pods -A   //获取所有pod

kubectl get nodes //获取节点

kubectl describe pods  //将列出与pod关联的所有事件,包括图像提取,容器启动。可能会有帮助。解决容器一直在创建中的问题

7、其他参考链接

K3S 介绍:https://blog.shabby.in/config-your-kubernetes-cluster/#%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA

k8s中正确删除一个pod:https://www.cnblogs.com/effortsing/p/10496547.html

手把手搭建K3S+Rancher : https://www.cnblogs.com/zhouzhifei/p/13683466.html

rancher+k3s的高可用部署以及k3s集群的导入:http://longrm.com/2021/06/23/2021-06-23-rancher-k3s-deploy/

安装要求:https://docs.rancher.cn/docs/rancher2/installation/requirements/_index/#概述

Rancher UI gives 404 backend when using helm chart :https://github.com/rancher/rancher/issues/26323

启动配置参考表:https://rancher.com/docs/k3s/latest/en/installation/install-options/server-config/

unable to connect agent to master:https://github.com/k3s-io/k3s/issues/1523

配置参考:

K8S 的轻量版 K3S 安装教程:https://github.com/eyasliu/blog/issues/26 

8、部署服务

我的集群部署完毕是这样的

部署nginx为例

先说明一下,Rancher中部署服务叫Deployments,映射 Deployments 服务叫 Services,lngress类似nginx,用于在集群中负载均衡使用。持久化的存储,可以在本地,但是多节点,需要在每个节点的主机都要有文件和存储。所以会抽离出来,用一个文件服务器在存持久化文件,我们这里用nfs来存储。K3S中创建PV用于连接nfs,然后用PVC连接到容器内部。

我的配置:

Deployments :

存储:

PV:

PVC:

Ingress负载均衡

nfs使用参考:https://www.pianshen.com/article/14872025223/

补充:nfs的安装和使用

NFS服务器配置

1、配置环境

  • 关闭防火墙服务
# 停止并禁用防火墙
$ systemctl stop firewalld
$ systemctl disable firewalld
  • 关闭并禁用SELinux
# 若当前启用了 SELinux 则需要临时设置其当前状态为 permissive
$ setenforce 0

# 编辑/etc/sysconfig selinux 文件,以彻底禁用 SELinux
$ sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

# 查看selinux状态
$ getenforce 

如果selinux状态为permissive,则执行reboot重新启动即可

2、安装nfs-utils和rpcbind

$ yum install -y nfs-utils rpcbind

3、创建存储的文件夹

# 创建文件夹
$ mkdir /nfs

# 更改归属组与用户
$ chown -R root.root /nfs

4、配置NFS

# 编辑exports
$ vi /etc/exports

# 输入以下内容(格式:FS共享的目录 NFS客户端地址1(参数1,参数2,...) 客户端地址2(参数1,参数2,...))
$ /nfs 192.168.2.0/24(rw,async,no_root_squash)

#如果设置为 /nfs *(rw,async,no_root_squash) 则对所以的IP都有效

我这个用的是这个配置

/home/k3s *(rw,insecure,async,no_root_squash)
  • 常用选项:
    • ro:客户端挂载后,其权限为只读,默认选项;
    • rw:读写权限;
    • sync:同时将数据写入到内存与硬盘中;
    • async:异步,优先将数据保存到内存,然后再写入硬盘;
    • Secure:要求请求源的端口小于1024
  • 用户映射:
    • root_squash:当NFS客户端使用root用户访问时,映射到NFS服务器的匿名用户;
    • no_root_squash:当NFS客户端使用root用户访问时,映射到NFS服务器的root用户;
    • all_squash:全部用户都映射为服务器端的匿名用户;
    • anonuid=UID:将客户端登录用户映射为此处指定的用户uid;
    • anongid=GID:将客户端登录用户映射为此处指定的用户gid

5、设置开机启动并启动

  • rpcbind
$ systemctl restart rpcbind
  • nfs
$ systemctl enable nfs
$ systemctl restart nfs

6、查看是否有可用的NFS地址

$ showmount -e 192.168.2.31

安装参考:

https://cloud.tencent.com/developer/article/1721166

https://www.cnblogs.com/sanduzxcvbnm/p/11780926.html

关于无法链接nfs的问题:https://www.cnblogs.com/tradoff/p/6149075.html#!comments

注意:使用nfs存储,节点也需要安装 nfs-utils ,否则会报错missing codepage or helper program, or other error

yum install nfs-utils

参考:https://www.cnblogs.com/will-xz/p/13532578.html

2022年2月3日更新:无法删除Terminating中的命名空间解决办法

issue链接:https://github.com/kubernetes/kubernetes/issues/60807

@ManifoldFR , I had the same issue as yours and I managed to make it work by making an API call with json file .
kubectl get namespace annoying-namespace-to-delete -o json > tmp.json
then edit tmp.json and remove"kubernetes"

curl -k -H "Content-Type: application/json" -X PUT --data-binary @tmp.json https://kubernetes-cluster-ip/api/v1/namespaces/annoying-namespace-to-delete/finalize

and it should delete your namespace,

调用命令需要开启代理:

If you start 'kubectl proxy' first you can direct the curl to http://127.0.0.1:8001/api/v1/namespaces/annoying-namespace-to-delete/finalize. I couldn't get authentication to work until I did it that way.


欢迎欢迎~热烈欢迎~