พื้นฐานที่เข้าใจได้ ถ้าไม่มี Playbooks ของคุณก็จะกลายเป็นพาสต้าเหนียวๆ ก้อนหนึ่ง

ฉันวิจารณ์โค้ด Ansible ของคนอื่นมากมายและเขียนเองก็เยอะมาก ในระหว่างการวิเคราะห์ข้อผิดพลาด (ทั้งของผู้อื่นและของฉันเอง) รวมถึงการสัมภาษณ์หลายครั้ง ฉันตระหนักถึงข้อผิดพลาดหลักที่ผู้ใช้ Ansible ทำ - พวกเขาเข้าสู่สิ่งที่ซับซ้อนโดยไม่ต้องเชี่ยวชาญสิ่งพื้นฐาน

เพื่อแก้ไขความอยุติธรรมที่เป็นสากลนี้ ฉันจึงตัดสินใจเขียนบทแนะนำเกี่ยวกับ Ansible สำหรับผู้ที่รู้อยู่แล้ว ฉันขอเตือนคุณว่า นี่ไม่ใช่การเล่าเรื่องของผู้ชาย แต่เป็นนิยายเรื่องยาวที่มีตัวอักษรจำนวนมากและไม่มีรูปภาพ

ระดับที่ผู้อ่านคาดหวังคือมีการเขียน yamla หลายพันบรรทัดแล้ว มีบางอย่างอยู่ในการผลิตแล้ว แต่ "ทุกอย่างคดโกง"

ชื่อ

ข้อผิดพลาดหลักที่ผู้ใช้ Ansible ทำคือการไม่รู้ว่าบางสิ่งเรียกว่าอะไร หากคุณไม่ทราบชื่อ คุณจะไม่เข้าใจสิ่งที่เอกสารระบุไว้ ตัวอย่างที่มีชีวิต: ในระหว่างการสัมภาษณ์ คนที่ดูเหมือนจะบอกว่าเขาเขียนอะไรมากมายใน Ansible ไม่สามารถตอบคำถามที่ว่า "Playbook ประกอบด้วยองค์ประกอบใดบ้าง" และเมื่อฉันแนะนำว่า "คำตอบที่คาดหวังได้ว่า playbook ประกอบด้วยการเล่น" ก็มีความคิดเห็นที่น่าสยดสยองว่า "เราไม่ใช้สิ่งนั้น" ตามมา ผู้คนเขียน Ansible เพื่อเงินและไม่ใช้การเล่น จริงๆ แล้วใช้แต่ไม่รู้ว่ามันคืออะไร

เรามาเริ่มกันด้วยสิ่งง่ายๆ: มันเรียกว่าอะไร บางทีคุณอาจรู้เรื่องนี้ หรืออาจจะไม่รู้ เนื่องจากคุณไม่ได้ใส่ใจเมื่อคุณอ่านเอกสาร

ansible-playbook รัน playbook Playbook คือไฟล์ที่มีนามสกุล yml/yaml ซึ่งภายในจะมีหน้าตาดังนี้:

---
- hosts: group1
  roles:
    - role1

- hosts: group2,group3
  tasks:
    - debug:

เรารู้แล้วว่าไฟล์ทั้งหมดนี้คือ playbook เราสามารถแสดงได้ว่าบทบาทอยู่ที่ไหนและงานอยู่ที่ไหน แต่เล่นที่ไหนล่ะ? และความแตกต่างระหว่างการเล่นและบทบาทหรือ playbook คืออะไร?

ทั้งหมดอยู่ในเอกสาร. และพวกเขาก็คิดถึงมัน ผู้เริ่มต้น - เนื่องจากมีมากเกินไปและคุณจะจำทุกอย่างไม่ได้ในคราวเดียว มีประสบการณ์ - เพราะ "สิ่งเล็กน้อย" หากคุณมีประสบการณ์แล้ว ให้อ่านหน้าเหล่านี้ซ้ำอย่างน้อยหนึ่งครั้งทุกๆ หกเดือน และโค้ดของคุณจะกลายเป็นระดับชั้นนำ

ดังนั้น โปรดจำไว้ว่า Playbook คือรายการที่ประกอบด้วยการเล่นและ import_playbook.
นี่คือละครเรื่องหนึ่ง:

- hosts: group1
  roles:
    - role1

และนี่ก็เป็นละครอีกเรื่องหนึ่ง:

- hosts: group2,group3
  tasks:
    - debug:

การเล่นคืออะไร? ทำไมเธอถึงเป็น?

