Ansible 核心功能進階:自動化任務的靈活控制與管理

一、管理 FACTS:獲取遠程主機的 “身份信息”

  • FACTS 是 Ansible 自動收集的遠程主機詳細信息(類似 “主機身份證”),包括主機名、IP、系統版本、硬件配置等。通過 FACTS 可以動態獲取主機信息,讓 Playbook 更靈活

1. 查看遠程主機的完整域名(FQDN)"playbook.yml"#vim編輯,查看遠程主機(node1)的完整域名(FQDN)1 --- ? ? ? ? ? ? ? ? ? ? ? ? ? ?2 - name: Dump facts ? ? ? ? ? ? 3 ? hosts: node1 ? ? ? ? ? ? ? ? 4 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?5 ? tasks: ? ? ? ? ? ? ? ? ? ? ? 6 ? ? - name: Print all facts ? ?7 ? ? ? debug: ? ? ? ? ? ? ? ? ? 8 ? ? ? ? var: ansible_facts.fqdn ? ?PLAY [Dump facts] ************************************************************************?TASK [Gathering Facts] *******************************************************************ok: [node1]?TASK [Print all facts] *******************************************************************ok: [node1] => {"ansible_facts.fqdn": "node1.lyk.cloud"-作用:在 node1 主機上執行,通過 debug 模塊打印主機的完整域名(FQDN)。-關鍵說明:ansible_facts.fqdn 是 FACTS 中的變量,存儲主機的完整域名(如 node1.lyk.cloud)。debug: var=變量名 用于在執行時顯示變量的值,方便調試。[lyk@controller web 09:51:25]$ ansible-playbook playbook.yml ????2. 查看遠程主機的 IPv4 網絡信息1 --- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2 - name: Dump facts ? ? ? ? ? ? ? ? ? ? 3 ? hosts: node1 ? ? ? ? ? ? ? ? ? ? ? ? 4 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?5 ? tasks: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 6 ? ? - name: Print all facts ? ? ? ? ? ?7 ? ? ? debug: ? ? ? ? ? ? ? ? ? ? ? ? ? 8 ? ? ? ? var: ansible_facts.default_ipv4 ?TASK [Print all facts] *******************************************************************ok: [node1] => {"ansible_facts.default_ipv4": {"address": "10.1.8.11", "alias": "ens33", "broadcast": "10.1.8.255", "gateway": "10.1.8.2", "interface": "ens33", "macaddress": "00:0c:29:1f:2f:2d", "mtu": 1500, "netmask": "255.255.255.0", "network": "10.1.8.0", "type": "ether"}}-作用:打印 node1 的默認 IPv4 網絡信息(IP 地址、網關、子網掩碼等)。關鍵說明:-ansible_facts.default_ipv4 是 FACTS 中存儲默認網卡 IPv4 信息的變量,包含 address(IP 地址)、gateway(網關)等子字段。?3. 導出所有 FACTS 到文件#ansible node1 -m setup > node1.facts:把 node1 的所有信息(不止網絡,還有系統、硬件等)導出到文件[lyk@controller web 09:52:44]$ ansible node1 -m setup > node1.facts#下載到本地電腦,notepad打開,語言選json[lyk@controller web 09:54:04]$ sz node1.facts?

二、loop 循環:批量執行重復任務

  • 當需要對多個對象執行相同操作(如安裝多個軟件、啟動多個服務)時,用 loop 循環可以簡化 Playbook,避免重復寫任務。

1. 批量安裝軟件包和啟動服務

[lyk@controller web 10:39:17]$ vim deploy_web.yml ?15 ? ? # 第一個任務16 ? ? # 任務具有屬性:涵name和模塊名等。17 ? ? # name屬性,用于簡要描述任務18 ? ? - name: latest version of httpd and firewalld installed19 ? ? ?20 ? ? ? # 指明模塊名,也就是要執行的任務21 ? ? ? yum:22 ? ? ?23 ? ? ? ? # 執行要操作的rpm包名稱24 ? ? ? ? name:25 ? ? ? ? ? # rpm包名稱是-開頭的列表格式,或者逗號分隔的列表格式26 ? ? ? ? ? - httpd27 ? ? ? ? ? - firewalld28 ? ? ?29 ? ? ? ? # 定義軟件包的狀態,lastet代表升級為最新版本30 ? ? ? ? state: latest31 ? ? ?32 ? ? # 第二個任務33 ? ? - name: test html page is installed34 ? ? ? # copy模塊,用于將content屬性值寫入到目標文件35 ? ? ? copy:36 ? ? ? ? content: "Welcome to {{ ansible_fqdn }}\n"37 ? ? ? ? dest: /var/www/html/index.html ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?38 ? ? ?39 ? ? # 第三個任務40 ? ? - name: enabled and start httpd/firewalld41 ? ? ? # service模塊,用于啟用并啟動httpd服務42 ? ? ? service:43 ? ? ? ? name: "{{ item }}" ?##注意對齊44 ? ? ? ? enabled: true45 ? ? ? ? state: started46 ? ? ? loop: ? ? ? ? ? ? ? ? ##注釋任務4,和任務3一起執行httpd/firewalld47 ? ? ? ? - httpd48 ? ? ? ? - firewalld49 ? ? ?50 ? ? # 第四個任務和任務三一起執行51 # ?  - name: firewalld enabled and running52 # ? ?  # service模塊,用于啟用并啟動firewalld服務53 # ? ?  service:54 # ? ? ?  name: firewalld55 # ? ? ?  enabled: true56 # ? ? ?  state: started ? ? ? 57 ? ? ?58 ? ? ?59 ? ? # 第五個任務60 ? ? - name: firewalld permits access to httpd service61 ? ? ? # firewalld,用于放行http服務62 ? ? ? firewalld:63 ? ? ? ? service: http64 ? ? ? ? permanent: true65 ? ? ? ? state: enabled66 ? ? ? ? immediate: yes67 ? ? ?68 # Playbook中第二個play,-開頭表示列表69 - name: Test intranet web server70 ? hosts: localhost71 ? become: no72 ? tasks:73 ? ? - name: connect to intranet web server74 ? ? ? # uri模塊,用于測試網站是否可以訪問75 ? ? ? uri:76 ? ? ? ? url: http://node177 ? ? ? ? return_content: yes78 ? ? ? ? status_code: 20079 ? ? ?80 # yaml格式結束行,一般省略81 ... ?[lyk@controller web 10:39:17]$ ansible-playbook deploy_web.yml ?

2. 循環字典列表:批量創建用戶(帶不同屬性)

[lyk@controller web 09:49:57]$ vim playbook.yml1 --- ? ? ? ? ? ? ? ? ? ?2 - name: add several users3 ? hosts: node1 ? ? ? ? 4 ? gather_facts: no ? ? 5 ? tasks: ? ? ? ? ? ? ? 6 ? ? - name: add user jane7 ? ? ? user: ? ? ? ? ? ?8 ? ? ? ? name: "{{ item }}" ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 9 ? ? ? ? groups: "wheel"10 ? ? ? ? state: present 11 ? ? ? loop: ? ? ? ? ? ?12 ? ? ? ? - jane ? ? ? ? 13 ? ? ? ? - joe ? ? ? ?[lyk@controller web 10:49:01]$ ansible-playbook playbook.yml ?PLAY [add several users] **************************************************************************?TASK [add user jane] ******************************************************************************changed: [node1] => (item=jane)changed: [node1] => (item=joe)???[lyk@controller web 10:16:10]$ vim playbook.yml ??1 --- ? ?2 - name: add several users3 ? hosts: node14 ? gather_facts: no5 ? tasks:6 # ?  - name: add user jane7 # ? ?  user:8 # ? ? ?  name: "{{ item }}"9 # ? ? ?  groups: "wheel"10 # ? ? ?  state: present11 # ? ?  loop:12 # ? ? ?  - jane13 # ? ? ?  - joe14 ? ? - name: add users15 ? ? ? user:16 ? ? ? ? name: "{{ item.name }}" ? ? ?##改item->item.name17 ? ? ? ? groups: "{{ item.groups }}" ?##改item->item.groups18 ? ? ? ? state: present19 ? ? ? loop: 20 ? ? ? ? - name: jane21 ? ? ? ? ? groups: wheel22 ? ? ? ? - name: joe23 ? ? ? ? ? groups: root ? ?
3. Do-Until 循環:重試直到成功
[lyk@controller web 10:16:10]$ vim playbook.yml ?1 - name: test loop2 ? hosts: node13 ? gather_facts: no ? ? ? ? 4 ? tasks: ? ? ?5 ? ? - shell: ping -c1 -w 2 node26 ? ? ? register: result ? ? 7 ? ? ? until: result.rc == 08 ? ? ? retries: 209 ? ? ? delay: 1 #斷開node2 [lyk@node2 ~ 09:36:13]$ init 0?#嘗試連接[lyk@controller web 11:21:53]$ ansible-playbook playbook.yml ?PLAY [test loop] *******************************************************************?TASK [shell] ***********************************************************************FAILED - RETRYING: command (20 retries left).FAILED - RETRYING: command (19 retries left).FAILED - RETRYING: command (18 retries left).......?#恢復連接node2,正常進入[lyk@controller web 11:23:15]$ ansible-playbook playbook.yml ?PLAY [test loop] *******************************************************************?TASK [shell] ***********************************************************************changed: [node1]?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=1 ? ?changed=1 ? ?unreachable=0 ? ?failed=0 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ???

三、when 條件判斷:按需執行任務

  • when 用于根據條件決定任務是否執行(類似 “如果滿足條件就做,否則跳過”),讓 Playbook 更智能

1. 基本條件判斷(布爾值、變量是否定義)

#vim playbook.yml1 --- ? ? ? ? ? ? ? ? ? ?2 - name: test ? ? ? ? ? 3 ? hosts: node1 ? ? ? ? 4 ? gather_facts: no ? ? 5 ? vars: ? ? ? ? ? ? ? ?6 ? ? run_my_task: true ?7 ? tasks: ? ? ? ? ? ? ? 8 ? ? - name: test when ?9 ? ? ? debug: ? ? ? ? ? 10 ? ? ? ? msg: "Hello run task"11 ? ? ? when: run_my_task [lyk@controller web 11:23:20]$ ansible-playbook playbook.yml ?PLAY [test] ************************************************************************?TASK [test when] *******************************************************************ok: [node1] => {"msg": "Hello run task"}?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=1 ? ?changed=0 ? ?unreachable=0 ? ?failed=0 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ???#vim playbook.yml1 --- ? ? ? ? ? ? ?2 - hosts: node1 ? 3 ? gather_facts: no4 ? vars: ? ? ? ? ?5 ? ? username: lll ? ? #lll也可以不寫,主要有username:就行 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 6 ? tasks: ? ? ? ? 7 ? ? - debug: ? ? 8 ? ? ? ? msg: "var: username?is?defined"9 ? ? ? when: username?is?defined???

2. 判斷變量 / 文件 / 設備是否存在

