SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-21

วิธีใช้ Ansible check mode และ --diff เพื่อทดสอบรัน

เรียนรู้วิธีใช้ --check และ --diff ใน Ansible เพื่อตรวจสอบการเปลี่ยนแปลงก่อนรันจริง พร้อมทำความเข้าใจข้อจำกัดของโมดูลที่ไม่รองรับโหมดนี้ ซึ่งอาจทำให้การทดสอบรันให้ผลลัพธ์ที่ผิดพลาดได้

การทำงานของ Ansible check mode

Ansible check mode คือการทดสอบรัน (dry run) โดยที่ ansible-playbook --check จะเชื่อมต่อไปยังทุกโฮสต์ใน play และสอบถามแต่ละโมดูลว่าสถานะปัจจุบันตรงกับสถานะที่คุณต้องการแล้วหรือไม่ จากนั้นจะรายงานสิ่งที่กำลังจะเปลี่ยนแปลงโดยไม่มีการเขียนข้อมูลใดๆ ลงไป หากเพิ่มแฟล็ก --diff เข้าไปด้วย Ansible จะแสดงเนื้อหาของไฟล์ก่อนและหลังการเปลี่ยนแปลงที่จะเกิดขึ้น ทั้งสองอย่างนี้รวมกันจะช่วยตอบคำถามสำคัญที่ควรตรวจสอบก่อนการรันจริงเสมอว่า: สิ่งใดกำลังจะเปลี่ยนแปลงบนเซิร์ฟเวอร์เหล่านี้บ้าง?

Check mode ไม่ใช่การจำลองการทำงานของ playbook ของคุณ เนื่องจากไม่มีโมเดลของเซิร์ฟเวอร์อยู่ที่ใดเลย แต่ละโมดูลจะถูกสั่งให้ตรวจสอบแทนการเขียนข้อมูล โมดูลที่สามารถตอบสนองแบบอ่านอย่างเดียวจะรายงานสถานะ changed แล้วทำงานต่อไป ส่วนโมดูลที่ไม่สามารถตอบสนองได้จะไม่ทำอะไรและไม่รายงานผลใดๆ เอกสารของ Ansible สรุปไว้ในบรรทัดเดียวว่า: "โมดูลที่ไม่รองรับ check mode จะไม่รายงานผลและไม่ดำเนินการใดๆ" ช่องว่างดังกล่าวคือจุดที่การทดสอบรันอาจให้คำตอบที่ผิดพลาด ดังนั้นเนื้อหาส่วนใหญ่ในคู่มือนี้จึงมุ่งเน้นไปที่ช่องว่างดังกล่าว

เรียกใช้การทดสอบแบบจำลอง (dry run): --check และ --diff

ansible-playbook -i inventory.ini site.yml --check --diff --limit web1

-C และ -D เป็นรูปแบบย่อของทั้งสองแฟล็ก ส่วน --limit นั้นตั้งใจให้เป็นเช่นนั้น ผลต่าง (diff) ของโฮสต์เดียวเป็นสิ่งที่อ่านทำความเข้าใจได้ แต่ผลต่างของโฮสต์ยี่สิบเครื่องเป็นสิ่งที่ทำได้เพียงแค่เลื่อนผ่านไป

คำผลลัพธ์สี่คำสรุปรายงานทั้งหมด

  • ok: [web1] หมายความว่าโมดูลได้ตรวจสอบแล้วและสถานะตรงกันอยู่ก่อนแล้ว จะไม่มีการเปลี่ยนแปลงใดๆ เกิดขึ้น
  • changed: [web1] หมายความว่าโมดูลจะทำการเขียนข้อมูลบางอย่าง หากใช้ร่วมกับ --diff บรรทัดด้านบนจะแสดงให้เห็นว่ามีการเปลี่ยนแปลงอย่างไร
  • skipping: [web1] หมายความว่างานดังกล่าวไม่ได้ถูกประเมินผล อาจเป็นเพราะเงื่อนไข when เป็นเท็จ หรือโมดูลไม่สามารถทำงานในโหมดตรวจสอบได้
  • fatal: [web1] หมายความว่างานล้มเหลวระหว่างการตรวจสอบ โปรดอ่านข้อความแจ้งเตือนก่อนที่จะสรุปว่า playbook มีข้อผิดพลาด

