目次
前回エントリ↓でコードからのイメージのpullが動かなくてあっれおかしーなーとなって悔しかったのでリベンジです。
client.ImagePull
の返り値はio.ReadCloser
型とerror
型- この
io.ReadCloser
が、イメージのpullのprogressなどを表すHTTPのストリーム - このストリームへの書き込みが終わる(つまり
docker pull
が完了する)まで待つ必要があった
以下読まなくてよいです
動かないコード
func main() { c, err := client.NewEnvClient() if err != nil { panic(fmt.Errorf("NewEnvClient: %v", err)) } ctx := context.Background() // "debian"(:latestは省略可)のpullを試みる rp, err := c.ImagePull(ctx, "debian", types.ImagePullOptions{}) if err != nil { panic(fmt.Errorf("ImageSave: %v", err)) } defer rp.Close() // エラーさえ無ければイメージのpullが成功していると誤解していた cc := &container.Config{Image: "debian"} hc := &container.HostConfig{AutoRemove: true} nc := &network.NetworkingConfig{} body, err := c.ContainerCreate(ctx, cc, hc, nc, "bar") if err != nil { panic(fmt.Errorf("ContainerCreate: %v", err)) // 結局ここで"debianなんてイメージは無い!"と叱られる } fmt.Printf("Created Container:\n%+v\n", body) }
動くコード
前後省略します
func main() { /* 省略(クライアントの初期化とかする) */ // "debian"(:latestは省略可)のpullを試みる rp, err := c.ImagePull(ctx, "debian", types.ImagePullOptions{}) if err != nil { panic(fmt.Errorf("ImageSave: %v", err)) } defer rp.Close() // {{{ こっからが味噌!! // こういう構造のバッファが書き込まれる payload := struct { ID string `json:"id"` Status string `json:"status"` Progress string `json:"progress"` ProgressDetail struct { Current uint16 `json:"current"` Total uint16 `json:"total"` } `json:"progressDetail"` }{} // bufio.Scannerマジでかわいい scanner := bufio.NewScanner(rp) for scanner.Scan() { json.Unmarshal(scanner.Bytes(), &payload) fmt.Printf("\t%+v\n", payload) } // }}} ここまでが味噌!! /* 省略(得られたイメージを指定してコンテナつくったりする) */ }
上記では、bufio.Scanner
を使ってHTTPのEOFまで待っている。ついでに、毎バッファ書き込みされるレスポンスを取り出して上げている。
↓こういうきれいな感じのペイロードが送られてくる。
Scanner使わないんだったらioutil.ReadAll
かなー他にストリームが終わるの同期的に待つのどうすっかなーと思ってググりました。
- Golangでのstreamの扱い方を学ぶ – Carpe Diem
- Streaming data in Go, without bytes.Buffer – Stupid Gopher Tricks – Medium
- go – How to find EOF while reading from a file – Stack Overflow
今回のように毎ペイロードが独立して意味のあるものであれば、Scanner使うのが良い気がするものの、もっと良い(単にReaderのEOFを待つための)方法があれば教えてくださいm(_ _)m
雑感
- Goのコードから
github.com/docker/docker/client
を使って (1) イメージのpull (2) コンテナ起動 が実現されたので、これでほぼ心置きなく俺々Dockerクライアントを自作できますね!やったね! - 腰椎椎間板ヘルニアになっちゃった。腰痛ぇ。
『腰痛持ちエンジニアが選ぶマットレス5選』みたいなのください
— エッチなリツイートをします (@otiai10) 2017年5月25日
DRYな備忘録として
[amazonjs asin=”4873117763″ locale=”JP” title=”Docker”]
[amazonjs asin=”1542739047″ locale=”JP” title=”Docker: A Quick-start Beginner’s
Guide”]
[amazonjs asin=”4873117968″ locale=”JP” title=”Infrastructure as Code ―クラウドにおけるサーバ管理の原則とプラクティス”]
投稿日:May 26th 2017