记 容器编排工具 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 时,说明该集群已准备完毕,可投入正常使用了。

traefik 安装

安装 traefik 前先来安装 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

若只是需要一个可以立刻开始部署应用的 k3s 集群,现在就可以结束了。
但是使用繁琐的命令行界面与脚本来管理集群与资源,对于我们非专业人员来说就有点繁琐,且容易误操作。这时可以使用图形化工具来辅助管理 k3s 集群。

Rancher 安装

Rancher 官网上有两种安装方式:一种是直接使用官方的 docker 镜像的非高可用安装方式,这个镜像会在容器内再创建一个 local 集群专用于 Rancher 软件的运行;另一种是直接在刚刚搭建好的集群上安装。

两种安装方式的主要区别应该就是难度了,使用官方的 docker 镜像安装方式虽然简单,几步即可搞定,但是对于未来集群的扩展时从容器中迁移到集群上时就不太容易了,而且极有可能有兼容性问题。而第二种安装方式需要知晓一些 Kubernetes 概念,在最开始经验甚少的我摸索时可谓是万分难受,稍有一个步骤不正确就得从头再来(从头 指的是重新从 k3s 的安装开始)。

但长痛不如短痛,与其在之后使用与迁移时难受,不如干脆一开始就直接装集群上好了。

首先,通过 helm repo add rancher-latest https://releases.rancher.com/server-charts/latest 命令添加 Rancher V2 仓库。

使用 kubectl create namespace cattle-system 创建一个名为 cattle-system 的命名空间,用来放置 Rancher 相关的资源。

然后是准备用于 https 连接的证书。如果我只是内网访问,不上 https 可以吗?答案是不可以的,因为 Rancher 的 https 是强制性的,所以必须要准备证书。。。在实际环境中,我所有的服务都要经过 Nginx 负载均衡,因此相比与官网提供的 cert-manager 和 letsencrypt 两种方案外,我采用的是自签名证书,此时便没有了维护 cert-manager 和 letsencrypt authentication 的成本了。

因此,下一个步骤便是生成自签名 CA 证书,然后加到 cattle-system 的 secrets 中去。

创建一个脚本文件,编辑以下内容,用于生成自签名 CA 证书:

#!/bin/bash -e

help ()
{
    echo  ' ================================================================ '
    echo  ' --ssl-domain: 生成ssl证书需要的主域名,如不指定则默认为www.rancher.local,如果是ip访问服务,则可忽略;'
    echo  ' --ssl-trusted-ip: 一般ssl证书只信任域名的访问请求,有时候需要使用ip去访问server,那么需要给ssl证书添加扩展IP,多个IP用逗号隔开;'
    echo  ' --ssl-trusted-domain: 如果想多个域名访问,则添加扩展域名(SSL_TRUSTED_DOMAIN),多个扩展域名用逗号隔开;'
    echo  ' --ssl-size: ssl加密位数,默认2048;'
    echo  ' --ssl-cn: 国家代码(2个字母的代号),默认CN;'
    echo  ' 使用示例:'
    echo  ' ./create_self-signed-cert.sh --ssl-domain=www.test.com --ssl-trusted-domain=www.test2.com \ '
    echo  ' --ssl-trusted-ip=1.1.1.1,2.2.2.2,3.3.3.3 --ssl-size=2048 --ssl-date=3650'
    echo  ' ================================================================'
}

case "$1" in
    -h|--help) help; exit;;
esac

if [[ $1 == '' ]];then
    help;
    exit;
fi

CMDOPTS="$*"
for OPTS in $CMDOPTS;
do
    key=$(echo ${OPTS} | awk -F"=" '{print $1}' )
    value=$(echo ${OPTS} | awk -F"=" '{print $2}' )
    case "$key" in
        --ssl-domain) SSL_DOMAIN=$value ;;
        --ssl-trusted-ip) SSL_TRUSTED_IP=$value ;;
        --ssl-trusted-domain) SSL_TRUSTED_DOMAIN=$value ;;
        --ssl-size) SSL_SIZE=$value ;;
        --ssl-date) SSL_DATE=$value ;;
        --ca-date) CA_DATE=$value ;;
        --ssl-cn) CN=$value ;;
    esac
done

# CA相关配置
CA_DATE=${CA_DATE:-3650}
CA_KEY=${CA_KEY:-cakey.pem}
CA_CERT=${CA_CERT:-cacerts.pem}
CA_DOMAIN=cattle-ca

