The Consul outage that never happened

Bài tóm tắt GitLab 2019 2. Tăng trưởng Độ khó: Trung bình

GitLab · 2019 · 2. Tăng trưởng · Độ khó: Trung bình — bài gốc

Bối cảnh

  • GitLab.com (2019): khoảng 4 triệu user, 12 triệu project, 271 server production, đội Infrastructure 20–24 kỹ sư rải khắp thế giới. Đang dần chuyển sang Consul cho service discovery; thành phần chính dựa vào Consul là database và hệ HA Patroni. Mọi kết nối Consul dùng TLS hai chiều.
  • Một DB staging restart xong không nối lại được Consul: cert TLS đã hết hạn. Cert là cert tự ký từ bản proof-of-concept một năm trước, CA key đã mất, chưa từng qua production readiness review hay được giám sát (lúc đó đội production chỉ 4 người, 3 người mới đang onboard).

Thay đổi chính (diễn biến)

  • Sự cố đã bắt đầu nhưng chưa sập: site còn sống chỉ vì kết nối đã mở trước khi cert hết hạn; bất kỳ kết nối nào bị ngắt sẽ phải xác thực lại và bị từ chối. Tắt kiểm tra ở một phía không giúp vì cả hai phía đều kiểm: server đã tắt kiểm thì bị các peer còn kiểm cô lập.
  • Ràng buộc: mọi phương án (CA mới, dùng CA chuẩn, tắt kiểm ngày hết hạn) đều cần đổi cấu hình rồi restart 255/271 server cùng một lúc; công cụ sẵn có (Chef, knife ssh, ansible) được thiết kế cho rollout dần. Consul phiên bản đó không reload được thiết lập cert.
  • Chọn tắt kiểm tra ngày hết hạn: thay đổi nhỏ nhất, gỡ rủi ro ngay, để làm giải pháp đúng sau.
  • Không bàn giao cho ca châu Âu; thay vào đó viết kế hoạch "break glass" (một MR có đủ thay đổi và hướng dẫn) để nếu sập thật trước khi người đang xử lý thức dậy thì ca sau dựng lại được, chấp nhận downtime.
  • Cơ chế đồng loạt: đẩy trước lệnh echo 'sudo systemctl restart consul.service' | at 02:20 tới mọi máy bằng mussh (20 máy một lượt), kiểm trên staging rằng at có $PATH và sudo không hỏi mật khẩu. Đổi file cấu hình trước (không có hiệu lực tới khi restart) và tắt Chef client để nó không ghi đè. Diễn tập ở môi trường disaster recovery vì staging đã restart hết, không còn kết nối cũ để thử.
  • Phát hiện phụ trong lúc chuẩn bị: một server Consul "treo" hoá ra do sshguard chặn bastion khi quá nhiều người SSH cùng lúc; một node pgbouncer dự phòng đang không khoẻ, mà khi mọi health check cùng lỗi thì GCP load balancer gửi traffic tới mọi node (fail-open) và có thể làm ngập DB, nên rút node đó khỏi pool; vài node Chef client tự bật lại vì đang giữa một lần chạy; kiểm lag replica bằng 0, múi giờ và đồng bộ giờ trên mọi máy.
  • Thực thi: tạm dừng Patroni (đóng băng failover), đổi config, kiểm, rút pgbouncer, đặt lịch at. Lúc 02:20 UTC mọi Consul cùng restart; giây thứ 8 có leader; đồ thị lỗi 500 của khách không đổi. DB nối lại Consul chậm hơn khoảng một phút. Sau đó bật lại HA, bật lại Chef với recipe đã pin, sửa health check pgbouncer bỏ cuộc sau vài lần retry.

Vì sao

  • Cert proof-of-concept vào production mà không ai ghi nhận; hệ bảo mật hai chiều làm cho mọi bản sửa đều phải đồng thời.

Bài học cho SWE

  • Theo GitLab: không có runbook cho tình huống "hàng trăm node phải đổi một thiết lập và kết nối lại trong vài giây"; không có lối tắt nào thay cho suy nghĩ có phương pháp và hiểu hệ chạy thế nào. Một mẹo sysadmin cũ (at) giải được thứ công cụ fleet không làm được.
  • Cert và CA key là hạ tầng: cần chủ, giám sát hạn, và lưu khoá. Thứ dựng cho thử nghiệm sẽ sống tới production nếu không có review.
  • Kết nối lâu dài có thể che một sự cố đang diễn ra; kiểm bằng cách thử ngắt kết nối trong môi trường an toàn.
  • Liệt kê và đóng băng mọi tác nhân tự động có thể chen vào (Chef, failover tự động, load balancer fail-open, công cụ chặn SSH) trước một thao tác đồng loạt.

Liên quan