#vim playbook.yml1 --- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2 - hosts: node1 ? ? ? ? ? ? ? ? ? ? ? ? ? ?3 ? gather_facts: yes ? ? ? ? ? ? ? ? ? ? ? 4 ? tasks: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?5 ? ? - debug: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?6 ? ? ? ? msg: "sr0 is exist" ? ? ? ? ? ? ? 7 ? ? ? when: ansible_devices.sr0 is defined [lyk@controller web 11:47:58]$ ansible-playbook playbook.yml ?PLAY [node1] ***********************************************************************?TASK [Gathering Facts] *************************************************************ok: [node1]?TASK [debug] ***********************************************************************ok: [node1] => {"msg": "sr0 is exist"}?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=2 ? ?changed=0 ? ?unreachable=0 ? ?failed=0 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ????#vim playbook.yml1 --- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2 - name: create and use lv ? ? ? ? ? ? ? 3 ? hosts: node1 ? ? ? ? ? ? ? ? ? ? ? ? ?4 ? tasks: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?5 ? ? - name: Create a logical volume of 4000m ? ? ? 6 ? ? ? lvol: ? ? ? ? ? ? ? ? ? ? ? ? ? ? 7 ? ? ? ? vg: research ? ? ? ? ? ? ? ? ? ?8 ? ? ? ? lv: data ? ? ? ? ? ? ? ? ? ? ? ?9 ? ? ? ? size: 4000 ? ? ? ? ? ? ? ? ? ? ?10 ? ? ? when: ansible_lvm.vgs.research is defined ? ?11 ? ? - debug: ? ? ? ? ? ? ? ? ? ? ? ? ? ?12 ? ? ? ? msg: Volume group does not exist ?[lyk@controller web 13:30:04]$ ansible-playbook playbook.yml ?PLAY [create and use lv] ***********************************************************?TASK [Gathering Facts] *************************************************************ok: [node1]?TASK [Create a logical volume of 4000m] ********************************************skipping: [node1]?TASK [debug] ***********************************************************************ok: [node1] => {"msg": "Volume group does not exist"?#判斷文件是否存在---- hosts: node1gather_facts: novars:file_name: /etc/hoststasks:- debug:msg: "{{ file_name }}?is regular file"when: file_name is?file

3. 1根據主機組安裝不同軟件

1 --- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2 - name: test ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?3 ? hosts: node1 ? ? ? ? ? ? ? ? 4 ? gather_facts: no ? ? ? ? ? ? ? ? 5 ? vars: ? ? ? ? ? ? 6 ? ? username: devops ? ? ? ? ? ? ? ? ? ? ? 7 ? ? supergroup: wheel ? ? ? ? ? ? ? ? ? ? ?8 ? tasks: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 9 ? ? - name: gather user information ? ? ? ?10 ? ? ? shell: id {{ username }} ? ? ? ? ? ? 11 ? ? ? register: result ? ? ? ? ? ? ? ? ? ? 12 ? ? - name: Task run if user is in supergroups13 ? ? ? user: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?14 ? ? ? ? name: "{{ username }}" ? ? ? ? ? ? 15 ? ? ? ? groups: "{{ supergroup }}" ? ? ? ? 16 ? ? ? ? append: yes ? ? ? ? ? ? ? ? ? ? ? ?17 ? ? ? when: supergroup not in result.stdout ? [lyk@node1 ~ 13:26:53]$ sudo useradd devops[lyk@controller web 13:49:17]$ ansible-playbook playbook.yml ?PLAY [test] ************************************************************************?TASK [gather user information] *****************************************************changed: [node1]?TASK [Task run if user is in supergroups] ******************************************changed: [node1]?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=2 ? ?changed=2 ? ?unreachable=0 ? ?failed=0 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ??

3.2

#根據不同的主機組在指定節點上安裝不同的軟件(web 服務器和數據庫)?#vim "playbook.yml"1 --- ? ?2 - name: test3 ? hosts: node1 node34 ? gather_facts: no5 ? tasks:6 ? ? - name: install httpd7 ? ? ? yum:8 ? ? ? ? name: httpd9 ? ? ? ? state: present10 ? ? ? when: inventory_hostname in groups.webs11 ? ? - name: install mariadb ? ? ? ? ? ? ? ?12 ? ? ? yum: ? ?13 ? ? ? ? name: mariadb ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 14 ? ? ? ? state: present15 ? ? ? when: inventory_hostname in groups.dbs?[lyk@controller web 13:49:20]$ vim inventory ?1 controller2 ?3 [nodes]4 node15 node26 node37 node48 ?9 [webs]10 node111 node212 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 13 [dbs]14 node315 node4??[lyk@controller web 14:00:07]$ ansible-playbook playbook.yml ?PLAY [test] ************************************************************************?TASK [install httpd] ***************************************************************skipping: [node3]ok: [node1]?TASK [install mariadb] *************************************************************skipping: [node1]changed: [node3]?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=1 ? ?changed=0 ? ?unreachable=0 ? ?failed=0 ? ?skipped=1 ? ?rescued=0 ? ?ignored=0 ? node3 ? ? ? ? ? ? ? ? ? ?  : ok=1 ? ?changed=1 ? ?unreachable=0 ? ?failed=0 ? ?skipped=1 ? ?rescued=0 ? ?ignored=0 ? ?

4. loop + when:循環中過濾執行

示例:當 / 文件系統可用空間大于300000000 安裝 mariadb-server

解決方法:通過 ansible_facts 獲取 / 文件系統可用空間

#vim "playbook.yml"?1 --- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2 - name: Combining Loops and Conditional Play3 ? hosts: node1 ? ? ? ? ? ? ? ? ? ? ? ? 4 ? tasks: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 5 ? - name: install mariadb-server if enough space on root6 ? ? yum: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 7 ? ? ? name: mariadb-server ? ? ? ? ? ? 8 ? ? ? state: latest ? ? ? ? ? ? ? ? ? ?9 ? ? loop: "{{ ansible_mounts }}" ? ? ? 10 ? ? when: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?11 ? ? ? - item.mount == "/" ? ? ? ? ? ? ?12 ? ? ? - item.size_available > 300000000 [lyk@controller web 14:20:44]$ ansible-playbook playbook.yml ?PLAY [Combining Loops and Conditional Play] ****************************************?TASK [Gathering Facts] *************************************************************ok: [node1]?TASK [install mariadb-server if enough space on root] ******************************skipping: [node1] => (item={u'block_used': 35554, u'uuid': u'b54b3764-2b2b-4a76-a0ec-83e308071ae5', u'size_total': 1063256064, u'block_total': 259584, u'mount': u'/boot', u'block_available': 224030, u'size_available': 917626880, u'fstype': u'xfs', u'inode_total': 524288, u'options': u'rw,relatime,attr2,inode64,noquota', u'device': u'/dev/sda1', u'inode_used': 326, u'block_size': 4096, u'inode_available': 523962}) ok: [node1] => (item={u'block_used': 523935, u'uuid': u'30af660e-85fc-4fa4-b7a8-72102f439059', u'size_total': 53660876800, u'block_total': 13100800, u'mount': u'/', u'block_available': 12576865, u'size_available': 51514839040, u'fstype': u'xfs', u'inode_total': 26214400, u'options': u'rw,relatime,attr2,inode64,noquota', u'device': u'/dev/mapper/centos-root', u'inode_used': 34064, u'block_size': 4096, u'inode_available': 26180336})?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=2 ? ?changed=0 ? ?unreachable=0 ? ?failed=0 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ?

5.register 和 when 聯合

示例:當 / 文件系統可用空間大于300000000 安裝 mariadb-server

解決方法:通過 shell 獲取 / 文件系統可用空間

#vim "playbook.yml"1 --- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2 - name: test 3 ? hosts: node14 ? gather_facts: no5 ? tasks: ? ?6 ? ? - name: get / available7 ? ? ? shell: df / | awk 'NR==2 {print $4}'8 ? ? ? register: fs_size ? 9 ? ? - name: install mariadb-server ? ? ? 10 ? ? ? yum: ?11 ? ? ? ? name: mariadb-server ? ? ? ? ? ? 12 ? ? ? ? state: present ? ?13 ? ? ? when: fs_size.stdout | int >= 300000?

一、兩個 Playbook 的核心功能

兩者的核心邏輯都是:

  1. 檢查根目錄(/)的可用空間

  2. 當可用空間滿足條件(大于某個值)時,安裝 mariadb-server

  3. 僅在 node1 主機上執行操作

二、具體區別

對比維度loop + ansible_facts 方式register + shell 方式
獲取磁盤信息的方式使用 Ansible 內置的ansible_facts收集磁盤信息通過shell命令(df + awk)手動獲取磁盤信息
是否需要收集 facts需要(默認啟用gather_facts: yes不需要(顯式設置gather_facts: no
循環的使用使用loop: "{{ ansible_mounts }}"遍歷所有掛載點不使用循環,直接獲取根目錄信息
條件判斷的邏輯1. 先通過item.mount == "/"篩選根目錄掛載點 2. 再判斷可用空間是否滿足條件直接對 shell 命令返回的根目錄可用空間進行判斷
可用空間的單位ansible_facts返回的是字節(bytes)df命令默認返回的是 KB(千字節)
適用場景適合需要處理多個掛載點的復雜場景適合只需要檢查單個特定目錄的簡單場景

四、Ansible Handlers:任務改變后觸發操作

示例:安裝軟件后重啟服務
[lyk@node1 ~ 14:41:45]$ sudo yum remove -y httpd?#vim "playbook.yml"1 --- ? ? ? ? ? ? ? ? 2 - name: deploy web server3 ? hosts: node1 ? ? ?4 ? tasks: ? ? ? ? ? ?5 ? ? - name: install packages6 ? ? ? yum: ? ? ? ? ?7 ? ? ? ? name: httpd 8 ? ? ? ? state: present9 ? ? ? notify: ? ? ? 10 ? ? ? ? - enable and restart apache11 ? ? ? ? ? ? ? ? ? ? 12 ? ? - name: install httpd-manual13 ? ? ? yum: ? ? ? ? ?14 ? ? ? ? name: httpd-manual15 ? ? ? ? state: present16 ? ? ? notify: ? ? ? 17 ? ? ? ? - enable and restart apache18 ? ? ? ? ? ? ? ? ? ? 19 ? ? - debug: ? ? ? ?20 ? ? ? ? msg: last task in tasks21 ? ? ? ? ? ? ? ? ? ? 22 ? handlers: ? ? ? ? 23 ? ? - name: enable and restart apache24 ? ? ? service: ? ? ?25 ? ? ? ? name: httpd 26 ? ? ? ? state: restarted27 ? ? ? ? enabled: yes ? ? ? ?[lyk@controller web 14:40:28]$ ansible-playbook playbook.yml ?PLAY [deploy web server] ***********************************************************?TASK [Gathering Facts] *************************************************************ok: [node1]?TASK [install packages] ************************************************************changed: [node1]?TASK [install httpd-manual] ********************************************************changed: [node1]?TASK [debug] ***********************************************************************ok: [node1] => {"msg": "last task in tasks"}?RUNNING HANDLER [enable and restart apache] ****************************************changed: [node1]?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=5 ? ?changed=3 ? ?unreachable=0 ? ?failed=0 ?  skipp?#再次執行有區別[lyk@controller web 14:42:02]$ ansible-playbook playbook.yml ?PLAY [deploy web server] ***********************************************************?TASK [Gathering Facts] *************************************************************ok: [node1]?TASK [install packages] ************************************************************ok: [node1]?TASK [install httpd-manual] ********************************************************ok: [node1]?TASK [debug] ***********************************************************************ok: [node1] => {"msg": "last task in tasks"}?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=4 ? ?changed=0 ? ?unreachable=0 ? ?failed=0 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ?

meta 模塊

在多個任務中間加入meta任務,那么在此之前調用的 handler 會立即處理。

示例:

---
- name: deploy db serverhosts: node1tasks:- name: install mariadbyum:name:- mariadb-server- python3-PyMySQLstate: presentnotify:- enable_and_start_db- meta: flush_handlers- name: add mariadb usermysql_user:name: lykpassword: redhathandlers:- name: enable_and_start_dbservice:name: mariadbstate: started

五、錯誤處理:控制任務失敗后的行為

處理 Errors

#node1[lyk@node1 ~ 15:00:39]$ sudo cp /etc/hosts /etc/myhosts#node2[lyk@node2 ~ 15:01:26]$ rm -f /etc/myhosts??[lyk@controller web 15:02:35]$ ansible-playbook playbook.yml ?PLAY [test] ************************************************************************?TASK [Gathering Facts] *************************************************************ok: [node2]ok: [node1]?TASK [show /etc/myhosts] ***********************************************************fatal: [node2]: FAILED! => {"changed": true, "cmd": "cat /etc/myhosts", "delta": "0:00:00.002070", "end": "2025-08-14 15:09:39.413406", "msg": "non-zero return code", "rc": 1, "start": "2025-08-14 15:09:39.411336", "stderr": "cat: /etc/myhosts: 沒有那個文件或目錄", "stderr_lines": ["cat: /etc/myhosts: 沒有那個文件或目錄"], "stdout": "", "stdout_lines": []}changed: [node1]?TASK [echo end] ********************************************************************ok: [node1] => {"msg": "echo end"}?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=3 ? ?changed=1 ? ?unreachable=0 ? ?failed=0 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? node2 ? ? ? ? ? ? ? ? ? ?  : ok=1 ? ?changed=0 ? ?unreachable=0 ? ?failed=1 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ?

ignore_errors

1 --- ? ? ? ? ? ? ? ? ? ? ? ? 2 - name: test ? ? ? ? ? ? ? ?3 ? hosts: node1 ? ? ? ? ? ? ?4 ? tasks: ? ? ? ? ? ? ? ? ? ?5 ? ? - name: install a not exist package6 ? ? ? yum: ? ? ? ? ? ? ? ? ?7 ? ? ? ? name: notexitpackage8 ? ? ? ? state: present ? ? ?9 ? ? ? ignore_errors: yes ? ?10 ? ? ? register: result ? ? ?11 ? ? - name: debug install result12 ? ? ? debug: ? ? ? ? ? ? ? ?13 ? ? ? ? msg: notexitpackage is not exit14 ? ? ? when: result is failed ? [lyk@controller web 15:09:39]$ ansible-playbook playbook.yml ?PLAY [test] ************************************************************************?TASK [Gathering Facts] *************************************************************ok: [node1]?TASK [install a not exist package] *************************************************fatal: [node1]: FAILED! => {"changed": false, "msg": "No package matching 'notexitpackage' found available, installed or updated", "rc": 126, "results": ["No package matching 'notexitpackage' found available, installed or updated"]}...ignoring?TASK [debug install result] ********************************************************ok: [node1] => {"msg": "notexitpackage is not exit"}?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=3 ? ?changed=0 ? ?unreachable=0 ? ?failed=0 ? ?skipped=0 ? ?rescued=0 ? ?ignored=1 ? ??

force_handlers

1 --- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2 - name: test3 ? hosts: node14 ? force_handlers: yes5 ? tasks: ? 6 ? ? - name: a task which always notifies its handler7 ? ? ? command: /bin/true8 ? ? ? notify: restart the sshd9 ? ? ? ? ? ?10 ? ? - name:  fails because the package doesn't exist11 ? ? ? yum: 12 ? ? ? ? name: notexistpkg13 ? ? ? ? state: latest ?14 ?15 ? handlers:16 ? ? - name: restart the sshd17 ? ? ? service: ? ? ?18 ? ? ? ? name: sshd ?19 ? ? ? ? state: restarted?[lyk@controller web 15:10:41]$ ansible-playbook playbook.yml ?PLAY [test] ************************************************************************?TASK [Gathering Facts] *************************************************************ok: [node1]?TASK [a task which always notifies its handler] ************************************changed: [node1]?TASK [fails because the package doesn't exist] *************************************fatal: [node1]: FAILED! => {"changed": false, "msg": "No package matching 'notexistpkg' found available, installed or updated", "rc": 126, "results": ["No package matching 'notexistpkg' found available, installed or updated"]}?RUNNING HANDLER [restart the sshd] *************************************************changed: [node1]?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=3 ? ?changed=2 ? ?unreachable=0 ? ?failed=1 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ?

fail 模塊

1 - name: test fail module ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2 ? hosts: node13 ? gather_facts: no4 ? tasks:5 ? ? - debug:6 ? ? ? ? msg: task17 ? ? - fail:8 ? ? - debug:9 ? ? ? ? msg: task3?[lyk@controller web 15:11:41]$ ansible-playbook playbook.yml ?PLAY [test fail module] ************************************************************?TASK [debug] ***********************************************************************ok: [node1] => {"msg": "task1"}?TASK [fail] ************************************************************************fatal: [node1]: FAILED! => {"changed": false, "msg": "Failed as requested from task"}?PLAY RECAP *************************************************************************node1 ? ? ? ? ? ? ? ? ? ?  : ok=1 ? ?changed=0 ? ?unreachable=0 ? ?failed=1 ? ?skipped=0 ? ?rescued=0 ? ?ignored=0 ? ?

failed_when

指明什么條件下,判定任務執行失敗

- name: test failed_whenhosts: node1tasks:- shell: /root/adduserregister: command_resultfailed_when: "'failed' in command_result.stdout"

環境準備:

[root@node1 ~]# cat /root/adduser #!/bin/bashuseradd devops &> /dev/nullif [ $? -eq 0 ];thenecho add user devops successelseecho add user devops failedfi[root@node1 ~]# chmod +x /root/adduser 

以上示例:

  • 當devops用戶不存在時,shell模塊跳過執行。

  • 當devops用戶存在時,shell模塊執行失敗。

以上示例可改寫為fail模塊和when語句聯合使用:

- name: test fail modulehosts: node1tasks:- shell: /root/adduserregister: command_result?- fail:msg: "add user devops failed"when: "'failed' in command_result.stdout"

changed_when

指明什么條件下,判定任務執行結果為changed。

示例1:

- name: changed_whenhosts: node1tasks:- name: upgrade-databaseshell: /usr/local/bin/upgrade-databaseregister: resultchanged_when: "'Success' in result.stdout"notify:- restart_databasehandlers:- name: restart_databaseservice:name: mariadbstate: restarted

環境準備:

[root@node1 ~]# yum install -y mariadb-server[root@node1 ~]# systemctl enable mariadb --now[root@node1 ~]# vim /usr/local/bin/upgrade-database#!/bin/bashmysql -e 'create user lyk@"%" identified by "123";' && mysql -e 'GRANT ALL PRIVILEGES on *.* TO 123@"%";' && echo update database Success[root@node1 ~]# chmod +x /usr/local/bin/upgrade-database

對于command模塊和shell模塊,只要命令正常執行,結果狀態通常都是changed。可以通過返回碼和輸出結果來判定它們是否做出更改。

關鍵字 changed_when: false ,讓任務結果狀態不為changed,只能報告為ok或failed。

示例2:

---- name: Test Whenhosts: node1gather_facts: notasks:- name: test changed_whenshell: cat /etc/redhat-releasechanged_when: false

Ansible block

示例2:在所有受管節點上創建符合以下要求的邏輯卷:

  • 在research卷組中創建邏輯卷:

    • 邏輯卷名稱為data

    • 邏輯卷大小為4000MiB

    • 使用ext4文件系統格式化邏輯卷

    • 將邏輯卷掛載到/data目錄

    • 如果無法創建請求的邏輯卷大小,應顯示錯誤信息:Could not create logical volume of that size 并且應改為使用大小800MiB。

  • 如果卷組research不存在,應顯示錯誤信息:Volume does not exist

環境準備

node1添加20Gnode2添加20G??[root@node1 ~ 15:36:17]# vgcreate research /dev/sdbPhysical volume "/dev/sdb" successfully created.Volume group "research" successfully created??[root@node2 ~ 15:37:09]# parted /dev/sdb unit MiB mklabel msdos信息: You may need to update /etc/fstab.?[root@node2 ~ 15:37:26]# parted /dev/sdb unit MiB mkpart primary 1 1025 ? 信息: You may need to update /etc/fstab.?[root@node2 ~ 15:37:34]# vgcreate research /dev/sdb1 ? ? ? ? ? ? ? ? ? ? ?Physical volume "/dev/sdb1" successfully created.Volume group "research" successfully created

vim編輯

[lyk@controller web 16:02:28]$ ansible-doc -l |grep -i lvmaix_filesystem ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?  Configure LVM and...aix_lvg ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Manage LVM volume...lvol ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?  Configure LVM log...aix_lvol ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?  Configure AIX LVM...lvg ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Configure LVM vol...?[lyk@controller web 16:03:12]$ ansible-doc lvol#進入文件復制EXAMPLES:?- name: Create a logical volume of 512mlvol:vg: fireflylv: testsize: 512???1 --- ? ? ? ? ? ? ? ? ? ? ? 2 - name: create logical volume3 ? hosts: all ? ? ? ? ? ? ?4 ? tasks: ? ? ? ? ? ? ? ? ?5 ? ? - name: create lv ? ? 6 ? ? ? block: ? ? ? ? ? ? ?7 ? ? ? ? - name: Create a logical volume of 4000m8 ? ? ? ? ? lvol: ? ? ? ? ? 9 ? ? ? ? ? ? vg: research ?10 ? ? ? ? ? ? lv: data ? ? ?11 ? ? ? ? ? ? size: 4000 ? ?12 ? ? ? rescue: ? ? ? ? ? ? 13 ? ? ? ? - name: Could not create logical volume of that size14 ? ? ? ? ? debug: ? ? ? ? ?15 ? ? ? ? ? ? msg: Could not create logical volume of that size16 ? ? ? ? - name: Create a logical volume of 800m17 ? ? ? ? ? lvol: ? ? ? ? ? 18 ? ? ? ? ? ? vg: research ?19 ? ? ? ? ? ? lv: data ? ? ?20 ? ? ? ? ? ? size: 800 ? ? 21 ? ? ? always: ? ? ? ? ? ? 22 ? ? ? ? - name: Create a ext4 filesystem23 ? ? ? ? ? filesystem: ? ? 24 ? ? ? ? ? ? fstype: ext4 ?25 ? ? ? ? ? ? dev: /dev/research/data26 ? ? ? ? - name: Create a directory27 ? ? ? ? ? file: ? ? ? ? ? 28 ? ? ? ? ? ? path: /data ? 29 ? ? ? ? ? ? state: directory30 ? ? ? ? - name: Mount up device31 ? ? ? ? ? mount: ? ? ? ? ?32 ? ? ? ? ? ? path: /data ? 33 ? ? ? ? ? ? src: /dev/research/data34 ? ? ? ? ? ? fstype: ext4 ?35 ? ? ? ? ? ? state: mounted ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 36 ? ? ? when: ansible_lvm.vgs.research is defined37 ? ? - name: Volume does not exist38 ? ? ? debug: ? ? ? ? ? ? ?39 ? ? ? ? msg: Volume does not exist40 ? ? ? when: ansible_lvm.vgs.research is defined???[lyk@controller web 16:37:04]$ ansible-playbook playbook.yml ?PLAY [create logical volume] *******************************************************?TASK [Gathering Facts] *************************************************************ok: [node3]ok: [node1]ok: [node2]ok: [node4]ok: [controller]?TASK [Create a logical volume of 4000m] ********************************************skipping: [controller]skipping: [node3]skipping: [node4][WARNING]: The value 4000 (type int) in a string field was converted to u'4000'(type string). If this does not look like what you expect, quote the entire valueto ensure it does not change.fatal: [node2]: FAILED! => {"changed": false, "err": "  Volume group \"research\" has insufficient free space (255 extents): 1000 required.\n", "msg": "Creating logical volume 'data' failed", "rc": 5}changed: [node1]?TASK [Could not create logical volume of that size] ********************************ok: [node2] => {"msg": "Could not create logical volume of that size"}?TASK [Create a logical volume of 800m] *********************************************[WARNING]: The value 800 (type int) in a string field was converted to u'800' (typestring). If this does not look like what you expect, quote the entire value toensure it does not change.changed: [node2]?TASK [Create a ext4 filesystem] ****************************************************skipping: [controller]skipping: [node3]skipping: [node4]changed: [node2]changed: [node1]?TASK [Create a directory] **********************************************************skipping: [controller]skipping: [node3]skipping: [node4]changed: [node2]changed: [node1]?TASK [Mount up device] *************************************************************skipping: [controller]skipping: [node3]skipping: [node4]changed: [node1]changed: [node2]?TASK [Volume does not exist] *******************************************************skipping: [controller]ok: [node2] => {"msg": "Volume does not exist"}ok: [node1] => {"msg": "Volume does not exist"}skipping: [node3]skipping: [node4]?PLAY RECAP *************************************************************************controller ? ? ? ? ? ? ? ? : ok=1 ?  changed=0 ?  unreachable=0 ?  failed=0 ?  skipped=5 ?  rescued=0 ?  ignored=0 ? node1 ? ? ? ? ? ? ? ? ? ?  : ok=6 ?  changed=4 ?  unreachable=0 ?  failed=0 ?  skipped=0 ?  rescued=0 ?  ignored=0 ? node2 ? ? ? ? ? ? ? ? ? ?  : ok=7 ?  changed=4 ?  unreachable=0 ?  failed=0 ?  skipped=0 ?  rescued=1 ?  ignored=0 ? node3 ? ? ? ? ? ? ? ? ? ?  : ok=1 ?  changed=0 ?  unreachable=0 ?  failed=0 ?  skipped=5 ?  rescued=0 ?  ignored=0 ? node4 ? ? ? ? ? ? ? ? ? ?  : ok=1 ?  changed=0 ?  unreachable=0 ?  failed=0 ?  skipped=5 ?  rescued=0 ?  ignored=0 ? ?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/919144.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/919144.shtml
英文地址,請注明出處:http://en.pswp.cn/news/919144.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

gRPC網絡模型詳解

gRPC協議框架 TCP層:底層通信協議,基于TCP連接。 TLS層:該層是可選的,基于TLS加密通道。 HTTP2層:gRPC承載在HTTP2協議上,利用了HTTP2的雙向流、流控、頭部壓縮、單連接上的多 路復用請求等特性。 gRPC層…

[優選算法專題二滑動窗口——將x減到0的最小操作數]

題目鏈接 將x減到0的最小操作數 題目描述 題目解析 問題重述 給定一個整數數組 nums 和一個整數 x,每次只能從數組的左端或右端移除一個元素,并將該元素的值從 x 中減去。我們需要找到將 x 恰好減為 0 的最少操作次數,如果不可能則返回 -…

AOP配置類自動注入

本文主要探究AopAutoConfiguration配置類里面的bean怎么被自動裝配的。代碼如下:package com.example.springdemo.demos.a05;import com.example.springdemo.demos.a04.Bean1; import com.example.springdemo.demos.a04.Bean2; import com.example.springdemo.demos…

云計算-K8s 實戰:Pod、安全上下文、HPA 、CRD、網絡策略、親和性等功能配置實操指南

簡介 此次圍繞Kubernetes 日常管理中的核心場景,提供了從基礎到進階的實操配置指南。內容涵蓋 9 大關鍵知識點:從使用 nginx 鏡像創建 QoS 類為 Guaranteed 的 Pod,到為 Pod 配置安全上下文以指定運行用戶和組;從自定義 Student 資源類型(CRD),到配置 Sidecar 實現跨命…

嵌入式LINUX——————TCP并發服務器

一、服務器1.服務器分類單循環服務器:只能處理一個客戶端任務的服務器 并發服務器:可同時處理多個客戶端任務的服務器二、TCP并發服務器的構建1.如何構建? (1)多進程(每一次創建都非常耗時耗空間&#…

論文潤色不能降低文章的重復率

最近大家問到多的,你們潤色好了重復率會不會就降低了。這事兒啊,得從好幾個方面去剖析,今天咱們就一塊兒來探個究竟。咱們先得清楚,重復率檢測工具一般會把內容標記成兩類:一是那些和其他文獻在文字表達上高度相似的部…

Python爬蟲實戰:構建alltheplaces平臺地理信息數據采集系統

1. 引言 1.1 研究背景與意義 在大數據與智慧城市建設的推動下,地理位置信息(如餐館、景點、公共設施等 POI 數據)已成為商業分析、城市規劃、公共服務優化的核心基礎數據。alltheplaces 作為全球領先的開放場所數據平臺,整合了來自多個數據源的標準化信息,涵蓋場所名稱、…

HTML第三次作業

抽獎項目代碼<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>簡易抽獎轉盤</title><sty…

PyTorch 面試題及詳細答案120題(01-05)-- 基礎概念與安裝

《前后端面試題》專欄集合了前后端各個知識模塊的面試題&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

云手機選哪個比較好用?

云手機作為基于云計算技術運行的一款虛擬手機&#xff0c;能夠幫助企業與個人用戶進行賬號多開和遠程訪問等多種功能&#xff0c;是手游玩家的首要選擇&#xff0c;能夠多開賬號掛機不卡頓&#xff0c;但是哪一款云手機更加流暢好用呢&#xff1f;對于熱衷于手游的玩家來說&…

[科研理論]無人機底層控制算法PID、LQR、MPC解析

文章目錄1. PX4飛控PID簡介1.1 位置控制器1.2 速度控制器1.3 加速度和yaw轉到姿態1.4 姿態控制器1.5 角速率控制器2. 線性二次型優化&#xff08;LQR&#xff09;控制3. 模型預測控制MPC/NMPC3.1 MPC3.2 NMPC1. PX4飛控PID簡介 相關鏈接&#xff1a;PX4官方中文文檔、PID概念(…

AI系統性思維復盤概述

核心價值&#xff1a;從“被動思考”到“主動進化”。 基于數據驅動、機器學習和知識圖譜的智能化組織學習系統&#xff0c;它將經驗積累從傳統的主觀性、碎片化模式轉變為客觀性、系統化的科學模式&#xff0c;最終實現從被動應對向主動預防、從經驗決策向數據決策、從個體智慧…

C++繼承(2)

2.基類和派生類間的轉換 ?public繼承的派?類對象可以賦值給基類的指針/基類的引?。這?有個形象的說法叫切?或者切 割。寓意把派?類中基類那部分切出來&#xff0c;基類指針或引?指向的是派?類中切出來的基類那部分。 ? 基類對象不能賦值給派?類對象。 ? 基類的指針或…

easya2a: 一鍵將 LangChain Agent 發布為 A2A 服務

easya2a: 一鍵將 LangChain Agent 發布為 A2A 服務 隨著 A2A (Agent-to-Agent) 協議的發布&#xff0c;相關的實踐項目也逐漸涌現。對于許多希望體驗 A2A 功能&#xff0c;但又擔心學習成本和開發時間的開發者來說&#xff0c;推薦使用 easya2a——一個可以快速、無縫地將現有 …

原學之設計模式- 設計模式來源

引言 各位旅行者們你們好&#xff0c;我是小森&#xff0c;首先我為啥是程序員。學了技術快六年了&#xff0c;但一直都是斷斷續續&#xff0c;本身自己的條件&#xff0c;從2021年11月份開始下載原神&#xff0c;總而言之不了解一些抽卡機制導致退了并且刪除了具體賬號打算重新…

有鹿機器人:AI技術如何重新定義「掃地」這件小事?

當掃地成為一門“技術活”掃地&#xff0c;可能是人類最古老的清潔行為之一。從掃帚到吸塵器&#xff0c;再到今天的無人駕駛清潔設備&#xff0c;我們一直在尋找更高效、更徹底的方式維護環境整潔。但有鹿機器人的出現&#xff0c;讓“掃地”這件事有了新的定義——它不再只是…

62.不同路徑

dp問題描述 62.不同路徑 確定本題的狀態表示 dp[i,j]表示的是從左上角走到這個位置的路徑條數 確定本題的狀態轉移方程 根據已知條件&#xff1a;dp[0,0]1&#xff0c;dp[0,1]1&#xff0c;dp[1,0]1 本題的狀態轉移方程是&#xff1a; dp[i,j]dp[i,j-1]dp[i-1,j] 填表求…

python---包

文章目錄包的基本概念創建包的基本結構__init__.py文件導入包和模塊相對導入&#xff08;在包內部使用&#xff09;導入包和導入模塊的區別包是Python中組織模塊的一種方式&#xff0c;它允許你將相關的模塊分組在一起&#xff0c;形成一個層次結構。包的主要目的是幫助避免命名…

超詳細yolov8/11-obb旋轉框全流程概述:配置環境、數據標注、訓練、驗證/預測、onnx部署(c++/python)詳解

因為yolo的檢測/分割/姿態/旋轉/分類模型的環境配置、訓練、推理預測等命令非常類似&#xff0c;這里不再詳細敘述環境配置&#xff0c;主要參考【超詳細yolo8/11-detect目標檢測全流程概述&#xff1a;配置環境、數據標注、訓練、驗證/預測、onnx部署(c/python)詳解】&#xf…

創世理論達成 全關聯的動態振動網:量子世界的“底層邏輯”

全關聯的動態振動網&#xff1a;量子世界的“底層邏輯”&#xff08;不帶公式&#xff0c;超級詳細&#xff09;要真正理解量子世界的本質&#xff0c;我們需要跳出“粒子”和“波”的傳統框架&#xff0c;從量子場論的核心邏輯出發&#xff0c;用最生活化的類比和日常經驗&…