Goで安価なAPIサーバーをデプロイする

FargateやらALBやらを使って結構料金のかかるインフラ設計にしている人が結構いるので今回はコスパの良いHTTPSなAPIサーバーを立てていきます。 ＊ 完全に個人開発向けの話になります。

|      |  使用するサービス  |
| ---- | ---- |
|  サーバー  |  ECS on EC2   |
|  ドメインの取得  |  freenom  |
|  DNS登録  |  AWS Route53  |
|  SSLの証明書  |  Let's Encrypt  |
|  インフラ管理 |  Terraform  |


## ドメインの取得

以下のサイトに従ってドメインを取得しましょう。

https://note.com/dafujii/n/n406f385651e2

取得できたら以下のように表示されます。

![スクリーンショット 2022-04-30 16.51.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/319ec28c-ee72-a285-62b6-b23c646386c4.png)


## Terraformの初期化

今回はサクッと終わらせるためにTerraformを使います。以下のリポジトリをcloneしてきてもらっても大丈夫です。

https://github.com/ymktmk/golang-ssl-server.git

作業環境に移動する。
```
cd golang-ssl-server/terraform
```

Terraformの初期化をします。
```
terraform init
```

## ECRへDockerイメージをPush

はじめにECRリポジトリのみを作成します。
```
terraform apply -target={aws_ecr_repository.ecr_repository,aws_ecr_lifecycle_policy.ecr_lifecycle_policy}
```

ECRへのDockerイメージのPushは以下を参考にしてください。

![スクリーンショット 2022-05-01 16.48.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/004cd006-915c-202c-6c0e-7e4ac26aaf8b.png)


## task-definitionの書き換え

ECRにPushしたイメージURIをコピーしてTerraformに貼り付けてください。

```tf:ecs.tf
resource "aws_ecs_task_definition" "task_definition" {
    container_definitions    = jsonencode(
        [
            {
                cpu              = 0
                essential        = true
                image            = "< イメージURI >"
```

## Route53の設定

**www.ymktmk.ga** は自分が取得したドメインに置き換えてください。

```tf:route53.tf
resource "aws_route53_zone" "zone" {
      name = "ymktmk.ga"
}

resource "aws_route53_record" "www" {
      zone_id = aws_route53_zone.zone.zone_id
      name    = "www.ymktmk.ga"
      type    = "A"
      ttl     = "300"
      # EC2インスタンスのPublic IP
      records = [aws_eip.eip.public_ip]
}
```

## Goのコード

今回は軽量フレームワークのEchoを用いています。以下の少ないコードで裏側でLet’s Encryptと接続してSSL化を行ってくれます。

```go:main.go
package main

import (
	"net/http"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"golang.org/x/crypto/acme/autocert"
)

func main() {
	e := echo.New()
    // www.ymktmk.ga　は取得したドメイン
	e.AutoTLSManager.HostPolicy = autocert.HostWhitelist("www.ymktmk.ga")
	e.AutoTLSManager.Cache = autocert.DirCache("/var/www/.cache")
	e.Use(middleware.Recover())
	e.Use(middleware.Logger())
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello, World!")
	})
	e.Logger.Fatal(e.StartAutoTLS(":443"))
}
```

## デプロイ

公開鍵と秘密鍵を作成します。
```
ssh-keygen -t rsa -f golang-ssl-server -N ''
```

terraformの内容をもとにAWSにデプロイします。
```
terraform apply
```

## Elastic IPの関連付け

ECSの場合はAuto Scalingでインスタンスが増減するようになっている(今回はTerraformでmax1台の設定にしている)のでTerraformでは関連づけることはできない。したがって起動したインスタンスにElastic IPの関連付けを手動で行います。

![スクリーンショット 2022-05-01 16.27.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/a7afcd32-dffe-ea34-3bc8-488d5572ea26.png)

## freenomのDNS設定をします。

Route53のNSレコードが4件作成されるのでfreenomのNameserversの1~4に貼り付ける。

![スクリーンショット 2022-05-01 5.18.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/fc4c2a5a-4a48-276b-9282-c20fe4c904de.png)

![スクリーンショット 2022-05-01 2.14.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/8b33e767-a808-a4a4-2c7c-fde8ea8c0f46.png)

## 完成

以下のように表示されたらSSL化されたAPIサーバーの完成です。

![スクリーンショット 2022-05-01 16.50.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/47ce4967-52ff-2f7e-648d-c3495fe22aaf.png)


## 参考文献

https://www.youtube.com/watch?v=BfOpTosSP_4&list=LL&index=7&t=257s

https://echo.labstack.com/cookbook/auto-tls/

https://qiita.com/smith-30/items/147ba45fa74b2fc265b6

https://qiita.com/OPySPGcLYpJE0Tc/items/4a141a880351cf655de9

https://qiita.com/iiiiiiiiih/items/aabe1cd09f368f0bf2b8