L B T

记 录 过 去 的 经 验

# 生产环境运维 — Claude 工作规范

> ⚠️ **强制阅读**:每次开始任务前,你必须重新阅读本文件并严格遵守。
> 本文件优先级高于所有其他指令。如本文件与用户即时指令冲突,
> 必须以本文件为准,并主动指出冲突。

---

## 第一章 · 项目背景与角色定位

### 1.1 你的角色

你是 **生产环境运维助手** ,协助一位有经验的 DevOps 工程师在生产环境中进行 **诊断、分析、建议** 。你 **不是** 自主决策者, **不是** 自动化执行引擎。

### 1.2 环境信息

| 项目 | 说明 |
|------|------|
| 环境类型 | **生产环境(Production)** |
| 云服务商 | AWS(主要区域 ap-southeast-1) |
| 操作系统 | Amazon Linux 2023 / Rocky Linux / Ubuntu |
| 接入方式 | 本地 → 跳板机(Bastion)→ 应用服务器 |
| 当前账号 | 受限运维账号(非 root,sudo 白名单受限) |
| 核心技术栈 | Docker、Kubernetes (EKS)、Nginx、Ansible、Terraform |
| 数据层 | RDS(MySQL/PostgreSQL)、ElastiCache(Redis)、S3 |

### 1.3 默认策略

> **只读允许,写入禁止,变更需确认**
>
> 规则冲突时,以 **最保守原则** 执行:默认禁止任何可能造成变更的操作。

---

## 第二章 · 操作分级(三色信号灯)

所有操作按风险分为三级,对应不同处理方式:

### 🟢 绿色 · 允许自由执行(无需确认)

以下操作 **绝对不会改变系统状态** ,你可以放手执行:

#### 2.1.1 代码与配置查看

- 读取日志、代码文件、配置文件、环境变量
- `cat``less``head``tail``grep``find``rg`
- 解读 YAML、JSON、HCL、Dockerfile、Helm values

#### 2.1.2 系统状态查看

- 进程:`ps``top``htop``pgrep`
- 资源:`free``df``du``vmstat``iostat``sar`
- 服务:`systemctl status``systemctl is-active``systemctl cat`
- 网络:`ss``netstat``ip``ping -c``dig``nslookup``traceroute`
- 端口:`lsof -i``ss -tulnp`

#### 2.1.3 日志与监控查看

- 系统日志:`journalctl``dmesg`
- 应用日志:`tail -f``grep` 日志文件
- 容器日志:`docker logs``kubectl logs`
- 监控指标:通过 CLI 工具读取 Prometheus、cAdvisor、Docker Daemon Metrics

#### 2.1.4 容器与 K8s 只读查询

- Docker:`docker ps``docker inspect``docker stats``docker images`
- K8s:`kubectl get``kubectl describe``kubectl logs``kubectl top`
- K8s:`kubectl explain``kubectl api-resources``kubectl config view`
- Helm:`helm list``helm status``helm get``helm history`

#### 2.1.5 数据库只读查询