--diff จะพิมพ์ผลต่างแบบ unified diff สำหรับโมดูลจัดการไฟล์ โดยบรรทัดที่ถูกลบจะทำเครื่องหมายด้วย - และบรรทัดที่เพิ่มเข้ามาจะทำเครื่องหมายด้วย + ภายใต้ส่วนหัวที่บรรทัดเริ่มต้นด้วย --- before และ +++ after ซึ่งระบุพาธปลายทาง โมดูลที่ไม่ได้เขียนไฟล์จะแสดงสถานะก่อนและหลังของตนเอง ดังนั้น ansible.builtin.user จะแสดงแอตทริบิวต์ที่จะถูกเปลี่ยนแทนที่จะเป็นเนื้อหาไฟล์

เปิดใช้งาน diff อย่างถาวรใน ansible.cfg เพื่อให้คุณไม่ลืมใส่แฟล็กนี้:

[diff]
always = true
context = 5

การตรวจสอบที่ประหยัดทรัพยากรกว่าสองรายการควรทำก่อนเข้าสู่โหมดตรวจสอบ ansible-playbook site.yml --syntax-check จะทำการแยกวิเคราะห์ (parse) YAML และโครงสร้างของ play โดยไม่ต้องติดต่อโฮสต์ใดๆ เลย ansible-playbook site.yml --list-tasks จะพิมพ์รายการงานที่จะถูกเรียกใช้งาน ซึ่งเป็นวิธีที่คุณจะทราบว่า role ที่คุณคิดว่าติดแท็กไว้นั้นจริงๆ แล้วไม่ได้ติด ทั้งสองคำสั่งนี้ไม่มีการเชื่อมต่อเครือข่าย จึงทำงานได้ทันที

โหมดตรวจสอบ (check mode) จะมีการเชื่อมต่อจริง โดยจะเปิด SSH ไปยังทุกโฮสต์ในรูปแบบที่กำหนดและรวบรวมข้อมูล (facts) ดังนั้นโฮสต์ที่ออฟไลน์อยู่จะทำให้การทดสอบแบบจำลองล้มเหลว ซึ่งเป็นสัญญาณที่มีประโยชน์ในตัวมันเอง และเป็นเหตุผลว่าทำไม การตัดสินใจว่า playbook ควรจัดการอย่างไรกับโฮสต์ที่ไม่สามารถเข้าถึงได้ จึงมีความสำคัญก่อนที่คุณจะนำการทดสอบแบบจำลองไปใช้ใน CI

เหตุใด check mode จึงล้มเหลวบนเซิร์ฟเวอร์ใหม่

Playbook นี้ถูกต้องแล้ว หากคุณรันด้วย --check บนเซิร์ฟเวอร์ที่ยังไม่ได้ติดตั้ง nginx ส่วนใหญ่ของงานจะล้มเหลว

- name: Install nginx
  ansible.builtin.apt:
    name: nginx
    state: present

- name: Write the site config
  ansible.builtin.template:
    src: site.conf.j2
    dest: /etc/nginx/conf.d/site.conf

- name: Start and enable nginx
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

งาน apt จะรายงานสถานะ changed ซึ่งถูกต้องแล้ว เนื่องจากแพ็กเกจยังไม่มีอยู่จริง การรันจริงจึงจะทำการติดตั้งให้ แต่ check mode ไม่ได้ทำการติดตั้งให้ งาน template จึงล้มเหลวตามมา เพราะ /etc/nginx/conf.d/ ไม่มีอยู่บนโฮสต์นี้และไม่มีกระบวนการใดสร้างมันขึ้นมา งาน service ก็ล้มเหลวเช่นกันเนื่องจากไม่มี unit nginx ให้ตรวจสอบ ความล้มเหลวทั้งสองกรณีไม่ใช่บั๊กใน playbook แต่เป็นการที่ dry run ขาดสถานะที่จำเป็น ซึ่งเป็นสิ่งที่เอกสารระบุไว้เมื่อเตือนว่า check mode ไม่สามารถให้ผลลัพธ์ที่มีประโยชน์สำหรับงานที่อินพุตขึ้นอยู่กับการเปลี่ยนแปลงของงานก่อนหน้า

ดังนั้น กฎที่แท้จริงคือ check mode จะแม่นยำเมื่อใช้กับโฮสต์ที่ playbook ได้ทำการปรับสถานะ (converge) เรียบร้อยแล้ว แต่จะแสดงผลแจ้งเตือนจำนวนมากเมื่อใช้กับโฮสต์ใหม่ การรัน --check ที่ทุกงานรายงานสถานะ ok เป็นการยืนยันที่แท้จริงเกี่ยวกับโฮสต์ที่ปรับสถานะแล้ว เพราะหมายความว่าจะไม่มีการเปลี่ยนแปลงใดๆ เกิดขึ้น แต่บนโฮสต์ใหม่ --check จะบอกคุณเพียงว่าโฮสต์นั้นยังใหม่ เมื่อคุณเขียน Ansible playbook แรกของคุณบน VPS ให้คาดการณ์ไว้เลยว่าการรัน dry run ครั้งแรกจะเต็มไปด้วยข้อความสีแดง และให้ประเมินคุณภาพของ playbook จากการรันครั้งที่สองแทน

เหตุใดงานประเภท command และ shell จึงถูกข้ามในโหมด check

ansible.builtin.command และ ansible.builtin.shell ไม่สามารถทราบได้ว่าคำสั่งของคุณทำหน้าที่อะไร เนื่องจากไม่มีวิธีใดที่จะรัน binary ใดๆ แบบอ่านได้อย่างเดียว (read-only) ในโหมด check โมดูลจึงปฏิเสธที่จะรันคำสั่งดังกล่าว ผลลัพธ์ของงานจะระบุสถานะเป็น skipped: true พร้อมข้อความ Command would have run if not in check mode และใน output ของคุณจะแสดงเป็น skipping: [web1]

เอกสารประกอบของโมดูลระบุว่าการรองรับโหมด check ของตนนั้นเป็นแบบ "บางส่วน" (partial) และวิธีแก้ปัญหาที่แนะนำคือการใช้ creates และ removes หากคุณระบุ path ของ creates ให้กับงานนั้น โหมด check จะสามารถประเมินผลการทดสอบไฟล์ได้:

- name: Extract the release bundle
  ansible.builtin.command: /usr/bin/tar xf /tmp/app.tar.gz -C /opt/app
  args:
    creates: /opt/app/bin/app

หาก /opt/app/bin/app มีอยู่แล้ว โหมด check จะรายงานผลเป็น Would not run command since '/opt/app/bin/app' exists ซึ่งถือเป็นคำตอบที่ถูกต้องตามจริง หากไม่มี path ดังกล่าว คุณจะได้รับผลเป็น Command would have run if not in check mode ซึ่งก็เป็นคำตอบที่ถูกต้องเช่นกัน หากปราศจาก creates งานนั้นจะเป็นเพียงช่องว่างในการรันแบบ dry run ของคุณ

ผลกระทบต่อเนื่องนั้นเลวร้ายยิ่งกว่าการเป็นเพียงช่องว่าง งานที่ถูกข้ามไปจะยังคงบันทึกผลลัพธ์ไว้ แต่เป็นผลลัพธ์ประเภท skip และไม่มี key stdout ส่งผลให้เงื่อนไขของงานถัดไปล้มเหลวในขณะที่กำลังถูกประเมิน โดยจะแสดงข้อผิดพลาดในทำนอง 'dict object' has no attribute 'stdout' ส่งผลให้ playbook ของคุณทำงานได้ปกติในการรันจริง แต่กลับล้มเหลวในการรันแบบ dry run ซึ่งถือเป็นความผิดพลาดที่สร้างความสับสนมากที่สุดในฟีเจอร์นี้

check_mode: false และตำแหน่งที่ควรใช้งาน

check_mode: false ใน task หมายถึง "ให้รันคำสั่งนี้จริง แม้จะอยู่ในโหมด --check" นี่คือวิธีแก้ไขปัญหาคำสั่งถูกข้าม และปลอดภัยเฉพาะกับ task ที่ทำหน้าที่อ่านข้อมูลเท่านั้น

- name: Read the installed app version
  ansible.builtin.command: /usr/local/bin/app --version
  register: app_version
  check_mode: false
  changed_when: false

task ดังกล่าวมีความตรงไปตรงมาในทั้งสองโหมด มันทำหน้าที่อ่านเวอร์ชันและไม่มีการเขียนข้อมูลใดๆ changed_when: false ช่วยป้องกันไม่ให้ระบบรายงานการเปลี่ยนแปลงที่ไม่ได้เกิดขึ้นจริง และ check_mode: false ทำให้ app_version.stdout มีตัวตนอยู่ระหว่างการรันแบบ dry run เพื่อให้เงื่อนไขที่อ้างอิงถึงค่านี้ยังคงประมวลผลได้ตามปกติ

โปรดทำความเข้าใจความหมายของ keyword นี้ให้ดีก่อนนำไปใช้ที่อื่น task ที่มี check_mode: false จะทำการเขียนข้อมูลลงบนเซิร์ฟเวอร์ของคุณระหว่างการรัน ansible-playbook --check หากคุณนำไปใส่ไว้ใน task ประเภท apt หรือ template เพื่อให้ผลลัพธ์ของ dry run ดูสะอาดตาขึ้น การรันนั้นจะไม่ใช่ dry run อีกต่อไป หาก task ที่มีการเขียนข้อมูลไม่สามารถทำให้ปลอดภัยได้ ให้ใช้การป้องกันแทน:

- name: Apply the database migration
  ansible.builtin.command: /usr/local/bin/app migrate --apply
  when: not ansible_check_mode

ansible_check_mode เป็นตัวแปรพิเศษที่ Ansible จะกำหนดค่าให้เป็น true ระหว่างการรันในโหมดตรวจสอบ นอกจากนี้ยังมี keyword ในทางกลับกันด้วย check_mode: true จะบังคับให้ task ทำงานในโหมดตรวจสอบเสมอ แม้จะเป็นการรันจริง ซึ่งจะเปลี่ยนให้มันกลายเป็นเครื่องมือตรวจจับความคลาดเคลื่อน (drift probe): ให้บันทึกผลลัพธ์ไว้ และหากมีรายงาน changed แสดงว่าโฮสต์นั้นไม่ตรงกับสถานะที่ task กำหนดไว้อีกต่อไป

เหตุใดงานจึงรายงานว่ามีการเปลี่ยนแปลงทุกครั้งที่รัน

ให้รัน playbook สองครั้งติดต่อกันโดยไม่มีการแทรกแซงใดๆ งานทุกงานควรรายงาน ok ในการรันครั้งที่สอง หากงานใดยังคงรายงาน changed แสดงว่าคุณกำลังเจอปัญหาอย่างใดอย่างหนึ่งในสองประการนี้: โมดูลไม่สามารถตรวจสอบสถานะที่มันดูแลอยู่ได้ หรือข้อมูลขาเข้าที่คุณป้อนให้ไม่คงที่ ทั้งสองกรณีสามารถแก้ไขได้และไม่ใช่สัญญาณรบกวนที่ควรเพิกเฉย

  • command และ shell ที่ไม่มี creates, removes หรือ changed_when จะรายงาน changed ทุกครั้ง เพราะโมดูลไม่มีทางทราบได้ว่าเกิดการเปลี่ยนแปลงขึ้นหรือไม่ ให้เพิ่ม creates หรือตั้งค่า changed_when เทียบกับสตริงในผลลัพธ์
  • ansible.builtin.file ที่ใช้ state: touch จะรายงาน changed ทุกครั้งตามการออกแบบ เพราะการใช้คำสั่ง touch จะอัปเดต timestamp ของไฟล์เสมอ ให้ใช้ state: file หากสิ่งที่คุณต้องการทำมีเพียงการกำหนดเจ้าของไฟล์หรือสิทธิ์การเข้าถึง (mode) เท่านั้น
  • template ที่มีผลลัพธ์จากการ render เปลี่ยนแปลงไปเรื่อยๆ จะเขียนไฟล์ใหม่ทุกครั้งที่รัน เช่น timestamp จาก ansible_date_time, การเรียกใช้ now() หรือรหัสผ่านที่ถูกสร้างขึ้นใหม่ทุกครั้ง ล้วนทำให้เกิดข้อมูลที่แตกต่างกัน โมดูลจึงรายงานการเปลี่ยนแปลงอย่างถูกต้อง ให้เอาค่าที่เปลี่ยนแปลงเหล่านั้นออกจาก template
  • ansible.builtin.user ที่ใช้ password: "{{ pw | password_hash('sha512') }}" จะเปลี่ยนทุกครั้ง เพราะ password_hash จะสุ่มค่า salt ใหม่ทุกครั้งที่ถูกเรียก ทำให้ hash ที่ได้ไม่ตรงกับค่าที่อยู่ใน /etc/shadow ให้ส่งค่า salt ที่คงที่ซึ่งได้มาจากแหล่งข้อมูลที่แน่นอนแทน
  • state: latest ในโมดูลจัดการแพ็กเกจจะรายงาน changed เสมอเมื่อมีการอัปเดตเวอร์ชันใหม่ ซึ่งเป็นการรายงานที่ถูกต้อง และเป็นเหตุผลว่าทำไม state: latest จึงทำให้ผลลัพธ์ของ playbook คาดเดาไม่ได้ ให้ใช้ state: present และเลือกอัปเดตอย่างตั้งใจ
  • ansible.builtin.unarchive ที่ชี้ไปยัง URL โดยไม่มี creates จะทำการดึงข้อมูลและแตกไฟล์ใหม่ทุกครั้ง ให้ระบุ creates เป็น path ในเครื่องแทน

--diff เป็นวิธีที่เร็วที่สุดในการแยกแยะปัญหาเหล่านี้ หากงานแจ้งว่า changed และ diff แสดงให้เห็นว่าข้อมูลมีความแตกต่างกัน แสดงว่าข้อมูลขาเข้าของคุณไม่คงที่ หากแจ้งว่า changed แต่ diff ไม่แสดงอะไรเลย แสดงว่าโมดูลไม่สามารถระบุได้ว่ามีการเปลี่ยนแปลงอะไร ซึ่งมักหมายถึงงานประเภท command หรือการเขียนข้อมูล metadata เท่านั้น เช่น timestamp

อย่าใช้ changed_when: false เพื่อปิดเสียงงานที่แจ้งเตือนบ่อยเกินไป เพราะมันจะระงับการรายงาน ทำให้ notify ไม่ทำงาน และ handler ที่คอย restart บริการจะไม่ถูกเรียกใช้งาน ให้แก้ไขที่ตัวงานแทน

ลดขอบเขตความเสียหาย: --limit, --tags และ --step

Check mode จะแสดงให้คุณทราบว่าจะมีการเปลี่ยนแปลงใดเกิดขึ้นบ้าง ส่วน flag เหล่านี้จะกำหนดจำนวนเครื่องที่จะได้รับผลกระทบในคราวเดียว

--limit จะจำกัดการทำงานของ play ให้เหลือเพียงกลุ่มย่อยของ inventory โดยรองรับรูปแบบเดียวกับ hosts: ดังนั้นทั้ง --limit web1 และ --limit 'webservers:!web3' จึงใช้งานได้ ให้ใส่เครื่องหมายคำพูดครอบรูปแบบที่ต้องการ หากคุณใช้ ! โดยไม่ใส่เครื่องหมายคำพูดใน bash session แบบโต้ตอบ จะทำให้เกิด การขยายประวัติคำสั่งจากเครื่องหมายอัศเจรีย์ และ shell จะเขียนคำสั่งใหม่ก่อนที่ Ansible จะได้รับคำสั่งนั้น

ตรวจสอบรูปแบบให้แน่ใจก่อนใช้งานจริง ansible-playbook site.yml --limit 'webservers:!web3' --list-hosts จะแสดงรายการ host ที่ตรงกับเงื่อนไขและจบการทำงานโดยไม่เชื่อมต่อไปยังเครื่องใดๆ รูปแบบที่ไม่ตรงกับ host ใดเลยถือว่าปลอดภัย เพราะ Ansible จะไม่ย้อนกลับไปทำงานกับ host ทั้งหมดใน inventory แต่จะแสดงคำเตือนว่าไม่สามารถจับคู่กับรูปแบบ host ได้ จากนั้นจะจบการทำงานพร้อมข้อความแจ้งเตือนว่า host และ --limit ไม่ตรงกับ host ใดๆ การเข้าใจ วิธีการกำหนดกลุ่มในไฟล์ inventory คือหัวใจสำคัญที่ทำให้รูปแบบการเลือก host มีความคาดเดาได้

