0%

k3s

k3s

k3s是经过CNCF认证的由Rancher公司开发维护的一个轻量级的 Kubernetes 发行版,内核机制还是和 k8s 一样,但是剔除了很多外部依赖以及 K8s 的 alpha、beta 特性,同时改变了部署方式和运行方式,目的是轻量化 K8s,简单来说,K3s 就是阉割版 K8s,消耗资源极少。它主要用于边缘计算、物联网等场景。

K3s 具有以下特点:

1)安装简单,占用资源少,只需要512M内存就可以运行起来;
2)apiserver 、schedule 等组件全部简化,并以进程的形式运行在节点上,把程序都打包为单个二进制文件,每个程序只需要占用100M内存;
3)使用基于sqlite3的轻量级存储后端作为默认存储机制。同时支持使用etcd3、MySQL 和PostgreSQL作为存储机制;
4)默认使用 local-path-provisioner 提供本地存储卷;
5)默认安装了Helm controller 和 Traefik Ingress controller;
6)所有 Kubernetes control-plane 组件的操作都封装在单个二进制文件和进程中,使 K3s 具有自动化和管理包括证书分发在内的复杂集群操作的能力。
7)减少外部依赖,操作系统只需要安装较新的内核(centos7.6就可以,不需要升级内核)以及支持cgroup即可,k3s安装包已经包含了containerd、Flannel、CoreDNS,非常方便地一键式安装,不需要额外安装Docker、Flannel等组件。

官网: https://k3s.io/

github: https://github.com/k3s-io/k3s

架构

k3s下载

k3s server和k3s agent对应k8s的master节点和worker(node)节点。下面部署节点时也许区分master(server)和worker(agent)的节点

k3s默认就集成了kubernets master/agent节点的apiserver、scheduler、controller manager、kube proxy、kubelet、kube proxy、containerd,无需手动部署和管理。其网络组件默认也集成了flannel(如果是正常kubernetes部署需要在节点部署完以后额外部署网络组件)

所以k3s的部署除了数据存储模块以外,其他已经集成在了K3S中,部署比较简单,当然数据存储默认也是集成了的,但用的是sqllite数据库,对于生产集群不太适合,这里推荐使用etcd这种分布式数据库。

部署

部署前需要注意的点

1
2
3
4
1.部署的节点有master节点和worker(node)节点两种类型,第一个节点肯定是master节点。需要在部署或加入集群的时候指定节点类型
2.虽然K3S的部署要求相较于kubernetes更低,但也有一定要求,尤其是作为运行apiserver、scheduler、controller manager的master节点,至少需要保证双核4G的配置。这里虽然官方最低要求为1核512M内存,但本人测试1核1G的配置加入K3S集群时即使是以master节点形式加入,也会自动变成worker节点(可能因为配置太低无法成为master节点)。如果是创建新集群节点(master节点)但配置过低会出现K3S apiserver无法启动的情况,并且运行一会儿就会挂掉(因为本身配置不足以运行master节点需要的所有服务)
3.如果默认在创建新集群时如果不指定数据库会使用SQLite来作为其数据库,如需要使用etcd或者mysql之类的外置数据库,需要手动指定。默认的sqlite的数据路径位于/var/lib/rancher/k3s/server/db
4.在k3s1.22版本以后,当创建新的集群指定--cluster-init参数时(不指定的话不会使用内置etcd,会使用默认的sqlite),会默认使用etcd作为存储。k3s会默认启动一个etcd进程监听2379端口,其数据目录位于: /var/lib/rancher/k3s/server/db/etcd ,默认证书目录位于:/var/lib/rancher/k3s/server/tls

部署(加入已有集群)

这里的部署主要是加入已有集群(非创建新集群)。这里默认的已有集群使用的数据库存储是外置etcd集群,使用内置数据库存储或者其他外置数据库存储后面会讲解,这里以外置etcd集群为例。

脚本部署

复制etcd密钥认证文件(这里K8S集群的信息都是存储于etcd中的,默认也支持其他数据存储例如mysql等)

1
2
mkdir /etc/etcd
scp -r 192.168.110.29:/etc/etcd/ssl /etc/etcd/

k3s有官方部署脚本,可以通关官方脚本进行部署。

1
2
3
4
5
6
7
8
9
10
11
export K3S_DATASTORE_CAFILE="/etc/etcd/ssl/ca.pem"
export K3S_DATASTORE_CERTFILE="/etc/etcd/ssl/etcd.pem"
export K3S_DATASTORE_ENDPOINT="https://192.168.110.29:2379,https://192.168.110.30:2379,https://192.168.110.31:2379,https://192.168.110.32:2379,https://192.168.110.33:2379"
export K3S_DATASTORE_KEYFILE="/etc/etcd/ssl/etcd-key.pem"
export K3S_TOKEN="K10233d0260e9db94568661572c2f526a89b1d82c665c92d14d1e64f1d6bde0fd80::server:finsiot-k3s-token"
export INSTALL_K3S_MIRROR=cn
export INSTALL_K3S_VERSION=v1.24.10+k3s1

master节点部署:curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh| sh -s - server
如果要以worker节点形式部署(加入集群):
worker节点部署: curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh| sh -s - agent --server https://192.168.110.29:6443

命令解释:

1
2
3
export后面都是定义环境变量,用于部署时使用。
K3S_DATASTORE_CAFILE、K3S_DATASTORE_CERTFILE、K3S_DATASTORE_KEYFILE定义etcd的证书文件,K3S_DATASTORE_ENDPOINT定义etcd的服务端地址(所有节点),K3S_TOKEN是K3S的token值:这个值取自已有k3s集群中任意一个节点的/var/lib/rancher/k3s/server/node-token文件中,用cat命令可以查看,INSTALL_K3S_MIRROR定义镜像源为中国源,INSTALL_K3S_VERSION定义安装版本号。
curl表示拉取脚本,后面 sh -s - server 表示运行脚本,并且以server的形式启动(还可以以agent的方式启动)

问题:

1
这个自动化部署脚本目前最低支持v1.24.10的版本(国内源),再老一点的版本无法进行部署安装,如果想要进行老版本的安装,要么使用国外源,要么就只能换别的部署方式。但国外源需要服务器本身网络可以翻墙,所以比较麻烦。
部署低于1.24.10的版本
1
curl -sfL https://get.k3s.io |INSTALL_K3S_VERSION=v1.24.4+k3s1 sh -s - server #上面的export变量仍然需要定义(除了需要换版本号),但把最后一步脚本换成官方源脚本。因为这里需要去github拉取镜像,所以国内网络可能会很慢甚至没办法下载。
关于–server参数

这里能看到有agent部署的时候是带了–server的,但master部署是没带的。首先这里master节点不一定需要跟–server参数,比如上面这里部署的时候就没带这个参数,master节点可以通过etcd的服务器端来找到k3s集群。这里agent是一定需要跟–server参数的,如果没有将无法启动成功。

所以这里启动的时候看情况会带–server参数,server端部署时如果找不到就可以使用–server参数(一般能通过etcd变量就能找到了),但一般情况不需要额外带这个参数,我在测试部署时有时候部署master节点加入已有集群时是没能找到集群的,就可以通过添加这个参数来找到,但只需要第一次启动添加参数,后面再重启不再需要跟上该参数。

关于master节点不跟–server找不到集群的情况(加入已有集群)

如果是二进制部署并且第一次启动就是通过systemctl start k3s启动(这里变量加载的是/etc/systemd/system/k3s.service.env中定义的变量),这种情况是一定找不到集群的。但如果是官方脚本自动部署的或者传递环境变量使用k3s命令启动,是可以找到已有集群的。

二进制方式部署

首先去github官网下载对应版本的二进制包文件

1
2
3
4
5
6
例如我这里是1.24.4
k3sv1.24.4地址:https://github.com/k3s-io/k3s/releases/tag/v1.24.4%2Bk3s1
wget https://github.com/k3s-io/k3s/releases/download/v1.24.4%2Bk3s1/k3s #这里使用wget下载,如果服务器不能翻墙,也可以用windows翻墙下载以后再上传到linux里面。
上传或者下载完毕以后:
chmod 755 ./k3s
mv k3s /usr/local/bin/

定义环境变量**(这里和上面一样需要事先准备好etcd的证书文件,下面不再重复复制证书操作)**:

1
2
3
4
5
export K3S_DATASTORE_CAFILE="/etc/etcd/ssl/ca.pem"
export K3S_DATASTORE_CERTFILE="/etc/etcd/ssl/etcd.pem"
export K3S_DATASTORE_ENDPOINT="https://192.168.110.29:2379,https://192.168.110.30:2379,https://192.168.110.31:2379,https://192.168.110.32:2379,https://192.168.110.33:2379"
export K3S_DATASTORE_KEYFILE="/etc/etcd/ssl/etcd-key.pem"
export K3S_TOKEN="K10233d0260e9db94568661572c2f526a89b1d82c665c92d14d1e64f1d6bde0fd80::server:finsiot-k3s-token"
1
k3s server --server https://192.168.110.29:6443  #这里的--server后面只需要指定一个已有集群的apiserver地址,任意一个都行。

当然上述这种方式可以直接部署,但是存在一个问题,不好随时查看k3s的状态以及没有办法很好的控制其重启或者暂停服务。这里如果用的linux系统为类centos系统可以使用systemctl来控制k3s

systemd配置

/etc/systemd/system/k3s.service

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
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
After=network-online.target

[Install]
WantedBy=multi-user.target
[Service]
Type=notify
EnvironmentFile=-/etc/default/%N
EnvironmentFile=-/etc/sysconfig/%N
EnvironmentFile=-/etc/systemd/system/k3s.service.env
KillMode=process
Delegate=yes
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
ExecStartPre=/bin/sh -xc '! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service'
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s server --server https://192.168.110.29:6443
#如果要以worker节点形式部署加入集群则将ExecStart改为
#ExecStart=/usr/local/bin/k3s agent --server https://192.168.110.29:6443

/etc/systemd/system/k3s.service.env(K3S服务的环境变量配置文件)

1
2
3
4
5
K3S_DATASTORE_CAFILE="/etc/etcd/ssl/ca.pem"
K3S_DATASTORE_CERTFILE="/etc/etcd/ssl/etcd.pem"
K3S_DATASTORE_ENDPOINT="https://192.168.110.29:2379,https://192.168.110.30:2379,https://192.168.110.31:2379,https://192.168.110.32:2379,https://192.168.110.33:2379"
K3S_DATASTORE_KEYFILE="/etc/etcd/ssl/etcd-key.pem"
K3S_TOKEN="K10233d0260e9db94568661572c2f526a89b1d82c665c92d14d1e64f1d6bde0fd80::server:finsiot-k3s-token"

配置好以后就可以使用systemctl来控制k3s了

1
2
启动:systemctl start k3s
停止:systemctl stop k3s

部署新的集群(使用etcd作为外置存储)

首先这里要准备好etcd集群,上面加入已有集群和这里部署新的集群默认都是使用外置etcd集群,使用内置数据库存储或者其他外置数据库存储后面会讲解,这里以外置etcd集群为例。

部署etcd集群

这里部署的etcd集群节点为三台,部署示例ip分别为:192.168.86.128、192.168.86.129、192.168.86.130。其hosts文件解析的节点名称分别为etcd.node1、etcd.node2、etcd.node3。下面的部署示例仅以node1节点为例。

颁发私有证书

这里需要用私有证书工具来颁发私有证书,用于etcd自身通信以及与K3S通信使用。(etcd还支持其他认证通信方式,到这里默认与k3s通信是用证书文件,所以要先颁发私有证书)

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
1.下载cfssl工具来生成证书
curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o /usr/local/bin/cfssl
curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o /usr/local/bin/cfssljson
curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o /usr/local/bin/cfssl-certinfo
chmod 755 /usr/local/bin/cfssl
chmod 755 /usr/local/bin/cfssljson
chmod 755 /usr/local/bin/cfssl-certinfo
2.自签Etcd SSL证书
mkdir -p /etc/etcd/ssl
cd /etc/etcd/ssl
2.1 创建CA配置文件
#expiry是证书过期时间
cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"etcd": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
}
EOF
2.2创建CA证书签名请求文件
cat > ca-csr.json << EOF
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "etcd",
"OU": "System"
}
],
"ca": {
"expiry": "87600h"
}
}
EOF
2.3生成CA证书和私钥
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2.4创建证书签名请求文件
#这里hosts需要填入所有将要部署的etcd节点的ip以及节点域名(在/etc/hosts文件中会定义)
cat > etcd-csr.json << EOF
{
"CN": "etcd",
"hosts": [
"192.168.86.128",
"192.168.86.129",
"192.168.86.130",
"etcd.node1",
"etcd.node2",
"etcd.node3"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Finsiot",
"L": "FJ",
"CN": "Etcd CA"
},
{
"type": "subjectAltName",
"value": "DNS:etcd.node1, DNS:etcd.node2, DNS:etcd.node3, IP:192.168.86.128, IP:192.168.86.129, IP:192.168.86.130, IP:127.0.0.1"
}
]
}
EOF
2.5为Etcd生成证书和私钥
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd etcd-csr.json | cfssljson -bare etcd
  • etcd-key.pem:etcd的私钥

  • etcd.pem:etcd的数字证书

  • ca-key.pem:ca的私钥

  • ca.pem:ca的数字证书

生成的证书文件需要放在每一个etcd节点的:/etc/etcd/ssl目录下

hosts文件

