1 คะแนน โดย GN⁺ 4 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เขียนงานอัตโนมัติสำหรับเซิร์ฟเวอร์ด้วย โค้ด Python และรันแบบขนานผ่าน SSH เพื่อสั่งงานอย่างมีคุณสมบัติ idempotent โดยไม่ต้องใช้เอเจนต์
  • pyinfra ชูจุดเด่นว่า เร็วกว่า Ansible 6 เท่า ในเวิร์กโหลดเดียวกัน โดยใช้การรันพร้อมกันบนพื้นฐานของ gevent และ SSH
  • ใช้ตัวเลือก --dry เพื่อตรวจสอบ diff ของการเปลี่ยนแปลงแยกตามโฮสต์ก่อนนำไปใช้จริง และเมื่อรันจริงผลลัพธ์จะถูกส่งกลับมาแบบ parallel streaming
  • โฮสต์ปลายทางต้องมีเพียง shell และ SSH เท่านั้น โดยไม่มี daemon, state file หรือ control plane
  • เน้นแนวทาง configuration ที่ยึดโค้ดเป็นศูนย์กลาง โดยไม่เข้ารหัส control flow ลงใน YAML แต่ใช้ลูปและเงื่อนไขของ Python ได้ตรง ๆ

ฟีเจอร์หลักและลำดับการทำงาน

  • ทำงานอัตโนมัติกับเซิร์ฟเวอร์นับพันเครื่อง

    • pyinfra เป็นเครื่องมืออัตโนมัติแบบ Python-native และ agentless ที่รันคำสั่งผ่าน SSH
    • การรันคำสั่งเน้นเรื่อง concurrency, idempotency และความเร็ว โดยชูว่า เร็วกว่า Ansible 6 เท่า ในเวิร์กโหลดเดียวกัน
    • คำสั่งติดตั้งคือ $ uv tool install pyinfra
    • คุณสมบัติพื้นฐานที่ระบุไว้คือ MIT license, Python 3.10 ขึ้นไป, no agents และ zero config
  • ตัวอย่างโค้ดสำหรับดีพลอย

    • ใช้งาน apt, files, systemd ผ่านโค้ด Python เพื่อทำการติดตั้งแพ็กเกจ วางเทมเพลต และรีโหลดบริการ
    • โค้ดตัวอย่างติดตั้งแพ็กเกจ nginx และ certbot แล้ววาง templates/nginx.conf.j2 ไปที่ /etc/nginx/sites-enabled/api
    • ขั้นตอนสุดท้ายรีโหลดบริการ nginx ด้วย systemd.service("nginx", reloaded=True)
    from pyinfra.operations import apt, files, systemd
    
    apt.packages(
        packages=["nginx", "certbot"],
        update=True,
    )
    
    files.template(
        src="templates/nginx.conf.j2",
        dest="/etc/nginx/sites-enabled/api",
    )
    
    systemd.service("nginx", reloaded=True)
    
  • อินเวนทอรีและผลลัพธ์การรัน

    • ตัวอย่างอินเวนทอรีประกอบด้วยโฮสต์เว็บตั้งแต่ web-01.prod ถึง web-23.prod และโฮสต์ฐานข้อมูล db-01.prod, db-02.prod
    • คำสั่ง $ pyinfra inventory.py deploy.py --limit web จะจำกัดการรันเฉพาะกลุ่มเป้าหมาย web
    • เอาต์พุตการรันทำงานตามลำดับคือโหลดอินเวนทอรี เก็บ fact พร้อมกัน รัน deploy.py แล้วสรุปผล
    • ตัวอย่างสรุประบุว่ามีโฮสต์สำเร็จ 23 เครื่อง เปลี่ยนแปลง 18 เครื่อง ล้มเหลว 0 เครื่อง ใช้เวลารวม 2.1 วินาที
  • ตรวจสอบก่อนเปลี่ยนแปลง

    • --dry ช่วยให้ตรวจสอบ diff แยกตามโฮสต์ ของทุกงานที่ pyinfra จะทำได้ล่วงหน้า
    • เมื่อรันจริง ผลลัพธ์จะถูกสตรีมกลับมาแบบขนาน พร้อมแสดงจำนวนการเปลี่ยนแปลงและเวลาที่ใช้ของแต่ละโฮสต์
    • ตัวอย่างการรันบันทึกว่าใน 24 โฮสต์ มี 18 โฮสต์ที่เปลี่ยนแปลง 6 โฮสต์ไม่เปลี่ยนแปลง ล้มเหลว 0 โฮสต์ และใช้เวลารวม 2.1 วินาที

คุณลักษณะ การเปรียบเทียบกับ Ansible และหลักการ

  • เหตุผลหกข้อที่ควรเลือก pyinfra

    • Just Python: เขียน control flow จริงด้วย Python โดยไม่ใช้ YAML และ Jinja-in-YAML
    • Concurrent SSH: รันพร้อมกันบนพื้นฐานของ gevent และ SSH และเร็วกว่า Ansible 6 เท่าในเวิร์กโหลดเดียวกัน
    • Diff before apply: ใช้ --dry เพื่อดูทุกการเปลี่ยนแปลงล่วงหน้า และงานแบบ idempotent จะกลายเป็น no-op เมื่อนำไปรันซ้ำ
    • 0 agents: โฮสต์ต้องมีเพียง shell และ SSH เท่านั้น โดยไม่มี daemon, state file หรือ control plane
    • Scale-ready: ทำงานได้ตั้งแต่ 1 โฮสต์จนถึง 10,000 โฮสต์ รองรับการรันแบบขนานและเอาต์พุตสตรีมมิงแบบเรียลไทม์
    • Hackable: สร้างงานแบบกำหนดเองได้ใน 10 บรรทัด และเชื่อมต่อกับ docker, lxc, k8s ที่สื่อสารผ่าน shell ได้
  • เปรียบเทียบโค้ดระหว่าง Ansible กับ pyinfra

    • ตัวอย่าง Ansible ใช้ playbook.yml 16 บรรทัดเพื่อติดตั้ง nginx, เรนเดอร์เทมเพลต และรีโหลดบริการผ่าน handler
    • ตัวอย่าง pyinfra ใช้ deploy.py 8 บรรทัดเพื่อเขียนลำดับงานเดียวกันด้วยโค้ด Python
    • ตัวอย่าง pyinfra จะรัน systemd.service("nginx", reloaded=True) เฉพาะเมื่อ cfg.will_change ของผลลัพธ์จาก files.template เป็นจริงเท่านั้น
    from pyinfra.operations import apt, files, systemd
    
    apt.packages(["nginx"], update=True)
    
    cfg = files.template(
        src="nginx.conf.j2",
        dest="/etc/nginx/sites-enabled/api",
    )
    if cfg.will_change:
        systemd.service("nginx", reloaded=True)
    
  • ถ้อยแถลงหลัก

    • Code > config: ลูปก็คือลูป ไม่เข้ารหัส control flow ลงใน YAML
    • Show, then do: ดู diff ก่อน แล้วค่อยนำไปใช้เพื่อลดการเปลี่ยนแปลงที่ไม่คาดคิด
    • Stay out of the way: รันผ่าน SSH ได้โดยตรงโดยไม่มีเอเจนต์ state file หรือ control plane
    • Read like english: งานสามารถอ่านได้เหมือนคำนามและคำกริยา เช่น apt.packages, files.template, systemd.service
  • คำสั่งเริ่มต้น

    • คำสั่งติดตั้งคือ $ uv tool install pyinfra
    • มีคำแนะนำให้อ่าน quickstart 5 นาทีแล้วดีพลอยโฮสต์เครื่องแรก

