初心者でもDockerでAmazonLinux+Go(Echo)+Mysqlの環境構築しつつ簡単なAPIを作って動かす

# DockerでAmazonLinux+Go+Mysqlの環境構築する

PHPerだったけど今度はGoやっていくので環境をDockerで作ってそこで簡単なAPIをGoのフレームワーク「[Echo](https://echo.labstack.com/)」で作っていく

# 環境

- **Docker Desktop on Windows：19.03.1**
- **AmazonLinux**（イメージ：https://hub.docker.com/_/amazonlinux ）
- **MySQL：8.0**：（イメージ：https://hub.docker.com/_/mysql ）
- **Go：1.13.3**
  - labstack/echo
  - go-sql-driver/mysql

ちなみに作業環境はWindows10 Proのi7メモリ32GBノートPCです

# ディレクトリ構成

```
|-Dockerfile
|-docker-compose.yml
|-./src
    |-main.go
```


# Dockerfile

まずAmazonLinuxにGoをインストールしたイメージを作成する

```Dockerfile
FROM amazonlinux:latest

ENV GOPATH /go
ENV PATH /usr/local/go/bin:/go/bin:$PATH

WORKDIR /usr/src

# go install
RUN yum update -y \
    && yum install -y tar \
    && yum install -y gzip \
    && curl -OL https://dl.google.com/go/go1.13.3.linux-amd64.tar.gz \
    && tar -C /usr/local -xzf ./go1.13.3.linux-amd64.tar.gz \

# git install for go get command
RUN yum install -y git

# go library
RUN  go get github.com/go-sql-driver/mysql \
        && go get github.com/labstack/echo

CMD ["go", "run", "main.go"]
```

# イメージ生成(docker build -t <Dockerイメージ名> <Dockerfileが存在するディレクトリ>)

イメージ名は何でもいいですけどここでは`test-aws_go-img`とします（`.`は同ディレクトリを指す）

```
docker build -t test-aws_go-img .
```

# docker-compose.yml

上記でビルドして作成したイメージ（`test-aws_go-img`）を`docker-compose.yml`で指定

```docker-compose.yml
version: '3.7'
services:
  test-aws_go-img:
    build: .
    container_name: test_app # わかりやすいコンテナ名にしておく（任意）
    ports:
      - 8080:8080
  db:
    container_name: test_db # わかりやすいコンテナ名にしておく（任意）
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password # 従来の認証方式にしておく
    volumes:
      - db-store:/var/lib/mysql
      - ./logs:/var/log/mysql
    environment:
      - MYSQL_DATABASE=test_todo
      - MYSQL_ROOT_PASSWORD=password
      - TZ=Asia/Tokyo
    ports:
      - 3307:3306
volumes: # データの永続化
  db-store:
```

これでDocker周りは完了

# main.go

アクセスするとテーブルに登録されているデータをJSONで返すようなかんたんなAPIを作る

```main.go
package main

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

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

// JSON用の構造体を定義
type Task struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

func main() {
	e := echo.New()
	e.GET("/tasks", getTasks)

	e.Start(":8080")
}

func dbConnect() *sql.DB {
	// DB接続処理
	db, err := sql.Open("mysql", "root:password@tcp(test_db)/test_todo")
	if err != nil {
		panic(err.Error())
	}
	return db
}

func getRows(db *sql.DB) *sql.Rows {
	rows, err := db.Query("SELECT id,name FROM tasks")
	if err != nil {
		panic(err.Error())
	}
	return rows
}

func getTasks(c echo.Context) error {
	// DB接続
	db := dbConnect()
	defer db.Close()
	rows := getRows(db)
	defer rows.Close()

	task := Task{}
	var results []Task
	for rows.Next() {
		err := rows.Scan(&task.ID, &task.Name)
		if err != nil {
			panic(err.Error())
		} else {
			results = append(results, task)
		}
	}

	return c.JSON(http.StatusOK, results)
}
```

# Docker起動

動くか確認するためにバックグラウンドのオプションはつけないで普通に起動

```
docker-compose up
```

無事起動したら次に確認用のサンプルデータを入れていく

# DBへ接続してデータを入れる

別の画面を開いて（Windowsならコマンドプロンプトとか）MySQLのコンテナの中に入る

```
docker exec -it test_db bash
```

MySQLへログイン（パスワードは上記で設定した`password`）

```
# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.18 MySQL Community Server - GPL

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use test_todo;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
```

以下のSQLを流す（コピペで可）

```sql
SET NAMES utf8;
SET time_zone = '+00:00';
SET foreign_key_checks = 0;
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';

SET NAMES utf8mb4;

CREATE DATABASE `test_todo` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `test_todo`;

DROP TABLE IF EXISTS `tasks`;
CREATE TABLE `tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

INSERT INTO `tasks` (`id`, `name`) VALUES
(1,"go"),
(2,	"php"),
(3,	"java"),
(4,	"html"),
(5,	"css");

```

念の為入ったか確認しておく

```
mysql> select * from tasks;
```

# URLを叩いてJSONが帰ってくるか確認

準備ができたのでターミナルやらで`curl`コマンドを叩く

```
curl -s http://localhost:8080/tasks
```

すると以下のようにJSONでデータが取得出来る

```
[{"id":1,"name":"go"},{"id":2,"name":"php"},{"id":3,"name":"java"},{"id":4,"name":"html"},{"id":5,"name":"css"}]
```

以下GitBashから実行した様子
![WS000012.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85815/3da60839-6a7a-fe26-57b6-16b1e7df3983.jpeg)

以下はChromeからアクセスした際の様子

![WS000016.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85815/c75a7de1-17fc-3117-07c6-c54c24f65d8c.jpeg)


# おわり
- 80%くらいの確率で動くと思うんですが動かなかったらおしえてほしいです
- それ以外でもこうしたほうがいい等あればコメント下さい

# 参考URL
- https://docs.docker.com/compose/compose-file/
- https://stackoverflow.com/questions/57566060/panic-dial-tcp-127-0-0-13306-connect-connection-refused
- https://tech.speee.jp/entry/2017/08/22/110000
- https://qiita.com/K-juju/items/f6d0eedb9aee5714cb73
- https://shinter8823.hatenablog.com/entry/2019/07/18/015051
- https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa
- https://omohikane.com/golang_on_dokcer/
- https://designsupply-web.com/knowledgeside/3325/
- https://qiita.com/lkeix_/items/b291eb9cebc76deeb916
- https://qiita.com/ShinyaIshikawa/items/fede44cee7c71721247a

などなど