← Назад к вопросам

Разворачивал ли приложение на рабочем сервере

2.0 Middle🔥 201 комментариев
#Docker, Kubernetes и DevOps#JVM и управление памятью#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разворачивал ли приложение на рабочем сервере

Опыт развёртывания

Да, я имею опыт развёртывания Java приложений на рабочих серверах. Вот примеры типичных сценариев, которые я выполнял.

Пример 1: Развёртывание Spring Boot приложения на Ubuntu сервере

Шаги развёртывания:

# 1. Подключение к серверу
ssh -i /path/to/key.pem ubuntu@example.com

# 2. Установка Java (если нужна)
sudo apt-get update
sudo apt-get install openjdk-17-jdk

java -version  # Проверяем версию

# 3. Создание директории приложения
sudo mkdir -p /opt/myapp
sudo chown ubuntu:ubuntu /opt/myapp

# 4. Загрузка приложения (из CI/CD или вручную)
cd /opt/myapp
wget https://releases.example.com/myapp-1.0.jar
# или скопировать файл локально:
# scp -i key.pem target/myapp-1.0.jar ubuntu@example.com:/opt/myapp/

# 5. Создание systemd сервиса
sudo nano /etc/systemd/system/myapp.service

Содержимое /etc/systemd/system/myapp.service:

[Unit]
Description=My Spring Boot Application
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/opt/myapp

# JVM параметры для оптимизации
Environment="JAVA_OPTS=-Xmx512m -Xms256m"
ExecStart=/usr/bin/java $JAVA_OPTS -jar /opt/myapp/myapp-1.0.jar

# Автозагрузка при перезагрузке сервера
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target

Запуск сервиса:

# Перезагружаем systemd конфигурацию
sudo systemctl daemon-reload

# Запускаем приложение
sudo systemctl start myapp

# Проверяем статус
sudo systemctl status myapp

# Разрешаем автозагрузку при перезагрузке сервера
sudo systemctl enable myapp

# Посмотреть логи
sudo journalctl -u myapp -f

Пример 2: Развёртывание с Nginx (reverse proxy)

Архитектура:

HTTP запрос (port 80/443)
    |
    v
Nginx (reverse proxy)
    |
    v
Spring Boot приложение (port 8080)
    |
    v
База данных

Конфигурация Nginx (/etc/nginx/sites-available/myapp):

server {
    listen 80;
    server_name myapp.com www.myapp.com;
    
    # Редирект с HTTP на HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name myapp.com www.myapp.com;
    
    # SSL сертификаты (Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;
    
    # Оптимизация SSL
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    
    # Логирование
    access_log /var/log/nginx/myapp_access.log;
    error_log /var/log/nginx/myapp_error.log;
    
    # Проксирование на Spring Boot приложение
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # Таймауты
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

Активация конфига:

# Создаём символическую ссылку
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/

# Проверяем конфигурацию
sudo nginx -t

# Перезагружаем Nginx
sudo systemctl restart nginx

# Установка SSL сертификата
sudo certbot certonly --nginx -d myapp.com -d www.myapp.com

Пример 3: Развёртывание с Docker и Docker Compose

Dockerfile приложения:

FROM openjdk:17-slim

WORKDIR /app

# Копируем JAR
COPY target/myapp-1.0.jar app.jar

# Экспортируем порт
EXPOSE 8080

# Запуск
ENTRYPOINT ["java", "-jar", "app.jar"]

Docker Compose (docker-compose.yml):

version: '3.8'

services:
  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  myapp:
    build: .
    container_name: myapp
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/myapp
      SPRING_DATASOURCE_USERNAME: postgres
      SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
      SPRING_JPA_HIBERNATE_DDL_AUTO: validate
    ports:
      - "8080:8080"
    depends_on:
      postgres:
        condition: service_healthy
    restart: always
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - myapp
    restart: always

volumes:
  postgres_data:

Запуск на сервере:

# Клонируем репозиторий
git clone https://github.com/user/myapp.git
cd myapp

# Создаём .env файл
echo "DB_PASSWORD=secure_password" > .env

# Собираем приложение
mvn clean package -DskipTests

# Запускаем в фоне
docker-compose up -d

# Смотрим логи
docker-compose logs -f myapp

# Проверяем статус
docker-compose ps

Пример 4: Мониторинг и логирование в продакшене

Spring Boot конфигурация логирования (application.yml):

spring:
  jpa:
    hibernate:
      ddl-auto: validate  # ❌ Никогда не используй create/update в продакшене!

logging:
  level:
    root: INFO
    com.myapp: DEBUG
    org.springframework.web: INFO
    org.hibernate.SQL: DEBUG
  file:
    name: /var/log/myapp/application.log
    max-size: 10MB
    max-history: 30
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,prometheus
  endpoint:
    health:
      show-details: when-authorized

Мониторинг здоровья приложения:

# Health check
curl https://myapp.com/actuator/health

# Метрики
curl https://myapp.com/actuator/metrics

# Prometheus формат
curl https://myapp.com/actuator/prometheus

Пример 5: Обновление приложения в продакшене (Blue-Green Deploy)

# 1. Текущая версия работает на порту 8080 (Blue)

# 2. Собираем новую версию
mvn clean package -DskipTests

# 3. Запускаем на порту 8081 (Green)
java -jar target/myapp-2.0.jar --server.port=8081 &

# 4. Тестируем новую версию
curl http://localhost:8081/api/health

# 5. Если всё OK, переключаем Nginx на новую версию
# Редактируем nginx.conf:
# proxy_pass http://127.0.0.1:8081;  # было 8080
sudo systemctl reload nginx

# 6. Останавливаем старую версию
kill <pid-old-app>

# 7. Откатываем обратно, если нужно:
sudo systemctl reload nginx  # Переключаем на 8080

Типичные проблемы и их решение

Проблема 1: Приложение съедает всю память
Решение: Установить JVM параметры
-Xmx512m -Xms256m (максимум 512MB, минимум 256MB)

Проблема 2: Медленное выключение (graceful shutdown)
Решение: Добавить в application.yml
server.shutdown: graceful
spring.lifecycle.timeout-per-shutdown-phase: 30s

Проблема 3: БД соединения исчерпаны
Решение: Настроить connection pool
spring.datasource.hikari.maximum-pool-size: 20
spring.datasource.hikari.minimum-idle: 5

Чеклист развёртывания

  • Java установлена и правильной версии
  • Переменные окружения настроены (БД, API ключи)
  • Логи ротируются и не заполняют диск
  • SSL сертификаты установлены и не истекли
  • Проверен health endpoint
  • Мониторинг настроен (metrics, alerts)
  • Есть план откатки (rollback strategy)
  • Есть резервная копия БД перед обновлением
  • Сервер имеет достаточно ресурсов (CPU, RAM, disk)
  • Firewall настроен правильно

Вывод

Развёртывание Java приложений в продакшене требует:

  1. Понимания Linux и сетевых концепций
  2. Аккуратности при работе с данными
  3. Мониторинга и логирования для отладки проблем
  4. Плана откатки на случай проблем
  5. Документирования процесса для следующих развёртываний
Разворачивал ли приложение на рабочем сервере | PrepBro