UMGUM.COM 

Pure + Tomcat + Nginx ( Развёртывание web-сервиса "Elsevier:Pure" на Linux-сервере, в контейнере "Apache Tomcat", с фронтом на Nginx и PostgreSQL в качестве СУБД. )

14 июня 2017  (обновлено 13 марта 2018)

OS: Linux Debian 9, Linux Ubuntu 16 LTS.
Applications: Java, Tomcat, Nginx и PostgreSQL.

Задача: описание этапов развёртывания типового web-приложения ("сервлета") под управлением "Apache Tomcat", на примере запуска сервера "Elsevier:Pure".

Для справки: "Elsevier" - это издательский дом, специализирующийся на публикации научных трудов, а "Pure" представляет собой один из множества инструментов взаимодействия с инфраструктурой "Elsevier". В частности, "Pure" помогает импортировать из разных локальных источников (вроде "DSpace" или "EPrints") и упорядочить данные в удобном (CERIF-совместимом) для публикации через "Elsevier" виде - особенно полезным это может быть для продвижения сведений о проводимых в исследовательских и учебных заведениях научных работах. Интересующиеся конкретно этим продуктом могут начать читать отсюда и отсюда.

Последовательность дальнейших действий такова:

1. Устанавливаем интерпретатор языка Java.
2. Устанавливаем контейнеризатор Tomcat.
3. Устанавливаем Nginx и связываем его с Tomcat.
4. Устанавливаем СУБД PostgreSQL.
5. Развёртываем Java-сервлет web-приложения "Pure" и производим первичную настройку.


Подготовка среды исполнения Java-сервлетов.

Итак, приступим. Напоминаю, что здесь мы развёртываем информационную систему "Elsevier:Pure", а она, как и большинство продуктов корпоративного уровня, ориентирована на использование компонентов стабильных и проверенных версий - в частности, для работы требуется "Java 8" (не старее "1.8") производства "Oracle".

Следуя предписаниям, загружаем отсюда последний стабильный релиз "Java SE 8, JDK", где:

JRE (Java Runtime Environment) - это среда исполнения полностью готовых Java-приложений, предназначенная для пользователей.
JDK (Java Development Kit) - среда разработки Java-приложений - специальный пакет для разработчиков, включающий в себя документацию, различные библиотеки классов, утилиты, документацию, компилятор, а также систему исполнения JRE.

По хорошему, для работы завершённого Java-приложения достаточно JRE, но, как обычно, где-то остались хвосты из среды разработки и без JDK не обойтись.

Установка "Java JRE/JDK" элементарна и сводится к распаковке в нужное место файловой системы дистрибутивного архива:

# mkdir -p /usr/lib/jdk
# tar -xvf ./jdk-8u131-linux-x64.tar.gz -C /usr/lib/jdk

Есть смысл сразу проверить, запустится ли в нашей системе Java-интерпретатор как таковой:

# /usr/lib/jdk/jdk1.8.0_131/bin/java -version

java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

Очень поможет сделать символическую ссылку на директорию с текущей инсталляцией JDK, чтобы в дальнейшем использовать её в конфигурации приложений, использующих Java:

# ln -s /usr/lib/jdk/jdk1.8.0_131 /usr/lib/jdk/default

Регистрируем Java-приложение в системе, чтобы в дальнейшем оно вызывалось с указанием короткого имени "java":

# update-alternatives --install /usr/bin/java java /usr/lib/jdk/jdk1.8.0_131/bin/java 100
# update-alternatives --install /usr/bin/javac javac /usr/lib/jdk/jdk1.8.0_131/bin/javac 100

По мере выпуска и применения новых версий программного обеспечения в системе наверняка окажется зарегистрировано более одной версии Java. Какую-то из них желательно выбрать задействуемой по умолчанию:

# update-alternatives --config java

....
  Selection  Path                       Priority  Status
------------------------------------------------
  0   /usr/lib/jdk/jdk1.8.0_161/bin/java  100   auto mode
  1   /usr/lib/jdk/jdk-9.0.4/bin/java     100   manual mode
  2   /usr/lib/jdk/jdk1.8.0_131/bin/java  100   manual mode
* 3   /usr/lib/jdk/jdk1.8.0_161/bin/java  100   manual mode

... type selection number: 3

Аналогично для "javac" (а также для "javaws" и "jar", при необходимости):

