Как извлечь docker-compose.yaml из образа на сервере?

В рамках Continuous Integration нам нужно уметь разворачивать не только контейнеры командой docker, но и группу контейнеров, например django + postgres + nginx.

На локальной машине это просто, команда docker-compose up -d выполнит все инструкции из файла docker-compose.yaml, но на сервере его нет.

Существует два способа доставить файл docker-compose.yaml на удаленный сервер. Мы не будем рассматривать вариант «доставить руками», ведь у нас непрерывная интеграция, а значит на каждый коммит и пуш в репозиторий на GitHub наш проект после прохождения всех тестов должен развернуться самостоятельно на сервере.

Вариант 1

Используя CI на базе GitHub Actions, мы можем воспользоваться сторонним действием, которое позволяет нам подключиться к удаленному серверу и скопировать произвольный файл из репозитория, который предварительно развернут на сервере GitHub:

      - name: copy docker-compose.yaml file to remote
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USER }}
          key: ${{ secrets.SSH_KEY }}
          passphrase: ${{ secrets.PASSPHRASE }}
          source: "./docker-compose.yaml"
          target: "./code/"

Обратите внимание, в разделе GitHub Secrets вам нужно будет указать необходимые переменные. Если вы не используете пароль на ваш SSH KEY — просто не указываете эту строчку.

Повторимся, копирует он с виртуальной машины GitHub, и для того, чтобы на ней были ваши файлы, необходимо перед этим действием выполнить команду сбора файлов:

      - name: Check out the repo
        uses: actions/checkout@v2

Вариант 2

Подключиться через SSH в GitHub Actions к серверу и достать нужный файл из образа, который мы скачаем с Docker Hub:

      - name: executing remote ssh commands to deploy
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            sudo docker pull ${{ secrets.DOCKER_USERNAME }}/yamdb:latest
            id=$(docker create ${{ secrets.DOCKER_USERNAME }}/yamdb:latest)
            sudo docker cp $id:code/docker-compose.yaml docker-compose.yaml
            sudo mkdir nginx
            sudo docker cp $id:code/nginx/Dockerfile nginx/Dockerfile
            sudo docker cp $id:code/nginx/nginx.conf nginx/nginx.conf
            sudo docker rm -v $id

Давайте разберем, что происходит. Вы подключаетесь по SSH, скачиваете ваш образ, дальше вы создаете временный контейнер из этого образа и кладете его имя в переменную id.

Следом идут обычные команды копирования из контейнера на хостовую машину. Мы берем файлы для docker-compose, в том числе настройки nginx, а затем удаляем ненужный нам контейнер. Все, заключительным действием мы на всякий случай выключим и удалим все контейнеры (если это не первый наш деплой, то действие поможет избежать конфликтов) и запустим наши контейнеры:

            docker kill $(docker ps -q)
            docker rm $(docker ps -a -q)
            sudo docker-compose up -d --force-recreate

Обратите внимание на флаг -d в последней команде — если его забыть, то логи докера никогда не закончатся и ваш CI никогда не завершится успешно.