Поделиться через


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

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

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

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

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

  • Понять данные в разных контейнерах.
  • Хранить данные с помощью именованных томов.
  • Используйте монтажи с привязкой.
  • Просмотр слоя изображения.
  • Зависимости кэша.
  • Понимание многоэтапных сборок.

Необходимые условия

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

Понимание данных в различных контейнерах

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

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

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

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

  2. В VS Code в обозревателе контейнеров щелкните правой кнопкой мыши контейнер Ubuntu и выберите "Подключить оболочку".

    Снимок экрана показывает расширение

    Откроется терминал, который выполняет оболочку в контейнере Ubuntu.

  3. Выполните следующую команду, чтобы просмотреть содержимое файла /data.txt.

    cat /data.txt
    

    В терминале отображается число от 1 до 10000.

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

    docker exec <container-id> cat /data.txt
    
  4. Запустите другой контейнер ubuntu.

    docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
    
  5. Используйте эту команду для просмотра содержимого папки.

    docker run -it ubuntu ls /
    

    Там не должно быть файла data.txt, так как он был записан в временную область только для первого контейнера.

  6. Выберите эти два контейнера Ubuntu. Щелкните правой кнопкой мыши и выберите Удалить. Из командной строки их можно удалить с помощью команды docker rm -f.

Сохраняйте данные "todo" с помощью именованных томов

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

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

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

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

    docker volume create todo-db
    
  2. В разделе КОНТЕЙНЕРЫвыберите getting-started и кликните правой кнопкой. Выберите «Остановить», чтобы завершить работу контейнера приложения.

    Чтобы остановить контейнер из командной строки, используйте команду docker stop.

  3. Запустите контейнер getting-started с помощью следующей команды.

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

    Параметр тома указывает том для монтирования и его местоположение, /etc/todos.

  4. Обновите браузер, чтобы перезагрузить приложение. Если вы закрыли окно браузера, перейдите к http://localhost:3000/. Добавьте некоторые элементы в список дел.

    снимок экрана: пример приложения с несколькими элементами, добавленными в список.

  5. Удалите контейнер getting-started для приложения для задач. Чтобы удалить, щелкните правой кнопкой мыши контейнер в обозревателе контейнеров и выберите Удалить или используйте команды docker stop и docker rm.

  6. Запустите новый контейнер с помощью той же команды:

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

    Эта команда подключает тот же диск, что и раньше. Обновите браузер. Добавленные элементы по-прежнему находятся в списке.

  7. Удалите контейнер с отметкой , снова.

Именованные тома и подключения привязок, рассмотренные ниже, являются основными типами томов, поддерживаемых установкой ядра 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 — это место, где хранятся данные. На большинстве компьютеров требуется корневой доступ для доступа к этому каталогу с узла.

Используйте привязанные точки монтирования

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

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

  1. Удалите все контейнеры getting-started.

  2. В папке app выполните следующую команду.

    docker run -dp 3000:3000 -w /app -v ${PWD}:/app node:lts-alpine sh -c "yarn install && yarn run dev"
    

    Эта команда содержит следующие параметры.

    • -dp 3000:3000 То же, что и раньше. Запустите в отсоединяемом режиме и создайте сопоставление портов.
    • -w /app рабочая директория внутри контейнера.
    • -v ${PWD}:/app" Привязать текущий каталог из узла в контейнере в каталог /app.
    • node:lts-alpine Используемое изображение. Это базовый образ приложения на основе Dockerfile.
    • sh -c "yarn install && yarn run dev" команду A. Она запускает оболочку с помощью sh и запускает yarn install для установки всех зависимостей. Затем он запускается yarn run dev. При просмотре в package.json, скрипт dev начинается nodemon.
  3. Журналы можно просматривать, используя docker logs.

    docker logs -f <container-id>
    
    $ 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
    

    Когда вы увидите последнюю запись в этом списке, приложение запущено.

    После просмотра журналов нажмите любую клавишу в окне терминала или выберите комбинацию клавиш Ctrl+C во внешнем окне.

  4. В VS Code откройте src/static/js/app.js. Измените текст кнопки Добавить элемент в строке 109.

    - {submitting ? 'Adding...' : 'Add Item'}
    + {submitting ? 'Adding...' : 'Add'}
    

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

  5. Обновите браузер. Вы увидите изменение.

    снимок экрана: пример приложения с новым текстом на кнопке.

  6. node:lts-alpine Удалите контейнер.

  7. В папке app выполните следующую команду, чтобы удалить node_modules папку, созданную на предыдущих шагах.

    rm -r node_modules
    

Просмотр слоев изображений

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

  1. Используйте docker image history, чтобы просмотреть слои в изображении по изучаемой теме, созданном ранее в руководстве.

    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                  
    <missing>           13 days ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B                  
    <missing>           13 days ago         /bin/sh -c #(nop) COPY file:238737301d473041…   116B                
    <missing>           13 days ago         /bin/sh -c apk add --no-cache --virtual .bui…   5.35MB              
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV YARN_VERSION=1.21.1      0B                  
    <missing>           13 days ago         /bin/sh -c addgroup -g 1000 node     && addu…   74.3MB              
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV NODE_VERSION=12.14.1     0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B                  
    <missing>           13 days ago         /bin/sh -c #(nop) ADD file:e69d441d729412d24…   5.59MB   
    

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

  2. Несколько линий усечены. Если добавить параметр --no-trunc, вы получите полные выходные данные.

    docker image history --no-trunc getting-started
    

Зависимости кэша

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

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

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

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

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

    FROM node:lts-alpine
    WORKDIR /app
    COPY package.json yarn.lock ./
    RUN yarn install --production
    COPY . .
    CMD ["node", "/app/src/index.js"]
    
  2. Создайте новый образ с помощью docker build.

    docker build -t getting-started .
    

    Выходные данные должны выглядеть следующим образом:

    Sending build context to Docker daemon  219.1kB
    Step 1/6 : FROM node:lts-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
    

    Все слои были перестроены. Этот результат ожидается, так как вы изменили Dockerfile.

  3. Внесите изменения в src/static/index.html. Например, измените название, чтобы сказать "Удивительное приложение Todo".

  4. Создайте образ Docker теперь с помощью docker build еще раз. На этот раз выходные данные должны выглядеть немного иначе.

    Sending build context to Docker daemon  219.1kB
    Step 1/6 : FROM node:lts-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 JDK требуется для компиляции исходного кода в байт-код Java. Этот 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. Если вы не выполняете отрисовку на стороне сервера, вам даже не нужна среда Node для рабочей сборки.

FROM node:lts-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:lts-alpine, который максимизирует кэширование слоев, а затем копирует выходные данные в контейнер nginx.

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

Сохраните все, что вы сделали до сих пор, чтобы продолжить эту серию учебных материалов.

Дальнейшие действия

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

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