رفتن به محتوا
LoopX

انتقال image بدون اینترنت

توی این درس یاد می‌گیری یک image را بدون هیچ registry و بدون اینترنت از یک ماشین به ماشین دیگر ببری: با docker save آن را در یک فایل tar می‌گذاری، با docker load روی ماشین مقصد بازش می‌کنی، با gzip حجمش را کم می‌کنی، با scp یا یک خط لوله‌ی ssh به سرور می‌فرستی و با هش مطمئن می‌شوی سالم رسیده. می‌فهمی داخل آن tar چیست، چطور چند image را یک‌جا ببری، و فرق docker save با docker export چیست (که اشتباه گرفتنشان رایج است).

مسئله: سروری که به registry نمی‌رسد

Section titled “مسئله: سروری که به registry نمی‌رسد”

سرور production پشت یک شبکه‌ی بسته است: اینترنت ندارد، یا به Docker Hub و registry شرکت دسترسی ندارد. ولی تو image را روی لپ‌تاپت ساخته‌ای. راه‌حل: image را مثل یک فایل معمولی ببر، همان‌طور که یک فایل فشرده را روی فلش می‌بری.

تشبیه: بسته‌بندی برای حمل

Section titled “تشبیه: بسته‌بندی برای حمل”

registry مثل انبار مرکزی است که هر کس خودش سفارش می‌دهد. docker save مثل بسته‌بندی کردن کالا در یک کارتن مهر و موم‌شده است: کارتن را با هر وسیله‌ای (فلش، ssh، دست) می‌بری و در مقصد باز می‌کنی؛ محتوا و مهر (هش) همان است.

save یک یا چند image را با همه‌ی لایه‌ها و متادیتا در یک فایل tar می‌ریزد؛ فایل را با هر روش دلخواه جابه‌جا می‌کنی؛ load در مقصد آن را به‌عنوان image برمی‌گرداند.

مثال ۱: ساخت یک image برای انتقال

Section titled “مثال ۱: ساخت یک image برای انتقال”

یک اپ کوچک وب (فقط با کتابخانه‌ی استاندارد پایتون) را می‌سازیم:

off/app/server.py
from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.end_headers()
self.wfile.write("سلام از image منتقل‌شده\n".encode())
HTTPServer(("0.0.0.0", 8000), Handler).serve_forever()
off/app/Dockerfile
FROM python:3.12-alpine
WORKDIR /app
COPY server.py .
EXPOSE 8000
CMD ["python", "server.py"]
Terminal window
docker build -q -t lx-app:1.0 off/app >/dev/null
docker image ls lx-app --format 'image: {{.Repository}}:{{.Tag}} حجم: {{.Size}}'
docker image inspect lx-app:1.0 --format 'معماری: {{.Os}}/{{.Architecture}}'
خروجی
image: lx-app:1.0 حجم: 87.9MB
معماری: linux/arm64

به معماری (مثلاً arm64 روی مک‌های Apple Silicon یا amd64 روی بیشتر سرورها) دقت کن: image ساخته‌شده برای یک معماری روی معماری دیگر درست اجرا نمی‌شود (مثال ۹).

Terminal window
docker save -o app.tar lx-app:1.0
ls -l app.tar | awk '{print "app.tar:", $5, "بایت"}'
echo "--- محتوای فایل (برخی ورودی‌ها):"
tar -tf app.tar | grep -vE '^blobs/sha256/.{20,}' | head -8
echo "تعداد بلاب‌ها (لایه‌ها و فایل‌های JSON): $(tar -tf app.tar | grep -c '^blobs/sha256/.')"
خروجی
app.tar: 21432320 بایت
--- محتوای فایل (برخی ورودی‌ها):
blobs/
blobs/sha256/
index.json
manifest.json
oci-layout
تعداد بلاب‌ها (لایه‌ها و فایل‌های JSON): 12

خروجی یک tar عادی است که می‌توانی با tar -tf ببینی. شامل manifest.json و index.json (فهرست image ها و لایه‌ها) و پوشه‌ی blobs/sha256/ که هر لایه و هر فایل پیکربندی در آن با هش محتوایش نام‌گذاری شده است. -o مقصد فایل را می‌دهد؛ به‌جای آن می‌توانی با > خروجی را به جایی هدایت کنی.

⚡ بررسی سریع

اگر docker save را بدون -o اجرا کنی و خروجی را به gzip پایپ کنی، داده کجا می‌رود؟

مثال ۳: فشرده‌سازی با gzip

Section titled “مثال ۳: فشرده‌سازی با gzip”
Terminal window
docker save lx-app:1.0 | gzip > app.tar.gz
ls -l app.tar app.tar.gz | awk '{print $9 ":", $5, "بایت"}'
gzip -t app.tar.gz && echo "فایل gzip سالم است"
خروجی
app.tar: 21432320 بایت
app.tar.gz: 21300863 بایت
فایل gzip سالم است

docker save بدون -o روی stdout می‌نویسد، پس می‌توانی با | به gzip بدهی. فایل کوچک‌تر شد (لایه‌های image معمولاً از قبل فشرده‌اند، پس صرفه‌جویی گاهی کم است؛ برای imageهای بزرگ ممکن است قابل‌توجه باشد). به‌جای gzip می‌توان از xz (فشرده‌تر، کندتر) یا zstd (سریع) هم استفاده کرد.

مثال ۴: سرور آزمایشی با ssh

Section titled “مثال ۴: سرور آزمایشی با ssh”

برای تمرین، یک «سرور» جدا می‌سازیم: یک daemon داکر داخل یک کانتینر (بدون هیچ image از قبل) که ssh هم دارد. یک کلید ssh موقت هم فقط برای همین آزمایش می‌سازیم:

Terminal window
docker run -d --privileged --name lx-srv -p 2299:22 -e DOCKER_TLS_CERTDIR= docker:dind >/dev/null
until docker exec lx-srv docker info >/dev/null 2>&1; do sleep 1; done
docker exec lx-srv sh -c 'apk add --no-cache openssh >/dev/null 2>&1; ssh-keygen -A >/dev/null; sed -i "s/^root:!:/root:*:/" /etc/shadow; mkdir -p /root/.ssh'
ssh-keygen -q -t ed25519 -N '' -C lx-demo -f off/key
docker cp off/key.pub lx-srv:/root/.ssh/authorized_keys
docker exec lx-srv sh -c 'chown root:root /root/.ssh/authorized_keys; chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys; /usr/sbin/sshd'
sleep 1
SSHOPT="-i $PWD/off/key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o BatchMode=yes"
ssh $SSHOPT -p 2299 root@localhost 'echo "ssh به سرور آزمایشی وصل شد"; docker images -q | wc -l | sed "s/^/image ها روی سرور: /"'
خروجی
ssh به سرور آزمایشی وصل شد
image ها روی سرور: 0

سرور هیچ imageای ندارد (صفر). کلید خصوصی فقط در یک پوشه‌ی موقت است و بعد از درس پاک می‌شود. (در واقعیت، رمز و کلید خودت را هرگز در درس یا Git نگذار؛ فقط از کلید عمومی در authorized_keys سرور استفاده می‌شود.)

مثال ۵: انتقال با scp و بازکردن با docker load

Section titled “مثال ۵: انتقال با scp و بازکردن با docker load”
Terminal window
SSHOPT="-i $PWD/off/key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o BatchMode=yes"
scp $SSHOPT -P 2299 app.tar.gz root@localhost:/var/tmp/app.tar.gz
echo "--- روی سرور:"
ssh $SSHOPT -p 2299 root@localhost 'docker load -i /var/tmp/app.tar.gz; docker images --format "{{.Repository}}:{{.Tag}}"'
خروجی
--- روی سرور:
Loaded image: lx-app:1.0
lx-app:1.0

scp فایل را از طریق ssh کپی کرد و docker load -i آن را روی سرور بازگرداند: پیام Loaded image: lx-app:1.0 و image حالا در فهرست سرور است. نکته: docker load فایل .tar.gz را هم مستقیم می‌خواند؛ لازم نیست اول باز کنی.

مثال ۶: اجرا روی سرور و تأیید یکپارچگی

Section titled “مثال ۶: اجرا روی سرور و تأیید یکپارچگی”

آیا آنچه روی سرور هست دقیقاً همان است؟ شناسه‌ی image (هش پیکربندی) را در دو طرف مقایسه می‌کنیم و اپ را روی سرور اجرا می‌کنیم:

Terminal window
SSHOPT="-i $PWD/off/key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o BatchMode=yes"
mine=$(docker image inspect lx-app:1.0 --format '{{.Id}}')
theirs=$(ssh $SSHOPT -p 2299 root@localhost "docker image inspect lx-app:1.0 --format '{{.Id}}'")
[ "$mine" = "$theirs" ] && echo "شناسه‌ی image در مبدأ و مقصد یکی است"
echo "شناسه: ${mine:0:19}…"
ssh $SSHOPT -p 2299 root@localhost 'docker run -d --name lx-off1 lx-app:1.0 >/dev/null; sleep 2; docker exec lx-off1 python -c "import urllib.request; print(urllib.request.urlopen(\"http://localhost:8000\").read().decode(), end=\"\")"'
echo "sha256 فایل: $(shasum -a 256 app.tar.gz | cut -c1-16)… (قبل از ارسال؛ بعد از ارسال هم همین را بسنج)"
خروجی
شناسه‌ی image در مبدأ و مقصد یکی است
شناسه: sha256:e39b1daff10a…
سلام از image منتقل‌شده
sha256 فایل: 34973e6b04b0dfd2… (قبل از ارسال؛ بعد از ارسال هم همین را بسنج)

شناسه‌ی image برابر است و اپ روی سرور (بدون هیچ اتصال به registry) اجرا شد. برای فایل خودِ tar هم قبل و بعد از انتقال sha256sum (لینوکس) یا shasum -a 256 (مک) بگیر و مقایسه کن؛ این کار خرابی نیمه‌راه را پیدا می‌کند.

مثال ۷: بدون فایل میانی: save | ssh load

Section titled “مثال ۷: بدون فایل میانی: save | ssh load”

می‌شود هیچ فایلی روی دیسک نماند: خروجی save را مستقیم از ssh به load سرور بدهی. اول یک نسخه‌ی جدید (۲.۰) بسازیم و بفرستیم:

Terminal window
SSHOPT="-i $PWD/off/key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o BatchMode=yes"
docker tag lx-app:1.0 lx-app:2.0
docker save lx-app:2.0 | gzip | ssh $SSHOPT -p 2299 root@localhost 'gunzip | docker load'
ssh $SSHOPT -p 2299 root@localhost 'docker images --format "{{.Repository}}:{{.Tag}}" | sort'
خروجی
Loaded image: lx-app:2.0
lx-app:1.0
lx-app:2.0

خط لوله‌ی save | gzip | ssh ... 'gunzip | docker load' همه‌چیز را بدون فایل موقت منتقل می‌کند. دو نکته: ۱) image جدید همان شناسه‌ی قبلی را دارد (فقط tag تازه است)، پس load سریع بود؛ ۲) برای یک ارتباط ناپایدار، فایل میانی بهتر است چون می‌توانی انتقال را از وسط ادامه بدهی (rsync --partial).

مثال ۸: چند image در یک فایل

Section titled “مثال ۸: چند image در یک فایل”
Terminal window
docker save -o both.tar lx-app:1.0 alpine
ls -l app.tar both.tar | awk '{print $9 ":", $5, "بایت"}'
echo "فهرست image های داخل both.tar:"
tar -xOf both.tar index.json | python3 -c "import json,sys; [print(' ', m.get('annotations',{}).get('io.containerd.image.name') or m.get('annotations',{}).get('org.opencontainers.image.ref.name','?')) for m in json.load(sys.stdin)['manifests']]"
خروجی
app.tar: 21432320 بایت
both.tar: 25479168 بایت
فهرست image های داخل both.tar:
docker.io/library/lx-app:1.0
docker.io/library/alpine:latest

با نوشتن چند نام بعد از save همه‌ی آن‌ها در یک tar جمع می‌شوند و لایه‌های مشترک فقط یک بار ذخیره می‌شوند. این برای بردن یک پروژه‌ی چند‌سرویسی (اپ + دیتابیس + nginx) در یک فایل عالی است. با docker load -i both.tar همه با هم برمی‌گردند.

مثال ۹: معماری درست برای سرور

Section titled “مثال ۹: معماری درست برای سرور”

اگر لپ‌تاپ تو arm64 است و سرور amd64، image ساخته‌شده روی لپ‌تاپ روی سرور اجرا نمی‌شود. هنگام pull یا build معماری مقصد را مشخص کن:

Terminal window
docker pull --platform linux/amd64 alpine >/dev/null 2>&1
docker pull --platform linux/arm64 alpine >/dev/null 2>&1
docker image inspect --platform linux/amd64 alpine --format 'نسخه‌ی اول: {{.Os}}/{{.Architecture}}'
docker image inspect --platform linux/arm64 alpine --format 'نسخه‌ی دوم: {{.Os}}/{{.Architecture}}'
echo "معماری daemon من: $(docker version --format '{{.Server.Arch}}')"
echo "--- اجرای نسخه‌ی معماری دیگر:"
docker run --rm --platform linux/amd64 alpine uname -m 2>&1 | tail -1
docker run --rm --platform linux/arm64 alpine uname -m 2>&1 | tail -1
خروجی
نسخه‌ی اول: linux/amd64
نسخه‌ی دوم: linux/arm64
معماری daemon من: arm64
--- اجرای نسخه‌ی معماری دیگر:
exec /bin/uname: exec format error
aarch64

--platform معماری مشخص را می‌کشد (و docker image inspect --platform همان را نشان می‌دهد). روی ماشین من (Apple Silicon، معماری arm64) نسخه‌ی amd64 اجرا نمی‌شود و خطای exec format error می‌دهد؛ یعنی بدون شبیه‌ساز، باینری برای CPU دیگر قابل اجرا نیست. روی ماشین amd64 نتیجه برعکس است. برای ساخت image مخصوص سرور: docker build --platform linux/amd64 -t myapp . (با شبیه‌ساز کار می‌کند ولی کندتر است). و بعد از load روی سرور: docker image inspect IMG --format '{{.Architecture}}'.

docker export محتوای فایل‌سیستم یک کانتینر را در tar می‌ریزد؛ نه لایه‌ها، نه CMD، نه ENV. docker import آن را به یک image تک‌لایه و بدون متادیتا تبدیل می‌کند:

Terminal window
docker create --name lx-exp lx-app:1.0 >/dev/null
docker export lx-exp -o exp.tar
docker import exp.tar lx-imported:1.0 >/dev/null
echo "CMD در image اصلی: $(docker image inspect lx-app:1.0 --format '{{.Config.Cmd}}')"
echo "CMD بعد از export/import: $(docker image inspect lx-imported:1.0 --format '{{.Config.Cmd}}')"
echo "لایه‌ها: اصلی=$(docker image inspect lx-app:1.0 --format '{{len .RootFS.Layers}}') / import‌شده=$(docker image inspect lx-imported:1.0 --format '{{len .RootFS.Layers}}')"
docker rm lx-exp >/dev/null; docker rmi lx-imported:1.0 >/dev/null
خروجی
CMD در image اصلی: [python server.py]
CMD بعد از export/import: []
لایه‌ها: اصلی=6 / import‌شده=1

بعد از export/import، CMD از دست رفت ([]) و لایه‌ها یکی شدند. پس برای جابه‌جایی image همیشه save و load؛ export فقط وقتی که واقعاً فقط فایل‌های یک کانتینر را می‌خواهی.

image در داکر لایه‌هایی با هش است. docker save یک آرشیو استاندارد (OCI) می‌نویسد: index.json و manifest.json می‌گویند «این image از کدام لایه‌ها و با چه پیکربندی ساخته شده»، و هر لایه و هر فایل پیکربندی در blobs/sha256/<هش> است. چون اسم هر بلاب هش محتوایش است، load می‌تواند درستی را بسنجد و لایه‌هایی که از قبل دارد را دوباره ننویسد. همین است که ارسال نسخه‌ی ۲.۰ در مثال ۷ تقریباً فوری بود.

نکته‌های مهم:

  • save و load tag ها را هم می‌برند. اگر دو بار load کنی با نامی که از قبل هست، tag به image جدید منتقل می‌شود و image قبلی بدون tag (dangling) می‌ماند.
  • حجم فایل تقریباً برابر مجموع لایه‌هاست، پس image کوچک (درس کوچک کردن image) انتقال را هم ساده‌تر می‌کند.
  • docker load برای معماری کنترلی ندارد؛ فایل را بدون بررسی می‌پذیرد. خطا بعداً هنگام اجرا می‌آید.
  • فایل tar حاوی همه‌ی محتوای image است، از جمله رازهایی که احتمالاً داخلش مانده (درس امنیت). آن را مثل یک فایل حساس نگه دار.
دستور کار
docker save -o f.tar IMG[:TAG] ... ذخیره‌ی یک یا چند image در فایل
docker save IMG | gzip > f.tar.gz ذخیره و فشرده‌سازی
docker load -i f.tar[.gz] بازگرداندن image ها از فایل
docker load < f.tar همان، از stdin
docker save IMG | ssh host 'docker load' انتقال مستقیم بدون فایل میانی
docker export C -o f.tar فایل‌سیستم یک کانتینر (بدون متادیتا)
docker import f.tar NAME ساخت image تک‌لایه از tar فایل‌سیستم
save/load export/import
image با لایه‌ها، tag و پیکربندی (CMD، ENV،…) فقط فایل‌های یک کانتینر
image را همان‌طور که هست می‌برد یک image تک‌لایه‌ی بی‌متادیتا می‌سازد
برای انتقال image برای گرفتن «عکس فایل‌ها»
Terminal window
docker save -o fake.tar lx-no-such-image:9 2>&1 | head -1 | cut -c1-140
خروجی
Error response from daemon: No such image: lx-no-such-image:9

نام یا tag وجود ندارد. راه‌حل: docker image ls را ببین و نام دقیق را بنویس.

۲) save بدون -o روی ترمینال (نمونه)

Section titled “۲) save بدون -o روی ترمینال (نمونه)”

اگر docker save IMG را بدون -o و بدون > یا | در یک ترمینال تعاملی بزنی، داکر داده‌ی باینری را روی صفحه نمی‌ریزد و خطا می‌دهد (این حالت در اسکریپت خودکار قابل اجرا نیست، پس متن زیر «نمونه» است و اجرا نشده):

نمونه‌ی خروجی (اجرا نشده)
cowardly refusing to save to a terminal. Use the -o flag or redirect.

راه‌حل: همیشه -o فایل یا > فایل یا | ... بگذار.

۳) load از فایلی که image نیست

Section titled “۳) load از فایلی که image نیست”
Terminal window
echo "این tar نیست" > fake.tar
docker load -i fake.tar 2>&1 | head -1 | cut -c1-120
خروجی
unexpected EOF

فایل فرمت درست ندارد (مثلاً دانلود ناقص یا فایلی که با export ساخته شده). راه‌حل: هش فایل را با مبدأ مقایسه کن؛ فایل export را با import باز کن نه load.

مثال ۹: image یک معماری روی معماری دیگر اجرا نمی‌شود (یا با شبیه‌ساز کند اجرا می‌شود). راه‌حل: با --platform برای معماری سرور بساز یا بکش.

۵) گرفتن فایل‌های بزرگ در یک مرحله از شبکه‌ی ناپایدار

Section titled “۵) گرفتن فایل‌های بزرگ در یک مرحله از شبکه‌ی ناپایدار”

یک انتقال چند‌گیگابایتی ممکن است وسط قطع شود. راه‌حل: فایل را روی دیسک بگیر و با rsync --partial -e ssh (ادامه‌پذیر) بفرست؛ بعد هش را بسنج.

✎ تمرینآسان

image alpine را با docker save در فایلی به اسم a.tar بریز، حجمش را ببین و با tar -tf بررسی کن فایل manifest.json در آن هست.

دیدن جواب
Terminal window
docker save -o a.tar alpine
ls -l a.tar | awk '{print "a.tar:", $5, "بایت"}'
tar -tf a.tar | grep -x manifest.json
خروجی
a.tar: 8240128 بایت
manifest.json
✎ تمرینمتوسط

تمرین اصلی: یک image را روی سیستم خودت بساز و روی «سرور» load کن. یک Dockerfile ساده (alpine با یک فایل متنی و CMD ["cat","/note.txt"]) بساز، با save | gzip به سرور آزمایشی (lx-srv از مثال ۴) بفرست، روی آن load کن و آن را اجرا کن.

دیدن جواب
Terminal window
mkdir -p e2 && printf 'FROM alpine\nRUN echo "سلام از سرور بدون اینترنت" > /note.txt\nCMD ["cat", "/note.txt"]\n' > e2/Dockerfile
docker build -q -t lx-note:1.0 e2 >/dev/null
SSHOPT="-i $PWD/off/key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o BatchMode=yes"
docker save lx-note:1.0 | gzip | ssh $SSHOPT -p 2299 root@localhost 'gunzip | docker load'
ssh $SSHOPT -p 2299 root@localhost 'docker run --rm lx-note:1.0'
docker rmi lx-note:1.0 >/dev/null
خروجی
Loaded image: lx-note:1.0
سلام از سرور بدون اینترنت
✎ تمرینسخت

دو image (lx-app:1.0 و alpine) را در یک فایل به‌همراه یک فایل هش (SHA256SUMS) بفرست و روی سرور اول هش را بسنج (sha256sum -c) و بعد load کن؛ در پایان ثابت کن هر دو image روی سرور هستند. (روی سرور sha256sum از busybox هست.)

دیدن جواب
Terminal window
SSHOPT="-i $PWD/off/key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o BatchMode=yes"
docker save -o pack.tar lx-app:1.0 alpine
shasum -a 256 pack.tar | sed 's# pack.tar# /var/tmp/pack.tar#' > SHA256SUMS
scp -q $SSHOPT -P 2299 pack.tar SHA256SUMS root@localhost:/var/tmp/
ssh $SSHOPT -p 2299 root@localhost 'cd /var/tmp && sha256sum -c SHA256SUMS && docker load -i pack.tar && docker images --format "{{.Repository}}:{{.Tag}}" | sort'
خروجی
/var/tmp/pack.tar: OK
Loaded image: lx-app:1.0
Loaded image: alpine:latest
alpine:latest
lx-app:1.0
lx-app:2.0
lx-note:1.0
؟ آزمونک
  1. docker save چه چیزی را ذخیره می‌کند؟

  2. فرق export با save؟

  3. دستور مقصد برای فایل app.tar.gz؟

  4. کدام یک بدون ساخت فایل میانی منتقل می‌کند؟

  5. مهم‌ترین چیزی که باید قبل از انتقال به سرور بررسی کنی؟

  6. چرا ارسال دوباره‌ی نسخه‌ی جدید با لایه‌های مشترک سریع است؟

  • docker save -o f.tar IMG (یا | gzip) image را در فایل می‌گذارد؛ docker load -i f.tar[.gz] برمی‌گرداند؛ tag ها همراه می‌روند.
  • انتقال: scp، یا خط لوله‌ی docker save IMG | gzip | ssh host 'gunzip | docker load' بدون فایل میانی.
  • درستی را با sha256sum فایل و مقایسه‌ی شناسه‌ی image (docker image inspect --format '{{.Id}}') بسنج.
  • معماری مبدأ و سرور باید یکی باشد؛ با --platform بساز یا بکش.
  • export/import فقط فایل‌های یک کانتینر را می‌برد (بدون CMD و لایه‌ها)؛ برای انتقال image نه.
  • فایل tar همه‌ی محتوای image را دارد؛ مثل یک فایل حساس نگهش دار.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
docker save -o app.tar myapp:1.0ذخیره‌ی image در فایل
docker save myapp:1.0 | gzip > app.tar.gzذخیره‌ی فشرده
docker load -i app.tar.gzبازگرداندن image از فایل
docker save myapp | gzip | ssh host 'gunzip | docker load'انتقال مستقیم بدون فایل میانی
scp app.tar.gz user@host:/path/کپی فایل به سرور
docker save -o pack.tar a bچند image در یک فایل
docker image inspect IMG --format '{{.Architecture}}'معماری image
docker pull --platform linux/amd64 IMGگرفتن نسخه‌ی معماری مشخص
docker export C -o f.tarفایل‌سیستم کانتینر (نه برای انتقال image)