Skip to main content

Як передати образ між хостами без реєстру?

Передача Docker image без registry це відповідь, коли image на host A потрібно на host B, а ти не можеш або не хочеш пушити у registry. Пара docker save/load це канонічне рішення.

Теорія

TL;DR

  • docker save = експортує IMAGE (з усіма шарами + метаданими) у tar-файл або stdout.
  • docker load = імпортує image-tar назад в інший daemon.
  • Відрізняється від docker export/import, що працюють на container і дають flattened single-layer image без метаданих.
  • Use cases: air-gapped середовища, USB-трансфер між dev-машинами, image-promotion між безпечними мережами, offline-демо.
  • Для рутинного cross-host трансферу registry значно кращий (дедуплікація, auth, pull-by-digest).

Швидкий приклад

bash
# Вихідний host: пакуємо image $ docker save myapp:1.0 -o myapp.tar $ ls -lh myapp.tar -rw------- 1 me me 256M ... myapp.tar # Стискаємо для швидшого трансферу $ docker save myapp:1.0 | gzip > myapp.tar.gz # Трансфер (як завгодно) $ scp myapp.tar.gz user@dest:/tmp/ # Цільовий host: load $ docker load -i /tmp/myapp.tar # АБО $ gunzip -c /tmp/myapp.tar.gz | docker load Loaded image: myapp:1.0 $ docker run --rm myapp:1.0

Image тепер на цільовому host, ніби pull з registry, з тим самим іменем, tag і шарами.

One-liner через SSH

Без проміжного файлу:

bash
$ docker save myapp:1.0 | gzip | ssh user@dest 'gunzip | docker load'

Stream через провід, без temp-файлу. Чудово для одноразових трансферів.

save vs export

Це людей плутає.

docker savedocker export
Оперує наimagecontainer
Шаризбережено (кожен шар у tar)flattened у один шар
Image-метаданізбережено (CMD, ENV, history тощо)втрачено
Зворотнійdocker loaddocker import
Use casesharing imagesnapshot filesystem only
bash
# IMAGE save → load (рекомендовано) docker save myimg -o image.tar docker load -i image.tar # CONTAINER export → import (тільки filesystem) docker export <container> -o fs.tar docker import fs.tar imported:1.0 # створює новий image без метаданих

99% часу хочеш save/load. export/import для legacy або специфічних кейсів (перебудова image filesystem з нуля).

Кілька image у одному tar

bash
docker save myapp:1.0 myapp:1.1 nginx:1.27 -o multi.tar docker load -i multi.tar

Корисно для шиппінгу цілого стеку у air-gapped середовище одним файлом.

Типові помилки

Плутати save з export

bash
# НЕПРАВИЛЬНО: container export, втрачає CMD/ENV/etc. $ docker export api > api.tar $ docker import api.tar api:fresh $ docker run api:fresh # error: no command specified # ПРАВИЛЬНО: image save, зберігає усе $ docker save myimg:1.0 > myimg.tar $ docker load < myimg.tar $ docker run myimg:1.0 # працює як було

Save у stdout без редиректу

bash
# НЕПРАВИЛЬНО: tar-бінар корумпує термінал $ docker save myimg # (термінал пішов у розноc) # ПРАВИЛЬНО $ docker save myimg -o myimg.tar # АБО $ docker save myimg > myimg.tar

Завжди -o file або > file. Дефолт це stdout, безпечно при редиректі, terminal-breaking без.

Забути, що tar величезний

Save-tar приблизно розміру image (multi-stage з 25MB фіналом → 25MB tar; 1GB image → 1GB tar). Стискай для трансферу:

bash
docker save myimg | zstd > myimg.tar.zst # zstd швидший за gzip docker save myimg | xz > myimg.tar.xz # xz менший, повільніший

Ім'я image не зберігається при import

bash
# `docker import` НЕ зберігає імен $ docker export api > fs.tar $ docker import fs.tar sha256:abc123... # untagged # Треба тегувати руками

docker load зберігає імена; docker import ні. Ще одна причина брати save/load.

Коли використовувати save/load (а коли ні)

Бери save/load коли:

  • Air-gapped або offline-трансфер (без мережі між host).
  • Одноразовий трансфер між двома відомими машинами.
  • Маленька команда, що ще не налаштувала registry.
  • Бекап/архів конкретних версій image.
  • Initial bootstrap registry (load image спочатку, потім push).

Бери registry натомість коли:

  • Кілька споживачів потребують image (кожен робить docker pull).
  • Хочеш pull-by-digest, signing, vulnerability scan, RBAC.
  • Трансфер це частина CI/CD-pipeline.
  • Дбаєш про дедуплікацію між версіями (registry зберігає шари раз).

Реальне застосування

  • Air-gapped enterprise: усі image течуть як save-tar між security-зонами.
  • Customer-on-premise деплой: ship застосунку як tar, що docker load'ить клієнт у своїй мережі.
  • Disaster recovery: save критичних image у backup-storage як tar; load, якщо registry втрачено.
  • Embedded / edge devices: preload image через docker load з USB-stick під час виробництва.
  • Image-promotion через security-межі: save у dev, scan offline, load у прод через one-way diode.

Питання для поглиблення

Q: Яка різниця між save і pull?


A: pull тягне image з registry (HTTP). save експортує локальний image у tar. Протилежні напрямки руху image з різними storage-носіями.

Q: Чи зберігається історія image?


A: З docker save/load так, повна image-історія, включно з усіма шарами і метаданими. З docker export/import ні, flattened у один шар.

Q: Чи цільовий host потребує тієї самої Docker-версії?


A: OCI-сумісні tarball'и interoperable між сучасними Docker-версіями. Дуже старі daemon можуть мати формат-проблеми, але для будь-якого Docker за останні кілька років працює.

Q: Що насправді у tar?


A: Директорія на шар (кожна з tar його filesystem-змін), manifest.json, config blob і tag-інфо. Tar це zip-bundled OCI image.

Q: (Senior) Як заскриптувати multi-image трансфер для air-gapped деплою?


A: Збери manifest потрібних image (grep image: compose.yaml | awk ...), pull кожен на connected-стороні, save усі у один tar (docker save img1 img2 img3 -o stack.tar), zstd-стискай для трансферу, шипни через зазор, load на air-gapped стороні. Додай digest-верифікацію на отримуючій стороні: docker images --digests | tee received.txt порівняно з digest-списком source, щоб ловити tampered або часткові трансфери.

Приклади

Air-gapped деплой Compose-стеку

bash
# На connected build-машині $ docker compose -f compose.yaml pull # переконатися, що всі image present $ images=$(grep image: compose.yaml | awk '{print $2}') $ docker save $images -o stack-2026-04-30.tar.gz # усі image в одному файлі # 1.2 GB ... трансфер через дозволений канал # На air-gapped target $ docker load -i stack-2026-04-30.tar.gz Loaded image: nginx:1.27-alpine Loaded image: postgres:16 Loaded image: myorg/api:1.2.3 $ docker compose up -d

Один tar, один load, увесь стек крутиться offline.

Stream через SSH

bash
$ docker save myapp:1.0 | ssh user@destination 'docker load' Loaded image: myapp:1.0

Без temp-файлу. Корисно, коли disk-space тісний на будь-якій стороні.

Порівняння з registry-підходом

bash
# save/load: просто, без setup, повільно для повторних трансферів docker save myapp:1.0 | ssh dest 'docker load' # 30 секунд, повний image передано # Registry: dedup, швидше на повторних трансферах docker push myreg.example.com/myapp:1.0 # На dest: docker pull myreg.example.com/myapp:1.0 # 5 секунд, лише змінені шари передано

Для щоденних workflow registry перемагає по швидкості і tooling. Для одноразових трансферів save/load перемагає по простоті.

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

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

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

Коментарі

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