课程范围:19-云原生监控系统 Prometheus 告警和高级管理 | 20-代码私有仓库 Git 和 GitLab | 21-代码私有仓库 GitLab 管理和 Jenkins 基础
实验环境:Ubuntu2404(最小化安装),2 台虚拟机(可按课程要求扩展为 1 主 2 从)
国内源说明:本实验所有软件源、镜像源、插件源均使用国内源(阿里云 / 清华 / DaoCloud 等),无需科学上网。
| 角色 | 主机名 | IP | 配置 |
|---|---|---|---|
| Master(控制节点) | k8s-master | 10.0.0.200 | 2C/4G |
| Node1(工作节点) | k8s-node1 | 10.0.0.81 | 2C/8G(GitLab 较吃内存) |
第一部分:K8s 集群创建(第 19 课前置环境)
1.1 基础环境配置【所有节点执行】
1.设置主机名
2.配置hosts解析
3.关闭防火墙、swap
4.时间同步
5.加载内核模块、开启转发(Ubuntu用modules-load持久化)
6.安装ipvs依赖
7.修复 systemd-resolved(Ubuntu 24.04 的 /etc/resolv.conf 指向 127.0.0.53,
会导致 kubelet 解析异常,改为指向真实 DNS)
1.2 配置阿里云 apt 源【所有节点执行】
1.3 安装 containerd 容器运行时并配置国内镜像加速【所有节点执行】
K8s 1.24+ 已移除 dockershim,此处安装 containerd(来自阿里云 docker-ce 仓库),并配置 DaoCloud 国内镜像加速,后续 Prometheus / GitLab / Jenkins 官方镜像均可直接拉取,无需修改任何镜像名。
1.4 安装 kubeadm / kubelet / kubectl(阿里云 kubernetes-new 源,apt 版)【所有节点执行】
注意:阿里云 Kubernetes apt 仓库的密钥和包都在v1.30/deb/目录下(密钥为deb/Release.key),仓库地址以/结尾(flat 仓库格式),不要写成 stable/main 普通仓库格式。
1.5 初始化集群【Master 执行】
1.5.1 故障排查:API server is not healthy / kubelet 未运行【Master 执行】
若 init 报The API server is not healthy after 4m0s,按以下顺序定位:
# 1. 看控制面容器状态(哪个在 CrashLoopBackOff / Exited)
crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock ps -a | grep -E 'kube|etcd|pause'
# 2. 看 kubelet 报错(最关键)
systemctl status kubelet --no-pager -l
journalctl -u kubelet --no-pager | tail -50
# 3. 看失败容器日志
crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock logs <CONTAINERID>
常见原因 A:cgroup 驱动不一致(journalctl 出现cgroup driver字样):
grep -n "SystemdCgroup" /etc/containerd/config.toml # 必须为 true
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd kubelet
常见原因 B:containerd 启动失败(mirrors 旧写法不兼容):改用官方certs.d目录方式配置镜像加速:
sed -i '/registry.mirrors/,$d' /etc/containerd/config.toml
sed -i 's#config_path = ""#config_path = "/etc/containerd/certs.d"#' /etc/containerd/config.toml
mkdir -p /etc/containerd/certs.d/{docker.io,registry.k8s.io,quay.io,ghcr.io,gcr.io}
cat > /etc/containerd/certs.d/docker.io/hosts.toml <<'EOF'
server = "https://registry-1.docker.io"
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
EOF
cat > /etc/containerd/certs.d/registry.k8s.io/hosts.toml <<'EOF'
server = "https://registry.k8s.io"
[host."https://k8s.m.daocloud.io"]
capabilities = ["pull", "resolve"]
EOF
cat > /etc/containerd/certs.d/quay.io/hosts.toml <<'EOF'
server = "https://quay.io"
[host."https://quay.m.daocloud.io"]
capabilities = ["pull", "resolve"]
EOF
cat > /etc/containerd/certs.d/ghcr.io/hosts.toml <<'EOF'
server = "https://ghcr.io"
[host."https://ghcr.m.daocloud.io"]
capabilities = ["pull", "resolve"]
EOF
cat > /etc/containerd/certs.d/gcr.io/hosts.toml <<'EOF'
server = "https://gcr.io"
[host."https://gcr.m.daocloud.io"]
capabilities = ["pull", "resolve"]
EOF
systemctl restart containerd kubelet
常见原因 C:sandbox 沙箱镜像拉取超时(containerd 日志出现failed to resolve "registry.k8s.io/pause:xxx" ... i/o timeout,kubelet 报CreatePodSandbox ... connection refused)
# 1. config_path 必须已指向 certs.d(否则加速不生效)
sed -i 's#config_path = ""#config_path = "/etc/containerd/certs.d"#g' /etc/containerd/config.toml
# 2. sandbox_image 只替换前缀、保留版本号(兼容不同 containerd 默认的 pause 版本)
sed -i 's#sandbox_image = "registry.k8s.io#sandbox_image = "registry.aliyuncs.com/google_containers#' /etc/containerd/config.toml
# 3. certs.d 目录和 hosts.toml 必须存在!config_path 指向的目录不存在会导致 containerd 直接起不来
ls /etc/containerd/certs.d/*/hosts.toml # 应列出 5 个文件,缺失就按 1.3 节第 4 步补建
# 4. 重启并实测拉取(成功输出镜像摘要才继续)
systemctl restart containerd
systemctl status containerd --no-pager # 必须 active (running)
crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock pull registry.k8s.io/pause:3.10.2
常见原因 D:DNS 解析异常(拉取报dial tcp 10.255.x.x:443: connect: connection refused之类的内网地址错误,或时好时坏)
# 1. 检查解析结果(若返回 10.x/192.168.x 等内网地址,说明 DNS 被污染或配置错误)
getent hosts registry.aliyuncs.com
cat /etc/resolv.conf
# 2. 写死阿里公共 DNS(覆盖 systemd-resolved 符号链接)
rm -f /etc/resolv.conf
cat > /etc/resolv.conf <<'EOF'
nameserver 223.5.5.5
nameserver 223.6.6.6
EOF
getent hosts registry.aliyuncs.com # 确认已解析到公网 IP
常见原因 E:containerd 反复挂掉 / 预检报 CRI connection refused(kubeadm init预检直接报[ERROR CRI]: container runtime is not running ... dial unix /var/run/containerd/containerd.sock: connect: connection refused,说明 init 根本没开始跑):
# 1. 先看 containerd 为什么没起来
systemctl status containerd --no-pager
journalctl -u containerd --no-pager -n 30 # 若见 "failed to load TOML" 等,说明 config.toml 被多轮修改改坏了
# 2. 配置文件被反复 sed 改坏时,最干净的办法是重建(镜像已缓存、DNS 已修复,重建只需 2 分钟)
systemctl stop containerd
mv /etc/containerd/config.toml /etc/containerd/config.toml.bak.$(date +%s)
containerd config default > /etc/containerd/config.toml
sed -i 's#sandbox_image = "registry.k8s.io#sandbox_image = "registry.aliyuncs.com/google_containers#' /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sed -i 's#config_path = ""#config_path = "/etc/containerd/certs.d"#' /etc/containerd/config.toml
# 3. certs.d 目录和 5 个 hosts.toml 按 1.3 节第 4 步重建(必须先建目录再启用 config_path!)
mkdir -p /etc/containerd/certs.d/{docker.io,registry.k8s.io,quay.io,ghcr.io,gcr.io}
# ...(写入各 hosts.toml,内容见 1.3 节)
# 4. 启动并验证
grep -nE "SystemdCgroup|config_path|sandbox_image" /etc/containerd/config.toml
systemctl restart containerd
systemctl status containerd --no-pager # 必须 active (running)
crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock images | grep pause
# 确认沙箱镜像版本与本地缓存一致后,重新执行 1.5 的 kubeadm init
技巧:预拉控制面镜像,让 init 不依赖网络(还能顺带确认 pause 实际版本号)
kubeadm config images pull \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version $(kubeadm version -o short)
# 预拉完成后把沙箱镜像版本改成与本地缓存一致(如 pause:3.10),避免沙箱去拉另一个版本
crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock images | grep pause
sed -i 's#pause:3.10.2#pause:3.10#' /etc/containerd/config.toml
systemctl restart containerd
重置后重新初始化(失败的 init 必须清理,否则重跑会撞 6443 端口):
注意:若 init 报 API server not healthy 但 kubelet 已 healthy,先别急着重置——等 2~3 分钟后用cp -i /etc/kubernetes/admin.conf $HOME/.kube/config && kubectl get nodes试一次。慢速虚拟机上 etcd 初始化常超过 kubeadm 的 4 分钟超时,API Server 随后正常启动,集群实际可用。
kubeadm reset -f
rm -rf $HOME/.kube /etc/cni/net.d
systemctl restart containerd kubelet
# 重新执行 1.5 的 kubeadm init
1.6 工作节点加入集群【Node 执行】
join 报 "already exists / Port 10250 in use" 怎么办:说明该 Node 之前加入过(或有残留的 kubelet 占着 10250 端口)。清理后重新 join:
kubeadm reset -f
rm -rf /etc/cni/net.d /var/lib/kubelet/pki
systemctl restart containerd kubelet
然后重新执行 join 命令
token 过期(报 token invalid):token 有效期 24 小时,在 Master 上重新生成 join 命令即可:kubeadm token create --print-join-command
1.7 部署 Flannel 网络插件【Master 执行】
1.8 验证集群【Master 执行】
第二部分:实验一 —— 部署 Prometheus 完成对 K8s 集群的监控
任务目标:部署 Prometheus 并完成对 k8s 集群的监控,包括 node 监控、pod 监控,建立使用率大盘 node 和 pod,并配置告警。
2.1 创建监控命名空间【Master 执行】
2.2 部署 node-exporter(Node 监控数据采集)【Master 执行】
说明:node-exporter 以 DaemonSet 方式运行,Master 与 Node1 上各一个 Pod,采集主机指标(端口 9100)。
2.3 部署 kube-state-metrics(Pod/K8s 对象监控)【Master 执行】
2.4 部署 Prometheus 并配置告警规则【Master 执行】
2.5 部署 Alertmanager(接收告警)【Master 执行】
2.6 部署 Grafana 并建立使用率大盘【Master 执行】
2.7 建立 Node 和 Pod 使用率大盘【Master 执行后浏览器操作】
- 浏览器访问
http://10.0.0.200:30300,账号admin,密码admin@123。 - 添加数据源:
Connections → Data sources → Add data source → Prometheus,URL 填http://prometheus.monitoring.svc.cluster.local:9090,保存并测试。 - 导入 Node 使用率大盘:
Dashboards → New → Import,输入社区大盘 ID1860(Node Exporter Full,含 CPU/内存/磁盘/网络使用率),数据源选 Prometheus,导入。 - 若 grafana.com 访问慢,可将大盘 JSON 从国内镜像站(如https://gitee.com搜索 node-exporter-full)下载后选择 "Upload JSON file" 本地导入。 - 导入 Pod 使用率大盘:同样方式导入大盘 ID6417(Kubernetes Pods,展示 Pod 的 CPU/内存使用率排行)。
- 截图保存:Node 大盘、Pod 大盘、
http://10.0.0.200:30900(Prometheus)的 Targets 页面(应看到全部节点和 Pod 目标为 UP 状态)。
2.8 验证监控与告警【Master 执行】![]()
第三部分:实验二 —— 部署 GitLab 并完成课程实验练习(第 20、21 课)
任务目标:在 K8s 上部署 GitLab,完成创建用户/群组/项目、配置 SSH 密钥、推送代码、分支与 Merge Request、Issue 管理等课程实验练习。
3.1 部署 GitLab(社区版)【Master 执行】
注意:PVC 声明在 default 命名空间但 PV 绑定的是 hostPath,GitLab 数据实际落在 k8s-node1 的/data/gitlab下。GitLab 启动需要 3~5 分钟,可用kubectl logs -f gitlab-xxxx观察。
3.2 获取初始 root 密码并登录【Master 执行】
浏览器访问
http://10.0.0.81:30081,用户名root,粘贴上述密码登录。
3.3 GitLab 课程实验练习
(1)设置中文界面:头像 →Preferences → Language选简体中文,保存刷新。
(2)修改 root 密码:头像 →Edit profile → Password,设置新密码。
(3)创建用户并管理权限:管理中心(Admin Area)→ 用户 → 新建用户,创建dev1、dev2两个普通用户,为 dev1 设置密码,通过 dev1 登录验证。
(4)创建群组和项目:管理中心 → 新建群组,命名devops;在群组下新建项目demo-web(可见级别:私有)。
(5)配置 SSH 密钥并推送代码【本机或 Node 执行】:
将公钥粘贴到 GitLab:dev1 头像 → Preferences → SSH Keys → Add key
克隆并首次提交(端口 30081)
(6)分支与 Merge Request 练习:
在 GitLab 页面创建 Merge Request(feature/add-readme → main),指定 dev2 为审核人,审核合并。
(7)Issue 管理练习:项目计划(Plan)→ Issues → 新建 Issue,标题如"首页样式优化",指派给 dev1,并在 MR 中引用#1关联该 Issue,合并后观察 Issue 自动关闭。
(8)保护分支设置:项目设置 → 仓库 → 受保护分支,将main设为仅 Maintainer 可推送、所有人可合并,验证 dev1 无法直接向 main 推送。
dev1 换到功能分支再推:
第四部分:实验三 —— 部署 Jenkins 并完成课程实验练习(第 21 课)
任务目标:在 K8s 上部署 Jenkins,使用国内插件源完成插件安装,创建 Freestyle 任务和 Pipeline 任务,并打通 GitLab 拉取代码。
4.1 部署 Jenkins【Master 执行】
先在 node1 上准备数据目录(Node 执行)
4.2 获取初始管理员密码【Master 执行】
浏览器访问http://10.0.0.81:30080,粘贴密码解锁。
4.4 安装课程所需插件
在Manage Jenkins → Plugins → Available plugins中安装(国内源秒装):
Localization: Chinese (Simplified)(中文界面)Git/GitLab(代码拉取与集成)Pipeline(流水线,若初始未装)Blue Ocean(可视化流水线,可选)
安装完成后重启:kubectl rollout restart deployment jenkins。
4.5 Jenkins 课程实验练习
(1)Freestyle 自由风格任务:
新建任务 → Freestyle project,命名demo-web-build。- 源码管理选
Git,仓库地址填 GitLab 项目 HTTP 地址:http://10.0.0.81:30081/devops/demo-web.git - 凭据:
添加 → Jenkins → 用户名/密码(填 GitLab 账号 dev1)。 - 构建步骤选
执行 shell,内容:
echo "========== 构建开始 =========="
ls -l
cat index.html
echo "========== 构建完成 =========="
- 点击
立即构建,查看Console Output,确认能成功从 GitLab 拉取代码并执行脚本。
(2)Pipeline 流水线任务:
新建任务 → Pipeline,命名demo-web-pipeline。- Pipeline 脚本:
groovy pipeline { agent any stages { stage('拉取代码') { steps { git branch: 'main', credentialsId: 'gitlab-dev1', url: 'http://10.0.0.81:30081/devops/demo-web.git' } } stage('编译测试') { steps { sh 'echo "Pipeline 构建:$(date)"' sh 'ls -l' } } stage('部署模拟') { steps { sh 'echo "模拟部署到 K8s 集群"' } } } post { always { echo '流水线结束,无论成败都会执行' } success { echo '构建成功!' } failure { echo '构建失败,请检查日志' } } }
3.构建并查看 Stage View。
(3)定时构建(CI 触发方式练习):在 Freestyle 任务构建触发器中勾选Build periodically,填写H/5 * * * *(每 5 分钟一次),观察自动构建历史。
第五部分:作业总结
| 实验 | 内容 | 访问入口 |
|---|---|---|
| K8s 集群 | kubeadm + containerd(阿里云源) | - |
| Prometheus 监控 | node 监控 + pod 监控 + 告警 + Grafana 大盘 | http://10.0.0.200:30900/:30903/:30300 |
| GitLab | 部署 + 用户/群组/项目/MR/Issue 练习 | http://10.0.0.81:30081 |
| Jenkins | 部署 + 国内插件源 + Freestyle/Pipeline 练习 | http://10.0.0.81:30080 |
国内源汇总:
| 用途 | 国内源地址 |
|---|---|
| 系统软件源 | mirrors.aliyun.com(Ubuntu apt,deb822 格式) |
| kubeadm/kubelet | mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/deb/(apt,密钥deb/Release.key) |
| K8s 控制面镜像 | registry.aliyuncs.com/google_containers |
| 容器镜像加速 | docker.m.daocloud.io/k8s.m.daocloud.io/quay.m.daocloud.io/ghcr.m.daocloud.io |
| Flannel 清单下载 | ghfast.top(GitHub 加速) |
| NTP 时间同步 | ntp.aliyun.com |
| Jenkins 插件源 | mirrors.tuna.tsinghua.edu.cn/jenkins/updates/ |
| Grafana 大盘备用 | 大盘 JSON 国内镜像站本地导入 |