ในฐานะนักพัฒนาซอฟต์แวร์หลักใน Cloudify.co ฉันมักจะทำงานบนโฮสต์ระยะไกลที่ใช้งานบนบริการคลาวด์ เช่น AWS หรือ Openstack งานประเภทนี้ทำให้คุณเกิดคำถาม: ฉันจะรันคำสั่งเดียวกัน (สคริปต์) กับคำสั่งทั้งหมดโดยอัตโนมัติได้อย่างไร คำตอบมักจะใช้ Ansible หรือ Fabric ในบทความนี้ ฉันตัดสินใจที่จะมุ่งเน้นไปที่โซลูชัน Fabric
ผ้าคืออะไร?
Fabric เป็นไลบรารี Python ระดับสูง (2.7, 3.4+) ที่ออกแบบมาเพื่อรันคำสั่งเชลล์จากระยะไกลผ่าน SSH โดยให้วัตถุ Python ที่เป็นประโยชน์เป็นการตอบแทน ("เว็บไซต์ Fabric")
มาเขียนโค้ดกับมันกันดีกว่า (ฉันใช้ Python 3.6 และ Fabric 2.5.0)
การเริ่มต้นใช้งาน — การสร้างการเชื่อมต่อ:
เนื่องจากเราใช้ python วิธีที่ดีที่สุดในการแสดงความสามารถของ Fabric คือการใช้ object เราจะเรียกมันว่า 'Host'
class Host(object): def __init__(self, host_ip, username, key_file_path): self.host_ip = host_ip self.username = username self.key_file_path = key_file_path def _get_connection(self): connect_kwargs = {'key_filename': self.key_file_path} return Connection(host=self.host_ip, user=self.username, port=22, connect_kwargs=connect_kwargs)
ในโค้ดด้านบน `Host` ถูกใช้เป็น "โฮสต์ระยะไกล" และใช้ฟังก์ชัน `_get_connection` เพื่อสร้างการเชื่อมต่อ SSH (เพื่ออ่านเพิ่มเติมเกี่ยวกับ `การเชื่อมต่อ`) เราจะใช้การเชื่อมต่อเป็นตัวจัดการบริบทเนื่องจากมีวงจรชีวิตพื้นฐาน “สร้าง เชื่อมต่อ/เปิด ทำงาน ยกเลิกการเชื่อมต่อ/ปิด” (จากเอกสาร)
คำสั่งที่กำลังรันอยู่:
ตอนนี้เรามีการเชื่อมต่อแล้ว เราก็สามารถรันคำสั่งบนรีโมตโฮสต์ของเราได้ ฟังก์ชั่นต่อไปนี้จะถูกเพิ่มเข้าไปในวัตถุ 'โฮสต์':
def run_command(self, command): try: with self._get_connection() as connection: print('Running `{0}` on {1}'.format(command, self.host_ip)) result = connection.run(command, warn=True, hide='stderr') except (socket_error, AuthenticationException) as exc: self._raise_authentication_err(exc) if result.failed: raise ExampleException( 'The command `{0}` on host {1} failed with the error: ' '{2}'.format(command, self.host_ip, str(result.stderr))) def put_file(self, local_path, remote_path): try: with self._get_connection() as connection: print('Copying {0} to {1} on host {2}'.format( local_path, remote_path, self.host_ip)) connection.put(local_path, remote_path) except (socket_error, AuthenticationException) as exc: self._raise_authentication_err(exc) def _raise_authentication_err(self, exc): raise ExampleException( "SSH: could not connect to {host} " "(username: {user}, key: {key}): {exc}".format( host=self.host_ip, user=self.username, key=self.key_file_path, exc=exc))
ในโค้ดข้างต้น ฟังก์ชันต่างๆ:
`run_command` ใช้เพื่อรันคำสั่งบนโฮสต์ระยะไกล คุณสามารถส่งผ่านฟังก์ชัน `Connect.run` พารามิเตอร์ต่างๆ ได้มากมาย ("ตามที่อธิบายไว้ที่นี่") แต่สิ่งที่ฉันต้องการสำหรับกลไก "การตรวจจับข้อผิดพลาด" คือ:
- `warn=True`: อย่าสร้างข้อยกเว้นเมื่อคำสั่งที่ดำเนินการออกโดยมีสถานะไม่เป็นศูนย์ (หมายถึงความล้มเหลว)
- `hide='stderr'': อย่าคัดลอกกระบวนการย่อย' stderr ไปยังเทอร์มินัลการควบคุม
พฤติกรรมเริ่มต้นของ `Connection.run` คือการคัดลอก stdout และ stderr ของกระบวนการย่อยไปยังเทอร์มินัลการควบคุม
`put_file` ใช้เพื่อคัดลอกไฟล์จากโลคัลโฮสต์ไปยังรีโมตโฮสต์ (เพื่ออ่านเพิ่มเติมเกี่ยวกับ `Connection.put`)
สิ่งสำคัญที่ควรทราบ คลาสการเชื่อมต่อคือ "ขี้เกียจ" ซึ่งหมายความว่าเมื่อเราเริ่มต้นคลาสนั้น จะไม่พยายามเชื่อมต่อกับโฮสต์ ดังนั้นเราจึงใส่คำสั่งของเราไว้ในบล็อกลองยกเว้นที่จะตรวจจับข้อผิดพลาดในการเชื่อมต่อ
สรุป:
การตัดสินใจเลือกระหว่าง Ansible และ Fabric มักจะขึ้นอยู่กับสิ่งที่คุณต้องการรันบนโฮสต์ระยะไกล หากเป็นสคริปต์ธรรมดา Fabric ก็ควรจะดีเพียงพอ ไม่เช่นนั้น Ansible อาจเป็นตัวเลือกที่ดีกว่า ไม่ว่าจะด้วยวิธีใด Cloudify Manager ให้คุณเลือกโซลูชันที่เหมาะกับคุณโดยใช้ปลั๊กอิน Ansible และ Fabric มีความสุข! :)
ภาคผนวก:
นี่คือตัวอย่างโค้ดแบบเต็มที่คุณสามารถใช้ได้ (อย่าลืมแทนที่พารามิเตอร์ `Host` ให้ตรงกับพารามิเตอร์ของคุณเอง):