k3s 安装部署

随着Kubernetes技术的发展,越来越多的开发者和运维人员开始接触和使用Kubernetes。但对于资源受限的环境,传统的Kubernetes部署显得过于复杂和资源密集。K3s,作为一个轻量级的Kubernetes发行版,为这些场景提供了完美的解决方案。本教程将带领K3s新手一步步搭建自己的Kubernetes集群。

K3s是Rancher Labs开发的轻量级Kubernetes发行版,专为边缘计算、IoT和小型部署环境设计。它通过减少资源消耗和简化安装流程,使得在单机或少数几台机器上快速部署Kubernetes成为可能。

一、k3s 与 Docker 的核心区别

Docker 与 k3s 的定位不同,前者聚焦“单节点容器运行”,后者聚焦“多节点容器集群管理”,核心差异可概括为:

  • Docker:像「单个快递员」,仅负责在单台机器上打包、运行容器(如 Nginx、MySQL 容器),无法跨机器管理。
  • k3s:像「快递公司调度系统」,可管理多台机器(节点) 上的容器,负责任务分配、故障重启、高可用保障,让多容器协同工作并保持稳定。

二、k3s 关键概念(对比 Docker)

k3s 基于 Kubernetes 精简而来,核心概念围绕“集群管理”设计,与 Docker 的单节点逻辑差异显著:

1. 容器(Container)

  • Docker 中:容器是独立运行的应用打包单元,通过 docker run nginx 直接启动,是 Docker 的核心操作对象。
  • k3s 中:容器仍是应用运行载体,但不允许直接管理,必须封装到“Pod”中才能部署(类比:Docker 直接指挥“快递员”,k3s 先把“快递员”编为“小组”再指挥)。

2. Pod

  • k3s 核心概念:k3s 最小部署单元,可包含 1 个或多个“关系紧密”的容器(如“应用容器 + 日志收集容器”)。
    同一 Pod 内的容器共享网络和存储(类比:小组共用一张办公桌和电话)。
  • 对比 Docker:Docker 直接运行单个容器(docker run),k3s 必须通过 Pod 部署容器,示例:
    • Docker 启动 Nginx:docker run nginx
    • k3s 启动 Nginx:先定义 Pod 配置文件(如 pod.yaml),再执行 k3s kubectl apply -f pod.yaml

3. Node(节点)

  • k3s 核心概念:运行容器的“物理机/虚拟机”,k3s 集群由两类节点组成:
    • Server 节点:集群“大脑”,负责管理集群(调度 Pod、监控状态、存储配置)。
    • Agent 节点:集群“工人”,负责实际运行 Pod 中的容器。
  • 对比 Docker:Docker 仅能在“单台机器”运行容器(该机器相当于“孤立节点”),k3s 可将多台机器组成集群统一管理。

4. Deployment(部署)

  • k3s 核心概念:Pod 的“自动化管理工具”,确保 Pod 按预期运行,核心能力包括:
    1. 维持指定数量的 Pod 副本(如“始终运行 3 个 Nginx Pod”)。
    2. 一键更新容器版本(如将 Nginx 从 1.21 升级到 1.25)。
    3. 故障自动回滚(升级失败时恢复到上一稳定版本)。
  • 对比 Docker:Docker 需手动执行 docker run 多次创建多副本,容器挂了需手动重启;k3s 可通过 Deployment 全自动管理。

5. Service(服务)

  • k3s 核心概念:Pod 的“稳定访问入口”。
    因 Pod 可能重启(IP 变化)或被调度到其他节点(IP 变化),直接访问 Pod IP 不稳定。Service 类似“固定前台电话”,无论 Pod 如何变动,都能通过 Service 找到目标 Pod。
  • 对比 Docker:Docker 通过 docker run -p 8080:80 nginx 映射端口,容器重启后需重新配置;k3s Service 自动跟踪 Pod 变化,访问入口始终可用。

6. Namespace(命名空间)

  • k3s 核心概念:集群内的“资源隔离工具”,可将集群划分为多个“虚拟子集群”,示例:
    • dev 命名空间:存放开发环境的 Pod/Service。
    • prod 命名空间:存放生产环境的 Pod/Service。
      不同命名空间的资源互不干扰,便于权限管理和环境隔离。
  • 对比 Docker:Docker 无类似功能,所有容器共享单节点资源,需手动通过网络/存储隔离(操作复杂)。

7. k3s 服务管理(systemctl 命令)

  • k3s 中:k3s 以系统服务形式运行,Server/Agent 节点的服务名不同:
    • Server 节点:服务名 k3s(如 systemctl start k3s)。
    • Agent 节点:服务名 k3s-agent(如 systemctl start k3s-agent)。
  • 对比 Docker:与 Docker 服务管理逻辑一致,Docker 服务名通常为 docker(如 systemctl start docker)。

k3s是轻量级 Kubernetes 发行版,核心差异在于为边缘计算、小集群场景做了极致简化,而k8s是完整版,面向企业级大规模生产环境。

8. 目标场景与定位

两者的设计初衷完全不同,这是所有差异的根源。

  • k3s:聚焦轻量化场景,如边缘计算设备(路由器、物联网设备)、单机/小集群(3-5节点)、开发测试环境、CI/CD流水线。
  • k8s(标准Kubernetes):面向企业级生产环境,用于大规模集群(数十到数千节点)、复杂业务部署(微服务、高并发应用),追求功能全面性和稳定性。

9. 架构与组件简化

k3s通过合并、替换组件大幅降低复杂度,k8s则组件独立且完整。

对比维度 k3s k8s(标准版)
核心组件合并 控制平面组件(API Server、Controller Manager等)打包成单个二进制文件,减少进程数量 控制平面组件独立部署(多进程),需单独维护
默认存储 用轻量级的SQLite作为默认存储,无需额外部署etcd 依赖etcd(需单独部署,需3/5节点保证高可用)
附加工具整合 内置容器网络(Flannel)、Ingress(Traefik)、CSI存储,开箱即用 需手动部署或集成第三方网络、Ingress、存储插件
节点通信 支持通过“server-agent”模式简化节点注册,无需手动配置证书 需手动配置节点与控制平面的证书、网络通信

10. 资源占用与部署难度

k3s对硬件要求极低,部署速度远快于k8s。

  • k3s
    1. 最低资源需求:1核CPU + 512MB内存(单机部署),适合低配置设备。
    2. 部署方式:单条命令(curl -sfL https://get.k3s.io | sh -)即可完成服务器部署,5分钟内可启动集群。
  • k8s
    1. 最低资源需求:控制平面建议2核CPU + 4GB内存,节点建议1核CPU + 2GB内存,资源占用高。
    2. 部署方式:需手动配置etcd、证书、网络等,或依赖工具(如kubeadm、kops),部署流程复杂,耗时较长。

11. 功能完整性

k3s默认移除部分不常用功能以简化,k8s功能全面无删减。

  • k3s:默认禁用或移除部分企业级功能,如PodSecurityPolicy(已废弃)、NodeRestriction、部分alpha/beta特性,需手动开启。
  • k8s:包含全部官方功能,支持alpha/beta特性(需配置)、完整的RBAC权限控制、节点亲和性/反亲和性等复杂调度策略,满足生产环境的复杂需求。

12. 选择建议

  • k3s:如果你需要在边缘设备部署、搭建小型测试集群,或追求快速部署、低资源占用。
  • k8s:如果你需要搭建企业级生产集群、运行大规模复杂业务,或依赖k8s的完整功能(如高级调度、全量权限控制)。

三、k3s 常用命令(分类整理)

k3s 兼容 Kubernetes 核心命令,同时新增自身服务管理命令,按“服务管理、安装卸载、集群操作”分类如下:

1. k3s 服务管理(Server/Agent 节点)

通过 systemctl 管理 k3s 服务生命周期,适用于启动、停止、查看状态等操作:

命令 用途 备注
sudo systemctl start k3s 启动 k3s Server 服务 仅 Server 节点使用
sudo systemctl stop k3s 停止 k3s Server 服务 仅 Server 节点使用
sudo systemctl restart k3s 重启 k3s Server 服务 仅 Server 节点使用
sudo systemctl status k3s 查看 k3s Server 运行状态 可查看是否正常启动、报错信息
sudo systemctl enable k3s 设置 k3s Server 开机自启 避免重启机器后手动启动
sudo systemctl disable k3s 关闭 k3s Server 开机自启 仅需临时使用时配置
sudo systemctl start k3s-agent 启动 k3s Agent 服务 仅 Agent 节点使用,替换 k3s 为 k3s-agent 即可

2. k3s 安装与卸载

推荐安装K3S Server和节点之前执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mkdir -p /etc/rancher/k3s/
cat >> /etc/rancher/k3s/registries.yaml << EOF
mirrors:
docker.io:
endpoint:
- "https://docker.m.daocloud.io"

gcr.io:
endpoint:
- "https://gcr.m.daocloud.io"

quay.io:
endpoint:
- "https://quay.m.daocloud.io"

registry.k8s.io:
endpoint:
- "https://k8s.m.daocloud.io"
EOF

(1)安装命令

  • Server 节点(初始化集群)
    基础安装(默认配置):

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

    自定义配置(如禁用 Traefik、指定数据目录):

    1
    2
    3
    4
    curl -sfL https://get.k3s.io | sh -s - \
    --disable=traefik \ # 禁用内置的Traefik ingress控制器
    --data-dir /var/lib/my-k3s \ # 指定k3s数据存储目录
    --docker
  • Agent 节点(加入集群)
    需先获取 Server 节点的 K3S_URL(API 地址)和 K3S_TOKEN(集群令牌):

    1
    2
    3
    4
    5
    6
    7
    # 1. 在Server节点获取令牌:cat /var/lib/rancher/k3s/server/node-token
    # 2. 替换<server-ip>和<token>后执行:
    curl -sfL https://get.k3s.io | \
    K3S_URL=https://<server-ip>:6443 \
    K3S_TOKEN=<token> \
    sh -s - \
    --docker

    返回示例

    1
    2
    root@ubuntu:~# cat /var/lib/rancher/k3s/server/node-token
    K102a28c38a37cc242058eaa774d061968b4c59416e3c5e418402bef590e78e568a::server:144b7cb8304c99d03d246b56c3a6ea52

(2)卸载命令

  • Server 节点

    1
    /usr/local/bin/k3s-uninstall.sh
  • Agent 节点

    1
    /usr/local/bin/k3s-agent-uninstall.sh

3. 集群与资源操作(兼容 kubectl)

k3s 内置 kubectl 工具,可通过 k3s kubectl 操作集群(配置环境变量后可简化为 kubectl),核心命令如下:

(1)集群基础信息

命令 用途
k3s kubectl cluster-info 查看集群基本信息(API 地址、核心组件状态)
k3s kubectl get nodes 查看集群节点列表(状态、角色、版本)
k3s kubectl get nodes -o wide 查看节点详细信息(IP、容器运行时、内核版本)
k3s kubectl describe node <节点名> 查看单个节点详情(资源使用、标签、污点)

(2)Pod 操作

命令 用途
k3s kubectl get pods 查看当前命名空间的 Pod 列表(默认 default 命名空间)
k3s kubectl get pods -n <命名空间> 查看指定命名空间的 Pod(如 -n kube-system 查看系统组件)
k3s kubectl get pods --all-namespaces 查看所有命名空间的 Pod
k3s kubectl describe pod <Pod名> 查看单个 Pod 详情(事件、容器配置、挂载存储)
k3s kubectl logs <Pod名> 查看 Pod 日志(默认查看第一个容器)
k3s kubectl logs <Pod名> -f 实时跟踪 Pod 日志(类似 tail -f)
k3s kubectl delete pod <Pod名> 删除指定 Pod(Deployment 管理的 Pod 会自动重建)

(3)Service 操作

命令 用途
k3s kubectl get svc 查看当前命名空间的 Service 列表
k3s kubectl get svc -n <命名空间> 查看指定命名空间的 Service
k3s kubectl describe svc <Service名> 查看 Service 详情(端口映射、后端 Pod 列表)
k3s kubectl expose deployment <部署名> --type=NodePort --port=80 --target-port=80 --name=<Service名> 从 Deployment 创建 NodePort 类型的 Service(暴露端口供外部访问)

(4)Deployment 操作

命令 用途
k3s kubectl get deploy 查看当前命名空间的 Deployment 列表
k3s kubectl get deploy -n <命名空间> 查看指定命名空间的 Deployment
k3s kubectl apply -f <YAML文件> 通过 YAML 文件创建/更新 Deployment(如 nginx-deployment.yaml)
k3s kubectl delete -f <YAML文件> 通过 YAML 文件删除 Deployment
k3s kubectl scale deploy <部署名> --replicas=<数量> 调整 Deployment 的 Pod 副本数(如 --replicas=3 扩容到 3 个副本)

(5)其他常用操作

命令 用途
k3s kubectl get ns 查看所有命名空间
k3s kubectl create ns <命名空间名> 创建新命名空间(如 kubectl create ns dev)
k3s kubectl get configmaps 查看当前命名空间的 ConfigMap(存储配置信息)
k3s kubectl get secrets 查看当前命名空间的 Secret(存储敏感信息,如密码)
k3s kubectl top nodes 查看节点资源使用情况(CPU/内存使用率)
k3s kubectl top pods 查看 Pod 资源使用情况(CPU/内存使用率)

4. 配置文件相关

k3s 集群配置文件默认路径:
/etc/rancher/k3s/k3s.yaml

若需通过本地 kubectl 连接远程 k3s 集群,操作步骤:

  1. 将远程 Server 节点的 k3s.yaml 复制到本地 ~/.kube/config
  2. 修改配置文件中的 server: https://127.0.0.1:6443 为远程 Server 节点的 IP(如 https://192.168.1.100:6443)。
  3. 执行 kubectl cluster-info 验证连接。

四、k3s 实操:安装与 Nginx 测试

1. 系统要求

确保 Linux 服务器满足以下基础条件:

  • 硬件:至少 1GB 内存、1 个 CPU 核心(生产环境建议 2GB+ 内存、2 核+ CPU)。
  • 架构:支持 x86_64、ARMv7 或 ARM64(如树莓派 4B 可安装 ARM64 版本)。
  • 环境:未占用容器运行时(k3s 内置轻量级运行时,无需提前安装 Docker,若需用 Docker 需额外配置)。

2. 安装 k3s(国内加速)

使用国内镜像源安装,避免网络问题,同时指定 Docker 为容器运行时(可选):

1
2
3
4
5
6
#Server 节点
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
INSTALL_K3S_MIRROR=cn \
K3S_NODE_NAME=server \
sh -s - \
--docker --disable=traefik --service-node-port-range=1-65535
1
2
3
4
5
6
7
8
#Agent 节点
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
INSTALL_K3S_MIRROR=cn \
K3S_NODE_NAME=k3node \
K3S_URL=https://192.168.31.222:6443 \
K3S_TOKEN=K109b98888ba53e53a72b5dc0df4ab87d396e3765bea9cbbd5ebdb22d8a8a8871a2::server:d4bc60b93cf4c86c0b6fe77cdea85d5e \
sh -s - \
--docker

3. 验证安装

查看 k3s 核心组件状态(所有组件状态为 Running 即安装成功):

1
2
3
4
5
6
# kubectl get pods -n kube-system
root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-64fd4b4794-rjgzb 1/1 Running 0 7h17m
local-path-provisioner-774c6665dc-f7s9x 1/1 Running 0 7h17m
metrics-server-7bfffcd44-5qjr2 1/1 Running 0 7h17m

4. 配置 kubectl(可选,简化命令)

默认需通过 k3s kubectl 执行命令,配置后可直接用 kubectl

1
2
3
4
5
6
# 1. 创建kubectl配置目录
mkdir -p $HOME/.kube
# 2. 复制k3s配置文件到用户目录
sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
# 3. 赋予文件读写权限(避免权限报错)
sudo chown $(id -u):$(id -g) $HOME/.kube/config

5. 部署 Nginx 测试

通过 Deployment 部署 Nginx,并暴露端口供外部访问。

5.1 创建 Deployment 配置文件

5.1.1 常见的资源类型
资源名称(Resource) 核心用途 关键特点 典型场景
StatefulSet 部署有状态应用 1. Pod有固定名称和网络标识(DNS),重建后不变; 2. 支持稳定持久化存储(每个Pod对应独立存储卷); 3. 按顺序部署/删除Pod,保证状态一致 MySQL主从集群、ZooKeeper、Elasticsearch
DaemonSet 确保指定节点运行相同Pod 1. 所有目标节点(或指定节点)必运行一个Pod; 2. 新增节点自动创建Pod,删除节点自动清理Pod 日志收集(Fluentd、Logstash)、监控代理(Prometheus Node Exporter)、网络插件(Calico、Flannel节点代理)
Job 运行一次性任务 1. 任务完成后Pod自动终止,状态变为Completed; 2. 支持配置失败重试次数 数据备份、批量计算
CronJob 定时执行周期性任务 1. 基于Job扩展,支持类似Linux cron的时间规则; 2. 按预设时间重复执行任务 定时数据备份、日志清理、周期性报表生成
ReplicaSet 维护指定数量的Pod副本 1. 确保集群中始终有N个Pod运行; 2. 是Deployment的底层依赖,通常不直接使用 配合Deployment管理无状态应用副本(不单独使用)
Pod 容器的基础封装单位 1. K8s最小资源单位,可包含多个容器; 2. 直接创建的Pod重启后可能换节点,IP会变化 临时测试场景(不推荐用于正式业务,需通过工作负载间接管理)
ReplicationController 早期管理Pod副本的资源 1. 功能类似ReplicaSet,用于维护Pod副本数量; 2. 现已被ReplicaSet替代,功能更弱 legacy旧集群兼容场景(建议优先用ReplicaSet或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  # API版本(Deployment属于apps组v1版本)
kind: Deployment # 资源类型:Deployment
metadata:
name: nginx # Deployment名称
spec:
replicas: 2 # 运行2个Pod副本(高可用)
selector:
matchLabels: # 选择器:匹配标签为「app: nginx」的Pod
app: nginx
template:
metadata:
labels: # Pod标签:与selector.matchLabels对应
app: nginx
spec:
containers: # 容器配置
- name: nginx # 容器名称
image: nginx:latest # 容器镜像(使用最新版Nginx)
ports:
- containerPort: 80 # 容器内部端口(Nginx默认端口)

5.2 部署 Nginx

执行配置文件创建 Deployment:

1
kubectl apply -f nginx-deployment.yaml
1
2
3
root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get deployment nginx
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 76m

5.3 暴露 Nginx 服务(NodePort 类型)

通过 Service 暴露 Nginx 端口,让外部可访问:

1
2
3
4
5
kubectl expose deployment nginx \
--type=NodePort \ # 服务类型:NodePort(通过节点IP+端口访问)
--port=80 \ # Service端口
--target-port=80 \ # 映射到容器的端口(与containerPort一致)
--name=nginx-service # Service名称

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
cat > nginx-service.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF
1
kubectl apply -f nginx-service.yml

5.4 查看 Pod 与 Service 状态

  • 查看 Nginx Pod 状态(确保 STATUS 为 Running):

    1
    kubectl get pods -l app=nginx  # -l 按标签筛选Pod
    1
    2
    3
    4
    root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get pods -l app=nginx 
    NAME READY STATUS RESTARTS AGE
    nginx-96b9d695-lk5pj 1/1 Running 0 34m
    nginx-96b9d695-zn48c 1/1 Running 0 34m
  • 查看 Service 暴露的端口(重点看 PORT(S) 列的“节点端口”,如 80:30567/TCP 中的 30567):

    1
    2
    3
    4
    5
    # kubectl get svc nginx-service

    root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get svc nginx-service
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    nginx-service ClusterIP 10.43.135.39 <none> 80/TCP 76m

5.5 访问 Nginx 测试

在浏览器中输入 http://<节点IP>:<节点端口>(如 http://192.168.31.222:30112),看到 Nginx 欢迎页即成功。

6. 部署 MySQL 8.0 测试

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
apiVersion: apps/v1
kind: StatefulSet # MySQL为有状态应用,用StatefulSet部署
metadata:
name: mysql
spec:
serviceName: mysql # 关联的Service名称
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0.28-debian
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "202019"
- name: MYSQL_DATABASE
value: "k3s" # 初始数据库名
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
args:
- --default-authentication-plugin=mysql_native_password # 兼容旧客户端
- --bind-address=0.0.0.0 # 允许所有IP连接
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
nodePort: 30306
type: NodePort
1
kubectl apply -f mysql.yaml

6.1 查看 Pod 状态

1
2
3
4
5
#kubectl get pods -l app=mysql

root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get pods -l app=mysql
NAME READY STATUS RESTARTS AGE
mysql-0 1/1 Running 0 6m51s

6.2 查看服务状态

1
2
3
4
5
#kubectl get svc mysql

root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get svc mysql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mysql NodePort 10.43.212.180 <none> 3306:30306/TCP 9m52s

连接数据库

1
192.168.31.141:30306  root  202019

7.0 部署集群

服务器 IP 角色
Ubuntu 22.0.4 192.168.31.141 Controller
Ubuntu 22.0.4 192.168.31.142 Worker

在此之前确保我们的主机名不同,或是重命名服务器

1
2
3
4
vim /etc/hosts

===添加以下内容===
127.0.0.1 ubuntu-agent

查看主节点token,我们需要凭借token加入集群

1
2
3
4
#sudo cat /var/lib/rancher/k3s/server/node-token

root@wyy-VMware-Virtual-Platform:~/k3s# cat /var/lib/rancher/k3s/server/node-token
K109b98888ba53e53a72b5dc0df4ab87d396e3765bea9cbbd5ebdb22d8a8a8871a2::server:d4bc60b93cf4c86c0b6fe77cdea85d5e

计算节点执行

1
2
3
4
5
6
7
8
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
INSTALL_K3S_MIRROR=cn \
INSTALL_K3S_VERSION=v1.33.5+k3s1 \
K3S_URL=https://192.168.87.163:6443 \ K3S_TOKEN=K102a28c38a37cc242058eaa774d061968b4c59416e3c5e418402bef590e78e568a::server:144b7cb8304c99d03d246b56c3a6ea52 \
K3S_SKIP_TLS_SAN_VERIFY=true \
K3S_NODE_NAME=ubuntu-agent \
sh -s - \
--docker
1
2
3
4
5
6
7
8
9
10
11
12
13
root@wyy-VMware-Virtual-Platform-2:~# systemctl status k3s-agent.service
● k3s-agent.service - Lightweight Kubernetes
Loaded: loaded (/etc/systemd/system/k3s-agent.service; enabled; preset: enabled)
Active: active (running) since Fri 2025-11-14 10:18:07 CST; 1h 27min ago
Invocation: fa7f34cf814c4684b139c4d3788601fa
Docs: https://k3s.io
Main PID: 1878 (k3s-agent)
Tasks: 12
Memory: 224.1M (peak: 229.1M)
CPU: 1min 10.734s
CGroup: /system.slice/k3s-agent.service
└─1878 "/usr/local/bin/k3s agent"

主节点视角

1
2
3
4
root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k3node Ready <none> 86m v1.33.5+k3s1
server Ready control-plane,master 7h26m v1.33.5+k3s1

五、ingress安装及测试

1.安装ingress-nginx

https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.14.0/deploy/static/provider/baremetal/deploy.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
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resourceNames:
- ingress-nginx-leader
resources:
- leases
verbs:
- get
- update
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: v1
data: null
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-controller
namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
spec:
automountServiceAccountToken: true
containers:
- args:
- /nginx-ingress-controller
- --election-id=ingress-nginx-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.k8s.io/ingress-nginx/controller:v1.14.0@sha256:e4127065d0317bd11dc64c4dd38dcf7fb1c3d72e468110b4086e636dbaac943d
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
readOnlyRootFilesystem: false
runAsGroup: 82
runAsNonRoot: true
runAsUser: 101
seccompProfile:
type: RuntimeDefault
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission-create
spec:
automountServiceAccountToken: true
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.4@sha256:bcfc926ed57831edf102d62c5c0e259572591df4796ef1420b87f9cf6092497f
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 65532
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
serviceAccountName: ingress-nginx-admission
ttlSecondsAfterFinished: 0
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission-patch
spec:
automountServiceAccountToken: true
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.4@sha256:bcfc926ed57831edf102d62c5c0e259572591df4796ef1420b87f9cf6092497f
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 65532
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
serviceAccountName: ingress-nginx-admission
ttlSecondsAfterFinished: 0
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: nginx
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.14.0
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: ingress-nginx
path: /networking/v1/ingresses
port: 443
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None

安装ingress-nginx

1
2
3
4
5
kubectl apply -f deploy.yaml

root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-7c658dcdb7-2tvrn 1/1 Running 0 51m

2.创建ingress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat > ingress.yml <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
spec:
ingressClassName: nginx
rules:
- host: traefik.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx-service # 前面nginx部署的service名称
port:
number: 80
EOF

1
2
3
4
5
kubectl apply -f ingress.yml

root@wyy-VMware-Virtual-Platform:~/k3s# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress nginx traefik.com 192.168.31.141 80 92m

service: ingress-nginx-controller 修改端口为

1
2
http: 80 → 80/http → http/TCP
https: 443 → 443/https → https/TCP

把上述ADDRESS部分的IP和域名绑定解析

1
echo 192.168.31.141 traefik.com >> /etc/hosts

六、问题解决

安装agent是出现以下问题

1
2
3
4
journalctl -u k3s-agent -f


11月 14 02:48:13 wyy-VMware-Virtual-Platform-2 k3s[8319]: time="2025-11-14T02:48:13+08:00" level=info msg="Waiting to retrieve agent configuration; server is not ready: /var/lib/rancher/k3s/agent/serving-kubelet.crt: Node password rejected, duplicate hostname or contents of '/etc/rancher/node/password' may not match server node-passwd entry, try enabling a unique node name with the --with-node-id flag"

Agent node对应的passwd和server中存储的hostname对应的passwd不一致

1
2
3
4
5
6
7
8
9
10
# agent
$ cat /etc/rancher/node/password
47211f28f469622cccf893071dbda698
$ hostname
xxxxxxx

# server
cat /var/lib/rancher/k3s/server/cred/passwd
31567be88e5408a31cbd036fc9b37975,ip-172-31-13-54,ip-172-31-13-54,
cf3f4f37042c05c631e07b0c0abc528f,xxxxx,xxxxxx,