Если проект написан целиком на JavaScript (серверная часть - на NodeJS), HTML и CSS, то нужда в разделении на исходные и выходные файлы отсутствует. Могу предположить, что все эти файлы нужно будет копировать в Docker контейнер. Но должны быть подходы и для того сценария, когда вся логика написана на TypeScript, а стили и разметка - на препроцессорах (правда, с точки зрения концепции TypeScript - тоже препроцессор, но сейчас не об этом).
Первое, чего по возможности хотелось бы избежать - это копирования всего исходного кода в контейнер. На конкретном примере: весь исходной код приложения находится в папке 00-Source
и его не хотелось бы копировать. А вот 01-DevelopmentBuild
, где находится собранный проект, копировать в контейнер необходимо. Сейчас там только точка входа серверного приложения, но в будущем там будет и папка public со стилями, скриптами и изображениями для клиентской части.
После запуска инкрементальной сборки приложения, содержимое 01-DevelopmentBuild
будет регулярно обновляться. Могу предположить, что Docker ничего об этом не узнает. А нужно, чтобы и сервер был перезапущен, и чтобы отображение в браузере перезарядилось. Я владею Gulp и Webpack, потому без Docker-a для меня было всё это легко настроить. А теперь непонятно: куда класть выходные файлы, если Docker лишь один раз копирует 01-DevelopmentBuild
в контейнер, и за какими файлами следить.
В этом вопросе я бы хотел узнать, какие подходы к решению данной проблемы существуют.
На всякий случай поясню, зачем я начал использовать Docker. Собственно затем, для чего и создавали: чтобы не настраивать каждый раз базы данных и другие сервисы на сервере, а также чтобы не зависеть от того, какое серверное программное обеспечение и каких версий установлено локально. Конкретно в данном примере у меня задача использовать базу данных MySQL без её локальной установки.
Хотелось бы также попросить не рекомендовать мне готовые базы типа Firebase или Mongoose, потому сейчас я расширяю свою навыки именно в сторону Docker.
Все вещи, упомянутые другими участниками, верны, но не дают целостного понимания, я постараюсь это исправить.
ПонятияВо-первых, начнём с определений:
Образ – это шаблон, содержащий ОС и код микросервиса с бизнес-логикой. Строится с помощью Dockerfile. Состоит из т.н слоёв, они последовательны, при этом каждая команда в Dockerfile создают новый слой.
Контейнер – это уже конкретное применение шаблона после запуска. К слову, все изменения и отличия контейнера от исходного образа являются новым слоем.
Прод среда – это окружение, где должны запускаться итоговые образы, обычно поднимаются кластеры с использованием оркестраторов вроде Docker Compose или Kubernetes.
Dev среда – это окружение на компьютере разработчика проекта.
CI & CD конвейер – это процесс и набор софта, который помогает дотащить код с компьютера разработчика в прод.
Я постарался описать всё вкратце и понятно, поэтому вероятно есть неточности; просьба к опытным коллегам – не придираться без каких-то ярых ошибок.
Во-вторых, есть несколько сценариев использования.
Сценарий 3. Выкатка кода в продЗдесь запускается весь процесс CI&CD, который в нормы выглядит примерно так:
Хорошей и полезной практикой считается создание отдельных серверных кластеров, предназначенных специально для отладки и тестирования кода в условиях, приближенных к проду. Соответственно, используется тот же CI&CD конвейер, только к образам прикрепляются другие метки, не latest
, а тестовые, и уже после полного тестирования системы, образы попадают в прод.
Но, ясное дело, что для быстрого тестирования во время разработки это всё излишне сложно и долго, а как я понял, исходный вопрос как раз об этом.
Сценарий 1. Разработка и тестированиеЗдесь всё на усмотрение разработчика / команды:
1.1. Вы можете запускать микросервис как и раньше, используя простой запуск Node.js и сопутствующих инструментов на своём ПО.
1.2. Вы можете собрать Docker образ и никуда его не отправлять, а запускать на небольшом локальном кластере – подняв у себя тот же Docker Compose или Minikube и подгрузив туда образы из своего локального Docker'a (пример для Миникуба). Это особенно актуально, если для нормального тестирования микросервиса нужны другие микросервисы (хотя в идеале всё должно покрываться юнит-тестированием) и переменные окружения, секреты, примонтированные директории и прочий функционал, который есть в проде и тоже требует быстрого локального тестирования.
Конечно, можно придумать и другие варианты, обыграв свой стэк, например, примонтировать исходный код в Докер-контейнер, организовать там hot-reload. Но способы выше будут адекватнее и проще в организации.
Иногда бывает такое, что микросервис создан с учётом запуска именно в Докере через оркестратор, ждёт секреты в файлах примонтированных по путях, которых на компьютере разработчика и нет, что затрудняет способ 1.1 с простым запуском кода. В таких случаях многие проекты организуют свою небольшую библиотеку с загрузкой конфигов и т.п, которая позволит удобно запускать код как в условиях оркестратора, так и в режиме разработчика, используя какие-то простые локальные конфиг-файлы или значения по умолчанию.
В общем, для отладки кода во время разработки вовсе не обязательно усложнять себе жизни используя CI&CD конвейер (:
Небольшой совет касательно FullStack приложений на Node.js, возможно будет полезным. Статические файлы стоит выносить в отдельный микросервис и раздавать быстрым прокси-сервером вроде NginX. Но статика генерится Node.js сервером, как быть, копировать весь проект и тащить серверный код мёртвым грузом?
Нет, для этого используются многоэтапные Docker сборки: в одном этапе и образе строится проект, а в другом, финальном образе копируется лишь NginX и статические файлы, без серверного кода. Пример можно найти здесь.
И высказывание нужда в разделении на исходные и выходные файлы отсутствует
не очень верное :)
Эти же многоэтапные сборки используются и для компиляции не интерпретируемых языков вроде Го, поэтому вероятно этот подход будет полезным и для конвертации TypeScript в JavaScript для микросервисов с серверной бизнес-логикой, чтобы не усложнять итоговые образы лишним исходным кодом.
MySQL в докере это очень правильно, для взаимодействия с исходным кодом без его копирования в контейнер просто используйте папку на сервере с общим доступом из контейнера
Я в одном из проектов использовал похожую схему, единственное - приложение полностью копируется внутрь, но в вашем случае это как раз может быть только необходимая для копирования часть приложения, остальное может использоваться через шаренную папку (уберите ненужные пакеты, естественно).
Dockerfile:
FROM python:3.7-alpine
ENV TZ=Europe/Helsinki
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apk update && apk add socat gcc musl-dev python3-dev tzdata git mariadb mariadb-client
RUN export PYTHONPATH=$PYTHONPATH:/app/ && export LIBRARY_PATH=/lib:/usr/lib
COPY ./app /app
COPY init_environment.sh /app/
RUN chmod +x /app/init_environment.sh
WORKDIR /app
ARG CACHEBUST=1
CMD /app/init_environment.sh \
&& gunicorn -b 0.0.0.0:8000 -w 4 main:app
#&& tail -f /dev/null
init_environment.sh (инициализирую MySQL там для первого запуска):
#!/bin/sh
DB_DATA_PATH="/var/lib/mysql"
DB_RUN_PATH="/run/mysqld"
DB_NAME="db"
DB_USER="db_user"
DB_PASS="some_password"
MAX_ALLOWED_PACKET="200M"
# this is to allow mysql user to create and use default /run/mysqld/mysql.sock descriptor
mkdir -p ${DB_RUN_PATH} && chmod -R 777 ${DB_RUN_PATH}
# Initializing DB
if [[ ! -d "${DB_DATA_PATH}/${DB_NAME}" ]]; then
mkdir -p ${DB_DATA_PATH}
chmod -R 777 ${DB_DATA_PATH}
mysql_install_db --user=mysql --datadir=${DB_DATA_PATH}
tfile=`mktemp`
echo "CREATE DATABASE IF NOT EXISTS ${DB_NAME};" > $tfile
echo "CREATE USER '${DB_USER}'@localhost IDENTIFIED BY '${DB_PASS}';" >> $tfile
echo "GRANT USAGE ON *.* TO '${DB_USER}'@localhost;" >> $tfile
echo "GRANT ALL privileges ON \`${DB_NAME}\`.* to '${DB_USER}'@localhost;" >> $tfile
echo "FLUSH PRIVILEGES;" >> $tfile
cat $tfile
mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 --skip-grant-tables=0 < $tfile
rm -f $tfile
fi
nohup /usr/bin/mysqld --skip-networking=0 --bind-address=127.0.0.1 --user=mysql &
# Give some time to MySQL service to be initiated
sleep 5
(перед первым запуском вам необходимо инициализировать mysql_data_volume: docker volume create mysql_data_volume) Запуск контейнера:
docker run --name your_image \
-p 5000:8000 \
-v /host_machine/folder:/app/container/folder \
-v mysql_data_volume:/var/lib/mysql \
--restart=unless-stopped your_image
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Задача, которую не выходит решить: написать на Python простейший код, который будет показывать таблицу из БД
В базе данных есть текстовый столбец, в котором хранятся ссылки и текст:
Коллеги, необходимо организовать поиск по 16 пунктам, не закидывайте камнями, я учусь как и все вы