LINUX.ORG.RU

Docker для разработки и деплоя компилируемого приложения

 


0

3

Добрый день, прошу совета как организовать процесс разработки, некоего компилируемого приложения, например на плюсах. У приложения есть зависимости, которые нужно сохранить как для develop версии так и для production. Develop версия должна еще содержать разные утилиты, такие как valgrind, dbg и т.п

1. Создаем общий образ:

FROM ubuntu
# установка gcc как пример некой зависимости для приложения
# в реальном проекте там будут библиотеки и т.п
RUN apt install gcc

билдим его:

docker build -t common_image .

2. Дальше нам нужен develop образ:

FROM common_image
# ставим утилиты для разработки
RUN apt install valgrind

В develop версии нам надо править исходный код, для этого нужно подключать тома, тут как я понял удобно использовать будет docker-compose:

# docker-compose.develop.yml
version: "3"
services:
  develop:
    build: ./develop
    volumes:
    - ./src:/src

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

docker-compose -f docker-compose.develop.yml run -it develop bash

Попадаем в контейнер в котором можем пересобирать приложение и использовать отладочные утилиты.

3. Для релиза создаем production образ:

FROM common_image
# с хост машины копируем исходники в новый контейнер
COPY ./src ./src
# собираем приложение из исходников 
# опускам моменты с созданием WORKDIR и прочего
RUN make

так же билдим этот контейнер:

docker build -t release_image .

Отправляем его на боевой сервер (или через push/pull) и там запускам с помощью docker-compose:

version: "3"
services:
  develop:
    image: release-image
    command: ./run_app
    volumes:
	# тома для настроек
    - ./settings:/settings
    restart:
      always

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

Ответ на: комментарий от anonymous

Постарался расписать по этапам как себе представляю разделение на разработку и релиз. Решение по ссылку в любом случае не объясняет процесс разработки у себя на локальной машине.

hell_wood ()
Ответ на: комментарий от anonymous

Например, я не совсем уверен в «правильности» ш. 1 когда мы создаем образ содержащий зависимости для сборки и запуска приложения. Или более правильный был бы такой вариант:

FROM ubuntu AS base
# установка gcc как пример некой зависимости для приложения
# в реальном проекте там будут библиотеки и т.п
RUN apt install gcc

FROM base AS develop
RUN apt install valgrind

Общий docker-compose.yml:

# docker-compose.yml
version: "3.4"
services:
  project:
    build: 
      context: .

Для разработки:

# docker-compose.release.yml:
version: "3.4"
services:
  project:
    build: 
      target: base # 
    volumes:
	# тома для настроек
    - ./settings:/settings
    restart:
      always

для разработки:

# docker-compose.develop.yml
version: "3"
services:
  develop:
    target: develop
    volumes:
    - ./src:/src

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

docker-compose -f docker-compose.yml -f docker-compose.develop.yml run -it develop bash

Или на боевом сервере:

docker-compose -f docker-compose.yml -f docker-compose.release.yml up -d

hell_wood ()
Ответ на: комментарий от anonymous

Еще такой момент, что в multistage build все этапа выполняются по порядку, мы можем только обозначить на каком этапе остановиться. Нет возможности ветвления, т.е для прода сделать одни шаги для девелопа другие. Например, для прода запуск приложения под другим пользователем или еще что-то, в общем, то что под docker-compose не выполнить.

hell_wood ()
Ответ на: комментарий от dem

только зачем тянуть зависимости для девелопмента в продакнш? Всякие valgrind и прочие. https://habr.com/ru/post/414109/ тут в каментах писали, что для прода и дева разные контейнеры используются, я так понимаю это шаг в сторону: Dockerfile.prod Dockerfile.dev

2. А copmose почему тут не нужен? Удобная же вещь, чтобы тома пробросить, порты, перезапуск настроить (как я понял, с одним приложением в контейнере можем не использовать супервизор)

hell_wood ()
Ответ на: комментарий от hell_wood

Не ты докерфайлом собрал и потом у тебя только бинарь. компиз просто ну тут не нужен. Зачем тебе в проде 1 девелопмент 2-й бинарь. Ты имидж создал запулил в реджистри и на проде выкатил. Тыж не билдишь на сервере да? (или нет)

dem ()
Ответ на: комментарий от dem

Сорян, за тупость свою) но не врубаюсь на счет:

1. Если использовать multi-stage builds, то у нас сборка из Dockerfile идет последовательно, например:


FROM gcc AS builder
RUN apt install some_libs

# часть которая нужна для проды
FROM builder AS production
RUN make
# создаем другого пользоватля от которого будем запускать приложение
# копируем бинарник приложения в другое место

# запускаем
ENTRYPOINT ["./myapp"]

# часть для дева
FROM builder AS develop
RUN apt install valgrind
ENTRYPOINT ["bash"]

Если надо выполнить часть для проды, то просто выполняем

docker build -t --target production my_image . 
В этом случае часть для дева не ставится. Мы берем этот образ и выкатываем на сервер где его запускам (получается, что на прод машине мы не запускаем сборку). Вот тут я и думал использовать compose чтобы не писать в ручную для docker run всякие порты, тома и прочее (удобно же, не?)

А вот если я хочу у себя на локальной машине для дева собрать образ:

docker build -t --target develop my_image .
То вместе с завимисоти для дева (valgrind) будет выполнен шаг для проды, сборки, копирование и т.п, что вроде бы для дева то и не нужно. Поэтому и предположил заранее создавать образ, в котором были бы общие зависиомсти (часть bulder), а части production и develop вынести в отдельные Dockerfile'ы Совсем херня, да?

hell_wood ()
Ответ на: комментарий от dem

1. На прод машине вытаскиваю имидж и не делаю сборку, это да. Но сам образ мне кажется удобно запускать через docker-compose, т.к в нем тупо проще указать томы, порты и прочее, чем через консоль.

2. Такой вариант:

FROM ubuntu AS builder

# ставим основные зависимости
RUN apt install gcc -y

# "наследуемся" от образа с общими зависимостями
# и ставим пакеты для отладки
FROM builder AS develop
RUN apt install valgrind -y

# образ для проды
FROM builder AS production
RUN make


Для создания образа для проды выполняю:

docker build -t release .

для дева, где нам нужны отладочные утилиты:

docker build -t --target develop release .
Тогда сборка образа остановится на develop Так лучше?

hell_wood ()

Я слегка не понял, что за девелоп образ. Ты же вроде плюсы разрабатываешь?

При пуше сиай собирает бинарник, можно при помощи докер образа (у меня так, так как 2 разные версии гцц надо использовать) и загружает полученные артефакты в хранилище.

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

Места для хранения требуется меньше, логика прозрачней.

stave ★★★★★ ()
Ответ на: комментарий от stave

Под девелоп образом я понимаю образ со всеми зависимостями для сборки и запуска приложения плюс всякие отладочные утилиты, gdd, valgrind etc. Выше кидал ссылку на хабр, где в каментах упоминали, что нужно использовать разные контейнеры для прода и разработки.

hell_wood ()

Для того, что ты расписал - compose выглядит лишней сущностью. Если только ты не хочешь всех разрабов под одну гребёнку усадить. Но на ci оно в любом случае не пригодиться.

Что точно нужно предусмотреть - так это возможность наследования и вынесения общего функционала в базовый image. Т.е. если gcc нужен и в dev и в rel окружениях то его нужно ставить в base, на котором будут основаны dev и rel.

pon4ik ★★★★★ ()
Ответ на: комментарий от pon4ik

Почему лишней сущностью? В compose удобно записать инструкции для томов, портов, как мне кажется. Ну или рядом класть скрипт на баше, который был делал docker run с нужными параметрами?

hell_wood ()
Ответ на: комментарий от hell_wood

Потому что compose для случаев когда у тебя больше одного контейнера нужно соркестрировать. Не ну если ты используешь build-bot или классический Jenkins, то может и имеет смысл, в остальных случаях CI executor оперирует образом и сам решает куда смонтировать сборочную директорию и как прокинуть окружение.

pon4ik ★★★★★ ()
Ответ на: комментарий от hell_wood

Хотя… если задуматься, на локалхосте это может быть даже и удобно.

Лично я на локальной машине поступаю по другому - просто беру базовый CI образ под x86_64 на его основе строю image для разработки с моим окружением уже, и да, держу свой собственный шелл скрипт вне репо. Но будь годный дефолт, с возможностью подменить образ, я бы возможно им пользовался.

pon4ik ★★★★★ ()