1 ความคิดเห็น

 
GN⁺ 4 시간 전
ความคิดเห็นจาก Lobste.rs
  • pyinfra ให้ความรู้สึกเหมือน Ansible ในแบบที่มันควรจะเป็นมาตั้งแต่แรก แทนที่จะเอา YAML ที่ปนเทมเพลตมาพอกด้วย control flow คุณสามารถเขียนงานอัตโนมัติเป็น Python ได้โดยตรง
    พอใช้ Ansible มานานแล้วก็รู้สึกสดใหม่ดี ไม่ได้อยู่ฝั่งที่เกลียด Ansible เป็นพิเศษด้วย

    • ถ้าจะให้แม่นยำ มันดูใกล้เคียงกับ อินเทอร์พรีเตอร์ที่แปลงจาก Python ไปเป็นเชลล์ มากกว่าจะเป็น Ansible ที่เขียนด้วย Python และแนวทางนั้นก็มีปัญหาในตัวเอง
      น่าจะดีกว่าถ้ามีแบบไฮบริดที่ใช้ Python บนเซิร์ฟเวอร์ปลายทางด้วย เพราะจะลดนรกเรื่องเครื่องหมายอัญประกาศเวลาแก้ไฟล์ และหลีกเลี่ยงข้อจำกัดของ regex ใน sed ได้
  • ชอบ pyinfra และอยากให้ถูกใช้อย่างแพร่หลายกว่านี้
    ทุกบริษัทที่เคยทำงานมาล้วนใช้ Ansible ไม่ว่าจะใช้ Terraform ควบคู่กันหรือไม่ก็ตาม และไม่มีที่ไหนที่ทีมพร้อมจะเขียนระบบอัตโนมัติเดิมทั้งหมดใหม่ด้วยเครื่องมือที่พนักงานยังไม่มีประสบการณ์
    pyinfra ต้องการให้ SysOps รู้ Python ซึ่งส่วนตัวมองว่า SysOps ควรรู้ภาษา scripting สักภาษาอยู่แล้ว โดยเฉพาะใน Ansible เอง ถ้าเขียนโมดูลด้วย Python ก็ช่วยลดความรกของ YAML ได้ แต่ดูเหมือนอย่างน้อยในฝรั่งเศสจะไม่ใช่ความคิดที่แพร่หลายนัก

    • ผมใช้ Ansible มาเยอะ และมองว่าจริง ๆ แล้วมันแทบจะเป็น สิ่งที่ปลอมตัวเป็นภาษา scripting
      อาจไม่ใช่ประเด็นที่ถกเถียงกันดุเดือดขนาดนั้นก็ได้
  • เคยใช้ Ansible ใน homelab แล้วเริ่มอึดอัดขึ้นเรื่อย ๆ การตั้งค่าด้วย YAML แย่มาก ทุกอย่างให้ความรู้สึกเหมือนเป็นการแฮ็ก และยังช้ามากด้วย ไม่เข้าใจเหมือนกันว่าการจะรันคำสั่งเชลล์ไม่กี่คำสั่งทำไมเซิร์ฟเวอร์ต้องมี python3
    รู้จัก pyinfra จาก Google AI Mode และในช่วงที่ลองใช้มาเกือบเดือน มันสดชื่นกว่ามาก ข้อดีคือเร็วกว่า Ansible มาก เขียนลูปและเงื่อนไขด้วย Python ได้ และไม่ต้องมี roles หรือไดเรกทอรีซ้อนกัน โดยฝั่งเซิร์ฟเวอร์แค่มีเชลล์ก็พอ มันจะสร้างแผนจากสถานะปัจจุบันก่อนรัน และถ้าไม่ใส่ -y ก็จะถามยืนยันก่อน
    ข้อเสียคือชุดงานพื้นฐานยังมีแค่บางส่วนเล็ก ๆ เมื่อเทียบกับโมดูลของ Ansible โค้ดก็กลายเป็นสปาเกตตีได้เร็ว และวิธีอย่าง if 'web_server' in hosts.groups ก็ไม่ได้ดีนัก ไม่แน่ใจว่า operation(..., filter_group='web_server') จะดีกว่าหรือเปล่า
    สิ่งที่แย่ที่สุดคือการ เขียน custom connector นั้นทรมานมาก ดูเหมือนต้องมี pyproject.toml ที่ใส่ entry point เฉพาะของ pyinfra และถึงจะใช้ uv การพัฒนา connector ภายในบริษัทก็ยังเหมือนฝันร้าย มันควรจะทำเป็นไฟล์ Python ปกติในโปรเจกต์ได้

  • กำลังลองใช้ pyinfra เป็นเครื่องมือ deploy ใน homelab มาหลายวันแล้ว และเมื่อเทียบกับ Ansible สิ่งที่ชอบที่สุดจนถึงตอนนี้ไม่ใช่ syntax ของ Python แต่เป็น ความเร็ว
    Ansible ให้ความรู้สึกว่าช้าจนทนไม่ไหวอยู่เสมอ

    • พื้นที่นี้น่าสนใจดี ผมก็กำลังทำเครื่องมือ deploy อยู่ และใช้มันกับงาน deploy จริงในงานประจำ
      อยากใช้แทนการใช้ Ansible และ Salt ในหลาย ๆ ที่
  • น่าสนใจดีที่ infrastructure as code วนกลับมาครบรอบ จากสคริปต์ไปเป็น YAML แล้วก็ย้อนกลับมาเป็นสคริปต์ที่ซับซ้อนขึ้นอีก
    แต่ละแนวทางมีจุดที่เหมาะของมัน และจากมุมมองของผู้ใช้ Ansible แล้ว pyinfra ก็ดูดีทีเดียว

  • เหตุผลสำคัญที่ทำให้เลือกใช้ Ansible คือ โหมด dry run และการดู diff เพราะมันทำให้มั่นใจได้ว่าจะไม่ไปทำอะไรที่ไม่คาดคิด
    แต่ดูเหมือนว่า CLI ของ pyinfra จะไม่มีตัวเลือกแบบนั้น อาจเป็นไปได้ว่าผมหาไม่เจอเพราะไม่เจอเอกสารอ้างอิงที่รวมออปชันทั้งหมดเรียงตามตัวอักษร

    • มีแฟลก —dry และโชว์อยู่ในหน้าแรกของ pyinfra เลย
  • สำหรับคนที่สนใจ ผมก็มีโปรเจกต์ที่คล้ายกันของตัวเองซึ่งทำมาแล้ว 14 ปี: https://github.com/sebastien/cuisine/tree/main
    มันเป็นแบบ agentless ใช้แค่ SSH และมี API สไตล์ Python ครอบอยู่บนความสามารถจัดการหลัก ๆ แต่ไม่รองรับ dry mode

  • เราใช้ Ansible สำหรับ provision resource บน OpenStack และใช้ pyinfra จัดการส่วนที่เหลือ ซึ่งตลอดหลายปีที่ผ่านมาก็ทำงานได้ค่อนข้างดี
    ข้อเสียใหญ่สุดคือชุมชนยังเล็ก เลยต้องเขียนทางแก้เอง เช่น เราเก็บ shared secret ที่ใช้ในการ deploy ไว้บนดิสก์ด้วย keyring + privy และเขียนโค้ดไม่กี่บรรทัดเองเพื่อแปลง inventory ของ OpenStack compute ให้เป็นข้อมูล hosts