Еще один способ использования docker-compose

от автора

По следам статьи Docker + Laravel = ? хочу рассказать о довольно необычном способе использования утилиты docker-compose.

Для начала, для тех кто не знает, зачем нужен docker-compose. Это утилита, которая позволяет запускать на отдельном хосте набор связанных сервисов, запакованных в docker-контейнеры. Изначальная версия была написана на python и могла быть установлена двумя способами:

  • через пакетный менеджер операционной системы (apt install docker-compose для Ubuntu и yum install docker-compose.noarch для Centos)
  • через менеджер зависимостей python (pip install docker-compose)

Проблемой первого способа является то, что обычно в репозиториях операционной системы docker-compose старой версии. Это является проблемой, если необходимо использовать свежую версию демона docker или используются специфические для определенной версии формата файла docker-compose.yaml возможности (матрицу поддерживаемых фич по версиям формата и версиям утилиты docker-compose можно найти на официальном сайте docker).

Сейчас же разработчики docker переписали утилиту на go и предоставляют ее в виде бинарного файла, что позволяет ее устанавливать следующим способом (это текущий рекомендуемый способ):

  1. смотрим последнюю версию на https://github.com/docker/compose/releases и скачиваем ее

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

  2. устанавливаем права для запуска приложения

    $ sudo chmod +x /usr/local/bin/docker-compose

  3. дополнительно можно установить автодополнение для командных интепретаторов bash и zsh

  4. проверяем установку

    $ docker-compose --version docker-compose version 1.22.0, build 1719ceb

Я считаю, что единый бинарник это очень здорово, т.к. нам не нужно тянуть зависимости python. Да, и вообще — может у нас python окружение совсем сломано на целевой машине, которую мы хотим настроить!!!


Пример путаницы в python-окружении

Но есть еще 4-й путь, о котором я и хотел рассказать. Это возможность запускать docker-compose через docker. Действительно, есть уже собранные официальные образы на Docker Hub (https://hub.docker.com/r/docker/compose/). Зачем они могут понадобиться?

  • если мы хотим работать с несколькими версиями docker-compose одновременно (хотя обычно достаточно последней стабильной)
  • если у нас нет python или мы не хотим его использовать (например, у нас облегченный дистрибутив CoreOS Container Linux)
  • использование в CI/CD пайплайнах.

Давайте попробуем!

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

$ docker-compose up -d 

Через утилиту, запакованную в docker-контейнер:

$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v "$PWD:/rootfs/$PWD" -w="/rootfs/$PWD" docker/compose:1.13.0 up -d

Слишком многословно, да? Мозг можно сломать запоминать все эти параметры. Поэтому попробуем облегчить себе жизнь и напишем обертку (wrapper) на языке оболочки. Но сначала разберемся в передаваемых параметрах:

  • --rm — удаляет временный контейнер после остановки, т.е. мы не оставляем мусора в системе
  • -v /var/run/docker.sock:/var/run/docker.sock — без этого docker-compose не сможет соединиться с docker-демоном на хосте
  • -v "$PWD:/rootfs/$PWD" -w="/rootfs/$PWD" — позволяет пробросить текущий каталог внутрь контейнера, чтобы утилита увидела docker-compose файл

Нам еще не хватает возможности интерполяции значений в docker-compose файле. Это процесс, при котором утилита подставляет переменные окружения в YAML-файл. Например, во фрагменте

version: "2.1" services:   pg:     image: postgres:9.6     environment:       POSTGRES_USER: ${POSTGRES_DB_USER}       POSTGRES_PASSWORD: ${POSTGRES_DB_PASSWORD}

переменные POSTGRES_DB_USER и POSTGRES_DB_PASSWORD будут считаны из окружения. Это позволяет с определенной степенью удобности шаблонизировать docker-compose файлы. Т.е. нам нужно захватить окружение с хост-машины и передать внутрь контейнера.

Решим проблему написанием bash-скрипта.

#!/bin/sh # создадим временный файл с уникальным именем TMPFILE=$(mktemp) # захватим окружение и запишем в файл env > "${TMPFILE}" # сохраним версию в отдельную переменную для удобства VERSION="1.13.0" # запустим docker-compose docker run \   --rm  \   -e PWD="$PWD" \   --env-file "${TMPFILE}"  \   -v /var/run/docker.sock:/var/run/docker.sock \   -v "$PWD:/rootfs/$PWD" \   -w="/rootfs/$PWD" \   docker/compose:"${VERSION}" \   "$@"  # удаляем временный файл с захваченным списком переменных окружения rm "{$TMPFILE}"

Появились дополнительные строчки:

  • -e PWD="$PWD" — на всякий случай пробросим текущий каталог
  • --env-file "${TMPFILE}" — здесь передаются все остальные переменные окружения с хост-машины
  • docker/compose:"${VERSION}" — имя образа, версию возьмем из переменной
  • "$@" — эта конструкция позволяет использовать скрипт как будто он и есть утилита docker-compose, т.е. «прозрачно» передает свои аргументы в docker-контейнер.

Скрипт можем сохранить, например, в /usr/local/bin/docker-compose, установить на него флаг eXecute и использовать. Приведенный скрипт не претендует на 100% отсутствие ошибок или недоработок и скорее является иллюстрацией метода.

Сами мы таким способом пользуемся в CI/CD пайплайнах. Это даже до некоторой степени позволяет экономить трафик, т.к. целевой образ docker берется из локального кэша.


ссылка на оригинал статьи https://habr.com/post/425273/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *