Тема: Docker для спрощення життя розробників
Є типовий веб-додаток, бек на NodeJs, фронт на ReacJs. В якості бази даних використовується MongoDB.
Треба якось налаштувати то все так, аби спростити життя розробникам.
Таке завдання в мене вперше в житті, тому це одночасно дуже цікаво, і не дуже зрозуміло.
Поки що я намагаюсь спростити життя для розробки беку.
Ідея така: робимо image з mongo, щоб не треба було встановлювати то самому, далі робимо image з потрібної нам node, аби розробникам не треба було переживати через не таку версію ноди, або ще щось.
Далі створюю volume, аби він в собі містив весь код, який може змінюватись.
Тобто, тепер розробнику не треба встановлювати ноду та налаштовувати монгодб, і завдяки тому, що додаток запускається через nodemon - будь-які зміни в файлах з кодом будуть перезапускати додаток всередині контейнера.
Але я пішов далі, бо локальну базу даних треба начиняти якоюсь інформацією, перш ніж запускати додаток, котрий буде з нею працювати.
Ідея така.
Спочатку запускаємо mongo, ми хочемо, аби зміни до цієї бази даних зберігалися між запусками, тому під'єднуємо volume до /data/db (це там файли бази даних будуть зберігатися, воно ніби у нашій файловій системі, але контейнер це все може бачити), після цього запускаємо контейнер, котрий почекає, доки база даних підніметься, для цього я нагуглив такий Dockerfile, котрий виконує такий скрипт.
FROM alpine
RUN apk add --update netcat-openbsd
COPY wait-for-mongo.sh .
RUN chmod 700 ./wait-for-mongo.sh
CMD ["/bin/sh", "./wait-for-mongo.sh"]
#!/bin/sh
: ${MONGODB_HOST:=mongo}
: ${MONGODB_PORT:=27017}
until nc -z $MONGODB_HOST $MONGODB_PORT
do
echo "Waiting for Mongo ($MONGODB_HOST:$MONGODB_PORT) to start..."
sleep 0.5
done
eval $*
Після цього, коли ми знаємо, що база даних працює, виконується етап наповнення бази даних власне даними. Я мучився з цим трішки, бо хотів використати ось такого скрипта
#!/bin/sh
: ${MONGODB_HOST:=mongo}
: ${MONGODB_PORT:=27017}
if [ $(mongo MONGODB_HOST:MONGODB_PORT --eval 'db.getMongo().getDBNames().indexOf("my-db-name")' --quiet) -lt 0 ]; then
echo "Database does not exist."
mongorestore --host MONGODB_HOST --port MONGODB_PORT --db my-db-name /data
else
echo "Database exists."
fi
Він мав би спочатку перевірити, чи база даних існує, і якщо так - тоді нічого не робимо, бо ми не хочемо перезаписувати всю базу даних кожного разу, коли перезапускаємо docker-compose, а якщо не існує - то створюємо її, і відразу наповнюємо даними.
Але як бачите, для цього нам треба
mongo
, а як його встановити на alpine - я хз, тому замість alpine для цієї задачі я використав ще один mongo контейнер, але в ньому той скрипт не виконується, матюкається на
[
.
Тому поки що я завис на цьому етапі.
Файл docker-compose виглядає так.
version: '3'
services:
mongo:
container_name: my-db
image: mongo
volumes:
- ./db/data:/data/db
logging:
driver: none
restart: always
mongo-wait:
build: ./db
environment:
- MONGODB_HOST=mongo
- MONGODB_PORT=27017
volumes:
- ./db/:/data
depends_on:
- mongo
mongo-seed:
build: ./db/seed
volumes:
- ./db/seed/my-db:/data
depends_on:
- mongo-wait
backend:
container_name: my_backend
build:
context: ./src
dockerfile: Dockerfile
ports:
- '3000:3000'
volumes:
- .:/app
depends_on:
- mongo-wait
mongo-seed:
FROM mongo
COPY ./seed-db.sh .
RUN chmod 700 seed-db.sh
ENTRYPOINT ["/bin/sh", "seed-db.sh"]
в seed-db.sh зараз є тільки рядок з mongorestore --host ..., без перевірок, чи база існує, бо якщо існує, воно просто покаже купу помилок, і не перезапише базу даних, але цей процес займає кілька секунд, тому хз, чи його так можна лишати.
my_backend:
FROM node:15
WORKDIR /app
RUN npm install
COPY . .
ENV PORT=3000
EXPOSE 3000
CMD ["npm", "start"]
Що я зробив не так, і як це все можна покращити?