# ssl相关配置
SSL_CONFIG=${SSL_CONFIG:-$PWD/openssl.cnf}
SSL_DOMAIN=${SSL_DOMAIN:-'www.rancher.local'}
SSL_DATE=${SSL_DATE:-3650}
SSL_SIZE=${SSL_SIZE:-2048}

## 国家代码(2个字母的代号),默认CN;
CN=${CN:-CN}

SSL_KEY=$SSL_DOMAIN.key
SSL_CSR=$SSL_DOMAIN.csr
SSL_CERT=$SSL_DOMAIN.crt

echo -e "\033[32m ---------------------------- \033[0m"
echo -e "\033[32m       | 生成 SSL Cert |       \033[0m"
echo -e "\033[32m ---------------------------- \033[0m"

if [[ -e ./${CA_KEY} ]]; then
    echo -e "\033[32m ====> 1. 发现已存在CA私钥,备份"${CA_KEY}"为"${CA_KEY}"-bak,然后重新创建 \033[0m"
    mv ${CA_KEY} "${CA_KEY}"-bak
    openssl genrsa -out ${CA_KEY} ${SSL_SIZE}
else
    echo -e "\033[32m ====> 1. 生成新的CA私钥 ${CA_KEY} \033[0m"
    openssl genrsa -out ${CA_KEY} ${SSL_SIZE}
fi

if [[ -e ./${CA_CERT} ]]; then
    echo -e "\033[32m ====> 2. 发现已存在CA证书,先备份"${CA_CERT}"为"${CA_CERT}"-bak,然后重新创建 \033[0m"
    mv ${CA_CERT} "${CA_CERT}"-bak
    openssl req -x509 -sha256 -new -nodes -key ${CA_KEY} -days ${CA_DATE} -out ${CA_CERT} -subj "/C=${CN}/CN=${CA_DOMAIN}"
else
    echo -e "\033[32m ====> 2. 生成新的CA证书 ${CA_CERT} \033[0m"
    openssl req -x509 -sha256 -new -nodes -key ${CA_KEY} -days ${CA_DATE} -out ${CA_CERT} -subj "/C=${CN}/CN=${CA_DOMAIN}"
fi

echo -e "\033[32m ====> 3. 生成Openssl配置文件 ${SSL_CONFIG} \033[0m"
cat > ${SSL_CONFIG} <<EOM
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
EOM

if [[ -n ${SSL_TRUSTED_IP} || -n ${SSL_TRUSTED_DOMAIN} || -n ${SSL_DOMAIN} ]]; then
    cat >> ${SSL_CONFIG} <<EOM
subjectAltName = @alt_names
[alt_names]
EOM
    IFS=","
    dns=(${SSL_TRUSTED_DOMAIN})
    dns+=(${SSL_DOMAIN})
    for i in "${!dns[@]}"; do
      echo DNS.$((i+1)) = ${dns[$i]} >> ${SSL_CONFIG}
    done

    if [[ -n ${SSL_TRUSTED_IP} ]]; then
        ip=(${SSL_TRUSTED_IP})
        for i in "${!ip[@]}"; do
          echo IP.$((i+1)) = ${ip[$i]} >> ${SSL_CONFIG}
        done
    fi
fi

echo -e "\033[32m ====> 4. 生成服务SSL KEY ${SSL_KEY} \033[0m"
openssl genrsa -out ${SSL_KEY} ${SSL_SIZE}

echo -e "\033[32m ====> 5. 生成服务SSL CSR ${SSL_CSR} \033[0m"
openssl req -sha256 -new -key ${SSL_KEY} -out ${SSL_CSR} -subj "/C=${CN}/CN=${SSL_DOMAIN}" -config ${SSL_CONFIG}

echo -e "\033[32m ====> 6. 生成服务SSL CERT ${SSL_CERT} \033[0m"
openssl x509 -sha256 -req -in ${SSL_CSR} -CA ${CA_CERT} \
    -CAkey ${CA_KEY} -CAcreateserial -out ${SSL_CERT} \
    -days ${SSL_DATE} -extensions v3_req \
    -extfile ${SSL_CONFIG}

echo -e "\033[32m ====> 7. 证书制作完成 \033[0m"
echo
echo -e "\033[32m ====> 8. 以YAML格式输出结果 \033[0m"
echo "----------------------------------------------------------"
echo "ca_key: |"
cat $CA_KEY | sed 's/^/  /'
echo
echo "ca_cert: |"
cat $CA_CERT | sed 's/^/  /'
echo
echo "ssl_key: |"
cat $SSL_KEY | sed 's/^/  /'
echo
echo "ssl_csr: |"
cat $SSL_CSR | sed 's/^/  /'
echo
echo "ssl_cert: |"
cat $SSL_CERT | sed 's/^/  /'
echo

echo -e "\033[32m ====> 9. 附加CA证书到Cert文件 \033[0m"
cat ${CA_CERT} >> ${SSL_CERT}
echo "ssl_cert: |"
cat $SSL_CERT | sed 's/^/  /'
echo

echo -e "\033[32m ====> 10. 重命名服务证书 \033[0m"
echo "cp ${SSL_DOMAIN}.key tls.key"
cp ${SSL_DOMAIN}.key tls.key
echo "cp ${SSL_DOMAIN}.crt tls.crt"
cp ${SSL_DOMAIN}.crt tls.crt

(上面的脚本来自 Rancher 官方文档 生成自签名 SSL 证书,非常好用,建议加入到个人笔记)
存盘后chmod +x 后直接运行,根据脚本的步骤一步步完成即可,备份一份后保存好生成的 key 与 crt 文件到临时目录中,然后打开 crt 文件,将第二个证书的内容另存为 pem 文件(这里为 cacerts.pem),这个就是所需的 CA 证书。

接下来执行下面的命令将证书添加到 cattle-system 的 secrets 中去:

kubectl -n cattle-system create secret generic tls-ca \
  --from-file=cacerts.pem=./cacerts.pem

接下来就可以开始 Rancher 的安装了,准备好访问 Rancher 的主机名(这里用 rancher.localhost 代替),然后执行下面的命令:

helm install rancher rancher-latest/rancher \
  --namespace cattle-system \
  --set hostname=rancher.localhost \
  --set ingress.tls.source=secret \
  --set privateCA=true

等待五分钟左右后,使用下面的命令检查 Rancher 是否已成功部署:

kubectl -n cattle-system rollout status deploy/rancher
Waiting for deployment "rancher" rollout to finish: 0 of 3 updated replicas are available...
deployment "rancher" successfully rolled out

若是按照上述步骤执行的话,大致是没有问题的。

先通过以下命令找到初始默认密码:

kubectl get secret --namespace cattle-system bootstrap-secret -o go-template='{{.data.bootstrapPassword|base64decode}}{{ "\n" }}'

安装时 Helm 会向 cattle-system 中添加 ingress,若部署成功后即可通过 Rancher 的主机名进行访问了。然后就像日志中所说的:Happy Containering!

登录后界面:

集群首页:(这里最下面有事件与告警,是因为我安装了 cluster-monitoring 应用;这个能够帮助你管理集群动态的栈可以在应用商店中找到并安装)

集群项目列表:

项目首页:

只要了解 Kubernetes 的大部分概念,Rancher 的使用应该是易如反掌。大部分操作只需试探几次便可熟稔于心了,这里也无需再作过多赘述。

Good Ending 2

接下来可以完成一些非必要,但是能够为以后节省配置时间的操作。

正如前面所提及,我的所有服务(包括由 k3s 部署的容器应用与直接在主机上部署的非容器应用)均会通过 Nginx 负载均衡,然后再通过 Cloudflare 负载均衡后暴露出来。若在每次部署新的服务后,如果都需要重新配置一遍 Nginx 配置文件和 Cloudflare 解析记录的话,未必过于冗杂。
有没有什么简单的方法,只需在 Rancher 上完成部署并创建 ingress 规则后,立刻就能通过 ingress 进行访问呢?我想到的方法是泛域名解析与 Nginx 配置优先级。只需在 Cloudflare 解析处与 Nginx 入口上配置一条泛域名解析,即可轻松实现这样的需求。

例如我的业务通配符域名为 *.toay.io,若此时有发往 workspace.toay.io 的流量,则其先经过 Cloudflare 后到达任意一台服务器中监听着 443 端口的 Nginx,再由 Nginx 依优先级顺序,先完全匹配子域名,失败后再遵循最低优先级的通配符子域名配置,将流量转发到监听 1443 端口的 traefik 上。最后,traefik 再根据配置的 ingress 规则,将流量传递到指定的服务 Mattermost Web 上去。至此,流量成功地抵达了对应的服务,而无需再作多余的配置。

参考链接

  1. Kubernetes
  2. K3s: Lightweight Kubernetes
  3. Rancher k3s 文档
  4. Rancher 2.6 Docs
  5. 生成自签名 SSL 证书 | Rancher 文档