Быстрое введение в Docker

Контейнеры и контейнеризация

Что такое контейнеры

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

Контейнеры изолируют программное обеспечение от его окружения и обеспечивают единообразную работу несмотря на различия, например, между development- и staging-окружениями. Это означает, что становится возможно упаковать приложение вместе со всеми его зависимостями и библиотеками в изолированный пакет, который может быть запущен на любой машине с контейнерной средой исполнения, в том числе Docker.

Что такое контейнеризация

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

Этот подход обеспечивает простое развертывание приложений и их надежную работу при переносе из одной среды в другую.

Выгоды контейнеризации 

  • Согласованность: Приложения ведут себя одинаково независимо от того, где они запущены. 
  • Эффективность: Контейнеры легковесны и совместно используют ядро ОС хоста, потребляя меньше системных ресурсов, чем виртуальные машины. 
  • Масштабируемость: Легче масштабировать приложения по мере укрупнения. 
  • Изолированность: Каждый контейнер работает в изолированном окружении, что повышает безопасность и стабильность.

Что такое Docker 

Docker — это открытая платформа, позволяющая: создавать, развертывать, запускать, обновлять и управлять контейнерными приложениями. 

Почему Docker популярен: он оптимизирует процесс разработки, устраняет источник ссор из-за причин дефектов, возможности масштабирования, а также:

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

Реализация идеи

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

Сегодня Docker поддерживается большим активным сообществом. Также он послужил толчком для развития смежных технологий типа Kubernetes, для оркестрации контейнеров.

Практика Docker

Прежде чем приступить, нужно установить Docker. Он доступен для Windows, macOS и Linux. 

Установка

Следуйте инструкциям на официальном сайте.

После установки убедитесь, что Docker запущен:

docker — version

Архитектура Docker 

Компоненты Docker

В Docker используется клиент-серверная архитектура с такими ключевыми компонентами: 

  • Docker Client: Инструмент командной строки (CLI) для работы пользователей с Docker. Он взаимодействует с Docker-демоном для выполнения команд.
  • Docker Daemon (или Docker Engine): Технология контейнеризации с открытым исходным кодом, которая упаковывает приложения в контейнеры. Демон слушает запросы Docker API и обрабатывает их.
  • containerd: Ключевой компонент, который управляет жизненным циклом контейнеров, включая запуск, остановку и управление процессами контейнеров. 
  • runc: Легкий инструмент CLI для создания и запуска контейнеров в соответствии со спецификацией Open Container Initiative (OCI).
  • Docker Registry: Сервис, который хранит и предоставляет образы Docker. По умолчанию публичным реестром является Docker Hub, но можно использовать и другие реестры. Он работает как github, но в нем размещается не исходный код, а Docker-образы.
  • Docker Networking: Сетевые возможности для контейнеров, позволяя им взаимодействовать друг с другом и внешним миром. 
  • Docker Volumes и Bind Mounts: Хранение и обмен данными между контейнерами и хост-системой. 
  • Docker Compose: Инструмент для определения и запуска мультиконтейнерных приложений с помощью YAML-файла.

Как Docker запускает приложения

  • Сборка: Docker-клиент отправляет запрос на сборку Docker-демону, который создает образ, на основе инструкций в Dockerfile
  • Ship: Образ хранится в реестре Docker (публичном или частном), откуда его можно загрузить. 
  • Run: Docker-клиент запрашивает демона Docker для создания и запуска контейнера на основе образа.

Образы Docker 

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

Загрузка образа из Docker Hub (Pull) 

Команда получения образа из Docker Hub:

docker pull hello-world

После получения образа его можно запустить командой docker run. 

Разницу между образом и контейнером легко представить следующим образом: контейнер — это когда вы запускаете node app.js на своей машине из исходного кода, полученного с github, а образ — это ваша кодовая база на github.

Основные команды docker

1.) Проверка версии Docker

docker version

2) Просмотр общесистемной информации о Docker

docker info

3) Список всех образов Docker

docker images

4.) Список запущенных контейнеров

docker ps

docker ps -a      // List All Containers (Running and Stopped)

5.) Получение образа из реестра

docker pull node:20      // Here 20 specifies a specific version of the node we want to pull

6.) Создание и запуск нового контейнера из образа

