Docker для ленивых: Локальная разработка сайтов. Часть 1

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

Жак Фреско

Пролог

Docker появился в 2013 году, но впервые мне довелось использовать его лишь в 2017 году, до этого приходилось на локальном компьютере поднимать свой сервер Apache + PHP + MySQL + PHPMySQLAdmin, и танцевать с бубном долго и самозабвенно.

Почти у всех разработчиков середины-конца 2000-х всегда возникали проблемы когда код прекрасно работает на локалке, но на продакшене - нет. То версии PHP и библиотеки не те, то настройки сервера. Да было весело )

И вот в 2017, работая над очередным проектом увидел, что предыдущие разработчики используют Docker, решил ознакомиться. Установил себе Docker (на Windows), скачал с сервера проекта docker-compose.yml и архивы БД и файлов, так как инструкций на руках не было потратил часа 3 на эксперименты методом тыка, но в итоге проект запустил. Если честно - мало чего понял (о Docker и его возможностях), но проект был развернут, работал, весь код написанный и протестированный в Docker прекрасно зашел на продакшн, работу сдал, и с чистой совестью про Docker забыл.

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

Почему для ленивых?

- Потому что не будем изучать матчасть Docker и Docker Compose, кому интересно может прочитать официальную документацию.

- Потому что будем использовать командную строку или терминал по минимуму! И начнем использовать графический интерфейс для управления Docker!

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

Зачем вообще Docker нужен?

Docker позволяет за пару минут на Вашем компьютере развернуть среду для разработки и тестирования, не только сайтов но и ОС, приложений и т.д. и т.п. В этой среде Вы можете сколь угодно экспериментировать не опасаясь за сам компьютер, так как все выполняется в изолированной от Вашей ОС среде. И свернуть проект так же легко и быстро.

Для web-разработчика крайне полезный инструмент! Рассмотрим пример из жизни, у меня несколько рабочих компов, активно использую я два, это Macbook Air с 120ГБ SSD и Asus Zenbook с 1ТБ SSD, как Вы понимаете с Asus проблем с нехваткой места на диске не случалось, а вот на Air’е всегда не больше 10 ГБ, но он легкий, работает без подзарядки долго, большую часть работы я привык уже делать именно на нем.

Но из-за перманентной нехватки места на SSD развернуть на нем “по старинке” Apache + PHP + MySQL + PHPMySQLAdmin (да еще и не одну версию PHP а как минимум 3-4) просто не представлялось возможности (либо ставить-настраивать и удалять всю связку под каждый проект, а проектов в работе могло быть от 1 до 20).

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

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

Установка Docker и Docker Compose на Windows и MacOS

Тут все просто переходим по ссылке (https://www.docker.com/get-started), выбираем версию для своей ОС и следуем инструкции установщика.

В итоге у Вас на компьютере есть Docker и Docker Compose.

Docker Compose - утилита для автоматизации запуска многоконтейнерных приложений. В нашем случае такими контейнерами будут Apache или Nginx, PHP, MySQL или MariaDB, PHPMySQLAdmin.

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

Как сделать свои docker-compose.yml и .env файлы и что они делают

docker-compose.yml - это инструкции для Docker с информацией какие контейнеры и какие их версии нам нужны для работы.

.env - это файл и с переменными, которые мы можем использовать для написания docker-compose.yml Он не обязателен, но Вы скоро поймете почему и зачем его использование будет полезно.

Давайте создадим папку для нашего проекта (например прямо на рабочем столе папку docker-experiment), а в ней создадим файл docker-compose.yml в кодировке UTF-8 и напишем в нем вот такие инструкции:

docker-compose.yml

# Версия протокола, нам достаточно указать 3.3
version: "3.3"

# Объявляем какие сервисы будем использовать (PHP, Mysql, Apache и т.д.)
services:

  # Объявляем сервис Apache
  apache:
    # Указываем название образа на https://hub.docker.com/ вот он https://hub.docker.com/_/httpd
    image: httpd:latest
    # Называем наш Apache как нам нужно
    container_name: "my_apache"
    # Подключаем папку WWW к Apache В нашей папке docker-experiment автоматически появится папка WWW
    volumes:
      - ./www:/usr/local/apache2/htdocs/
    # Настраиваем порт 80 на 80 что бы наш сайт был доступен по адресу http://localhost
    ports:
      - "80:80"

ВНИМАНИЕ не забудьте выключить Apache или любой другой веб сервер на Вашем компьютере который может занимать порт 80! А так же MySQL или любую другую БД которая может использовать порты 3306!

Теперь давайте всё это запустим, для этого запускаем терминал или командную строку Вашей ОС и переходим в нашу папку docker-experiment командой:

cd /путь/до/папки/docker-experiment/

И выполняем следующую команду:

docker-compose up -d

Вы увидите что-то похожее:

Снимок экрана

Теперь давайте добавим в HOSTS вашего компьютера localhost (если вы этого не сделали раньше), для этого сделаем следующее:

Для Windows командная строка от имени администратора:

notepad C:\Windows\System32\drivers\etc\hosts

Для MacOS:

sudo nano /private/etc/hosts

Добавим в открывшейся файл строку:

127.0.0.1 localhost

Сохраняем и открываем в любимом браузере http://localhost где увидим на странице Index of / - так Apache нам сообщает, что у нас нет файлов.

Давайте создадим файл index.html, в нем напишем всего одно слово hello и сохраним его в нашей папке docker-experiment в ней вы увидите папку www - именно туда и сохраним наш новый index.html. Обновляем страницу http://localhost и видим текст hello. Вот и всё, все работает и минимум усилий!

Это конечно же просто пример, в нем нет ни PHP ни MySQL, так что для какой либо серьезной задачи наш эксперимент не годится, но мы уже имеем примерное представление, что и как писать в docker-compose.yml

Теперь давайте рассмотрим пример вот такой популярной связки Apache2 + PHP7.1 + MySQL5.7.21 + PHPMySQLAdmin

А также для удобства работы добавим еще два контейнера это Traefik (прокси сервер с визуальным интерфейсом, который позволит нам упростить работу с портами) и Portainer (Это удобный интерфейс который даст нам возможность управлять нашими контейнерами без командной строки!).

Давайте создадим еще одну папку my-project и в ней создадим файлы docker-compose.yml и .env со следующим содержанием:

.env

# Задаем название проекта
PROJECT_NAME=my_project
# Задаем URL для нашего проекта
PROJECT_BASE_URL=my-project.local

# Задаем параметры доступа к БД, тут думаю объяснять не нужно
DB_NAME=test
DB_USER=test
DB_PASSWORD=test
DB_ROOT_PASSWORD=password
DB_HOST=mysql
DB_PORT=3306
DB_DRIVER=mysql

# Выбираем версию mysql
MYSQL_TAG=5.7.21

# Указываем версию PHP
PHP_TAG=7.1-dev-4.13.12

# Указываем нужную нам версию Apache
APACHE_TAG=2.4-4.2.6

docker-compose.yml

version: "3.3"

services:

  # Настроавиваем контейнер для PHP
  php:
    # Выбираем образ wodby/drupal-php так как в нем уже все настроено и установлены компоненты для PHP Вот документация https://github.com/wodby/drupal-php
    # Если вы будете работать не с Drupal то моищите на https://hub.docker.com/ подходящий образ для Вашей CMS.
    image: wodby/drupal-php:$PHP_TAG
    # Задаем понятное нам имя для контейнера используя переменную которую мы объявили в ранее созданном файле .env
    container_name: "${PROJECT_NAME}_php"
    # Теперь задаем настройки для самого PHP
    environment:
      PHP_SENDMAIL_PATH: /usr/sbin/sendmail -t -i -S opensmtpd:25
      DB_HOST: $DB_HOST
      DB_PORT: $DB_PORT
      DB_USER: $DB_USER
      DB_PASSWORD: $DB_PASSWORD
      DB_NAME: $DB_NAME
      DB_DRIVER: $DB_DRIVER
      PHP_FPM_USER: wodby
      PHP_FPM_GROUP: wodby
    # Даем доступ PHP к нашей папки WWW где будет размещен сайт
    volumes:
      - ./www:/var/www/html:cached

  # Настроавиваем контейнер для MySQL
  mysql:
    # здесь все так же как и в PHP, указываем нужный нам образ, задаем версию MySQL, имя для контейнера и настройки
    image: mysql:$MYSQL_TAG
    container_name: "${PROJECT_NAME}_mysql"
    environment:
      MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD
      MYSQL_PASSWORD: $DB_PASSWORD
      MYSQL_USER: $DB_USER
      MYSQL_DATABASE: $DB_NAME
    # Позволяем MySQL хранить Базу данных test в папке db которая автоматически будет создана в папке нашего проекта my-project
    volumes:
      - ./db:/var/lib/mysql

  # Настроавиваем контейнер для PHPMySQLAdmin
  pma:
    image: phpmyadmin/phpmyadmin
    container_name: "${PROJECT_NAME}_pma"
    environment:
      PMA_HOST: $DB_HOST
      PMA_USER: $DB_USER
      PMA_PASSWORD: $DB_PASSWORD
      UPLOAD_LIMIT: 1G
      PMA_PORT: $DB_PORT
    # А вот тут мы задаем поддомен для PHPMySQLAdmin в виде http://pma.my-project.local используя Traefik
    labels:
      - "traefik.http.routers.${PROJECT_NAME}_pma.rule=Host(`pma.${PROJECT_BASE_URL}`)"
    # Объясняем Docker что PHPMySQLAdmin не можетработать без MySQL
    depends_on:
      - mysql

  # Настроавиваем контейнер для Apache, здесь мы будем использовать образ wodby/apache, так как он уже настроен под Drupal. Вот документация https://github.com/wodby/apache
  apache:
    image: wodby/apache:$APACHE_TAG
    container_name: "${PROJECT_NAME}_apache"
    # Объявляем необходимость контейнера с PHP
    depends_on:
      - php
    environment:
      APACHE_LOG_LEVEL: debug
      APACHE_BACKEND_HOST: php
      APACHE_VHOST_PRESET: php
      APACHE_DOCUMENT_ROOT: /var/www/html
    # Указываем Apache что наш проект будет лежать в папке my-project/www
    volumes:
      - ./www:/var/www/html
    # Инструкция для Traefik чтобы сайт открывался по адресу http://my-project.local который мы задали в .env
    labels:
      - "traefik.http.routers.${PROJECT_NAME}_apache.rule=Host(`${PROJECT_BASE_URL}`)"

  # Настроавиваем контейнер для Portainer
  portainer:
    image: portainer/portainer
    container_name: "${PROJECT_NAME}_portainer"
    # Задаем дополнительные команды для Portainer
    command: --no-auth -H unix:///var/run/docker.sock
    # Даем Portainer доступ к Docker
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    # Инструкция для Traefik чтобы Portainer открывался по адресу http://portainer.my-project.local
    labels:
      - "traefik.http.routers.${PROJECT_NAME}_portainer.rule=Host(`portainer.${PROJECT_BASE_URL}`)"

  # Настроавиваем контейнер для Traefik
  traefik:
    image: traefik:v2.0
    container_name: "${PROJECT_NAME}_traefik"
    # Задаем дополнительные команды для Traefik
    command: --api.insecure=true --providers.docker
    # Указываем порты
    ports:
      - '80:80'
      - '8080:8080' # На этот порт будет выведен интерфейс самого Traefik и будет доступен по адресу http://my-project.local:8080
    # Даем Portainer доступ к Docker
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

Теперь добавляем следующие строчки к файлу hosts:

127.0.0.1 my-project.local
127.0.0.1 pma.my-project.local
127.0.0.1 portainer.my-project.local

Запускаем командную строку или терминал, переходим в нашу папку my-project:

cd /путь/до/папки/my-project

И запускаем наш проект командой:

docker-compose up -d

После выполнения команды Вы увидите как в папке my-project автоматически будут созданы две новые папки это www и db где будут храниться наш сайт и база данных соответственно.

Теперь нужно дать время MySQL создать БД test которую мы прописали в .env, для этого дождитесь когда в папке my-project/db появиться папка test. Это может занять от 1 до 5-6 минут.

В результате мы получаем доступ к следующим доменам:

http://my-project.local/ - сам наш проект, там будет ошибка 403, так как у нас пока нет файлов в папке my-project/www
http://pma.my-project.local/ - доступ к PHPMySQLAdmin, сразу без логинов и паролей!
http://portainer.my-project.local/ - доступ к Portainer, там Вы сможете останавливать/запускать/перезапускать/удалять контейнеры без командной строки!
http://my-project.local:8080/ - доступ к Traefik так же без командной строки.

И всё, теперь мы можем установить и настроить нашу любимую CMS, например Drupal 8, скачав официальную версию, распаковав файлы и из разархивированной папки переместить её содержимое в нашу папку my-project/www и начать установку http://my-project.local

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

В результате у нас есть сайт, все данные хранятся у нас на диске.

Закончив работу с проектом выполним в командной строке или терминале команду:

docker-compose down

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

Либо скачать нашу папку my-project на флешку или в облако и запустить docker-compose.yml на другом компьютере (не забыв добавить наши домены в hosts!) и, о чудо, одной командой docker-compose up -d мы получаем тот же результат!

Таким образом скопировав docker-compose.yml и .env в новую папку  (например: my-site), затем внеся пару правок в .env где задать нужные нам параметры, а также добавив новые домены в наш HOSTS файл, Вы легко сможете запустить другой проект (например Joomla или Wordpress) в работу!

Единственный минус в том, что одновременно таким способом может работать только один проект, чтобы запустить другой достаточно в папке активного проекта (в нашем случае my-project) выполнить из командной строки команду:

docker-compose down

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

docker-compose up -d

И всё, всего два файла! А результат просто шикарный, быстро, без лишних действий, для нас ленивых )

Как очистить компьютер от скачанных Docker’ом файлов

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

Будем работать из командной строки (можно было бы и через Portainer, но он к сожалению не может сам себя удалить).

Для этого выполняем ряд команд в терминале или командной строке (они кроссплатформенные):

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
docker rmi $(docker images -a -q)
docker volume prune
docker network prune
docker system prune

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

Вот результат очистки диска на моем Macbook Air:

До очистки:

Снимок экрана

После:

Снимок экрана

Два гигабайта для одного проекта, неплохо! Особенно если свободных всего то 6ГБ :)

В следующей статье Docker для ленивых: Локальная разработка сайтов. Часть 2, я расскажу как сделать возможным запуск сразу несколько проектов на Вашем компьютере!

Если у Вас появились вопросы, не стесняйтесь пишите мне!
Оставьте Ваш комментарий