はじめに
本番環境ではホットデプロイが有効な場合もありますが、開発フェーズにおける頻繁なデプロイ作業を手動で行うことは効率的とは言えません。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)も合わせて確認してください。