Автор оригинала: FreeCodeCamp Community Member.
Концепция сама контейнеризации довольно старая. Но появление Docker Engine В 2013 году намного проще консистерировать ваши приложения.
Согласно Обзор разработчика переполнения стека – 2020 , Докер это # 1 Самая разная платформа , # 2 самая любимая платформа , а также # 3 самая популярная платформа Отказ
Как это может быть востребовано, начать работу может показаться немного запугиваться. Таким образом, в этой книге мы будем изучать все от основ до более промежуточного уровня контейнера. После прохождения всей книги вы должны быть в состоянии:
- Контейнеризация (почти) любое приложение
- Загрузите пользовательские изображения Docker в онлайн-реестры
- Работа с несколькими контейнерами, используя Docker Compose
Предпосылки
- Знакомство с терминалом Linux
- Знакомство с JavaScript (некоторые более поздние проекты используют JavaScript)
Оглавление
- Введение в контейнеризацию и докер
- Как установить Docker
- Как установить Docker на MacOS
- Как установить Docker на Windows
- Как установить Docker на Linux
- Здравствуйте, World в Docker – Intro в основы докера
- Что такое контейнер?
- Что такое документ докера?
- Что такое Docker Registry?
- Обзор архитектуры докера
- Полная картина
- Основы манипулирования контейнера Docker
- Как запустить контейнер
- Как опубликовать порт
- Как использовать отдельный режим
- Как перечислить контейнеры
- Как назвать или переименовать контейнер
- Как остановить или убить беговой контейнер
- Как перезапустить контейнер
- Как создать контейнер без бега
- Как удалить свисающие контейнеры
- Как запустить контейнер в интерактивном режиме
- Как выполнить команды внутри контейнера
- Как работать с исполняемыми изображениями
- Основы манипулирования изображения докера
- Как создать образа докера
- Как поместить документы Docker
- Как перечислить и удалить образы докера
- Как понять много слоев докера
- Как построить Nginx из источника
- Как оптимизировать образы докера
- Обнимая альпийский Linux
- Как создать исполняемые изображения Docker
- Как поделиться своими изображениями Docker онлайн
- Как контейнеризировать приложение JavaScript
- Как написать Development DockerFile
- Как работать с креплениями Bind в Docker
- Как работать с анонимными томами в докере
- Как выполнить многоядерные сборки в Docker
- Как игнорировать ненужные файлы
- Основы манипулирования сетью в докере
- Основы Docker Network
- Как создать пользовательский мост в Docker
- Как прикрепить контейнер к сети в Docker
- Как отсоединить контейнеры из сети в докере
- Как избавиться от сетей в Docker
- Как контейнеризировать многофункциональное приложение JavaScript
- Как запустить сервер базы данных
- Как работать с названными томами в докере
- Как получить доступ к журналам из контейнера в Docker
- Как создать сеть и прикрепление сервера базы данных в Docker
- Как написать DockerFile
- Как выполнить команды в запущенном контейнере
- Как написать сценарии управления в Docker
- Как составить проекты, используя docker-compose
- Docker Compose Основы
- Как начать сервисы в Docker Compose
- Как перечислить услуги в Docker Compose
- Как выполнить команды внутри беговой службы в Docker Compose
- Как получить доступ к журналам из беговой службы в Docker Compose
- Как остановить услуги в Docker Compose
- Как составить приложение полнотека в Docker Compose
- Заключение
Код проекта
Код для примеров проектов можно найти в следующем репозитории:
Вы можете найти полный код в Завершено
ветка.
Взносы
Эта книга полностью открыта источника и качественные взносы более чем приветствуются. Вы можете найти полный контент в следующем репозитории:
Я обычно делаю свои изменения и обновляю на версию Gitbook в книге, а затем опубликуете их на FreeCodeCamp. Вы можете найти всегда обновленную и часто нестабильную версию книги по следующей ссылке:
Если вы ищете замороженную, но стабильную версию книги, то FreeCodeCamp будет лучшее место для поезда:
В зависимости от того, что версия книги вы в конечном итоге прочитайте, не забудьте дать мне знать ваше мнение. Конструктивная критика всегда приветствуется.
Введение в контейнеризацию и докер
По словам IBM ,
Другими словами, контейнеризация позволяет подключить ваше программное обеспечение наряду со всеми его зависимостями в автономном пакете, чтобы его можно было запускать, не проходя через проблему проблемной настройки.
Давайте рассмотрим реальный сценарий здесь. Предположим, вы разработали потрясающее приложение для управления книгами, которое может хранить информацию, касающуюся всех собственных книг, и также может служить целями системы кредитования книги для ваших друзей.
Если вы сделаете список зависимостей, этот список может выглядеть следующим образом:
- Node.js.
- Express.js.
- SQLite3.
Ну, теоретически это должно быть это. Но практически есть и другие вещи. Оказывается Node.js использует инструмент сборки, известный как Узел-GYP
Для строительства нативных дополнений. И согласно Инструкция по установке В Официальный репозиторий Этот инструмент сборки требует Python 2 или 3 и соответствующую цепочку инструментов компилятора C/C ++.
Принимая все это во внимание, окончательный список зависимостей заключается в следующем:
- Node.js.
- Express.js.
- SQLite3.
- Python 2 или 3
- C/C ++ цепь инструментов
Установка Python 2 или 3 довольно прост, независимо от платформы, которую вы включенные. Настройка цепочки инструментов C/C ++ довольно проста в Linux, но на Windows и Mac это болезненная задача.
В Windows The C ++ Build Tools Package меры в гигабайтах и занимают довольно много времени для установки. На Mac вы можете либо установить гигантский Xcode Применение или намного меньше Инструменты командной строки для Xcode упаковка.
Независимо от того, что вы устанавливаете, он все же может нарушить обновления ОС. На самом деле проблема настолько распространена, что есть Установка заметки для MacOS Catalina Доступно на официальном хранилище.
Предположим, что вы проходили через все хлопоты на создание зависимостей и начали работать над проектом. Это значит, что вы не опасны сейчас? Конечно нет.
Что, если у вас есть товарищ по команде, который использует Windows, пока вы используете Linux. Теперь вы должны рассмотреть несоответствия того, как эти две разные операционные системы обрабатывают пути. Или тот факт, что популярные технологии, такие как nginx не очень хорошо оптимизированы для работы в Windows. Некоторые технологии, такие как Redis Даже не приходите предварительно построенные для Windows.
Даже если вы проходите по всей фазе разработки, что если лицо, ответственное за управление серверами, следует неправильному процедуру развертывания?
Все эти проблемы могут быть решены, если только вы могли бы как-то:
- Разработать и запустить приложение внутри изолированной среды (известной как контейнер), которая соответствует вашей окончательной среде развертывания.
- Поместите свое приложение внутри одного файла (известный как изображение) вместе со всеми его зависимостями и необходимыми конфигурациями развертывания.
- И поделитесь этим изображением через центральный сервер (известный как реестр), который доступен кто-либо с надлежащим разрешением.
Затем ваши товарищи по команде смогут загрузить изображение из реестра, запустите приложение, так как он находится в изолированной среде, свободных от несоответствий платформы или даже развертывающуюся непосредственно на сервере, поскольку изображение поставляется со всеми правильными производственными конфигурациями.
То есть идея контейнеризации: положить ваши приложения внутри автономного пакета, что делает его портативным и воспроизводимым в различных средах.
Сейчас вопрос: «Какую роль играет здесь?»
Как я уже объяснил, контейнеризация – это идея, которая решает множество проблем в разработке программного обеспечения, положив вещи в коробки.
Эта сама идея имеет довольно несколько реализаций. Докер такая реализация. Это платформа контейнераровки с открытым исходным кодом, которая позволяет контейнеризировать ваши приложения, поделиться с ними, используя публичные или частные реестры, а также на Оршестрек их.
Теперь Docker – это не единственный инструмент для контейнеров на рынке, это просто самый популярный. Другой двигатель контейнеразации, который я люблю, называется Подман Разработан красной шляпой. Другие инструменты, такие как Канико Google, RKT Кровару удивительно, но они еще не готовы быть заправленной заменой для докера.
Кроме того, если вы хотите урок истории, вы можете прочитать удивительную Краткая история контейнеров: с 1970-х годов до сих пор который охватывает большую часть основных токарных точек для технологии.
Как установить Docker
Установка Docker сильно варьируется в зависимости от операционной системы, которую вы используете. Но это универсально просто через доску.
Докер безупречно работает на всех трех основных платформах, Mac, Windows и Linux. Среди трех процесс установки на Mac является самым простым, поэтому мы начнем там.
Как установить Docker на MacOS
На Mac все, что вам нужно сделать, это перейти к официальному Скачать страницу и нажмите на Скачать для Mac (стабильный) кнопка.
Вы получите регулярный вид Image Disk Apple Файл и внутри файла будет приложение. Все, что вам нужно сделать, это перетащить файл и бросить его в каталог приложений.
Вы можете начать Docker, просто дважды щелкнув значок приложения. Как только приложение запускается, вы увидите, что значок Docker появится в вашем меню-баре.
Теперь откройте терминал и выполните Docker --version
и Docker-Compose --version
обеспечить успех установки.
Как установить Docker на Windows
В Windows процедура практически то же самое, за исключением нескольких дополнительных шагов, которые вам нужно будет пройти. Шаги установки следующие:
- Перейдите к Этот сайт И следуйте инструкциям для установки WSL2 на Windows 10.
- Затем перейдите к официальному Скачать страницу и нажмите на Загрузить для Windows (стабильный) кнопка.
- Дважды щелкните загруженный установщик и пройдите по установке по умолчанию.
Как только установка будет сделана, начните Docker Desktop либо из меню «Пуск» или «Ваш рабочий стол». Значок докера должен отображаться на вашей панели задач.
Теперь откройте Ubuntu или любой расстройт, который вы установили из Microsoft Store. Выполнить Docker --version
и Docker-Compose --version
Команды, чтобы убедиться, что установка была успешной.
Вы можете получить доступ к Docker из вашей обычной командной строки или PowerShell. Просто я предпочитаю использовать WSL2 над любой другой командной строкой в Windows.
Как установить Docker на Linux
Установка Docker на Linux – это немного другого процесса, и в зависимости от распределения, который вы включены, он может варьироваться еще больше. Но если честно, установка так же легкая (если не проще) как две другие платформы.
Пакет Docker Desktop на Windows или Mac – это коллекция инструментов, таких как Docker Engine
, Docker Compose
, Docker Dashboard
, Кубернаны
И несколько других вкусностей.
На Linux, однако, вы не получаете такого расслоения. Вместо этого вы устанавливаете все необходимые инструменты, которые вам нужны вручную. Процедуры установки для разных распределений следующие:
- Если вы на Ubuntu, вы можете следовать за Установите Docker Engine на Ubuntu раздел от официальных документов.
Для других распределений Установка на дистрибутив Руководства доступны на официальных документах.
- Если вы на распределении, который не указан в документах, вы можете следовать за Установите Docker Engine от двоичных файлов Руководство вместо этого.
- Независимо от следующей процедуры, вы должны пройти через некоторые Шаги после установки для Linux которые очень важны.
- Как только вы закончите с помощью установки Docker, вам придется установить другой инструмент с именем Docker Compose. Вы можете следовать за Установить Docker Compose Руководство от официальных документов.
Как только установка будет сделана, откройте терминал и выполните Docker --version
и Docker-Compose --version
обеспечить успех установки.
Хотя Docker выполняет довольно хорошо, независимо от платформы, которую вы включенные, я предпочитаю Linux над другими. На протяжении всей книги я буду переключаться между моим Ubuntu 20.10 и Федора 33 рабочие станции.
Еще одна вещь, которую я хотел бы уточнить, если я не буду использовать любой инструмент GUI для работы с Docker по всей книге.
Я знаю о хороших инструментах GUI, доступных для разных платформ, но изучение команд Common Docker является одним из основных целей этой книги.
Здравствуйте, World в Docker – Intro в основы докера
Теперь, когда у вас есть докер и работает на вашу машину, пришло время запускать свой первый контейнер. Откройте терминал и запустите следующую команду:
docker run hello-world # Unable to find image 'hello-world:latest' locally # latest: Pulling from library/hello-world # 0e03bdcc26d7: Pull complete # Digest: sha256:4cf9c47f86df71d48364001ede3a4fcd85ae80ce02ebad74156906caff5378bc # Status: Downloaded newer image for hello-world:latest # # Hello from Docker! # This message shows that your installation appears to be working correctly. # # To generate this message, Docker took the following steps: # 1. The Docker client contacted the Docker daemon. # 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. # (amd64) # 3. The Docker daemon created a new container from that image which runs the # executable that produces the output you are currently reading. # 4. The Docker daemon streamed that output to the Docker client, which sent it # to your terminal. # # To try something more ambitious, you can run an Ubuntu container with: # $ docker run -it ubuntu bash # # Share images, automate workflows, and more with a free Docker ID: # https://hub.docker.com/ # # For more examples and ideas, visit: # https://docs.docker.com/get-started/
Привет-мир Изображение представляет собой пример минимальной контейнеризации с докером. У него есть одна программа, собранная из hello.c Файл, ответственный за печать сообщения, которое вы видите на вашем терминале.
Теперь в вашем терминале вы можете использовать Docker PS-A
Команда, чтобы посмотреть на все контейнеры, которые в данный момент работают или запускаются в прошлом:
docker ps -a # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 128ec8ceab71 hello-world "/hello" 14 seconds ago Exited (0) 13 seconds ago exciting_chebyshev
На выходе контейнер с именем Exciting_chebyshev
был запущен с идентификатором контейнера 128ec8ceab71
используя Привет-мир
изображение. Это имеет Выходу (0) 13 секунд назад
где . (0)
Выходной код означает, что во время выполнения контейнера не было создано ошибка.
Теперь, чтобы понять, что только что произошло за кулисами, вам придется познакомиться с архитектурой докера и тремя очень фундаментальными концепциями контейнеров в целом, что выглядит следующим образом:
- Контейнер
- Изображение
- Реестр
Я перечислил три концепции в алфавитном порядке и начнут мои объяснения с первым в списке.
Что такое контейнер?
В мире контейнеров не может быть ничего более фундаментального, чем концепция контейнера.
Официальный докер Ресурсы сайт говорит –
Вы можете рассмотреть контейнеры, чтобы быть следующим поколением виртуальных машин.
Также как виртуальные машины, контейнеры – это совершенно изолированные среды от хост-системы, а также друг от друга. Они также намного легче, чем традиционная виртуальная машина, поэтому большое количество контейнеров можно запускать одновременно, не влияя на производительность хост-системы.
Контейнеры и виртуальные машины на самом деле различные способы виртуализации вашего физического оборудования. Основное отличие этих двух – это метод виртуализации.
Виртуальные машины обычно создаются и управляются программой, известной как гипервизор, как Oracle VM VirtualBox , VMware WorkStation , КВМ , Microsoft Hyper-V и так далее. Эта программа Hypervisor обычно находится между хост-операционной системой и виртуальными машинами для выступления в качестве средства связи.
Каждая виртуальная машина поставляется с собственной гостевой операционной системой, которая так же тяжелая, как операционная система хоста.
Применение, работающее внутри виртуальной машины, связывается с гостевой операционной системой, которая разговаривает с гипервизором, который затем в свою очередь, переговоры с операционной системой Host, чтобы выделить необходимые ресурсы из физической инфраструктуры к запущенной приложению.
Как видите, существует длинная цепочка связи между приложениями, работающими внутри виртуальных машин и физической инфраструктуры. Применение, работающее внутри виртуальной машины, может принимать только небольшое количество ресурсов, но гостевая операционная система добавляет заметной накладной расходы.
В отличие от виртуальной машины, контейнер делает работу виртуализации более умным путем. Вместо того, чтобы иметь полную гостевую операционную систему внутри контейнера, он просто использует операционную систему хоста через время выполнения контейнера при сохранении изоляции – как и традиционная виртуальная машина.
Время выполнения контейнера, то есть Docker, сидит между контейнерами и операционной системой хоста вместо гипервизора. Затем контейнеры связываются с временем выполнения контейнера, которые затем связываются с операционной системой Host, чтобы получить необходимые ресурсы из физической инфраструктуры.
В результате устранения всего слоя операционной системы хоста контейнеры намного легче и меньше ресурсов, чем традиционные виртуальные машины.
В качестве демонстрации точки посмотрите на следующий код код:
uname -a # Linux alpha-centauri 5.8.0-22-generic #23-Ubuntu SMP Fri Oct 9 00:34:40 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux docker run alpine uname -a # Linux f08dbbe9199b 5.8.0-22-generic #23-Ubuntu SMP Fri Oct 9 00:34:40 UTC 2020 x86_64 Linux
В блоке кода выше я выполнил uname -a
Команда на моей операционной системе Host, чтобы распечатать детали ядра. Затем на следующей строке я выполнил одну и ту же команду внутри контейнера, работающего Alpine Linux Отказ
Как вы можете видеть на выходе, контейнер действительно использует ядро из моей операционной системы Host. Это идет, чтобы доказать точку, которая контейнеры виртуализируют операционную систему хоста вместо собственной операционной системы.
Если вы на машине Windows, вы узнаете, что все контейнеры используют ядро WSL2. Это происходит потому, что WSL2 действует как задняя часть для докера на Windows. На MacOS Back-End по умолчанию является VM, работающим на Гиперкит гипервизор.
Что такое документ докера?
Изображения представляют собой многослойные автономные файлы, которые действуют как шаблон для создания контейнеров. Они похожи на замороженные, только для чтения копию контейнера. Изображения могут быть обменены через реестры.
В прошлом разные контейнерные двигатели имели разные форматы изображения. Но позже, Открытая контейнерная инициатива (OCI) Определяется стандартной спецификацией для контейнерных изображений, которые выполняются основными двигателями контейнеризации. Это означает, что изображение, построенное с Docker, может использоваться с другим временем выполнения, такими как Podman без каких-либо дополнительных хлопот.
Контейнеры – это просто изображения в работе. Когда вы получаете изображение из Интернета и запустите контейнер, используя это изображение, вы по существу, создаете еще один временный писательский слой сверху предыдущих только для чтения.
Эта концепция станет намного яснее в предстоящих разделах этой книги. Но на данный момент просто имейте в виду, что изображения являются многослойными файлами только для чтения, несущие приложение в желаемом состоянии внутри них.
Что такое Docker Registry?
Вы уже узнали о двух очень важных кусках головоломки, Контейнеры и Изображения Отказ Последний кусок является Реестр Отказ
Реестр изображений является централизованным местом, где вы можете загрузить свои изображения, а также можно загрузить изображения, созданные другими. Докер Хаб Это публичный реестр по умолчанию для Docker. Еще один очень популярный реестр изображений Набережная красной шляпой.
На протяжении всей этой книги я буду использовать Docker Hub как мой реестр выбора.
Вы можете поделиться любым количеством публичных изображений на Docker Hub бесплатно. Люди по всему миру смогут загрузить их и использовать их свободно. Изображения, которые я загрузил, доступны в моем профиле ( Fhsinchy ).
Помимо Docker Hub или Quay, вы также можете создать свой собственный реестр изображений для размещения частных изображений. Существует также локальный реестр, который работает внутри вашего компьютера, что кэширует изображения, вытянутые из удаленных реестров.
Обзор архитектуры докера
Теперь, когда вы знакомы с большинством фундаментальных концепций, касающихся контейнеризации и докера, пришло время понять, как был разработан Docker, как было разработано программное обеспечение.
Двигатель состоит из трех основных компонентов:
- Docker Daemon: Демон (
Dockerd
) – это процесс, который продолжает работать в фоновом режиме и ждет команд от клиента. Демон способен управлять различными объектами докера. - Докерный клиент: Клиент (
Docker
) – это программа командной строки, в основном несет ответственность за транспортирующие команды, выданные пользователями. - REST API: Остальные API действуют как мост между демоном и клиентом. Любая команда, выданная с помощью клиента, проходит через API, чтобы наконец достичь демона.
Согласно официальному Документы ,
Вы, как пользователь, обычно выполняют команды с помощью клиентского компонента. Затем клиент использует API для отдыха, чтобы добраться до долгое управление демон и выполнить свою работу.
Полная картина
Хорошо, достаточно говорить. Теперь пришло время понять, как все эти части головоломки вы только что узнали о работе в гармонии. Прежде чем я погрузился в объяснение того, что действительно происходит, когда вы управляете Докер бегите Hello-World
Команда, позвольте мне показать вам небольшую диаграмму, которую я сделал:
Это изображение – слегка модифицированная версия, которую можно найти в официальном Документы Отказ События, которые возникают при выполнении команды, следующие:
- Вы выполняете
Докер бегите Hello-World
Команда, гдеПривет-мир
это имя изображения. - Докерный клиент достигает демона, говорит ему, чтобы получить
Привет-мир
изображение и запустить контейнер от этого. - Docker Daemon смотрит на изображение в местном хранилище и понимает, что он там нет, в результате чего
Невозможно найти изображение «Hello-World: последние» локально
Это напечатано на вашем терминале. - Затем демон достигает публичного реестра по умолчанию, который является Docker Hub и тянет в последней копии
Привет-мир
Изображение, указанноеПоследнее: вытягивание из библиотеки/Hello-World
линия в вашем терминале. - Docker Daemon затем создает новый контейнер из свежего изображения.
- Наконец, Docker Daemon запускает контейнер, созданный с помощью
Привет-мир
Изображение выводит стену текста на вашем терминале.
Это поведение дефолта Docker Daemon для поиска изображений в концентраторе, которые нет локально. Но после того, как изображение было получено, он останется в местном кеше. Поэтому, если вы снова выполните команду, вы не увидите следующие строки в выходе:
Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 0e03bdcc26d7: Pull complete Digest: sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9 Status: Downloaded newer image for hello-world:latest
Если в публичном реестре есть более новая версия изображения, демон снова принесет изображение. Что : последние
это тег. Изображения обычно имеют осмысленные теги для обозначения версий или сборки. Вы узнаете об этом более подробно позже.
Основы манипулирования контейнера Docker
В предыдущих разделах вы узнали о строительных блоках Docker и также запустили контейнер, используя Docker Run
команда.
В этом разделе вы будете изучать о манипулировании контейнера в гораздо более подробно. Манипуляция контейнера – одна из наиболее распространенных задач, которые вы будете выполнять каждый день, поэтому наличие надлежащего понимания различных команд имеет решающее значение.
Имейте в виду, однако, что это не исчерпывающий список всех команд, которые вы можете выполнить на Docker. Я буду говорить только о самых распространенных. В любое время вы хотите узнать больше о доступных командах, просто посетите официальный Ссылка для Docker Command-Line.
Как запустить контейнер
Ранее вы использовали Docker Run
Чтобы создать и запустить контейнер, используя Привет-мир
изображение. Общий синтаксис для этой команды выглядит следующим образом:
docker run
Хотя это совершенно допустимая команда, есть лучший способ диспетчеризации команд Докер
демон
До версии 1.13
У докера был только ранее упомянутый командный синтаксис. Позже командная строка была реструктурированный иметь следующий синтаксис:
docker
В этом синтаксисе:
объект
Указывает тип объекта Docker, который вы будете манипулировать. Это может бытьКонтейнер
,изображение
,сеть
илиТом
объект.команда
Указывает, что задача выполняется демоном, то естьБеги
команда.Варианты
Может быть любой допустимый параметр, который может переопределить поведение по умолчанию команду, как--publish
Вариант для отображения порта.
Теперь, следуя этому синтаксису Беги
Команда может быть написана следующим образом:
docker container run
Имя изображения
Может быть любого изображения из онлайн-реестра или вашей локальной системы. В качестве примера вы можете попробовать запустить контейнер, используя FHSINCHY/HELLO-DOCK изображение. Это изображение содержит простой Vue.js Приложение, которое работает на порту 80 внутри контейнера.
Чтобы запустить контейнер, используя это изображение, выполните следующую команду на вашем терминале:
docker container run --publish 8080:80 fhsinchy/hello-dock # /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration # /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ # /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh # 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf # 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf # /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh # /docker-entrypoint.sh: Configuration complete; ready for start up
Команда довольно объяснительная. Единственная часть, которая может потребовать некоторого объяснения, это --publish 8080: 80
Часть, которая будет объяснена в следующем подразделе.
Как опубликовать порт
Контейнеры являются изолированными средами. Ваша хост-система ничего не знает о том, что происходит внутри контейнера. Следовательно, приложения, работающие внутри контейнера, остаются недоступными снаружи.
Чтобы обеспечить доступ снаружи контейнера, вы должны опубликовать соответствующий порт внутри контейнера в порт в вашей локальной сети. Общий синтаксис для --publish
или -П
Вариант выглядит следующим образом:
--publish:
Когда вы написали --publish 8080: 80
В предыдущем подразделе это означало, что любой запрос, отправленный в порт 8080 вашей хост-системы, будет перенаправлен в порт 80 внутри контейнера.
Теперь, чтобы получить доступ к приложению в вашем браузере, посетите http://127.0.0.1:8080
Отказ
Вы можете остановить контейнер, просто нажав Ctrl + C
Комбинация ключей во время окна терминала полностью полностью закрывается или закрывает окно терминала.
Как использовать отдельный режим
Еще один очень популярный вариант Беги
Команда – это --detach
или -d
вариант. В приведенном выше примере, чтобы контейнер продолжать работать, вам пришлось открыть окно терминала. Закрытие окна терминала также остановило бегунного контейнера.
Это связано с тем, что по умолчанию контейнеры работают на переднем плане и прикрепляются к терминалу, как и любая другая обычная программа, вызываемая из терминала.
Для того, чтобы переопределить это поведение и сохранить контейнер, работающий в фоновом режиме, вы можете включить --detach
вариант с Беги
Команда следующим образом:
docker container run --detach --publish 8080:80 fhsinchy/hello-dock # 9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc
В отличие от предыдущего примера, вы не получите стену текста, брошенного на этот раз на этот раз. Вместо этого вы получите идентификатор вновь созданного контейнера.
Порядок вариантов, которые вы предоставляете, не имеет значения. Если вы поместите --publish
вариант до --detach
Вариант, это будет работать точно так же. Одна вещь, которую вы должны иметь в виду в случае Беги
Команда заключается в том, что имя изображения должно прийти последнее. Если вы положите что-либо после названия изображения, то это будет передано в качестве аргумента в точку входа контейнера (объяснено в командах для выполнения внутри контейнера подсечка) и может привести к неожиданным ситуациям.
Как перечислить контейнеры
Контейнер Ls
. Команда может быть использована для перечисления контейнеров, которые в данный момент работает. Для этого выполнить следующую команду:
docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 5 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp gifted_sammet
Контейнер с именем Gifted_sammet
это работает. Это было создано 5 секунд назад
и статус это До 5 секунд,
что указывает на то, что контейнер работает нормально с момента его создания.
Контейнер ID
это 9F21CB777058
Какие из первых 12 символов полного идентификатора контейнера. Полный контейнер ID 9F21CB77705810797C4B847DBD330D9C732FFDDBA14FB435470567A7A3F46CDC
который длиной 64 символа. Этот полный идентификатор контейнера был напечатан как выход Docker Container Run
команда в предыдущем разделе.
Перечислены под Порты
Столбец, порт 8080 из вашей локальной сети указывает на порт 80 внутри контейнера. Имя Gifted_sammet
генерируется докером и может быть что-то совершенно другое на вашем компьютере.
Контейнер Ls
. Команда только перечисляет контейнеры, которые в данный момент работают в вашей системе. Для того, чтобы перечислить контейнеры, которые запускаются в прошлом, вы можете использовать - Все
или -А
вариант.
docker container ls --all # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp gifted_sammet # 6cf52771dde1 fhsinchy/hello-dock "/docker-entrypoint.…" 3 minutes ago Exited (0) 3 minutes ago reverent_torvalds # 128ec8ceab71 hello-world "/hello" 4 minutes ago Exited (0) 4 minutes ago exciting_chebyshev
Как вы можете видеть, второй контейнер в списке Reverent_torvalds
Был создан ранее и вышел с кодом состояния 0, который указывает на то, что во время выполнения контейнера не было создано ошибка.
Как назвать или переименовать контейнер
По умолчанию каждый контейнер имеет два идентификатора. Они следующие:
Контейнер ID
– Случайный 64 символ длиной символов.Имя
– Сочетание двух случайных слов, соединенных с подчеркиванием.
Ссылаясь на контейнер, основанный на этих двух случайных идентификаторах, довольно неудобно. Было бы здорово, если бы контейнеры могут быть переданы на использование имени, определенного вами.
Наименование контейнера может быть достигнуто с помощью --Name
вариант. Чтобы запустить другой контейнер, используя FHSINCHY/HELLO-DOCK
Изображение с именем Привет-док-контейнер
Вы можете выполнить следующую команду:
docker container run --detach --publish 8888:80 --name hello-dock-container fhsinchy/hello-dock # b1db06e400c4c5e81a93a64d30acc1bf821bed63af36cab5cdb95d25e114f5fb
Порт 8080 в локальной сети занимает Gifted_sammet
Контейнер (контейнер, созданный в предыдущем подразделе). Вот почему вам придется использовать другой номер порта, например, 8888. Теперь, чтобы проверить, запустить Контейнер Ls
. команда:
docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 28 seconds ago Up 26 seconds 0.0.0.0:8888->80/tcp hello-dock-container # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:8080->80/tcp gifted_sammet
Новый контейнер с именем Привет-док-контейнер
был начат.
Вы даже можете переименовать старые контейнеры, используя Контейнер переименовать
команда. Синтаксис для команды выглядит следующим образом:
docker container rename
Переименовать Gifted_sammet
Контейнер к Привет-док-контейнер-2
Выполните следующую команду:
docker container rename gifted_sammet hello-dock-container-2
Команда не дает никакой вывод, но вы можете убедиться, что изменения имели место с помощью Контейнер Ls
. команда. Переименовать
Команда работает для контейнеров как в запущенном состоянии, так и остановленное состояние.
Как остановить или убить беговой контейнер
Контейнеры, работающие на переднем плане, могут быть остановлены, просто закрывая окно терминала или нажав Ctrl + C
Отказ Однако контейнеры, работающие на заднем плане, не могут быть остановлены таким же образом.
Есть две команды, которые имеют дело с этой задачей. Первый – это Контейнер Стоп
команда. Общий синтаксис для команды выглядит следующим образом:
docker container stop
Где Контейнер идентификатор
Может быть либо идентификатор или имя контейнера.
Я надеюсь, что вы помните контейнер, который вы начали в предыдущем разделе. Это все еще работает на заднем плане. Получите идентификатор для этого контейнера, используя Докерный контейнер Ls
(Я буду использовать Привет-док-контейнер
Контейнер для этой демонстрации). Теперь выполните следующую команду, чтобы остановить контейнер:
docker container stop hello-dock-container # hello-dock-container
Если вы используете имя в качестве идентификатора, вы получите отброшенное имя в качестве вывода. Стоп
Команда изящно отключает контейнер, отправив SIGTERM
сигнал. Если контейнер не останавливается в течение определенного периода, а SIGKILL
Отправляется сигнал, который немедленно отключает контейнер.
В тех случаях, когда вы хотите отправить SIGKILL
сигнал вместо SIGTERM
Сигнал, вы можете использовать Контейнер убить
команда вместо этого. Контейнер убить
Команда следует за тем же синтаксисом, что и Стоп
команда.
docker container kill hello-dock-container-2 # hello-dock-container-2
Как перезапустить контейнер
Когда я говорю, перезапустите, я имею в виду два сценария специально. Они следующие:
- Перезапуск контейнера, который был ранее остановлен или убит.
- Перезагрузка бегового контейнера.
Как вы уже узнали из предыдущего подраздела, остановленные контейнеры остаются в вашей системе. Если вы хотите, вы можете перезапустить их. Старт контейнера
Команда может быть использована для запуска любого остановка или убитого контейнера. Синтаксис команды выглядит следующим образом:
docker container start
Вы можете получить список всех контейнеров, выполнив Контейнер ls --all
команда. Тогда ищите контейнеры с Выходил
статус.
docker container ls --all # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 3 minutes ago Exited (0) 47 seconds ago hello-dock-container # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 7 minutes ago Exited (137) 17 seconds ago hello-dock-container-2 # 6cf52771dde1 fhsinchy/hello-dock "/docker-entrypoint.…" 7 minutes ago Exited (0) 7 minutes ago reverent_torvalds # 128ec8ceab71 hello-world "/hello" 9 minutes ago Exited (0) 9 minutes ago exciting_chebyshev
Теперь, чтобы перезапустить Привет-док-контейнер
Контейнер, вы можете выполнить следующую команду:
docker container start hello-dock-container # hello-dock-container
Теперь вы можете убедиться, что контейнер работает, глядя на список беговых контейнеров, используя Контейнер Ls
. команда.
Старт контейнера
Команда начнет любой контейнер в отдельночном режиме по умолчанию и сохраняет какие-либо конфигурации портов, сделанные ранее. Так что, если вы посетите http://127.0.0.1:8080
Теперь вы должны иметь возможность получить доступ к Привет-док
Приложение просто как раньше.
Теперь, в сценариях, где вы хотели бы перезагрузить контейнер для запуска, вы можете использовать Контейнер перезапускает
команда. Контейнер перезапускает
Команда последовала за точным синтаксисом в качестве Старт контейнера
команда.
docker container restart hello-dock-container-2 # hello-dock-container-2
Основное различие между двумя командами заключается в том, что Контейнер перезапускает
Команда пытается остановить целевой контейнер, а затем снова запускает его резервное копирование, тогда как команда запуска просто запускает уже остановленную контейнер.
В случае остановленного контейнера обе команды точно так же. Но в случае бегового контейнера вы должны использовать Контейнер перезапускает
команда.
Как создать контейнер без бега
До сих пор в этом разделе вы начали контейнеры, используя Контейнер работает
Команда, которая на самом деле является комбинацией двух отдельных команд. Эти команды следующие:
Контейнер создает
Команда создает контейнер с данного изображения.Старт контейнера
Команда запускает контейнер, который был уже создан.
Теперь, чтобы выполнить демонстрацию, показанную в разделе «Беговые контейнеры», используя эти две команды, вы можете сделать что-то вроде следующего:
docker container create --publish 8080:80 fhsinchy/hello-dock # 2e7ef5098bab92f4536eb9a372d9b99ed852a9a816c341127399f51a6d053856 docker container ls --all # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 2e7ef5098bab fhsinchy/hello-dock "/docker-entrypoint.…" 30 seconds ago Created hello-dock
Очевидно на выходе Контейнер ls --all
Команда, контейнер с именем Привет-док
был создан с помощью FHSINCHY/HELLO-DOCK
изображение. Статус
контейнера Создано
На данный момент и, учитывая, что он не работает, он не будет перечислен без использования - Все
вариант.
Как только контейнер создан, он может быть запущен с помощью Старт контейнера
команда.
docker container start hello-dock # hello-dock docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 2e7ef5098bab fhsinchy/hello-dock "/docker-entrypoint.…" About a minute ago Up 29 seconds 0.0.0.0:8080->80/tcp hello-dock
Контейнер Статус
изменился с Создано
к До 29 секунд
что указывает на то, что контейнер сейчас находится в запущенном состоянии. Конфигурация порта также показана в Порты
столбец, который был ранее пустым.
Хотя вы можете уйти с Контейнер работает
Команда для большинства сценариев, в книге будут некоторые ситуации в книге, которые требуют, чтобы вы использовали эту Контейнер создает
команда.
Как удалить свисающие контейнеры
Как вы уже видели, контейнеры, которые были остановлены или убиты, остаются в системе. Эти висячие контейнеры могут заниматься пространством или могут конфликт с более новыми контейнерами.
Для того, чтобы удалить остановленный контейнер, вы можете использовать Контейнер RM
команда. Общий синтаксис выглядит следующим образом:
docker container rm
Чтобы узнать, какие контейнеры не работают, используйте Контейнер ls --all
Команда и искать контейнеры с Выходил
статус.
docker container ls --all # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 6 minutes ago Up About a minute 0.0.0.0:8888->80/tcp hello-dock-container # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 10 minutes ago Up About a minute 0.0.0.0:8080->80/tcp hello-dock-container-2 # 6cf52771dde1 fhsinchy/hello-dock "/docker-entrypoint.…" 10 minutes ago Exited (0) 10 minutes ago reverent_torvalds # 128ec8ceab71 hello-world "/hello" 12 minutes ago Exited (0) 12 minutes ago exciting_chebyshev
Как видно на выходе, контейнеры с ID 6CF52771DDE1
и 128ec8ceab71
не бегают. Удалить 6CF52771DDE1
Вы можете выполнить следующую команду:
docker container rm 6cf52771dde1 # 6cf52771dde1
Вы можете проверить, был ли контейнер удален или не используя Контейнер Ls
. команда. Вы также можете удалить несколько контейнеров одновременно, передавая их идентификаторы один за другим, разделенным пробелами.
Или вместо удаления отдельных контейнеров, если вы хотите удалить все висячие контейнеры, вы можете использовать Контейнер Brune
команда.
Вы можете проверить список контейнеров, используя Контейнер ls --all
Команда, чтобы убедиться, что висячие контейнеры были удалены:
docker container ls --all # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # b1db06e400c4 fhsinchy/hello-dock "/docker-entrypoint.…" 8 minutes ago Up 3 minutes 0.0.0.0:8888->80/tcp hello-dock-container # 9f21cb777058 fhsinchy/hello-dock "/docker-entrypoint.…" 12 minutes ago Up 3 minutes 0.0.0.0:8080->80/tcp hello-dock-container-2
Если вы следуете за книгу именно так, как написано до сих пор, вы должны увидеть только Привет-док-контейнер
и Привет-док-контейнер-2
в списке. Я бы предложил остановить и удалить обе контейнеры, прежде чем перейти к следующему разделу.
Есть также --rm
Вариант для Контейнер работает
и Старт контейнера
Команды, которые указывают на то, что вы хотите, чтобы контейнеры были удалены, как только они остановились. Начать другое Привет-док
Контейнер с --rm
Опция, выполнить следующую команду:
docker container run --rm --detach --publish 8888:80 --name hello-dock-volatile fhsinchy/hello-dock # 0d74e14091dc6262732bee226d95702c21894678efb4043663f7911c53fb79f3
Вы можете использовать Контейнер Ls
. Команда для проверки того, что контейнер работает:
docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 0d74e14091dc fhsinchy/hello-dock "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:8888->80/tcp hello-dock-volatile
Теперь, если вы остановите контейнер, а затем снова проверьте с Контейнер ls --all
команда:
docker container stop hello-dock-volatile # hello-dock-volatile docker container ls --all # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Контейнер был удален автоматически. Отныне я буду использовать --rm
вариант для большинства контейнеров. Я явно упомяну, где он не нужен.
Как запустить контейнер в интерактивном режиме
До сих пор у вас только контейнеры, созданные из-за Привет-мир изображение или FHSINCHY/HELLO-DOCK изображение. Эти изображения сделаны для выполнения простых программ, которые не интерактивны.
Ну, все изображения не так просто. Изображения могут инкапсулировать целое распространение Linux внутри них.
Популярные распределения, такие как Ubuntu , Федора и Debian Все имеют официальные документы докера, доступные в концентрате. Языки программирования, такие как Python , PHP , идти или время пробега, как Узел и Deno У всех есть свои официальные изображения.
Эти изображения не просто запускают некоторую предварительно настроенную программу. Это вместо этого настроено для запуска оболочки по умолчанию. В случае изображения операционной системы это может быть что-то вроде Sh
или Bash
И в случае языков программирования или время прохождения, это обычно их языковая оболочка по умолчанию.
Как вы, возможно, уже узнали из вашего предыдущего опыта с компьютерами, оболочки являются интерактивными программами. Изображение, настроенное для запуска такой программы, является интерактивным изображением. Эти изображения требуют специального -итайте
Опция для передачи в Контейнер работает
команда.
В качестве примера, если вы запустите контейнер с помощью Ubuntu
Изображение, выполняя Контейнер Docker запустить Ubuntu
Вы увидите ничего не происходит. Но если вы выполняете одну и ту же команду с -итайте
Вариант, вы должны приземлиться прямо на Bash внутри контейнера Ubuntu.
docker container run --rm -it ubuntu # root@dbb1f56b9563:/# cat /etc/os-release # NAME="Ubuntu" # VERSION="20.04.1 LTS (Focal Fossa)" # ID=ubuntu # ID_LIKE=debian # PRETTY_NAME="Ubuntu 20.04.1 LTS" # VERSION_ID="20.04" # HOME_URL="https://www.ubuntu.com/" # SUPPORT_URL="https://help.ubuntu.com/" # BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" # PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" # VERSION_CODENAME=focal # UBUNTU_CODENAME=focal
Как вы можете увидеть с вывода CAT/ETC/OS-RELEACE
Команда, я действительно взаимодействую с Bash, бегающим внутри контейнера Ubuntu.
-итайте
Опция Устанавливает сцену для вас, чтобы взаимодействовать с любой интерактивной программой внутри контейнера. Этот вариант на самом деле два отдельных параметра, пюреных вместе.
-
-Я
или- Интерактивность
Опция подключает вас к входному потоку контейнера, чтобы вы могли отправлять входы в Bash. -
-t
или--Тти
Опция гарантирует, что вы получите хорошее форматирование и нативный терминальный опыт, выделяя псевдо-TTY.
Вам нужно использовать -итайте
Вариант всякий раз, когда вы хотите запустить контейнер в интерактивном режиме. Другой пример может работать Узел
Изображение следующим образом:
docker container run -it node # Welcome to Node.js v15.0.0. # Type ".help" for more information. # > ['farhan', 'hasin', 'chowdhury'].map(name => name.toUpperCase()) # [ 'FARHAN', 'HASIN', 'CHOWDHURY' ]
Любой действительный код JavaScript может быть выполнен в оболочке узла. Вместо письма -итайте
Вы можете быть более Verbose, написав --interactive --tty
в отдельности.
Как выполнить команды внутри контейнера
В Hello World in Docker раздел этой книги вы видели, как я выполнял команду внутри альпийского контейнера Linux. Это пошло что-то вроде этого:
docker run alpine uname -a # Linux f08dbbe9199b 5.8.0-22-generic #23-Ubuntu SMP Fri Oct 9 00:34:40 UTC 2020 x86_64 Linux
В этой команде я выполнил uname -a
Команда внутри альпийского контейнера Linux. Сценарии, как это (где все, что вы хотите сделать, это выполнить определенную команду внутри определенного контейнера) довольно распространена.
Предположим, что вы хотите кодировать строку с помощью Base64
программа. Это то, что доступно практически в любой операционной системе Linux или Unix (но не на Windows).
В этой ситуации вы можете быстро раскрутить контейнер с использованием изображений, таких как Bitebox И пусть это сделает работу.
Общий синтаксис для кодирования строки с использованием Base64
составляет:
echo -n my-secret | base64 # bXktc2VjcmV0
И общий синтаксис для передачи команды на контейнер, который не работает, выглядит следующим образом:
docker container run
Чтобы выполнить кодировку Base64 с помощью изображения Bitebox, вы можете выполнить следующую команду:
docker container run --rm busybox echo -n my-secret | base64 # bXktc2VjcmV0
Что происходит вот что, в Контейнер работает
Команда, что бы вы ни проходили после того, как имя изображения передается на точку записи по умолчанию изображения.
Точка входа похожа на шлюз к изображению. Большинство изображений, кроме исполняемых изображений (объясненные в Работа с исполняемыми изображениями Подборка) Используйте оболочку или Sh
как точка входа по умолчанию. Таким образом, любая действительная команда Shell может быть передана им в качестве аргументов.
Как работать с исполняемыми изображениями
В предыдущем разделе я кратко упомянул исполняемые изображения. Эти изображения предназначены для того, чтобы вести себя как исполняемые программы.
Взять, например, мой RMbyext проект. Это простой сценарий Python, способный рекурсивно удалять файлы данных расширений. Чтобы узнать больше о проекте, вы можете проверить репозиторий:
Если у вас установлен Git и Python, вы можете установить этот скрипт, выполнив следующую команду:
pip install git+https://github.com/fhsinchy/rmbyext.git#egg=rmbyext
Предполагая, что Python был правильно настроен в вашей системе, скрипт должен быть доступен в любом месте через терминал. Общий синтаксис для использования этого сценария выглядит следующим образом:
rmbyext
Чтобы проверить его, откройте свой терминал в пустом каталоге и создайте некоторые файлы в нем разных расширений. Вы можете использовать коснуться
Команда для этого. Теперь у меня есть каталог на моем компьютере со следующими файлами:
touch a.pdf b.pdf c.txt d.pdf e.txt ls # a.pdf b.pdf c.txt d.pdf e.txt
Удалить все PDF
Файлы из этого каталога, вы можете выполнить следующую команду:
rmbyext pdf # Removing: PDF # b.pdf # a.pdf # d.pdf
Исполняемое изображение для этой программы должно иметь возможность принимать расширения файлов в качестве аргументов и удалять их так же, как RMbyext
Программа сделала.
FHSINCHY/RMBYEXT Изображение ведет себя аналогично. Это изображение содержит копию RMbyext
Скрипт и настроен для запуска скрипта в каталоге /зона
внутри контейнера.
Теперь проблема в том, что контейнеры изолированы от вашей локальной системы, поэтому RMbyext
Программа, работающая внутри контейнера, не имеет никакого доступа к вашей локальной файловой системе. Итак, если каким-то образом вы можете сопоставить локальный каталог, содержащий PDF
Файлы к /зона
Каталог внутри контейнера файлы должны быть доступны для контейнера.
Один из способов предоставить контейнер прямого доступа к вашей локальной файловой системе, используя Привязать крепления Отказ
BIND COUNT позволяет сформировать двустороннюю связывание данных между содержимым локальной файловой системой каталога (источника) и другого каталога внутри контейнера (пункт назначения). Таким образом, любые изменения в каталоге назначения вступит в силу в исходном каталоге и Vise Versa.
Давайте посмотрим на привязку крепление в действии. Чтобы удалить файлы, используя это изображение вместо самой программы, вы можете выполнить следующую команду:
docker container run --rm -v $(pwd):/zone fhsinchy/rmbyext pdf # Removing: PDF # b.pdf # a.pdf # d.pdf
Как вы уже догадались, увидев -v $ (pwd):/зона
Часть в команде, -V
или --volume
Опция используется для создания крепления связывания для контейнера. Этот вариант может предпринять три поля, разделенные двоеточиями ( :
). Общий синтаксис для опции выглядит следующим образом:
--volume: :
Третье поле является необязательной, но вы должны пройти абсолютный путь вашего локального каталога и абсолютный путь каталога внутри контейнера.
Исходный каталог в моем случае это /home/fhsinchy/Zone
Отказ Учитывая, что мой терминал открывается внутри каталога, $ (PWD)
будет заменен на /home/fhsinchy/Zone
который содержит ранее упомянутые .PDF
и .txt
файлы.
Вы можете узнать больше о Команда замена здесь если вы хотите.
--volume
или -V
Опция действительна для Контейнер работает
а также Контейнер создает
команды. Мы рассмотрим объемы более подробно в предстоящих разделах, так что не волнуйтесь, если вы не понимаете их здесь очень хорошо.
Разница между обычным изображением и исполняемым исполняемым является то, что точка входа для исполняемого изображения установлена на пользовательскую программу вместо Sh
в этом случае RMbyext
программа. И, как вы узнали в предыдущем подраздельном разделе, что вы пишете после имени изображения в Контейнер работает
Команда передается на точку входа на изображение.
Так что в конце концов Контейнер Docker Run --RM -V $ (PWD):/ZONE FHSINCHY/RMBYEXT PDF
Команда переводит на Rmbyext PDF
внутри контейнера. Исполняемые изображения не являются частотыми в дикой природе, но могут быть очень полезны в определенных случаях.
Основы манипулирования изображения докера
Теперь, когда у вас есть твердое понимание того, как управлять контейнерами с использованием общедоступных изображений, пришло время узнать о создании ваших собственных изображений.
В этом разделе вы узнаете основы создания изображений, используя их контейнеры, и совместно используете их онлайн.
Я бы предложил вам установить Визуальный студийный код с официальным Дочсерское расширение с рынка. Это значительно поможет вашему опыту развития.
Как создать образа докера
Как я уже объяснил в мире Hello в разделе Docker, изображения являются многослойными автономными файлами, которые действуют как шаблон для создания контейнеров докеров. Они похожи на замороженные, только для чтения копию контейнера.
Чтобы создать изображение, используя одну из ваших программ, вы должны иметь четкое видение того, что вы хотите от изображения. Возьми официальный nginx Изображение, например. Вы можете запустить контейнер, используя это изображение, просто выполняя следующую команду:
docker container run --rm --detach --name default-nginx --publish 8080:80 nginx # b379ecd5b6b9ae27c144e4fa12bdc5d0635543666f75c14039eea8d5f38e3f56 docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # b379ecd5b6b9 nginx "/docker-entrypoint.…" 8 seconds ago Up 8 seconds 0.0.0.0:8080->80/tcp default-nginx
Теперь, если вы посетите http://127.0.0.1:8080
В браузере вы увидите страницу отклика по умолчанию.
Это все хорошо и хорошо, но что, если вы хотите сделать пользовательское изображение Nginx, которое функционирует точно так же, как официальный, но это построено вами? Это совершенно действительный сценарий, если честно. На самом деле, давайте сделаем это.
Чтобы сделать пользовательское изображение Nginx, у вас должна быть четкая картина того, что будет окончательное состояние изображения. На мой взгляд, изображение должно быть следующим:
- Изображение должно иметь предварительно установленное nginx, которое можно сделать с помощью менеджера пакета или может быть построен из источника.
- Изображение должно запустить Nginx автоматически при запуске.
Это просто. Если вы клонировали репозиторию проекта, связанные в этой книге, идите в корне в проекте и ищите каталог с именем Custom-Nginx
там.
Теперь создайте новый файл с именем Dockerfile
внутри этого каталога. А Dockerfile
Является ли сборник инструкций, которые когда-то обрабатываются демоном, приводит к изображению. Содержание для Dockerfile
составляет:
FROM ubuntu:latest EXPOSE 80 RUN apt-get update && \ apt-get install nginx -y && \ apt-get clean && rm -rf /var/lib/apt/lists/* CMD ["nginx", "-g", "daemon off;"]
Изображения представляют собой многослойные файлы и в этом файле, каждая строка (известная как инструкции), которые вы написали, создает слой для вашего изображения.
- Каждый действительный
Dockerfile
начинается сОт
Инструкция. Эта инструкция устанавливает базовое изображение для вашего результирующего изображения. УстановкаUbuntu: последние
В качестве базового изображения здесь вы получаете все доброту Ubuntu, уже доступно на вашем пользовательском изображении, поэтому вы можете использовать такие вещи, какAPT-Get
Команда для удобной установки пакета. -
Выставлять
Инструкция используется для указания порта, который необходимо опубликовать. Использование этой инструкции не означает, что вам не понадобится--publish
порт. Вам еще нужно использовать--publish
опция явно. ЭтоВыставлять
Инструкция работает как документация для тех, кто пытается запустить контейнер, используя ваше изображение. У него также есть некоторые другие виды использования, которые я здесь не буду обсуждать. -
Беги
Инструкция вDockerfile
Выполняет команду внутри корпуса контейнера.APT-Get Update && apt-get install install nginx -y
Команда проверяет обновленные версии пакета и устанавливает nginx.apt-get clean && rm -rf/var/lib/apt/liess/*
Команда используется для очистки кэша пакета, потому что вы не хотите ни одного ненужного багажа на вашем изображении. Эти две команды простые вещи Ubuntu, ничего нравятся.Беги
Инструкции здесь написаны воболочка
форма. Они также могут быть написаны вexec
форма. Вы можете проконсультироваться с Официальная ссылка для дополнительной информации. - Наконец
CMD
Инструкция Устанавливает команду по умолчанию для вашего изображения. Эта инструкция написана вexec
Форма здесь состоит из трех отдельных частей. Здесьnginx
Относится к исполняемому NGINX.-G
идемон от
являются вариантами для Nginx. Запуск Nginx в качестве одного процесса внутри контейнеров считается наилучшей практикой, следовательно, использование этой опции.CMD
Инструкция также может быть написана воболочка
форма. Вы можете проконсультироваться с Официальная ссылка для дополнительной информации.
Теперь, когда у вас есть действительный Dockerfile
Вы можете создать изображение из него. Как правило, связанные с контейнерами, связанные с изображением, связанные с изображением, которые могут быть выданы, используя следующий синтаксис:
docker image
Чтобы создать изображение, используя Dockerfile
Вы только что написали, откройте свой терминал внутри Custom-Nginx
каталог и выполнить следующую команду:
docker image build . # Sending build context to Docker daemon 3.584kB # Step 1/4 : FROM ubuntu:latest # ---> d70eaf7277ea # Step 2/4 : EXPOSE 80 # ---> Running in 9eae86582ec7 # Removing intermediate container 9eae86582ec7 # ---> 8235bd799a56 # Step 3/4 : RUN apt-get update && apt-get install nginx -y && apt-get clean && rm -rf /var/lib/apt/lists/* # ---> Running in a44725cbb3fa ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container a44725cbb3fa # ---> 3066bd20292d # Step 4/4 : CMD ["nginx", "-g", "daemon off;"] # ---> Running in 4792e4691660 # Removing intermediate container 4792e4691660 # ---> 3199372aa3fc # Successfully built 3199372aa3fc
Для выполнения сборки изображений демон нуждается в двух очень конкретных частях информации. Это название Dockerfile
и контекст сборки. В команде, выданном выше:
Docker Image Build
это команда для создания изображения. Демон находит любой файл с именемDockerfile
в контексте.-
Отказ
В конце устанавливает контекст для этой сборки. Контекст означает каталог, доступный на демон во время процесса сборки.
Теперь, чтобы запустить контейнер, используя это изображение, вы можете использовать Контейнер работает
Команда в сочетании с идентификатором изображения, который вы получили в результате процесса сборки. В моем случае удостоверение личности 3199372AA3FC
Очевидно, что Успешно построен 3199372AA3FC
строка в предыдущем блоке кода.
docker container run --rm --detach --name custom-nginx-packaged --publish 8080:80 3199372aa3fc # ec09d4e1f70c903c3b954c8d7958421cdd1ae3d079b57f929e44131fbf8069a0 docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # ec09d4e1f70c 3199372aa3fc "nginx -g 'daemon of…" 23 seconds ago Up 22 seconds 0.0.0.0:8080->80/tcp custom-nginx-packaged
Чтобы проверить, посетить http://127.0.0.1:8080
И вы должны увидеть страницу отклика по умолчанию.
Как поместить документы Docker
Также как контейнеры, вы можете назначить пользовательские идентификаторы на ваши изображения вместо того, чтобы полагаться на случайно сгенерированный идентификатор. В случае изображения, это называется меткой вместо именования. --tag
или -t
Опция используется в таких случаях.
Общий синтаксис для опции выглядит следующим образом:
--tag:
Репозиторий обычно известен как имя изображения, и тег указывает на определенную сборку или версию.
Возьми официальный MySQL Изображение, например. Если вы хотите запустить контейнер, используя определенную версию MySQL, например, 5,7, вы можете выполнить Контейнер Docker Run MySQL: 5.7
где MySQL
это репозиторий изображения и 5.7
это тег.
Для того, чтобы пометить свой пользовательский образ Nginx с Custom-Nginx: упаковано
Вы можете выполнить следующую команду:
docker image build --tag custom-nginx:packaged . # Sending build context to Docker daemon 1.055MB # Step 1/4 : FROM ubuntu:latest # ---> f63181f19b2f # Step 2/4 : EXPOSE 80 # ---> Running in 53ab370b9efc # Removing intermediate container 53ab370b9efc # ---> 6d6460a74447 # Step 3/4 : RUN apt-get update && apt-get install nginx -y && apt-get clean && rm -rf /var/lib/apt/lists/* # ---> Running in b4951b6b48bb ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container b4951b6b48bb # ---> fdc6cdd8925a # Step 4/4 : CMD ["nginx", "-g", "daemon off;"] # ---> Running in 3bdbd2af4f0e # Removing intermediate container 3bdbd2af4f0e # ---> f8837621b99d # Successfully built f8837621b99d # Successfully tagged custom-nginx:packaged
Ничто не изменится, кроме того, что теперь вы можете ссылаться на ваше изображение как Custom-Nginx: упаковано
вместо некоторой длинной случайной строки.
В тех случаях, когда вы забыли пометить изображение во время сборки, или, возможно, вы хотите изменить тег, вы можете использовать Тег изображения
Команда сделать это:
docker image tag: ## or ## docker image tag : :
Как перечислить и удалить образы докера
Так же, как Контейнер Ls
. Команда, вы можете использовать Изображение ls
Команда для перечисления всех изображений в вашей локальной системе:
docker image ls # REPOSITORY TAG IMAGE ID CREATED SIZE #3199372aa3fc 7 seconds ago 132MB # custom-nginx packaged f8837621b99d 4 minutes ago 132MB
Перечисленные здесь изображения могут быть удалены, используя Image RM
команда. Общий синтаксис выглядит следующим образом:
docker image rm
Идентификатор может быть идентификатор изображения или репозиторий изображения. Если вы используете репозиторий, вам придется идентифицировать тег также. Чтобы удалить Custom-Nginx: упаковано
Изображение, вы можете выполнить следующую команду:
docker image rm custom-nginx:packaged # Untagged: custom-nginx:packaged # Deleted: sha256:f8837621b99d3388a9e78d9ce49fbb773017f770eea80470fb85e0052beae242 # Deleted: sha256:fdc6cdd8925ac25b9e0ed1c8539f96ad89ba1b21793d061e2349b62dd517dadf # Deleted: sha256:c20e4aa46615fe512a4133089a5cd66f9b7da76366c96548790d5bf865bd49c4 # Deleted: sha256:6d6460a744475a357a2b631a4098aa1862d04510f3625feb316358536fcd8641
Вы также можете использовать Image Brune
Команда для очистки всех не помеченных висных изображений следующим образом:
docker image prune --force # Deleted Images: # deleted: sha256:ba9558bdf2beda81b9acc652ce4931a85f0fc7f69dbc91b4efc4561ef7378aff # deleted: sha256:ad9cc3ff27f0d192f8fa5fadebf813537e02e6ad472f6536847c4de183c02c81 # deleted: sha256:f1e9b82068d43c1bb04ff3e4f0085b9f8903a12b27196df7f1145aa9296c85e7 # deleted: sha256:ec16024aa036172544908ec4e5f842627d04ef99ee9b8d9aaa26b9c2a4b52baa # Total reclaimed space: 59.19MB
- Форс
или -f
Опция пропускает какие-либо вопросы подтверждения. Вы также можете использовать - Все
или -А
Возможность удалить все кэшированные изображения в вашем локальном реестре.
Как понять много слоев докера
С самого начала этой книги я говорил, что изображения являются многослойными файлами. В этом подсечении я продемонстрирую различные слои изображения и как они играют важную роль в процессе сборки этого изображения.
Для этой демонстрации я буду использовать Custom-Nginx: упаковано
Изображение из предыдущего подраздела.
Чтобы визуализировать многие слои изображения, вы можете использовать История изображений
команда. Различные слои Custom-Nginx: упаковано
Изображение может быть визуализировано следующим образом:
docker image history custom-nginx:packaged # IMAGE CREATED CREATED BY SIZE COMMENT # 7f16387f7307 5 minutes ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B # 587c805fe8df 5 minutes ago /bin/sh -c apt-get update && apt-get ins… 60MB # 6fe4e51e35c1 6 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B # d70eaf7277ea 17 hours ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B #17 hours ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B # 17 hours ago /bin/sh -c [ -z "$(apt-get indextargets)" ] 0B # 17 hours ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 811B # 17 hours ago /bin/sh -c #(nop) ADD file:435d9776fdd3a1834… 72.9MB
Есть восемь слоев этого изображения. Верхний уровень слоя является последним, и когда вы идете вниз, слои становятся старше. Верхний большинство слоев – это тот, который вы обычно используете для беговых контейнеров.
Теперь давайте посмотрим на изображения, начиная с изображения d70af7277ea
до 7f16387f7307
Отказ Я буду игнорировать нижние четыре слоя, где Изображение
это <Отсутствует>
Как они не имеют нашей заботы.
d70af7277ea
был создан/bin/sh -c # (nop) cmd ["/bin/bash"]
Что указывает на то, что оболочка по умолчанию внутри Ubuntu была успешно загружена.6FE4E51E35C1
был создан/bin/sh -c # (nop) выставляют 80
Какое было второе инструкция в вашем коде.587C805FE8DF
был создан/bin/sh -c apt-get update update && apt-get install nginx -y && apt-get clean && rm -rf/var/lib/apt/liess/*
который был третьим инструкцией в вашем коде. Вы также можете увидеть, что это изображение имеет размер60 МБ
Учитывая все необходимые пакеты были установлены во время выполнения этой инструкции.- Наконец верхний самый слой
7f16387f7307
был создан/bin/sh -c # (nop) cmd ["nginx", "-G", "демон выключен;"]
которые устанавливают команду по умолчанию для этого изображения.
Как видите, изображение содержит множество слоев только для чтения, каждая запись нового набора изменений в состояние, вызванное определенными инструкциями. Когда вы запускаете контейнер, используя изображение, вы получаете новый пирентный слой поверх других слоев.
Это наслоение явления, которое происходит каждый раз, когда вы работаете с Docker, стал возможен благодаря удивительной технической концепции, называемой профсоюзной файловой системой. Здесь профсоюз означает союз в теории набора. По словам Википедия –
Используя эту концепцию, Docker может избежать дублирования данных и может использовать ранее созданные слои в качестве кеша для более поздних сборки. Это приводит к компактным, эффективным изображениям, которые можно использовать везде.
Как построить Nginx из источника
В предыдущем подразделе вы узнали о От
, Выставлять
, Беги
и CMD
инструкции. В этом подсечении вы будете учиться намного больше о других инструкциях.
В этом подразделе вы снова создадите пользовательские изображения Nginx. Но поворот заключается в том, что вы будете строить Nginx от источника вместо того, чтобы установить его, используя некоторые пакетные менеджер, такие как APT-Get
как в предыдущем примере.
Чтобы построить NGINX из источника, вам сначала нужен источник Nginx. Если вы квалифицировали мою репозиторию проектов, вы увидите файл с именем nginx-1.19.2.tar.gz
внутри Custom-Nginx
каталог. Вы будете использовать этот архив как источник для строительства Nginx.
Перед погружением в писать какой-то код, давайте сначала спланируем процесс. Процесс создания изображения на этот раз может быть сделан за семь шагов. Это следующие:
- Получите хороший базовый образ для построения приложения, как Ubuntu Отказ
- Установите необходимые зависимости сборки на базовом изображении.
- Скопируйте
nginx-1.19.2.tar.gz
Файл внутри изображения. - Извлечь содержимое архива и избавиться от него.
- Настройте сборку, компилируйте и установите программу, используя
сделать
инструмент. - Избавьтесь от извлеченного исходного кода.
- Беги
nginx
исполняемый.
Теперь, когда у вас есть план, давайте начнем с открытия старого Dockerfile
и обновление его содержимого следующим образом:
FROM ubuntu:latest RUN apt-get update && \ apt-get install build-essential\ libpcre3 \ libpcre3-dev \ zlib1g \ zlib1g-dev \ libssl1.1 \ libssl-dev \ -y && \ apt-get clean && rm -rf /var/lib/apt/lists/* COPY nginx-1.19.2.tar.gz . RUN tar -xvf nginx-1.19.2.tar.gz && rm nginx-1.19.2.tar.gz RUN cd nginx-1.19.2 && \ ./configure \ --sbin-path=/usr/bin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --with-pcre \ --pid-path=/var/run/nginx.pid \ --with-http_ssl_module && \ make && make install RUN rm -rf /nginx-1.19.2 CMD ["nginx", "-g", "daemon off;"]
Как видите, код внутри Dockerfile
отражает семь шагов, о которых я говорил выше.
-
От
Инструкции наборы Ubuntu в качестве базового изображения, делая идеальную среду для создания любого приложения. -
Беги
Инструкция устанавливает стандартные пакеты, необходимые для строительства Nginx от источника. -
Скопировать
Инструкция здесь – что-то новое. Эта инструкция несет ответственность за копированиеnginx-1.19.2.tar.gz
Файл внутри изображения. Общий синтаксис дляСкопировать
Инструкция – этоСкопируйте <Пункт назначения>
Где источник находится в вашей локальной файловой системе, и место назначения находится внутри вашего изображения.Отказ
В качестве пункта назначения означает рабочий каталог внутри изображения, который по умолчанию/
Если не установлено иначе. - Второй
Беги
Инструкция здесь извлекает содержимое из архива, используяTar
и избавляется от этого потом. - Файл архива содержит каталог под названием
nginx-1.19.2
содержащий исходный код. Так на следующем шаге вам придетсяCD
Внутри этого каталога и выполните процесс сборки. Вы можете прочитать Как установить программное обеспечение из исходного кода … и удалить его потом статья, чтобы узнать больше по теме. - После завершения сборки и установки вы удалите
nginx-1.19.2
каталог, используяRM
команда. - На заключительном шаге вы запускаете Nginx в одном режиме процесса, как вы делали раньше.
Теперь, чтобы создать изображение, используя этот код, выполните следующую команду:
docker image build --tag custom-nginx:built . # Step 1/7 : FROM ubuntu:latest # ---> d70eaf7277ea # Step 2/7 : RUN apt-get update && apt-get install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev -y && apt-get clean && rm -rf /var/lib/apt/lists/* # ---> Running in 2d0aa912ea47 ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container 2d0aa912ea47 # ---> cbe1ced3da11 # Step 3/7 : COPY nginx-1.19.2.tar.gz . # ---> 7202902edf3f # Step 4/7 : RUN tar -xvf nginx-1.19.2.tar.gz && rm nginx-1.19.2.tar.gz ---> Running in 4a4a95643020 ### LONG EXTRACTION STUFF GOES HERE ### # Removing intermediate container 4a4a95643020 # ---> f9dec072d6d6 # Step 5/7 : RUN cd nginx-1.19.2 && ./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module && make && make install # ---> Running in b07ba12f921e ### LONG CONFIGURATION AND BUILD STUFF GOES HERE ### # Removing intermediate container b07ba12f921e # ---> 5a877edafd8b # Step 6/7 : RUN rm -rf /nginx-1.19.2 # ---> Running in 947e1d9ba828 # Removing intermediate container 947e1d9ba828 # ---> a7702dc7abb7 # Step 7/7 : CMD ["nginx", "-g", "daemon off;"] # ---> Running in 3110c7fdbd57 # Removing intermediate container 3110c7fdbd57 # ---> eae55f7369d3 # Successfully built eae55f7369d3 # Successfully tagged custom-nginx:built
Этот код в порядке, но есть несколько мест, где мы можем сделать улучшения.
- Вместо жесткого кодирования имени файла, как
nginx-1.19.2.tar.gz
, вы можете создать аргумент, используяArg
Инструкция. Таким образом, вы сможете изменить версию или имя файла, просто изменив аргумент. - Вместо того, чтобы загружать архив вручную, вы можете позволить демону загрузить файл во время процесса сборки. Есть еще одна команда, как
Скопировать
называетсяДобавить
Инструкция, которая способна добавлять файлы из Интернета.
Откройте Dockerfile
Файл и обновите его контент следующим образом:
FROM ubuntu:latest RUN apt-get update && \ apt-get install build-essential\ libpcre3 \ libpcre3-dev \ zlib1g \ zlib1g-dev \ libssl1.1 \ libssl-dev \ -y && \ apt-get clean && rm -rf /var/lib/apt/lists/* ARG FILENAME="nginx-1.19.2" ARG EXTENSION="tar.gz" ADD https://nginx.org/download/${FILENAME}.${EXTENSION} . RUN tar -xvf ${FILENAME}.${EXTENSION} && rm ${FILENAME}.${EXTENSION} RUN cd ${FILENAME} && \ ./configure \ --sbin-path=/usr/bin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --with-pcre \ --pid-path=/var/run/nginx.pid \ --with-http_ssl_module && \ make && make install RUN rm -rf /${FILENAME}} CMD ["nginx", "-g", "daemon off;"]
Код практически идентичен предыдущему блоке кода, за исключением новой инструкции, называемой Arg
на линии 13, 14 и использование Добавить
Инструкция по линии 16. Объяснение для обновленного кода выглядит следующим образом:
-
Arg
Инструкция позволяет объявлять переменные, как на других языках. Эти переменные или аргументы могут быть доступны позже, используя использование$ {Имя аргумента}
синтаксис. Здесь я поставил имя файлаnginx-1.19.2
и расширение файлаtar.gz
в двух отдельных аргументах. Таким образом, я могу переключаться между новыми версиями Nginx или формата архива, сделав изменение всего в одном месте. В вышеуказанном коде я добавил значения по умолчанию для переменных. Изменные значения могут быть переданы как параметрыИзображение построить
команда также. Вы можете проконсультироваться с Официальная ссылка Больше подробностей. - В
Добавить
Инструкция, я сформировал URL-адрес загрузки, динамически используя аргументы, объявленные выше.https://nginx.org/download/$?ileName }.$ линия приведет к тому, что что-то вроде
https://nginx.org/download/nginx-1.19.2.tar.gzво время процесса сборки. Вы можете изменить версию файла или расширение, изменив его только в одном месте благодаря
ArgИнструкция.
- Добавить
Инструкция не извлекает файлы, полученные из Интернета по умолчанию, поэтому использование
Tarна линии 18.
Остальная часть кода практически не изменится. Вы должны быть в состоянии понять использование аргументов самостоятельно. Наконец, давайте попробуем создать изображение из этого обновленного кода.
docker image build --tag custom-nginx:built . # Step 1/9 : FROM ubuntu:latest # ---> d70eaf7277ea # Step 2/9 : RUN apt-get update && apt-get install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev -y && apt-get clean && rm -rf /var/lib/apt/lists/* # ---> cbe1ced3da11 ### LONG INSTALLATION STUFF GOES HERE ### # Step 3/9 : ARG FILENAME="nginx-1.19.2" # ---> Running in 33b62a0e9ffb # Removing intermediate container 33b62a0e9ffb # ---> fafc0aceb9c8 # Step 4/9 : ARG EXTENSION="tar.gz" # ---> Running in 5c32eeb1bb11 # Removing intermediate container 5c32eeb1bb11 # ---> 36efdf6efacc # Step 5/9 : ADD https://nginx.org/download/${FILENAME}.${EXTENSION} . # Downloading [==================================================>] 1.049MB/1.049MB # ---> dba252f8d609 # Step 6/9 : RUN tar -xvf ${FILENAME}.${EXTENSION} && rm ${FILENAME}.${EXTENSION} # ---> Running in 2f5b091b2125 ### LONG EXTRACTION STUFF GOES HERE ### # Removing intermediate container 2f5b091b2125 # ---> 2c9a325d74f1 # Step 7/9 : RUN cd ${FILENAME} && ./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module && make && make install # ---> Running in 11cc82dd5186 ### LONG CONFIGURATION AND BUILD STUFF GOES HERE ### # Removing intermediate container 11cc82dd5186 # ---> 6c122e485ec8 # Step 8/9 : RUN rm -rf /${FILENAME}} # ---> Running in 04102366960b # Removing intermediate container 04102366960b # ---> 6bfa35420a73 # Step 9/9 : CMD ["nginx", "-g", "daemon off;"] # ---> Running in 63ee44b571bb # Removing intermediate container 63ee44b571bb # ---> 4ce79556db1b # Successfully built 4ce79556db1b # Successfully tagged custom-nginx:built
Теперь вы должны иметь возможность запускать контейнер, используя Custom-Nginx: построен
изображение.
docker container run --rm --detach --name custom-nginx-built --publish 8080:80 custom-nginx:built # 90ccdbc0b598dddc4199451b2f30a942249d85a8ed21da3c8d14612f17eed0aa docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 90ccdbc0b598 custom-nginx:built "nginx -g 'daemon of…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp custom-nginx-built
Контейнер с использованием Custom-Nginx: STORKET-V2
Изображение было успешно запущено. Контейнер должен быть доступен в http://127.0.0.1:8080
сейчас.
И вот страница доверия по умолчанию от Nginx. Вы можете посетить Официальная ссылка Сайт, чтобы узнать больше о доступных инструкциях.
Как оптимизировать образы докера
Изображение, которое мы встроенные в последнем подраздельном разделе, это функционально, но очень неочищено. Чтобы доказать свою точку зрения, давайте посмотрим на размер изображения, используя Изображение ls
команда:
docker image ls # REPOSITORY TAG IMAGE ID CREATED SIZE # custom-nginx built 1f3aaf40bb54 16 minutes ago 343MB
Для изображения, содержащего только Nginx, это слишком много. Если вы вытащите официальный образ и проверьте его размер, вы увидите, насколько он маленький:
docker image pull nginx:stable # stable: Pulling from library/nginx # a076a628af6f: Pull complete # 45d7b5d3927d: Pull complete # 5e326fece82e: Pull complete # 30c386181b68: Pull complete # b15158e9ebbe: Pull complete # Digest: sha256:ebd0fd56eb30543a9195280eb81af2a9a8e6143496accd6a217c14b06acd1419 # Status: Downloaded newer image for nginx:stable # docker.io/library/nginx:stable docker image ls # REPOSITORY TAG IMAGE ID CREATED SIZE # custom-nginx built 1f3aaf40bb54 25 minutes ago 343MB # nginx stable b9e1dc12387a 11 days ago 133MB
Для того, чтобы выяснить корневую причину, давайте посмотрим на Dockerfile
первый:
FROM ubuntu:latest RUN apt-get update && \ apt-get install build-essential\ libpcre3 \ libpcre3-dev \ zlib1g \ zlib1g-dev \ libssl1.1 \ libssl-dev \ -y && \ apt-get clean && rm -rf /var/lib/apt/lists/* ARG FILENAME="nginx-1.19.2" ARG EXTENSION="tar.gz" ADD https://nginx.org/download/${FILENAME}.${EXTENSION} . RUN tar -xvf ${FILENAME}.${EXTENSION} && rm ${FILENAME}.${EXTENSION} RUN cd ${FILENAME} && \ ./configure \ --sbin-path=/usr/bin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --with-pcre \ --pid-path=/var/run/nginx.pid \ --with-http_ssl_module && \ make && make install RUN rm -rf /${FILENAME}} CMD ["nginx", "-g", "daemon off;"]
Как вы можете увидеть на линии 3, Беги
Инструкция устанавливает много вещей. Хотя эти пакеты необходимы для строительства Nginx от источника, они не нужны для его работы.
Из 6 пакетов, которые мы установили, только два необходимы для работы Nginx. Это libpcre3
и zlib1g
Отказ Таким образом, лучшая идея будет удалить другие пакеты после выполнения процесса сборки.
Чтобы сделать это, обновите свой Dockerfile
следующим образом:
FROM ubuntu:latest EXPOSE 80 ARG FILENAME="nginx-1.19.2" ARG EXTENSION="tar.gz" ADD https://nginx.org/download/${FILENAME}.${EXTENSION} . RUN apt-get update && \ apt-get install build-essential \ libpcre3 \ libpcre3-dev \ zlib1g \ zlib1g-dev \ libssl1.1 \ libssl-dev \ -y && \ tar -xvf ${FILENAME}.${EXTENSION} && rm ${FILENAME}.${EXTENSION} && \ cd ${FILENAME} && \ ./configure \ --sbin-path=/usr/bin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --with-pcre \ --pid-path=/var/run/nginx.pid \ --with-http_ssl_module && \ make && make install && \ cd / && rm -rfv /${FILENAME} && \ apt-get remove build-essential \ libpcre3-dev \ zlib1g-dev \ libssl-dev \ -y && \ apt-get autoremove -y && \ apt-get clean && rm -rf /var/lib/apt/lists/* CMD ["nginx", "-g", "daemon off;"]
Как вы можете видеть, на линии 10 единого Беги
Инструкция делает все необходимое тяжелое подъема. Точная цепочка событий выглядит следующим образом:
- От линии 10 до линии 17, все необходимые пакеты устанавливаются.
- В строке 18 извлекается исходный код, и загруженный архив удаляется.
- Из строки 19 до линии 28, Nginx настроен, создан и установлен в системе.
- В строке 29 извлеченные файлы из загруженного архива удаляются.
- Из строки 30 до линии 36 все ненужные пакеты удаляют, и кэш очищен.
libpcre3
иzlib1g
Пакеты необходимы для работы Nginx, поэтому мы сохраняем их.
Вы можете спросить, почему я делаю так много работы в одном Беги
Инструкция вместо того, чтобы красиво расщепляться в нескольких инструкциях, как мы ранее. Ну, расщепление их будет ошибкой.
Если вы устанавливаете пакеты, а затем удалите их в отдельном Беги
Инструкции, они будут жить в отдельных слоях изображения. Хотя окончательное изображение не будет иметь удаленные пакеты, их размер все еще будет добавлен к окончательному изображению, поскольку они существуют в одном из слоев, состоящих из изображения. Поэтому убедитесь, что вы делаете такие изменения на одном слое.
Давайте построим изображение, используя это Dockerfile
и увидеть различия.
docker image build --tag custom-nginx:built . # Sending build context to Docker daemon 1.057MB # Step 1/7 : FROM ubuntu:latest # ---> f63181f19b2f # Step 2/7 : EXPOSE 80 # ---> Running in 006f39b75964 # Removing intermediate container 006f39b75964 # ---> 6943f7ef9376 # Step 3/7 : ARG FILENAME="nginx-1.19.2" # ---> Running in ffaf89078594 # Removing intermediate container ffaf89078594 # ---> 91b5cdb6dabe # Step 4/7 : ARG EXTENSION="tar.gz" # ---> Running in d0f5188444b6 # Removing intermediate container d0f5188444b6 # ---> 9626f941ccb2 # Step 5/7 : ADD https://nginx.org/download/${FILENAME}.${EXTENSION} . # Downloading [==================================================>] 1.049MB/1.049MB # ---> a8e8dcca1be8 # Step 6/7 : RUN apt-get update && apt-get install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev -y && tar -xvf ${FILENAME}.${EXTENSION} && rm ${FILENAME}.${EXTENSION} && cd ${FILENAME} && ./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module && make && make install && cd / && rm -rfv /${FILENAME} && apt-get remove build-essential libpcre3-dev zlib1g-dev libssl-dev -y && apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* # ---> Running in e5675cad1260 ### LONG INSTALLATION AND BUILD STUFF GOES HERE ### # Removing intermediate container e5675cad1260 # ---> dc7e4161f975 # Step 7/7 : CMD ["nginx", "-g", "daemon off;"] # ---> Running in b579e4600247 # Removing intermediate container b579e4600247 # ---> 512aa6a95a93 # Successfully built 512aa6a95a93 # Successfully tagged custom-nginx:built docker image ls # REPOSITORY TAG IMAGE ID CREATED SIZE # custom-nginx built 512aa6a95a93 About a minute ago 81.6MB # nginx stable b9e1dc12387a 11 days ago 133MB
Как видите, размер изображения ушел от 343 МБ до 81,6 МБ. Официальное изображение 133 МБ. Это довольно оптимизированная сборка, но мы можем немного пойти немного в следующем подразделе.
Обнимая альпийский Linux
Если вы уже некоторое время возились контейнерами, вы, возможно, слышали о том, что называется Alpine Linux Отказ Это полнофункциональный Linux Распределение как Ubuntu , Debian или Федора Отказ
Но хорошая вещь о альпийском языке в том, что он построен вокруг мускул
Libc
и Bitebox
и легкий. Где последние Ubuntu Изображение весит около 28 МБ, альпийский 2,8 МБ.
Помимо легкой природы, альпий также безопасна и намного лучше подходит для создания контейнеров, чем другие распределения.
Хотя не в качестве удобства пользователя, как другие коммерческие распределения, переход к альпину все еще очень прост. В этом подсечении вы узнаете о воссоздании Custom-Nginx
Изображение с использованием альпийского изображения в качестве его базы.
Откройте свой Dockerfile
и обновить его контент следующим образом:
FROM alpine:latest EXPOSE 80 ARG FILENAME="nginx-1.19.2" ARG EXTENSION="tar.gz" ADD https://nginx.org/download/${FILENAME}.${EXTENSION} . RUN apk add --no-cache pcre zlib && \ apk add --no-cache \ --virtual .build-deps \ build-base \ pcre-dev \ zlib-dev \ openssl-dev && \ tar -xvf ${FILENAME}.${EXTENSION} && rm ${FILENAME}.${EXTENSION} && \ cd ${FILENAME} && \ ./configure \ --sbin-path=/usr/bin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --with-pcre \ --pid-path=/var/run/nginx.pid \ --with-http_ssl_module && \ make && make install && \ cd / && rm -rfv /${FILENAME} && \ apk del .build-deps CMD ["nginx", "-g", "daemon off;"]
Код практически идентичен, за исключением нескольких изменений. Я буду перечислять изменения и объяснять их, как я иду:
- Вместо использования
apt-get install
Для установки пакетов мы используемAPK Добавить
Отказ- Нет-кэш
Опция означает, что загруженный пакет не будет кэширован. Точно так же мы будем использоватьapk del
вместоapt-get Удалить
удалить пакеты. -
--virtual
Вариант дляAPK Добавить
Команда используется для объединения куча пакетов в один виртуальный пакет для облегчения управления. Пакеты, которые необходимы только для построения программы, помечены как.Build-DEPS
которые затем удаляются на линии 29, выполняяapk del .build-dems
команда. Вы можете узнать больше о виртуальные в официальных документах. - Имена пакетов здесь немного отличаются. Обычно каждое дистрибутив Linux имеет свой репозиторий пакета, доступный каждому, где вы можете искать пакеты. Если вы знаете, что пакеты, необходимые для определенной задачи, вы можете просто отправиться в назначенный репозиторий для распределения и поиска его. Вы можете Посмотрите на альпийские пакеты Linux здесь Отказ
Теперь постройте новое изображение, используя этот Dockerfile
и увидеть разницу в размере файла:
docker image build --tag custom-nginx:built . # Sending build context to Docker daemon 1.055MB # Step 1/7 : FROM alpine:latest # ---> 7731472c3f2a # Step 2/7 : EXPOSE 80 # ---> Running in 8336cfaaa48d # Removing intermediate container 8336cfaaa48d # ---> d448a9049d01 # Step 3/7 : ARG FILENAME="nginx-1.19.2" # ---> Running in bb8b2eae9d74 # Removing intermediate container bb8b2eae9d74 # ---> 87ca74f32fbe # Step 4/7 : ARG EXTENSION="tar.gz" # ---> Running in aa09627fe48c # Removing intermediate container aa09627fe48c # ---> 70cb557adb10 # Step 5/7 : ADD https://nginx.org/download/${FILENAME}.${EXTENSION} . # Downloading [==================================================>] 1.049MB/1.049MB # ---> b9790ce0c4d6 # Step 6/7 : RUN apk add --no-cache pcre zlib && apk add --no-cache --virtual .build-deps build-base pcre-dev zlib-dev openssl-dev && tar -xvf ${FILENAME}.${EXTENSION} && rm ${FILENAME}.${EXTENSION} && cd ${FILENAME} && ./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module && make && make install && cd / && rm -rfv /${FILENAME} && apk del .build-deps # ---> Running in 0b301f64ffc1 ### LONG INSTALLATION AND BUILD STUFF GOES HERE ### # Removing intermediate container 0b301f64ffc1 # ---> dc7e4161f975 # Step 7/7 : CMD ["nginx", "-g", "daemon off;"] # ---> Running in b579e4600247 # Removing intermediate container b579e4600247 # ---> 3e186a3c6830 # Successfully built 3e186a3c6830 # Successfully tagged custom-nginx:built docker image ls # REPOSITORY TAG IMAGE ID CREATED SIZE # custom-nginx built 3e186a3c6830 8 seconds ago 12.8MB
Где версия Ubuntu была 81,6 МБ, альпийский наступил до 12,8 МБ, что является огромным усилением. Помимо APK
Менеджер по пакетам, есть некоторые другие вещи, которые отличаются в альпийском от Ubuntu, но они не такие большие сделки. Вы можете просто найти Интернет, когда вы застряли.
Как создать исполняемые изображения Docker
В предыдущем разделе вы работали с FHSINCHY/RMBYEXT изображение. В этом разделе вы узнаете, как сделать такое исполняемое изображение.
Для начала открыть каталог, в котором вы клонировали репозиторий, пришел с этой книгой. Код для RMbyext
Приложение проживает внутри подсчетов с тем же именем.
Прежде чем начать работать на Dockerfile
Найдите минутку, чтобы спланировать то, что должно быть окончательный выход. На мой взгляд, это должно быть как что-то вроде этого:
- Изображение должно иметь предварительно установленное Python.
- Он должен содержать копию моего
RMbyext
скрипт - Рабочий каталог должен быть установлен, где будет выполняться скрипт.
-
RMbyext
Сценарий должен быть установлен в качестве точки входа, поэтому изображение может принимать удлинительные имена в качестве аргументов.
Чтобы создать вышеупомянутое изображение, примите следующие шаги:
- Получите хорошее базовое изображение для бега сценариев Python, как Python Отказ
- Настройка рабочего каталога до легкодоступного каталога.
- Установите Git так, чтобы скрипт был установлен с моего репозитория GitHUB.
- Установите скрипт, используя git и pip.
- Избавьтесь от ненужных пакетов сборки.
- Установить
RMbyext
Как точка входа для этого изображения.
Теперь создайте новый Dockerfile
внутри RMbyext
каталог и поместить следующий код в нем:
FROM python:3-alpine WORKDIR /zone RUN apk add --no-cache git && \ pip install git+https://github.com/fhsinchy/rmbyext.git#egg=rmbyext && \ apk del git ENTRYPOINT [ "rmbyext" ]
Объяснение инструкций в этом файле следующим образом:
-
От
Наборы инструкций Python В качестве базового изображения, сделав идеальную среду для беговых сценариев Python.3-ALPINE
Тег указывает, что вы хотите, чтобы альпийский вариант Python 3. -
Workdir
Инструкция Устанавливает рабочий каталог по умолчанию для/зона
здесь. Название рабочего каталога здесь совершенно случайно. Я нашел зону, чтобы быть приспособленным именем, вы можете использовать все, что вы хотите. - Учитывая
RMbyext
Сценарий установлен из GitHub,Гит
это зависимость времени установки.Беги
Инструкция по линии 5 УстановитьГит
затем устанавливаетRMbyext
Сценарий с использованием Git и Pip. Это также избавляется отГит
после. - Наконец на линии 9,
Выходная точка
Инструкция устанавливаетRMbyext
Сценарий как точка входа для этого изображения.
В этом досле один файл линии 9 – это магия, которая превращает это, казалось бы, нормальное изображение в исполняемое. Теперь, чтобы построить изображение, которое вы можете выполнить следующую команду:
docker image build --tag rmbyext . # Sending build context to Docker daemon 2.048kB # Step 1/4 : FROM python:3-alpine # 3-alpine: Pulling from library/python # 801bfaa63ef2: Already exists # 8723b2b92bec: Already exists # 4e07029ccd64: Already exists # 594990504179: Already exists # 140d7fec7322: Already exists # Digest: sha256:7492c1f615e3651629bd6c61777e9660caa3819cf3561a47d1d526dfeee02cf6 # Status: Downloaded newer image for python:3-alpine # ---> d4d4f50f871a # Step 2/4 : WORKDIR /zone # ---> Running in 454374612a91 # Removing intermediate container 454374612a91 # ---> 7f7e49bc98d2 # Step 3/4 : RUN apk add --no-cache git && pip install git+https://github.com/fhsinchy/rmbyext.git#egg=rmbyext && apk del git # ---> Running in 27e2e96dc95a ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container 27e2e96dc95a # ---> 3c7389432e36 # Step 4/4 : ENTRYPOINT [ "rmbyext" ] # ---> Running in f239bbea1ca6 # Removing intermediate container f239bbea1ca6 # ---> 1746b0cedbc7 # Successfully built 1746b0cedbc7 # Successfully tagged rmbyext:latest docker image ls # REPOSITORY TAG IMAGE ID CREATED SIZE # rmbyext latest 1746b0cedbc7 4 minutes ago 50.9MB
Здесь я не предоставил ни теги после имени изображения, поэтому изображение было помечено как Последнее
по умолчанию. Вы должны иметь возможность запускать изображение, когда вы видели в предыдущем разделе. Не забудьте обратиться к фактическому названию изображения, а не FHSINCHY/RMBYEXT
здесь.
Как поделиться своими изображениями Docker онлайн
Теперь, когда вы знаете, как сделать изображения, пришло время поделиться с ними с миром. Обмен изображениями онлайн легко. Все, что вам нужно, это учетная запись в любой из онлайн-реестров. Я буду использовать Докер Хаб здесь.
Перейдите к Зарегистрируйтесь Страница и создайте бесплатную учетную запись. Бесплатная учетная запись позволяет размещать неограниченные публичные репозитории и один частный репозиторий.
Как только вы создали учетную запись, вам придется войти в нее, используя Docker CLI. Так что откройте свой терминал и выполните следующую команду, чтобы сделать это:
docker login # Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. # Username: fhsinchy # Password: # WARNING! Your password will be stored unencrypted in /home/fhsinchy/.docker/config.json. # Configure a credential helper to remove this warning. See # https://docs.docker.com/engine/reference/commandline/login/#credentials-store # # Login Succeeded
Вам будет предложено ваше имя пользователя и пароль. Если вы их правильно вводите, вы должны быть успешно войти на свою учетную запись.
Для того, чтобы поделиться изображением онлайн, изображение должно быть помечено. Вы уже узнали о метке в предыдущем подразделе. Просто чтобы обновить вашу память, общий синтаксис для --tag
или -t
Вариант выглядит следующим образом:
--tag:
В качестве примера давайте поделимся Custom-Nginx
Изображение онлайн. Чтобы сделать это, откройте новое окно терминала внутри Custom-Nginx
каталог проекта.
Чтобы поделиться изображением онлайн, вам придется пометить его после <Имя пользователя Docker Hub>/<Имя изображения>: <Тег изображения>
синтаксис. Мое имя пользователя Fhsinchy
Так что команда будет выглядеть так:
docker image build --tag fhsinchy/custom-nginx:latest --file Dockerfile.built . # Step 1/9 : FROM ubuntu:latest # ---> d70eaf7277ea # Step 2/9 : RUN apt-get update && apt-get install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev -y && apt-get clean && rm -rf /var/lib/apt/lists/* # ---> cbe1ced3da11 ### LONG INSTALLATION STUFF GOES HERE ### # Step 3/9 : ARG FILENAME="nginx-1.19.2" # ---> Running in 33b62a0e9ffb # Removing intermediate container 33b62a0e9ffb # ---> fafc0aceb9c8 # Step 4/9 : ARG EXTENSION="tar.gz" # ---> Running in 5c32eeb1bb11 # Removing intermediate container 5c32eeb1bb11 # ---> 36efdf6efacc # Step 5/9 : ADD https://nginx.org/download/${FILENAME}.${EXTENSION} . # Downloading [==================================================>] 1.049MB/1.049MB # ---> dba252f8d609 # Step 6/9 : RUN tar -xvf ${FILENAME}.${EXTENSION} && rm ${FILENAME}.${EXTENSION} # ---> Running in 2f5b091b2125 ### LONG EXTRACTION STUFF GOES HERE ### # Removing intermediate container 2f5b091b2125 # ---> 2c9a325d74f1 # Step 7/9 : RUN cd ${FILENAME} && ./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre --pid-path=/var/run/nginx.pid --with-http_ssl_module && make && make install # ---> Running in 11cc82dd5186 ### LONG CONFIGURATION AND BUILD STUFF GOES HERE ### # Removing intermediate container 11cc82dd5186 # ---> 6c122e485ec8 # Step 8/9 : RUN rm -rf /${FILENAME}} # ---> Running in 04102366960b # Removing intermediate container 04102366960b # ---> 6bfa35420a73 # Step 9/9 : CMD ["nginx", "-g", "daemon off;"] # ---> Running in 63ee44b571bb # Removing intermediate container 63ee44b571bb # ---> 4ce79556db1b # Successfully built 4ce79556db1b # Successfully tagged fhsinchy/custom-nginx:latest
В этой команде fhsinchy/custom-nginx
это репозиторий изображения и Последнее
это тег. Имя изображения может быть все, что вы хотите, и не может быть изменен, как только вы загрузили изображение. Тег может быть изменен всякий раз, когда вы хотите, и обычно отражают версию программного обеспечения или разных видов сборки.
Возьми Узел
изображение в качестве примера. Узел: LTS
Изображение относится к долгосрочной поддержке версии Node.js, тогда как Узел: LTS-Alpine
Версия относится к версии Node.js, построенной для Alpine Linux, которая намного меньше, чем обычный.
Если вы не даете изображения любой тег, он будет автоматически помечен как Последнее
Отказ Но это не значит, что Последнее
Тег всегда будет ссылаться на последнюю версию. Если по какой-то причине вы явно тег старая версия изображения как Последнее
Затем Docker не приложит никакие дополнительные усилия, чтобы пересечь это.
После того, как изображение было построено, вы можете их загрузить его, выполнив следующую команду:
docker image push:
Так что в моем случае команда будет следующим:
docker image push fhsinchy/custom-nginx:latest # The push refers to repository [docker.io/fhsinchy/custom-nginx] # 4352b1b1d9f5: Pushed # a4518dd720bd: Pushed # 1d756dc4e694: Pushed # d7a7e2b6321a: Pushed # f6253634dc78: Mounted from library/ubuntu # 9069f84dbbe9: Mounted from library/ubuntu # bacd3af13903: Mounted from library/ubuntu # latest: digest: sha256:ffe93440256c9edb2ed67bf3bba3c204fec3a46a36ac53358899ce1a9eee497a size: 1788
В зависимости от размера изображения загрузка может занять некоторое время. Как только это будет сделано, вы сможете найти изображение в странице профиля HUB.
Как контейнеризировать приложение JavaScript
Теперь, когда у вас есть представление о том, как создавать изображения, пришло время работать с чем-то более актуальным.
В этом подраздел вы будете работать с исходным кодом FHSINCHY/HELLO-DOCK Изображение, с которым вы работали в предыдущем разделе. В процессе контейнера к этому очень простому приложению вы будете введены в объемы и многоядерные сборки, две из самых важных концепций в Docker.
Как написать Development DockerFile
Для начала открыть каталог, в котором вы клонировали репозиторий, пришел с этой книгой. Код для Привет-док
Приложение проживает внутри подсчетов с тем же именем.
Это очень простой проект JavaScript, питающийся от Vitejs/Vite проект. Не волнуйтесь, хотя вам не нужно знать JavaScript или Vite, чтобы пройти через этот подраздел. Имея основное понимание Node.js и NPM будет достаточно.
Как и любой другой проект, который вы сделали в предыдущем подразделе, вы начнете, сделав план того, как вы хотите, чтобы это приложение запустилось. На мой взгляд, план должен быть следующим:
- Получите хорошее базовое изображение для запуска приложений JavaScript, например Узел Отказ
- Установите рабочий каталог по умолчанию внутри изображения.
- Скопируйте
Package.json
файл на изображение. - Установите необходимые зависимости.
- Скопируйте остальные файлы проекта.
- Начать
Вите
Сервер разработки путем выполненияNPM запустить dev
команда.
Этот план всегда должен прийти от разработчика приложения, который вы контейнерируете. Если вы сами разработчик, то у вас уже должно быть правильное понимание того, как необходимо выполнить это приложение.
Теперь, если вы поставили вышеупомянутый план внутри Dockerfile.dev
, файл должен выглядеть следующим образом:
FROM node:lts-alpine EXPOSE 3000 USER node RUN mkdir -p /home/node/app WORKDIR /home/node/app COPY ./package.json . RUN npm install COPY . . CMD [ "npm", "run", "dev" ]
Объяснение этого кода выглядит следующим образом:
-
От
Инструкция здесь устанавливает официальный образ Node.js в качестве основы, предоставляя вам всю доброту Node.js, необходимых для запуска любого приложения JavaScript.LTS-ALPINE
Тег указывает, что вы хотите использовать альпийский вариант, долгосрочную поддержку версии изображения. Доступные теги и необходимая документация для изображения можно найти на Узел Страница HUB. -
Пользователь
Инструкция Устанавливает пользователя по умолчанию для изображения наУзел
Отказ По умолчанию Docker управляет контейнерами как пользователь root. Но по словам Докер и Node.js лучшие практики Это может представлять угрозу безопасности. Таким образом, это лучшее представление о том, чтобы работать как пользователь без root, когда это возможно. Изображение узла поставляется с пользователем Non-root с именемУзел
который вы можете установить как пользователь по умолчанию, используяПользователь
Инструкция. -
Run mkdir -p/home/node/app
Инструкция создает каталог под названиемприложение
Внутри домашнего каталогаУзел
Пользователь. Домашний каталог для любого пользователем без root в Linux обычно/home/<имя пользователя>
по умолчанию. - Тогда
Workdir
Инструкция Устанавливает рабочий каталог по умолчанию для вновь созданного/Home/Node/App
каталог. По умолчанию рабочий каталог любого изображения является корнем. Вы не хотите, чтобы никакие ненужные файлы распыляются по всему корневому каталогу, делаете ли вы? Следовательно, вы меняете рабочий каталог по умолчанию на что-то более разумное, как/Home/Node/App
или что угодно. Этот рабочий каталог будет применим к любому последующемуСкопировать
,Добавить
,Беги
иCMD
инструкции. -
Скопировать
Инструкция здесь копируетPackage.json
Файл, который содержит информацию о всех необходимых зависимостях для этого приложения.Беги
Инструкция выполняетNPM установить
Команда, которая является командой по умолчанию для установки зависимостей с помощью APackage.json
Файл в Node.js проекты.Отказ
В конце представляет рабочий каталог. - Второй
Скопировать
Инструкция копирует остальную часть содержимого из текущего каталога (.
) файловой системы хоста в рабочий каталог (.
) Внутри изображения. - Наконец,
CMD
Инструкция здесь устанавливает команду по умолчанию для этого изображения, которое являетсяNPM запустить dev
написано вexec
форма. -
Вите
Сервер разработки по умолчанию работает на порту3000
и добавляяВыставлять
Команда казалась хорошей идеей, так что вы идете.
Теперь, чтобы построить изображение из этого Dockerfile.dev
Вы можете выполнить следующую команду:
docker image build --file Dockerfile.dev --tag hello-dock:dev . # Step 1/7 : FROM node:lts # ---> b90fa0d7cbd1 # Step 2/7 : EXPOSE 3000 # ---> Running in 722d639badc7 # Removing intermediate container 722d639badc7 # ---> e2a8aa88790e # Step 3/7 : WORKDIR /app # ---> Running in 998e254b4d22 # Removing intermediate container 998e254b4d22 # ---> 6bd4c42892a4 # Step 4/7 : COPY ./package.json . # ---> 24fc5164a1dc # Step 5/7 : RUN npm install # ---> Running in 23b4de3f930b ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container 23b4de3f930b # ---> c17ecb19a210 # Step 6/7 : COPY . . # ---> afb6d9a1bc76 # Step 7/7 : CMD [ "npm", "run", "dev" ] # ---> Running in a7ff529c28fe # Removing intermediate container a7ff529c28fe # ---> 1792250adb79 # Successfully built 1792250adb79 # Successfully tagged hello-dock:dev
Учитывая имя файла не Dockerfile
Вы должны явно пройти имя файла, используя --file
вариант. Контейнер может быть запущен с помощью этого изображения, выполнив следующую команду:
docker container run \ --rm \ --detach \ --publish 3000:3000 \ --name hello-dock-dev \ hello-dock:dev # 21b9b1499d195d85e81f0e8bce08f43a64b63d589c5f15cbbd0b9c0cb07ae268
Теперь посетите http://127.0.0.1:3000
чтобы увидеть Привет-док
Приложение в действии.
Поздравляем с запуском вашего первого реального применения внутри контейнера. Код, который вы только что написали, в порядке, но есть одна большая проблема с ним и несколько мест, где он может быть улучшен. Давайте сначала начнем с проблемой.
Как работать с креплениями Bind в Docker
Если вы работали с любым интерфейсом JavaScript Framework, вы должны знать, что серверы разработки в этих рамках обычно поставляются с функцией горячей перезагрузки. То есть, если вы внесите изменения в свой код, сервер будет перезагружаться, автоматически отражая любые изменения, которые вы сделали сразу.
Но если вы вносите какие-либо изменения в своем коде прямо сейчас, вы увидите ничего не происходящего с вашим приложением, работающим в браузере. Это связано с тем, что вы вносите изменения в код, который у вас есть в вашей локальной файловой системе, но приложение, которое вы видите в браузере, расположен внутри файловой системы контейнера.
Чтобы решить эту проблему, вы можете снова использовать привязать крепление Отказ Используя крепления BING, вы можете легко установить одну из ваших местных каталогов файловой системы внутри контейнера. Вместо того, чтобы сделать копию локальной файловой системы, крепление BING может ссылаться на локальную файловую систему непосредственно изнутри контейнера.
Таким образом, любые изменения, которые вы делаете в ваш локальный исходный код, немедленно отражают внутри контейнера, запуская функцию горячей перезагрузки Вите
Сервер развития. Изменения, внесенные в файловую систему внутри контейнера, также будут отражены в вашей локальной файловой системе.
Вы уже узнали в Работа с исполняемыми изображениями Подборка, крепления связывания могут быть созданы с помощью --volume
или -V
Вариант для Контейнер работает
или Старт контейнера
команды. Просто чтобы напомнить вам, общий синтаксис выглядит следующим образом:
--volume: :
Остановите, что вы начали ранее Hello-Dock-dev
Контейнер и начните новый контейнер, выполнив следующую команду:
docker container run \ --rm \ --publish 3000:3000 \ --name hello-dock-dev \ --volume $(pwd):/home/node/app \ hello-dock:dev # sh: 1: vite: not found # npm ERR! code ELIFECYCLE # npm ERR! syscall spawn # npm ERR! file sh # npm ERR! errno ENOENT # npm ERR! hello-dock@0.0.0 dev: `vite` # npm ERR! spawn ENOENT # npm ERR! # npm ERR! Failed at the hello-dock@0.0.0 dev script. # npm ERR! This is probably not a problem with npm. There is likely additional logging output above. # npm WARN Local package.json exists, but node_modules missing, did you mean to install?
Имейте в виду, я опустил --detach
Вариант, и это демонстрировать очень важный момент. Как видите, приложение вообще не работает.
Это потому, что хотя использование объема решает проблему горячих перезарядков, он вводит другую проблему. Если у вас есть какой-либо предыдущий опыт работы с Node.js, вы можете знать, что зависимости проекта Node.js живут внутри node_modules
каталог на корне проекта.
Теперь, когда вы устанавливаете Root Project в локальной файловой системе в качестве громкости внутри контейнера, содержимое внутри контейнера заменяется вместе с node_modules
каталог, содержащий все зависимости. Это означает, что Вите
Пакет пропал без вести.
Как работать с анонимными томами в докере
Эта проблема может быть решена с использованием анонимного объема. Анонимный том идентичен для крепления Bind, за исключением того, что вам не нужно указывать исходный каталог здесь. Общий синтаксис для создания анонимного объема выглядит следующим образом:
--volume:
Так что финальная команда для запуска Привет-док
Контейнер с обеими объемами должен быть следующим:
docker container run \ --rm \ --detach \ --publish 3000:3000 \ --name hello-dock-dev \ --volume $(pwd):/home/node/app \ --volume /home/node/app/node_modules \ hello-dock:dev # 53d1cfdb3ef148eb6370e338749836160f75f076d0fbec3c2a9b059a8992de8b
Здесь докер займет весь node_modules
Каталог изнутри контейнера и заправить его в каком-то другом каталоге, управляемом Docker Daemon на вашей файловой системе хоста и установит этот каталог AS node_modules
внутри контейнера.
Как выполнить многоядерные сборки в Docker
До сих пор в этом разделе вы построили изображение для запуска приложения JavaScript в режиме разработки. Теперь, если вы хотите создать изображение в производственном режиме, появятся некоторые новые вызовы.
В режиме разработки NPM запустить
Команда запускает сервер разработки, который обслуживает приложение пользователю. Этот сервер не только обслуживает файлы, но также обеспечивает функцию горячей перезагрузки.
В режиме производства NPM запустить сборку
Команда компилирует весь ваш код JavaScript в некоторые статические файлы HTML, CSS и JavaScript. Чтобы запустить эти файлы, вам не нужен узел или любые другие зависимости выполнения. Все, что вам нужно, это сервер, такой как nginx
Например.
Чтобы создать изображение, в котором приложение работает в режиме производства, вы можете принять следующие шаги:
- Использовать
Узел
в качестве базового изображения и создайте приложение. - Установить
nginx
Внутри изображения узла и используйте, что для обслуживания статических файлов.
Этот подход полностью действителен. Но проблема в том, что Узел
Изображение большая, и большинство вещей, которые он несет не нужен, чтобы обслуживать ваши статические файлы. Лучший подход к этому сценарию выглядит следующим образом:
- Использовать
Узел
Изображение в качестве основы и построить приложение. - Скопируйте файлы, созданные с помощью
Узел
Изображение дляnginx
изображение. - Создайте окончательное изображение на основе
nginx
и отказаться от всехУзел
Связанные вещи.
Таким образом, ваше изображение содержит только файлы, которые необходимы, и становится действительно удобным.
Этот подход – это многостоятельная сборка. Чтобы выполнить такую сборку, создайте новый Dockerfile
Внутри вашего Привет-док
каталог проекта и поместить следующий контент в нем:
FROM node:lts-alpine as builder WORKDIR /app COPY ./package.json ./ RUN npm install COPY . . RUN npm run build FROM nginx:stable-alpine EXPOSE 80 COPY --from=builder /app/dist /usr/share/nginx/html
Как вы можете увидеть Dockerfile
очень похоже на ваши предыдущие с несколькими странами. Объяснение этого файла выглядит следующим образом:
- Линия 1 начинает первый этап сборки, используя
Узел: LTS-Alpine
как базовое изображение.как строитель
Синтаксис назначает имя на этот этап, чтобы его можно было упомянуть позже. - Из строки 3 до линии 9, это стандартные вещи, которые вы видели много раз ранее.
Запустите NPM Run Build
Команда фактически компилирует все приложение и заправляет его внутри/app/dist
каталог, где/приложение
рабочий каталог и/dist
это выходной каталог по умолчанию дляВите
Приложения. - Линия 11 начинается второй этап сборки, используя
nginx: стабильный альпийский
как базовое изображение. - Сервер Nginx работает на порту 80 по умолчанию, так что линия
Выдержать 80
добавлен. - Последняя строка –
Скопировать
Инструкция.- из построителя
Часть указывает, что вы хотите скопировать некоторые файлы изстроитель
сцена. После этого это стандартная команда копирования, где/app/dist
это источник и/usr/share/nginx/html
это пункт назначения. Используемый здесь пункт назначения – путь сайта по умолчанию для Nginx, поэтому любой статический файл, который вы помещаете внутри, будет автоматически подан.
Как видите, полученное изображение является nginx
Базовое изображение, содержащее только файлы, необходимые для запуска приложения. Для создания этого изображения выполняется следующая команда:
docker image build --tag hello-dock:prod . # Step 1/9 : FROM node:lts-alpine as builder # ---> 72aaced1868f # Step 2/9 : WORKDIR /app # ---> Running in e361c5c866dd # Removing intermediate container e361c5c866dd # ---> 241b4b97b34c # Step 3/9 : COPY ./package.json ./ # ---> 6c594c5d2300 # Step 4/9 : RUN npm install # ---> Running in 6dfabf0ee9f8 # npm WARN deprecated fsevents@2.1.3: Please update to v 2.2.x # # > esbuild@0.8.29 postinstall /app/node_modules/esbuild # > node install.js # # npm notice created a lockfile as package-lock.json. You should commit this file. # npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.1.2 (node_modules/chokidar/node_modules/fsevents): # npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"}) # npm WARN hello-dock@0.0.0 No description # npm WARN hello-dock@0.0.0 No repository field. # npm WARN hello-dock@0.0.0 No license field. # # added 327 packages from 301 contributors and audited 329 packages in 35.971s # # 26 packages are looking for funding # run `npm fund` for details # # found 0 vulnerabilities # # Removing intermediate container 6dfabf0ee9f8 # ---> 21fd1b065314 # Step 5/9 : COPY . . # ---> 43243f95bff7 # Step 6/9 : RUN npm run build # ---> Running in 4d918cf18584 # # > hello-dock@0.0.0 build /app # > vite build # # - Building production bundle... # # [write] dist/index.html 0.39kb, brotli: 0.15kb # [write] dist/_assets/docker-handbook-github.3adb4865.webp 12.32kb # [write] dist/_assets/index.eabcae90.js 42.56kb, brotli: 15.40kb # [write] dist/_assets/style.0637ccc5.css 0.16kb, brotli: 0.10kb # - Building production bundle... # # Build completed in 1.71s. # # Removing intermediate container 4d918cf18584 # ---> 187fb3e82d0d # Step 7/9 : EXPOSE 80 # ---> Running in b3aab5cf5975 # Removing intermediate container b3aab5cf5975 # ---> d6fcc058cfda # Step 8/9 : FROM nginx:stable-alpine # stable: Pulling from library/nginx # 6ec7b7d162b2: Already exists # 43876acb2da3: Pull complete # 7a79edd1e27b: Pull complete # eea03077c87e: Pull complete # eba7631b45c5: Pull complete # Digest: sha256:2eea9f5d6fff078ad6cc6c961ab11b8314efd91fb8480b5d054c7057a619e0c3 # Status: Downloaded newer image for nginx:stable # ---> 05f64a802c26 # Step 9/9 : COPY --from=builder /app/dist /usr/share/nginx/html # ---> 8c6dfc34a10d # Successfully built 8c6dfc34a10d # Successfully tagged hello-dock:prod
Как только изображение будет построено, вы можете запустить новый контейнер, выполнив следующую команду:
docker container run \ --rm \ --detach \ --name hello-dock-prod \ --publish 8080:80 \ hello-dock:prod # 224aaba432bb09aca518fdd0365875895c2f5121eb668b2e7b2d5a99c019b953
Запускное приложение должно быть доступно на http://127.0.0.1:8080
:
Здесь вы можете увидеть мой Привет-док
Применение во всей его славе. Многофункциональные сборки могут быть очень полезны, если вы строите большие приложения с большим количеством зависимостей. Если настроен правильно, изображения, встроенные на нескольких этапах, могут быть очень оптимизированы и компактны.
Как игнорировать ненужные файлы
Если вы работали с Гит
Некоторое время вы можете знать о .gitignore
Файлы в проектах. Они содержат список файлов и каталогов, которые будут исключены из репозитория.
Ну, у докера есть подобная концепция. .dockerignore
Файл содержит список файлов и каталогов, которые будут исключены из сборки изображений. Вы можете найти предварительно созданный .dockerignore
Файл в Привет-док
каталог.
.git *Dockerfile* *docker-compose* node_modules
Это .dockerignore
Файл должен быть в контексте сборки. Упомянутые здесь файлы и каталоги будут игнорироваться Скопировать
Инструкция. Но если вы делаете крепление Bind, .dockerignore
Файл не будет иметь никакого эффекта. Я добавил .dockerignore
Файлы, где это необходимо в репозитории проекта.
Основы манипулирования сетью в докере
Пока в этой книге вы работали только с одним контейнером. Но в реальной жизни большинство проектов, которые вам придется работать, будет иметь более одного контейнера. И, честно говоря, работа с кучей контейнеров может быть немного сложно, если вы не понимаете нюансы контейнерной изоляции.
Таким образом, в этом разделе книги вы познакомитесь с базовыми сетью с Docker, и вы будете работать в руках с небольшим многофункциональным проектом.
Ну, вы уже узнали в предыдущем разделе, что контейнеры являются изолированными средами. Теперь рассмотрим сценарий, где у вас есть Notes-API
Приложение Powered by Express.js и а PostgreSQL Сервер базы данных работает в двух отдельных контейнерах.
Эти две контейнеры полностью изолированы друг от друга и не обрабатывают существование друг друга. Так как вы подключаете два? Не будет ли это проблемой?
Вы можете подумать о двух возможных решениях этой проблемы. Они следующие:
- Доступ к серверу базы данных с помощью открытого порта.
- Доступ к серверу базы данных с использованием его IP-адреса и порта по умолчанию.
Первый предполагает разоблачение порта из Postgres
Контейнер и Notes-API
подключу через это. Предположим, что открытый порт из Postgres
Контейнер 5432. Теперь, если вы попытаетесь подключиться к 127.0.0.1:5432
изнутри Notes-API
Контейнер, вы обнаружите, что Notes-API
Не можете найти сервер базы данных вообще.
Причина в том, что когда вы говорите 127.0.0.1
внутри Notes-API
Контейнер, вы просто ссылаетесь на localhost
этого контейнера и этот контейнер только. Postgres
Сервер просто там не существует. В результате Notes-API
Приложение не удалось подключиться.
Второе решение, которое вы можете подумать, – найти точный IP-адрес Postgres
Контейнер с использованием Контейнер проверяет
Команда и используя это с портом. Предполагая название Postgres
Контейнер Notes-API-DB-сервер
Вы можете легко получить IP-адрес, выполнив следующую команду:
docker container inspect --format='{{range .NetworkSettings.Networks}} {{.IPAddress}} {{end}}' notes-api-db-server # 172.17.0.2
Теперь дал, что порт по умолчанию для Postgres
это 5432
, вы можете легко получить доступ к серверу базы данных, подключив к 172.17.0.2:5432
от Notes-API
контейнер.
Есть проблемы в этом подходе. Использование IP-адресов для обозначения контейнера не рекомендуется. Кроме того, если контейнер разрушается и воссоздан, IP-адрес может измениться. Отслеживание этих изменяющихся IP-адресов может быть довольно беспокойным.
Теперь, когда я уволил возможные неправильные ответы на оригинальный вопрос, правильный ответ, Вы подключаете их, надевая их в пользовательскую мостовую сеть.
Основы Docker Network
Сеть в Docker – еще один логический объект, такой как контейнер и изображение. Как и два других, есть множество команд под Дочсерская сеть
Группа для манипулирования сетью.
Чтобы перечислить сети в вашей системе, выполните следующую команду:
docker network ls # NETWORK ID NAME DRIVER SCOPE # c2e59f2b96bd bridge bridge local # 124dccee067f host host local # 506e3822bf1f none null local
Вы должны увидеть три сети в вашей системе. Теперь посмотрите на Водитель
столбец таблицы здесь. Эти драйверы могут рассматриваться как тип сети.
По умолчанию Docker имеет пять сетевых драйверов. Они следующие:
мост
– драйвер сети по умолчанию в Docker. Это может быть использовано, когда несколько контейнеров работают в стандартном режиме и должны взаимодействовать друг с другом.хозяин
– полностью удаляет сетевую изоляцию. Любой контейнер работает подхозяин
Сеть в основном прикреплена к сети хост-системы.Нет
– Этот драйвер отключает сетевые контейнеры в целом. Я еще не нашел никакого использования для этого.наложение
– Это используется для подключения нескольких Docker Daemons по компьютерам и отсутствует в объеме этой книги.Macvlan
– Позволяет присвоению MAC-адресов в контейнеры, что делает их функцией, такие как физические устройства в сети.
Есть также сторонние плагины, которые позволяют интегрировать Docker со специализированными сетевыми стеками. Из пяти упомянутых выше вы будете работать только с мост
Сетевой драйвер в этой книге.
Как создать пользовательский мост в Docker
Прежде чем начать создавать свой собственный мост, я хотел бы занять некоторое время, чтобы обсудить сеть мостов по умолчанию, которая поставляется с Docker. Давайте начнем с участия всех сетей в вашей системе:
docker network ls # NETWORK ID NAME DRIVER SCOPE # c2e59f2b96bd bridge bridge local # 124dccee067f host host local # 506e3822bf1f none null local
Как видите, Docker поставляется с сетью моста по умолчанию с именем мост
Отказ Любой управляемый контейнер будет автоматически прикреплен к этой сети мостов:
docker container run --rm --detach --name hello-dock --publish 8080:80 fhsinchy/hello-dock # a37f723dad3ae793ce40f97eb6bb236761baa92d72a2c27c24fc7fda0756657d docker network inspect --format='{{range .Containers}}{{.Name}}{{end}}' bridge # hello-dock
Контейнеры, прикрепленные к сети моста по умолчанию, могут взаимодействовать друг с другом, используя IP-адреса, которые я уже обескуражен в предыдущем подразделе.
Однако пользовательский мост, однако, имеет несколько дополнительных функций по сравнению с одним. Согласно официальному Документы На этой теме некоторые заметные дополнительные функции следующие:
- Пользовательские мосты обеспечивают автоматическое разрешение DNS между контейнерами: Это означает, что контейнеры, прикрепленные к той же сети, могут взаимодействовать друг с другом, используя имя контейнера. Так что, если у вас есть два контейнера по имени
Notes-API
иNotes-db
Контейнер API сможет подключиться к контейнеру базы данных, используяNotes-db
название. - Пользовательские мосты обеспечивают лучшую изоляцию: Все контейнеры прикреплены к сети моста по умолчанию по умолчанию, что может вызвать конфликты среди них. Прикрепление контейнеров к пользовательскому мосту может обеспечить лучшую изоляцию.
- Контейнеры могут быть прикреплены и отделены от пользовательских сетей на лету: Во время срока службы контейнера вы можете подключить или отключить его от пользовательских сетей на лету. Чтобы удалить контейнер из сети мостов по умолчанию, вам нужно остановить контейнер и воссоздать его разными параметрами сети.
Теперь, когда вы узнали довольно много о пользовательской сети, пришло время создавать его для себя. Сеть может быть создана с помощью Сеть создавать
команда. Общий синтаксис для команды выглядит следующим образом:
docker network create
Чтобы создать сеть с именем Skynet
Выполнить следующую команду:
docker network create skynet # 7bd5f351aa892ac6ec15fed8619fc3bbb95a7dcdd58980c28304627c8f7eb070 docker network ls # NETWORK ID NAME DRIVER SCOPE # be0cab667c4b bridge bridge local # 124dccee067f host host local # 506e3822bf1f none null local # 7bd5f351aa89 skynet bridge local
Как вы можете видеть, что новая сеть была создана с указанным именем. Ни один контейнер в настоящее время не подключен к этой сети. В следующем подразделе вы узнаете о прикреплении контейнеров к сети.
Как прикрепить контейнер к сети в Docker
Существуют в основном два способа подключения контейнера к сети. Во-первых, вы можете использовать команду Network Connect для подключения контейнера к сети. Общий синтаксис для команды выглядит следующим образом:
docker network connect
Подключить Привет-док
Контейнер к Skynet
Сеть, вы можете выполнить следующую команду:
docker network connect skynet hello-dock docker network inspect --format='{{range .Containers}} {{.Name}} {{end}}' skynet # hello-dock docker network inspect --format='{{range .Containers}} {{.Name}} {{end}}' bridge # hello-dock
Как вы можете видеть с выходов двух Сеть проверяет
Команды, Привет-док
Контейнер теперь прикреплен к обоим Skynet
и по умолчанию мост
сеть.
Второй способ подключения контейнера к сети – использование --network
Вариант для Контейнер работает
или Контейнер создает
команды. Общий синтаксис для опции выглядит следующим образом:
--network
Чтобы запустить другой Привет-док
Контейнер, прикрепленный к той же сети, вы можете выполнить следующую команду:
docker container run --network skynet --rm --name alpine-box -it alpine sh # lands you into alpine linux shell / # ping hello-dock # PING hello-dock (172.18.0.2): 56 data bytes # 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.191 ms # 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.103 ms # 64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.139 ms # 64 bytes from 172.18.0.2: seq=3 ttl=64 time=0.142 ms # 64 bytes from 172.18.0.2: seq=4 ttl=64 time=0.146 ms # 64 bytes from 172.18.0.2: seq=5 ttl=64 time=0.095 ms # 64 bytes from 172.18.0.2: seq=6 ttl=64 time=0.181 ms # 64 bytes from 172.18.0.2: seq=7 ttl=64 time=0.138 ms # 64 bytes from 172.18.0.2: seq=8 ttl=64 time=0.158 ms # 64 bytes from 172.18.0.2: seq=9 ttl=64 time=0.137 ms # 64 bytes from 172.18.0.2: seq=10 ttl=64 time=0.145 ms # 64 bytes from 172.18.0.2: seq=11 ttl=64 time=0.138 ms # 64 bytes from 172.18.0.2: seq=12 ttl=64 time=0.085 ms --- hello-dock ping statistics --- 13 packets transmitted, 13 packets received, 0% packet loss round-trip min/avg/max = 0.085/0.138/0.191 ms
Как видите, работает Ping Hello-Dock
изнутри альпийская коробка
Контейнерные работы, потому что обе контейнеры находятся под тем же пользовательской сетью мостов, и работает автоматическое разрешение DNS.
Имейте в виду, хотя, чтобы, чтобы автоматическое разрешение DNS работать, вы должны назначить пользовательские имена для контейнеров. Использование случайно сгенерированного имени не будет работать.
Как отсоединить контейнеры из сети в докере
В предыдущем подразделе вы узнали о прикреплении контейнеров к сети. В этом подраздел вы узнаете о том, как их отсоединить.
Вы можете использовать Сетевое отключение
Команда для этой задачи. Общий синтаксис для команды выглядит следующим образом:
docker network disconnect
Отсоединить Привет-док
Контейнер из Skynet
Сеть, вы можете выполнить следующую команду:
docker network disconnect skynet hello-dock
Так же, как Network Connect
Команда, Сетевое отключение
Команда не дает никакого вывода.
Как избавиться от сетей в Docker
Как и другие логические объекты в Docker, сети могут быть удалены с помощью Сеть RM
команда. Общий синтаксис для команды выглядит следующим образом:
docker network rm
Удалить Skynet
Сеть из вашей системы, вы можете выполнить следующую команду:
docker network rm skynet
Вы также можете использовать Сетевой Brune
Команда удалить любые неиспользуемые сети из вашей системы. У команды также есть -f
или - Форс
и -А
или - Все
параметры.
Как контейнеризировать многофункциональное приложение JavaScript
Теперь, когда вы узнали достаточно о сетях в Docker, в этом разделе вы научитесь контейнерировать полноценный многоконтонченный проект. Проект вы будете работать, это просто Notes-API
Работает на Express.js и postgresql.
В этом проекте всего есть две контейнеры, которые вам придется подключаться к сети. Помимо этого, вы также узнаете о концепциях, таких как переменные среды и именованные объемы. Так что без дальнейшего ADO давайте прыгнем прямо в.
Как запустить сервер базы данных
Сервер базы данных в этом проекте является простым PostgreSQL Server и использует официальный Postgres изображение.
Согласно официальным документам, чтобы запустить контейнер с этим изображением, вы должны предоставить Postgres_password
Переменная среды. Помимо этого, я также предоставим имя для базы данных по умолчанию, используя Postgrees_db
Переменная среды. PostgreSQL по умолчанию слушает порта 5432
Так что вам нужно публиковать это тоже.
Для запуска сервера базы данных вы можете выполнить следующую команду:
docker container run \ --detach \ --name=notes-db \ --env POSTGRES_DB=notesdb \ --env POSTGRES_PASSWORD=secret \ --network=notes-api-network \ postgres:12 # a7b287d34d96c8e81a63949c57b83d7c1d71b5660c87f5172f074bd1606196dc docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # a7b287d34d96 postgres:12 "docker-entrypoint.s…" About a minute ago Up About a minute 5432/tcp notes-db
--env
Вариант для Контейнер работает
и Контейнер создает
Команды могут быть использованы для предоставления переменных среды к контейнеру. Как видите, контейнер базы данных был успешно создан и работает сейчас.
Хотя контейнер работает, есть небольшая проблема. Базы данных, такие как PostgreSQL, Mongodb, и MySQL, сохраняют свои данные в каталоге. PostgreSQL использует /var/lib/postgresql/data
каталог внутри контейнера для сохранения данных.
Теперь, если контейнер по какой-то причине уничтожен? Вы потеряете все ваши данные. Чтобы решить эту проблему, можно использовать названный объем.
Как работать с названными томами в докере
Раньше вы работали с монтажами связывания и анонимными объемами. Именный объем очень похож на анонимный том, за исключением того, что вы можете обратиться к названному тому, используя его имя.
Тома также являются логическими объектами в Docker и могут быть манипулированы с помощью командной строки. Том создать
Команда может быть использована для создания именованного тома.
Общий синтаксис для команды выглядит следующим образом:
docker volume create
Создать объем имени Notes-db-data
Вы можете выполнить следующую команду:
docker volume create notes-db-data # notes-db-data docker volume ls # DRIVER VOLUME NAME # local notes-db-data
Этот объем теперь может быть установлен на /var/lib/postgresql/data
внутри Notes-db
контейнер. Сделать это, остановитесь и удалите Notes-db
контейнер:
docker container stop notes-db # notes-db docker container rm notes-db # notes-db
Теперь запустите новый контейнер и назначьте громкость, используя --volume
или -V
вариант.
docker container run \ --detach \ --volume notes-db-data:/var/lib/postgresql/data \ --name=notes-db \ --env POSTGRES_DB=notesdb \ --env POSTGRES_PASSWORD=secret \ --network=notes-api-network \ postgres:12 # 37755e86d62794ed3e67c19d0cd1eba431e26ab56099b92a3456908c1d346791
Теперь проверьте Notes-db
Контейнер, чтобы убедиться, что монтаж был успешным:
docker container inspect --format='{{range .Mounts}} {{ .Name }} {{end}}' notes-db # notes-db-data
Теперь данные будут безопасно храниться внутри Notes-db-data
объем и может быть повторно использован в будущем. Монтаж связывания также можно использовать вместо названного тома здесь, но я предпочитаю названный том в таких сценариях.
Как получить доступ к журналам из контейнера в Docker
Для того, чтобы увидеть журналы из контейнера, вы можете использовать Контейнерные журналы
команда. Общий синтаксис для команды выглядит следующим образом:
docker container logs
Чтобы получить доступ к журналам из Notes-db
Контейнер, вы можете выполнить следующую команду:
docker container logs notes-db # The files belonging to this database system will be owned by user "postgres". # This user must also own the server process. # The database cluster will be initialized with locale "en_US.utf8". # The default database encoding has accordingly been set to "UTF8". # The default text search configuration will be set to "english". # # Data page checksums are disabled. # # fixing permissions on existing directory /var/lib/postgresql/data ... ok # creating subdirectories ... ok # selecting dynamic shared memory implementation ... posix # selecting default max_connections ... 100 # selecting default shared_buffers ... 128MB # selecting default time zone ... Etc/UTC # creating configuration files ... ok # running bootstrap script ... ok # performing post-bootstrap initialization ... ok # syncing data to disk ... ok # # # Success. You can now start the database server using: # # pg_ctl -D /var/lib/postgresql/data -l logfile start # # initdb: warning: enabling "trust" authentication for local connections # You can change this by editing pg_hba.conf or using the option -A, or # --auth-local and --auth-host, the next time you run initdb. # waiting for server to start....2021-01-25 13:39:21.613 UTC [47] LOG: starting PostgreSQL 12.5 (Debian 12.5-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit # 2021-01-25 13:39:21.621 UTC [47] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" # 2021-01-25 13:39:21.675 UTC [48] LOG: database system was shut down at 2021-01-25 13:39:21 UTC # 2021-01-25 13:39:21.685 UTC [47] LOG: database system is ready to accept connections # done # server started # CREATE DATABASE # # # /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/* # # 2021-01-25 13:39:22.008 UTC [47] LOG: received fast shutdown request # waiting for server to shut down....2021-01-25 13:39:22.015 UTC [47] LOG: aborting any active transactions # 2021-01-25 13:39:22.017 UTC [47] LOG: background worker "logical replication launcher" (PID 54) exited with exit code 1 # 2021-01-25 13:39:22.017 UTC [49] LOG: shutting down # 2021-01-25 13:39:22.056 UTC [47] LOG: database system is shut down # done # server stopped # # PostgreSQL init process complete; ready for start up. # # 2021-01-25 13:39:22.135 UTC [1] LOG: starting PostgreSQL 12.5 (Debian 12.5-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit # 2021-01-25 13:39:22.136 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 # 2021-01-25 13:39:22.136 UTC [1] LOG: listening on IPv6 address "::", port 5432 # 2021-01-25 13:39:22.147 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" # 2021-01-25 13:39:22.177 UTC [75] LOG: database system was shut down at 2021-01-25 13:39:22 UTC # 2021-01-25 13:39:22.190 UTC [1] LOG: database system is ready to accept connections
Очевидно по тексту в строке 57 база данных поднимается и готова принять соединения снаружи. Есть также --follow
или -f
Опция для команды, которая позволяет подключить консоль к выводу журналов и получить непрерывный поток текста.
Как создать сеть и прикрепление сервера базы данных в Docker
Как вы узнали в предыдущем разделе, контейнеры должны быть прикреплены к пользовательской сети мостовой сети, чтобы взаимодействовать друг с другом, используя имена контейнера. Для этого создайте сеть с именем Notes-API-сеть
В вашей системе:
docker network create notes-api-network
Теперь прикрепите Notes-db
Контейнер к этой сети, выполняя следующую команду:
docker network connect notes-api-network notes-db
Как написать DockerFile
Перейдите в каталог, в котором вы клонируете код проекта. Внутри там, иди внутрь Notes-API/API
каталог и создать новый Dockerfile
Отказ Поместите следующий код в файл:
# stage one FROM node:lts-alpine as builder # install dependencies for node-gyp RUN apk add --no-cache python make g++ WORKDIR /app COPY ./package.json . RUN npm install --only=prod # stage two FROM node:lts-alpine EXPOSE 3000 ENV NODE_ENV=production USER node RUN mkdir -p /home/node/app WORKDIR /home/node/app COPY . . COPY --from=builder /app/node_modules /home/node/app/node_modules CMD [ "node", "bin/www" ]
Это многостоятельная сборка. Первый этап используется для построения и установки зависимостей, использующих Узел-GYP
А второй этап предназначен для запуска приложения. Я перейду на шаги кратко:
- Этап 1 использует
Узел: LTS-Alpine
Как его база и используетстроитель
как сценическое имя. - В строке 5 мы устанавливаем
Python
,сделать
иG ++
ОтказУзел-GYP
Инструмент требует от этих трех пакетов для пробега. - На линии 7, мы устанавливаем
/приложение
каталог какWorkdir
Отказ - На строке 9 и 10 мы копируем
Package.json
Файл кWorkdir
И установите все зависимости. - Этап 2 также использует
Узел-ЛТС: Alpine
как база. - В строке 16 мы устанавливаем
Node_env
Переменная среды дляПроизводство
Отказ Это важно для API для правильной работы. - Из строки 18 до линии 20, мы устанавливаем пользователя по умолчанию на
Узел
Создайте/Home/Node/App
каталог, и установите, что какWorkdir
Отказ - В строке 22 мы копируем все файлы проекта и в строке 23 мы копируем
node_modules
каталог изстроитель
сцена. Этот каталог содержит все встроенные зависимости, необходимые для запуска приложения. - В строке 25 мы устанавливаем команду по умолчанию.
Чтобы построить изображение из этого Dockerfile
Вы можете выполнить следующую команду:
docker image build --tag notes-api . # Sending build context to Docker daemon 37.38kB # Step 1/14 : FROM node:lts-alpine as builder # ---> 471e8b4eb0b2 # Step 2/14 : RUN apk add --no-cache python make g++ # ---> Running in 5f20a0ecc04b # fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz # fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz # (1/21) Installing binutils (2.33.1-r0) # (2/21) Installing gmp (6.1.2-r1) # (3/21) Installing isl (0.18-r0) # (4/21) Installing libgomp (9.3.0-r0) # (5/21) Installing libatomic (9.3.0-r0) # (6/21) Installing mpfr4 (4.0.2-r1) # (7/21) Installing mpc1 (1.1.0-r1) # (8/21) Installing gcc (9.3.0-r0) # (9/21) Installing musl-dev (1.1.24-r3) # (10/21) Installing libc-dev (0.7.2-r0) # (11/21) Installing g++ (9.3.0-r0) # (12/21) Installing make (4.2.1-r2) # (13/21) Installing libbz2 (1.0.8-r1) # (14/21) Installing expat (2.2.9-r1) # (15/21) Installing libffi (3.2.1-r6) # (16/21) Installing gdbm (1.13-r1) # (17/21) Installing ncurses-terminfo-base (6.1_p20200118-r4) # (18/21) Installing ncurses-libs (6.1_p20200118-r4) # (19/21) Installing readline (8.0.1-r0) # (20/21) Installing sqlite-libs (3.30.1-r2) # (21/21) Installing python2 (2.7.18-r0) # Executing busybox-1.31.1-r9.trigger # OK: 212 MiB in 37 packages # Removing intermediate container 5f20a0ecc04b # ---> 637ca797d709 # Step 3/14 : WORKDIR /app # ---> Running in 846361b57599 # Removing intermediate container 846361b57599 # ---> 3d58a482896e # Step 4/14 : COPY ./package.json . # ---> 11b387794039 # Step 5/14 : RUN npm install --only=prod # ---> Running in 2e27e33f935d # added 269 packages from 220 contributors and audited 1137 packages in 140.322s # # 4 packages are looking for funding # run `npm fund` for details # # found 0 vulnerabilities # # Removing intermediate container 2e27e33f935d # ---> eb7cb2cb0b20 # Step 6/14 : FROM node:lts-alpine # ---> 471e8b4eb0b2 # Step 7/14 : EXPOSE 3000 # ---> Running in 4ea24f871747 # Removing intermediate container 4ea24f871747 # ---> 1f0206f2f050 # Step 8/14 : ENV NODE_ENV=production # ---> Running in 5d40d6ac3b7e # Removing intermediate container 5d40d6ac3b7e # ---> 31f62da17929 # Step 9/14 : USER node # ---> Running in 0963e1fb19a0 # Removing intermediate container 0963e1fb19a0 # ---> 0f4045152b1c # Step 10/14 : RUN mkdir -p /home/node/app # ---> Running in 0ac591b3adbd # Removing intermediate container 0ac591b3adbd # ---> 5908373dfc75 # Step 11/14 : WORKDIR /home/node/app # ---> Running in 55253b62ff57 # Removing intermediate container 55253b62ff57 # ---> 2883cdb7c77a # Step 12/14 : COPY . . # ---> 8e60893a7142 # Step 13/14 : COPY --from=builder /app/node_modules /home/node/app/node_modules # ---> 27a85faa4342 # Step 14/14 : CMD [ "node", "bin/www" ] # ---> Running in 349c8ca6dd3e # Removing intermediate container 349c8ca6dd3e # ---> 9ea100571585 # Successfully built 9ea100571585 # Successfully tagged notes-api:latest
Перед запуском контейнера с помощью этого изображения убедитесь, что контейнер базы данных работает и подключен к Notes-API-сеть
Отказ
docker container inspect notes-db # [ # { # ... # "State": { # "Status": "running", # "Running": true, # "Paused": false, # "Restarting": false, # "OOMKilled": false, # "Dead": false, # "Pid": 11521, # "ExitCode": 0, # "Error": "", # "StartedAt": "2021-01-26T06:55:44.928510218Z", # "FinishedAt": "2021-01-25T14:19:31.316854657Z" # }, # ... # "Mounts": [ # { # "Type": "volume", # "Name": "notes-db-data", # "Source": "/var/lib/docker/volumes/notes-db-data/_data", # "Destination": "/var/lib/postgresql/data", # "Driver": "local", # "Mode": "z", # "RW": true, # "Propagation": "" # } # ], # ... # "NetworkSettings": { # ... # "Networks": { # "bridge": { # "IPAMConfig": null, # "Links": null, # "Aliases": null, # "NetworkID": "e4c7ce50a5a2a49672155ff498597db336ecc2e3bbb6ee8baeebcf9fcfa0e1ab", # "EndpointID": "2a2587f8285fa020878dd38bdc630cdfca0d769f76fc143d1b554237ce907371", # "Gateway": "172.17.0.1", # "IPAddress": "172.17.0.2", # "IPPrefixLen": 16, # "IPv6Gateway": "", # "GlobalIPv6Address": "", # "GlobalIPv6PrefixLen": 0, # "MacAddress": "02:42:ac:11:00:02", # "DriverOpts": null # }, # "notes-api-network": { # "IPAMConfig": {}, # "Links": null, # "Aliases": [ # "37755e86d627" # ], # "NetworkID": "06579ad9f93d59fc3866ac628ed258dfac2ed7bc1a9cd6fe6e67220b15d203ea", # "EndpointID": "5b8f8718ec9a5ec53e7a13cce3cb540fdf3556fb34242362a8da4cc08d37223c", # "Gateway": "172.18.0.1", # "IPAddress": "172.18.0.2", # "IPPrefixLen": 16, # "IPv6Gateway": "", # "GlobalIPv6Address": "", # "GlobalIPv6PrefixLen": 0, # "MacAddress": "02:42:ac:12:00:02", # "DriverOpts": {} # } # } # } # } # ]
Я сократил вывод для удобного просмотра здесь. На мою систему Notes-db
Контейнер работает, использует Notes-db-data
Объем и прилагается к Notes-API-сеть
мост.
Как только вы уверены, что все на месте, вы можете запустить новый контейнер, выполнив следующую команду:
docker container run \ --detach \ --name=notes-api \ --env DB_HOST=notes-db \ --env DB_DATABASE=notesdb \ --env DB_PASSWORD=secret \ --publish=3000:3000 \ --network=notes-api-network \ notes-api # f9ece420872de99a060b954e3c236cbb1e23d468feffa7fed1e06985d99fb919
Вы должны быть в состоянии понять эту длинную команду самостоятельно, поэтому я кратко пройду через переменные среды.
Notes-API
Приложение требует трех изменений среды для установки. Они следующие:
Db_host
– Это хост сервера базы данных. Учитывая, что оба сервера базы данных, так и API прикреплены к той же пользовательской сети мостовой сети, сервер базы данных может быть воздействием для использования своего имени контейнера, который являетсяNotes-db
в таком случае.Db_database
– База данных, которую эта API будет использовать. На Запуск сервера базы данных Мы устанавливаем имя базы данных по умолчанию дляNotesDB
используяPostgrees_db
Переменная среды. Мы будем использовать это здесь.Db_password
– Пароль для подключения к базе данных. Это также было установлено на Запуск сервера базы данных подраздел, используяPostgres_password
Переменная среды.
Чтобы проверить, работает ли контейнер правильно или нет, вы можете использовать Контейнер Ls
. команда:
docker container ls # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # f9ece420872d notes-api "docker-entrypoint.s…" 12 minutes ago Up 12 minutes 0.0.0.0:3000->3000/tcp notes-api # 37755e86d627 postgres:12 "docker-entrypoint.s…" 17 hours ago Up 14 minutes 5432/tcp notes-db
Контейнер работает сейчас. Вы можете посетить http://127.0.0.1:3000/
чтобы увидеть API в действии.
API имеет пять маршрутов всего, что вы можете видеть внутри /notes-api/api/api/routes/notes.js
файл.
Хотя контейнер работает, есть последнее, что вам придется сделать, прежде чем вы сможете начать использовать его. Вам придется запустить миграцию базы данных, необходимую для настройки таблиц базы данных, и вы можете сделать это путем выполнения NPM запустить дБ: мигрировать
Команда внутри контейнера.
Как выполнить команды в запущенном контейнере
Вы уже узнали о выполнении команд в остановленном контейнере. Другой сценарий выполняет команду внутри бегового контейнера.
Для этого вам придется использовать exec
Команда для выполнения пользовательской команды внутри бегового контейнера.
Общий синтаксис для exec
Команда выглядит следующим образом:
docker container exec
Выполнить NPM запустить дБ: мигрировать
внутри Notes-API
Контейнер, вы можете выполнить следующую команду:
docker container exec notes-api npm run db:migrate # > notes-api@ db:migrate /home/node/app # > knex migrate:latest # # Using environment: production # Batch 1 run: 1 migrations
В тех случаях, когда вы хотите запустить интерактивную команду внутри бегового контейнера, вам придется использовать -итайте
флаг. В качестве примера, если вы хотите получить доступ к оболочке, запущенной внутри Notes-API
Контейнер, вы можете выполнить после команды:
docker container exec -it notes-api sh # / # uname -a # Linux b5b1367d6b31 5.10.9-201.fc33.x86_64 #1 SMP Wed Jan 20 16:56:23 UTC 2021 x86_64 Linux
Как написать сценарии управления в Docker
Управление мульти-контейнером проектом наряду с сетью и томами и материалами означает, что написание много команд. Чтобы упростить процесс, у меня обычно есть помощь от простого Скрипты оболочки и а Makefile Отказ
Вы найдете четыре сценария оболочки в Notes-API
каталог. Они следующие:
boot.sh
– используется для запуска контейнеров, если они уже существуют.build.sh
– Создает и управляет контейнерами. Это также создает изображения, объемы и сети при необходимости.уничтожить .SH
– Удаляет все контейнеры, объемы и сети, связанные с этим проектом.Стоп.ш
– останавливает все беговые контейнеры.
Есть также Makefile
который содержит четыре цели, названные Начать
, Стоп
, построить
и уничтожить
Каждый из них вызывает ранее упомянутые сценарии оболочки.
Если контейнер находится в запущенном состоянии в вашей системе, выполняя сделать остановку
должен остановить все контейнеры. Выполнение сделать уничтожить
Должен остановить контейнеры и удалить все. Убедитесь, что вы запускаете скрипты внутри Notes-API
Каталог:
make destroy # ./shutdown.sh # stopping api container ---> # notes-api # api container stopped ---> # stopping db container ---> # notes-db # db container stopped ---> # shutdown script finished # ./destroy.sh # removing api container ---> # notes-api # api container removed ---> # removing db container ---> # notes-db # db container removed ---> # removing db data volume ---> # notes-db-data # db data volume removed ---> # removing network ---> # notes-api-network # network removed ---> # destroy script finished
Если вы получаете разрешение, запрещено ошибка, чем выполнять chmod + x
На скриптах:
chmod +x boot.sh build.sh destroy.sh shutdown.sh
Я не собираюсь объяснить эти сценарии, потому что они просто Если-ж
Заявления вместе с некоторыми командами Docker, которые вы уже видели много раз. Если у вас есть некоторое понимание оболочки Linux, вы также сможете понять сценарии.
Как составить проекты, используя docker-compose
В предыдущем разделе вы узнали о управлении многофункциональным проектом и трудностями. Вместо того, чтобы написать так много команд, есть более простым способом управления многофункциональными проектами, инструментом под названием Docker Compose Отказ
По словам докера Документация –
Хотя составляют работу во всех средах, это более сосредоточено на разработке и тестировании. Использование композиции на производственной среде вообще не рекомендуется.
Docker Compose Основы
Перейдите в каталог, в котором вы клонировали репозиторий, пришли с этой книгой. Идите внутрь Notes-API/API
каталог и создать Dockerfile.dev
файл. Поместите следующий код в нем:
# stage one FROM node:lts-alpine as builder # install dependencies for node-gyp RUN apk add --no-cache python make g++ WORKDIR /app COPY ./package.json . RUN npm install # stage two FROM node:lts-alpine ENV NODE_ENV=development USER node RUN mkdir -p /home/node/app WORKDIR /home/node/app COPY . . COPY --from=builder /app/node_modules /home/node/app/node_modules CMD [ "./node_modules/.bin/nodemon", "--config", "nodemon.json", "bin/www" ]
Код практически идентичен Dockerfile
что вы работали в предыдущем разделе. Три различия в этом файле следующие:
- В строке 10 мы бежим
NPM установить
вместоNPM запустить установку
Потому что мы хотим также зависимости разработки. - На строке 15 мы устанавливаем
Node_env
Переменная среды дляРазвитие
вместоПроизводство
Отказ - В строке 24 мы используем инструмент под названием Номемон Чтобы получить функцию горячей перезагрузки для API.
Вы уже знаете, что у этого проекта есть две контейнеры:
Notes-db
– сервер базы данных, работающий по PostgreSQL.Notes-API
– Остальное API Powered by Express.js
В мире составляют каждый контейнер, который составляет приложение, известен как услуга. Первый шаг в составлении многофункционального проекта – определить эти услуги.
Так же, как Docker Daemon использует Dockerfile
Для создания изображений Docker Compose использует Docker-Compose.yaml
Файл для чтения определений службы от.
Голова до Notes-API
каталог и создать новый Docker-Compose.yaml
файл. Поместите следующий код в вновь созданный файл:
version: "3.8" services: db: image: postgres:12 container_name: notes-db-dev volumes: - notes-db-dev-data:/var/lib/postgresql/data environment: POSTGRES_DB: notesdb POSTGRES_PASSWORD: secret api: build: context: ./api dockerfile: Dockerfile.dev image: notes-api:dev container_name: notes-api-dev environment: DB_HOST: db ## same as the database service name DB_DATABASE: notesdb DB_PASSWORD: secret volumes: - /home/node/app/node_modules - ./api:/home/node/app ports: - 3000:3000 volumes: notes-db-dev-data: name: notes-db-dev-data
Каждый действительный Docker-Compose.yaml
Файл запускается, определяя версию файла. На момент написания, 3.8
это последняя версия. Вы можете посмотреть последнюю версию здесь Отказ
Блоки в файле yaml определяются отданием. Я пройду через каждую из блоков и объясню, что они делают.
-
Услуги
Блок содержит определения для каждого из услуг или контейнеров в приложении.дБ
иAPI
являются двумя услугами, которые составляют этот проект. -
дБ
Блок определяет новую услугу в приложении и удерживает необходимую информацию для запуска контейнера. Каждый сервис требует либо предварительно построенного изображения, либоDockerfile
Для запуска контейнера. ДлядБ
Сервис Мы используем официальный образ PostgreSQL. - В отличие от
дБ
Сервис, предварительно построенное изображение дляAPI
Служба не существует. Итак, мы будем использоватьDockerfile.dev
файл. -
Объемы
Блок определяет любое название объема, необходимое любым из услуг. В то время он только приключается толькоNotes-db-dev-data
Объем, используемыйдБ
услуга.
Теперь, когда есть обзор высокого уровня Docker-Compose.yaml
Файл, давайте посмотрим на отдельные услуги.
Код определения для дБ
Сервис выглядит следующим образом:
db: image: postgres:12 container_name: notes-db-dev volumes: - db-data:/var/lib/postgresql/data environment: POSTGRES_DB: notesdb POSTGRES_PASSWORD: secret
-
изображение
Клавиша содержит репозиторий изображения и тег, используемый для этого контейнера. Мы используемPostgres: 12
Изображение для запуска контейнера базы данных. -
Container_Name
Указывает имя контейнера. По умолчанию контейнеры называются следующими<Название каталога проекта> _ <имя обслуживания>
синтаксис. Вы можете переопределить, что используяContainer_Name
Отказ -
Объемы
Массив содержит сопоставления громкости для обслуживания и поддержки с именованными томами, анонимными томами и креплениями связывания. Синтаксис<Источник>: <Пункт назначения>
идентичен тому, что вы видели раньше. -
окружающая среда
Карта содержит значения различных переменных среды, необходимые для обслуживания.
Код определения для API
Сервис выглядит следующим образом:
api: build: context: ./api dockerfile: Dockerfile.dev image: notes-api:dev container_name: notes-api-dev environment: DB_HOST: db ## same as the database service name DB_DATABASE: notesdb DB_PASSWORD: secret volumes: - /home/node/app/node_modules - ./api:/home/node/app ports: - 3000:3000
-
API
Сервис не приходит с предварительно построенным изображением. Вместо этого он имеет конфигурацию сборки. Подпостроить
Блок. Мы определяем контекст и имя DockerFile для создания изображения. Теперь у вас должно быть понимание контекста и докера, поэтому я не буду тратить время, объясняя их. -
изображение
Ключ содержит имя изображения, которое будет построен. Если не назначен, изображение будет названо после<Название каталога проекта> _ <имя обслуживания>
синтаксис. - Внутри
окружающая среда
карта,Db_host
Переменная демонстрирует особенность композиции. То есть вы можете обратиться к другой службе в том же приложении, используя его имя. Итак,дБ
Здесь будет заменен IP-адресAPI
Сервисный контейнер.Db_database
иDb_password
Переменные должны совпадать сPostgrees_db
иPostgres_password
соответственно отдБ
Определение обслуживания. - В
Объемы
Карта, вы можете увидеть анонимный том и описанный привязка. Синтаксис идентичен тому, что вы видели в предыдущих разделах. -
Порты
Карта определяет любое отображение порта. Синтаксис,
идентичен: <Контейнерный порт> --publish
Вариант вы использовали ранее.
Наконец, код для Объемы
составляет:
volumes: db-data: name: notes-db-dev-data
Любой именованный объем, используемый в любом из услуг, должен быть определен здесь. Если вы не определите имя, объем будет назван после <Название каталога проекта> _
И ключ вот DB-Data
Отказ
Вы можете узнать о различных вариантах для конфигурации громкости в официальном Документы Отказ
Как начать сервисы в Docker Compose
Есть несколько способов начальных служб, определенных в YAML-файле. Первая команда, о которой вы узнаете о вверх
команда. вверх
Команда создает любые недостающие изображения, создает контейнеры и начинает их за один ход.
Прежде чем вы выполнять команду, убедитесь, что вы открыли свой терминал в том же каталоге, где Docker-Compose.yaml
Файл есть. Это очень важно для каждого Docker-Compose
Команда вы выполняете.
docker-compose --file docker-compose.yaml up --detach # Creating network "notes-api_default" with the default driver # Creating volume "notes-db-dev-data" with default driver # Building api # Sending build context to Docker daemon 37.38kB # # Step 1/13 : FROM node:lts-alpine as builder # ---> 471e8b4eb0b2 # Step 2/13 : RUN apk add --no-cache python make g++ # ---> Running in 197056ec1964 ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container 197056ec1964 # ---> 6609935fe50b # Step 3/13 : WORKDIR /app # ---> Running in 17010f65c5e7 # Removing intermediate container 17010f65c5e7 # ---> b10d12e676ad # Step 4/13 : COPY ./package.json . # ---> 600d31d9362e # Step 5/13 : RUN npm install # ---> Running in a14afc8c0743 ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container a14afc8c0743 # ---> 952d5d86e361 # Step 6/13 : FROM node:lts-alpine # ---> 471e8b4eb0b2 # Step 7/13 : ENV NODE_ENV=development # ---> Running in 0d5376a9e78a # Removing intermediate container 0d5376a9e78a # ---> 910c081ce5f5 # Step 8/13 : USER node # ---> Running in cfaefceb1eff # Removing intermediate container cfaefceb1eff # ---> 1480176a1058 # Step 9/13 : RUN mkdir -p /home/node/app # ---> Running in 3ae30e6fb8b8 # Removing intermediate container 3ae30e6fb8b8 # ---> c391cee4b92c # Step 10/13 : WORKDIR /home/node/app # ---> Running in 6aa27f6b50c1 # Removing intermediate container 6aa27f6b50c1 # ---> 761a7435dbca # Step 11/13 : COPY . . # ---> b5d5c5bdf3a6 # Step 12/13 : COPY --from=builder /app/node_modules /home/node/app/node_modules # ---> 9e1a19960420 # Step 13/13 : CMD [ "./node_modules/.bin/nodemon", "--config", "nodemon.json", "bin/www" ] # ---> Running in 5bdd62236994 # Removing intermediate container 5bdd62236994 # ---> 548e178f1386 # Successfully built 548e178f1386 # Successfully tagged notes-api:dev # Creating notes-api-dev ... done # Creating notes-db-dev ... done
--detach
или -d
Опция здесь функционирует так же, как тот, который вы видели раньше. --file
или -f
Вариант необходим только если файл yaml не назван Docker-Compose.yaml
(Но я использовал здесь для демонстрационных целей).
Кроме того вверх
Команда есть Начать
команда. Основное отличие этих двух в том, что Начать
Команда не создает отсутствующих контейнеров, только начинает существующие контейнеры. Это в основном так же, как Старт контейнера
команда.
--build
Вариант для вверх
Команда заставляет восстановить изображения. Есть некоторые другие варианты для вверх
Команда, которую вы можете увидеть в официальном Документы Отказ
Как перечислить услуги в Docker Compose
Хотя контейнеры обслуживания, созданные COMPOPE, могут быть перечислены с использованием Контейнер Ls
. Команда, есть PS
Команда для листинга контейнеров, определенных только в YAML.
docker-compose ps # Name Command State Ports # ------------------------------------------------------------------------------- # notes-api-dev docker-entrypoint.sh ./nod ... Up 0.0.0.0:3000->3000/tcp # notes-db-dev docker-entrypoint.sh postgres Up 5432/tcp
Это не как информативно, как Контейнер Ls
. Вывод, но это полезно, когда у вас есть тонны контейнеров, работающих одновременно.
Как выполнить команды внутри беговой службы в Docker Compose
Я надеюсь, что вы помните с предыдущего раздела, который вы должны запустить несколько сценариев миграции для создания таблиц базы данных для этого API.
Так же, как Контейнер Exec
Команда, есть exec
Команда для Docker-Compose
Отказ Общий синтаксис для команды выглядит следующим образом:
docker-compose exec
Для выполнения NPM запустить дБ: мигрировать
Команда внутри API
Сервис, вы можете выполнить следующую команду:
docker-compose exec api npm run db:migrate # > notes-api@ db:migrate /home/node/app # > knex migrate:latest # # Using environment: development # Batch 1 run: 1 migrations
В отличие от Контейнер Exec
Команда, вам не нужно проходить -итайте
Флаг для интерактивных сессий. Docker-Compose
Это автоматически.
Как получить доступ к журналам из беговой службы в Docker Compose
Вы также можете использовать журналы
Команда для извлечения журналов из бегущей службы. Общий синтаксис для команды выглядит следующим образом:
docker-compose logs
Чтобы получить доступ к журналам из API
Сервис, выполните следующую команду:
docker-compose logs api # Attaching to notes-api-dev # notes-api-dev | [nodemon] 2.0.7 # notes-api-dev | [nodemon] reading config ./nodemon.json # notes-api-dev | [nodemon] to restart at any time, enter `rs` # notes-api-dev | [nodemon] or send SIGHUP to 1 to restart # notes-api-dev | [nodemon] ignoring: *.test.js # notes-api-dev | [nodemon] watching path(s): *.* # notes-api-dev | [nodemon] watching extensions: js,mjs,json # notes-api-dev | [nodemon] starting `node bin/www` # notes-api-dev | [nodemon] forking # notes-api-dev | [nodemon] child pid: 19 # notes-api-dev | [nodemon] watching 18 files # notes-api-dev | app running -> http://127.0.0.1:3000
Это просто часть от вывода журнала. Вы можете вроде крюк в выходной поток службы и получить журналы в режиме реального времени, используя -f
или --follow
вариант. Любой более поздний журнал появится мгновенно в терминале, если вы не выходите, нажав Ctrl + C
или закрывая окно. Контейнер будет продолжать работать, даже если вы выходите из окна журнала.
Как остановить услуги в Docker Compose
Чтобы остановить услуги, есть два подхода, которые вы можете взять. Первый – это вниз
команда. вниз
Команда останавливает все контейнеры и удаляет их из системы. Это также удаляет любые сети:
docker-compose down --volumes # Stopping notes-api-dev ... done # Stopping notes-db-dev ... done # Removing notes-api-dev ... done # Removing notes-db-dev ... done # Removing network notes-api_default # Removing volume notes-db-dev-data
--Волумы
Опция указывает, что вы хотите удалить любые именованные объема (ы), определенные в Объемы
блокировать. Вы можете узнать о дополнительных вариантах для вниз
команда в официальном Документы Отказ
Другая команда для остановки услуг – Стоп
команда, которая функционирует идентично для Контейнер Стоп
команда. Он останавливает все контейнеры для приложения и сохраняет их. Эти контейнеры могут быть начаты с Начать
или вверх
команда.
Как составить приложение полнотека в Docker Compose
В этом подсечении мы будем добавлять интерфейс для наших API наших заметок и превратив его в полное приложение для полного стека. Я не буду объяснять ни одного из Dockerfile.dev
Файлы в этом подразделе (кроме одного для услуги nginx
Service), поскольку они идентичны некоторым другим остальным, которые вы уже видели в предыдущих подразделах.
Если вы клонировали репозиторий кода проекта, затем идите внутрь FullStack-Notes-приложение
каталог. Каждый каталог внутри корня проекта содержит код для каждого сервиса и соответствующую Dockerfile
Отказ
Прежде чем начать с Docker-Compose.yaml
Файл Давайте посмотрим на диаграмму, как приложение будет работать:
Вместо того, чтобы принимать запросы непосредственно, как и ранее, в данном приложении все запросы будут впервые получены NGINX (давайте назовем его маршрутизатора).
Маршрутизатор будет посмотреть, имеет ли запрошенную конечную точку /API
в этом. Если да, маршрутизатор будет направлять запрос на заднев или, если нет, маршрутизатор будет направлять запрос на передний план.
Вы делаете это потому, что когда вы запускаете предельное приложение, он не работает внутри контейнера. Он работает на браузере, подается из контейнера. В результате составные сети не работают, как ожидалось, и предельное приложение не может найти API
услуга.
Nginx, с другой стороны, работает внутри контейнера и может взаимодействовать с различными услугами по всему приложению.
Я не буду войти в конфигурацию Nginx здесь. Эта тема рода из-за объема этой книги. Но если вы хотите посмотреть на него, продолжайте и проверьте /notes-api/nginx/development.conf
и /notes-api/nginx/broduction.conf
файлы. Код для /notes-api/nginx/Dockerfile.dev
составляет:
FROM nginx:stable-alpine COPY ./development.conf /etc/nginx/conf.d/default.conf
Все это делает, это скопируйте файл конфигурации на /etc/nginx/Conf.d/default.conf
внутри контейнера.
Давайте начнем написать Docker-Compose.yaml
файл. Помимо API
и дБ
Услуги будут клиент
и nginx
Сервисы. Также будут определены определения сети, которые я буду вскоре.
version: "3.8" services: db: image: postgres:12 container_name: notes-db-dev volumes: - db-data:/var/lib/postgresql/data environment: POSTGRES_DB: notesdb POSTGRES_PASSWORD: secret networks: - backend api: build: context: ./api dockerfile: Dockerfile.dev image: notes-api:dev container_name: notes-api-dev volumes: - /home/node/app/node_modules - ./api:/home/node/app environment: DB_HOST: db ## same as the database service name DB_PORT: 5432 DB_USER: postgres DB_DATABASE: notesdb DB_PASSWORD: secret networks: - backend client: build: context: ./client dockerfile: Dockerfile.dev image: notes-client:dev container_name: notes-client-dev volumes: - /home/node/app/node_modules - ./client:/home/node/app networks: - frontend nginx: build: context: ./nginx dockerfile: Dockerfile.dev image: notes-router:dev container_name: notes-router-dev restart: unless-stopped ports: - 8080:80 networks: - backend - frontend volumes: db-data: name: notes-db-dev-data networks: frontend: name: fullstack-notes-application-network-frontend driver: bridge backend: name: fullstack-notes-application-network-backend driver: bridge
Файл практически идентичен предыдущему, с которым вы работали. Единственное, что нужно, – это конфигурация сети. Код для сети
Блок выглядит следующим образом:
networks: frontend: name: fullstack-notes-application-network-frontend driver: bridge backend: name: fullstack-notes-application-network-backend driver: bridge
Я определил два мостовых сети. По умолчанию Compose создает мостовую сеть и прикрепляет все контейнеры к этому. В этом проекте, однако, я хотел правильную сетевую изоляцию. Итак, я определил две сети, один для интерфейсных служб и один для внутренних сервисов.
Я также добавил сети
Блок в каждом из определений обслуживания. Таким образом, то API
и дБ
Сервис будет прикреплен к одной сети и клиент
Сервис будет прикреплен к отдельной сети. Но nginx
Сервис будет прикреплен как к сетям, чтобы он мог выполнять как маршрутизатор между передними и задними сервисами.
Начните все услуги, выполнив следующую команду:
docker-compose --file docker-compose.yaml up --detach # Creating network "fullstack-notes-application-network-backend" with driver "bridge" # Creating network "fullstack-notes-application-network-frontend" with driver "bridge" # Creating volume "notes-db-dev-data" with default driver # Building api # Sending build context to Docker daemon 37.38kB # # Step 1/13 : FROM node:lts-alpine as builder # ---> 471e8b4eb0b2 # Step 2/13 : RUN apk add --no-cache python make g++ # ---> Running in 8a4485388fd3 ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container 8a4485388fd3 # ---> 47fb1ab07cc0 # Step 3/13 : WORKDIR /app # ---> Running in bc76cc41f1da # Removing intermediate container bc76cc41f1da # ---> 8c03fdb920f9 # Step 4/13 : COPY ./package.json . # ---> a1d5715db999 # Step 5/13 : RUN npm install # ---> Running in fabd33cc0986 ### LONG INSTALLATION STUFF GOES HERE ### # Removing intermediate container fabd33cc0986 # ---> e09913debbd1 # Step 6/13 : FROM node:lts-alpine # ---> 471e8b4eb0b2 # Step 7/13 : ENV NODE_ENV=development # ---> Using cache # ---> b7c12361b3e5 # Step 8/13 : USER node # ---> Using cache # ---> f5ac66ca07a4 # Step 9/13 : RUN mkdir -p /home/node/app # ---> Using cache # ---> 60094b9a6183 # Step 10/13 : WORKDIR /home/node/app # ---> Using cache # ---> 316a252e6e3e # Step 11/13 : COPY . . # ---> Using cache # ---> 3a083622b753 # Step 12/13 : COPY --from=builder /app/node_modules /home/node/app/node_modules # ---> Using cache # ---> 707979b3371c # Step 13/13 : CMD [ "./node_modules/.bin/nodemon", "--config", "nodemon.json", "bin/www" ] # ---> Using cache # ---> f2da08a5f59b # Successfully built f2da08a5f59b # Successfully tagged notes-api:dev # Building client # Sending build context to Docker daemon 43.01kB # # Step 1/7 : FROM node:lts-alpine # ---> 471e8b4eb0b2 # Step 2/7 : USER node # ---> Using cache # ---> 4be5fb31f862 # Step 3/7 : RUN mkdir -p /home/node/app # ---> Using cache # ---> 1fefc7412723 # Step 4/7 : WORKDIR /home/node/app # ---> Using cache # ---> d1470d878aa7 # Step 5/7 : COPY ./package.json . # ---> Using cache # ---> bbcc49475077 # Step 6/7 : RUN npm install # ---> Using cache # ---> 860a4a2af447 # Step 7/7 : CMD [ "npm", "run", "serve" ] # ---> Using cache # ---> 11db51d5bee7 # Successfully built 11db51d5bee7 # Successfully tagged notes-client:dev # Building nginx # Sending build context to Docker daemon 5.12kB # # Step 1/2 : FROM nginx:stable-alpine # ---> f2343e2e2507 # Step 2/2 : COPY ./development.conf /etc/nginx/conf.d/default.conf # ---> Using cache # ---> 02a55d005a98 # Successfully built 02a55d005a98 # Successfully tagged notes-router:dev # Creating notes-client-dev ... done # Creating notes-api-dev ... done # Creating notes-router-dev ... done # Creating notes-db-dev ... done
Теперь посетите http://localhost: 8080
И VUILà!
Попробуйте добавить и удалять заметки, чтобы посмотреть, работает ли приложение правильно. Проект также поставляется с Shell Scripts и A Makefile
Отказ Исследуйте их, чтобы увидеть, как вы можете запустить этот проект без помощи Docker-Compose
Как вы сделали в предыдущем разделе.
Заключение
Я хотел бы поблагодарить вас от всего сердца на то время, когда вы потратили эту книгу. Я надеюсь, что вам понравилось и узнал все основные основы докера.
Помимо этого, я написал по всей длине справочники на других сложных темах, доступных бесплатно на FreeCodeCamp.
Эти руководства являются частью моей миссии, чтобы упростить упрощению технологий для всех. Каждое из этих руководств занимает много времени и усилий, чтобы написать.
Если вы наслаждались моим письмом и хотите, чтобы меня мотивированы, подумайте о том, чтобы уйти начать на Github и одобрить меня за соответствующие навыки на LinkedIn Отказ Я также принимаю спонсорство, чтобы вы могли рассмотреть Покупая мне кофе если вы хотите.
Я всегда открыт для предложений и дискуссий на Количество платформ Отказ Следуй за мной на Twitter или LinkedIn И ударил меня прямыми сообщениями.
В конце концов, подумайте об использовании ресурсов с другими, потому что
До следующего, оставайся в безопасности и продолжай учиться.