# update-alternatives --config javac

Проверяем успешность регистрации приложения в системном окружении:

# java -version

java version "1.8.0_131"
....

Обращаю внимание, что в нашем случае основной программный сервис требует себе "Java v8", но для тестов также установлена "Java v9", которую при необходимости можно вызвать явно указав путь к её исполняемым файлам:

# /usr/lib/jdk/jdk-9.0.4/bin/java -version

java version "9.0.4"
....

Установка сервера приложений "Tomcat".

Для публикации корпоративных Java-приложений традиционно применяют web-сервер "Apache Tomcat" со встроенным контейнеризатором "Catalina". Конечно же, стабильной версии, коей на данный момент является восьмая.

Следуем в раздел загрузки на сайте разработчиков, забираем дистрибутив и устанавливаем его в рекомендуемое место файловой системы простой распаковкой архива:

# mkdir -p /opt/tomcat8
# tar -xzf apache-tomcat-8.5.15.tar.gz -C /opt/tomcat8

Очень поможет сделать символическую ссылку на директорию с текущей инсталляцией "Tomcat", чтобы в дальнейшем использовать её в конфигурации приложений, использующих таковой:

# ln -s /opt/tomcat8 /opt/tomcat-default

Я предпочитаю разделять сущности, оставляя исполняемые файлы сервера "Tomcat" и его разделяемые библиотеки в "/opt/", а web-приложения и их данные вынести в директорию динамичных данных "/var".

# mkdir -p /var/lib/tomcat
# mv /opt/tomcat8/conf /var/lib/tomcat/conf
# mv /opt/tomcat8/temp /var/lib/tomcat/temp
# mv /opt/tomcat8/webapps /var/lib/tomcat/webapps
# mv /opt/tomcat8/work /var/lib/tomcat/work

Легко и непринуждённо вынести журналы событий "Tomcat" из общей директории данных (указываемой в переменной окружения "$CATALINA_BASE") не получится - каждое Java-приложение может насоздавать кучу своих журналов, параметры которых на стороне несущего сервера не контролируются. Однако, у разработчиков "Tomcat+Java" принято складывать журналы в "$CATALINA_BASE/logs", так что можно эту директорию вынести в подобающее ей место, сделав из точки преткновения символическую ссылку:

# mv /opt/tomcat8/logs /var/log/tomcat
# ln -s /var/log/tomcat /var/lib/tomcat/logs

Вообще, возня с журналами событий "Tomcat" - особая песня, которая вынесена в отдельную публикацию.

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

# groupadd --system tomcat
# useradd --system --home-dir /opt/tomcat8 --shell /bin/false tomcat

Естественно, файловые ресурсы "Tomcat" передаём во владение его пользователю:

# chown -R tomcat:tomcat /opt/tomcat8 /var/lib/tomcat /var/log/tomcat
# chmod -R o-rwx /opt/tomcat8 /var/lib/tomcat /var/log/tomcat

Регистрация "Tomcat" в "Systemd" и запуск сервиса.

Современные Linux-ы дружно перепрыгнули с системы инициализации "System-V" на "Systemd", так что создаём файл описания параметров запуска и остановки "Tomcat" в качестве сервиса для последней:

# vi /etc/systemd/system/tomcat.service

[Unit]
Description=Tomcat
After=network.target

[Service]
Type=forking
User=tomcat
Group=tomcat

Environment=LANG=en_US.UTF-8
Environment=CATALINA_PID=/var/run/tomcat-default.pid
Environment=JAVA_HOME=/usr/lib/jdk/default
Environment=CATALINA_HOME=/opt/tomcat-default
Environment=CATALINA_BASE=/var/lib/tomcat
Environment=CATALINA_TMPDIR=/var/lib/tomcat/temp
Environment="CATALINA_OPTS="
Environment="JAVA_OPTS=-Xms12G -Xmx12G -XX:+UseConcMarkSweepGC -XX:+UseNUMA -XX:+UseCompressedOops -DpropFile=/var/lib/tomcat/conf/db.properties -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Duser.language=en -Duser.country=US"

ExecStart=/opt/tomcat-default/bin/startup.sh > ${CATALINA_BASE}/logs/console.log 2>&1
ExecStop=/opt/tomcat-default/bin/shutdown.sh

[Install]
WantedBy=multi-user.target

