
记 容器编排工具 k3s + Rancher 环境的搭建
很久没写博客了啊。。。大三啦,准备着电子设计大赛和考研,还是有点忙的,一直没来打理博客;要写的东西其实并不少(说白了就是懒~)。最近有空升级了集群的部署方案,为了以后能有个参考,可以来水一篇了。
我在香港的两台服务器上托管着各种各样的服务,有轻量级别的 RSS阅读器 Miniflux、IFTTT 开源替代品 Huginn、有中等量级别的 数据收集与可视化 Grafana + Prometheus 栈、消息队列服务 RabbitMQ,也有重量级别的 Git + CI 服务 GitLab、Minecraft 服务器等,他们都蜗居在这两台中等配置的服务器上。
为了方便管理与减少维护的精力与时间,我使用的部署方式/工具一代代地升级着:
- 高中时有了第一台云服务器,主要用来运行如 Wordpress、tt-rss 等一些非常轻量级别的应用和一些自己写的简单的 Python 与 PHP 网页应用,只需简单粗暴地 直接在宿主机系统中安装部署。
- 随着部署的应用越来越多,云服务器的配置也在提升。或是因为部分的应用依赖着不同版本的数据库、缓存器等基础服务,或是因为单个应用可能占用过多的资源,不方便对部署应用的资源占用进行限制,而逐渐产生了应用间环境隔离的需求,我便开始学习使用 Docker 容器化部署方式 + Docker Compose 容器编排工具。
- 之后拥有了第二台配置低一点的服务器,这时开始有了多节点灵活调度服务、安排资源、部分基础服务高可用的需求,于是便开始学习使用 Rancher V1 及其自带的编排工具 Cattle;但可能使用的人并不多,再加上 容器编排工具的未来 Kubernetes 迅猛的发展势不可挡,Rancher 公司在一七年就直接弃坑了 Cattle,于是 V2 版本后 Rancher 只支持 Kubernetes 编排了,而我一直使用着这个停止更新甚至维护的老技术😂。
- 最终便是几年前就了解过的 Kubernetes,但一直畏于其较高的学习成本(其实并不太想花心思在这上面)而没能尝试过这么方便而高效率的部署工具。最近因为担心 Log4J 漏洞 的影响,以及 Rancher V1 对较高版本 docker-compose.yml 文件的不兼容(虽能正常工作,但日志里就是不停地吐 Error,实在是受不了了),终于狠下心来抛弃了四年前就停止维护的老技术(Rancher V1 自带了解为的 Cattle 的编排工具),将绝大部分原来的服务都迁移至 k3s 上了。
kubernetes、k3s 与 Rancher
先来简要介绍一下 k8s 和 k3s 他们俩。
Kubernetes
又名 k8s(8 指的是 k 与 s 间有8个字母,类似于 internationalization 和 i18n),据 Kubernetes 官网 称是源自 Google 15年生产环境的运维经验的用于自动部署,扩展和管理容器化应用程序的开源系统。

使用 Kubernetes 进行容器管理有什么实际的好处呢?从官网上介绍的特性中对与我来讲最有用的有以下这么几个:
- 自动化上线和回滚: 可使用 CI 工具(如 Gitlab 自带 CI/CD 工具)进行整合实现自动构建与部署,也可回滚到某个特定版本的应用
- 服务发现与负载均衡: 非常方便的 Pod 地址解析和流量分配的负载均衡功能
- Secret 和配置管理: 将证书、密钥、环境变量单独放在同一命名空间下的 Secrets 和配置映射中,更改后只需重启 Pod 即可生效,方便了对机密信息与配置变量的统一管理
- 水平扩缩: 对于如 Worker、后台作业处理等无状态应用,可根据任务量变化与资源分配情况灵活地使用 API 进行扩展和收缩
- 自我修复: 使用健康检查进行状态监控;在应用可用时向外界暴露访问端点,而在应用不可用时关闭访问端点避免误操作对应用的破坏,并在必要时重新创建容器,以保证应用(特别是基础服务)的正常运行
可 Kubernetes 并不是可以使用在任何环境下,至少当机器资源并不充裕时。这时,k3s 便进入了我们的视野。
k3s
k3s 是 Rancher Labs 的作品。

作为 k8s 的轻量级发行版,k3s 对 k8s 做了很大幅度的精简化,例如默认不使用 Etcd、去掉了部分 k8s 中很少使用的冗杂功能、使用更轻量级的容器运行时 containerd、将所需组件压缩在了一个小于 50MB 的二进制可执行文件中等,因此 k3s 非常适合用于资源紧张的大多数场景。此外,k3s 还增强了对 Arm 处理器服务器的支持,适合于 IoT 与边缘计算环境,例如运行在树莓派组成的集群上。
k3s 安装
接下来进入正题,开始 k3s 工具的安装。
架构拓扑
对于应用在生产环境的集群,建议在一开始就使用 高可用 + 外部 MySQL 数据库 架构(而非单节点 + 嵌入式 SQLite 数据库),就算最开始只是使用一个 Server 节点;这样在以后能够更加容易地扩展集群规模。不建议使用目前还处于开发阶段且难以迁移的 嵌入式 Etcd。
单个或多个 Server 节点管理多个拥有 Worker 角色(Role)的 Agent 节点(一个节点可以拥有多个角色,因此 Server 节点也可用作 Worker 节点来部署应用或服务),然后通过外置负载均衡器(例如我正在使用的 Cloudflare)来将流量分配到这些运行应用或服务的 Agent 节点上。
整体架构拓扑图如下:(图片摘自 Rancher k3s 文档 - 架构介绍)

