记 容器编排工具 k3s + Rancher 环境的搭建

记 容器编排工具 k3s + Rancher 环境的搭建

很久没写博客了啊。。。大三啦,准备着电子设计大赛和考研,还是有点忙的,一直没来打理博客;要写的东西其实并不少(说白了就是懒~)。最近有空升级了集群的部署方案,为了以后能有个参考,可以来水一篇了。

我在香港的两台服务器上托管着各种各样的服务,有轻量级别的 RSS阅读器 Miniflux、IFTTT 开源替代品 Huginn、有中等量级别的 数据收集与可视化 Grafana + Prometheus 栈、消息队列服务 RabbitMQ,也有重量级别的 Git + CI 服务 GitLabMinecraft 服务器等,他们都蜗居在这两台中等配置的服务器上。

为了方便管理与减少维护的精力与时间,我使用的部署方式/工具一代代地升级着:

  • 高中时有了第一台云服务器,主要用来运行如 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-ipnode-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 暴露的外部主机端口,则需要以下几个步骤来更新配置并升级部署:

  1. 使用 helm show values traefik/traefik > traefik_values.yml 将 yml 格式的 traefik 部署文件输出到 traefik_values.yml 文件中

  2. 打开 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
  3. 使用 helm upgrade -f traefik_values.yml traefik traefik/traefik --namespace traefik-ingress 命令更新配置并升级部署

  4. 使用 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 仓库。

参考链接

  1. Kubernetes
  2. K3s: Lightweight Kubernetes
  3. Rancher k3s 文档
  4. Rancher 2.6 Docs