资讯动态

Ansible Playbook核心机制与实战:从语法到自动化运维落地

发布时间:2026/9/23 4:55:44 来源:尧图企业网站定制
说实话干了这么多年运维Ansible在我手里早就不是“会不会用”的问题而是“怎么用得让人不骂娘”的问题。早期踩过的坑、写过的烂剧本、被同事吐槽过的YAML缩进都是血泪史。今天把Ansible Playbook这玩意儿一次讲透——从设计思路到语法坑、从实战案例到排查心得希望你看完能少走几步弯路。这篇文章适合这些读者刚把Ansible装好、在ubuntu server上跑通了两条ad-hoc命令的新手已经写过几个Playbook但总感觉哪里别扭、想理清变量和复用体系的进阶者以及团队里准备推自动化运维项目、需要把脚本整理成可维护剧本的人。我会尽量用大白话解释原理穿插真实项目里的实操记录。1. 为什么要深入理解Playbook自动化运维的核心载体1.1 从Ad-Hoc命令到Playbook你迟早要跨过这道坎很多人接触Ansible是从ad-hoc命令开始的。一条ansible all -m ping测通再顺手ansible all -m apt -a namenginx statepresent装个包挺爽。但用不了几天你就会发现严重问题你根本不记得上周给那十几台机器执行过什么命令新来的同事接手时更是一脸懵。运维操作如果没有记录、没有版本、没有评审那就等于裸奔。Ad-hoc命令适合临时探活、调试和应急操作但它不是“自动化运维项目”的正式形态。Playbook才是。我习惯把ad-hoc比作随口说的一句话而Playbook是写进合同里的条款——前者说完就忘后者白纸黑字、可以追溯、可以反复执行。从ad-hoc走向Playbook的真正门槛不是语法而是思维转变你要从“执行一条命令”转变为“描述一个目标状态”。比如装Nginxad-hoc关心的是“执行安装命令”Playbook关心的是“Nginx这个最终状态是否存在”。这种声明式思维是整个Ansible玩得转的关键也是后面理解幂等性的基础。1.2 Playbook到底解决了什么问题用一句话总结Playbook是把运维流程代码化、标准化、可复用化的一套机制。它解决了三个让人头疼的问题。第一可重复性。同样的任务今天执行和三个月后执行结果应该一样。以前写Shell脚本也能做到这一点但Shell脚本天然是“面向步骤”的遇到目标环境与预期不符的情况脚本就乱了阵脚——要么报错退出要么做出不可控的操作。Playbook则通过模块的幂等性设计让“执行多次”和“执行一次”的结果尽量一致。第二可读性。Playbook写出来是接近自然语言的声明式文本比如“安装nginx”“启动nginx服务”“复制配置文件”。哪怕是不懂Ansible的同事第一次看也能大概猜出这段剧本在做什么。而一段500行的bash脚本除非你逐行写注释否则三个月后连自己都看不懂。第三可审计性。Playbook是一个文件可以放进Git里做版本管理。谁改了什么、为什么改、哪个版本引入了某个变更清清楚楚。这对于团队协作、故障回溯、合规审计来说都是硬需求。1.3 一个Playbook的“最小可用”结构先别管复杂概念记住Playbook最基本的骨架就行。它是个YAML文件顶层是一个列表列表里每个元素是一个play每个play定义了“在哪些机器上执行什么任务”。--- - name: 安装并启动nginx hosts: web_servers become: yes tasks: - name: 确保nginx已安装 ansible.builtin.apt: name: nginx state: present - name: 确保nginx已启动 ansible.builtin.service: name: nginx state: started这个剧本干了什么它声明了两件事目标机器是web_servers组里的机器且使用超级权限执行要做的任务是“安装nginx”和“启动nginx服务”。become: yes是提权开关相当于sudo。tasks下面每个name是对这个任务的描述这个描述会打印在执行日志里所以写清楚点别敷衍。后面所有复杂功能——变量、模板、循环、条件、角色、处理器——都是在丰富这个骨架。但骨架永远是这个在哪里hosts、干什么tasks、以什么身份干become。把这三点刻在脑子里你就不会在Playbook里迷路。2. Playbook语法核心YAML、Task与模块的协同2.1 YAML是地基缩进、列表、字典一个都不能错Playbook的载体是YAML。很多人玩Ansible玩得崩溃一半时间是在跟YAML格式搏斗。YAML的规则说简单也简单说严格也严格最核心的无非三条缩进表示层级、冒号表示键值、短横线表示列表项。但就是这三条能坑掉无数新手和部分老手。最常见的问题是用Tab键缩进。YAML只认空格不认Tab。你在编辑器里看着对齐了Ansible跑起来直接抛Syntax Error或者解析出一个完全错误的结构。我建议所有写Playbook的人把编辑器的“Tab转空格”打开缩进统一用两个空格。另一类问题发生在写字典值时忘了加空格比如hosts:web_servers——冒号后面必须跟一个空格否则YAML会把它整个当字符串。这类错误其实很好排查因为Ansible会提示“Syntax Error”但问题在于控制台报错信息往往带有一堆堆栈新手容易慌。我遇到这种情况的第一反应永远是看报错里的line和column直接定位到那一行八成是缩进错乱或者冒号空格问题。- name: 示例 hosts: all vars: user_name: zhangsan user_info: { age: 18, city: beijing } package_list: - nginx - git - curl上面这个例子展示了三种最常见的YAML写法普通字符串键值、行内字典、列表。写熟了你会觉得YAML挺舒服的但在那之前请养成写完自检的习惯。2.2 Task的本质模块加参数Ansible的灵魂Playbook玩得再花最后真正干活的还是“模块”。Task是对模块的一次调用它由模块名、模块参数、任务属性三部分组成。模块是Ansible内置好的一堆“操作原语”比如apt管包、copy管文件复制、service管服务状态、command管执行命令。这里我想强调一个很多初学者完全误解的地方能用模块干的事尽量不要用command或shell模块硬凑。为什么因为模块被设计成幂等的而command默认不幂等。比如你用command: apt install -y nginx第一次执行是安装第二次执行它依然会走一遍Ansible无法判断“是否需要执行”。但apt模块不同它内部会检查nginx是不是已经装了装了就直接跳过并把状态标记为ok——这就是幂等性的来源。写Task的时候推荐尽量把模块名写完整。从Ansible 2.10开始模块被收纳到集合中比如apt应该写作ansible.builtin.apt。这个写法虽然啰嗦一点但能避免很多版本兼容性问题。如果你的环境是Ansible 2.9或更老版本用apt这种短名也行但新项目建议直接上完整名后面升级时省心。模块参数有长格式和短格式两种。短格式是keyvalue一行拼写适合参数少的场景长格式是用YAML字典逐行写适合参数多、可读性要求高的场景。永远记住可读性优先。tasks: - name: 用短格式安装nginx ansible.builtin.apt: namenginx statepresent - name: 用长格式安装nginx ansible.builtin.apt: name: nginx state: present长格式多写几行但结构清晰、后续加参数方便。实践中我基本全用长格式。2.3 变量与优先级别再被“变量不生效”逼疯了变量是Playbook里最容易出乱子的地方因为Ansible的变量来源太多了命令行--extra-vars、Play文件里的vars、inventory里的host_vars和group_vars、角色里的defaults和vars、甚至set_fact动态设置的变量。这些变量之间有严格的优先级记不住优先级顺序就会出现我明明在group_vars里设了值为什么playbook里还是用旧值的惨案。给你一个简化版记忆法按优先级从低到高排角色的defaults/main.yml最低inventory里的host_vars和group_varsPlay中的vars和vars_files角色的vars/main.yml任务里通过set_fact/register设置的变量命令行--extra-vars最高也就是说命令行传入的变量永远是老大谁也盖不过它。defaults里的值最容易被覆盖适合放“可以被使用者覆盖的默认值”。这里分享一个我踩过的大坑在inventory文件中给一组机器定义了ansible_user结果某台机器要用不同用户名登录我在playbook里又写了vars: ansible_user: xxx以为能覆盖。执行的时候发现压根没生效。原因就是inventory的变量优先级高于play直接定义的vars所以你必须去host_vars里改或者用--extra-vars强推。从那以后我每次排查变量问题都会先用ansible-inventory --host 主机名 --vars看一下实际生效的变量值省了很多排查时间。2.4 模板系统与Facts动态生成配置文件的利器真实环境里配置文件往往因机器而异。比如Nginx的worker_processes要根据CPU核数调整应用的数据库连接串要区分测试环境和生产环境。如果每个环境写一份配置累死且容易漏。Playbook的解决方案是“模板”。Ansible使用Jinja2模板引擎模板文件以.j2结尾。模板里可以嵌入变量、写简单的循环和条件。结合“Facts”——Ansible在每台机器上自动采集的系统信息CPU核数、内存、IP、操作系统等可以轻松生成贴合当前机器的配置。先看一个模板示例这是nginx.conf.j2的片段worker_processes {{ ansible_processor_cores }}; server { listen 80; server_name {{ server_name }}; root {{ web_root }}; }再看Playbook里怎么使用模板- name: 渲染nginx配置模板 ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf owner: root group: root mode: 0644 notify: reload nginx这里有个细节值得注意ansible_processor_cores和server_name的来源不同。前者是Facts自动采集的后者是你在vars或host_vars里定义的。Facts是Ansible很强大的能力执行Playbook时默认会先跑一遍gather_facts把系统信息抓回来放在变量里供模板使用。如果不需要Facts可以在play里设gather_facts: no来提速但前提是你确实用不到。3. 项目实测一个完整的Web服务部署Playbook3.1 场景设定与目录结构理论讲再多不如实际跑一版。下面我模拟一个非常典型的场景在一个ubuntu server组上通过Ansible部署一套Nginx静态站点服务包括安装Nginx、渲染index页面、启动服务、配置防火墙放行80端口。实际运维项目里我强烈建议按“角色”组织目录结构。先建好目录骨架就算现在只有一个角色也为后续扩展留好了位置。web-deploy/ ├── inventory.ini ├── playbook.yml └── roles/ └── nginx/ ├── tasks/ │ └── main.yml ├── templates/ │ └── index.html.j2 ├── handlers/ │ └── main.yml └── defaults/ └── main.yml这个结构是Ansible官方推荐的Roles标准布局tasks放主任务、templates放模板、handlers放处理器、defaults放默认变量。别小看这个布局它让每个角色的职责边界非常清楚——以后你要加个PHP-FPM角色直接新建一个roles/php-fpm/目录就行互不干扰。3.2 编写部署Nginx的Playbook先看inventory文件。最简单的写法是INI格式可以定义主机组和组变量[web_servers] 192.168.1.10 ansible_userubuntu 192.168.1.11 ansible_userubuntu [web_servers:vars] ansible_ssh_private_key_file~/.ssh/id_ed25519再看看入口playbook文件。这个文件是执行时的入口它负责把角色关联到主机组上并可以传入一些play级别的变量--- - name: 部署nginx静态站点 hosts: web_servers become: yes gather_facts: yes roles: - nginx非常简单对吧但实际干活的都在roles/nginx/里面。roles/nginx/defaults/main.yml定义默认变量--- nginx_port: 80 site_name: mysite web_root: /var/www/mysiteroles/nginx/tasks/main.yml是核心任务列表--- - name: 更新apt缓存 ansible.builtin.apt: update_cache: yes cache_valid_time: 3600 - name: 安装nginx ansible.builtin.apt: name: nginx state: present - name: 创建站点目录 ansible.builtin.file: path: {{ web_root }} state: directory owner: www-data group: www-data mode: 0755 - name: 渲染index页面模板 ansible.builtin.template: src: index.html.j2 dest: {{ web_root }}/index.html owner: www-data group: www-data mode: 0644 - name: 渲染nginx站点配置 ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/sites-available/{{ site_name }} notify: reload nginx - name: 启用站点配置 ansible.builtin.file: src: /etc/nginx/sites-available/{{ site_name }} dest: /etc/nginx/sites-enabled/{{ site_name }} state: link notify: reload nginx - name: 确保nginx服务运行 ansible.builtin.service: name: nginx state: started enabled: yes - name: 放行80端口 community.general.ufw: rule: allow port: {{ nginx_port }} proto: tcp逐行解释几个容易忽略的细节。第一cache_valid_time: 3600的意思是apt缓存如果在3600秒内更新过就跳过update_cache。这个参数能有效减少重复执行时的等待时间。第二启用站点配置时没有直接复制文件而是做软链接这是Nginx官方推荐的站点管理方式——你可以同时存在多个sites-available配置但只在sites-enabled里链接需要的。第三notify: reload nginx这个声明会和handlers联动配置文件一旦发现变化就触发Nginx重载而不是重启。重载比重启优雅得多不会中断现有连接这在下文会展开讲。roles/nginx/templates/index.html.j2也很简单!DOCTYPE html html headtitle{{ site_name }}/title/head body h1Welcome to {{ site_name }}!/h1 pThis page is deployed by Ansible./p /body /html通过模板不同环境下只要传不同的site_name变量就能渲染出不同的页面不需要手工修改每一个文件。3.3 Handlers与notify的联动机制handler是Playbook里非常巧妙的机制用来处理“变更后的动作”。它和普通task长得很像但有两个关键区别它是通过notify被触发的而不是直接执行同一个handler在一次playbook运行中即使被多次notify也只会执行一次。举个例子。上面任务里有两处notify: reload nginx分别对应渲染nginx站点配置和启用站点配置链接。如果两个任务都发生了变更handler也不会被调用两次。它会在本轮play所有task执行完后统一处理而且只运行一次。这看起来是个小事但避免了重复reload导致的服务抖动。定义handler的地方在roles/nginx/handlers/main.yml--- - name: reload nginx ansible.builtin.service: name: nginx state: reloaded这个机制的精髓在于“按需执行”配置文件没变就绝不reload配置文件变了才触发一次reload。这一设计让Playbook在反复执行时非常安全。我在生产环境里见过因为配置管理工具每次都重启服务、导致线上偶发闪断的事故用handlernotify机制就能从根上避免。3.4 用角色组织后的实际执行效果执行整个项目只需要一条命令ansible-playbook -i inventory.ini playbook.yml如果一切顺利你会看到每个task的输出状态都是ok或者changed。首次执行时安装类任务大概率是changed因为确实装了东西第二次执行时应该基本变成ok——这就是幂等性在工作。这里顺手提一个实用参数加-v可以看到更多执行细节加--check做演练模式。演练模式不会真正修改系统只会告诉你“会发生哪些变更”这在改动生产环境前是必须做的一步。我在实际部署中经常这么干先在测试机上执行一次完整playbook确认无误后再到生产环境加--check先干跑一遍最后再真实执行。这一步看似多余但能拦住绝大多数低级错误。4. Playbook核心机制条件、循环与幂等性4.1 when条件判断让任务在合适的机器上做合适的事当你的inventory里不再是“清一色的ubuntu server”时条件判断就成刚需了。比如你管理着一批机器一部分是Debian系一部分是RedHat系apt和yum模块就不能混用。Playbook的解决方案是when关键字它支持表达式判断常用的是结合Facts。- name: Debian系安装nginx ansible.builtin.apt: name: nginx state: present when: ansible_os_family Debian - name: RedHat系安装nginx ansible.builtin.yum: name: nginx state: present when: ansible_os_family RedHatwhen后面跟的是一个Jinja2表达式。它可以直接写ansible_os_family Debian这种比较也可以写variable is defined变量已定义、variable is not defined变量未定义、以及组合条件when: (a is defined) and (b is defined)。我遇到的比较实用的场景是配置差异化。比如内网机器需要配置NTP到内网时钟源而云端机器则用默认的云厂商时钟源。这种差异性非常适合用whengroup_vars里的变量来控制。同类机器归到同一个组组里定义一个ntp_server变量任务里判断这个变量是否有值、值是什么再决定写入哪份配置。这样一套playbook就能管住多环境而不是为每个环境复制一份几乎相同的文件。4.2 loop循环批量处理的正确姿态重复写十几个几乎一样的task是新手最爱犯的错。比如创建十个用户有些人会真写十条user模块的task。实际上用loop一行就搞定了。- name: 批量创建用户 ansible.builtin.user: name: {{ item }} state: present groups: dev loop: - zhangsan - lisi - wangwu - zhaoliuloop遍历列表每次把当前元素赋给item然后在模块参数里通过{{ item }}引用。如果你需要遍历更复杂的数据结构比如字典列表item.name、item.uid这样取字段就行- name: 批量创建带uid的用户 ansible.builtin.user: name: {{ item.name }} uid: {{ item.uid }} state: present loop: - name: zhangsan uid: 1001 - name: lisi uid: 1002循环的价值不只是少写几行代码更重要的是“批量操作的配置项集中在一起”改动时只需修改列表里的数据任务本身不用动。这体现了一种数据和逻辑分离的思想和模板的原理异曲同工。4.3 幂等性为什么我的Playbook每次执行结果都不一样这是整个Ansible里最容易被问崩的话题。幂等性是指“多次执行的结果与一次执行的结果一致”Playbook的理想状态是每次跑完系统都处于声明好的目标状态而不是越跑越偏。但很多人会发现自己的playbook执行两次第二次还是显示一堆changed甚至导致系统状态不对。之所以会这样绝大部分原因是用了不幂等的操作方式。command模块和shell模块是不做状态检查的——你让它执行cp它就执行你让它执行systemctl restart nginx它就重启它不会去思考“这个文件是不是已经复制过了”“服务是不是本来就在运行”。滥用这两个模块是Playbook失去幂等性的头号元凶。那怎么救分两种情况。第一能换模块就换模块。复制文件用copy和template安装包用apt/yum管理服务用service/systemd。这些模块内部实现了状态检测。第二如果确实必须用命令模块就要人为补上幂等性。command模块有creates参数和removes参数分别表示“如果该文件已存在就跳过”和“如果该文件不存在就跳过”让命令只在必要的时候执行。- name: 只在文件不存在时初始化数据库 ansible.builtin.command: /usr/local/bin/init_db.sh args: creates: /var/lib/myapp/db_initialized.lock另一个常见问题是你用了shell模块但它检测不到文件变化导致重复执行。这种情况下可以用changed_when手动告诉Ansible“什么时候才算发生了变更”- name: 判断配置是否有更新 ansible.builtin.shell: /usr/local/bin/check_and_update.sh register: result changed_when: updated in result.stdoutregister把命令执行的输出存到变量里changed_when根据输出内容决定这个任务是否被标记为变更。这个技巧在封装一些不内置幂等逻辑的脚本时特别有用。记着一句话幂等性不是模块自带的光环而是写Playbook的人必须具备的工程意识。每写一个任务都问自己一句如果这台机器已经处于目标状态我再执行一次这个任务会发生什么如果答案是“还是会变”那就得想办法让它“能检测不变”。5. 常见问题与排查技巧实录5.1 YAML格式错误90%的报错都发生在这里Ansible报错最常见的就是Syntax Error但它的提示往往不够直观尤其对于刚入门的人。我遇到过的经典案例是某次在写变量字典时把键值对的两个空格缩进写成了四个空格导致Ansible把字典误判成了列表片段抛出的报错完全看不出来问题在哪。遇到格式错误别慌按顺序做三步。第一步看报错最后的line和column定位到具体位置。第二步用编辑器打开那个文件把不可见字符显示出来检查是不是混入了Tab。第三步如果还是找不到把出错的片段暂时注释掉一半二分法缩小范围。这里给你一个可以立即用起来的土办法本地装个yamllint每次写完Playbook先跑一下yamllint playbook.yml。它能告诉你行尾空格多了、缩进不一致、文件末尾缺换行等一连串格式问题。虽然它有点“吹毛求疵”但用来保底很舒服。5.2 变量类型混淆数字、字符串、布尔值真的不一样YAML里看似随意的写法背后是严格的数据类型。很多人被state: present养成了手抽习惯写端口号时写port: 80没问题但写版本号时写version: 1.0就会因为被解析成字符串而踩坑。最常见的坑是布尔值。YAML里yes/no、true/false、on/off都会被解析成布尔值。早期Ansible的老项目里有大量become: yes这种写法这是合法的。但如果变量值是给某个配置文件用的比如debug_enabled: yes模板里输出出来可能是个True而不是yes——你想要的文本和你得到的数据就对不上了。处理这种问题我的习惯是凡是模板里要输出成文本的变量统一在模板里用| string过滤器强制转成字符串或者用to_json明确指定输出格式。别依赖YAML的“智能类型转换”类型明确才是王道。5.3 提权与become问题明明连上了却什么也改不了Playbook连上了主机但执行任务时报权限不足这是新手最常遇到的问题。Ansible默认用配好的ansible_user登录这个用户不一定是root。像ubuntu server这种云服务器默认用户是ubuntu有sudo权限但需要密码或免密配置。Playbook里的提权配置主要靠三个关键词become是否提权、become_user提权到哪个用户默认root、become_method用什么方式提权默认sudo。如果sudo需要密码你需要在执行时加-K参数手动输入sudo密码或者把密码配置到inventory的变量ansible_become_password里务必用vault加密不要明文写。有个细节become: yes放在play级别表示这个play里的所有任务都提权放在task级别表示只有这个任务提权。后者粒度更细更安全。但要注意file模块创建文件时owner和group如果不指定默认是运行Ansible的用户而不是become后的用户。这个坑会导致你明明用了become创建出来的文件属主还是错乱的。所以涉及文件属主的任务显式写好owner和group永远是更稳的。5.4 模块参数错误看文档看文档还是看文档模块的参数写错Ansible会给出错误提示但你得能看懂。比如service模块的state参数合法值是started、stopped、restarted、reloaded——你用enable想表达开机自启就写错了正确参数是enabled。每个模块的参数很多记不住是常态别硬背。我的建议是拿不准模块用法时先在本地起个测试虚机跑一遍ansible-doc 模块名查看文档或者直接在命令行敲ansible-doc ansible.builtin.copy看示例。ansible-doc是安了Ansible就自带的工具给出的参数说明和示例非常权威。经验越多反而越会频繁用这个命令因为它能避免一切“我以为是这样”的惨案。6. 进阶打磨几个让Playbook更好用的调试与优化技巧6.1 调试三板斧语法检查、干跑、逐步执行写完一个Playbook第一件事永远是ansible-playbook --syntax-check playbook.yml。它只做语法解析不连接任何主机消耗极低但能拦住百分之八十的低级错误。我一般会把这步放进Git的pre-commit钩子或者CI流程里防止带病代码进入版本库。第二件事是--check也就是干跑模式。Ansible会“模拟执行”任务告诉你哪些任务会变更、哪些不会但不会真正修改系统。这个模式对copy、template、service这种状态型模块非常准但对command、shell这种命令型模块基本没法预测——因为它不会真跑命令也就不知道命令的结果。所以看到--check输出里命令模块显示changed或skipped时别太当真真正的验证还得靠第三招。第三招是分步执行和定位。ansible-playbook playbook.yml --start-at-task安装nginx可以从指定任务开始执行非常适合中途挂了后重跑。配合--limit hostname可以只跑某一台机器。如果想定位某台机器上的具体输出-vvv详细日志模式能把SSH连接、模块执行细节全部打出来代价是输出会非常啰嗦日常调试够用了。6.2 性能优化当你的inventory膨胀到几十台机器管理三五台机器时Playbook慢一点无所谓。但到了几十上百台你会发现一个明显的瓶颈gather_facts阶段要SSH连到每台机器采集系统信息Completely串行执行时非常耗时。实际上Ansible默认就是并行执行的forks参数控制并发数默认是5。如果你管理20台机器把forks调到15到20速度提升会立竿见影。serial参数则相反它控制“每批次多少台机器”。这主要用于滚动更新场景。比如你把serial: 1设置为一批一台某台更新失败时Ansible会停下来不至于整批机器全部挂掉。这个参数在生产环境变更中非常重要——我更愿意让它慢一点也不想看到一次挂掉一个机房的场面。如果你确信playbook里用不到系统Facts可以在play级别设置gather_facts: no直接跳过采集阶段。但这个优化要谨慎万一后面某个任务使用了ansible_facts里的变量就会报“变量未定义”。我的习惯是playbook刚写的时候默认开着Facts等稳定了再根据实际引用情况决定是否关闭。6.3 关于这个项目后续扩展和我个人的一点实践体会Playbook这个东西能讲的远不止这些。变量模板、角色、集合、Vault加密、AWX/Ansible Tower的界面化调度每块都能再写一篇。但如果你把上面这些核心机制弄明白相当于已经拿到了“自动化运维项目”的通行证后面的路不过是按需扩展。最后的最后说几句掏心窝的话。第一Playbook的工程规范比“能跑”重要得多。目录结构、命名习惯、变量作用域、handlers的用法这些在写第一个角色时就该定好规矩否则项目一复杂你就会陷入无休止的重构。第二尽量让Playbook保持“描述状态”而不是“堆砌命令”。这条原则贯彻得越好你的剧本维护成本就越低。第三善用社区的角色库——Ansible Galaxy上有大量现成角色不用重复造轮子。但引入第三方角色前一定要通读其tasks目录因为别人的写法你未必认同出了安全问题更不划算。我自己现在写任何一套自动化部署都是从最小可用的Playbook起步跑通后再逐步加角色、加变量、加CI联动。最忌讳的是一上来就设计一个庞大无比的目录结构结果写了一半自己都不想维护。先让机器动起来再慢慢把代码变优雅。这大概也是Ansible教给我的最朴素、也最实用的道理了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价