diff --git a/technical/xinfra-preview.md b/technical/xinfra-preview.md new file mode 100644 index 0000000..073436f --- /dev/null +++ b/technical/xinfra-preview.md @@ -0,0 +1,47 @@ +--- +tags: [xinfra, preview, infra] +create time: 2026-07-04 12:00 +--- + +# XINFRA 预习总览 + +## 概述 + +xininfra 是公司的统一基础设施平台,以**七机房容器资源池化**为核心,配套 CI/CD 双引擎、数据库平台、WAF 安全态势、大内网互联和多云成本看板。本系列笔记覆盖开营前需要了解的全部技术栈,每篇聚焦一个工具/方向的核心概念和基本用法。 + +## 知识地图 + +```mermaid +graph LR + subgraph 底层 + K8s[K8s / RKE2] + end + subgraph 容器管理 + Wayne[Wayne 多集群管理] + end + subgraph 数据层 + CloudDM[CloudDM SQL 审核] + CacheCloud[CacheCloud Redis 管理] + end + subgraph 自动化部署 + Ansible[Ansible Playbook] + end + K8s --> Wayne + Wayne --> CloudDM + Wayne --> CacheCloud + CloudDM -.-> Ansible + CacheCloud -.-> Ansible +``` + +> [!info] 如何使用这组笔记 +> 预习阶段**不必深读源码**。重点理解每个工具的:①定位(解决什么问题)②基本架构(有哪些组件)③典型使用流程(如部署一个服务的完整链路)。后续在实习中遇到具体问题时再回溯对应笔记。 + +## 快速索引 + +| # | 笔记 | 一句话定位 | +|---|------|-----------| +| 1 | [[technical/xinfra-preview/k8s-rke2-fundamentals]] | 容器编排底层基础 | +| 2 | [[technical/xinfra-preview/wayne-overview]] | 多集群容器管理和发布入口 | +| 3 | [[technical/xinfra-preview/cloud-dm-overview]] | 数据库 SQL 审核平台 | +| 4 | [[technical/xinfra-preview/cachecloud-overview]] | Redis 实例管理平台 | +| 5 | [[technical/xinfra-preview/ansible-playbook-basics]] | 服务自动化部署工具 | diff --git a/technical/xinfra-preview/ansible-playbook-basics.md b/technical/xinfra-preview/ansible-playbook-basics.md new file mode 100644 index 0000000..1dd401a --- /dev/null +++ b/technical/xinfra-preview/ansible-playbook-basics.md @@ -0,0 +1,515 @@ +--- +tags: [ansible, playbook, infra, automation, iaas] +create time: 2026-07-04 13:30 +--- + +# Ansible Playbook 基础 + +## 概述 + +Ansible 是一个无 Agent 的自动化运维工具,通过 SSH 协议远程管理主机。**Playbook** 是 Ansible 的核心概念——用 YAML 描述的自动化任务编排文件。xinfra 的进阶目标中要求使用 Ansible Playbook 部署 MySQL Server、PostgreSQL 和 Redis Cluster,这是实现数据库层**基础设施即代码(IaC)**的关键技能。 + +## 核心概念 + +### 工作原理 + +```mermaid +graph LR + Controller[控制节点 / Laptop or CI Host] + SSH[SSH 连接] + Nodes[(被控主机列表)] + Controller -->|读取 Playbook YAML| SSH + SSH -->|推送临时模块脚本| Nodes + Nodes -->|返回 JSON 结果| Controller +``` + +关键特点: +- **无 Agent**:不需要在被控机器上安装任何软件,仅依赖 Python + SSH +- **幂等性(Idempotent)**:同一个 Playbook 执行多次效果相同,不会重复创建或修改 +- **模块化**:每个操作封装为独立模块(如 `ansible.builtin.shell`、`ansible.builtin.yum`、`ansible.builtin.template`) + +### 特权提升(Become) + +`become` 是 Ansible 的 **跨平台权限提升机制**,允许非 root 用户登录主机后切换到目标账户执行任务。不改变初始 SSH 连接会话——临时模块脚本仍通过原始身份推送,但实际运行时切换身份。 + +```yaml +# Playbook 级别 — 所有任务以 root 执行 +- hosts: all_mysql_servers + become: yes + +# Task 级别 — 精细控制 +- name: Run command as postgres user + ansible.builtin.command: /usr/bin/pg_dump mydb + become: yes + become_user: postgres + become_method: sudo # su | doas | pfexec (OpenSolaris) + become_flags: '-s /bin/sh' # 额外标志位 +``` + +| 参数 | 作用 | 示例值 | +|------|------|--------| +| **become** | 是否启用权限提升 | `yes` / `true` | +| **become_user** | 切换的目标用户 | `root`, `postgres`, `apache` | +| **become_method** | 底层实现方式 | `sudo`(默认), `su`, `pfexec` | +| **become_flags** | 传递给底层方法的附加参数 | `-s /bin/sh` | + +> [!warning] 安全注意事项 +> - **密码不能明文存储**:敏感凭据应通过 Ansible Vault 加密(见延伸阅读链接) +> - **Pipelining**:在 `/etc/ansible/ansible.cfg` 中开启 `pipelining = True`,可避免临时文件写入磁盘,减少安全风险 +> - **每台主机仅能启用一种方法**:同时配置 `sudo` + `su` 会导致冲突 +> - **最佳实践**:SSH 连入时已有较高权限 → 按需向下切换,比全程用 root 更安全 + +### Playbook 结构骨架 + +```yaml +- hosts: all_mysql_servers + become: yes # 提升 root 权限执行 + vars: # 变量定义 + mysql_port: 3306 + mysql_data_dir: /data/mysql + roles: # 引用角色 + - common-setup # 系统级准备 + - install-mysql # MySQL 安装 + tasks: # 显式任务列表 + - name: Ensure MySQL is running + ansible.builtin.service: # 推荐写全称(命名空间规范) + name: mysqld + state: started + notify: restart mysql # 触发 handler + handlers: # 响应通知动作 + - name: restart mysql + ansible.builtin.service: + name: mysqld + state: restarted +``` + +### 关键概念对照 + +| 概念 | 作用 | 类比 | +|------|------|------| +| **Hosts** | 指定目标机器组(Inventory 中定义) | SSH target | +| **Tasks** | 按顺序执行的操作 | 脚本命令 | +| **Roles** | 可复用的任务集合 | 函数库 | +| **Handlers** | 监听通知的触发器(常用于重启服务) | 事件回调 | +| **Modules** | 单功能执行单元 | 子命令 | +| **Inventory** | 被控主机清单 | SSH config 中的 host | + +### 变量优先级体系(由低到高) + +```yaml +# 变量加载顺序(低 → 高): +# 1. host_vars//all.yml — 特定主机变量 +# 2. group_vars//all.yml — 主机组共享变量 +# 3. roles//defaults/main.yml — 角色默认值(可被覆盖) +# 4. Playbook 顶层 vars — Playbook 内联变量 +# 5. extra_vars (-e 参数) — 运行时传入,优先级最高 +``` + +> [!tip] 为什么需要多级变量? +> 同一个 `mysql_port` 在开发环境可能是 `3307`,生产环境是 `3306`。**group_vars 按环境隔离 + defaults 提供安全兜底**——这是大型 Ansible 项目中最常用的变量管理模式。 + +### 变量引用语法 + +```yaml +# YAML 文件中用双大括号引用 +- name: Set MySQL port + debug: + msg: "MySQL is running on port {{ mysql_port }}" + +# 在模板文件(.j2)中同样使用 +port = {{ mysql_port }} + +# 支持字典访问和索引 +- name: Access nested variables + debug: + msg: "{{ db_config.host }},{{ db_config.credentials.password }}" +``` + +### MySQL 部署的角色拆分示例 + +一个典型的 MySQL 部署 Playbook 会拆成多个 Role: + +``` +roles/ +├── common-setup/ +│ ├── tasks/main.yml # 时间同步、内核参数调优、防火墙规则 +│ └── templates/ # 系统级配置文件模板 +├── install-mysql/ +│ ├── tasks/main.yml # 安装、配置主从复制 +│ └── files/ # 二进制包或 RPM 安装包 +└── config-mysql/ + ├── tasks/main.yml # 编写 my.cnf(Jinja2 模板) + └── templates/my.cnf.j2 # 根据变量动态生成配置 +``` + +每个 Role 可以独立测试和复用,不同服务的安装只需替换中间两个 Role。 + +### Jinja2 模板实战 + +```ini +# my.cnf.j2 +[mysqld] +port = {{ mysql_port | default(3306) }} +datadir = {{ mysql_data_dir | default('/var/lib/mysql') }} +server-id = {{ inventory_hostname | regex_replace('\\D', '') | int }} +{% if role == 'master' %} +log-bin = mysql-bin +binlog-format = ROW +{% elif role == 'slave' %} +read-only = 1 +relay-log = relay-bin +{% endif %} +``` + +> [!tip] 为什么需要 Jinja2 模板? +> 同一套 Playbook 要用于 Master 和 Slave,它们的配置有差异。**模板 + 变量注入**比硬编码多个 Playbook 更灵活——这也是 IaC 的核心思想:**一套代码,多种环境**。 + +## 控制流 + +### 循环(Loops) + +Ansible 推荐使用简洁的 `loop` 语法替代旧式的 `with_items`。`loop` 在 2.5 版本引入,功能等价于 `with_list`,但更简洁且与 `lookup` 兼容更好。 + +#### 基础用法 + +```yaml +- name: Install multiple packages + ansible.builtin.yum: + name: "{{ item }}" + state: present + loop: + - vim + - curl + - git + - wget + +# 字典列表循环 — 适合批量创建用户/配置 +- name: Create database users + community.mysql.mysql_user: + name: "{{ item.name }}" + password: "{{ item.password }}" + priv: "{{ item.priv }}" + state: present + loop: "{{ db_users }}" # 引用 vars 中定义的变量列表 +``` + +#### 字典迭代(dict2items) + +当需要遍历 YAML 字典时,用 `dict2items` 将其转为 `[{"key": ..., "value": ...}, ...]` 结构: + +```yaml +- name: Configure servers from dictionary + ansible.builtin.debug: + msg: "{{ item.key }}: IP={{ item.value.ip_address }}, role={{ item.value.role }}" + loop: "{{ server_configs | dict2items }}" + vars: + server_configs: + web_01: + ip_address: "10.1.1.50" + role: "frontend" + web_02: + ip_address: "10.1.1.51" + role: "backend" +``` + +> [!tip] query vs lookup +> `loop` 要求返回一个 list。使用 lookup 插件时,推荐用 `query`(2.5+),它保证返回列表;如果用 `lookup`,需加 `wantlist=True`: +> ```yaml +> loop: "{{ query('inventory_hostnames', 'all') }}" +> # 或 +> loop: "{{ lookup('inventory_hostnames', 'all', wantlist=True) }}" +> ``` + +#### 循环控制(loop_control) + +```yaml +- name: Create cloud instances with delay + digital_ocean: + name: "{{ item.name }}" + state: present + loop: + - { name: server1, disk: 3gb } + - { name: server2, disk: 4gb } + loop_control: + label: "{{ item.name }}" # 自定义输出标识(避免冗长日志) + pause: 3 # 每项之间等待 N 秒(避免瞬时并发压力) + loop_var: outer_item # 指定外层循环变量名(嵌套循环防冲突) +``` + +#### 自动重试(until 循环) + +`until` 不是用来遍历数据的——它是 **轮询重试** 模式,适用于可能暂时失败、最终会成功的操作(如等待服务启动): + +```yaml +- name: Wait for service to be ready + shell: /usr/bin/check_service_ready + register: result + until: result.stdout.find("ready") != -1 + retries: 5 # 最大尝试次数 + delay: 10 # 每次间隔秒数 +``` + +注册变量在循环中的结构是嵌套的:`{{ my_loop.results[0].stdout }}`、`{{ my_loop.results[1].rc }}` 等,后续用 `when: item.rc != 0` 过滤即可。 + +> [!warning] with_items → loop 迁移注意 +> `with_items` 有**隐式扁平化**行为:`with_items: [1, [2,3], 4]` 会展平为 `[1, 2, 3, 4]`。切换到 `loop` 后需手动处理: +> ```yaml +> loop: "{{ [1, [2, 3], 4] | flatten(1) }}" +> ``` + +### 条件判断(when) + +```yaml +- name: Configure slave replication + template: + src: my.cnf.j2 + dest: /etc/my.cnf + when: inventory_hostname in groups['mysql_slaves'] + +# 复杂条件 +- name: Only on CentOS 7 + debug: + msg: "CentOS detected" + when: + - ansible_os_family == "RedHat" + - ansible_distribution_major_version == "7" +``` + +> [!warning] 何时不用 when? +> 如果 `when` 只是过滤几行数据,优先在 Jinja2 模板内部用 `{% if %}` 处理,而不是写一个全量任务再套 `when`——后者会在所有目标主机上都执行一次无意义的模块调用。 + +### notify / handlers 机制详解 + +```yaml +tasks: + - name: Update Nginx config + ansible.builtin.template: + src: nginx.conf.j2 + dest: /etc/nginx/nginx.conf + notify: reload nginx # ← 仅设置"标记",不立即执行 + +handlers: + - name: reload nginx + ansible.builtin.service: + name: nginx + state: reloaded # ← 仅在 Playbook 阶段结束时触发 +``` + +> [!info] notify 的关键语义 +> 即使多个 task 都 `notify` 同一个 handler,handler 也只会**在每个 Play 结束后执行一次**。这正是幂等性设计的一部分——避免重复重启服务。 + +### 结果捕获与错误处理 + +```yaml +# register — 将命令输出保存到变量 +- name: Check if MySQL data dir exists + ansible.builtin.stat: + path: /data/mysql + register: mysql_data_check + +- name: Initialize data dir if missing + ansible.builtin.file: + path: /data/mysql + state: directory + owner: mysql + group: mysql + when: not mysql_data_check.stat.exists + +# ignore_errors — 允许任务失败不中断 Playbook +- name: Try to stop already-stopped service + ansible.builtin.service: + name: mysqld + state: stopped + ignore_errors: yes + +# failed_when — 自定义失败判定逻辑 +- name: Check API health + ansible.builtin.uri: + url: http://localhost:8080/health + register: health_check + failed_when: "'unhealthy' in health_check.content" + +# set_fact — 动态设置变量供后续任务使用 +- name: Capture private IP + ansible.builtin.set_fact: + node_private_ip: "{{ ansible_default_ipv4.address }}" +``` + +> [!tip] register 的经典使用场景 +> `stat` 模块检查文件存在 → `when` 判断决定是否创建 → 这就是 **"先查后做"** 的 Ansible 范式,完美体现幂等性原则。 + +### 状态控制(changed_when / any_errors_fatal) + +除了 `failed_when` 外,Ansible 还允许通过 **`changed_when`** 精确控制任务的变更状态——这直接影响统计报告和 handler 触发: + +```yaml +# ❌ command 永远是 "changed",即使数据库连接无变化 +- name: Check DB connection + command: mysql -e "SELECT 1" + +# ✅ 仅在真正有变更时标记为 changed +- name: Check DB connection + shell: mysql -e "SELECT 1" + register: db_check + changed_when: "'ERROR' in db_check.stdout" + +# 强制不报告变更(常用于健康检查类任务) +- name: Health check endpoint + uri: + url: http://localhost:8080/health + changed_when: false +``` + +| 参数 | 作用域 | 说明 | +|------|--------|------| +| **ignore_errors** | Task 级 | 失败继续执行,不中断 Play | +| **ignore_unreachable** | Play 级 | 跳过网络不可达的主机,继续其他主机 | +| **any_errors_fatal** | Play/Block 级 | 任一主机报错即终止全部执行 | +| **max_fail_percentage** | Play 级 | 失败超过阈值(%)时停止 | +| **changed_when** | Task 级 | 条件性覆盖 "已变更" 报告 | +| **failed_when** | Task 级 | 条件性覆盖 "失败" 判定 | + +### Block / Rescue / Always — 结构化异常处理 + +这是编程中 `try/catch/finally` 的 Ansible 等价物,适合需要 **原子化操作 + 自动回滚** 的场景: + +```yaml +- name: Deploy application with rollback + block: + - name: Backup current release + archive: + path: /opt/app/current + dest: /opt/backups/release-$(date +%s).tar.gz + register: backup_result + + - name: Extract new version + unarchive: + src: new-app-v2.tar.gz + dest: /opt/app/releases/v2 + remote_src: yes + + - name: Symlink to active release + file: + src: /opt/app/releases/v2 + dest: /opt/app/current + state: link + + rescue: + - name: Log failure details + debug: + msg: "Task '{{ ansible_failed_task.name }}' failed on {{ inventory_hostname }}" + + - name: Rollback to previous release + file: + src: /opt/app/releases/v1 + dest: /opt/app/current + state: link + when: backup_result is succeeded # 仅当备份成功时才尝试还原 + + always: + - name: Notify deployment team + ansible.builtin.command: > + curl -X POST https://hooks.slack.com/deploy-webhook + -d '{"text":"Deployment {{ ansible_failed_task.name if ansible_failed_task else 'succeeded' }} on {{ inventory_hostname}}"}' + changed_when: false +``` + +> [!info] 语义对比表 +> +> | 编程概念 | Ansible 关键字 | 触发条件 | +> |----------|---------------|---------| +> | `try {}` | `block:` | 正常任务流,始终执行 | +> | `catch {}` | `rescue:` | 仅当前置任务返回 `failed` 时触发 | +> | `finally {}` | `always:` | 无论成败均执行 | +> +> - **Rescue 中的恢复若成功,Play 会继续**——但统计日志仍记录一次故障 +> - **语法错误、断连等情况不会触发 Rescue**,与编程语言不同 +> - **Handler 可以在 Rescue 中被调用**(通过元数据命令触发) + +## 常用模块速查 + +> [!info] 命名空间规范(Namespace Prefix) +> Ansible 2.10+ 开始引入 `collections` 概念,推荐始终使用前缀格式: +> - `ansible.builtin.copy` — 内置模块 +> - `community.general.selinux` — 社区集合 +> - 现代 Playbook 中优先写全称;如果省略前缀,Ansible 会按内置 → 已安装的集合顺序自动匹配。 + +| 模块 | 用途 | 关键参数 | +|------|------|---------| +| **ansible.builtin.copy** | 本地文件复制到远程 | `src`, `dest`, `owner`, `mode` | +| **ansible.builtin.template** | Jinja2 模板渲染后复制 | `src (.j2)`, `dest`, `owner`, `mode` | +| **ansible.builtin.file** | 管理文件/目录权限和属性 | `state: touch/file/directory/link/absent`, `mode` | +| **ansible.builtin.yum** / **ansible.builtin.apt** | 包管理 | `name`, `state: present/installed/latest/absent` | +| **ansible.builtin.service** | 管理服务生命周期 | `name`, `state: started/stopped/restarted/reloaded` | +| **ansible.builtin.lineinfile** | 确保某行存在或不存在于文件中 | `path`, `line`, `state`, `regexp` | +| **ansible.builtin.replace** | 正则替换文件内容 | `path`, `regexp`, `replace` | +| **ansible.builtin.command** / **ansible.builtin.shell** | 执行命令(慎用) | `cmd`, `chdir` | +| **ansible.builtin.get_url** / **ansible.builtin.uri** | HTTP 下载 / API 调用 | `url`, `dest`, `method`, `status_code` | +| **ansible.builtin.user** | 管理系统用户 | `name`, `state`, `groups`, `shell` | +| **ansible.builtin.cron** | 管理 crontab | `name`, `minute`, `job`, `state` | +| **ansible.builtin.debug** | 调试输出 | `msg`, `var` | +| **ansible.builtin.stat** | 检查文件/路径属性 | `path`, returns `.stat.exists` | +| **community.mysql.mysql_user** | MySQL 用户管理 | `name`, `password`, `priv`, `state` | +| **community.postgresql.postgresql_user** | PostgreSQL 用户管理 | `name`, `password`, `role_attr` | + +> [!warning] command vs shell 的选择 +> `command` 不经过 Shell 解释器(更安全,推荐优先使用),`shell` 才支持管道 `\|`、重定向 `>`、变量扩展 `$VAR`。**能用模块完成的操作绝不碰 command/shell**。 + +## 常见陷阱与最佳实践 + +### 1. 不要跳过 `state` 检查 + +错误写法: +```yaml +- ansible.builtin.command: systemctl start mysqld # ❌ 每次都会尝试启动,即使已在运行 +``` + +正确写法: +```yaml +- ansible.builtin.service: # ✅ Ansible 自带的 service 模块会检查当前状态 + name: mysqld + state: started +``` + +### 2. Inventory 分层管理 + +把开发、测试、生产环境的机器分开管理: +```ini +# inventory/prod +[mysql_prod] +mysql-prod-01 ansible_host=10.0.1.11 +mysql-prod-02 ansible_host=10.0.1.12 + +[redis_prod] +redis-prod-01 ansible_host=10.0.1.21 +``` + +### 3. 首次运行时务必先 Dry Run + +```bash +# --check 只做预演,不实际执行 +ansible-playbook deploy.yml --check --diff +``` + +### 4. 警惕 shell/command 失去幂等性 + +```yaml +# ❌ 每次运行都会在日志末尾追加一行 +- ansible.builtin.shell: echo "deployed" >> /tmp/deploy-history + +# ✅ 用 file module 保证状态一致性 +- ansible.builtin.file: + path: /tmp/deploy-marker + state: touched + modification_time: preserve +``` + +## 延伸阅读 + +- [[technical/xinfra-preview/k8s-rke2-fundamentals]] — K8s 内的实例 vs Ansible 管理的裸机/VM +- [[technical/xinfra-preview/cachecloud-overview]] — CacheCloud 管 Redis,Ansible 负责底层部署 +- [[technical/xinfra-preview/cloud-dm-overview]] — Ansible 部署的 MySQL 由 CloudDM 做 SQL 审核 +- [官方 Playbook 指南](https://github.com/ansible/ansible-documentation/tree/devel/docs/docsite/rst/playbook_guide) — Ansible 文档源码,涵盖从入门到高级语法的全部章节 +- https://www.ansible.com/docs — Ansible 官方文档入口 +- [Ansible Vault 文档](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html) — 加密敏感凭据(密码、密钥),解决 Become 中的安全合规问题 +- [入门教程](https://www.cnblogs.com/easonscx/p/10622781.html) — Ansible 基础用法参考 diff --git a/technical/xinfra-preview/cachecloud-overview.md b/technical/xinfra-preview/cachecloud-overview.md new file mode 100644 index 0000000..21e712e --- /dev/null +++ b/technical/xinfra-preview/cachecloud-overview.md @@ -0,0 +1,377 @@ +--- +tags: [cachecloud, redis, infra, self-hosted] +create time: 2026-07-04 12:00 +--- + +# CacheCloud Redis 管理台 + +## 概述 + +CacheCloud(搜狐开源)是一个 **Redis 私有云平台**,支持 Standalone、Sentinel、Cluster 三种架构的一站式高效管理。xinfra 中所有需要 Redis 服务的场景都通过 CacheCloud 进行**统一的实例申请和管理**——开发同学不再需要手动安装部署 Redis,只需在平台上提交工单即可获取可用实例。 + +核心目标:**降低大规模 Redis 运维成本,提升资源管控能力和利用率**。平台提供快速搭建/迁移、运维管理、弹性伸缩、统计监控、客户端整合接入等功能。 + +--- + +## 系统架构 + +### 整体拓扑 + +```mermaid +graph TB + subgraph "用户层" + Dev[开发同学 / 运维人员] + end + + subgraph "接入层 (Nginx 双机房)" + NG1[Nginx 机房 A] + NG2[Nginx 机房 B] + VIP[Virtual IP → 双向漂移] + VIP --> NG1 + VIP --> NG2 + end + + subgraph "应用层 (Spring Boot)" + CC[CacheCloud Web Server] + DB[(MySQL 元数据)] + AGT_Mgr[Agent 管理器] + ALERT[报警组件
邮件 / 微信 / HTTP] + CUSTOM[自定义扩展模块] + end + + subgraph "执行层 (Agent 代理)" + AGT1[Agent 宿主机 A
Redis Standalone / Sentinel] + AGT2[Agent 宿主机 B
Redis Cluster Shard 1] + AGT3[Agent 宿主机 C
Redis Cluster Shard 2] + end + + Dev -->|cc.company.com| VIP + VIP --> NG1 & NG2 + NG1 & NG2 --> CC + CC <--> DB + CC --> AGT_Mgr + CC --> ALERT + CC --> CUSTOM + AGT_Mgr -->|SSH + 心跳| AGT1 & AGT2 & AGT3 +``` + +> **关键设计决策**:CacheCloud 采用 **Agent 模式**而非直接 SSH 连接 Redis 实例。每个宿主机部署一个 Agent 进程,负责该机器上所有 Redis 实例的生命周期管理(启停、升级、备份恢复)。这样做的好处是 Agent 可复用 SSH 连接、缓存本地状态,大幅减少管理平台到 Redis 主机的网络开销。 + +### 核心组件 + +| 组件 | 职责 | +|------|------| +| **Web UI / REST API** | 自助申请实例、配置修改、工单审批、监控大屏 | +| **Agent 代理** | 部署在每个宿主机上,负责 Redis 进程生命周期管理、状态上报、远程命令执行 | +| **元数据库 (MySQL)** | 存储实例拓扑、配置模板、账号权限、工单流转记录 | +| **报警模块** | 内置邮件和微信报警,同时暴露 HTTP 接口供任意语言集成 | +| **扩展模块** | 登录组件 (`LoginComponent`)、报警组件 (`EmailComponent`/`WeChatComponent`) 均可自行实现 | + +--- + +## 实例类型与选型指南 + +### 三种架构对比 + +| 维度 | Standalone | Sentinel (Master-Slave) | Cluster | +|------|-----------|------------------------|---------| +| **高可用** | ❌ 单机,无 Failover | ✅ 主从 + Sentinel 自动故障转移 | ✅ 多分片,自动槽迁移 | +| **横向扩展** | ❌ 受单机容量限制 | ❌ 受单机容量限制 | ✅ 新增节点即扩容 | +| **复杂度** | 简单 | 中等 | 较高 | +| **推荐场景** | 测试环境、低频读写缓存 | 生产环境常规业务、内存需求 ≤ 6GB | 大数据量、高并发、内存需求 > 6GB | + +> **建议**:并不是 Cluster 越好。如果当前或未来所需内存不超过 6GB 且要求高可用,选择 Sentinel 就足够了。 + +### 选型决策树 + +```mermaid +flowchart TD + Start{是否需要高可用?} + Start -->|否: 测试/灰度| Standalone[Standalone] + Start -->|是| NeedScale{是否需要横向扩展?} + NeedScale -->|否≤6GB| Sentinel[Sentinel 主从] + NeedScale -->|是>6GB| Cluster[Redis Cluster] +``` + +--- + +## 客户端接入方式 + +CacheCloud 提供了多种客户端 SDK 及 REST API,覆盖 Java、Python 等主流语言。 + +### REST API(最通用) + +通过简单 HTTP 请求即可获取实例连接信息,适用于任何语言: + +``` +GET http://{domain}/cache/client/redis/{appType}/{appId}.json?clientVersion={version} +``` + +**参数说明**: + +| 参数 | 含义 | 枚举值 | +|------|------|--------| +| `appType` | 实例类型 | `cluster` / `sentinel` / `standalone` | +| `appId` | 应用 ID | 平台分配的数字 ID | + +**响应示例**: + +```json +{ + "message": "client is up to date, Cheers!", + "shardNum": 10, + "appId": 10192, + "status": 1, + "shardInfo": "10.10.xx.xx:6390,10.10.xx.xx:6382 10.10.xx.xx:6387,10.10.xx.xx:6379 ..." +} +``` + +> `shardInfo` 字段以空格分隔每个分片,逗号分隔同一个分片的主从地址。解析后即可直连。 + +### Java — cachecloud-client-redis(Jedis 封装) + +```java +@Configuration +public class RedisConfiguration { + + @Bean(destroyMethod = "close") + public PipelineCluster pipelineCluster(@Value("${cachecloud.demo.appId}") long appId) { + return ClientBuilder.redisCluster(appId).build(); + } + + @Bean(destroyMethod = "destroy") + public JedisSentinelPool jedisSentinelPool(@Value("${cachecloud.demo.appId}") long appId) { + return ClientBuilder.redisSentinel(appId).build(); + } + + @Bean(destroyMethod = "destroy") + public JedisPool jedisPool(@Value("${cachecloud.demo.appId}") long appId) { + return ClientBuilder.redisStandalone(appId).build(); + } +} +``` + +**使用方式**: + +```java +@Autowired private PipelineCluster pipelineCluster; + +public String get(String key) { + return pipelineCluster.get(key); +} +``` + +> 所有 `...Pool.getResource()` 使用后必须调用 `jedis.close()` —— 它并非真正关闭连接,而是将连接归还给连接池(内部判断连接是否损坏后决定 `returnResource` 还是 `returnBrokenResource`)。 + +### Java — cachecloud-client-lettuce(Lettuce 封装) + +适合需要异步/响应式场景的应用: + +```java +@Bean(destroyMethod = "shutdown") +public RedisClusterClient redisClusterClient(long appId, String password) { + return LettuceClientBuilder.redisCluster(appId, password).build(); +} + +@Bean(destroyMethod = "close") +public StatefulRedisClusterConnection clusterConnection(RedisClusterClient client) { + StatefulRedisClusterConnection conn = client.connect(); + conn.setReadFrom(ReadFrom.REPLICA_PREFERRED); // 读操作优先走从节点 + return conn; +} +``` + +### Python 接入(REST API 动态拉取连接信息) + +```python +import requests +from rediscluster import RedisCluster + +app_id = 10192 +url = f'http://cc.company.com/cache/client/redis/cluster/{app_id}.json' +resp = requests.get(url).json() + +startup_nodes = [ + dict(zip(['host', 'port'], addr.split(':'))) + for shard in resp['shardInfo'].split(' ') + for addr in shard.split(',') +] +rc = RedisCluster(startup_nodes=startup_nodes, password='your-pass') +``` + +### 跨机房部署(Cross-Room) + +对于容灾要求高的业务,CacheCloud 支持**跨机房双活**:同一业务在两个机房分别部署应用实例,客户端 SDK 自动做双写双读和机房切换。原理是两个 `PipelineCluster` 实例被包装进一个 `RedisCrossRoomClient`。 + +--- + +## 系统功能全景 + +### 用户端功能 + +| 功能 | 说明 | +|------|------| +| **应用管理** | 查看统计信息、实例列表、应用拓扑、连接信息 | +| **监控面板** | 命令曲线、延迟监控、日报统计 | +| **命令执行** | 在线执行 Redis 命令用于排查 | +| **键值分析** | 分析 bigkey、hotkey 分布 | + +### 运维端功能 + +| 功能分类 | 具体能力 | +|----------|---------| +| **数据统计** | 全局统计、client 统计、server 统计 | +| **工单审批** | 实例申请、配置修改、数据清理等操作需管理员审批 | +| **应用运维** | 应用维度的启停、配置下发、日志查看 | +| **实例运维** | 实例维度的启停、配置查询、数据清理 | +| **数据迁移** | 跨实例数据迁移工具 | +| **诊断工具** | 慢查询分析、连接数诊断等 | +| **模板管理** | 按规格预设 Redis 配置模板(maxmemory、持久化策略等) | +| **任务流** | 编排运维操作流程(如批量升级) | + +### 报警配置 + +CacheCloud 内置的报警覆盖了 Redis 机器级别和实例级别的重要指标,支持的报警渠道: + +- **邮件报警** — 默认实现,也可替换为 HTTP 回调 +- **微信报警** — 企业微信/钉钉 webhook 风格 + +报警可通过 HTTP 接口自定义,格式如下: + +``` +POST www.xxx.com/emailAlert?title=xx&content=xx&receiver=x&cc=x +POST www.xxx.com/weChatAlert?title=xx&message=xx&weChatList=xx +``` + +--- + +## 基础运维实践 + +### maxmemory-policy 策略选择 + +| 策略 | 行为 | 适用场景 | +|------|------|---------| +| `volatile-lru` | 删除有过期时间的 key,LRU 淘汰 | 默认策略,有 TTL 的缓存 | +| `allkeys-lru` | 对所有 key 做 LRU 淘汰 | 纯缓存场景,不设 TTL | +| `volatile-ttl` | 删除即将过期的 key | 希望按过期时间优先淘汰 | +| `noeviction` | 不淘汰,写操作返回错误 | 需要绝对保证数据完整性 | + +> **注意**:修改的配置会对应用的所有节点生效,因为所有节点的配置是统一的。 + +### Jedis 连接池调优参考 + +```java +GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); +poolConfig.setMaxTotal(DEFAULT_MAX_TOTAL * 5); // 根据实际 QPS 调整 +poolConfig.setMaxIdle(DEFAULT_MAX_IDLE * 3); +poolConfig.setMinIdle(DEFAULT_MIN_IDLE * 2); +poolConfig.setMaxWaitMillis(3000); // 连接耗尽时最多等待 3s +poolConfig.setJmxEnabled(true); // 开启 JMX 便于观察 +poolConfig.setTestWhileIdle(true); // 空闲时定期检查连接有效性 +poolConfig.setTimeBetweenEvictionRunsMillis(60000); // 每分钟检查一次 +``` + +关键字段解读: + +| 配置项 | 默认值 | 调优建议 | +|--------|--------|---------| +| `maxTotal` | 8 | 根据峰值连接数估算,通常 × 3~5 | +| `testOnBorrow` | false | 不建议设为 true,会显著增加延迟 | +| `testOnReturn` | false | 一般保持 false,由 `testWhileIdle` 兜底 | +| `whenExhaustedAction` | 1 (阻塞) | 配合 `maxWaitMillis` 使用,避免无限等待 | + +--- + +## 常见陷阱与最佳实践 + +### 1. Bigkey 的寻找与优化 + +**什么是 bigkey**:value 所占内存空间较大的 key。字符串类型超过 100KB 即视为 bigkey;非字符串类型(Hash/List/Set/ZSet)则以元素数量过多为准。 + +**危害**: +- 内存不均匀:Cluster 中造成部分节点内存暴增 +- 超时阻塞:Redis 单线程特性下,大 key 操作耗时 > 客户端超时 +- 网络拥塞:单次大流量冲击网卡,影响同机其他实例 +- 过期删除阻塞:未启用 lazyfree 时阻塞主线程 +- 碎片整理冲突:Redis 4.0+ activeDefrag 对超大 key 可能导致周期性延迟 + +**发现手段**: + +| 方法 | 命令 | 特点 | +|------|------|------| +| redis-cli | `redis-cli --bigkeys` | 全量扫描,建议在从节点执行 | +| DEBUG OBJECT | `DEBUG OBJECT key` | 获知序列化长度 `serializedlength` | +| MEMORY USAGE | `MEMORY USAGE key` | 仅 Redis 4.0+,返回精确内存占用 | +| 监控输出缓冲区 | `info clients` 关注 `client_biggest_input_buf` / `client_recent_max_output_buffer` | 间接判断是否存在大 key 读取 | + +**优雅删除方案**: + +- **String**:直接使用 `DEL`,通常不会阻塞 +- **Hash/List/Set/ZSet**:使用 `HSCAN/SSCAN/ZSCAN` 分批获取元素 + `HDEL/SREM/ZREM` 逐个删除,或使用 Redis 4.0+ 的 `UNLINK`(异步删除) + +```python +def del_big_hash(r, key): + cursor = 0 + while True: + cursor, members = r.hscan(key, cursor, count=100) + if not members: + break + r.hdel(key, *members) # pipeline 批量更高效 + if cursor == 0: + break +``` + +### 2. Hotkey 的处理方向 + +当某个 key 的访问量远超平均水平时: +- **本地缓存**:在应用侧加一层 Guava/Caffeine 缓存 +- **key 拆分**:将一个大 key 拆成多个子 key(如 `user:1001:friends` → `user:1001:friends:1`, `user:1001:friends:2`) +- **读写分离**:读操作通过 Sentinel 路由到从节点 + +### 3. 实例规格匹配 + +不要盲目选大规格。建议先通过 Prometheus/Grafana 观察历史 QPS、内存使用和连接数,再确定实例规格。过度配置会在资源看板上体现为浪费。 + +### 4. 临时 vs 长期实例 + +- **临时实例**(测试/灰度用)应设置自动回收策略——超出保留期后系统自动销毁 +- **长期实例**则需要完善监控、定期巡检配置变更 + +### 5. 机房就近原则 + +Redis 对网络延迟非常敏感。跨机房访问比同机房慢数倍,因此应用申请时应填写服务所在机房,确保实例分配到最近的机器。 + +--- + +## Redis 版本演进速览 + +CacheCloud 管理的 Redis 实例可能运行在不同版本,了解各版本的关键特性有助于理解平台行为差异: + +| 版本 | 核心新特性 | CacheCloud 相关 | +|------|-----------|----------------| +| **3.x** | 原生 Cluster | 最早支持的 Cluster 形态 | +| **4.0** | Lazyfree 异步删除、AOF/RDB 混合持久化、内存碎片整理 | 支持 UNLINK 删除 bigkey | +| **5.0** | Stream 数据类型、RESP3 协议、Dynamic HZ | 客户端兼容性更好 | +| **6.0** | 多线程 IO、ACL、SSL 加密、协助客户端缓存 | 多线程 IO 提升非 Pipeline 场景 2 倍性能 | + +> **启发问题**:为什么 Redis 6.0 的多线程只处理网络 IO 而不涉及命令执行?这背后有什么权衡? + +--- + +## 与 xinfra 的对接方向 + +进阶目标中提到要「基于 CacheCloud API 实现页面直接创建 Redis Cluster」,这意味着: + +1. **阅读 Open API 文档**:梳理可用的创建/配置/查询接口 +2. **封装创建流程**:选择规格 → 调用 API → 等待就绪 → 返回连接信息 +3. **集成到 xinfra 统一服务管理页面**:让开发者在 xinfra 内即可完成 Redis 实例的全生命周期操作 +4. **可选增强**:对接 xinfra 的审批流、用量统计、成本分摊等模块 + +--- + +## 关联笔记 + +- [[technical/xinfra-preview/cloud-dm-overview]] — SQL 审核与 Redis 访问同属数据层基础设施 +- [[technical/xinfra-preview/k8s-rke2-fundamentals]] — CacheCloud 的宿主机未来可能迁移至 K8s 部署 +- https://github.com/sohutv/cachecloud — CacheCloud GitHub 仓库(含完整 Wiki 和代码) +- https://github.com/antirez/redis — Redis 官方仓库 diff --git a/technical/xinfra-preview/cloud-dm-overview.md b/technical/xinfra-preview/cloud-dm-overview.md new file mode 100644 index 0000000..caa57fd --- /dev/null +++ b/technical/xinfra-preview/cloud-dm-overview.md @@ -0,0 +1,130 @@ +--- +tags: [cloud-dm, sql-audit, dbms, preview, infra] +create time: 2026-07-04 12:00 +--- + +# CloudDM SQL 审核平台 + +## 概述 + +CloudDM(open-cdm)是一款**免费且开源的团队化数据库管理平台**,由 ClouGence 团队开发,采用 Apache License 2.0 许可。它的定位远超"SQL 审核工具"——覆盖数据查询、权限管控、SQL 审核、数据脱敏、数据库 CI/CD 和跨地区部署的全链路能力。 + +在 xinfra 中,所有操作 MySQL 的场景都必须经过 CloudDM 的审核机制——这是防止**误操作直接打到生产库**的第一道防线。同时,开发人员也可以直接在 CloudDM 中进行安全的数据查询与变更交付。 + +当前版本:**3.1.1** | 官网: + +## 核心概念 + +### 定位与设计哲学 + +```mermaid +sequenceDiagram + participant dev as 开发人员 + participant cdm as CloudDM + participant auditor as DBA/审核人 + participant mysql as MySQL实例 + dev->>cdm: 提交SQL上线工单 / 数据查询 + cdm->>cdm: SQL语法检查 + 54条规则校验 + cdm->>auditor: 通知审核 + auditor->>cdm: 审核通过 / 驳回 + cdm->>mysql: 按窗口执行(限流+分批) +``` + +核心原则:**每一次数据库操作都要有记录、可审计、可回滚**。 + +### 核心能力模块 + +| 模块 | 职责 | +|------|------| +| **数据查询** | 支持 MySQL、Oracle、PG、DB2、SQL Server、OceanBase、ClickHouse、Redis、MongoDB 等 **20+** 数据源;提供统一 Web 控制台,含语法高亮、智能提示、执行计划预览 | +| **SQL 审核** | 内置 54 条审核规则,支持规则脚本自定义扩展;执行前预检,提示风险或阻断高危语句 | +| **权限控制** | 资源权限(实例/库/Schema/表粒度)+ 功能权限(RBAC 角色授权);支持申请权限、赋予权限及临时权限 | +| **数据管理** | 可视化管理数据库对象:库、表、索引、视图、函数、存储过程、用户、角色等 | +| **数据脱敏** | 对查询结果或流程中的敏感数据进行隐藏或转换 | +| **数据库 CI/CD** | Git Push / Web Hook / HttpCall 三种触发方式,支持 Gitee 作为变更仓库 | +| **协同流程** | 三种流程类型:**SQL 审核**、**权限工单**、**变更流程**;三种执行方式:**手动执行**、**立即执行**、**定时执行** | +| **统一认证** | OpenLDAP / OIDC / Windows AD / 钉钉 / 飞书 / 企业微信 SSO | + +### 部署模式对比 + +| 维度 | Alone(单机) | Console + Sidecar(集群) | +|------|---------------|---------------------------| +| 组件 | Web + Sidecar + MySQL 合一 | Console 独立 + 多个 Sidecar | +| 适用场景 | 小规模验证、个人使用 | 团队协作、跨地区多数据源 | +| 特点 | 开箱即用,一条 Docker 命令启动 | 最大特点是**跨地区数据库统一授权访问** | +| Web 端口 | 8222 | Console: 8222, Sidecar: 8080 | + +> [!tip] 快速体验 +> ```bash +> # 一键启动单机版 +> docker run -d --name cgdm-alone -p 8222:8222 bladepipe/cgdm-alone:3.1.1 +> # 中国区加速镜像 +> docker run -d --name cgdm-alone -p 8222:8222 \ +> cloudcanal-registry.cn-shanghai.cr.aliyuncs.com/clougence/cgdm-alone:3.1.1 +> ``` + +### 典型操作流程 + +``` +1. 开发在 CloudDM 添加数据源(MySQL / PG / Redis ...) +2. 通过 Web 查询编辑器进行数据查询或编写变更 SQL +3. 若涉及变更 → 创建 SQL 上线工单 +4. CloudDM 自动执行 54 条规则预检 +5. DBA 审核通过后进入排队队列 +6. 按指定时间窗或立即由系统执行 +7. 执行结果回填工单,全程留痕 +``` + +### 元数据存储 + +CloudDM 的元数据存储在内置(Alone 模式)或外部 MySQL 中。无需深入具体表结构——Console 提供了完整的可视化对象管理界面。需要了解的重点是: + +- 元信息数据库使用 **MariaDB/MySQL**(Alone 模式自带嵌入式 MySQL) +- 集群模式的元数据持久化为 `cdmgr` 库,默认账号 root +- 忘记管理员密码时,可删除 `drivers/cgdm-runtime-mysql` 目录后重启以重新走初始化向导(不重建数据库即可重置) + +## 常见陷阱与最佳实践 + +### 1. 审核规则要适配实际业务 + +过于严格的规则可能在特定场景下误杀正常需求。**建议**:初期允许白名单豁免,积累一段时间后再收紧规则。 + +### 2. 区分 DML 和 DDL 审核策略 + +- **DML**(INSERT/UPDATE/DELETE):重点防范误删、锁表 +- **DDL**(ALTER TABLE/CREATE INDEX):重点防范大表长时间锁表 + +两者需要不同的审核标准和执行窗口。 + +### 3. Alone vs Cluster 选型 + +- 单人或小团队直接用 **Alone 模式**,一条 `docker run` 即可上手 +- 当需要在不同地域连接多台数据库并做统一权限管控时,迁移到 **Console + Sidecar 集群模式** + +### 4. 生产部署安全事项 + +- 务必替换默认的 JWT 密钥和管理员密码 +- K8s 部署中将敏感配置改为 `Secret` 管理 +- PVC 容量根据实际数据规模调整 + +## 关键术语速查 + +| 术语 | 含义 | +|------|------| +| **Alone** | 单机部署模式,Web 控制台、Sidecar 和元信息数据库合并运行 | +| **Console** | 中央 Web 控制台,负责数据库访问、审批流程和全局配置 | +| **Sidecar** | 配合 Console 使用的数据库访问代理,常用于跨地区部署 | +| **SQL 审核** | SQL 执行或变更交付前的规则化风险检查 | +| **数据脱敏** | 查询结果或流程中对敏感数据的隐藏/转换保护 | +| **资源权限** | 按实例、库、Schema、表粒度授予的权限 | +| **功能权限** | 基于 RBAC 的功能访问权限 | +| **权限工单** | 用于申请、审批和授予访问权限的流程 | +| **变更流程** | 用于审核和交付受控数据库变更的流程 | +| **数据库 CI/CD** | 通过 Git Push / Web Hook / HttpCall 触发的数据库变更交付 | + +## 延伸阅读 + +- [[technical/xinfra-preview/k8s-rke2-fundamentals]] — K8s 内的 MySQL 容器化部署基础 +- — open-cdm 主仓库(GitHub) +- — 中国镜像仓库 +- [[technical/xinfra-preview/cloud-dm-overview#核心能力模块]] — 本文档「核心能力模块」章节 diff --git a/technical/xinfra-preview/k8s-rke2-fundamentals.md b/technical/xinfra-preview/k8s-rke2-fundamentals.md new file mode 100644 index 0000000..03921dc --- /dev/null +++ b/technical/xinfra-preview/k8s-rke2-fundamentals.md @@ -0,0 +1,375 @@ +--- +tags: [k8s, rke2, preview, infra] +create time: 2026-07-04 12:00 +--- + +# K8s + RKE2 基础 + +## 概述 + +Kubernetes(K8s)是容器编排的事实标准,Rancher RKE2 是 CNCF 认证的轻量级、安全优先的 K8s 发行版,专为边缘和混合云场景设计。xinfra 平台的容器调度底层基于 RKE2,后续所有服务部署都建立在对这个知识栈的理解之上。 + +## 核心概念 + +### Kubernetes 核心对象关系 + +```mermaid +graph TD + Node[Node / 节点] --> Pod[Pod / 最小部署单元] + Pod --> C[Containers / 容器] + Deployment[Deployment / 副本控制] --> Pod + Service[Service / 网络暴露] --> Pod + Namespace[Namespace / 资源隔离] --> Deployment + Namespace --> Service + PV[PersistentVolume / 持久存储] --> PVC[PVC / 申请存储] + PvcRef[PVC ref by Pod] --> Pod +``` + +| 对象 | 职责 | 类比 | +|------|------|------| +| **Node** | 运行 Pod 的物理机或虚拟机 | 服务器 | +| **Pod** | 一个或多个容器的打包体 | 应用实例 | +| **Deployment** | 管理 Pod 的副本数、滚动更新策略 | 发布控制器 | +| **Service** | 为一组 Pod 提供稳定的访问入口(负载均衡) | 反向代理 | +| **Namespace** | 逻辑隔离的资源分组 | 多租户文件夹 | +| **ConfigMap / Secret** | 将配置注入 Pod(非敏感/敏感数据分离) | .env 文件 | +| **Ingress** | 七层路由,HTTP/HTTPS 域名到 Service 的映射 | Nginx 规则 | + +### RKE2 vs 原生 K8s + +RKE2(Rancher Kubernetes Engine v2)的核心特点: + +1. **单二进制部署**:不需要单独安装 etcd、containerd 等依赖,一条命令拉起整集群 +2. **SST(Simple System Tray)**内置 SQLite,etcd 作为可选而非必须 +3. **FIPS 140-2 合规**:内置加密要求,适合企业对安全审计的需要 +4. **自动注册与拉取**:可配合 Rancher Server 实现节点无感加入 + +> [!info] 为什么选 RKE2? +> xinfra 需要管理**七机房多套集群**,RKE2 的"一键部署 + 低运维成本"特性正好契合——减少环境差异导致的兼容问题,让平台专注于上层抽象而非底层排障。 + +### RKE2 安装方式对比 + +| 方式 | 命令特点 | 适用场景 | 是否支持 Rancher 集成 | +|------|---------|---------|---------------------| +| **单二进制直接运行** | `curl -sfL https://get.rke2.io | sh -` | 开发测试、小规模集群(≤3 节点) | ✅ — 自动发现并注册 | +| **Systemd 服务管理** | 安装后通过 `systemctl enable --now rke2-server` | 生产环境标准化部署 | ✅ | +| **Air-gap(离线)** | 预下载 `.tar.gz` 包 + `INSTALL_DIR=/opt/rke2` 指向本地文件 | 内网无外网环境的机房 | ❌ — 需手动同步镜像 | + +> [!warning] Air-gap 是常见坑点 +> RKE2 Server/Agent 首次启动时会从官方 registry 拉取 K8s 组件 OCI 镜像。如果机房**无法访问外网**,必须提前准备 image bundle tarball,并通过 `--image-volume-mount /var/lib/rancher/rke2/agent/image-store` 指定本地缓存路径。 + +### 节点注册机制详解 + +Worker 节点加入集群有两种认证方式: + +```bash +# 方式 1:静态 Token(最简单,适合小集群) +# 服务端会在 /etc/rancher/rke2/rke2.yaml 旁生成 token +export TOKEN="K10xxx...from server node" +rke2 agent --server https://master-ip:6443 --token $TOKEN + +# 方式 2:Bootstrap 证书签名(推荐,支持 TLS 双向认证) +# Agent 首次连接时发送 CSR(Certificate Signing Request), +# kube-controller-manager 审批后颁发客户端证书 +``` + +关键文件分布: + +| 路径 | 内容 | 说明 | +|------|------|------| +| `/etc/rancher/rke2/rke2.yaml` | kubeconfig(含 admin 权限证书) | ⚠️ 等同于集群 master key,务必备份保护 | +| `/var/lib/rancher/rke2/agent/` | 容器镜像、kubelet 证书 | Agent 工作目录 | +| `/var/lib/rancher/rke2/server/` | etcd 数据、控制平面组件 | Server 工作目录 | +| `/var/lib/rancher/rke2/bin/` | rke2、kubectl、crictl 等 | 可执行文件软链到原位置 | + +### RKE2 配置管理 + +RKE2 支持多种配置来源,优先级从低到高: + +```yaml +# 1. 系统级配置(最低优先级) +# /etc/rancher/rke2/config.yaml +tls-san: + - "k8s.company.com" +cluster-cidr: 10.42.0.0/16 +service-cidr: 10.43.0.0/16 + +# 2. Systemd Override(覆盖默认 service 参数) +# /etc/systemd/system/rke2-server.service.d/override.conf +[Service] +Environment="RKE2_TOKEN=${TOKEN}" +Environment="NODE_LABEL=node-role=true,datacenter=bj" + +# 3. CLI 参数(最高优先级,覆盖 config.yaml) +# systemctl start rke2-server --token=TOKEN --cluster-cidr=10.42.0.0/16 +``` + +> [!tip] 自定义 CNI 插件 +> RKE2 默认使用 Canal(Calico + Flannel 组合)。如果需要更换为 Cilium,只需在 `config.yaml` 中添加: +> ```yaml +> cni: cilium +> ``` +> 重新拉起 Server 即可自动替换网络方案——这是 RKE2 比原生 K8s 更省心的地方:**网络方案可以配置驱动,而不是代码依赖**。 + +### RKE2 集群架构 + +```mermaid +graph TB + subgraph "Master Node(控制平面)" + RKE2[RKE2 Server
rke2 server --token=TOKEN] + APIServer[Kube-apiserver] + ControllerMgr[Kube-controller-manager] + Scheduler[Kube-scheduler] + ETCD[(etcd DB)] + CCM[Cloud Controller Manager] + APIServer --> ControllerMgr + APIServer --> Scheduler + APIServer <--> ETCD + RKE2 --> APIServer + RKE2 --> ControllerMgr + RKE2 --> Scheduler + RKE2 --> ETCD + RKE2 --> CCM + end + + subgraph "Worker Node(工作节点)" + RKE2W[RKE2 Agent
rke2 agent --server=https://MASTER_IP:6443 --token=TOKEN] + Kubelet1[Kubelet] + KubeProxy1[Kube-proxy] + Containerd1[containerd] + RKE2W --> Kubelet1 + RKE2W --> KubeProxy1 + RKE2W --> Containerd1 + end + + Dev[kubectl / Wayne API] --> APIServer + APIServer -. kubeconfig .-> RKE2W + Kubelet1 -. etcd sync .-> ETCD +``` + +关键流程说明: +1. **RKE2 Server 启动后**会自动拉取对应 K8s 版本的组件包(kube-apiserver、controller-manager 等),解压到 `/var/lib/rancher/rke2/`,通过 systemd 管理运行 +2. **Agent 节点**只需传入 `--token`(静态认证令牌)和 `--server` URL,即可自动完成 TLS 证书握手并加入集群 +3. **默认使用 containerd** 作为容器运行时——无需单独安装 Docker,这也是 RKE2 比 k3s 更"正规"的原因之一 + +### Pod 生命周期与调度流程 + +Pod 从创建到运行的完整链路: + +```mermaid +sequenceDiagram + participant user as 开发者 (kubectl/Wayne) + participant apiserver as kube-apiserver + participant scheduler as kube-scheduler + participant node as Node Kubelet + participant containerd as containerd + + user->>apiserver: POST /api/v1/namespaces/default/pods + apiserver->>apiserver: 验证 RBAC + 持久化到 etcd + Note over apiserver: Pod 状态 = Pending + apiserver-->>user: 201 Created + + scheduler->>apiserver: LIST pods (unassigned) + scheduler->>scheduler: 预选 (Fit) → 优先级排序 (Score) + scheduler->>apiserver: PATCH pod -> set nodeName + Note over apiserver: Pod 状态仍为 Pending(等待 Kubelet 响应) + + apiserver-->>node: WATCH pod assigned to this node + node->>containerd: Pull image (if not cached) + node->>containerd: Create container + node->>node: Set readinessProbe + Note over node: Pod 状态 = Running + node->>apiserver: UPDATE pod status +``` + +> **启发问题**:为什么调度器选中节点后,Pod 不会立即变成 Running,而还需要 Kubelet 配合?——因为调度器只负责"选地址",真正的镜像拉取、容器创建、网络挂载都由 Kubelet 在本机完成。这体现了**控制面与数据面的职责分离**。 + +### 典型部署流程 + +```bash +# 1. 编写 Deployment YAML +kubectl apply -f deployment.yaml + +# 2. 编写 Service YAML +kubectl apply -f service.yaml + +# 3. 查看状态 +kubectl get pods -n +kubectl describe pod -n + +# 4. 滚动更新(改镜像版本) +kubectl set image deployment/ app= -n +kubectl rollout status deployment/ -n +``` + +**Deployment YAML 骨架:** + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-service + namespace: default +spec: + replicas: 3 # 期望副本数 + strategy: + type: RollingUpdate # 滚动更新策略 + rollingUpdate: + maxSurge: 1 # 更新时最多比期望多 1 个 Pod + maxUnavailable: 0 # 更新时不允许不可用 + selector: + matchLabels: + app: my-service + template: # Pod 模板 + metadata: + labels: + app: my-service + spec: + containers: + - name: app + image: registry/my-service:v1.2.0 + ports: + - containerPort: 8080 +``` + +### Service 类型详解 + +Service 是 Pod 的"稳定门面",不同 type 决定了流量如何到达 Pod: + +| type | 工作原理 | 适用场景 | +|------|---------|---------| +| **ClusterIP**(默认) | K8s 内部虚拟 IP,仅集群内可访问 | 服务间调用,不对外暴露 | +| **NodePort** | 在每个节点上开放一个端口,外部可通过 `:` 访问 | 快速测试、开发环境验证 | +| **LoadBalancer** | 对接云厂商 LB 自动创建公网 IP | 云上生产环境 | +| **Ingress** | 七层路由,基于域名/路径分发到不同 Service | 多服务共享入口,HTTPS 终结 | + +> [!warning] NodePort vs Ingress +> NodePort 只做到四层 TCP/UDP 负载均衡——无法按域名路由。如果你的应用需要 `api.example.com` → Service-A、`web.example.com` → Service-B 这种能力,必须用 **Ingress**。xinfra 中通常配合 Nginx Ingress Controller 使用。 + +**Ingress 示例:** + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: my-service-ingress + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "true" # 强制 HTTPS +spec: + rules: + - host: api.myapp.company.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: my-service # 对应 ClusterIP Service + port: + number: 80 +``` + +--- + +### kubectl 速查手册 + +日常运维最高频的命令组合: + +```bash +# ── 查看 ── +kubectl get pods -A # 所有 namespace 的 Pod +kubectl get svc,ingress -n prod # 查看 Service + Ingress +kubectl top pod -n staging --containers # 容器级 CPU/Memory 用量 + +# ── 调试 ── +kubectl exec -it -- /bin/sh # 进入容器 Shell +kubectl logs -f -c -n ns # 查看指定 Sidecar 日志 +kubectl describe pod -n ns # 查看详细事件(调度失败原因等) + +# ── 资源操作 ── +kubectl rollout undo deployment/ -n ns # 回滚到上一版本 +kubectl scale deployment/ --replicas=5 -n ns # 手动扩缩容 +kubectl patch deployment/ -p '{"spec":{"template":{"spec":{"containers":[{"name":"app","image":"new:v2"}]}}}}' -n ns # 热更新镜像 +``` + +> [!tip] `-A` 标志 = `--all-namespaces`,当你不确定资源在哪个 namespace 时非常有用。但正式脚本中不建议滥用,容易造成误操作。 + +--- + +## 常见陷阱与最佳实践 + +### 1. Resource Limit 缺失 + +不设置 `resources.limits` 的 Pod 在节点资源紧张时会抢占其他 Pod 资源,导致雪崩: + +```yaml +# 推荐:每个容器都要设请求值和上限 +containers: +- name: app + resources: + requests: { cpu: "100m", memory: "128Mi" } # 调度依据 + limits: { cpu: "500m", memory: "512Mi" } # 硬上限 +``` + +### 2. Liveness vs Readiness 混淆 + +- **livenessProbe**:判断容器是否"活着",失败则重启 Pod +- **readinessProbe**:判断容器能否接收流量,失败则从 Service 后端摘除 + +```yaml +# 正确姿势:两个都设,readiness 更激进(快判快入),liveness 更保守 +readinessProbe: + httpGet: { path: /healthz, port: 8080 } + initialDelaySeconds: 3 + periodSeconds: 5 +livenessProbe: + httpGet: { path: /healthz, port: 8080 } + initialDelaySeconds: 15 + periodSeconds: 10 +``` + +### 3. 频繁查看日志的习惯 + +```bash +# 实时跟踪单个 Pod 日志 +kubectl logs -f -n + +# 如果是重启过的 Pod,看上一次容器的日志 +kubectl logs -f -n --previous +``` + +### 4. CrashLoopBackOff — 最常见的 Pod 异常状态 + +Pod 反复崩溃重启时,排查顺序如下: + +```mermaid +flowchart TD + S[CrashLoopBackOff] --> C1{kubectl describe pod
看 REASON} + C1 -->|ImagePullBackOff| I1[检查镜像仓库可达性 + ImagePullSecrets] + C1 -->|OOMKilled| M1[调大 memory limit / 排查内存泄漏] + C1 -->|CreateContainerConfigError| CM1[检查 ConfigMap/Secret 是否存在] + C1 -->|ErrImagePull| E1[镜像 tag 错误或 registry 认证失败] + + C1 -->|Initialized/Ready/-/Running| LOGS[kubectl logs -p] + LOGS --> APP[应用自身启动失败?] + APP -->|Yes| FIX[检查启动参数 + 依赖服务连接性] + APP -->|No| DEEP[深入 containerd/containerd-shim 日志] +``` + +### 5. Ingress 404 或无法访问 + +开发环境常见"Service 存在但外部打不通"的问题,排查清单: + +1. **Nginx Ingress Controller Pod 是否 Running** → `kubectl get pods -n ingress-nginx` +2. **Ingress 资源是否有 `loadBalancer.ip`** → `kubectl get ingress -n `(若无 IP,可能云厂商 LB 未就绪) +3. **Endpoint 是否有地址** → `kubectl get endpoints -n `(为空说明没有 Ready 的 Pod 匹配) +4. **DNS 解析是否正确** → 内网环境可能需要手动配置 hosts 或使用 CoreDNS + +## 关联笔记 + +以下文档构成了 xinfra 容器化部署的知识链: + +- [[technical/xinfra-preview/wayne-overview]] — Wayne 上层的 YAML 模板就是基于这些 K8s 对象 +- [[technical/xinfra-preview/cachecloud-overview]] — CacheCloud 管理 Redis,其宿主机未来可能迁移至 K8s 部署 +- [[technical/xinfra-preview/cloud-dm-overview]] — K8s 内的 MySQL 实例由 CloudDM 做 SQL 审核 +- [[technical/xinfra-preview/ansible-playbook-basics]] — Ansible Playbook 负责 RKE2 集群的底层裸机/VMAutomation diff --git a/technical/xinfra-preview/wayne-overview.md b/technical/xinfra-preview/wayne-overview.md new file mode 100644 index 0000000..e61a7a1 --- /dev/null +++ b/technical/xinfra-preview/wayne-overview.md @@ -0,0 +1,152 @@ +--- +tags: [wayne, preview, infra] +create time: 2026-07-04 12:00 +--- + +# Wayne 多集群容器管理平台 + +## 概述 + +Wayne(由 360 开源)是一个基于 Web 的多集群 Kubernetes 容器管理平台,支持通过可视化的方式创建、管理 Deployment 和 Service。xininfra 平台将其作为核心的**服务发布入口**——开发同学无需直接操作 kubectl,通过 Wayne UI 或 API 即可完成服务部署。 + +> [!info] 背景 +> Wayne 已大规模服务于 360 搜索内部,稳定管理近千个业务、上万个容器,运行两年以上。命名源于 DC 漫画角色「Bruce Wayne」(蝙蝠侠)。 + +## 核心概念 + +### 架构概览 + +```mermaid +graph LR + subgraph 前端 + UI["Web UI / Angular + Ace Editor"] + end + subgraph 后端 + API["API Server / Beego (Go)"] + Worker["Worker / 异步任务"] + DB[("MySQL - 持久化存储")] + end + subgraph 底层 + K8s1[K8s Cluster A] + K8s2[K8s Cluster B] + K8N[...] + end + UI --> API + API <--> DB + API -->|"Client-Go"| K8s1 + API -->|"Client-Go"| K8s2 + API -->|"消息队列"| Worker + Worker -->|"Audit / Webhook"| K8s1 +``` + +核心交互: +- **前端**:Angular 框架 + Ace Editor 实现 YAML 模板编辑,提供表单式部署界面 +- **后端**:Beego(Go 框架)处理 HTTP API → Client-Go 操作 K8s API,数据持久化到 MySQL +- **Worker**:基于消息队列的异步任务组件,负责审计日志、Webhook 通知等 +- **数据库**:存储项目/用户/部门权限关系、YAML 模板版本历史、发布记录与审计数据 + +### 核心模型 + +| 模型 | 说明 | +|------|------| +| **Project** | 项目级分组,相当于 Git Repo 的映射 | +| **Cluster** | 注册的 K8s 集群连接信息(kubeconfig) | +| **Namespace** | 集群内的逻辑隔离空间 | +| **Environment** | 环境(dev / staging / prod),用于区分不同阶段的部署 | +| **Deployment** | 应用层面的容器编排配置 | +| **Service** | 网络层面的服务暴露配置 | + +### Wayne 与 K8s 对象的对应关系 + +``` +Wayne Deployment YAML ──→ K8s Deployment + ConfigMap + Ingress +Wayne Service YAML ──→ K8s Service +``` + +Wayne 对这两种资源的 YAML 做了**标准化封装**,内置了一套模板体系: + +```yaml +# Wayne 中的 Deployment 模板骨架 +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }} +spec: + replicas: {{ .Env.Replicas | default 2 }} + template: + spec: + containers: + - name: {{ .ContainerName }} + image: {{ .Image.Repository }}:{{ .Image.Tag }} + ports: + - containerPort: {{ .Container.Ports }} +``` + +### Wayne 核心能力 + +| 能力 | 说明 | 对你的意义 | +|------|------|-----------| +| **RBAC 权限管理** | 用户通过角色关联部门与项目,部门角色 vs 项目角色分离 | 多租户场景下按团队划分资源边界 | +| **简化 K8s 对象创建** | 基础模式(表单+模板)+ 高级模式(直接编辑 JSON/YAML) | 降低业务接入成本,无需记忆 kubectl 命令 | +| **多集群管理** | 统一入口管理多个 K8s 集群,可针对集群定制配置 | xininfra 跨机房、跨集群部署的基础 | +| **完整审计模块** | 每次操作留痕,支持自定义 Webhook 回调 | 故障追溯、合规检查的关键支撑 | +| **发布历史与回滚** | 保存所有版本发布记录,一键回滚或基于旧版更新 | 生产安全的底线保障 | +| **Web Shell** | 基于严格权限校验的 Pod 远程终端 | 排查线上问题的快捷通道 | +| **资源报表** | 各项目资源使用占比、上线频次等图表 | 容量规划与成本分摊依据 | +| **站内通知系统** | 管理员推送集群公告、故障报告等 | 信息同步通道 | +| **APIKey 开放接口** | 用户可自助申请 APIKey 管理自己的部门/项目,运维可获取全局 APIKey 进行批量操作 | CI/CD 自动化的基础凭证 | + +### 认证登录模式 + +Wayne 支持三种认证方式,适应不同企业的集成需求: + +| 模式 | 适用场景 | +|------|---------| +| **DB 内置** | 独立运行,不依赖外部认证服务 | +| **LDAP** | 与企业组织架构打通,同步部门用户 | +| **OAuth 2.0** | 对接已有 SSO / Identity Provider | + +> [!warning] 实习环境 +> xininfra 目前使用 DB 模式 + LDAP 混合架构。开发同学通过 LDAP 账号登录 Wayne,但权限分配由 xininfra 侧统一管控。 + +### API 对接思路 + +Wayne 提供 RESTful API,适合 CI/CD 流水线自动化调用: + +```bash +# 1. 登录获取 token +curl -X POST http://wayne-host/api/user/token/ \ + -H "Content-Type: application/json" \ + -d '{"username": "admin", "password": "wayne"}' + +# 2. 基于模板创建 Deployment(GitLab CI 场景) +curl -X POST http://wayne-host/api/project/{project-id}/environment/{env-id}/deployment/template/ \ + -H "Authorization: Bearer {token}" \ + -H "Content-Type: application/json" \ + -d '{"templateName": "my-service", ...}' +``` + +> [!tip] GitLab CI 对接 Wayne 的设计方向 +> 实习目标是开发 GitLab CI 自动触发 Wayne API 创建 Deployment 和 Service,流程大致为: +> `CI 编译 → 镜像推送到 Registry → CI 调 Wayne API 传入镜像 tag → Wayne 执行部署` + +## 常见陷阱与最佳实践 + +### 1. 权限模型要提前规划 + +Wayne 的 Project → Environment → Namespace 三级结构容易与实际的 K8s 权限边界不对齐。**建议**:每个业务团队一个 Project,按环境划分 Environment,避免多人混用同一命名空间。 + +### 2. YAML 模板版本管理 + +Wayne 允许保存多个 Deployment Template 版本。生产环境的模板应该锁定版本并纳入代码仓库,避免「今天能跑明天不行」的问题。 + +### 3. APIKey 权限边界要明确 + +运维人员的全局 APIKey 拥有所有集群和资源的操作权限。**原则**:给 CI/CD 流水线分配最小必要范围的 APIKey,限制其可操作的 Project 和环境范围,避免凭证泄漏导致大面积影响。 + +## 延伸阅读 + +- [[technical/xinfra-preview/k8s-rke2-fundamentals]] — Wayne 上层的 K8s 对象知识基础 +- [[technical/xinfra-preview/cloud-dm-overview]] — Wayne 部署的服务通常依赖 CloudDM 管理的 MySQL +- [[technical/xinfra-preview/cachecloud-overview]] — Wayne 部署的服务可能使用 CacheCloud 管理的 Redis +- https://github.com/Qihoo360/wayne — Wayne GitHub 仓库 diff --git a/weekly/00-week-zero-prep-guide.md b/weekly/00-week-zero-prep-guide.md index 5fa5666..34fd304 100644 --- a/weekly/00-week-zero-prep-guide.md +++ b/weekly/00-week-zero-prep-guide.md @@ -59,5 +59,53 @@ create time: 2026-07-01 00:00 - [ ] Go(GOPROXY)配置完成并验证 - [ ] 跑通至少一个 Coding Agent,配置好 GitHub CLI +## 五、项目8 · xinfra 预备知识 + +### 项目背景 + +xininfra 是公司的统一基础设施平台(Project 8),旨在解决因多条业务线长期独立建设带来的技术债:网络平面混杂(BGP/NAT/macvlan 并存)、K8s 方案多套(KubeSphere/KubeVirt/裸集群/EKS)、存储异构(Ceph/OpenEBS)、发布体系手工操作多、多云资源分散管理等。平台以七机房容器资源池化为核心,配套 CI/CD 双引擎、数据库平台、WAF 安全态势、大内网互联和多云成本看板,系统性重建公司基础设施底座。 + +### 技术栈与学习资源 + +以下工具和平台需在开营前初步了解其概念和基本用法,详细知识点可参考下方对应预习笔记: + +| # | 工具 | 用途 | 预习笔记 | +|---|------|------|----------| +| 1 | Wayne | 多集群容器管理和发布平台 | [[technical/xinfra-preview/wayne-overview]] | +| 2 | Rancher RKE2 / K8s | 容器编排底层 | [[technical/xinfra-preview/k8s-rke2-fundamentals]] | +| 3 | CloudDM (open-cdm) | 数据库管理及 SQL 审核平台 | [[technical/xinfra-preview/cloud-dm-overview]] | +| 4 | CacheCloud | Redis 管理平台 | [[technical/xinfra-preview/cachecloud-overview]] | +| 5 | Ansible & Playbook | 自动化部署工具 | [[technical/xinfra-preview/ansible-playbook-basics]] | + +入口导航:[[xinfra-preview]] — xinfra 预习知识地图 + +> [!tip] 预习建议 +> 不必深入源码,重点理解:**每个工具的定位**(解决什么问题)、**基本架构**(有哪些组件)、**典型使用流程**(如部署一个服务的完整链路)。 + +### 学习目标 + +#### 基础目标 + +1. 熟练搭建 **RKE2 K8s 集群**,能基于 YAML 和 `kubectl` 部署服务 +2. 熟悉 **Wayne 多集群容器管理平台**的安装部署,能基于 Wayne 进行服务发布 +3. 熟悉 Wayne 的 API 及库表,基于 Deployment 和 Service 部署 YAML 模板,开发 GitLab CI 对接 Wayne 自动创建部署和服务 +4. 熟悉 **CloudDM 审核平台**及 **CacheCloud Redis 管理台**部署,能通过这两个平台进行 SQL 上线和 Redis 实例开启 +5. 基于 Wayne + CloudDM + CacheCloud 的 API 来实现 XINFRA 统一服务管理平面 + +#### 进阶目标 + +1. 熟练使用 **Ansible Playbook** 来部署 MySQL Server、PostgreSQL、Redis Cluster +2. 创建 xininfra 统一服务管理页面,可通过页面直接创建 MySQL 主从、PostgreSQL 主从、Redis Cluster + +### 打卡清单 + +- [ ] 了解 Wayne 项目,阅读 README 并理解其架构 +- [ ] 浏览 RKE2 / K8s 文档,熟悉基本概念(Cluster、Deployment、Service、Pod) +- [ ] 了解 CloudDM 和 CacheCloud 的基本功能和定位 +- [ ] 学习 Ansible Playbook 基础语法(hosts、tasks、roles) +- [ ] 确认 Go 或 Python + Flask 至少其一的开发环境可用 +- [ ] 通读基础目标和进阶目标,明确后续实习期间的能力要求 + ## 关联笔记 - [[technical/mac-dev-env-setup]] — macOS 开发环境详细配置指南 +- [[xinfra-preview]] — xininfra 预习知识地图(5 篇预习笔记入口)