การเล่นเป็นองค์ประกอบสำคัญสำหรับ Playbook เนื่องจากการเล่นและการเล่นเท่านั้นเชื่อมโยงรายการบทบาทและ/หรืองานเข้ากับรายชื่อโฮสต์ที่ต้องดำเนินการ ในส่วนลึกของเอกสาร คุณสามารถดูการกล่าวถึงได้ delegate_to, ปลั๊กอินการค้นหาในเครื่อง, การตั้งค่าเฉพาะเครือข่าย, โฮสต์ข้าม ฯลฯ ช่วยให้คุณสามารถเปลี่ยนสถานที่ปฏิบัติงานได้เล็กน้อย แต่ลืมเรื่องนี้ซะ ตัวเลือกอันชาญฉลาดเหล่านี้แต่ละตัวเลือกมีการใช้งานเฉพาะเจาะจง และไม่ใช่แบบสากลอย่างแน่นอน และเรากำลังพูดถึงเรื่องพื้นฐานที่ทุกคนควรรู้และนำไปใช้

หากคุณต้องการแสดง "บางสิ่งบางอย่าง" "ที่ไหนสักแห่ง" คุณเขียนบทละคร ไม่ใช่บทบาท. ไม่ใช่บทบาทกับโมดูลและผู้ได้รับมอบหมาย คุณรับมันและเขียนเล่น โดยในฟิลด์โฮสต์ คุณจะแสดงรายการตำแหน่งที่จะดำเนินการ และในบทบาท/งาน - สิ่งที่จะดำเนินการ

ง่ายใช่มั้ย? มันจะเป็นอย่างอื่นได้อย่างไร?

ช่วงเวลาที่มีลักษณะเฉพาะอย่างหนึ่งที่ผู้คนปรารถนาที่จะทำสิ่งนี้โดยไม่ผ่านการเล่นคือ "บทบาทที่กำหนดทุกสิ่งทุกอย่าง" ฉันต้องการมีบทบาทที่กำหนดค่าทั้งเซิร์ฟเวอร์ประเภทแรกและเซิร์ฟเวอร์ประเภทที่สอง

ตัวอย่างตามแบบฉบับคือการเฝ้าติดตาม ฉันต้องการมีบทบาทการตรวจสอบที่จะกำหนดค่าการตรวจสอบ บทบาทการตรวจสอบถูกกำหนดให้กับโฮสต์การตรวจสอบ (ตามการเล่น) แต่ปรากฎว่าในการตรวจสอบเราจำเป็นต้องส่งแพ็คเกจไปยังโฮสต์ที่เรากำลังตรวจสอบอยู่ ทำไมไม่ใช้ผู้รับมอบสิทธิ์? คุณต้องกำหนดค่า iptables ด้วย ผู้รับมอบสิทธิ์? คุณต้องเขียน/แก้ไขการกำหนดค่าสำหรับ DBMS เพื่อเปิดใช้งานการตรวจสอบ มอบหมาย! และหากขาดความคิดสร้างสรรค์ คุณก็สามารถมอบหมายงานได้ include_role ในวงซ้อนโดยใช้ตัวกรองที่ซับซ้อนในรายการกลุ่มและภายใน include_role คุณสามารถทำได้มากกว่านี้ delegate_to อีกครั้ง. แล้วเราก็ไป...

ความปรารถนาดี - มีบทบาทในการติดตามเพียงบทบาทเดียวซึ่ง "ทำทุกอย่าง" - นำเราไปสู่นรกที่สมบูรณ์ซึ่งส่วนใหญ่มักจะมีทางออกทางเดียวเท่านั้น: เขียนทุกอย่างใหม่ตั้งแต่เริ่มต้น

ความผิดพลาดเกิดขึ้นที่นี่ที่ไหน? ทันทีที่คุณค้นพบว่าในการทำงาน "x" บนโฮสต์ X คุณต้องไปที่โฮสต์ Y และทำ "y" ที่นั่น คุณต้องทำแบบฝึกหัดง่ายๆ: ไปและเขียนเล่น ซึ่งบนโฮสต์ Y ทำ y อย่าเพิ่มอะไรเข้าไปใน "x" แต่ให้เขียนตั้งแต่ต้น แม้จะมีตัวแปรฮาร์ดโค้ดก็ตาม

ดูเหมือนว่าทุกอย่างในย่อหน้าข้างต้นพูดถูกต้อง แต่นี่ไม่ใช่กรณีของคุณ! เพราะคุณต้องการเขียนโค้ดแบบใช้ซ้ำได้ซึ่งเป็นแบบ DRY และมีลักษณะคล้ายไลบรารี่ และคุณจำเป็นต้องค้นหาวิธีดำเนินการด้วย

นี่คือจุดที่ข้อผิดพลาดร้ายแรงอีกอย่างหนึ่งแฝงตัวอยู่ ข้อผิดพลาดที่ทำให้หลายโครงการจากการเขียนที่พอทนได้ (อาจจะดีกว่านี้ แต่ทุกอย่างได้ผลและจบง่าย) กลายเป็นเรื่องสยองขวัญที่แม้แต่ผู้เขียนก็ยังไม่เข้าใจ มันใช้งานได้ แต่พระเจ้าห้ามไม่ให้คุณเปลี่ยนแปลงสิ่งใด

