はじめに
最後のレッスン: E コマース プラットフォーム全体を Kubernetes にデプロイし、GitHub Actions CI/CD で自動化し、Prometheus と Grafana で本番環境を監視します。 Quarkusには拡張機能があります quarkus-kubernetes 自己生成マニフェスト。
Kubernetes 上のアーキテクチャ
┌─── Ingress (Nginx) ───┐
│ ecommerce.xdev.asia │
└──────┬────────────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌────────────┐ ┌───────────┐ ┌────────────┐
│ Product │ │ Order │ │ Payment │
│ Service │ │ Service │ │ Service │
│ (3 pods) │ │ (3 pods) │ │ (2 pods) │
└──────┬─────┘ └─────┬─────┘ └──────┬─────┘
│ │ │
▼ ▼ ▼
┌────────────────────────────────────┐
│ PostgreSQL (StatefulSet) │
│ Kafka (Strimzi Operator) │
│ Keycloak (Operator) │
│ Redis (StatefulSet) │
└────────────────────────────────────┘
│
┌──────┴────────────────────────────┐
│ Monitoring Namespace │
│ Prometheus + Grafana + Jaeger │
└──────────────────────────────────┘
Quarkus Kubernetes 拡張機能
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes</artifactId>
</dependency>
application.properties
# Kubernetes deployment config
quarkus.kubernetes.deployment-target=kubernetes
quarkus.kubernetes.namespace=ecommerce
# Container image
quarkus.container-image.group=xdev
quarkus.container-image.name=product-service
quarkus.container-image.tag=${quarkus.application.version}
quarkus.container-image.registry=ghcr.io
# Deployment settings
quarkus.kubernetes.replicas=3
quarkus.kubernetes.image-pull-policy=always
# Resources
quarkus.kubernetes.resources.requests.cpu=100m
quarkus.kubernetes.resources.requests.memory=64Mi
quarkus.kubernetes.resources.limits.cpu=500m
quarkus.kubernetes.resources.limits.memory=128Mi
# Health probes (auto-configured từ SmallRye Health)
quarkus.kubernetes.liveness-probe.http-action-path=/q/health/live
quarkus.kubernetes.readiness-probe.http-action-path=/q/health/ready
quarkus.kubernetes.startup-probe.http-action-path=/q/health/started
# Service
quarkus.kubernetes.service-type=cluster-ip
quarkus.kubernetes.ports.http.container-port=8080
# Labels
quarkus.kubernetes.labels."app.kubernetes.io/part-of"=ecommerce
quarkus.kubernetes.labels."app.kubernetes.io/managed-by"=quarkus
# Env from ConfigMap & Secret
quarkus.kubernetes.env.configmaps=product-service-config
quarkus.kubernetes.env.secrets=product-service-secret
ビルドが生成する target/kubernetes/kubernetes.yml:
./mvnw package -Dnative \
-Dquarkus.container-image.build=true \
-Dquarkus.container-image.push=true
Kubernetes マニフェスト
名前空間と構成マップ
# k8s/base/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ecommerce
labels:
app.kubernetes.io/part-of: ecommerce
---
# k8s/base/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: product-service-config
namespace: ecommerce
data:
QUARKUS_DATASOURCE_JDBC_URL: >-
jdbc:postgresql://postgres:5432/productdb
QUARKUS_OIDC_AUTH_SERVER_URL: >-
http://keycloak:8080/realms/ecommerce
QUARKUS_LOG_LEVEL: INFO
QUARKUS_OTEL_EXPORTER_OTLP_ENDPOINT: >-
http://jaeger-collector:4317
秘密 (封印)
# k8s/base/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: product-service-secret
namespace: ecommerce
type: Opaque
stringData:
QUARKUS_DATASOURCE_USERNAME: product
QUARKUS_DATASOURCE_PASSWORD: "${DB_PASSWORD}"
プロダクション: プレーン シークレットの代わりに Sealed Secrets または 外部シークレット オペレーター を使用します。
HPA — 水平ポッド オートスケーラー
# k8s/base/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: product-service
namespace: ecommerce
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: product-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 120
イングレス
# k8s/base/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ecommerce-ingress
namespace: ecommerce
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- api.ecommerce.xdev.asia
secretName: ecommerce-tls
rules:
- host: api.ecommerce.xdev.asia
http:
paths:
- path: /products(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: product-service
port:
number: 8080
- path: /orders(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: order-service
port:
number: 8080
- path: /payments(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: payment-service
port:
number: 8080
ヘルムチャート
ecommerce-chart/
├── Chart.yaml
├── values.yaml
├── values-staging.yaml
├── values-production.yaml
└── templates/
├── _helpers.tpl
├── deployment.yaml
├── service.yaml
├── configmap.yaml
├── secret.yaml
├── hpa.yaml
└── ingress.yaml
値.yaml
# values.yaml
global:
namespace: ecommerce
imageRegistry: ghcr.io/xdev
services:
product:
name: product-service
image:
tag: latest
replicas: 2
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 128Mi
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPU: 70
order:
name: order-service
image:
tag: latest
replicas: 2
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 128Mi
payment:
name: payment-service
image:
tag: latest
replicas: 2
notification:
name: notification-service
image:
tag: latest
replicas: 1
ingress:
enabled: true
host: api.ecommerce.xdev.asia
tls: true
値-production.yaml
# values-production.yaml
services:
product:
replicas: 3
resources:
limits:
cpu: "1"
memory: 256Mi
hpa:
minReplicas: 3
maxReplicas: 20
order:
replicas: 3
payment:
replicas: 2
デプロイ
# Install
helm install ecommerce ./ecommerce-chart \
-n ecommerce --create-namespace \
-f values-production.yaml
# Upgrade
helm upgrade ecommerce ./ecommerce-chart \
-n ecommerce \
-f values-production.yaml \
--set services.product.image.tag=v1.2.0
# Rollback
helm rollback ecommerce 1 -n ecommerce
GitHub アクション CI/CD
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }}
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
service:
- product-service
- order-service
- payment-service
- notification-service
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Run tests
run: |
cd ${{ matrix.service }}
./mvnw verify
contract-test:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Consumer contract tests
run: |
cd order-service
./mvnw test -Dtest="*ContractTest"
- name: Provider verification
run: |
cd product-service
./mvnw test -Dtest="*ContractVerificationTest"
build-and-push:
needs: [test, contract-test]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
service:
- product-service
- order-service
- payment-service
- notification-service
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build native image & push
run: |
cd ${{ matrix.service }}
./mvnw package -Dnative \
-Dquarkus.native.container-build=true \
-Dquarkus.container-image.build=true \
-Dquarkus.container-image.push=true \
-Dquarkus.container-image.registry=ghcr.io \
-Dquarkus.container-image.group=\
${{ github.repository_owner }} \
-Dquarkus.container-image.tag=\
${{ github.sha }} \
-DskipTests
deploy-staging:
needs: build-and-push
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v4
- name: Set K8s context
uses: azure/k8s-set-context@v4
with:
kubeconfig: ${{ secrets.KUBE_CONFIG_STAGING }}
- name: Deploy to staging
run: |
helm upgrade --install ecommerce \
./ecommerce-chart \
-n ecommerce-staging \
--create-namespace \
-f ecommerce-chart/values-staging.yaml \
--set global.imageTag=${{ github.sha }}
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v4
- name: Set K8s context
uses: azure/k8s-set-context@v4
with:
kubeconfig: ${{ secrets.KUBE_CONFIG_PRODUCTION }}
- name: Deploy to production
run: |
helm upgrade --install ecommerce \
./ecommerce-chart \
-n ecommerce \
--create-namespace \
-f ecommerce-chart/values-production.yaml \
--set global.imageTag=${{ github.sha }}
- name: Verify deployment
run: |
kubectl rollout status deployment/product-service \
-n ecommerce --timeout=300s
kubectl rollout status deployment/order-service \
-n ecommerce --timeout=300s
Kubernetes での監視
Prometheus 用 ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: quarkus-services
namespace: ecommerce
labels:
release: prometheus
spec:
selector:
matchLabels:
app.kubernetes.io/part-of: ecommerce
endpoints:
- port: http
path: /q/metrics
interval: 15s
Grafana ダッシュボード
ダッシュボード ID 14370 (Quarkus Microprofile Metrics) をインポートするか、カスタムを作成します。
{
"dashboard": {
"title": "E-Commerce Platform",
"panels": [
{
"title": "Request Rate",
"targets": [{
"expr": "rate(http_server_requests_seconds_count{namespace='ecommerce'}[5m])"
}]
},
{
"title": "P99 Latency",
"targets": [{
"expr": "histogram_quantile(0.99, rate(http_server_requests_seconds_bucket{namespace='ecommerce'}[5m]))"
}]
},
{
"title": "Error Rate",
"targets": [{
"expr": "rate(http_server_requests_seconds_count{namespace='ecommerce',status=~'5..'}[5m])"
}]
}
]
}
}
制作チェックリスト
| カテゴリー | アイテム | ステータス |
|---|---|---|
| セキュリティ | 暗号化されたシークレット (Sealed Secret) | ☐ |
| セキュリティ | ネットワーク ポリシーが構成されました | ☐ |
| セキュリティ | サービス アカウントの RBAC | ☐ |
| 信頼性 | 正常性プローブが構成されました | ☐ |
| 信頼性 | HPA が設定されました | ☐ |
| 信頼性 | PodDisruption予算セット | ☐ |
| 可観測性 | 分散トレーシング (Jaeger) | ☐ |
| 可観測性 | メトリクス (Prometheus + Grafana) | ☐ |
| 可観測性 | 集中ログ (EFK/Loki) | ☐ |
| CI/CD | 自動テスト | ☐ |
| CI/CD | 受託テスト | ☐ |
| CI/CD | 自動展開 | ☐ |
| CI/CD | ロールバック戦略 | ☐ |
演習
- 次のコマンドを使用して Kubernetes マニフェストを生成します
quarkus-kubernetes拡張子 - Eコマースプラットフォーム用のHelmチャートを作成する
- GitHub Actions CI/CD パイプラインのセットアップ
- ローカル Kubernetes (minikube/kind) にデプロイします。
- HPA を構成し、自動スケーリングを確認する
- Prometheus + Grafana モニタリングのセットアップ
シリーズの概要
22 のレッスンを通じて、以下を完全に構築しました。
- Quarkus プラットフォーム — REST API、PostgreSQL、検証
- マイクロサービス設計 — DDD、サービスごとのデータベース、4 つの実用的なサービス
- セキュリティ — Keycloak OIDC、RBAC、トークン伝播
- 通信 — REST クライアント、gRPC、Kafka イベント駆動型
- 復元力と可観測性 — フォールト トレランス、OpenTelemetry、キャッシング
- テスト — @QuarkusTest、契約テスト
- 本番環境 — GraalVM ネイティブ、Kubernetes、CI/CD
次のステップ:
- 分散トランザクション用に Saga パターン を追加
- GraphQL API ゲートウェイ (quarkus-smallrye-graphql)
- サービス メッシュ (Istio) トラフィック管理用
- ArgoCD を使用した GitOps
- Quarkus Virtual Threads (Project Loom) リアクティブ ワークロード用