vault backup: 2026-07-04 20:23:48
This commit is contained in:
@@ -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]] | 服务自动化部署工具 |
|
||||
@@ -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/<hostname>/all.yml — 特定主机变量
|
||||
# 2. group_vars/<group>/all.yml — 主机组共享变量
|
||||
# 3. roles/<role>/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 基础用法参考
|
||||
@@ -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[报警组件<br/>邮件 / 微信 / HTTP]
|
||||
CUSTOM[自定义扩展模块]
|
||||
end
|
||||
|
||||
subgraph "执行层 (Agent 代理)"
|
||||
AGT1[Agent 宿主机 A<br/>Redis Standalone / Sentinel]
|
||||
AGT2[Agent 宿主机 B<br/>Redis Cluster Shard 1]
|
||||
AGT3[Agent 宿主机 C<br/>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<String, String> clusterConnection(RedisClusterClient client) {
|
||||
StatefulRedisClusterConnection<String, String> 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 官方仓库
|
||||
@@ -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** | 官网:<https://www.cdmgr.com/>
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 定位与设计哲学
|
||||
|
||||
```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 容器化部署基础
|
||||
- <https://github.com/ClouGence/open-cdm> — open-cdm 主仓库(GitHub)
|
||||
- <https://gitee.com/clougence/open-cdm> — 中国镜像仓库
|
||||
- [[technical/xinfra-preview/cloud-dm-overview#核心能力模块]] — 本文档「核心能力模块」章节
|
||||
@@ -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<br/>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<br/>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 <namespace>
|
||||
kubectl describe pod <pod-name> -n <namespace>
|
||||
|
||||
# 4. 滚动更新(改镜像版本)
|
||||
kubectl set image deployment/<name> app=<new-image> -n <namespace>
|
||||
kubectl rollout status deployment/<name> -n <namespace>
|
||||
```
|
||||
|
||||
**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** | 在每个节点上开放一个端口,外部可通过 `<NodeIP>:<port>` 访问 | 快速测试、开发环境验证 |
|
||||
| **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 <pod> -- /bin/sh # 进入容器 Shell
|
||||
kubectl logs -f <pod> -c <sidecar-name> -n ns # 查看指定 Sidecar 日志
|
||||
kubectl describe pod <pod> -n ns # 查看详细事件(调度失败原因等)
|
||||
|
||||
# ── 资源操作 ──
|
||||
kubectl rollout undo deployment/<name> -n ns # 回滚到上一版本
|
||||
kubectl scale deployment/<name> --replicas=5 -n ns # 手动扩缩容
|
||||
kubectl patch deployment/<name> -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 <pod-name> -n <namespace>
|
||||
|
||||
# 如果是重启过的 Pod,看上一次容器的日志
|
||||
kubectl logs -f <pod-name> -n <namespace> --previous
|
||||
```
|
||||
|
||||
### 4. CrashLoopBackOff — 最常见的 Pod 异常状态
|
||||
|
||||
Pod 反复崩溃重启时,排查顺序如下:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S[CrashLoopBackOff] --> C1{kubectl describe pod<br/>看 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 <ns>`(若无 IP,可能云厂商 LB 未就绪)
|
||||
3. **Endpoint 是否有地址** → `kubectl get endpoints <service-name> -n <ns>`(为空说明没有 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
|
||||
@@ -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 仓库
|
||||
@@ -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 篇预习笔记入口)
|
||||
|
||||
Reference in New Issue
Block a user