«Clock skew detected» — одна з тих помилок, що здається, ніби комп’ютер засуджує вас за віру в об’єктивність часу. Ваша збірка працює 12 хвилин, а потім падає, бо один файл ніби з майбутнього. Пайплайн деплою відмовляється підписувати артефакт, бо TLS вважає, що сертифікат ще не діє. А канал інцидентів перетворюється на філософський семінар.
На Ubuntu 24.04 це можна надійно виправити — якщо ставитись до синхронізації часу як до залежності продакшну, а не фонової опції. Ось практичний план: як довести, звідки береться ск’ю, як його зупинити і як утримати синхронізацію на bare metal, VM, контейнерах і CI-ранерах.
Що насправді означає «clock skew detected» (і чому це ламає збірки)
Повідомлення зазвичай походить від make (або інструментів з аналогічною поведінкою), коли часи модифікації файлів виглядають неконсистентно. Класичний приклад: згенерований файл має мітку часу пізнішу за поточний системний час, або файл-залежність виглядає новішим за своїх залежників у неможливий спосіб. Система збірки припускає, що ваш годинник неправильний, бо покладається на впорядкування mtime, щоб вирішувати, що потрібно перебудувати.
Але «clock skew detected» рідко лише про make. Це симптом того, що час більше не монотонний і його не можна довіряти на цій машині. Коли це відбувається, виникає каскад:
- CI-збірки нескінченно перебудовуються або падають, бо мітки часу раптово перемикаються назад або вперед під час виконання.
- TLS і підписані артефакти не проходять перевірку, коли система вважає, що сертифікати ще не дійсні або вже прострочені.
- APT і репозиторії пакетів скаржаться «Release file is not valid yet», коли клієнт випереджає часові мітки метаданих репо.
- Розподілені системи стають дивними. Не завжди зламані, але дивні: помилки в порядку логів, проблеми з токенами, фліппінг виборів лідера, незгідні аудити.
На Linux час має два важливі виміри:
- Годинник реального часу (CLOCK_REALTIME): те, що бачать люди, що використовують мітки часу і перевірки TLS.
- Монотонний годинник (CLOCK_MONOTONIC): завжди рухається вперед, використовується для таймаутів і вимірювання тривалостей.
Більшість проблем синхронізації — це проблеми годинника реального часу. Але корені часто лежать нижче в ОС: прошивка, гіпервізор, стани живлення CPU, вибір clocksource або хост, що просто не може дістатися до NTP-серверів.
Надійна ментальна модель: якщо ваше середовище не в змозі тримати час, воно не в змозі виконувати домовленості. Збірки, деплои та механізми безпеки припускають, що часові мітки значущі.
Парафразована ідея (приписують): Gene Kranz відстоював «жорсткість і компетентність» — опс працює, коли фундаментальні речі тримаються міцно під тиском. Синхронізація часу — це фундамент.
Жарт №1: Єдине гірше за clock skew — це clock skew у хронології постмортему. Раптом усі невинні, бо «логи брешуть».
Швидкий план діагностики
Якщо ви посеред падаючого деплою, у вас немає часу на лекцію з NTP. Ось порядок перевірок, який найшвидше знаходить вузьке місце на Ubuntu 24.04.
По-перше: підтвердіть ск’ю і чи він триває зараз
- Перевірте поточний час, часовий пояс і стан синхронізації (одна команда дає більшість потрібних даних).
- Перевірте, чи час «стрибає» (великий крок) чи «дрейфує» (повільне накопичення помилки).
По-друге: визначте, хто відповідає за синхронізацію часу
- Це
systemd-timesyncdчиchronyd(chrony)? - Ви в середині VM/контейнера з особливими правилами часу?
По-третє: перевірте досяжність і вибір джерел часу
- Чи доступний вам UDP/123 до налаштованих серверів?
- Чи синхронізуєтесь ви з хорошим сервером (низький stratum, адекватний офсет, стабільний)?
По-четверте: перевірте платформу: VM, гіпервізор, clocksource, suspend/resume
- Якщо VM дрейфує, часто це означає, що хост у порядку, але інтеграція гостьової ОС налаштована неправильно.
- Великі стрибки часто корелюють з відновленням із сніпшоту, виходом зі сну або якщо хост настільки навантажений, що пропускає тікання годинника.
По-п’яте: зменште вплив на продуктивність
- Виправте час, потім інвалідовуйте пошкоджені артефакти (вихідні файли збірки можуть бути отруєні неправильними mtime).
- Перезапустіть лише те, що потрібно перезапустити (демон синхронізації часу, а не весь флот, якщо вам не до вподоби хаос).
Факти та історичний контекст, які справді допомагають
- NTP старий і перевірений. Network Time Protocol походить із 1980-х і залишається основою синхронізації часу в інтернеті.
- Кроки високосної секунди — це реальна операційна подія. Вони спричиняли аутіджі, коли системи обробляли їх по-різному (step vs smear vs ignore).
- Linux має не просто «годинник». У нього кілька годинників і кілька джерел годинника (TSC, HPET, ACPI PM timer), і поганий вибір може проявитися як дрейф.
- Віртуалізація змінила механіку часу. Гості можуть відставати, якщо хост перевантажений, призупинений, відновлений зі сніпшоту або мігрував.
- Chrony створений для ворожого середовища. Він популярний у дата-центрах, бо краще справляється з переривчастим з’єднанням і великими початковими зсувами, ніж класичний ntpd у багатьох налаштуваннях.
- Systemd-timesyncd мінімалістичний. Він синхронізує час, але не позиціонує себе як повний набір NTP-інструментів; цього достатньо, доки вам не потрібна діагностика й контроль.
- Системи збірки покладаються на mtime, бо це швидко. Але це крихке в мережевих файлових системах, при відновленні з сніпшотів і при ск’ю годинника.
- TLS — це машина часу з правилами. Вікна дійсності сертифікатів суворі; якщо ваш годинник неправильний, безпека вас зупинить (це правильно).
- Монотонний час врятував багато софту. Багато багів із таймаутами зникли, як тільки програми перестали використовувати wall clock для тривалостей — можливо, ваші інструменти збірки ще не отримали цю інструкцію.
Практичні завдання: команди, виходи, рішення (12+)
Ось команди, які я запускаю на Ubuntu 24.04, коли пейджер каже «clock skew», а CI-пайплайн вогненний. Кожне завдання містить: команду, що означає вивід і яке рішення прийняти.
Завдання 1 — Перевірити системний час, стан синхронізації й який сервіс керує
cr0x@server:~$ timedatectl
Local time: Mon 2025-12-30 09:41:12 UTC
Universal time: Mon 2025-12-30 09:41:12 UTC
RTC time: Mon 2025-12-30 09:40:02
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: no
NTP service: active
RTC in local TZ: no
Значення: System clock synchronized: no — це червоний прапор. RTC відрізняється приблизно на ~70 секунд — теж підозріло.
Рішення: Підтвердьте, чим саме є «NTP service» (chrony чи systemd-timesyncd) і чому синхронізація не досягнута.
Завдання 2 — Визначити активні демони синхронізації часу
cr0x@server:~$ systemctl status chrony systemd-timesyncd --no-pager
● chrony.service - chrony, an NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chrony.service; enabled; preset: enabled)
Active: active (running) since Mon 2025-12-30 09:37:01 UTC; 4min 11s ago
● systemd-timesyncd.service - Network Time Synchronization
Loaded: loaded (/usr/lib/systemd/system/systemd-timesyncd.service; disabled; preset: enabled)
Active: inactive (dead)
Значення: Chrony працює; timesyncd вимкнено. Добре: один керівник, не два.
Рішення: Використовуйте chronyc для реальної діагностики. Якби обидва були активні, вимкнули б один (зазвичай timesyncd, якщо ви обираєте chrony).
Завдання 3 — Швидке здоров’я chrony: tracking
cr0x@server:~$ chronyc tracking
Reference ID : 00000000 ()
Stratum : 0
Ref time (UTC) : Thu Jan 01 00:00:00 1970
System time : 0.832145678 seconds fast of NTP time
Last offset : +0.832145678 seconds
RMS offset : 0.500000000 seconds
Frequency : 0.000 ppm
Residual freq : +0.000 ppm
Skew : 0.000 ppm
Root delay : 1.000000000 seconds
Root dispersion : 10.000000000 seconds
Update interval : 0.0 seconds
Leap status : Not synchronised
Значення: Stratum 0 з Reference ID 0 означає, що chrony не вибрав джерело. Не синхронізовано.
Рішення: Подивіться джерела й досяжність далі. Зазвичай проблема в мережі, DNS або конфігурації.
Завдання 4 — Подивитися налаштовані джерела й чи вони доступні
cr0x@server:~$ chronyc sources -v
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current best, '+' = combined, '-' = not combined,
| / 'x' = may be in error, '~' = too variable, '?' = unusable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^? ntp1.corp.lan 0 6 0 - +0ns[ +0ns] +/- 0ns
^? ntp2.corp.lan 0 6 0 - +0ns[ +0ns] +/- 0ns
Значення: ^? і Reach 0 означають, що відповіді не надходять. Тут stratum 0 — це «невідомо/недоступно», а не «дуже точно».
Рішення: Перевірте DNS і шлях UDP/123. Поки не чіпайте clocksource; швидше за все просто блокування мережі.
Завдання 5 — Підтвердити розв’язання DNS для NTP-хостів
cr0x@server:~$ getent ahosts ntp1.corp.lan
10.20.30.40 STREAM ntp1.corp.lan
10.20.30.40 DGRAM ntp1.corp.lan
10.20.30.40 RAW ntp1.corp.lan
Значення: Ім’я резолвиться. Добре. Якщо це не проходить, chrony виглядатиме «зламаним», але насправді це DNS.
Рішення: Якщо DNS не працює — спочатку лагодьте резолвер. Якщо DNS у порядку, перевіряйте файрвол/маршрутизацію для UDP/123.
Завдання 6 — Перевірити підключення UDP/123 (проблеми фаєрволу або маршрутизації)
cr0x@server:~$ sudo nft list ruleset | sed -n '1,80p'
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
tcp dport 22 accept
ip protocol icmp accept
}
}
Значення: Політика drop на input, немає явного правила для UDP/123 inbound — це нормально для клієнта. Але потрібно дозволити egress і мати стейтфул повернення (воно є: established/related).
Рішення: Якщо egress блокується зверху (security group у хмарі, корпоративний фаєрвол) — виправляйте там. На хості перевіряйте output chain, якщо ви його застосовуєте.
Завдання 7 — Слідкувати за логами chrony на предмет «no reply» і подій step
cr0x@server:~$ sudo journalctl -u chrony --since "30 min ago" --no-pager
Dec 30 09:37:01 server chronyd[932]: chronyd version 4.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER)
Dec 30 09:37:02 server chronyd[932]: Could not resolve address for ntp2.corp.lan: Name or service not known
Dec 30 09:37:05 server chronyd[932]: No suitable source for synchronisation
Значення: Тут ми бачимо реальну причину: неможливо резолвити одне джерело; взагалі немає придатного джерела.
Рішення: Лагодьте DNS або тимчасово замініть хости на IP, поки DNS не відновиться.
Завдання 8 — Перевірити, чи RTC дрейфує або встановлений неправильно
cr0x@server:~$ sudo hwclock --verbose
hwclock from util-linux 2.39.3
System Time: 1735551672.123456
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 0 seconds after 1969
RTC time: 1735551602.000000, RTC epoch: 1900, offset: 0
Time since last adjustment is 1735551602 seconds
Calculated Hardware Clock drift is 0.000000 seconds
Hardware clock is on UTC time
Значення: RTC відстає приблизно на 70 секунд від системного часу. Таке може статися після завантаження, якщо NTP ще не синхронізувався і системний час теж був неправильний.
Рішення: Після стабілізації NTP синхронізуйте RTC із системним часом (hwclock --systohc) на bare metal. У VM RTC часто віртуалізований — поводьтесь обережно.
Завдання 9 — Підтвердити, яке джерело часу бачить systemd (для timesyncd)
cr0x@server:~$ timedatectl timesync-status
Server: 185.125.190.57 (ntp.ubuntu.com)
Poll interval: 32min 0s (min: 32s; max 34min 8s)
Leap: normal
Version: 4
Stratum: 2
Reference: 7B5E1A2F
Precision: 1us (-20)
Root distance: 28.217ms (max: 5s)
Offset: +3.122ms
Delay: 24.503ms
Jitter: 2.731ms
Packet count: 41
Frequency: -12.345ppm
Значення: Якщо ви використовуєте timesyncd, це надзвичайно корисно: stratum 2, малий офсет, стабільний джиттер — здоровий стан.
Рішення: Якщо офсет великий або сервер відсутній — переходьте на chrony для кращого відновлення і діагностики, особливо у VM або на ненадійних мережах.
Завдання 10 — Виявити «стриби» часу (suspend, restore snapshot або пауза хоста)
cr0x@server:~$ sudo journalctl --since "2 hours ago" | grep -E "Time has been changed|clock.*jump|System clock"
Dec 30 08:55:11 server systemd[1]: Time has been changed
Dec 30 08:55:11 server chronyd[932]: System clock was stepped by -38.214567 seconds
Значення: Крок на -38 секунд — це зворотній стрибок. Саме так ви отримуєте «файл з майбутнього» або «залежності в минулому».
Рішення: З’ясуйте, чому сталося стрибання. Chrony робить step при старті/великих офсетах за замовчуванням (конфігуровано). Якщо це трапляється під час роботи — підозрюйте паузу VM/відновлення сніпшоту або погане джерело часу.
Завдання 11 — Перевірити kernel clocksource (рідко, але реально)
cr0x@server:~$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
Значення: tsc зазвичай підходить на сучасному залізі й VM, але якщо ви бачите нестабільність або відомі багаи на платформі, переключення може допомогти (обережно).
Рішення: Змінюйте clocksource лише за наявності доказів (стриби/дрейф, корельований з конкретними платформами). Інакше це лікування симптомів молотком.
Завдання 12 — Порівняти час із відомим зовнішнім референтом швидко
cr0x@server:~$ chronyc -n tracking | sed -n '1,6p'
Reference ID : C0A80101 (192.168.1.1)
Stratum : 3
Ref time (UTC) : Mon Dec 30 09:42:01 2025
System time : -0.000231456 seconds slow of NTP time
Last offset : -0.000120001 seconds
Значення: Офсет субмілісекундний: відмінно. Це не коробка, що спричиняє ваші збої збірки (якщо тільки mtime файлової системи не пошкоджені).
Рішення: Перейдіть до розслідування середовища збірки (спільні томи, мітки часу у чекутах, час хоста контейнера тощо).
Завдання 13 — З’ясувати, чи збірка йде на мережевій файловій системі з дивними мітками часу
cr0x@server:~$ findmnt -T "$PWD"
TARGET SOURCE FSTYPE OPTIONS
/ /dev/mapper/vg0-root ext4 rw,relatime
Значення: Локальний ext4 передбачуваний. Якщо ви бачите nfs, cifs або щось екзотичне, mtime може відображати час сервера, а не клієнта.
Рішення: Якщо робоча папка збірки на NFS/CIFS — упевніться, що сервер синхронізований, або переносіть збірки на локальний диск.
Завдання 14 — Довести аномалію mtime, що тригерить make
cr0x@server:~$ ls -l --full-time build/output.o src/input.c
-rw-r--r-- 1 cr0x cr0x 8216 2025-12-30 09:50:01.000000000 +0000 build/output.o
-rw-r--r-- 1 cr0x cr0x 412 2025-12-30 09:41:10.000000000 +0000 src/input.c
Значення: Якщо зараз 09:42, а output.o має 09:50, файл із майбутнього створено при неправильному часі.
Рішення: Зробіть clean і перебудову після виправлення часу; не довіряйте інкрементальним збіркам, поки мітки часу отруєні.
Завдання 15 — Після виправлення синхронізації: перевірити «synchronized» і стабільні джерела
cr0x@server:~$ timedatectl
Local time: Mon 2025-12-30 09:43:22 UTC
Universal time: Mon 2025-12-30 09:43:22 UTC
RTC time: Mon 2025-12-30 09:43:22
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Значення: Це бажаний кінцевий стан: synchronized yes, RTC вирівняний, UTC всюди.
Рішення: Тепер відновіть виходи збірки (очищення робочої папки, очищення кешів, що зберігають мітки часу) і додайте моніторинг, щоб це не повернулося наступного вівторка.
Шаблони виправлень, що працюють на Ubuntu 24.04
Ubuntu 24.04 охоче працює як із systemd-timesyncd, так і з chrony. Виберіть один. Налаштуйте його правильно. Моніторте його. Найбільші інциденти синхронізації часу, з якими я мав справу, не були спричинені «неправильним» демоном; вони були спричинені невизначеністю і занедбанням.
Шаблон A: Стандартний флот серверів/VM — використовуйте chrony, тримайте все простим
Chrony зазвичай правильний вибір для серверів і CI-ранерів, бо він пристосований до «реального життя»: переривчастого з’єднання, пауз VM, нодів, що завантажуються зі сніпшотів, і мереж, які іноді блокують UDP для розваги.
Встановлення й увімкнення chrony (якщо ще немає)
cr0x@server:~$ sudo apt update
...output...
cr0x@server:~$ sudo apt install -y chrony
...output...
cr0x@server:~$ sudo systemctl enable --now chrony
...output...
Рішення: Якщо у вас вже був active timesyncd, вимкніть його, щоб уникнути дуельних циклів дисципліни часу.
cr0x@server:~$ sudo systemctl disable --now systemd-timesyncd
Removed "/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service".
Налаштуйте адекватні джерела
Редагуйте /etc/chrony/chrony.conf. У корпоративних мережах вказуйте внутрішні NTP-сервери (ідеально — резервні). У менших середовищах використовуйте pool ntp.ubuntu.com або сервіс часу вашого провайдера. Головне — надлишковість і досяжність.
Приклад (не копіюйте бездумно імен; використовуйте реальні сервери):
cr0x@server:~$ sudo sed -n '1,80p' /etc/chrony/chrony.conf
pool ntp.ubuntu.com iburst maxsources 4
keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift
ntsdumpdir /var/lib/chrony
logdir /var/log/chrony
makestep 1.0 3
Що важливо:
iburstпришвидшує початкову синхронізацію після завантаження.makestep 1.0 3дозволяє зробити step (стрибок) годинника, якщо офсет > 1с протягом перших 3 оновлень. Добре для буту; небезпечно, якщо це відбувається пізніше під час роботи.
Думка: тримайте makestep увімкненим для початкового завантаження. CI-ноди, що стартують з поганим годинником, витратять більше грошей, ніж коштує один стрибок.
Перезапустіть і перевірте
cr0x@server:~$ sudo systemctl restart chrony
...output...
cr0x@server:~$ chronyc sources -v
...output...
cr0x@server:~$ chronyc tracking
...output...
Рішення: Вам потрібне вибране джерело (*), регістр Reach ненульовий (не 0) і адекватний stratum (звично 2–4 в ентерпрайзі). Якщо нічого немає — знову мережа/DNS/фаєрвол.
Шаблон B: Мінімальні десктопи або апарати — timesyncd підходить
Systemd-timesyncd справляється для багато яких некритичних систем. Але його легше перерости, ніж пошкодувати, що не встановили chrony. Якщо тримаєте timesyncd, хоча б зафіксуйте надійний список серверів.
Редагуйте /etc/systemd/timesyncd.conf і встановіть явні сервери, якщо ваша мережа блокує публічні пулли.
cr0x@server:~$ sudo sed -n '1,120p' /etc/systemd/timesyncd.conf
[Time]
NTP=ntp1.corp.lan ntp2.corp.lan
FallbackNTP=ntp.ubuntu.com
cr0x@server:~$ sudo systemctl restart systemd-timesyncd
...output...
cr0x@server:~$ timedatectl timesync-status
...output...
Рішення: Якщо timesyncd не може дістатися до серверів, він тихо зазнає невдачі, поки щось інше не залається (наприклад ваша збірка). Якщо вам потрібна сильніша діагностика й стійкість — переходьте на chrony.
Шаблон C: Гості VM — не бийтеся з гіпервізором, але не довіряйте йому сліпо
Дрейф часу у VM — звична справа. Гість може бути правильним, але також може бути призупиненим, відновленим зі сніпшоту, мігруваним або тротлованим. Це всі події часу.
Практичні поради:
- Завжди запускайте сервіс синхронізації часу в гостьовій ОС. Навіть якщо гіпервізор допомагає, гість має дисциплінувати себе сам.
- Узгодьте стратегію хоста й гостя. Якщо гіпервізор інжектить час, а гість агресивно стрибає, може виникнути осциляція.
- Слідкуйте за step-подіями під час роботи. Це зазвичай не «нормальний дрейф», а подія платформи.
Якщо ви бачите стрибки під час нормальної роботи VM — перевірте перевантаження хоста або CPU steal. Це SRE-проблема, замаскована під проблему часу.
Шаблон D: Контейнери — ви не можете виправити час хоста зсередини
Контейнери використовують ядро хоста. Якщо в контейнері збірка каже «clock skew detected», значить час хоста неправильний або робоча директорія змонтована з місця з поганими мітками часу. Ви можете встановити chrony в контейнері і почувати себе корисним, але він не дисциплінуватиме годинник хоста, якщо ви не робите привілейовані трюки — що вже інший клас інцидентів.
Виправляйте вузол. Або виправляйте файлову систему, що постачає mtime.
Шаблон E: CI/CD — очистіть артефакти після виправлення часу
Після виправлення часу у вас залишаться отруєні артефакти: згенеровані файли з мітками часу з майбутнього, кеші з метаданими і графи інкрементальної збірки, які тепер брешуть. Правильна дія зазвичай:
- Очистити робочу папку (
git clean -xfdв disposable runner; обережніші дії на персистентних хостах). - Інвалідовувати кеші, що зберігають mtime (мовні кеші, компіляторні кеші, кеші артефактів).
- Перебудувати з нуля один раз, щоб відновити коректний ланцюжок залежностей.
Жарт №2: Синхронізація часу як чищення зубів — пропустіть тиждень, і раптом усе дороге й усі незадоволені.
Три корпоративні міні-історії (анонімізовані, правдоподібні й технічно болючі)
Міні-історія 1 — Інцидент через неправильне припущення
Компанія мала нове зображення runner для CI на Ubuntu 24.04. Воно було «загартоване», тому вихідний UDP був заблокований за замовчуванням. Припущення: «Ми не запускаємо сервіси, що потребують UDP». Це формулювання звучить охайно в таблиці, але в продакшні воно стає поганим.
Протягом кількох годин збірки почали падати з make: warning: Clock skew detected. Одночасно інша команда повідомляла про переривчасті помилки «certificate not valid yet» при вилученні з внутрішнього реєстру. Симптоми виглядали не пов’язаними, але спільною причиною був дрейф часу: ранери завантажувалися з годинником на кілька хвилин не точно, а потім дрейфували далі, бо NTP не міг нічого досягнути.
Розбір інциденту був типовою корпоративною археологією. Security ввів блокування UDP. Platform переключився з timesyncd на chrony «для кращої точності», не перевіривши egress правила. CI опинився відповідальним за падіння, але не за мережеву політику. Дашборди показували CPU і пам’ять; синхронізація часу взагалі не моніторилася.
Виправлення було непрезентабельне: дозволити UDP/123 egress для ранерів до внутрішніх NTP-серверів, додати друге NTP-джерело і сповіщення, якщо timedatectl повідомляє unsynchronized більше кількох хвилин після завантаження. Найбільша зміна була культурною: перестали думати «UDP це для дивного legacy». NTP — не дивність. Це фундамент.
Міні-історія 2 — Оптимізація, що обернулась проти
Інфракоманда хотіла пришвидшити деплои. Вони ввімкнули агресивне масштабування на основі сніпшотів: відновити VM зі сніпшоту, запустити збірку, відкинути. Це скоротило час підготовки, допоки не сталося перше відновлення сніпшоту зробленого при трохи неправильному часі й коли гостьові інструменти були призупинені.
Відновлені VM мали часові зсуви від секунд до хвилин. Іноді chrony виправляв ситуацію швидко. Іноді він стрибав годинник назад посеред збірки, коли система генерувала хедери. В результаті артефакти мали невідповідні мітки часу, і збірки падали спорадично. «Спорадично» — слово, що старить інженерів.
Перша спроба виправлення була відключити step, бо «step ламає збірки». Це трохи поліпшило одні види збоїв і погіршило інші. Без step деякі VM лишалися з сильним зміщенням достатньо довго, щоб TLS і логіка прострочення токенів почали фейлити, і завантаження з реєстру стало нестабільним.
Насправді потрібно було вважати сніпшоти «небезпечними щодо часу», якщо не проектувати під це: робити сніпшот тільки після стабільної синхронізації часу, примусово синхронізувати час при старті, і видаляти будь-які кешовані робочі директорії, що пережили сніпшот. Вони також ввели health gate: якщо VM не синхронізована в коротке вікно — її зупиняли і створювали заново. Це не елегантно. Це надійно. Надійність перемагає елегантність у продакшні.
Міні-історія 3 — Нудна, але правильна практика, що врятувала ніч
Інша організація мала правило: кожен вузол має дві незалежні навички часу (внутрішні stratum-1 прилади і сервіс часу провайдера), і кожен кластер сигналізує, якщо будь-який вузол не синхронізований більше 10 хвилин. Ніхто не любив це правило. Воно бувало «ще одним шумом моніторингу», поки ним не стало.
Одного вівторка зміна корпоративного фаєрволу заблокувала доступ до первинних NTP-пристроїв із нового підмережі. Більшість команд цього не помітили відразу, бо «в основному все працювало». Але моніторинг помітив. Сповіщення спрацювали: вузли скидалися на резерв і показували збільшений джиттер.
Тому що була надлишковість, нічого видимого користувачу не поламалося. Деплои продовжувалися. Збірки працювали. TLS був задоволений. Команда мала час виправити фаєрвол у робочий час, а не під час інциденту.
Це звучить нудно у звіті і славетно о 3-й ранку: правильна практика не була хитрою. Це була надлишковість і оповіщення про стан синхронізації часу. Вона врятувала їх від інциденту, коли не можна довіряти логам, токенам або сертифікатам. Це вже «всюкомпанійний інцидент», а не «маленька відмова».
Типові помилки: симптом → корінна причина → виправлення
1) Симптом: «Clock skew detected» під час make, особливо в CI
Корінна причина: системний час стрибнув назад або вперед, або робоча папка містить файли, створені під час неправильного часу (mtimes з майбутнього).
Виправлення: спочатку стабілізуйте синхронізацію часу; потім очистіть робочу папку і перебудуйте. Не намагайтесь «touch» кілька файлів і сподіватися. Використовуйте ls -l --full-time, щоб знайти файли з майбутніми мітками, потім витріть виходи.
2) Симптом: «Release file is not valid yet» від apt
Корінна причина: годинник вузла випереджає часові мітки метаданих репозиторію.
Виправлення: лагодьте NTP; не закріплюйте старі метадані репозиторія як тимчасове рішення. Після синхронізації повторіть apt update.
3) Симптом: TLS-помилки «certificate is not yet valid» або дивна поведінка токенів
Корінна причина: офсет годинника (часто хвилини) на клієнті або сервері; іноді викликано відновленням VM або блокуванням NTP.
Виправлення: перевірте синхронізацію обох кінців. Виправте мережеву досяжність до NTP. Для флоту — налаштуйте оповіщення про стан синхронізації й офсет.
4) Симптом: chrony працює, але ніколи не синхронізується (stratum 0, reach 0)
Корінна причина: NTP-сервери недосяжні, DNS ламається, UDP/123 блокується або неправильні адреси серверів.
Виправлення: перевірте резолюцію і мережевий шлях; додайте резервні джерела; упевніться, що ви не вказали адресу, яка працює лише в іншому VLAN.
5) Симптом: час «стрибає» на десятки секунд під час роботи
Корінна причина: пауза/відновлення VM, відновлення сніпшоту, перевантаження хоста або chrony step через великий пізній офсет.
Виправлення: дослідіть події платформи; налаштуйте makestep, щоб дозволяти step тільки на ранній стадії завантаження; упевніться, що гостьові інструменти й NTP на хості налаштовані узгоджено.
6) Симптом: логи поза хронологією, розподілені трейси безглузді
Корінна причина: деякі вузли мають ск’ю; інші — ні. Стек спостережуваності фіксує неправду.
Виправлення: забезпечте синхронізацію часу по всьому флоту; розгляньте відхилення вузлів, що не проходять health check синхронізації часу (особливо для worker-нодів Kubernetes).
7) Симптом: лише збірки на робочих просторах з NFS падають зі ск’ю
Корінна причина: невідповідність часу сервера і клієнта або семантика timestamp файлової системи, особливо коли NFS-сервер не синхронізований.
Виправлення: синхронізуйте час NFS-сервера; перемістіть робочі простори локально; включіть NFS у домен моніторингу синхронізації часу.
8) Симптом: два демони часу борються між собою (осциляція офсету, часті «stepped» події)
Корінна причина: і timesyncd, і chrony (або інші інструменти) намагаються дисциплінувати часовий годинник.
Виправлення: оберіть одного демона. Вимкніть інший. Перевірте стабільність синхронізації після зміни.
Контрольні списки / покроковий план
Контрольний список A — Екстрена відповідь, коли збірки/деплои падають
- Підтвердіть ск’ю: запустіть
timedatectlі зафіксуйте стан синхронізації. - Визначте демон часу:
systemctl status chrony systemd-timesyncd. - Перевірте здоров’я джерел часу:
chronyc trackingіchronyc sources -v(абоtimedatectl timesync-status). - Відновіть досяжність: перевірте DNS і мережеву політику для UDP/123.
- Примусова стабілізація: перезапустіть сервіс часу після виправлення мережі/DNS.
- Перевірте стабільність синхронізації: synchronized = yes, є вибране NTP-джерело, малий офсет.
- Очистіть отруєні виходи збірки: витріть робочу папку/директорії збірки і зберіть з нуля.
- Повторіть деплой: якщо були помилки TLS/токенів — повторіть після виправлення часу.
Контрольний список B — Загартування флоту, щоб це не повернулося
- Стандартизувати: оберіть chrony (рекомендація для серверів/CI) або timesyncd (мінімум), але не обидва.
- Надлишковість: налаштуйте принаймні два NTP-джерела по різних шляхах інфраструктури.
- Моніторинг: сповіщення про unsynchronized стан і великі офсети. Не чекайте, поки make скаже вам.
- Узгодження платформи: переконайтесь, що гіпервізори й bare metal хости теж синхронізуються; гості не компенсують це вічно.
- Гігієна CI: обробляйте виправлення часу як подію інвалідизації кешу; очищайте артефакти при ск’ю.
- Контроль змін: зміни файрволу і DNS мають включати перевірку «чи NTP все ще працює?» як тест.
- Крихти інциденту: зберігайте логи подій step і зміни NTP-джерел для судово-технічної хронології.
Контрольний список C — Коли підозрюєте дрейф часу VM/платформи
- Пошук у логах по «System clock was stepped».
- Кореляція з lifecycle-подіями VM (restore snapshot, migration, pause/resume).
- Перевірка clocksource і kernel-повідомлень, якщо дрейф сильний.
- Перевірка синхронізації часу на хості; поганий хост дає погані гості.
- Використання chrony і обмеження step лише для раннього завантаження, якщо немає сильної причини інакше.
FAQ
1) Чому «clock skew detected» з’являється в make взагалі?
make покладається на часи модифікації файлів, щоб вирішувати, що потрібно перебудувати. Якщо залежність виглядає новішою, ніж має бути — або новішою за «тепер» — воно попереджає, бо не може надійно обчислити граф залежностей.
2) Я виправив NTP, але make все одно попереджає. Чому?
Бо у вас ще є файли з майбутніми мітками часу, створені під час періоду неправильного часу. Виправте час спочатку, потім очистіть виходи і перебудуйте. Інкрементальні збірки після події ск’ю недостовірні, поки ви не санітуєте mtime.
3) Що обрати: chrony чи systemd-timesyncd на Ubuntu 24.04?
Для серверів, CI-ранерів і всього, що має відновлюватися в умовах неповної мережі або VM-особливостей — chrony. Для простих десктопів або мінімальних девайсів — timesyncd достатній. Неправильний вибір — запускати обидва.
4) Чи можна просто вручну встановити час за date і продовжити?
Можна, але це тимчасова пластирка. Якщо машина не може дістатися до NTP або продовжує дрейфувати через проблеми платформи, це повториться. Також ручні зміни часу під час роботи можуть порушити TLS, кеші і логи.
5) У чому різниця між stepping і slewing?
Stepping стрибає годинник до коректного часу швидко. Slewing регулює поступово. Stepping може ламати роботу, чутливу до міток часу; slewing може залишити систему неправильною довше. Chrony з makestep дає розумний компроміс: стрибати тільки на ранньому етапі завантаження, коли система й так крихка.
6) Чи викликає конфігурація часового поясу помилки ск’ю?
Налаштування часового поясу зазвичай викликає людську плутанину, а не ск’ю. Системний час (UTC внутрішньо) може бути правильним. Але якщо ви бачите розбіжності RTC/localtime — це може вказувати на неакуратне провізування. Тримайте сервери в UTC. Завжди.
7) Чому контейнери отримують помилки clock skew, якщо вони не можуть встановити час?
Бо вони успадковують час ядра хоста. Якщо збірка в контейнері скаржиться, виправляйте час хоста або мітки часу змонтованої файлової системи. Встановлення NTP у непривілейованому контейнері — переважно театральний жест.
8) Який офсет «занадто великий» для CI і деплоїв?
Субсекундний офсет — норма. Кілька секунд можуть ламати суворі системи (деякі токени, деякі підписні робочі процеси). Хвилини безумовно зламають TLS і менеджмент пакетів. Якщо ви бачите десятки секунд — вважайте це дефектом продакшну.
9) Ми заблокували UDP повсюди. Чи можна синхронізувати час без UDP/123?
Класичний NTP використовує UDP/123. Деякі середовища використовують альтернативні методи розповсюдження часу всередині мережі, але операційна істина така: потрібно дозволити той протокол часу, який ви обрали. Якщо ви блокуєте — системи винайдуть власну хронологію.
10) Чи варто синхронізувати апаратний годинник (RTC)?
На bare metal: так, коли системний час правильний і стабільний, запишіть його назад за допомогою hwclock --systohc. На VM: будьте обережні; поведінка RTC залежить від гіпервізора і інтеграції гостьової ОС.
Наступні кроки, які варто зробити
Якщо ви виправляєте активну несправність: спочатку забезпечте роботу синхронізації часу, потім знищіть отруєні артефакти збірки. Не торгуйтеся з отруєними mtime. Вони не стануть кращими від надії.
Для довготривалого рішення на Ubuntu 24.04:
- Визначтесь на одному сервісі часу (chrony — прагматичний вибір для серверів і CI).
- Налаштуйте резервні NTP-джерела, які ваша мережа дійсно дозволяє.
- Оповіщуйте про unsynchronized стан і події step.
- Аудитуйте практики життєвого циклу VM (сніпшоти, відновлення, міграції) на предмет впливу на час.
- Після будь-якого інциденту зі ск’ю — очистіть збірки й кеші один раз, щоб відновити порядок.
Висновок нудний, але правильний: надійний час — це залежність, як DNS і зберігання. Ви не «запустили і забули». Ви керуєте ним, моніторите його і тримаєте його нудним.