2014年5月25日日曜日

Golang Cafe #30を開催しました。

Golang Cafe #30を開催しました。

今回はGoのプレゼンテーションツールのpresentの使い方を紹介して頂いた後、Dockerのソースコードを読み進めるという内容になりました。

Goのプレゼンテーションツールであるpresentの使い方は+Takanobu Haginoさんが事前に調べてくれていたので、その結果から使い方を説明していただきました。
インストール方法は、まず、go getを使ってソースコードをダウンロードします。ダウンロード後、go installでコマンドができあがるので準備完了です。

$ go get code.google.com/p/go.tools/cmd/present
$ cd src/code.google.com/p/go.tools/cmd/present
$ go install

その後、プレゼンテーション用のファイルを作成(中身はテキストファイル、フォーマットはmarkdown風)して

$ $GOPATH/bin/present

とするだけで、ローカルにWebサーバが起動しプレゼンテーションを参照する事ができます。このプレゼンテーションツールはプレゼンを表示した状態で、Goのプログラムを動かす事ができるので、いちいち画面を切り替えなくても良いという点では非常に便利です。

ただし、PowerPointとか、Google Presentationのような柔軟な配置が難しいので、凝ったプレゼン資料が作りにくいのも確かです。

後半は、Dockerのソースコードを読み進めました。
今回は、docker versionと、docker runコマンドの2つを読み進めました。
結局、クライアント側を読んだ結果、プロセス通信とHTTPのプロトコルの組み合わせの通信をしているということがわかったので、サーバ側も、各コマンドがリクエストURLから分析した結果から実行する処理が決まるというものでした。

あまり、新しい成果が生まれなかった(Engine構造体とJob構造体がキモというのが変わらない)のと、Docker自体がかなりのペースでMergeとCommitが加わっているので
現状のソースコードを読むことに意味を成さなくなる可能性がでてきました。
(最新のものと比べてかなりの乖離がある)

ということで、最新ソースを追いかけながら読み進める事をすると、Dockerの勉強会になりそうだという判断もあって、次回はGoの資料を読み進める事になりました。

個人的に、ですが、Dockerのソースコードは読みにくい…。と思います。
でも、いい経験になったと個人的に思っているので、人のソースコードを読むのは
間違いじゃないと思います。

最近、Golang Cafe直前になってBlogを書いているので、少し改善したい今日この頃。


2014年5月17日土曜日

Golang Cafe #29を開催しました。

Golang Cafe #29を開催しました。

今回は、#27に引き続き、dockerのソースコードを読み進めました。

前回は、deamon側に向かって、リクエストを飛ばすクライアント側のソースコードを読みましたので、docker/docker.goの98行目から開始しました。
(-d、-deamonオプションを付けた場合に動作する部分)

dockerにはHandlerという内部コマンド(?)があって、最初にHandlerを実行するための準備をします。(builtins/builtins.go)内部コマンドはコマンドの名前(例:initserverなど)をキーにして実行する関数を保持するmapとして定義されていて、各処理の時に、名前を指定して呼び出します。
最初は、"initserver"、"init_networkdriver"、"serveapi"の3つが登録されています。

initserverの中で、クライアントからのリクエストに対するHandlerが登録されます。

ただ、読み方としてコツがあって、以前にもでてきた、「goroutinesの切り替わり」を考えて処理の順番を考えないといけません。

したがって、登録したHandlerの順番としては、最初に"serveapi"が実行されます。これは、docker.goの133行目付近はgoroutineになっていますので、バックグラウンドで動くことになります。よって、先にdocker.goの179行目にある、job.Run()が実行されることになります。docker.goを見る限りでは、runtime.GOMAXPROCS()を呼び出していませんのでMAXPROCSは1で動作していますから、「明示的なスレッドのブロック」が無い限りは"serveapi"が動作すると思われます。(ということは、runtime.GOMAXPROCS()を呼び出すとまともに動作しないのかも…?)