生成etcd node节点的hosts文件,确保节点之间可以相互解析。(需要在每个etcd节点执行

1
2
3
4
5
cat >> /etc/hosts << EOF
192.168.86.128 etcd.node1
192.168.86.129 etcd.node2
192.168.68.130 etcd.node3
EOF
etcd部署

每个节点执行部署命令

1
yum -y install etcd
配置文件

执行下面的命令生成etcd的配置文件,每个节点都需要生成该配置文件,但不同节点之间需要将变量:ETCD_INITIAL_ADVERTISE_PEER_URLS、ETCD_ADVERTISE_CLIENT_URLS更改为自己节点的节点名称。ETCD_INITIAL_CLUSTER记录了所有节点的etcd服务器地址,如果有其他节点都需要加进去。

需要特别注意的点:

ETCD_INITIAL_CLUSTER:这个如果有三个服务器应该写为:ETCD_INITIAL_CLUSTER=”etcd.node1=https://etcd.node1:2380,https://etcd.node2:2380,https://etcd.node3:2380"这种形式,但如果都写进去就需要节点一起启动才行,否则节点会因为找不到其他节点(因为没启动或者还没部署),会启动失败。所以这里就先填了一个node1的信息。

ETCD_INITIAL_CLUSTER_STATE: 第一个初始化节点这里配置值为 new,后面的节点配置值为existing

后面的节点在配置完启动前还需要在第一个节点上面先通过下面的命令添加节点(这里不考虑其他集群节点注册方式):

1
2
etcdctl  --ca-file=/etc/etcd/ssl/ca.pem --cert-file=/etc/etcd/ssl/etcd.pem --key-file=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.86.128:2379 member add etcd.node2 --peer-urls="http://192.168.86.129:2380"
etcdctl --ca-file=/etc/etcd/ssl/ca.pem --cert-file=/etc/etcd/ssl/etcd.pem --key-file=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.86.128:2379 member add etcd.node3 --peer-urls="http://192.168.86.130:2380"

etcd.conf(配置文件)

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
cat > /etc/etcd/etcd.conf << EOF
[Member]
ETCD_DATA_DIR="/home/etcd/data"
ETCD_WAL_DIR="/home/etcd/logs"
ETCD_LISTEN_PEER_URLS="https://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="https://0.0.0.0:2379"
ETCD_MAX_SNAPSHOTS="5"
ETCD_MAX_WALS="5"
ETCD_NAME="etcd.node1"
ETCD_SNAPSHOT_COUNT="100000"
ETCD_HEARTBEAT_INTERVAL="100"
ETCD_ELECTION_TIMEOUT="1000"
ETCD_QUOTA_BACKEND_BYTES="0"
ETCD_MAX_REQUEST_BYTES="1572864"
ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"

[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://etcd.node1:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://etcd.node1:2379"
ETCD_DISCOVERY=""
ETCD_DISCOVERY_FALLBACK="proxy"
ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="etcd.node1=https://etcd.node1:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_STRICT_RECONFIG_CHECK="true"
ETCD_ENABLE_V2="true"

[Proxy]
ETCD_PROXY="off"
ETCD_PROXY_FAILURE_WAIT="5000"
ETCD_PROXY_REFRESH_INTERVAL="30000"
ETCD_PROXY_DIAL_TIMEOUT="1000"
ETCD_PROXY_WRITE_TIMEOUT="5000"
ETCD_PROXY_READ_TIMEOUT="0"

[Security]
ETCD_CERT_FILE="/etc/etcd/ssl/etcd.pem"
ETCD_KEY_FILE="/etc/etcd/ssl/etcd-key.pem"
ETCD_CLIENT_CERT_AUTH="true"
ETCD_TRUSTED_CA_FILE="/etc/etcd/ssl/ca.pem"
ETCD_AUTO_TLS="true"
ETCD_PEER_CERT_FILE="/etc/etcd/ssl/etcd.pem"
ETCD_PEER_KEY_FILE="/etc/etcd/ssl/etcd-key.pem"
ETCD_PEER_CLIENT_CERT_AUTH="true"
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/ssl/ca.pem"
ETCD_PEER_AUTO_TLS="true"

[Logging]
ETCD_DEBUG="false"
ETCD_LOG_PACKAGE_LEVELS=""
ETCD_LOG_OUTPUT="default"

[Unsafe]
ETCD_FORCE_NEW_CLUSTER="false"

[Version]
ETCD_VERSION="false"
ETCD_AUTO_COMPACTION_RETENTION="0"

[Profiling]
ETCD_ENABLE_PPROF="false"
ETCD_METRICS="basic"

[Auth]
ETCD_AUTH_TOKEN="simple"

EOF

这里需要将etcd的配置文件和证书文件授予etcd用户权限(因为yum安装的etcd默认的service(systemd)文件中定义的启动用户是etcd)

etcd用户无需创建,因为使用yum安装etcd的时候自动创建了etcd用户。

etcd的数据目录/home/etcd/data和日志目录/home/etcd/logs由于本身就是在etcd的家目录(没有权限问题),etcd启动时会自己创建。

1
chown -R etcd:etcd /etc/etcd #将etcd的配置文件和证书文件授予etcd用户权限

部署完启动

1
systemctl start etcd

脚本部署

1
2
3
4
5
6
7
export K3S_DATASTORE_CAFILE="/etc/etcd/ssl/ca.pem"
export K3S_DATASTORE_CERTFILE="/etc/etcd/ssl/etcd.pem"
export K3S_DATASTORE_ENDPOINT="https://etcd.node1:2379,https://etcd.node2:2379,https://etcd.node3:2379"
export K3S_DATASTORE_KEYFILE="/etc/etcd/ssl/etcd-key.pem"
export INSTALL_K3S_MIRROR=cn
export INSTALL_K3S_VERSION=v1.24.10+k3s1 #版本号,这是目前国内源最低支持的版本
curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh| sh -s - server

由于上面脚本部署已经写过了,这里就不重复赘述了。由于是新部署集群,所以不需要指定K3S的token。当其他节点加入集群时,除了etcd的相关配置变量以外,还需要额外指定k3s集群的token,这个上面有写。

二进制部署

1
2
3
4
和上面一样,这里使用v1.24.4
wget https://github.com/k3s-io/k3s/releases/download/v1.24.4%2Bk3s1/k3s
chmod 755 ./k3s
mv k3s /usr/local/bin/
systemd配置

/etc/systemd/system/k3s.service

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
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
After=network-online.target

[Install]
WantedBy=multi-user.target
[Service]
Type=notify
EnvironmentFile=-/etc/default/%N
EnvironmentFile=-/etc/sysconfig/%N
EnvironmentFile=-/etc/systemd/system/k3s.service.env
KillMode=process
Delegate=yes
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
ExecStartPre=/bin/sh -xc '! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service'
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s server

/etc/systemd/system/k3s.service.env(K3S服务的环境变量配置文件)

1
2
3
4
K3S_DATASTORE_CAFILE="/etc/etcd/ssl/ca.pem"
K3S_DATASTORE_CERTFILE="/etc/etcd/ssl/etcd.pem"
K3S_DATASTORE_ENDPOINT="https://etcd.node1:2379,https://etcd.node2:2379,https://etcd.node3:2379"
K3S_DATASTORE_KEYFILE="/etc/etcd/ssl/etcd-key.pem"

启动k3s

1
2
3
systemctl start k3s
如果想要直接启动可以使用命令(如果传了环境变量就不用带后面的参数):
k3s server --datastore-endpoint="https://etcd.node1:2379,https://etcd.node2:2379,https://etcd.node3:2379" --datastore-cafile=/etc/etcd/ssl/ca.pem --datastore-certfile=/etc/etcd/ssl/etcd.pem --datastore-keyfile=/etc/etcd/ssl/etcd-key.pem

使用k3s的内置数据库存储部署

1
2
如果不适用外置数据库则在部署时无需传datastore-endpoint也无需定义etcd的环境变量,例如上面的部署集群如果不用etcd则去掉k3s.service.env文件的所有变量,直接启动即可,这样会使用k3s的SQLite做为数据库。
也可以在部署启动时跟上参数--cluster-init,这样会把sqllite替换为内置etcd,使用内置的etcd作为k3s数据库存储(可高可用)。

备注:如果使用外置存储但非etcd,例如mysql,直接把–datastore-endpoint参数替换为对应数据库的url连接地址即可,详情请参考官方文档:https://docs.k3s.io/zh/datastore/ha

停止k3s服务以及卸载

停止k3s

1
2
k3s命令没有stop选项,一般可以使用:systemctl stop k3s
但这里需要注意的是,停止k3s只是停止其本身服务,但其依赖组件containerd并不会停止(所有容器实际上还是在运行),所以k3s停止或者重启的速度是很快的,几乎不会有任何用户能感知到变化,但本质上是并未真正停用服务。

完全停止k3s服务

1
2
如果是官方脚本部署的k3s,会存在一个k3s-killall.sh脚本,位于/usr/local/bin/k3s-killall.sh。环境变量可以直接调用脚本,执行了会停止k3s所有服务以及containerd。
执行命令: k3s-killall.sh

但如果是二进制包部署的是没有这个脚本的,可以手动添加到服务器中,直接执行脚本即可彻底停掉k3s服务(只能停掉systemd控制的k3s)。

k3s-killall.sh
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/bin/sh
[ $(id -u) -eq 0 ] || exec sudo $0 $@

for bin in /var/lib/rancher/k3s/data/**/bin/; do
[ -d $bin ] && export PATH=$PATH:$bin:$bin/aux
done

set -x

for service in /etc/systemd/system/k3s*.service; do
[ -s $service ] && systemctl stop $(basename $service)
done

for service in /etc/init.d/k3s*; do
[ -x $service ] && $service stop
done

pschildren() {
ps -e -o ppid= -o pid= | \
sed -e 's/^\s*//g; s/\s\s*/\t/g;' | \
grep -w "^$1" | \
cut -f2
}

pstree() {
for pid in $@; do
echo $pid
for child in $(pschildren $pid); do
pstree $child
done
done
}

killtree() {
kill -9 $(
{ set +x; } 2>/dev/null;
pstree $@;
set -x;
) 2>/dev/null
}

getshims() {
ps -e -o pid= -o args= | sed -e 's/^ *//; s/\s\s*/\t/;' | grep -w 'k3s/data/[^/]*/bin/containerd-shim' | cut -f1
}

killtree $({ set +x; } 2>/dev/null; getshims; set -x)

do_unmount_and_remove() {
set +x
while read -r _ path _; do
case "$path" in $1*) echo "$path" ;; esac
done < /proc/self/mounts | sort -r | xargs -r -t -n 1 sh -c 'umount "$0" && rm -rf "$0"'
set -x
}

do_unmount_and_remove '/run/k3s'
do_unmount_and_remove '/var/lib/rancher/k3s'
do_unmount_and_remove '/var/lib/kubelet/pods'
do_unmount_and_remove '/var/lib/kubelet/plugins'
do_unmount_and_remove '/run/netns/cni-'

# Remove CNI namespaces
ip netns show 2>/dev/null | grep cni- | xargs -r -t -n 1 ip netns delete

# Delete network interface(s) that match 'master cni0'
ip link show 2>/dev/null | grep 'master cni0' | while read ignore iface ignore; do
iface=${iface%%@*}
[ -z "$iface" ] || ip link delete $iface
done
ip link delete cni0
ip link delete flannel.1
ip link delete flannel-v6.1
ip link delete kube-ipvs0
ip link delete flannel-wg
ip link delete flannel-wg-v6
rm -rf /var/lib/cni/
iptables-save | grep -v KUBE- | grep -v CNI- | grep -iv flannel | iptables-restore
ip6tables-save | grep -v KUBE- | grep -v CNI- | grep -iv flannel | ip6tables-restore

卸载k3s

如果是二进制部署的k3s删除/var/lib/rancher以及/etc/rancher的文件即可。如果是外置etcd的数据源还需要额外删除etcd的数据。

如果是脚本一键部署的可以使用k3s-uninstall.sh来删除,脚本部署的k3s和上面的kill脚本一样,会自带这个脚本,位于:/usr/local/bin/k3s-uninstall.sh,直接执行即可卸载k3s。

下面附上卸载脚本(二进制部署的也可以直接使用)

k3s-uninstall.sh
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
54
55
56
57
#!/bin/sh
set -x
[ $(id -u) -eq 0 ] || exec sudo $0 $@

/usr/local/bin/k3s-killall.sh

if command -v systemctl; then
systemctl disable k3s
systemctl reset-failed k3s
systemctl daemon-reload
fi
if command -v rc-update; then
rc-update delete k3s default
fi

rm -f /etc/systemd/system/k3s.service
rm -f /etc/systemd/system/k3s.service.env

remove_uninstall() {
rm -f /usr/local/bin/k3s-uninstall.sh
}
trap remove_uninstall EXIT

if (ls /etc/systemd/system/k3s*.service || ls /etc/init.d/k3s*) >/dev/null 2>&1; then
set +x; echo 'Additional k3s services installed, skipping uninstall of k3s'; set -x
exit
fi

for cmd in kubectl crictl ctr; do
if [ -L /usr/local/bin/$cmd ]; then
rm -f /usr/local/bin/$cmd
fi
done

rm -rf /etc/rancher/k3s
rm -rf /run/k3s
rm -rf /run/flannel
rm -rf /var/lib/rancher/k3s
rm -rf /var/lib/kubelet
rm -f /usr/local/bin/k3s
rm -f /usr/local/bin/k3s-killall.sh

if type yum >/dev/null 2>&1; then
yum remove -y k3s-selinux
rm -f /etc/yum.repos.d/rancher-k3s-common*.repo
elif type rpm-ostree >/dev/null 2>&1; then
rpm-ostree uninstall k3s-selinux
rm -f /etc/yum.repos.d/rancher-k3s-common*.repo
elif type zypper >/dev/null 2>&1; then
uninstall_cmd="zypper remove -y k3s-selinux"
if [ "${TRANSACTIONAL_UPDATE=false}" != "true" ] && [ -x /usr/sbin/transactional-update ]; then
uninstall_cmd="transactional-update --no-selfupdate -d run $uninstall_cmd"
fi
$uninstall_cmd
rm -f /etc/zypp/repos.d/rancher-k3s-common*.repo
fi

k3s-agent-uninstall.sh

这个主要是worker(agent)节点卸载使用的(其实和server的uninstall脚本差不多)

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
54
55
56
57
#!/bin/sh
set -x
[ $(id -u) -eq 0 ] || exec sudo $0 $@

/usr/local/bin/k3s-killall.sh

if command -v systemctl; then
systemctl disable k3s-agent
systemctl reset-failed k3s-agent
systemctl daemon-reload
fi
if command -v rc-update; then
rc-update delete k3s-agent default
fi

rm -f /etc/systemd/system/k3s-agent.service
rm -f /etc/systemd/system/k3s-agent.service.env

remove_uninstall() {
rm -f /usr/local/bin/k3s-agent-uninstall.sh
}
trap remove_uninstall EXIT

if (ls /etc/systemd/system/k3s*.service || ls /etc/init.d/k3s*) >/dev/null 2>&1; then
set +x; echo 'Additional k3s services installed, skipping uninstall of k3s'; set -x
exit
fi

for cmd in kubectl crictl ctr; do
if [ -L /usr/local/bin/$cmd ]; then
rm -f /usr/local/bin/$cmd
fi
done

rm -rf /etc/rancher/k3s
rm -rf /run/k3s
rm -rf /run/flannel
rm -rf /var/lib/rancher/k3s
rm -rf /var/lib/kubelet
rm -f /usr/local/bin/k3s
rm -f /usr/local/bin/k3s-killall.sh

if type yum >/dev/null 2>&1; then
yum remove -y k3s-selinux
rm -f /etc/yum.repos.d/rancher-k3s-common*.repo
elif type rpm-ostree >/dev/null 2>&1; then
rpm-ostree uninstall k3s-selinux
rm -f /etc/yum.repos.d/rancher-k3s-common*.repo
elif type zypper >/dev/null 2>&1; then
uninstall_cmd="zypper remove -y k3s-selinux"
if [ "${TRANSACTIONAL_UPDATE=false}" != "true" ] && [ -x /usr/sbin/transactional-update ]; then
uninstall_cmd="transactional-update --no-selfupdate -d run $uninstall_cmd"
fi
$uninstall_cmd
rm -f /etc/zypp/repos.d/rancher-k3s-common*.repo
fi

使用

命令使用

k3s命令本身不止集成了apiserver、kubelet、containerd等k8s服务端服务,其命令本身也集成了k8s和containerd的客户端程序。使用 k3s –help可以看到命令帮助详情

image-20230614133147633

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
例如使用kubectl查看pod,这里只需要在k3s命令后面跟上kubectl,至于kubectl后面的参数和kubectl本身是一样的。当然这里下载ctr客户端工具和kubectl工具一样可以使用,但需要注意的是kubectl默认读取的apiserver认证文件位于/root/.kube/config,而k3s默认的认证文件是/etc/rancher/k3s/k3s.yaml,如果需要使用kubelet原生客户端工具需要将配置文件复制过去或者修改默认读取文件路径。ctr原生客户端工具需要手动指定server服务端的socket文件或更改默认读取的socket文件位置,k3s运行时内置的containerd服务端的socket文件位于/run/k3s/containerd/containerd.sock。
[root@node1 ~]# k3s kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-b96499967-vgcm6 1/1 Running 0 2m28s
helm-install-traefik-crd-62dmt 0/1 Completed 0 2m28s
helm-install-traefik-xb8sk 0/1 Completed 1 2m28s
local-path-provisioner-7b7dc8d6f5-5r6qc 1/1 Running 0 2m28s
metrics-server-668d979685-8969f 1/1 Running 0 2m28s
svclb-traefik-f4b5dc41-2d4jx 2/2 Running 0 96s
traefik-7cd4fcff68-ml55r 1/1 Running 0 96s
使用ctr命令查看运行的容器信息
[root@node1 ~]# k3s ctr c ls
CONTAINER IMAGE RUNTIME
4032e0fa228b5bb0031946cbfa050099c6acbef40c52fb79e84689617ffa42ce docker.io/rancher/mirrored-pause:3.6 io.containerd.runc.v2
582b9b8554ba365bde9229cff77cdad3f2a75f16c37a8c8ff2b9598ca7467f7f docker.io/rancher/mirrored-pause:3.6 io.containerd.runc.v2
608dac86aa7630377f55e00345c931efad2b0420521902a23a1c3ed0f7663563 docker.io/rancher/klipper-lb:v0.3.5 io.containerd.runc.v2
93de38ac34d4ffd90658a118ca5f22fbdf46e489fd0b08b7f4887e261e07c24e docker.io/rancher/klipper-lb:v0.3.5
客户端操作本身和k8s无异,这里不再赘述。

私有仓库配置

默认情况下containerd以及docker的客户端工具在拉取仓库时都需要证书认证,所以k3s在这里也需要证书认证,这里讲解如何通过配置实现拉取私有仓库的方法。

K3s 启动时会检查 /etc/rancher/k3s/ 中是否存在 registries.yaml 文件,如果该文件存在则会根据该文件内容生成containerd配置文件,最终生成到/var/lib/rancher/k3s/agent/etc/containerd/config.toml,然后k3s启动时会启动containerd,而containerd会读取该配置文件。

需注意的点:

1
2
1.这里需要注意的是/var/lib/rancher/k3s/agent/etc/containerd/config.toml是自动生成的,直接改这里是没有用,每次K3S会自动覆盖其配置,所以需要更改k3s配置文件中的registrys.yaml。
2.在初始化 k3s 的时候,不能使用 --private-registry 参数,使用这个参数,就不会使用 /etc/rancher/k3s/registries.yaml 文件生成新的 contained 配置文件 /var/lib/rancher/k3s/agent/etc/containerd/config.toml

/etc/rancher/k3s/registries.yaml:

1
2
3
4
5
6
7
8
9
10
mirrors:
docker-registry.finsiot.com:
endpoint:
- "http://docker-registry.finsiot.com"
configs:
"docker-registry.finsiot.com":
auth:
username: manager # this is the registry username
password: finsiot.com # this is the registry password

这里的docker-registry.finsiot.com是仓库服务器端地址,修改了配置文件重启k3s即可。

踩坑

K3S问题记录之集群内部dns解析不通

某一个节点出现偶发性的dns不通情况

集群解析原理

一般访问的时候都是通过service作为入口来访问pod,不会直接访问pod,因为pod的ip并非固定。但svc到pod本质是域名解析映射,通过svc上解析的pod的ip来找到具体的pod,而用于实现这一块功能的组件,也就是K8S的core-dns。

具体问题

节点出现解析不通的情况,用ping命令或者直接连接都会出现Name or service not known的报错,但并非一直是这样,更具体的表现为:一会儿可以解析到,一会儿又无法解析到的情况。

image-20230404105235201

问题排查

首先想到的应该是core-dns出了问题,但由于有时是可以解析到的(这里也有可能是一直无法解析到,总之解析是存在问题的),并且其他节点的解析并无这个问题,所以应该不是core-dns本身存在问题,和节点本身有关系。(单节点故障)

由于本身集群没问题,只是节点故障并且K3S的社区以及技术支持很差,无法定位到具体的问题,更无法从网上找到有关的问题讨论,这里只能移除掉故障节点,并重装故障的节点的K3S,重新加入集群以解决这个问题。

1
curl -sfL  https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh| INSTALL_K3S_VERSION=v1.24.4+k3s1 INSTALL_K3S_MIRROR=cn sh -s - server

封装的组件

k3s默认封装了很多组件,如 corednstraefiklocal-storagemetrics-serverservicelb

例如local-storage会使用本机的存储作为sc,并且是默认storageclass,即使去掉其默认sc标签,当有k3s主节点重启时依然会设置成默认。解决办法只能在所有主节点k3s启动时配置禁用。

造成这种的原因是k3s默认将其封装在了自身服务中,并且每次重启主节点都会将所有封装组件重装以此保证组件服务完整性。但有一个缺点,例如这里使用的treafik作为ingress入口,那么每当有一个主节点重启时会自动重装traefik,虽然重装的速度很快,但依然会造成不稳定以及服务波动。

可以在k3s启动选项中使用--disable参数跟上对应服务来禁用该服务,例如禁用traefik: k3s server –disable traefik

无法加入节点,报错:connection reset by peer

详细报错如下

image-20230614144434776

解决办法:关闭所有node的firewalld

k3s master节点每次重启系统组件都会重新安装的问题

k3s主节点默认封装了很多组件,除了类如kube-proxy、apiserver等kubernetes系统组件以外,还内置了很多第三方的组件,官方并没有列出自己的所有组件信息,我这边目前发现有如下组件:coredns, servicelb, traefik, local-storage, metrics-server。

问题暴露

具体问题为每次重启任何一个K3S主节点的时候,其所有部署的组件都会重新部署,导致所有依赖这些组件的其他K3S中的服务无法正常使用。例如traefik是ingress服务,每次重启主节点都会造成域名一定时间内无法访问的故障。

问题原因

造成该问题的主要原因是K3S的主节点默认封装了这些组件,在每次启动(重启)K3S服务的时候,会以yaml形式的方式将这些组件统一自动部署,但这里有问题的地方在于K3S会将其重新部署(即使集群里面已经有该组件并且正常运行),所以就会出现上面的问题。

这个问题尤其是在部署了多个主节点的集群暴露更为明显,当集群内任意一个主节点因出现问题或其他原有而重启时,K3S的该节点就会将这些组件重新部署一遍,在部署期间这些组件都是无法使用的,以至于依赖于这些组件的服务将无法正常使用,这样的话原本多主节点实现的高可用也就没了意义,反而影响系统稳定性。 这里需要注意如果有节点与集群内其他节点版本不一致还会导致组件部署有故障(无法正常部署)。

这里翻阅了官方文档(https://docs.k3s.io/zh/installation/packaged-components),根据官方文档中管理封装组件的描述,这些组件为自动部署清单(addon)组件,其部署yaml文件位于/var/lib/rancher/k3s/server/manifests目录下。清单内的所有addon组件在每次主节点启动的时候会自动部署,部署于kube-system名称空间。

image-20230724145441534

官方文档中禁用部署这些组件的方式有两种:

1.使用–disable标志

2.使用.skip文件

第一种方法:

在k3s服务启动的时候跟上–disable value的参数来禁用该组件的自动部署,例如这里要禁用所有组件,K3S的命令如下:

1
2
3
/usr/local/bin/k3s \
server \
--disable servicelb --disable coredns --disable servicelb --disable traefik --disable local-storage --disable metrics-server

对于第一种方法,disable后在启动或重启k3s服务时,不仅不会部署该服务,甚至会删除原有已经部署的服务,将会彻底禁用,所以这里不太适合作为该问题的解决方式。这种方式是完全禁用卸载组件。

第二种方法:

/var/lib/rancher/k3s/server/manifests 下的所有yaml文件,可以创建一个对应的 .skip 文件,然后 K3s 会忽略相应的清单。.skip 文件的内容不重要,因为只会检查文件是否存在。例如里面要忽略traefik的部署,在manifests下面有一个traefik.yaml的文件,这里如果创建一个traefik.yaml.skip文件,则k3s启动时会忽略traefik的部署。

对于第二种方法,如果在创建 AddOn 之后再创建 .skip 文件(也就是如果集群中已经部署了这些组件),则不会删除或修改 AddOn 以及 AddOn 创建的资源,只会认为该文件不存在。这种方式是忽略部署组件。

解决方法

所以这里可以通过第二种方法来解决这个问题。这里在集群里面有多个主节点并且已经部署了这些组件的情况下,可以在所有主节点的

/var/lib/rancher/k3s/server/manifests下面将所有组件部署文件的yaml创建对应的.skip文件,以此解决主节点因重启的时候重复自动部署组件而导致的系统不稳定的问题。

由于/var/lib/rancher/k3s/server/manifests组价部署文件还挺多,为了避免手动一个一个创建.skip文件,我这边已经准备好了脚本,直接在每个节点运行该就可以自动创建所有组件的.skip文件。

k3s-disable.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash

# 切换到目标目录
manifests='/var/lib/rancher/k3s/server/manifests'

# 查找所有的YAML文件并为每个文件创建一个同名的.skip文件
for file in `ls ${manifests}`; do
if echo "${file}" | grep -q -E '\.yaml$'
then
touch ${manifests}/${file}.skip
elif [ -d "${manifests}/${file}" ]
then
second_directory=`ls ${manifests}/${file}`
for second_file in ${second_directory}
do
touch ${manifests}/${file}/${second_file}.skip
done
fi
done

echo "已为每个YAML文件创建相应的.skip文件。"

备注

1.请确保集群内本身已经部署了这些组件再执行以上操作,否则集群内是不会自动部署这些组件,尤其是组件里面如coredns这种服务如果不部署会造成集群本身有使用问题。当然这里先配置k3s忽略部署组件然后手动在/var/lib/rancher/k3s/server/manifests中通过这些组件的yaml部署文件手动部署维护这些组件也是可以的。

2.由于k3s自身历史原因servicelb LoadBalancer controller 是没有清单文件,目前要禁用的话只能采用–disable servicelb的方式来禁用。

3.通过某一个节点中启动时使用–disable禁用并卸载掉的组件以后其他主节点在启动时又部署了该组件的话,此时这个节点由于设置了–disable,按道理来说重启时会卸载掉该组件,但实际上不会,它只会卸载一次,之后再通过任何节点部署启动了该组件这个节点都不会再进行卸载禁用,即使已经在启动命令中配置了 –disable。所以这里最好保证所有主节点启动参数的组件配置一致性,以免出现这种奇怪的情况。