แทนที่ Kubernetes ด้วย systemd (2024)
(blog.yaakov.online)- สำหรับเซิร์ฟเวอร์ส่วนตัวและ VPS ขนาดเล็ก ระบบอัตโนมัติแบบประกาศสถานะของ Kubernetes น่าสนใจ แต่ภาระด้าน CPU·หน่วยความจำ และความซับซ้อนในการดูแล อาจมากกว่าประโยชน์ที่ได้รับจริง
- Kubernetes ทำงานโดยคอยปรับให้ระบบอยู่ในสถานะที่ต้องการอยู่เสมอ จึงช่วยทำงานอัตโนมัติอย่างการจัดการ Pod และการต่ออายุใบรับรอง TLSได้ แต่ต้องแลกกับการมีรันไทม์ขนาดค่อนข้างใหญ่ทำงานตลอดเวลา
- ในการทดลองกับ Azure Kubernetes Service, Microk8s, K3S และ Raspberry Pi ปัญหาการใช้ทรัพยากรว่าง ความร้อน และเสียงพัดลม เกิดซ้ำๆ อยู่เสมอ
- Podman สามารถทำให้คอนเทนเนอร์เป็นบริการ systemd ได้ และใช้
io.containers.autoupdateกับpodman auto-updateเพื่อตรวจจับอิมเมจใหม่แล้วสลับใช้งานได้ - การใช้ Podman, systemd และ user lingering ร่วมกัน ให้ระบบอัตโนมัติส่วนใหญ่ที่เคยต้องการจาก Kubernetes ได้อย่างเรียบง่ายกว่า แต่การผสานกับ systemd กำลังขยับไปในทิศทางของ Quadlet
ทำไมระบบอัตโนมัติของ Kubernetes ถึงหนักเกินไปสำหรับเซิร์ฟเวอร์ส่วนตัว
- Kubernetes ประกอบด้วยหลายส่วน เว็บเซอร์วิส sidecar และ webhook แต่แกนการทำงานจริงใกล้เคียงกับลูปที่คอยเปรียบเทียบสถานะปัจจุบันกับสถานะที่ต้องการและนำความต่างไปปรับใช้
- ถ้าควรมี Pod แต่ไม่มี ก็จะสร้างขึ้นมา
- ถ้าควรมี replica 3 ตัว แต่มี 4 ตัว ก็จะลบออก 1 ตัว
- โมเดลนี้มีประโยชน์อย่างมากโดยเฉพาะกับส่วนขยายอย่าง cert-manager
- ประกาศว่าต้องมีใบรับรอง TLSที่ใช้ได้สำหรับโดเมนหนึ่ง
- เมื่อกำหนดวิธีขอใบรับรองไว้แล้ว หากยังไม่มีใบรับรองหรือใกล้หมดอายุ ระบบจะขอใบรับรองใหม่และติดตั้งให้เว็บเซิร์ฟเวอร์
- สำหรับการทดลองส่วนตัว มันทั้งสนุกและมีคุณค่าในการเรียนรู้ แต่สำหรับการใช้งานจริงกลับใกล้เคียงกับการใช้เครื่องมือที่ใหญ่เกินความจำเป็น
- ภาระด้านทรัพยากรเกิดขึ้นซ้ำในหลายสภาพแวดล้อม
- บน NUC เครื่องทำงานอยู่ตลอด ร้อนขึ้นเรื่อยๆ และมีเสียงพัดลมจนหลับยาก
- บน Azure Kubernetes Service ตัวระบบ Kubernetes เองใช้ RAM มาก และใช้ CPU ว่างบน worker node ราว 7~10%
- Microk8s แบบอินสแตนซ์เดียวบน VPS x86_64 2 vCPU ใช้ CPU ตอนว่างราว 12%
- K3S บนเครื่อง Ampere A1 2 vCPU ซึ่งขึ้นชื่อว่าเบากว่า ก็ยังใช้ CPU ต่อเนื่องประมาณ 6%
- แม้แต่บน Raspberry Pi ก็ยังหา implementation ที่ไม่เจอปัญหาความร้อน·พัดลม และยังเหลือ CPU พอสำหรับ workload ไม่ได้
รูปแบบอัตโนมัติที่เปลี่ยนมาใช้ Podman และ systemd
- เหตุผลใหญ่ที่สุดที่ยังใช้ Kubernetes ต่อเนื่องคือระบบอัตโนมัติในการดีพลอย
- ใช้ GitOps กับ Flux แล้วจัดการการเปลี่ยนแปลงได้ง่าย
- เมื่อใช้ระบบอัตโนมัติของอิมเมจคอนเทนเนอร์และ webhook ของ Flux v2 พอ push อิมเมจใหม่เข้าไป ภายในไม่กี่วินาทีเซิร์ฟเวอร์ก็จะดึงอิมเมจใหม่และรันแอปพลิเคชันโปรดักชัน
- ทางเลือกเดิมที่หาได้นอก Kubernetes ยังไม่น่าพอใจ
- วิธีสร้างคอนเทนเนอร์ใหม่โดยต้องจำอาร์กิวเมนต์ของคำสั่งทั้งหมดเดิมไว้ มีภาระในการดูแลสูง
- และก็ไม่ชอบเครื่องมือที่ต้องการสิทธิ์ควบคุม
docker.sockทั้งหมด
- Podman auto-updating ใกล้เคียงกับสิ่งที่ต้องการมาก
- Podman มองได้ว่าเป็นทางเลือกแทน Docker CLI
- หลังสร้างคอนเทนเนอร์แล้ว สามารถสร้าง ไฟล์บริการ systemd ได้
- เมื่อเริ่มบริการ ระบบจะสร้างหรือเปลี่ยนคอนเทนเนอร์ และเมื่อหยุดบริการก็จะลบคอนเทนเนอร์ออก
- การอัปเดตอัตโนมัติทำงานผ่านแท็ก
io.containers.autoupdate- จะให้ทำงานวันละครั้งผ่าน timer หรือเรียก
podman auto-updateโดยตรงก็ได้ - ถ้ามีอิมเมจใหม่ ระบบจะสร้างคอนเทนเนอร์ใหม่จากอิมเมจนั้น
- จะให้ทำงานวันละครั้งผ่าน timer หรือเรียก
- บทความของ Fedora Magazine เรื่อง Auto-updating Podman containers with systemd ให้แนวทางการทำส่วนใหญ่ไว้แล้ว และยังต้องตั้งค่าเพิ่มอีก 2 อย่าง
- ใช้
systemctl --user enable mycontainer.serviceเพื่อให้คอนเทนเนอร์เริ่มอัตโนมัติเมื่อเข้าสู่ระบบ - ใช้
loginctl enable-lingerเพื่อให้ user session ทำงานตั้งแต่ตอนเซิร์ฟเวอร์บูต
- ใช้
- การใช้ Podman, systemd และ user lingering ร่วมกัน ทำให้ได้ข้อดีประมาณ 99% ที่เคยได้จาก Kubernetes แต่มีความซับซ้อนและภาระด้าน CPU·หน่วยความจำน้อยกว่ามาก
- ผู้เขียนย้ายบริการทั้งหมดจาก VPS เดิมไปยัง VPS ใหม่ที่มี vCPU และ RAM เหลือเพียงครึ่งเดียว และเมื่อรันไปไม่กี่ชั่วโมงก็พบว่าเบากว่า เร็วกว่า และมีค่าใช้จ่ายด้านคอมพิวต์ต่ำกว่า
- อย่างไรก็ตาม การผสาน Podman กับ systemd ดูเหมือนถูกยุติการรองรับไปแล้ว และการนิยามคอนเทนเนอร์กำลังถูกพูดถึงในทิศทางของไฟล์ Quadlet
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
เห็นอกเห็นใจความรู้สึกของผู้เขียนต้นฉบับอย่างเต็มที่ ที่ทำงานเราจัดการ Kubernetes cluster หลายชุดที่รัน microservice หลายสิบตัวได้ค่อนข้างง่าย แต่สำหรับโปรเจกต์งานอดิเรกที่ไม่มีรายได้ งบมีน้อยจนแม้อยากใช้ Kubernetes ก็ใช้ไม่ได้
บน VPS เดือนละ $10 ที่มี vCPU แบบแชร์ 1 ตัวกับ RAM 2GB นั้น Kubernetes หนักเกินไป แทนที่จะใช้ Deployment ก็ต้อง SSH เข้าไปสั่ง
docker compose up/downเอง แทนที่จะใช้ Ingress ก็พึ่งฟีเจอร์ค้นหา container ของ Traefik และเพราะใช้ CronJobs ไม่ได้ เลยถึงกับเขียนสคริปต์เล็ก ๆ เองเพื่อจัดการ crontab แบบ idempotentสิ่งที่อยากได้จริง ๆ คือทางเลือกที่เบา ซึ่งให้ API ที่เข้ากันได้กับ Kubernetes และรันได้ดีแม้บน VPS ราคาถูก ช่องว่างระหว่าง container orchestration ระดับ enterprise กับโฮสติ้งราคาถูกสำหรับงานอดิเรกยังใหญ่เกินไปมาก
docker composeที่ใช้ Kubernetes manifestและยังใช้ร่วมกับ systemd unit ได้เหมือนแนวทางที่อธิบายในบทความด้วย Podman ยังรองรับ Docker API ส่วนใหญ่หรือทั้งหมด ดังนั้น
docker composeก็ทำงานได้ และยังเชื่อมต่อไปยัง remote socket ผ่าน SSH เพื่อทำงานได้ด้วยhttps://docs.podman.io/en/latest/markdown/podman-kube-play.1...
https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
ให้ ARM64 4 คอร์กับ RAM 24GB ฟรี และแบ่งเป็น 1–4 node ได้ตามรูปแบบที่ต้องการ
https://www.oracle.com/cloud/free/
docker composeเวอร์ชันเสริมพลังอย่างหนึ่งใช้ Traefik กับ label เพื่อทำให้ reverse proxy และใบรับรอง TLS เป็นแบบทั่วไป แล้วผูก Authelia เป็นผู้ให้บริการ authentication แบบง่าย ๆ ได้ มีโปรเจกต์ตัวอย่างใน GitHub อยู่มากมาย และถ้าตั้งค่าสักสุดสัปดาห์หนึ่ง ก็จะได้ระบบที่จัดการค่อนข้างง่าย
systemd ถูกด่าเยอะ แต่แก้ปัญหาได้มากจริง ๆ จึงไม่ควรมองข้ามง่าย ๆ ตอนที่มันเริ่มถูกใส่มาเป็นค่าเริ่มต้นในดิสโทรต่าง ๆ ผู้คนไม่ชอบส่วนใหญ่เพราะต้องเปลี่ยนวิธีทำงาน
มีทั้ง container,
machinectl,nspawnซึ่งเป็น chroot ที่ทรงพลังกว่า,vmspawnสำหรับเวลาที่ต้องการ virtualization เต็มรูปแบบ,importctlสำหรับดาวน์โหลด นำเข้า และส่งออก machine,homed/homectlที่ช่วยให้การเข้ารหัส home directory และการควบคุมสิทธิ์ทำได้ง่ายขึ้น เป็นต้นแทนที่จะใช้
fstabก็จัดการ mount เป็น unit ได้ ควบคุมลำดับการบูตและการเริ่ม/หยุด service และยังมี timer ที่ทรงพลังกว่าcronด้วย เช่น รู้ได้ว่างานไหนไม่ได้รันเพราะเครื่องปิดอยู่ หรือสั่งให้รันแบบหน่วงเวลาหลังบูตภายใต้เงื่อนไขบางอย่างได้service unit สามารถควบคุมงานได้ละเอียดและจำกัดสิทธิ์ได้ และสร้างค่า override ด้วย
systemctl editได้โดยไม่แตะการตั้งค่าต้นฉบับ ช่วงแรกอาจน่ารำคาญนิดหน่อยที่ต้องเรียนรู้ แต่ถ้าจะทำงานซับซ้อน ยังไงก็ไม่มีเครื่องมือไหนที่ไม่ต้องเปิดเอกสารดูเลยอยู่แล้วปัญหาคือ ท่าทีของ maintainer มากกว่า คือทำของที่เคยทำงานได้ดีพังอย่างไม่แยแส และไม่ให้วิธีแก้ที่เหมาะสม ถ้าคุณไม่เคยรู้สึกเจ็บปวดเพราะ systemd ก็อาจเป็นเพราะเข้ามาทีหลัง หรือความต้องการของคุณบังเอิญตรงกับความต้องการของ maintainer หลักก็ได้
execตัวเองทับที่เดิมโปรแกรมที่ทำสิ่งที่ PID 1 ต้องทำให้ถูกต้อง 100% และไม่ทำอย่างอื่นเลย สามารถเล็กกว่านี้ได้มาก หากรัน systemd จากตรงนั้น ต่อให้ systemd มีปัญหาอะไร ก็จะไม่กลายเป็น kernel panic ทันที
ที่มา: https://ewontfix.com/14/
cronนั้นเข้าใจได้ยาก มันทำงานได้ดีมาตลอด 50 ปี แล้วจู่ ๆ ก็กลายเป็นสิ่งที่ผิดมหันต์และแน่นอนว่าต้องถูกแทนที่ด้วย systemd แบบนั้นหรือfstabแล้วใช้ systemd mount กฎ automount จะซับซ้อน และบางครั้งแม้จับคู่กับเอกสารแบบ 1:1 แล้วก็ยังไม่ทำงานเฉย ๆ ทำให้ filesystem อาจไม่ถูก mount ทันเวลาสำหรับดิสโทรหรือ upstream แล้ว มันทำให้ชีวิตง่ายขึ้นมาก แต่แลกกับการเพิ่มความซับซ้อนที่โตขึ้นเรื่อย ๆ เข้าไปในชั้นล่างสุดของระบบ แล้วแต่มุมมอง สิ่งอย่าง
journalctl,timedatectl, การพึ่งพา dbus หรือการทดแทนเครื่องมืออื่น ๆ อาจถูกมองว่าไม่เข้ากับ ปรัชญา Unixถ้าเป้าหมายมีแค่ประสานงาน process ต่าง ๆ ให้รันตามลำดับที่ถูกต้องและรับประกัน auto-activation ผมมองว่าเป็นเครื่องมือในระดับที่เหมาะสมกว่า k8s หรือ Docker
ผมรันโฮมแล็บด้วย podman-systemd หรือก็คือ Quadlet มาสักพักแล้ว และทุกครั้งที่ลองดู k8s สายพันธุ์ใหม่ ๆ ก็ไม่เคยรู้สึกว่าคุ้มกับความยุ่งยากที่เพิ่มขึ้น แค่ใช้ Ansible playbook เก่า ๆ ดึงอิมเมจไว้ล่วงหน้า แล้ววางไฟล์ยูนิตให้ถูกที่ก็พอแล้ว
ทั้งสแตกของเครื่องพิมพ์ 3D Voron ก็รันด้วย podman-systemd ทำให้สามารถอัปเดตและโรลแบ็กคอมโพเนนต์ทั้งหมดได้ในครั้งเดียว แต่ตอนนี้ก็กำลังพิจารณาวิธีอัปเดต/โรลแบ็กอิมเมจดิสก์ทั้งลูกในครั้งเดียวด้วย
mkosiและsystemd-sysupdateอยู่ด้วยปัญหาหลักคือคนส่วนใหญ่มักแจกมาแค่ไฟล์
docker-composeจึงต้องแปลงเป็น systemd unit และอิมเมจ Docker บางตัวก็มีความซับซ้อนเรื่องผู้ใช้/สิทธิ์ที่ไม่จำเป็นสำหรับ Podman โดยเฉพาะถ้าคอนเทนเนอร์ปฏิเสธการรันเป็น root หรือสลับไปใช้ผู้ใช้อื่น บางครั้งก็ต้องทำการแมป ID ของusernsที่น่ารำคาญแต่โดยรวมแล้วยังซับซ้อนน้อยกว่าการตั้งค่า k8s หรือสายพันธุ์ของ k8s แบบใด ๆ มาก และชอบที่มันผสานเข้ากับทั้ง systemd และ journald ไม่ต้องแยกเป็นสองที่
แค่วางยูนิตก็พอ เป็นวิธีที่เสถียรและเรียบง่ายมาก
composeเป็น ไฟล์ Quadlet สามารถใช้podletได้: https://github.com/containers/podletแต่มันไม่ได้แทนที่ abstraction ด้าน orchestration และ scheduling บนหลายโหนดที่ k8s มอบให้ ส่วนที่ขาดไปคือ “นี่คือเครื่องที่รันไฟล์ Podman-systemd ได้ และนี่คือสเปกที่อยากรัน ช่วยจัดวางให้เองที”
podman runลองสตาร์ตคอนเทนเนอร์ ดูว่ารันได้ถูกต้องหรือไม่ จากนั้นใช้podletสร้างไฟล์คอนเทนเนอร์พื้นฐาน แล้วแก้ไฟล์คอนเทนเนอร์โดยแยก volume และ network ออกเป็นไฟล์ Quadlet อื่น ๆ ก็จบโปรเจกต์
podman-composeก็ดูเหมือนยังดูแลอย่างต่อเนื่อง และอาจเป็นทางเลือกที่ดีแทนdocker-composeได้ แต่การผสาน Podman กับ systemd นั้นน่าพอใจมากจริง ๆขั้นต่อไปที่จะทำให้เรื่องนี้ง่ายขึ้นอีกคือการจัดการคอนเทนเนอร์ด้วย Quadlet ภายใน systemd รายละเอียดอยู่ที่ https://www.redhat.com/en/blog/quadlet-podman
docker composeไปเป็น rootless Podman Quadlet แม้การย้ายจะลำบาก แต่ก็พอใจกับผลลัพธ์มากผมสร้าง skate ขึ้นมา: https://github.com/skateco/skate โดยพื้นฐานก็เพื่อเป้าหมายแบบนี้ แต่รองรับหลายโฮสต์และรองรับ k8s manifest ด้วย ภายในใช้ Podman กับ systemd
แต่ผมมองว่า k8s มี API และประสบการณ์ผู้ใช้แย่มาก สเปก Docker Compose เป็นมิตรกับผู้ใช้กว่ามาก ตอนนี้จึงกำลังทดลอง
docker-composeสำหรับหลายโฮสต์อยู่: https://github.com/psviderski/uncloudกลับไปแพ็กเป็น deb package แล้วรันโดยตรงด้วย systemd บนอินสแตนซ์ EC2 อีกครั้ง และไม่ใช้คอนเทนเนอร์แล้ว อินสแตนซ์ถูกใส่ไว้ใน Auto Scaling Group ที่มี ALB ผูกอยู่ และตอนบูตจะมี
ansible-pullง่าย ๆ ติดตั้ง debเป็นวิธีค่อนข้างดิบ ๆ แต่เบื่อกับ HCL ที่อยู่ใน YAML ที่อยู่ใน JSON แบบไม่มีที่สิ้นสุดแล้ว ตอนนี้อยากยุ่งแค่กับ Ansible YAML ก็พอ
apt full-upgradeแล้วรีสตาร์ตเฉพาะโปรเซสที่กำลังรันอยู่ก็ได้รับการป้องกันแล้วไม่ต้องไป build อะไรใหม่ หรือหาวิธีอัปเดตไลบรารีที่ฝังลึกอยู่ในคอนเทนเนอร์ซึ่งอาจเป็นสิ่งที่เราสร้างเองหรือไม่ก็ได้
ด้วย การรองรับ cgroup ทำให้เหมาะกับการรันหลายบริการบน VPS เครื่องเดียวด้วย
บทความนี้เกิน 1 ปีแล้ว ตอนนี้ยังมี ParticleOS ซึ่งเป็นดิสทริบิวชัน OS อย่างเป็นทางการที่รองรับเวิร์กโฟลว์แบบ immutable สำหรับ systemd ด้วย
https://github.com/systemd/particleos
https://news.ycombinator.com/item?id=43649088
systemd-kernelแล้วก็สมบูรณ์อ่านดูแล้วเหมือนว่าทั้งหมดนี้น่าจะแทนได้ด้วยคำสั่ง
docker composeกับอะไรอย่าง Caddy ที่ช่วยรับใบรับรองให้อัตโนมัติถ้ามีแค่
compose.yamlโดยพื้นฐานแล้วก็จบด้วยบรรทัดเดียวคือdocker compose up -d --pull alwaysการตั้งค่า CI ก็แค่scp compose.yaml user@remote-host:~/แล้วตามด้วยssh user@remote-host 'docker compose up -d --pull always'ก็พอข้อดีคือเรียบง่ายและทำงานได้แม้บนเครื่องพัฒนา แน่นอนว่าถ้าเป้าหมายเสริมคืออยากลองทำอะไรสนุก ๆ และเรียนรู้ Quadlet, k8s, systemd ก็เป็นตัวเลือกที่ดีเช่นกัน
docker context create --docker 'host=ssh://user@remote-host' remote-hostครั้งเดียวก็พอจากนั้นใช้
docker -c remote-host compose -f compose.yaml up -d --pull alwaysได้เลย ไม่ต้องคัดลอกไฟล์ อีกอย่าง ถ้าตั้งค่าข้อมูลผู้ใช้ไว้ใน~/.ssh/configก็ไม่ต้องใส่user@ตอนเรียก SSH ทำให้ทีมคัดลอกเอกสารหรือคำสั่งไปใช้ได้สะดวกDOCKER_HOSTก็ได้ เพียงแต่ต้องระวังว่าในการ interpolation ของไฟล์composeจะใช้ ตัวแปรสภาพแวดล้อมในเครื่องโลคัลเพราะคิดว่าการ deploy ไปยังเซิร์ฟเวอร์เดี่ยวไม่ควรซับซ้อนขนาดนี้ เลยสร้างเครื่องมือสำหรับ deploy ตามแบบที่ต้องการขึ้นมา: https://harbormaster.readthedocs.io/
Harbormaster จะหา repository จากไฟล์ YAML, clone และอัปเดตเป็นระยะ แล้วรันไฟล์ Docker Compose ภายในนั้น สถานะทั้งหมดก็เก็บไว้ในไดเรกทอรีเดียว จึงสำรองข้อมูลได้ง่าย
ถ้าต้องการแค่เซิร์ฟเวอร์เดี่ยว นี่เป็นเครื่องมือ container orchestration ที่ง่ายและดีที่สุดเท่าที่เคยเห็นมา ชอบตรงที่การตั้งค่าทั้งหมดถูกประกาศไว้ใน repository, สถานะทั้งหมดอยู่ในไดเรกทอรีเดียว และทุกอย่างก็เป็นแค่ไฟล์ Compose
อ่านคอมเมนต์แถวนี้แล้วรู้สึกแก่ขึ้นมา สงสัยว่าตอนนี้ไม่มีใครใช้แค่ ssh กับ nginx กันแล้วหรือไง
ยัดทุกอย่างลงในเครื่องเดียว แล้วสำรองข้อมูลเครื่องนั้นแบบจริงจังก็จบแล้ว สำหรับการใช้งานที่บ้าน ไม่จำเป็นต้องจัดการไมโครเซอร์วิสถึงขนาดนั้นจริง ๆ