当前位置: 首页 > news >正文

10.Ansible角色管理

10-Ansible 角色管理

文章目录

    • 10-Ansible 角色管理
      • 实验环境准备
      • Ansible 角色
        • 角色介绍:为什么需要角色?
        • 角色结构:标准化的目录布局
        • 角色存放位置:Ansible 去哪里找角色?
        • 创建角色:实战示例(部署 Apache 服务)
        • 调用角色:在 Playbook 中使用角色
        • 角色依赖:一个角色依赖另一个角色
        • 任务执行顺序:pre_tasks、roles、tasks、post_tasks
        • Handlers 执行顺序:何时触发处理程序?
        • include_role 和 import_role:在任务中动态调用角色
      • Ansible 角色优势与开发最佳实践
        • 优势
        • 开发最佳实践
      • 使用系统角色(以 RHEL 为例)
        • 系统角色介绍
        • 安装与查看
        • 案例 1:用 timesync 角色配置时间同步
        • 案例 2:用 selinux 角色配置 SELinux
      • 使用 Ansible Galaxy 获取公共角色
        • 常用`ansible-galaxy`命令
        • 实战:用 Galaxy 角色部署 Web 集群

实验环境准备

操作流程

  1. 创建工作目录并进入
  2. 配置 Ansible 全局设置(ansible.cfg
  3. 定义主机清单(inventory
# 创建名为web的工作目录并进入
[bq@controller ~]$ mkdir web && cd web# 创建Ansible配置文件ansible.cfg,定义默认参数
[bq@controller web]$ cat > ansible.cfg <<'EOF'
[defaults]
remote_user = bq               # 默认远程登录用户为bq
inventory = ./inventory        # 指定inventory文件路径为当前目录下的inventory[privilege_escalation]
become = True                  # 允许提权(切换到root)
become_user = root             # 提权目标用户为root
become_method = sudo           # 提权方式为sudo
become_ask_pass = False        # 提权时不询问密码(需提前配置sudo免密)
EOF# 创建主机清单文件,定义需要管理的主机
[bq@controller web]$ cat > inventory <<'EOF'
controller  # 控制节点
node1       # 被控节点1
node2       # 被控节点2
node3       # 被控节点3
node4       # 被控节点4
EOF

Ansible 角色

角色介绍:为什么需要角色?

在实际工作中,我们编写的 Playbook 会越来越复杂:可能包含几十甚至上百个任务,还会引用各种文件、模板和变量。如果每次部署类似服务(比如 Web 服务器、数据库)都重新写一遍 Playbook,不仅效率低,还容易出错。

Ansible 角色就是为解决这个问题而生的:它把部署一个服务所需的所有任务、变量、文件、模板等资源,按标准化的目录结构打包。这样一来,我们可以把角色复制到不同项目中,直接调用即可,大大提高了代码的复用性和可维护性。

角色结构:标准化的目录布局

Ansible 角色有固定的目录结构,通过ansible-galaxy init命令可以自动创建。我们先看一个示例:

# 初始化一个名为bq的角色(自动创建标准目录结构)
[bq@controller web]$ ansible-galaxy init bq
- bq was created successfully# 查看角色的目录结构
[bq@controller web]$ tree bq
bq
├── defaults          # 角色默认变量(优先级低,可被覆盖)
│   └── main.yml
├── files             # 静态文件(如配置文件、脚本等,可被任务直接引用)
├── handlers          # 处理程序(如服务重启等,由任务触发)
│   └── main.yml
├── meta              # 角色元信息(作者、依赖、支持的平台等)
│   └── main.yml
├── README.md         # 角色说明文档(用途、用法、依赖等)
├── tasks             # 核心任务(角色的主要操作,如安装、配置等)
│   └── main.yml
├── templates         # Jinja2模板文件(动态生成配置文件,带变量)
├── tests             # 测试相关(测试用的inventory和Playbook)
│   ├── inventory
│   └── test.yml
└── vars              # 角色内部变量(优先级高,不建议在Playbook中修改)└── main.yml8 directories, 8 files

各目录作用详解

  • defaults/main.yml:默认变量,几乎所有其他变量(如清单变量、Playbook 中的 vars)都能覆盖它。适合作为 “可自定义的参数”,比如 Web 服务的默认端口。
  • files:存放静态文件(如固定内容的配置文件),任务中引用时无需写路径,Ansible 会自动在这里查找。
  • handlers/main.yml:处理程序,比如 “重启 Apache”“重载 Nginx” 等操作,由任务通过notify触发。
  • meta/main.yml:元信息,包括作者、支持的操作系统(如 CentOS、Ubuntu)、角色依赖(如部署 Web 服务前需要先部署防火墙)等。
  • tasks/main.yml:核心任务集合,定义角色要执行的操作(如安装软件、启动服务、复制文件等)。
  • templates:存放 Jinja2 模板(文件名通常以.j2结尾),可通过变量动态生成配置文件(如根据主机名生成不同的虚拟主机配置)。
  • vars/main.yml:角色内部变量,优先级较高(仅低于事实变量、注册变量等),用于角色内部逻辑,不建议在外部修改。
角色存放位置:Ansible 去哪里找角色?

Ansible 默认会从以下目录查找角色(优先级从高到低):

  1. ~/.ansible/roles(当前用户的角色目录)
  2. /usr/share/ansible/roles(系统级共享角色目录)
  3. /etc/ansible/roles(系统默认角色目录)

如果想自定义角色路径,可以在ansible.cfg中通过roles_path设置:

[defaults]
# 多个路径用冒号分隔,Ansible会按顺序查找
roles_path = ./roles:/etc/ansible/roles/custom
创建角色:实战示例(部署 Apache 服务)

实验流程

  1. 创建roles目录(统一存放角色)
  2. 初始化apache角色
  3. 配置角色的核心文件(任务、变量、模板、处理程序等)
  4. 编写 Playbook 调用角色
  5. 执行并验证结果

步骤细化

  1. 创建角色目录并初始化apache角色
# 创建roles目录(用于存放所有角色)
[bq@controller web]$ mkdir roles# 初始化apache角色,并指定存放路径为./roles
[bq@controller web]$ ansible-galaxy init apache --init-path=./roles
- apache was created successfully# 进入apache角色目录,准备配置文件
[bq@controller web]$ cd roles/apache/
  1. 配置tasks/main.yml(核心任务)
    任务定义了角色要执行的操作:安装 Apache、启动服务、生成配置文件等。
---
# tasks file for apache:部署Apache服务的核心任务# 安装Web服务软件(包名通过变量web_package指定)
- name: install web serveryum:name: "{{ web_package }}"  # 引用变量(默认值在defaults中定义)state: latest              # 确保安装最新版本# 启动Web服务并设置开机自启
- name: start and enable web serviceservice:name: "{{ web_service }}"  # 服务名通过变量web_service指定state: started             # 确保服务处于启动状态enabled: yes               # 开机自启# 生成/etc/motd文件(登录提示,用模板动态生成)
- name: generate motd filetemplate:src: motd.j2               # 模板文件(位于templates目录)dest: /etc/motd            # 目标路径# 生成Apache虚拟主机配置文件
- name: generate virtual host configtemplate:src: bq.conf.j2            # 虚拟主机模板dest: /etc/httpd/conf.d/bq.conf  # Apache额外配置目录notify:                      # 配置文件变化时,触发处理程序- restart_web              # 重启Web服务(在handlers中定义)# 创建网站根目录(路径包含当前主机名,确保每个主机独立)
- name: create document rootfile:path: "/var/www/html/{{ ansible_hostname }}"  # ansible_hostname是facts变量(主机名)state: directory           # 确保目录存在mode: '0755'               # 权限设置# 生成网站首页(动态显示主机名)
- name: generate index.htmltemplate:src: index.html.j2         # 首页模板dest: "/var/www/html/{{ ansible_hostname }}/index.html"
  1. 配置defaults/main.yml(默认变量)
    定义可自定义的变量,比如 Web 服务的包名和服务名(默认是httpd,如需部署 Nginx 可在此修改)。
---
# defaults file for apache:可自定义的默认变量
web_package: httpd  # Web服务软件包名(如httpd、nginx)
web_service: httpd  # Web服务名(需与包名对应)
  1. 配置templates目录下的模板文件
    模板文件用于动态生成配置,这里以 3 个关键模板为例:
  • templates/motd.j2(登录提示模板):
hello guys!
Welcome to {{ ansible_fqdn }}!  # ansible_fqdn是facts变量(主机全名)
  • templates/bq.conf.j2(Apache 虚拟主机模板):
# {{ ansible_managed }}  # 标记此文件由Ansible管理
<VirtualHost *:80>ServerAdmin bq@{{ ansible_fqdn }}  # 管理员邮箱(包含主机名)ServerName {{ ansible_fqdn }}      # 虚拟主机域名ErrorLog logs/{{ ansible_hostname }}-error.log  # 错误日志路径(含主机名)CustomLog logs/{{ ansible_hostname }}-common.log common  # 访问日志路径DocumentRoot /var/www/html/{{ ansible_hostname }}/  # 网站根目录<Directory /var/www/html/{{ ansible_hostname }}/>Options +Indexes +FollowSymlinks +Includes  # 目录选项Order allow,denyAllow from all  # 允许所有IP访问</Directory>
</VirtualHost>
  • templates/index.html.j2(网站首页模板):
Welcome to {{ ansible_fqdn }} !  # 显示主机全名
  1. 配置handlers/main.yml(处理程序)
    定义需要被任务触发的操作(如配置文件更新后重启服务)。
---
# handlers file for apache:处理程序(由任务notify触发)
- name: restart_web  # 处理程序名称(需与tasks中的notify对应)service:name: "{{ web_service }}"  # 服务名(引用变量)state: restarted           # 重启服务
  1. 配置meta/main.yml(元信息)
    说明角色的作者、支持的平台、标签等(方便其他人理解和使用)。
---
galaxy_info:author: bq                    # 作者description: Deploy Apache web server  # 角色描述company: bq world             # 公司/组织license: GPLv2                # 许可证min_ansible_version: 2.4      # 最低支持的Ansible版本platforms:                    # 支持的操作系统- name: Fedoraversions:- all- 25galaxy_tags: [apache, web]    # 标签(方便搜索)
dependencies: []                # 角色依赖(暂时为空)
调用角色:在 Playbook 中使用角色

角色配置完成后,只需在 Playbook 中通过roles关键字调用即可。

示例 Playbook(deploy_apache.yml

---
- name: deploy apache web server  # Play名称hosts: node1                   # 目标主机(部署到node1)roles:- apache                     # 调用apache角色(从roles目录查找)

执行与验证

# 执行Playbook
[bq@controller web]$ ansible-playbook deploy_apache.yml# 验证1:登录node1,查看motd(登录提示)
[bq@controller web]$ ssh root@node1
# 预期输出:
hello guys!
Welcome to node1.lab.example.com!  # 显示node1的主机全名# 验证2:访问Web服务(node1的首页)
[root@node1 ~]# curl http://node1/
# 预期输出:
Welcome to node1.bq.cloud !  # 显示node1的主机全名
角色依赖:一个角色依赖另一个角色

场景:部署 Web 服务时,需要先确保防火墙放行 80 端口。这时可以让apache角色依赖firewall角色,实现自动部署防火墙并配置规则。

实验流程

  1. 修改apache角色的元信息,添加对firewall角色的依赖
  2. 创建firewall角色,配置其任务和默认变量
  3. 执行 Playbook,验证依赖是否生效(防火墙自动配置并放行 http)

步骤细化

  1. 配置apache角色的依赖(roles/apache/meta/main.yml
---
galaxy_info:# 省略其他配置...
dependencies:- role: firewall  # 依赖firewall角色service: http   # 传递变量给firewall角色(放行http服务)
  1. 创建firewall角色并配置
# 初始化firewall角色,存放于roles目录
[bq@controller web]$ ansible-galaxy init firewall --init-path=./roles
- firewall was created successfully# 进入firewall角色目录
[bq@controller web]$ cd roles/firewall/
  • 配置tasks/main.yml(防火墙任务):
---
# tasks file for firewall:配置防火墙并放行指定服务# 安装firewalld软件
- name: install firewalldyum:name: firewalldstate: latest# 启动firewalld并设置开机自启
- name: start and enable firewalldservice:name: firewalldstate: startedenabled: true# 放行指定服务(服务名通过变量service传递)
- name: allow service through firewallfirewalld:state: enabled       # 永久生效immediate: true      # 立即生效(无需重启服务)permanent: true      # 永久配置(重启后不失效)service: "{{ service }}"  # 服务名(从依赖传递的变量)
  • 配置defaults/main.yml(防火墙默认变量):
---
# defaults file for firewall:默认放行ssh服务(如未传递变量则使用此值)
service: ssh
  1. 验证依赖效果
    再次执行部署apache角色的 Playbook,Ansible 会先自动执行firewall角色,再执行apache角色:
# 执行Playbook
[bq@controller web]$ ansible-playbook deploy_apache.yml# 验证:查看node1的防火墙规则,确认http服务已放行
[bq@controller web]$ ansible node1 -m shell -a "firewall-cmd --list-services"
# 预期输出包含http
任务执行顺序:pre_tasks、roles、tasks、post_tasks

Ansible 中,任务的执行顺序是固定的,与 Playbook 中编写的顺序无关:

  1. pre_tasks:在角色执行前运行的任务
  2. roles:角色中的任务
  3. tasks:Playbook 中直接定义的任务
  4. post_tasks:在所有任务和角色执行后运行的任务

实验验证

  1. 创建测试角色test_task_exec_order
# 初始化角色
[bq@controller web]$ ansible-galaxy init test_task_exec_order --init-path=roles# 配置角色任务(roles/test_task_exec_order/tasks/main.yml)
[bq@controller web]$ vim roles/test_task_exec_order/tasks/main.yml
---
# 角色中的任务:输出提示信息
- name: task in roleshell: echo 'task in role'
  1. 编写测试 Playbook(test_order.yml
---
- name: test task execute order  # 测试任务执行顺序hosts: node1gather_facts: false  # 关闭facts收集(简化输出)pre_tasks:- name: task in pre_tasksshell: echo 'task in pre_tasks'  # 输出pre_tasks提示roles:- test_task_exec_order  # 调用测试角色tasks:- name: task in tasksshell: echo 'task in tasks'  # 输出tasks提示post_tasks:- name: task in post_tasksshell: echo 'task in post_tasks'  # 输出post_tasks提示
  1. 执行并查看顺序
[bq@controller web]$ ansible-playbook test_order.yml
# 预期输出顺序:
# task in pre_tasks → task in role → task in tasks → task in post_tasks
Handlers 执行顺序:何时触发处理程序?

处理程序(Handlers)的执行顺序与任务阶段相关,规则如下:

  1. 执行pre_tasks → 触发pre_tasks中的 Handlers
  2. 执行roles → 执行tasks
  3. 触发rolestasks中的 Handlers
  4. 执行post_tasks → 触发post_tasks中的 Handlers

实验验证

  1. 修改测试角色,添加 Handlers(roles/test_task_exec_order/handlers/main.yml
---
# 角色中的处理程序
- name: role_handlershell: echo 'handle in role'
  1. 修改角色任务,触发 Handlers(roles/test_task_exec_order/tasks/main.yml
---
- name: task in roleshell: echo 'task in role'notify:  # 触发角色中的处理程序- role_handler
  1. 编写测试 Playbook(test_handler_order.yml
---
- name: test handler execute orderhosts: node1gather_facts: falsepre_tasks:- name: task in pre_tasksshell: echo 'task in pre_tasks'notify: iamhandler  # 触发全局Handlersroles:- test_task_exec_order  # 角色任务会触发role_handlertasks:- name: task in tasksshell: echo 'task in tasks'notify: iamhandler  # 触发全局Handlerspost_tasks:- name: task in post_tasksshell: echo 'task in post_tasks'notify: iamhandler  # 触发全局Handlershandlers:  # 全局处理程序- name: iamhandlershell: echo 'iamhandler'
  1. 执行并查看顺序
[bq@controller web]$ ansible-playbook test_handler_order.yml
# 预期输出顺序:
# 1. task in pre_tasks → 2. iamhandler(pre_tasks触发)
# 3. task in role → 4. task in tasks
# 5. role_handler(角色触发) → 6. iamhandler(tasks触发)
# 7. task in post_tasks → 8. iamhandler(post_tasks触发)
include_role 和 import_role:在任务中动态调用角色

这两个模块用于在tasks中调用角色(而非直接在roles中定义),支持when条件判断,灵活度更高。

  • import_role:在 Playbook 解析阶段加载角色(类似 “静态导入”),即使when条件为false,也会先解析角色(若角色有语法错误,会直接报错)。
  • include_role:在任务执行到此时才加载角色(类似 “动态导入”),若when条件为false,则不会解析角色。

示例

---
- hosts: node1tasks:- shell: echo 'first task'  # 第一个任务- name: use role in tasksimport_role:  # 或include_rolename: hello  # 调用hello角色when: ansible_hostname == 'node1'  # 仅在node1上执行

Ansible 角色优势与开发最佳实践

优势
  • 代码复用:一次编写,多处调用(如部署多个 Web 服务器时直接复用同一角色)。
  • 并行开发:不同管理员可分别开发不同角色(如一人写数据库角色,一人写 Web 角色)。
  • 易于维护:角色结构标准化,便于多人协作和后期修改。
开发最佳实践
  1. 不存储敏感信息:密码、SSH 密钥等敏感数据应通过变量传递(如用 Ansible Vault 加密),而非硬编码到角色中。
  2. 精简目录:用ansible-galaxy init创建角色后,删除不需要的目录(如无需测试可删除tests)。
  3. 完善文档:维护README.md(说明用法)和meta/main.yml(说明作者、依赖等)。
  4. 功能单一:一个角色专注于一件事(如 “部署 Apache” 而非 “部署 Apache+MySQL+PHP”)。
  5. 避免重复:优先重构现有角色以支持新场景,而非创建新角色。

使用系统角色(以 RHEL 为例)

系统角色介绍

RHEL 系统提供了rhel-system-roles软件包,包含标准化的 Ansible 角色(如时间同步、SELinux 配置等),可跨 RHEL 6/7/8 版本使用,无需担心不同版本的配置差异。

安装与查看
# 安装系统角色
[bq@controller ~]$ sudo yum install -y rhel-system-roles# 系统角色存放路径(Ansible默认会搜索此目录)
[bq@controller ~]$ ls -1 /usr/share/ansible/roles/# 查看角色文档(每个角色的用法和变量说明)
[bq@controller ~]$ ls /usr/share/doc/rhel-system-roles/
案例 1:用 timesync 角色配置时间同步

rhel-system-roles.timesync角色可统一配置 NTP 时间同步,支持 RHEL 各版本。

Playbook 示例

---
- name: configure time synchronizationhosts: node1vars:# 指定NTP服务器(classroom.example.com),启用快速同步(iburst: yes)timesync_ntp_servers:- hostname: classroom.example.comiburst: yestimezone: "Asia/Shanghai"  # 设置时区为上海roles:- rhel-system-roles.timesync  # 调用时间同步角色tasks:# 额外任务:设置时区- name: set timezonetimezone:name: "{{ timezone }}"
案例 2:用 selinux 角色配置 SELinux

rhel-system-roles.selinux角色可简化 SELinux 配置(如模式切换、布尔值设置等)。

Playbook 示例

---
- hosts: node1vars:selinux_state: permissive  # 设置SELinux为宽容模式(仅记录不阻止)# 启用httpd访问家目录的布尔值selinux_booleans:- name: 'httpd_enable_homedirs'state: 'on'persistent: 'yes'  # 永久生效# 设置/srv/www目录的SELinux上下文为httpd_sys_content_t(Web内容)selinux_fcontexts:- target: '/srv/www(/.*)?'setype: 'httpd_sys_content_t'state: 'present'# 对/srv/www目录执行restorecon(恢复SELinux上下文)selinux_restore_dirs:- /srv/www# 允许TCP 82端口使用http_port_t类型(支持HTTP服务)selinux_ports:- ports: '82'setype: 'http_port_t'proto: 'tcp'state: 'present'roles:- rhel-system-roles.selinux  # 调用SELinux角色

使用 Ansible Galaxy 获取公共角色

Ansible Galaxy(galaxy.ansible.com)是社区维护的角色仓库,提供大量现成角色(如部署 Docker、Nginx 等),可直接下载使用。

常用ansible-galaxy命令
命令作用
ansible-galaxy list查看本地已安装的角色
ansible-galaxy search 关键词搜索 Galaxy 仓库中的角色
ansible-galaxy info 角色名查看角色详情(作者、用法等)
ansible-galaxy install 角色名安装角色到本地
实战:用 Galaxy 角色部署 Web 集群

需求

  • node3 作为负载均衡器(haproxy)
  • node1 和 node2 作为 Web 服务器(apache)

实验流程

  1. 配置主机清单,区分负载均衡器和 Web 服务器
  2. 从 Galaxy 下载geerlingguy.haproxy(负载均衡)和geerlingguy.apache(Web 服务)角色
  3. 编写 Playbook,分别部署负载均衡器和 Web 服务器
  4. 执行并验证集群效果

步骤细化

  1. 配置主机清单(inventory
[loadbalancers]
loadbalancer ansible_host=node3  # node3作为负载均衡器[webservers]
node1  # Web服务器1
node2  # Web服务器2
  1. 安装 Galaxy 角色
# 安装haproxy角色(用于负载均衡)
[bq@controller web]$ ansible-galaxy install geerlingguy.haproxy# 安装apache角色(用于Web服务)
[bq@controller web]$ ansible-galaxy install geerlingguy.apache
  1. 编写部署 Playbook(deploy_web_cluster.yml
---
# 第一个Play:部署负载均衡器(haproxy)
- name: deploy load balancerhosts: loadbalancersvars:# 配置haproxy后端服务器(指向node1和node2的80端口)haproxy_backend_servers:- name: node1address: 10.1.8.11:80  # node1的IP和端口- name: node2address: 10.1.8.12:80  # node2的IP和端口roles:- geerlingguy.haproxy  # 调用haproxy角色# 第二个Play:部署Web服务器(apache)
- name: deploy web servershosts: webserversroles:- geerlingguy.apache  # 调用apache角色tasks:# 生成Web首页(显示当前主机名)- name: create index.htmlcopy:content: "Welcome to {{ ansible_fqdn }}.\n"  # 动态内容dest: /var/www/html/index.html  # Apache默认首页路径
  1. 执行并验证
# 执行Playbook
[bq@controller web]$ ansible-playbook deploy_web_cluster.yaml# 测试负载均衡效果(多次访问node3,会交替显示node1和node2的页面)
[bq@controller web]$ curl http://node3/
Welcome to node1.bq.cloud.  # 第一次输出[bq@controller web]$ curl http://node3/
Welcome to node2.bq.cloud.  # 第二次输出(负载均衡生效)

如涉及版权问题,请联系作者处理!!!!!!

http://www.dtcms.com/a/339405.html

相关文章:

  • Ubuntu 和麒麟系统创建新用户 webapp、配置密码、赋予 sudo 权限并禁用 root 的 SSH 登录的详细
  • 网络间的通用语言TCP/IP-网络中的通用规则3
  • 缓存雪崩、缓存穿透、缓存击穿在实际中如何处理
  • Windows Git安装配置
  • PCL+Spigot服务器+python进行MC编程(使用Trae进行AI编程)---可以生成彩虹
  • 代码随想录Day56:图论(冗余连接、冗余连接II)
  • 【python】列表复制注意事项
  • 大模型+RPA:如何用AI实现企业流程自动化的“降本增效”?
  • 什么类型的项目会优先选择Headless CMS
  • 【habitat学习二】Habitat-Lab 快速入门指南(Quickstart)详解
  • 完美解决git报错拉取不到项目
  • 如何禁用 Windows 服务器的自动更新以避免意外重启
  • VMWare主机和客户机无法ping通
  • Android-ContentProvider的跨应用通信学习总结
  • Matplotlib数据可视化实战:Matplotlib安装与入门-跨平台环境配置与基本操作
  • 第四章:大模型(LLM)】07.Prompt工程-(2)Zero-shot Prompt
  • 【Linux】信号(二):Linux原生线程库相关接口
  • C#多线程学习—主子线程,Invoke与begininvoke
  • RabbitMQ:SpringBoot+RabbitMQ入门案例
  • 《用Proxy解构前端壁垒:跨框架状态共享库的从零到优之路》
  • vue3使用RouterLink跳转的时候,路径正确但是不显示对应内容
  • Computer Using Agents:数字世界中的超级用户——架构设计与产业实践
  • RNN深层困境:残差无效,Transformer为何能深层?
  • Qt猜数字游戏项目开发教程 - 从零开始构建趣味小游戏
  • 【数据库】通过‌phpMyAdmin‌管理Mysql数据
  • 概率论基础教程第5章 连续型随机变量(二)
  • 字节开源了一款具备长期记忆能力的多模态智能体:M3-Agent
  • RabbitMQ:SpringBoot+RabbitMQ Direct Exchange(直连型交换机)
  • 第7章 React性能优化核心
  • [langgraph]创建第一个agent