Dành cho ai
Bạn đưa một binary Go lên một server và chạy nó dưới systemd. Hiện giờ deploy là scp, systemctl restart, rồi liếc qua log. Cách đó ổn cho tới khi một lần restart rơi vào đúng phút đông khách và Caddy trả 502 trong vài giây, hoặc khi bạn đẩy lên một bản build khởi động bình thường nhưng request nào cũng lỗi, và không có gì ngăn nó nhận traffic.
Bộ kit này thay cách đó bằng một script deploy: chạy release mới cạnh bản cũ, kiểm tra nó trước khi nó nhận traffic, chuyển sang, và tự lùi lại nếu release mới hỏng. Đây là bản cho Go và systemd của bộ kit Node và pm2 mà chúng tôi đã bán, dành cho người không dùng pm2 và không muốn dùng.
Trong bộ này có gì
deploy.sh: thư mục release với symlinkcurrentđổi nguyên tử, deploy binary bạn build trong CI hoặc build ngay trên server, health check (N lần trả lời liên tiếp), chuyển traffic, drain, tự rollback,deploy.sh rollback, và một cái lock để hai lần deploy không chồng lên nhau.- Các systemd unit đã siết bảo mật:
Type=notify, stop êm, chính sách restart, user không đặc quyền, secret nằm trong file environment quyền 600 mà user của service không đọc được. - Một script cài đặt dựng sẵn user, thư mục, unit và file environment.
- Một app Go mẫu nhỏ (chỉ dùng thư viện chuẩn) có graceful shutdown, kèm một helper đã test cho socket activation và
sd_notify. - Cảnh báo qua Telegram hoặc webhook khi deploy lỗi. Deploy thành công thì không báo gì.
- Một bộ test harness và kết quả của lần chạy gần nhất.
Hai cách chuyển traffic
Blue/green (mặc định). Hai instance, app@a và app@b, đứng sau Caddy. Release mới khởi động trên port đang rảnh và phải trả lời health check nhiều lần liên tiếp thì Caddy mới được báo. Sau đó Caddy reload êm, instance cũ drain rồi dừng. Nếu release mới hỏng sau khi đã chuyển, script đặt mọi thứ về như cũ. Rollback là cùng thao tác đó chạy ngược, và với KEEP_PREVIOUS=1 thì instance cũ vẫn chạy sẵn nên rollback chỉ là đổi Caddy.
Socket activation. systemd giữ socket đang lắng nghe trong lúc service restart, nên kết nối được xếp hàng chứ không bị từ chối. Release mới trước hết chạy thử như một canary trên port khác, nên bản build hỏng không bao giờ tới được bước restart.
Blue/green là mặc định vì nó giữ request chậm nhất ở gần độ dài của chính request đó. Chế độ socket dành cho những trường hợp bạn không chạy được hai instance: một port cố định không đổi được, hoặc một tài nguyên mà chỉ một process được giữ. Các số đo bên dưới có cả hai chế độ.
Số đo
Cách đo: container Debian 12 với systemd 252 làm PID 1, Caddy 2.6.2, một app mẫu cần 1.5 s để khởi động, tải đều 20 request mỗi giây qua Caddy, mỗi kịch bản chạy ba lần. Request bị tính là lỗi nếu gặp bất kỳ lỗi kết nối, timeout hay status nào khác 200.
| Kịch bản | Đã gửi | Lỗi |
|---|---|---|
systemctl restart thường, một instance | 152 đến 162 | 33 đến 42 (toàn HTTP 502) |
Như trên, thêm lb_try_duration 5s của Caddy | 162 | 0, nhưng request chậm nhất mất 2.3 s |
| Blue/green, deploy tốt | 293 đến 295 | 0 |
Blue/green, release có /health trả 500 | 458 đến 460 | 0 |
| Blue/green, release chết ngay khi khởi động | 132 | 0 |
| Blue/green, release hỏng sau khi đã chuyển | 381 đến 383 | 0 (bản lỗi đã trả lời 182 hoặc 183 request trước khi rollback) |
| Blue/green, rollback | 293 đến 295 | 0 |
Blue/green, rollback với KEEP_PREVIOUS=1 | 222 đến 223 | 0, traffic chuyển sau 0.1 s |
| Blue/green, deploy tốt khi có request 2 s đang xử lý | 234 | 0, các request chậm vẫn xong, không bị cắt |
| Chế độ socket, deploy tốt | 268 đến 269 | 0 |
| Chế độ socket, deploy tốt khi có request 2 s đang xử lý | 307 đến 310 | 0, request chậm nhất 5.65 s |
Một lần deploy ở chế độ blue/green mất 8 đến 9 giây, và traffic sang release mới sau khoảng 3.6 giây. Đó là số đo cho app này trên máy này.
Một lần deploy diễn ra thế nào
README đi qua bảy bước. Tóm lại: lấy lock, tạo thư mục release, khởi động instance đang rảnh và chờ nó báo sẵn sàng, health check trực tiếp, ghi upstream mới và reload Caddy, đổi symlink, chờ, kiểm tra lại, và chỉ lúc đó mới dừng instance cũ. Mỗi bước đều có đường xử lý khi lỗi, và những đường quan trọng đã được test: release không khỏe, chết ngay khi khởi động, và release hỏng sau khi đã chuyển.
Yêu cầu
Linux có systemd, Caddy, curl và flock. Go và git chỉ cần nếu bạn build ngay trên server. Một service trên một host.
Câu hỏi hay gặp
Tôi dùng Node và pm2. Bộ này có hợp không?
Không, hãy xem VPS Deploy & Backup Kit. Bộ đó làm cùng việc này cho stack kia.
Có bắt buộc dùng Caddy không?
Blue/green cần Caddy để chuyển traffic. Cả hai chế độ đều được đo với Caddy đứng phía trước.
Chạy trên Ubuntu được không?
Ubuntu cũng dùng systemd, mà bộ này chỉ cần systemd và Caddy nên dùng được. Chúng tôi đã test trên Debian 12.
Lần deploy thứ hai thì sao khi một lần đang chạy?
Nó thoát ngay với code 75 và không gửi cảnh báo. Đó là việc của cái lock.
Giấy phép
Dùng trên server của bạn. Xin đừng bán lại các file.
Lịch sử thay đổi
- 0.1.0: bản đầu tiên.
Bài liên quan
- What a plain systemctl restart costs a Go service under load (tiếng Anh)
- systemd socket activation: no dropped requests, but a cost (tiếng Anh)
- Roll back a bad deploy in a minute with release folders (tiếng Anh)
- Database migrations that survive a zero-downtime deploy (tiếng Anh)
- Deploy health checks that catch bad releases (tiếng Anh)
- Caddy blue/green config for a one-server app, line by line (tiếng Anh)
Mua sản phẩm này
Polar lo thanh toán, thuế và hóa đơn (họ là merchant of record). Thanh toán xong bạn nhận link tải ngay.