Деплой Java приложения на VPS: продвинутый уровень с CI/CD, Docker и SSL
В этой статье мы рассмотрим продвинутый процесс деплоя Java-приложения на VPS (Virtual Private Server). Мы не будем останавливаться на базовых шагах вроде установки JDK или запуска JAR-файла. Вместо этого сфокусируемся на настройке CI/CD пайплайна, контейнеризации с Docker, использовании Nginx в качестве обратного прокси, автоматическом получении SSL-сертификатов, а также на мониторинге и отказоустойчивости приложения.
Предполагается, что у вас уже есть VPS с Ubuntu 22.04 LTS, базовый домен, и вы знакомы с командной строкой Linux. Все примеры кода написаны на Java 17+ с использованием Spring Boot, но принципы применимы к любому Java-фреймворку.
1. Контейнеризация Java-приложения с Docker
Первый шаг к продвинутому деплою — упаковка приложения в Docker-контейнер. Это обеспечивает воспроизводимость окружения и упрощает развертывание.
Создайте Dockerfile в корне проекта:
# Используем multi-stage build для уменьшения размера финального образа
FROM maven:3.9.6-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Файл docker-compose.yml для запуска с базой данных:
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
- SPRING_DATASOURCE_USERNAME=user
- SPRING_DATASOURCE_PASSWORD=pass
depends_on:
- db
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
volumes:
pgdata:
После сборки образа командой docker compose build вы получите готовый к деплою контейнер.
2. Настройка CI/CD пайплайна (GitHub Actions)
Автоматизация деплоя — ключевой элемент продвинутого уровня. Используем GitHub Actions для сборки, тестирования и отправки образа на сервер.
Создайте файл .github/workflows/deploy.yml:
name: Deploy Java App to VPS
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Maven
run: mvn clean package
- name: Build Docker image
run: docker build -t myapp:latest .
- name: Save Docker image to tar
run: docker save myapp:latest | gzip > myapp.tar.gz
- name: Copy image to VPS via SCP
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
source: "myapp.tar.gz"
target: "/opt/app/"
- name: Deploy on VPS
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
cd /opt/app
docker load < myapp.tar.gz
docker compose down
docker compose up -d
rm myapp.tar.gz
Не забудьте добавить секреты VPS_HOST, VPS_USER, VPS_SSH_KEY в настройках репозитория GitHub. Теперь каждый пуш в ветку main будет автоматически деплоить новую версию приложения.
3. Настройка Nginx как обратного прокси и SSL
Для продакшн-среды необходимо скрыть внутренний порт 8080 и настроить HTTPS. Используем Nginx с Let's Encrypt.
Конфигурация Nginx (/etc/nginx/sites-available/myapp):
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
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_read_timeout 90;
}
location /actuator/health {
access_log off;
return 200 "OK";
add_header Content-Type text/plain;
}
}
Автоматическое получение SSL-сертификата с Certbot:
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d example.com -d www.example.com
Certbot автоматически обновит конфигурацию Nginx и настроит автоматическое обновление сертификатов каждые 90 дней.
4. Мониторинг и отказоустойчивость
Продвинутый деплой невозможен без мониторинга. Добавим Spring Boot Actuator и Prometheus.
Добавьте зависимости в pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>