文章目录
-
- 一、项目背景与实践目标
- 二、部署前的环境评估
-
- [2.1 服务器配置](#2.1 服务器配置)
- [2.2 原有业务架构](#2.2 原有业务架构)
- [三、安装 K3s](#三、安装 K3s)
-
- [3.1 安装策略](#3.1 安装策略)
- [3.2 验证安装结果](#3.2 验证安装结果)
- [四、故障排查:系统 Pod 启动期间的镜像拉取问题](#四、故障排查:系统 Pod 启动期间的镜像拉取问题)
-
- [4.1 故障现象](#4.1 故障现象)
- [4.2 区分根因与后续异常](#4.2 区分根因与后续异常)
- [4.3 为什么 Docker 镜像加速配置没有自动解决问题?](#4.3 为什么 Docker 镜像加速配置没有自动解决问题?)
- [4.4 配置 K3s 镜像仓库](#4.4 配置 K3s 镜像仓库)
- [4.5 验证镜像拉取](#4.5 验证镜像拉取)
- 五、集群验收:从节点到业务服务
-
- [5.1 节点验收](#5.1 节点验收)
- [5.2 系统组件验收](#5.2 系统组件验收)
- [5.3 资源指标验收](#5.3 资源指标验收)
- [5.4 原有业务验收](#5.4 原有业务验收)
- [5.5 本次验收结论](#5.5 本次验收结论)
- 六、配置归档与运维闭环
- 七、实践总结
- [八、下一步计划:从 K3s 部署走向 Kubernetes 持续交付](#八、下一步计划:从 K3s 部署走向 Kubernetes 持续交付)
摘要: 本文记录在已有 Docker、Jenkins 和个人博客服务的 Ubuntu 云服务器上部署 K3s 的全过程,重点介绍部署前的环境评估、容器镜像拉取故障排查、containerd 镜像仓库配置,以及集群和原有业务的验收过程。通过这次实践,将 Kubernetes 的基础概念转化为可验证、可复现的运维经验。
关键词: K3s、Kubernetes、Docker、containerd、DevOps、镜像仓库、故障排查
一、项目背景与实践目标
之前,我已经在云服务器上部署了个人博客项目「逐浪笔记」,并使用 Docker 管理前后端应用和 MySQL,通过 Jenkins 实践自动化构建与部署。
现有环境已经具备基础的 CI/CD 实践能力。为了进一步学习 Kubernetes,我决定在原有服务器上增加一套轻量级 Kubernetes 实验环境。
经过评估,本次选择 K3s 作为 Kubernetes 发行版。
K3s 经过轻量化设计,适合开发测试、边缘计算及资源受限的场景。它能够提供熟悉的 Kubernetes API 和工作负载管理能力,适合个人学习 Deployment、Service、ConfigMap、持久化存储以及自动化发布等内容。
本次实践的目标并不是立即迁移原有业务,而是先在不破坏现有服务的前提下完成以下任务:
- 安装并启动单节点 K3s 集群。
- 验证节点状态与 Kubernetes 系统组件。
- 排查容器镜像拉取异常。
- 配置 K3s 使用的镜像仓库。
- 验证节点资源指标是否正常。
- 确认博客前端、后端 API 和 Jenkins 仍然可用。
二、部署前的环境评估
2.1 服务器配置
| 项目 | 配置 |
|---|---|
| 操作系统 | Ubuntu 24.04.4 LTS |
| CPU | 4 vCPU |
| 内存 | 约 8 GB |
| 磁盘 | 约 80 GB |
| K3s 版本 | v1.36.5+k3s1 |
| 集群模式 | 单节点 |
| Kubernetes 容器运行时 | containerd |
2.2 原有业务架构
部署前,服务器已经运行以下 Docker 容器:
| 容器 | 作用 | 主要端口 |
|---|---|---|
| my-blog-frontend | Vue 前端与 Nginx | 80 |
| my-blog-backend | Spring Boot 后端 | 8080(容器内部) |
| mysql | MySQL 数据库 | 127.0.0.1:3306 |
| jenkins | CI/CD 流水线 | 8080、50000 |
其中,宿主机的 80 端口和 8080 端口已经被现有业务使用。如果直接启用可能监听相同端口的 Ingress 或负载均衡组件,就可能与现有服务产生冲突。
因此,本次部署前重点检查了:
- 现有容器状态及端口映射;
- 服务器 CPU、内存与磁盘余量;
- Docker 网络地址段与 Kubernetes 网络地址段;
- 数据库和 Jenkins 的备份情况;
- K3s 新增组件对现有业务的潜在影响。
这一步体现了运维变更中的一个重要原则:先掌握现状,再评估影响,最后实施变更并验证结果。
三、安装 K3s
3.1 安装策略
本次使用已准备好的 K3s 安装脚本和二进制文件进行安装,并指定具体版本。
安装时禁用了 Traefik 和 ServiceLB:
bash
INSTALL_K3S_SKIP_DOWNLOAD=true \
INSTALL_K3S_VERSION='v1.36.5+k3s1' \
INSTALL_K3S_EXEC='server --disable=traefik --disable=servicelb' \
/opt/devops/backups/install-k3s.sh
几个关键参数的含义如下:
INSTALL_K3S_SKIP_DOWNLOAD=true:跳过安装程序中的下载步骤,依赖本地已经准备好的安装文件。INSTALL_K3S_VERSION:指定安装版本,便于环境复现。--disable=traefik:不部署默认的 Traefik Ingress Controller。--disable=servicelb:不部署默认的 ServiceLB 组件。
禁用这些组件并不意味着集群不能对外提供服务,而是将入口和负载均衡方案留到后续实践中单独设计。
需要注意,该命令依赖本地安装文件,不能直接当作适用于所有环境的通用安装命令。
3.2 验证安装结果
安装完成后,首先检查 K3s 服务和版本:
bash
sudo systemctl is-active k3s
sudo k3s --version
随后查看 Kubernetes 节点:
bash
sudo k3s kubectl get nodes -o wide
本次实际输出的关键内容如下:
text
NAME STATUS ROLES
izwz9cz3p7i9gev2gfreo6z Ready control-plane
VERSION CONTAINER-RUNTIME
v1.36.5+k3s1 containerd://2.3.4-k3s1.36
节点成功进入 Ready 状态,说明节点已经注册到集群,且满足 Kubernetes 对节点可用性的基本判断。
从运行时信息可以确认,本次 K3s 使用的是其内置的 containerd,而不是直接复用 Docker 的容器运行时。
四、故障排查:系统 Pod 启动期间的镜像拉取问题
4.1 故障现象
安装初期,K3s 的部分系统 Pod 无法顺利启动。
进一步排查发现,容器运行时在拉取以下镜像时出现超时:
text
rancher/mirrored-pause:3.10.2
Kubernetes 创建 Pod 时,容器运行时需要先准备 Pod 沙箱环境。相关基础镜像无法获取时,即使 K3s 服务本身已经启动,Pod 也可能无法正常创建。
这说明,服务启动成功不等于集群已经具备完整的运行能力。
4.2 区分根因与后续异常
排查时,我将问题拆分为两个层面:
- K3s 服务和节点是否正常。
- containerd 是否能够访问镜像仓库并获取所需镜像。
针对镜像仓库,我检查了 HTTPS 连通性、Registry 返回的 HTTP 状态码、认证响应以及实际镜像拉取结果。
需要注意,HTTP 401 不一定代表镜像仓库故障。对于需要认证的 Registry,401 可能是正常的认证挑战,应结合响应头和后续认证请求判断。
排查过程中也出现过与 Pod 网络和组件就绪状态有关的后续异常。对此不能只根据某一条日志就认定网络配置损坏,而应优先检查最早发生的错误,并验证依赖条件是否满足。
4.3 为什么 Docker 镜像加速配置没有自动解决问题?
这是本次实践中一个值得记录的知识点。
Docker 与 K3s 内置的 containerd 是两套独立的容器运行环境:
- Docker 使用自己的守护进程和镜像配置。
- K3s 使用内置的 containerd 管理 Kubernetes Pod。
- 两者的镜像缓存和镜像仓库配置不会自动共享。
因此,即使 Docker 已配置镜像加速,K3s 仍可能因为无法访问上游仓库而拉取失败。
排查问题时,需要确认究竟是哪一个容器运行时在执行镜像拉取。
4.4 配置 K3s 镜像仓库
K3s 支持通过以下配置文件设置镜像仓库:
text
/etc/rancher/k3s/registries.yaml
本次使用的配置为:
yaml
mirrors:
docker.io:
endpoint:
- "https://docker.m.daocloud.io"
该配置为 docker.io 提供一个镜像仓库端点。
配置完成后,重启 K3s 服务:
bash
sudo systemctl restart k3s
重启后,需要重新检查节点状态和系统 Pod,确认配置生效且相关组件恢复正常。
镜像代理属于外部依赖,其可用性可能受网络、上游仓库和服务策略影响。复现时应检查当前代理的可访问性与使用要求,不应假设该地址长期稳定。
4.5 验证镜像拉取
使用 K3s 提供的容器运行时工具验证目标镜像:
bash
sudo k3s crictl pull \
docker.m.daocloud.io/rancher/mirrored-pause:3.10.2
本次命令执行成功,说明该镜像能够通过配置的仓库端点获取。
随后继续检查系统 Pod,而不是在镜像拉取成功后就结束排查。
这次故障让我更加明确:排障应该从错误链条的上游入手,逐层验证依赖条件,再确认最终的业务状态。
五、集群验收:从节点到业务服务
镜像拉取问题解决后,对 K3s 集群和原有业务进行了多层验收。
5.1 节点验收
检查命令:
bash
sudo k3s kubectl get nodes -o wide
实际验收结果:
| 检查项 | 结果 |
|---|---|
| 节点数量 | 1 |
| 节点状态 | Ready |
| 节点角色 | control-plane |
| Kubernetes 版本 | v1.36.5+k3s1 |
| 容器运行时 | containerd 2.3.4-k3s1.36 |
节点处于 Ready 状态,满足本次单节点集群的基础验收要求。
5.2 系统组件验收
检查命令:
bash
sudo k3s kubectl get pods -n kube-system -o wide
本次实际结果:
| 组件 | READY | STATUS | 作用 |
|---|---|---|---|
| CoreDNS | 1/1 | Running | 集群 DNS 与服务发现 |
| Local Path Provisioner | 1/1 | Running | 本地路径型持久卷动态供给 |
| Metrics Server | 1/1 | Running | 提供资源指标 API |
三个组件均处于正常运行状态,且没有发生容器重启。
其中,Local Path Provisioner 可以帮助后续实践持久卷申请,但它提供的是本地路径型存储,并不等同于跨节点高可用存储。
5.3 资源指标验收
执行:
bash
sudo k3s kubectl top nodes
本次实际输出:
text
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
izwz9cz3p7i9gev2gfreo6z 39m 0% 2812Mi 38%
在验收时:
- CPU 使用量约为 39m,即约 0.039 个 CPU 核心。
- 内存使用量约为 2812 MiB。
- 内存使用率约为 38%。
CPU 使用率显示为 0% 是指标展示精度和取整的结果,不代表节点完全没有使用 CPU。
该命令能够正常返回节点资源指标,说明 Metrics Server 已具备基本的数据采集与查询能力。
这些数据只代表本次检查时刻的资源使用情况,不应视为服务器的固定开销。
5.4 原有业务验收
本次实践并未将博客或 Jenkins 迁移到 K3s,因此还需要确认原有 Docker 服务仍然正常。
执行:
bash
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
本次四个容器均处于运行状态:
| 容器 | 状态 | 关键端口 |
|---|---|---|
| my-blog-frontend | Up 18 hours | 80 |
| my-blog-backend | Up 18 hours | 容器内部 8080 |
| jenkins | Up 3 hours | 8080、50000 |
| mysql | Up 2 weeks | 127.0.0.1:3306 |
随后使用 HTTP 请求检查三个入口:
bash
# 博客首页
curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
http://127.0.0.1/
# 博客 API
curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
http://127.0.0.1/api/categories
# Jenkins 登录页
curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
http://127.0.0.1:8080/login
实际结果:
| 检查项 | HTTP 状态码 | 结果 |
|---|---|---|
| 博客首页 | 200 | 通过 |
| 博客 API | 200 | 通过 |
| Jenkins 登录页 | 200 | 通过 |
这意味着,在本次验收时,原有业务入口仍然能够正常响应。
需要说明的是,HTTP 200 主要验证接口可访问性,不能完全替代登录、数据库读写、博客发布等端到端业务测试。
5.5 本次验收结论
| 验收维度 | 验收结果 |
|---|---|
| K3s 服务 | 正常 |
| Kubernetes 节点 | Ready |
| 核心系统 Pod | 全部 Running,1/1 Ready |
| 节点资源指标 | 查询成功 |
| 原有 Docker 容器 | 全部保持运行 |
| 博客首页与 API | HTTP 200 |
| Jenkins 登录页 | HTTP 200 |
综合以上结果,本次单节点 K3s 部署达到预定的基础验收目标。
六、配置归档与运维闭环
部署成功后,下一步是保存配置和验收证据,方便后续排障与复盘。
建议归档以下内容:
- K3s 版本与 systemd 服务信息;
- Registry 配置文件;
- 节点和系统 Pod 检查结果;
- 节点资源指标;
- 原有 Docker 容器状态;
- HTTP 健康检查结果;
- 备份文件的 SHA-256 校验值。
需要区分配置归档与完整灾难恢复备份:保存 Registry 配置和验收报告,并不意味着已经备份了完整的集群状态。
如果后续需要研究集群恢复,还应单独规划 K3s 控制平面数据、证书、Token、持久化卷及业务数据的备份与恢复流程,并进行实际恢复验证。
对个人实验环境而言,先建立可追溯的变更记录,再逐步完善恢复演练,是比较稳妥的实践路径。
七、实践总结
本次部署的价值不仅在于安装成功,更在于将部署前检查、故障定位、配置修改和结果验收串联成完整流程。
通过这次实践,我进一步理解了以下内容:
- 环境评估的重要性: 新增基础设施前,应检查已有服务、端口、网络和资源。
- 容器运行时的区别: Docker 与 K3s 内置 containerd 的配置和镜像管理相互独立。
- 故障排查的层次: 从最早的镜像拉取错误开始,逐步验证依赖条件,而不是直接修改网络配置。
- 验收需要多层证据: 不仅检查服务启动,还要验证节点、系统组件、资源指标和现有业务。
- 运维需要形成闭环: 配置归档、验收报告和恢复计划同样是部署工作的一部分。
八、下一步计划:从 K3s 部署走向 Kubernetes 持续交付
完成单节点集群搭建后,下一步计划逐步引入 Kubernetes 工作负载和自动化发布实践:
- 使用 Deployment 部署独立测试应用。
- 使用 Service 实现集群内部服务访问。
- 使用 ConfigMap 与 Secret 管理应用配置。
- 使用 PersistentVolumeClaim 验证持久化存储。
- 研究 Ingress 的流量入口和端口规划。
- 探索 Jenkins 构建镜像、推送镜像并触发 Kubernetes 滚动更新。
- 实践应用发布、健康检查、故障排查与版本回滚。
希望逐步将「逐浪笔记」扩展为一个覆盖代码提交、持续集成、镜像构建、Kubernetes 发布与运行维护的个人 DevOps 实验项目。
实践环境说明: 本文记录的是个人云服务器上的单节点 K3s 实验环境,适用于学习与技术验证,不代表生产级高可用架构。镜像仓库代理和软件版本可能变化,复现时应以实际环境为准。