安装前准备
编辑 /etc/hostname
文件更改主机名,如 stage.central
。
编辑 /etc/hosts
文件,配置所有集群中的机器的主机名与 ip 地址的映射,也可加上外部数据库主机地址,例如:
192.168.1.1 stage.central
192.168.1.2 native.central
101.60.60.60 mysql.external
安装与配置 Server 节点
Rancher 提供的安装脚本非常实用;运行时只需添加少数的参数或环境变量便可以方便地进行自定义。
下面给出我在安装时使用的命令作为例子:
curl -sfL https://get.k3s.io | sh -s - server \
--token=TOKEN_KEEP_SECRET --docker --no-deploy traefik \
--node-ip 192.168.1.1 --node-external-ip 101.50.50.1 \
--datastore-endpoint="mysql://username:[email protected](mysql.external:3306)/database"
其中所包含的启动选项与参数:
- token: 用于 Agent 节点连接 Server 节点时作身份校验用
- docker: 使用 docker 而非 k3s 默认的 containerd 作为容器运行时。因为我除了 k3s 外还需要 docker-compose 进行简便的容器部署,所以此处使用的是 docker 运行时。若没有特殊需求,建议使用默认 containerd
- no-deploy traefik: 在安装时不部署 traefik。traefik 作为容器化环境中反向代理与负载均衡器的优先选择,轻量、易用;可默认自动部署,其将工作在 80 与 443 端口。你也可以选择使用 Nginx 作为负载均衡器来代理流量。此处因为我还有部分应用并没有容器化,需要使用已部署在主机中,工作在 80 与 443 端口的 Nginx 反向代理流量才使用禁用部署 traefik 的选项
- node-ip: 节点地址,设置为内网地址
- node-external-ip: 节点外部地址,设置为外网地址
- datastore-endpoint: 外部数据库连接字符串,按照格式配置自己部署或是外部的高可用数据库即可
上述启动选项也可组合为字符串赋给 INSTALL_K3S_EXEC
环境变量来配置。安装前可通过配置 INSTALL_K3S_SKIP_START
环境变量为 true
来阻止安装过程结束时 k3s 的自动启动以进行更多的首次运行前配置操作。安装结束后也可通过编辑 .service 文件来需要更改启动选项,其文件位于 /etc/systemd/system/k3s.service
。
若需部署多个 Server 节点,可在这几个节点上执行更改对应 node-ip
与 node-external-ip
启动选项后的上述安装命令。
PS. 若服务器位于国内,也可使用镜像地址 https://rancher-mirror.rancher.cn/k3s/k3s-install.sh
来加速软件的下载过程。
安装与配置 Agent 节点
下面给出我在安装时使用的命令作为例子:
curl -sfL https://get.k3s.io | \
K3S_TOKEN=TOKEN_KEEP_SECRET \
K3S_URL=https://stage.central:6443 \
INSTALL_K3S_EXEC="--docker --no-deploy traefik --node-ip 192.168.1.2 --node-external-ip 101.50.50.2"
其中所包含的环境变量:
- K3S_TOKEN: 前面安装 Server 节点时准备的 token 字符串
- K3S_URL: Server 节点 API Server 地址,默认工作在 6443 端口。若高可用架构 Server 节点不止一个,则需要使该端点通过负载均衡器
- INSTALL_K3S_EXEC: 即启动选项,与 Server 大致相同
类似地,在安装结束后也可通过编辑 .service 文件来需要更改启动选项,其文件位于 /etc/systemd/system/k3s-agent.service
。其他的配置与与 Server 节点基本一致。
安装后配置
在完成所有 Server 与 Agent 节点的安装后,可通过 kubectl get node -o wide
命令来获取集群中的所有节点,命令会输出如下的消息:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
stage.central Ready control-plane,master 27d v1.23.6+k3s1 192.168.1.1 101.50.50.1 Ubuntu 20.04.4 LTS 5.4.0-110-generic docker://20.10.12
native.central Ready <none> 27d v1.23.6+k3s1 192.168.1.2 101.50.50.2 Ubuntu 20.04.4 LTS 5.4.0-110-generic docker://20.10.12
若要向节点添加 Worker 角色,可使用 kubectl
命令:
kubectl label node/stage.central node-role.kubernetes.io/worker=true
kubectl label node/native.central node-role.kubernetes.io/worker=true
然后再次使用 kubectl get node -o wide
命令查看所有节点信息:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
stage.central Ready control-plane,master,worker 27d v1.23.6+k3s1 192.168.1.1 101.50.50.1 Ubuntu 20.04.4 LTS 5.4.0-110-generic docker://20.10.12
native.central Ready worker 27d v1.23.6+k3s1 192.168.1.2 101.50.50.2 Ubuntu 20.04.4 LTS 5.4.0-110-generic docker://20.10.12
可以观察到节点的角色已更新。
通过 kubectl get pods -n kube-system
命令可观察由系统启动的基础服务是否成功启动,命令会输出如下的信息:
NAME READY STATUS RESTARTS AGE
coredns-d76bd69b-fkdtm 1/1 Running 0 27d
local-path-provisioner-6c79684f77-v7m8n 1/1 Running 0 27d
metrics-server-7cd5fcb6b7-hmssl 1/1 Running 0 27d
svclb-traefik-x4knv 2/2 Running 0 27d
svclb-traefik-sbs7c 2/2 Running 0 27d
当观察到所有 Pod 的 STATUS 均为 Running
时,说明该集群已准备完毕,可投入正常使用了。
Helm 安装
Helm 为 Kubernetes 包管理器,使用 Helm 进行应用(称为 Chart)的搜寻与安装非常方便快捷。
Helm 的安装非常简单,只需在 Helm Github Releases 上找到对应版本的二进制文件,下载后软连接或复制到 /usr/local/bin
文件夹中即可。
使用 Helm 安装与配置 traefik
若要手动安装 traefik,此时便可方便地使用 Helm 工具来进行应用的部署了。
首先使用 helm repo add traefik https://helm.traefik.io/traefik
命令添加 traefik 的仓库。
然后使用 helm install --namespace=kube-system traefik traefik/traefik
命令将 traefik 部署到 kube-system 命名空间。
若需要修改 traefik 暴露的外部主机端口,则需要以下几个步骤来更新配置并升级部署:
-
使用
helm show values traefik/traefik > traefik_values.yml
将 yml 格式的 traefik 部署文件输出到traefik_values.yml
文件中 -
打开
traefik_values.yml
文件,找到Ports
节(大致在 276 行),将 web 和 websecure 节中的exposedPort
更改为希望的监听端口号(如 1080 和 1443)# Configure ports ports: # The name of this one can't be changed as it is used for the readiness and # liveness probes, but you can adjust its config to your liking traefik: port: 9000 # Use hostPort if set. # hostPort: 9000 # # Use hostIP if set. If not set, Kubernetes will default to 0.0.0.0, which # means it's listening on all your interfaces and all your IPs. You may want # to set this value if you need traefik to listen on specific interface # only. # hostIP: 192.168.100.10 # Override the liveness/readiness port. This is useful to integrate traefik # with an external Load Balancer that performs healthchecks. # healthchecksPort: 9000 # Defines whether the port is exposed if service.type is LoadBalancer or # NodePort. # # You SHOULD NOT expose the traefik port on production deployments. # If you want to access it from outside of your cluster, # use `kubectl port-forward` or create a secure ingress expose: false # The exposed port for this service exposedPort: 9000 # The port protocol (TCP/UDP) protocol: TCP web: port: 8000 # hostPort: 8000 expose: true exposedPort: 1080 # The port protocol (TCP/UDP) protocol: TCP # Use nodeport if set. This is useful if you have configured Traefik in a # LoadBalancer # nodePort: 32080 # Port Redirections # Added in 2.2, you can make permanent redirects via entrypoints. # https://docs.traefik.io/routing/entrypoints/#redirection # redirectTo: websecure websecure: port: 8443 # hostPort: 8443 expose: true exposedPort: 1443 # The port protocol (TCP/UDP) protocol: TCP # nodePort: 32443 # Enable HTTP/3. # Requires enabling experimental http3 feature and tls. # Note that you cannot have a UDP entrypoint with the same port. # http3: true # Set TLS at the entrypoint # https://doc.traefik.io/traefik/routing/entrypoints/#tls tls: enabled: true # this is the name of a TLSOption definition options: "" certResolver: "" domains: [] # - main: example.com # sans: # - foo.example.com # - bar.example.com
-
使用
helm upgrade -f traefik_values.yml traefik traefik/traefik --namespace traefik-ingress
命令更新配置并升级部署 -
使用
kubectl get pods -n kube-system
命令查看刚部署的、以 traefik 开头的 Pods,若状态均为运行,即部署更新成功。此时可打开 1080 端口查看,因为没有配置路由,将会得到 404 响应
此后,可通过向命名空间中添加 ingress 服务即可使用 traefik 来将流量引至对应的服务中去。
Good Ending 1
若只是需要一个
Rancher 安装
通过 helm repo add rancher-latest https://releases.rancher.com/server-charts/latest
命令添加 Rancher V2 仓库。