Предистория
Одним прекрасным днём мне понадобилось развернуть среду разработки для своего проекта. Vagrant уже порядком поднадоел и хотелось иметь единую среду разработки для всех участников проекта которая была бы идентичной production серверу. Соответственно наслушавшись информации про хипстерский docker, я решил начать с ним разбираться. Далее я постараюсь максимально подробно описать все шаги начиная от установки докера на локалке вплоть до разворачивания продуктива на KVM.
Исходный стек технологий:
— Docker
— Symfony 4
— nginx
— php-fpm
— postgresql
— elasticsearch
— rabbitmq
— jenkins
Железо:
— ноутбук под ОС Ubuntu 16.04
— продакшн сервер на
Почему кроме технологического стека я перечислил ещё и стек железа?
Если вы никогда ранее не работали с докером, то вы можете столкнуться с рядом проблем, связанных именно с железом, операционной системой вашего ноутбука или типом виртуализации на
Первый и наверно самый важный аспект при начале работы с докером — это операционная система вашего ноутбука. Проще всего работать с докером именно на linux системах. Если вы работаете на Windows или Mac то у вас 100 % будут некоторые сложности, но эти сложности не будут являться критическими и при желании «нагуглить» как это исправляется не составит никаких проблем.
Второй вопрос — это
Подитог: для самого быстрого старта на докере резоннее всего выбирать Ubuntu в качестве локальной операционки и KVM
Docker-compose для локалки
Установка
Для начала необходимо установить локально сам докер. Инструкцию по установке можно посмотреть на официальном сайте ссылка на официальную документацию для ubuntu (необходимо установить docker и docker-compose), либо запустив команду в консоли:
curl -sSl https://get.docker.com/ | sh
Эта команда установит и docker и docker-compose. После этого проверить версию докера можно командой:
docker --version
Я все это дело запускаю на докере версии 18.06.0-ce.
Установка закончена!
Осознание
Чтобы с чем-то работать более менее успешно — необходимо иметь представление как оно работает. Если вы ранее работали только с Vagrant или чем-либо похожим, то будет крайне непривычно и непонятно поначалу, но это лишь поначалу.
Я постараюсь провести аналогию к Vagrant. Сейчас многие могут сказать, что сравнивать Vagrant и Docker коренным образом не верно. Да, я с этим согласен, но я их сравнивать и не собираюсь, я лишь попытаюсь донести до новичков, работавших только с Vagrant, систему работы Docker, апеллируя тем, что знают новички.
Мое видение контейнера «на пальцах» представляется так: каждый контейнер — это крохотный изолированный мирок. Каждый контейнер можно представить как будто бы это крохотный Vagrant на котором установлен всего 1 инструмент, например nginx или php. Изначально контейнеры изолированы вообще от всего вокруг, но путём не хитрых манипуляций можно настроить все так, чтобы они общались между собой и работали совместно. Это не значит, что каждый из контейнеров — это отдельная виртуальная машина, совсем нет. Но так проще для первоначального понимания, как мне кажется.
Vagrant просто откусывает у вашего компьютера часть ресурсов, создает виртуальную машину, устанавливает на нее операционную систему, устанавливает библиотеки, устанавливает все то, что вы прописали в скрипте после vagrant up. В конечном итоге это выглядит примерно так:
Docker в свою очередь работает кардинально иначе. Он не создает виртуальных машин. Docker создает контейнеры (можете воспринимать пока что их как микро-виртуалки) со своей операционной системой Alpine и 1-3 библиотеками, которые необходимы для работы приложения, например php или nginx. При этом Docker не блокирует под себя ресурсы вашей системы, а просто использует их по мере необходимости. В конечном итоге, если проиллюстрировать, то это выглядеть будет примерно так:
Каждый из контейнеров имеет образ из которого он создаётся. Подавляющая часть образов представляет из себя расширение другого образа, например Ubuntu xenial или Alpine или Debian, на которые сверху накатываются дополнительные драйверы и другие компоненты.
Мой первый образ был для php-fpm. Мой образ расширяет официальный образ php:7.2-fpm-alpine3.6. То есть по сути он берет официальный образ и доставляет на него нужные мне компоненты, например, pdo_pgsql, imagick, zip и прочее. Таким образом можно создать образ, который нужен именно вам. Если есть желание можете пользоваться тут.
С созданием образов все довольно просто на мой взгляд, если они сделаны на базе xenial например, но доставляют немного геморроя, если они сделаны на базе Alpine. До начала работы с докером я про Alpine в принципе и не слышал, так как Vagrant у меня всегда работал под Ubuntu xenial. Alpine представляет из себя пустую Linux операционную систему, в которой по сути вообще нет ничего (крайний минимум). Поэтому поначалу работать с ней крайне не удобно, так как нет например того же apt-get install (к которому так привыкаешь), а есть только apk add и не вполне вменяемый набор пакетов. Большой плюс Alpine заключается в его весе, например, если Xenial весит (абстрактно) 500мешков, то Alpine (абстрактно) порядка 78мешков. На что же это вообще влияет? А влияет это на скорость сборки и на конечный вес всех образов, которые будут храниться у вас на сервере в конечном итоге. Допустим, у вас 5 разных контейнеров и все на базе xenial суммарный их вес будет более 2,5 гигов, а alpine — порядка 500 мешков всего лишь. Поэтому в идеале надо стремиться к тому, чтобы контейнеры были как можно более худые. (Полезная ссылка для установки пакетов в Alpine — Пакеты Alpine).
На docker hub везде пишут как запускать контейнер используя команду docker run
, и при этом почему-то не пишут как его можно запустить через docker-compose, а ведь именно через docker-compose он и будет запускаться большую часть времени, так как мало кому охота вручную запускать все контейнеры, сетки, порты открывать и прочее. Docker-compose от лица пользователя выглядит просто файл yaml с настройками. Он включает в себя описание каждого из сервисов, которые необходимо запустить. Моя сборка для локального окружения выглядит следующим образом:
version: '3.1'
services:
php-fpm:
image: otezvikentiy/php7.2-fpm:0.0.11
ports:
- '9000:9000'
volumes:
- ../:/app
working_dir: /app
container_name: 'php-fpm'
nginx:
image: nginx:1.15.0
container_name: 'nginx'
working_dir: /app
ports:
- '7777:80'
volumes:
- ../:/app
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
postgres:
image: postgres:9.6
ports:
- '5432:5432'
container_name: 'postgresql'
working_dir: /app
restart: always
environment:
POSTGRES_DB: 'db_name'
POSTGRES_USER: 'db_user'
POSTGRES_PASSWORD: 'db_pass'
volumes:
- ./data/dump:/app/dump
- ./data/postgresql:/var/lib/postgresql/data
rabbitmq:
image: rabbitmq:3.7.5-management
working_dir: /app
hostname: rabbit-mq
container_name: 'rabbit-mq'
ports:
- '15672:15672'
- '5672:5672'
environment:
RABBITMQ_DEFAULT_USER: user
RABBITMQ_DEFAULT_PASS: password
RABBITMQ_DEFAULT_VHOST: my_vhost
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:6.3.0
container_name: 'elastic-search'
environment:
- discovery.type=single-node
- "discovery.zen.ping.unicast.hosts=elasticsearch"
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- 9200:9200
- 9300:9300
working_dir: /app
volumes:
- ../:/app
- ./data/elasticsearch:/usr/share/elasticsearch/data
volumes:
elasticsearch:
postgresql:
docker-compose.yaml для SF4 представляет из себя определенный набор сервисов: nginx, php-fpm, postgresql, rabbitmq (если он вам нужен), elasticsearch (если он вам нужен). Для локального окружения этого хватит. Чтобы все это заработало — есть минимальный набор настроек, без которых ничего работать не будет. Чаще всего это image, volumes, ports, environment, working_dir и container_name. Все для запуска того или иного образа описано в его документации на hub.docker.com. Там не всегда есть описание для docker-compose, но это не значит, что оно с ним не работает. Просто необходимо перенести все входящие данные из команды docker run в docker-compose и все заработает.
Например, есть образ для RabbitMQ тут. Когда видишь ЭТО впервые — это вызывает смешанные чувства и эмоции, но не все так страшно. В Этом образе указаны тэги. Обычно тэги — представляют собой разные образы, разных версий приложения с различными расширяемыми образами. Например, тэг 3.7.7-alpine означает, что этот образ более тонкий, нежели чем, например, 3.7.7, так как он сделан на базе Alpine. Ну и так же в тэгах указываются чаще всего версии самого приложения. Я обычно выбираю наиболее свежую версию и стабильную версию самого приложения и образ alpine.
После того как вы изучили и выбрали тэг — далее зачастую вы видите что-то подобного рода:
docker run -d --hostname my-rabbit --name some-rabbit -e RABBITMQ_DEFAULT_USER=user -e RABBITMQ_DEFAULT_PASS=password rabbitmq:3-management
И первая мысль — WTF? Как перебросить это в docker-compose?
Все довольно не сложно. По факту, в этой строке указываются все те же параметры, что и в yaml файле, только сокращенные. Например, -e — это environment, в который передаются различные параметры, могут быть так же записи типа -p — это порты, которые в yaml называются ports. Соответственно, чтобы качественно использовать незнакомый образ, надо просто «загуглить» сокращения docker run команды и применять полные наименования в yaml файле.
Теперь вернемся в docker-compose.yml, который я привел в виде образца выше.
В данном примере используется мой образ для php7.2 сделанный как расширение для официального образа php7.2-fpm-alpine, но если вам не требуется такого количества дополнительных библиотек — то вы можете собрать своё расширение для официального образа и использовать его. Остальные образы для локалки у меня используются полностью оригинальные и официальные.
image — указываем какой образ скачать. Например (rabbitmq:3.7.7-management-alpine).
ports — указываем порты, которые будет использовать контейнер (см. документацию образа). Пример порт nginx это 80 по дефолту. Соответственно, если вы хотите использовать порт 80, то здесь необходимо указать 80:80 и ваш сайт будет доступен на localhost. Либо можно указать 7777:80, и тогда ваш сайт будет по url localhost:7777. Это необходимо бывает для того, чтобы несколько проектов можно было разворачивать на одном и том же хосте.
volumes — здесь указываются расшаренные директории. Например ваш проект лежит в директории ~/projects/my-sf4-app, а контейнер php настроен на работу с директорией /app (то же самое, что в варианте /var/www/my-sf4-app). Соответственно было бы удобно, чтобы контейнер имел доступ к проекту. Соответственно в volumes мы прописываем ~/projects/my-sf4-app:/app
(см. этот пример в docker-compose.yml выше (у меня это указано относительным путем ../:/app)).
Таким образом для контейнера будет расшарена папка и он сможет выполнять в ней различные действия типа php bin/console doctrine:migrations:migrate
. Так же эти директории удобно использовать для того, чтобы сохранять данные приложений. Например postgresql можно указать директорию для хранения данных БД и тогда при пересоздании контейнера не нужно будет накатывать дамп или фикстуры.
working_dir — указывается рабочая директория контейнера. В данном случае /app (или по аналогии с вагрантом /var/www/my-sf4-app).
environment — сюда передаются все переменные для контейнера. Например для rabbitmq передаются имя пользователя и пароль, для postgresql передаётся имя базы, имя пользователя, пароль.
container_name — не обязательное поле, однако я предпочитаю указывать, для удобства подсоединения к контейнерам. Если не указать, то будут присвоены имена по дефолту с хэшами.
Это основные параметры, которые необходимо указывать. Остальные могут быть по желанию для дополнительных настроек, либо по документации к контейнеру.
Теперь, чтобы все это запустить необходимо провести команду docker-compose up -d
в директории, где расположен файл docker-compose.
Как и где все это хранить для локалки?
Для локалки я использую папку docker в корне проекта.
В ней находится папка data в которой я храню всю информацию postgresql и elasticsearch, чтобы при пересоздании проекта не приходилось накатывать фикстуры с нуля. Так же есть папочка nginx в которой я храню конфиг для локального nginx контейнера. Эти папки я синхронизирую в docker-compose.yml с соответствующими файлами и папками в контейнерах. Так же на мой взгляд очень удобно писать bash скрипты для работы с докером. Например, start.sh скрипт запускает контейнеры, потом проводит composer install, чистит кэш и проводит миграции. Для коллег по проекту это так же удобно, им не приходится что-либо делать, они просто запускают скрипт и все работает.
Пример скрипта start.sh
#!/usr/bin/env bash
green=$(tput setf 2)
toend=$(tput hpa $(tput cols))$(tput cub 6)
echo -n 'Как к вам обращаться?: '
read name
echo "Привет тебе $name! Мы начинаем старт докера для проекта tutmesto.ru"
echo -n "$name, ты хочешь использовать дамп для БД? (y/n): "
read use_dump
echo 'Сейчас мы запустим сборку докера!'
docker-compose up -d || exit
echo -en 'n'
echo -n "Докер успешно собрался! ${green}${toend}[OK]"
echo -en 'n'
echo 'Теперь нам необходимо собрать композер.'
./composer-install.sh
echo -en 'n'
echo -n "Композер успешно собрался ${green}${toend}[OK]"
echo -en 'n'
echo 'Сейчас надо будет заснуть на 40 секунд, чтобы успела развернуться postgres-ка'
sleep 5
echo 'Осталось еще 35 секунд...'
sleep 5
echo 'Осталось еще 30 секунд...'
sleep 5
echo 'Осталось еще 25 секунд...'
sleep 5
echo 'Осталось еще 20 секунд...'
sleep 5
echo 'Осталось еще 15 секунд...'
sleep 5
echo 'Осталось еще 10 секунд...'
sleep 5
echo 'Осталось еще 5 секунд...'
sleep 5
echo 'Сон завершился. По идее postgres-ка уже поднялась и сейчас мы будем закачивать дамп!'
case "$use_dump" in
y|Y) ./dump.sh
echo -en 'n'
echo -n "Дамп успешно закачался! ${green}${toend}[OK]"
echo -en 'n'
;;
*) echo "$name, хорошо, обойдемся без дампа! =)"
;;
esac
echo 'Теперь нам надо провести миграции!'
./migrations-migrate.sh
echo -en 'n'
echo -n "Миграции успешно проведены! ${green}${toend}[OK]"
echo -en 'n'
echo 'Теперь почистим кэш!'
./php-fpm-command.sh rm -rf var/cache/*
./php-fpm-command.sh chmod 777 var/ -R
./cache-clear.sh
echo -en 'n'
echo -n "Кэш успешно очищен! ${green}${toend}[OK]"
echo -en 'n'
echo 'Теперь скопируем настройки для локалки!'
./env.sh
echo -en 'n'
echo -n "Настройки для локалки скопированы! ${green}${toend}[OK]"
echo -en 'n'
echo "Теперь, $name, ты можешь пользоваться локалкой! Открой в браузере localhost:7777 и наслаждайся!"
echo -en 'n'
echo "------------------------------------------------------------------------------"
echo -en 'n'
echo "ОСНОВНЫЕ КОМАНДЫ КОТОРЫЕ МОЖНО ИСПОЛЬЗОВАТЬ:"
echo "./cache-clear.sh |Очистка кэша symfony 4"
echo "./composer.sh [command(ex. install)] |Обращение к композеру"
echo "./composer-install.sh |Запуск composer install"
echo "./connect-to-php-fpm.sh |Подключение к консоли php"
echo "./console.sh [command(ex. cache:clear)] |Запуск команды php bin/console"
echo "./destroy.sh |Жесткое сворачивание локалки. Убивает все кроме образов."
echo "./dump.sh |Закачать дамп, который находится в корне (dump.sql)"
echo "./env.sh |Скопировать настройки для локалки"
echo "./migrations-migrate.sh |Провести миграции"
echo "./php-fpm-command.sh [command(ex. php -m)] |Выполнить команду в php-fpm контейнере"
echo "./start.sh |Запуск локалки (этот скрипт)"
echo "./stop.sh |Gracefull shutdown локалки"
echo -en 'n'
echo "ДЛЯ УДОБНОГО ПОЛЬЗОВАНИЯ В ДАМПЕ БЫЛИ СОЗДАНЫ СЛЕДУЮЩИЕ ПОЛЬЗОВАТЕЛИ:"
echo "client@c.cc | QWEasd123"
echo "admin@a.aa | QWEasd123"
echo "moderator@m.mm | QWEasd123"
echo -en 'n'
echo "------------------------------------------------------------------------------"
echo -en 'n'
echo -en 'n'
echo 'OtezVikentiy brain corporation!'
echo -en 'n'
echo -en 'n'
Пример скрипта php-fpm-command.sh
#!/usr/bin/env bash
cd "`dirname "$0"`" &&
docker-compose exec -T "php-fpm" sh -c "cd /app && $*"
Пример скрипта connect-to-php-fpm.sh
#!/usr/bin/env bash
docker exec -i -t --privileged php-fpm bash
Локальная среда разработки на этом заканчивается. Поздравляю, можете поделиться с коллегами готовым результатом! )
Продуктив
Подготовка
Допустим, вы уже что-то написали на локалке и хотите выложить это на production сервер или на тестовый сервер. У вас есть
Чтобы развернуть продуктив или бету — на сервере должна быть операционная система (в идеале linux) и установленный docker. Docker можно установить точно так же, как и на локалку, отличий никаких.
Docker в продуктиве немного отличается от локалки. Во-первых, вы уже не можете просто брать и указывать пароли и прочую информацию и docker-compose. Во-вторых, вы не можете использовать непосредственно docker-compose.
Docker для продуктива использует docker swarm и docker stack. Если прям на пальцах, то эта система отличается лишь другими командами и тем, что docker swarm представляет из себя распределитель нагрузок для кластера (опять же немного абстрактно, но так будет проще для понимания).
P.S.: советую потренироваться настраивать docker swarm на Vagrant (как бы ни парадоксально это звучало). Простой рецепт для тренировки — поднимаете пустой Vagrant с той же операционной системой, что и в продуктиве и настраиваете его для начала.
Чтобы настроить docker swarm — необходимо просто выполнить несколько команд:
docker swarm init --advertise-addr 192.168.***.** (ip-адрес вашего сервера)
mkdir /app (в случае если ваш докер настроен на работу с директорией app)
chown docker /app (ну или раздать права на директорию)
docker stack deploy -c docker-compose.yml my-first-sf4-docker-app
Рассмотрим теперь все это немного подробнее.
docker swarm init --advertise-addr — оно запускает непосредственно сам docker swarm и шарит ссылку, чтобы вы могли бы подцепить к этому «рою» еще какой-то другой сервер, чтобы они работали в кластере.
mkdir /app && chown .. — необходимо создать заранее все необходимые директории для работы докера, чтобы во время сборки он не жаловался бы на отсутствие директорий.
docker stack deploy -c docker-compose.yml my-first-sf4-docker-app — эта команда запускает сборку самого вашего приложения, аналог docker-compose up -d только для docker swarm.
Чтобы началась какая-либо сборка, вам необходим все тот же docker-compose.yaml, но уже немного измененный именно под продуктив/бету.
version: '3.1'
services:
php-fpm:
image: otezvikentiy/php7.2-fpm:0.0.11
ports:
- '9000:9000'
networks:
- my-test-network
depends_on:
- postgres
- rabbitmq
volumes:
- /app:/app
working_dir: /app
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]
nginx:
image: nginx:1.15.0
networks:
- my-test-network
working_dir: /app
ports:
- '80:80'
depends_on:
- php-fpm
volumes:
- /app:/app
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]
postgres:
image: postgres:9.6
ports:
- '5432:5432'
working_dir: /app
networks:
- my-test-network
secrets:
- postgres_db
- postgres_user
- postgres_pass
environment:
POSTGRES_DB_FILE: /run/secrets/postgres_db
POSTGRES_USER_FILE: /run/secrets/postgres_user
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_pass
volumes:
- ./data/dump:/app/dump
- ./data/postgresql:/var/lib/postgresql/data
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]
rabbitmq:
image: rabbitmq:3.7.5-management
networks:
- my-test-network
working_dir: /app
hostname: my-test-sf4-app-rabbit-mq
volumes:
- /app:/app
ports:
- '5672:5672'
- '15672:15672'
secrets:
- rabbitmq_default_user
- rabbitmq_default_pass
- rabbitmq_default_vhost
environment:
RABBITMQ_DEFAULT_USER_FILE: /run/secrets/rabbitmq_default_user
RABBITMQ_DEFAULT_PASS_FILE: /run/secrets/rabbitmq_default_pass
RABBITMQ_DEFAULT_VHOST_FILE: /run/secrets/rabbitmq_default_vhost
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:6.3.0
networks:
- my-test-network
depends_on:
- postgres
environment:
- discovery.type=single-node
- discovery.zen.ping.unicast.hosts=elasticsearch
- bootstrap.memory_lock=true
- ES_JAVA_OPTS=-Xms512m -Xmx512m
ports:
- 9200:9200
- 9300:9300
working_dir: /app
volumes:
- /app:/app
- ./data/elasticsearch:/usr/share/elasticsearch/data
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]
jenkins:
image: otezvikentiy/jenkins:0.0.2
networks:
- my-test-network
ports:
- '8080:8080'
- '50000:50000'
volumes:
- /app:/app
- ./data/jenkins:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]
volumes:
elasticsearch:
postgresql:
jenkins:
networks:
my-test-network:
secrets:
rabbitmq_default_user:
file: ./secrets/rabbitmq_default_user
rabbitmq_default_pass:
file: ./secrets/rabbitmq_default_pass
rabbitmq_default_vhost:
file: ./secrets/rabbitmq_default_vhost
postgres_db:
file: ./secrets/postgres_db
postgres_user:
file: ./secrets/postgres_user
postgres_pass:
file: ./secrets/postgres_pass
Как вы можете видеть — файл с настройками для продуктива немного отличается от файла для локалки. В нем добавились secrets, deploy и networks.
secrets — файлы для хранения ключей. Ключи создаются довольно просто. Вы создаете файл с названием ключа — внутрь пишете значение. После этого в docker-compose.yml вы указываете раздел secrets и в него передаете весь список файлов с ключами. Подробнее.
networks — это созадется некая внутренняя сетка, через которую общаются между собой контейнеры. На локалке — это делается автоматически, но на продуктиве — это необходимо немного сделать вручную. Плюс ко всему, можно указывать дополнительные настройки кроме дефолтных. Подробнее.
deploy — это основное отличие локалки от продуктива/беты.
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]
Минимальный набор бойца:
replicas — указываете количество реплик, которое необходимо запускать (по сути это используется в случае, если у вас кластер и вы используете распределитель нагрузок от докера). Например, у вас есть два сервера и вы их соединили через docker swarm. Указывая здесь цифру 2, например, 1 инстанс у вас будет создан на 1 сервере, а второй на втором сервере. Таким образом, нагрузка на сервера будет разделяться напополам.
restart_policy — политика автоматического «переподнятия» контейнера в случае, если он по какой-то причине упал.
placement — расположение инстанса контейнера. Например бывает случаи, когда вы хотите, чтобы все инстансы контейнера крутились именно на 1 из 5 серверов, а не распределялись между ними.
Итак, мы немного подразобрались с тем, что отличает docker-compose.yaml для локалки от версии для продуктива/беты. Теперь давайте попробуем запустить это дело.
Допустим, вы тренируетесь на Vagrant'е и в корне сервера у вас лежит уже настроенный файл для продуктива docker-compose.yml
sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get install -y language-pack-en-base
export LC_ALL=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LANG=en_US.UTF-8
curl -sSl https://get.docker.com/ | sh
sudo usermod -aG docker ubuntu
sudo apt-get install git
sudo docker swarm init --advertise-addr 192.168.128.77
sudo mkdir /app
sudo chmod 777 /app -R
docker stack deploy -c /docker-compose.yml my-app
git clone git@bitbucket.org:JohnDoe/my-app.git /app
docker stack ps my-app
docker stack ls
docker stack services my-app
P.S.: не пинайте за sudo и 777, естественно на продуктиве так делать не стоит. Это лишь для скорости обучения.
Итак, нас более всего интересуют строки связанные с докером.
Сначала мы инициализируем «рой» (docker swarm).
Потом создаем директории, необходимые для работы.
Скачиваем репу с нашим кодом на SF4 в директорию /app.
После этого идут три команды: ps, ls и services.
Каждая из них по-своему полезна. Я чаще всего использую ps, так как она отображает состояние контейнеров и часть ошибки, в случае, если таковая имеется.
Допустим, у нас поднялись контейнеры, но какой-то из них постоянно падает с ошибкой и в docker stack ps my-app вы видите кучу перезапусков. Чтобы увидеть причину падения необходимо выполнить docker container ps -a — и там будет отображаться контейнер, который постоянно падает. Их будет много инстансов одного и того же контейнера, например my-app_php-fpm.1.*какой-либо лютый hash*.
Соответственно, теперь, зная имя контейнера — выполняем docker logs my-app_php-fpm.1.*какой-либо лютый hash* и просматриваем логи. Исправляем ошибку и перезапускаем ВСЁ. Чтобы грохнуть все контейнеры можно сделать так:
docker stack rm my-app
После этого у вас будет чистый swarm без каких-либо контейнеров. Исправляете ошибку — и снова docker stack deploy -c docker-compose.yml my-app.
Автор: otezvikentiy
Добрый день пытаюсь разобраться с настройками для прода.
У меня связка nginx+php-fpm+mysql+nodejs. И у меня все контейнеры выдают ошибки кроме php. Если вводить docker compose ps -a то запущены только php и node, при этом mysql и nginx вообще не запускаются, можете что-нибудь посоветовать? у node в docker-compose.yml стоит depends_on: mysql.