惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
腾讯CDC
G
Google Developers Blog
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
有赞技术团队
有赞技术团队
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
M
MIT News - Artificial intelligence
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
美团技术团队
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志

少数派

派早报:Google 发布 Fitbit Air 等 - 少数派 「新人报到」確認需求,再開始 - 少数派 从 SOLO 独立开发者社区,我看到了越来越多开发者开始做自己的产品 - 少数派 我怎么管理那些"不常做,但总会忘"的生活事项 - 少数派 人形机器人量产元年,数据才是具身智能的“生死线” - 少数派 BuhoLaunchpad 高度还原 Mac 启动台:开发历程与思考 - 少数派 五年陪伴依然不舍,DIY 换壳后让罗技 MX Master 3 继续服役 - 少数派 新玩意 240|少数派的编辑们最近买了啥? - 少数派 一日一技|为什么你应该关闭 iOS 的键盘声音 - 少数派 我做了个插件和 Skills,一键提取任何网站的设计规范 Design.md - 少数派 住在三四线城市的你,该开始录播客了 - 少数派 甘南秘境,大白高国 - 少数派 AI的审美:谁让把我变成川内倫子 - 少数派 返工怎能不烦恼,打工人片单总有一部是你的「嘴替」 - 少数派 为了让「上厕所」更健康,我做了一个小工具 - 少数派 AI + Skill,能够让生成的文章去除 AI 味吗? - 少数派 新玩意|韶音OpenDots ONE 耳夹式耳机 - 少数派 《美满》| 在每一个春天的晚上相爱(362) - 少数派 新玩意|优篮子 PS01 MagSnap 磁吸支架 - 少数派 自我整合手记 | 我开始早睡了:用稳定规则,为自由托底 - 少数派 用龙虾(OpenClaw)两个多月,我最深的12个体会 - 少数派 听歌时间到,12 张你可能错过的 2025 华语乐坛好专辑 - 少数派 承诺能追吗 - 少数派 macOS 26启动台没了? 我做了个不一样的App启动器 - Keboard - 少数派 《四海为家的人》| INTJ对话INTJ(361) - 少数派 你发过的那些黑历史,是时候一次清干净了 - 少数派 新玩意:安安静静玩,越玩越专注:计客密码机 - 少数派 iPad 用户首次体验 Android 平板:vivo Pad6 Pro - 少数派 数据逻辑强 - 少数派 极北行+ | 一路向北,探访日本至北之地 | 001 - 少数派
技术笔记 · 我用树莓派搭了个 Kubernetes 集群 - 少数派
2022-02-27 · via 少数派

众所周知(并不),我有一台群晖 DS918+,上面用 Docker 跑了很多服务(比如馒头地球的服务端,还有一些自己写的家庭自动化的东西)。年前突发奇想要把它们迁到树莓派上,并且用 Kubernetes(简称 k8s)管理起来。整个过程我记录了一些笔记,这里整理出来。

为什么要用 k8s

我的现状:我的所有服务使用 docker-compose 进行编排。其中通过 Traefik 将不同域名反代到不同服务上。这里就产生了一些问题:

  1. 我需要通过一个 git 仓库来管理我这个 docker-compose.yml 和其它一些配置文件
  2. 每次增减服务都需要手动编辑这个 docker-compose.yml,提交;然后 SSH 到服务器上,拉取,然后 docker-compose up -d
  3. 我手上还有几台机器,但是它们彼此互相独立。我需要记住我的每一个服务都运行在拿台服务器,并且手动维护域名解析

这种情况下,k8s 就是一个万能的解决方案。

一些概念

k8s 把所有概念都抽象成了「资源」。对集群的所有操作也抽象成了对这些资源的增删查改。常用的几个资源类型可以简化理解如下:

  • Node:节点,可以是一台云主机,一台树莓派,一部电脑。上面运行了很多 Pod
  • Pod:一个基本的业务单位(一时没想到咋解释)。一个镜像跑起来就是一个 Pod(当然还有其它一些辅助性的东西在里面)。通常不需要手动创建
  • Deployment:部署。集群会根据这个资源的定义拉取其中指定的镜像,并创建对应的 Pod,为 Pod 赋予相应的 label 以及其它元数据
  • Service:服务。用于定义由哪一些具备对应 label 的 Pod 来承载这个 Service。同时也定义了这个服务会对外提供哪些端口
  • Ingress:用于定义域名与 Service 的关系。外面的请求进来,集群的 Ingress Controller(比如 Nginx 或 Traefik)根据请求的域名对应的 Ingress 资源取得所指向的 Service,再通过 Service 定义的 label 筛选出对应的 Pod,并且将请求反代到其中的某个 Pod 上

系统安装

在树莓派上跑完整的 Kubernetes 是不太可行的。所以我选用了一个轻量级实现:k3s。硬件使用的是 8GB RAM 版本的树莓派 4B。

要运行 k3s,首先你需要 64 位版本的 Raspberry Pi OS。官网首页看到的是 32 位的,64 位需要通过链接下载:https://downloads.raspberrypi.org/raspios_lite_arm64/images/

下载完的镜像通过 balenaEtcher 之类的工具写到 TF 卡上,并且还编辑 cmdline.txt 开启 cgroups。在 cmdline.txt 末尾加上:

cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1

保存,退盘,插卡,上电。

更新软件

因为众所周知的原因,树莓派的 APT 源在国内访问速度不太理想。可以切换为 USTC 镜像。这里有一点注意的是,64 位版的 Rasp OS 使用的直接就是 Debian 的官方源,而不是 32 位的 Raspbian 源。

sudo sed -i 's|deb.debian.org|mirrors.ustc.edu.cn|g' /etc/apt/sources.list && \
sudo sed -i 's|security.debian.org/debian-security|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list && \
sudo sed -i 's|//archive.raspberrypi.org|//mirrors.ustc.edu.cn/archive.raspberrypi.org|g' /etc/apt/sources.list.d/raspi.list && \
sudo apt update && \
sudo apt upgrade

部署 master 节点

参考:https://rancher.com/docs/k3s/latest/en/quick-start/

非常简单:

curl -sfL https://get.k3s.io | sh -

远程操作集群

本机安装了 kubectl 之后,通过配置,可以直接从本机通过 kubectl 命令操作集群,而不需要每次都 SSH 到 master 节点上。

注意,向公网暴露集群 API 是有一定危险性的。通常我的做法是只开放必要的端口,而本机操作服务器通过 OpenVPN 进行。当然,这篇文章假设你的树莓派放在家里的内网,也就不用关心这个。

在 master 节点上复制 kube config:

sudo cat /etc/rancher/k3s/k3s.yaml

将上面的内容复制到本地的 ~/.kube/config。其中的 server 字段改为你的树莓派的地址。

部署 worker 节点

其实后来我发现我的业务就算单个 master 节点也完全够用…但既然记下了,也发出来,万一你们需要呢。

在 master 节点上执行这个命令,并记下 token:

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

在 worker 节点上执行:

curl -sfL https://get.k3s.io | K3S_URL=https://master节点的地址:6443 K3S_TOKEN=刚刚的token sh -

检查运行情况:

sudo systemctl status k3s-agent.service
sudo journalctl -b -f -u k3s-agent.service

安装 cert-manager

cert-manager 用于管理 Let's Encrypt 证书的自动签发。这样对外就能提供 HTTPS 服务,且整个过程都可以自动完成、免维护。

参考:https://cert-manager.io/docs/installation/helm/
参考:https://artifacthub.io/packages/helm/cert-manager/cert-manager#configuration

helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
    --namespace cert-manager --create-namespace \
    --version v1.7.0 \
    --set installCRDs=true

配置 DNS-01

Let's Encrypt 需要定期进行证书更新(ACME)。默认的做法是走 HTTP-01 认证,也就是开放一个 HTTP 接口让 Let's Encrypt 服务访问你来完成核验。但我们的服务器跑在内网,而且我也不想开端口。因此有另一个选择是 DNS-01。

DNS-01 的原理简单来说,就是通过域名提供商的 API 创建一条 DNS TXT 记录携带必要的信息,让 Let's Encrypt 的服务器去解析这条记录取得信息,完成核验。我的域名解析是放在 Cloudflare 上的,对这个流程支持非常友好。

参考:https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/

https://dash.cloudflare.com/profile/api-tokens 创建一个 API token。

本地创建下面两个 yml 文件,并且通过 kubectl apply -f xxxx.yml 将它们提交到 k8s 集群。

apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
  namespace: cert-manager
type: Opaque
stringData:
  api-token: 刚刚申请的 API token
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: 你的Email地址
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - dns01:
        cloudflare:
          email: 你的CF账号Email地址
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

安装 Rancher

Rancher 是一个 k8s 管理面板。

参考:https://rancher.com/docs/rancher/v2.6/en/installation/install-rancher-on-k8s/
参考:https://rancher.com/docs/rancher/v2.6/en/installation/install-rancher-on-k8s/chart-options/#common-options
参考:rancher/rancher#26850

为了方便使用,我给它分配了一个二级域名。域名地址不一定(也不建议)用公网 API,用内网的就可以。

建一个 Certificate,这样 cert-manager 就会自动通过 Let's Encrypt 给你这个二级域名申请 HTTPS 证书:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: tls-rancher-ingress
  namespace: cattle-system
spec:
  secretName: tls-rancher-ingress
  commonName: 你的rancher二级域名
  dnsNames:
  - 你的rancher二级域名
  issuerRef:
    name: letsencrypt
    kind: ClusterIssuer

加一条 Ingress,用以将这个域名指向到 Rancher 服务:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rancher
  namespace: cattle-system
spec:
  rules:
  - host: 你的rancher二级域名
    http:
      paths:
      - backend:
          service:
            name: rancher
            port:
              number: 80
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - 你的rancher二级域名
    secretName: tls-rancher-ingress

安装 Rancher:

helm repo add rancher-latest https://releases.rancher.com/server-charts/latest
helm install rancher rancher-latest/rancher \
    --namespace cattle-system --create-namespace \
    --set hostname=你的rancher二级域名 \
    --set bootstrapPassword=admin \
    --set ingress.tls.source=secret

DevOps

留个坑…