個人的備忘録：ECS上でのGoアプリデプロイ時に起きた.envエラーと、私の環境で解決した方法

## はじめに
開発環境では `.env` ファイルを利用して環境変数を管理することが一般的ですが、本番環境（特に AWS ECS などのクラウド環境）では `.env` ファイルがなくても動作するように設計する必要があります。

今回、ECS にデプロイした Go アプリケーションで 「`.env` ファイルが読み込めません」 というエラーが発生しました。その原因と対処法について解説します。

## 起きていたエラー
ECS 上で Go アプリケーションをデプロイした際に、以下のエラーが発生しました。

```
2025/02/19 02:11:07 .envファイルが読み込めません: open .env: no such file or directory
```

このエラーは、Go アプリケーションが `.env` ファイルを読み込もうとして、ファイルが見つからずにクラッシュしていることを示しています。

## エラーの原因

### 1. `.env` の読み込み処理が `GO_ENV=prod` でも実行されていた
Go のコード内で `.env` を読み込む処理が含まれていました。

```go
if os.Getenv("GO_ENV") == "dev" {
    err := godotenv.Load()
    if err != nil {
        log.Fatal(err)
    }
}
```

このコードは `GO_ENV=dev` のときのみ `.env` を読み込むはずですが、実際には `GO_ENV` が正しく設定されていないか、空の状態だったため `.env` を読み込もうとしてエラーになりました。

### 2. `GO_ENV` の環境変数が正しく設定されていなかった
ECS のタスク定義では以下のように `GO_ENV=prod` を設定していましたが、実際のコンテナ内では設定されていなかった可能性があります。

#### ECSのタスク定義（Terraform）
```json
"environment": [
  {
    "name": "GO_ENV",
    "value": "prod"
  }
]
```

しかし、ECS のデプロイ後にコンテナ内で `GO_ENV` を確認すると、設定されていない（`""` になっている）ことがありました。

#### コンテナに入って確認
```sh
aws ecs execute-command --cluster my-ecs-cluster --task タスクID --container my-app-repo --command "/bin/sh" --interactive
```

#### コンテナ内で実行
```sh
echo $GO_ENV
```

`GO_ENV` が空のままだった場合、 `.env` の読み込み処理が実行され、エラーが発生することになります。

### 3. `.env` に依存せずに環境変数を利用するべきだった
ECS では環境変数を `.env` ではなく、ECS のタスク定義 (`environment`) に直接設定するのが一般的です。そのため、Go のコードで `.env` を読み込む必要はありませんでした。

## 解決策

### 1. `.env` の読み込み処理を削除する
最も簡単な対策は、`.env` の読み込みを削除し、環境変数のみに依存するようにすることです。

#### 修正前
```go
if os.Getenv("GO_ENV") == "dev" {
    err := godotenv.Load()
    if err != nil {
        log.Fatal(err)
    }
}
```

#### 修正後
```go
// `.env` を読み込む処理を削除
func NewDB() {
    url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True",
        os.Getenv("MYSQL_USER"),
        os.Getenv("MYSQL_PW"),
        os.Getenv("MYSQL_HOST"),
        os.Getenv("MYSQL_PORT"),
        os.Getenv("MYSQL_DB"))

    var err error
    DB, err = gorm.Open(mysql.Open(url), &gorm.Config{})
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Connected")
}
```

この変更により、 ECS でも `.env` ファイルが不要になり、エラーが解消されます。

### 2. `GO_ENV=prod` が正しく設定されているか確認
ECS で環境変数が正しく適用されているか確認するには、次のコマンドを実行します。

```sh
aws ecs describe-tasks --cluster my-ecs-cluster --tasks $(aws ecs list-tasks --cluster my-ecs-cluster --query 'taskArns[0]' --output text) --query 'tasks[0].containers[0].environment'
```

ここに `GO_ENV=prod` が含まれているかチェックしてください。

もし `GO_ENV` がない場合は、Terraform でタスク定義を適用し直します。

```sh
terraform apply -auto-approve
aws ecs update-service --cluster my-ecs-cluster --service my-ecs-service --force-new-deployment
```

### 3. ECS の環境変数設定を見直す
ECS のタスク定義に `GO_ENV=prod` を明示的に追加します。

#### Terraform の ECS タスク定義
```json
"environment": [
  {
    "name": "GO_ENV",
    "value": "prod"
  },
  {
    "name": "MYSQL_USER",
    "value": "myuser"
  },
  {
    "name": "MYSQL_PW",
    "value": "${jsondecode(data.aws_secretsmanager_secret_version.rds_password_v5.secret_string)[\"password\"]}"
  },
  {
    "name": "MYSQL_HOST",
    "value": "${aws_db_instance.rds_instance.endpoint}"
  }
]
```

Terraform を適用後、ECS のタスクを強制再デプロイすることで、環境変数が適用されます。

```sh
aws ecs update-service --cluster my-ecs-cluster --service my-ecs-service --force-new-deployment
```

## まとめ

### エラーの原因
- `.env` の読み込み処理が実行されていた
- `GO_ENV=prod` が適用されていなかった
- `.env` に依存するコードになっていた

### 解決策
- `.env` の読み込み処理を削除
- `GO_ENV=prod` を ECS のタスク定義に明示的に設定
- Terraform を適用後、ECS タスクを再デプロイ

この対応を行うことで、 ECS 環境で `.env` に依存せずに動作するようになり、エラーが解消できました。