ข้อผิดพลาดคือ: Role คือฟังก์ชันไลบรารี การเปรียบเทียบนี้ได้ทำลายจุดเริ่มต้นที่ดีมากมายจนน่าเศร้าที่ต้องดู บทบาทนี้ไม่ใช่ฟังก์ชันไลบรารี เธอคำนวณไม่ได้และเธอก็ไม่สามารถตัดสินใจในระดับการเล่นได้ เตือนฉันว่าการตัดสินใจเล่นทำให้อะไร?

ขอบคุณ คุณพูดถูก Play เป็นผู้ตัดสินใจ (โดยเจาะจงมากขึ้นคือประกอบด้วยข้อมูล) เกี่ยวกับงานและบทบาทที่จะดำเนินการกับโฮสต์ใด

หากคุณมอบหมายการตัดสินใจนี้ให้กับบทบาท และถึงแม้จะมีการคำนวณ คุณจะโทษตัวเอง (และผู้ที่พยายามแยกวิเคราะห์โค้ดของคุณ) ไปสู่การดำรงอยู่อย่างน่าสังเวช บทบาทไม่ได้ตัดสินใจว่าจะดำเนินการที่ไหน การตัดสินใจครั้งนี้เกิดขึ้นจากการเล่น บทบาททำในสิ่งที่ได้รับการบอกกล่าวและได้รับการบอกกล่าว

เหตุใดการเขียนโปรแกรมใน Ansible จึงเป็นอันตราย และเหตุใด COBOL จึงดีกว่า Ansible เราจะพูดคุยในบทเกี่ยวกับตัวแปรและจินจา สำหรับตอนนี้ สมมติว่าสิ่งหนึ่ง - การคำนวณแต่ละครั้งของคุณทิ้งร่องรอยการเปลี่ยนแปลงในตัวแปรร่วมไว้เบื้องหลัง และคุณไม่สามารถทำอะไรกับมันได้ ทันทีที่ "ร่องรอย" ทั้งสองตัดกัน ทุกอย่างก็หายไป

หมายเหตุสำหรับผู้ที่คลื่นไส้: บทบาทนี้สามารถมีอิทธิพลต่อโฟลว์การควบคุมได้อย่างแน่นอน กิน delegate_to และก็มีประโยชน์พอสมควร กิน meta: end host/play. แต่! จำได้ไหมว่าเราสอนพื้นฐาน? ลืมเกี่ยวกับ delegate_to. เรากำลังพูดถึงโค้ด Ansible ที่เรียบง่ายและสวยงามที่สุด ซึ่งอ่านง่าย เขียนง่าย แก้จุดบกพร่องง่าย ทดสอบง่าย และจบง่าย ดังนั้นอีกครั้ง:

เล่นและเล่นเท่านั้นที่จะตัดสินใจว่าโฮสต์ใดที่จะดำเนินการ

ในส่วนนี้ เราจะจัดการกับความขัดแย้งระหว่างการเล่นและบทบาท ตอนนี้เรามาพูดถึงความสัมพันธ์ระหว่างงานกับบทบาทกันดีกว่า

งานและบทบาท

พิจารณาเล่น:

- hosts: somegroup
  pre_tasks:
    - some_tasks1:
  roles:
     - role1
     - role2
  post_tasks:
     - some_task2:
     - some_task3:

สมมติว่าคุณต้องทำ foo และดูเหมือนว่า foo: name=foobar state=present. ฉันควรเขียนสิ่งนี้ที่ไหน? ก่อน? โพสต์? สร้างบทบาท?

...แล้วงานไปไหนล่ะ?

เรากำลังเริ่มต้นจากพื้นฐานอีกครั้ง - อุปกรณ์การเล่น หากคุณลอยนวลในประเด็นนี้ คุณจะไม่สามารถใช้การเล่นเป็นพื้นฐานสำหรับทุกสิ่งทุกอย่างได้ และผลลัพธ์ของคุณจะ "สั่นคลอน"

อุปกรณ์การเล่น: คำสั่งโฮสต์ การตั้งค่าสำหรับการเล่นและงานล่วงหน้า งาน บทบาท ส่วน post_tasks ค่าพารามิเตอร์ที่เหลือในการเล่นไม่สำคัญสำหรับเราในตอนนี้

ลำดับของส่วนงานและบทบาท: pre_tasks, roles, tasks, post_tasks. เนื่องจากลำดับการดำเนินการทางความหมายอยู่ระหว่าง tasks и roles ไม่ชัดเจน ดังนั้นแนวทางปฏิบัติที่ดีที่สุดบอกว่าเรากำลังเพิ่มหัวข้อ tasksเฉพาะในกรณีที่ไม่ roles... ถ้ามี rolesจากนั้นงานที่แนบมาทั้งหมดจะถูกวางไว้ในส่วนต่างๆ pre_tasks/post_tasks.

