現在、勉強がてら個人開発をしていて、せっかくの個人開発なので、今までさわったことがないReact, Go, MongoDBでwebアプリを作ります。 その最初の段階として、Docker Composeを使って環境構築を進めます。

Reactの環境構築

今回の開発では、プロジェクト配下をこんな感じにしています。

プロジェクト
├── backend
├── frontend

Reactはfrontend配下に構築します。

Dockerfileの作成

DockerfileにDocker上で起動させるコンテナの構成情報を書きます。 frontend配下に以下内容で作成します。

FROM node:13.12.0-alpine3.10
WORKDIR /usr/src/app

1行目にはコンテナのDockerイメージ、2行目にはコンテナ内の作業ディレクトリを記載しています。 alpineはAlpine Linuxのことで、必要最低限の構成がされているおかげで、Dockerイメージの軽量化を図ることができます。

docker-compose.ymlの作成

docker-compose.ymlで複数のコンテナをまとめて起動することができます。拡張子は「.yml」「.yaml」どちらでも動きます。 どっちかに統一してくれればいいのに。
プロジェクト配下に以下内容で作成します。

version: '3'
services:
    node:
        build:
            context: ./frontend
            dockerfile: Dockerfile
        volumes:
            - ./frontend:/usr/src/app
        command: sh -c "yarn start"
        ports:
            - "3000:3000"

volumesではコンテナ内のusr/src/appfrontendに永続化させます。 portsでは外部の3000ポートとコンテナ内の3000ポートをつなげています。ローカル環境ではlocalhost:3000でアクセスができるようになります。

Dockerイメージのビルド

docker-compose.ymlのある階層で以下コマンドを叩きます。

docker-compose build
Building node
Step 1/2 : FROM node:13.12.0-alpine3.10
 ---> b529a862f234
Step 2/2 : WORKDIR /usr/src/app
 ---> Using cache
 ---> b753b92fbf97
Successfully built b753b92fbf97
Successfully tagged プロジェクト名_node:latest

上記のような表示がされ、ビルドすることができます。

コンテナの起動

僕はすでにローカル環境でReactのひな形を作成していたので、Reactの導入は省きます。 niftyさんのReactの開発環境をDockerで構築してみた を参考にして作業を進めてください。 コンテナの起動をするには以下コマンドを叩きます。

docker-compose up

このコマンドにより、docker-compose.ymlsh -c "yarn start"が実行されて、Reactが起動します。

Starting プロジェクト名_node_1 ... done
Attaching to プロジェクト名_node_1
node_1  | yarn run v1.22.4
node_1  | $ react-scripts start
node_1  | ℹ 「wds」: Project is running at http://172.20.0.2/
node_1  | ℹ 「wds」: webpack output is served from
node_1  | ℹ 「wds」: Content not from webpack is served from /usr/src/app/public
node_1  | ℹ 「wds」: 404s will fallback to /
node_1  | Starting the development server...
node_1  |
node_1  | Files successfully emitted, waiting for typecheck results...
node_1  | Compiled successfully!
node_1  |
node_1  | You can now view frontend in the browser.
node_1  |
node_1  |   Local:            http://localhost:3000
node_1  |   On Your Network:  http://172.20.0.2:3000
node_1  |
node_1  | Note that the development build is not optimized.
node_1  | To create a production build, use npm run build.
node_1  |

http://localhost:3000にアクセスすると次のような画面が表示されます。

React Sample

Go, MongoDBの環境構築

次にGo, MongoDBの環境構築を進めます。 今のところ以下のようなディレクトリ構成になっています。

プロジェクト
├── backend
├── frontend
      ├── node_modules
      ├── public
      ├── src
      ├── Dockerfile
      ├── package.json
      ├── README.md
      └── yarn.lock

僕のReactのひな形の作り方が参考記事とは違っているので、間違っているかもしれないです。
backend配下にGoディレクトリを作成して、そこにGoを構築します。 今回はGoのサーバを起動するコンテナとMongoDBのコンテナを連携させていきます。

Dockerfileの作成

Go配下に以下内容で作成します。

FROM golang:1.14

WORKDIR /go/
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["go", "run", "src/serversample/main.go"]

go run src/serversample/main.goでWebサーバを立ち上げています。go runでコンパイルをして実行してくれます。

GoのWebサーバ作成

go配下にsrc/serversample/main.goを以下内容で作成します。

package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()       //オプションを解析します。デフォルトでは解析しません。
	fmt.Println(r.Form) //このデータはサーバのプリント情報に出力されます。
	fmt.Println("path", r.URL.Path)
	fmt.Println("scheme", r.URL.Scheme)
	fmt.Println(r.Form["url_long"])
	for k, v := range r.Form {
		fmt.Println("key:", k)
		fmt.Println("val:", strings.Join(v, ""))
	}
	fmt.Fprintf(w, "Hello astaxie!") //ここでwに入るものがクライアントに出力されます。
}

func main() {
	http.HandleFunc("/", sayhelloName)       //アクセスのルーティングを設定します。
	err := http.ListenAndServe(":9090", nil) //監視するポートを設定します。
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

9090ポートからGoのWebサーバにアクセスすることができるようになります。

docker-compose.ymlに追記

ここら辺からはこの記事 を参考に作成しました。

docker-compose.ymlを以下内容に更新します。

version: '3'
services:
    node:
        build:
            context: ./frontend
            dockerfile: Dockerfile
        volumes:
            - ./frontend:/usr/src/app
        command: sh -c "yarn start"
        ports:
            - "3000:3000"
    dbapi:
        build:
            context: ./backend/go
            dockerfile: Dockerfile
        links:
            - mongodb
        depends_on:
            - mongodb
        ports:
            - "9090:9090"
    mongodb:
        image: mongo
        container_name: mongodb
        volumes:
            - mongodata
volumes:
  mongodata:
    driver: local

MongoDBはimage: mongoでdockerイメージを作成していて、mongodbという名前のコンテナになっています。 dbapiはGoのDockerfileのビルド、linksmongodbとの連携、depends_onmongodbを先に実行する設定にしています。

volumes:
  mongodata:
    driver: local

でMongoDBのデータを永続化するようにしています。

Dockerイメージのビルド

準備は整ったので、Dockerイメージをビルドします。

docker-compose build
mongodb uses an image, skipping
Building node
Step 1/2 : FROM node:13.12.0-alpine3.10
 ---> b529a862f234
Step 2/2 : WORKDIR /usr/src/app
 ---> Using cache
 ---> b753b92fbf97
Successfully built b753b92fbf97
Successfully tagged プロジェクト名_node:latest
Building dbapi
Step 1/6 : FROM golang:1.14
 ---> b022a9b82d88
Step 2/6 : WORKDIR /go/
 ---> Using cache
 ---> b44021327ebc
Step 3/6 : COPY . .
 ---> Using cache
 ---> f2f46b278392
Step 4/6 : RUN go get -d -v ./...
 ---> Using cache
 ---> bdf5c8a92f17
Step 5/6 : RUN go install -v ./...
 ---> Using cache
 ---> 8700edd290d2
Step 6/6 : CMD ["go", "run", "src/serversample/main.go"]
 ---> Using cache
 ---> 5f9bd6f4def1
Successfully built 5f9bd6f4def1
Successfully tagged プロジェクト名_dbapi:latest

ビルドに成功しています。

コンテナの起動

いよいよ全コンテナを起動します。

docker-compose up

今回はターミナルに表示される量がかなり多いので、省きます。
http://localhost:3000にアクセスして、Reactの画面が表示され、 http://localhost:9090にアクセスして、このような画面になれば成功です!

go webserver

終わりに

今回はReact + Go + MongoDBの環境をDocker Composeで作成することができました! docker-compose.ymlに全てまとめて記載をしましたが、クラウドにデプロイするときは同じサーバにはおかないですし、コンテナ起動も時間がかかってしまうので、フロントとサーバサイドで分けた方がいいですね。
また、今回はGoとMongoDBの接続をすることはできていなくて、Goに関してはWebサーバを立ち上げただけなので、そこらへんに次回は取り組みたいです。