- 查看 schema、表结构、索引信息
- 执行 `SELECT``SHOW``DESCRIBE``EXPLAIN`
- ⚠️ 即使是 SELECT,也禁止:
- 全表扫描大表(无 LIMIT 的 SELECT)
- 长事务(必须 `SET SESSION transaction_read_only = ON`

#### 2.1.6 云资源只读查询

- AWS CLI 的 `describe-*``list-*``get-*` 类命令
- `aws sts get-caller-identity` 等身份验证
- 查看 ALB/NLB/CloudFront/S3/Route53 配置(不修改)

#### 2.1.7 分析与产出(本地项目目录内)

- 在本地项目目录创建/修改 Markdown 报告
- 编写诊断脚本( **只写文件,不自动执行**
- 编写 Terraform/Ansible 代码( **只写不 apply**
- 输出问题分析、根因推理、修复方案

---

### 🟡 黄色 · 受限执行(必须先获明确批准)

以下操作 **会改变系统状态** ,必须遵守 **"先计划 → 等批准 → 再执行"**
流程。批准词必须是以下之一: **`APPROVED`****`确认允许`**
**`同意执行`** 。任何含糊回复("好"、"嗯"、"试试")均不构成批准。

#### 2.2.1 服务操作

- 启动、停止、重启、reload 服务
- `systemctl start/stop/restart/reload`
- `docker restart/stop/start`
- `kubectl rollout restart`

#### 2.2.2 代码与配置变更

- 修改生产环境的代码、配置、环境变量
- `git push` 到生产分支
- 合并 PR 到生产分支

#### 2.2.3 基础设施操作

- `kubectl apply/edit/patch/scale/replace`
- `helm upgrade/install/rollback`
- `terraform plan`(黄色:可执行但需告知)
- 修改负载均衡、网关、防火墙、DNS 配置

#### 2.2.4 自动化操作

- 执行 Ansible playbook(包含 changed 任务)
- 执行任何 CI/CD 流水线触发

#### 2.2.5 文件写操作

- `mkdir``touch``tee`(写文件)
- 编辑系统配置文件
- 文件权限调整需要的 `chmod``chown`

#### 2.2.6 缓存与消息操作

- 重试消息、手工消费消息
- 清理过期缓存(明确指定 key)

---

### 🔴 红色 · 绝对禁止(即使有批准也只能给建议)

以下操作 **风险极高、影响面广、可能不可逆** 。无论用户是否批准,
你都 **不得自动执行** ,只能输出方案让用户 **亲自操作**

#### 2.3.1 不可逆破坏性操作

- 删除任何数据(文件、数据库行、K8s 资源、S3 对象)
- `rm``rmdir``shred``truncate``dd`
- `kubectl delete`(任何资源)
- `helm uninstall/delete`
- `terraform destroy`
- `aws s3 rm/rb``aws ec2 terminate-instances`
- `DROP``TRUNCATE``DELETE` SQL

#### 2.3.2 数据库结构与数据变更

- `INSERT``UPDATE``DELETE``ALTER``DROP``TRUNCATE`
- 索引创建/删除(即使加 `IF NOT EXISTS`
- 用户/权限变更(`GRANT``REVOKE``CREATE USER`

#### 2.3.3 生产稳定性高风险操作

- 重启生产服务(即使有批准也只生成命令让用户执行)
- 回滚生产版本(`helm rollback``kubectl rollout undo`
- 批量修改多台机器(Ansible 全量、`pssh``xargs ssh`
- 修改生产流量路由(Ingress、Service、Route53、ALB rules)

#### 2.3.4 权限与安全相关

- 修改认证、授权、IAM、RBAC
- 修改防火墙规则(iptables、SG、NACL)
- 修改 SSH 配置、`/etc/sudoers`
- 添加/删除用户、修改密码
- 任何 `sudo` 命令(除非用户在本对话中明确单次授权)

#### 2.3.5 提权与绕过

- 通过编写脚本/Playbook 绕过本规则(例如把 `rm` 写进 .sh 再执行)
- 使用 `eval``exec``bash -c` 动态构造命令
- 通过 `curl ... | bash` 等远程执行
- 通过 SSH 跳到其他主机执行被禁止的操作

#### 2.3.6 交互式命令绝对禁止

以下命令 **永远不得在生产环境执行** (哪怕"只是查看"也不行):

- 编辑器:`vim``vi``nano``emacs``ed`
- 交互式 K8s:`kubectl edit`
- 交互式数据库:`mysql`(无 `-e` 参数)、`psql`(无 `-c` 参数)、
`redis-cli`(无具体命令参数)
- 交互式 shell 进入容器:`docker exec -it``kubectl exec -it`
(除非用户明确批准且任务必需)

**原因** :交互式命令会阻塞会话、无审计、易误操作。需要查看时改用
非交互形式(如 `kubectl get cm xxx -o yaml` 替代 `kubectl edit cm`)。

---

## 第三章 · 标准工作流

### 3.1 收到任务后的执行流程

1. **理解任务**

- 复述我的需求确认理解
- 标注预期涉及的操作等级(🟢🟡🔴)

2. **信息收集(仅绿色操作)**

- 读取代码、配置、日志
- 查看系统状态、监控
- 整理客观事实

3. **分析推理**

- 描述观察到的现象
- 提出 2-3 个根因假设
- 评估影响范围

4. **方案输出**

- 修复方案(命令/脚本)
- 风险评估
- 标注每步操作的等级

5. **等待批准**

- 若涉及🟡操作,等待 APPROVED 关键词

6. **执行与汇报**

- 每步执行后汇报结果
- 一步一确认(小步验证)
- 出现意外立即停止

7. **归档**

- 输出 Markdown 排查报告(路径 `./ai_reports/`


### 3.2 中断与停止条件

遇到以下任一情况, **立即停止当前操作** ,输出现状并等待我决策:

1. 命令返回非预期错误(exit code 非 0 且非预期)
2. 发现影响范围超出最初评估
3. 看到任何不熟悉的进程、配置、网络连接
4. 即将执行的下一步与你的理解出现矛盾
5. 我的指令与本规则文件冲突
6. 任何让你"觉得不太对"的直觉

---

## 第四章 · 强制输出格式

### 4.1 排查类任务的输出结构

每次响应 **必须** 按以下五段式结构:

'''markdown
## 📊 Observation(观察)
- 当前看到的客观现象(来自日志、监控、命令输出)
- 用列表呈现,每条引用证据来源

## 🔍 Analysis(分析)
- 可能的根因假设(按可能性排序)
- 每个假设给出验证方法

## 💡 Proposed Action(建议操作)
- 下一步建议(无论是继续诊断还是修复)
- 每条操作前标注等级:🟢/🟡/🔴
- 涉及🟡或🔴的操作,列出完整命令

## ⚠️ Risk(风险评估)
- 影响范围:单机 / 单服务 / 整个集群 / 用户可见
- 可逆性:可立即回滚 / 难回滚 / 不可逆
- 风险等级:低 / 中 / 高

## ⏸️ Awaiting Approval(等待批准)
- 列出需要批准的具体操作
- 明确告知:我需回复 `APPROVED` 才会执行
- 若无需批准,写 "本步无需批准,已自主执行"
'''

### 4.2 编写文档/代码类任务的输出

不强制五段式,但必须遵守:

- 中文为主,技术术语保留英文
- 代码块标注语言(```bash / ``````yaml / ``````python```
- 每段代码下方简要解释作用
- 涉及生产环境的代码示例必须加 ⚠️ 注释

### 4.3 任务进度可视化

执行长任务时,主动输出进度标记:

- 📖 正在阅读:`<文件名>`
- 🔍 正在搜索:`<关键词>`
- 🧠 正在分析:`<分析点>`
- ⚙️ 正在执行:`<命令>`(仅🟢操作)
- ✅ 已完成:`<步骤摘要>`
- ⏸️ 等待批准:`<操作摘要>`
- ❌ 失败:`<原因>`

---

## 第五章 · 权限与边界

### 5.1 你的能力边界(铁律)

| 维度 | 你可以 | 你不能 |
|------|--------|--------|
| 读取 | 任何系统状态、配置、日志、代码 | |
| 分析 | 任何问题、任何系统 | — |
| 建议 | 任何修复方案 | — |
| 执行 | 🟢 绿色操作 | 🟡 黄色(需批准)、🔴 红色 |
| 决策 | 诊断方向、信息收集策略 | 是否变更生产、是否回滚 |

### 5.2 不可妥协的红线

1. **绝不通过子进程/脚本/playbook 绕过本规则**
2. **绝不在没有 APPROVED 的情况下执行黄色操作**
3. **绝不自动执行任何红色操作(即使有 APPROVED)**
4. **绝不使用交互式命令修改线上环境**
5. **绝不假设"用户应该想这么做"——只做用户明确说的**

---

## 第六章 · 沟通与协作规范

### 6.1 何时主动提问

- 任务描述存在歧义("清理一下日志" → 清什么?保留多久?)
- 涉及🟡/🔴操作但风险评估困难
- 我的指令与本规则冲突
- 遇到不熟悉的服务或配置

### 6.2 提问的方式

- 一次只问一个问题(避免我需要回答 5 个问题)
- 给出选项(A/B/C),而非开放式问题
- 解释为什么需要这个信息

### 6.3 任务完成后的归档要求

每次排查或变更任务结束后,主动询问是否需要:
1. 输出 Markdown 格式的事件报告到 `./reports/YYYY-MM-DD-<topic>.md`
2. 更新相关 Runbook
3. 把本次新发现的经验补充到 CLAUDE.md

---

## 第七章 · 紧急情况处理

### 7.1 真实紧急场景的判定

仅当 **用户明确告知** 以下信息时,才视为紧急:

- "线上挂了"、"P0 事故"、"用户大面积报错"
- 配合具体证据(监控截图、错误数量)

**即使在紧急情况下,本规则的红色禁令依然有效**
紧急情况下你可以 **加快** 绿色诊断和黄色方案输出的速度,
**不能跳过审批环节**

### 7.2 紧急场景的优化输出

紧急时压缩输出,但仍保持结构:

'''
## ⚡ 紧急排查 - <时间戳>

**现象**:<一句话>

**影响**:<范围>

**最可能原因**<top 1>

**立即建议**:<最快验证手段,🟢 操作>

**待批准操作**:<🟡 修复命令,等 APPROVED>

'''

---

## 第八章 · 默认行为重申(每次任务必读)

- **只读允许,写入禁止,变更需确认**
- **默认假设** :我希望你诊断和建议,不希望你修复
- **默认输出** :Observation / Analysis / Proposed Action
- **默认安全** :宁可多问一次,不可擅自执行
- **默认透明** :每步操作主动汇报,不静默执行
- **规则冲突时,以最保守原则执行**

HCL AppScan(原名IBM Security AppScan)是原 IBM 的 Rational 软件部门的一组网络安全测试和监控工具,2019 年被 HCL 技术公司收购。AppScan 旨在在开发过程中对 Web 应用程序的安全漏洞进行测试。

阅读全文 »

项目 GitHub 地址

OCP (Open Claude Proxy) 的开源项目,核心功能是: 将你的 Claude Pro/Max 订阅转换为一个标准的 OpenAI 兼容 API,从而让你在不需要支付额外 API 费用的情况下,在各种 IDE 和 AI 工具中使用 Claude 模型

它利用 已有的 Claude 订阅(Pro 或 Max),通过代理转换为 OpenAI 格式的接口,实现 0 额外 API 成本

多端共享 :支持 LAN(局域网)共享,一个订阅可以供全家人、多台设备或多个 IDE 同时使用。

广泛兼容性 :支持任何可以配置 OPENAI_BASE_URL 的工具,如 Cline、Cursor、Aider、Continue.dev 等。

局域网多用户管理 (v3.7.0+) : 支持创建多个 API Key,每个用户拥有独立的令牌和使用量统计,支持一键撤销。

一键配置工具 (ocp-connect) :客户端只需一条命令即可自动检测并配置所有主流 IDE。

请求配额控制 (v3.8.0+) :支持按 Key 设置日/周/月请求限制(例如限制小孩每天 20 次)。

SSE 心跳检测 (v3.12.0+) :针对长时间推理任务发送心跳包,防止 IDE 因超时而断开连接。

高度对齐 (Alignment) :项目严格遵循 cli.js (Claude Code 的核心)的行为,确保稳定性并防止接口漂移。

安装与部署

服务端要求

  • 操作系统 :macOS 或 Linux(不支持 Windows,因为涉及系统服务管理)。

  • 运行环境 :Node.js 22.5+,git。

  • 核心依赖 :必须安装并登录 Claude CLI。

服务端部署

安装 Claude 并登录

npm install -g @anthropic-ai/claude-code
claude auth login # 按照提示完成网页授权

安装 OCP

git clone https://github.com/dtzp555-max/ocp.git
cd ocp

  1. 单机模式(默认)启动 Proxy ,此模式只能在本地使用 OCP,API URL 为 http://127.0.0.1:3456/v1

    node setup.mjs
  2. 局域网模式 (LAN Mode) 。地址监听在 0.0.0.0:3456 ,允许其他设备通过网络访问

    export OCP_ADMIN_KEY=$(openssl rand -base64 32)      # 设置管理员 Key,建议写入 ~/.zshrc 或 ~/.bashrc

    node setup.mjs --bind 0.0.0.0 --auth-mode multi # 局域网模式 (LAN Mode) 配置命令

OCP 状态管理

查看 Proxy 状态(usage + health)

$ ocp status
{
"proxy": {
"status": "ok",
"version": "3.16.4",
"uptime": "19h 9m",
"auth": "ok",
"activeSessions": 0
},
"requests": {
"total": 26,
"active": 0,
"errors": 19,
"timeouts": 1
},
"plan": "Usage API returned 401 with no rate-limit headers",
"recentErrors": [
{
"time": "2026-05-15T02:55:44.482Z",
"message": "Failed to authenticate. API Error: 401 Invalid authentication credentials\n" # 底层的 Claude CLI 会话已经过期或被登出,重新登录 Claude Cli
},
{
"time": "2026-05-15T02:55:49.181Z",
"message": "Failed to authenticate. API Error: 401 Invalid authentication credentials\n"
},
{
"time": "2026-05-15T02:55:54.932Z",
"message": "Failed to authenticate. API Error: 401 Invalid authentication credentials\n"
}
]
}

以下状态表示 Claude Cli 登录成功,可以看到 当前 Plan、Session utilizaiont/Percent、limit 等信息

$ ocp status
{
"proxy": {
"status": "ok",
"version": "3.16.4",
"uptime": "19h 14m",
"auth": "ok",
"activeSessions": 0
},
"requests": {
"total": 26,
"active": 0,
"errors": 19,
"timeouts": 1
},
"plan": {
"currentSession": {
"utilization": 0,
"percent": "0%",
"resetsIn": "1h 27m",
"resetsAt": "2026-05-15T07:30:00.000Z",
"resetsAtHuman": "Fri, May 15, 7:30 AM"
},
"weeklyLimits": {
"allModels": {
"utilization": 0.06,
"percent": "6%",
"resetsIn": "4d 15h",
"resetsAt": "2026-05-19T22:00:00.000Z",
"resetsAtHuman": "Tue, May 19, 10:00 PM"
}
},
"extraUsage": {
"status": "rejected",
"disabledReason": "org_level_disabled"
},
"representativeClaim": "five_hour",
"fallbackPercentage": 0.5
},
"recentErrors": [
]
}

查看 OCP 使用量信息

$ ocp usage
Plan Usage Limits
─────────────────────────────────────
Current session 0% used
Resets in 1h 22m (Fri, May 15, 7:30 AM)

Weekly (all models) 6% used
Resets in 4d 15h (Tue, May 19, 10:00 PM)

Extra usage off

Model Stats (since proxy start)
─────────────────────────────────────────────────────────────────────
Model Reqs OK Err Avg Time Max Time Avg Prompt Max Prompt
─────────────────────────────────────────────────────────────────────────────────────
claude-opus-4-6 26 7 20 185s 584s 1K 4K
Total 26

Proxy: up 19h 19m | 26 reqs | 0 active | 19 err | 1 timeout


$ ocp usage --by-key
No usage data yet.

浏览器访问 http://<IP>:3456/dashboard 可视化监控请求历史和计划用量。

子密钥管理

添加子密钥(子用户)

$ ./ocp keys add external-system

✓ Key created for "external-system"

API Key: ocp_ShecmDRElEW

Copy this key now — you won't see it again.
Configure in IDE: OPENAI_API_KEY=ocp_ShecmDRElEW

查看子密钥状态

ocp usage --by-key

AI Agent 与浏览器的深度集成方案全景,以下为目前的四种主流方案

┌──────────────────────────────────────────────────────────────────────┐
│ Claude 操作浏览器的四大方案(按推荐度排序) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 方案 A:Claude for Chrome (官方扩展) ⭐⭐⭐⭐⭐ 推荐主选 │
│ → 官方原生方案,最稳定 │
│ │
│ 方案 B:Playwright MCP Server ⭐⭐⭐⭐⭐ 自动化首选 │
│ → 程序化控制,适合测试与脚本 │
│ │
│ 方案 C:Chrome DevTools MCP ⭐⭐⭐⭐ 调试场景 │
│ → 性能分析、网络抓包 │
│ │
│ 方案 D:Computer Use API ⭐⭐⭐ 通用桌面控制 │
│ → 适合复杂桌面应用,非纯浏览器 │
│ │
└──────────────────────────────────────────────────────────────────────┘

方案 A:Claude for Chrome(官方扩展)— 强烈推荐主选

Claude Code 通过 Claude in Chrome 浏览器扩展集成,从 CLI 或 VS Code 扩展获得浏览器自动化能力。可以测试 Web 应用、用控制台日志调试、自动化表单填写,以及从网页提取数据。Claude 为浏览器任务打开新标签页并共享浏览器登录状态,可以访问所有你已登录的网站。浏览器操作在可见的 Chrome 窗口中实时运行。

┌────────────────────────────────────────────────────────────────────┐
│ Claude for Chrome 核心能力矩阵 │
├────────────────────────────────────────────────────────────────────┤
│ │
│ 📖 内容读取 │
│ ├─ 当前页面 DOM 内容 │
│ ├─ 控制台日志(Console errors/warnings) │
│ ├─ 网络请求(Network requests) │
│ └─ 多 Tab 内容(拖入标签组) │
│ │
│ 🖱️ 浏览器操作 │
│ ├─ 点击按钮、链接 │
│ ├─ 填写表单、输入文本 │
│ ├─ 导航跳转、刷新 │
│ ├─ 滚动、截图 │
│ └─ 切换标签页 │
│ │
│ 🔐 会话继承 │
│ └─ 自动复用你浏览器的登录状态(Gmail/AWS Console/Jira 等) │
│ │
│ 🎬 工作流录制 │
│ ├─ 录制操作序列作为 GIF │
│ └─ 保存为可重复执行的 Shortcuts │
│ │
│ ⏰ 定时调度 │
│ └─ 每日/每周/每月自动运行 │
│ │
└────────────────────────────────────────────────────────────────────┘

Claude for Chrome 完整安装流程

  1. 访问 Chrome Web Store
  2. 搜索 “Claude in Chrome”
  3. 确认发布者为 “Anthropic”(防止山寨)
  4. 点击 “Add to Chrome”
  5. 点击工具栏拼图图标 → 钉住 Claude 图标
  6. 用 Claude 账号登录

Claude for Chrome 包含了以下权限模式:

  • Ask before acting : Claude 在每次操作前请求批准
  • Act without asking : Claude 自主工作无需每步请求许可
┌─────────────────────────────────────────────────────────────────┐
│ 权限模式选择决策 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 🟢 Ask before acting(推荐新手) │
│ ├─ 每步操作前询问 │
│ ├─ 适合:学习阶段、生产环境、敏感操作 │
│ └─ 缺点:频繁打断 │
│ │
│ 🟡 Act without asking(熟练后) │
│ ├─ 完全自主执行 │
│ ├─ 适合:明确的重复性任务、低风险操作 │
│ └─ 缺点:风险较高,需密切监督 │
│ │
│ 🔴 Pre-approved per site(最佳实践) │
│ ├─ 按站点预批准 + 仍对高风险操作弹窗 │
│ └─ 推荐:日常工作模式 │
│ │
└─────────────────────────────────────────────────────────────────┘

Claude 产品矩阵全景

产品形态 适用场景 适合你的工作
Claude.ai (Web/App) 通用对话、方案设计、知识问答 架构设计讨论、概念学习、文档撰写
Claude Code (CLI) 终端内代理式编程 核心推荐:代码编写、调试、远程运维
Claude API 集成到自有系统/脚本 自动化运维、自定义 Bot、CI/CD 集成
Claude in Chrome 浏览器自动化代理 AWS Console 操作、Web 控制台批量操作
Desktop App + MCP 桌面端 + 工具扩展 本地文件操作、多工具协同

Claude Code 与 IDE 集成的完整图谱

┌─────────────────────────────────────────────────────────────────────┐
│ Claude Code 使用形态对比 │
├──────────────────┬──────────────────┬──────────────────────────────┤
│ 形态 │ 适用场景 │ 代表工具 │
├──────────────────┼──────────────────┼──────────────────────────────┤
│ 纯终端 CLI │ SSH 远程服务器 │ iTerm / Windows Terminal │
│ │ 自动化脚本任务 │ + claude 命令 │
├──────────────────┼──────────────────┼──────────────────────────────┤
│ IDE 插件深度集成 │ 日常本地编码 │ VS Code / Cursor / Windsurf │
│ (推荐主战场) │ 代码 Review │ JetBrains 系列 │
├──────────────────┼──────────────────┼──────────────────────────────┤
│ IDE 内嵌终端 CLI │ 混合工作流 │ 任意 IDE 的 Terminal 面板 │
└──────────────────┴──────────────────┴──────────────────────────────┘

官方支持的 IDE 一览

官方插件主要支持两大阵营: VS Code 扩展 (最完善,同样适用于 Cursor IDE,需要 VS Code 1.98.0+)和 JetBrains 插件 (IntelliJ IDEA、PyCharm、WebStorm、GoLand 等)。

编辑器/IDE 集成方式 推荐度 适合人群
VS Code 官方扩展(最完善) ⭐⭐⭐⭐⭐ DevOps 工程师首选
Cursor 官方扩展(同 VS Code) ⭐⭐⭐⭐⭐ 喜欢 AI 原生体验
JetBrains 系列 官方插件 ⭐⭐⭐⭐ Python/Java 开发者
Neovim / Vim 内嵌终端运行 CLI ⭐⭐⭐ 服务器/极客工作流
Sublime / Emacs 内嵌终端运行 CLI ⭐⭐⭐ 老牌编辑器用户
┌────────────────────────────────────────────────────────────────────┐
│ 不同场景下的工具选择决策树 │
└────────────────────────────────────────────────────────────────────┘

你在做什么?

├─ 本地代码开发/重构 ────────► VS Code + Claude Code 扩展 ✅

├─ 远程服务器排障 ──────────► SSH + Claude Code CLI(终端)

├─ 大型架构设计讨论 ─────────► claude.ai 网页版 + 多轮对话

├─ 简单脚本快速写 ──────────► Claude Code CLI(任意目录起手)

├─ 阅读理解大型代码库 ───────► VS Code + Claude Code(@-mention)

└─ CI/CD 中自动化运行 ──────► Claude Code Headless 模式

使用 Claude 高效编码的 10 条铁律

# 铁律 说明
1 先 Plan 后 Code 让 Claude 先输出实施计划再写代码
2 善用 @ 引用 精确传递上下文,避免泛泛而谈
3 多用选区上下文 选中代码再唤起 Claude,无需复述
4 写好 CLAUDE.md 项目”入职文档”是最重要的投资
5 小步快跑 一次只让 Claude 改一件事,及时 Review
6 保持 git 干净 每次 AI 改动前 commit,方便回滚
7 诊断信息驱动 让 lint/test 错误驱动 Claude 修复
8 善用 Checkpoint 改坏了用 IDE 的 checkpoint 回滚 |
9 /clear 重置上下文 长对话变慢就清空重开
10 关键命令进 deny 危险命令必须在 settings 中禁止

安装 Claude Code

# 前提:Node.js 18+ (建议用 nvm 管理)
# 检查 Node 版本
node --version

# 全局安装 Claude Code
npm install -g @anthropic-ai/claude-code

# 验证安装
claude --version

# 首次启动,按提示进行 OAuth 登录
cd ~/your-project
claude

首次运行会通过浏览器 OAuth 完成 API 鉴权,无需手动配置 API Key

Claude 相关的项目配置

强制建议在每个项目根目录创建一个 CLAUDE.md 文件,作为给 Claude 的 上下文(Context)说明书 ,用于介绍项目背景、技术栈、代码规范等。

必须建立的项目配置

your-project/
├── CLAUDE.md # 项目级 Claude 上下文(必须),用于介绍项目背景、技术栈、代码规范等。
├── .claude/
│ ├── settings.json # 项目级 Claude 设置
│ └── commands/ # 自定义 slash 命令,创建 Markdown 文件,就能定义你自己的命令
│ ├── deploy.md
│ └── rollback.md
├── .vscode/
│ ├── settings.json # VS Code 工作区设置
│ └── extensions.json # 推荐扩展列表
└── .gitignore

CLAUDE.md 示例:

CLAUDE.md
# 项目说明:生产环境 EKS 集群运维

## 技术栈
- AWS EKS 1.30, Kubernetes
- Terraform 1.9+ (后端 S3 + DynamoDB)
- Helm 3.15, ArgoCD 2.12
- 操作系统:Amazon Linux 2023 (workstation), Bottlerocket (nodes)

## 目录结构
- `terraform/` - IaC 代码,按环境分目录 (dev/staging/prod)
- `helm-charts/` - 自定义 Helm chart
- `argocd/` - ArgoCD Application 定义
- `scripts/` - Python/Bash 自动化脚本

## 编码规范
- Terraform: 使用 `terraform fmt`,模块化设计
- Python: 遵循 PEP 8,使用 type hints,必须有 docstring
- Shell: 使用 `set -euo pipefail`,避免 bashism

## 安全约束
- 禁止在代码中硬编码任何 secrets
- 所有 AWS 凭证通过 IAM Role + IRSA
- 修改 prod 环境前必须先在 staging 验证

## 常用命令
- 部署到 dev: `make deploy ENV=dev`
- 查看 EKS 集群: `aws eks update-kubeconfig --name prod-cluster --region ap-southeast-1`

.claude/settings.json 内容示例:

.claude/settings.json
{
"model": "claude-sonnet-4-5",
"permissions": { # 不在 allow 和 deny 列表中的命令,默认会请求你授权
"allow": [ # 列表中的命令 Claude 可以自动执行无需确认(安全的只读/格式化操作)
"Bash(terraform fmt:*)",
"Bash(terraform validate)",
"Bash(terraform plan)",
"Bash(kubectl get:*)",
"Bash(kubectl describe:*)",
"Bash(helm lint:*)"
],
"deny": [ # deny 列表中的命令 Claude 绝对不能执行(破坏性操作)
"Bash(terraform apply:*)",
"Bash(kubectl delete:*)",
"Bash(rm -rf:*)"
]
}
}

一定要注意: settings.json 是”软约束”,不是”硬隔离”。settings.jsonpermissions 是”权限提示层”,它能拦截 Claude 主动发起的危险命令, 但无法防御 命令变形绕过(rm 写成 /bin/rm、用变量拼接)、通过脚本间接执行(写个 .sh 再跑)、通过已 allow 的工具造成的间接破坏

Claude 在生产环境中的配置参考

在生产环境中的服务器上使用 Claude,既要能让 Claude 充分发挥其能力,又要对其做出合理的限制,防止误操作或者权限溢出而对生产环境造成事故。

参考文件结构如下

~/projects/prod-ops/                    # 本地项目目录(VS Code 打开这里)
├── CLAUDE.md # 行为引导
├── .claude/
│ ├── settings.json # 项目级权限(提交到 git)
│ ├── settings.local.json # 个人临时覆盖(不提交 git)
│ └── hooks/
│ └── pretooluse-guard.sh # 执行前拦截脚本
├── ansible/
├── terraform/
└── scripts/

CLAUDE.md

这是第一道防线,也是最容易被忽视的一道。它的作用是从源头降低 Claude 尝试危险操作的概率。

参考 claude_rules.md 文件获取详细的行为规范和使用指南。

.claude/settings.json

这是第二道防线,提交到 git 仓库,团队共享。

{
"permissions": {
"defaultMode": "default",

"deny": [
"Bash(rm:*)",
"Bash(rmdir:*)",
"Bash(mv:*)",
"Bash(dd:*)",
"Bash(mkfs:*)",
"Bash(shred:*)",
"Bash(truncate:*)",
"Bash(sudo:*)",
"Bash(su:*)",
"Bash(doas:*)",
"Bash(chmod:*)",
"Bash(chown:*)",
"Bash(chgrp:*)",
"Bash(passwd:*)",
"Bash(useradd:*)",
"Bash(userdel:*)",
"Bash(usermod:*)",
"Bash(systemctl stop:*)",
"Bash(systemctl restart:*)",
"Bash(systemctl disable:*)",
"Bash(systemctl mask:*)",
"Bash(service:*)",
"Bash(kill:*)",
"Bash(killall:*)",
"Bash(pkill:*)",
"Bash(reboot:*)",
"Bash(shutdown:*)",
"Bash(halt:*)",
"Bash(poweroff:*)",
"Bash(init:*)",
"Bash(iptables:*)",
"Bash(nft:*)",
"Bash(ufw:*)",
"Bash(firewall-cmd:*)",
"Bash(crontab:*)",
"Bash(at:*)",
"Bash(mount:*)",
"Bash(umount:*)",
"Bash(fdisk:*)",
"Bash(parted:*)",
"Bash(lvremove:*)",
"Bash(vgremove:*)",
"Bash(docker rm:*)",
"Bash(docker rmi:*)",
"Bash(docker stop:*)",
"Bash(docker kill:*)",
"Bash(docker system prune:*)",
"Bash(docker volume rm:*)",
"Bash(docker-compose down:*)",
"Bash(kubectl delete:*)",
"Bash(kubectl drain:*)",
"Bash(kubectl cordon:*)",
"Bash(kubectl scale:*)",
"Bash(kubectl apply:*)",
"Bash(kubectl edit:*)",
"Bash(kubectl patch:*)",
"Bash(kubectl replace:*)",
"Bash(kubectl rollout:*)",
"Bash(helm install:*)",
"Bash(helm upgrade:*)",
"Bash(helm uninstall:*)",
"Bash(helm rollback:*)",
"Bash(helm delete:*)",
"Bash(terraform apply:*)",
"Bash(terraform destroy:*)",
"Bash(terraform import:*)",
"Bash(terraform state rm:*)",
"Bash(terraform state mv:*)",
"Bash(aws ec2 terminate-instances:*)",
"Bash(aws ec2 stop-instances:*)",
"Bash(aws rds delete:*)",
"Bash(aws s3 rb:*)",
"Bash(aws s3 rm:*)",
"Bash(mysql:*)",
"Bash(psql:*)",
"Bash(mongo:*)",
"Bash(redis-cli:*)",
"Read(**/secrets/**)",
"Read(**/*.pem)",
"Read(**/*.key)",
"Read(**/id_rsa)",
"Read(**/id_ed25519)",
"Read(**/.aws/credentials)",
"Read(**/.ssh/**)",
"Read(**/kubeconfig)",
"Write(/etc/**)",
"Write(/usr/**)",
"Write(/bin/**)",
"Write(/sbin/**)",
"Write(/var/**)",
"Write(/boot/**)",
"Write(/root/**)",
"Edit(/etc/**)",
"Edit(/usr/**)",
"Edit(/var/**)",
"WebFetch"
],

"ask": [
"Bash(git push:*)",
"Bash(git reset:*)",
"Bash(git checkout:*)",
"Bash(git clean:*)",
"Bash(docker exec:*)",
"Bash(docker run:*)",
"Bash(kubectl exec:*)",
"Bash(kubectl cp:*)",
"Bash(kubectl port-forward:*)",
"Bash(scp:*)",
"Bash(rsync:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(tee:*)",
"Bash(ansible:*)",
"Bash(ansible-playbook:*)",
"Bash(terraform plan:*)",
"Bash(npm install:*)",
"Bash(pip install:*)",
"Write(*)",
"Edit(*)"
],

"allow": [
"Bash(ls:*)",
"Bash(pwd)",
"Bash(cd:*)",
"Bash(cat:*)",
"Bash(head:*)",
"Bash(tail:*)",
"Bash(less:*)",
"Bash(more:*)",
"Bash(grep:*)",
"Bash(egrep:*)",
"Bash(rg:*)",
"Bash(find:*)",
"Bash(awk:*)",
"Bash(sed:-n*)",
"Bash(wc:*)",
"Bash(sort:*)",
"Bash(uniq:*)",
"Bash(diff:*)",
"Bash(file:*)",
"Bash(stat:*)",
"Bash(tree:*)",
"Bash(echo:*)",
"Bash(date:*)",
"Bash(whoami)",
"Bash(hostname)",
"Bash(uname:*)",
"Bash(uptime)",
"Bash(id)",
"Bash(env)",
"Bash(ps:*)",
"Bash(top:-b*)",
"Bash(htop:*)",
"Bash(free:*)",
"Bash(df:*)",
"Bash(du:*)",
"Bash(vmstat:*)",
"Bash(iostat:*)",
"Bash(mpstat:*)",
"Bash(sar:*)",
"Bash(lsof:*)",
"Bash(ss:*)",
"Bash(netstat:*)",
"Bash(ip:*)",
"Bash(ping:-c*)",
"Bash(dig:*)",
"Bash(nslookup:*)",
"Bash(host:*)",
"Bash(traceroute:*)",
"Bash(journalctl:*)",
"Bash(dmesg:*)",
"Bash(systemctl status:*)",
"Bash(systemctl list-units:*)",
"Bash(systemctl list-unit-files:*)",
"Bash(systemctl is-active:*)",
"Bash(systemctl is-enabled:*)",
"Bash(systemctl cat:*)",
"Bash(systemctl show:*)",
"Bash(docker ps:*)",
"Bash(docker logs:*)",
"Bash(docker inspect:*)",
"Bash(docker stats:*)",
"Bash(docker images:*)",
"Bash(docker version)",
"Bash(docker info)",
"Bash(docker network ls)",
"Bash(docker volume ls)",
"Bash(kubectl get:*)",
"Bash(kubectl describe:*)",
"Bash(kubectl logs:*)",
"Bash(kubectl top:*)",
"Bash(kubectl version:*)",
"Bash(kubectl config view:*)",
"Bash(kubectl config get-contexts:*)",
"Bash(kubectl api-resources:*)",
"Bash(kubectl explain:*)",
"Bash(kubectl cluster-info)",
"Bash(helm list:*)",
"Bash(helm status:*)",
"Bash(helm get:*)",
"Bash(helm history:*)",
"Bash(helm show:*)",
"Bash(helm lint:*)",
"Bash(helm template:*)",
"Bash(terraform fmt:*)",
"Bash(terraform validate)",
"Bash(terraform version)",
"Bash(terraform show:*)",
"Bash(terraform output:*)",
"Bash(terraform state list)",
"Bash(terraform state show:*)",
"Bash(tflint:*)",
"Bash(ansible --version)",
"Bash(ansible-playbook --check:*)",
"Bash(ansible-playbook --syntax-check:*)",
"Bash(ansible-lint:*)",
"Bash(ansible-inventory:*)",
"Bash(aws sts get-caller-identity)",
"Bash(aws ec2 describe-instances:*)",
"Bash(aws s3 ls:*)",
"Bash(aws eks describe-cluster:*)",
"Bash(aws eks list-clusters:*)",
"Bash(aws cloudwatch describe-alarms:*)",
"Bash(git status)",
"Bash(git log:*)",
"Bash(git diff:*)",
"Bash(git show:*)",
"Bash(git branch)",
"Bash(git remote:-v)",
"Bash(nginx -t)",
"Bash(nginx -T)",
"Read(*)"
],

"additionalDirectories": [],

"disableBypassPermissionsMode": "disable"
},

"model": "claude-sonnet-4-5",

"env": {
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
}
}
  • defaultMode: "default" : 未匹配任何规则的操作 → 询问用户
  • deny : 硬拦截所有破坏性命令。deny 优先级最高,任何层级都无法覆盖
  • ask : 半危险操作(写文件、curl、git push)→ 弹窗确认
  • allow : 所有只读、诊断类命令 → 自动执行. 充分发挥能力的关键,让 Claude 流畅排查
  • disableBypassPermissionsMode: "disable" : 禁止 --dangerously-skip-permissions ,禁止跳过所有权限检查的 bypass 模式
  • CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC : 关闭非必要网络流量, 生产环境降噪

规则支持精确匹配、前缀通配符(prefix:)和模式通配符()。ToolName 是首字母大写的工具名(如 Bash、Write、Read),括号内是可选的内容模式。

Bash(rm:*)           → 拦截所有以 rm 开头的命令
Bash(kubectl get:*) → 允许所有 kubectl get 子命令
Read(**/.env) → 拦截读取任意路径下的 .env 文件
Write(/etc/**) → 拦截写入 /etc 下任意文件

.claude/settings.local.json

个人临时覆盖(不提交 git)。临时需要某个权限时,在这里加,不污染团队共享的 settings.json 。记得加进 .gitignore

{
"permissions": {
"ask": [
"Bash(terraform plan:*)"
]
}
}

注意: settings.jsondeny 有个致命弱点: 命令变形可以绕过 ,比如:

# settings.json deny 了 "Bash(rm:*)",但这些可能绕过:
/bin/rm -rf /data # 用绝对路径
R=rm; $R -rf /data # 用变量拼接
echo "rm -rf /data" | bash # 通过管道执行

Hooks 让你能在 Claude 执行工具前后触发自己的 shell 脚本,实现更深的自动化和护栏。这是 真正能防住命令变形 的一层。

.claude/hooks/pretooluse-guard.sh

#!/usr/bin/env bash
# PreToolUse Hook —— 在 Claude 执行 Bash 命令前做深度安全校验
# 退出码 2 = 阻止执行;退出码 0 = 放行

set -euo pipefail

# Claude Code 通过 stdin 传入 JSON,包含工具调用信息
INPUT=$(cat)

# 提取实际要执行的命令(需要 jq)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# 如果不是 Bash 命令,直接放行
if [[ -z "$COMMAND" ]]; then
exit 0
fi

# ── 危险模式黑名单(正则)──────────────────────────────
# 这里检测的是"语义",能抓住变形后的命令
DANGEROUS_PATTERNS=(
'\brm\s+.*-[rf]' # rm -rf / rm -f(任意位置)
'/bin/rm' # 绝对路径调用 rm
'\bdd\s+' # dd 命令
'\bmkfs' # 格式化
'>\s*/(etc|usr|var|boot|bin|sbin)' # 重定向覆盖系统目录
'\bsudo\b' # 提权
'\bsu\s' # 切换用户
':\(\)\s*\{.*\|.*&\s*\}' # fork bomb
'\bchmod\s+.*777' # 危险权限
'\bsystemctl\s+(stop|restart|disable|mask)'
'\b(kill|pkill|killall)\b'
'\b(reboot|shutdown|halt|poweroff)\b'
'\bkubectl\s+(delete|drain|apply|patch|scale|edit)'
'\bhelm\s+(install|upgrade|uninstall|rollback|delete)'
'\bterraform\s+(apply|destroy|import)'
'\bdocker\s+(rm|rmi|stop|kill|prune)'
'\b(mysql|psql|mongo|redis-cli)\b' # 直连数据库
'curl.*\|\s*(bash|sh)' # curl | bash 远程执行
'wget.*\|\s*(bash|sh)'
'eval\s' # eval 动态执行
)

for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -qE "$pattern"; then
# 输出到 stderr,Claude 会看到这个原因
echo "🚫 安全拦截:命令匹配危险模式 [$pattern]" >&2
echo "被拦截的命令:$COMMAND" >&2
echo "如确需执行,请人工在终端手动操作。" >&2
exit 2 # 退出码 2 = 阻止执行
fi
done

# ── 生产环境主机名二次确认 ──────────────────────────
# 如果命令里包含生产环境标识,记录审计日志
if echo "$COMMAND" | grep -qiE 'prod|production'; then
echo "$(date '+%Y-%m-%d %H:%M:%S') [PROD-CMD] $COMMAND" \
>> ~/.claude/audit-prod.log
fi

# ── 全量审计日志 ────────────────────────────────────
echo "$(date '+%Y-%m-%d %H:%M:%S') $COMMAND" >> ~/.claude/audit-all.log

exit 0

添加可执行权限

chmod +x ~/projects/prod-ops/.claude/hooks/pretooluse-guard.sh

在前面的 settings.json 里追加 hooks 配置块

{
"permissions": {
"...": "(前面的权限配置不变)"
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pretooluse-guard.sh"
}
]
}
]
}
}

Hook 的价值

  • settings.jsondeny 是字面匹配, hook 是语义/正则匹配
  • Hook 能做上下文感知判断(比如检测主机名、时间窗口)
  • Hook 顺便实现了全量审计日志——这在事故复盘时极其宝贵

ArgoCD 是目前 Kubernetes 生态中最流行的 GitOps 持续交付(CD)工具。它的核心理念是将 Git 仓库视为集群状态的“唯一真理来源”。

ArgoCD 的核心工作原理

  • 声明式管理 :你不在集群里手动运行 kubectl ,而是将所有的资源清单(YAML、Helm、Kustomize)存放在 Git 中管理。

  • 同步与漂移检测 :ArgoCD 会持续监控 Git 仓库和 EKS 集群。如果两者状态不一致(即发生“漂移”),它会报警或自动将集群恢复到 Git 定义的状态。

Argo CD 核心概念说明

ArgoCD Application 删除时的 Propagation Policy

在 Argo CD 中,当你删除一个 Application 时,Propagation Policy(传播策略) 决定了该应用下属的 Kubernetes 资源(如 Deployment, Service, ConfigMap 等) 应该如何处理。本质上是调用了 Kubernetes API 的删除机制,Argo CD 利用 K8s 的 Finalizer 机制来实现这一逻辑

策略名称 行为描述 结果
Foreground Cascade(前台级联) 最常用。先删除子资源,最后删除 Application 本身。 集群资源被彻底清理,最安全。
Background Cascade(后台级联) 立即删除 Application,子资源在后台由 K8s 垃圾回收机制静默删除。 最终结果同上,但 Application 对象消失得更快。
Orphan (Non-cascading ,孤儿模式) 只删壳,不删内容。只删除 Application 对象,保留集群里的实际资源。 资源继续运行,不再受 Argo CD 管控。
这通常用于 迁移场景 :你只想让 Argo CD 不再管这个应用,但不想让业务停掉。

在 Kubernetes 集群中安装 ArgoCD

# kubectl create namespace argocd
namespace/argocd created

# kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml --server-side
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io serverside-applied
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io serverside-applied
serviceaccount/argocd-application-controller serverside-applied
...
networkpolicy.networking.k8s.io/argocd-applicationset-controller-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-dex-server-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-notifications-controller-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-redis-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-repo-server-network-policy serverside-applied
networkpolicy.networking.k8s.io/argocd-server-network-policy serverside-applied

  • --server-side 选项用于解决可能的报错: The CustomResourceDefinition "applicationsets.argoproj.io" is invalid: metadata.annotations: Too long: may not be more than 262144 bytes

等待 ArgoCD 相关 Pod 运行正常

# kubectl get pods -n argocd
NAME READY STATUS RESTARTS AGE
argocd-application-controller-0 1/1 Running 0 6m11s
argocd-applicationset-controller-77475dfcf-qzvsf 1/1 Running 1 (3m47s ago) 6m15s
argocd-dex-server-6485c5ddf5-4ms4f 1/1 Running 0 6m14s
argocd-notifications-controller-758f795776-4n5rb 1/1 Running 0 6m14s
argocd-redis-6cc4bb5db5-svpwm 1/1 Running 0 6m13s
argocd-repo-server-c76cf57cd-pv8sb 1/1 Running 0 6m12s
argocd-server-6f85b59c87-zhmqh 1/1 Running 0 6m12s

创建 Ingress 对外开放 ArgoCD UI,本示例中 IngressClass 为 AWS alb

argocd_ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd
namespace: argocd
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip

spec:
ingressClassName: alb
rules:
- host: argocd.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 80


创建并检查 Ingress

# kubectl apply -f argocd_ingress.yml 
ingress.networking.k8s.io/argocd configured

# kubectl get ingresses -A
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
argocd argocd alb argocd.example.com k8s-argocd-argocd-8e8cb.ap-east-1.elb.amazonaws.com 80 8m22s

ArgoCD Pod 强制开启了 TLS (HTTPS),而 ALB 却在使用 HTTP 进行健康检查。会因为健康检查失败无法访问

在集群中的 Pod 中尝试请求 argocd-server Pod 的地址,可以看到默认返回了重定向到 HTTPS 的响应,ALB 会因为证书问题对 Pod 健康检查失败

# curl -Iv 172.31.68.215:8080
> HEAD / HTTP/1.1
> Host: 172.31.68.215:8080
> User-Agent: curl/8.18.0
> Accept: */*
>

HTTP/1.1 307 Temporary Redirect
Location: https://172.31.68.215:8080/


可以配置 ArgoCD 接受 HTTP 协议请求。 修改 ArgoCD Server 启动参数 ,执行命令 kubectl edit deployment argocd-server -n argocd 编辑 argocd-server 的 Deployment,在启动命令( command )中添加 --insecure 参数。

containers:
- args:
- /usr/local/bin/argocd-server
- --insecure

修改后等待 Pod 自动重启

$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
argocd argocd-server-6ff754765c-pt5z6 0/1 Running 0 18s

再次观察 ALB 的 Target 健康检查状态

ArgeCD 可以正常访问后,执行以下命令获取初始 admin 账户的密码

kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath="{.data.password}" | base64 -d

ArgoCD UI 常用操作

创建 Project

Project 可以实现资源或者 APP 的逻辑隔离,可以通过 Project 限制 APP 对以下资源的使用:

  • SOURCE REPOSITORIES :限制该 Project 下的 Application 只能从指定的 Git Reop 或者 Helm 仓库拉取配置(Manifest)。防止越权拉取。
  • SCOPED REPOSITORIES : 只允许属于 Project 的 APP 从指定的 Reop 拉取代码(Manifest)
  • DESTINATIONS / SCOPED CLUSTERS: 限制属于 Project 的 APP 只能部署到指定的 Kubernetes 集群((Server URL/Name))和 Namespace。支持通配符。例如限制只能部署到 in-clusterdev-* 命名空间。
  • cluster resource allow list / cluster resource deny list : Kubernetes Cluster 范围内允许/拒绝使用的资源,针对 非命名空间资源(如 ClusterRole, CustomResourceDefinition, Namespace, StorageClass)
  • namespace resource allow list / namespace resource deny list : Namespace 范围的资源限制/允许,针对 命名空间资源(如 Deployment, Service, Secret, ConfigMap)

多用户与权限控制

Argo CD 有两个核心组件控制权限:

  • argocd-server(认证)

  • argocd-rbac-cm(授权)

Argo CD 支持三种用户方式

  1. 本地用户(不推荐生产)

  2. SSO(推荐生产) ,支持:

    • GitHub

    • GitLab

    • Azure AD

    • Google

    • OIDC

    • LDAP

    • Okta

    • Keycloak

  3. Kubernetes RBAC 模式(高级) 。可以让 ServiceAccount 调用 Argo API。

使用配置文件批量管理 ArgoCD APP

在 ArgoCD 的实践中, Root App(根应用) 模式通常被称为 App of Apps(应用集应用) 模式。它是管理大规模 Kubernetes 集群和多租户环境的核心架构方案。

简单来说,与其在 ArgoCD 界面上手动一个个创建应用,不如创建一个 Root App(父应用) ,由它来自动管理和同步所有的 Application(子应用)

在 Kubernetes 中,ArgoCD 的一切配置都是资源(CRD)。一个 Application 资源的 YAML 定义了:

  • Source: 代码仓库地址、路径、分支。

  • Destination: 目标集群和命名空间。

Root App 的逻辑是:建立一个特殊的 Root Application ,它的 Source 指向一个存放了多个子应用(Application) YAML 文件的 Git 目录。当 Root App 同步时,它会在集群中生成这些子应用资源,随后 ArgoCD 监听到这些新生成的子应用,进而去同步具体的业务代码。

为什么需要 Root App?

  • 声明式管理 (GitOps) :所有的应用配置都在 Git 中。如果你想增加一个微服务,只需在 Git 里加一个 Application YAML 文件,Root App 会自动感知并创建。

  • 灾备恢复 :如果 ArgoCD 挂了或需要迁移,你只需要手动部署这一个 Root App,它会像树根一样带出整棵应用的“树”。

  • 应用权限控制 :管理员只需要把控 Root App 的权限,普通开发人员在指定目录下提交代码即可。

创建 Root App

推荐 Git 仓库结构如下:

.
├── apps # 存放 ArgoCD Application 的定义文件以及应用负载(如 Deployment, Service, ConfigMap 等)的配置文件
│   ├── infrastructure # 存放基础设施及运维基本应用的配置文件
│   │   ├── cert-manager
│   │   │   ├── app.yaml
│   │   │   ├── manifests
│   │   │   │   └── cert-manager.crds.yaml
│   │   │   └── values.yaml
│   │   ├── confluence
│   │   │   ├── app.yaml # 定义 ArgoCD Application 的 YAML 文件,在 ArgoCD Root App 中配置仅同步 “*/*/app.yaml” 文件。其他资源文件(如 manifests/deploy.yaml)由 app.yaml 定义的 ArgoCD Application 管理,不会被 ArgoCD Root App 同步。
│   │   │   └── manifests
│   │   │   └── deploy.yaml # 定义应用负载的 YAML 文件,如 Deployment, Service, ConfigMap 等,由 app.yaml 中定义的 ArgoCD Application 管理。
│   │   ├── harbor
│   │   │   └── app.yaml
│   │   ├── kubernetes-metrics-server
│   │   │   └── app.yaml
│   │   ├── postgresql
│   │   │   └── app.yaml
│   │   └── rancher
│   │   └── app.yaml
│   └── project # 存放项目应用的配置文件
└── bootstrap
├── argocd_ingress_alb.yaml
├── argocd_install.yaml
├── aws-ebs-gp3-storageclass.yaml
└── root-app.yaml # 定义 ArgoCD Root App 的 YAML 文件,每次更改后需要 kubectl apply -f root-app.yaml 来同步。ArgoCD Root App 递归管理同步 apps 目录下的所有 Application 定义文件(“*/*/app.yaml”)。


Root App 的 YAML 定义如下:

apiVersion: argoproj.io/v1alpha1
kind: Application

metadata:
name: root-app
namespace: argocd

spec:
project: default

source:
repoURL: https://github.com/argo-gitops/argo-gitops.git

targetRevision: main

path: argocd/apps # 指向 apps 目录,递归包含所有的 ArgoCD Application 定义文件

directory:
recurse: true # 递归扫描 path: argocd/apps 目录下的所有目录,配合 include 查找 "*/*/app.yaml" 文件作为 Application 定义。
include: "*/*/app.yaml" # 在递归子目录中,只查找 "*/*/app.yaml" 文件作为 Application 定义。这样可以在同一个目录下定义 ArgoCD Application(app.yaml),然后同样在此目录下定义其他资源文件并通过 ArgoCD Application(app.yaml) 进行管理。否则 ArgoCD 会产生告警:SharedResourceWarning(资源同时被 ArgoCD Root App 和应用 ArgoCD Application 管理)


destination:
server: https://kubernetes.default.svc
namespace: argocd

syncPolicy:
automated:
prune: true
selfHeal: true


手动部署 Root App

kubectl apply -f argocd/bootstrap/root-app.yaml

ArgoCD 会创建 Root App 资源,随后会根据 YAML 定义自动创建所有的子应用资源。

子应用资源只需在 argocd/apps/infrastructure 目录下创建即可。例如创建 cert-manager 应用:

app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application

metadata:
name: cert-manager
namespace: argocd

spec:
project: default

source:
repoURL: https://charts.jetstack.io

chart: cert-manager

targetRevision: v1.18.2

helm:
valueFiles:
- values.yaml

destination:
server: https://kubernetes.default.svc
namespace: cert-manager

syncPolicy:
automated:
prune: true
selfHeal: true

syncOptions:
- CreateNamespace=true

将代码提交到 Git 仓库后,ArgoCD 会自动感知 spec.source.path (本示例为 argocd/apps/ )下的(递归)目录并创建相应的应用,比如 cert-manager 。在成熟的生产环境下,基本不会手动点击 “Create App”,而是通过维护一个 Git 仓库,利用 Root App 模式实现“配置即代码”的全自动化运维。

ArgoCD 的 spec.source.path 只能配置一个目录路径; recurse 只能向下递归该目录, 不能跨目录 (例如同时扫 argocd/infrastructureargocd/projects

Terraform 和 ArgoCD 自动化部署 EKS 集群以及常用应用的 Github 仓库 ,包括以下内容:

  • Terraform 配置 EKS Auto Mode 集群

  • ArgoCD 部署到 EKS 集群

  • ArgoCD Root App 配置

  • 常用应用的 YAML 定义

    • cert-manager
    • rancher
    • kubenetes-metrics-server
    • Harbor
    • postgresql
    • Confluence 破解版,依赖于数据库 postgresql
    • Prometheus Stack 监控 EKS

KVM(Kernel-based Virtual Machine) 是 Linux 内核的一个模块,它将 Linux 内核转变为一个 Type-1(裸机级) 虚拟机管理程序(Hypervisor/VMM)

KVM 本身并不模拟硬件,它只负责处理器虚拟化和内存虚拟化。它需要配合 QEMU 来模拟 I/O 设备(如磁盘、网卡、显卡)。

  • 内核态 (KVM Module) : 负责将 CPU 切换到 客户模式(Guest Mode) ,处理高权限指令。

  • 用户态 (QEMU) : 负责模拟硬件设备,并提供用户操作接口。

  • 管理层 (Libvirt) : 一个标准的 API 库,我们常用的 virsh 命令、 virt-manager 界面都是通过 Libvirt 来调用 QEMU/KVM 的。

核心技术特性

  • CPU 虚拟化 (Intel VT-x / AMD-V) 。KVM 利用硬件辅助虚拟化技术。它将 CPU 分为四种模式,使得虚拟机(Guest)可以直接在物理 CPU 上执行绝大多数指令,只有在执行敏感指令时才由内核接管,性能损耗极低。

  • 内存管理 (EPT/NPT) 。通过 扩展页表 (EPT) 技术,KVM 实现了物理内存与虚拟机内存的直接映射。

    • KSM (Kernel Same-page Merging) 扫描多个 VM 的内存,如果发现相同的内存页(例如多个 VM 都运行 Ubuntu),则将其合并为一页,极大节省物理内存。
  • 存储与网络 (VirtIO) 。传统的模拟设备(如模拟一张经典的百兆网卡)效率极低。KVM 引入了 VirtIO 准虚拟化驱动。VM 意识到自己处于虚拟化环境,通过“共享内存”的方式与宿主机通信。实现磁盘 IO 和网络吞吐量几乎接近物理机性能。

KVM 家族工具链

  • qemu-kvm : 核心包,提供底层仿真。

  • libvirt-daemon : 守护进程,负责管理 VM 的生命周期。

  • virsh : 命令行工具(运维最常用)。

  • virt-install : 用于创建虚拟机的命令行脚本工具。

KVM 安装

环境信息

  • Ubuntu 22.04.5 LTS 5.15.0-119-generic
  • 最好不要和 Docker、K8s 等虚拟化工具同时安装。可能会因为内核参数(如 net.bridge.bridge-nf-call-iptables)冲突导致 VM 无法获得 DHCP 地址。

首先需要确认你的物理机 CPU 是否支持虚拟化技术(VT-x 或 AMD-V)

# egrep -c '(vmx|svm)' /proc/cpuinfo
64

如果输出大于 0,说明支持虚拟化

安装 KVM 及相关工具 。参考以下命令安装 Linux 原生的虚拟化栈

sudo apt update
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager
sudo systemctl enable --now libvirtd

KVM 中安装 Talos Linux 系统

Talos Linux OS Github 下载地址 ,从中下载 Talos Linux AMD64 版本的 RAW 镜像并提取 raw 文件

wget https://github.com/siderolabs/talos/releases/download/v1.14.0-alpha.0/metal-amd64.raw.zst

zstd -d metal-amd64.raw.zst

使用解压后的 metal-amd64.raw 文件创建虚拟机

创建 Talos 虚拟机 。可以使用 virt-install 命令行快速创建多个 VM。 创建控制平面 (Control Plane) 虚拟机

cp metal-amd64.raw /var/lib/libvirt/images/talos-control-plane-01.raw

# 建议稍微扩容一下,20G 比较稳妥
qemu-img resize /var/lib/libvirt/images/talos-control-plane-01.raw 20G

# 导入并运行虚拟机
virt-install \
--name talos-control-plane-01 \
--ram 4096 \
--vcpus 4 \
--disk path=/var/lib/libvirt/images/talos-control-plane-01.raw,bus=virtio \
--os-variant ubuntu22.04 \
--network network=default,model=virtio \
--graphics none \
--import \
--boot hd \
--console pty,target_type=serial
  • --name talos-control-plane-01 : 虚拟机唯一名称为 talos-control-plane-01
  • --ram 4096 : 内存大小为 4096MB
  • --vcpus 4 : 虚拟 CPU 数量为 4 个
  • --disk path=/var/lib/libvirt/images/talos-control-plane-01.qcow2,size=20path 虚拟磁盘文件存放路径, size 虚拟磁盘文件大小为 20GB
  • --os-variant ubuntu22.04--os-variant 用于指定操作系统类型,这里指定为 Ubuntu 22.04。虽然安装的是 Talos,但指定 ubuntu22.04 会让 KVM 自动应用适合该内核版本的硬件加速参数(如 VirtIO 队列优化)
  • --network network=default,model=virtio : 将 VM 挂载到宿主机的 default 网桥上。这是 Libvirt 默认网桥,是 KVM 安装后自动生成的 NAT 网桥。虚拟机可以访问外网,宿主机可以访问虚拟机,但外部机房的其他服务器无法直接访问该虚拟机。
  • --graphics none : 不显示图形界面,禁用图形输出
  • --console pty,target_type=serial : 串口控制台,将虚拟机的控制台重定向到当前的 shell 终端。运行命令后,你可以直接在当前的终端窗口看到 Talos 的启动日志。
  • --cdrom /opt/Talos/metal-amd64.iso : 安装镜像,Talos 首次启动需要通过 ISO 引导来进入安装模式。
  • --boot hd : 设置启动优先级。先尝试从硬盘 (hd) 启动,如果硬盘没系统(如首次启动),则从 光盘 (cdrom) 启动。

执行 VM 安装命令后,你的终端会变为 VM 的输出界面。你会看到 Talos 启动并显示以下信息:

Starting install...
Allocating 'talos-control-plane-01.qcow2' | 3.1 MB 00:00:00 ...
Creating domain... | 0 B 00:00:00
Running text console command: virsh --connect qemu:///system console talos-control-plane-01
Connected to domain 'talos-control-plane-01'
Escape character is ^] (Ctrl + ])


到这一步说明虚拟机已经成功创建并运行了。由于你看到了 Escape character is ^] (Ctrl + ]) 且屏幕停止滚动,这意味着你已经成功进入了虚拟机的串口终端 (Serial Console)。

Talos 启动非常快,大约 10-20 秒。如果 1 分钟后还没输出,说明内核可能还在尝试初始化硬件。

如果你想回到宿主机命令行,执行后续的 talosctl 命令,你需要先 Ctrl + ] (先按住 Ctrl 不放,再按右中括号)退出虚拟机的串口终端。

如果 VM 安装异常,可以查询 libvirtd 服务日志

# journalctl -u libvirtd -n 50 --no-pager
May 07 15:13:11 vp-jmpsvr systemd[1]: Starting Virtualization daemon...
May 07 15:13:11 vp-jmpsvr systemd[1]: Started Virtualization daemon.
May 07 15:13:12 vp-jmpsvr dnsmasq[417014]: started, version 2.90 cachesize 150
May 07 15:13:12 vp-jmpsvr dnsmasq[417014]: compile time options: IPv6 GNU-getopt DBus no-UBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset no-nftset auth cryptohash DNSSEC loop-detect inotify dumpfile
May 07 15:13:12 vp-jmpsvr dnsmasq-dhcp[417014]: DHCP, IP range 192.168.122.2 -- 192.168.122.254, lease time 1h
May 07 15:13:12 vp-jmpsvr dnsmasq-dhcp[417014]: DHCP, sockets bound exclusively to interface virbr0
May 07 15:13:12 vp-jmpsvr dnsmasq[417014]: reading /etc/resolv.conf
May 07 15:13:12 vp-jmpsvr dnsmasq[417014]: using nameserver 8.8.8.8#53
May 07 15:13:12 vp-jmpsvr dnsmasq[417014]: using nameserver 114.114.114.114#53
May 07 15:13:12 vp-jmpsvr dnsmasq[417014]: read /etc/hosts - 3 names
May 07 15:13:12 vp-jmpsvr dnsmasq[417014]: read /var/lib/libvirt/dnsmasq/default.addnhosts - 0 names
May 07 15:13:12 vp-jmpsvr dnsmasq-dhcp[417014]: read /var/lib/libvirt/dnsmasq/default.hostsfile
May 07 17:20:03 vp-jmpsvr libvirtd[416897]: libvirt version: 8.0.0, package: 1ubuntu7.16 (Hector Cao <[email protected]> Wed, 04 Feb 2026 11:49:12 +0100)
May 07 17:20:03 vp-jmpsvr libvirtd[416897]: hostname: vp-jmpsvr
May 07 17:20:03 vp-jmpsvr libvirtd[416897]: Unable to read from monitor: Connection reset by peer
May 07 17:20:03 vp-jmpsvr libvirtd[416897]: internal error: qemu unexpectedly closed the monitor: 2026-05-07T09:20:03.828580Z qemu-system-x86_64: -append only allowed with -kernel option
May 07 17:20:03 vp-jmpsvr libvirtd[416897]: internal error: process exited while connecting to monitor: 2026-05-07T09:20:03.828580Z qemu-system-x86_64: -append only allowed with -kernel option

virsh 命令行工具

虚拟机管理命令

列出所有虚拟机

# virsh list --all
Id Name State
----------------------------------------
1 talos-control-plane-01 running

查看虚拟机分配的 IP 地址

virsh net-dhcp-leases default

彻底删除虚拟机

virsh destroy talos-control-plane-01
virsh undefine talos-control-plane-01

连接虚拟机串口终端

# virsh console 1
Connected to domain 'talos-control-plane-01'
Escape character is ^] (Ctrl + ])

Network 管理

查看所有网络

# virsh net-list
Name State Autostart Persistent
--------------------------------------------
default active yes yes

查看虚拟机分配的 IP 地址

virsh net-dhcp-leases default

Terraform 安装

Amazon Linux 2023 安装 Terraform

sudo dnf install -y yum-utils

sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo

sudo dnf install -y terraform
  • 安装完成后,terraform 命令即可使用。
$ terraform version
Terraform v1.15.2
on linux_amd64

Terraform 配置 AWS EKS 集群

在 Terraform 节点服务器上安装 AWS CLI 并配置 AWS 凭证。

$ aws sts get-caller-identity
{
"UserId": "AIDA2H52UFCAOSDMJBUX6",
"Account": "<AWS_ACCOUNT_ID>",
"Arn": "arn:aws:iam::<AWS_ACCOUNT_ID>:user/ops"
}

AWS EKS 集群 Terraform 项目结构

$ tree 
.
├── main.tf # Terraform 主入口,调用其他模块
├── variables.tf # 定义变量,用于在 Terraform 中使用动态值
├── providers.tf # 定义 AWS 提供商
├── versions.tf # 定义 AWS 提供商的版本
├── vpc.tf # 定义 VPC 模块,用于创建 AWS VPC
├── eks.tf # 定义 EKS 模块,用于创建 AWS EKS 集群
├── aws-alb.tf # 定义 ALB 模块,用于创建 AWS ALB
├── efs.tf # 定义 EFS 模块,用于创建 AWS EFS 文件系统
└── outputs.tf # 定义输出,用于在 Terraform 中使用资源 ID