Указываем "Systemd" перечитать и принять новую конфигурацию, а также явно активируем и запускаем новый сервис:

# systemctl daemon-reload
# systemctl enable tomcat
# systemctl start tomcat

Сразу же можно удостоверится, прослушивает ли "Tomcat" сеть в ожидании запросов от пользователей:

# netstat -apn | grep -i java

....
tcp  0  0 127.0.0.1:8080  0.0.0.0:*  LISTEN  6189/java
....

Уже сейчас можно было бы развёртывать web-приложение под управлением "Tomcat" и обращаться к нему через через локальную сетевую петлю (в нашем случае по адресу "http://localhost:8080"). Однако я предлагаю предварительно закончить установку и базовую настройку всех программных компонентов нашего несущего сервисы сервера.

Установка фронтального web-сервера Nginx.

Как я уже упоминал выше, "Tomcat" предназначен не только для контейнеризации Java-сервлетов, но и выступает в роли web-сервера. Однако на практике для приёма и первичной обработки клиентских подключений удобнее использовать более легковесный web-сервер. Я предпочитаю "Nginx":

# aptitude install nginx-light

Конфигурация принимающего подключения пользователей web-сервера Nginx проста и сводится к описанию параметров "проксирования" всех запросов нижележащему "Tomcat":

# vi /etc/nginx/nginx.conf