В приведенном ниже примере мы развертываем сервер NGINX в detached-режиме (-d), соединяя порт хоста 8080 с портом контейнера 80.

docker run -d -p 8080:80 nginx

7.) Остановить запущенный контейнер и удалить его:

docker stop <container_id>

docker rm <container_id>                // Remove a Stopped Container

8.) Удалить образ

docker rmi <image_id>

9.) Сборка образа

docker build -t <your-image-name> .

10.) Загрузка своего образа в реестр

docker push <Name of the image> <Name of the repo>

Маппинг портов в Docker

Сопоставление (маппинг) портов в Docker — это сопоставление порта на хост-машине с портом в контейнере (как в примере 6 выше). Маппинг необходим для доступа к приложениям, работающим в контейнерах, извне Docker-хоста.

Как работает сопоставление портов

Представьте, что у вас веб-сервер, работающий внутри Docker-контейнера на порту 3000. По умолчанию этот порт доступен только в сети Docker, но не доступен с хост-машины или из внешней сети. 

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

Пример:

docker run -p [HOST_PORT]:[CONTAINER_PORT] [IMAGE-NAME]

-p — флаг для сопоставления портов.

Dockerfile

Dockerfile — это текстовый файл, содержащий инструкции по созданию образа. Каждая инструкция создает слой в образе, и эти слои кэшируются, для ускорения последующих сборок.

Ключевые инструкции в Dockerfile

  • FROM: Устанавливает базовый образ для последующих инструкций.
  • WORKDIR: Устанавливает рабочий каталог внутри контейнера. 
  • COPY: Копирует файлы из хост-системы в контейнер. 
  • RUN: Выполняет команду в контейнере. 
  • CMD: Указывает команду для выполнения при запуске контейнера. 
  • EXPOSE: Документирует, какие порты прослушивает контейнер.

.dockerignore

Файл .dockerignore работает аналогично файлу .gitignore. Он указывает, какие файлы и каталоги следует игнорировать при сборке образа Docker. Это помогает сохранить образ небольшим, не принимая ненужные файлы. Это уменьшает размер контекста сборки и экономит время сборки. Файлы из node_modules, папки dist и т. д.

Как создать образ

Рассмотрим докеризацию на примере простого приложения mongo-express typescript.

1.) Инициализация проекта

mkdir ts-express-app
cd ts-express-app
npm init -y

npm install express mongoose dotenv
npm install --save-dev typescript @types/node @types/express @types/mongoose ts-node
tsc --init

2.) Создаем файл tsconfig.json

{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true
    }
}

3.) Создаем файл src/index.ts

import express from 'express';
import mongoose from 'mongoose';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
const PORT = 3000;
const DB_URL = process.env.DATABASE_URL || '';

mongoose.connect(DB_URL, { useNewUrlParser: true, useUnifiedTopology: true })
    .then(() => console.log('Connected to MongoDB'))
    .catch(err => console.error('Could not connect to MongoDB', err));

app.get('/', (req, res) => {
    res.send('Ram Ram bhai Sareya Ne');
});

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

4.) Создаем файл package.json и файл .env

"scripts": {
    "start": "node dist/index.js",
    "build": "tsc"
}  
DATABASE_URL=mongodb://localhost:27017/ts-express-app

Теперь докеризируем.

5.) Создаем Dockerfile в корне проекта

# Use the Node.js 20 image as the base image
FROM node:20

# Set the working directory inside the container
WORKDIR /usr/src/app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code
COPY . .

# Build the TypeScript code
RUN npm run build

# Expose the port the app runs on
EXPOSE 3000

# Command to run the app
CMD ["npm", "start"]

6.) Создаем файл .dockerignore в корне проекта:

node_modules
dist
npm-debug.log

7.) Создаем образ

docker build -t ts-express-app .

Приведенная выше команда должна успешно выполниться и выдать результат, аналогичный показанному ниже:

8.) Запуск контейнера

После создания образа можно запустить из него контейнер следующей командой:

docker run -p 3000:3000 ts-express-app

Как уже сказано, вышеописанное запускает ваш контейнер и сопоставляет порт 3000 на вашей хост-машине с портом 3000 контейнера. Можно зайти на localhost:3000 и убедиться, что контейнер запущен.

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

