このサーバをさらにDockerのコンテナに搭載します。
サーバも何も入っていないが、Golang開発環境だけが入っているコンテナを作ります。DockerでGoの開発環境を構築するを参考させて頂きました。
mkdir work # workディレクトリ作成 cd work # 作成したworkディレクトリに移動
ここに、Dockerfileとdocker-compose.ymlを作ります。
(Dockerfileの内容)
# ベースとなるDockerイメージ指定
FROM golang:latest
# コンテナ内に作業ディレクトリを作成
RUN mkdir /go/src/work
# コンテナログイン時のディレクトリ指定
WORKDIR /go/src/work
# ホストのファイルをコンテナの作業ディレクトリに移行
ADD . /go/src/work
上記の、/go/src/work は、ローカル(PC)のディレクトリではなくて、コンテナの中のディレクトリなので、パスの構成は気にしなくてよい。
(docker-compose.yml
の中身)
version: '3' # composeファイルのバーション指定
services:
app: # service名
build: . # ビルドに使用するDockerfileがあるディレクトリ指定
tty: true # コンテナの起動永続化
volumes:
- .:/go/src/work # マウントディレクトリ指定
次に、
docker-compose build
を実行する。
$ docker-compose build
Building app
Step 1/4 : FROM golang:latest
---> a794da9351a3
Step 2/4 : RUN mkdir /go/src/work
---> Using cache
---> 094b928e9bfb
Step 3/4 : WORKDIR /go/src/work
---> Using cache
---> b7a938d02446
Step 4/4 : ADD . /go/src/work
---> 9d95f42d64e3
Successfully built 9d95f42d64e3
Successfully tagged work_app:latest
さらに、docker-compose up -d を実行する。
$ docker-compose up -d
Creating network "work_default" with the default driver
Creating work_app_1 ... done
コンテナができているか同化を確認します。
$ docker-compose ps
Name Command State Ports
------------------------------------
work_app_1 bash Up
現在、~/go_echo にある、server.goを、~/go_echo/workにコピーします。
これで、server.go が、ローカル(PC)と、コンテナの中で共有されるようになります。
では、コンテナの中に入ります。
$ winpty docker container exec -it work_app_1 bash # 江端のMSYS2 のシェルでは、"winpty"を付ける必要があるが、通常のシェルでは不要
root@abe44622eccf:/go/src/work# ls
'#main.go#' Dockerfile Dockerfile~ server.go docker-compose.yml docker-compose.yml~ main main.go main.go~ websocket-server.go
ここで、Goプログラムを実行します。
root@abe44622eccf:/go/src/work# go run server.go
server.go:21:2: cannot find package "github.com/gorilla/websocket" in any of:
/usr/local/go/src/github.com/gorilla/websocket (from $GOROOT)
/go/src/github.com/gorilla/websocket (from $GOPATH)
ふむ、やはり、こうなりますね。では、パッケージをインストールしましょう。
root@abe44622eccf:/go/src/work# go get github.com/gorilla/websocket
何のメッセージも出さずに20秒後くらいに静かにプロンプトが戻ってきました(ちょっと不安になる)。
root@abe44622eccf:/go/src/work# go run client_multi_agent.go
connecting to ws://localhost:8080/echo
dial:dial tcp 127.0.0.1:8080: connect: connection refused
exit status 1
うーん、やっぱりネットワーク回りの設定をしていないから当然か。ポート開けていないし。docker-compose downして、docker-compose.ymlに以下を追加してみました。
ports:
- "8080:8080"
$ more docker-compose.yml
version: '3' # composeファイルのバーション指定
services:
app: # service名
build: . # ビルドに使用するDockerfileがあるディレクトリ指定
tty: true # コンテナの起動永続化
volumes:
- .:/go/src/work # マウントディレクトリ指定
ports:
- "8080:8080"
それと、"go get github.com/gorilla/websocket"を毎回実行しない為には、Dockerfileに "RUN go get github.com/gorilla/websocket"を1行加えれば良いみたい。
# ベースとなるDockerイメージ指定
FROM golang:latest
# コンテナ内に作業ディレクトリを作成
RUN mkdir /go/src/work
# コンテナログイン時のディレクトリ指定
WORKDIR /go/src/work
# ホストのファイルをコンテナの作業ディレクトリに移行
ADD . /go/src/work
# gorillaのパッケージを入れる
RUN go get github.com/gorilla/websocket
そんでもって、再びdocker-compose build → docker-compose up -d を実施して、docker container exec -it work_app_1 bash をして、コンテナの中に入って、go run server.goをやったんだけど、ブラウザで、http://localhost:8080やっても表示されない。
C:\Users\ebata\go_echo\work>curl http://localhost:8080/
curl: (52) Empty reply from server
となっているところを見ると。8080ポートは外側に見えていないみたい。
でも、
C:\Users\ebata\go_echo\work>netstat -a | grep 8080
TCP 0.0.0.0:8080 DESKTOP-P6KREM0:0 LISTENING
TCP [::]:8080 DESKTOP-P6KREM0:0 LISTENING
にはなっているんだよなぁ。
試しに、コンテナの中で"curl http://localhost:8080/"をやってみたら、
oot@b30e685f9cc6:/go/src/work# curl http://localhost:8080/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
window.addEventListener("load", function(evt) {
var output = document.getElementById("output");
var input = document.getElementById("input");
var ws;
てな感じで、ばっちり見えます。
うーん、変だなぁ。"8080:8080"ってポートフォワードしているじゃないのか? WebSocketの場合は、特殊な設定がいるのか?分かりません。
もう6時間くらい闘ったので、引き上げようとして、最後に、"curl: (52) Empty reply from server" でググってみたら、ドンピシャな感じの記事を見つけました。
docker上のアプリにlocalhostでアクセスしたらERR_EMPTY_RESPONSEが出る
まさに、同じ現象が表われていて、『そう! そう!』と言いながら読み進めていき、結果として、
(解決) アプリの設定を0.0.0.0でLISTENするよう変更する
と記載されていましたので、server.goのソースコードを、
//var addr = flag.String("addr", "localhost:8080", "http service address")
var addr = flag.String("addr", "0.0.0.0:8080", "http service address") // テスト
と変更してみたところ、http://localhost:8080 でWebもcurlも表示されるようになりました。
ああ、これで、サーバのコンテナ化にメドがついた ―― と思ったら、どっと疲れが出てきました。
『Dockerのコンテナは、江端が作れ』と、指示されていましたので。
Dockerfileの最後に、
CMD ["go", "run", "server.go"]
をつけると、dockerコンテナをサーバ化にできる。
ただし、
# docker-compose build,
# docker-compose up (-d ← これを付けたらダメ。バックグラウンドで起動するとDockerが終了してしまう)
で起動すること。