Skip to main content

Як провести 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 --checkpoint resume з нього.
  • Потребує "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 працює

  1. Зупини всі process у target's PID-namespace (через ptrace).
  2. Читай від кожного process:
    • Memory-page
    • Open file / socket-state / pipe
    • Namespace (PID, mnt, net, uts, ipc, user)
    • Thread, futex, signal
  3. Serialize все вище на disk як protobuf-encoded-файли.
  4. (Опційно) тримай process running, re-attach'ом, або kill його.
  5. На target-host recreate process з тими ж PID (Linux дозволяє requesting specific PID у новому namespace), restore memory-page, reattach FD.
  6. 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 мають. Перевір:

bash
zgrep CONFIG_CHECKPOINT /proc/config.gz # CONFIG_CHECKPOINT_RESTORE=y

Встанови CRIU:

bash
sudo apt install -y criu # Debian/Ubuntu sudo dnf install -y criu # Fedora/RHEL criu check # Looks OK.

Enable experimental у /etc/docker/daemon.json:

json
{ "experimental": true }
bash
sudo systemctl restart docker docker version | grep Experimental

Same-host snapshot/restore (найпростіший випадок)

Запусти long-running-container:

bash
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 # ... # 47

Checkpoint на 47:

bash
docker checkpoint create counter cp1 # cp1

Container тепер stopped (дефолтна поведінка). Checkpoint-файли у /var/lib/docker/containers/<id>/checkpoints/cp1/.

Restore:

bash
docker start --checkpoint=cp1 counter docker logs -f counter # 48 # 49 # ...

Counter resume з 48, не з 0. State preserved.

Snapshot без зупинки container

bash
docker checkpoint create --leave-running counter cp1 # Container продовжує running, поки checkpoint береться

Cross-host-migration

Крок 1, image має бути на обох host'ах

bash
# На host A docker save myorg/app:1.0 | ssh hostb "docker load" # Або push у registry і pull на B

Крок 2, checkpoint на host A

bash
docker checkpoint create --checkpoint-dir=/var/checkpoints app cp1

--checkpoint-dir override default-location, щоб ти міг легко grab файли.

Крок 3, copy checkpoint і volume-data на host B

bash
rsync -a --delete /var/checkpoints/cp1/ hostb:/var/checkpoints/cp1/ # Плюс bind-mounted-каталоги, named-volume тощо.

Крок 4, на host B recreate container у stopped-state

bash
ssh hostb docker create --name app \ -v /data:/data \ -p 8080:8080 \ myorg/app:1.0 # Нота: ті самі volume-mount, ті самі port, той самий image

Крок 5, restore з checkpoint

bash
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:

bash
# День 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

  1. Experimental. Docker не graduate checkpoint до GA. API можуть змінитися.
  2. Без GPU-state migration у stock-CRIU. Active research, не production.
  3. Без support деяких namespace у старих версіях.
  4. Не у Docker Desktop. Docker Desktop VM не enable CRIU.
  5. Performance: writing всю memory на disk бере секунди-до-хвилин для великих container.

Альтернативи, що краще вирішують ту саму проблему

ПотребаКращий tool
Перенести web-server без downtimeBlue-green-deploy зі stateless-app
Перенести stateful-сервісExternalize state (DB, S3); redeploy stateless wrapper
Maintenance-вікно на nodeDrain, 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 ні одне.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Коментарі

Ще немає коментарів