Перейти к содержимому

Docker как сохранить изменения в контейнере

  • автор:

Учебник. Сохранение данных в приложении-контейнере с помощью томов в VS Code

Из этого учебника вы узнаете, как сохранять данные в приложении-контейнере. При запуске или обновлении данные по-прежнему остаются доступными. Существует два основных типа томов, используемых для хранения данных. В этом учебнике основное внимание уделяется именованным томам.

Кроме того, вы узнаете о подключениях привязок, которые контролируют точку подключения на узле. Подключение привязки можно использовать для хранения данных, однако оно также может привести к добавлению дополнительных данных в контейнеры. При работе с приложением можно использовать подключение BIND для подключения исходного кода к контейнеру, чтобы он мог видеть изменения в коде, реагировать и сразу отображать изменения.

В этом учебнике также рассматриваются слои в образе, кэширование слоев и многоэтапные сборки.

В этом руководстве описано следующее:

  • Общие сведения о данных в контейнерах.
  • Сохранение данных с помощью именованных томов.
  • Использование подключений привязок.
  • Просмотр слоя образа.
  • Кэширование зависимостей.
  • Общие сведения о многоэтапных сборках.

Необходимые компоненты

Этот учебник является продолжением предыдущего — Создание приложения Docker и предоставление к нему общего доступа с помощью Visual Studio Code. Начните с первого учебника, поскольку в нем приводятся предварительные требования.

Общие сведения о данных в контейнерах

В этом разделе вы запустите два контейнера и создайте файл в каждом из них. Файлы, созданные в одном контейнере, недоступны в другом.

    Запустите контейнер ubuntu с помощью следующей команды:

docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null" 

Screenshot shows the Docker extension with a container selected and a context menu with Attach Shell selected.

