Featured image of post Homelab(1):使用Kubernetes(K8s)或K3s自建家庭集群

Homelab(1):使用Kubernetes(K8s)或K3s自建家庭集群

使用Kubernetes(K8s)或K3s自建家庭集群

缘起

在开始自建家庭服务器和用容器技术来部署各种私有服务约5年后,我已经熟悉了一套用docker compose管理所有容器的方案,这套方案很优雅也很有用,但这仅限单台电脑。最近我突然有了管理使用多台电脑的需求,我终于开始觉得有必要从单个服务器转向服务器集群,或者说Homelab了。

具体来说,我之前作为服务器的电脑有着比较大的内存和硬盘,但没安装显卡,这对于我之前部署的许多服务已经够了。现在我有了一台有显卡的电脑,想要跑一些大语言模型。当然我可以单独在这台电脑上部署,但这样与我之前的方案就比较割裂了,我希望能有个方案能同时管理这两台电脑。将来再添加其他电脑时也更容易扩展。

当然,转向Kubernetes之前,你最好已经对容器的概念比较熟悉了。我之前写过一系列的关于容器(主要是Docker)的文章可供参考:

Homelab

什么是Homelab

Homelab表面上的意思是指在家中搭建一个实验室,用于学习、实验和开发。Homelab通常包括一台或多台服务器、网络设备、存储设备等,可以用来运行各种服务和应用程序。

Homelab的规模可大可小,如果你财力充足,可以购买多台高性能服务器,搭建一个大型的家庭实验室;如果你财力有限,也可以只用一台普通的电脑,甚至一个树莓派(Raspberry Pi)就可以搭建一个小型的家庭实验室。

为什么需要Homelab

服务器集群或者Homelab听起来离个人用户比较遥远,但实际上并非如此,我甚至觉得很多玩私有服务器的人可能都会慢慢走向Homelab。即使你没有多台电脑或服务器,依然可以尝试使用Kubernetes(K8s)或K3s来管理你的容器化应用,之后如果你有了多台电脑或服务器,你可以很容易地将现有的Kubernetes集群扩展到多台机器上。

总之,Homelab具有很高的灵活性和可扩展性,可以满足个人用户的各种需求。即使你只有简单的需求和简单的硬件,也可以通过搭建Homelab来学习很多新技术和新知识。

Kubernetes(K8s)和K3s

Kubernetes(K8s)是一个开源的容器编排平台,用于自动化容器化应用的部署、扩展和管理。它可能是应用最广泛的搭建Homelab的方案。

当然,Kubernetes里的知识相当复杂,涉及到很多概念和组件,例如Pod、Service、Deployment、Ingress等。对于初学者来说,可能会觉得过于复杂而有些难以理解。K3s是Kubernetes的一个轻量级版本,专为资源受限的环境设计。它去掉了一些不必要的组件和功能,使得K3s更容易安装和管理。K3s非常适合在家庭实验室或小型集群中使用。

在这个系列的文章中,我们将从非常简单的应用出发,使用K3s从零开始搭建一个Kubernetes集群,并逐步扩展到更复杂的应用和多节点。

K3s基础知识

Kubernetes(K8s)是一个很复杂的系统,里面包含了很多组件。K3s对其做了简化,只留下了最核心的组件。我们这里也先只介绍最核心、最基本的概念,来简单了解一下K3s是怎样运作的,其他的组件和概念以后用到时再做介绍。

下图是一个单节点的服务器上K3s运行的基本框架示例:

K3s基本框架

当一个用户对某个服务做出一个请求时,运行过程是这样的:

  1. 当一个外部用户的请求到达K3s集群时,首先会通过Ingress Controller(通常是Traefik)来处理请求。
  2. Ingress Controller会根据Ingress资源定义的路由规则,将请求转发到相应的Service。
  3. Service会将请求转发到对应的Pod,Pod中运行着实际的应用程序容器。

另外,管理员可以通过命令行工具kubectl来管理K3s集群内的组件和资源。

