Как запустить веб-приложение на Nginx в Docker 🐳👨🏽💻
Инструкция по настройке совместной работы веб-приложения и сервера Nginx в Docker-контейнере, а также о том, как создать их общий Docker-образ для использования в других контейнерах.
Nginx – это хорошо известный высокопроизводительный HTTP-сервер и обратный прокси-сервер. Nginx предоставляет балансировку нагрузки, кэширование, поддержку SSL/TLS, журналирование и ротацию логов. В статье мы будем использовать Nginx для сервера одностраничного приложения (SPA). На этом примере мы поймём, как создавать и запускать Docker-образ с веб-приложением и NGINX.
Небольшие приготовления: создаём веб-приложение
Для начала нам нужно какое-то веб-приложение, которое будет обслуживаться сервером Nginx. Вы можете использовать любой JavaScript-фреймворк, в нашем примере мы используем демо-проект Angular:
ng new angular-nginx-docker --minimal cd angular-nginx-docker ng build --prod
В результате выполнения указанных команд будет создано новое приложение Angular, находящееся в папке $PWD/dist/angular-nginx-docker. Этот каталог содержит файл index.html и несколько типичных для одностраничного приложения JavaScript и CSS файлов. Приложение, весь код и команды из этой статьи находятся в GitHub-репозитории.
Запускаем приложение на Nginx в Docker-контейнере
Nginx и Docker на удивление хорошо работают вместе. Вместо того чтобы устанавливать Nginx на нашу машину напрямую, мы будем запускать его в Docker на примере nginx:alpine.
Образ nginx:alpine очень производителен, хотя занимает лишь около 20 Мб дискового пространства. Для интерактивного запуска образа nginx: alpine в контейнере мы выполняем следующую команду:
docker run -it -p 80:80 \
-v /$PWD/dist/angular-nginx-docker://usr/share/nginx/html:ro \
nginx:alpine
Приведённая команда монтирует том в Docker-контейнер в режиме read only (устанавливается с помощью флага: ro). Том отображает наше приложение в дефолтную корневую папку веб-контента Nginx. Команда также сопоставляет порт 80 в контейнере с портом 80 в хосте, чтобы мы могли увидеть наше приложение на http://localhost. Когда клиент запрашивает содержимое приложения, мы видим в консоли логи Nginx.
Без дополнительных настроек Nginx использует дефолтные файлы конфигурации веб-сервера. Если вам интересно, вы можете использовать следующие команды для их изучения в Docker-образе:
docker run -it nginx:alpine sh cd etc/nginx/
Исходная конфигурация NGINX уже может обслуживать наше приложение. Но мы можем оптимизировать веб-сервер, создав папку .nginx и поместив в нее конфигурационный файл nginx.conf со следующим содержимым:
# Запускать в качестве менее привилегированного пользователя по соображениям безопасности..
user nginx;
# Значение auto устанавливает число максимально доступных ядер CPU,
# чтобы обеспечить лучшую производительность.
worker_processes auto;
events { worker_connections 1024; }
http {
server {
# Hide nginx version information.
server_tokens off;
listen 80;
root /usr/share/nginx/html;
include /etc/nginx/mime.types;
location / {
try_files $uri $uri/ /index.html;
}
gzip on;
gzip_vary on;
gzip_http_version 1.0;
gzip_comp_level 5;
gzip_types
application/atom+xml
application/javascript
application/json
application/rss+xml
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/svg+xml
image/x-icon
text/css
text/plain
text/x-component;
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 256;
gunzip on;
}
}
Каталог .nginx используется для организации файлов конфигурации для Nginx. По большей части файл конфигурации не требует пояснений, стоит упомянуть лишь о двух моментах:
- Инструкция
try_filesиспользуется для определения запасных маршрутов, когда у сервера запрашивается неизвестный ему файл. Конфигурационные инструкцииtry_filesобычно можно увидеть в веб-приложениях с паттерном Front Controller. - Во второй половине файла описывается
gzip-сжатие и распаковка HTTP-ответов.
Мы также можем использовать другие параметры конфигурации, которые повысят производительность, безопасность и масштабируемость Nginx. К примеру, для реальных приложений в файле nginx.conf понадобится настроить SSL-сертификат. Чтобы узнать больше о конфигурациях Nginx, ознакомьтесь с руководством для новичков в Nginx.
Чтобы Nginx мог использовать настроенный файл nginx.conf, запускаем следующую команду:
docker run -it -p 80:80 \
-v /$PWD/dist/angular-nginx-docker://usr/share/nginx/html:ro \
-v /$PWD/.nginx/nginx.conf://etc/nginx/nginx.conf:ro \
nginx:alpine
Эта команда подключает два read-only-тома к контейнеру Docker. Один том соответствует нашему приложению с контейнером, а другой – сопоставит файл nginx.conf в качестве файла конфигурации.
Как понять, что Nginx использует наш файл nginx.conf? Достаточно проверить заголовок ответа HTTP. На следующем скриншоте показано сравнение заголовков ответов при использовании конфигураций по умолчанию (слева) и пользовательской конфигурации (справа).
Когда Nginx использует кастомный файл конфигурации, HTTP-ответ скрывает номер версии Nginx и кодирует содержимое в режиме gzip.
Докеризация веб-приложения с Nginx
В предыдущем разделе мы научились работать с нашим одностраничным приложением, используя Nginx в контейнере. Мы также можем отправлять наше приложение вкупе с Nginx в виде Docker-образа в контейнеры других сред. Контейнерные приложения дают ряд преимуществ: простота обновления, локализация сбоев, простая смена технологии. Так что теперь мы создадим Docker-образ, содержащий и веб-приложение, и сервер Nginx, который при запуске Docker-образа будет его автоматически обслуживать.
Чтобы получить Docker-образ, создаём следующий Dockerfile:
# 1. Создаем приложение Angular FROM node:alpine as builder WORKDIR /app COPY package.json package-lock.json ./ ENV CI=1 RUN npm ci COPY . . RUN npm run build -- --prod --output-path=/dist # 2. Развертываем приложение Angular на NGINX FROM nginx:alpine # Заменяем дефолтную страницу nginx соответствующей веб-приложению RUN rm -rf /usr/share/nginx/html/* COPY --from=builder /dist /usr/share/nginx/html COPY ./.nginx/nginx.conf /etc/nginx/nginx.conf ENTRYPOINT ["nginx", "-g", "daemon off;"]
Этот Dockerfile включает две фазы создания Docker-образа. Сначала он стягивает образ node:alpine для создания приложения Angular, которое публикуется по выходному пути /dist. Далее он переключается на образ nginx:alpine, заменяет дефолтный корень приложения Nginx приложением Angular и копирует кастомный файл nginx.conf в систему Nginx.
В последней строке указывается точка входа образа для команды: nginx -g daemon off;. Это гарантирует, что Nginx останется «на переднем плане», так что Docker сможет правильно отслеживать процесс (в противном случае контейнер остановится сразу после запуска).
node_modules, можно добавить файл .dockerignore.С помощью описанного Dockerfile мы можем создать образ Docker и запустить его в контейнере, используя следующие команды:
docker build -t angular-nginx-docker . docker run -d -p 80:80 angular-nginx-docker
Готово! В этой статье мы продемонстрировали, как обслуживать простые веб-приложения с использованием Nginx в контейнере, кратко рассказали о файле конфигурации для Nginx, а также о том, как можно вместе упаковать в один образ и приложение сервера, и frontend-часть.
Читайте также другие наши статьи о технологии Docker:
- «Контейнер дал течь»: проверьте безопасность Docker-образа
- Понятные видеоуроки по Docker для начинающих
- 12 друзей Docker-а – опенсорсные инструменты в помощь разработке
- Как использовать docker-compose для Python и Jupyter