ansible安装部署及常用模块详解(超详细)
目录前言一、环境概况修改主机名可选项二、安装部署1.安装epel扩展源2.安装Ansible3.修改Ansible的hosts文件4.生成密钥三、Ansible模块使用介绍Command模块Shell模块User模块Copy模块File模块Hostname模块Yum模块Service和System模块Setup 模块四、playbook前言1.ansible-playbook介绍2.playbook yml文件格式介绍playbook实例1.在目标主机上安装docker使用docker部署nginx前言Ansible 是一种开源的自动化工具用于配置管理、应用程序部署和任务自动化。它采用简单易懂的 YAML 语法和基于 SSH 协议的远程执行能够实现快速、可靠的自动化配置和部署。Ansible 的一些主要特点和功能简单易用: Ansible 使用 YAML 格式的声明性语言使得编写和阅读 PlaybooksAnsible 的配置文件变得非常直观和易于理解。无需编写复杂的脚本或程序代码就可以完成大部分配置和部署任务。无代理架构: Ansible 采用基于 SSH 的无代理架构不需要在目标主机上安装任何额外的代理或客户端软件。这简化了部署和管理过程并提供了更强的安全性。模块化: Ansible 提供了丰富的模块库用于执行各种操作如包管理、文件操作、服务管理、用户管理等。模块化的设计使得用户可以轻松地扩展和定制 Ansible以满足特定的自动化需求。剧本化: Ansible 使用 Playbooks 来描述配置和部署任务。Playbooks 是用 YAML 编写的文本文件可以定义一系列任务和主机组以及执行这些任务的顺序和条件。这使得用户可以将复杂的配置和部署过程分解为可管理的、可重用的剧本。多平台支持: Ansible 可以在多种操作系统和云平台上运行包括 Linux、Windows、macOS、VMware、AWS、Azure、Google Cloud 等。这使得 Ansible 成为一个通用的自动化工具可用于管理多样化的 IT 环境。可扩展性: Ansible 可以集成到现有的工具链和流程中并与其他自动化和编排工具如 Jenkins、Kubernetes进行集成。此外Ansible 还具有丰富的插件和扩展机制可以根据需要进行功能定制和扩展。一、环境概况192.168.159.128 ------------ Ansible服务端管理端192.168.159.129 ------------ 客户端受控端修改主机名可选项修改Ansible服务端的主机名客户端不修改hostnamectl set-hostname ansible.server hostname ansible.server reboot后永久生效二、安装部署1.安装epel扩展源yum install -y epel-release2.安装Ansibleyum install -y ansible3.修改Ansible的hosts文件cd /etc/ansible/ tree . ├── ansible.cfg #ansible的配置文件默认即可 ├── hosts #ansible的主机清单用于存储需要管理的远程主机的相关信息需要编辑 └── roles/ #公共角色目录默认即可vim hosts #webservses行取消注释添加被控端IP [webservers] ## alpha.example.org ## beta.example.org 192.168.159.129 ## 192.168.1.1104.生成密钥Ansible 的工作原理是通过 SSH 连接到远程主机在目标主机上执行预定义的任务或命令所以需要配置免密ssh-keygen ssh-copy-id root192.168.159.129三、Ansible模块使用介绍现在开始ansible就已经可以开始使用了查看Ansible版本[rootansible ansible]# ansible --version ansible 2.9.27 config file /etc/ansible/ansible.cfg configured module search path [u/root/.ansible/plugins/modules, u/usr/share/ansible/plugins/modules] ansible python module location /usr/lib/python2.7/site-packages/ansible executable location /usr/bin/ansible python version 2.7.5 (default, Jun 20 2023, 11:36:40) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] [rootansible ansible]#查看ping和telnet模块的简要描述和摘要ansible-doc -s ping ansible-doc -s telnet用于查看有关telnet模块的文档类似于man手册ansible-doc telnetCommand模块格式ansible hosts -m command -a commandansible webservers -m command -a free -h ansible 192.168.159.129 -m command -a free -h ansible all -m command -a free -h ansible webservers -a uname -ahosts可以使用以上三种方式指定webservershosts配置文件中的【webservers】组执行某些命令实际IP指定IP运行某些命令all代表所有hosts主机包含hosts配置文件中的【dbservers】组Shell模块格式ansible hosts -m shell -a commandansible all -m shell -a for i in {1..5}; do touch \$i.txt;done ls -la *.txt1.上述示例当中的touch命令部分为什么在$符号前面要加上转义符ansible webservers -m shell -a df -hT|grep /$ | awk {print $6} ansible webservers -m shell -a df -hT|grep /$ | awk {print \$6}2.上述示例当中的awk命令部分为什么在$符号前面要加上转义符解释为了确保 $6 不被解释为命令行变量而是作为字符串的一部分传递给远程主机执行需要使用转义符 \ 进行转义。\$6 的目的是将 $6 这个字符串传递给远程主机而不被本地 Shell 解释为变量所以正确写法是这样的ansible all -m shell -a for i in {129,130}; do ping -c 1 192.168.159.\$i; done错误写法示范User模块格式ansible hosts -m user -a optionshosts 指定要管理用户的目标主机可以是单个主机或者主机组的名称。 -m user 通过 -m 参数指定要使用的模块为 user。 -a options 使用 -a 参数传递模块的选项。选项可以是创建用户、修改用户属性或删除用户等操作。 user 模块的常用选项包括 name 指定用户的名称。 password 指定用户的密码已加密。 state 指定用户的状态present表示创建absent表示删除。 groups 指定用户所属的组。 shell 指定用户的登录 Shell。 systemyes|no 是否为系统账号。 uid 用户uid move_homeyse|no如果设置的家目录已经存在是否将已经存在的家目录进行移动 password 用户的密码建议使用加密后的字符串 comment 用户的注释信息 removeyes|no 当stateabsent时是否删除用户的家目录 comment 指定用户的注释信息。ansible webservers -m user -a namewang statepresent password123456 groupsroot shell/sbin/nologin ansible webservers -m command -a grep wang /etc/shadowCopy模块格式ansible hosts -m copy -a optionshosts: 指定要复制文件的目标主机可以是单个主机或者主机组的名称。 -m copy: 通过 -m 参数指定要使用的模块为 copy。 -a options: 使用 -a 参数传递模块的选项。选项包括源文件路径、目标文件路径、权限等。 copy 模块的常用选项包括 src 指定源文件或目录的路径。可以是绝对路径或相对路径。 dest 指定目标文件或目录的路径。可以是绝对路径或相对路径。 mode 指定目标文件的权限模式例如 0644。 owner 指定目标文件的所有者。 group 指定目标文件的所属组。 backup 指定是否创建备份文件。 force 指定是否强制复制即使目标文件已经存在。ansible webservers -m copy -a src/root/shdir/xin.sh dest/root/xin_bak.sh ownerroot grouproot mode777 ansible webservers -m shell -a bash /root/xin_bak.shFile模块格式ansible hosts -m file -a optionshosts: 指定要操作文件的目标主机可以是单个主机或主机组的名称。 -m file: 通过 -m 参数指定要使用的模块为 file。 -a options: 使用 -a 参数传递模块的选项。选项包括要操作的文件路径、属性变更等。 file 模块的常用选项包括 path 指定要操作的文件或目录的路径。可以是绝对路径或相对路径。 mode 指定文件的权限模式例如 0644。 owner 指定文件的所有者。 group 指定文件的所属组。 state 指定文件的状态可以是 file文件存在、directory目录存在或 absent文件不存在。 recurse 指定是否递归地应用更改到目录及其子目录。 follow 指定是否跟随符号链接进行更改。ansible webservers -m file -a path/root/xin_bak.sh ownerroot grouproot mode755 statefile ansible webservers -m command -a ls -la /root/xin_bak.shHostname模块格式ansible hosts -m copy -a optionsansible webservers -m hostname -a nametest ansible webservers -m command -a hostnameYum模块格式ansible hosts -m yum -a namepackage_name statestatehosts: 指定要操作文件的目标主机可以是单个主机或主机组的名称。 -m file: 通过 -m 参数指定要使用的模块为 file。 -a options: 使用 -a 参数传递模块的选项。选项包括要操作的文件路径、属性变更等。 yum 模块的常用选项包括 name 要安装的包的名字 state present安装、absent卸载或 latest更新为最新版本。 update_cache: 是否刷新 YUM 缓存。默认情况下为 yes表示会自动更新缓存。设置为 no 则不刷新缓存。 disable_gpg_check: 是否禁用 GPG 检查。默认为 no表示会进行 GPG 检查。设置为 yes 则禁用 GPG 检查。 enablerepo 和 disablerepo: 控制仓库的启用和禁用。可以指定要启用或禁用的仓库名称。多个仓库以逗 号分隔。 installroot: 指定要安装软件包的根目录路径。 conf_file: 指定要使用的 YUM 配置文件路径。 vars: 用于传递额外的变量给 Ansible。ansible webservers -m yum -a namednsmasq statepresent ansible webservers -m shell -a systemctl restart dnsmasq systemctl enable dnsmasq systemctl status dnsmasqService和System模块格式ansible hosts -m service -a nameservice name enabledyes/no statestatehosts: 指定要操作文件的目标主机可以是单个主机或主机组的名称。 -m file: 通过 -m 参数指定要使用的模块为 file。 -a options: 使用 -a 参数传递模块的选项。选项包括要操作的文件路径、属性变更等。 service 模块的常用选项包括 name: 服务名称 state: 服务状态started|stopped|restarted enabled: 是否自启动yes|no pattern: 进程匹配模式 .点 匹配任意单个字符。 * 匹配前一个字符的零次或多次重复。 匹配前一个字符的一次或多次重复。 ? 匹配前一个字符的零次或一次重复。 ^ 匹配字符串的开始位置。 $ 匹配字符串的结束位置。 [] 用于定义字符集匹配其中的任意一个字符。 () 创建捕获组用于分组匹配。 sleep: 等待时间 timeout: 超时时间 runlevel: 运行级别 args: 额外参数 system 模块命令格式 name: 项名称 state: 系统状态 value: 要设置的值started|stopped|restarted enabled: 是否自动加载yes|no regenerate: 是否重新生成 system_file: 系统文件路径 runtime_file: 运行时文件路径 config_file: 配置文件路径Setup 模块格式ansible hosts -m setup -a nameservice name enabledyes/no statestatehosts: 指定要操作文件的目标主机可以是单个主机或主机组的名称。 -m file: 通过 -m 参数指定要使用的模块为 file。 -a options: 使用 -a 参数传递模块的选项。选项包括要操作的文件路径、属性变更等。 setup 模块的常用选项包括 gather_subset 指定要收集的子集信息的列表。默认情况下会收集所有可用的信息。可以使用 hardware, network, virtual, ohai, facter, ohai_timed, puppet, vagrant 或 all 来指定子集。 fact_path 用于指定自定义信息facts路径的列表。Ansible 会搜索这些路径以查找自定义事实。 filter 过滤已收集的信息facts仅返回匹配指定模式的结果。 gather_timeout 设置收集事实的超时时间单位为秒。 gather_timeout_multiplier 用于调整超时时间的倍数默认为 1。 gather_timeout_retry 在超时后重试的次数默认为 1。 cache_valid_time 设置缓存的有效时间单位为秒。 fact_caching 启用或禁用缓存功能可以是 memory、jsonfile、json、yaml 或 text。filter常用的过滤参数ansible_all_ipv4_addresses ipv4的所有地址 ansible_all_ipv6_addresses ipv6的所有地址 ansible_date_time 获取到控制节点时间 ansible_default_ipv4 默认的ipv4地址 ansible_distribution 系统 ansible_distribution_major_version 系统的大版本 ansible_distribution_version 系统的版本号 ansible_domain 系统所在的域 ansible_env 系统的环境变量 ansible_hostname 系统的主机名 ansible_fqdn 系统的全名 ansible_machine 系统的架构 ansible_memory_mb 系统的内存信息 ansible_os_family 系统的家族 ansible_pkg_mgr 系统的包管理工具 ansible_processor_cores 系统的cpu的核数(每颗) ansible_processor_count 系统cpu的颗数 ansible_processor_vcpus 系统cpu的总个数cpu的颗数*CPU的核数 ansible_python 系统上的pythonansible webservers -m setup -a gather_subsethardwareansible webservers -m setup -a filter*device_link*四、playbook前言1.ansible-playbook介绍Playbook是一个包含一系列任务的YAML文件用于描述和定义Ansible的配置、部署和管理操作。ansible-playbook命令的基本格式ansible-playbook playbook_file [options]其中playbook_file是指定要运行的Playbook文件的路径。一些常用的选项-i, --inventory inventory_file指定主机清单文件的路径。默认情况下Ansible会使用 /etc/ansible/hosts 文件作为主机清单。 -l, --limit pattern限制运行Playbook的主机范围可以使用模式匹配。例如--limit webservers 将只在名为 webservers 的主机上运行Playbook。 -e, --extra-vars extra_vars传递额外的变量给Playbook。可以使用 -e 选项多次来传递多个变量。例如-e var1value1 -e var2value2。 -t, --tags tags只运行带有指定标签的任务。可以使用 -t 选项多次来指定多个标签。例如-t tag1 -t tag2。 -s, --sudo以sudo权限运行Playbook。需要在目标主机上配置好sudo权限。 -K, --ask-become-pass在运行Playbook之前提示输入sudo密码。2.playbook yml文件格式介绍缩进: yaml使用一个固定的缩进风格表示层级结构每个缩进由两个空格组成不能使用tab键冒号: 以冒号结尾的除外其他所有冒号后面所有必须有空格冒号必须是英文冒号。短横线:表示列表项,使用一个短横线加一个空格作为一个列表项多个项使用同样的缩进级别作为同一列表。--- 表示YAML文档的开始 -name: 定义该playbook名字 hosts: 主机可以是all也可以是组也可以是具体的IP become: yes/no 执行某个任务的时候尝试切换成特权用户这个可加可不加 gather_facts: yes/no 获取目标主机的信息 tasks: - name任务名字 module模块例如 command、yum、copy、file等模块 Options1参数1 Options2参数2 ...... #每个模块都有一组参数介绍这些参数被用来控制模块的行为和执行结果。 name任务名称用于在输出中标识任务。 state指定状态通常可以设置为 present、 absent 或 latest表示目标应该处于的状态。 enabled指定服务是否应该在启动时启用或禁用。 args指定传递给命令或脚本的参数列表。playbook实例1.在目标主机上安装docker使用docker部署nginx--- - name: docker_nginx install hosts: webservers gather_facts: yes #获取主机信息 tasks: - name: setup memory setup: filter: ansible_memory_mb #获取主机内存 - name: setup date setup: filter: ansible_date_time #获取主机时间 - name: copy docker.repo copy: #copy模块将本地的docker-ce.repo拷贝到目标主机上权限644 src: /tmp/docker-ce.repo dest: /etc/yum.repos.d/docker-ce.repo owner: root group: root mode: 0644 - name: install docker yum: #yum模块分别安装cece-clicontainerd.io name: - docker-ce - docker-ce-cli - containerd.io state: latest - name: start firewalld service: #service模块开启自启firewalld name: firewalld state: started enabled: yes - name: start docker service: #同上开启自启docker name: docker state: started enabled: yes - name: pull nginx command: docker pull nginx #command模块pull镜像 - name: create nginx_html_directory file: #file模块state指定directory创建该目录 path: /usr/share/nginx/html state: directory owner: root group: root mode: 0755 - name: touch nginx_index #同上state指定touch创建该文件 file: path: /usr/share/nginx/html/index.html state: touch owner: root group: root mode: 0644 - name: copy nginx_index copy: #copy模块拷贝index文件到目标主机 src: /usr/share/nginx/html/index.html dest: /usr/share/nginx/html/index.html owner: root group: root mode: 0644 - name: start nginx_container #command模块run一个nginx镜像 command: docker run --name mynginx -p 8080:80 -v /usr/share/nginx/html/index.html:/usr/share/nginx/html/index.html -d nginx - name: get nginx_html #get_url模块访问8080端口 get_url: url: http://localhost:8080 dest: /tmp/nginx.html运行结果ansible-playbook docker.yml访问nginx测试ansible webservers -m command -a curl -k -v http://localhost:8080

