Fargateの所属サブネットを変更する。

# はじめに
先日、ブルーグリーンデプロイを行っているFargateサービスのIPアドレスが足りなくなったので、セカンダリCIDRを作ってサブネットを追加して、GUIの設定画面から追加しようとしたところ、GUIからは追加できず、CLIから所属サブネットを追加する必要があったため、CLIで所属サブネットを変更する際の手順をまとめておきます。

## Fargateでのサブネット変更方法
Fargateのネットワーク変更は前述した通り、GUIの設定画面から追加・修正することができず、CLIでの操作を行う必要があります。

また、ローリングアップデート構成の場合と、ブルーグリーンデプロイ構成の場合で所属サブネットを変更するやり方が異なるため、それぞれ紹介します。

- [ローリングアップデート構成のFargateサービスのサブネット変更](#ローリングアップデート構成のfargateサービスのサブネット変更)
    - [サブネットを追加する場合と削除する場合の動作の違い](#サブネットを追加する場合と削除する場合の動作の違い)
- [ブルーグリーンデプロイ構成のFargateサービスのサブネット変更](#ブルーグリーンデプロイ構成のfargateサービスのサブネット変更)
    - [appspec.ymlの準備](#appspecymlの準備)
    - [appspec.ymlのアップロード](#appspecymlのアップロード)
    - [create-deployment.jsonの準備](#create-deploymentjsonの準備)
    - [CodeDeployの実行](#codedeployの実行)

## ローリングアップデート構成のFargateサービスのサブネット変更
Fargateをローリングアップデート構成で運用している場合、`aws ecs update-service`コマンドでECSサービスの設定を更新することで所属サブネットの追加・削除・変更が可能です。

但し、注意点として、サブネットの構成を変更するためには`networkConfiguration`オプションの`awsvpcConfiguration`に含まれる`subnets`にサブネットを指定することで更新できますが、同列の設定項目として`securityGroups`、`assignPublicIp`の設定も含まれております。
※以下`aws ecs describe-services`での設定確認結果抜粋

```json:networkConfiguration項目の抜粋
（設定抜粋）
                    "networkConfiguration": {
                        "awsvpcConfiguration": {
                            "subnets": [
                                "subnet-0fc5f6e4998d944fa",
                                "subnet-0204f19c2ef706488"
                            ],
                            "securityGroups": [
                                "sg-0e386ecaf896d33f5"
                            ],
                            "assignPublicIp": "ENABLED"
                        }
                    },
```

今回のサブネット変更の場合、設定としては`awsvpcConfiguration`の要素の部分を丸ごと差し替える方式となるため、セキュリティグループやパブリックIPの使用有無の設定を変更しない場合でも、指定するようにしてください。

:::note info
コマンド実行時、`securityGroups`、`assignPublicIp`の指定をしなくても実行することは可能ですが、その場合、`securityGroups`、`assignPublicIp`の値にはデフォルト値が設定されてしまうため、必ず明示的に設定するようにしましょう。
:::

上記の内容を踏まえて、元々2サブネット（`subnet-0fc5f6e4998d944fa`、`subnet-0204f19c2ef706488`）だった設定を3サブネット（`subnet-03c99b7d22ff1ce5b`を追加）に変更した場合のコマンドは以下となります。
※各種ID等の設定は環境に合わせて適宜変更してください。

```bash:Fargateサービスの所属サブネット変更（ローリングアップデート構成）
aws ecs update-service --cluster test-cluster \
--service test-service \
--network-configuration "awsvpcConfiguration={ \
    subnets=[subnet-070d590a86b69d654, subnet-05e48b5ea5ba86313, subnet-03c99b7d22ff1ce5b], \
    securityGroups=[sg-0e386ecaf896d33f5], \
    assignPublicIp=ENABLED \
}"
```

- コマンド参考
    - [AWS CLI Command Refelence aws ecs update-service](https://docs.aws.amazon.com/cli/latest/reference/ecs/update-service.html)

### サブネットを追加する場合と削除する場合の動作の違い

実際に試してみたところ、サブネットを追加する場合と削除する場合で以下のようにコマンド実行後の動作が異なっておりました。

|操作|コマンド実行後動作|
|:--|:--|
|所属サブネットを追加した場合|何もなし|
|所属サブネットを削除した場合|タスクのローリングアップデート|

新たにサブネットを追加した場合は特に何も変化はありませんでしたが、サブネットを減らした場合はローリングアップデートが行われ、タスクが入れ替えられました。

サブネットを減らした場合は既に起動中のタスクが所属するサブネットか否かにかかわらず、タスクの入れ替えが発生したため、サブネットを減らす場合にはご注意ください。

:::note info
サブネット1とサブネット2だった設定をサブネット1とサブネット3に変更した場合も、サブネット2が削除された扱いとなるため、タスクの入れ替えが発生します。
:::

## ブルーグリーンデプロイ構成のFargateサービスのサブネット変更
Fargateをブルーグリーンデプロイ構成で運用している場合、ローリングアップデート構成の場合と異なり、コマンド一発で変更することができず、CodeDeployでデプロイする際に使用する`appspec.yml`ファイルを使ってブルーグリーンデプロイし直すことで所属サブネットの追加・削除・変更を行う必要があります。

- [CLI で CreateDeployment を使用する](https://docs.aws.amazon.com/ja_jp/code-library/latest/ug/codedeploy_example_codedeploy_CreateDeployment_section.html)

### appspec.ymlの準備
CodeDeployをCLIで実行する場合には、デプロイを実行する際のデプロイ構成・設定が記載されている`appspec.yml`を準備する必要があります。

所属サブネットを変更する場合、`appspec.yml`にネットワークの設定を記載することで、デプロイ時のネットワーク設定を変更します。

ネットワークの設定としてはローリングアップデートの場合と同じく`NetworkConfiguration`オプションの`AwsvpcConfiguration`に含まれる`Subnets`にサブネットを指定するやり方となりますが、ローリングアップデートの場合と同様の理由で、`SecurityGroups`、`AssignPublicIp`の設定も行うようにしてください。

また、ローリングアップデートの場合と異なり、ブルーグリーンデプロイの場合はタスク定義やロードバランサーの指定も必要となります。

上記の内容を踏まえて、先ほどと同様2サブネット→3サブネットに変更した場合の`appspec.yml`は以下となります。
※各種ID等の設定は環境に合わせて適宜変更してください。

```yml:appspec.yml
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/task-definition:1"
        LoadBalancerInfo:
          ContainerName: "nginx"
          ContainerPort: 80
        NetworkConfiguration:
          AwsvpcConfiguration:
            Subnets: ["subnet-070d590a86b69d654","subnet-05e48b5ea5ba86313","subnet-03c99b7d22ff1ce5b"]
            SecurityGroups: ["sg-0e386ecaf896d33f5"]
            AssignPublicIp: "ENABLED"
```

`TaskDefinition`については、末尾のリビジョン番号を除けば最新リビジョンが選択されます。

また、`ContainerName`は、Web等のサービスを提供しているコンテナ名（今回の場合は`nginx`）を指定します。

- appspec.yml参考
    - [Amazon ECS デプロイの AppSpec ファイルの例](https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-example.html#appspec-file-example-ecs)
    - [CLI で CreateDeployment を使用する](https://docs.aws.amazon.com/ja_jp/code-library/latest/ug/codedeploy_example_codedeploy_CreateDeployment_section.html)

### appspec.ymlのアップロード

`appspec.yml`はS3バケットやGitHubのリポジトリ等、CodeDeploy時に読み取れる場所に格納する必要があるため、今回は適当なS3バケットに`appspec.yml`をアップロードします。

```bash:S3バケットへのアップロード
aws s3 cp ./appspec.yml s3://deploy-s3-bucket/appspec.yml
```

指定できる場所の種類については以下参照。

- [RevisionLocation](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/APIReference/API_RevisionLocation.html)

### create-deployment.jsonの準備

`appspec.yml`でCodeDeployによるデプロイを実行する際のデプロイ構成・設定について定義しましたが、`create-deployment.json`ではどのCodeDeployアプリケーション、デプロイグループを使用するかを指定します。

なお、`create-deploymet.json`については`appspec.yml`と違い、S3バケット等に格納する必要はなく、CLIを実行する際にCLIを実行する端末から指定できれば良いので、ローカルに作成しておきます。

```json:create-deployment.json
{
    "applicationName": "codedeploy-deploy-app",
    "deploymentGroupName": "codedeploy-deploy-group",
    "revision": {
        "revisionType": "S3",
        "s3Location": {
            "bucket": "deploy-s3-bucket",
            "key": "appspec.yml",
            "bundleType": "YAML"
        }
    }
}
```

- 参考
    - [ブルー/グリーンデプロイを使用した Amazon ECS サービスのデプロイ](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/create-blue-green.html)

### CodeDeployの実行

先ほど作成したデプロイ用ファイルを指定してCLIでCodeDeployを実行します。

今回は`create-deployment.json`をローカルに作成したため、`file://`でローカルファイルを指定します。

```bash:コマンドからのCodeDeploy実行
aws deploy create-deployment --cli-input-json file://create-deployment.json
```

実行後、以下のようにデプロイIDが表示されたら、CodeDeployが実行されているはずなので、CodeDeployの画面に移動してブルーグリーンデプロイの操作を行ってください。

```json:コマンド実行時の出力例
{
    "deploymentId": "d-XXXXXXXXX"
}
```

![Monosnap_20250522_085309.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/32f6308c-a1aa-4f46-828e-bf209ae255e9.png)

デプロイ完了後、ECSサービスのネットワーク設定を確認すると、サブネット構成が変更されていることが確認できます。

![Monosnap_20250522_085704.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/d479bbeb-dc2d-483c-a9f6-100ed4b660bc.png)

# おわりに
ECSのサービス設定をした後、変更することはあまりないと思いますが、変更するとなった場合、簡単に変更することができないため、もし変更する事になった場合は今回の記事を参考にしていただければと思います。