ReactのAPIクライアント と GoのAPIサーバー をEC2上のDockerに載せます

作成：2023年3月27日

[前回まで](https://qiita.com/RYO_/items/b037ce930f41059c8bd1)で、GoのAPIサーバー(GET,POST,PATCH,DELETE)とReactのAPIクライアント(GETのみ）を試作しました。今回はこれをDockerに載せてみたいと思います。

# 練習で新規ReactアプリをDockerへ載せてみる
## Reactアプリをローカルで作成
```:terminal
% npx create-react-app docker-react20230325
```
App.jsをサンプルコードで更新します。
```:App.js
import React, { useState, useEffect } from "react";

const INITIAL_COUNT = 0;
const SampleComponent = () => {
  const [count, setCount] = useState(INITIAL_COUNT);
  const callbackFunction = () => {
    document.title = `${count} 回クリックされました`;
  }
  useEffect(callbackFunction, [count]);
  const countIncrement = () => {
    setCount((prevCount) => prevCount + 1);
  };
  const countReset = () => {
    setCount(INITIAL_COUNT);
  };

  return (
    <div className="App">
      <p>現在のカウント数：{count}</p>
      <button onClick={countIncrement}>+1 ボタン</button>
      <button onClick={countReset}>リセット</button>
    </div>
  );
};

export default function App() {
  return <SampleComponent />;
}
```
試しにローカルで実行します。
```:terminal
% yarn install
% yarn start
```
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/892c43f5-84b7-0547-ab21-00dfa270d6e1.png">

## Dockerfileを作成
docker-react20230325フォルダの直下に Dockerfile を作成します。
```:Dockerfile
# ベースイメージの作成
FROM node:latest
# コンテナ内で作業するディレクトリを指定
WORKDIR /usr/src/app
# package.jsonとyarn.lockを/usr/src/appにコピー
COPY ["package.json", "yarn.lock", "./"]
# パッケージをインストール
RUN yarn install
# ファイルを全部作業用ディレクトリにコピー
COPY . .
# コンテナを起動する際に実行されるコマンド
ENTRYPOINT [ "yarn", "start" ]
```

## イメージをビルド
```:terminal
% docker build -t test20230325:1.0 .
```
作成したイメージを確認します。
```:terminal
% docker image ls
REPOSITORY                         TAG                    IMAGE ID       CREATED          SIZE
test20230325                       1.0                    4c6f98c9577a   35 seconds ago   1.46GB
```

## コンテナを起動
```:terminal
% docker run -dit --name sample20230325 -p 3000:3000 test20230325:1.0
% docker ps
CONTAINER ID   IMAGE                        COMMAND                   CREATED         STATUS              PORTS                                       NAMES
991a053dc232   test20230325:1.0             "yarn start"              8 seconds ago   Up 6 seconds        0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   sample20230325
```
実行できました！
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/08254b14-18eb-ddff-1d29-6cbd712ca54a.png">

# AWS上 の Docker で起動してみます

イメージをファイル化します。
```:terminal
% docker save -o test20230325.tar test20230325:1.0
```
ファイル化したイメージを EC2 にファイル転送
```:terminal
% scp -i ~/.aws/docker20230223.pem ./test20230325.tar ubuntu@54.168.241.85:/home/ubuntu
```

EC2 で docker load する
```:EC2 terminal
$ docker load -i test20230325.tar
```

利用可能なポートをAWSコンソールで確認します。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/140b93c0-a82f-694b-2407-998e592260b8.png">

イメージが利用できることを確認して、実行します。ポートは8082を使ってみます。
```:EC2 terminal
% docker image ls
% docker run -dit --name sample20230325 -p 8082:3000 test20230325:1.0
```
EC2上の Docker で React を実行できました。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/fd509538-9854-3547-03ac-6907e22fc8aa.png">


# Go の APIサーバーを Docker で実行

## ローカルの Docker で実行

### コードの改修
Docker ではうまく動作しなかったので、[103〜104行（Githubのコード）](https://github.com/ryoyuki6/go-api202301/blob/qiita20230326/go-api/main.go)を更新しました。

### Dockerfileを作成
go-api の直下に Dockerfile を作成します。
```:Dockerfile
# https://hub.docker.com/_/golang
FROM golang:1.18.1-alpine
WORKDIR /app
# main.go と go.mod と go.sum を /app にコピー
COPY ["main.go", "go.mod", "go.sum", "./"]
# パッケージをインストール
RUN go build
# コンテナを起動する際に実行されるコマンド
CMD ["go", "run", "main.go"]
```

### イメージをビルド
```:terminal
% docker build -t go_test20230326:1.0 .
```
作成したイメージを確認します。
```:terminal
% docker image ls
REPOSITORY                         TAG                    IMAGE ID       CREATED          SIZE
go_test20230326                    1.0                    3d7a9e08b500   17 seconds ago   329MB
```

### コンテナを起動
```:terminal
% docker run -it --name go_api -p 8080:8080 go_test20230326:1.0
% docker ps
CONTAINER ID   IMAGE                        COMMAND                   CREATED         STATUS         PORTS                                       NAMES
3eaec32c28f0   go_test20230326:1.0          "go run main.go"          5 seconds ago   Up 3 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   go_api
```
Postman から GET でデータを取得できました。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/e800fde3-416e-d0e4-756f-208caf750aa7.png">

# Go の APIサーバーを EC2上の Docker で実行

イメージをファイル化します。
```:terminal
% docker image list
REPOSITORY                         TAG                    IMAGE ID       CREATED          SIZE
go_test20230326                    1.0                    f4b523363243   15 minutes ago   501MB
% docker save -o go_test20230326.tar go_test20230326:1.0
```

ファイル化したイメージを EC2 にファイル転送します。
```:terminal
% scp -i ~/.aws/docker20230223.pem ./go_test20230326.tar ubuntu@13.115.30.209:/home/ubuntu
```

EC2 で docker load します
```:EC2 terminal
$ docker load -i go_test20230326.tar
```

イメージが利用できることを確認して、実行します。ポートは8080を使ってみます。
```:EC2 terminal
$ docker image ls
$ docker run -it --name go-api -p 8080:8080 go_test20230326:1.0
```
Postman で、EC2 上の Docker の Go API からデータを取得できました。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/dae1ba16-d531-e2cc-2c3b-f27cac40d52d.png">

# Docker network の中で通信

## ローカルの Docker で GoのAPIサーバー のコンテナ立てて、別のコンテナからリクエスト

ネットワーク apinet に GoのAPIサーバーのコンテナを立てる
```:terminal
% docker network create apinet
% docker run -it --name go-api --net apinet go-api20230326:1.0
```

APIリクエストするためのコンテナを立てます
```:terminal
% docker run -rm -it --net apinet ubuntu /bin/bash
```
コンテナの中で各種ソフトインストールと、APIリクエストして確認します
```:docker
# apt update
# apt -y upgrade
# apt install -y iproute2 iputils-ping curl
# ping -c 4 go-api
# curl http://go-api:8080/health_data
[
    {
        "id": 1,
        "month": 1,
        "day": 1,
        "weight": 55.5
    },
    {
        "id": 2,
        "month": 1,
        "day": 2,
        "weight": 66.6
    },
    {
        "id": 3,
        "month": 1,
        "day": 3,
        "weight": 77.7
    }
```

# ローカルのDocker上に、GoのAPIサーバーとReactのAPIクライアントのコンテナを立てます

Reactプログラムはローカルのブラウザに読み込まれて実行されて、「ローカルのブラウザ」から「ローカルのDocker上のGoのAPIサーバー」に
リクエストされます。
[Githubのコード置き場のリンク](https://github.com/ryoyuki6/go-api202301/tree/qiita20230327)です。

ネットワーク apinet を作ります。今回は直接使いませんが、将来のDB接続で使用予定です。
```:terminal
% docker network create apinet
```

## GoのAPIサーバーのコンテナ立てます

```:terminal
% pwd
/***/go-api
% docker build -t go-api20230327:1.0 .
% docker run -it --name go-api --net apinet -p 8080:8080 go-api20230327:1.0
```

# ReactのAPIクライアントのコンテナ立てます

```:terminal
% pwd
/***/react
% docker build -t react-api20230327:1.0 .
% docker run -it --name react-api --net apinet -p 3000:3000 react-api20230327:1.0
```

うまく実行できました。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/736f627a-d811-7121-e078-f5571068578a.png">

# AWS EC2上のDockerに、GoのAPIサーバーとReactのAPIクライアントを立てます

## [Reactのコード](https://github.com/ryoyuki6/go-api202301/blob/qiita20230327a/react/src/App.js)にEC2のIPアドレスを反映

```:App.js
const response = await axios.get("http://54.199.172.102:8080/health_data");
```

## [Goのコード](https://github.com/ryoyuki6/go-api202301/blob/qiita20230327a/go-api/main.go)にEC2のIPアドレスを反映
```:main.go
config.AllowOrigins = []string{"http://54.199.172.102:3000"}
```

## イメージをファイル化してEC2にコピー

```:terminal
% docker build -t react-api20230327a:1.0 .
% docker build -t go-api20230327a:1.0 .
% docker image ls
REPOSITORY                         TAG                    IMAGE ID       CREATED         SIZE
react-api20230327a                 1.0                    873f12e8926c   2 hours ago     1.52GB
go-api20230327a                    1.0                    086fb0816a7c   17 hours ago    501MB
% docker save -o react-api20230327a.tar react-api20230327a:1.0
% docker save -o go-api20230327a.tar go-api20230327a:1.0
% scp -i ~/.aws/docker20230223.pem ./react-api20230327a.tar ubuntu@54.199.172.102:/home/ubuntu
% scp -i ~/.aws/docker20230223.pem ./go-api20230327a.tar ubuntu@54.199.172.102:/home/ubuntu
```

## EC2 で docker load
```:EC2 terminal
$ docker load -i react-api20230327a.tar
$ docker load -i go-api20270327a.tar
```

## EC2 でポート3000を開けておきます
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/720d75a0-546c-d611-5e4d-8b25bf2318f1.png">


## EC2 でコンテナ立てます（GoのAPIサーバーとReactのAPIクライアント）
ReactのAPIクライアントにポートは3000を使用します。
```:EC2 terminal
$ docker network create apinet
$ docker run -it --name go-api --net apinet -p 8080:8080 go-api20230327:1.0
$ docker run -it --name react-api --net apinet -p 3000:3000 react-api20230327a:1.0
```

## EC2 の Docker上のReactにアクセスして、EC2 の Docker上のGoのAPIサーバーからGETできました
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298045/40cdf57d-81dc-f28d-4478-cf855562439c.png">


# 参考
・[DockerでReactの開発環境を作る](https://qiita.com/tanaka-tt/items/49628cd423e490120eeb)
・[SCP】AWSのEC2にファイル転送する](https://rurukblog.com/post/scp-es2/)
・[UbuntuサーバーにNginxをインストールしよう](https://asameshicode.com/install-nginx-to-ubuntu-server/)
・[EC2でReactをhttpsでnpm startして外部からアクセスする](https://qiita.com/duplicate1984/items/f1cfa7747fc9aa197d7c)
・[Docker 入門 | golang & gin の環境構築](https://kiyobl.com/docker-go/)