K3s 集群的安装、配置与使用

简介

英文官网 | 中文官网 | 中文文档

K3s 是一个轻量级的 Kubernetes 发行版,它针对边缘计算、物联网等场景进行了高度优化。本文将安装并配置一个 K3s 集群,并测试其的使用。

值得注意的是,与 Kubernetes 不同,这里的 Master 节点叫 Server 节点,而 Slave 节点叫 Agent 节点。

环境

主机名 IP Role vCPUs RAM
k3s-server 10.0.0.39 Server 2 2G
k3s-agent-1 10.0.0.31 Agent 2 2G
k3s-agent-2 10.0.0.32 Agent 2 2G

网络与端口

k3s-server 需要 6443 端口才能被所有节点访问。

其他参考这里

部署 Server 节点

1
root@k3s-server:~# curl -sfL https://get.k3s.io | sh -

使用如下命令查看节点运行状态:

1
2
3
root@k3s-server:~# kubectl get node
NAME STATUS ROLES AGE VERSION
k3s-server Ready control-plane,master 20s v1.24.4+k3s1

使用如下命令获取 node-token

1
2
root@k3s-server:~# cat /var/lib/rancher/k3s/server/node-token
K101e23ad4c6b37c9fdf****::server:****f7538ded6

这个 node-token 一会在部署 Agent 节点的时候需要用到。

部署 Agent 节点

对于每个 Agent 节点,使用如下命令安装 K3s 并直接加入集群:

1
root@k3s-agent-1:~# curl -sfL https://get.k3s.io | K3S_URL=https://myserver:6443 K3S_TOKEN=mynodetoken sh -

例如:

1
root@k3s-agent-1:~# curl -sfL https://get.k3s.io | K3S_URL=https://10.0.0.39:6443 K3S_TOKEN=K101e23ad4c6b37c9fdf****::server:****f7538ded6 sh -

执行完成后,到 Server 节点查看所有节点状态:

1
2
3
4
root@k3s-server:~# kubectl get node
NAME STATUS ROLES AGE VERSION
k3s-server Ready control-plane,master 25m v1.24.4+k3s1
k3s-agent-1 Ready <none> 18s v1.24.4+k3s1

同样,对于 k3s-agent-2 也做同样的部署,完成后节点状态如下:

1
2
3
4
5
root@k3s-server:~# kubectl get node
NAME STATUS ROLES AGE VERSION
k3s-server Ready control-plane,master 31m v1.24.4+k3s1
k3s-agent-2 Ready <none> 3m36s v1.24.4+k3s1
k3s-agent-1 Ready <none> 6m19s v1.24.4+k3s1

设置 K3S_URL 参数会使 K3s 以 worker 模式运行。K3s agent 将在所提供的 URL 上向监听的 K3s 服务器注册。K3S_TOKEN 使用的值存储在你的服务器节点上的 /var/lib/rancher/k3s/server/node-token 路径下。

创建 Pod

将以下代码写入 nginx-pod.yaml

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80

使用如下命令应用:

1
2
root@k3s-server:~/k3s# kubectl apply -f nginx-pod.yaml
pod/nginx created

查看运行状态:

1
2
3
root@k3s-server:~# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 11h

与 Docker 不同,这里进入容器的需要在命令前加上 --

进入 Pod 并测试访问:

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
root@k3s-server:~/k3s# kubectl exec -it nginx -- /bin/bash
root@nginx:/# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

到此为止,我们创建了一个功能正常的 Pod。

创建 Deployment

将以下代码写入 nginx-deployment.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80

使用如下命令应用:

1
2
root@k3s-server:~/k3s# kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx created

查看运行状态:

1
2
3
root@k3s-server:~/k3s# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 29s

此时再查看 Pod,如下:

1
2
3
4
root@k3s-server:~/k3s# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-544dc8b7c4-lzvz9 1/1 Running 0 3m4s
nginx-544dc8b7c4-5nbcw 1/1 Running 0 3m4s

可以看到,由 Deployment 产生的 Pod 命名规则如下:

1
${DeploymentName}-${DeploymentUid}-${Hash}

在查看 Pod 的时候,如果加上 -o wide 参数,就可以查看更多信息:

1
2
3
4
root@k3s-server:~/k3s# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-544dc8b7c4-lzvz9 1/1 Running 0 9m30s 10.42.1.4 k3s-agent-1 <none> <none>
nginx-544dc8b7c4-5nbcw 1/1 Running 0 9m30s 10.42.3.3 k3s-agent-2 <none> <none>

可以看到,该 nginx 被创建了两个 Pod 副本,分别部署在了 k3s-agent-1k3s-agent-2 上面。

创建 Service

Service,将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。

举个例子,考虑一个图片处理后端,它运行了 3 个副本。这些副本是可互换的 —— 前端不需要关心它们调用了哪个后端副本。 然而组成这一组后端程序的 Pod 实际上可能会发生变化, 前端客户端不应该也没必要知道,而且也不需要跟踪这一组后端的状态。

Service 定义的抽象能够解耦这种关联。

Service 有两种类型,一种是 NodePort,选择该种类型的可直接通过 ${serverIP}:${nodePort} 访问内部的服务;另一种是 ClusterIP 类型,它只会在集群内部可以访问到该 Pod,不会把 Pod 的内容映射在某一个外网可以访问的端口上,但这并不意味着不能对外提供服务,而是需要 Ingress 的帮助,来将外网的流量转发到 Service 上来。

NodePort

将以下代码写入 nginx-service-nodeport.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
type: NodePort

这里 nodePort 的范围是 30000-32767

使用如下命令应用:

1
2
root@k3s-server:~/k3s# kubectl apply -f nginx-service-nodeport.yaml 
service/nginx-service created

现在访问 http://10.0.0.39:30080http://10.0.0.31:30080http://10.0.0.32:30080,都可以正常访问到内容:

访问测试

查看 Service:

1
2
3
4
root@k3s-server:~/k3s# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 12h
nginx-service NodePort 10.43.74.219 <none> 80:30080/TCP 7m21s

ClusterIP

Service

将以下代码写入 nginx-service-clusterip.yaml

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80

使用如下命令应用:

1
2
root@k3s-server:~/k3s# kubectl apply -f nginx-service-clusterip.yaml 
service/nginx-service created

这样就创建了 Service,但外部还不能访问,所以需要 Ingress。

Ingress

先做个 DNS 解析:

类型 名称 内容
A *.k3s.jiji.pro 10.0.0.39
A *.k3s.jiji.pro 10.0.0.31
A *.k3s.jiji.pro 10.0.0.32

将以下代码写入 nginx-ingress.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
spec:
rules:
- host: nginx.k3s.jiji.pro
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80

使用如下命令应用:

1
2
root@k3s-server:~/k3s# kubectl apply -f nginx-ingress.yaml 
ingress.networking.k8s.io/nginx-ingress created

现在访问 http://nginx.k3s.jiji.pro 即可访问到部署的服务:

访问测试

尝试关掉 k3s-agent-1

1
root@k3s-agent-1:/home/jiji# shutdown -h now

证实 k3s-agent-1 确实下线了:

1
2
3
4
5
root@k3s-server:~# kubectl get node
NAME STATUS ROLES AGE VERSION
k3s-server Ready control-plane,master 13h v1.24.4+k3s1
k3s-agent-2 Ready <none> 12h v1.24.4+k3s1
k3s-agent-1 NotReady <none> 12h v1.24.4+k3s1

再访问 http://nginx.k3s.jiji.pro,服务出现不可用,但刷新后也可访问正常。经过两次连续的 ping,我们发现 DNS 解析由原本失效的 10.0.0.31,变为了 10.0.0.39。这也就保证了在 Agent 宕机的情况下服务高可用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ ping nginx.k3s.jiji.pro

正在 Ping nginx.k3s.jiji.pro [10.0.0.31] 具有 32 字节的数据:
来自 10.0.0.1 的回复: 无法访问目标主机。
来自 10.0.0.1 的回复: 无法访问目标主机。
来自 10.0.0.1 的回复: 无法访问目标主机。
来自 10.0.0.1 的回复: 无法访问目标主机。

10.0.0.31 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),

$ ping nginx.k3s.jiji.pro

正在 Ping nginx.k3s.jiji.pro [10.0.0.39] 具有 32 字节的数据:
来自 10.0.0.39 的回复: 字节=32 时间=3ms TTL=63
来自 10.0.0.39 的回复: 字节=32 时间=5ms TTL=63
来自 10.0.0.39 的回复: 字节=32 时间=5ms TTL=63
来自 10.0.0.39 的回复: 字节=32 时间=12ms TTL=63

10.0.0.39 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 3ms,最长 = 12ms,平均 = 6ms

但当我关闭 k3s-server 的时候,服务出现了不可用,且无自动切换。或许对于高可用 K3s 集群来说,需要至少两台 Server 节点。

HTTPS

1
2
3
root@k3s-server:~# kubectl create secret tls my-tls-secret \
--cert=path/to/cert/file \
--key=path/to/key/file

nginx-ingress.yaml 中追加:

1
2
3
4
5
spec:
tls:
- hosts:
- nginx.k3s.jiji.pro
secretName: my-tls-secret

K3s 集群的安装、配置与使用

https://mmdjiji.com/2022/09/1201/

作者

吉吉

发布于

2022-09-12

更新于

2022-10-07

许可协议