30
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

閉域 VPC で ECR と ECS on Fargate を使えるようにする

Last updated at Posted at 2025-09-14

あるシステムで閉域 VPC の中で Elastic Container Service (ECS) を Fargate で使う必要が出てきたので、早速検証してみました。

閉域 VPC での ECS on Fargate 検証作業の流れ

ECS on Fargate の検証作業の大まかな流れは次のとおりです。

  1. 必要な VPC エンドポイントの作成
  2. Elastic Container Registry (ECR) レジストリの作成と VPC エンドポイント経由以外でのプッシュを禁止
  3. ローカル環境で Docker イメージをビルドして S3 へアップロード
  4. 閉域 VPC のプライベートサブネットに作業用 EC2 を立てて S3 の VPC エンドポイント経由で Docker イメージをコピーしてロード
  5. ECR の VPC エンドポイント経由で Docker イメージをプッシュ
  6. ECS でプライベートサブネットに Fargate タスクを起動

Auto Scaling や ELB の設定は今回しないことにします。

なお、環境は全て東京リージョン (ap-northeast-1) に作ることとします。

ECR と ECS 用の VPC エンドポイントを作成

今回 ECS は Fargate 起動タイプで実行します。

閉域 VPC から ECR へ Docker イメージを Push できるようにするため、ECR へのインターフェース型の VPC エンドポイントを作成します。作成するエンドポイントは次のとおりです。

  • com.amazonaws.ap-northeast-1.ecr.dkr
  • com.amazonaws.ap-northeast-1.ecr.api
  • com.amazonaws.ap-northeast-1.logs(ログに CloudWatch Logs を使う場合)

EC2 で ECS を実行する場合は、この他に ECS 関係の VPC エンドポイントが必要なようです。

その他に S3 への VPC エンドポイントも必要なので作成します。ゲートウェイ型エンドポイントにしておくとコストがかからずおすすめです。

検証用途のため、インターフェース型エンドポイントは作業終了後にまとめて消せるように、CloudFormation のスタックにしておきます。参考にテンプレートを載せます。

AWSTemplateFormatVersion: 2010-09-09
Description: CloudFormation Template for Create VPC Endpoint

Parameters:
  TargetVpcId:
    Description: Enter VPC ID
    Type: String
    Default: 'デフォルトの VPC ID'
  TargetSubnetId:
    Description: Enter Subnet ID
    Type: String
    Default: 'デフォルトのサブネット ID'

Resources:
  EcrDkrInterfaceEndpoint:
    Type: 'AWS::EC2::VPCEndpoint'
    Properties:
      VpcEndpointType: 'Interface'
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.dkr'
      VpcId: !Ref TargetVpcId
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref TargetSubnetId
      SecurityGroupIds:
        - !Ref VpceSecurityGroup

  EcrApiInterfaceEndpoint:
    Type: 'AWS::EC2::VPCEndpoint'
    Properties:
      VpcEndpointType: 'Interface'
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.api'
      VpcId: !Ref TargetVpcId
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref TargetSubnetId
      SecurityGroupIds:
        - !Ref VpceSecurityGroup

  LogInterfaceEndpoint:
    Type: 'AWS::EC2::VPCEndpoint'
    Properties:
      VpcEndpointType: 'Interface'
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.logs'
      VpcId: !Ref TargetVpcId
      PrivateDnsEnabled: true
      SubnetIds:
        - !Ref TargetSubnetId
      SecurityGroupIds:
        - !Ref VpceSecurityGroup

  VpceSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: 'Allow HTTPS traffic from the VPC'
      GroupName: test01-dev-sg-ecr-ap-vpce
      VpcId: !Ref TargetVpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 10.128.128.0/20

ECR にリポジトリを作成する

ECR のマネジメントコンソールから ECR のプライベートレジストリにリポジトリを作成します。ここではリポジトリ名は「test01/repo-keycloak」としました。

スクリーンショット 2025-09-13 22.34.56.png

この時、プライベートレジストリのアクセス許可に特定の VPC エンドポイントからのみのアクセスを許可する設定をすることで、インターネット経由でのプライベートレジストリへのアクセスを禁止します。

ECR のマネジメントコンソールから「プライベートレジストリ」→「許可」に進み、以下のような JSON を編集します。

{
  "Sid": "DenyExceptSpecificVPCEndpoint",
  "Effect": "Deny",
  "Principal": "*",
  "Action": "ecr:*",
  "Resource": "*",
  "Condition": {
    "StringNotEquals": {
      "aws:SourceVpce": [
        "com.amazonaws.ap-northeast-1.ecr.api の VPC エンドポイント ID",
        "com.amazonaws.ap-northeast-1.ecr.dkr の VPC エンドポイント ID"
      ]
    }
  }
}

キャプチャの例では保守用に特定の IAM ロールの場合の除外設定を入れていますが気にしないでください。

スクリーンショット 2025-09-14 16.42.53.png

検証用の Docker イメージを S3 へアップロードする

検証用の Docker イメージなので何でもいいのですが、今回は認証認可サーバーとしてよく使われる Keycloak のイメージを使うことにしました。

インターネット接続可能なローカルの環境にて Keycloack 公式サイト の手順でローカルに Keycloak の Docker コンテナを実行します。今回 Mac で実行したので、アーキテクチャが Linux/ARM64 になることを意識しておきます。

$ docker run -p 127.0.0.1:8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.3.4 start-dev

一旦コンテナを停止して、Docker イメージを tar にアーカイブし、s3 へアップロードします。

$ docker save 'イメージ ID' > keycloak.26.3.4.tar
$ aws s3 cp keycloak.26.3.4.tar s3://'アップロード先の S3 バケット' --profile 'プロファイル名'

ここからは基本的にインターネット接続のできない閉域 VPC にて作業していきます。

作業用 EC2 の設定

閉域 VPC から ECR へ Docker イメージをプッシュするため、この作業は VPC 内の EC2 インスタンスから実施します。

閉域 VPC のプライベートサブネットに EC2 インスタンスを起動します。ここではアーキテクチャが Graviton の Amazon Linux 2023 でインスタンスを起動しました。

IAM ロールのアタッチ

このインスタンスには、S3 にアクセス可能で、以下の ECR のアクションが許可されたポリシーを割り当てた IAM ロールをアタッチしておきます。

  • ecr:GetAuthorizationToken
  • ecr:InitiateLayerUpload
  • ecr:UploadLayerPart
  • ecr:CompleteLayerUpload
  • ecr:ListImages
  • ecr:PutImage
  • ecr:DescribeImages
  • ecr:BatchCheckLayerAvailability

ecr:BatchCheckLayerAvailability については、AWS CLI から ECR へイメージをプッシュするには不要という情報があったのですが、私の環境ではこれを追加しないと 'error parsing HTTP 403 response body: unexpected end of JSON input: ""' となってしまい、プッシュが成功しませんでした。

Docker のインストール

作業用の EC2 インスタンスに、Docker をインストールします。Amazon Linux 2023 だと次のとおりです。なお、このインスタンスはプライベートサブネットにあるためインターネット接続ができませんが、事前に S3 の VPC エンドポイントを作成すれば dnf からパッケージのダウンロードが可能です。

$ sudo dnf update
$ sudo dnf install docker
$ sudo systemctl start docker
$ sudo systemctl enable docker
$ sudo usermod -aG docker ec2-user

Docker イメージのロード

S3 から先ほどアップロードした tar ファイルになっている Docker イメージを S3 の VPC エンドポイント経由でダウンロードし、Docker にロードします。

$ aws s3 cp s3://'アップロード先の S3 バケット' .
$ docker load < keycloak.26.3.4.tar

Docker イメージを ECR へプッシュする

Docker イメージの ECR リポジトリへのプッシュは、マネジメントコンソールにサンプルのコマンドが表示されますので、これを参考に作業します。

スクリーンショット 2025-09-13 22.55.53.png

まずは Keycloak の Docker イメージの名前を ECR に作成したリポジトリと合わせて変更します。

$ docker tag 'Docker イメージの ID' 'AWS アカウント ID'.dkr.ecr.ap-northeast-1.amazonaws.com/'リポジトリ名':latest 

作業用 EC2 インスタンスの Docker クライアントを VPC エンドポイント経由で ECR に認証します。AWS CLI から次のコマンドを実行します。

$ aws ecr get-login-password | docker login --username AWS --password-stdin 'AWS アカウント ID'.dkr.ecr.ap-northeast-1.amazonaws.com

ログインに成功したら、Docker イメージを ECR リポジトリにプッシュします。

$ docker push 'AWS アカウント ID'.dkr.ecr.ap-northeast-1.amazonaws.com/test01/repo-keycloak:latest

ここでエラーが出る場合は VPC エンドポイントが足りてないか、IAM ロールに権限が不足しているかの可能性が高いと思います。(何度も嵌りました)

Docker イメージを ECR のリポジトリへプッシュできたら、次は ECS の設定です。

ECS on Fargate の設定

ECS クラスターの作成

ECS のマネジメントコンソールからクラスターを作成します。インフラストラクチャは「AWS Fargate」を選びます。

スクリーンショット 2025-09-14 13.13.18.png

実はマネジメントコンソールからクラスターを作成すると、初回は以下のキャプチャのようなエラーが出ます。これはクラスター作成時に裏で CloudFormation のスタックが動いており、この中でクラスターの作成に必要な IAM ロール (AWSServiceRoleForECS) が作られるのですが、これが無いために失敗しているようです。

スクリーンショット 2025-09-14 13.16.34.png

この場合、CloudFormation のマネジメントコンソールからエラーとなっているスタックを削除してから、再度クラスターを作成することで今度は IAM ロールが作成済みのため、クラスターの作成に成功します。

スクリーンショット 2025-09-14 13.25.21.png

ECS タスク定義の作成

次にタスク定義を作成します。「起動タイプ」は「AWS Fargate」、「オペレーティングシステム/アーキテクチャ」は「Linux/ARM64」とします。

スクリーンショット 2025-09-14 17.53.05.png

「タスク実行ロール」は、自動作成してもらうことにします。事前に適切な IAM ロールを作成済みであればそれを選択します。

スクリーンショット 2025-09-14 17.55.10.png

次にコンテナの設定です。「イメージ URI」には ECR にプッシュ済みの Docker イメージを選択します。Keycloak のコンテナは TCP:8080 でサービスを待ち受けているので、ポートマッピングをそのように設定します。

スクリーンショット 2025-09-14 13.43.34.png

環境変数には Keycloack 公式サイト を参考に、「KC_BOOTSTRAP_ADMIN_USERNAME」「KC_BOOTSTRAP_ADMIN_PASSWORD」の値を渡します(検証ではなく本番であれば Parameter Store などで値を渡した方が良いと思います。)

スクリーンショット 2025-09-14 14.11.23.png

ログの設定はデフォルトで CloudWatch になっているのでそのままにしました。

スクリーンショット 2025-09-14 13.44.37.png

CloudWatch Logs にロググループが作成されます。このため閉域 VPC で ECS を動かす場合は CloudWatch Logs への VPC エンドポイントを作成する必要があるわけです。

スクリーンショット 2025-09-15 10.13.06.png

コンテナに渡すコマンドを指定します。これも Keycloak 公式サイトのとおり、検証用なので「start-dev」を渡します。

スクリーンショット 2025-09-14 15.06.21.png

ECS サービスの作成

タスク定義が作成できたら、サービスを作成します。「既存のクラスター」に作成したクラスターを、「起動タイプ」は「FARGATE」を選びます。

スクリーンショット 2025-09-14 13.48.23.png

コンテナを起動するネットワークを設定します。併せてコンテナに割り当てるセキュリティグループも作ってしまいます。

プライベートサブネット内なのでパブリック IP アドレスの割当てはオフにします。

スクリーンショット 2025-09-14 13.50.54.png

サービスが作成できました。

スクリーンショット 2025-09-14 15.12.00.png

サービスにアクセスするためのプライベート IP アドレスを確認します。

スクリーンショット 2025-09-14 15.14.05.png

確認したプライベート IP アドレスの 8080 番ポートへ、閉域 VPC と接続されたオンプレミスにあるクライアントの Web ブラウザからアクセスしてみます。

スクリーンショット 2025-09-14 15.15.45.png

閉域 VPC の中でも ECS on Fargate のコンテナで Keycloak が実行できていることが確認できました。

ECS on Fargate を構築してみた感想

Fargate の利点は Docker ホストとなるサーバー自体の管理をマネージドでやってくれるため、管理しなくて済むことです。今回は構築しただけなのでその真価は感じられていないですが、インフラをタスクとして定義できるのは運用がかなり楽になるのではと思いました。

一方、閉域の VPC 内で構築するには、ECR にインターネット経由でアクセスできないようにしたり、VPC エンドポイントをいくつか作成する必要があったり、土台の環境を作るのに若干の面倒さがありました。

今回、Fargate の運用面にはほとんど触れられなかったので、引き続き検証を続けてみたいと思います。

ちなみに Keycloak 自体の構築について興味があれば、以下の記事で少し解説していますので参考にしてみてください。

30
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?