สิ่งที่เหลืออยู่ก็คือทุกอย่างชัดเจนทางความหมาย: อันดับแรก pre_tasksแล้ว rolesแล้ว post_tasks.

แต่เรายังไม่ได้ตอบคำถาม: การเรียกโมดูลอยู่ที่ไหน? foo เขียน? เราจำเป็นต้องเขียนบทบาททั้งหมดสำหรับแต่ละโมดูลหรือไม่? หรือจะดีกว่าถ้ามีบทบาทหนาในทุกสิ่ง? แล้วถ้าไม่ใช่บทบาทจะเขียนตรงไหนก่อนหรือหลัง?

หากไม่มีคำตอบที่สมเหตุสมผลสำหรับคำถามเหล่านี้ แสดงว่าเป็นสัญญาณของการขาดสัญชาตญาณ นั่นคือ "รากฐานที่สั่นคลอน" แบบเดียวกัน ลองคิดดูสิ ขั้นแรก คำถามเพื่อความปลอดภัย: ถ้ามีการเล่น pre_tasks и post_tasks (และไม่มีงานหรือบทบาท) จากนั้นบางอย่างอาจพังได้หากฉันทำงานแรก post_tasks ฉันจะย้ายมันไปให้สุด pre_tasks?

แน่นอนว่าถ้อยคำของคำถามบ่งบอกเป็นนัยว่ามันจะพัง แต่อะไรกันแน่?

... ผู้ดำเนินการ การอ่านข้อมูลพื้นฐานเผยให้เห็นข้อเท็จจริงที่สำคัญ: ตัวจัดการทั้งหมดจะถูกล้างโดยอัตโนมัติหลังจากแต่ละส่วน เหล่านั้น. งานทั้งหมดจาก pre_tasksจากนั้นผู้ดำเนินการทั้งหมดที่ได้รับแจ้ง จากนั้นบทบาททั้งหมดและตัวจัดการทั้งหมดที่ได้รับแจ้งในบทบาทนั้นจะถูกดำเนินการ หลังจาก post_tasks และผู้ดูแลของพวกเขา

ดังนั้นหากคุณลากงานจาก post_tasks в pre_tasksจากนั้นคุณอาจดำเนินการก่อนที่ตัวจัดการจะถูกดำเนินการ เช่น ถ้าใน pre_tasks มีการติดตั้งและกำหนดค่าเว็บเซิร์ฟเวอร์แล้ว และ post_tasks มีบางอย่างถูกส่งไป จากนั้นจึงโอนงานนี้ไปยังส่วนนั้น pre_tasks จะนำไปสู่ความจริงที่ว่าในขณะที่ "ส่ง" เซิร์ฟเวอร์จะยังไม่ทำงานและทุกอย่างจะพัง

ทีนี้ลองคิดดูอีกครั้งว่าทำไมเราถึงต้องการ pre_tasks и post_tasks? ตัวอย่างเช่น เพื่อที่จะทำทุกอย่างที่จำเป็นให้เสร็จสิ้น (รวมถึงตัวจัดการ) ก่อนที่จะทำหน้าที่ให้สำเร็จ ก post_tasks จะช่วยให้เราสามารถทำงานกับผลลัพธ์ของการดำเนินการตามบทบาท (รวมถึงตัวจัดการ)

ผู้เชี่ยวชาญ Ansible ที่ชาญฉลาดจะบอกเราว่ามันคืออะไร meta: flush_handlersแต่ทำไมเราถึงต้องการflush_handlersถ้าเราสามารถพึ่งพาลำดับการดำเนินการของส่วนที่เล่นได้? นอกจากนี้ การใช้ meta:flush_handlers สามารถให้สิ่งที่ไม่คาดคิดแก่เราด้วยตัวจัดการที่ซ้ำกัน ทำให้เราได้รับคำเตือนแปลกๆ เมื่อใช้ when у block ฯลฯ ยิ่งคุณรู้จักคำตอบมากเท่าไร คุณก็จะยิ่งแยกแยะความแตกต่างสำหรับโซลูชันที่ "ยุ่งยาก" ได้มากขึ้นเท่านั้น และวิธีแก้ปัญหาง่ายๆ โดยใช้การแบ่งตามธรรมชาติระหว่างก่อน/บทบาท/หลัง - ไม่ทำให้เกิดความแตกต่าง

และกลับไปที่ 'foo' ของเรา ฉันควรวางไว้ที่ไหน? ก่อนหน้า โพสต์ หรือบทบาท? แน่นอนว่าสิ่งนี้ขึ้นอยู่กับว่าเราต้องการผลลัพธ์ของตัวจัดการ foo หรือไม่ หากไม่มีอยู่ ก็ไม่จำเป็นต้องวาง foo ไว้ข้างหน้าหรือหลัง ส่วนเหล่านี้มีความหมายพิเศษ นั่นคือการดำเนินการงานก่อนและหลังเนื้อหาหลักของโค้ด

