Время в виртуальной машине уходит по понятным причинам. У гостя нет своего кварцевого генератора, он считает время по тикам, которые ему отдаёт гипервизор. Когда хост перегружен, ВМ ставят на паузу, делают снимок с памятью или переносят на другой узел, часы гостя отстают или прыгают. Без синхронизации за сутки набегают секунды, а после восстановления из снимка — минуты и часы.
Самое частое решение: в каждой Linux-ВМ работает chrony, хост тоже синхронизирован по NTP. Для KVM и Proxmox VE можно сделать лучше — брать время прямо с хоста через виртуальное устройство ptp_kvm, без сети. В Windows-гостях синхронизацию ведёт служба w32time, а Proxmox сам включает для них правильные таймеры.
Ниже — как настроить chrony в Debian 12/13, Ubuntu 24.04 и AlmaLinux 9/10, как подключить ptp_kvm, что делать в Hyper-V и как проверить результат через chronyc tracking и timedatectl.
Почему уходит время в ВМ
- Конкуренция за процессор. Если vCPU гостя долго не получает процессорное время, прерывания таймера теряются или приходят пачкой.
- Пауза и снимки. Приостановленная ВМ, восстановление из снимка с памятью, сохранение состояния при выключении хоста — после возобновления гость продолжает с того момента, где остановился.
- Живая миграция. Часы разных хостов немного расходятся, после переноса гость может увидеть скачок.
- Неудачный источник часов. Если гость считает время по эмулируемым таймерам (PIT, HPET) вместо паравиртуальных, погрешность выше.
- Не синхронизирован сам хост. Тогда все ВМ на нём аккуратно повторяют его ошибку.
Первое правило: сначала синхронизируйте хост, потом гостей. Proxmox VE ставит chrony на узлы по умолчанию. Для кластера это обязательно: corosync и особенно Ceph плохо переносят расхождение часов между узлами.
Источник часов в гостевом Linux: kvm-clock
В KVM гостевое ядро Linux получает паравиртуальный источник времени kvm-clock. Он не эмулирует железный таймер, а читает данные, которые гипервизор пишет в общую память. Это быстро и точно. Проверьте, что гость его использует:
cat /sys/devices/system/clocksource/clocksource0/current_clocksource
cat /sys/devices/system/clocksource/clocksource0/available_clocksource
Примерно так:
kvm-clock
kvm-clock tsc acpi_pm
На современных процессорах с инвариантным TSC и типом CPU host ядро может выбрать tsc, это тоже нормально. Плохой признак — hpet или acpi_pm в текущем источнике. Посмотрите dmesg | grep -i clocksource: ядро пишет, почему отказалось от TSC или kvm-clock.
kvm-clock сам по себе не синхронизирует время с хостом. Он лишь даёт ровный ход часов. Поправки всё равно делает chrony.
chrony в гостевой ВМ
Установка
| Debian 12/13, Ubuntu 24.04 | AlmaLinux/Rocky 9 и 10 | |
|---|---|---|
| По умолчанию | systemd-timesyncd (простой SNTP-клиент) | chronyd |
| Установка | apt install chrony | dnf install chrony |
| Служба | chrony.service | chronyd.service |
| Конфигурация | /etc/chrony/chrony.conf, доп. файлы в /etc/chrony/conf.d/ и /etc/chrony/sources.d/ | /etc/chrony.conf |
В Debian и Ubuntu пакет chrony конфликтует с systemd-timesyncd, поэтому apt удалит timesyncd автоматически. Два клиента синхронизации одновременно работать не должны.
# Debian, Ubuntu
apt install chrony
systemctl enable --now chrony
# AlmaLinux, Rocky
dnf install chrony
systemctl enable --now chronyd
Источники времени
По умолчанию chrony берёт время из публичного пула дистрибутива. Для ВМ в своей инфраструктуре лучше указать внутренние NTP-серверы или сам гипервизор. В Debian/Ubuntu удобно положить отдельный файл в /etc/chrony/sources.d/:
# /etc/chrony/sources.d/local.sources
server 10.0.0.1 iburst
server 10.0.0.2 iburst
chronyc reload sources
В AlmaLinux строки server или pool добавляются прямо в /etc/chrony.conf, после чего systemctl restart chronyd.
Параметр makestep
chrony по умолчанию не прыгает временем, а плавно подгоняет ход часов. Это правильно для работающих сервисов, но после восстановления из снимка разница может быть в часы, и плавная подгонка займёт очень долго. Директива makestep разрешает прыжок:
makestep 1 3
Это значит: если расхождение больше секунды, прыгнуть, но только при первых трёх обновлениях после старта. Такая строка уже есть в стандартных конфигах Debian, Ubuntu и AlmaLinux. Для ВМ, которые часто ставят на паузу, можно разрешить прыжки всегда:
makestep 1 -1
Учтите, что прыжок времени назад может смутить базы данных, очереди и всё, что сравнивает отметки времени. Если такие сервисы есть, оставьте стандартное значение и делайте прыжок вручную после восстановления: chronyc makestep.
ptp_kvm: время с хоста без сети
Модуль ядра ptp_kvm отдаёт гостю часы хоста в виде PTP-устройства (/dev/ptp0). chrony использует его как опорные часы (refclock). Время приходит не по сети, а через гипервизор, поэтому точность выше, чем у NTP, и после живой миграции гость быстро подстраивается под новый хост.
Условие: сам хост синхронизирован (в Proxmox VE это chrony по умолчанию). Если хост врёт, гости будут врать вместе с ним.
Загрузка модуля
modprobe ptp_kvm
echo ptp_kvm > /etc/modules-load.d/ptp_kvm.conf
ls -l /dev/ptp*
Примерно так:
crw------- 1 root root 248, 0 ... /dev/ptp0
lrwxrwxrwx 1 root root 4 ... /dev/ptp_kvm -> ptp0
Символическую ссылку /dev/ptp_kvm создаёт правило udev из systemd. Лучше ссылаться на неё, а не на /dev/ptp0: если в ВМ есть сетевая карта с аппаратными метками времени, номер устройства может смениться. Если ссылки нет, проверьте имя часов: cat /sys/class/ptp/ptp0/clock_name должно вывести KVM virtual PTP.
Настройка chrony
# Debian/Ubuntu: /etc/chrony/conf.d/ptp_kvm.conf
# AlmaLinux: добавить в /etc/chrony.conf
refclock PHC /dev/ptp_kvm poll 2
Сетевые источники можно оставить как запасные. После перезапуска chrony (systemctl restart chrony или chronyd) проверьте, что PHC выбран основным:
chronyc sources
Примерно так:
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* PHC0 0 2 377 3 -45ns[ -60ns] +/- 120ns
^- 10.0.0.1 2 6 377 40 +12us[ +11us] +/- 800us
Символ #* означает: опорные часы, выбраны текущим источником. ptp_kvm работает на x86-хостах KVM, где сам хост использует TSC как источник часов. Если устройство не появляется, сначала проверьте источник часов хоста.
Proxmox VE: что настраивается само
- Узлы. chrony установлен по умолчанию, конфигурация в
/etc/chrony/chrony.conf. В кластере проверьте синхронизацию на каждом узле. - Linux-ВМ. Получают
kvm-clock. chrony в госте и при желанииptp_kvmнастраиваются как описано выше. - Windows-ВМ. Если в параметрах ВМ выбран тип ОС Windows, Proxmox включает Hyper-V enlightenments, включая паравиртуальные часы, и выставляет часы RTC в локальное время, как ожидает Windows.
- LXC-контейнеры. Используют часы ядра хоста. Ставить в контейнер chrony бессмысленно: у контейнера нет права менять системное время. Синхронизируйте хост.
Если включён QEMU Guest Agent, после восстановления из снимка можно подтолкнуть часы гостя без входа в него:
qm guest exec 101 -- chronyc makestep
В чистом libvirt для этого есть virsh domtime vm1 --sync: команда через гостевой агент выставляет часы ВМ по часам хоста. Про установку самого Proxmox — в статье Установка Proxmox VE на свой сервер.
Hyper-V
Linux-гость в Hyper-V получает службу синхронизации времени из модуля hv_utils и PTP-устройство /dev/ptp_hyperv. Схема та же, что с ptp_kvm: chrony берёт время с хоста как refclock.
refclock PHC /dev/ptp_hyperv poll 3 dpoll -2 offset 0
Эту строку рекомендует Microsoft для Linux-ВМ в Azure. В настройках ВМ Hyper-V служба интеграции «Синхронизация времени» должна быть включена. Исключение — контроллеры домена Active Directory в виртуальной машине: у них время должно идти из иерархии домена, а не от хоста.
Windows-гость
Windows считает время по своим правилам. В KVM ей помогают Hyper-V enlightenments (таймер hypervclock), а синхронизацию делает служба w32time. Для ВМ вне домена:
w32tm /config /manualpeerlist:"10.0.0.1 pool.ntp.org" /syncfromflags:manual /update
w32tm /resync
w32tm /query /status
Компьютеры в домене синхронизируются с контроллером домена автоматически, вручную источники им задавать не нужно. Про таймеры и остальные настройки Windows под KVM подробно в статье Ускорение Windows в виртуальной машине KVM и Proxmox.
Проверка результата
timedatectl
timedatectl
Примерно так:
Local time: Sat 2026-10-03 12:00:00 MSK
Universal time: Sat 2026-10-03 09:00:00 UTC
RTC time: Sat 2026-10-03 09:00:00
Time zone: Europe/Moscow (MSK, +0300)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Главное — System clock synchronized: yes и NTP service: active. Если NTP service неактивен, включите его: timedatectl set-ntp true. Часовой пояс меняется командой timedatectl set-timezone Europe/Moscow. Строка RTC in local TZ для Linux-ВМ должна быть no.
chronyc tracking
chronyc tracking
Примерно так:
Reference ID : 50484330 (PHC0)
Stratum : 1
System time : 0.000000041 seconds fast of NTP time
Last offset : -0.000000052 seconds
RMS offset : 0.000000120 seconds
Frequency : 12.345 ppm slow
Skew : 0.010 ppm
Leap status : Normal
Смотрите на System time — текущее расхождение — и на Leap status: Normal. Значение Not synchronised означает, что chrony не видит ни одного рабочего источника. Тогда смотрите chronyc sources -v и журнал: journalctl -u chrony (в AlmaLinux -u chronyd).
Симптом, причина, решение
| Симптом | Причина | Решение |
|---|---|---|
| Время в ВМ постепенно отстаёт | Нет синхронизации, перегружен хост | chrony в госте, проверить chronyc tracking |
| После восстановления из снимка время в прошлом | Гость продолжил с момента снимка, chrony подгоняет плавно | chronyc makestep, через агент: qm guest exec или virsh domtime --sync |
| Все ВМ на хосте врут одинаково | Не синхронизирован хост | chrony на хосте, проверить его источники |
Leap status: Not synchronised | Закрыт исходящий UDP 123 или недоступны серверы | Открыть NTP наружу или указать внутренние серверы, либо ptp_kvm |
В госте нет /dev/ptp0 | Модуль не загружен или хост не на TSC | modprobe ptp_kvm, проверить clocksource хоста |
| Windows показывает время со сдвигом на часовой пояс | RTC в UTC, а Windows ждёт локальное время | Тип ОС Windows в Proxmox или <clock offset='localtime'/> в libvirt |
| chrony и timesyncd «спорят» | Работают два клиента | Оставить один; в Debian/Ubuntu установка chrony удаляет timesyncd |
Исторически: Xen и independent_wallclock
Раньше в паравиртуальных гостях Xen с ядром xenlinux время гостя по умолчанию жёстко следовало за часами гипервизора, и NTP внутри ВМ ничего не мог исправить. Чтобы гость вёл часы сам, включали параметр independent_wallclock через /proc/sys/xen/independent_wallclock и строку xen.independent_wallclock = 1 в /etc/sysctl.conf, а затем настраивали ntpd. В современных ядрах с поддержкой Xen (pvops) этого параметра нет: у гостя свой источник часов xen, и время синхронизируют так же, как везде, — chrony внутри ВМ. Если вы встретили совет про independent_wallclock, он относится к системам десятилетней давности.
Частые вопросы
Нужен ли chrony в каждой ВМ, если хост синхронизирован?
Да. Хост задаёт ровный ход часов через kvm-clock, но не выставляет время гостю. Без клиента синхронизации внутри ВМ ошибки после пауз и миграций не исправятся. Исключение — контейнеры LXC: они используют часы хоста напрямую.
Что лучше: chrony или systemd-timesyncd?
Для серверов и ВМ — chrony. Он умеет опорные часы (ptp_kvm, ptp_hyperv), быстрее сходится после скачков и показывает подробную статистику. timesyncd — простой SNTP-клиент, его хватает для рабочей станции, но не для кластера или базы данных.
Можно ли сделать хост Proxmox NTP-сервером для ВМ?
Можно. Добавьте в конфигурацию chrony на узле строку allow 10.0.0.0/24 со своей подсетью ВМ и откройте UDP 123 только для неё. Но если гости на том же хосте, ptp_kvm проще и точнее: не нужен ни сетевой доступ, ни открытый порт.
Почему после живой миграции время в ВМ прыгает?
Часы двух узлов немного расходятся, и гость после переноса видит разницу. Если оба узла синхронизированы chrony, скачок измеряется миллисекундами. С ptp_kvm гость сразу начинает следовать часам нового хоста. Большие скачки означают, что один из узлов не синхронизирован.
Как быстро поправить время, если оно уже ушло на несколько минут?
Выполните chronyc makestep: chrony сразу выставит правильное время. Проверьте результат через chronyc tracking. Если проблема повторяется после каждого снимка или паузы, задайте makestep 1 -1 или настройте вызов chronyc makestep через гостевой агент.