--tags deploy จะรันเฉพาะ task ที่มี tag ที่กำหนด ส่วน --skip-tags packages จะรัน task อื่นๆ ทั้งหมดที่เหลือ --list-tags จะแสดงรายการ tag ที่มีอยู่ทั้งหมด การใช้ tag จะคุ้มค่าเมื่อ playbook มีขนาดใหญ่เกินกว่าที่คุณต้องการรันทั้งหมด ซึ่งเป็นเหตุผลหนึ่งที่ควร แยก playbook ขนาดใหญ่เป็น role

--start-at-task "Write the site config" ใช้เพื่อรันต่อจาก task ที่ระบุหลังจากเกิดความล้มเหลว ให้ใช้เพื่อกู้คืนสถานะและทำความเข้าใจผลกระทบที่ตามมา: ทุก task ก่อนหน้านั้นจะถูกข้ามไป รวมถึง task ที่ทำหน้าที่กำหนด facts หรือลงทะเบียนตัวแปรที่ task ในลำดับถัดไปต้องใช้งาน

--step จะแสดงข้อความถามก่อนเริ่มแต่ละ task และรอให้คุณตอบตกลง (yes), ปฏิเสธ (no) หรือดำเนินการต่อ (continue) แม้วิธีนี้จะช้า แต่เป็นเครื่องมือที่เหมาะสมที่สุดสำหรับการรันคำสั่งที่มีความเสี่ยงสูงเป็นครั้งแรก เพราะคุณสามารถหยุดพักระหว่าง task ได้ แทนที่จะต้องรอให้จบหลังจากรันไปแล้วยี่สิบ task

การปรับใช้การเปลี่ยนแปลงแบบอนุกรมด้วย serial

โดยปกติแล้ว Ansible จะรันหนึ่ง task กับทุกโฮสต์ใน play ก่อนที่จะเริ่ม task ถัดไป ซึ่งเป็นวิธีที่รวดเร็ว แต่หมายความว่าหากมี task ที่ผิดพลาด มันจะส่งผลกระทบต่อโฮสต์ทั้งหมดในเวลาเดียวกัน กว่าที่คุณจะอ่านข้อผิดพลาดและกด Ctrl-C การเปลี่ยนแปลงนั้นก็ได้กระจายไปทั่วแล้ว

serial จะแบ่งการทำงานของ play ออกเป็นกลุ่มย่อย โดยจะรัน play ทั้งหมดกับกลุ่มแรกให้เสร็จสิ้นก่อน แล้วจึงเริ่มกลุ่มถัดไป

- name: Roll out the web tier
  hosts: webservers
  serial: [1, 5, "30%"]
  max_fail_percentage: 0
  tasks:
    - name: Deploy the release
      ansible.builtin.include_role:
        name: webapp

กลุ่มแรกจะมีโฮสต์เพียงหนึ่งเครื่อง หากผ่านไปได้ด้วยดี กลุ่มที่สองจะมีโฮสต์ห้าเครื่อง และกลุ่มหลังจากนั้นจะเป็น 30 เปอร์เซ็นต์ของจำนวนโฮสต์ทั้งหมดใน play นั้น max_fail_percentage: 0 จะยุติการทำงานของ play ทันทีที่มีโฮสต์ใดโฮสต์หนึ่งในกลุ่มล้มเหลว ดังนั้นหากการ release มีปัญหา มันจะหยุดลงที่เครื่องแรกเท่านั้น ส่วน any_errors_fatal: true เป็นวิธีที่รุนแรงกว่า โดยจะยุติการทำงานของ play สำหรับทุกคนทันทีที่โฮสต์แรกเกิดความล้มเหลว

