Як провести live migration контейнера між хостами (CRIU)?
CRIU (Checkpoint/Restore In Userspace) це Linux-feature, що freezes running process-tree у набір файлів і restoring later, на тому ж host або іншому, ідеально, з program-ом ні в чому не помічаючим. Docker інтегрує CRIU через experimental docker checkpoint-subcommand, що найближче Docker має до live container-migration. Працює для вузьких use case. Для більшості команд stateless-redeploy простіший і надійніший.
Теорія
TL;DR
- CRIU dump'ить process-memory, file-descriptor, socket і namespace на disk; restoring on demand.
docker checkpoint createвиробляє checkpoint;docker start --checkpointresume з нього.- Потребує
"experimental": trueуdaemon.jsonі kernel з CRIU-support. - Обидва host'и потребують ту ж kernel-version, той самий CPU-instruction-set, ту ж Docker-version, identical filesystem-state у момент snapshot.
- Network-state finicky: IP/MAC container'а рухається з migration; потребує network, що це дозволяє.
- Use case вузький: довгі обчислення, де не можеш restart from scratch (HPC, ML-training, довгі simulation).
- Більшість production-патернів (web-app, microservice) беруть stateless-redeploy замість, де state живе поза container (DB, object-storage).
Як CRIU працює
- Зупини всі process у target's PID-namespace (через
ptrace). - Читай від кожного process:
- Memory-page
- Open file / socket-state / pipe
- Namespace (PID, mnt, net, uts, ipc, user)
- Thread, futex, signal
- Serialize все вище на disk як protobuf-encoded-файли.
- (Опційно) тримай process running, re-attach'ом, або kill його.
- На target-host recreate process з тими ж PID (Linux дозволяє requesting specific PID у новому namespace), restore memory-page, reattach FD.
- Resume execution.
Крукс у тому, що kernel-state має матчити: file-path, mounted-volume, network-state, /etc/hosts, device. CRIU детектить mismatch і refuse restore у багатьох випадках.
Чому це рідко на практиці
- Kernel-version sensitivity. Process snapshotted на kernel 5.10 може fail restore на 5.15, бо internal kernel-structure changed.
- Hardware sensitivity. Різний CPU-vendor або microarchitecture може ламати (AVX-availability, TSC-behavior, randomness-sources).
- Network і filesystem-state. Open TCP-connection, NFS-handle, special-file, легко зламати.
- Більшість workload не потребує. Stateless web-server може restart за секунди; не треба live-migrate, ти просто deploy новий.
- Сучасні альтернативи. Kubernetes pod-eviction + rescheduling, blue-green-deploy, rolling-update, всі простіші за CRIU.
Коли реально допомагає
- Наукові обчислення: 12-годинна simulation, що крутилася 8 годин; host потребує maintenance. Snapshot, migrate, resume. Краще за restart.
- Довгі ML-training-job: similar.
- Hot-patching stateful in-memory-сервісів: рідко, advanced.
- Container live-migration у research/POC: CRIU це building-block для проєктів типу P.Haul (process haul) або container live-migration-прототипів.
Приклади
Setup
Kernel має бути built з CRIU-options. Більшість сучасних distro мають. Перевір:
zgrep CONFIG_CHECKPOINT /proc/config.gz
# CONFIG_CHECKPOINT_RESTORE=yВстанови CRIU:
sudo apt install -y criu # Debian/Ubuntu
sudo dnf install -y criu # Fedora/RHEL
criu check
# Looks OK.Enable experimental у /etc/docker/daemon.json:
{
"experimental": true
}sudo systemctl restart docker
docker version | grep ExperimentalSame-host snapshot/restore (найпростіший випадок)
Запусти long-running-container:
docker run -d --name counter --rm \
busybox sh -c 'i=0; while true; do echo $i; i=$((i+1)); sleep 1; done'
# Дивися, як рахує
docker logs -f counter
# 0
# 1
# 2
# ...
# 47Checkpoint на 47:
docker checkpoint create counter cp1
# cp1Container тепер stopped (дефолтна поведінка). Checkpoint-файли у /var/lib/docker/containers/<id>/checkpoints/cp1/.
Restore:
docker start --checkpoint=cp1 counter
docker logs -f counter
# 48
# 49
# ...Counter resume з 48, не з 0. State preserved.
Snapshot без зупинки container
docker checkpoint create --leave-running counter cp1
# Container продовжує running, поки checkpoint беретьсяCross-host-migration
Крок 1, image має бути на обох host'ах
# На host A
docker save myorg/app:1.0 | ssh hostb "docker load"
# Або push у registry і pull на BКрок 2, checkpoint на host A
docker checkpoint create --checkpoint-dir=/var/checkpoints app cp1--checkpoint-dir override default-location, щоб ти міг легко grab файли.
Крок 3, copy checkpoint і volume-data на host B
rsync -a --delete /var/checkpoints/cp1/ hostb:/var/checkpoints/cp1/
# Плюс bind-mounted-каталоги, named-volume тощо.Крок 4, на host B recreate container у stopped-state
ssh hostb
docker create --name app \
-v /data:/data \
-p 8080:8080 \
myorg/app:1.0
# Нота: ті самі volume-mount, ті самі port, той самий imageКрок 5, restore з checkpoint
docker start --checkpoint=cp1 --checkpoint-dir=/var/checkpoints app
docker logs app
# Має resume з того, де host A залишивЩо може піти не так
- «Failed to restore: open files mismatch»: file був open на host A, що не існує на host B. Фіксь bind-mount.
- «Failed to restore: socket peer not found»: open TCP-connection не може бути re-established. CRIU має
--tcp-established-режим для коротких connection, але ненадійний для long-lived. - «Unable to restore PID X»: PID вже зайнятий на host B's PID-namespace. CRIU зазвичай обробляє це у container (private PID-namespace), але edge-cases існують.
- Kernel/glibc/CPU-mismatch: один з десятків subtle-помилок. Читай CRIU-docs.
Де реально блищить (реальний приклад)
Довга наукова simulation:
# День 1: start 24-годинної simulation
docker run -d --name sim --gpus all myorg/simulation:1.0 sim_run config.toml
# 18 годин in, GPU-driver host'а потребує оновлення. Не можна restart.
docker checkpoint create --leave-running sim cp1 --checkpoint-dir=/scratch/cp1
rsync -a /scratch/cp1/ gpu-host-2:/scratch/cp1/
ssh gpu-host-2
docker create --name sim --gpus all myorg/simulation:1.0 sim_run config.toml
docker start --checkpoint=cp1 --checkpoint-dir=/scratch/cp1 sim
# Simulation resume на іншому host, продовжує ще 6 годинРеальне застосування
- HPC-кластери і research-environment (оригінальний use case).
- Деякі container-orchestrator типу Singularity (HPC-focused) інтегрують CRIU як feature.
- Kubernetes Pod Live-Migration у alpha з 2024 (KEP-2008), використовує CRIU під капотом.
- Docker Swarm і stock K8s production: не покладайся. Бери deploy-стратегію (rolling, blue-green, canary).
Limitation
- Experimental. Docker не graduate
checkpointдо GA. API можуть змінитися. - Без GPU-state migration у stock-CRIU. Active research, не production.
- Без support деяких namespace у старих версіях.
- Не у Docker Desktop. Docker Desktop VM не enable CRIU.
- Performance: writing всю memory на disk бере секунди-до-хвилин для великих container.
Альтернативи, що краще вирішують ту саму проблему
| Потреба | Кращий tool |
|---|---|
| Перенести web-server без downtime | Blue-green-deploy зі stateless-app |
| Перенести stateful-сервіс | Externalize state (DB, S3); redeploy stateless wrapper |
| Maintenance-вікно на node | Drain, reschedule (K8s, Swarm, Nomad) |
| Довге обчислення | Periodic application-level checkpoint (write progress на disk кожні N хвилин; resume звідти) |
Application-level checkpoint зазвичай кращий answer за CRIU, бо:
- Portable через kernel/CPU/distro-зміни.
- Менші (тільки твої дані, не вся memory).
- Переживають image-upgrade.
- Testable.
Типові помилки
Treating CRIU як production-grade live-migration
Це experimental у Docker. Для production, бери rolling-deploy.
Не матчити state через host'и
Volume-content, mounted-secret, host's /etc/resolv.conf, все має матчити. Легше сказати, ніж зробити.
Спроба migrate container з active TCP-connection
CRIU's --tcp-established крихкий. Drain connection спочатку, або прийми reset.
Skip kernel-match
Migration з kernel 5.10 на 5.15 може працювати, може ні. Test у staging.
Питання для поглиблення
Q: Чи docker checkpoint enabled за замовчуванням?
A: Ні. Маєш enable "experimental": true у /etc/docker/daemon.json і restart daemon.
Q: Що з Kubernetes live-migration?
A: KEP-2008 (Container Live-Migration) у alpha. Використовує CRIU під капотом. Не рекомендовано для prod ще (станом на кінець 2024).
Q: Чи можу я checkpoint container з database всередині?
A: Технічно так, але on-disk DB-файли мають бути на target-host. Це одна з причин, чому DB зазвичай на volume, і volume реплікується окремо (DB-replication).
Q: (Senior) Чому CRIU не стандартний answer для перенесення stateful-сервісів?
A: Бо universe «identical state on both hosts» крихкий. Сучасні stateful-сервіси (DB, message-queue) спроєктовані для replication: leader/follower, multi-master, distributed-consensus. Ти переносиш дані через application-replication-протокол, не через snapshot kernel-state. CRIU обходить data-model app і припускає, що може recreate кожен byte process-state, far more brittle, ніж дзеркалити дані через Postgres-replication або Kafka-mirroring.
Q: (Senior) Коли правильний час розглядати CRIU?
A: Коли (1) workload single-instance і не може trivially restart, (2) progress у process-memory (не в DB чи file), (3) контролюєш обидва host, включаючи kernel-version, (4) ціна reproduction state from scratch перевищує engineering-ціну роботи з quirk CRIU. HPC/research check всі чотири. Production-microservice check ні одне.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів