こんにちは、KOUKIです。
Golang/ReactでMovie Appの開発を行います。
フロントエンド側はReact、バックエンド側はGo言語で実装するので、Webアプリ開発を一通り経験したい人には必見な記事になると思います。
今回は、Golangの開発環境をDockerを使って構築してみましょう。
※順番的にReact開発環境構築の後になります
尚、Udemyの「Working with React and Go (Golang)」を参考にしているので、よかったら受講してみてください。
<目次>
事前準備
フォルダ/ファイル
1 2 3 4 5 6 7 8 |
touch Dockerfile-golang mkdir backend-app cd backend-app/ go mod init backend mkdir -p cmd/api touch cmd/api/main.go touch .air.tom go get -u github.com/bxcodec/faker/v3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
. ├── Dockerfile-golang ├── Dockerfile-react ├── README.md ├── backend-app // Goのプロジェクト │ ├── .air.toml │ ├── cmd │ ├── go.mod │ ├── go.sum │ └── tmp ├── docker-compose.yml └── go-movies // Reactのプロジェクト ├── .gitignore ├── README.md ├── node_modules ├── package-lock.json ├── package.json ├── public ├── src ├── tsconfig.json └── yarn.lock |
WebServerの構築
Go言語では、簡単にWebServerを構築することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
// cmd/api/main.go package main import ( "encoding/json" "flag" "fmt" "log" "net/http" ) const version = "1.0.0" type config struct { port int env string } type AppStatus struct { Status string `json:"status"` Environment string `json:"environment"` Version string `json:"version"` } func main() { var cfg config flag.IntVar(&cfg.port, "port", 4000, "Server port to listen on") flag.StringVar(&cfg.env, "env", "development", "Application environment (development|production)") flag.Parse() fmt.Println("Running") http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { currentStatus := AppStatus{ Status: "Available", Environment: cfg.env, Version: version, } js, err := json.MarshalIndent(currentStatus, "", "\t") if err != nil { log.Println(err) } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write(js) }) err := http.ListenAndServe(fmt.Sprintf(":%d", cfg.port), nil) if err != nil { log.Println(err) } } |
動作確認をしましょう。
terminalからWebサーバーを立ち上げてください。
1 2 |
$ go run cmd/api/main.go Running |
次に、以下のパラメータでリクエストを送ってみましょう。私は、Chromeの「Talend API Tester – Free Edition」を使って動作確認をします。
- URL: http://localhost:4000/status
- 形式: GET

Docker化
Webサーバーが動作することが確認できたので、Docker化しましょう。
Dockerfile
Backendのdockerイメージを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Dockerfile-golang FROM golang:1.16 WORKDIR /app COPY backend-app/go.mod . COPY backend-app/go.sum . # airの設定ファイルをコピー COPY backend-app/*air.toml . RUN go mod download COPY ./backend-app . RUN curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin CMD ["air"] |
docker-compose.yml
Backendサービスを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# docker-compose.yml version: "3.3" services: # 追加 backend: build: context: . dockerfile: ./Dockerfile-golang ports: - 4000:4000 volumes: - ./backend-app:/app frontend: build: context: . dockerfile: ./Dockerfile-react volumes: - ./go-movies:/go-movies command: > sh -c "npm run start" ports: - "3000:3000" container_name: frontend |
ホットリロード
golang製の「air」を使って、ホットリロードの仕組みを導入します。これを使うと、ファイルの変更を検知して、自動的にビルドし直してくれます。つまり、変更を反映するためにコンテナを立ち上げ直す必要がなくなるというわけです。
.air.tomlに設定を記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# .air.toml # Config file for [Air](https://github.com/cosmtrek/air) in TOML format # Working directory # . or absolute path, please note that the directories following must be under root. root = "." tmp_dir = "tmp" [build] # Just plain old shell command. You could use `make` as well. cmd = "go build -o ./tmp/main ./cmd/api" # Binary file yields from `cmd`. bin = "tmp/main" # Customize binary. full_bin = "APP_ENV=dev APP_USER=air ./tmp/main" # Watch these filename extensions. include_ext = ["go", "tpl", "tmpl", "html"] # Ignore these filename extensions or directories. exclude_dir = ["assets", "tmp", "vendor"] # Watch these directories if you specified. include_dir = [] # Exclude files. exclude_file = [] # This log file places in your tmp_dir. log = "air.log" # It's not necessary to trigger build each time file changes if it's too frequent. delay = 1000 # ms # Stop running old binary when build errors occur. stop_on_error = true # Send Interrupt signal before killing process (windows does not support this feature) send_interrupt = false # Delay after sending Interrupt signal kill_delay = 500 # ms [log] # Show log time time = false [color] # Customize each part's color. If no color found, use the raw app log. main = "magenta" watcher = "cyan" build = "yellow" runner = "green" [misc] # Delete tmp directory on exit clean_on_exit = true |
ビルド&実行
下記のコマンドで、コンテナをビルドし、立ち上げましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$ docker-compose build backend $ docker-compose up backend Starting movie-app_backend_1 ... done Attaching to movie-app_backend_1 backend_1 | backend_1 | __ _ ___ backend_1 | / /\ | | | |_) backend_1 | /_/--\ |_| |_| \_ 1.27.3, built with Go 1.16.3 backend_1 | backend_1 | watching . backend_1 | watching cmd backend_1 | watching cmd/api backend_1 | watching cmd/api/tmp backend_1 | !exclude tmp backend_1 | building... backend_1 | running... backend_1 | Running |
次回
次回は、ルーティング処理を実装しましょう。
記事まとめ
参考書籍
ソースコード
ここまで実装したソースコードを下記に記載します。
Dockerfile-golang
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Dockerfile-golang FROM golang:1.16 WORKDIR /app COPY backend-app/go.mod . COPY backend-app/go.sum . # airの設定ファイルをコピー COPY backend-app/*air.toml . RUN go mod download COPY ./backend-app . RUN curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin CMD ["air"] |
docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# docker-compose.yml version: "3.3" services: backend: build: context: . dockerfile: ./Dockerfile-golang ports: - 4000:4000 volumes: - ./backend-app:/app frontend: build: context: . dockerfile: ./Dockerfile-react volumes: - ./go-movies:/go-movies command: > sh -c "npm run start" ports: - "3000:3000" container_name: frontend |
main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
// cmd/api/main.go package main import ( "encoding/json" "flag" "fmt" "log" "net/http" ) const version = "1.0.0" type config struct { port int env string } type AppStatus struct { Status string `json:"status"` Environment string `json:"environment"` Version string `json:"version"` } func main() { var cfg config flag.IntVar(&cfg.port, "port", 4000, "Server port to listen on") flag.StringVar(&cfg.env, "env", "development", "Application environment (development|production)") flag.Parse() fmt.Println("Running") http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { currentStatus := AppStatus{ Status: "Available", Environment: cfg.env, Version: version, } js, err := json.MarshalIndent(currentStatus, "", "\t") if err != nil { log.Println(err) } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write(js) }) err := http.ListenAndServe(fmt.Sprintf(":%d", cfg.port), nil) if err != nil { log.Println(err) } } |
.atom.toml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# .air.toml # Config file for [Air](https://github.com/cosmtrek/air) in TOML format # Working directory # . or absolute path, please note that the directories following must be under root. root = "." tmp_dir = "tmp" [build] # Just plain old shell command. You could use `make` as well. cmd = "go build -o ./tmp/main ./cmd/api" # Binary file yields from `cmd`. bin = "tmp/main" # Customize binary. full_bin = "APP_ENV=dev APP_USER=air ./tmp/main" # Watch these filename extensions. include_ext = ["go", "tpl", "tmpl", "html"] # Ignore these filename extensions or directories. exclude_dir = ["assets", "tmp", "vendor"] # Watch these directories if you specified. include_dir = [] # Exclude files. exclude_file = [] # This log file places in your tmp_dir. log = "air.log" # It's not necessary to trigger build each time file changes if it's too frequent. delay = 1000 # ms # Stop running old binary when build errors occur. stop_on_error = true # Send Interrupt signal before killing process (windows does not support this feature) send_interrupt = false # Delay after sending Interrupt signal kill_delay = 500 # ms [log] # Show log time time = false [color] # Customize each part's color. If no color found, use the raw app log. main = "magenta" watcher = "cyan" build = "yellow" runner = "green" [misc] # Delete tmp directory on exit clean_on_exit = true |
コメントを残す
コメントを投稿するにはログインしてください。