การรันกับโฮสต์หนึ่งเครื่องก่อนไม่ใช่ความหวาดระแวงเกินเหตุ แต่มีเหตุผลเฉพาะเจาะจงอยู่ กลุ่มของ inventory มักจะเกิดการเปลี่ยนแปลงที่ไม่สอดคล้องกัน (drift) เซิร์ฟเวอร์ที่ถูกเพิ่มเข้ามาหลังจากเครื่องอื่นหกเดือนอาจใช้ distribution release ที่ต่างออกไป หรือมีบริการที่ใครบางคนติดตั้งไว้ด้วยตนเอง หรือมีการจัดวางดิสก์ที่แตกต่างกัน playbook อาจถูกต้องสำหรับกลุ่มโดยรวมแต่กลับผิดพลาดสำหรับโฮสต์เครื่องนั้น และการรันแบบ dry run กับโฮสต์ที่ตั้งค่าสมบูรณ์แล้วจะไม่แสดงปัญหานี้ให้เห็น การจัดการกลุ่มเซิร์ฟเวอร์ Linux ส่วนใหญ่จึงเป็นเรื่องของการค้นหาโฮสต์ที่ผิดปกติก่อนที่การเปลี่ยนแปลงจะส่งผลกระทบจริง

ลำดับการดำเนินการ

  1. ansible-playbook site.yml --syntax-check ใช้ตรวจสอบความผิดพลาดของรูปแบบ YAML และโครงสร้างโดยไม่ต้องเชื่อมต่อเครือข่าย
  2. ansible-playbook site.yml --limit web1 --list-hosts ใช้ยืนยันว่ารูปแบบของคุณตรงกับสิ่งที่คุณคาดหวัง
  3. ansible-playbook site.yml --limit web1 --check --diff คือการทดสอบรันจริง (dry run) ให้ตรวจสอบผลลัพธ์ diff ที่แสดงออกมา
  4. ansible-playbook site.yml --limit web1 --diff คือการนำไปใช้กับโฮสต์เป้าหมายนั้นเพียงเครื่องเดียว
  5. รันขั้นตอนที่ 4 ซ้ำอีกครั้ง ทุกอย่างควรรายงานผลเป็น ok หากยังมีส่วนใดที่แสดงสถานะ changed นั่นคือภารกิจที่คุณต้องแก้ไขก่อนที่จะนำไปใช้กับโฮสต์ส่วนที่เหลือในระบบ
  6. ansible-playbook site.yml --check --diff ทั่วทั้ง inventory จะให้ผลลัพธ์ที่มีความหมายในตอนนี้ เนื่องจากโฮสต์ที่คอนเวอร์จแล้วจะไม่มีการเปลี่ยนแปลง และสิ่งที่เหลืออยู่คือส่วนต่างที่แท้จริง

คำเตือนสำหรับขั้นตอนที่ 3: --diff จะพิมพ์เนื้อหาไฟล์ลงในเทอร์มินัลและบันทึกของ CI job ดังนั้นเทมเพลตที่เรนเดอร์รหัสผ่านฐานข้อมูลจะแสดงรหัสผ่านนั้นลงในบันทึกด้วย ให้ตั้งค่า diff: false ในภารกิจนั้นเพื่อระงับการแสดงผล หรือใช้ no_log: true เพื่อซ่อนผลลัพธ์ทั้งหมด และเก็บค่าดังกล่าวไว้ใน ไฟล์ Ansible Vault ที่เข้ารหัส แทนการเก็บไว้ใน repository โดยตรง

FAQ

การใช้ ansible-playbook --check จะทำให้เกิดการเปลี่ยนแปลงใดๆ บนเซิร์ฟเวอร์หรือไม่?

ไม่เกิดการเปลี่ยนแปลง ยกเว้นกรณีที่คุณกำหนดไว้เป็นพิเศษ ในโหมดตรวจสอบ (check mode) โมดูลทุกตัวจะถูกสั่งให้รายงานผลแทนการเขียนข้อมูลลงจริง และโมดูลที่ไม่สามารถทำเช่นนั้นได้จะไม่รายงานผลและไม่ดำเนินการใดๆ ข้อยกเว้นคือคีย์เวิร์ดของงาน (task keyword) ที่ชื่อ check_mode: false ซึ่งจะบังคับให้งานนั้นทำงานจริงแม้จะอยู่ในระหว่างการรัน --check ก็ตาม ให้ค้นหาคำว่า check_mode: false ใน playbook และ role ของคุณก่อนที่จะเชื่อถือผลการรันจำลอง และตรวจสอบให้แน่ใจว่าทุกรายการที่พบเป็นงานที่ทำหน้าที่อ่านสถานะของระบบเท่านั้น

--check และ --diff แตกต่างกันอย่างไร?

--check เป็นตัวกำหนดว่าจะมีการรันงานจริงหรือไม่ ส่วน --diff เป็นตัวกำหนดระดับรายละเอียดที่คุณจะได้รับ --check เพียงอย่างเดียวจะแจ้งให้คุณทราบว่าไฟล์จะมีการเปลี่ยนแปลงเกิดขึ้น --diff เพียงอย่างเดียวจะดำเนินการเปลี่ยนแปลงและแสดงบรรทัดที่ถูกแก้ไขให้คุณเห็น ควรใช้ทั้งสองอย่างร่วมกันเพื่อให้ได้ผลการรันจำลองที่คุณสามารถอ่านทำความเข้าใจได้ และควรเปิด --diff ไว้เสมอสำหรับการรันงานจริงโดยตั้งค่า always = true ไว้ภายใต้ [diff] ในไฟล์ ansible.cfg

ทำไมงาน Ansible ของฉันถึงรายงานว่า changed ในทุกครั้งที่รัน?

เพราะโมดูลไม่สามารถตรวจสอบสถานะที่มันดูแลอยู่ได้ หรือค่าที่คุณส่งให้มันนั้นแตกต่างกันในทุกครั้งที่รัน command และ shell จะรายงานสถานะ changed เสมอเว้นแต่คุณจะเพิ่ม creates หรือ changed_when เข้าไป ส่วน file ที่ใช้ร่วมกับ state: touch จะมีการเปลี่ยนแปลงตามการออกแบบอยู่แล้ว สำหรับ template ที่สร้าง timestamp หรือรหัสผ่านที่สุ่มขึ้นมาใหม่จะทำให้ข้อมูลในไฟล์เปลี่ยนไปในทุกครั้งที่รัน ส่งผลให้ไฟล์ถูกเขียนทับจริง ให้ลองรัน playbook สองครั้งติดต่อกัน งานใดที่ยังคงแสดงสถานะ changed ในการรันครั้งที่สองคืองานที่คุณต้องแก้ไข

ทำไมงานประเภท command และ shell ถึงถูกข้ามไปในระหว่างการรันจำลอง?

เพราะไม่มีวิธีใดที่จะรันคำสั่งตามอำเภอใจในรูปแบบอ่านอย่างเดียวได้ ในโหมดตรวจสอบ โมดูล command จะตั้งค่า skipped: true พร้อมข้อความ Command would have run if not in check mode ให้เพิ่ม creates หรือ removes เพื่อให้โหมดตรวจสอบสามารถประเมินการทดสอบไฟล์แทนได้ สำหรับงานที่ทำหน้าที่อ่านสถานะเท่านั้น ให้ตั้งค่า check_mode: false ร่วมกับ changed_when: false เพื่อให้ผลลัพธ์ที่ลงทะเบียนไว้ยังคงอยู่ระหว่างการรันจำลอง และเงื่อนไขที่สร้างขึ้นจากผลลัพธ์นั้นจะยังคงทำงานได้ตามปกติ

ทำไมโหมดตรวจสอบถึงล้มเหลวบนเซิร์ฟเวอร์ใหม่ แต่ผ่านบนเซิร์ฟเวอร์ที่มีอยู่เดิม?

เพราะโหมดตรวจสอบไม่ได้สร้างสถานะที่งานลำดับถัดไปต้องใช้ การรันจำลองบนโฮสต์ที่ยังไม่ได้ติดตั้ง nginx จะรายงานการติดตั้งเป็น changed จากนั้นจะล้มเหลวในงานที่ต้องเขียนข้อมูลลงใน /etc/nginx/conf.d/ เนื่องจากไดเรกทอรีดังกล่าวไม่เคยถูกสร้างขึ้น นี่เป็นพฤติกรรมปกติ โหมดตรวจสอบมีไว้เพื่อตรวจหาความคลาดเคลื่อน (drift) ของโฮสต์ที่ playbook ได้ปรับแต่งจนเข้าที่แล้วเท่านั้น ไม่สามารถใช้ตรวจสอบการรันครั้งแรกได้ สำหรับโฮสต์ใหม่ ให้รัน playbook บนเครื่องหนึ่งเครื่องแล้วอ่านผลลัพธ์จากการรันครั้งที่สองแทน

#ansible#check-mode#idempotency#automation#safety