接下来我们来简单介绍一下这几个概念。

Pod

Pod是Kubernetes的最小部署单元,它可以包含一个或多个容器。Pod中的容器共享网络和存储资源。Pod通常用于运行一个应用程序或服务。

Service

Service是Kubernetes中的一个抽象概念,用于定义一组Pod的访问策略。Service可以通过一个固定的IP地址和端口来访问Pod,无论Pod的实际IP地址如何变化。Service可以分为ClusterIP、NodePort、LoadBalancer等类型。

  • ClusterIP:默认类型,Service只能在集群内部访问。
  • NodePort:Service可以在集群外部通过指定的端口访问。
  • LoadBalancer:Service可以通过云提供商的负载均衡器来访问。

Ingress和Ingress Controller

Ingress是Kubernetes中的一个资源,用于管理外部访问集群内部服务的路由规则。Ingress可以通过域名或路径来路由请求到不同的Service。Ingress通常与Ingress Controller一起使用,Ingress Controller负责实现Ingress资源定义的路由规则。

Deployment

Deployment是Kubernetes中的一个控制器,用于管理Pod的部署和更新。Deployment可以定义Pod的副本数、更新策略等。通过Deployment,我们可以轻松地扩展或缩减Pod的数量,并且可以在不影响服务可用性的情况下进行滚动更新。

K3s的安装和配置

接下来我们以一个单节点集群为例,来说明如何使用K3s。之后会介绍如果有更多节点时如何扩展集群。

这里我们选择部署一个最简单的whoami服务。

1. 安装K3s

在Linux服务器上安装K3s非常简单,只需要运行以下命令:

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

运行完成后,K3s会自动创建一个默认的单节点集群。当安装结束时,你会在命令行看到如下输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[INFO]  Creating /usr/local/bin/kubectl symlink to k3s
[INFO]  Creating /usr/local/bin/crictl symlink to k3s
[INFO]  Creating /usr/local/bin/ctr symlink to k3s
[INFO]  Creating killall script /usr/local/bin/k3s-killall.sh
[INFO]  Creating uninstall script /usr/local/bin/k3s-uninstall.sh
[INFO]  env: Creating environment file /etc/systemd/system/k3s.service.env
[INFO]  systemd: Creating service file /etc/systemd/system/k3s.service
[INFO]  systemd: Enabling k3s unit
Created symlink '/etc/systemd/system/multi-user.target.wants/k3s.service''/etc/systemd/system/k3s.service'.
[INFO]  systemd: Starting k3s

这说明这条命令做了以下工作:

  1. 下载并安装K3s。
  2. 创建了kubectlcrictlctr的符号链接,这些工具可以用来管理K3s集群。其中
    • kubectl是Kubernetes的命令行工具,用于管理Kubernetes集群。
    • crictl是容器运行时接口(CRI)的命令行工具,用于管理容器。
    • ctr是容器运行时的命令行工具,用于直接与容器运行时交互。
  3. 创建了k3s-killall.shk3s-uninstall.sh脚本,用于停止和卸载K3s。
    • 运行命令sudo /usr/local/bin/k3s-killall.sh可以停止K3s服务。
    • 运行命令sudo /usr/local/bin/k3s-uninstall.sh可以卸载K3s。
  4. 创建了环境变量文件/etc/systemd/system/k3s.service.env,用于配置K3s服务。
  5. 创建了K3s的systemd服务文件/etc/systemd/system/k3s.service,并启用了该服务。之后每次电脑开机时,K3s服务都会自动启动。
  6. 启动了K3s服务。

2. 验证K3s安装

安装完成后,K3s会在/etc/rancher/k3s目录下创建一个名为k3s.yaml的配置文件。这个文件包含了K3s集群的配置信息,包括API服务器的地址、认证信息等。

上面提到,K3s还安装了一个kubectl作为管理K3s的命令行工具,kubectl运行时需要根据API服务器的地址、认证信息知道它要管理的是哪个集群。kubectl运行时默认读取/etc/rancher/k3s/k3s.yaml文件中的配置信息,如果你不是以root来运行kubectl,会因为权限问题无法读取/etc/rancher/k3s/k3s.yaml文件。这时我们可以将/etc/rancher/k3s/k3s.yaml复制到~/.kube目录下,并更改文件权限,让kubectl可以读取集群信息:

1
2
3
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

现在你可以使用kubectl来管理K3s集群了。可以运行以下命令来验证K3s是否安装成功:

1
kubectl get nodes

如果安装成功,你应该能看到类似下面的输出:

1
2
NAME                  STATUS   ROLES                  AGE   VERSION
fedora.attlocal.net   Ready    control-plane,master   15s   v1.32.5+k3s1

然后查看正在运行的pods:

1
kubectl get pods -A

如果一切正常,你应该能看到类似下面的输出:

1
2
3
4
5
6
NAME                                      READY   STATUS              RESTARTS   AGE   IP       NODE                  NOMINATED NODE   READINESS GATES
coredns-697968c856-scmft                  0/1     ContainerCreating   0          15s   <none>   fedora.attlocal.net   <none>           <none>
helm-install-traefik-crd-7dkch            0/1     ContainerCreating   0          15s   <none>   fedora.attlocal.net   <none>           <none>
helm-install-traefik-qkl97                0/1     ContainerCreating   0          15s   <none>   fedora.attlocal.net   <none>           <none>
local-path-provisioner-774c6665dc-jrbrj   0/1     ContainerCreating   0          15s   <none>   fedora.attlocal.net   <none>           <none>
metrics-server-6f4c6675d5-v97zv           0/1     ContainerCreating   0          15s   <none>   fedora.attlocal.net   <none>           <none>

其中coredns是Kubernetes的DNS服务,helm-install-traefik-crdhelm-install-traefik-qkl97是指安装了Traefik,local-path-provisioner是K3s的默认存储类,metrics-server是Kubernetes的监控服务。

3. 部署whoami服务

现在我们可以部署一个简单的whoami服务来测试K3s集群。whoami是一个非常简单的HTTP服务,它会返回请求的IP地址、请求头等信息,非常适合用来测试K3s集群。

创建whoami应用的manifest

K3s使用一个被称作manifest的YAML文件来定义应用程序的部署。我们可以创建一个名为whoami.yaml的文件,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
  labels:
    app: whoami
spec:
  replicas: 1
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
      - name: whoami
        image: traefik/whoami
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: whoami
  labels:
    app: whoami
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: whoami
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: whoami-ingress
spec:
  ingressClassName: traefik
  rules:
  - host: whoami.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: whoami
            port:
              number: 80

虽然这是一个YAML文件,但实际上有三部分。这里为了简单起见,我们把这三部分放在了同一个文件里,后续的文章会说明,为了更好地组织和管理K3s里的应用,我们应该怎样组织文件结构。

这三部分用---分隔开来,分别定义了:

  1. Deployment:定义了一个名为whoami的Deployment,表示我们要部署一个名为whoami的应用。这个应用有1个副本(replica),使用Traefik官方提供的whoami镜像,并监听80端口。
  2. Service:定义了一个名为whoami的Service,表示我们要创建一个名为whoami的服务。这个服务的类型是ClusterIP,表示只能在集群内部访问。它监听80端口,并将请求转发到Pod中的whoami容器的80端口。
  3. Ingress:定义了一个名为whoami-ingress的Ingress,表示我们要创建一个名为whoami-ingress的Ingress资源。这个Ingress使用Traefik作为Ingress Controller,并将请求路由到名为whoami的Service。
应用whoami服务

现在我们可以使用kubectl来应用这个manifest文件了。运行以下命令:

1
kubectl apply -f whoami.yaml

如果一切正常,你应该能看到类似下面的输出:

1
2
3
deployment.apps/whoami created
service/whoami created
ingress.networking.k8s.io/whoami-ingress created
查看whoami服务状态

首先,我们来确认whoami服务是否已经成功部署。运行以下命令:

1
kubectl get deployments

如果一切正常,你应该能看到类似下面的输出:

1
2
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
whoami        1/1     1            1           2m

接下来,我们来确认whoami服务的Pod是否已经成功运行。运行以下命令:

1
kubectl get pods

如果一切正常,你应该能看到类似下面的输出:

1
2
NAME                        READY   STATUS    RESTARTS   AGE
whoami-5b6c7f8d9f-2j4k5      1/1     Running   0          2m

接下来,我们来确认whoami服务的Service是否已经成功创建。运行以下命令:

1
kubectl get svc

如果一切正常,你应该能看到类似下面的输出:

1
2
3
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
whoami       ClusterIP   10.43.42.148   <none>         8080/TCP  20s
kubernetes   ClusterIP   10.43.0.1      <none>         443/TCP   3m15s
访问whoami服务

现在我们可以通过Ingress来访问whoami服务了。首先,我们在部署whoami的电脑上,或者在同一局域网的电脑上,使用本机地址或者局域网内的地址来访问whoami服务。 如果你在本机上访问,可以使用以下命令:

1
curl "Host: whoami.example.com" http://localhost

如果你在局域网内的其他电脑上访问,例如你的K3s服务器的IP地址是192.168.1.233,可以使用以下命令:

1
curl "Host: whoami.example.com" http://192.168.1.233

这里添加了Host头部信息,因为Ingress需要根据这个头部信息来路由请求到对应的Service,否则Ingress怎么知道你要访问的是哪个Service呢?

如果一切正常,你应该能看到类似下面的输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Hostname: whoami-64f6cf779d-zxsm4
IP: 127.0.0.1
IP: ::1
IP: 10.42.0.9
IP: fe80::b43d:c0ff:fe52:80bd
RemoteAddr: 10.42.0.8:39990
GET / HTTP/1.1
Host: whoami.example.com
User-Agent: curl/8.12.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.42.0.1
X-Forwarded-Host: whoami.jinli.li
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-c98fdf6fb-5q6m6
X-Real-Ip: 10.42.0.1

如果你能看到类似上面的输出,说明whoami服务已经成功运行了。但是注意,这里的X-Forwarded-ForX-Real-Ip的值10.42.0.1是K3s集群内部的IP地址,而不是你访问的电脑的IP地址。这是因为Ingress Controller(Traefik)会将请求转发到whoami服务时,使用了K3s集群内部的IP地址。

TODO: 如何解决这一问题?

如果你想在外部访问whoami服务,你需要将域名whoami.example.com解析到你的K3s服务器的公网IP地址上。然后你就可以通过浏览器或其他HTTP客户端来访问whoami服务了。

如果你在浏览器中访问http://whoami.example.com,你应该能看到类似下面的页面:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Hostname: whoami-64f6cf779d-ktwm9
IP: 127.0.0.1
IP: ::1
IP: 10.42.0.18
IP: fe80::1453:3cff:fe59:5835
RemoteAddr: 10.42.0.8:50132
GET / HTTP/1.1
Host: whoami.jinli.li
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, br
Accept-Language: en
Cache-Control: max-age=0
Priority: u=0, i
Sec-Ch-Ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 10.42.0.11
X-Forwarded-Host: whoami.jinli.li
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-c98fdf6fb-5q6m6
X-Real-Ip: 10.42.0.11

总结

在本篇文章中,我们介绍了K3s的基础知识,并演示了如何在单节点K3s集群上部署一个简单的whoami服务。

在接下来的文章中,我们将继续扩展K3s集群,介绍如何部署更复杂的应用,如何管理多节点集群,以及如何使用K3s的其他功能来满足不同的需求。

鸣谢

我在学习如何使用K3s时参考了Youtube博主LinuxCloudHacks的视频From Zero to Hero: K3s, Traefik & Cloudflare Your Home Lab Powerhouse

comments powered by Disqus