golang+reactなアプリの開発環境をモノレポで作る

こんにちは。

モノレポという、1つのリポジトリに複数のアプリを1つのリポジトリに保存するというパターンがあるということを知ったので、
実際にその構成での開発環境を作ってみます。

今回考えるのは、APIサーバとしてgolangで作られたものがあり、reactではそのフロントエンドを実装するようなアーキテクチャにします。

# この記事で達成すること

- golangでAPIの開発環境を作る
- reactの開発環境を作る
- 1つのリポジトリで↑2つのアプリが保存されている再現できる(モノレポ構成にする)
    - reactとgolangをモノレポで構成

# 言語、ミドルウェアのバージョン

|    言語、ミドルウェア    |   バージョン      | 
|:----------:|:---------------:|
| docker   | 20.10.11        | 
| docker-compose | 1.29.2          |
| golang     | Dockerfile参照 | 
| mysql     | Dockerfile参照   | 
| react     | Dockerfile参照   | 
| node     | Dockerfile参照   | 

## dockerのコンテナを作る

今回はdockerコンテナ上で動作するようにしたいので、golang、react、mysqlそれぞれのコンテナを作ります。
ディレクトリの構成は以下のようになります。

```shell
docker/
    |- golang/
    |- mysql/
    |- react/
go-app/
react-app/
docker-compose.yml
```

## docker-compose.ymlを書く

説明の順番としては、前後していますが全体の構成を示すため先にdocker-compose.ymlを示します。

今回の`docker-compose.yml`は以下のようになります。

```docker
version: '3'
services:
  react:
    build:
      context: .
      dockerfile: ./docker/react/Dockerfile
    container_name: react_container
    tty: true
    volumes:
      - ./react-app/react-app:/app/react
    command: sh -c "cd /app/react && yarn install && yarn start"
    ports:
      - 3000:3000
  go:
    build:
      context: .
      dockerfile: ./docker/golang/Dockerfile
    container_name: go_container
    ports:
      - 8000:8000
    tty: true
    volumes:
      - ./go-app:/app/go
  mysql:
    build:
      context: .
      dockerfile: ./docker/mysql/Dockerfile
    container_name: mysql_container
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: react-go-app
      TZ: 'Asia/Tokyo'
    volumes:
      - ./docker/mysql/initdb.d:/docker-entrypoint-initdb.d
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
      - ./docker/mysql/mysql_data:/var/lib/mysql
    ports:
    - 3306:3306
    links:
      - go
```

golang、react、mysqlのコンテナごとにDockerfileを用意し、それぞれのDockerfileを利用してコンテナを作ります。
それぞれのコンテナはローカル環境での開発を想定しているので、ローカルのディレクトリをボリュームとしてマウントします。
あとは適宜、必要に応じてポートを設定したり、パスワードを設定したりしています。

## reactのコンテナを作る

`docker/react/Dockerfile`は以下のようにしています。

docker/react/Dockerfile
```Dockerfile
FROM node:16.0.0
WORKDIR /app/react
RUN npm i --save prop-types
RUN npm i -g create-react-app
```

`Dockerfile`に`npm`を使ってreactのプロジェクトを作成するようにしています。

## golang(APIサーバ)のコンテナを作る

`docker/golang/Dockerfile`は以下のようにしています。

docker/golang/Dockerfile
```Dockerfile
FROM golang:alpine
RUN apk update
RUN apk add alpine-sdk
COPY ./go-app /app/go
WORKDIR /app/go
RUN go build -o main .
CMD [ "/app/go/main" ]
```

`go-app/main.go`というファイルを作成しておきます。内容はとりあえず以下のようにしておきます。

```go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", echoHello)
	http.ListenAndServe(":8000", nil)
}

func echoHello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "<h1>Hello World</h1>")
}
```

## mysqlのコンテナを作る

golangのAPIがデータを保存したり、取得したりするために`mysql`を用意します。
今回は`mysql`のコンテナを用意し、mysqlコンテナにデータを保存するようにします。

踏まえて、`docker/mysql/Dockerfile`は以下のようにしています。

docker/mysql/Dockerfile
```Dockerfile
FROM --platform=linux/x86_64 mysql:latest
```

本来的にはmysqlのバージョンを指定するのが良いです。
またお仕事の案件ならmysqlのバージョンを指定しましょう。
とはいえ、個人や技術検証レベルで使うものであればとりあえず`latest`を使っておいてOKでしょう。

# 実際にコンテナを起動して、動作確認をする

ここまでで設定してきたコンテナを起動して、動作確認していきます。

## コンテナを起動する

ここまでで一通り、準備は整いました。あとはコンテナを起動していきます。
コンテナの起動には`docker-compose`を使います。

```shell
// 初回はこのコマンドを実行する
docker-compose up -d

// コンテナのイメージとコンテナが一度出来上がったら以下のコマンドでコンテナを起動する
docker-compose start

// コンテナの停止
docker-compose stop
```

初回はそれぞれのコンテナのイメージが無いはずなので、それぞれのイメージをpullして、ビルドする必要があります。
そのため`docker-compose up -d`を実行してそれらを行います。

実行してそれぞれのコンテナについて、`done`が表示されたらOKです。

## golangが実行できることを確認する

`localhost://8000`にアクセスして、`Hello World`が表示されたらOKです。

## reactが実行できることを確認する

`localhost://3000`にアクセスして、reactのページが表示されたらOKです。

↓うまくいけばのような画像が表示されます。
![react.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3507088/87db51b6-92be-cfd9-b302-bcd06694427e.png)

# まとめ

golangでAPIとを開発ができる環境の準備ができました。
次回は実際にデータを保存する、取得するという部分を実装していきます。

今日は以上です。
ありがとうございました。