Docker windows проброс портов

Докер — начало работы

Введение ¶

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

Эту статью я писал, используя Debian 9 на VirtualBox. Конечно, это не обязательное условие, но докер сам по себе, на мой взгляд, ставит много лишнего в систему, поэтому я предпочитаю держать его в виртуальной машине.

Из чего состоит Docker ¶

Сам по себе докер, это виртуальная машина. И нужно рассматривать его именно как полноценную виртуальную машину, в которой есть свой жёсткий диск, оперативная память и сетевая карта. Если вы работали с виртуальными машинами, напримкер, VirtualBox, то многие вещи будут уже знакомы, правда, с той разницей, что докер не имеет красивую GUI-оболочку, а управляется в основном из консоли.

Основные компоненты докера:

  • Образ (image) — образ диска, который будет запускаться в контейнере.
  • Контейнер (container) — виртуальная машина, в которой запущен образ.
  • Репозиторий образов (image repository) — удалённое или локальное хранилище для образов.

Нужно помнить, что в контейнере всегда запускается образ. При этом, если докер не нашёл образ в локальном хранилище, то он будет искать его в удалённом репозитории (как правило, на Dockerhub).

Как запустить образ ¶

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

Это приведёт к следующим действиям:

  1. Докер скачает образ hello-world в локальное хранилище.
  2. Создаст новый контейнер.
  3. Запустит контейнер, в котором выполнится команда /hello .

Если запустить команду несколько раз, то будет создано несколько контейнеров. Убедиться в этом можно, если выполнить docker ps -a :

Чтобы удалить ненужные контейнеры и образы, выполните:

Поздравляю! Теперь вы стали почти докер-мастером.

Немного теории ¶

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

Именно на идеи изоляции процесса построена основная часть логики докера. Контейнер работает, пока работает начальный процесс (его называют entry point или command). Как только процесс завершается, контейнер останавливается. Это ключевое отличие докера от привычных виртуальных машин (вроде VirtualBox).

Благодаря изоляции процессов, на одной машине можно запускать много версий приложения, которое в обычных условиях будет конфликтовать. Например, можно запустить сразу MySQL 8 и MySQL 5, nodejs 8 и nodejs 10. Без докера сделать это тоже можно, но проблематичней.

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

Как использовать ресурсы контейнера ¶

По умолчанию контейнер закрыт от любых контактов извне. Вы не можете ни скопировать в него файл, ни подключиться к сокету. Он закрыт. Но при запуске контейнера можно пробросить порт или папку. Тогда к нему можно будет подключиться, добавить файл или что-то скачать. Всё это делается при создании (запуске) контейнера через аргументы.

Проброс портов ¶

Для примера запустим контейнер с Debian 9 и пробросим локальный порт 3132 на 80 порт контейнера:

Читайте также:  Каталог рабочих столов windows 10

Пояснения к команде:

  • docker run — создаёт и запускает новый контейнер.
  • —tty — подключает виртуальную консоль. Это нужно, чтобы команда cat не завершала работу, иначе контейнер остановится.
  • —detach — запускает выполнение контейнера в фоне. Без этого аргумента консоль будет ждать, когда контейнер остановится (для остановки придётся использовать другую консоль).
  • —entrypoint /bin/cat — использовать в качестве процесса системную утилиту cat . Просто потому, что она не завершится пока не закроется stdin, а значит и контейнер будет работать.
  • —name my_container — уникальное имя, которое используется для управления контейнером. Если его не указывать, то докер сам придумает какое-нибудь имя.
  • —publish 3132:80 — проброс портов. Сначала надо указать порт машины (можно указать вместе с IP), потом порт в контейнере.

Общий принцип запуска контейнеров довольно простой:

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

Теперь давайте рассмотрим, как выполнять команды внутри контейнера. Для примера установим и запустим консольный сервер php 7:

Пояснения к команде:

  • docker exec — выполняет команду внутри запущенного контейнера.
  • —tty — подключает виртуальную консоль. Без этого аргумента вывод будет неправильным.
  • —interactive — подключает ввод. Без него не будет работать клавиатура.
  • my_container — имя контейнера, в котором выполняется команда.
  • команда и аргументы — команда, которая будет выполнена внутри контейнера.

Чтобы проверить, работает сервер или нет, нужно подключиться на 3132 порт основной машины, например так:

В этом примере я использовал две разные консоли. На одной я запускал сервер, а на другой curl. Ещё можно использовать браузер, если докер установлен у вас в системе.

Проброс папки ¶

В предыдущем примере я создал index.php прямо в контейнере. Это не самый удобный способ разработки проектов в через докер. Во-первых, много файлов так не создашь, во-вторых ими сложно управлять, а, в-третьих, если удалить контейнер, они тоже удалятся. Чтобы решить эти проблемы, можно пробросить (примонтировать) папку из реальной машины в виртуальный контейнер. Делается это, как всегда, при создании контейнера, через аргумент —volume исходная_папка:папка_контейнера .

Прежде, чем начать что-то менять, надо удалить старый контейнер:

Теперь подготовим наш «проект»:

А теперь запускаем контейнер с пробросом папки проекта:

Если вы помните, я удалил контейнер, в котором был установлен php, а это значит, что мне заново придётся установить пакет php7.0-cli:

Теперь в контейнере есть и проект, и php, можно запускать сервер:

Теперь проверяем, как работает наш проект:

Для наглядности давайте создадим ещё один файл в «проекте», чтобы удостовериться, что всё работает как надо:

Должно вывести что-то вроде этого:

Если у вас получилось, смело пишите в резюме, что владеете докером!

Собираем образ (image) ¶

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

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

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

  1. Установить пакет php7.0-cli.
  2. Сделать точку входа (чтобы не мучить cat)

Указать проброс портов или папки в Dockerfile файле нельзя (несмотря на директивы EXPOSE и VOLUME, проброс и монтирование можно делать только при запуске контейнера). Сделано это специально по причинам безопасности, иначе владелец образа в репозитории мог бы подключать любую системную папку в контейнер без ведома пользователя и красть данные.

Создаём Dockerfile в любой папке со следующим содержимым:

Несколько слов об установке пакетов. Изначально в сборках *-slim отсутствует дерево пакетов (для уменьшения размера образа), поэтому надо обязательно выполнять apt-get update . После установки желательно удалить ненужные файлы и папки, поэтому выполняются команды очистки.

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

Читайте также:  Linux 2016 как windows

Теперь нужно собрать образ командой:

Пояснения к команде:

  • docker build — запускает сборку образа.
  • -t my_image:1.0.1 — задаёт имя и тэг образа. Если тэг не указан, используется значение lastest .
  • -f Dockerfile — явно указывает расположение Dockerfile. Можно опустить, если файл называется Dockerfile и находится в текущей директории.
  • $/project — рабочая директория для сборки образа. Относительные пути в Dockerfile будут строиться от этой папки.

Готово! Теперь можно запустить контейнер из нашего образа:

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

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

Что дальше ¶

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

Попробуйте выполнить следующие шаги:

  • Протестировать холодную перезагрузку сервера (лучше в VirtualBox). В реальной жизни это нечастое явление, но случается, поэтому лучше заранее знать, как поведёт себя докер.
  • Поднять несколько контейнеров и настроить между ними сеть. Пожалуй, это самая частая задача, с которой вы будете сталкиваться.
  • Научиться передавать переменные окружения в контейнер.
  • Научиться работать с документацией докера. Конечно, в интернетах есть много статей, но уметь найти нужную информацию в первоисточнике — бесценно.
  • Почитать про docker-compose. Рано или поздно это вам точно пригодится.

Docker: привязываем порты

Решаем вопрос с портами раз и навсегда

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

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

Даже если вы уже опытный разработчик, вы должны знать, что такое привязка портов. В противном случае во время собеседования вы можете выглядеть глупо. Если у вас нет об этом ни малейшего представления, возьмите чашку кофе и устраивайтесь поудобнее. Я постараюсь рассказать всё, что вам нужно знать об этом. Всего за несколько минут!

Начнём с контейнера Nginx Docker

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

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

Мы все устанавливали программы на Windows, Mac или Linux. Когда программе чего-то не хватает, она сообщает об этом и всё. Это раздражает. Наверное, можно тоже просто установить её, да? Тогда не хотите ли вы установить и эту программу? Ох… В конце концов вы получаете множество программ. При этом часто нужно настроить системные переменные и так далее. В худшем случае это может повредить систему. Вы же не хотите, чтобы все ваши коллеги прошли через это? Так вот, образ Docker содержит все необходимое для установки программы, а контейнер Docker — это запущенный экземпляр образа.

Итак, Docker решает проблему установки. Контейнер содержит все необходимое для работы и ничего больше. Вы можете запустить его на Windows, Linux или Mac и, в принципе, везде, где установлен Docker. Но хватит о преимуществах. Мы здесь для того, чтобы поднять и запустить контейнер.

Давайте, наконец, начнём с Nginx Docker. Nginx — это веб-сервер, работающий на 80 порту. Я сразу же запущу контейнер Docker (в отсоединенном режиме), используя образ Nginx Docker :

docker container run -d nginx

Создается контейнер. Вы увидите его UUID. Если вы не знаете, что такое UUID. С помощью команды container ps вы получаете список активных контейнеров:

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

— Но почему? В Docker-файле говорится, что порт 80 открыт… я его не понимаю.

— Не волнуйтесь, я объясню это в следующей части статьи!

curl -I 127.0.0.1:80
curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused

Почему нельзя подключиться напрямую?

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

— А, понятно. То есть не наоборот. Как же тогда мы должны подключиться?

— Есть несколько вариантов сделать это. Изучим их.

1. Предоставить все порты Docker’а.

docker container run -P -d nginx

Параметр -P открывает порты, предоставленные контейнеру. Docker идентифицирует каждый порт, предоставленный в Dockerfile , а также те, что предоставляются с помощью команды и параметра docker container build —expose. Каждый открытый порт напрямую привязан к “случайному” порту хоста.

— Хорошо звучит, но как теперь найти этот порт?

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

• docker container port

Начнём с команды Docker. Просто допишите к ней UUID контейнера. Вы увидите, что порт контейнера 80 привязан к IP-адресу хоста 0.0.0.0 и порту хоста 32768 (или другому порту при самостоятельном выполнении команды).

docker container port вставьте UUID контейнера
80/tcp -> 0.0.0.0:32768

Другой вариант — команда netstat. Чтобы найти все открытые порты, вы также можете выполнить команду ниже. Заметьте, что вы найдёте свой любимый порт среди других портов. Искомый порт находится в третьей строке.

Все открытые порты, найденные netstat.

2. Доступ к определённому порту

Пример привязки портов: привязка порта 80 контейнера Docker к 8080 порту хост-машины.

Предоставление всех портов Docker обычно не очень хорошая идея: по умолчанию не выставляется вообще ни один порт. Думаю, это сделано в целях безопасности. Вы же не хотите открывать всё: это не имеет никакого смысла. Верно? Чтобы открыть только один порт, выполните эту команду:

docker container run -p 8080:80 -d nginx

Порт 80 контейнера Nginx открыт внешнему миру на порту хоста 8080. Теперь вы можете подключиться к контейнеру несколькими способами. Например, с помощью curl или вашего браузера. Это потрясающе!

Поздравляю, теперь вы понимаете самую важную часть привязки портов в Docker! Я покажу результат выполнения curl:

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

Ещё одна вещь

По умолчанию Docker предоставляет контейнерные порты IP-адресу 0.0.0.0 (это соответствует любому IP-адресу в системе). Вы также можете указать Docker, к какому IP привязываться. Это может быть 127.0.0.1 или другой IP. Чтобы привязать 80 порт контейнера к порту 8000 хоста и IP-адресу 127.0.0.1, также известному как localhost, просто выполните команду ниже:

docker run -d -p 127.0.0.1:8000:80 nginx

Заключение

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

Я надеюсь, эта статья прояснила для вас привязку портов.

Читайте также:  Windows 10 and xbox 360 controller
Оцените статью