....
http {
  ....
  # Велим Nginx не выдавать сведения о номере своей версии
  server_tokens off;

  # Отключаем проверку размера тела передаваемого Tomcat запроса
  client_max_body_size 0;
....

# vi /etc/nginx/sites-available/pure.example.net

# Блок перехвата обращений посредством открытого HTTP и перенаправления таковых на HTTPS
server {
  listen 80 default_server;
  server_name pure.example.net;
  access_log off;
  error_log off;
  rewrite ^(.+)$ https://pure.example.net$1 permanent;
}

# Блок описания web-сервиса приёма, терминирования SSL/TLS запросов и проксирования их нижележащему Tomcat
server {
  listen       443 ssl http2;
  server_name  pure.example.net;

  access_log  /var/log/nginx/pure.example.net_access.log;
  error_log   /var/log/nginx/pure.example.net_error.log;

  # Явно указываем обслуживать здесь только SSL/TLS подключения
  ssl on;

  # Описываем параметры установления соединений SSL/TLS
  ssl_certificate      /etc/nginx/ssl/example.net.crt;
  ssl_certificate_key  /etc/nginx/ssl/example.net.key.decrypt;
  ssl_protocols  SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers    HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers  on;

  # Перенаправление на страницу "по умолчанию", при запросе корня web-ресурса (особенность реализации "Elsevier:Pure")
  location = / {
    rewrite ^ $scheme://$host/admin/ last;
  }

  # Отправляем все запросы на обработку в Tomcat
  location / {
    proxy_pass http://localhost:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_connect_timeout  240;
    proxy_send_timeout     240;
    proxy_read_timeout     240;
  }
}

Активируем для "Nginx" новую конфигурацию, проверяем её и запускаем в работу:

# rm /etc/nginx/sites-enabled/default
# ln -s /etc/nginx/sites-available/pure.example.net /etc/nginx/sites-enabled/pure.example.net
# nginx -t
# /etc/init.d/nginx reload

Адаптация "Tomcat" для работы в спарке с "Nginx".

С учётом того, что запросы пользователей будут приниматься web-сервером "Nginx", а обрабатываться скрытым за ним "Tomcat", потребуется согласовать адреса FQDN и номера сетевых портов терминирования, которые должны сохранятся неизменными на протяжении всей цепочки обработки запроса, при передачи от сервера к серверу.

В самом простом случае достаточно уведомить наш web-сервис "Tomcat" о параметрах терминирования клиентских запросов вышестоящим проксирующим web-сервисом, чтобы в ответах таковому вместо внутренних имени сайта "localhost", порта "8080" и протокола "http" было указано то, что видится клиентам снаружи. Для этого достаточно модифицировать всего одну секцию в XML-файле конфигурации "Tomcat":

# vi /var/lib/tomcat/conf/server.xml

....
<Connector port="8080" protocol="HTTP/1.1"
  address="127.0.0.1"
  connectionTimeout="20000"
  URIEncoding="UTF-8"
  ....

  # Невостребованный в нашей схеме обслуживания SSL/TLS вышестоящим Nginx параметр редиректа для обслуживания HTTPS-запросов
  # redirectPort="8443"

  # Дополнительный набор параметров описания точки терминирования клиентских запросов вышестоящим проксирующим web-сервисом
  proxyName="pure.example.net" proxyPort="443" scheme="https"
/>

В конфигурационном файле "Tomcat" есть секция описания поддержки соединений по специальном протоколу согласования (AJP) с вышестоящим web-сервером "Apache". Мы выбрали для этой роли "Nginx", так что прослушивание ненужного в схеме порта останавливаем:

# vi /var/lib/tomcat/conf/server.xml

....
  <!--
  <Connector port="8009" protocol="AJP/1.3"
    address="127.0.0.1"
    ....
  />
  -->
....

На этом с настройкой web-сервисов заканчиваем и переходим к хранилищу данных.

Установка и базовая настройка "PostgreSQL".

"Elsevier:Pure" может работать с СУБД "MS SQL", "Oracle" и "PostgreSQL". Последний мне нравится больше всего:

# aptitude install postgresql postgresql-client

Разработчики "PostgreSQL" сделали её такой, что она запускается сразу и везде, не требуя вообще никаких настроек для начала работы. Если заранее известных особых требований к производительности в связке с обслуживаемым проектом нет, то СУБД можно просто начать использовать, разве что предварительно убедившись, что разрешено подключение обычных пользователей с указанием пароля (шифрованного в MD5):

# cat /etc/postgresql/9.5/main/pg_hba.conf

....
# TYPE  DATABASE  USER  ADDRESS       METHOD
....
# IPv4 local connections:
host    all       all   127.0.0.1/32  md5
....

Перезапускаем (при необходимости) СУБД:

# /etc/init.d/postgresql restart

Простейшим образом проверяем, запущен ли "PostgreSQL":

# ps wax --forest | grep -i postgres

3664 ? S  0:00 /usr/lib/postgresql/9.5/bin/postgres -D /var/lib/postgresql/9.5/main -c config_file=/etc/postgresql/9.5/main/postgresql.conf
....

Естественно, для хранения данных проекта необходимо создать внутри БД соответствующие структуры. Воспользуемся утилитой CLI для этого:

# su - postgres
postgres@pure:~$ psql

postgres=# DROP DATABASE IF EXISTS pure;
postgres=#
postgres=# CREATE USER pure WITH PASSWORD '<userPassword>';
postgres=#
postgres=# CREATE DATABASE pure;
postgres=#
postgres=# GRANT ALL PRIVILEGES ON DATABASE pure TO pure;
postgres=# \q

Проверяем соединение с СУБД и возможность доступа к ресурсам БД:

# psql -h localhost -U pure -W pure

SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
pure=> \q

Программный продукт "Elsevier:Pure" большой и требовательный к ресурсам несущего сервера, так что вероятнее всего он будет запущен там в одиночку. В таких условиях параметры подключения к СУБД проще задать в глобальном контексте, для всего контейнера "Tomcat":

# vi /var/lib/tomcat/conf/db.properties

db.user=pure
db.password=<userPassword>
db.url=jdbc:postgresql://localhost:5432/pure

Запуск web-сайта "Elsevier:Pure".

Инсталляция (и обновление) "Pure" сводится к зачистке от всего содержимого директории обслуживаемых "Tomcat" контейнеров "/var/lib/tomcat/webapps/" и укладки туда содержимого предоставленного разработчиками архива:

# mv /var/lib/tomcat/webapps /var/lib/tomcat/webapps.backup
# tar -xzf cust-XXX-distribution.tar.gz -C /var/lib/tomcat/webapps

Для работы "сервлетов" требуется наличие следующих директорий и файлов:

# mkdir -p /var/lib/tomcat/webapps/pure-data/perm/
# mkdir -p /var/lib/tomcat/webapps/pure-data/search_index/
# mkdir -p /var/lib/tomcat/webapps/pure-data/maintenance.html

Разумеется, после создания или обновления файловой структуры проекта следует явно перевести всё её содержимое во владение пользователю, от имени которого запускается сервис, с ними работающий:

# chown -R tomcat:tomcat /var/lib/tomcat/webapps
# chmod -R ug+rw /var/lib/tomcat/webapps

В общем, на этом конфигурирование несущих сервисов завершена - можно обращаться к web-сайту (в нашем случае по адресу "https://pure.example.net/") и в дальнейшем работать уже с его внутренними настройками.

На этапе начального конфигурирования web-сайта "Elsevier:Pure" потребуется внести следующие сведения:

mail host: mx.example.net
index folder: /var/lib/tomcat/webapps/pure-data/search_index/
binary storage folder: /var/lib/tomcat/webapps/pure-data/perm/
default URL: https://pure.example.net/
server data dir: /var/lib/tomcat/webapps/pure-data/
maintenance file: /var/lib/tomcat/webapps/pure-data/maintenance.html

При первом запуске (после инсталляции или обновления ПО web-сайта) потребуется пройти по адресу "https://pure.example.net/admin/prestartup/maintenance.xhtml" и ввести специальный пароль, подтверждающий полномочия суперпользователя. Этот пароль одноразовый, генерируется автоматически и показывается в "консольном" выводе "Tomcat":

# tail -100 /var/lib/tomcat/logs/console.log

....
[INFO] -----------------------------------------------------------------
[INFO] | Entering maintenance mode!                                    |
[INFO] | Go to http://<your server>/admin/prestartup/maintenance.xhtml |
[INFO] | Password: 8b17ecf2-090f-413b-af65-53a96fb26b82                |
[INFO] -----------------------------------------------------------------
....

Логин и пароль "по умолчанию" для первоначального доступа к web-интерфейсу сайта: "root/password".

Резервное копирование и восстановление данных "Elsevier:Pure".

Учитывая то, что на этапе внедрения наверняка потребуется неоднократно делать срезы данных проекта и восстанавливать их состояние на определённый момент, нелишним будет зафиксировать здесь места хранения данных и способы работы с ними.

Приложение "Elsevier:Pure" хранит свои данные в двух местах: "базе данных" SQL и непосредственно в файловой системе в директории "./webapps/pure_data" проекта.

Резервная копия всех БД сервера "PostgreSQL" создаётся соответствующей утилитой (практически путём полного пофайлового копирования):

# mkdir -p /var/lib/postgresql/.backup
# sudo -u postgres pg_basebackup -X fetch -D /var/lib/postgresql/.backup

Важно не забывать, что "PostgreSQL" требует высокого уровня безопасности для своих файлов БД и не запустится, если права доступа к таковым не задавать строго:

# chown -R postgres:postgres /var/lib/postgresql/9.5/main
# chmod -R go-rwx /var/lib/postgresql/9.5/main

Применение резервной копии БД проекта производится по следующему регламенту:

1. Останавливаем СУБД.
2. Подменяем всё содержимое директории "/var/lib/postgresql/9.5/main" файлами из архива.
3. Явно передаём файлы СУБД во владение пользователя, от имени которого таковая запускается.
4. Запускаем СУБД.

В процессе запуска "PostgreSQL" проверит наличие файлов журнала несохранённых транзакций (WAL) и самостоятельно внесёт данные оттуда в БД как таковую. Разумеется, предварительно нужно будет включить поддержку режима журналирования транзакций WAL.

Очевидно, что для создания резервной копии файлов проекта достаточно их упаковать в архив:

# mkdir -p /var/lib/tomcat/.backup
# cd /var/lib/tomcat/webapps/pure-data
# tar -czf /var/lib/tomcat/.backup/webapps-pure-data.tar.gz ./

Распаковать архив в нужное место файловой системы можно следующим образом:

# tar -xzf ./webapps-pure-data.tar.gz -C /var/lib/tomcat/webapps/pure-data

Конечно же, после замены файлов проекта нужно сделать их доступными только сервису обслуживающему этот проект и никому более:

# chown -R tomcat:tomcat /var/lib/tomcat/webapps/pure-data
# chmod -R go-rwx /var/lib/tomcat/webapps/pure-data

Применение резервной копии файлов данных проекта производится по следующему регламенту:

1. Останавливаем Tomcat.
2. Подменяем всё содержимое директории "/var/lib/tomcat/webapps/pure-data" файлами из архива.
3. Явно передаём файлы данных проекта во владение пользователя, от имени которого запускается Tomcat.
4. Запускаем Tomcat.

На практике проект работоспособный и ничего непоправимо плохого за полгода эксплуатации не случилось.


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )