Dockerを使ってGo言語のHTTPサーバーを構築する

## 環境

**[play with docker](https://labs.play-with-docker.com/)** を使用したサンドボックス環境で行いました。
環境は以下の通りです。

```bash
$ more /etc/issue
Welcome to Alpine Linux 3.8
Kernel \r on an \m (\l)
```

## サンプルを用意

作業ディレクトリは以下の通りです。

```bash
$ mkdir go-docker && cd go-docker
```

最終的なディレクトリ構造は以下のようになります。

```bash
$ tree
.
├── Dockerfile
├── docker-compose.yml
└── main.go
```

必要なファイルを用意します。

```yml:docker-compose.yml
version: '3'
services:
  app:
    build: .
    ports:
      - "18888:18888" # "ホストのポート:コンテナのポート"
```

```Dockerfile:Dockerfile
FROM golang:apline
WORKDIR /go
ADD . /go
CMD ["go", "run", "main.go"]
```
`Go`言語の`HTTP`サーバーはクライアントからのリクエスト情報をダンプしテキストとしてログを出力します。

```go:main.go
package main

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

func handler(w http.ResponseWriter, r *http.Request) {
    dump, err := httputil.DumpRequest(r, true)
    if err != nil {
        http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
        return
    }
    fmt.Println(string(dump))
    fmt.Fprintf(w, "<html><body>hello</body></html>\n")
}

func main() {
    var httpServer http.Server
    http.HandleFunc("/", handler)
    log.Println("start http listening :18888")
    httpServer.Addr = ":18888"
    log.Println(httpServer.ListenAndServe())
}
```

## テストサーバーの実行

サーバーのログと`curl`のレスポンスの両方を確認したいので`tmux`を使いターミナルのウィンドウを複数立ち上げます。

```bash
$ tmux

[0] bash*
```

サービスを開始します。

```bash
$ docker-compose up
Building app
Step 1/4 : FROM golang:alpine
7e273b0dfc44: Pull complete
952c3806fd1a: Pull complete
daee55ea059d: Pull complete
18dd7cffb4bd: Pull complete
Digest: sha256:8dea7186cf96e6072c23bcbac842d140fe0186758bcc215acb1745f584984857
Status: Downloaded newer image for golang:alpine
 ---> a0d0176aa927
Step 2/4 : WORKDIR /go ---> Running in 996698f42f81
Removing intermediate container 996698f42f81
 ---> a92d9619a5bd
Step 3/4 : ADD . /go
 ---> 600f566e39b3
Step 4/4 : CMD ["go", "run", "main.go"]
 ---> Running in d95e2f0c2bd5
Removing intermediate container d95e2f0c2bd5
 ---> f9414817258f
Successfully built f9414817258f
Successfully tagged go-docker_app:latest
WARNING: Image for service app was built because it did not already exist. To rebild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating go-docker_app_1 ... done
Attaching to go-docker_app_1
app_1  | 2019/01/26 12:23:21 start http listening :18888

[0] 0:python2*
```

もしタイポ等でビルドが失敗し、ファイルを修正した場合、以下のコマンドでビルドし直します。
キャッシュが残っていると修正が適用されないことがあるためです。

```bash
$ docker-compose build --no-cache
```

`Ctrl+b` `c`で新しい`tmux`で新しいウィンドウを立ちあげます。
`curl`で`GET`リクエストを送ってみるとレスポンスが返ります。

```bash
$ curl http://localhost:18888
<html><body>hello</body></html>

[0] 0:python2- 1:bash*  
```

レスポンスが確認できたのでサーバー側のログを確認します。
`Ctrl+b` `0`でウィンドウを移動します。

```bash
app_1  | GET / HTTP/1.1
app_1  | Host: localhost:18888
app_1  | Accept: */*
app_1  | User-Agent: curl/7.61.1
app_1  |
app_1  |
```

サーバー側にログが出ているのが確認できました。

また、ブラウザでアクセスすると以下のログが出力されました。

```bash
app_1  | GET /favicon.ico HTTP/1.1
app_1  | Host: ip172-18-0-26-bh62khspkul000e5uv20-18888.direct.labs.play-with-docker.com
app_1  | Accept: image/webp,image/apng,image/*,*/*;q=0.8
app_1  | Accept-Encoding: gzip, deflate
app_1  | Accept-Language: ja,en-US;q=0.9,en;q=0.8
app_1  | Connection: keep-alive
app_1  | Cookie: ajs_group_id=null; ajs_anonymous_id=%227418f5d2-b470-4486-87e5-9a30b706a1d6%22; _mkto_trk=id:929-FJL-178&token:_mch-play-with-docker.com-1542894871838-65318; ajs_user_id=%229b8a2d07-0124-464a-92dd-cba9c6b8ebfc%22; _ga=GA1.2.1538667850.1548340200; _gid=GA1.2.1371521392.1548432670
app_1  | Referer: http://ip172-18-0-26-bh62khspkul000e5uv20-18888.direct.labs.play-with-docker.com/
app_1  | User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
app_1  |
app_1  |
```

今回のサンプルは GitHub の以下のリポジトリに置きました。
https://github.com/sano-suguru/go-docker-http-server

## 参考

以下の書籍を参考にさせていただきました。
**[Real World HTTP - 渋川 よしき](https://www.oreilly.co.jp/books/9784873118048/)**