Если вы видите что-то необычное, просто сообщите мне.

Docker-compose

Создание инфраструктуры для работы приложения.

Клонируем проект:

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

git clone https://github.com/gasick/docker-compose-exempleapp --branch onlyapp

Если вы не знаете с чего начать, тогда смотрите в README проекта. Обычно в нем разрабочики указывают подготовительные шаги для того, чтобы развернуть приложени локально. Это позволит набросать какой-то простой пример Dockerfile от которого уже можно будет двигаться дальше. Ошибки при создании докер файла будет говорить, о том, что нам необхдимо добавить в докер, чтобы приложение могло запуститься.

Наша задача автоматизировать шаги развертывания приложения.

Результатом нашей работы должна получиться подобнаяструктура папок:

.
├── docker-compose.yml
├── Dockerfile
├── example.env
└── todoapp
    ├── go.mod
    ├── go.sum
    └── todo.go

Упаковываем приложение в docker контейнер

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

Dockerfile

# Указываем какой образ мы будем использовать в качестве основы проекта, и присвоем ему имя build
FROM golang:1.16 as build
# Устанавливаем необходимое по, в данном случае это только git но этот список может быть сильно больше.
RUN apt update && apt install -y git
# Указываем рабочую папку
WORKDIR /app
# Копируем в рабочую папку необходимые файлы
COPY todoapp/go.mod .
COPY todoapp/go.sum .
# Подготавливаем окружение, скачиваем необхдимые для построения зависимости.
RUN go mod download 
# Копируем проект
COPY todoapp .
# Запускаем build проекта
RUN go build -o /out/app /app

# Теперь на основе нового образа будем создавать сам рабочий контейнер.
FROM fedora
# Копируем из базового образа наше приложение для указания образа используется ключ --from=build
COPY --from=build /out/app /app
# Указываем директиву с которой будет запускаться проект
CMD ["/app"]
# Так как проект слушает порт для подключения клиентов, выставляем его.
EXPOSE 8000

Тепреь давайте прверим, что Dockerfile коректен и мы можем упаковать наше приложение:

docker build -t test .

Если билд прошел, и все шаги отработали идем дальше. Запускать проект пока не нужно, он всё равно выдаст ошибку, так как для работы необходим Postgres.

Создаем docker-compose, связываем приложение и базу данных в одну инфраструктуру.

docker-compose.yml

version: "3"

services:
  todoapp:
    build: .
    ports: 
      - 8000:8000
    env_file:
      - example.env
    depends_on:
      - postgres
    
  postgres:
    image: postgres:13-alpine
    restart: always
    env_file:
      - example.env
    volumes:
    - ./postgres/data:/var/lib/postgresql/data
    - ./postgres/dumps:/dumps

example.env

Для полноценной работы в проекте нам нужен example.env.

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

Для данного проекта файл будет являтся ключничей, из него postgres будет знать с какими данными создавать пользователь/пароль/бд, а приложение будет знать с какими параметрами подключаться к ней:

POSTGRES_DB=db
POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_HOST=postgres
POSTGRES_PORT=5432

Во время разрабтки, и работы сервера в целом, мы привыкли к тому, что все общение различных сервисов происходит через localhost. В случае с docker-compose это не работает. Для понимания того, что произойдет после поднятия docker-compose, представьте себе локальную сеть, в которй большое количество серверов. Все сервисы запущенные на одной машиние, теперь разнесены таким образом, чтобы на каждой машине в сети работал только один сервис, то есть общение может быть только исключительно через локальную сеть, в реальной сети такое общение будет происходить с помощью ip, в docker-compose мы указываем названия сервисов.

То есть во время работы приложение и бд не будут доступны через localhost, друг для друга они будут доступны только через свои имена: todoapp, postgres.

Проверяем работу

Для запуска проекта выполните:

docker-compose up 

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

curl http://localhost:8000/ -v

В ответе должна быть строка: Всё работает!

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

curl -H "Content-Type: application/json" http://localhost:8000/todos/ -d '{"name":"Wash the garbage","description":"Be especially thorough"}' -v

В ответ прилетит json с ID нашего todo

Чтобы проверить, что у нас всё работает, из текущей папки:

  1. входим в docker контейнер
docker-compose exec postgres psql -U user db
  1. Просим показать содержание таблицы todos
select *from todos;

В ответе видим таблицу с нашими вводными данными:

 id |       name       |      description       
----+------------------+------------------------
  1 | Wash the garbage | Be especially thorough
(1 row)

Docker-compose файл.

Docker-compose - инструмент для совместного запуска несколких контенеров. Основой для docker-compoes является yaml-файл с настройками. Удобство заключается в том, что единожды написанный docker-compose.yml можно легко перенести с устройства на устройство.

Установка

 sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
 sudo chmod +x /usr/local/bin/docker-compose
 sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

Третья строчка скрипта дает нам возможность использовать docker-compose от имени сисетмы, если этот команда не будет выполнена. команда docker-compose потребует указания полноценного пути расположения.

Пример написания docker-compose

Пример взят с docs.microsoft.com

version: "3.7"

services:
  app:
    image: node:12-alpine
    #build: .
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos
    networks:
      app_net:

  mysql:
    image: mysql:5.7
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment: 
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos
    networks:
      app_net:

volumes:
  todo-mysql-data:
  
networks:
  app_net:
    driver: bridge

Ключевые слова используемые в docker-compose:

Ключи Применение
build Указывает путь откуда брать Dockerfile для создания образа
args Указание аргументов билда которые требуются во время создания образа
command Переписывает CMD указанную в Dockerfile
devices Мапирование физических устройств в рабочий контейнер
depends_on Указание зависимости сервисов друг от друга. Зависимый сервис будет запускаться последний
dns Указанный в ручуню DNS сервер
entrypoint Переписывает ENTRYPOINT директиву из Dockerfile
env_file Добавление переменных с помощью файла переменных окружения
environment Явное указание переменных в контейнер
expose Выставление портов контейнера, они будут доступны только linked сервисам, могут быть указаны только внутренние порты.
image Указание образа, который будет взят для старта контейнера
links Связывание контейнеров разных сервисах
logging Настройки логирования для сервиса.
networks Сеть к которой будет присоденен сервис
ports Маирование портов из контейнера в хост систему
volumes Мапирование папок из хост системы в контенер

Docker-compose cli

Сборка контенера, имеет смысл если в yaml файле присутствует директива build. Можно использовать ключ --no-cache, в таком случае игнорируются кэшированные образы.

docker-compose build

Запуск приложения. В запуск можно добавить --build ключ, тогда docker-compose перебилдит незакешированные шаги.

docker-compose up

Docker-compose останавливает и удаляет запущенные контенеры, согласно yaml конфигурации. То есть выполянется 2 команды docker: docker stop и docker rm

docker-compose stop

Отображает запущенные контейнеры принадлежащие yaml файлу.

docker-compose  ps

ВНИМАНИЕ! Выполенение команда, в отличии от docker, должно быть с в папке с yaml файлом. Команда docker может выполнятся из любой папки.