job.Run()の中では、登録されているHandlerを呼び出すので、初見では、何かの関数か?と思うかもしれませんが、関数型のmapの関数を呼び出すような仕組みなので、呼び出しの部分は勘違いしないようにしなければいけないと思います。

以前のクライアントからUnixソケットを使って接続するようになっていましたが、docker.goの155行目でacceptconnectionsが実行されています。
(中で、net.DialUnix()されています。(Unixソケットってサーバ、クライアントどちらもDialなのか…?))

正直、dockerのソースコードは読みづらい…。俺だけか?

次回は、各コマンドの内部を読み解いていく予定です。

2014年5月11日日曜日

Golang Cafe #28を開催しました。

Golang Cafe #28を開催しました。

今回は前回に引き続き、dockerのソースコードを読もうと思っていたのですが、東京から返ってきた、+Shingo Ishimuraさんの「デプロイツールをGoで」というお題がでて、その検証をしていました。

結局、os/execパッケージのCommandを使って、標準入力と標準出力を取得する。というのがポイントになります。これは、以前のGolang Cafeでもやりました。
ということで、自身満々に

と、言ったのですが、単純なコードだとうまくいくソースコードは書けたのですが、実際にはどうなんだろうか。(業務に係わるものだったので、直接見たわけではないので…)

作成したソースコードはgithubにありますのでごらんください。

今回は、os/execパッケージが主な機能だったので、golangcafeのexecsampleディレクトリに含めてあります。exec.Commandを使うときの参考までに。

それから、その後、今回の内容を活かして、aetesthelperというツールを作ってみました。これは、GAE/Gのgoapp testをサポートするコマンドです。

公式サイトの通りに、goapp testを行えば良いのですが、どうしても、パッケージを分けて、別のパッケージを参照する時に、GOPATH変数を参照して、GOPATH変数で設定したパスの上にファイルがないとテストが動作しない(私だけ?)ので、仕方なく、Tempdir()で作った、ディレクトリにSetenv()して、ファイルを全てコピーして、goapp testを流すという単純な動作にしています。
これで、プロジェクト内の全てのパッケージに対してgoapp testが実行できるので、非常に快適になりました。

次回(と言っても、あと3時間後ですが)は、先々週に引き続いてdockerのdaemon側のソースコードを読みます。

2014年4月29日火曜日

Golang Cafe #27を開催しました。

Golang Cafe #27を開催しました。

今回も前回に引き続き、Dockerのソースコードを読み進めました。

前回は、クライアントでのコマンド実行のところまで読んだので、今回は、docker runコマンドの実行部分を読んでみました。

該当の場所は、api/client/command.goの1776行目にある、

func (cli *DockerCli) CmdRun(args ...string) error {

からとなります。

処理の概要は

  1. コマンドの解析(ParseSubCommand)
  2. ContainerIDFileが存在しなければ、ContainerIDFileを生成する。
    1. ただし、ホストの設定(hostConfig)で指定されている場合のみ。
    2. ContainerIDFileは最後に削除する。
  3. cli.call("POST", "/containers/create?")で、デーモン側にコンテナの作成を指示。
    1. ファイルがない(httpのレスポンスが404の時)時は、コンテナImageがないので、imageを作成を指示する。(これも、cli.call())
  4. コンテナの作成の結果を受け取る。
  5. コンテナにattach(cli.hijack("/containers/"+runResult.Get("Id")+"/attach?"))
  6. コンテナの開始(cli.call("/containers/"+runResult.Get("Id")+"/start"))
  7. 結果を取得
結局クライアントからはデーモンに向かってプロセス通信しているだけで、何も処理がありませんでしたので、デーモン側の処理を読むことで、コンテナの配置とか、処理の実行の部分の理解を深めることができそうです。

デーモンはいつ起動させるのか?
Ubuntuだと、サービスとしてPC起動時に起動してしまうようです。また、Macだと、boot2dockerを使ってサービスを起動させた状態で使っています。
Windowsだとどうやら無理みたいですw(中身をみると、syscallをバリバリ使っているので、Windowsとは相性が悪そうです…。)

さて、細かい処理を(複雑で時間がかかるので)見ていないのですが、処理の概要は読めました。

今回のポイントですが、プロセス通信をする時に中身では、httpを使っています。
標準パッケージのnet/http/httputilを使って、http通信をしていました。

httputil.ClientConnを使ったリクエストを行う場合、net.Connを自分で指定させるため、Socketを自分で作ります。今回は、Unixドメインソケットだったり、tcpソケットだったりするわけです。(Macだと-Hオプションで指定したURL(私の環境だとtcp://localhost:[Port])を使ってソケットを生成されるようです)

よく考えると、これまでnet/http周りはじっくり読むということをしていなかったので、またのタイミングで読みたいと思います。

ということで、次回はデーモン側のソースコードを読む予定です。

2014年4月26日土曜日

Golang Cafe #26を開催しました。

Golang Cafe #26を開催しました。

今回からdockerソースコードを読み進めることになりましたので、”当然”main()から読み進めるのが妥当だろうということでmain()が書かれているdocker/docker.goから読み始めました。

流れとしては、最初に".dockerinit"という文字列が含まれているとinit modeでの起動ということで、sysinit.Sysinit()が呼び出されます。パスに".dockerinit"が含まれる時ということなので、docker自身が隠しディレクトリを作る事があるのだと思いますが、sysinitは少し重たそうだったので、少しだけ見て、先に進むことにしました。sysinitパッケージは後日に回します。

dockerは引数、オプションを扱うflagパッケージを自作しているようで、別名でflagパッケージを定義してありました。

flag "github.com/dotcloud/docker/pkg/mflag"

使っている所をみると、オプションを配列で指定することができるようにしてあるだけのようにも見えますが、とりあえずは最初の起動の処理をみるということにして、flagも存在だけのチェックで終わっています。

それぞれの引数がどのような意味なのかは、mflagパッケージを読む時にじっくり見たいと思います。デフォルトコメントが書かれているので、そこから判断して頂いてもいいかと思います。

処理の流れとしては、


  1. versionフラグがtrueの時、version情報を出力して終了
  2. Hosts(?)の長さが0(指定されていない時)に環境変数DOCKER_HOSTを取得
    1. DOCKER_HOSTが未定義または、Daemonとして動作する時はデフォルトのUnixSocketを保持する。
      1. ちなみに、デフォルトのUnixSocketのパスは/var/run/docker.sockなので、Macだと存在しないと怒られて動作しないので、-HオプションでSocketを指定する。
  3. -bと--bipオプションが両方指定してあるとエラーになる。
  4. -Dか--debugオプションが指定してある場合は、環境変数DEBUGを1にする。
  5. -dか--daemonオプションが指定されているとDaemonモードで動作する。
    1. ※こちらは今回読んでいないので、中身はまだわかりません。
  6. 指定されていない場合は、clientモード(docker run XXXとかで動かすモード)の処理
    1. TLSを使うかどうかのチェック
    2. client.NewDockerCli()を呼び出し、clientオブジェクトを取得
      1. TLSを使うかどうかの違いは最後の引数がnilか、configが指定してあるかの違い。
    3. ParseCommands()でコマンドの解析とサブコマンドの実行が行われる。
      1. 解析だけかと思ったら実行もされていた。
今回のポイントとして、Unused Importsを使ったパッケージの初期化処理が便利だということと、strings.SplitN()を使って、最大N個までの分割で済ませるというAPIがあることが、新たな発見でした。

特に、Unused Importsはsql/driverあたりでも使われるのですが、その時は、interfaceのみだから、interfaceを認識させるために使うと思っていましたが、init()関数が呼び出されることで、ドライバの初期化ができるというのは、初期化処理の呼び出しをいちいち書かなくても良いという点でいい発見でした。(使う時があるかどうかは別にして…)

次回はdockerのサブコマンドである、apiパッケージを読み進めたいと思います。
新たな発見が出るかな?




2014年4月19日土曜日

Golang Cafe #25を開催しました。

Golang Cafe #25を開催しました。

今回は、初めての方の参加があり、Goが初めてということだったので、+Ryuji Iwataさんにお願いして、#1の時にやった、「How to Write Go Code」の内容を説明して頂きました。
私と+Takanobu Haginoさんはずっとやっていますので、改めて話を聞く必要はありませんでしたが、無茶ぶり以外のなにものでもなかったことは確かでした。
(本来は私がやるのですが、復習というのも兼ねて別の方に頼むのもいいのかなとも思いましたので。)

で、今回のGolang Cafe #25では、私は特に成果物がありませんでしたので、少しだけ考えた、「Golang Cafeの今後」についてまとめてみたいと思います。

今回で25回開催してきたのですが、1回目から欠かさず続けているという事は、正直すごいと思うのですが、その状況での問題点がちらほらでてくるわけです。
ずっと参加して頂いている2人に関してはGoのノウハウが蓄積されてきて、それぞれの熟練度もある程度上がってきました。

ここからは恐らく…ですが、例えば、コードを書いて動かしたい人と、いろんな資料を読み、ノウハウを蓄積したい人、公式ドキュメントとか、書籍を読みたい人といういろいろ「やりたいこと」がわかれてくるのだろうと思っています。

Golang Cafe自体、「ネタ」ですから、私一人でもやるのですが、独断で決めてもいいのですが、せっかく集まってくれているので、ある程度、希望に沿ったものにしたいなーと考えたりもしました。

それから、仕事が詰まって忙しくなるとかで、参加者が変化する(入れ替わりが発生する)かと思ったのですが、入れ替わることもなく、増えることもなかったので、今の状態なったのかもしれません。

今のところのテンションだと、「終了」はまだまだ先になりそうですが、
個人的な野望としては、「Golang Cafeの並列化」が実現するとおもしろいなと思っています。ですが、今のところ、私以外にGolang Cafeを開催する人はいませんね。

あとは、いつGoがプロダクションで使われ、金に繋がるか。
それまではがんばってみようかと思ってたりしてます。

2014年4月8日火曜日

Golang Cafe #24を開催しました。

Golang Cafe #24を開催しました。今回は、Devfest Japan 2014 Springのなかの1トラックでの開催となりました。

40分しかなかったのと、参加者のGoを使っている度合いをつかむことが難しかったので、当日も参加して頂いた、+Takanobu Haginoさんに協力していただきまして、ある程度使っている人とGolang Cafeをやってもらいました。

私は、というと、初心者の方が多かったので、Goの導入と簡単なプログラムの書き方(Golang Cafe #1に至る直前までの内容)を自由に話してみました。
導入とか、実行方法などをお話してみましたので、今後ハマったら質問など投げて見て下さい。

Golang Cafe自体が、自由だったので、Devfestでやることか?とも思いましたが、「Golang Cafeへの幻想をぶち壊す!」的なノリで、好き勝手にやってみることにしましたw

中身は、「雑談」と、「質問への回答」が主なので、力をいれずやるのが良いのかなと思っています。

で、参加して頂いた方にもGolang Cafeがどんなものかは、十分わかったと思いますので、ご自由に開催して下さい。

某所で、このGolang Cafeのイベント情報を共有したいという意見(アピールしたいという意味で)も上がってきたのですが、できれば、GDG中国にあるGolang Cafeのサイトに誘導して頂く方が、私はうれしいです。
ですが、性質上たくさんの人が申し込まれると、場所の確保と内容に制限が出てくるので、難しいところです。

次回からは、また倉式珈琲店での開催となります。多分、出張はもうありませんw