Какие способы запуска Java-приложения в контексте DevOps/автоматизации вы знаете?

«Какие способы запуска Java-приложения в контексте DevOps/автоматизации вы знаете?» — вопрос из категории Скриптинг и автоматизация, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В DevOps-практике запуск Java-приложения — это не просто команда java -jar, а этап в цепочке сборки, доставки и развертывания, который должен быть воспроизводимым, изолированным и управляемым. Вот как мы это делаем:

  1. Сборка и упаковка в исполняемый JAR (или WAR) Используем Maven или Gradle для сборки финального артефакта, содержащего все зависимости (например, spring-boot-maven-plugin для создания fat JAR). Это основа для дальнейших шагов.

    # Стандартная сборка
    mvn clean package
    # На выходе: target/my-application-1.0.0.jar
  2. Контейнеризация (Docker) Это стандарт де-факто. Создаем Docker-образ на основе официального OpenJDK или дистрибутивов с оптимизированной JVM (например, Eclipse Temurin). Используем многоступенчатую сборку (multi-stage build) для уменьшения размера финального образа.

    # Multi-stage build
    FROM maven:3.8-eclipse-temurin-17 AS builder
    WORKDIR /app
    COPY . .
    RUN mvn clean package -DskipTests
    
    FROM eclipse-temurin:17-jre-jammy
    WORKDIR /app
    COPY --from=builder /app/target/*.jar app.jar
    # Настройка JVM для контейнеров (критически важно!)
    ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
    ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]

    Затем образ пушится в Container Registry (Docker Hub, ECR, GCR).

  3. Оркестрация (Kubernetes) Запуск контейнеризированного приложения в K8s через Deployment, который управляет Pod'ами.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: java-app
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: java-app
      template:
        metadata:
          labels:
            app: java-app
        spec:
          containers:
          - name: app
            image: my-registry/java-app:1.0.0
            ports:
            - containerPort: 8080
            resources:
              requests:
                memory: "512Mi"
                cpu: "250m"
              limits:
                memory: "1Gi"
                cpu: "500m"
            env:
            - name: SPRING_PROFILES_ACTIVE
              value: "production"
  4. Запуск через системы инициализации (systemd) на виртуальных машинах Если используется не контейнерная, а VM-инфраструктура, приложение управляется как системный сервис.

    # /etc/systemd/system/my-java-app.service
    [Unit]
    Description=My Java Application
    After=network.target
    
    [Service]
    Type=simple
    User=appuser
    WorkingDirectory=/opt/myapp
    Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk"
    Environment="JAVA_OPTS=-Xmx1g -Dspring.profiles.active=prod"
    ExecStart=/usr/bin/java $JAVA_OPTS -jar app.jar
    SuccessExitStatus=143
    Restart=always
    RestartSec=10
    
    [Install]
    WantedBy=multi-user.target

    Управление: sudo systemctl start my-java-app.

  5. Интеграция в CI/CD пайплайн Все вышеперечисленные шаги автоматизируются в пайплайне (Jenkins, GitLab CI, GitHub Actions).

    # Пример этапов в GitHub Actions
    jobs:
      build-and-deploy:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - name: Set up JDK 17
            uses: actions/setup-java@v3
            with:
              distribution: 'temurin'
              java-version: '17'
          - name: Build with Maven
            run: mvn clean package
          - name: Build and push Docker image
            run: |
              docker build -t ${{ secrets.REGISTRY }}/app:${{ github.sha }} .
              docker push ${{ secrets.REGISTRY }}/app:${{ github.sha }}
          - name: Deploy to Kubernetes
            run: |
              kubectl set image deployment/java-app app=${{ secrets.REGISTRY }}/app:${{ github.sha }}

Главный тренд: Контейнеризация с последующим запуском в оркестраторе (Kubernetes) стала стандартом, так как обеспечивает неизменяемость, изоляцию, простое масштабирование и единый способ управления приложениями любого стека.