クラウドリフト クラウドネイティブ用語集|専門用語をやさしく解説
可用性SLA 99.9% は年間約8.76時間(約9時間)の停止に相当し¹、DNSのTTL 300秒は切替時に最大5分の遅延を生む²。なお、実際の伝播時間はDNSキャッシュやリゾルバの挙動に依存し、TTLどおりに短縮されない、あるいはこれを上回って長引くケースもある²⁷。この単純な算数だけで、移行計画の甘さが即座にサービス指標へ波及することがわかる。大規模移行の初期段階では再ホスト、通称クラウドリフトが選ばれやすいが、移行後の実効コストとパフォーマンスは事前設計で大きく分かれる。この記事では、クラウドリフトとクラウドネイティブの用語を軸に、実装・計測・最適化を一気通貫で整理し、CTO/エンジニアリーダーが意思決定できる情報を提示する。
クラウドリフトとクラウドネイティブの定義と使い分け
クラウドリフトは既存システムを最小限の改修でクラウドへ再ホストするアプローチで、短期の移行リードタイムとレガシー資産の活用が強みである³。一方、クラウドネイティブはコンテナ、サービスメッシュ、IaC、GitOps、イベント駆動などを前提に、可観測性と弾力性を設計に織り込む⁵。両者は対立軸ではなく、移行フェーズとアーキテクチャの成熟度を示す座標であり、現実的には「リフト」→「最小のモダン化」→「本格ネイティブ化」と段階的に進めるのが再現性が高い⁴。
用語整理(技術仕様)
| 用語 | 定義 | 代表技術 | 適用判断軸 |
|---|---|---|---|
| クラウドリフト(再ホスト) | アプリはほぼ無改修でIaaS/コンテナへ移設 | EC2/Compute Engine、ECS/EKSで単一Pod | 短期移行、データセンター閉鎖期限、低リスク |
| リプラットフォーム | 軽微な改修でマネージド利用 | RDS/Cloud SQL、ElastiCache、ALB | 運用コスト低減、SLA向上、具体的な制約解除 |
| クラウドネイティブ | クラウド前提の分散設計 | Kubernetes、Service Mesh、Serverless、OTel | 伸縮性、MTTR短縮、デリバリー頻度向上 |
| 可観測性 | メトリクス/ログ/トレース統合 | OpenTelemetry、Prometheus、Grafana | p95遅延、エラー率、SLO/SLI運用 |
移行目的がデータセンター退出やEOL対応であるなら、まずはリフトで「止血」し、すぐに可観測性・CI/CD・キャッシュなどの低リスク改善を重ねる³⁴。ビジネス価値は、ダウンタイム削減と変更リードタイム短縮、インフラの弾力性による需要変動対応で回収する。
前提条件と移行手順(2〜6週間での現実解)
前提条件
- アプリはコンテナ化可能(POSIX準拠、ローカルFS依存は抽象化)
- ステートはRDB/オブジェクトストレージへ分離可能(NFS常駐排除)
- 最低限の計測基盤(OTel/Prometheus)を導入する意思決定
- DNS切替のためのTTL管理(300秒→60秒→30秒の段階短縮)²
実装手順
- ベースライン計測を確立(現行p50/p95、CPU/メモリ、エラー率、コスト/日)。
- コンテナ化と最小の設定外出し(環境変数・シークレット管理)。
- リフト先IaaS/コンテナ基盤をIaCで定義(セキュリティグループ/ネットワーク)。
- 可観測性SDKをアプリに組込み、トレースとメトリクスを収集。
- ヘルスチェックとリードネスを定義してローリング更新可能化。
- スモークテストと段階的トラフィック移送(10%→30%→100%)。
- ベンチマーク実施(k6/wrk)し、p95とエラー率を収集。
- 軽量の最適化(接続プール、タイムアウト、キャッシュ)を適用。
- コスト監視と自動スケーリングの閾値調整。
- 移行後のSLOを確立し、エラーバジェットで意思決定を運用化⁶。
コード例1: Dockerfile(最小のリフト準備)
# syntax=docker/dockerfile:1
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd -m appuser \
&& chown -R appuser:appuser /app
USER appuser
EXPOSE 8000
CMD ["gunicorn", "app:app", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000", "--timeout", "30"]
コード例2: Kubernetes Deployment(ヘルスチェック/リソース制御)
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 3
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: registry.example.com/app:1.0.0
ports:
- containerPort: 8000
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
readinessProbe:
httpGet:
path: /healthz
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /livez
port: 8000
initialDelaySeconds: 10
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: app
spec:
selector:
app: app
ports:
- name: http
port: 80
targetPort: 8000
type: ClusterIP
コード例3: FastAPI + OpenTelemetry + Redis(計測・キャッシュ・エラーハンドリング)
import os import asyncio from fastapi import FastAPI, HTTPException import httpx from redis.asyncio import Redis from tenacity import retry, stop_after_attempt, wait_exponential from opentelemetry import trace from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor from opentelemetry.sdk.resources import SERVICE_NAME, Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporterOTEL_ENDPOINT = os.getenv(“OTEL_EXPORTER_OTLP_ENDPOINT”, “http://otel:4318”) REDIS_URL = os.getenv(“REDIS_URL”, “redis://redis:6379/0”) UPSTREAM = os.getenv(“UPSTREAM”, “https://httpbin.org/delay/0.2”)
provider = TracerProvider(resource=Resource.create({SERVICE_NAME: “lifted-app”})) processor = BatchSpanProcessor(OTLPSpanExporter(endpoint=f”{OTEL_ENDPOINT}/v1/traces”)) provider.add_span_processor(processor) trace.set_tracer_provider(provider) tracer = trace.get_tracer(name)
app = FastAPI() FastAPIInstrumentor.instrument_app(app) HTTPXClientInstrumentor().instrument()
redis: Redis | None = None
@app.on_event(“startup”) async def on_startup(): global redis redis = Redis.from_url(REDIS_URL, encoding=“utf-8”, decode_responses=True)
@app.on_event(“shutdown”) async def on_shutdown(): if redis: await redis.close()
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=0.1, min=0.1, max=1.0)) async def fetch_with_retry(client: httpx.AsyncClient, url: str) -> str: try: resp = await client.get(url, timeout=2.0) resp.raise_for_status() return resp.text except httpx.HTTPError as e: # エラーハンドリング: リトライはtenacityに委譲 raise e
@app.get(“/healthz”) async def healthz(): return {“status”: “ok”}
@app.get(“/livez”) async def livez(): return {“status”: “alive”}
@app.get(“/api”) async def api(): cache_key = “upstream:latest” try: if redis: cached = await redis.get(cache_key) if cached: return {“source”: “cache”, “data”: cached} async with httpx.AsyncClient() as client: data = await fetch_with_retry(client, UPSTREAM) if redis: await redis.setex(cache_key, 5, data) return {“source”: “origin”, “data”: data} except Exception as e: # ビジネス上の影響を抑えるフォールバック raise HTTPException(status_code=502, detail=f”upstream error: {e}”)
コード例4: Go HTTPサーバ(タイムアウト・グレースフルシャットダウン)
package mainimport ( “context” “fmt” “log” “net/http” “os” “os/signal” “syscall” “time” )
func main() { mux := http.NewServeMux() mux.HandleFunc(“/healthz”, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) fmt.Fprint(w, “ok”) })
srv := &http.Server{ Addr: ":8000", Handler: mux, ReadHeaderTimeout: 3 * time.Second, ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, IdleTimeout: 60 * time.Second, } go func() { log.Println("server starting on :8000") if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %v", err) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) <-stop ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Printf("graceful shutdown failed: %v", err) } log.Println("server stopped")
}
コード例5: k6 ベンチマークスクリプト(p95収集)
import http from 'k6/http'; import { sleep } from 'k6';export const options = { vus: 50, duration: ‘2m’, thresholds: { http_req_failed: [‘rate<0.01’], http_req_duration: [‘p(95)<300’], }, };
export default function () { const res = http.get(${__ENV.TARGET || 'http://localhost'}/api); sleep(0.2); }
コード例6: Terraform(最小のEC2 + SGでリフト着地)
provider "aws" { region = var.region }resource “aws_security_group” “web” { name = “lift-web-sg” description = “Allow HTTP” ingress { from_port = 80 to_port = 80 protocol = “tcp” cidr_blocks = [“0.0.0.0/0”] } egress { from_port = 0 to_port = 0 protocol = “-1” cidr_blocks = [“0.0.0.0/0”] } }
resource “aws_instance” “lift” { ami = var.ami instance_type = “t3.small” vpc_security_group_ids = [aws_security_group.web.id] user_data = <<EOF #!/bin/bash apt-get update -y apt-get install -y docker.io systemctl start docker systemctl enable docker /usr/bin/docker run -d -p 80:8000 registry.example.com/app:1.0.0 EOF }
variable “region” { default = “ap-northeast-1” } variable “ami” {}
ベンチマーク結果と運用設計:指標・コスト・ROI
以下は、オンプレ(Baseline)、リフト直後(Lifted)、軽量最適化適用後(Optimized)の比較例である。いずれも50 VU/2分、HTTP keep-alive、CPU相当2vCPUで測定。重要なのは絶対値ではなく、改善の方向性と費用対効果の関係だ。なお、これらの結果は環境やワークロードに大きく依存する参考例であり、自社環境での再現性を保証するものではない(検証条件の違いにより数値は変動する)。
| 状態 | p50 (ms) | p95 (ms) | RPS | エラー率 | 月間推定コスト | RPSあたりコスト |
|---|---|---|---|---|---|---|
| Baseline | 95 | 420 | 380 | 0.8% | 固定費高 | 変動不可 |
| Lifted | 85 | 360 | 420 | 0.6% | 約$180/インスタンス | $0.00043 |
| Optimized | 70 | 240 | 520 | 0.3% | 約$200/インスタンス | $0.00038 |
パフォーマンス指標の要点:p95遅延はユーザ体感に直結するため優先度が高い。キャッシュ数秒の導入とHTTPクライアントのタイムアウト/リトライ整備だけでも、p95は顕著に改善することが多い。スループットはコア数だけでなく、スレッド/接続プールやGCチューニングの影響が支配的である。
運用指標(SLO/SLI): SLO=99.9%、対象SLIは「/api のp95 < 300ms」「エラー率 < 1%」。エラーバジェットは月間約43分であり、変更の凍結/解凍をこのバジェットで管理する⁶¹。デプロイはBlue/Greenまたは加重ルーティングで10%→30%→100%の段階移行とし、DNS/ALBのヘルスチェック合格後に昇格する。
コストとROI(例): ・現状オンプレ費 150万円/月、リフト後 IaaS 80万円/月、運用工数削減 40時間/月(時給8,000円で32万円/月)。合計削減=102万円/月。初期費用 500万円(設計/構築/教育)。単純回収期間=約4.9ヶ月。これらはあくまで試算例であり、契約条件・アーキテクチャ・トラフィックにより大きく変動する点に留意してほしい。ベースラインの可用性向上による機会損失削減は別途上乗せされ、回収はさらに短縮される。
よくある落とし穴と実装上のベストプラクティス
状態管理の取り扱いは最大の落とし穴である。セッションはCookie署名 + サーバレスストア(Redis/ElastiCache)へ退避し、ローカルディスクへの書き込みは/tmpの一時領域かオブジェクトストレージへ移す。ファイルロックに依存した設計は分散環境で破綻するため、DBによる分散ロックやIdempotency Keyへ置き換える。
ネットワークはタイムアウトとリトライを正規化する。クライアント側は接続プール上限、全体タイムアウト、指数バックオフ、サーキットブレーカーの順で適用し、サーバ側はキューの背圧と適切な429/503応答を返す。上記のFastAPI例は2秒の全体タイムアウトと3回の指数リトライを組み合わせ、フォールバックで502を返している。
ゼロダウンタイム切替には、以下の順で準備する。第一に、DNS TTLを7日以上前から段階的に短縮する²。第二に、新旧環境で同一のヘルスチェックエンドポイントを用意する。第三に、ステートマイグレーション(DBスキーマ/DMS/CDC)のリハーサルを2回以上行う。第四に、ログ/トレースの相関IDを跨いで追跡できるよう、Ingress/ALBでヘッダを透過する。
セキュリティはリフトでも前倒しでやる。最低限、 ・IAMは最小権限、 ・Secretsはマネージドストア(SSM/Secrets Manager)、 ・OSパッチは起動時適用、 ・通信は内部もTLS終端、 を方針として固定し、IaCにエンコードする。これにより「あとで直す」を避け、監査対応コストを平準化できる。
最後に、可観測性のデータから改善ループを回す。トレースでN+1や外部依存のホットスポットを特定し、k6で再現負荷をかけて最適化前後の差分を計測する。ダッシュボードは「ビジネスKPIに直結するSLI」を最上段に置き、開発チームが毎日見る運用習慣を作ることが、移行後のROIを最大化する近道である。
まとめ:まずは“計測できるリフト”、次に“素早い改善”
クラウドリフトは目的ではなく、クラウドネイティブへの現実的な入口だ。重要なのは、移行直後からp95・エラー率・コストを継続計測し、低リスクの改善(タイムアウト/リトライ、キャッシュ、ヘルスチェック、IaC化)を素早く重ねる運用リズムを確立することだ。あなたのシステムは、どの指標から着手すれば最も短期で効果が出るだろうか。次のアクションとして、既存サービスにOTelを1エンドポイントだけ組み込み、k6で2分の負荷試験を実施してベースラインを可視化してほしい。計測できれば、移行は意思決定の連続になり、結果としてROIは自然と向上する。
参考文献
- Oracle. Availability Percentages and Downtime. Oracle Fusion Middleware High Availability Guide. https://docs.oracle.com/cd/E23549_01/core.1111/b55898/intro.htm#:~:text=%E5%8F%AF%E7%94%A8%E6%80%A7%E3%81%AE%E5%89%B2%E5%90%88%20%20%7C%20%E5%B9%B4%E9%96%93%E5%81%9C%E6%AD%A2%E6%99%82%E9%96%93%E3%81%AE%E6%A6%82%E7%AE%97%20,%7C%201%E6%99%82%E9%96%93
- AWS. Best practices for Amazon Route 53. https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/best-practices-dns.html
- AWS Blog. The lift and shift: Rehosting servers to AWS during a cloud transformation. https://aws.amazon.com/jp/blogs/news/the-lift-and-shift-rehosting-servers-to-aws-during-a-cloud-transformation/
- NTT西日本 Biz Clip. クラウドリフト・クラウドシフトの考え方(リフト&シフト). https://business.ntt-west.co.jp/bizclip/articles/bcl00177-016.html
- NECソリューションイノベータ コラム. クラウドネイティブ技術と成果(CNCFのポリシー等). https://www.nec-solutioninnovators.co.jp/sp/contents/column/20220121b.html
- Google SRE Book. Service Level Objectives. https://sre.google/sre-book/service-level-objectives/
- 富士フイルム 公式FAQ. DNSの反映に関する一般的な注意(反映には時間がかかる場合がある). https://faq01-fb.fujifilm.com/faq/show/62437?site_domain=oars