𝕏 f B! L
案件・求人数 12,345
案件を探す(準備中) エージェントを探す(準備中) お役立ち情報 ログイン
案件・求人数 12,345
AWS App Runnerコンテナ実行完全ガイド|コンテナデプロイ・オートスケール・CI/CD連携【SES案件対応】

AWS App Runnerコンテナ実行完全ガイド|コンテナデプロイ・オートスケール・CI/CD連携【SES案件対応】

AWSApp RunnerコンテナデプロイSES
目次

「コンテナアプリをAWSにデプロイしたいけど、ECSやEKSは設定が複雑すぎる」「もっと手軽にコンテナを動かしたい」——こうした悩みを持つSESエンジニアに最適なのが、AWS App Runnerです。

結論から言えば、AWS App Runnerを使えばコンテナイメージまたはソースコードからわずか数ステップでWebアプリケーションをデプロイできます。本記事では、基本的な使い方からオートスケール設定、CI/CD連携まで実践的に解説します。

この記事を3秒でまとめると

  • App RunnerはECS/EKSより圧倒的にシンプルなコンテナ実行サービス
  • ECR連携で自動デプロイ、オートスケーリングも組み込み済み
  • VPC Connectorで既存のRDS/ElastiCacheとも安全に接続可能

AWS App Runnerアーキテクチャの全体像

AWS App Runnerとは

AWS App Runnerは、2021年にリリースされたフルマネージドのコンテナ実行サービスです。コンテナイメージまたはソースコード(Python、Node.js、Java等)を指定するだけで、ロードバランシング・オートスケーリング・TLS終端が自動的に設定されます。

App Runner vs ECS vs EKS:どう使い分ける?

比較項目App RunnerECS (Fargate)EKS
学習コスト★☆☆(低い)★★☆(中程度)★★★(高い)
カスタマイズ性★☆☆(限定的)★★☆(中程度)★★★(高い)
運用負荷★☆☆(低い)★★☆(中程度)★★★(高い)
コスト効率(小規模)★★★(最良)★★☆★☆☆
コスト効率(大規模)★★☆★★★(最良)★★★(最良)
向いている用途WebAPI、マイクロサービス本番ワークロード大規模・マルチテナント

App Runnerが最適なケース:

  • プロトタイプやMVPの素早いデプロイ
  • 小〜中規模のWebAPI・マイクロサービス
  • インフラ管理を最小限にしたいチーム
  • SES案件での開発環境・検証環境の構築

SES案件でのApp Runner需要

App Runnerの登場により、コンテナデプロイの民主化が進んでいます。

  • スタートアップ案件: MVPを最短でリリースしたい
  • マイクロサービス移行案件: 小さなサービスから段階的にコンテナ化
  • 開発環境構築: PR単位の一時環境をApp Runnerで自動構築
  • 内部ツール: 管理画面やダッシュボードの社内デプロイ

App Runnerの基本的な使い方

ECRからのデプロイ

まず、コンテナイメージをECRにプッシュし、App Runnerにデプロイする基本フローを見ていきましょう。

Dockerfile例(Node.js Express API):

# マルチステージビルド
FROM node:22-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build

FROM node:22-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

# App Runnerはポート8080をデフォルトで使用
EXPOSE 8080
CMD ["node", "dist/server.js"]

ECRへのプッシュとApp Runnerの作成:

# ECRリポジトリ作成
aws ecr create-repository --repository-name my-api

# Dockerイメージのビルドとプッシュ
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION=ap-northeast-1
ECR_URL="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com"

aws ecr get-login-password --region $REGION | \
  docker login --username AWS --password-stdin $ECR_URL

docker build -t my-api .
docker tag my-api:latest ${ECR_URL}/my-api:latest
docker push ${ECR_URL}/my-api:latest

# App Runnerサービス作成
aws apprunner create-service \
  --service-name my-api \
  --source-configuration '{
    "AuthenticationConfiguration": {
      "AccessRoleArn": "arn:aws:iam::'$ACCOUNT_ID':role/AppRunnerECRAccessRole"
    },
    "AutoDeploymentsEnabled": true,
    "ImageRepository": {
      "ImageIdentifier": "'$ECR_URL'/my-api:latest",
      "ImageConfiguration": {
        "Port": "8080",
        "RuntimeEnvironmentVariables": {
          "NODE_ENV": "production",
          "DATABASE_URL": "postgresql://..."
        }
      },
      "ImageRepositoryType": "ECR"
    }
  }' \
  --instance-configuration '{
    "Cpu": "1024",
    "Memory": "2048",
    "InstanceRoleArn": "arn:aws:iam::'$ACCOUNT_ID':role/AppRunnerInstanceRole"
  }' \
  --health-check-configuration '{
    "Protocol": "HTTP",
    "Path": "/health",
    "Interval": 10,
    "Timeout": 5,
    "HealthyThreshold": 1,
    "UnhealthyThreshold": 5
  }'

