Vì sao đồng hồ VPS bị trôi và cách sửa
Đồng hồ VPS sai làm TOTP lỗi dù password đúng. Kiểm tra chronyc, timedatectl, tìm sync daemon xung đột hoặc UDP port 123 bị chặn để sửa.
Vì sao đồng hồ VPS bị trôi
Đồng hồ VPS bị trôi vì không có cơ chế nào hiệu chỉnh nó. Kernel tính thời gian từ một bộ đếm phần cứng chạy nhanh hơn hoặc chậm hơn một chút. Nếu không có time sync client đang chạy, sai số nhỏ đó sẽ tăng dần theo từng giờ. Trong máy ảo còn có một nguyên nhân khác: guest dùng chung CPU vật lý với các guest khác, nên trong thời gian không được scheduler cấp CPU, nó không thể tiếp tục đếm thời gian.
Trên guest KVM hiện nay, bản thân bộ đếm hiếm khi là nguyên nhân thực sự. Nguồn paravirtual kvm-clock đọc một giá trị do host duy trì, nên guest hoạt động bình thường sẽ bám sát clock của host. Đồng hồ bị sai rõ rệt thường do một nguyên nhân đơn giản hơn. Không có sync daemon nào đang chạy, hoặc có 2 daemon chạy đồng thời và xung đột với nhau, hoặc lưu lượng UDP outbound đến port 123 không bao giờ rời khỏi network của nhà cung cấp. Guest lấy cơ chế hiệu chỉnh thời gian từ host hoặc từ NTP (network time protocol), không phải từ oscillator của chính nó.
Những lỗi thực tế do clock sai
- Mã xác thực hai yếu tố TOTP (time-based one-time password) không còn khớp, khiến bạn bị khóa khỏi server dù password và key đều đúng.
- Certificate vừa được cấp một phút trước bị từ chối, và
curlin raSSL certificate problem: certificate is not yet valid. apt updatetừ chối repository vớiE: Release file for ... is not valid yet (invalid for another 1d 2h 3min 4s).- Công việc được lập lịch chạy sai thời điểm. Clock nhảy có thể khiến một job chạy hai lần trong khi job khác bị bỏ qua.
- Không thể căn chỉnh log từ hai server, nên phải dựng timeline của incident bằng cách phỏng đoán.
Khoảng dung nhỏ hơn nhiều so với suy nghĩ của hầu hết mọi người. Các con số dưới đây là default được tài liệu hóa, không phải số đo từ một bài test.
The data behind this chart
[
{
"label": "TLS certificate boundary",
"tolerance_seconds": 0,
"documented_in": "RFC 5280"
},
{
"label": "chrony steps instead of slewing",
"tolerance_seconds": 1,
"documented_in": "Debian and Ubuntu chrony.conf"
},
{
"label": "TOTP code, one time step",
"tolerance_seconds": 30,
"documented_in": "RFC 6238"
},
{
"label": "Kerberos clock skew",
"tolerance_seconds": 300,
"documented_in": "MIT krb5 default"
}
]TOTP được tính từ một counter tăng sau mỗi 30 giây, và hầu hết verifier chấp nhận lệch một step về mỗi phía. Sai lệch nửa phút theo mỗi hướng chính là toàn bộ khoảng cho phép. Kerberos dễ chịu hơn nhiều, với mức cho phép clock skew mặc định là 300 giây. Certificate hoàn toàn không có độ linh hoạt này: certificate được kiểm tra dựa trên các thời điểm cố định với grace period là 0 giây, nên clock chạy sớm một giây cũng khiến một certificate hoàn toàn hợp lệ bị từ chối.
Ba clock và clock nào quan trọng
System clock là clock quan trọng nhất. Đây là CLOCK_REALTIME của kernel: số giây tính từ 1 January 1970 UTC, được giữ trong memory và được mọi thành phần cần gắn timestamp đọc lại. Dòng log, kiểm tra certificate, mã TOTP và thời gian sửa file đều lấy dữ liệu từ clock này. Khi ai đó nói thời gian của server bị sai, họ đang nói đến clock này.
Hardware clock, còn gọi là RTC (real time clock), là một bộ đếm riêng vẫn chạy khi máy đã tắt. Trên máy vật lý, đây là một chip được cấp nguồn bằng pin. Bên trong guest, hypervisor mô phỏng nó, nên phần lớn đây là thông tin do host cung cấp. Linux đọc clock này một lần lúc boot để lấy giá trị ban đầu, sau đó tự duy trì bộ đếm riêng. timedatectl in clock này trên dòng RTC time. Không dùng dòng đó để debug trên VPS, vì nó cho biết nhận định về thời gian của host, không phải trạng thái đồng bộ của system clock trên hệ thống của bạn. Trong container thường không có /dev/rtc, nên hwclock --show thất bại với hwclock: Cannot access the Hardware Clock via any known method.
Clocksource là nguồn mà kernel dùng để đếm thời gian giữa những lần đọc đó. Kiểm tra clocksource mà kernel đã chọn:
cat /sys/devices/system/clocksource/clocksource0/current_clocksource
cat /sys/devices/system/clocksource/clocksource0/available_clocksourceTrên KVM, bạn thường sẽ thấy kvm-clock. Nó đọc một giá trị do host duy trì. Vì vậy, guest KVM không chạy NTP client vẫn thường giữ được thời gian tương đối chính xác trong một khoảng thời gian. tsc là bộ đếm riêng của CPU. Guest Xen báo cáo xen, còn guest Hyper-V báo cáo một clocksource hyperv. Không thay đổi thiết lập này nếu chưa có lý do được đo đạc rõ ràng, vì kernel đã tự chọn nguồn tốt nhất mà nó tin cậy trên phần cứng đó.
Một số host cũng cấp thiết bị PTP (precision time protocol) cho guest. Nhờ đó, chrony có thể đọc clock của host trực tiếp thay vì đọc qua network. Bạn nên kiểm tra, nhưng thiết bị này thường không có trên VPS dùng chung:
sudo modprobe ptp_kvm
ls /dev/ptp*
cat /sys/class/ptp/ptp0/clock_nameNếu modprobe thất bại hoặc không có device nào xuất hiện, host không cung cấp thiết bị này và network NTP là lựa chọn của bạn. Nếu clock_name chỉ clock ảo KVM, chrony có thể dùng nó với dòng refclock PHC /dev/ptp0 poll 2 trong file cấu hình.
Đọc trạng thái thời gian trên chính máy của bạn
Bắt đầu bằng một lệnh. Lệnh này trả lời câu hỏi “có thành phần nào đang giữ cho đồng hồ này chạy đúng không” trên một màn hình.
timedatectlHãy đọc các dòng này thay vì chỉ tin vào một con số bạn nhớ:
Local timevàUniversal timelà cùng một thời điểm, được hiển thị theo múi giờ của bạn và theo UTC. Nếu hai giá trị giống hệt nhau, máy đã dùng UTC.RTC timelà hardware clock được mô tả ở trên. Trên VPS, hãy bỏ qua giá trị này.Time zonelà giá trị system dùng để định dạng giờ địa phương.System clock synchronizedlà flag riêng của kernel. Time daemon đặt flag này sau khi tin cậy các nguồn thời gian, vì vậynocó nghĩa là chưa có thành phần nào đồng bộ clock này kể từ lúc boot.NTP servicebáo cáo riêng về systemd-timesyncd.n/alà trạng thái bình thường trên máy chạy chrony, vì timesyncd không được cài trên máy đó.System clock synchronized: yescùng vớiNTP service: n/acó nghĩa là chrony đang xử lý việc đồng bộ và kernel đồng ý với trạng thái này.
Tiếp theo, hãy kiểm tra clock của bạn lệch bao xa. Đừng ước lượng bằng cách so với điện thoại. Nếu chrony đang chạy:
chronyc tracking
chronyc sources -vchronyc tracking in ra các số liệu trả lời câu hỏi này. System time là offset hiện tại so với giờ NTP, theo sau là từ fast hoặc slow. Last offset là độ lớn của lần hiệu chỉnh gần nhất. Frequency là sai số tốc độ mà chrony đo được trên clock của bạn và đang bù trừ. Leap status phải có giá trị Normal. Nếu có giá trị Not synchronised và Reference ID là 00000000 (), chrony vẫn chưa chọn được source.
chronyc sources -v in ra phần chú giải phía trên danh sách, nên bạn không cần nhớ các ký hiệu. Hai cột chứa phần lớn thông tin. Ký tự trạng thái ở đầu mỗi dòng cho biết chrony đánh giá source đó như thế nào; * đánh dấu source đang được sử dụng, còn ? trên mọi dòng có nghĩa là không source nào phản hồi. Reach là lịch sử phản hồi của 8 lần poll gần nhất, được in ở dạng bát phân: 377 có nghĩa là cả 8 lần đều được phản hồi, còn 0 có nghĩa là không lần nào được phản hồi.
Nếu systemd-timesyncd đang phụ trách:
timedatectl timesync-status
timedatectl show-timesync --alltimesync-status in ra server mà máy đang kết nối, khoảng thời gian poll và giá trị Offset. Nếu lệnh trả về lỗi về service thay vì in trạng thái, timesyncd không phải daemon đang phụ trách trên máy này. Đây cũng chính là câu trả lời cho câu hỏi của bạn.
Để kiểm tra sơ bộ với thế giới bên ngoài mà không cần thêm tool, hãy so sánh clock của bạn với header HTTP công khai Date. Header này được gửi theo GMT và có độ phân giải 1 giây:
date -u
curl -sI https://www.cloudflare.com | grep -i '^date:'Chênh lệch 1 hoặc 2 giây ở đây là bình thường và không có ý nghĩa. Chênh lệch 1 phút là lỗi của bạn.
chrony hay systemd-timesyncd trên VPS
Ubuntu và Debian mặc định cài systemd-timesyncd. Đây là client SNTP (simple network time protocol): nó lần lượt truy vấn từng server rồi điều chỉnh clock về phía thời gian của server đó. Với máy luôn online và có thời gian ban đầu tương đối chính xác, như vậy là đủ và gần như không tốn tài nguyên.
chrony là một triển khai NTP đầy đủ và là lựa chọn mặc định tốt hơn trên máy ảo, vì những lý do có thể thấy ngay trong output của nó. Nó polling đồng thời nhiều source và loại bỏ những source có thời gian lệch với các source khác. Nó đo sai số tốc độ của clock rồi ghi kết quả vào drift file, nên có thể sửa xu hướng lệch của clock thay vì chạy theo từng sample. Nó cũng khôi phục nhanh sau 2 tình huống mà VM có thể gặp nhưng máy vật lý thường không gặp: host có thể pause VM, và VM có thể được chuyển sang host khác khi đang chạy. Nếu host cung cấp thiết bị PTP, chrony sẽ đọc thiết bị đó.
sudo apt update && sudo apt install -y chrony
systemctl status chrony --no-pager
chronyc sources -v
chronyc trackingTheo dõi output của apt trong lúc lệnh chạy. Trên Debian và Ubuntu, cả package chrony và systemd-timesyncd đều cung cấp time-daemon, nên apt sẽ gỡ timesyncd khi cài chrony. Đây là hành vi đúng và cần thiết. Không bao giờ chạy cả hai, vì 2 daemon cùng thiết lập một clock sẽ xung đột, và trong thời gian đó không thể tin vào offset mà daemon nào báo cáo. Trên Rocky và AlmaLinux, cài bằng sudo dnf install -y chrony; unit ở đây có tên chronyd thay vì chrony.
File cấu hình là /etc/chrony/chrony.conf trên Debian và Ubuntu, còn trên Rocky và Alma là /etc/chrony.conf. Cấu hình mặc định của distribution đã phù hợp cho VPS, nên chỉ thay đổi khi có lý do cụ thể. Có 2 directive cần hiểu:
- Các dòng
poolvàserverchỉ định time source. Thêmiburstsẽ yêu cầu chrony gửi một burst nhanh lúc khởi động, nhờ đó lần sync đầu tiên hoàn tất trong vài giây thay vì vài phút. makestepquyết định khi nào chrony sẽ jump clock thay vì điều chỉnh dần. Kiểm tra giá trị hiện tại bằnggrep -n makestep /etc/chrony/chrony.conf. Giá trị mặc định trên Debian và Ubuntu làmakestep 1 3, có nghĩa như sau: trong 3 lần update đầu tiên sau khi chronyd khởi động, clock sẽ được step nếu lệch hơn 1 giây; sau đó chỉ được sửa bằng cách slew.
Nếu muốn xác thực time traffic để chống sửa đổi trên đường truyền, chrony 4 trở lên hỗ trợ NTS (network time security). Trước tiên hãy xác nhận version bằng chronyd -v. Lưu ý rằng NTS cần mở outbound TCP port 4460 cùng với UDP 123:
server time.cloudflare.com iburst ntsHãy restart và verify trước khi tin tưởng cấu hình. Nếu cấu hình không parse được, bạn sẽ không còn time daemon nào chạy, nhưng clock sẽ không tự báo cho bạn biết điều đó.
sudo systemctl restart chrony
chronyc sources -v
chronyc trackingVì sao đồng hồ lệch vài phút vẫn tiếp tục lệch
Một time daemon có 2 cách sửa độ lệch. Slew sẽ tăng hoặc giảm tốc độ đồng hồ cho đến khi hết sai số. Cách này giữ cho thời gian luôn tiến về phía trước và không lặp lại hoặc bỏ qua timestamp nào. Step sẽ nhảy thẳng đến giá trị đúng. Cách này nhanh nhưng có thể làm đồng hồ chạy lùi. Chạy lùi rất nguy hiểm đối với mọi thành phần đo thời gian đã trôi qua dựa trên wall clock. Vì vậy, cả 2 daemon đều ưu tiên slew.
Đó là lý do đồng hồ lệch nhiều có thể tiếp tục lệch trong thời gian dài. chrony chỉ step trong khoảng thời gian mà makestep cho phép. Mặc định, khoảng này chỉ áp dụng cho vài lần update đầu tiên sau khi daemon khởi động. Nếu chronyd đã chạy được 1 tuần rồi mới phát hiện đồng hồ lệch 40 giây, nó sẽ slew độ lệch đó. Việc slew 40 giây mất lâu hơn nhiều so với thời gian bạn muốn chờ. Hãy cố ý force sửa một lần vào lúc hệ thống ít hoạt động:
sudo chronyc makestep
chronyc trackingchronyc tracking lúc này sẽ báo một offset System time gần bằng 0, còn Last offset sẽ hiển thị mức độ lệch vừa được sửa. Hãy cân nhắc trước khi chạy lệnh này trên database host đang bận, vì đồng hồ chạy lùi có thể làm rối các phần mềm giả định thời gian chỉ tiến về phía trước. Restart daemon là cách nhẹ nhàng hơn để thực hiện cùng việc sửa này, vì cửa sổ makestep sẽ mở lại khi daemon khởi động.
Container dùng chung clock của host
Container không có wall clock riêng, nên không có gì để đồng bộ bên trong container. Linux time namespace chỉ ảo hóa monotonic clock và boot-time clock. CLOCK_REALTIME không được ảo hóa, nghĩa là container đọc cùng system clock với host đang chạy nó. Sửa clock trên host thì mọi container trên host đó cũng được sửa tại cùng thời điểm.
Điều này dẫn đến một số hệ quả. Không cài chrony hoặc ntpd vào image, vì trong trường hợp tốt nhất chúng cũng không làm gì. Đặt ngày giờ bên trong một container không có đặc quyền sẽ thất bại với date: cannot set date: Operation not permitted, vì kernel yêu cầu CAP_SYS_TIME cho system call đó. Cấp CAP_SYS_TIME không tạo clock riêng cho container. Quyền này cho phép container thay đổi clock của host, và do đó thay đổi clock của mọi container khác.
Múi giờ khác bên trong container không phải là vấn đề về clock. Một image có /etc/localtime riêng sẽ hiển thị cùng một thời điểm nhưng được format theo múi giờ khác, nên date có vẻ sai trong khi clock vẫn đúng. Đặt TZ=UTC trong environment của container để loại bỏ nhầm lẫn này. Runtime bạn chọn không thay đổi điều gì ở đây, còn bài so sánh Podman và Docker rootless giải thích những điểm mà nó thực sự thay đổi.
Múi giờ: UTC trên server, giờ địa phương cho người dùng
Đặt máy về UTC và giữ nguyên như vậy.
timedatectl list-timezones | grep -i utc
sudo timedatectl set-timezone UTC
timedatectlUTC không có giờ mùa hè. Đây là lý do chính. Một job chạy hằng ngày lúc 02:30 trong múi giờ có áp dụng giờ mùa hè sẽ chạy 2 lần vào ngày đồng hồ lùi lại, và không chạy lần nào vào ngày đồng hồ tiến lên. man 8 cron mô tả cách xử lý đặc biệt đối với các thay đổi dưới 3 giờ: job bị bỏ qua do đồng hồ tiến lên sẽ chạy ngay sau khi thay đổi, còn job rơi vào giờ bị lặp do đồng hồ lùi lại sẽ không chạy lần 2. Cách xử lý này hợp lý, nhưng bạn không nên phải suy luận về nó lúc 03:00. Với UTC, job chạy 1 lần mỗi ngày, mọi ngày trong năm. Nếu job của bạn hoàn toàn không chạy thay vì chạy vào một giờ bất thường, các nguyên nhân khiến cron job âm thầm không chạy có khả năng là nguyên nhân đúng hơn.
Lập luận tương tự cũng áp dụng khi đọc log. journalctl định dạng timestamp theo múi giờ của system, còn journalctl --utc buộc dùng UTC. 2 server ở 2 múi giờ khác nhau sẽ biến mọi sự cố thành bài toán quy đổi thời gian. Khi xử lý sự cố dưới áp lực, việc quy đổi này dễ khiến bạn đọc sai timeline. Giữ system dùng UTC, lưu timestamp theo UTC, rồi chỉ quy đổi tại nơi con người đọc chúng. Nếu cần xem giờ địa phương cho 1 command, bạn có thể yêu cầu mà không cần đổi múi giờ của máy:
TZ=Europe/Berlin dateMột dòng khác trong output của timedatectl cũng thuộc phần này. RTC in local TZ phải có giá trị no. Đặt giá trị này thành yes là cách xử lý tạm thời cho trường hợp dual-boot Windows trên laptop. Trên server, nó chỉ thêm một độ lệch thời gian để người khác vấp phải về sau. Khi được đặt như vậy, timedatectl sẽ in cảnh báo rằng system được cấu hình để đọc thời gian RTC theo múi giờ địa phương.
Khắc phục sự cố theo triệu chứng
Mã two-factor bị từ chối trên một server. Kiểm tra clock trước mọi thứ khác. Mã được tạo từ một counter tăng mỗi 30 giây, nên server chậm 90 giây sẽ tính mã thuộc một bước mà phone của bạn đã vượt qua. timedatectl sẽ hiển thị System clock synchronized: no, hoặc chronyc tracking sẽ báo offset System time lớn. Đây là lỗi khác với trường hợp key bị từ chối hoàn toàn, vốn in ra thông báo riêng và được đề cập trong hướng dẫn về lỗi xác thực publickey.
apt update báo một Release file chưa hợp lệ. Thông báo đầy đủ cho biết repository và thời gian file còn không hợp lệ, ví dụ is not valid yet (invalid for another 1d 2h 3min 4s). Clock của bạn chậm hơn thời điểm trong Release file của repository, và khoảng thời gian đó đo trực tiếp độ chậm. Hãy sửa clock. Không tắt kiểm tra ngày của apt để bỏ qua lỗi này, vì chính kiểm tra đó ngăn người khác cung cấp cho bạn một package index đã cũ.
Mọi source line đều hiển thị trạng thái unreachable và Reach bằng 0. Không có gì phản hồi, vì vậy hãy kiểm tra egress thay vì kiểm tra config. NTP dùng UDP port 123 cho lưu lượng outbound, và một số network filter hoặc redirect lưu lượng này. sudo chronyc ntpdata in ra các counter theo từng source, bao gồm Total TX và Total RX. Nếu TX count tăng trong khi RX vẫn bằng 0, nghĩa là packet rời khỏi máy bạn nhưng không có packet quay lại. Điều này cho thấy có firewall nằm giữa bạn và source.
Clock đúng rồi sau đó nhảy giờ. Các sự kiện trên host có thể gây ra việc này. Snapshot được restore, guest bị pause hoặc live migration sang host khác có thể khiến thời gian mà guest nhận biết chậm hơn thời gian thực. chrony phát hiện ở lần poll tiếp theo và hiệu chỉnh; systemd-timesyncd có thể chờ hết một poll interval dài trước. Xác nhận daemon khởi động lúc boot bằng systemctl is-enabled chrony, vì daemon khởi động thủ công sẽ dừng sau lần reboot tiếp theo.
Offset nhỏ nhưng không bao giờ ổn định. Kiểm tra CPU steal. Guest không được schedule đúng lúc timer interrupt đến hạn sẽ nhận sample trễ, nên offset dao động thay vì hội tụ. top hiển thị việc này dưới dạng chỉ số st trên dòng CPU. Cách đọc CPU steal time trên shared host giải thích ý nghĩa của con số này và các biện pháp xử lý.
Certificate vừa cấp bị từ chối vì chưa có hiệu lực. curl in ra SSL certificate problem: certificate is not yet valid, và browser cũng báo lỗi tương tự. Certificate không có vấn đề; clock dùng để kiểm tra certificate đang bị chậm. Máy client hoặc server đều có thể là nguyên nhân, nên hãy kiểm tra cả hai. Nếu server cấp certificate là máy có clock sai, hướng dẫn certificate certbot và nginx trình bày phần renewal trong cùng mô hình này.
Đưa vào các bước kiểm tra bạn đã thực hiện
Đồng bộ thời gian là một thiết lập lúc boot có thể âm thầm lỗi sau nhiều tháng. Đây chính xác là loại vấn đề mà một quy trình định kỳ sẽ phát hiện, còn trí nhớ thì không. timedatectl và chronyc tracking chỉ mất 2 giây để đọc cùng nhau. Hãy chạy chúng trong 10 phút đầu tiên khi thiết lập một VPS mới, rồi chạy lại khi bạn thực hiện checklist bảo trì Linux server định kỳ. Nếu muốn tự động chạy check và cảnh báo khi offset tăng, viết một systemd service và timer trình bày mẫu cho một unit nhỏ báo cáo theo lịch. Một check như vậy là script ngắn thay vì daemon, nên cần Type=oneshot thay cho giá trị mặc định. Phần tổng quan về các loại systemd service giải thích vì sao chọn sai loại sẽ khiến unit báo thành công dù thực tế chưa đạt.
FAQ
Làm thế nào để kiểm tra đồng hồ trên VPS có được đồng bộ không?
Chạy timedatectl và đọc dòng System clock synchronized. Đây là flag của chính kernel, được daemon đang điều chỉnh đồng hồ thiết lập. Vì vậy, yes cùng với NTP service: n/a là trạng thái bình thường và tốt trên máy chạy chrony. Để biết độ lớn của sai số, chạy chronyc tracking và đọc System time. Nếu systemd-timesyncd đang quản lý đồng hồ, chạy timedatectl timesync-status và đọc Offset. Để kiểm tra với một nguồn bên ngoài máy, so sánh date -u với header Date do bất kỳ website HTTPS nào trả về.
Nên dùng chrony hay systemd-timesyncd trên VPS?
Hãy dùng chrony cho mọi máy quan trọng. systemd-timesyncd là một SNTP client theo dõi một server. Nó phù hợp với máy luôn trực tuyến và có thời gian ban đầu gần chính xác. chrony thăm dò nhiều nguồn, loại bỏ các nguồn có thời gian chênh lệch, học tốc độ sai lệch của đồng hồ và khôi phục nhanh sau khi host tạm dừng hoặc live migration. Cài chrony trên Debian hoặc Ubuntu sẽ tự động gỡ systemd-timesyncd, vì cả hai package đều cung cấp time-daemon. Không bao giờ chạy đồng thời hai time daemon.
Tại sao mã TOTP thất bại trên một server nhưng hoạt động ở mọi nơi khác?
Vì mã TOTP là một hàm của thời gian hiện tại. Mã được tạo từ một counter tăng mỗi 30 giây. Vì vậy, server và điện thoại của bạn phải thống nhất đang ở step nào. Hầu hết verifier chấp nhận lệch một step ở mỗi phía, nên có khoảng đệm khoảng nửa phút theo mỗi hướng. Kiểm tra timedatectl trên server đó. Nếu System clock synchronized có giá trị no, hãy sửa việc đồng bộ. Sau đó mã sẽ khớp lại mà không cần thay đổi shared secret.
Có thể đặt thời gian bên trong Docker container không?
Không, và bạn cũng không cần làm vậy. Container dùng chung CLOCK_REALTIME của host, vì Linux time namespace chỉ virtualise clock đơn điệu và clock tính từ thời điểm boot. Container không có quyền đặc biệt sẽ nhận date: cannot set date: Operation not permitted. Thêm CAP_SYS_TIME cho phép container thay đổi clock của host, thay vì cấp cho nó một clock riêng. Hãy đồng bộ host. Thời gian địa phương khác bên trong container thực chất là thiết lập múi giờ, vì vậy hãy đặt TZ trong môi trường của container.
Server nên dùng UTC hay giờ địa phương?
UTC, và chỉ áp dụng giờ địa phương tại nơi người dùng đọc output. UTC không thay đổi theo giờ mùa hè, nên một job hằng ngày chạy một lần mỗi ngày quanh năm. Timestamp từ các server khác nhau cũng khớp nhau mà không cần chuyển đổi. Đặt UTC bằng sudo timedatectl set-timezone UTC. Nếu muốn đọc theo giờ địa phương, có thể thêm tiền tố vào một lệnh đơn, chẳng hạn TZ=America/New_York date. Cách này không thay đổi system clock.