目次
前回エントリ↓でコードからのイメージの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