Руководство по docker compose для начинающих

Время на прочтение
9 мин

Количество просмотров 559K

Автор статьи, перевод которой мы сегодня публикуем, говорит, что она предназначена для тех разработчиков, которые хотят изучить Docker Compose и идут к тому, чтобы создать своё первое клиент-серверное приложение с использованием Docker. Предполагается, что читатель этого материала знаком с основами Docker. Если это не так — можете взглянуть на эту серию материалов, на эту публикацию, где основы Docker рассмотрены вместе с основами Kubernetes, и на эту статью для начинающих.

image

Что такое Docker Compose?

Docker Compose — это инструментальное средство, входящее в состав Docker. Оно предназначено для решения задач, связанных с развёртыванием проектов.

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

Как узнать, нужно ли вам, при развёртывании некоего проекта, воспользоваться Docker Compose? На самом деле — очень просто. Если для обеспечения функционирования этого проекта используется несколько сервисов, то Docker Compose может вам пригодиться. Например, в ситуации, когда создают веб-сайт, которому, для выполнения аутентификации пользователей, нужно подключиться к базе данных. Подобный проект может состоять из двух сервисов — того, что обеспечивает работу сайта, и того, который отвечает за поддержку базы данных.

Технология Docker Compose, если описывать её упрощённо, позволяет, с помощью одной команды, запускать множество сервисов.

Разница между Docker и Docker Compose

Docker применяется для управления отдельными контейнерами (сервисами), из которых состоит приложение.

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

Docker (отдельный контейнер) и Docker Compose (несколько контейнеров)

Типичный сценарий использования Docker Compose

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

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

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

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

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

Разработка клиент-серверного приложения с использованием Docker Compose

Теперь, когда вы знаете о том, для чего мы собираемся использовать Docker Compose, пришло время создать ваше первое клиент-серверное приложение с использованием этого инструмента. А именно, речь идёт о разработке небольшого веб-сайта (сервера) на Python, который умеет выдавать файл с фрагментом текста. Этот файл у сервера запрашивает программа (клиент), тоже написанная на Python. После получения файла с сервера программа выводит текст, хранящийся в нём, на экран.

Обратите внимание на то, что мы рассчитываем на то, что вы владеете основами Docker, и на то, что у вас уже установлена платформа Docker.

Приступим к работе над проектом.

▍1. Создание проекта

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

  • Файл docker-compose.yml. Это файл Docker Compose, который будет содержать инструкции, необходимые для запуска и настройки сервисов.
  • Папка server. Она будет содержать файлы, необходимые для обеспечения работы сервера.
  • Папка client. Здесь будут находиться файлы клиентского приложения.

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

.
├── client/
├── docker-compose.yml
└── server/
2 directories, 1 file

▍2. Создание сервера

Тут мы, в процессе создания сервера, затронем некоторые базовые вещи, касающиеся Docker.

2a. Создание файлов

Перейдите в папку server и создайте в ней следующие файлы:

  • Файл server.py. В нём будет находиться код сервера.
  • Файл index.html. В этом файле будет находиться фрагмент текста, который должно вывести клиентское приложение.
  • Файл Dockerfile. Это — файл Docker, который будет содержать инструкции, необходимые для создания окружения сервера.

Вот как должно выглядеть содержимое вашей папки server/:

.
├── Dockerfile
├── index.html
└── server.py
0 directories, 3 files

2b. Редактирование Python-файла.

Добавим в файл server.py следующий код:

#!/usr/bin/env python3

# Импорт системных библиотек python.
# Эти библиотеки будут использоваться для создания веб-сервера.
# Вам не нужно устанавливать что-то особенное, эти библиотеки устанавливаются вместе с Python.

import http.server
import socketserver

# Эта переменная нужна для обработки запросов клиента к серверу.

handler = http.server.SimpleHTTPRequestHandler

# Тут мы указываем, что сервер мы хотим запустить на порте 1234. 
# Постарайтесь запомнить эти сведения, так как они нам очень пригодятся в дальнейшем, при работе с docker-compose.

with socketserver.TCPServer(("", 1234), handler) as httpd:

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

   httpd.serve_forever()

Этот код позволяет создать простой веб-сервер. Он будет отдавать клиентам файл index.html, содержимое которого позже будет выводиться на веб-странице.

2c. Редактирование HTML-файла

В файл index.html добавим следующий текст:

Docker-Compose is magic!

Этот текст будет передаваться клиенту.

2d. Редактирование файла Dockerfile

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

# На всякий случай напоминаю, что Dockerfile всегда должен начинаться с импорта базового образа.
# Для этого используется ключевое слово 'FROM'.
# Здесь нам нужно импортировать образ python (с DockerHub).
# В результате мы, в качестве имени образа, указываем 'python', а в качестве версии - 'latest'.

FROM python:latest

# Для того чтобы запустить в контейнере код, написанный на Python, нам нужно импортировать файлы 'server.py' и 'index.html'.
# Для того чтобы это сделать, мы используем ключевое слово 'ADD'.
# Первый параметр, 'server.py', представляет собой имя файла, хранящегося на компьютере.
# Второй параметр, '/server/', это путь, по которому нужно разместить указанный файл в образе.
# Здесь мы помещаем файл в папку образа '/server/'.

ADD server.py /server/
ADD index.html /server/

# Здесь мы воспользуемся командой 'WORKDIR', возможно, новой для вас.
# Она позволяет изменить рабочую директорию образа.
# В качестве такой директории, в которой будут выполняться все команды, мы устанавливаем '/server/'.

WORKDIR /server/

Теперь займёмся работой над клиентом.

▍3. Создание клиента

Создавая клиентскую часть нашего проекта, мы попутно вспомним некоторые основы Docker.

3a. Создание файлов

Перейдите в папку вашего проекта client и создайте в ней следующие файлы:

  • Файл client.py. Тут будет находиться код клиента.
  • Файл Dockerfile. Этот файл играет ту же роль, что и аналогичный файл в папке сервера. А именно, он содержит инструкцию, описывающую создание среды для выполнения клиентского кода.

В результате ваша папка client/ на данном этапе работы должна выглядеть так:

.
├── client.py
└── Dockerfile
0 directories, 2 files

3b. Редактирование Python-файла

Добавим в файл client.py следующий код:

#!/usr/bin/env python3

# Импортируем системную библиотеку Python.
# Она используется для загрузки файла 'index.html' с сервера.
# Ничего особенного устанавливать не нужно, эта библиотека устанавливается вместе с Python.

import urllib.request

# Эта переменная содержит запрос к 'http://localhost:1234/'.
# Возможно, сейчас вы задаётесь вопросом о том, что такое 'http://localhost:1234'.
# localhost указывает на то, что программа работает с локальным сервером.
# 1234 - это номер порта, который вам предлагалось запомнить при настройке серверного кода.

fp = urllib.request.urlopen("http://localhost:1234/")

# 'encodedContent' соответствует закодированному ответу сервера ('index.html').
# 'decodedContent' соответствует раскодированному ответу сервера (тут будет то, что мы хотим вывести на экран).

encodedContent = fp.read()
decodedContent = encodedContent.decode("utf8")

# Выводим содержимое файла, полученного с сервера ('index.html').

print(decodedContent)

# Закрываем соединение с сервером.

fp.close()

Благодаря этому коду клиентское приложение может загрузить данные с сервера и вывести их на экран.

3c. Редактирование файла Dockerfile

Как и в случае с сервером, мы создаём для клиента простой Dockerfile, ответственный за формирование среды, в которой будет работать клиентское Python-приложение. Вот код клиентского Dockerfile:

# То же самое, что и в серверном Dockerfile.

FROM python:latest

# Импортируем 'client.py' в папку '/client/'.

ADD client.py /client/

# Устанавливаем в качестве рабочей директории '/client/'.

WORKDIR /client/

▍4. Docker Compose

Как вы могли заметить, мы создали два разных проекта: сервер и клиент. У каждого из них имеется собственный файл Dockerfile. До сих пор всё происходящее не выходит за рамки основ работы с Docker. Теперь же мы приступаем к работе с Docker Compose. Для этого обратимся к файлу docker-compose.yml, расположенному в корневой папке проекта.

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

Вот код, который нужно поместить в файл docker-compose.yml:

# Файл docker-compose должен начинаться с тега версии.
# Мы используем "3" так как это - самая свежая версия на момент написания этого кода.

version: "3"

# Следует учитывать, что docker-composes работает с сервисами.
# 1 сервис = 1 контейнер.
# Сервисом может быть клиент, сервер, сервер баз данных...
# Раздел, в котором будут описаны сервисы, начинается с 'services'.

services:

  # Как уже было сказано, мы собираемся создать клиентское и серверное приложения.
  # Это означает, что нам нужно два сервиса.
  # Первый сервис (контейнер): сервер.
  # Назвать его можно так, как нужно разработчику.
  # Понятное название сервиса помогает определить его роль.
  # Здесь мы, для именования соответствующего сервиса, используем ключевое слово 'server'.

  server:
 
    # Ключевое слово "build" позволяет задать
    # путь к файлу Dockerfile, который нужно использовать для создания образа,
    # который позволит запустить сервис.
    # Здесь 'server/' соответствует пути к папке сервера,
    # которая содержит соответствующий Dockerfile.

    build: server/

    # Команда, которую нужно запустить после создания образа.
    # Следующая команда означает запуск "python ./server.py".

    command: python ./server.py

    # Вспомните о том, что в качестве порта в 'server/server.py' указан порт 1234.
    # Если мы хотим обратиться к серверу с нашего компьютера (находясь за пределами контейнера),
    # мы должны организовать перенаправление этого порта на порт компьютера.
    # Сделать это нам поможет ключевое слово 'ports'.
    # При его использовании применяется следующая конструкция: [порт компьютера]:[порт контейнера]
    # В нашем случае нужно использовать порт компьютера 1234 и организовать его связь с портом
    # 1234 контейнера (так как именно на этот порт сервер 
    # ожидает поступления запросов).

    ports:
      - 1234:1234

  # Второй сервис (контейнер): клиент.
  # Этот сервис назван 'client'.

  client:
    # Здесь 'client/ соответствует пути к папке, которая содержит
    # файл Dockerfile для клиентской части системы.

    build: client/

    # Команда, которую нужно запустить после создания образа.
    # Следующая команда означает запуск "python ./client.py".
 
    command: python ./client.py

    # Ключевое слово 'network_mode' используется для описания типа сети.
    # Тут мы указываем то, что контейнер может обращаться к 'localhost' компьютера.

    network_mode: host

    # Ключевое слово 'depends_on' позволяет указывать, должен ли сервис,
    # прежде чем запуститься, ждать, когда будут готовы к работе другие сервисы.
    # Нам нужно, чтобы сервис 'client' дождался бы готовности к работе сервиса 'server'.
 
    depends_on:
      - server

▍5. Сборка проекта

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

$ docker-compose build

▍6. Запуск проекта

Теперь, когда проект собран, пришло время его запустить. Этот шаг нашей работы соответствует шагу, на котором, при работе с отдельными контейнерами, выполняется команда docker run:

$ docker-compose up

После выполнения этой команды в терминале должен появиться текст, загруженный клиентом с сервера: Docker-Compose is magic!.

Как уже было сказано, сервер использует порт компьютера 1234 для обслуживания запросов клиента. Поэтому, если перейти в браузере по адресу http://localhost:1234/, в нём будет отображена страница с текстом Docker-Compose is magic!.

Полезные команды

Рассмотрим некоторые команды, которые могут вам пригодиться при работе с Docker Compose.

Эта команда позволяет останавливать и удалять контейнеры и другие ресурсы, созданные командой docker-compose up:

$ docker-compose down

Эта команда выводит журналы сервисов:

$ docker-compose logs -f [service name]

Например, в нашем проекте её можно использовать в таком виде: $ docker-compose logs -f [service name].

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

$ docker-compose ps

Данная команда позволяет выполнить команду в выполняющемся контейнере:

$ docker-compose exec [service name] [command]

Например, она может выглядеть так: docker-compose exec server ls.

Такая команда позволяет вывести список образов:

$ docker-compose images

Итоги

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

Уважаемые читатели! Пользуетесь ли вы Docker Compose в своих проектах?

Руководство по Docker Compose для начинающих

Содержание:

  • Возможности Docker Compose
  • Практика применения
  • Создание клиент-серверного приложения
  • Работа с Docker Compose
  • Дополнительная информация

Инструмент Docker Compose входит в комплект официального программного обеспечения для Docker. Он позволяет решать различные задачи, связанные с управлением одновременно несколькими контейнерами, составляющих в целом один проект.

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

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

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

Практика применения

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

Допустим, по мере развития проекта становится понятно, что мощностей текущего сервера уже недостаточно. Принимается решение перенести сайты на новый сервер. Без Docker Compose придется переносить и настраивать все сервисы заново. Тогда сама работа займет много времени. Кто же возникает вероятность что-нибудь забыть в процессе.

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

Создание клиент-серверного приложения

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

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

Примечание. Этот проект создавался и тестировался на дистрибутивах Ubuntu и CentOS 7. Для выполнения всех приведенных ниже команд используется стандартный терминал Linux.

Разработка проекта

Создание основного каталога

Сборка тестируемого клиент-серверного приложения начинается с создания каталога проекта (в примере — «project»).

Компоненты каталога
  • Файл docker-compose.yml. В нем сохраняются инструкции, которые используются для запуска и дальнейшей настройки сервисов.
  • Каталог server. Здесь будут храниться файлы, отвечающие за функционирование сервера.
  • Каталог client. В нем расположены файлы для клиент-приложения.

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

содержимое основного каталога

Работа с папкой server

Подготовка файлов сервера

Следует открыть каталог «server», чтобы создать в нем следующие файлы:

  • Файл server.py. Предназначен для хранения программного кода сервера.
  • Файл index.html. Здесь сохранен текст, который должно выводить при запросе клиент-приложение.
  • Файл Dockerfile. Непосредственно файл контейнера, который содержит директивы для создания серверного окружения.

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

содержимое каталога «server

Работа с файлом server.py

Теперь нужно открыть файл «server.py» предпочитаемым текстовым редактором, чтобы добавить в него следующий код:

#!/usr/bin/env python3
# Импорт системных библиотек Python.
# Эти библиотеки будут использоваться для создания веб-сервера.
# Не нужно устанавливать что-то особенное, эти библиотеки устанавливаются вместе с Python.
import http.server
import socketserver

# Эта переменная нужна для обработки запросов клиента к серверу.
handler = http.server.SimpleHTTPRequestHandler
# Здесь указываемся, что сервер будет запущен на порте 1234.
# Нужно запомнить эти сведения, так как они очень пригодятся в дальнейшем, при работе с docker-compose.
with socketserver.TCPServer(("", 1234), handler) as httpd:
# Благодаря этой команде сервер будет выполняться постоянно, ожидая запросов от клиента.
  httpd.serve_forever()

Важно! При добавлении информации нужно обязательно сохранять форматирование, как дано в примере.

Работа с файлом index.html

Далее потребуется отредактировать index.html, добавив в него такое содержимое:

Docker-Compose is magic!

Работа с Dockerfile

Теперь следует произвести настройку файла Dockerfile. С помощью него будет организована среда выполнения для Python-сервера. В примере основой создаваемого контейнера будет официальный образ для запуска Python-приложений.

Ниже приведено содержимое файла:

# На всякий случай – Dockerfile всегда должен начинаться с импорта базового образа.
# Для этого используется ключевое слово 'FROM'.
# Здесь следует импортировать образ python (с DockerHub).
# В результате, в качестве имени образа, нужно указать 'python', а в качестве версии - 'latest'.

FROM python:latest

# Для того чтобы запустить в контейнере код, написанный на Python, нужно импортировать файлы 'server.py' и 'index.html'. Для этого используется ключевое слово 'ADD'.
# Первый параметр, 'server.py', представляет собой имя файла, хранящегося на компьютере.
# Второй параметр — '/server/' — это путь, по которому нужно разместить указанный файл в образе.
# помещаем файл в папку образа '/server/'.

ADD server.py /server/
ADD index.html /server/

# Воспользуемся командой 'WORKDIR'.
# Она позволяет изменить рабочую директорию образа.
# В качестве директории, в которой будут выполняться все команды, нужно установить '/server/'.

WORKDIR /server/

Важно! При добавлении информации нужно обязательно сохранять форматирование, как дано в примере.

Создание клиент-приложения

Можно приступать к разработке клиента. При создании клиент-приложения проекта будут одновременно использоваться основные возможности Docker.

Файлы клиента

Сначала следует открыть каталог «client» и создать в нем файлы:

  • Файл client.py. Предназначен для хранения выполняемого кода клиента.
  • Файл Dockerfile. Используется так же, как и одноименный файл в папке server. В нем сохранена инструкция по созданию среды запуска кода на стороне клиента.

После этих операций в каталоге client должны храниться следующие файлы:

содержимое каталога client

Работа с файлом Python

Снова следует открыть текстовый редактор, чтобы добавить в client.py такой код:

#!/usr/bin/env python3
# Импортируется системная библиотека Python.
# Она используется для загрузки файла 'index.html' с сервера.
# Специально ничего устанавливать не нужно, эта библиотека устанавливается вместе с Python.

import urllib.request

# Эта переменная содержит запрос к 'http://localhost:1234/'.
# localhost указывает на то, что программа работает с локальным сервером.
# 1234 - номер порта, который предлагается запомнить при настройке серверного кода.

fp = urllib.request.urlopen("http://localhost:1234/")

# 'encodedContent' соответствует закодированному ответу сервера ('index.html').
# 'decodedContent' соответствует раскодированному ответу сервера (тут будет то, что нужно вывести на экран).

encodedContent = fp.read()
decodedContent = encodedContent.decode("utf8")

# Выводим содержимое файла, полученного с сервера ('index.html').

print(decodedContent)

# Закрываем соединение с сервером.

fp.close()

Важно! При добавлении информации нужно обязательно сохранять форматирование, как дано в примере.

Работа с файлом Dockerfile

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

Ниже представлен его код:

# То же самое, что и в серверном Dockerfile.

FROM python:latest

# Импортируем 'client.py' в папку '/client/'.

ADD client.py /client/

# Устанавливаем в качестве рабочей директории '/client/'.

WORKDIR /client/

Важно! При добавлении информации нужно обязательно сохранять форматирование, как дано в примере.

Работа с Docker Compose

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

В этом примере не стоит задача ознакомиться со всеми возможными командами, доступными для использования в docker-compose.yml. Основная цель – увидеть, как Docker Compose можно применить на практике.

Пример файла docker-compose.yml

Важно! При добавлении информации в файл docker-compose.yml нужно обязательно сохранять форматирование, данное в примере. Это прежде всего касается отступов перед блоками. Если это расстояние нарушить, будет выведена ошибка.

# Файл docker-compose должен начинаться с тега версии.
# Мы используем "3" так как это - самая свежая версия на момент написания этого кода.

version: "3"

# Следует учитывать, что docker-composes работает с сервисами. 1 сервис = 1 контейнер.
# Сервисом может быть клиент, сервер, сервер баз данных...
# Раздел, в котором будут описаны сервисы, начинается с 'services'.

services:

  # Будут созданы клиентское и серверное приложения.
  # Это означает, что нам нужно два сервиса.
  # Первый сервис (контейнер): сервер. Назвать его можно так, как нужно разработчику.
  # Понятное название сервиса помогает определить его роль.
  # Здесь мы, для именования соответствующего сервиса, используем ключевое слово 'server'.

  server:
 
    # Ключевое слово "build" позволяет задать
    # путь к файлу Dockerfile, который нужно использовать для создания образа,
    # который позволит запустить сервис.
    # Здесь 'server/' соответствует пути к папке сервера,
    # которая содержит соответствующий Dockerfile.

    build: server/

    # Команда, которую нужно запустить после создания образа.
    # Следующая команда означает запуск "python ./server.py".

    command: python ./server.py

    # Вспомните о том, что в качестве порта в 'server/server.py' указан порт 1234.
    # Если нужно обратиться к серверу со своего компьютера (находясь за пределами контейнера),
    # следует организовать перенаправление этого порта на порт компьютера.
    # Сделать это поможет ключевое слово 'ports'.
    # При его использовании применяется следующая конструкция: [порт компьютера]:[порт контейнера]
    # В данном случае нужно использовать порт компьютера 1234 и организовать его связь с портом
    # 1234 контейнера (так как именно на этот порт сервер ожидает поступления запросов).

    ports:
      - 1234:1234

  # Второй сервис (контейнер): клиент.
  # Этот сервис назван 'client'.

  client:
    # Здесь 'client/ соответствует пути к папке, которая содержит
    # файл Dockerfile для клиентской части системы.

    build: client/

    # Команда, которую нужно запустить после создания образа.
    # Следующая команда означает запуск "python ./client.py".
 
    command: python ./client.py

    # Ключевое слово 'network_mode' используется для описания типа сети.
    # Тут указывается, что контейнер может обращаться к 'localhost' компьютера.

    network_mode: host

    # Ключевое слово 'depends_on' позволяет указывать, должен ли сервис,
    # прежде чем запуститься, ждать, когда будут готовы к работе другие сервисы.
    # Нужно, чтобы сервис 'client' дождался бы готовности к работе сервиса 'server'.
 
    depends_on:
      - server

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

Когда docker-compose.yml получит требуемые для работы команды, останется выполнить сборку проекта. Она делается почти аналогично docker build.

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

$ docker-compose build

Если все сделано правильно, в терминале будет отображен следующий результат:

команда docker-compose build

Тестирование проекта

Сборка проекта завершена и можно переходить к тестированию проекта. Для этого следует выполнить команду:

$ docker-compose up

Она по сути соответствует команде docker run, используемой в Docker при работе с одним контейнером.

команда docker-compose up

В окне терминала можно увидеть строку «Docker-Compose is magic!». Так клиентская программа сигнализирует, что выполнила запрос на вывод содержимого файла «index.html» серверной программе, после чего вторая передала информацию клиенту. Это значит, что проект успешно запущен и работает.

Аналогичный результат можно получить в окне браузера, после ввода соответствующего веб-адреса (не забыв указать порт 1234):

Docker-Compose is magic!

Дополнительная информация

Ниже приведены несколько часто используемых полезных команд Docker Compose.

  • Команда предназначена для остановки и удаления контейнеров, которые были созданы с помощью «docker-compose up»:
$ docker-compose down
  • Ознакомиться с журналами сервисов можно выполнив команду:
$ docker-compose logs -f [service name]
  • Посмотреть список используемых сервисов можно командой (на примере данного проекта):
$ docker-compose ps

команда docker-compose ps

  • Чтобы запустить команду в работающем контейнере используется следующий синтаксис:
$ docker-compose exec [service name] [command]
  • Увидеть в терминале список образов можно, введя команду:
$ docker-compose images

description keywords title

Check out this tutorial on how to use Docker Compose from defining application dependencies to experimenting with commands.

docker compose example, docker compose tutorial, how to use docker compose, running docker compose, how to run docker compose, docker compose build image, docker compose command example, run docker compose file, how to create a docker compose file, run a docker compose file

Try Docker Compose

{% include compose-eol.md %}

This tutorial is designed to introduce the key concepts of Docker Compose whilst building a simple Python web application. The application uses the Flask framework and maintains a hit counter in
Redis.

The concepts demonstrated here should be understandable even if you’re not familiar with Python.

Prerequisites

You need to have Docker Engine and Docker Compose on your machine. You can either:

  • Install Docker Engine and Docker Compose as standalone binaries
  • Install Docker Desktop which includes both Docker Engine and Docker Compose

You don’t need to install Python or Redis, as both are provided by Docker images.

Step 1: Define the application dependencies

  1. Create a directory for the project:

    $ mkdir composetest
    $ cd composetest
  2. Create a file called app.py in your project directory and paste the following code in:

    import time
    
    import redis
    from flask import Flask
    
    app = Flask(__name__)
    cache = redis.Redis(host='redis', port=6379)
    
    def get_hit_count():
        retries = 5
        while True:
            try:
                return cache.incr('hits')
            except redis.exceptions.ConnectionError as exc:
                if retries == 0:
                    raise exc
                retries -= 1
                time.sleep(0.5)
    
    @app.route('/')
    def hello():
        count = get_hit_count()
        return 'Hello World! I have been seen {} times.n'.format(count)

    In this example, redis is the hostname of the redis container on the
    application’s network. We use the default port for Redis, 6379.

    Handling transient errors

    Note the way the get_hit_count function is written. This basic retry
    loop lets us attempt our request multiple times if the redis service is
    not available. This is useful at startup while the application comes
    online, but also makes the application more resilient if the Redis
    service needs to be restarted anytime during the app’s lifetime. In a
    cluster, this also helps handling momentary connection drops between
    nodes.

  3. Create another file called requirements.txt in your project directory and
    paste the following code in:

Step 2: Create a Dockerfile

The Dockerfile is used to build a Docker image. The image
contains all the dependencies the Python application requires, including Python
itself.

In your project directory, create a file named Dockerfile and paste the following code in:

# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]

This tells Docker to:

  • Build an image starting with the Python 3.7 image.
  • Set the working directory to /code.
  • Set environment variables used by the flask command.
  • Install gcc and other dependencies
  • Copy requirements.txt and install the Python dependencies.
  • Add metadata to the image to describe that the container is listening on port 5000
  • Copy the current directory . in the project to the workdir . in the image.
  • Set the default command for the container to flask run.

Important

Check that the Dockerfile has no file extension like .txt. Some editors may append this file extension automatically which results in an error when you run the application.
{: .important}

For more information on how to write Dockerfiles, see the
Docker user guide
and the Dockerfile reference.

Step 3: Define services in a Compose file

Create a file called docker-compose.yml in your project directory and paste
the following:

version: "{{ site.compose_file_v3 }}"
services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"

This Compose file defines two services: web and redis.

The web service uses an image that’s built from the Dockerfile in the current directory.
It then binds the container and the host machine to the exposed port, 8000. This example service uses the default port for the Flask web server, 5000.

The redis service uses a public Redis
image pulled from the Docker Hub registry.

Step 4: Build and run your app with Compose

  1. From your project directory, start up your application by running docker compose up.

    $ docker compose up
    
    Creating network "composetest_default" with the default driver
    Creating composetest_web_1 ...
    Creating composetest_redis_1 ...
    Creating composetest_web_1
    Creating composetest_redis_1 ... done
    Attaching to composetest_web_1, composetest_redis_1
    web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
    redis_1  | 1:C 17 Aug 22:11:10.480 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    redis_1  | 1:C 17 Aug 22:11:10.480 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started
    redis_1  | 1:C 17 Aug 22:11:10.480 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
    web_1    |  * Restarting with stat
    redis_1  | 1:M 17 Aug 22:11:10.483 * Running mode=standalone, port=6379.
    redis_1  | 1:M 17 Aug 22:11:10.483 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
    web_1    |  * Debugger is active!
    redis_1  | 1:M 17 Aug 22:11:10.483 # Server initialized
    redis_1  | 1:M 17 Aug 22:11:10.483 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
    web_1    |  * Debugger PIN: 330-787-903
    redis_1  | 1:M 17 Aug 22:11:10.483 * Ready to accept connections

    Compose pulls a Redis image, builds an image for your code, and starts the
    services you defined. In this case, the code is statically copied into the image at build time.

  2. Enter http://localhost:8000/ in a browser to see the application running.

    If this doesn’t resolve, you can also try http://127.0.0.1:8000.

    You should see a message in your browser saying:

    Hello World! I have been seen 1 times.

    hello world in browser

  3. Refresh the page.

    The number should increment.

    Hello World! I have been seen 2 times.

    hello world in browser

  4. Switch to another terminal window, and type docker image ls to list local images.

    Listing images at this point should return redis and web.

    $ docker image ls
    
    REPOSITORY        TAG           IMAGE ID      CREATED        SIZE
    composetest_web   latest        e2c21aa48cc1  4 minutes ago  93.8MB
    python            3.4-alpine    84e6077c7ab6  7 days ago     82.5MB
    redis             alpine        9d8fa9aa0e5b  3 weeks ago    27.5MB

    You can inspect images with docker inspect <tag or id>.

  5. Stop the application, either by running docker compose down
    from within your project directory in the second terminal, or by
    hitting CTRL+C in the original terminal where you started the app.

Step 5: Edit the Compose file to add a bind mount

Edit docker-compose.yml in your project directory to add a
bind mount for the web service:

version: "{{ site.compose_file_v3 }}"
services:
  web:
    build: .
    ports:
      - "8000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_DEBUG: "true"
  redis:
    image: "redis:alpine"

The new volumes key mounts the project directory (current directory) on the
host to /code inside the container, allowing you to modify the code on the
fly, without having to rebuild the image. The environment key sets the
FLASK_DEBUG environment variable, which tells flask run to run in development
mode and reload the code on change. This mode should only be used in development.

Step 6: Re-build and run the app with Compose

From your project directory, type docker compose up to build the app with the updated Compose file, and run it.

$ docker compose up

Creating network "composetest_default" with the default driver
Creating composetest_web_1 ...
Creating composetest_redis_1 ...
Creating composetest_web_1
Creating composetest_redis_1 ... done
Attaching to composetest_web_1, composetest_redis_1
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
...

Check the Hello World message in a web browser again, and refresh to see the
count increment.

Shared folders, volumes, and bind mounts

  • If your project is outside of the Users directory (cd ~), then you
    need to share the drive or location of the Dockerfile and volume you are using.
    If you get runtime errors indicating an application file is not found, a volume
    mount is denied, or a service cannot start, try enabling file or drive sharing.
    Volume mounting requires shared drives for projects that live outside of
    C:Users (Windows) or /Users (Mac), and is required for any project on
    Docker Desktop for Mac and Docker Desktop for Windows that uses
    Linux containers.
    For more information, see
    File sharing on Docker for Mac,
    File sharing on Docker for Windows,
    and the general examples on how to
    Manage data in containers.

  • If you are using Oracle VirtualBox on an older Windows OS, you might encounter an issue with shared folders as described in this VB trouble
    ticket. Newer Windows systems meet the
    requirements for Docker Desktop for Windows and do not
    need VirtualBox.
    {: .important}

Step 7: Update the application

Because the application code is now mounted into the container using a volume,
you can make changes to its code and see the changes instantly, without having
to rebuild the image.

Change the greeting in app.py and save it. For example, change the Hello World!
message to Hello from Docker!:

return 'Hello from Docker! I have been seen {} times.n'.format(count)

Refresh the app in your browser. The greeting should be updated, and the
counter should still be incrementing.

hello world in browser

Step 8: Experiment with some other commands

If you want to run your services in the background, you can pass the -d flag
(for «detached» mode) to docker compose up and use docker compose ps to
see what is currently running:

$ docker compose up -d

Starting composetest_redis_1...
Starting composetest_web_1...

$ docker compose ps

       Name                      Command               State           Ports         
-------------------------------------------------------------------------------------
composetest_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp              
composetest_web_1     flask run                        Up      0.0.0.0:8000->5000/tcp

The docker compose run command allows you to run one-off commands for your
services. For example, to see what environment variables are available to the
web service:

$ docker compose run web env

See docker compose --help to see other available commands.

If you started Compose with docker compose up -d, stop
your services once you’ve finished with them:

You can bring everything down, removing the containers entirely, with the down
command. Pass --volumes to also remove the data volume used by the Redis
container:

$ docker compose down --volumes

Where to go next

  • Next, try the Sample apps with Compose
  • Explore the full list of Compose commands
  • Explore the Compose configuration file reference
  • To learn more about volumes and bind mounts, see Manage data in Docker


ноябрь
3
, 2019

Докер везде. Когда-то на него смотрели, как на очередную забаву неугомонных программистов, но докер оказался не таков.
Если раньше в любой вакансии писали jquery и zend framework, то сейчас — git и docker. Не удивлюсь, если докер станет таким же стандартом, как и гит в свое время.
Или уже стал, это я только из пещеры вылез.

Зачем мне понадобился докер? Ну не знал и не знал, сидел не умничал, сейчас-то что началось?

Разбираться с ним меня сподвигли вы, дорогие читатели. Да ладно? Серьезно.
Четверть вопросов по интернет-магазину звучит примерно так: не работает, что делать?
Почти всегда причина в том, что нужно настроить окружение. Поставить веб-сервер, завести php и mysql, развернуть базу и прочие рутинные штуки.

Вопрос разворачивания рабочего окружения для веб-проектов волновал меня давно.

Когда я начал заниматься первыми веб-проектами, то ухитрился поднять apache, php и mysql на windows 7. Было это лет 8 назад.
История из серии «один раз получилось, но повторить не смогу». Это медаль, которую получаешь раз в жизни.

Вторая попытка осмыслить вопрос рабочего окружения случилась в 2015 году. Я тогда написал адовую статью, как развернуть окружение для веб-разработчика.
Это было страшно, но я сам так работал. Схема предполагала винду как основную ОС, в винде ставилась виртуальная машина VirtualBox, в которой поднимался debian.
В debian уже nginx, php, mysql и nodejs. Также ssh-сервер на виртуалке и ssh-клиент на винде. Все это волшебным образом соединялось вместе и реально работало!
Я не жалею, что творил эту дичь, но вам не советую проделывать такой же путь. Просто не надо. Мир стал намного проще.

Затем я пересел на linux и сразу стало легче. nginx, php и mysql ставились несколькими командами. Раз поставил, нашел типовую конфигурацию для nginx и фигачишь.
Создать виртуальный хост для нового проекта — дело двух минут. По сей день так работаю.

Но вопрос читателей меня не оставлял. Ведь все мы разные. Одни только начинают разбираться в веб-разработке. Другие работают на винде и им так удобнее.
Третьи занимаются фронтендом и им вообще до фонаря эти php и базы данных. Они хотят потрогать javascript-код, а как его потрогаешь, если магазин просто не заводится?

Часто меня выручали системы вроде denwer и open server. Я сам ими не пользовался, но видел со стороны, как это работает, и поэтому советовал.
В том же денвере apache, php и mysql поднимаются довольно просто, на мой взгляд. Судя по отзывам, некоторых читателей это выручало.

Но пора было делать следующий шаг.

Докер

Докер — это такая штука для разработки и разворачивания приложений. В случае веб-проектов докер позволяет развернуть nginx, php, mysql, phpmyadmin и вообще любые приложения.
Причем все это добро не нужно ставить руками и засорять систему. Все сервисы запускаются в виртуальных контейнерах и никак не влияют на основную ОС.
То есть у вас в системе будут только докер, редактор кода, браузер и командная строка. Звучит круто, но пока бесполезно, да? Но смотрим дальше.

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


    docker-compose up --build

Да-да, это все. Забудьте об nginx, php и mysql, о том, что под капотом крутится вебпак и нужно не забывать делать npm install — всю эту работу возьмет на себя докер.
Больше не нужно гадать, заведется ли код на вашей версии php или какую базу данных нужно поставить. Все это докер делает под капотом. Нам остается работать над кодом и не думать об окружении.

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

Основы докера

Разбираясь в теме, я прочитал десятка три статей по докеру. Но в голове все уложилось только когда я нашел вот эту

Docker самый простой и понятный туториал

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

Докер на практике, docker-compose

docker-compose — это система, которая позволяет управлять набором из докер-контейнеров.
То есть работают отдельные контейнеры nginx, php, mysql, но все это еще нужно подружить между собой.
Любой туториал по докеру приводит в пример, как запустить nginx, но нам этого мало. Как завести сразу все, что нужно? Иными словами, LEMP — linux, nginx, php и mysql.

Здесь случилось то же самое, что и с теорией по основам докера. Я перепробовал много разных вариантов, но то php не заводился, то mysql не подключался.
Удалось все сделать только по примеру из этой статьи

Установка LEMP с помощью Docker’а

Рекомендую читать всем, но особенно тем, кто уже разбирался с docker и docker-compose. Если вы знаете общие принципы или просто хотите завести свой проект, то лучше прочитать эту статью.
Автор расписал коротко и по делу. Это не как у меня, статьи только с литром пива читать.

А еще мне понравилась структура проекта из поста. С разрешения автора в своей статье я использую его структуру и конфиги проекта практически без изменений, разве что слегка сократив.

docker и docker-compose. Аналогия для фронтендщиков

Процесс докеризации проекта напоминает мне сборку фронтенда.

В обоих случаях нам нужно решить набор задач. На фронте это собрать весь javascript в один файл и сжать его, препроцессить стили и тоже их сжать, оптимизировать картинки, запустить watcher.
А с докером это поднять nginx, php, mysql и развернуть базу.

Для сборки фронта мы используем npm-пакеты, готовые библиотеки для сжатия и склеивания. В докере это готовые образы nginx, php, mysql.

Все это добро на фронте собирается в один конфиг gulpfile.js или webpack.config.js, а в докере — в docker-compose.yml.
И все задачи запускаются одной командой, например, gulp build или docker-compose up —build

Вот такая у меня аналогия. С общими делами разобрались, переходим к практике

Ставим docker и docker-compose

Докер отлично работает на линуксе и маке. Говорят, на 10-й винде тоже, но не пробовал. Я не знаю, какая у вас система, поэтому смотрите инструкции здесь.

Установить docker — ссылка для ubuntu, но там рядом и другие ОС

Установить docker-compose

Выбирайте версию CE — Community Edition, она бесплатная. EE — enterprise, нам ни к чему.

После установки докера перезагрузитесь и проверьте, все ли в порядке


    docker -v && docker-compose -v

Если что-то не заработает, то наберите такие команды


    sudo groupadd docker
    sudo usermod -aG docker $USER
    
    sudo chmod +x /usr/local/bin/docker-compose

Структура проекта


    - hosts/
    - images/
        - php/
    - logs/
    - mysql/
    - www/
        - default.test/
    docker-compose.yml
  1. В папке hosts мы будем хранить конфиги nginx
  2. В images — образы докера, пока только php
  3. Папка logs нужна для хранения логов nginx
  4. mysql будет содержать файлы базы данных
  5. В www будем складывать непосредственно проекты. Каждый проект в отдельной папке. Для начала — default.test, который будем использовать для примера.
  6. docker-compose.yml — файл конфига, который соберет все в кучу

Тестовый проект default.test

Он будет очень простой. Закинем в папку www/default.test файлик index.php с содержимым


    phpinfo();

Вот и весь проект. На первом этапе мы всего лишь убедимся, что правильно настроили nginx и php. Давайте же посмотрим, как это сделать

Конфиг nginx

Это файл hosts/default.conf такого содержимого


    server {
        index index.php index.html;
        server_name default.test;
        error_log  /var/log/nginx/default.error.log;
        access_log /var/log/nginx/default.access.log;
        root /var/www/default.test;
    
        location ~ .php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+.php)(/.+)$;
            fastcgi_pass php:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }

Если вам приходилось настраивать nginx, то отличие найдете только одно. Раньше в локейшене .php$ в fastcgi_pass вы писали что-то вроде


    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

Теперь же php:9000. Это докеровская тема, php — это название хоста, по которому доступен php-контейнер, а 9000 — порт, по которому до него можно достучаться.

Такой конфиг более менее универсальный и подходит для локальной разработки несложных проектов. В статье мы рассмотрим 3 проекта и конфиги в них будут различаться только 4 строками.

  1. index index.php index.html; — это путь к корневому файлу проекта. Можно оставить оба, и php, и html. Если в папке будет index.php, то исполльзуется он, если нет — то index.html
  2. server_name default.test; — имя хоста, которое мы будем вбивать в браузере
  3. error_log /var/log/nginx/default.error.log; — куда складывать error логи nginx. Вот и пригодилась папка logs.
    Для каждого проекта будем заводить отдельные логи, хотя никто не запрещает складывать все в просто error.log и у вас будет один файл на все проекты. Для разработки годится
  4. access_log /var/log/nginx/default.access.log; — аналогично, только для access логов
  5. root /var/www/default.test; — папка проекта. Хост и название папки указываем одинаково, с точкой, чтобы не путаться

Настраиваем php и Dockerfile для него

По идее можно не делать отдельный Dockerfile для php, а взять готовый образ. Именно так мы сделаем с nginx и mysql, когда будем настраивать docker-compose.yml.
Но проблема в том, что nginx и mysql прекрасно работают из коробки, а с php немного иначе.
Он тоже работает, но в официальный образ не включены никакие расширения, которые могут понадобиться при работе.
Именно поэтому мы будем собирать php хитрее, через Dockerfile.

Давайте посмотрим на конфиг. Это файл images/php/Dockerfile


    FROM php:7.2-fpm
    
    RUN apt-get update && apt-get install -y 
            curl 
            wget 
            libfreetype6-dev 
            libjpeg62-turbo-dev 
            libmcrypt-dev 
        && pecl install mcrypt-1.0.1 
        && docker-php-ext-install -j$(nproc) iconv mbstring mysqli pdo_mysql zip 
        && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ 
        && docker-php-ext-install -j$(nproc) gd 
        && docker-php-ext-enable mcrypt
    
    ADD php.ini /usr/local/etc/php/conf.d/40-custom.ini
    
    WORKDIR /var/www
    
    CMD ["php-fpm"]

Напоминаю, что мы взяли конфиги из этой статьи.
Я чуть сократил конфиг, поэтому читайте исходный, найдете там еще что-то интересное.
Кратко что здесь происходит.

  1. FROM php:7.2-fpm — указываем официальный образ. Напоминаю, он пустой, без всяких расширений
  2. Блок RUN — куча линукс-команд, которые ставят curl, wget и различные расширения вроде mysqli и mcrypt. Без mysqli, например, наш интернет-магазин просто не заработает
  3. ADD php.ini /usr/local/etc/php/conf.d/40-custom.ini — это возможность использовать кастомный php.ini. Кстати, добавьте его в папку images/php, пусть будет пустой
  4. WORKDIR /var/www — рабочая директория для php
  5. CMD [«php-fpm»] — команда запуска контейнера

Да, Dockerfile для php посложнее, чем стандартный nginx-конфиг. nginx мы просто будем копипастить, меняя хост и пути.
Здесь же, чтобы самому написать такой файл, нужно представлять, как работает php, где хранится php.ini, что такое рабочая директория и как ставить расширения.
Но с другой стороны, базовые настройки меняться не будет, главное, разобраться со страшной портянкой в RUN.

Блок RUN — это набор команд, которые мы нагуглили «как установить php в linux» и вбили в консоли. Разве что расширения ставятся через docker-php-ext-install.
Например, в линуксе мы бы поставили mysqli примерно так


    sudo apt-get install php7.2-mysqli

А в докере нужно указать его в строке


    docker-php-ext-install -j$(nproc) mysqli

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

Пора собирать nginx и php в единое целое — переходим к docker-compose.yml

Конфиг docker-compose.yml

Файл будет такого содержания


    version: '2'
    services:
      nginx:
        image: nginx:latest
        ports:
          - "8000:80"
        volumes:
          - ./hosts:/etc/nginx/conf.d
          - ./www:/var/www
          - ./logs:/var/log/nginx
        links:
          - php
      php:
        build: ./images/php
        volumes:
          - ./www:/var/www

Разберем, что здесь написано.

version: ‘2’ — версия docker-compose. Сейчас есть и 3-я, но там какие-то совсем хитрые штуки, нам хватит и 2

services — здесь перечисляем контейнеры, которые будут у нас работать в связке. Пока что nginx и php, позже добавим mysql

image: nginx:latest — используем последнюю версию образа nginx с официального хранилища dockerhub

ports: — «8000:80» — здесь прокидываем порты. nginx в контейнере работает на дефолтном 80, а мы возьмем 8000. Это значит, в браузере будем открывать не default.test, a default.test:8000

volumes: — здесь монтируем файлы и папки. Или прокидываем их из локальной системы в контейнер. Посмотрим первый пример ./hosts:/etc/nginx/conf.d.
В папке hosts у нас лежат конфиги nginx, но контейнер-то об этом не знает.
Контейнер изолирован от нашей основной системы, а раздел volumes как раз и позволяет «общаться» контейнеру с нашей ОС.
Можно считать эту команду копированием содержимого локальной папки ./hosts в «удаленную папку» контейнера /etc/nginx/conf.d.
Или еще лучше настройкой ссылки (симлинки). Аналогично ./www:/var/www указывает рабочую директорию для nginx, а ./logs:/var/log/nginx — расположение логов

links: — php указывает, что контейнер nginx имеет зависимость от php

Дальше раздел php. Здесь короче, потому что основное мы указали в Dockerfile

build: ./images/php — папка, где располагается Dockerfile

volumes: — ./www:/var/www — прокидываем рабочую директорию точно так же, как и для nginx

С конфигом docker-compose.yml пока все. Идем дальше

Правим файл hosts

Чтобы наш пробный сайт default.test заработал в браузере, нужно не забыть добавить его в файл hosts. Открываем /etc/hosts с sudo (на unix-системах) и добавляем в него


    127.0.0.1 default.test

Точно так же, как и при работе с локальным веб-сервером. Сохраняем файл, закрываем

Запускаем проект

Наконец-то самое интересное, проверим, как все это работает. В консоли из корневой папки проекта запускаем команду


    docker-compose up 

И ждем… Первый запуск будет проходить не быстро. В консоль будет сыпаться до фига всего разного, но можно будет разглядеть, как скачиваются образы ngnix и php,
как выполняются команды RUN из php-шного Dockerfile, как запускаются контейнеры.

Если мы все сделали правильно, то увидим в консоли примерно такую картину


    Starting docker_php_1 ... done
    Starting docker_nginx_1 ... done
    Attaching to docker_php_1, docker_nginx_1
    php_1    | [01-Nov-2019 16:21:18] NOTICE: fpm is running, pid 1
    php_1    | [01-Nov-2019 16:21:18] NOTICE: ready to handle connections

done напротив названий контейнеров говорит, что они успешно запущены.
Идем в браузер, переходим на http://default.test:8000/ и видим полный расклад phpinfo. Работает!

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

Но сначала немного отвлечемся и посмотрим, какие команды нам пригодятся при работе с docker-compose и вообще с проектами

Как работать с docker-compose

Первой командой, которую мы запустили, был docker-compose up. Команда анализирует конфиг docker-compose.yml, скачивает нужные образы, монтирует файлы и папки и запускает контейнеры.
При этом процесс висит в консоли, а чтобы остановить его, нужно нажать ctrl+C, стандартно. А еще в консоли будут выводиться логи docker-compose.

Можно запустить контейнеры с опцией —build, вот так


    docker-compose up --build

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

Если вы не хотите, чтобы в консоли висел открытый docker-compose, запускайте его как процесс, с опцией -d


    docker-compose up --build -d

Тогда докер запустит все контейнеры, но в фоне. Все будет работать точно так же, но чтобы остановить контейнеры, нужно будет запускать


    docker-compose down 

А логи смотреть, запуская отдельно


    docker-compose logs -f

Если мы разворачиваем приложение в продакшене, то конечно, запускать его стоит как фоновый процесс.
Но в режиме разработки мне больше нравится держать консоль открытой и сразу смотреть логи. И не думать, нужна ли пересборка всех образов или нет. То есть запускать


    docker-compose up --build

Еще при разработке бывает полезно заглянуть в логи nginx. Отслеживать их будем через обычный tail -f


    tail -f ./logs/default.error.log

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

Запускаем второй проект. Мое старое портфолио

Предлагаю немного передохнуть и закрепить информацию. Каким образом? Мы создадим второй проект. Он тоже php-ный, но чуть сложнее одного файла.
Там уже подключаются шрифты, стили и javascript. Технически это не будет отличаться от первого default.test, но фишка в другом.
Мы увидим, как просто нам теперь создавать новые проекты, а заодно и посмотрим на мое старое портфолио, которое я создал лет 6-7 назад.
Это простой сайт на php, где рассказывается, какой я замечательный человек и разработчик.

Создаем новую папку www/w-portfolio.test. Кладем туда файлы проекта.
Расписывать их нет смысла, все найдете в исходниках.

Дальше добавляем nginx конфиг в hosts — w-portfolio.conf с содержимым


    server {
        index index.php index.html;
        server_name w-portfolio.test;
        error_log  /var/log/nginx/portfolio.error.log;
        access_log /var/log/nginx/portfolio.access.log;
        root /var/www/w-portfolio.test;
    
        location ~ .php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+.php)(/.+)$;
            fastcgi_pass php:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }

То есть мы скопировали конфиг из дефолтного default.conf и поменяли default на w-portfolio. Что может быть проще?

Осталось добавить в файл hosts строку


    127.0.0.1 w-portfolio.test

И перезапустить docker-compose


    docker-compose up --build

И открыть в браузере http://w-portfolio.test:8000

Итак, второй сайт разобрали, идем дальше.

Создаем проект интернет-магазина

Все то же самое, что и с проектом w-portfolio.test.

Создаем папку w-shop.test, копируем туда файлы магазина. Если вы читали статьи по магазину или админке, то в курсе, что это за магазин.
Можете просто взять свои локальные файлы.
А если нет, то взгляните, как этот самый магазин выглядит shop.webdevkin.ru и
берите файлы из исходников

Дальше заводим nginx-конфиг w-shop.conf в папке hosts


    server {
        index index.php index.html;
        server_name w-shop.test;
        error_log  /var/log/nginx/shop.error.log;
        access_log /var/log/nginx/shop.access.log;
        root /var/www/w-shop.test;
    
        location ~ .php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+.php)(/.+)$;
            fastcgi_pass php:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }

И прописываем в /etc/hosts строку


    127.0.0.1 w-shop.test

Если вы прямо сейчас перезапустите docker-compose, то у вас откроется
первая страница http://w-shop.test:8000/ и
корзина http://w-shop.test:8000/cart.html.
Будет работать даже добавление в корзину. А вот каталог с фильтрами, каталог с пагинацией и отправка заказов не заведутся, потому что там уже включается база.
Давайте разбираться, как работать с mysql

Подключаем mysql

Добрались до самого интересного. Идем сразу в конфиг docker-compose.yml и добавим в services новый раздел mysql, вот так


  mysql:
    image: mysql
    ports:
      - "3307:3306"
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root

А в раздел php добавим зависимость от нового контейнера


  php:
    build: ./images/php
    links:
      - mysql
    volumes:
      - ./www:/var/www

Разбираемся по порядку.

image: mysql — образ mysql из dockerhub-хранилища

ports: — «3307:3306» — справа дефолтный порт, на котором mysql работает в контейнере. Слева — порт, который займет mysql в локальной ОС. Почему я не оставил тоже дефолтный 3306?
Потому что у меня уже установлен локальный mysql. У вас, скорее всего, тоже. И когда я попытался запустить докер, то он мне сказал, извини, чувак, порт 3306 уже занят, не шмогла.
Проверяем в консоли


    $ sudo netstat -nlpt | grep 3306
    tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      1121/mysqld     

Действительно занят. Можно остановить локальный mysql через sudo service mysql stop, а можно просто повесить докеровский mysql на другой порт. Например, на 3307 или любой другой свободный.

Идем дальше.

volumes: — ./mysql:/var/lib/mysql — монтируем папки, ./mysql — это папка в нашем проекте, куда будем складывать файлы базы, а /var/lib/mysql — это папка, где лежит база по дефолту.
По идее, можно держать базу и внутри контейнера, но удобнее вытащить в «свою» ОС. Например, так можно будет делать бэкапы и использовать одну и ту же базу в разных проектах

И последнее

environment: MYSQL_ROOT_PASSWORD: root — переменные среды. Здесь указываем только пароль для root-пользователя. В интернет-магазине у нас использовался root/root, пусть и здесь так же

В php мы добавили блок-зависимость от нового контейнера mysql

links: — mysql

Все, база mysql у нас будет подниматься и будет работать. Но есть одно но. Как с ней работать руками? Чтобы прямо войти и посмотреть.

Конечно, можно подключаться к ней в консоли и фигачить create table и прочие хакерские заклинания, но хочется чего-то попроще.
Люди давно изобрели PhpMyAdmin, который стоит на каждом хостинге и нам привычен. Давайте и его заведем в докер.

Устанавливаем PhpMyAdmin

В docker-compose.yml добавляем еще один контейнер


    pma:
        image: phpmyadmin/phpmyadmin
        restart: always
        links:
          - mysql:mysql
        ports:
          - 8001:80
        environment:
          PMA_HOST: mysql
          MYSQL_USERNAME: root
          MYSQL_ROOT_PASSWORD: root

Разбираем

  • image: phpmyadmin/phpmyadmin — берем официальный образ
  • restart: always — вот этой магии, честно, не понял. Всегда перезапускать контейнер, но почему только этот? Как узнаю, расскажу, а пока оставим так
  • links: — mysql:mysql — зависимость от mysql
  • ports: — 8001:80 — справа дефолтный порт, на котором phpmyadmin запущен в контейнере, слева — любой свободный, я взял 8001 — следующий за 8000, по которому открываем сам сайт
  • И переменные среды: хост, пользователь и пароль. В реальном приложении, конечно, не будем заходить под рутом, но для примера годится

    environment: PMA_HOST: mysql, MYSQL_USERNAME: root, MYSQL_ROOT_PASSWORD: root

Готово, скоро будем пробовать. Но пока еще раз отвлечемся

Зависимости в docker-compose

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


    nginx:
        links:
            - php
    php:
        links:
            - mysql
    mysql:
        ...
    pma:
        links:
            - mysql:mysql

nginx зависит от php, то есть сначала стартует php, а потом nginx.
php от mysql, phpmyadmin тоже от mysql и лишь mysql ни от кого не зависит. Она база, она сама по себе работает.

Когда мы запустим docker-compose снова, то увидим в консоли такую картину


    Starting docker_mysql_1 ... done
    Starting docker_php_1   ... done
    Recreating docker_pma_1 ... done
    Starting docker_nginx_1 ... done

Это как раз демонстрирует порядок запуска контейнеров. А останавливаются они в обратном порядке


    Killing docker_pma_1    ... done
    Killing docker_nginx_1  ... done
    Killing docker_php_1    ... done
    Killing docker_mysql_1  ... done

Сначала те, от которых никто не зависит, в конце — самые «важные».

Но это было отступление, погнали дальше, проверять mysql

Подключаемся к базе через PhpMyAdmin

Запускаем docker-compose up —build. Снова придется подождать, потому что докеру нужно выкачать 2 новых образа.
Ждем, дожидаемся успеха и открываем http://w-shop.test:8001.
Видим привычную форму входа в PhpMyAdmin. Вбиваем логин/пароль root/root и входим в интерфейс базы. Но здесь нас может ждать сюрприз.

У меня получилось так — я успешно зашел в PhpMyAdmin один раз, поковырялся там, создал базу и вышел. А вот второй раз зайти уже не смог.
Вбиваю root/root, а в ответ mysql not connect или что-то такое.

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


    ALTER USER root IDENTIFIED WITH mysql_native_password BY 'PASSWORD';

PASSWORD в смысле root — наш пароль рута. Это понятно, а как войти-то в базу, раз PhpMyAdmin не пускает? Нужно лезть руками, в консоли, по хакерски. mysql -uroot -proot и вот это вот.
Тонкость в том, что нужно сначала зайти в контейнер mysql, а уже потом в саму базу mysql.
Давайте вспомним статью по основам докера,
которую я рекомендовал в самом начале.

Чтобы попасть в контейнер, нужно узнать его id. Набиваем docker ps и видим примерно такой список

webdevkin. docker-ps

Id контейнера mysql — 3825c5051ee9. Давайте заглянем в него


    docker exec -it 3825c5051ee9 bash

Мы зашли в контейнер и запустили в нем команду bash. Ключ -it нужен, чтобы создать интерактивный терминал. Проще говоря, мы попали в консоль контейнера.
Здесь уже привычнее. Подключаемся к базе рутом и выполняем нагугленный запрос


    mysql -uroot -proot
    ALTER USER root IDENTIFIED WITH mysql_native_password BY 'root';
    exit // выходим из базы данных
    exit // выходим из контейнера mysql

После этого все заработало и PhpMyAdmin стал пускать без ограничений.

Создаем базу данных интернет-магазина

По фэншую мы должны были создать базу и накатить sql-дамп через докер. Запустить команду mysql -uroot -proot < dump.sql.
Но предварительно проверив, существуют ли нужные таблицы, чтобы не перезатереть созданные ранее. Уверен, что докер это умеет, но я не осилил, простите дурака.
Как осилю, расскажу, скорее всего, можно создать Dockerfile по аналогии с php и добавить в блок RUN такую команду


    mysql -uroot -proot < ./www/w-shop.test/sql/dump.sql. 

Но пока давайте заведем базу руками.

Заходим в PhpMyAdmin, создаем там базу webdevkin и импортируем данные. Если у вас магазин уже развернут, то можете снять дамп со своей базы.
Если же нет, то берите из исходников — файл www/w-shop.test/sql/dump.sql. После это у вас получится такая структура

webdevkin. docker, таблицы mysql

Там уже забиты товары, бренды и категории. Вроде бы все, можно открывать магазин.
Открываем страницу каталога с фильтрами — http://w-shop.test:8000/catalog.html,
ан нет — крутится спиннер и товары не подгружаются. Разбираемся, в чем дело.
С бекенда приходит страшный ворнинг


    Warning: mysqli::query(): Couldn't fetch mysqli in /var/www/w-shop.test/scripts/catalog.php on line 16

Дело в том, что мы не можем подключиться к mysql. Посмотрим на файл www/w-shop.test/scripts/catalog.php, самое начало, где объявляем константы с настройками базы. Вот строка


    define('DB_HOST', 'localhost');

Фишка в том, что нам нужно подключаться не к localhost, а к mysql — название контейнера в docker-compose. Поменяем в константе DB_HOST значение localhost на mysql и все заработает.
Благодаря качественному проектированию у нас подключение к базе разбросано по всем скриптам, поэтому придется это делать в четырех местах: catalog.php, common.php, compare.php и order.php.

Если вы работаете с магазином, то надеюсь, вместо дублирования настроек уже подключаете common.php и используете функцию connectDB оттуда. Если нет, то самое время это сделать :-)

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

Выводы. Преимущества докера

Давайте сведем воедино найденные плюсы докера.

1. Не нужно ставить тонну всего

В рабочей системе нет nginx, php, mysql, nodejs.
Мы можем поставить любые базы и приложения: монгу, редис, postgresql, sphinx, nodejs и черта лысого, но все это будет закрыто в контейнерах и не засорит основую ОС.

2. Изолированность

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

3. Кроссплатформенность и универсальность

Больше нет нужды переживать, в какой ОС вы работаете. Можно днем работать за системником с линуксом, а вечерами за ноутбуком с macOS или виндой.

4. Гибкость, легко менять версии и технологии

Легко проверить приложение на разных версиях php, mysql и других приложений.

5. Удобство разворачивания

Эту тему я не затрагивал, но докер хорош не только в локальной разработке, но при разворачивании сервиса на продакшене.
Я даже слышал мнение, что докер — это в первую очередь поставка, а не разработка. Но оставим этот срач экспертам.
Нас же, программистов, больше интересует удобство разработки. Например, мне совершенно не нравится ковыряться в десятке микросервисов, чтобы запустить какой-то проект.
И докер в этом плане отличное решение.

6. И наконец, докер везде

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

Минусы докера

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

Зачем изучать докер? Мне и без него хорошо

У каждого своя ситуация, я расскажу про свою. Недавно думал насчет изучения новых технологий и вывел для себя 5 стадий работы с ними.

1. не знаю и знать не хочу

2. чот все знают, а я нет, ну и фиг с ними

3. может все-таки посмотреть, вроде прикольно

4. нормальная рабочая тема, надо пользоваться

5. как я без этого жил раньше

Пока что я застрял между 3 и 4 стадией, но надеюсь, дойду до конца. Все 5 стадий мы проходим, если технология действительно хороша и полезна.
Если же это очередная распиаренная хрень, то хорошо если доходим до третьей стадии «может, посмотреть?». А то и вообще до второй или даже первой.
Почему-то кажется, что это не про докер, и он стоит того, чтобы с ним заморочиться.

Ровно так у меня получилось с гитом — как я перестал бояться и полюбил гит

Что дальше будет с докером в блоге

У меня нет в планах строить серию постов по докеру по примеру уроков vue. Тем более, сначала нужно получше разобраться.
Скорее всего, я буду понемножку осваивать докер, заверну админку магазина, проект на vuejs и дальше буду пробовать еще что-то.
Когда соберусь написать о полнотекстовом поиске sphinx или о работе с монго в php, то пожалуй, буду разворачивать это все в докере. Но постараюсь без фанатизма. Поживем — увидим.

Ссылки

Docker — самый простой и понятный туториал

Установка LEMP с помощью Docker’а

Демо интернет-магазина

Исходники всех проектов из статьи

На этом все. Всем удачи и до встречи.

Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.

Истории из жизни айти и обсуждение кода.

Fundamentals of Docker

Before diving into advanced Docker concepts, like Docker Compose, we want to make sure to refresh the fundamentals of Docker as a whole. Let’s define and explore the basics of Docker.

Docker Client

A Docker Client is a component used by a Docker user to interact with the Docker daemon and issue commands. These commands are based on the Docker API.

Docker Architecture

The Docker Architecture is made of layers, as we will discuss below. The bottom layer is the physical server that we use to host virtual machines. This is the same as a traditional virtualization architecture.

The second layer is the Host OS, which is the base machine (i.e. Windows or Linux). Next, is the Docker Engine, which we use to run the operating system. Above that are the Apps which run as Docker containers. Those Docker Objects are made up of images and containers.

Containers and images

The basic structure of Docker relies on images and containers. We can think of a container as an object and an image as its class.

A container is an isolated system that holds everything required to run a specific application. It is a specific instance of an image that simulates the necessary environment. The following is an example command for running an Ubuntu Docker container and accessing the bash shell:

docker run -i -t ubuntu /bin/bash

Images, on the other hand, are used to start up containers. From running containers, we can get images, which can be composed together to form a system-agnostic way of packaging applications.

Images can be pre-built, retrieved from registries, created from already existing ones, or combined together via a common network.

Dockerfiles

Dockerfiles are how we containerize our application, or how we build a new container from an already pre-built image and add custom logic to start our application. From a Dockerfile, we use the Docker build command to create an image.

Think of a Dockerfile as a text document that contains the commands we call on the command line to build an image.

Below is an example of a Dockerfile:

FROM python:3
 
WORKDIR /usr/src/app
 
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
 
COPY . .
 
CMD [ "python", "./your-daemon-or-script.py" ]

Layers

A Dockerfile works in layers. These are the building blocks of Docker. The first layer starts with the FROMkeyword and defines which pre-built image we will use to build an image. We can then define user permissions and startup scripts.

In Docker, a container is an image with a readable layer built on top of a read-only layer. These layers are called intermediate images, and they are generated when we execute the commands in our Dockerfile during the build stage.

Docker Registry

Docker Registry is a centralized location for storing and distributing Docker images. The most commonly used public registry is Docker Hub, but you can also create your own private registry.

Docker Daemon

Docker Daemon runs on a host machine and manages containers, images, networks, and volumes. It receives commands from the Docker client and executes them. The Docker daemon uses Docker images to create containers.

Docker Hub

Docker Hub is a Docker Registry that provides unlimited storage for public images and offers paid plans for hosting private images. Anybody can access a public image. But to publish and access images on Docker Hub, you must create an account first.

Here are some common commands for using Docker Hub:

  • docker login: Login to your Docker Hub account from the command line.

  • docker pull: Download an image from Docker Hub to your local machine. For example, docker pull alpine.

  • docker push: Upload a local image to Docker Hub. For example, docker push username/image-name.

  • docker search: Search for an image on Docker Hub. For example, docker search alpine.

  • docker tag: Tag an image with a new repository name and/or tag. For example, docker tag image-id username/repository:tag.

  • docker images: List all images on the local machine.
    docker rmi: Remove an image from the local machine. For example, docker rmi 4535, where 4535 is an ID of an existing image on your machine.

Понравилась статья? Поделить с друзьями:
  • Мультиварка комфорт мв 611д инструкция по применению
  • Должностная инструкция оператора газовой котельной скачать
  • Руководство пользователя кайзер
  • Hitachi h60ma инструкция по применению на русском
  • Детская нефрология руководство для врачей