Эта команда запускает две команды с помощью && . Первая часть выбирает одно случайное число и записывает его в файл /data.txt . Вторая команда наблюдает за файлом, чтобы работа контейнера не прекращалась.

  • В VS Code в области Docker щелкните правой кнопкой мыши контейнер Ubuntu и выберите команду Присоединить оболочку. Откроется терминал с запущенной оболочкой в контейнере Ubuntu.
  • Выполните следующую команду, чтобы просмотреть содержимое файла /data.txt .

    cat /data.txt 

    В терминале отображается число от 1 до 10000. Чтобы использовать командную строку для просмотра этого результата, получите идентификатор контейнера с помощью команды docker ps и выполните следующую команду.

    docker exec cat /data.txt 
    docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null" 
    docker run -it ubuntu ls / 

    Сохранение данных приложения Todo с помощью именованных томов

    По умолчанию приложение todo сохраняет данные в базе данных SQLite в /etc/todos/todo.db . База данных SQLite — это реляционная база данных, которая хранит данные в одном файле. Этот подход приемлем для небольших проектов.

    Можно сохранить один файл на узле. Когда вы сделаете его доступным для следующего контейнера, приложение сможет продолжить работу с того места, где оно было остановлено. Создавая том и присоединяя его (или подключая) к папке, в которой хранятся данные, можно сохранить данные. Контейнер выполняет запись в файл todo.db, и эти данные сохраняются на узле в томе.

    Для выполнения инструкций в этом разделе используется именованный том. Docker сохраняет физическое расположение тома на диске. Укажите имя тома, и Docker предоставит правильные данные.

      Создайте том с помощью команды docker volume create .

    docker volume create todo-db 
    docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started 

    Screenshot shows the sample app with several items added to the list.

    Параметр volume указывает том для подключения и расположение ( /etc/todos ).

  • Обновите браузер, чтобы перезагрузить приложение. Если вы закрыли окно браузера, перейдите по адресу http://localhost:3000/ . Добавьте несколько элементов в список дел.
  • Удалите контейнер getting-started для приложения Todo. Щелкните правой кнопкой мыши контейнер в области Docker и выберите Удалить либо используйте команды docker stop и docker rm .
  • Запустите новый контейнер с помощью той же команды:

    docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started 

    Именованные тома и подключения привязок, рассматриваемые ниже, являются основными типами томов, поддерживаемыми установкой подсистемы Docker по умолчанию.

    Свойство Именованные тома Привязка подключений
    Расположение узла Выбирает Docker Указываете вы
    Пример подключения (с использованием -v ) my-volume:/usr/local/data /path/to/data:/usr/local/data
    Заполняет новый том содержимым контейнера Да Нет
    Поддерживает драйверы томов Да Нет

    Существует множество подключаемых модулей драйверов томов для поддержки NFS, SFTP, NetApp и т. д. Эти подключаемые модули особенно важны для запуска контейнеров на нескольких узлах в кластеризованной среде, такой как Swarm или Kubernetes.

    Чтобы узнать, где Docker на самом деле хранит ваши данные, выполните следующую команду.

    docker volume inspect todo-db 

    Взгляните на выходные данные, приведенные ниже.

    [ < "CreatedAt": "2019-09-26T02:18:36Z", "Driver": "local", "Labels": <>, "Mountpoint": "/var/lib/docker/volumes/todo-db/_data", "Name": "todo-db", "Options": <>, "Scope": "local" > ] 

    Mountpoint — это фактическое расположение, в котором хранятся данные. На большинстве компьютеров для доступа к этому каталогу с узла необходим доступ с правами root.

    Использование подключения BIND

    Подключения BIND позволяют указать точную точку подключения на узле. Этот подход сохраняет данные, но часто используется для добавления большого объема данных в контейнеры. Подключение привязки можно использовать для подключения исходного кода к контейнеру, чтобы он мог видеть изменения в коде, реагировать и сразу отображать изменения.

    Чтобы запустить контейнер для поддержки рабочего процесса разработки, выполните приведенные ниже действия.

    1. Удалите все контейнеры getting-started .
    2. В папке app выполните следующую команду.

    docker run -dp 3000:3000 -w /app -v $:/app node:20-alpine sh -c "yarn install && yarn run dev" 
    • -dp 3000:3000 — то же, что и раньше. Выполните команду в отключенном режиме и создайте сопоставление портов.
    • -w /app — рабочий каталог внутри контейнера.
    • -v $:/app» — подключение текущего каталога из узла в контейнере к каталогу /app .
    • node:20-alpine — используемый образ. Это базовый образ для вашего приложения из Dockerfile.
    • sh -c «yarn install && yarn run dev» — команда. Она запускает оболочку, используя sh , и выполняет yarn install для установки всех зависимостей. Затем она выполняет yarn run dev . Если взглянуть на package.json , сценарий dev запускает nodemon .
    docker logs -f
    $ nodemon src/index.js [nodemon] 2.0.20 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node src/index.js` Using sqlite database at /etc/todos/todo.db Listening on port 3000 

    Screenshot shows the sample app with the new text on the button.

    Сохраните изменения.

  • Обновите свой браузер. Вы должны увидеть изменение.
  • Просмотр слоев образа

    Можно просмотреть слои, составляющие образ. Выполните команду docker image history , чтобы просмотреть команды, которые использовались для создания каждого слоя в образе.

      Используйте docker image history для просмотра слоев в образе getting-started, созданном ранее в этом учебнике.

    docker image history getting-started 

    Результат должен быть похож на выходные данные, приведенные ниже.

    IMAGE CREATED CREATED BY SIZE COMMENT a78a40cbf866 18 seconds ago /bin/sh -c #(nop) CMD ["node" "/app/src/ind… 0B f1d1808565d6 19 seconds ago /bin/sh -c yarn install --production 85.4MB a2c054d14948 36 seconds ago /bin/sh -c #(nop) COPY dir:5dc710ad87c789593… 198kB 9577ae713121 37 seconds ago /bin/sh -c #(nop) WORKDIR /app 0B b95baba1cfdb 13 days ago /bin/sh -c #(nop) CMD ["node"] 0B 13 days ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B 13 days ago /bin/sh -c #(nop) COPY file:238737301d473041… 116B 13 days ago /bin/sh -c apk add --no-cache --virtual .bui… 5.35MB 13 days ago /bin/sh -c #(nop) ENV YARN_VERSION=1.21.1 0B 13 days ago /bin/sh -c addgroup -g 1000 node && addu… 74.3MB 13 days ago /bin/sh -c #(nop) ENV NODE_VERSION=12.14.1 0B 13 days ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B 13 days ago /bin/sh -c #(nop) ADD file:e69d441d729412d24… 5.59MB 
    docker image history --no-trunc getting-started 

    Кэширование зависимостей

    После изменения слоя все нижестоящие слои также необходимо создать заново. Вот Dockerfile:

    FROM node:20-alpine WORKDIR /app COPY . . RUN yarn install --production CMD ["node", "/app/src/index.js"] 

    Каждая команда в Dockerfile становится новым слоем в образе. Чтобы максимально сократить количество слоев, можно изменить структуру Dockerfile для поддержки кэширования зависимостей. Для приложений на основе узлов эти зависимости определяются в файле package.json .

    Подход заключается в том, чтобы сначала скопировать только этот файл, установить зависимости и затем скопировать все остальное. Повторное создавать зависимости Yarn нужно будет только в том случае, если было внесено изменение в файл package.json .

      Сначала измените Dockerfile, чтобы выполнить копирование в package.json , установите зависимости, а затем скопируйте все остальное. Вот новый файл:

    FROM node:20-alpine WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install --production COPY . . CMD ["node", "/app/src/index.js"] 
    docker build -t getting-started . 

    Вы должны увидеть выходные данные, аналогичные приведенным ниже.

    Sending build context to Docker daemon 219.1kB Step 1/6 : FROM node:12-alpine ---> b0dc3a5e5e9e Step 2/6 : WORKDIR /app ---> Using cache ---> 9577ae713121 Step 3/6 : COPY package* yarn.lock ./ ---> bd5306f49fc8 Step 4/6 : RUN yarn install --production ---> Running in d53a06c9e4c2 yarn install v1.17.3 [1/4] Resolving packages. [2/4] Fetching packages. info fsevents@1.2.9: The platform "linux" is incompatible with this module. info "fsevents@1.2.9" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies. [4/4] Building fresh packages. Done in 10.89s. Removing intermediate container d53a06c9e4c2 ---> 4e68fbc2d704 Step 5/6 : COPY . . ---> a239a11f68d8 Step 6/6 : CMD ["node", "/app/src/index.js"] ---> Running in 49999f68df8f Removing intermediate container 49999f68df8f ---> e709c03bc597 Successfully built e709c03bc597 Successfully tagged getting-started:latest 
    Sending build context to Docker daemon 219.1kB Step 1/6 : FROM node:12-alpine ---> b0dc3a5e5e9e Step 2/6 : WORKDIR /app ---> Using cache ---> 9577ae713121 Step 3/6 : COPY package* yarn.lock ./ ---> Using cache ---> bd5306f49fc8 Step 4/6 : RUN yarn install --production ---> Using cache ---> 4e68fbc2d704 Step 5/6 : COPY . . ---> cccde25a3d9a Step 6/6 : CMD ["node", "/app/src/index.js"] ---> Running in 2be75662c150 Removing intermediate container 2be75662c150 ---> 458e5c6f080c Successfully built 458e5c6f080c Successfully tagged getting-started:latest 

    Многоэтапная сборка

    Многоэтапные сборки — невероятно мощное средство для использования нескольких этапов при создании образа. У них есть несколько преимуществ.

    • Отделение зависимостей времени сборки от зависимостей среды выполнения.
    • Уменьшение общего размера образа за счет доставки только того, что нужно вашему приложению для работы.

    В этом разделе приводятся краткие примеры.

    Пример с Maven и Tomcat

    При создании приложений на основе Java для компиляции исходного кода в байт-код Java требуется JDK. JDK не требуется в рабочей среде. Для упрощения сборки приложения можно использовать такие средства, как Maven или Gradle. Они также не нужны в окончательном образе.

    FROM maven AS build WORKDIR /app COPY . . RUN mvn package FROM tomcat COPY --from=build /app/target/file.war /usr/local/tomcat/webapps 

    В этом примере один этап ( build ) используется для выполнения фактической сборки Java с помощью Maven. Второй этап (начиная с «FROM tomcat») копирует в файлы с этапа build . Окончательный образ создается только на последнем этапе (что можно переопределить с помощью параметра —target ).

    Пример React

    При создании приложений React требуется среда Node для компиляции кода JavaScript, таблиц стилей SASS и др. в статический HTML, JavaScript и CSS. Если вы не выполняете отрисовку на стороне сервера, вам даже не нужна среда узла для рабочей сборки.

    FROM node:20-alpine AS build WORKDIR /app COPY package* yarn.lock ./ RUN yarn install COPY public ./public COPY src ./src RUN yarn run build FROM nginx:alpine COPY --from=build /app/build /usr/share/nginx/html 

    В этом примере для выполнения сборки используется образ node:20 , который максимально эффективно кэширует слой, а затем копирует выходные данные в контейнер nginx.

    Очистка ресурсов

    Чтобы продолжить работу с этой серией учебников, оставьте все настройки, сделанные на данный момент.

    Следующие шаги

    Вы узнали о вариантах сохранения данных для приложений-контейнеров.

    Что вы хотите сделать дальше?

    • Работа с несколькими контейнерами с помощью Docker Compose: Создание многоконтейнерных приложений с помощью MySQL и Docker Compose
    • Развертывание в приложениях контейнеров Azure:
      • Краткое руководство. Развертывание в приложениях контейнеров Azure с помощью Visual Studio Code
      • Руководство по развертыванию в приложениях контейнеров Azure
      • Развертывание контейнерного приложения в Azure

      Сохранить изменения в docker

      Запустил docker с образом ubuntu. Обновил, поменял конфиги, вышел, зашел и ничего не сохранилось. Как правильно сохранять изменения в docker? Гугл предлагает сохранение образа, а мне надо сохранять изменения внутри контейнера.

      NoobeR ★★★★
      30.05.16 18:00:16 MSK

      Use volumes, Luke!

      theNamelessOne ★★★★★
      ( 30.05.16 18:02:09 MSK )

      монтируй вольюм и пиши в него

      leave ★★★★★
      ( 30.05.16 18:02:43 MSK )

      Но скорее всего ты хочешь странного от докера.

      staseg ★★★★★
      ( 30.05.16 18:03:06 MSK )
      Последнее исправление: staseg 30.05.16 18:03:33 MSK (всего исправлений: 1)

      Ответ на: комментарий от staseg 30.05.16 18:03:06 MSK

      я хочу обновить ПО, подредачить конфиги и потом запускать с этими изменениями, а не делать всё с нуля

      NoobeR ★★★★
      ( 30.05.16 18:04:44 MSK ) автор топика
      Ответ на: комментарий от NoobeR 30.05.16 18:04:44 MSK

      Тащемта, ты запускаешь контейнер на основе какого-то образа, редактируешь в нём конфиги, коммитишь изменения и получаешь уже новый образ, в котором эти изменения зафиксированы.

      theNamelessOne ★★★★★
      ( 30.05.16 18:06:22 MSK )
      Ответ на: комментарий от NoobeR 30.05.16 18:04:44 MSK

      Смотри эту ссылку, обращай внимания на картинки и описания к ним.

      theNamelessOne ★★★★★
      ( 30.05.16 18:07:40 MSK )
      Ответ на: комментарий от NoobeR 30.05.16 18:04:44 MSK

      Обновлять ПО вручную 99% не надо, просто используй свежий образ. Или создай его сам с помощью docker commit или Dockerfile. Конфиги и персистентные стораджи лучше просовывать с помощью volumes.

      staseg ★★★★★
      ( 30.05.16 18:09:26 MSK )
      Ответ на: комментарий от staseg 30.05.16 18:09:26 MSK

      А, и еще важно понять разницу между контейнером и образом, у многих из-за этого каша в голове.

      staseg ★★★★★
      ( 30.05.16 18:10:25 MSK )
      Ответ на: комментарий от staseg 30.05.16 18:10:25 MSK

      контейнер это то, что работает, а образ это то, из чего создаем контейнер?

      NoobeR ★★★★
      ( 30.05.16 18:23:29 MSK ) автор топика
      Ответ на: комментарий от NoobeR 30.05.16 18:23:29 MSK

      Образ — это совокупность неизменяемых “слоев” (layers), представляющих различия (differences) в состояниях файловой системы. Контейнер — это рантайм-инстанс образа. Как я уже сказал, образа сами по себе неизменяемы, однако контейнеры содержат вдобавок к неизменяемым слоям образа содержат доступный для записи слой, в котором отражаются его изменения. Когда ты запустил контейнер и внёс изменения в конфиги, эти изменения записались в этот самый слой контейнера. Чтобы зафиксировать эти изменения, есть команда docker commit , которая создаёт из контейнера новый образ, добавляя его доступный для записи слой поверх неизменяемых слоёв базового контейнера. Можно также описывать изменения базового слоя декларативно с помощью Dockerfile .

      theNamelessOne ★★★★★
      ( 30.05.16 18:34:46 MSK )
      Ответ на: комментарий от theNamelessOne 30.05.16 18:34:46 MSK

      NoobeR ★★★★
      ( 30.05.16 18:37:03 MSK ) автор топика
      Ответ на: комментарий от theNamelessOne 30.05.16 18:34:46 MSK

      Можно также описывать изменения базового слоя декларативно с помощью Dockerfile .

      Можно также описывать изменения базового образа декларативно с помощью Dockerfile .

      Посмотри ещё на volume’ы, вполне возможно, для твоей задачи они будут предпочтительней.

      theNamelessOne ★★★★★
      ( 30.05.16 18:42:53 MSK )
      Ответ на: Fix от theNamelessOne 30.05.16 18:42:53 MSK

      я и так использую тома, для хранения самих сайтов (~/www). в контейнере ~/www смонтирован в /var/www/srv. если это правильно..

      NoobeR ★★★★
      ( 30.05.16 18:47:32 MSK ) автор топика
      Ответ на: комментарий от NoobeR 30.05.16 18:47:32 MSK

      Ну так можно с помощью томов примонтировать конфиги.

      theNamelessOne ★★★★★
      ( 30.05.16 18:54:50 MSK )
      Ответ на: комментарий от theNamelessOne 30.05.16 18:54:50 MSK

      что-то вроде ~/www/config/:/etc/apache2/sites-available ?

      NoobeR ★★★★
      ( 30.05.16 18:56:46 MSK ) автор топика
      Ответ на: комментарий от NoobeR 30.05.16 18:56:46 MSK

      Насколько я знаю, в таком случае в типовой конфигурации апача ещё требуется симлинк в sites-enabled , так что лучше сразу монтировать туда.

      theNamelessOne ★★★★★
      ( 30.05.16 19:00:09 MSK )
      Ответ на: комментарий от theNamelessOne 30.05.16 19:00:09 MSK

      NoobeR ★★★★
      ( 30.05.16 19:01:59 MSK ) автор топика
      Ответ на: комментарий от NoobeR 30.05.16 18:04:44 MSK

      я хочу обновить ПО, подредачить конфиги и потом запускать с этими изменениями, а не делать всё с нуля

      Если ты хочешь ручками что-то править в системе и работать с контейнером как с отдельным компьютером, то тебе нужно смотреть не на Docker, а на LXC.

      В Docker же твоя задача решается так:

      — Делаем Dockerfile для твоих изменений (исходный образ + действия в нём)
      — Из Dockerfile делаем image (или это сделает автоматом docker-compose)
      — Запускаем docker-образ, монтируя внутрь него индивидуальные для контейнера конфиги, сохраняемые данные и т.п.

      Если тебе требуется сохранять сделанные в Docker изменения, то 99% за то, что ты делаешь что-то не так.

      Не могу сохранить изменения в контейнере докера

      Я с хоста коппирую файл в докер (docker cp file.txt 4f20e373e04b: / root) захожу в диркторирию докера и там есть этот файл. Но только я перезапускаю докер этот файлик пропадаеа.Запускаю докер командой docker run -p 5000: 5000 lorry- server.Я новичок в докерах , помогите пожалуста)

      Отслеживать
      задан 6 мар 2019 в 13:42
      Андрій Гавриляк Андрій Гавриляк
      69 1 1 серебряный знак 9 9 бронзовых знаков

      2 ответа 2

      Сортировка: Сброс на вариант по умолчанию

      Данные в контейнере сохраняться, если Вы остановите просто остановите контейнер, а не удалите.

      # запуск контейнера (без опции --rm) docker run --name foo . # скопировали туда файлик docker cp . # остановили контейнер docker stop foo # запустили контейнер, файлик еще там docker start foo # остановили и удалили контейнер docker stop foo && docker rm foo # файлик утерян навсегда, надо снова делать docker run и docker cp 

      А вообще, чтоб не делать лишних телодвижений рекомендую использовать опцию -v в команде docker run , тогда Ваш файл будет всегда в контейнере

      docker run -v /path/to/file.txt:/path/inside/container/file.txt 

      Как сохранить свои изменения во взятом Docker-образе для последующего повторного использования?

      Несмотря на возможность сделать docker commit , то, что Вы получите в результате, будет чёрным ящиком, который непонятно каким образом создан. Хорошая практика в данном случае заключается в том, чтобы описать все изменения, которые Вы производите в контейнере, с помощью Dockerfile -а. Этот Dockerfile можно будет сохранить в системе контроля версий, провести его ревью, модифицировать, воспроизвести в сборочном конвеере.

      Да, под капотом на каждую строчку в Dockerfile -е происходит вызов docker commit , но важно то, что в этом случает сохраняется источник этих изменений.

      Не знаю, как точно настраивается FreePBX, но Вам может понадобиться, например, использовать envsubst для применения переменных окружения, с которыми запущен контейнер, к конфигурационным файлам. А может потребоваться сделать стартовый .sh-скрипт, который при запуске произведёт нужные
      конфигурационные действия.

      В случае использования переменных окружения также очень полезно в скрипте запуска проверить, заданы ли они, и если нет — упасть с осмысленным сообщением об ошибке:

      echo MY_ENV_VAR "$"

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *