Как скопировать файлы из Docker-контейнера на хост и обратно
Скопировать файл из контейнера в текущую папку:
docker cp app:/app/config.yml .
app — имя или ID контейнера из docker ps. Первый путь — внутри контейнера, второй — на вашем компьютере. Чтобы сразу переименовать файл, укажите новое имя: ./config.backup.yml. Если такой файл уже есть, Docker перезапишет его без вопросов.
Проверено на Docker 29.7 и Docker Compose 5.5 с контейнерами Alpine 3.24 и nginx:alpine.
Как узнать имя контейнера и путь к файлу
docker ps -a
docker exec app ls -l /app
docker ps -a показывает и остановленные контейнеры. Путь в контейнере всегда отсчитывается от корня: рабочую директорию docker cp не учитывает. Если WORKDIR контейнера — /app, то app:config.yml означает /config.yml. Полный путь к файлу из WORKDIR покажет docker exec app readlink -f config.yml.
Как скопировать папку из контейнера
# ./logs нет: Docker создаст её и положит туда файлы
docker cp app:/app/logs ./logs
# ./backup есть: получится ./backup/logs
docker cp app:/app/logs ./backup
# только содержимое: ./backup/a.log, ./backup/b.log
docker cp app:/app/logs/. ./backup
Если папки назначения нет, Docker создаёт её и кладёт туда содержимое исходной папки. Если она есть, исходная папка окажется внутри. Исключение — источник с /. на конце: тогда копируется только содержимое. Один слэш на конце (logs/) ничего не меняет.
Как скопировать файл с хоста в контейнер
Поменяйте аргументы местами:
docker cp ./settings.yml app:/app/
# получится /srv/static
docker cp ./static app:/srv
# содержимое static попадёт в /var/www
docker cp ./static/. app:/var/www
Правила для папок те же. Скопированный файл живёт только в этом контейнере: после docker rm или docker compose up --force-recreate его не будет. Файлы, без которых приложение не работает, кладите в образ (COPY в Dockerfile) или в том (volume).
Как скопировать файл внутри контейнера или между контейнерами
Скопировать файл внутри контейнера можно обычным cp:
docker exec app cp /app/config.yml /app/config.bak
Чтобы скопировать файлы между двумя контейнерами, передайте вывод одного docker cp в другой:
docker cp app:/app/logs - | docker cp - other:/tmp
Остановленный контейнер тоже подойдёт
docker cp работает с остановленными контейнерами в обе стороны. Если контейнер падает при старте, достаньте из него логи, положите исправленный конфиг и запустите docker start app. Файлы из томов тоже копируются.
docker compose cp
В папке с compose.yaml вместо имени контейнера пишите имя сервиса:
docker compose cp web:/app/config.yml .
docker compose cp ./override.yml web:/app/
Если у сервиса несколько реплик, при копировании в сервис файл попадёт в каждую. При копировании из сервиса Compose возьмёт файл у одной реплики, не обязательно у первой. Нужную выберите через --index:
docker compose cp --index 2 web:/app/config.yml .
С остановленными сервисами docker compose cp тоже работает.
Права и владелец файлов
Права доступа (rwx) сохраняются в обе стороны. Владелец сохраняется только при копировании в контейнер, и только как числа UID и GID.
Из контейнера на хост: файлы принадлежат тому, кто запустил docker cp. Поэтому после sudo docker cp в Linux файлы на хосте принадлежат root. Вернуть их себе:
sudo chown -R "$(id -u):$(id -g)" ./logs
Чтобы обходиться без sudo, добавьте себя в группу docker (sudo usermod -aG docker $USER) и перелогиньтесь, как с любой новой группой. Учтите: эта группа даёт на машине права root.
С хоста в контейнер: файлы сохраняют числовые UID и GID, которые были у них на хосте, и sudo docker cp их не меняет. У обычного пользователя Linux это 1000:1000, на Mac — 501:20. Если приложение в контейнере работает под другим пользователем, записать в такой файл оно не сможет: Permission denied. С флагом -a Docker отдаёт файлы пользователю контейнера, тому, что задан в --user или USER в Dockerfile:
docker cp -a ./settings.yml app:/app/
Если ни --user, ни USER не заданы, -a ничего не меняет. При копировании из контейнера флаг тоже ни на что не влияет. Поменять владельца потом: docker exec -u 0 app chown 1000:1000 /app/settings.yml.
Как достать файл из образа
docker cp работает только с контейнером, но запускать его не обязательно. docker create создаёт контейнер из образа и ничего не запускает:
docker create --name tmp nginx:alpine
docker cp tmp:/etc/nginx/nginx.conf .
docker rm tmp
Если у образа нет команды по умолчанию (FROM scratch), Docker ответит no command specified. Передайте любую команду, выполнять её никто не будет:
docker create --name tmp my-image none
Как передать tar-архив через -
Если вместо локального пути написать -, docker cp выдаст tar-архив в stdout или прочитает его из stdin:
docker cp app:/app/logs - > logs.tar
docker cp app:/app/logs - | gzip > logs.tar.gz
tar -c -C ./site . | docker cp - app:/var/www
При чтении из stdin папка назначения должна существовать, архив в gzip тоже подойдёт. На Mac tar добавляет в архив расширенные атрибуты, и Docker падает с ошибкой xattr "com.apple.provenance": operation not supported. Упакуйте без них:
COPYFILE_DISABLE=1 tar --no-xattrs -c -C ./site . | docker cp - app:/var/www
У обычного docker cp ./site/. app:/var/www такой проблемы нет.
Как скопировать файлы по маске или из tmpfs
Маски docker cp не раскрывает: docker cp 'app:/app/logs/*.log' . закончится ошибкой. В tmpfs он видит пустую папку, а /proc, /sys и /dev не читает вовсе. В таких случаях запустите tar в работающем контейнере:
mkdir -p logs scratch
docker exec app sh -c 'cd /app/logs && tar -c *.log' | tar -x -C ./logs
docker exec app tar -c -C /scratch . | tar -x -C ./scratch
docker exec здесь без -t: с терминалом архив придёт битым.
Как скопировать файл из контейнера в Windows
В PowerShell команда та же. Путь с буквой диска Docker считает локальным:
docker cp app:/app/config.yml C:\Users\me\Desktop
Частые ошибки
No such container: app— контейнера с таким именем или ID нет, сверьтесь сdocker ps -a. Compose называет контейнеры видаproject-web-1, а вdocker compose cpнужно имя сервиса.Could not find the file /app/config.yml in container app— неверный путь в контейнере. При копировании в контейнер ошибка значит, что нет папки, куда вы копируете: дляapp:/app/conf/settings.ymlэто/app/conf. Та же ошибка бывает с путями от WORKDIR, с масками и с файлами в tmpfs.no such directoryилиinvalid output path: directory "…" does not exist— нет папки назначения на хосте или в контейнере. Создайте её черезmkdir -p, в контейнере —docker exec app mkdir -p /app/conf.cannot copy directory— вы копируете папку поверх существующего файла.copying between containers is not supported— в обоих аргументах есть двоеточие. Если двоеточие стоит в имени локального файла, допишите в начало./:./backup:1.yml.must specify at least one container source— ни в одном аргументе нетконтейнер:.container rootfs is marked read-only— контейнер запущен с--read-only. В его тома копировать можно.- Вместо файла пришла битая ссылка: источник был симлинком, и Docker скопировал саму ссылку. С флагом
-Lон скопирует файл, на который она указывает.