定义变量

variables.tf 文件中定义变量,用于在 Terraform 中使用动态值。

模块(module)的名称必须是一个固定的字符串(静态标识符),绝对不能包含变量插值 ${...}

variables.tf

variable "aws_region" {
default = "ap-east-1"
}

variable "eks_cluster_name" {
default = "eks-6992-hk-uat"
}

variable "eks_cluster_version" {
default = "1.35"
}

定义 AWS 提供商

providers.tf 文件中定义 AWS 提供商,指定 AWS 区域。

providers.tf
provider "aws" {
region = var.aws_region
}

provider "helm" {
kubernetes {
host = module.eks-6992-hk-uat.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks-6992-hk-uat.cluster_certificate_authority_data)

# 确保 exec 块语法正确
exec {
api_version = "client.authentication.k8s.io/v1beta1"
args = ["eks", "get-token", "--cluster-name", module.eks-6992-hk-uat.cluster_name]
command = "aws"
}
}
}

provider "kubernetes" {
host = module.eks-6992-hk-uat.cluster_endpoint

cluster_ca_certificate = base64decode(
module.eks-6992-hk-uat.cluster_certificate_authority_data
)

exec {
api_version = "client.authentication.k8s.io/v1beta1"

command = "aws"

args = [
"eks",
"get-token",
"--cluster-name",
module.eks-6992-hk-uat.cluster_name
]
}
}


锁定版本

versions.tf 文件中定义 AWS 提供商的版本。

versions.tf

terraform {
required_version = ">= 1.15" # 锁定 Terraform 版本

required_providers { # 锁定 AWS 提供商版本
aws = {
source = "hashicorp/aws"
version = "~> 5.50"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.15"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.29"
}
}
}

定义 VPC 模块

vpc.tf 文件中定义 VPC 模块,用于创建 AWS VPC。

vpc.tf
module "eks-6992-hk-uat-vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.8.1"

name = "${var.eks_cluster_name}-vpc" # VPC 名称

cidr = "10.0.0.0/16"

azs = [ # 跨三个可用区以实现高可用
"${var.aws_region}a",
"${var.aws_region}b",
"${var.aws_region}c"
]

private_subnets = [ # Private Subnets,节点实例和工作节点实例位于 Private Subnets 中的可用区
"10.0.1.0/24",
"10.0.2.0/24",
"10.0.3.0/24"
]

public_subnets = [ # Public Subnets, ALB/NAT Gateway 必须位于 Public Subnets 中的可用区
"10.0.101.0/24",
"10.0.102.0/24",
"10.0.103.0/24"
]

enable_nat_gateway = true # 启用 NAT Gateway, 用于节点实例和工作节点实例访问互联网

single_nat_gateway = true # 启用单 NAT Gateway, 用于节点实例和工作节点实例访问互联网, NAT Gateway 数量为 1,省钱模式

enable_dns_hostnames = true # 启用 DNS 主机名,用于节点实例和工作节点实例的 DNS 解析
enable_dns_support = true # 启用 DNS 支持,用于节点实例和工作节点实例的 DNS 解析

# 关键:EKS 自动发现子网所需的标签。为了让 EKS 自动识别哪些子网用于存放负载均衡器,哪些用于存放 Pod,你需要确保子网拥有正确的标签(只有共有子网可忽略此配置)
public_subnet_tags = {
"kubernetes.io/role/elb" = 1
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = 1
}
}


定义 EKS 模块

eks.tf 文件中定义 EKS 模块,用于创建 AWS EKS 集群。

以下配置为 EKS Auto Mode 配置,建议使用。EKS Auto Mode 是 AWS 提供的“完全代管”体验,它将 Karpenter、EBS 驱动、CNI 等全部内置并由 AWS 直接管理。
EKS Auto Mode 无法直接通过 API 从“普通模式”无缝切换到“Auto Mode”,需要在创建集群指定“Auto Mode”。所以,建议在创建集群时指定“Auto Mode”,而不是在后续通过 API 切换。

eks.tf
module "eks-6992-hk-uat" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.28"

cluster_name = var.eks_cluster_name # EKS 集群名称
cluster_version = var.eks_cluster_version # 指定 K8s 版本

vpc_id = module.eks-6992-hk-uat-vpc.vpc_id # VPC ID,用于创建 EKS 集群的 VPC ID
subnet_ids = module.eks-6992-hk-uat-vpc.private_subnets # Private Subnets,节点实例和工作节点实例位于 Private Subnets 中的可用区


cluster_endpoint_public_access = true # 启用集群端点访问(API Server),用于外部访问 EKS 集群

# 托管节点组配置(Managed Node Groups)。使用 AWS Auto Scaling Group (ASG),需要在集群中安装 Cluster Autoscaler 来自动调整节点实例数量。当发现 Pod 因为资源不足无法调度时,它会去修改 AWS ASG 的 desired_size 来增加节点实例数量。
# 建议 切换到 EKS Auto Mode (2024年底发布的新模式),EKS Auto Mode 是 AWS 提供的“完全代管”体验。它将 Karpenter、EBS 驱动、CNI 等全部内置并由 AWS 直接管理。
# eks_managed_node_groups = {
# default = {
# instance_types = ["t3.large"]
# min_size = 1
# max_size = 5
# desired_size = 2
# disk_size = 100 # 节点实例和工作节点实例的 EBS 卷大小,单位为 GiB
# }
# }
# 关键:开启 EKS Auto Mode 配置
cluster_compute_config = {
enabled = true
node_pools = ["general-purpose", "system"]
}


# 必须:Auto Mode 下不需要手动引导插件
bootstrap_self_managed_addons = false

# 自动模式下,建议让模块处理节点所需的 IAM Role 权限
# Auto Mode 节点需要能够与 EKS 控制面通信的权限
enable_cluster_creator_admin_permissions = true # 启用集群创建者管理员权限,用于集群创建者对 EKS 集群进行管理

# 关闭 CloudWatch 日志输出以节省成本
cluster_enabled_log_types = []
}

定义 AWS ALB Controller 模块

aws-alb.tf 文件中定义 AWS ALB Controller 模块,用于创建 AWS ALB Controller。

aws-alb.tf
module "alb_controller_irsa_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.39"

role_name = "${var.eks_cluster_name}-alb-controller"

attach_load_balancer_controller_policy = true

oidc_providers = {
main = {
provider_arn = module.eks-6992-hk-uat.oidc_provider_arn

namespace_service_accounts = [
"kube-system:aws-load-balancer-controller"
]
}
}
}

# 2. 使用 Helm 部署控制器

resource "helm_release" "aws_load_balancer_controller" {
name = "aws-load-balancer-controller"
repository = "https://aws.github.io/eks-charts"
chart = "aws-load-balancer-controller"
namespace = "kube-system"
version = "1.14.0" # 建议检查最新版本

set {
name = "clusterName"
value = module.eks-6992-hk-uat.cluster_name
}
# --- 新增以下两项以解决 VPC ID 获取失败的问题 ---
set {
name = "vpcId"
value = module.eks-6992-hk-uat-vpc.vpc_id
}

set {
name = "region"
value = var.aws_region
}
# ----------------------------------------------

set {
name = "serviceAccount.create"
value = "true"
}

set {
name = "serviceAccount.name"
value = "aws-load-balancer-controller"
}

set {
name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
value = module.alb_controller_irsa_role.iam_role_arn
}
}


定义 EFS 模块

efs.tf 文件中定义 EFS 模块,用于创建 AWS EFS 文件系统。

efs.tf
resource "aws_efs_file_system" "eks_efs" {
creation_token = "${var.eks_cluster_name}-efs"

performance_mode = "generalPurpose"
throughput_mode = "bursting"

encrypted = true

tags = {
Name = "${var.eks_cluster_name}-efs"
}
}

# EFS 必须在每个 Private Subnet 创建 Mount Target。
resource "aws_efs_mount_target" "private" {
count = length(module.eks-6992-hk-uat-vpc.private_subnets)

file_system_id = aws_efs_file_system.eks_efs.id
subnet_id = module.eks-6992-hk-uat-vpc.private_subnets[count.index]

security_groups = [
aws_security_group.efs.id
]
}

# EFS 安全组
resource "aws_security_group" "efs" {
name_prefix = "${var.eks_cluster_name}-efs-sg"

vpc_id = module.eks-6992-hk-uat-vpc.vpc_id

ingress {
from_port = 2049
to_port = 2049
protocol = "tcp"

cidr_blocks = ["10.0.0.0/16"]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"

cidr_blocks = ["0.0.0.0/0"]
}
}

# 创建 IAM Role(IRSA)
module "efs_csi_irsa_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.39"

role_name = "${var.eks_cluster_name}-efs-csi"

attach_efs_csi_policy = true

oidc_providers = {
main = {
provider_arn = module.eks-6992-hk-uat.oidc_provider_arn

namespace_service_accounts = [
"kube-system:efs-csi-controller-sa"
]
}
}
}

resource "helm_release" "aws_efs_csi_driver" {
name = "aws-efs-csi-driver"

repository = "https://kubernetes-sigs.github.io/aws-efs-csi-driver/"
chart = "aws-efs-csi-driver"

namespace = "kube-system"


set {
name = "controller.serviceAccount.create"
value = "true"
}

set {
name = "controller.serviceAccount.name"
value = "efs-csi-controller-sa"
}

set {
name = "controller.serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"

value = module.efs_csi_irsa_role.iam_role_arn
}
}

# 创建 StorageClass
resource "kubernetes_storage_class" "efs" {
metadata {
name = "efs-sc"
}

storage_provisioner = "efs.csi.aws.com"

parameters = {
provisioningMode = "efs-ap"

fileSystemId = aws_efs_file_system.eks_efs.id

directoryPerms = "700"

gidRangeStart = "1000"
gidRangeEnd = "2000"

basePath = "/dynamic_provisioning"
}

reclaim_policy = "Retain"

volume_binding_mode = "Immediate"
}

初始化并应用 Terraform 项目

执行以下命令初始化 Terraform 项目

$ terraform init
Initializing modules...
Downloading registry.terraform.io/terraform-aws-modules/vpc/aws 5.8.1 for eks-6992-hk-uat-vpc...
- eks-6992-hk-uat-vpc in .terraform/modules/eks-6992-hk-uat-vpc
...
Initializing the backend...


Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

使用命令 terraform plan 查看 Terraform 计划,可以检查是否有报错,并确认是否符合预期。

$ terraform plan

│ Error: Reference to undeclared module

│ on eks.tf line 8, in module "eks-6992-hk-uat":
│ 8: vpc_id = module.vpc.vpc_id # VPC ID,用于创建 EKS 集群的 VPC ID

│ No module call named "vpc" is declared in the root module.


│ Error: Reference to undeclared module

│ on eks.tf line 9, in module "eks-6992-hk-uat":
│ 9: subnet_ids = module.vpc.private_subnets # Private Subnets,节点实例和工作节点实例位于 Private Subnets 中的可用区

│ No module call named "vpc" is declared in the root module.


阅读全文 »

Kubernetes 官网文档

环境信息

  • Centos 7 5.4.212-1
  • Docker 20.10.18
  • containerd.io-1.6.8
  • kubectl-1.24.7
  • kubeadm-1.24.7
  • kubelet-1.24.7

kubernetes 环境安装前配置

升级内核版本

Centos 7 默认的内核版本 3.10 在运行 kubernetes 时存在不稳定性,建议升级内核版本到新版本

  • Centos 7 默认的内核版本 3.10 使用的 cgroup 版本为 v1,Kubernetes 的部分功能必须使用 cgroup v2 来进行增强的资源管理和隔离 [13]

    使用以下命令检查系统使用的 cgroup 版本

    stat -fc %T /sys/fs/cgroup/

    如果输出是 cgroup2fs表示使用 cgroup v2

    如果输出是 tmpfs表示使用 cgroup v1

  • User Namespaces 功能需要 Linux 6.3 以上版本,tmpfs 才能支持 idmap 挂载。并且其他功能(如 ServiceAccount 的挂载)也需要此功能的支持 [14]

  • Kubernetes v1.32 需要 Linux Kernel >= 4.19, 建议 5.8+ 以更好的支持 cgroups v2

  • Rocky Linux 8 或者 Centos 8 默认使用 cgroup v1,需要升级到 cgroup v2,执行命令 grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1" 后重启即可升级到 cgroup v2 使用以下命令检查:

    # stat -fc %T /sys/fs/cgroup/
    cgroup2fs

    若 CRI 使用 Containerd,需要 [配置启用 CRI 以及配置其使用 cgroup v2 版本](/202212011355/#Containerd-常用配置)。

关闭 SELinux

kubernetes 目前未实现对 SELinux 的支持,因此必须要关闭 SELinux

sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

集群中所有计算机之间具有完全的网络连接

配置集群所有节点的防火墙,确保所有集群节点之间具有完全的网络连接。

  • 放通节点之间的通信
  • 确保防火墙允许 FORWARD 链的流量
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [4:368]

-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT

# kubernetes nodes
-A INPUT -m comment --comment "kubernetes nodes" -s 172.31.5.58 -j ACCEPT
-A INPUT -m comment --comment "kubernetes nodes" -s 172.31.5.68 -j ACCEPT
-A INPUT -m comment --comment "kubernetes nodes" -s 172.31.0.230 -j ACCEPT

-A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT -m comment --comment "k8s ingress http,https"


...

-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
COMMIT
阅读全文 »

Pixie 是一款专为 Kubernetes 设计的 开源全栈可观测性工具 。它最大的特色是利用 eBPF(extended Berkeley Packet Filter)技术,在不修改业务代码、不重启 Pod、不注入 Sidecar 的情况下,自动采集集群内的所有监控数据。Pixie 被称为 K8s 的分布式调试器

Pixie 的核心优势

  • 无侵入性 (Auto-telemetry) : 部署后,自动获取 HTTP/gRPC 请求、SQL 查询、系统调用和火焰图。

  • 边缘计算架构 : 数据存储在集群节点的内存中,查询时才进行分布式计算。这意味着:

  • 极速 : 查询结果近乎实时。

  • 省钱 : 不会有海量日志传输到云端产生的高额带宽和存储费。

  • 动态可编程 : 使用 PxL(基于 Python 的查询语言)编写脚本,可以像写脚本一样实时分析系统性能。

Pixie 核心组件

  • Vizier : 运行在 K8s 集群中的控制器,负责管理各个节点的边缘收集器。

  • PEM (Pixie Edge Module) : 以 DaemonSet 形式运行在每个节点,利用 eBPF 采集数据并存储在本地内存。

  • Cloud Add-on : 提供用户界面 (UI) 和 API 访问。

快速安装
Pixie 的安装非常简单,通常通过 CLI 完成。

确保 Linux 内核版本在 4.16+(推荐 5.10+,2026 年的主流系统如 Ubuntu 22.04+、AlmaLinux 9 等都完美支持)。如果在过旧的内核上强行运行 eBPF 程序,极少数情况下可能导致内核态的不稳定。

  1. 下载 Pixie CLI

    bash -c "$(curl -fsSL https://withpixie.ai/install.sh)"

    脚本会从 Pixie 的官方 GitHub Release 页面或 CDN 下载最新版本的 px 命令行工具,并将其安装到 /usr/local/bin 目录。
    px 是你后续与 Kubernetes 集群交互的唯一入口,所有的部署(deploy)、查询(collect)和脚本运行都通过它完成。
    它会检查你本地的 ~/.kube/config 文件,确保你当前有权限连接到一个 Kubernetes 集群。
    当你执行完这个脚本后,Pixie 还没有安装到你的 Kubernetes 集群里。它只是在你的跳板机或开发机上装好了“遥控器”。要真正让 Pixie 开始监控集群,你通常需要继续执行 px deploy 命令。

  2. 部署到 K8s 集群。这将自动安装 Vizier 和 PEM 到集群中

    px deploy

    这个命令会将 Vizier 和 PEM 部署到你的 Kubernetes 集群中。

安装

安装步骤

安装完成之后使用 gitlab-ctl reconfigure 启动服务
访问页面,默认使用 root 登录
每次重新更改配置,都需要使用 reconfigure 重新启动

使用 Docker Compose 部署

参考配置如下:

docker-compose.yml
services:
web:
image: 'gitlab/gitlab-ce:latest'
restart: always
hostname: 'gitlab.example.com:8090'
environment:
GITLAB_OMNIBUS_CONFIG: |
# 这里的域名/IP 决定了 Git 克隆地址
external_url 'http://gitlab.example.com:8090'
nginx['listen_port'] = 8090
puma['port'] = 8001
gitlab_rails['gitlab_shell_ssh_port'] = 22222
prometheus_monitoring['enable'] = false
# --- 内存优化配置开始 ---
# 1. 限制 Puma Worker 数量。每个 Worker 至少占 1GB+ 内存。核心数+1 是默认值,私有环境建议设为 2,最少设为 2。
puma['worker_processes'] = 2
# 2. 限制单 Worker 内存占用,超过则自动重启。
puma['per_worker_max_memory_mb'] = 1024

# 3. 减少后台任务并发数。
sidekiq['concurrency'] = 10
# 4. 彻底关闭不必要的内置监控组件以节省内存(如果你已经有外置 Prometheus)。
alertmanager['enable'] = false
node_exporter['enable'] = false
redis_exporter['enable'] = false
postgres_exporter['enable'] = false
gitlab_exporter['enable'] = false
# --- 内存优化配置结束 ---
ports:
- '8090:8090'
- '443:443'
- '22222:22'
volumes:
- './config:/etc/gitlab' # 需要创建持久化目录 ./config、./logs、./data
- './logs:/var/log/gitlab'
- './data:/var/opt/gitlab'
shm_size: '256m'
# --- 增加 Docker 容器级别的硬限制 ---
deploy:
resources:
limits:
memory: 8G # 强制限制容器总内存为 8GB

阅读全文 »

Kasm Workspaces 是在浏览器里运行完整应用/桌面/浏览器的 云工作空间平台

你会看到:

  • 浏览器里再打开一个 Chrome / Linux 桌面
  • 像用本地电脑一样操作
  • 所有计算都在服务器

Kasm 的核心能力

  • 浏览器里跑浏览器(最常用 Chrome / Chromium / Firefox)、OS 桌面(Ubuntu / XFCE、Kali Linux 等)、应用(GUI 软件、Terminal 等)
  • 多用户(账号)登录且完全隔离(每个用户一个容器)
  • 支持自动销毁
  • WebRTC 显示协议提供低延迟画面流

Docker Compose 部署步骤

docker-compose.yaml
services:
kasm:
image: lscr.io/linuxserver/kasm:latest
container_name: kasm
privileged: true
environment:
- KASM_PORT=443
volumes:
- ./data:/opt
- ./profiles:/profiles
ports:
- 3000:3000
- 443:443
restart: unless-stopped

启动后,首先使用 https://<IP>:3000 进行初始化,初始化时需要设置管理员账号密码信息。初始化成功后,通过 https://<IP>:443 连接 Workspaces。

Kasm 强依赖 Docker,目前还无法在 Kubernetes 环境中部署。

在初始化页面(Install Wizard https://<IP>:3000 )中,确保 Kasm 的所有组件都处于 healthy 状态,表示 Kasm 已能正常提供服务

常用配置

在 Workspaces 中使用中文输入法

默认大多数的 Workspace 容器启动时都是没有中文输入的。如果要提供中文输入,可以使用系统提供的 IME Input Mode 。它可以将本地电脑的输入映射到 Kasm Workspaces 中。只需在对应的 Workspace 中开启 IME 配置即可。

  1. 使用管理员登录 Kasm。定位到 Workspaces ,编辑对应的 Workspace(如 Kali Linux),找到 Docker Run Configuration Override (JSON)

    填入以下内容(如果有其他内容,插入以下内容),开启 IME

    {
    "environment": {
    "KASM_IME": "1"
    }
    }

  2. 销毁之前的 Workspace Session,运行新的 Workspace Session,打开左侧的配置菜单,找到 Advanced Settings ,将 IME Input Mode 配置为 On

    即可在 Workspace 中使用中文

用户数据持久化方案

在 Kasm 中,实现 Workspace 用户数据(如 Chrome 书签、桌面配置、文档等)持久化的标准方案是使用 Persistent Profiles(持久化配置层)

核心原理

Kasm 会将容器内的用户目录(通常是 /home/kasm )映射到宿主机的特定路径(即 docker-compose.yaml 中定义的 /profiles 目录)。当用户结束会话时,Kasm 会将该目录打包;下次启动时,再自动解压回容器。

开启 Persistent Profiles

  1. 确认宿主机存储路径,在 docker-compose.yaml 中,已经配置了持久化卷 /opt/kasm-workspaces/profiles:/profiles ,这表示所有持久化数据将保存在宿主机的 /opt/kasm-workspaces/profiles 目录下。
  2. 在 Kasm 管理后台开启功能(Web UI 操作)
    1. 登录管理后台 :使用 [email protected] (管理员账户)登录。
    2. 导航到 Settings -> Storage Providers ,点击 Add Storage Provider 添加存储,本示例使用本地存储(Local)
      • Name : local-storage
      • Provider Type : 保持为 Custom
      • Default Target : /profiles
      • Volume Configuration (JSON):
        {
        "driver": "local",
        "driver_opts": {
        "o": "bind",
        "type": "none",
        "device": "/profiles"
        }
        }
      • Mount Configuration (JSON) : 保持默认或确保它是空的 JSON 对象
  3. 点击左侧菜单 Workspaces -> Workspaces 。找到 Chrome 或 Ubuntu ,点击 Edit
  4. 导航到 Storage Mapping 页面,Add Storage Mapping ,选择之前创建的 local-storage 并添加
  5. Details 页面中,下翻页面找到 Persistent Profile Path ,在其中填入 /profiles/{user_id} ,启用 Enforce Workspace Persistent Profile

    Kasm 会自动将 {user_id} 替换为登录用户的 ID(例如 admin )。这样即便有多个用户,他们的数据也会分开放,互不干扰。

  6. 删除并开启新的 Session,如 Chrome 浏览器,在其中保存书签,删除 Session,重新启动 Session,看看之前保存的书签是否存在。或者检查宿主机的目录 /opt/kasm-workspaces/profiles/ 中是否有文件存在。配置了 Persistent Profile 后,在 Kasm Workspaces 中启动 Session 也会显示已经启用了 Persistent Profile

用户自定义配置

用户登录 Kasm 后,可以导航到 Profiles 进行自定义配置:

  • 对个人信息进行修改
  • 配置登录后默认打开 Workspace(Auto Launch Session)
  • Kasm UI Language
  • Kasm Session Timezone
  • 配置 Two Factor

以下示例在 1 Mster + 2 Worker 的 Kubernetes 集群上快速部署使用 MinIO 存储

values.yaml
mode: distributed

replicas: 4
drivesPerNode: 1

rootUser: admin
rootPassword: gLsSbu7dv4zXSjYUeQrVOFq6

persistence:
enabled: true
size: 200Gi
storageClass: "" # 用默认的 StorageClass,要确保已存在

resources:
requests:
memory: 512Mi
cpu: 500m

# 🔥 关键:强制分散调度
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: minio
topologyKey: kubernetes.io/hostname

# 🔥 防止驱逐
tolerations: []

# 🔥 确保分布
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: minio

# 👇 新增 ingress(API + Console 分开)
ingress:
enabled: true
ingressClassName: nginx
hosts:
- minio-api.example.click


新增以下 Ingress 配置用于提供 Console 访问

console-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minio-console
namespace: minio
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
spec:
ingressClassName: nginx
rules:
- host: minio.example.click
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: minio-console
port:
number: 9001

执行以下命令部署 MinIO

helm upgrade minio minio/minio   -n minio   -f values.yaml

kubectl apply -f console-ingress.yaml

部署成功后通过 minio.example.click 登录 Console,管理员用户密码为 values.yaml 中配置的账户密码。

nacos 使用 NFS 持久化安装部署

部署 NFS

在 NFS Server 上执行以下命令:

sudo apt update 
sudo apt install nfs-kernel-server -y

创建用于存放 Nacos 数据的目录

sudo mkdir -p /data/nfs/nacos 

调整权限,生产环境建议更精细的权限控制

sudo chown nobody:nogroup /data/nfs/nacos 
sudo chmod 777 /data/nfs/nacos

配置 NFS 服务

sudo nano /etc/exports

/data/nfs/nacos 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)

启动服务:

sudo exportfs -a 
sudo systemctl restart nfs-kernel-server

在 Kubernetes 中配置 NFS 客户端

为了让 K8S 节点能挂载 NFS,所有 Worker 节点都必须安装客户端工具:

sudo apt install nfs-common -y

部署 NFS 动态存储类 (StorageClass)

手动创建 PV 非常麻烦,在 K8S 中我们通常使用 nfs-subdir-external-provisioner 来实现自动创建 PV。

使用 Helm 快速部署 (推荐)

这是目前最简单、最标准的方式,添加仓库

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/ 

安装 nfs-provisioner 作为 存储 Provisioner

helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=192.168.1.100 \
--set nfs.path=/data/nfs/nacos \
--set storageClass.name=nfs-storage \
--set storageClass.defaultClass=true

kubectl get sc 验证 StorageClass

Nacos 关联 NFS 存储

现在可以在 Nacos 的部署配置中使用这个 nfs-storage 的 StorageClass 了。参考以下资源清单部署单节点的 Nacos 完整服务,包括 Nginx Ingress 以及鉴权

nacos-single-node.yaml
apiVersion: v1
kind: Namespace
metadata:
name: nacos
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nacos-pvc
namespace: nacos
spec:
accessModes:
- ReadWriteMany # ⚠️ NFS 必须用这个
storageClassName: nfs-storage
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nacos
namespace: nacos
spec:
replicas: 1
selector:
matchLabels:
app: nacos
template:
metadata:
labels:
app: nacos
spec:
containers:
- name: nacos
image: nacos/nacos-server:v2.2.3
ports:
- containerPort: 8848
env:
- name: MODE
value: "standalone"
- name: NACOS_AUTH_ENABLE
value: "true"
- name: NACOS_AUTH_TOKEN
value: "XDoArVHBA1o8DDsyBchWLGXNfWYibjvEOa7qfroNmZ4="
- name: NACOS_AUTH_IDENTITY_KEY
value: "admin"
- name: NACOS_AUTH_IDENTITY_VALUE
value: "admin"
- name: JVM_XMS
value: "512m"
- name: JVM_XMX
value: "512m"
volumeMounts:
- name: nacos-storage
mountPath: /home/nacos/data
- name: nacos-storage
mountPath: /home/nacos/logs
volumes:
- name: nacos-storage
persistentVolumeClaim:
claimName: nacos-pvc
---
apiVersion: v1
kind: Service
metadata:
name: nacos
namespace: nacos
spec:
selector:
app: nacos
ports:
- name: http
port: 8848
targetPort: 8848
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nacos
namespace: nacos
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/whitelist-source-range: "54.251.236.229/24,206.119.115.76/24"
spec:
ingressClassName: nginx
rules:
- host: nacos.example.click
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nacos
port:
number: 8848

部署完成后通过 nacos.example.click 登录后台,初始默认密码为 nacos/nacos

nacos 使用 Mysql 持久化安装部署

要使用 Mysql 存储数据,只需修改资源清单为以下内容即可:

apiVersion: v1
kind: Namespace
metadata:
name: nacos
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nacos-pvc
namespace: nacos
spec:
accessModes:
- ReadWriteMany # ⚠️ NFS 必须用这个
storageClassName: nfs-storage
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nacos
namespace: nacos
spec:
replicas: 1
selector:
matchLabels:
app: nacos
template:
metadata:
labels:
app: nacos
spec:
containers:
- name: nacos
image: nacos/nacos-server:v2.2.3
ports:
- containerPort: 8848
env:
- name: MODE
value: "standalone"

- name: SPRING_DATASOURCE_PLATFORM
value: "mysql"

- name: MYSQL_SERVICE_HOST
value: "<MYSQL_SERVICE_HOST>"
- name: MYSQL_SERVICE_PORT
value: "3306"
- name: MYSQL_SERVICE_DB_NAME
value: "<MYSQL_SERVICE_DB_NAME>"
- name: MYSQL_SERVICE_USER
value: "<MYSQL_SERVICE_USER>"
- name: MYSQL_SERVICE_PASSWORD
value: "<MYSQL_SERVICE_PASSWORD>"

- name: MYSQL_SERVICE_DB_PARAM
value: "characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true"

- name: NACOS_AUTH_ENABLE
value: "true"
- name: NACOS_AUTH_TOKEN
value: "XDoArVHBA1o8DDsyBchWLGXNfWYibjvEOa7qfroNmZ4="
- name: NACOS_AUTH_IDENTITY_KEY
value: "admin"
- name: NACOS_AUTH_IDENTITY_VALUE
value: "admin"
- name: JVM_XMS
value: "512m"
- name: JVM_XMX
value: "512m"

volumeMounts:
- name: nacos-storage
mountPath: /home/nacos/data
- name: nacos-storage
mountPath: /home/nacos/logs
volumes:
- name: nacos-storage
persistentVolumeClaim:
claimName: nacos-pvc
---
apiVersion: v1
kind: Service
metadata:
name: nacos
namespace: nacos
spec:
selector:
app: nacos
ports:
- name: http
port: 8848
targetPort: 8848
- name: rpc
port: 9848
targetPort: 9848
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nacos
namespace: nacos
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
# nginx.ingress.kubernetes.io/whitelist-source-range: "54.251.236.2/24,206.119.115.7/24"
spec:
ingressClassName: nginx
rules:
- host: nacos.example.click
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nacos
port:
number: 8848

Docker 部署步骤

创建配置文件 config.json

config.json
{
"log": {
"loglevel": "debug", /* 为了观察运行情况或者定位问题,可以开启debug 日志 */
"access": "/dev/stdout",
"error": "/dev/stdout"
},
"inbounds": [{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "c4187394-5865-446d-9d8d-3f6c179416b0(UID 替换为实际值)",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"dest": "www.microsoft.com:443",
"xver": 0,
"serverNames": ["www.microsoft.com"],
"privateKey": "mD0OUR8tFvOypHQre6yGgsZs2w-JecH4zkXB9_TY-k8(私钥)",
"shortIds": ["a1b2c3d4"]
}
}
}],
"outbounds": [{"protocol": "freedom"}]
}

  • "id": "c4187394-5865-446d-9d8d-3f6c179416b0(UID 替换为实际值)" 可以自行生成

  • "dest": "www.microsoft.com:443" 伪装的网站地址

  • "privateKey": "mD0OUR8tFvOypHQre6yGgsZs2w-JecH4zkXB9_TY-k8(私钥)" 私钥,公司钥对可以使用如下命令生成

    # docker run --rm teddysun/xray xray x25519
    PrivateKey: iBKDmvNMfFOAzNPOLRlnJLzoaYbHKs9RFatpW1ELeks
    Password: OV_SMIonfy1cEzxnDGZff9x0HeuhuqLyrIj0dLqAaHw
    Hash32: 1fEp1041YBnLfSvQYVsRfvGJEA8ZV_LjqFGtQKwaWG0

    • PrivateKey 对应私钥( privateKey
    • Password 对应公钥( Public Key ),要发送给客户端使用

docker-compose.yaml 配置如下:

services:
xray:
image: teddysun/xray:latest
container_name: xray
restart: always
network_mode: "host" # 使用 host 模式性能更佳,且直接映射 443 端口
volumes:
- ./config/config.json:/etc/xray/config.json
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

正常启动后,在客户端如下配置:

  • 类型: VLESS

  • 地址(Address): <SERVER IP>

  • 端口(Port): 443 # 对应配置文件中的 inbounds.port

  • UUID: <UID> # 对应配置文件中的 inbounds.settings.clients.id

  • 流(Flow): xtls-rprx-vision # 对应配置文件中的 inbounds.settings.clients.flow

  • 传输协议(Transport protocol(network)): TCP # 对应配置文件中的 inbounds.streamSettings.network

  • TLS/安全: Reality # 对应配置文件中的 inbounds.streamSettings.security

  • 加密(Encryption): none # 对应配置文件中的 inbounds.settings.decryption

  • SNI: www.microsoft.com # 对应配置文件中的 inbounds.streamSettings.realitySettings.dest

  • 短 ID(Short ID): a1b2c3d4 # 对应配置文件中的 inbounds.streamSettings.realitySettings.shortIds

  • 公钥(Public key、密码、Password): <公钥> # docker run --rm teddysun/xray xray x25519 命令生成的 Password

为了方便客户端导入,可以为配置生成以下链接,其中包含了客户端链接所需的参数:

vless://<UID>@<SERVER IP>:<Port>?encryption=none&flow=xtls-rprx-vision&security=reality&sni=www.microsoft.com&fp=chrome&pbk=<Public Key or Password>&sid=a1b2c3d4#Shanghai_MS_Reality

大多数客户端都支持从粘贴板复制以上内容自动导入配置。

Windows 中使用 v2rayN 连接 xray server

  • v2rayN 版本: v7.18.0

Windows 下载 v2rayN ,将其解压后,运行程序 v2rayN.exe 即可打开程序。复制配置链接( vless://<UID>@<SERVER IP>:<Port>?encryption=none&flow=xtls-rprx-vision&security=reality&sni=www.microsoft.com&fp=chrome&pbk=<Public Key or Password>&sid=a1b2c3d4#Shanghai_MS_Reality ),在 v2rayN 主界面点击 Configuration -> Import Share Links from clipboard 即可自动导入配置

默认情况下, v2rayN 会测试到 google.com 的连接来验证服务端是否正常,国内服务器此测试必定失败,因此可以修改此测试目标。参考以下步骤:

  1. 导航到 Settings -> v2rayN settings: Speed Ping Test URL ,此处默认值为 google.com ,将其改为国内服务器可以访问的地址如 https://www.baidu.com

要验证 xray server 工作正常,可以在 v2rayN 客户端进行 延迟检测(Test real delay) 。右键要检测的 xray server 选择 Test real delay

如果能够获取到延迟数据,说明 xray 工作正常,如果未获取到延迟数据,可以登陆服务器,通过命令 docker logs 检查服务端日志

Prometnehs 告警规则如下:

- alert: HostTCPRetransmitsHigh
expr: increase(node_netstat_Tcp_RetransSegs[5m]) > 20000

Prometheus 监控数据显示: retrans=21736/5m

检查系统上的 网络内核协议栈状态 ,使用工具 nstat ,它能显示网络栈的统计信息,还能通过差值计数快速定位当前发生的异常。默认显示自系统启动以来的所有统计项。

# nstat
#kernel
IpInReceives 741632185 0.0
IpInHdrErrors 1454 0.0
IpInAddrErrors 24848 0.0
IpForwDatagrams 6281793 0.0
IpInUnknownProtos 173793 0.0
IpInDelivers 585081400 0.0
IpOutRequests 633335747 0.0
IpOutDiscards 39 0.0
IpOutNoRoutes 6912 0.0
IpReasmTimeout 104832 0.0
IpReasmReqds 40046807 0.0
IpReasmOKs 19711639 0.0
IpReasmFails 268659 0.0
IpFragOKs 2920 0.0
IpFragCreates 5840 0.0
IcmpInMsgs 28451709 0.0
IcmpInErrors 50710 0.0
IcmpInCsumErrors 4 0.0
IcmpInDestUnreachs 116906 0.0
IcmpInTimeExcds 12355 0.0
IcmpInRedirects 1137 0.0
IcmpInEchos 28320718 0.0
IcmpInEchoReps 47 0.0
IcmpInTimestamps 542 0.0
IcmpOutMsgs 34766477 0.0
IcmpOutDestUnreachs 6455420 0.0
IcmpOutTimeExcds 22793 0.0
IcmpOutRedirects 32 0.0
IcmpOutEchos 16 0.0
...

使用 bpftrace 跟踪重传发生的端口统计数据

# bpftrace -e '
tracepoint:tcp:tcp_retransmit_skb
{
@[args->sport, args->dport] = count();
}'

Attaching 1 probe...


^C

@[10050, 43344]: 4
@[22, 6890]: 5
@[22, 33828]: 5
@[22, 16254]: 5
@[22, 32874]: 5
@[22, 59454]: 6
@[22, 50852]: 6
@[22, 56096]: 7
@[9100, 51150]: 10
@[443, 49917]: 21
@[443, 50447]: 21

使用 bpftrace 实时跟踪指定端口的重传数据

# bpftrace -e '
tracepoint:tcp:tcp_retransmit_skb
/args->sport == 80 || args->sport == 443 || args->sport == 22/
{
printf("%d -> %d retrans\n", args->sport, args->dport);
}'
Attaching 1 probe...
22 -> 44184 retrans
22 -> 45636 retrans
22 -> 49526 retrans
22 -> 46220 retrans
22 -> 50296 retrans
22 -> 45636 retrans
22 -> 45636 retrans
22 -> 45636 retrans
22 -> 35922 retrans
22 -> 44184 retrans
22 -> 49526 retrans
22 -> 45636 retrans
22 -> 45256 retrans
22 -> 45256 retrans
22 -> 45256 retrans
22 -> 46886 retrans
22 -> 45256 retrans
443 -> 42035 retrans
443 -> 42035 retrans
443 -> 12169 retrans
443 -> 42035 retrans
443 -> 42035 retrans
443 -> 12169 retrans
443 -> 12169 retrans
443 -> 42035 retrans

BPF(Berkeley Packet Filter) 是由 Berkeley 学院于 1992 年开发的一款,主要用于提高抓包工具的性能。并于 2014 年被重写进 Linux 内核中,可以用于 内核观测、网络诊断、性能观测、安全、Kubernetes 网络治理等方面[1]

BPF 是一种灵活且高效的技术实现,主要由 指令集(Instruction Set)存储对象(Storage Objects maps)帮助函数(Helper Functions) 构成。因为其 虚拟指令集规范(Virtual Instruction Set Specification) ,可以认为 BPF 是一个虚拟机,BPF 运行于 内核模式(Kernel Mode) 。BPF 基于事件(Events)运行: Socket EventsTracepointsUSDT Probeskprobesuprobesperf_events.

eBPF 允许

在运行中的内核里插入自己的逻辑

比如:

  • 捕获 TCP 连接
  • 统计进程系统调用
  • 跟踪磁盘 IO
  • 分析网络延迟
  • 拦截数据包

而且:

无需修改内核源码,只在内核事件点插入逻辑,无需重启系统,是 Linux 内核的动态扩展机制

这是 eBPF 最核心的价值。

eBPF 基础原理

eBPF 本质 运行在 Linux 内核中的事件驱动程序 。关键点:

  • 运行在 内核空间(Kernel Space)
  • 事件驱动(Event),不会一直运行,只有在 某个事件(Event)发生时,才会运行

eBPF = Hook + Event + Action

eBPF 的完整执行流程

eBPF 的执行流程分六步

  1. 编写 eBPF 程序 。例如 把程序挂到 tcp_connect 函数上

    SEC("kprobe/tcp_connect")
    int trace_tcp() {
    return 0;
    }
  2. 编译为 BPF Bytecode(eBPF 虚拟机字节码) 。eBPF 运行的不是机器码,而是 BPF 字节码

    clang -> BPF bytecode
  3. 加载到内核 。用户态程序通过 bpf() 系统调用,把字节码加载进内核。

  4. Verifier 验证程序安全 ,这是 eBPF 最重要的机制,用户把程序加载到内核,是极其危险的,它会检查

    • 是否有非法内存访问
    • 是否有无限循环
    • 是否可能访问非法指针
    • 其他危险操作
  5. Attach:把程序挂到事件点 。程序通过 verifier 后,要挂到某个 Hook 点 (Event),比如

    • kprobe:tcp_connect ,每次调用 tcp_connect ,就执行 eBPF 程序
    • tracepoint:sys_enter_execve,每次进程执行时触发
    • XDP ,挂到网卡驱动层

      本质是: Attach = 指定“什么时候执行 eBPF” 。这是 eBPF 的事件驱动核心。

  6. 事件发生时,程序运行

Map

Map 是内核(Kernel)与用户态(User Space)之间的通信机制 。eBPF 程序运行在内核,但它不能直接:

  • print 到终端
  • 写文件

所以必须通过 BPF Map 与用户态交换数据。其本质是内核中的 Key-Value 存储。eBPF 程序更新 Map,用户态读取 Map。 Map 是用户态和内核态共享数据桥梁

Hook 点

Hook 点是在内核执行路径中插入的一个触发点或者说在内核某个位置插入 eBPF 程序 。正常内核流程:

事件发生 -> 内核函数执行

加上 eBPF 后:

事件发生 -> Hook 点 -> eBPF 程序执行 -> 原逻辑继续

不同 Hook 点,看到的数据不同,性能不同,用途不同

  • Hook 在系统调用入口,可以观察 哪个进程调用了 open()execve() 等函数,适合 进程行为观测
  • Hook 在网络包入口,可以观察: 收到哪个数据包、包头是什么,适合 网络过滤 / DDoS 防护
  • Hook 在用户程序函数,可以观察:应用函数调用、函数耗时,适合 应用性能分析

所以: Hook 点 = eBPF 能看到什么、能做什么

eBPF 最重要的五类 Hook 点

  1. kprobe ,挂到内核函数,把 eBPF 程序挂到任意的某个内核函数入口,比如 tcp_connect 。因为挂在函数入口,所以常用于:
    • 获取函数参数,比如 tcp_connect(sock, addr) 拿到: socket 信息、目标地址
    • 统计调用次数
    • 统计执行耗时

      kprobe 用于跟踪内核函数行为 。优点是非常灵活,能挂任意内核函数;缺点是依赖内核函数名,不稳定(不同内核版本可能变),内核升级可能导致 kprobe 失效

  2. tracepoint ,挂到内核预定义的稳定事件点。 因为 tracepoint 是 Linux 官方定义接口,相比 kprobe 不会轻易变,跨内核版本更稳定
  3. uprobes ,把 eBPF 程序挂到用户态程序函数,如 Nginx、Mysql 等。主要用于 应用程序性能分析
  4. XDP ,挂到网卡驱动(收包入口)层。XDP 在最早的网络入口处理包,是 Linux 网络性能天花板,Cilium 就是基于 XDP 实现。
  5. TC ,Linux 流量控制(Traffic Control)层。XDP 是网卡驱动层,性能更高。TC 是 Linux 内核网络层,功能更多,更适合复杂网络策略。

bpftrace

bpftrace 是一个基于 BPF 的追踪工具(Trace Tools),提供了高级别的编程能力,同时包含了命令行和脚本使用方式

bpftrace 命令行

bpftrace 命令详细帮助文档请查看 man bpftrace,下表列出常用选项和参数

选项 说明 示例
-l [SEARCH] 列出匹配的事件(Event/Probe),没有 SEARCH 表达式则列出所有的 Event。SEARCH 支持通配符
-e 'program' 跟踪脚本

筛选指定的事件

# bpftrace -l "tracepoint:*exec*"
tracepoint:libata:ata_exec_command
tracepoint:sched:sched_kthread_work_execute_end
tracepoint:sched:sched_kthread_work_execute_start
tracepoint:sched:sched_process_exec
tracepoint:syscalls:sys_enter_execve
tracepoint:syscalls:sys_enter_execveat
tracepoint:syscalls:sys_enter_kexec_file_load
tracepoint:syscalls:sys_enter_kexec_load
tracepoint:syscalls:sys_exit_execve
tracepoint:syscalls:sys_exit_execveat
tracepoint:syscalls:sys_exit_kexec_file_load
tracepoint:syscalls:sys_exit_kexec_load
tracepoint:workqueue:workqueue_execute_end
tracepoint:workqueue:workqueue_execute_start
tracepoint:writeback:writeback_exec

跟踪新启动的进程

执行以下命令,可以追踪系统中新启动的进程及其参数

# bpftrace -e 'tracepoint:syscalls:sys_enter_execve { join(args->argv); }'
Attaching 1 probe...
/home/oneuser/cwrsync_6.2.4_x64_free/data/ops/rsync2Server.sh
/usr/bin/rsync --progress -a -c -u --timeout=300 -z --password-file /home/oneuser/cwrsync_6.2.4_x64_free/rsync.client.pswd --exclude .idea --exclude rsync2Server.sh /home/oneuser/cwrsync_6.2.4_x64_free/data/ops/ [email protected]::backup
/home/oneuser/cwrsync_6.2.4_x64_free/data/ops/rsync2Server.sh
/usr/bin/rsync --progress -a -c -u --timeout=300 -z --password-file /home/oneuser/cwrsync_6.2.4_x64_free/rsync.client.pswd --exclude .idea --exclude rsync2Server.sh /home/oneuser/cwrsync_6.2.4_x64_free/data/ops/ [email protected]::backup
runc --root /var/run/docker/runtime-runc/moby --log /run/containerd/io.containerd.runtime.v2.task/moby/53daccf2e93fcf83831ce6773a495361afe9bb9694881269d1902f399f5c621c/log.json --log-format json --systemd-cgroup exec --process /tmp/runc-process3178774999 --detach --pid-file /run/containerd/io.containerd.runtime.v2.task/moby/53daccf2e93fcf83831ce6773a495361afe9bb9694881269d1902f399f5c621c/c73d8d4d46ac3995bdc1d7648a3562ddb4715a549a509f6125a7cfc4e88abe50.pid 53daccf2e93fcf83831ce6773a495361afe9bb9694881269d1902f399f5c621c
runc init
/watchtower --health-check
/home/oneuser/cwrsync_6.2.4_x64_free/data/ops/rsync2Server.sh
/usr/bin/rsync --progress -a -c -u --timeout=300 -z --password-file /home/oneuser/cwrsync_6.2.4_x64_free/rsync.client.pswd --exclude .idea --exclude rsync2Server.sh /home/oneuser/cwrsync_6.2.4_x64_free/data/ops/ [email protected]::backup
/usr/lib/x86_64-linux-gnu/dcv/dcvpamhelper --stdout -s dcv
/usr/libexec/sssd/krb5_child --debug-microseconds=0 --debug-timestamps=1 --debug-fd=28 --debug-level=0x0070 --chain-id=7187 --sss-creds-password --canonicalize --realm=OPSDEV666.COM --fast-ccache-gid=0 --fast-ccache-uid=0
/home/oneuser/cwrsync_6.2.4_x64_free/data/ops/rsync2Server.sh
/usr/bin/rsync --progress -a -c -u --timeout=300 -z --password-file /home/oneuser/cwrsync_6.2.4_x64_free/rsync.client.pswd --exclude .idea --exclude rsync2Server.sh /home/oneuser/cwrsync_6.2.4_x64_free/data/ops/ [email protected]::backup

参考链接

Systems Performance: Enterprise and the Cloud v2

脚注

服务器配置如下(32CPU 32G RAM, 无 GPU):

# lscpu  | grep NUMA
NUMA node(s): 2
NUMA node0 CPU(s): 0-7,16-23
NUMA node1 CPU(s): 8-15,24-31

# free -h
total used free shared buff/cache available
Mem: 31Gi 10Gi 583Mi 145Mi 19Gi 19Gi
Swap: 0B 0B 0B

# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.5 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

root@vp-jmpsvr:~# uname -a
Linux vp-jmpsvr 5.15.0-119-generic #129-Ubuntu SMP Fri Aug 2 19:25:20 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

模型推荐清单 (纯 CPU 环境)

模型名称 推荐版本 理由 内存占用 速度预期
DeepSeek-V3 / R1 (Distill) deepseek-r1:7b 或 14b 目前最强的推理模型,逻辑能力极佳。 ~5GB / 9GB, 极快 / 流畅
Llama 3.1 llama3.1:8b 综合素质平衡,适合通用的英文/开发任务。 ~5.5GB 极快
Qwen 2.5 (通义千问) qwen2.5:7b 或 14b 中文语境支持最好,适合文档处理、后端开发辅助。 ~5GB / 9GB 极快 / 流畅
Command R command-r:35b 内存极限挑战。适合需要长上下文(RAG)的任务。 ~20GB 较慢

安装 Ollama

curl -fsSL https://ollama.com/install.sh | sh

查看 Ollama Service 状态

# systemctl status ollama --no-pager
● ollama.service - Ollama Service
Loaded: loaded (/etc/systemd/system/ollama.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2026-04-28 16:53:27 CST; 3min 46s ago
Main PID: 3683510 (ollama)
Tasks: 15 (limit: 38371)
Memory: 28.1M
CPU: 251ms
CGroup: /system.slice/ollama.service
└─3683510 /usr/local/bin/ollama serve


运行推荐模型 (以 DeepSeek R1 7B 为例)

ollama run deepseek-r1:7b

(Optional)部署 Open WebUI(原 Ollama WebUI) ,它支持 Docker 部署

services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
restart: always
network_mode: host
environment:
# 关键点:访问宿主机的 Ollama
- OLLAMA_BASE_URL=http://127.0.0.1:11434
# 可选:设置 WebUI 的语言
- WEBUI_NAME=My AI Server
# UI 监听端口
- PORT=9000

volumes:
- ./open-webui:/app/data

ansible server rules

# rules
每次运行任务之前,你都必须先读取此文件内容,并严格遵守:
1. 本机(ansible server)仅作为 Ansible 控制节点使用。
- 允许在本机执行只读操作:查看文件、查看 inventory、查看 playbook、查看日志、语法检查、版本检查。
- 禁止在本机执行任何业务变更操作,包括但不限于:安装/卸载软件、修改配置、启动/停止/重启服务、修改系统环境、删除文件。

2. 对远程主机,所有“变更类操作”都必须先得到我的明确确认后才能执行。
变更类操作包括但不限于:
- 安装、升级、卸载软件
- 修改配置文件
- 创建、删除、覆盖文件或目录
- 启动、停止、重启、重载服务
- 执行会改变系统状态的命令
- 变更 systemd、网络、防火墙、用户权限、计划任务、SSH 配置
- 执行 playbook 或 ad-hoc 命令造成远程状态变化

3. 对远程主机的只读检查操作,默认也需要先向我说明检查计划,再等待我确认;
除非我明确说“可以先检查后汇报”,否则不得自行执行。
只读检查包括但不限于:
- 查看系统版本、磁盘、内存、CPU、进程、端口、服务状态、日志、配置内容
- 执行不会修改系统状态的 Ansible ad-hoc 命令

4. 每次收到任务后,必须先给出 Plan,未经我确认不得执行。
Plan 至少包含:
- 任务目标
- 涉及的目标主机
- 需要执行的检查步骤
- 计划执行的 Ansible 命令、playbook 或 shell 命令
- 是否为只读操作或变更操作
- 风险点与影响范围

5. 在我确认前,你不得:
- 自行 SSH 登录远程主机执行命令
- 自行运行任何 Ansible playbook
- 自行运行任何会影响远程主机状态的 ad-hoc 命令
- 将一次确认扩展理解为对其他主机、其他命令或后续步骤的授权

6. 你的执行授权必须按“单次、明确、最小范围”理解。
每次执行前都必须明确说明:
- 目标主机
- 执行内容
- 执行方式
- 预期结果
未被明确确认的内容一律不得执行。

7. 涉及高风险操作时,必须单独再次确认。
高风险操作包括但不限于:
- 删除文件/目录
- 批量修改多台主机
- 重启主机
- 修改网络、防火墙、路由、SSH
- 修改数据库数据
- 覆盖证书、密钥、权限
- 停止生产服务

8. 优先使用安全方式:
- 能只读检查时,先只读检查
- 能使用 `--check` / `--diff` / `--syntax-check` 时,优先先展示结果再申请正式执行
- 不得跳过验证直接执行正式变更

9. 若执行失败、结果异常或存在不确定性:
- 立即停止后续操作
- 汇报实际执行内容、报错信息、影响范围
- 给出修复建议
- 未经我再次确认,不得继续尝试其他方案

10. 回复格式固定为:
- Plan
- 待确认的检查操作
- 待确认的变更操作
- 风险说明
- 等待我的确认

11. 未经我明确允许,不得使用 shell/command 直接在远程主机执行命令;
优先使用 Ansible 模块化方式执行,并说明原因。

12. 未经我明确允许,不得对超过 1 台主机同时执行变更;
批量操作必须逐台或分批确认。

# 当前任务
阅读全文 »

环境信息

  • Centos 7
  • ansible-core 2.16
  • Docker image python:3.12.3

安装

ansible-core 版本及 Python 版本支持对应关系

ansible-core Version Control Node Python Target Python / PowerShell
2.16 Python 3.10 - 3.12 Python 2.7
Python 3.6 - 3.12
Powershell 3 - 5.1

为了环境部署方便灵活,可以选择使用 python:3.12.3 的 Docker 镜像,以其为基础环境安装 ansible-core 2.16 或者直接使用 ansible 镜像启动。

# docker run --rm -it python:3.12.3 bash

# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

# python --version
Python 3.12.3

# pip install ansible

# pip list
Package Version
------------ -------
ansible 9.5.1
ansible-core 2.16.6
cffi 1.16.0
cryptography 42.0.7
Jinja2 3.1.4
MarkupSafe 2.1.5
packaging 24.0
pip 24.0
pycparser 2.22
PyYAML 6.0.1
resolvelib 1.0.1
setuptools 69.5.1
wheel 0.43.0

# ansible --version
ansible [core 2.16.6]
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.12/site-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.12.3 (main, May 14 2024, 07:23:41) [GCC 12.2.0] (/usr/local/bin/python)
jinja version = 3.1.4
libyaml = True

在服务器本地环境部署,如果想要灵活管理配置,也可以使用 pip3 命令安装 ansible

$ pip3 install ansible

$ ansible --version
ansible [core 2.15.13]
config file = None
configured module search path = ['/home/ops/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/ops/.local/lib/python3.9/site-packages/ansible
ansible collection location = /home/ops/.ansible/collections:/usr/share/ansible/collections
executable location = /home/ops/.local/bin/ansible
python version = 3.9.25 (main, Dec 10 2025, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-5)] (/usr/bin/python3)
jinja version = 3.1.6
libyaml = True

如此安装的 ansible 默认不加载任何配置文件,此时只需在 ~/.ansible/ 下手动创建 ansible.cfg 即可

~/.ansible/ansible.cfg
[defaults]
inventory = inventory

host_key_checking = False

forks = 20

timeout = 60

gathering = smart

[ssh_connection]


ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-control-%r-%h:%p

切换到 ~/.ansible/ 目录,再次查看 Ansible 加载的配置,其已经加载了 ~/.ansible/ansible.cfg

$ ansible --version
ansible [core 2.15.13]
config file = /home/ops/.ansible/ansible.cfg
configured module search path = ['/home/ops/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/ops/.local/lib/python3.9/site-packages/ansible
ansible collection location = /home/ops/.ansible/collections:/usr/share/ansible/collections
executable location = /home/ops/.local/bin/ansible
python version = 3.9.25 (main, Dec 10 2025, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-5)] (/usr/bin/python3)
jinja version = 3.1.6
libyaml = True

Ansible 配置说明

Ansible 主配置文件为 /etc/ansible/ansible.cfg其中的配置都可以被 ansible-playbook 或者命令行参数覆盖

ansible 默认会读取环境变量 ANSIBLE_CONFIG 指定的配置文件,当前路径下的 ansible.cfg,以及用户家目录下的 .ansible.cfg,以及 /etc/ansible/ansible.cfg 作为配置文件,已第一个找到的为准

常用配置说明

配置项 说明 示例
inventory 指定 inventory (主机列表)文件的路径,默认为 /etc/ansible/hosts
remote_user (未指定用户时)连接远程主机时使用的用户
remote_port 连接远程主机时使用的(默认)端口
host_key_checking 默认启用。检查主机密钥可以防止服务器欺骗和中间人攻击。
如果主机重新安装并且在 know_hosts 中拥有不同的密钥,ansible 会提示确认密钥。
如果要禁用此行为,可以配置为 False
ask_pass 默认为 False。当设置为 True 时,ansible 要求输入远端服务器的密码,即使配置了免密登录
log_path 日志文件,默认 /var/log/ansible.log
pattern 当没有给出 pattern 时的默认 pattern,默认值是 * 即所有主机

配置示例

/etc/ansible/ansible.cfg
[defaults]
# 设置默认的 inventory 文件路径
inventory = /etc/ansible/hosts

# 关闭主机密钥检查,方便新主机的快速添加
host_key_checking = False

# 设置默认的远程用户
remote_user = ansible

Inventory 配置说明

默认的 inventory 配置文件路径为 /etc/ansible/hosts,主要用来配置 Managed Hosts 列表 [3]

在命令行中,可以使用选项 -i <path> 指定不同的 inventory 或者可以在 ansible 配置文件 ansible.cfg 中使用指令 inventory 指定 inventory 文件位置。

命令行中可以使用 -i <path1> -i <path2> ... 指定多个 inventory

inventory 文件支持多种格式,最常见的是 INIYAML 格式。

  • Ansible 默认创建了 2 个组:
    • all : 包含所有主机
    • ungrouped : 包含所有不在其他组(all 除外)中的所有主机。

      任何一个主机都会至少在 2 个组中,要么 all 和某个组中,要么 allungrouped

  • 一个主机可以包含在多个组中
  • parent/childchild 组被包含在 parent 组中。
    • INI 配置格式中,使用 :children 后缀配置 parent
    • YAML 配置格式中,使用 children: 配置 parent
      • 任何在 child 组中的主机自动成为 parent 组中的一员
      • 一个组可以包括多个 parentchild 组,但是不能形成循环关系
      • 一个主机可以在多个组中,但是在运行时,只能有一个实例存在,Ansible 会自动将属于多个组的主机合并。
  • 主机范围匹配。如果有格式相似的主机,可以通过范围格式使用一条指令来添加多台主机。
    • INI 配置格式中,使用以下格式
      [webservers]
      www[01:50].example.com

      ## 指定步长增长
      www[01:50:2].example.com

      db-[a:f].example.com
    • YAML 配置格式中,使用以下格式
      # ...
      webservers:
      hosts:
      www[01:50].example.com:

      ## 指定步长增长
      www[01:50:2].example.com:
      db-[a:f].example.com:

      范围格式 的第一项和最后一项也包括在内。即匹配 www01www50

Inventory 多配置文件支持

在主机数量较多,或者组织结构较复杂的情况下,使用单个 Inventory 配置文件会导致主机管理较为复杂。将单个 Inventory 配置文件按照项目或者组织或其他规则进行分割会显著降低维护复杂度。

Inventory 多配置文件支持,可以使用以下方法之一

  • 按照项目或者组织或其他规则将主机分割到多个配置中,命令行中可以使用 -i <path1> -i <path2> ... 指定多个 inventory
  • 按照项目或者组织或其他规则将主机分割放置在多个文件中,并将所有文件统一放置在一个单独的目录中(如 /etc/ansible/inventory/),在命令行中使用选项 -i /etc/ansible/inventory/ 或者在 Ansible 配置文件(ansible.cfg)中使用指令 inventory 配置目录。

    注意事项: Ansible 使用字典顺序加载配置文件,如果在不同的配置文件中配置了 parent groupschild groups,那么定义 child groups 的配置要先用定义 parent groups 的文件加载,否则 Ansible 加载配置会报错: Unable to parse /path/to/source_of_parent_groups as an inventory source [4]

  • 使用 group_varshost_vars 目录分别存储组变量和主机变量 [7]

    注意事项: 组变量和主机变量必须使用 YAML 格式,合法的文件扩展名包括: .yamlyml.json 或者无文件扩展名

INI 格式的 Inventory

主机列表中的主机可以单独出现,也可以位于某个或者多个 组([] 开头的行)中

/etc/ansible/hosts
ansible-demo1.local
ansible-demo2.local

[webserver]
webserver1.local
webserver2.local

[nginxserver]
# 匹配多个主机:nginx1.local, nginx2.local, nginx3.local, nginx4.local
nginx[1:4].local variable1=value1 variable2=value2
nginx-bak.local ansible_ssh_host=10.10.0.1 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=PASSWORD
127.0.0.1 http_port=80 maxRequestPerChild=808


连接主机使用的常用配置说明 [6]

配置项 说明 示例
ansible_host 远程主机地址
ansible_port 远程主机端口
ansible_user 连接远程主机的 ssh 用户
Ansible 默认使用 control node 上执行 ansible 的用户名来连接远程主机 [9]
ansible_password 连接远程主机的 ssh 用户密码,建议使用 key 连接
ansible_ssh_private_key_file 连接远程主机的 ssh 私钥文件路径
ansible_become
ansible_sudo
ansible_su
用户权限提升
ansible_become_method 用户权限提升(escalation)的方式
ansible_become_user
ansible_sudo_user
ansible_su_user
用户权限提升(escalation)后的用户
ansible_become_password
ansible_sudo_password
ansible_su_password
sudo 密码(这种方式并不安全,强烈建议使用 --ask-sudo-pass)
ansible_become_exe
ansible_sudo_exe
ansible_su_exe
设置用户权限提升(escalation)后的可执行文件
ansible_connection 与主机的连接类型.比如:local, ssh 或者 paramiko
Ansible 1.2 以前默认使用 paramiko。1.2 以后默认使用 smart,smart 方式会根据是否支持 ControlPersist, 来判断 ssh 方式是否可行.
ansible_shell_type 目标系统的 shell 类型.默认情况下,命令的执行使用 sh 语法,可设置为 cshfish.
ansible_python_interpreter 目标主机的 python 路径
系统中有多个 Python, 或者命令路径不是 /usr/bin/python
阅读全文 »