Skip to content

k3s 安装笔记

约 1705 字大约 6 分钟

计算机技术云原生

2025-04-17

k3s 是轻量级单节点集群,当然也可以加入多节点。

集群引导

单master节点

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

# 中国区加速
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -

运行完就安装完成了,需要保证 6443 和 443 端口可用。

安装完,集群默认配置文件在/etc/rancher/k3s/k3s.yaml​,如果不想sudo使用的话,可以移动配置文件:

mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER:$USER ~/.kube/config

设置环境变量export KUBECONFIG=~/.kube/config

  • 加入agent节点

查看/var/lib/rancher/k3s/server/node-token​得到token,加入

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn INSTALL_K3S_EXEC='agent --node-ip=10.0.0.14 --node-name=p4' K3S_URL='master url' K3S_TOKEN='token' sh -

# 建议指定--node-ip和-node-name,多网卡下自动获取的node-ip可能不对,而node-name一般不太标准

多主节点

上面的初始化是单master节点的,因为使用的是sqlite,如果要使用多节点,需要在第一台机器上加入--cluster-init​,即:

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn INSTALL_K3S_EXEC='server --node-ip=10.0.0.21 --node-name=h1 --flannel-backend=none --disable-network-policy --disable=traefik --cluster-init' sh -

# --flannel-backend=none --disable-network-policy --disable=traefik
# 是禁用自带的CNI和网络配置,为后面的cilium做准备

后面的server节点不需要,即:

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn INSTALL_K3S_EXEC='server --node-ip=10.0.0.24 --node-name=h4 --flannel-backend=none --disable-network-policy --disable=traefik' K3S_URL='https://10.0.0.21:6443' K3S_TOKEN='token' sh -

# 除此之外的INSTALL_K3S_EXEC参数需要和第一个节点相同,否则无法同步

其他agent加入与server相同,但注意不要INSTALL_K3S_EXEC参数控制网络插件

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn INSTALL_K3S_EXEC='agent --node-ip=10.0.0.14 --node-name=p4' K3S_URL='https://10.0.0.21:6443' K3S_TOKEN='token' sh -

删除

# master
/usr/local/bin/k3s-uninstall.sh
# agent
/usr/local/bin/k3s-agent-uninstall.sh

删除后集群数据并不会完全删除,可能残留有网络插件数据,查阅文档删除即可。

集群网络

CNI cilium

由于自带的是flannel+vxlan,性能比较差,一般希望换成cilium,官方文档

由于cilium是取代了kube-proxy的,这里面还需要处理一下,安装server的时候:

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC='--flannel-backend=none --disable-network-policy' sh -

# 如果不想使用自带的LB,再加入--disable=traefik

来diable network

然后照官方文档安装cilium就可以了

 helm install cilium ./cilium --version 1.17.0 \
   --namespace cilium \
   --set hubble.relay.enabled=true \
   --set operator.replicas=1 \
   --set hubble.ui.enabled=true \
   --create-namespace

# operator.replicas=1建议只使用1

另外注意的是ip段,cilium默认使用10.0.0.0/8,如果CIDR冲突,需要更改集群IP段,用helm拉下找到CIDR即可,不然cilium修改route后会断网

集群存储

Longhorn

按照官网的安装教程来,使用helm,但是需要做一些初始化工作,每个节点都需要达到要求

# 基础工具nfs-common
sudo apt install -y nfs-common cryptsetup

# dm_crypt 模块
lsmod | grep dm_crypt
sudo modprobe dm_crypt
sudo echo "dm_crypt" | sudo tee -a /etc/modules # 加入启动列表自动加载


# 关闭multipathd
sudo systemctl stop multipathd.socket
sudo systemctl disable multipathd.socket
sudo systemctl stop multipathd.service
sudo systemctl disable multipathd.service

完毕后,安装:

helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace --version 1.8.0

longhorn自带一个UI来设置所有的values,所以我们不需要改

集群LB

Ingress Gateway

安装

helm install eg oci://docker.io/envoyproxy/gateway-helm --version v0.0.0-latest -n envoy-gateway-system --create-namespace
# 测试
kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available
kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/latest/quickstart.yaml -n default

