Alibaba CloudへのSpring Bootマルチモジュールアプリケーション本番環境デプロイ完全ガイド

はじめに

本番環境ではホットデプロイが有効な場合もありますが、開発フェーズにおける頻繁なデプロイ作業を手動で行うことは効率的とは言えません。KubernetesやJenkinsによるCI/CDパイプラインの構築が理想的ですが、今回はAlibaba Cloud環境への直接デプロイ手法について解説します。

デプロイ前のソースコード設定

プロファイル設定の切り替え

各モジュールのリソース設定ファイルを本番環境用に変更します。以下のように環境プロファイルを変更してください。

# ec-system/ec-management/src/main/resources/application.yml
# 変更前
spring:
  config:
    activate:
      on-profile: dev

# 変更後
spring:
  config:
    activate:
      on-profile: production

データベース認証情報の更新

application-production.yml内のデータベース接続設定をAlibaba Cloud上の実際の値に更新します。

app:
  datasource:
    primary:
      url: jdbc:mysql://your-rds-endpoint:3306/ecommerce?useSSL=false
      username: ${DB_USER:admin_user}
      password: ${DB_PASS:secure_password}

親プロジェクト参照の修正

マルチモジュールプロジェクトでは、サブモジュールのpom.xmlで親プロジェクトの相対パスを明示的に指定する必要があります。

<!-- ec-system/ec-frontend/pom.xml -->
<parent>
    <groupId>com.example</groupId>
    <artifactId>ec-root</artifactId>
    <version>2.0.1-RELEASE</version>
    <relativePath>../../pom.xml</relativePath>
</parent>

デプロイ手法の選択肢

手法A: Maven Dockerプラグインによるローカルビルド

Dockerfileをプロジェクト内に配置し、Mavenのdockerfile-maven-pluginを使用してイメージをビルドします。

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>
    <configuration>
        <repository>${docker.registry}/ec-system/${project.artifactId}</repository>
        <tag>${project.version}</tag>
        <buildArgs>
            <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
        </buildArgs>
    </configuration>
</plugin>

手法B: Alibaba Cloud Toolkitによる直接デプロイ

IntelliJ IDEAにAlibaba Cloud Toolkitプラグインをインストールし、ECSインスタンスへの直接デプロイを設定します。マルチモジュールプロジェクトでは、各サブモジュールに対して以下のMavenゴールを設定します。

clean compile jib:build -Dimage=registry.cn-hangzhou.aliyuncs.com/ec-system/${project.artifactId}:${project.version}

手法C: コンテナレジストリ連携による運用

Alibaba Cloud Container Registryにプッシュしたイメージを、ECS上でDocker Composeで運用する方法です。以降、この手法の詳細を解説します。

基盤サービスの構築

まず、データベースやキャッシュなどの基盤サービスをDocker Composeで起動します。

# /app/ec-platform/docker-compose-infrastructure.yml
version: '3.8'

services:
  product-database:
    image: mysql:8.0
    container_name: product-db
    command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4
    environment:
      MYSQL_DATABASE: ecommerce
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    volumes:
      - db-data:/var/lib/mysql
      - ./mysql/conf:/etc/mysql/conf.d
    ports:
      - "3306:3306"
    restart: unless-stopped

  cache-server:
    image: redis:6.2-alpine
    container_name: cache-svc
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis-data:/data
    ports:
      - "6379:6379"
    restart: unless-stopped

  message-broker:
    image: rabbitmq:3.9-management-alpine
    container_name: msg-broker
    environment:
      RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER}
      RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASS}
    volumes:
      - rabbit-data:/var/lib/rabbitmq
    ports:
      - "5672:5672"
      - "15672:15672"
    restart: unless-stopped

  search-engine:
    image: elasticsearch:7.15.0
    container_name: search-svc
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
    volumes:
      - es-data:/usr/share/elasticsearch/data
      - ./elasticsearch/plugins:/usr/share/elasticsearch/plugins
    ports:
      - "9200:9200"
    restart: unless-stopped

  log-visualizer:
    image: kibana:7.15.0
    container_name: kibana-svc
    environment:
      - ELASTICSEARCH_HOSTS=http://search-engine:9200
    depends_on:
      - search-engine
    ports:
      - "5601:5601"
    restart: unless-stopped

  document-store:
    image: mongo:5.0-focal
    container_name: doc-store
    volumes:
      - mongo-data:/data/db
    ports:
      - "27017:27017"
    restart: unless-stopped

volumes:
  db-data:
  redis-data:
  rabbit-data:
  es-data:
  mongo-data:

実行コマンド:

cd /app/ec-platform
docker-compose -f docker-compose-infrastructure.yml up -d

各サービスの初期設定

Elasticsearch日本語解析プラグインのインストール

docker exec -it search-svc bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.15.0/elasticsearch-analysis-ik-7.15.0.zip
docker restart search-svc

MySQLデータベースの初期化

スキーマファイルをコンテナにコピーし、初期データを投入します。

# スキーマファイルのコピー
docker cp ./sql/ecommerce-schema.sql product-database:/tmp/

# コンテナ内で実行
docker exec -it product-database mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "
CREATE USER 'app_user'@'%' IDENTIFIED BY '${APP_DB_PASSWORD}';
GRANT ALL PRIVILEGES ON ecommerce.* TO 'app_user'@'%';
CREATE DATABASE IF NOT EXISTS ecommerce CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE ecommerce;
source /tmp/ecommerce-schema.sql;
"

RabbitMQ管理ユーザーの作成

docker exec -it msg-broker rabbitmqctl add_user ${RABBITMQ_APP_USER} ${RABBITMQ_APP_PASSWORD}
docker exec -it msg-broker rabbitmqctl set_user_tags ${RABBITMQ_APP_USER} administrator
docker exec -it msg-broker rabbitmqctl set_permissions -p / ${RABBITMQ_APP_USER} ".*" ".*" ".*"

アプリケーションのデプロイ

ビルド済みのDockerイメージを使用して、3つのモジュールを起動します。

# /app/ec-platform/docker-compose-applications.yml
version: '3.8'

services:
  management-api:
    image: registry.cn-hangzhou.aliyuncs.com/ec-system/management-api:${APP_VERSION}
    container_name: mgmt-api
    environment:
      - SPRING_PROFILES_ACTIVE=production
      - DB_HOST=product-database
      - DB_PORT=3306
    ports:
      - "8080:8080"
    depends_on:
      - product-database
    restart: unless-stopped

  search-service:
    image: registry.cn-hangzhou.aliyuncs.com/ec-system/search-service:${APP_VERSION}
    container_name: srch-svc
    environment:
      - SPRING_PROFILES_ACTIVE=production
      - ES_HOST=search-engine
      - DB_HOST=product-database
    ports:
      - "8081:8081"
    depends_on:
      - search-engine
      - product-database
    restart: unless-stopped

  frontend-api:
    image: registry.cn-hangzhou.aliyuncs.com/ec-system/frontend-api:${APP_VERSION}
    container_name: fe-api
    environment:
      - SPRING_PROFILES_ACTIVE=production
      - REDIS_HOST=cache-server
      - MONGO_HOST=document-store
      - DB_HOST=product-database
      - RABBIT_HOST=message-broker
    ports:
      - "8085:8085"
    depends_on:
      - cache-server
      - document-store
      - product-database
      - message-broker
    restart: unless-stopped

起動コマンド:

export APP_VERSION=2.0.1
docker-compose -f docker-compose-applications.yml up -d

セキュリティグループとファイアウォール設定

Alibaba Cloudのセキュリティグループで以下のポートを開放します。

# ファイアウォール設定(firewalld使用時)
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --add-port=8081/tcp
sudo firewall-cmd --permanent --add-port=8085/tcp
sudo firewall-cmd --permanent --add-port=15672/tcp
sudo firewall-cmd --permanent --add-port=9200/tcp
sudo firewall-cmd --permanent --add-port=5601/tcp
sudo firewall-cmd --reload

# またはファイアウォールを停止(開発環境のみ)
sudo systemctl stop firewalld

動作確認

各サービスのSwagger UIにアクセスして正常起動を確認します。

  • 管理API: http://<ECS_PUBLIC_IP>:8080/swagger-ui.html
  • 検索サービス: http://<ECS_PUBLIC_IP>:8081/swagger-ui.html
  • フロントエンドAPI: http://<ECS_PUBLIC_IP>:8085/swagger-ui.html

また、RabbitMQ管理コンソール(http://<ECS_PUBLIC_IP>:15672)とKibana(http://<ECS_PUBLIC_IP>:5601)も合わせて確認してください。

タグ: Alibaba Cloud Spring Boot Docker Compose MySQL Elasticsearch

7月2日 00:50 投稿