ตอนนี้คำตอบสำหรับคำถาม "บทบาทหรืองาน" ขึ้นอยู่กับสิ่งที่กำลังเล่นอยู่ - หากมีงานอยู่ที่นั่นคุณต้องเพิ่มงานเหล่านั้นลงในงาน หากมีบทบาท คุณจะต้องสร้างบทบาท (แม้จะมาจากงานเดียวก็ตาม) ฉันขอเตือนคุณว่างานและบทบาทไม่ได้ถูกใช้ในเวลาเดียวกัน

การทำความเข้าใจพื้นฐานของ Ansible จะให้คำตอบที่สมเหตุสมผลสำหรับคำถามเกี่ยวกับรสนิยม

งานและบทบาท (ตอนที่ XNUMX)

ตอนนี้เรามาดูสถานการณ์เมื่อคุณเพิ่งเริ่มเขียน Playbook กัน คุณต้องทำฟู บาร์ และบาซ งานทั้งสามนี้เป็นหนึ่งบทบาทหรือสามบทบาท? เพื่อสรุปคำถาม: คุณควรเริ่มเขียนบทบาทเมื่อใด? การเขียนบทบาทมีประโยชน์อย่างไรในเมื่อคุณสามารถเขียนงานได้?... บทบาทคืออะไร?

หนึ่งในข้อผิดพลาดที่ใหญ่ที่สุด (ฉันได้พูดถึงเรื่องนี้แล้ว) คือการคิดว่าบทบาทก็เหมือนกับฟังก์ชันในไลบรารีของโปรแกรม คำอธิบายฟังก์ชันทั่วไปมีลักษณะอย่างไร ยอมรับอาร์กิวเมนต์อินพุต โต้ตอบกับสาเหตุด้านข้าง ทำผลข้างเคียง และส่งกลับค่า

ตอนนี้ให้ความสนใจ สิ่งที่สามารถทำได้จากบทบาทนี้? คุณสามารถเรียกผลข้างเคียงได้เสมอ นี่คือสาระสำคัญของ Ansible ทั้งหมด - เพื่อสร้างผลข้างเคียง มีสาเหตุข้างเคียงหรือไม่? ประถมศึกษา. แต่ด้วยการ "ส่งค่าแล้วส่งคืน" - นั่นคือสิ่งที่มันไม่ได้ผล ขั้นแรก คุณไม่สามารถส่งค่าให้กับบทบาทได้ คุณสามารถตั้งค่าตัวแปรร่วมด้วยขนาดการเล่นตลอดชีวิตได้ในส่วน vars สำหรับบทบาทนั้น คุณสามารถตั้งค่าตัวแปรส่วนกลางโดยมีบทบาทตลอดอายุการใช้งานได้ หรือแม้แต่กับอายุการใช้งานของ Playbooks (set_fact/register). แต่คุณไม่สามารถมี "ตัวแปรท้องถิ่น" ได้ คุณไม่สามารถ "รับค่า" และ "ส่งคืน" ได้

สิ่งสำคัญตามมาจากนี้: คุณไม่สามารถเขียนบางสิ่งใน Ansible ได้โดยไม่ก่อให้เกิดผลข้างเคียง การเปลี่ยนแปลงตัวแปรร่วมถือเป็นผลข้างเคียงของฟังก์ชันเสมอ ตัวอย่างเช่นใน Rust การเปลี่ยนตัวแปรโกลบอลคือ unsafe. และใน Ansible มันเป็นวิธีเดียวที่จะมีอิทธิพลต่อค่านิยมของบทบาท สังเกตคำที่ใช้: ไม่ใช่ "ส่งค่าให้กับบทบาท" แต่ "เปลี่ยนค่าที่บทบาทใช้" ไม่มีการแยกระหว่างบทบาท ไม่มีการแยกระหว่างงานและบทบาท

รวม: บทบาทไม่ใช่ฟังก์ชัน.

มีบทบาทอะไรดี? ขั้นแรก บทบาทมีค่าเริ่มต้น (/default/main.yaml) ประการที่สอง บทบาทมีไดเร็กทอรีเพิ่มเติมสำหรับจัดเก็บไฟล์

ประโยชน์ของค่าเริ่มต้นคืออะไร? เนื่องจากในพีระมิดของ Maslow ซึ่งเป็นตารางลำดับความสำคัญของตัวแปรที่ค่อนข้างบิดเบี้ยวของ Ansible ค่าเริ่มต้นของบทบาทจึงมีลำดับความสำคัญต่ำที่สุด (ลบด้วยพารามิเตอร์บรรทัดคำสั่ง Ansible) ซึ่งหมายความว่า หากคุณต้องการระบุค่าเริ่มต้นและไม่ต้องกังวลว่าค่าเหล่านั้นจะแทนที่ค่าจากตัวแปรสินค้าคงคลังหรือกลุ่ม ค่าเริ่มต้นของบทบาทจะเป็นที่ที่เหมาะสมสำหรับคุณเท่านั้น (ฉันโกหกนิดหน่อย - ยังมีอีกมาก |d(your_default_here)แต่ถ้าเราพูดถึงสถานที่นิ่ง ก็จะมีเฉพาะค่าเริ่มต้นของบทบาทเท่านั้น)

มีอะไรที่ยอดเยี่ยมเกี่ยวกับบทบาทนี้อีก? เนื่องจากมีแคตตาล็อกเป็นของตัวเอง เหล่านี้เป็นไดเร็กทอรีสำหรับตัวแปรทั้งค่าคงที่ (เช่น คำนวณสำหรับบทบาท) และไดนามิก (มีทั้งรูปแบบหรือรูปแบบต่อต้าน - include_vars พร้อมกับ {{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml.) เหล่านี้คือไดเร็กทอรีสำหรับ files/, templates/. นอกจากนี้ยังช่วยให้คุณมีโมดูลและปลั๊กอินของคุณเอง (library/). แต่เมื่อเปรียบเทียบกับงานใน playbook (ซึ่งสามารถมีทั้งหมดนี้ได้) ข้อดีเพียงอย่างเดียวคือไฟล์จะไม่ถูกทิ้งลงในกองเดียว แต่จะแยกหลายๆ กอง

รายละเอียดอีกอย่างหนึ่ง: คุณสามารถลองสร้างบทบาทที่จะสามารถนำมาใช้ซ้ำได้ (ผ่านกาแล็กซี) ด้วยการถือกำเนิดของคอลเลกชัน การกระจายบทบาทถือได้ว่าแทบจะลืมไปแล้ว

ดังนั้นบทบาทจึงมีคุณลักษณะที่สำคัญสองประการ: บทบาทมีค่าเริ่มต้น (คุณลักษณะเฉพาะ) และอนุญาตให้คุณจัดโครงสร้างโค้ดของคุณได้

กลับมาที่คำถามเดิม: เมื่อใดควรทำงานและเมื่อใดควรทำหน้าที่? งานใน Playbook มักใช้เป็น "กาว" ก่อน/หลังบทบาท หรือเป็นองค์ประกอบการสร้างอิสระ (จากนั้นไม่ควรมีบทบาทในโค้ด) กองงานปกติที่ปะปนกับบทบาทถือเป็นความเลอะเทอะที่ชัดเจน คุณควรยึดถือสไตล์ที่เฉพาะเจาะจง ไม่ว่าจะเป็นงานหรือบทบาท บทบาททำให้มีการแยกเอนทิตีและค่าเริ่มต้น งานช่วยให้คุณอ่านโค้ดได้เร็วขึ้น โดยปกติแล้ว โค้ดที่ "คงที่" (สำคัญและซับซ้อน) จะถูกใส่เข้าไปในบทบาท และสคริปต์เสริมจะถูกเขียนในรูปแบบงาน

เป็นไปได้ที่จะทำ import_role เป็นงาน แต่ถ้าคุณเขียนสิ่งนี้ เตรียมพร้อมที่จะอธิบายความรู้สึกดีๆ ของตัวเองว่าทำไมคุณถึงอยากทำสิ่งนี้

ผู้อ่านที่ชาญฉลาดอาจบอกว่าบทบาทสามารถนำเข้าบทบาทได้ บทบาทสามารถมีการพึ่งพาผ่าน galaxy.yml และยังมีสิ่งที่แย่และแย่มากอีกด้วย include_role — ฉันขอเตือนคุณว่าเรากำลังพัฒนาทักษะ Ansible ขั้นพื้นฐาน ไม่ใช่ยิมนาสติกลีลา

ตัวจัดการและงาน

เรามาพูดถึงอีกสิ่งหนึ่งที่ชัดเจน: ตัวจัดการ การรู้วิธีใช้อย่างถูกต้องแทบจะเป็นศิลปะอย่างหนึ่ง ความแตกต่างระหว่างตัวจัดการและการลากคืออะไร?

เนื่องจากเราจำข้อมูลพื้นฐานได้ ต่อไปนี้คือตัวอย่าง:

- hosts: group1
  tasks:
    - foo:
      notify: handler1
  handlers:
     - name: handler1
       bar:

ตัวจัดการของบทบาทอยู่ใน Rolename/handlers/main.yaml ตัวจัดการค้นหาระหว่างผู้เข้าร่วมการเล่นทั้งหมด: pre/post_tasks สามารถดึงตัวจัดการบทบาทได้ และบทบาทสามารถดึงตัวจัดการออกจากการเล่นได้ อย่างไรก็ตาม การเรียก "ข้ามบทบาท" ไปยังตัวจัดการทำให้เกิด wtf มากกว่าการทำซ้ำตัวจัดการเล็กน้อย (องค์ประกอบหนึ่งของแนวทางปฏิบัติที่ดีที่สุดอีกประการหนึ่งคือพยายามอย่าใช้ชื่อตัวจัดการซ้ำ)

ข้อแตกต่างที่สำคัญคืองานจะถูกดำเนินการเสมอ (idempotently) (แท็กบวก/ลบ และ when) และตัวจัดการ - โดยการเปลี่ยนแปลงสถานะ (แจ้งเตือนการยิงเฉพาะในกรณีที่มีการเปลี่ยนแปลง) สิ่งนี้หมายความว่า? ตัวอย่างเช่น ความจริงที่ว่าเมื่อคุณรีสตาร์ท หากไม่มีการเปลี่ยนแปลง จะไม่มีตัวจัดการ เหตุใดเราจึงต้องดำเนินการจัดการเมื่อไม่มีการเปลี่ยนแปลงในงานสร้าง? ตัวอย่างเช่น เนื่องจากมีบางอย่างพังและเปลี่ยนแปลง แต่การดำเนินการไปไม่ถึงตัวจัดการ เช่น เนื่องจากเครือข่ายล่มชั่วคราว การกำหนดค่ามีการเปลี่ยนแปลง บริการยังไม่ได้เริ่มต้นใหม่ ครั้งถัดไปที่คุณเริ่มใช้งาน การกำหนดค่าจะไม่เปลี่ยนแปลงอีกต่อไป และบริการยังคงอยู่กับการกำหนดค่าเวอร์ชันเก่า

สถานการณ์ที่มีการกำหนดค่าไม่สามารถแก้ไขได้ (อย่างแม่นยำยิ่งขึ้น คุณสามารถสร้างโปรโตคอลรีสตาร์ทพิเศษสำหรับตัวคุณเองด้วยแฟล็กไฟล์ ฯลฯ ได้ แต่นี่ไม่ใช่ 'พื้นฐานที่ทำได้' ในรูปแบบใด ๆ อีกต่อไป) แต่มีอีกเรื่องหนึ่งที่เหมือนกัน: เราติดตั้งแอปพลิเคชันและบันทึกไว้ .service-file และตอนนี้เราต้องการมัน daemon_reload и state=started. และสถานที่ตามธรรมชาติสำหรับสิ่งนี้ดูเหมือนจะเป็นผู้จัดการ แต่ถ้าคุณทำให้มันไม่ใช่ตัวจัดการ แต่เป็นงานที่ส่วนท้ายของรายการงานหรือบทบาท มันจะถูกดำเนินการอย่างไม่มีศักยภาพทุกครั้ง แม้ว่าเพลย์บุ๊กจะแตกกลางทางก็ตาม การดำเนินการนี้ไม่สามารถแก้ปัญหาการรีสตาร์ทได้เลย (คุณไม่สามารถทำงานด้วยแอตทริบิวต์ restarted ได้ เนื่องจากค่า idempotency หายไป) แต่ก็คุ้มค่าที่จะทำ state=started อย่างแน่นอน ความเสถียรโดยรวมของ playbooks จะเพิ่มขึ้น เนื่องจาก จำนวนการเชื่อมต่อและสถานะไดนามิกลดลง

คุณสมบัติเชิงบวกอีกประการหนึ่งของตัวจัดการคือ มันไม่อุดตันเอาต์พุต ไม่มีการเปลี่ยนแปลง - ไม่มีการข้ามเพิ่มเติมหรือตกลงในผลลัพธ์ - อ่านง่ายกว่า นอกจากนี้ยังเป็นคุณสมบัติเชิงลบด้วย - หากคุณพบว่ามีการพิมพ์ผิดในงานที่ดำเนินการเชิงเส้นในการรันครั้งแรก ตัวจัดการจะถูกดำเนินการเมื่อมีการเปลี่ยนแปลงเท่านั้น เช่น ภายใต้เงื่อนไขบางประการ - น้อยมาก ตัวอย่างเช่น เป็นครั้งแรกในชีวิตของฉันในอีกห้าปีต่อมา และแน่นอนว่าจะต้องมีการพิมพ์ชื่อผิดและทุกอย่างจะพัง และถ้าคุณไม่เรียกใช้เป็นครั้งที่สอง ก็จะไม่มีการเปลี่ยนแปลง

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

... ดังนั้นตัวจัดการจึงมีประโยชน์น้อยกว่าและมีปัญหามากกว่าที่เห็นมาก หากคุณสามารถเขียนบางสิ่งได้อย่างสวยงาม (โดยไม่ต้องมีตัวจัดการ) โดยไม่ต้องใช้ตัวจัดการ ก็จะดีกว่าถ้าเขียนโดยไม่มีสิ่งเหล่านั้น ถ้ามันไม่ได้ผลสวยงามก็ดีกว่ากับพวกเขา

ผู้อ่านที่มีฤทธิ์กัดกร่อนชี้ให้เห็นอย่างถูกต้องว่าเรายังไม่ได้พูดคุยกัน listenที่ตัวจัดการสามารถเรียกแจ้งเตือนสำหรับตัวจัดการอื่น ตัวจัดการสามารถรวม import_tasks (ซึ่งสามารถรวม_role กับ with_items) ว่าระบบตัวจัดการใน Ansible นั้นทัวริงสมบูรณ์ ตัวจัดการนั้นจาก include_role ตัดกันด้วยวิธีที่อยากรู้อยากเห็นกับตัวจัดการจากการเล่น ฯลฯ .d. - ทั้งหมดนี้ไม่ใช่ "พื้นฐาน") อย่างชัดเจน

แม้ว่าจะมี WTF เฉพาะอย่างหนึ่งซึ่งเป็นฟีเจอร์ที่คุณต้องจำไว้ หากงานของคุณถูกดำเนินการด้วย delegate_to และมีการแจ้งเตือน จากนั้นตัวจัดการที่เกี่ยวข้องจะถูกดำเนินการโดยไม่มี delegate_to, เช่น. บนโฮสต์ที่ได้รับมอบหมายให้เล่น (ถึงแม้ผู้ดูแลก็อาจจะมี delegate_to เดียวกัน).

แยกกัน ฉันต้องการพูดสองสามคำเกี่ยวกับบทบาทที่นำมาใช้ซ้ำได้ ก่อนที่คอลเลกชันจะปรากฏ มีความคิดที่ว่าคุณสามารถสร้างบทบาทสากลที่อาจเป็นได้ ansible-galaxy install และไป ใช้งานได้กับระบบปฏิบัติการทุกรูปแบบในทุกสถานการณ์ ดังนั้นความคิดเห็นของฉัน: มันใช้งานไม่ได้ บทบาทใด ๆ ที่มีมวล include_varsซึ่งรองรับเคสได้ 100500 เคส ถึงวาระที่จะพบข้อบกพร่องของเคสมุมลึก พวกเขาสามารถครอบคลุมได้ด้วยการทดสอบจำนวนมาก แต่เช่นเดียวกับการทดสอบอื่นๆ คุณจะมีผลคูณคาร์ทีเซียนของค่าอินพุตและฟังก์ชันทั้งหมด หรือคุณมี "สถานการณ์ส่วนบุคคลที่ครอบคลุม" ความคิดเห็นของฉันคือจะดีกว่ามากหากบทบาทเป็นแบบเส้นตรง (ความซับซ้อนแบบไซโคลมาติก 1)

ifs น้อยลง (ชัดเจนหรือประกาศ - ในรูปแบบ when หรือแบบฟอร์ม include_vars ตามชุดตัวแปร) บทบาทก็จะยิ่งดีขึ้นเท่านั้น บางครั้งคุณต้องสร้างกิ่งไม้ แต่ฉันขอย้ำว่ายิ่งมีน้อยก็ยิ่งดี ดูเหมือนว่าจะมีบทบาทที่ดีกับกาแล็กซี (ใช้งานได้!) กับพวงของ when อาจจะดีกว่าบทบาท "ของตัวเอง" จากห้างาน ช่วงเวลาที่บทบาทของกาแล็กซีดีขึ้นคือเมื่อคุณเริ่มเขียนอะไรบางอย่าง ช่วงเวลาที่แย่ลงคือเมื่อมีบางอย่างพังและคุณสงสัยว่าเป็นเพราะ "บทบาทของกาแล็กซี" คุณเปิดมันขึ้นมา และจะมีการรวมห้ารายการ แผ่นงานแปดแผ่น และสแต็กหนึ่ง when'ov... และเราต้องคิดออก แทนที่จะเป็น 5 งาน เป็นรายการเชิงเส้นที่ไม่มีอะไรจะพัง

ในส่วนต่อไปนี้

  • เล็กน้อยเกี่ยวกับสินค้าคงคลัง, ตัวแปรกลุ่ม, ปลั๊กอิน host_group_vars, hostvars วิธีผูกปมกอร์เดียนกับสปาเก็ตตี้ ตัวแปรขอบเขตและลำดับความสำคัญ โมเดลหน่วยความจำ Ansible “แล้วเราจะเก็บชื่อผู้ใช้สำหรับฐานข้อมูลไว้ที่ไหน?”
  • jinja: {{ jinja }} — nosql notype จมูกดินน้ำมันอ่อน มันมีอยู่ทุกที่ แม้ในที่ที่คุณไม่คาดคิดก็ตาม นิดหน่อยเกี่ยวกับ !!unsafe และมันเทศแสนอร่อย

ที่มา: will.com

เพิ่มความคิดเห็น