Go | MySQL | EC2 | RDS の環境構築

## 追記
この記事を書き終わってから、他の方々の記事を検索してみたのですが、AWS SDK for Goを使うのが一般的みたいです。
https://aws.amazon.com/jp/sdk-for-go/

この記事は、EC2を手動で作って、GoのコードをコンパイルしたバイナリファイルをEC2にアップロードする方法です。よろしくお願いします。

## やりたいこと
ゴールは、GoをEC2に、MySQLをRDSに配置して、GoからMySQLに接続できることです。

## Goアプリ
ローカルにGoは既にインストールされている前提です。
ちなみに、僕のGoのバージョンは1.16.6でした。
### ファイル構成
```
.
├── go.mod
├── go.sum
├── init.sql
└── main.go
```
### ファイル作成
usernameとappnameは適宜変更してください。

```zsh:zsh
$ go mod init github.com/username/appname
$ go get github.com/go-sql-driver/mysql
```
```go:main.go
package main

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"os"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	h := func(w http.ResponseWriter, _ *http.Request) {
		user := os.Getenv("DB_USERNAME")
		pass := os.Getenv("DB_PASSWORD")
		host := os.Getenv("DB_HOST")
		db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:3306)/appname", user, pass, host))
		if err != nil {
			log.Fatal(err)
		}
		defer db.Close()

		var name string
		err = db.QueryRow("SELECT name FROM users LIMIT 1").Scan(&name)
		if err != nil {
			log.Fatal(err)
		}

		fmt.Fprintf(w, "Hello, %s!", name)
	}

	http.HandleFunc("/", h)

	log.Fatal(http.ListenAndServe(":8080", nil))
}
```
```sql:init.sql
CREATE DATABASE IF NOT EXISTS appname;

USE appname;

DROP TABLE IF EXISTS users;

CREATE TABLE IF NOT EXISTS users (
  id INT PRIMARY KEY,
  name VARCHAR(255)
);

INSERT INTO users (id, name)
VALUES (1, 'Bob');
```
## セキュリティグループの作成
コンソール画面でセキュリティグループを作成する。

|項目|値|
|-|-|
|セキュリティグループ名|appname-sg-ec2|
|説明|for ec2|
|VPC|(デフォルト)|
|インバウンドルール|タイプ:SSH ソース:0.0.0.0/0|
|インバウンドルール|タイプ:HTTP ソース:0.0.0.0/0|
|インバウンドルール|タイプ:HTTPS ソース:0.0.0.0/0|
|アウトバウンドルール|タイプ:すべて ソース:0.0.0.0/0|

## EC2の作成
コンソール画面でEC2を作成する。

|項目|値|
|-|-|
|Amazonマシンイメージ|Amazon Linux2 AMI|
|インスタンスタイプ|t2.micro|
|ネットワーク|(デフォルト)|
|サブネット|優先順位なし(デフォルト)|
|自動割り当てパブリックIP|有効|
|EBSサイズ(GiB)|20|

タグ

|キー|値|
|-|-|
|Name|appname-ec2|

セキュリティグループ　※既存のセキュリティグループを選択する

|名前|
|-|
|default|
|appname-sg-ec2|
※2つ選択する

## RDSの作成
コンソール画面でRDSを作成する。
usernameとpasswordは適宜変更してください。

|項目|値|
|-|-|
|作成方法|簡単に作成|
|エンジンのタイプ|MySQL|
|テンプレート|無料利用枠|
|DBインスタンス識別子|appname-db|
|マスターユーザー名|username|
|マスターパスワード|password|

## ターミナル作業
以下、ターミナルで作業していきます。
xxxxx.pemは、キーペアのダウンロードした秘密鍵ファイル、
xxx.xxx.xxx.xxxは、EC2のパブリックIPv4アドレスです。
適宜読み替えてください。

```zsh:local
# 秘密鍵ファイルを移動、権限変更
$ mv ~/Downloads/xxxxx.pem ~/.ssh
$ chmod 700 ~/.ssh/xxxxx.pem

# linux形式でコンパイルする
$ GOOS=linux GOARCH=amd64 go build main.go

# ファイル転送モードでログイン
$ sftp -i ~/.ssh/xxxxxx.pem ec2-user@xxx.xxx.xxx.xxx
```
```bash:ec2
# ec2へ、localのmainバイナリファイル、SQLファイルを転送
$ put main
$ put init.sql
$ exit
```
```zsh:local
# sshでログイン
$ ssh -i ~/.ssh/xxxxxx.pem ec2-user@xxx.xxx.xxx.xxx
```
```bash:ec2
# nginxをインストール
$ sudo amazon-linux-extras install nginx1.12

# nginx設定ファイルを編集
$ sudo vim /etc/nginx/nginx.conf
```
```conf:nginx.conf
http {
    server {
        location / {
            # 追記箇所
            proxy_pass    http://localhost:8080;
        }
    }
}
```
```bash:ec2
# nginx起動
$ sudo service nginx start

# MySQLのドライバーをインストール
$ sudo yum -y install mysql

# データベース作成(接続先はRDSのエンドポイントを指定)
$ mysql -u username -p -h appname-db.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com < init.sql
Enter password: password

# データベースの環境変数を設定
$ export DB_USERNAME=username
$ export DB_PASSWORD=password
$ export DB_HOST=appname-db.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com

# goアプリ起動
$ ./main
```
xxx.xxx.xxx.xxxをブラウザで開くと、「Hello, Bob!」が見れるはず！
ご覧いただき、ありがとうございました！