Продвигаясь дальше, вы можете пробовать отправить (пушить) образ в реестр DockerHub с помощью простых команд —

9.) Передача образа в реестр Docker

docker login
docker tag ts-express-app your-dockerhub-username/ts-express-app:latest
docker push your-dockerhub-username/ts-express-app:latest

В поле выше введите имя пользователя dockerhub вместо "your-dockerhub-username". Я использовал тег, который объясню позже.

Поздравляю вас с отправкой первого образа в DockerHub. Теперь, когда вы ознакомились с основами создания образов и запуска контейнеров, давайте углубимся в эту тему.

В production-режиме вы скрываете свой .env-файл, чтобы защитить свои секреты. Как же передать эти секреты в вашем .env в docker без использования .env-файла? Просто используйте флажок «-e«, который позволит вам передать переменные окружения в ваше приложение.

docker run -p 3000:3000 -e DATABASE_URL=mongodb://localhost:27017/ts-express-app ts-express-app

Теги Docker

Теги передают полезную информацию о версии/варианте образа. Теги позволяют идентифицировать и извлекать различные версии образа из реестра Docker. Они являются псевдонимами идентификатора образа, который часто выглядит так: f1477ec11d12. Это просто способ обозначения образа. Аналогом является то, как теги в Git ссылаются на коммиты в истории. 

Общий синтаксис тегов образов таков:

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

Если тег не указан, Docker по умолчанию использует тег latest.

Когда используются теги:

1. При сборке образа используем следующую команду:

docker build -t username/image_name:tag_name .

2. Эксплицитное обозначение образа командой tag.

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

3. Управление версиями: Теги обычно используются для обозначения различных версий образа. Например, теги 1.0, 1.1, 2.0 и т. д., обозначающие основные или незначительные обновления версии.

4. Идентификация среды или этапа: Теги помогают различать development, staging и production — тегами dev, staging и prod

5. Обозначение архитектуры или платформы: Теги позволяют идентифицировать образы, созданные для различных архитектур и платформ, например amd64, arm64 или windows

Разберемся в этом подробнее, используя тег в командах —

Создание образа с тегом:

docker build -t express-mongo-app:1.0 .

Получение конкретного тега:

docker pull node:14.18.0

Отметить существующий образ другим тегом:

docker tag express-mongo-app:1.0 express-mongo-app:latest

Управление версиями с помощью тегов:

Использование семантических версий (MAJOR.MINOR.PATCH) -…

docker build -t express-mongo-app:1.0.0 .
docker tag express-mongo-app:1.0.0 express-mongo-app:1.0
docker tag express-mongo-app:1.0.0 express-mongo-app:latest

Команда Docker exec

Команда docker exec позволяет выполнять команды внутри запущенного Docker-контейнера, для отладки, администрирования, создания папок/томов или проверки состояния контейнера.

Базовые команды docker exec

docker exec [OPTIONS] CONTAINER_ID|CONTAINER_NAME COMMAND [ARG…]
  • OPTIONS: Различные опции, например -it для интерактивного режима. 
  • CONTAINER: Имя или ID контейнера. 
  • COMMAND: Команда, которую нужно запустить внутри контейнера. 
  • [ARG…]: Аргументы команды.

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

Опция -it в docker exec означает «-interactive -tty», что позволяет взаимодействовать с оболочкой контейнера. 

Теперь разберемся в томах Docker.

Тома Docker

Тома — это файловые системы, которые устанавливаются на контейнеры, для хранения данных, генерируемых контейнером. 

Как работает файловая система Docker

Контейнер выполняет программный стек, описанный в образе. Образы состоят из слоев только для чтения, файловая система Union File System. Когда мы запускаем новый контейнер, Docker добавляет слой чтения-записи поверх слоев образа, позволяя контейнеру функционировать как обычная файловая система в Linux. Таким образом, каждая модификация файла в контейнере создает функционирующую копию в слое чтения-записи. Однако когда контейнер останавливается или удаляется, слой чтения-записи исчезает.

Docker управляет томами, хранящимися в разделе файловой системы хоста — /var/lib/docker/volumes в Linux. Эта часть файловой системы не должна изменяться процессами, не относящимися к Docker. В Docker тома являются наиболее эффективным способом хранения данных. Используя команду docker volume create, мы напрямую создаем том, или Docker делает это за нас при создании контейнера или сервиса.

Существует три основных типа томов:

  • Именованный: (Named Volumes) Управляются Docker и хранятся в выделенном месте в файловой системе хоста. 
  • Bind: Монтирует каталог или файл с хост-машины в контейнер. На хост-системе они могут храниться в любом месте. Это могут быть важные системные папки или файлы. Они всегда могут быть изменены процессами, не относящимися к Docker, запущенными на хосте или в контейнере. В целом, это хуже вариант, чем тома.
  • tmpfs: Монтирует временную файловую систему в контейнер, хранящийся в памяти хоста. Эти контейнеры никогда не записываются в файловую систему хост-системы; вместо этого они хранятся исключительно в памяти хост-системы. Ни на хосте, ни в контейнере они не хранятся на диске. Чувствительные или непостоянные данные могут храниться в таком контейнере в течение всего времени работы контейнера.

Именованные тома

Создаем именованный том следующей командой:

docker volume create my-ts-app-data

Теперь давайте смонтируем том в каталог внутри контейнера. Мы монтируем том my-ts-app-data в каталог /app/data внутри контейнера. Любые данные, записанные в /app/data внутри контейнера, будут храниться в названном томе на хосте.

docker run -d -p 3000:3000 -e DATABASE_URL=mongodb://mongo:27017/ts-express-app -v my-ts-app-data:/data/db ts-express-app

Используем команду docker volume inspect "my-ts-app-data", чтобы посмотреть подробную информацию о томе, включая его расположение в файловой системе хоста. 

Чтобы удалить том, если он больше не нужен, просто используйте команду «rm»:

docker volume rm my-ts-app-data

Операции с томами в docker

Теперь попробуем что-нибудь еще. Допустим, я хочу визуализировать свои данные в приложении-компасе на mongoDB. Как мне подключить его к моему тому в контейнере?

Запускаем mongo-контейнер локально, выполнив следующую команду —

docker run -p 27017:27017 -d mongo

Открываем свое приложение-компас на mongoDB и подключаемся к порту 27017. Создаем базу данных и коллекцию, вставляем в нее данные и сохраняем их.

Добавлена новая БД и случайные данные в нее.

Теперь уничтожьте контейнер, а затем перезапустите его. Откройте mongoDB compass и проверьте БД и данные, которые мы создали ранее. Что вы видите? Она исчезла, верно?

Как же мы сохраним данные? С помощью томов! Мы уже создали том с именем "my-ts-app-data", давайте использовать только его. Смонтируйте том в каталоге /data/db контейнера mongo и запустите его с помощью следующей команды:

docker run -d -v my-ts-app-data:/data/db -p 27017:27017 mongo

Теперь повторите описанные выше шаги, создайте БД и добавьте в нее данные. Уничтожьте контейнер, перезапустите его и перепроверьте данные, которые вы ранее ввели. Вы увидите, что ваши данные сохранились.

Теперь погрузимся в другие темы по Docker. Как вы заметили выше, я использовал слово «слои» при объяснении томов. Но что такое слой? Рассмотрим далее. О bind mount и tmpfs mount поговорим позже.

Слои в Docker

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

Слои Docker

  • Базовый слой: Это начальная точка образа Docker. Он содержит операционную систему, например Ubuntu, Alpine и т. д. и т. п. (все, что указано в dockerfile). Этот слой неизменяем и служит основой для последующих слоев. 
  • Промежуточные слои: Эти слои представляют собой инструкции в вашем Dockerfile, такие как RUN, COPY и ADD. Каждая инструкция создает новый слой поверх предыдущих. Промежуточные слои доступны только для чтения и кэшируются. 
  • Верхний слой для чтения/записи: Когда вы запускаете контейнер из образа, Docker добавляет слой с возможностью записи поверх слоев образа, доступных только для чтения. Это позволяет контейнеру вносить изменения без модификации нижележащего образа.
  • Реюзабельные и расшаренные: Слои кэшируются и могут повторно использоваться в разных образах, что повышает эффективность создания и совместного использования образов. Если несколько образов созданы на основе одного и того же базового образа, или имеют общие инструкции, они могут параллельно использовать одни и те же слои, что сокращает объем памяти и ускоряет загрузку и сборку образов.

Как создаются слои 

Слои создаются на основе инструкций, указанных в Dockerfile. Каждая инструкция в Dockerfile генерирует новый слой поверх предыдущих. Пример Dockerfile —

FROM ubuntu: 18.04      // This instruction creates a base layer by pulling the ubuntu: 18.04 image from the Docker registry.

COPY . /app            // This instruction creates a new layer on top of the base layer. It copies the entire contents of the build context (the directory containing the Dockerfile) into the /app directory inside the container.
              
RUN make /app          // This instruction creates another layer by running the make /app command inside the container. This command builds the application located in the /app directory.

CMD python /app/app.py  // This creates a new layer and specifies the default command to run when the container starts, which is python /app/app.py.

Мы знаем, что каждая инструкция создает новый слой поверх предыдущих, образуя как бы стопку слоев, которые и составляют конечный Docker-образ. Для большей наглядности:

Слой Docker

Кэширование слоев

Когда мы собираем образ с помощью Dockerfile, Docker последовательно обрабатывает каждую инструкцию и создает новый слой для каждой из них. Если слой образа не изменился, то билдер берет его из кэша сборки. Если же слой изменился с момента последней сборки, то этот слой и все следующие за ним слои должны быть пересобраны. Позвольте изобразить это на следующем примере —

Создание первого образа 

Сборка образа во второй раз с небольшими изменениями в файле app.js

Как видите на скриншотах, на первом я отправил свое приложение Express в образ, и вижу, что каждый слой создан с нуля. Теперь я делаю небольшое изменение (просто добавил console.log('hi') в файл app.js и теперь я пересобираю образ. Теперь во втором образе видно, что слои 2,3,4 кэшируются, поскольку в них нет изменений, но поскольку в файле произошло изменение, docker распознает это изменение, и поэтому слой 5 не кэшируется и собирается с нуля. А так как слой 5 изменен, все слои, построенные на его основе (после него), будут собраны с нуля.

Примечание: слой 1 на втором скриншоте все еще кэшируется, хотя на скриншоте не видно что он кэширован. На самом деле я не знаю почему. Но не волнуйтесь, он кэшируется.

Итак, теперь у вас есть довольно знания о докеризации приложений и о слоях.

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

Сеть в Docker

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

Типы сетей в Docker

Docker предоставляет несколько типов сетей:

1.Мостовая сеть (Bridge):

Тип сети по умолчанию для отдельных контейнеров. Мостовые сети создают программный мост между вашим хостом и контейнером. Контейнеры, подключенные к сети, могут общаться друг с другом, но они изолированы от тех, которые находится за пределами сети. Каждому контейнеру в сети присваивается собственный IP-адрес. Поскольку сеть соединена мостом с вашим хостом, контейнеры также могут общаться в вашей локальной сети и в Интернете. Однако они не будут отображаться как физические устройства в вашей локальной сети.

2. Сеть хоста (Host):

Контейнеры, использующие режим сети хоста, совместно используют сетевой стек вашего хоста без какой-либо изоляции. Им не выделяются собственные IP-адреса, а привязки портов будут публиковаться непосредственно к сетевому интерфейсу вашего хоста. Это означает, что процесс контейнера, который прослушивает порт 80, будет привязан к <ip_вашего_хоста>:80

3. Оверлейная сеть (Overlay):

Оверлейные сети — это распределенные сети, включающие несколько Docker-хостов. Сеть позволяет всем контейнерам, запущенным на любом из хостов, взаимодействовать друг с другом, не требуя поддержки маршрутизации на уровне ОС. Оверлейные сети реализуют сетевое взаимодействие для кластеров Docker Swarm, но также могут использоваться при запуске двух отдельных экземпляров Docker Engine с контейнерами, которые должны напрямую связываться друг с другом. Это позволяет создавать собственные окружения типа Swarm.

4. Macvlan-сеть:

Macvlan — еще одна расширенная опция, позволяющая контейнерам выглядеть как физические устройства в сети. Она работает путем присвоения каждому контейнеру в сети уникального MAC-адреса. Этот тип сети требует выделения одного из физических интерфейсов хоста для виртуальной сети. Более крупная сеть также должна быть соответствующим образом настроена для поддержки потенциально большого количества MAC-адресов, которые могут быть созданы активным хостом Docker, на котором запущено множество контейнеров.

5. ipvlan:

IPvLAN — это драйвер, который обеспечивает контроль над адресами IPv4 и IPv6, назначенными вашим контейнерам, а также маркировку и маршрутизацию VLAN уровней 2 и 3. Этот драйвер нужен при интеграции контейнерных сервисов с существующей физической сетью. Сети IPvLAN назначаются собственные интерфейсы, что дает преимущества в производительности по сравнению с мостовыми сетями.

6. Нет сети (None):

Контейнеры изолированы и не имеют сетевых интерфейсов.


Теперь попробуем заставить контейнеры общаться друг с другом. 

Создайте сеть с помощью команды ниже (по умолчанию это мостовая сеть): — 

(Примечание: когда вы запускаете контейнер без указания сети, он подключается к мостовой сети.)

docker network create my-first-network
docker network ls

Запуск контейнеров в мостовой сети —

docker run -d --name c1 --network my-first-network nginx
docker run -d --name c2 --network my-first-network nginx

Теперь соединим контейнер 1 с контейнером 2, зайдем внутрь c1 и пропингуем c2

docker exec -it c1 /bin/bash
ping c2

Как видите, все работает. Теперь попробуем кое-что новое. Я запущу mongo в контейнере, а мое приложение Express в другом контейнере, а затем попытаюсь получить доступ к контейнеру mongo через мое приложение. Используйте тот же код приложения, который мы создали ранее, только в .env-файл поместите следующее —

DATABASE_URL=[container_name]://mongodb:27017/ts-express-app-db

DATABASE_URL=mongodb://mongodb:27017/ts-express-app-db
docker run -d --name mongodb --network my-first-network -v my-ts-app-data:/data/db -p 27017:27017 mongo

docker run -d -p 3000:3000 --network my-first-network -e DATABASE_URL='mongodb://mongodb:27017/ts-express-app-db' ts-express-app 

Вы видите оба контейнера, теперь попробуйте добавить некоторые данные с помощью команды postman или curl в терминале. Вы увидите успешный ответ, что данные находятся в mongodb, можете зайти внутрь контейнера и выполнить следующие команды mongo.

docker exec -it mongodb mongo
use mydatabase
db.users.find().pretty()

Также можете проверить логи контейнера mongoDB, чтобы убедиться, что данные сохранены.

Удалить сеть —

docker network rm my-first-network

# remove all unused network (networks that aren't connected to even a single container)
docker network prune

Отключить контейнер от сети —

docker network disconnect my-first-network mongodb

Docker Compose 

Docker Compose — инструмент, позволяющий описывать и запускать многоконтейнерные Docker-приложения. Он использует YAML-файл (docker-compose.yml) для настройки и оркестрации сервисов, составляющих приложение, включая их зависимости, сети, тома и другие параметры конфигурации.

Пример файла docker-compose.yml для нашего приложения (которое мы использовали в примерах выше) —

version: '3.9'

services:
  ts-express-app:
    build: .
    image: "express-mongo-ts-docker"
    container_name: ts-express-app
    ports:
      - "3000:3000"
    environment:
      - MONGO_URL=mongodb://mongodb:27017/ts-express-app-db
    depends_on:
      - mongodb

  mongodb:
    image: mongo
    container_name: mongodb
    volumes:
      - my-ts-app-data:/data/db
    ports:
      - "27017:27017"

volumes:
  my-ts-app-data:

Объясню построчно этот файл.

1.) Version Declaration:

version: ‘3.9’: Указывает версию формата файла.

2.) Services:

Service (сервис или служба) — это единица развертывания, которая определяет, какой образ контейнера использовать. Я определил 2 сервиса в файле выше —

a.) ts-express-app

Этот сервис (служба) описывает наше приложение Express.

  • build: .: Собирает образ Docker из Dockerfile в текущем каталоге.
  • image: «express-mongo-ts-docker»: Именует образ как express-mongo-ts-docker. (Опционально)
  • container_name: ts-express-app: Устанавливает имя контейнера как ts-express-app. 
  • ports: — «3000:3000»: Маппинг портов как обычно. 
  • environment: — MONGO_URL= mongodb ://mongodb :27017/ ts-express-app-db: Устанавливает переменную окружения MONGO_URL, используемую нашим приложением для подключения к MongoDB. Этот URL указывает на службу mongodb, определенную в файле compose ниже. 
  • depends_on: — mongodb: Обеспечивает запуск службы ts-express-app после службы mongodb.

b.) mongodb:

Этот сервис описывает базу данных MongoDB.

  • image: mongo: Использует официальный образ MongoDB из Docker Hub. 
  • container_name: mongodb: Устанавливает имя контейнера на mongodb. 
  • volumes: — my-ts-app-data:/data/db: Монтирует том Docker my-ts-app-data в /data/db в контейнере, где MongoDB хранит свои данные. (как мы изучили выше) 
  • ports: — «27017:27017»: Маппинг портов стандартный

3.) Volumes

  • my-ts-app-data: Здесь, в конце файла, мы определяем, какие тома мы используем.

Итак, раз уж мы изучили файл compose, скопируйте приведенный выше код и создайте файл docker-compose.yml в корневом каталоге нашего приложения. Затем зайдите в терминал и выполните команду docker-compose up --build и подождите, пока она соберет ваши образы и запустит контейнеры. Вы увидите сообщение об успешном выполнении, и теперь ваши контейнеры mongo и express app работают в одной сети, правильно подключенные к определенным нами томам, и готовы к использованию.

Для остановки приложения используйте команду — docker-compose down.

Ниже показаны наши дашборды в Docker, где вы можете увидеть контейнер docker, запущенный внутри двух контейнеров (нашего приложения mongo и express). На третьем изображении я добавил некоторые данные с помощью POSTMAN, а затем получил их из нашей БД с помощью GET.

Кроме того, мы можем создать кастомную сеть и некоторые другие вещи. Если мы не определим сеть, как мы сделали это выше, Docker автоматически создаст дефолтную сеть для наших сервисов, обычно называется по имени директории проекта, в которой находится наш файл docker-compose.yml.

version: '3.8'

services:
  ts-express-app:
    build:
      context: .
      dockerfile: Dockerfile
    image: express-mongo-ts-docker
    container_name: ts-express-app
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - MONGO_URL=mongodb://mongodb:27017/ts-express-app-db
      - NODE_ENV=production
    depends_on:
      - mongodb
    networks:
      - ts-app-network

  mongodb:
    image: mongo
    container_name: mongodb
    restart: unless-stopped
    volumes:
      - my-ts-app-data:/data/db
    networks:
      - ts-app-network 
    ports:
      - "27017:27017"

volumes:
  my-ts-app-data:

networks:
  ts-app-network:
    driver: bridge 

Я также прикрепляю ссылку на github-репо нашего приложения в примерах, просто клонируйте его, установите библиотеки, создайте том с помощью docker-compose.yml, и запустите команду docker-compose up —build.

GitConnected

Оф Документация


Какой была ваша первая зарплата в QA и как вы искали первую работу?

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии

Мы в Telegram

Наш официальный канал
Полезные материалы и тесты
Готовимся к собеседованию
Project- и Product-менеджмент

? Популярное

? Telegram-обсуждения

Наши подписчики обсуждают, как искали первую работу в QA. Некоторые ищут ее прямо сейчас.
Наши подписчики рассказывают о том, как не бояться задавать тупые вопросы и чувствовать себя уверенно в новой команде.
Обсуждаем, куда лучше податься - в менеджмент или по технической ветке?
Говорим о конфликтных ситуациях в команде и о том, как их избежать
$1100*
медианная зарплата в QA в июне 2023

*по результатам опроса QA-инженеров в нашем телеграм-канале

Собеседование

19%*
IT-специалистов переехало или приняло решение о переезде из России по состоянию на конец марта 2022

*по результатам опроса в нашем телеграм-канале

live

Обсуждают сейчас

casibomcasibomjojobet girişHOLİGANBETjojobetCasibomCasibom Girişcasibomholiganbet girişCasibomholiganbet girişcasibom girişCasibomjojobetcasibomcasibomcasibom girişCASİBOMholiganbet girişizmir escort bayanjojobet girişCasibom Giriş