Содержание
Docker (DKA-Develop)
Образ (image) - основа для запуска контейнеров. Образы хранятся в реестрах (registries) - публичных (типа hub.docker.com) или приватных, т. е., можно развернуть свой.
# Добавить пользователя в группу Docker, чтобы он имел там все права: sudo usermod -aG docker username newgrp docker # чтобы не перезапускать машину # Запустить контейнер с Ubuntu и зайти в его терминал docker run -it ubuntu bash # Список всех контейнеров, в т. ч. остановленных docker ps -a # Запустить остановленный контейнер docker start containername # Остановить docker stop containername # Запуск с указанием имени хоста docker run -h hostname -it ubuntu bash # Список запущенных контейнеров docker ps # Информация о контейнере docker inspect containername # Задать имя контейнера docker run --name containername -it ubuntu bash # Посмотреть изменения в контейнере docker diff containername # Журнал контейнера docker logs containername # Удалить контейнер docker rm containername # Удалить все остановленные контейнеры docker rm -v $(docker ps -aq -f status=exited) # Удалить все образы docker rmi $(docker images -q) --force # Запустить в фоне с пробросом порта хост:контейнер docker run -d -p 8000:8080 apache # Список образов docker images # Создать образ из контейнера docker commit containername username/imagename # Закачать образ в реестр-репозиторий # Тэг можно не указывать, тогда будет присвоено значение latest docker push username/imagename:tag
Dockerfile
Набор инструкций для сборки образа.
# Базовый образ FROM ubuntu # Информация о создателе MAINTAINER Username <mail@mail.com> # Команды для выполнения внутри контейнера RUN apt update && apt install cowsay -y && ln -s /usr/games/cowsay /usr/bin/cowsay # Что выполнять по умолчанию при запуске контейнера ENTRYPOINT ["cowsay"]
# Собрать образ docker build -t username/imagename . # Запустить docker run username/imagename "test" # Если бы в Dockerfile не был указан параметр ENTRYPOINT, # то запускать надо было бы так: docker run username/imagename cowsay "test"
Связь между контейнерами
Например, запускается MariaDB:
docker run --name mysqlserver -e MYSQL_ROOT_PASSWORD=123456 -d mariadb
Затем нужно запустить adminer и связать его с MariaDB. Параметр --link делает в /etc/hosts контейнера запись db, указывающую на контейнер mysqlserver.
docker run --link mysqlserver:db -p 8080:8080 adminer
Более современный вариант связи - через publish services.
docker-compose
docker-compose.yaml = docker-compose.yml
# Use root/example as user/password credentials version: '3.1' services: db: image: mariadb # build: ./db Можно указать вместо image сборку из Dockerfile в каталоге db restart: always environment: MYSQL_ROOT_PASSWORD: example adminer: image: adminer restart: always ports: - 8080:8080
# Запустить docker-compose up # Запуск в фоне docker-compose up -d # Список контейнеров, запущенных через compose docker-compose ps # Собрать, пересобрать проект docker-compose build # Удалить контейнер с БД (по имени сервиса) docker-compose rm db
Если в Windows установлен Docker toolbox, то вход в браузере через localhost не сработает, нужно заходить на IP виртуальной машины, который можно узнать, выполнив команду
docker-machine ip default
Volumes
Назначение путям внутри контейнера локальных каталогов на хосте. Удобно тем, что при остановке или уничтожении контейнера данные остаются в целости.
Есть 3 способа указания томов:
- Объявить том при запуске контейнера.
docker run -v /data ubuntu
Здесь каталог /data внутри контейнера станет томом, и всё, что пишется в /data, сохраняется на этот том. Местоположение тома можно посмотреть командой
docker inspect -f {{.Mounts}} containername
Обратное тоже верно - если что-то положить в каталог монтирования тома, это сразу будет видно в контейнере. Можно явно указать соответствие каталогов на хосте и внутри контейнера:
docker run -v /localdir:/data ubuntu
- Объявить том с помощью инструкции VOLUME в Dockerfile, например,
VOLUME /data
Сопоставление явно указанного локального каталога и каталога внутри контейнера не работает.VOLUME ./localdir:/data
- Объявить том в docker-compose.yml.
volumes: - ./localdir:/data - ./database:/var/lib/mysql
Пример (Laravel)
Необходимо 3 сервиса: PHP, MySQL и Composer.
Файл .env с переменными:
# Paths DB_PATH_HOST=./databases APP_PATH_HOST=./blog APP_PATH_CONTAINER=/var/www/html/
В данном случае в папку ./blog кладётся проект, например, клон репозитория Github.
docker-compose.yml:
version: '3' services: web: build: ./web environment: - APACHE_RUN_USER=www-data volumes: - ${APP_PATH_HOST}:${APP_PATH_CONTAINER} ports: - 8080:80 working_dir: ${APP_PATH_CONTAINER} db: image: mariadb restart: always environment: MYSQL_ROOT_PASSWORD: example volumes: - ${DB_PATH_HOST}:/var/lib/mysql adminer: image: adminer restart: always ports: # должны быть разными для хоста у разных сервисов - 6080:8080 composer: image: composer:1.6 volumes: - ${APP_PATH_HOST}:${APP_PATH_CONTAINER} working_dir: ${APP_PATH_CONTAINER} command: composer install
./web/Dockerfile
FROM php:7.2-apache RUN docker-php-ext-install pdo_mysql \ && a2enmod rewrite
# Сборка и запуск docker-compose up --build # Запустить bash в сервисе-контейнере web # Благодаря указанию working_dir, оболочка сразу попадёт в /var/www/html/ docker-compose exec web bash
Решение проблем
В Windows при запуске контейнера с Volume ругается на то, что нет прав. Для этого нужно зайти в настройки Docker Desktop и на вкладке Shared Drives поставить галки на нужных дисках.
Ситуация может осложняться тем, что у пользователя нет пароля, и в таком случае расшарить диски не получится, так как Докер не даёт нажать ОК, если нет пароля пользователя.
Решение - завести нового локального пользователя с бессрочным паролем, дать ему права локального админа, расшарить диски под его именем, а затем дать ему полные права на локальный каталог с проектами.
Get started
Get started
Docker CLI
Top 10 Docker CLI commands you can’t live without
## List Docker CLI commands docker docker container --help ## Display Docker version and info docker --version docker version docker info ## Execute Docker image docker run hello-world ## List Docker images docker image ls ## List Docker containers (running, all, all in quiet mode) docker container ls docker container ls --all docker container ls -aq # Containers docker build -t friendlyhello . # Create image using this directory's Dockerfile docker run -p 4000:80 friendlyhello # Run "friendlyname" mapping port 4000 to 80 docker run -d -p 4000:80 friendlyhello # Same thing, but in detached mode docker container ls # List all running containers docker container ls -a # List all containers, even those not running docker container stop <hash> # Gracefully stop the specified container docker container kill <hash> # Force shutdown of the specified container docker container rm <hash> # Remove specified container from this machine docker container rm $(docker container ls -a -q) # Remove all containers docker image ls -a # List all images on this machine docker image rm <image id> # Remove specified image from this machine docker image rm $(docker image ls -a -q) # Remove all images from this machine docker login # Log in this CLI session using your Docker credentials docker tag <image> username/repository:tag # Tag <image> for upload to registry docker push username/repository:tag # Upload tagged image to registry docker run username/repository:tag # Run image from a registry # Services docker stack ls # List stacks or apps docker stack deploy -c <composefile> <appname> # Run the specified Compose file docker service ls # List running services associated with an app docker service ps <service> # List tasks associated with an app docker inspect <task or container> # Inspect task or container docker container ls -q # List container IDs docker stack rm <appname> # Tear down an application docker swarm leave --force # Take down a single node swarm from the manager # Swarms docker-machine create --driver virtualbox myvm1 # Create a VM (Mac, Win7, Linux) docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1 # Win10 docker-machine env myvm1 # View basic information about your node docker-machine ssh myvm1 "docker node ls" # List the nodes in your swarm docker-machine ssh myvm1 "docker node inspect <node ID>" # Inspect a node docker-machine ssh myvm1 "docker swarm join-token -q worker" # View join token docker-machine ssh myvm1 # Open an SSH session with the VM; type "exit" to end docker node ls # View nodes in swarm (while logged on to manager) docker-machine ssh myvm2 "docker swarm leave" # Make the worker leave the swarm docker-machine ssh myvm1 "docker swarm leave -f" # Make master leave, kill swarm docker-machine ls # list VMs, asterisk shows which VM this shell is talking to docker-machine start myvm1 # Start a VM that is currently not running docker-machine env myvm1 # show environment variables and command for myvm1 eval $(docker-machine env myvm1) # Mac command to connect shell to myvm1 & "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression # Windows command to connect shell to myvm1 docker stack deploy -c <file> <app> # Deploy an app; command shell must be set to talk to manager (myvm1), uses local Compose file docker-machine scp docker-compose.yml myvm1:~ # Copy file to node's home dir (only required if you use ssh to connect to manager and deploy the app) docker-machine ssh myvm1 "docker stack deploy -c <file> <app>" # Deploy an app using ssh (you must have first copied the Compose file to myvm1) eval $(docker-machine env -u) # Disconnect shell from VMs, use native docker docker-machine stop $(docker-machine ls -q) # Stop all running VMs docker-machine rm $(docker-machine ls -q) # Delete all VMs and their disk images
Docker (udemy.com)
Докер упрощает установку и запуск программ без возни с зависимостями. Это платформа, создающая и запускающая т. н. контейнеры. Контейнер - это запущенный изолированный экземпляр приложения из заранее заготовленного образа (image).
При установке Докера ставится 2 компонента - клиент (CLI, управление) и сервер (функциональная часть). При установке Докера рекомендуется регистрация на docker.com. После установки Докера и перезагрузки нужно вбить рег. данные в запущенный Докер для доступа к Docker Cloud.
01 Dive Into Docker
# Версия: docker version # Запустить тестовый контейнер: docker run hello-world
Если образа нет в локальном кэше (image cache), он скачивается автоматически из репозитория (Docker Hub).
Программы взаимодействуют с железом через ядро (kernel) путём системных запросов (system call). Контейнер - это изолированная область для запуска процессов, использует namespacing для изолирования системных ресурсов для запуска процесса, и control groups (cgroups) для лимита выделяемой мощности. В частности, это позволяет, например, запускать программы с разными зависимостями, в то время как эти зависимости не могли бы работать одновременно в одной и той же ОС. Т. е., виртуализация приложения или сервиса внутри одной ОС.
Так как namespacing и cgroups - сугубо линуксовое явление, то, когда Докер ставится на Windows или Mac, в реальности туда ставится виртуальная машина с линуксом, через которую и работает контейнеризация.
02 Manipulating Containers with the Docker Client
# Аргументы контейнеру docker run busybox echo hi there docker run busybox ls # Список запущенных контейнеров docker ps # Список когда-либо запущенных контейнеров docker ps --all
docker run = docker create + docker start
docker create hello-world # создаёт контейнер и показывает его ID docker start -a ID # запускает конкретный контейнер с выводом результатов docker start ID # просто запускает контейнер без вывода результатов на экран. Выводится только ID запущенного контейнера. docker logs ID # посмотреть вывод уже отработавшего контейнера по команде docker start ID # (не в реальном времени, а то, что успело выполниться на момент запроса).
Запущенный однажды контейнер лежит на диске и его всегда можно вызвать по ID, но команду заменить не получится. Например, запускали
docker run busybox echo hi there # Если запустить docker start -a ID echo bye there # то ничего не получится.
# Удаление остановленных контейнеров, используемых ими сетей, кэша # (образы нужно будет скачивать заново из Docker Hub) docker system prune
docker stop ID docker kill ID # Если stop не отрабатывает за 10 сек, автоматически посылается kill.
# Запуск команд внутри контейнера docker exec -it ID <command> # Например, docker exec -it ID redis-cli # Без ключа -it (-i -t) процесс запустится, но без возможности ввода. # -i - STDIN, -t - вывод текста. Можно запустить и docker exec -i ID redis-cli # но в этом случае не будет выводиться консоль и будет показываться # только ввод пользователя, выглядит непривычно и неудобно, хотя всё работает.
# Запустить "удалённую" консоль в контейнере docker exec -it ID sh # потом можно запускать redis-cli и всё остальное за один сеанс, чтобы не вводить каждый раз docker exec -i ID redis-cli # Создать контейнер и запустить там консоль docker run -it busybox sh
Файловые системы разных контейнеров изолированы, и созданное что-либо в одном контейнере не видится из других.
03 Building Custom Images Through Docker Server
Для создания собственного образа нужно написать Dockerfile, который через клиент передаётся серверу, который на основе докерфайла создаёт образ.
Докерфайл пишется так:
- Указывается базовый образ (типа выбора ОС)
- Запускаются команды для установки доп. программ (типа скачивания инсталлятора и установки, команды относятся к базовому образу, не к Докеру)
- Указываются команды, выполняемые в момент запуска контейнера (типа запуска .exe)
Создаётся каталог, где размещается файл Dockerfile (с большой буквы, без расширения). Например:
FROM alpine RUN apk add --update redis CMD ["redis-server"]
Затем запускается
docker build .
На каждом этапе сборки создаётся промежуточный контейнер, где выполняется команда, затем контейнер стирается и выполняется следующая.
Если добавить команду на 2 этап, например,
RUN apk add --update gcc
то предыдущие команды уже не будут выполняться, потому что результат уже есть в кэше. Но если поменять порядок команд, то всё будет выполняться заново, т. к. в кэше нет таких контейнеров.
# Чтобы задать человеческое имя образу при сборке: docker build -t YourDockerID/RepoOrProjectName:Version . # Например, docker build -t username/redis:latest . # Версия latest грузится и запускается Докером по умолчанию. # Если просто написать docker build -t username/redis, # то версия latest добавится автоматически.
# Можно сделать образ руками, запустив все нужные команды в консоли, а затем "закоммитив" образ. docker run -it alpine sh apk add --update redis # Из другой консоли: docker ps # (узнать ID изменяемого контейнера) docker commit -c 'CMD ["redis-server"]' ID # Создастся образ с новым ID.
Чтобы запустить образ, можно не копировать весь ID, достаточно части, которая будет уникальной.
04 Making Real Projects with Docker
Задача: сделать образ, который при обращении браузером на порт 8080 показывает страничку. Функционал состоит из package.json
{ "dependencies": { "express": "*" }, "scripts": { "start": "node index.js" } }
и index.js
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('How are you doing'); }); app.listen(8080, () => { console.log('Listening on port 8080'); });
Dockerfile:
# FROM alpine - не сработает, т. к. там нет npm, и на втором шаге будет ошибка FROM node:alpine # это вариант (тэг) alpine установки образа node, где npm есть # RUN npm install - не сработает, т. к. внутри контейнера нет файла package.json, # поэтому сначала надо их скопировать туда COPY ./ ./ # копирование в контексте сборочного каталога. В данном случае - скопировать все файлы RUN npm install # теперь можно запускать установку CMD ["npm", "start"]
# Собрать: docker build -t username/simpleweb . # Запуск: docker run username/simpleweb
Но localhost:8080 работать не будет, т. к. нужно настроить проброс порта в контейнер.
Для этого нужно запустить контейнер так:
docker run -p 8080:8080 username/simpleweb # запросы на localhost:порт в контейнере
COPY ./ ./ бросает файлы в корень файловой системы контейнера, что нехорошо. Для решения проблемы добавляется параметр WORKDIR /usr/app и все дальнейшие команды будут выполняться в контексте указанного каталога.
Есть нюанс: если изменить что-либо в коде index.js и запустить пересборку образа, то это потянет за собой npm install заново. Решение - так как для запуска npm install нужен только package.json, то Dockerfile нужно писать так:
COPY ./package.json ./ RUN npm install COPY ./ ./
Это предоствратит постоянную инсталляцию с нуля зависимостей npm при пересборке.
05 Docker Compose with Multiple Local Containers
Задача: сделать веб-страницу со счётчиком посещений. Node отвечает за веб-часть, а Redis считает посещения. Можно засунуть Node и Redis в один контейнер, но при масштабировании (увеличении кол-ва контейнеров) получится так, что посещения будут записываться в разные экземпляры Redis. Поэтому нужно сделать два контейнера - один с Node, другой с Redis, и масштабировать только контейнеры с Node.
Так как два контейнера должны взаимодействовать между собой, нужно их соответственно настроить, т. к. изначально всё, что внутри контейнера, изолировано от внешней среды. Есть два способа - использовать Docker CLI (что очень неудобно) или docker-compose, который позволяет избежать постоянного ввода одних и тех же команд через Docker CLI и позволяет автоматизировать работу.
Docker-compose использует конфиг docker-compose.yml, куда добавляются команды Docker CLI.
version: '3' services: redis-server: image: 'redis' node-app: build . ports: - "4001:8081"
docker-compose автоматически открывает сетевой доступ между контейнерами, созданными в docker-compose.yml.
В качестве хоста в index.js нужно указывать название сервиса, указанного в docker-compose.yml, например,
host: 'redis-server', port: 6379
# Запуск: docker-compose up # = docker run myimage docker-compose up -d # (запуск в фоне) # Сборка и запуск docker-compose up --build # = docker build . + docker run myimage # Остановка (всех контейнеров) docker-compose down
Автоперезапуск контейнера при падении
Варианты перезапуска:
- no - не перезапускать (по умолчанию)
- always - всегда перезапускать
- on-failure - перезапускать в случае ошибки (код возврата не 0)
- unless-stopped - всегда перезапускать, если только это не было остановлено специально
Добавляется в docker-compose.yml в параметры конкретного сервиса.
restart: always
# Статус контейнеров docker-compose docker-compose ps
показывает статус контейнеров, перечисленных в docker-compose.yml. Если этого файла в каталоге нет, то будет ошибка, т. к. docker-compose не знает, о чём идёт речь.
06 Creating a Production-Grade Workflow
Этапы развития ПО - разработка, тестирование, продуктивное использование.
Создаётся 2 файла: Dockerfile.dev (для разработки) и просто Dockerfile (продакшн).
Вызвать Dockerfile.dev можно так:
docker build -f Dockerfile.dev .
Volume - ссылки изнутри контейнера на ресурсы вовне, например, на файлы и каталоги, чтобы не пересобирать и не перезапускать контейнер каждый раз, как требуются изменения. Например,
docker run -p 3000:3000 -v /app/node_modules -v $(pwd):/app <image_id>
$(pwd):/app - $(pwd) - present working directory в хостовой системе, привязать её к каталогу /app внутри контейнера.
-v /app/node_modules указывает, что нужно использовать этот каталог внутри контейнера и не использовать ссылку вовне (синтаксис без :). Это используется, если ресурсы имеются в контейнере и их нет на хосте, вроде исключения.
Чтобы избежать излишней сложности запуска контейнеров через docker run, можно использовать docker-compose. В docker-compose.yml нужно указать:
version: '3' services: web: build: context: . dockerfile: Dockerfile.dev ports: - "3000:3000" volumes: - /app/node_modules - .:/app
и запустить docker-compose up. Секция build содержит опции context: и dockerfile:, т. к. используется нестандартное имя докерфайла Dockerfile-dev.
После того, как создан Volume, который смотрит из контейнера на хост, возникает вопрос, нужна ли операция копирования (COPY . .) в докерфайле? Лучше её оставить, т. к. в будущем может быть принято решение не использовать docker-compose, или этот докерфайл будет использован впоследствии для создания докерфайла для продуктивного использования.
Тестирование: после
docker build -f Dockerfile.dev . # запустить docker run -it ID npm run test
Тесты в данном случае находятся в src/app.test.js, и чтобы менять их на ходу, можно создать для них Volume в docker-compose.yml, но есть другой способ - выполнить команду для запущенного контейнера:
docker exec -it ID npm run test
Можно применять это как временное решение, т. к. надо выяснять ID запущенного контейнера.
Есть ещё один способ - добавить сервис для тестирования в docker-compose.yml
services: tests: build: context: . dockerfile: Dockerfile.dev volumes: - /app/node_modules - .:/app command: ["npm", "run", "test"]
# Далее нужно пересобрать и запустить контейнеры docker-compose up --build
После этого можно менять файл тестов и видеть, как они сразу выполняются в терминале. Недостаток в том, что нельзя управлять выполнением тестов, т. к. нет меню управления.
# Вывод процесса в контейнере на стандартный вывод, т. е. экран, не помогает. docker attach -it ID
Это связано с тем, что процесс запускается отдельным потоком, а подключение через attach происходит в первичную консоль. Можно посмотреть процессы, запустив
docker exec -it ID sh # и там выполнив команду ps
Продакшен
Замена движка на nginx. Вопрос в том, что в данном случае нужно использовать ДВА исходных образа - node и nginx, который нужно добавить после сборки npm. Dockerfile:
#Build phase FROM node:alpine as builder WORKDIR '/app' COPY package.json . RUN npm install COPY . . RUN npm run build # всё барахло (результат сборки) теперь находится в /app/build # Run phase FROM nginx # копировать из builder (пред. стадии), # из каталога с барахлом в стандартный каталог nginx COPY --from=builder /app/build /usr/share/nginx/html
# Собрать образ для продакшена: docker build . # Запустить: docker run -p 8080:80 ID
07 Continuous Integration and Deployment with AWS
Теперь с задействованием Гитхаба - двух веток feature и master. Master делает pull request из feature. Код проверяется Travis CI, который при новых коммитах также делает pull request кода и запускает проверки. Сначала нужно создать открытый пустой репозиторий на Гитхабе. Затем
git init git add . git commit -m "initial commit"
Содержимое каталога скопируется.
git remote add origin <github repo link>
travis-ci.org, авторизовать Тревис на Гитхабе, указать нужный репозиторий.
Настройки тревиса буду указаны в файле .travis.yml, его нужно положить в корень каталога проекта. Схема файла - копировать запущенный докер, построить образ из Dockerfile.dev, настройки тестов, настройки выкладки кода на AWS (Amazon Web Services) и т. п.
sudo: required services: - docker before_install: - docker build -t username/docker-react (or testme or smth else) -f Dockerfile.dev . script: - docker run username/docker-react npm run test -- --coverage
– –coverage нужен, чтобы после прохождения тестов скрипт выходил, а не ждал выбора пользователя. Затем выполняем
git add . git commit -m "added travis file" git push origin master
После этого коммит проваливается в Гит и забирается Тревисом, который действует сообразно .travis.yml и выдаёт результат теста.
Далее идём в AWS и ищем там Elastic beanstalk, создать приложение, например, docker-react, создать там окружение - web server environment, платформа - docker.
Затем нужно добавить в .travis.yml
deploy: provider: elasticbeanstalk region: "us-west-2" (берётся из URL приложения на Амазоне) app: "docker-react" env: "Docker-env" bucket_name: "elasticbeanstalk-us-west-2-28354762534" bucket_path: "docker" (= app:) on: branch: master
Затем на Амазоне надо добавить IAM - ключи для доступа и права для пользователя, например, docker-react-travis-ci. Ключи надо добавить в Environment variables Тревиса, но не в .travis.yml! В .travis.yml в раздел deploy затем нужно добавить
access_key_id: $AWS_ACCESS_KEY secret_access_key: secure: "$AWS_SECRET_KEY"
git add . git commit -m "added travis deploy config" git push origin master
Чтобы пробросить порт из контейнера в случае использования elastic-beanstalk, нужно прописать в Dockerfile после FROM nginx:
EXPOSE 80
Потом опять та же мантра:
git add . git commit -m "added expose 80" git push origin master
09 Dockerizing Multiple Services
Сервис состоит из нескольких компонентов - самого приложения (подпапки client, api и worker), Postgres и Redis. Dockerfile подпапок client, api и worker:
FROM node:alpine WORKDIR '/app' COPY ./package.json ./ RUN npm install COPY . . CMD ["npm", "run", "start"]
Docker-compose.yml в корне:
version: '3' services: # просто добавляем соответствующие контейнеры последних версий postgres: image: 'postgres:latest' redis: image: 'redis:latest' api: build: dockerfile: Dockerfile # без путей context: ./api # путь здесь volumes: - /app/node_modules # не трогать эту папку внутри контейнера - ./api:/app # скопировать в /app контейнера содержимое ./server # Следующая секция - переменные (configuration variables). # Переменные задают параметры контейнера при его запуске (не при создании образа). # В примере параметры хранятся в файле ./server/keys.js, # там всякие настройки базы, адреса хостов и порты, пароли и т. п. # Есть два способа задать значение переменной: # variableName=value - жёстко задать значение # variableName - взять значение с хоста environment: - REDIS_HOST=redis # в данном случае, имя сервиса - REDIS_PORT=6379 # и т. д. client: build: dockerfile: Dockerfile context: ./client volumes: - /app/node_modules - ./client:/app worker: build: dockerfile: Dockerfile context: ./worker volumes: - /app/node_modules - ./worker:/app
Далее нужно добавить nginx как редиректор разных URL в разные сервисы. Это нужно, чтобы не плодить порты доступа в контейнеры этих сервисов. На примере nginx - настройки в файле default.conf:
- Указать upstream-сервер client:3000
- Указать upstream-сервер server:5000
- Слушать порт 80
- Если кто приходит на /, слать на client upstream
- Если кто приходит на /api, слать на server upstream
Нужно создать в проекте папку nginx, а в ней - default.conf:
upstream client { server client:3000; } upstream api { server api:5000; } server { listen 80; location / { proxy_pass http://client; } # Починить ругань на websockets, # которые обращаются на /sockjs-node location /sockjs-node { proxy_pass http://client; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; } location /api { rewrite /api/(.*) /$1 break; proxy_pass http://api; } }
Дальше нужно создать Dockerfile в папке ./nginx:
FROM nginx WORKDIR '/app' COPY ./default.conf /etc/nginx/conf.d/default.conf
Добавить в Docker-compose.yml сервис nginx:
nginx: restart: always build: dockerfile: Dockerfile context: ./nginx ports: - 3050:80