TerraformでECS Fargate構築

## はじめに
先日投稿したECS FargateでWordPressを構築したパラメータを使用してTerraformでのデプロイを実践してみました。

## 構成
![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/eb9046fe-655a-4f1a-a014-79ab9b130fc7.png)

### ディレクトリ構成
```
├── terraform/
│   ├── main.tf                 
│   ├── terraform.tfvars                            
│
├── modules/                    
│   ├── vpc/                    
│   │   ├── main.tf             
│   │   ├── variables.tf        
│   │   └── outputs.tf          
│   ├── ecs/
│   │   ├── main.tf             
│   │   ├── variables.tf        
│   ├── rds/
│   │   ├── main.tf             
│   │   ├── variables.tf        
│   │   └── outputs.tf
│   ├── alb/
│   │   ├── main.tf             
│   │   ├── variables.tf        
│   │   └── outputs.tf
│   ├── cloudfront/
│   │   ├── main.tf             
│   │   ├── variables.tf        
│   │   └── outputs.tf
│   ├── route53/
│   │   ├── main.tf             
│   │   ├── variables.tf        
│   │   └── outputs.tf          
│
│             
├── .gitignore               
└── README.md 
```

## Terraform
#### ECSは本記事で掲載しますが、前提となるリソースは下記リポジトリをご参照ください
 ※一部ハードコーディングあり

https://github.com/ryt117/fargate_wordpress
 
#### ../modules/ecs/main.tf
```
# ECSクラスタ
resource "aws_ecs_cluster" "this" {
  name = "wordpress"
}

# タスク定義
resource "aws_ecs_task_definition" "wordpress" {
  family = "wordpress-difinition"
  requires_compatibilities = ["FARGATE"]
  cpu = "1024"
  memory = "2048"
  network_mode = "awsvpc"
  execution_role_arn = "arn:aws:iam::<アカウントID>:role/ecsTaskExecutionRole" # タスク実行ロール 

  container_definitions = jsonencode([
    {
      name = "wordpress"
      image = "<アカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/wordpress:latest" # URI 
      essential = true
      portMappings = [
        {
          containerPort = 80
          hostport      = 80
          protocol      = "tcp"
        }
      ],
      environment = [
        {
          name =  "WORDPRESS_DB_HOST"
          value = var.db_host
        },
        {
          name = "WORDPRESS_DB_NAME"
          value = var.db_name
        },
        {
          name =  "WORDPRESS_DB_USER"
          value = var.db_user
        },
        {
          name = "WORDPRESS_DB_PASSWORD"
          value = var.db_password
        }
      ]
    }
  ])
}

# ECSサービス
resource "aws_ecs_service" "wordpress" {
  name = "wordpress-service"
  cluster = aws_ecs_cluster.this.id
  task_definition = aws_ecs_task_definition.wordpress.arn
  desired_count = 1
  launch_type = "FARGATE"

  network_configuration {
    subnets = [var.public_subnet1_id, var.public_subnet2_id]
    security_groups = [aws_security_group.ecs_sg.id]
    assign_public_ip = true
  }

  load_balancer {
    target_group_arn = var.alb_tg
    container_name = "wordpress"
    container_port = 80
  }
}

#SG
resource "aws_security_group" "ecs_sg" {
  name = "ecs-sg"
  description = "Allow HTTP"
  vpc_id = var.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/16"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
```
#### ../modules/ecs/variable.tf
```
variable "vpc_id" {
  description = "The VPC ID for the ECS"
  type        = string
}

variable "public_subnet1_id" {
  description = "The Subnet ID for the ECS"
  type = string
}

variable "public_subnet2_id" {
  description = "The Subnet ID for the ECS"
  type = string
}

variable "alb_tg" {
  description = "The Target Group for the ECS"
  type = string
}

variable "db_host" {
  description = "RDS hostname"
  type = string
}

variable "db_name" {
  description = "Database name"
  type = string
}

variable "db_user" {
  description = "Database username"
  type = string
}

variable "db_password" {
  description = "Database password"
  type = string
}
```

## 確認
#### ヘルスチェック
![20250330_000003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/8ed1ae33-a787-47bc-b09d-8b36da60c09c.jpeg)
![20250330_000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/200f427f-39b2-4aca-934a-456dded25c0e.jpeg)

#### レスポンス
| 項目                  | 説明                                                      
|-----------------------|----------------------------------------------------------
| HTTPステータスコード  | `HTTP/1.1 302 Found` リダイレクトの発生を示す             
| Location              | リダイレクト先URL 独自ドメインにリダイレクトされている                                        
| Server               | MWとOSがドッカーイメージのものと一致 (`Apache/2.4.62 (Debian)`)        
| X-Powered-By         | PHP (`PHP/8.1.32`)       
| X-Redirect-By        | WordPressがリダイレクトを行っている              
| Cache-Control        | キャッシュ設定がCaching Disabled（オリジンから）

![20250330_000002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/a2658d42-12e5-4292-972d-11cb7b259fcc.jpeg)

#### WordPress
![20250330_000001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/551732d2-deae-4b82-a622-903df2e1d996.jpeg)

## 改善（
-  なるべく手動を減らしたいので、GitHub Actionsでterraform apply後、ドッカーイメージをプッシュするワークフローを入れたい
- echo "$your_password" | docker login -u ryu117 --password-stdinのパスワードはGitHub ActionsのSecretsで環境変数化


## 最後に
とりあえずDockerを触ってみたく実践しましたが、docker run一発で動くので裏で何が起きているかを把握することは今後の応用のためにも不可欠。
改めてコンテナの概念や多層構造の理解のためにも体系的な勉強も並行してやっていかねばと思います。
良さげなドキュメント見つけたら下に書いていきます。
[Docker 公式ドキュメント](https://docs.docker.jp/)
[実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本](https://zenn.dev/suzuki_hoge/books/2022-03-docker-practice-8ae36c33424b59)