Как добавить контейнеры на Digital Ocean registry с помощью docker-compose
Теги:
Нам понадобится создать [github-action] и иметь доступ к [digital-ocean-container-registry]. Тут есть ряд нюансов:
- на бесплатном тарифе в закрытых репозиториях нет [github-environment-variables]. Только [github-secrets]. Переменные окружения доступны только на тарифе enterprize
- на [digital-ocean-container-registry] на бесплатном тарифе помимо ограничений по объему, ограничено число контейнеров (только 1). На следующем тарифе только 5. В этом контексте пожалуй лучше использовать [github-packages], котоыре при тех же ограничениях по объему никак не лимитированы по количеству контейнров… к тому же на публичных репозиториях нет и ограничений по объему
- потребуется [digital-ocean-doctl] - вот тут надо создать персональный acces tocken для doctl на github
Нам понадобится workflow в репозитории на github, в котором мы сделаем следующее:
- установим среду
- соберем контейнеры
- соединимся с [digital-ocean-container-registry]
- отправим туда контейнеры
Руководствоваться можно вот этой статьей
Поставить doctl
можно с помощью вот такого экшена из маркетплейса github. В данном случае в зашифрованную переменную как раз и помещен ключ, созданный на DO для доступа через cli doctl
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: $
Собирать контейнеры мы будем внутри github action jobs, для этого нам потребуется сначала собрать из исходников. размещенных в репозитории. а затем отправить в registry результат сборки. Чтобы понять где окажется image после сбьорки, это нужно сообщить в docker-compose.yml
, например так (локально):
version: '3'
services:
build-1:
build:
context: ./build-1
image: user/project-1
build-2:
build:
context: ./build-2
image: user/project-2
Естественно, если контейнеры будут нелокально, то необходимо указать адреса registry в сети, в нашем случае на [digital-ocean]. Соответственно сборку мы туда отправим с помощтью docker compose push
, который обратиться к docker-compose.yml
и увидит там эти адреса. Подробнее о docker compose push
Сложностью может оказаться то, что мы можем захотеть размещать стек как локально, так и удаленно. Можно использовать переменные окружения для задания пути (смотри статью)
version: '3'
services:
myapp:
image: ${REGISTRY_HOST}/myproject/myapp:latest
build: ./services/myapp
В этом случаем ожно задать переменные и использовать [dot-env] - переменные из .env
файлов. Для [fastapi-template-deployment] это будет выглядеть так (на примере фронта) в docker-compose.yml
:
frontend:
image: '${DOCKER_IMAGE_FRONTEND?Variable not set}:${TAG-latest}'
build:
context: ./frontend
args:
FRONTEND_ENV: ${FRONTEND_ENV-production}
Тогда мы можем выполнить сначала билд, а затем пуш, с помощью скрипта, выполняющего рекурсивно другой скрипт (так реализовано у tiangolo):
#! /usr/bin/env sh
# Exit in case of error
set -e
TAG=${TAG?Variable not set} \
FRONTEND_ENV=${FRONTEND_ENV-production} \
sh ./scripts/build.sh
docker-compose -f docker-compose.yml push
#! /usr/bin/env sh
# Exit in case of error
set -e
TAG=${TAG?Variable not set} \
FRONTEND_ENV=${FRONTEND_ENV-production} \
docker-compose \
-f docker-compose.yml \
build
А остальные переменные мы пропишем через .env
в docker-compose.yml
вот так:
env_file:
- .env
Тут две пробелмы - надо либо держать зоопарк .env
для разных стадий проекта. К тому же, если мы хотим собирать контейнеры на github, то надо как-то передать эти .env
в репозиторий (а там пароли/ключи, что нежелательно). Вариант решения - задать пароли/ключи с помощью секретов на github, а остальные переменные прописать в отдельном env
, который передавать в репозиторий. Наконец, чтобы получить правильный файл переменных окружения перед сборкой и пушем, можно сам файл переменных собирать в workflow, к примеру с помощью экшена из маркетплейса гитхаб
name: Create envfile
on: [push]
jobs:
create-envfile:
runs-on: ubuntu-18.04
steps:
- name: Make envfile
uses: SpicyPizza/create-envfile@v1
with:
envkey_DEBUG: false
envkey_SOME_API_KEY: "123456abcdef"
envkey_SECRET_KEY: $
some_other_variable: foobar
directory: <directory_name>
file_name: .env
Данная конкретная реализация пока работает неправильно - ключ directory
не реализован. Если в проекте должно быть несколько энвов в разных папках, их можно создавать в руте и копироват ьв нужную папку с помощью такого вот экшена (ну или подобного).
Еще одна полезная штука - прочитать .env
и передать переменные в build шаг. В принципе это можно сделать обычным питоньим скриптом.