- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに
- 1. DevOps基礎:CI/CDパイプライン
- 2. GitOpsとInfrastructure as Code
- 3. Kubernetes完全攻略
- 4. モニタリングと可観測性
- 5. SREの原則
- 6. AI/MLワークフローの自動化
- 7. セキュリティ:RBACとSecretsの管理
- 8. インシデント管理
- まとめ
- クイズ
はじめに
現代のソフトウェア開発において、DevOpsと**SRE(Site Reliability Engineering)**はもはや選択肢ではなく、必須事項です。Netflixは1日に数千回デプロイし、Googleは数十億ユーザーに99.99%の可用性を保証しています。その背後には、徹底的に自動化されたパイプラインとデータ駆動の運用哲学があります。
このガイドでは、DevOps/SREの核心概念からKubernetesの実践運用、AI/MLワークフロー自動化まで、実際のコードとともに完全解説します。
1. DevOps基礎:CI/CDパイプライン
CI/CDとは何か
**CI(Continuous Integration)**は、開発者が頻繁にコードを統合し、自動的にビルド・テストする実践です。**CD(Continuous Delivery/Deployment)**は、検証済みコードを自動的にプロダクションにデプロイします。
| 区分 | 目的 | 自動化範囲 |
|---|---|---|
| CI | コード統合の検証 | ビルド、テスト、Lint |
| CD (Delivery) | リリース準備 | ステージングまで自動 |
| CD (Deployment) | 自動デプロイ | プロダクションまで自動 |
GitHub ActionsでCI/CDを構築
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
name: Test & Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-cov flake8
- name: Lint with flake8
run: flake8 src/ --max-line-length=88
- name: Run tests
run: pytest tests/ --cov=src --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
file: coverage.xml
build:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=sha-
type=ref,event=branch
type=semver,pattern={{version}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
name: Deploy to Kubernetes
runs-on: ubuntu-latest
needs: build
environment: production
steps:
- uses: actions/checkout@v4
- name: Configure kubectl
uses: azure/k8s-set-context@v3
with:
kubeconfig: ${{ secrets.KUBECONFIG }}
- name: Deploy with Helm
run: |
helm upgrade --install my-app ./helm/my-app \
--namespace production \
--set image.tag=${{ github.sha }} \
--wait --timeout=5m
デプロイ戦略の比較
Blue-Greenデプロイ:同一のプロダクション環境を2つ(Blue/Green)維持します。新バージョンをGreenにデプロイ後、トラフィックを一度に切り替えます。ロールバックは即座ですが、リソースが2倍必要です。
Canaryデプロイ:トラフィックの一部(例:5%)のみを新バージョンへルーティングし、段階的に拡大します。実際のユーザーで検証しながらリスクを最小化します。
# Argo Rollouts Canaryデプロイ設定
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: my-app
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10
- pause: { duration: 5m }
- setWeight: 30
- pause: { duration: 10m }
- setWeight: 60
- pause: { duration: 10m }
- setWeight: 100
canaryService: my-app-canary
stableService: my-app-stable
2. GitOpsとInfrastructure as Code
GitOpsの原則
GitOpsはGitを**唯一の信頼できる情報源(Single Source of Truth)**として使用する運用モデルです。
- 宣言的(Declarative):システム状態をコードで宣言
- バージョン管理:すべての変更がGit履歴で追跡
- 自動化:Git変更 → 自動同期
- 監査可能:PR ベースの変更で誰が何をなぜ変更したかを記録
主要ツールとしてArgoCDとFluxがあります。
TerraformでIaCを実装
# main.tf - AWS EKSクラスターのプロビジョニング
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "prod/eks/terraform.tfstate"
region = "ap-northeast-1"
}
}
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "prod-cluster"
cluster_version = "1.29"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_groups = {
general = {
instance_types = ["m5.xlarge"]
min_size = 2
max_size = 10
desired_size = 3
}
gpu = {
instance_types = ["g4dn.xlarge"]
min_size = 0
max_size = 5
desired_size = 1
taints = [{
key = "nvidia.com/gpu"
value = "true"
effect = "NO_SCHEDULE"
}]
}
}
}
3. Kubernetes完全攻略
コアリソースの理解
| リソース | 役割 |
|---|---|
| Pod | 実行単位、1つ以上のコンテナの集合 |
| Deployment | Podレプリカ管理、ローリングアップデート |
| Service | Podグループへのネットワークエンドポイント |
| HPA | CPU/メモリ基準の水平自動スケーリング |
| ConfigMap | 環境変数/設定ファイルの分離 |
| Secret | 機密情報(パスワード、トークン)の管理 |
| Ingress | 外部HTTPトラフィックのルーティング |
実践的なDeployment + HPAマニフェスト
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-inference-api
namespace: production
labels:
app: ml-inference-api
version: v1
spec:
replicas: 3
selector:
matchLabels:
app: ml-inference-api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: ml-inference-api
version: v1
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '8080'
prometheus.io/path: '/metrics'
spec:
containers:
- name: api
image: ghcr.io/myorg/ml-inference-api:sha-abc123
ports:
- containerPort: 8080
env:
- name: MODEL_NAME
valueFrom:
configMapKeyRef:
name: ml-config
key: model_name
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
cpu: '500m'
memory: '512Mi'
limits:
cpu: '2000m'
memory: '2Gi'
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
---
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ml-inference-api-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ml-inference-api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: '100'
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 4
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
HelmチャートによるPackage管理
HelmはKubernetesのパッケージマネージャです。複雑なアプリケーションのデプロイをテンプレートで管理します。
# helm/my-app/values.yaml
replicaCount: 3
image:
repository: ghcr.io/myorg/my-app
pullPolicy: IfNotPresent
tag: 'latest'
service:
type: ClusterIP
port: 80
targetPort: 8080
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: api.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: api-tls
hosts:
- api.example.com
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 70
postgresql:
enabled: true
auth:
database: myapp
existingSecret: db-credentials
redis:
enabled: true
architecture: replication
4. モニタリングと可観測性
可観測性の3つの柱
| 柱 | ツール | 用途 |
|---|---|---|
| メトリクス(Metrics) | Prometheus, Grafana | 数値データ、ダッシュボード |
| ログ(Logs) | Loki, Elasticsearch | イベント記録、デバッグ |
| トレース(Traces) | Jaeger, Tempo | 分散リクエスト追跡 |
Prometheusアラートルール
# prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: ml-service-alerts
namespace: monitoring
spec:
groups:
- name: ml-service.rules
interval: 30s
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m])) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: '高いエラーレートを検出'
description: '過去5分間のエラーレートは{{ $value | humanizePercentage }}です'
- alert: SlowResponseTime
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
) > 1.0
for: 5m
labels:
severity: warning
annotations:
summary: 'p99レイテンシが遅い'
description: '{{ $labels.service }}のp99レイテンシは{{ $value }}秒です'
- alert: PodCrashLooping
expr: |
increase(kube_pod_container_status_restarts_total[15m]) > 3
for: 0m
labels:
severity: critical
annotations:
summary: 'Podがクラッシュループ中'
description: 'Pod {{ $labels.namespace }}/{{ $labels.pod }}がクラッシュループしています'
- alert: HighMemoryUsage
expr: |
container_memory_usage_bytes
/
container_spec_memory_limit_bytes > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: 'メモリ使用率が高い'
OpenTelemetryによる計装
# instrumentation.py
from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
def setup_telemetry(service_name: str, otlp_endpoint: str):
"""OpenTelemetryの設定"""
# トレーサーの設定
tracer_provider = TracerProvider()
otlp_exporter = OTLPSpanExporter(endpoint=otlp_endpoint)
tracer_provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
trace.set_tracer_provider(tracer_provider)
# メトリクスの設定
meter_provider = MeterProvider()
metrics.set_meter_provider(meter_provider)
return trace.get_tracer(service_name)
# FastAPIアプリへの適用
from fastapi import FastAPI
app = FastAPI()
tracer = setup_telemetry("ml-inference-api", "http://otel-collector:4317")
# 自動計装
FastAPIInstrumentor.instrument_app(app)
RequestsInstrumentor().instrument()
@app.post("/predict")
async def predict(payload: dict):
with tracer.start_as_current_span("model-inference") as span:
span.set_attribute("model.name", "bert-base")
span.set_attribute("input.length", len(str(payload)))
result = run_inference(payload)
span.set_attribute("prediction.confidence", result["confidence"])
return result
5. SREの原則
SLI / SLO / SLAの階層構造
- SLI(Service Level Indicator):実際に測定されるサービスパフォーマンス指標(例:リクエスト成功率、レイテンシ)
- SLO(Service Level Objective):SLIに対する目標値(例:99.9%の可用性)
- SLA(Service Level Agreement):顧客と合意した契約レベル(SLOより緩く設定)
Error Budgetの計算
SLOが99.9%の場合、1か月(30日)で許容されるダウンタイムは以下の通りです。
エラーバジェット = 100% - SLO = 0.1%
月次許容ダウンタイム = 30日 x 24時間 x 60分 x 0.1% ≈ 43.2分
エラーバジェットが消費されると、新機能のデプロイを停止し、安定性作業に集中します。
| SLOレベル | 月次許容ダウンタイム |
|---|---|
| 99% | 7時間18分 |
| 99.9% | 43分48秒 |
| 99.99% | 4分22秒 |
| 99.999% | 26秒 |
Toil削減戦略
Toilは手動的・反復的・自動化可能な運用作業です。Google SREは、Toilを全業務時間の50%未満に抑えることを推奨しています。
Toil削減の方法:
- 繰り返し作業のスクリプト化・自動化
- ランブック(Runbook)を自動化コードへ変換
- アラート品質の改善によるノイズ削減
- セルフヒーリング(Self-Healing)システムの構築
6. AI/MLワークフローの自動化
MLflowによる実験管理
# train.py
import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score
mlflow.set_tracking_uri("http://mlflow-server:5000")
mlflow.set_experiment("fraud-detection-v2")
with mlflow.start_run(run_name="rf-baseline"):
# ハイパーパラメータの記録
params = {"n_estimators": 100, "max_depth": 10, "random_state": 42}
mlflow.log_params(params)
# モデルの学習
model = RandomForestClassifier(**params)
model.fit(X_train, y_train)
# メトリクスの記録
y_pred = model.predict(X_test)
mlflow.log_metric("accuracy", accuracy_score(y_test, y_pred))
mlflow.log_metric("f1_score", f1_score(y_test, y_pred))
# モデルの保存
mlflow.sklearn.log_model(model, "model",
registered_model_name="fraud-detector")
Argo WorkflowsによるMLパイプライン
# ml-pipeline.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: ml-training-pipeline
spec:
entrypoint: ml-pipeline
templates:
- name: ml-pipeline
dag:
tasks:
- name: data-prep
template: prepare-data
- name: train
template: train-model
dependencies: [data-prep]
- name: evaluate
template: evaluate-model
dependencies: [train]
- name: deploy
template: deploy-model
dependencies: [evaluate]
- name: prepare-data
container:
image: ghcr.io/myorg/data-prep:latest
command: [python, prepare_data.py]
resources:
requests:
memory: 4Gi
cpu: '2'
- name: train-model
container:
image: ghcr.io/myorg/ml-trainer:latest
command: [python, train.py]
resources:
requests:
memory: 16Gi
cpu: '8'
nvidia.com/gpu: '1'
- name: evaluate-model
container:
image: ghcr.io/myorg/ml-evaluator:latest
command: [python, evaluate.py]
- name: deploy-model
container:
image: ghcr.io/myorg/model-deployer:latest
command: [python, deploy.py]
Python MLサービスのDockerfile
# Dockerfile
FROM python:3.11-slim AS builder
WORKDIR /app
# 依存関係レイヤーの分離(キャッシュ活用)
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.11-slim AS runtime
# セキュリティ:root権限なしで実行
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
# ビルダーからパッケージをコピー
COPY /root/.local /home/appuser/.local
COPY src/ ./src/
COPY models/ ./models/
USER appuser
ENV PATH=/home/appuser/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
EXPOSE 8080
HEALTHCHECK \
CMD python -c "import requests; requests.get('http://localhost:8080/health').raise_for_status()"
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8080", "--workers", "4"]
7. セキュリティ:RBACとSecretsの管理
Kubernetes RBAC
# rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: ml-service-account
namespace: production
---
# 最小権限のRole
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ml-service-role
namespace: production
rules:
- apiGroups: ['']
resources: ['pods', 'services']
verbs: ['get', 'list', 'watch']
- apiGroups: ['']
resources: ['secrets']
resourceNames: ['ml-model-secrets']
verbs: ['get']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ml-service-rolebinding
namespace: production
subjects:
- kind: ServiceAccount
name: ml-service-account
namespace: production
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: ml-service-role
HashiCorp VaultによるSecret管理
# vault_client.py
import hvac
import os
def get_secret(secret_path: str) -> dict:
"""Vaultからシークレットを安全に取得します。"""
client = hvac.Client(
url=os.environ["VAULT_ADDR"],
token=os.environ["VAULT_TOKEN"]
)
if not client.is_authenticated():
raise RuntimeError("Vault認証失敗")
secret = client.secrets.kv.v2.read_secret_version(
path=secret_path,
mount_point="secret"
)
return secret["data"]["data"]
# KubernetesではVault Agent Injectorを使用して
# Podアノテーションによる自動シークレット注入が可能
NetworkPolicyによるトラフィック制御
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ml-service-netpol
namespace: production
spec:
podSelector:
matchLabels:
app: ml-inference-api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector:
matchLabels:
name: database
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 4317 # OTLP gRPC
8. インシデント管理
インシデント対応プロセス
- 検出(Detection):Prometheusアラートまたはユーザー報告
- トリアージ(Triage):深刻度の判断(P1/P2/P3)
- コミュニケーション(Communication):ステータスページ更新、ステークホルダーへの通知
- 緩和(Mitigation):トラフィック切り替え、ロールバック、スケールアウト
- 解決(Resolution):根本原因の修正
- 事後レビュー(Post-Mortem):ブレームレスPost-Mortemの作成
効果的なPost-Mortemの書き方
良いPost-Mortemは個人の責任ではなく、システムの改善に集中します。
- 詳細なタイムラインの記録
- 根本原因(Root Cause)と誘発要因(Trigger)の区別
- 5 Whys分析の実施
- 具体的なアクションアイテム(担当者と期限付き)
まとめ
DevOps/SREは単なるツールセットではなく、文化と哲学です。自動化で人為的ミスを減らし、データで意思決定を行い、継続的な改善でシステムの信頼性を高めます。
核心原則をまとめると:
- 自動化優先:すべての繰り返し作業はコードで
- 測定可能性:SLI/SLOで目標を明確に
- 高速な失敗:Canaryデプロイでリスクを最小化
- ブレームレス文化:システムを改善し、人を非難しない
クイズ
Q1. CI/CDパイプラインにおけるBlue-GreenデプロイとCanaryデプロイの違いは何ですか?
答え: Blue-Greenは2つの同一プロダクション環境を維持し、トラフィックを一度に切り替える方式で、Canaryはトラフィックの一部のみを新バージョンに段階的に切り替える方式です。
解説: Blue-Greenデプロイはロールバックが即座(トラフィック切り替えのみ)でダウンタイムがありませんが、リソースが2倍必要です。Canaryデプロイは実際のユーザートラフィックで新バージョンを検証しながらリスクを最小化できますが、監視が複雑になります。Argo Rolloutsのようなツールが両方式をサポートします。
Q2. Kubernetes HPAがスケーリングする基準メトリクスは何ですか?
答え: デフォルトではCPU使用率とメモリ使用率です。Custom Metrics APIを通じて、RPS(秒あたりリクエスト数)やキュー深度などのカスタムメトリクスも使用できます。
解説: HPA(HorizontalPodAutoscaler)のv2 APIでは、resource、pods、object、externalの4種類のメトリクスタイプをサポートします。CPU 70%の目標を設定すると、既存Podの平均CPUがそれを超えたときにPod数を増やします。Prometheus Adapterをインストールすると、PrometheusメトリクスをHPAに連携できます。
Q3. SREにおけるError Budgetの役割は何ですか?
答え: Error Budgetは、SLOで定義された許容失敗量であり、安定性と機能開発速度のバランスを取るメカニズムです。
解説: SLOが99.9%の場合、Error Budgetは0.1%です。このバジェットが十分であれば、新機能のデプロイや実験的な変更が可能です。バジェットが枯渇すると、新しいデプロイを凍結し、安定性の改善に集中します。これにより、開発チームと運営チームがデータに基づいてデプロイ速度を協議できます。
Q4. Prometheusのpull方式によるメトリクス収集の利点は何ですか?
答え: pull方式はPrometheusがスクレイピング対象を中央で管理するため設定がシンプルで、対象サービスがダウンした際に即座に検出でき、セキュリティ面でファイアウォールのインバウンドルールが不要です。
解説: push方式(StatsD、InfluxDBなど)では、各サービスがメトリクスサーバーのアドレスを知る必要があり、ネットワーク問題時にデータが失われる可能性があります。pull方式はPrometheusが設定ファイルやサービスディスカバリで対象を管理するため、サービスの追加・削除が柔軟です。非常に短命なバッチジョブにはPushgatewayを活用します。
Q5. GitOpsと従来のCI/CDの違いは何ですか?
答え: GitOpsはGitを唯一の信頼できる情報源として使用し、宣言的な状態を継続的に同期させるのに対し、従来のCI/CDはパイプラインが直接命令的にデプロイを実行します。
解説: 従来のCI/CD(Jenkins、GitHub Actions)はパイプラインから直接kubectl applyやhelm upgradeを実行します。GitOps(ArgoCD、Flux)はGitの宣言的な状態とクラスターの実際の状態を継続的に比較し、自動同期します。GitOpsはドリフト検出、自動ロールバック、完全な監査証跡が可能で、CI/CDシステムにクラスターアクセス権限を付与する必要がなくセキュリティが強化されます。