
Go言語によるRESTアプリケーションの開発を加速するために、Docker化し、freshでオートリロードを可能にする方法を紹介します。
見出し
はじめに
以前の記事でGo言語でRESTアプリケーションを実装する方法を紹介しました。今回は、開発環境を簡単に構築できるようにするために、Docker化し、その際に、「fresh」というオートリロード用のモジュールを導入する方法を紹介します。それでは、始めましょう。
前提
以下の準備が完了している必要があります。
- Go言語がインストールされていること
- Dockerがインストールされていること
- 以前の記事で実装したRESTアプリケーションが準備されていること(いつも通りチュートリアル形式で進めていきますが、内容を参考にするだけで良いなら不要です)
詳しくは「環境」を参照してください。
Go言語のRESTアプリケーションを開発用にオートリロード可能な状態でDocker化する
必要なファイルとフォルダを準備する
以前の記事で実装したRESTアプリケーションを準備して、そのプロジェクト内に必要なファイルとフォルダを作成します。
$ cd golang-rest-api/
$ touch Dockerfile.dev
$ touch docker-compose.yml
$ mkdir data
$ touch wait-for-it.sh
今回はローカルにPostgreSQLのデータを残すためにdataフォルダも作成します。また、PostgreSQLのデータベースが起動するのを待つために「wait-for-it」を使います。「wait-for-it.sh」にはGitHub上のスクリプトをコピペしてください。
Dockerファイルを作成する
Dockerファイル内でオートリロードのためのモジュール「fresh」を設定するようにします。
Dockerfile.dev
FROM golang:1.11.4-stretch
LABEL maintainer="YOU"
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
RUN go get github.com/pilu/fresh
RUN go get -u github.com/go-delve/delve/cmd/dlv
COPY . .
EXPOSE 3000
CMD fresh main.go
Docker Composeファイルを作成する
docker-compose.yml
version: '3'
services:
app:
container_name: my_app
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- .:/app
depends_on:
- db
command: >
bash -c "chmod +x ./wait-for-it.sh &&
./wait-for-it.sh db:5432 -t 30 -- fresh main.go"
db:
container_name: my_postgres
image: postgres:11.1
restart: always
environment:
- "TZ: Etc/UTC"
- POSTGRES_USER=puser
- POSTGRES_PASSWORD=ppassword
- POSTGRES_DB=testdb
ports:
- 5432:5432
volumes:
- ./data:/var/lib/postgresql/data
- ./initdb:/docker-entrypoint-initdb.d
RESTアプリケーション内のPostgreSQLの接続先をDocker Composeの設定に合わせて変更する
接続先を「localhost」から「my_postgres」に変更します。
main.go
package main
import (
"database/sql"
"golang-rest-api/controllers"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/lib/pq"
)
func main() {
pgURL, err := pq.ParseURL("postgres://puser:ppassword@my_postgres:5432/testdb?sslmode=disable")
if err != nil {
log.Fatal(err)
}
db, err := sql.Open("postgres", pgURL)
if err != nil {
log.Fatal(err)
}
controller := controllers.Controller{}
router := mux.NewRouter()
router.HandleFunc("/api/tweets", controller.GetTweets(db)).Methods("GET")
router.HandleFunc("/api/tweets/{id}", controller.GetTweet(db)).Methods("GET")
router.HandleFunc("/api/tweets", controller.AddTweet(db)).Methods("POST")
router.HandleFunc("/api/tweets/{id}", controller.PutTweet(db)).Methods("PUT")
router.HandleFunc("/api/tweets/{id}", controller.RemoveTweet(db)).Methods("DELETE")
log.Println("Server up on port 3000...")
log.Fatal(http.ListenAndServe(":3000", router))
}
動作確認
では動作確認してみましょう。
まずは、Docker化したRESTアプリケーションが正しく動くか確認します。
$ docker-compose up -d
Creating network "golang-rest-api_default" with the default driver
Creating my_postgres ... done
Creating my_app ... done
$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------
my_app bash -c chmod +x ./wait-fo ... Up 0.0.0.0:3000->3000/tcp
my_postgres docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp
$ curl -v -H "Accept:application/json" -H "Content-Type:application/json" -X POST -d '{"content":"This is my first tweet.","user_name":"@keidrun","comment_num":5,"star_num":15,"re_tweet_num":25}' http://localhost:3000/api/tweets | jq
$ curl -v -H "Accept:application/json" -H "Content-Type:application/json" -X POST -d '{"content":"Golang is my favorite language!","user_name":"@superdeveloper","comment_num":22,"star_num":222,"re_tweet_num":2222}' http://localhost:3000/api/tweets | jq
$ curl -v -H "Accept:application/json" -H "Content-Type:application/json" -X POST -d '{"content":"I am nothing. Just an ordinary guy.","user_name":"@person"}' http://localhost:3000/api/tweets | jq
$ curl -v -H "Accept:application/json" http://localhost:3000/api/tweets | jq
...
[
{
"id": 1,
"content": "This is my first tweet.",
"user_name": "@keidrun",
"comment_num": 5,
"star_num": 15,
"re_tweet_num": 25
},
{
"id": 2,
"content": "Golang is my favorite language!",
"user_name": "@superdeveloper",
"comment_num": 22,
"star_num": 222,
"re_tweet_num": 2222
},
{
"id": 3,
"content": "I am nothing. Just an ordinary guy.",
"user_name": "@person",
"comment_num": 0,
"star_num": 0,
"re_tweet_num": 0
}
]
次に、オートリロードが動作するか確認するために、エラーメッセージを変更してみます。
$ curl -v -H "Accept:application/json" http://localhost:3000/api/tweets/1 | jq
...
{
"id": 1,
"content": "This is my first tweet.",
"user_name": "@keidrun",
"comment_num": 5,
"star_num": 15,
"re_tweet_num": 25
}
$ curl -v -H "Accept:application/json" http://localhost:3000/api/tweets/num | jq
...
{
"message": "\"id\" is wrong"
}
(ここでソースコード上のエラーメッセージを変更する)
$ curl -v -H "Accept:application/json" http://localhost:3000/api/tweets/num | jq
...
{
"message": "\"id\" is absolutely wrong"
}
正しく動くことが確認できました。
おまけ
プロダクション用にDocker化する
Go言語はコンパイル言語なので、プロダクション用にはコンパイルして実行可能な状態にする必要があります。alpineで軽量のDockerイメージにする場合のDockerファイルは以下のようになります。
Dockerfile
FROM golang:1.11.4-stretch AS builder
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server
FROM alpine:3.8
LABEL maintainer="YOU"
WORKDIR /app
EXPOSE 3000
COPY --from=builder /app/server /app/
ENTRYPOINT ["/app/server"]
最後に
いかがでしたか?これでGo言語のRESTアプリケーションをDocker上で開発できるようになったことでしょう。それでは。
環境
- Go: go1.11.4
- Docker: 18.09.1, build 4c52b90
- fresh: v0.0.0-20170301142741-9c0092493eff


コメントを残す