相关新闻

终极指南:用yuzu模拟器在PC上畅玩Switch游戏

终极指南:用yuzu模拟器在PC上畅玩Switch游戏

终极指南:用yuzu模拟器在PC上畅玩Switch游戏 【免费下载链接】yuzu 任天堂 Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/yu/yuzu 想要在电脑上体验任天堂Switch的精彩游戏世界吗?yuzu模拟器就是你的最佳选择!作为目…

2026/10/18 0:03:10 阅读更多 →
3秒搞定网页图片格式转换:Save Image as Type 浏览器扩展深度解析

3秒搞定网页图片格式转换:Save Image as Type 浏览器扩展深度解析

3秒搞定网页图片格式转换:Save Image as Type 浏览器扩展深度解析 【免费下载链接】Save-Image-as-Type Save Image as Type is an chrome extension which add Save as PNG / JPG / WebP to the context menu of image. 项目地址: https://gitcode.com/gh_mirror…

2026/10/19 14:38:59 阅读更多 →
Linux镜像常用启动盘制作工具推荐

Linux镜像常用启动盘制作工具推荐

Rufus(推荐,常用) Rufus 是一个免费的 USB 启动盘制作工具,支持 Windows、Linux 和 UEFI。可以使用 Rufus 来将 Linux ISO 镜像文件写入到 USB 闪存驱动器中,从而创建一个可引导的 Linux 启动盘。 快速高效&#xff1…

2026/10/14 21:27:02 阅读更多 →

最新新闻

IDEA多模块工程:Java与Python自动化测试框架统一管理实战

IDEA多模块工程:Java与Python自动化测试框架统一管理实战

讲个真实场景。我接手某个自动化测试框架改造的时候,团队同时维护着两套代码:Java 这边用 TestNG 写接口用例已经跑了两三年,Python 那边用 pytest 处理数据校验和运维脚本也形成了规模。每次发布前,负责 Java 的同学跑完要导一份…

2026/10/21 5:01:00 阅读更多 →
STM32+红外模块控制格力空调:从硬件到代码的完整方案

STM32+红外模块控制格力空调:从硬件到代码的完整方案

简介:这份资源面向嵌入式开发初学者与智能家居DIY爱好者,提供基于STM32微控制器驱动红外模块控制格力空调的完整工程实践。内容围绕STM32的GPIO推挽输出、定时器PWM波形生成、NEC红外编码与解码、协议适配及示波器调试等关键环节展开,帮助读者…

2026/10/21 5:01:00 阅读更多 →
rea监控分析组件:从统一事件模型到告警收敛的实战指南

rea监控分析组件:从统一事件模型到告警收敛的实战指南

深夜两点十七分,我盯着屏幕上滚动的告警流,第无数次按下刷新键。这不是什么特殊的日子,只是一个普通的线上值班夜。系统表现得很“正常”——业务指标平稳,日志没有报错,可监控大盘上那条细小的毛刺,却让我…

2026/10/21 5:01:00 阅读更多 →
5G接入控制机制详解:从统一接入控制到切片感知的参数配置与调优

5G接入控制机制详解:从统一接入控制到切片感知的参数配置与调优

1. 5G接入控制到底在控制什么第一次接触5G接入控制这个概念,很多人会把它和“能不能连上基站”混为一谈。实际上,接入控制要解决的问题比“连不连得上”精细得多。它管的是:在什么条件下允许一个终端发起接入、以什么身份接入、接入后能占用多…

2026/10/21 5:01:00 阅读更多 →
零基础转岗网络安全?十个简单实操任务助你快速入门

零基础转岗网络安全?十个简单实操任务助你快速入门

转岗网安,零基础,十个简单教程,避开复杂理论,轻松掌握核心技能——这话听起来很营销,但我可以负责任地告诉你,它确实是可以成立的。前提只有一条:你找对入门方向。很多人劝退转岗网安&#xff0…

2026/10/21 5:01:00 阅读更多 →
资源效率分析器REA落地实践:从需求拆解到优化建议生成

资源效率分析器REA落地实践:从需求拆解到优化建议生成

说实话,第一次见到“REA”这三个字母时,我以为是某个新框架的缩写。等到需求文档推到我面前,才发现这是一个极简到极致的项目代号,背后要做的是一个资源效率分析器(Resource Efficiency Analyzer)。当时团队…

2026/10/21 4:59:59 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →