Комментарии 82
Шёл 2019 год. PHP разработчикам рассказали про Docker… Продолжение следует )
У меня тоже один мелкий проект. Для своей полной работы требует что-то под 120Гб RAM и поднимает порядка 80+ контейнеров
Доктор, мне поможет докер?
Есть сложности, которые решаются только разного уровня костылями. Банально, сделать composer install в билд-тайме с закрытыми репозиториями, чтобы ключи в образ не попали. Multi stage билды не сразу были. Запуск процесса типа того же php-fpm от пользователя, соответствующего локальному, чтобы права и в контейнере, и на хосте были минимальные, но работали. Несколько способов обеспечить правильное и удобное заполнение статики и динамики на образах nginx и php, желательно без дублирования, каждый со своими плюсами и минусами. Да совсем банально: запустить две ветки проекта под разными доменными именами, не лазая в /etc/hosts
Кстати, какими именно костылями вы делали, чтобы ключи в образ не попали? Ведь сокет ssh-agent напрямую не прокидывается с MacOS и Linux-контейнер.
Прокидывал ssh-agent (что такое MacOS? :), передавал через ARG как сами ключи, так и ссылки на внешние самописные сервисы, недоступные снаружи, предоставляющие ключ с очень ограниченным сроком действия, много чего пробовал и всегда это был компромис за счёт безопасности — закрывали одни векторы атаки, создавая новые, которые волевым решением были признаны как маловероятные.
- Не шарить volume с хостом, а просто давать ему висеть «в воздухе» (docker-compose исправно данные на нем сохраняет, не стирает). Когда volume не берется с хост-машины, то и тормозов файловых операций между MacOS и Linux нет. Это «volumes: blah: external: false» в docker-compose.yml.
- Для редактирования файлов внутри контейнера есть вот такое расширение: code.visualstudio.com/docs/remote/containers (оно реально создает иллюзию локального редактирования; кстати, вся разработка в фейсбуке ведется похожим образом, через IDE и «толстый» серверный модуль-агент для него).
- Вот с ключами git проблема (никак ее не решить, если ключ защищен паролем), но зато данное расширение для vscode магически прокидывает токен от credential.helper, так что если клонировать git-репозиторий по https (а не по ssh), то логин-пароль приходится вводить всего один раз (а не для каждой git-операции). И в терминале vscode работают git-команды без пароля. Я сам всю жизнь хожу в git по ssh-ключам, но, похоже, https-способ и правда более современный.
Костыльно все это, конечно. А что делать.
Ну вот вроде завезли пару фич https://docs.docker.com/develop/develop-images/build_enhancements/#new-docker-build-secret-information Ещё не тестил даже локально под линуксом
На мой взгляд volume удобнее делать именованными. Например, volume для кода можно описать и использовать так:
volumes:
code:
driver: local
driver_opts:
type: 'none'
o: 'bind'
device: $PWD
services:
myservice:
container_name: mycontainer
build:
context: .
dockerfile: docker/go/Dockerfile
volumes:
- ./docker/go/path:/data/path # обычный
- code:/go/src/myproject # именованный
В таком случае легче, например, грохнуть volume при надобности не разыскивая его среди закодированных названий.
$ docker volume ls
DRIVER VOLUME NAME
local b4a3ceda689f820e5ef1add990e1853b032fe9048e1ed7668a9cf160de9cff3d
local myservice_code
Тут первая строка — обычный volume, а вторая строка — именованный volume. По названию можно легко понять, к какому проекту он относится.
Попробуйте как-нибудь, очень удобно.
А насчет docker volume prune
, он не удаляет, например, последние версии остановленных контейнеров (и это, конечно же, хорошо). Но если надо удалить и их, и вместе с волюмом, то удобнее, когда он именованный. Контейнер, кстати, тоже удобно именовать как написал выше. Тогда потом удобно, например, смотреть логи этого контейнера не разыскивая его по закодированным именам.
Теперь представим, у нас есть один проект на PHP, для его работы крутятся 3 конейтенера: nginx + php-fpm + mysql server. Из контейнера nginx проброшен 80 порт на хост машину (в конфигах nginx прописан доступ по your-domain.loc).
И вот появляется необходимость развернуть еще один проект параллельно. Как быть в этом случае?
1) Добавлять в существующие контейнеры настройки для второго проекта — протеворечить принципам изоляции сервисов, ну и, соотвественно, в случае падения одного из проектов (ошибка nginx или типа того) все проекты, которые были завязаны на этих контейнерах тоже упадут.
2) Создать +3 контйенра для второго пректа, но так, как 80 порт уже занят первым проектом, то нам необходимо будет из браузера стучаться через кастомный порт, что весьма неудобно. Та же самая проблема касается и всех остальных сервисов. С хост машины в MySQL уже придется ломиться по кастомному порту.
3) Находил еще вариант с добавлением доп. контейнера nginx, который будет выступать в качестве прокси сервера, принимащего все запросы, выявлять имя домена и направлять запросы в соотвествующие контейнеры. Но этот вариант тоже не самый удобный, и не решает проблем с остальными сервисами (php-fpm и mysql тоже придется вешать на другие порты).
Вот и сижу и думаю, как этот вопрос решается с Docker, наверняка многие должны были сталкиваться с ним.
Касаемо Mysql, исключительно для нужд приложения проброс портов на хостовую машину вообще не нужен. Я порой пробрасываю кастомные порты, чтобы соединятся с контейнером через PHPSTORM (может быть кто-то из местных подскажет функцию у шторма, чтобы без проброса коннектиться к базе в докере.) Или если использовать например phpmyadmin настроенную через прокси, то можно обойтись и без проброса.
Ну да, nginx-proxy — это и есть мой вариант №3. Он мне не понравился наличием отдельного контейнера, но, возможно, я тогда погорячился и на самом деле это не так страшно.
может быть кто-то из местных подскажет функцию у шторма, чтобы без проброса коннектиться к базе в докере
Тоже активно использую Phpstrom, на сколько мне известно, на текущий момент функции прямого подключения БД в Docker нет. Вот только недавно подвезли возможность запускать composer через Docker из шторма, не думаю, что есть вариант коннекта для БД.
Можно через SSH тунель, но экосистема Docker не рекомендует использование SSH внутри контейнеров (хоть и не запрещено).
Ну это дефолтный метод, мы можем пробросить порт на хост машину, но в случае, когда нужно поднять несколько контейнеров с MySQL, то придется пробрасывать на разные кастомные порты, а это не всегда удобно. Например, из терминала придется коннектиться по кастомному порту. Не говорю, что это прям критично, но все же...
Ну, можно же юникс-сокет пробросить, не? Как volume? И к нему подключаться уже.
может быть кто-то из местных подскажет функцию у шторма, чтобы без проброса коннектиться к базе в докере
Можно, как немного костыльный вариант, после создания контейнера выполнить
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' idOrName
и подключаться уже по этому адресу.На хостингах могут добавлять выделенные IP для отдельных доменов, на локальной машине возможно такое изобразить?
Просто-же, начали работать со вторым проектом — закрыли первый. Или умеете программировать асинхронно? :)
Во-первых, это просто неудобно — каждый раз останавливать одни контейнеры, запускать другие. Во-вторых, достаточно частый кейс, когда необходимо работать с несколькими проектами одновременно (например, переносить функционал с одного проекта на другой).
Для сравнения, при использовании Vagrant достаточно всего пару строк добавить в конфиг, дабы поднять новый хост. Да-да, я знаю разницу с Docker-ом, и понимаю, что у Vagrant есть свои недостатки, поэтому и пытаюсь найти решения как использовать Docker, но при этом решить возникающие проблемы.
Мне кажется, лучше просто развертывать проекты на отдельных тестовых серверах и оттуда переносить.
Подскажите, а как в 2019 году на практике обстоят дела с производительностью файлового доступа к подмонтированной таким образом папке? Хост-система MacOS (вероятно, это важно!), в контейнере Linux.
Я слышал, что раньше люди мучались с дев-окружением в Докере, потому что доступ к примонтированным файлам был ну ооочень медленным (например, запускать какой-нибудь build, лопатящий много файлов, внутри контейнера было весьма неприятно). А как сейчас?
Все так же хреново.
Не используйте мак для разработки.
Но если без мазохизма никак, то docker sync и dinghy
1. Docker sync создает новый свой искусственный контейнер, в котором крутится линукс, и монтирует в него нашу папку с MacOS под именем dir1.
2. Дальше он уже эту папку dir1 там, в этом контейнере, unison-синкает с другой папкой в том же (!) контейнере, dir2. Фактически, копирует пофайлово в обе стороны.
3. И, наконец, мы монтируем папку dir2 из искусственного контейнера в наш настоящий контейнер (с webpack-ами, php и т.д.). Т.к. это докер-монтирование «из линукса в линукс», то файловый доступ происходит мгновенно.
И все это с 2016-го где-то года. Какой ужас. Неудивительно, что Соломон ушел. :)
(Unison написан на Окамле в стиле «плюс-минус разница в третьей цифре версии Окамла между клиентом и сервером — смерть», а также почти что не поддерживается уже. Впрочем, для п. 1 это не важно, т.к. искусственный контейнер уже заранее подготовлен.)
docker -v
Docker version 18.09.1, build 4c52b90
MacOs 10.13.6
Пропустил момент, откуда появился идентификатор lesson1 и куда класть docker-compose.yml, чтобы docker-compose up его нашел
Ничего сложного. docker-compose.yml класть в то место, где ты его будешь запускать. Он ищет в той папке, где ты вызвал команду docker-compose up -d. Идентификатор lesson1 появился из названия папки в которой запускается проект. То есть автор запускал проект в папке lesson1.
docker-compose -f docker-compose.yml -f docker-compose.app.yml -f docker-compose.override.yml up -d
1. Почему так коротко? Это больше на новость похоже
2. Подобных статей навалом, чем Ваша статья отличается от остальных? Например, этой habr.com/ru/post/346086
У меня в закладках эта habr.com/ru/company/flant/blog/336654
А когда просят рассказать как работает, даю эту habr.com/ru/company/ruvds/blog/438796
- Есть production-образ с каким-нибудь php и веб-приложением внутри. Исходники приложения принадлежат www-data:www-data.
- Есть локальная машина для разработки с docker-compose. В docker-compose стягивается этот production-образ и в docker-compose.override.yml исходники монтируется снаружи, но принадлежат они vasya:vasya.
Вот такие советы иначе как костылями язык не поворачивается назвать toster.ru/q/542064
А по хорошему, вообще кажется не совсем верный подход монтировать образ с прода.
Должно быть локальное окружение для нужд разработчиков и отдельно сборка из исходников образа для прода.
А мне кажется неверным подход использовать разные образы. Опять увеличиваем вероятность "локально у меня всё работает". В крайнем случае дев-образ наследуем от прода, но очень аккуратно.
/bin/sh -c "envsubst < /tmp/www.conf.tpl > /tmp/www.conf"
Проблема достаточно распространённая и каждый решает на свой лад:
stackoverflow.com/questions/23544282/what-is-the-best-way-to-manage-permissions-for-docker-shared-volumes
www.inanzzz.com/index.php/post/q1rj/running-docker-container-with-a-non-root-user-and-fixing-shared-volume-permissions-with-dockerfile
denibertovic.com/posts/handling-permissions-with-docker-volumes
github.com/moby/moby/issues/2259
medium.com/@nielssj/docker-volumes-and-file-system-permissions-772c1aee23ca
Что касается composer install, то это отдельная головная боль. Для установки зависимостей приходится запускать отдельный контейнер из-под root, в который пробрасывается приватный ключ.
#!/usr/bin/env bash
source .env
IMAGE=composer
docker run --rm --interactive --tty \
--volume $PWD/app:/usr/src/app \
--workdir /usr/src/app \
--env COMPOSER_ALLOW_SUPERUSER=1 \
--entrypoint '/bin/bash' \
${IMAGE} \
-c "mkdir -p /root/.ssh && chmod 0700 /root/.ssh && \
cp /usr/src/app/deploy_key /root/.ssh/id_rsa && chmod 600 /root/.ssh/id_rsa && \
composer $@ &&
chown -R www-data:www-data vendor composer.json composer.lock"
Можно было бы пробросить SSH_AUTH_SOCK, но есть ещё Windows/Mac.
github.com/docker/for-linux/issues/388
Разработка под Docker. Локальное окружение. Часть 1