ソースコードからのデプロイ

GitHubリポジトリを直接指定してデプロイすることもできます。

aws apprunner create-service \
  --service-name my-api-from-source \
  --source-configuration '{
    "AuthenticationConfiguration": {
      "ConnectionArn": "arn:aws:apprunner:'$REGION':'$ACCOUNT_ID':connection/github/..."
    },
    "AutoDeploymentsEnabled": true,
    "CodeRepository": {
      "RepositoryUrl": "https://github.com/your-org/your-repo",
      "SourceCodeVersion": {
        "Type": "BRANCH",
        "Value": "main"
      },
      "CodeConfiguration": {
        "ConfigurationSource": "API",
        "CodeConfigurationValues": {
          "Runtime": "NODEJS_18",
          "BuildCommand": "npm ci && npm run build",
          "StartCommand": "npm start",
          "Port": "8080"
        }
      }
    }
  }'

オートスケーリングの設定

App Runnerのオートスケーリングは、同時リクエスト数に基づいて自動的にインスタンスを増減します。

# オートスケーリング設定の作成
aws apprunner create-auto-scaling-configuration \
  --auto-scaling-configuration-name my-api-scaling \
  --max-concurrency 100 \
  --min-size 1 \
  --max-size 10

# サービスに適用
aws apprunner update-service \
  --service-arn $SERVICE_ARN \
  --auto-scaling-configuration-arn $AUTO_SCALING_ARN

スケーリングの仕組み

パラメータ説明デフォルト値推奨設定
MaxConcurrencyインスタンスあたりの最大同時リクエスト数10050〜200
MinSize最小インスタンス数11(コスト重視)/ 2(可用性重視)
MaxSize最大インスタンス数25ワークロードに応じて設定

コールドスタート対策: App Runnerでは、MinSizeを1以上に設定しておくことで、常に少なくとも1つのインスタンスがウォーム状態を維持します。これにより、初回リクエストのレイテンシが大幅に改善されます。

VPC Connectorで内部リソースに接続する

App Runnerはデフォルトではパブリックなネットワークで動作しますが、VPC Connectorを使うことでプライベートサブネット内のRDSやElastiCacheに安全に接続できます。

# VPC Connector作成
aws apprunner create-vpc-connector \
  --vpc-connector-name my-vpc-connector \
  --subnets subnet-xxx subnet-yyy \
  --security-groups sg-zzz

# サービスにVPC Connectorを関連付け
aws apprunner update-service \
  --service-arn $SERVICE_ARN \
  --network-configuration '{
    "EgressConfiguration": {
      "EgressType": "VPC",
      "VpcConnectorArn": "'$VPC_CONNECTOR_ARN'"
    }
  }'

RDSとの接続パターン

// src/lib/database.ts
import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 20,
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 5000,
  // App RunnerのVPC Connector経由でRDSに接続
  ssl: process.env.NODE_ENV === 'production'
    ? { rejectUnauthorized: false }
    : undefined,
});

export async function query(text: string, params?: any[]) {
  const client = await pool.connect();
  try {
    const result = await client.query(text, params);
    return result;
  } finally {
    client.release();
  }
}

カスタムドメインとHTTPS

App Runnerでは、カスタムドメインの設定も簡単です。

# カスタムドメインの関連付け
aws apprunner associate-custom-domain \
  --service-arn $SERVICE_ARN \
  --domain-name api.example.com \
  --enable-www-subdomain

# DNS設定の確認
aws apprunner describe-custom-domains \
  --service-arn $SERVICE_ARN \
  --query 'CustomDomains[].{Domain:DomainName,Status:Status,Records:CertificateValidationRecords}'

DNS設定後、ACM証明書が自動的に発行・管理されます。手動での証明書更新は不要です。

CI/CDパイプラインの構築

GitHub Actionsでの自動デプロイ

# .github/workflows/deploy.yml
name: Deploy to App Runner

on:
  push:
    branches: [main]

env:
  AWS_REGION: ap-northeast-1
  ECR_REPOSITORY: my-api
  SERVICE_NAME: my-api

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to ECR
        id: ecr-login
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and push image
        env:
          ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG \
                     $ECR_REGISTRY/$ECR_REPOSITORY:latest
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest

      - name: Wait for App Runner deployment
        run: |
          # AutoDeployment有効の場合、ECRプッシュで自動デプロイ
          echo "Waiting for App Runner auto-deployment..."
          sleep 30
          STATUS=""
          for i in $(seq 1 30); do
            STATUS=$(aws apprunner describe-service \
              --service-arn ${{ secrets.APP_RUNNER_ARN }} \
              --query 'Service.Status' --output text)
            echo "Status: $STATUS (attempt $i)"
            if [ "$STATUS" = "RUNNING" ]; then
              echo "Deployment successful!"
              break
            fi
            sleep 10
          done
          if [ "$STATUS" != "RUNNING" ]; then
            echo "Deployment timeout"
            exit 1
          fi

CDKでのインフラ定義

// lib/app-runner-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as apprunner from '@aws-cdk/aws-apprunner-alpha';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';

export class AppRunnerStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const vpc = ec2.Vpc.fromLookup(this, 'Vpc', {
      vpcId: 'vpc-xxx',
    });

    const repository = ecr.Repository.fromRepositoryName(
      this, 'Repo', 'my-api'
    );

    const vpcConnector = new apprunner.VpcConnector(
      this, 'VpcConnector', {
        vpc,
        vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
      }
    );

    const service = new apprunner.Service(this, 'ApiService', {
      serviceName: 'my-api',
      source: apprunner.Source.fromEcr({
        repository,
        imageConfiguration: {
          port: 8080,
          environmentVariables: {
            NODE_ENV: 'production',
          },
        },
        tagOrDigest: 'latest',
      }),
      cpu: apprunner.Cpu.ONE_VCPU,
      memory: apprunner.Memory.TWO_GB,
      vpcConnector,
      autoDeploymentsEnabled: true,
      healthCheck: apprunner.HealthCheck.http({
        path: '/health',
        interval: cdk.Duration.seconds(10),
      }),
    });

    new cdk.CfnOutput(this, 'ServiceUrl', {
      value: service.serviceUrl,
    });
  }
}

Observabilityの設定

CloudWatch連携

App Runnerは自動的にCloudWatch Logsにログを送信します。メトリクスも標準で利用可能です。

# ログの確認
aws logs get-log-events \
  --log-group-name "/aws/apprunner/my-api/${SERVICE_ID}/application" \
  --log-stream-name "instance/..." \
  --limit 50

# メトリクスの確認
aws cloudwatch get-metric-statistics \
  --namespace "AWS/AppRunner" \
  --metric-name "RequestCount" \
  --dimensions Name=ServiceName,Value=my-api \
  --start-time $(date -u -v-1H '+%Y-%m-%dT%H:%M:%SZ') \
  --end-time $(date -u '+%Y-%m-%dT%H:%M:%SZ') \
  --period 300 \
  --statistics Sum

X-Rayトレーシング

// src/tracing.ts
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';

const provider = new NodeTracerProvider();

provider.addSpanProcessor(
  new BatchSpanProcessor(
    new OTLPTraceExporter({
      url: 'https://xray.ap-northeast-1.amazonaws.com',
    })
  )
);

provider.register({
  propagator: new AWSXRayPropagator(),
});

コスト最適化

App Runnerの料金体系

リソース料金(東京リージョン)
vCPU(アクティブ時)$0.081/vCPU-時間
vCPU(一時停止時)$0.008/GB-時間
メモリ$0.009/GB-時間
自動デプロイ$1/月/サービス

月額コスト試算(1 vCPU / 2GB メモリ):

  • 常時稼働: 約$65/月
  • 日中のみ稼働(12h/日): 約$35/月
  • MinSize=0の完全従量制: トラフィックに応じて変動

コスト削減のテクニック

  1. MinSizeを0に設定: トラフィックがない時間帯のコストをゼロに
  2. 適切なCPU/メモリ設定: オーバープロビジョニングを避ける
  3. MaxConcurrencyの最適化: インスタンスあたりの処理効率を最大化
  4. 自動一時停止: 開発環境は使用時のみアクティブに

まとめ:App Runnerでコンテナデプロイをシンプルにしよう

AWS App Runnerは、コンテナアプリケーションのデプロイを極限まで簡素化するサービスです。ECS/EKSの複雑な設定なしに、本番品質のコンテナ実行環境を数分で構築できます。

SESエンジニアにとって、App Runnerの知識はコンテナ案件への参入障壁を大きく下げます。ECS/EKSの経験がなくても、App Runnerから始めてコンテナ技術のスキルを積み上げていけます。

AWSの基本はAWS入門ガイドを、ECSについてはAWS ECS Fargateガイドをご覧ください。CI/CD全般はAWS CodePipelineガイド、コスト最適化はAWS FinOpsガイドが参考になります。

SES案件をお探しですか?

SES記事をもっと読む →
🏗️

SES BASE 編集長

SES業界歴10年以上のメンバーが在籍する編集チーム。SES企業での営業・エンジニア経験、フリーランス独立経験を持つメンバーが、業界のリアルな情報をお届けします。

📊 業界データに基づく記事制作 🔍 IPA・経済産業省データ参照 💼 SES実務経験者が執筆・監修