Dockerを使って本番さながらのGolangの環境を構築してIntelliJで開発する
やっと季節は三寒四温の状態から抜け、もう春だと言っていい季節ですが、僕は痔に苦しんでいてやっとの思いで回復に向かっております。
春って素敵。
というわけで、業務で新しいプロジェクトがGolangで実装する方針になってしまったので、仕方なくGolangの開発環境を構築します。
Scalaどこ行った。
僕自身はレガシープロジェクトに長いこといたので今更ながらDockerへの入門レベルの情報を書き並べつつ環境構築していきます。
準備
- VirtualBoxのインストール
- Vagrantのインストール
環境
- Mac OSX 10.9.5 Mavericks
- Vagrant 1.7.2
目標
MacのIntelliJからGolangのソースコードを修正して、Dockerコンテナ内に反映させ、
Macのブラウザ経由でアクセスしてレスポンスを確認できる。
仮想OSを準備してMacとファイルの同期を行う。
仮想OSはCoreOSを使います。
Vagrantfileは
から拝借します。
拝借したらひとつ細工を施します。
というのも、Macと(CoreOSと)Dockerのディレクトリを共有する方法がいくつかあるのですが、
MacからCoreOSがデフォルトではNFSになっており、
MacのIntelliJでファイルを修正した場合にCoreOSにファイルを同期してくれません。
linux - Vagrant, shared folder: take advantage of inotify over NFS - Stack Overflow
そこで同期の方法をrsyncに変更します。
#config.vm.synced_folder ".", "/home/core/share", id: "core", :nfs => true, :mount_options => ['nolock,vers=3,udp']
こう書いてあるのを
config.vm.synced_folder ".", "/home/core/share", id: "core", type: "rsync"
こう。 修正が終わったら仮想OSを立ち上げましょう。
$ vagrant up
立ち上げたら vagrant rsync-auto
を実行すればIntelliJで修正したファイルがCoreOSに同期されます。
vagrant ssh
して確認してみてください。
rsyncが上手く動かない時は下の方に書いてある「注意」の項を読んでください。
CoreOSでDockerコンテナを立ち上げる
上記のCoreOSには既にDockerがインストールされているので、早速Dockerを立ち上げましょう。
今回は以下のスクリプトを用意したので、それを実行してみてください。
docker-golang/create_container.sh at master · takasing/docker-golang · GitHub
まずはGolangコンテナの起動
core@core-01 ~ $ ./share/create_container.sh golang api
このスクリプト内で実行されている docker
コマンドのざっくり解説はこんな感じ。
内容 | 意味 | 参考 |
---|---|---|
docker run |
指定したDockerコンテナを立ち上げる | |
--name |
コンテナの名前を指定 これがない場合はデフォルトでなんかかっちょいい名前をつけてもらえます(^q^) |
|
-itd |
コンテナの標準入力を開いてtty(端末デバイス)を確保するそう | CoreOS docker のコマンド - わすれないうちにメモしよう |
-d |
コンテナをバックグラウンドで実行 これがないとコンテナからexitするとコンテナごとstopしてしまいます |
|
-p |
ポートフォワーディングの設定 ホストOS(CoreOS)のポートとコンテナのポートを指定する |
|
-h |
ホスト名を指定 | |
-v |
ホストOSのファイルシステムをマウントする vはvolumeの意味っぽい |
|
golang:1.4 |
起動するイメージを指定 ローカルに無かったらpullしてくる |
というわけで先ほどのコマンドを実行すればGolangのインストールされたコンテナが立ち上がります。
core@core-01 ~ $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1eb71b579780 golang:1.4 "/bin/bash" 12 minutes ago Up 12 minutes 0.0.0.0:8080->8080/tcp api core@core-01 ~ $ docker exec -it api bash root@golang:/go# echo $GOPATH /go
golangのコンテナが何やってるかはDockerfileを見ればわかります。
Dockerfileあたりは次回ブログに書こうかなと思ってます。
Nginxのコンテナを立ち上げる
これもさっき用意したスクリプトを使います。
core@core-01 ~ $ ./share/create_container.sh nginx web
コンテナ間の通信には --link
を使う
このnginxでは、リクエストを受け取ったらgolangのコンテナの8080ポートへプロキシしています。
コンテナ間で通信を行うための機構をDockerは用意していて、それが --link
です。
--link hoge:fuga
と書くことによって、
「hogeというコンテナにfugaというエイリアスでアクセス」できます。
ここではapiとそのままです。
ここで先ほどのリポジトリに含まれているnginxの設定ファイルを見てみます。
docker-golang/golang-app.conf at master · takasing/docker-golang · GitHub
--link
を指定したことによって、nginxコンテナの中からapiというエイリアスでコンテナへの通信ができるようになったので、nginxの設定ファイルの中でapiというエイリアスが使えます。
これでシンプルにプロキシを設定されます。
IntelliJ側の設定
以下を参照(手抜き)。
外部パッケージを利用したいけど、参照解決してくれないって時は
Go の開発環境は IntelliJ IDEA + golang plugin がマトモだった - Qiita
GAE - go getしたライブラリをIntelliJ IDEAの補完候補に追加するには - Qiita
このへんを参考にすれば良い。
ちなみにIntelliJを開発で使うためにはMacのローカル環境にGolangを入れなければならないようです。
DokcerのGolangのランタイム参照できたりしないのかな、しないだろうな。
ブラウザからアクセス!
あとはIntelliJで作ったプロジェクトのディレクトリを golang/go
にシンボリックリンクなどをおいて自分のリポジトリとかをGolangのDockerコンテナに共有して実行してみましょう。
今回は適当にginフレームワークでGETのエンドポイントを幾つか試しに作ります。
$ cat golang/go/src/hello/hello.go package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() router.GET("/", func(c *gin.Context) { c.String(http.StatusOK, "hello world") }) router.GET("/ping", func(c *gin.Context) { c.String(http.StatusOK, "pong") }) router.GET("/pong", func(c *gin.Context) { c.String(http.StatusOK, "ping") }) router.Run(":8080") } root@golang:/go# go get root@golang:/go# go run hello.go
go get
ではパッケージ内の*.goファイルのimport文を見て必要なパッケージのソースコードを$GOPATH/srcに落としてきます。
正常に立ち上がったらブラウザでVagrantのCoreOSの80ポートにアクセスすればpingだったりpongが返ってくると思います。
IntelliJでプロジェクトを作るときは
注意
もしVPN接続などで、CiscoのAnyConnect使ってる人はvagrantまでのrouteが生えなかったりしそうなので、一度切断して以下のコマンドを打ってください。もちろん環境に合わせて。
$ sudo route -nv add -net 172.17.8 -interface vboxnet0
-netに指定するところは vagrant ssh
した後に
core@core-01 ~ $ cat /etc/systemd/network/50-vagrant1.network
などとコマンドを実行してあげるとCoreOSまでのIPがわかるので、そのプライベートネットワークへのrouteを追加してやればよいです。
route通っていてもダメっぽい時は vagrant rsync-auto --poll
とオプションを付けてみてください。
TODO
- dockerコマンドの箇所をDockerfileにする
GOPATHとか弄りたいかも。 vagrant rsync-auto
でsyncされない時があるのでboot2dockerにした方がいい気がしてきたが要検証
一応--poll
オプションをつけたら動くんですがPC重くなるっていう。- DBのlinkもする
ポスグりたい。 - --linkじゃなくてUnixドメインソケットで連携する
Docker を利用した Web アプリケーションのデプロイ - クックパッド開発者ブログ - 依存関係解決ツール周りとワークスペース
なんか公式見解含めてあんまイケてない気がする。
godepとかgomとか使っても結局カレントディレクトリ配下にディレクトリ作って入れる感じになっていて、GOPATHをDockerfileとかで設定したとしても$GOPATH/src
以下に入れてくれないし意味あるの?みたいになる。
ワークスペースについてはこういうのがいいらしい。
Goコードの書き方 - The Go Programming Language
なんかまだまだ未開拓ですね。
誰か詳しい人いたら教えて下さい。
まとめ
とりあえず入門してみてざっと書いてみたけど、まだまだDockerとかGolang周りはベストプラクティス定まってなかったりとか議論されてたりとかするので悩ましいことがいっぱいだった。