HA Loadbalance

frontend k3s-frontend
    bind *:16443 # 这里必须是*,否则没拿到IP的backup节点启动失败
    mode tcp
    option tcplog
    default_backend k3s-backend

backend k3s-backend
    mode tcp
    option tcp-check
    balance roundrobin
    default-server inter 10s downinter 5s
    server server-1 10.0.0.21:6443 check
    server server-2 10.0.0.22:6443 check
    server server-3 10.0.0.24:6443 check

其他

集群调试

实践中关键数据库一般不会暴露到集群外,如 mysql,假设上面我们只有一个 mysql-ci-service 可用,怎么连上mysql 进行调试呢?

  1. port-forward:使用 kubectl 端口转发:可以转发到 pod 和服务,只转发端口
  2. proxy:通过 k8s api 访问集群服务,但只能访问 http 服务
  3. 使用 telepresence:推荐

port-forward

我们已知上面的service 名称为 mysql-ci-service,端口为 30002,则可以输入:

kubectl port-forward service/mysql-ci-service 3306:30002

就把本地端口转发到 service 的 30002,service 再转发到 pod 3306

如果要转发 pod(比如说可能想绕过 service 的负载均衡到达指定 pod),则需要得到 pod 名称,然后输入:

kubectl port-forward pod/mysql-6d57fdf866-f492r 3306:3306

proxy

输入 kubectl proxy 即可使用

telepresence

telepresence 可以直接拦截本地流量发送到 k8s 上,看起来就好像身处集群中。

telepresence

telepresence connect

如果想要拦截云上服务的流量,telepresence 也能做到,详细参考文档。

其他问题

集群代理问题

k3s一般安装containerd,国内拉镜像需要代理,但TUN模型会严重影响pod的dns,导致大部分服务找不到内网IP,所以需要配置拉取镜像的代理:

sudo mkdir -p /etc/systemd/system/containerd.service.d/

sudo cat > /etc/systemd/system/containerd.service.d/http-proxy.conf <<-EOF
[Service]
Environment="HTTP_PROXY=http://ip:7890"
Environment="HTTPS_PROXY=http://ip:7890"
Environment="NO_PROXY=localhost,::1,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16"
EOF

sudo systemctl daemon-reload && sudo systemctl restart containerd

docker的配置同理,这里注意要改代理IP和NO_PROXY比较好,防止代理内网

根据一篇文章阐述,k3s必须配置专用的代理,如下,注意server和agent有点不一样:

# /etc/systemd/system/k3s.service.env
# /etc/systemd/system/k3s-agent.service.env

HTTP_PROXY="http://10.0.0.23:7890"
HTTPS_PROXY="http://10.0.0.23:7890"
NO_PROXY="localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

sudo systemctl daemon-reload && sudo systemctl restart k3s
sudo systemctl daemon-reload && sudo systemctl restart k3s-agent

查阅官方文档的确是这样,但是上面的配法会影响到kubelet,导致延迟偏高,所以最好只配containerd的:

CONTAINERD_HTTP_PROXY="http://10.0.0.23:7890"
CONTAINERD_HTTPS_PROXY="http://10.0.0.23:7890"
CONTAINERD_NO_PROXY="127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

而且据文档所述,k3s的ip域自动会添加到NO_PROXY中,所以不需要加

K3s 会自动将集群内部 Pod 和 Service IP 范围以及集群 DNS 域添加到 NO_PROXY​ 条目列表中。你需要确保 Kubernetes 节点本身使用的 IP 地址范围(即节点的公共和私有 IP)包含在 NO_PROXY​ 列表中,或者可以通过代理访问节点。

本地私有仓库配置

k3s不是在containerd的配置文件中配置本地仓库,而是配置k3s,自动生成containerd的配置文件,假设10.0.0.21:5000上有一个镜像站:

# /etc/rancher/k3s/registries.yaml

sudo mkdir -p /etc/rancher/k3s
# 添加
mirrors:
  "10.0.0.21:5000":
    endpoint:
      - "http://10.0.0.21:5000"

然后重启k3s服务

命名空间无法删除的问题

查看命名空间存在的资源:

kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl -n <name-of-namespace> get

然后删除对应的资源