Задать вопрос
@gvpugachev
Разработчик Delphi, Go, FrontEnd

Как написать Docker файл для связки Front+Back+DB?

Здравствуйте, есть проект состоящий из Front (JS+React) + Back (бинарник на Go + config files) + DB (PostgreSQL).

Возможно ли это всё запихнуть в контейнер и связать вместе?
Если да, то есть ли примеры Docker файла для такой связки?
Нужно ли в этот Docker файл интегрировать саму среду PostgreSQL или можно только базу данных?
Бинарник бэка запускается на определённом порту, будет ли доступ к этому бинарнику по порту из-вне? Спрашиваю потому, что если запущу несколько подобных контейнеров не будут ли они конфликтовать за порты? Или каждый образ надо кофигурировать под отдельный порт?

Благодарю.
  • Вопрос задан
  • 1841 просмотр
Подписаться 3 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
@q2digger
никого не трогаю, починяю примус
Все раскладывается по разным контейнерам.
Отдельно фронт, отдельно бэк, отдельно база, отдельно статик и т.п.
Доступы можно разрисовать как угодно, и да, судя по вашим вопросам - это для фрилансим . ру вопрос.
Ответ написан
Комментировать
И вам привет.

Docker-compose вам в помощь, для начала. Голыми командами докера оперировать достаточно муторно, да и не требуется в реальных условиях.

Возможно ли это всё запихнуть в контейнер и связать вместе?


В один контейнер все это дело запихнуть однозначно можно, но - не нужно. Как понять, из какого набора контейнеров будет состоять ваша платформа? Очень просто.

есть проект состоящий из Front (JS+React) + Back (бинарник на Go + config files) + DB (PostgreSQL)


Вот и определились. Ваше приложение - состоит из frontend, backend и database. Названия взяты исключительно ради примера, но я не думаю, что в реалиях разработки продуктовых систем - вашему тим лиду понравится название "binarnik_na_go" вместо названия "backend" на код-ревью.

Нужно ли в этот Docker файл интегрировать саму среду PostgreSQL или можно только базу данных?


В каждом контейнере - содержится только одно приложение. Каждый контейнер - выполняет только одну команду. Если говорить о вашем бинарнике на Go, то команда, которую будет выполнять контейнер с backend - будет именем бинарника. Если это контейнер с БД, то в нем будет выполнятся только одна команда - запускающая сервер PostgreSQL. Для фронта - это будет команда pm2, или другая, с помощью которой вы запускаете сервер frontend.

Бинарник бэка запускается на определённом порту, будет ли доступ к этому бинарнику по порту из-вне?


Когда вы напишите конфигурацию своих сервисов в docker-compose.yml - и сделаете docker-compose up, docker-compose создаст виртуальную сеть. Сеть будет называться в формате <наименование директории, где лежит ваш docker-compose.yml>_default. Внутри этой сети, все сервисы будут иметь доступ друг к другу по имени сервиса и порту, указанному в EXPOSE в Dockerfile сервиса. Соответственно, ваш backend будет доступен по имени backend и порту, который вы укажите при сборке образа. Например, http://backend:8080. При этом, вы не сможете обратиться к этому имени/порту за пределами виртуальной сети. Чтобы вытащить порт "наружу", потребуется настроить биндинг портов от контейнера с backend на локальный хост, делается это с помощью директивы ports в описании сервиса в файле docker-compose.yml.

Спрашиваю потому, что если запущу несколько подобных контейнеров не будут ли они конфликтовать за порты?


Внутри сети - конфликтов не будет. Т.к. запустить несколько контейнеров с одинаковым именем их сервиса - не возможно. Но, можно скалировать контейнеры - с помощью определенных команд, о которых на данном этапе говорить нет смысла. На локальный хост, соответственно, вытащить два и более сервиса на один и тот же порт не получится, по понятным причинам.

Или каждый образ надо кофигурировать под отдельный порт?


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

К практике.

Dockerfile для backend-а на Go может выглядеть так:

# Тут берем официальный образ Golang для компиляции бинарника
# В нем есть все для сборки, за редким исключением
FROM golang:stretch as builder

# Устанавливаем рабочую директорию внутри образа сборки бинарника
WORKDIR /app

# Копируем содержимое директории с вашим проектом в образ для сборки
COPY . .

# Скачиваем зависимости
RUN go get -d -v

# Собираем бинарник в директорию /app/bin
RUN GOOS=linux GOARCH=amd64 go build -i -o bin/backend main.go

# А теперь берем минимальный образ для запуска бинарника
FROM scratch

# Из образа для сборки, копируем готовый бинарник backend-а
COPY --from=builder /app/bin/backend /app/bin/backend

# Назначаем полученный бинарник точкой входа в контейнер
ENTRYPOINT ["/app/bin/backend"]


Теперь, если зайти в директорию с проектом backend и выполнить:

docker build -t backend:latest .

У вас соберется image с именем backend и тегом latest. Можно запускать, собственно.

Образ для frontend собирите своими силами, зато разберетесь. Там суть таже, первым этапом можно взять image с node-js, собрать в нем frontend, а для запуска - использовать image c pm2 - скопировав директорию с приложением из этапа сборки.

Как будет выглядеть ваш docker-compose.yml:

version: "3.7"

volumes:
  database:

services:

  # Postgres. Берем готовый официальный образ
  database:
    image: postgres:12-alpine
    # Вот собственно тут и указывается, какие порты будут видны на вашей локали
    ports:
      - 5432:5432
    # Там выше в volumes указывали набор volumes. Используем вольюм database, чтобы хранить БД
    volumes:
      - database:/var/lib/postgresql/data
    restart: always

  # Backend. Берем образ, что собрали выше
  backend:
    image: backend:latest
    # В Dockerfile мы для гибкости не указывали порт backend-a. Укажем его тут. 
    expose: 
      - 8080
    ports:
      - 8080:8080
    restart: always

  # Frontend
  frontend:
    image: frontend:latest
    expose: 
      - 80
    ports:
      - 80:80
    restart: always


Собственно и все. Остается поправить синтаксические ошибки и запустить, командой docker-compose up. Кстати, в интернетах есть очень много примеров проектов с кучами сервисов, с отдельными сетями для backend/frontend, с проксированием api через nginx/traefik и прочими фишками.

Удачи.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы