Docker の GitHub Issues のやりとりにいろいろ矛盾があるので, これはもしかして誰も気づいていないだけでいろいろぶっ壊れたままなのでは? と思って調べてみたら, どうやら 20.10 ですべて治るというのだけは本当らしい. 眠気が収まらない間片手間にやった調べものなので内容は不正確かもしれない.
-
BuildKit の
ResolverOptions
(レジストリ上にある既存のイメージを pull するときのオプション) はdaemon.NewResolveOptionsFunc()
により作られる.https://github.com/moby/moby/blob/v19.03.13/cmd/dockerd/daemon.go#L312
-
daemon.NewResolveOptionsFunc()
は以下の順に動作する.https://github.com/moby/moby/blob/v19.03.13/daemon/daemon.go#L152-L204
registry-mirrors
が設定されている場合、m["docker.io"].Mirrors
にミラーの一覧を追加する.- Pull するイメージがおかれているレジストリのホスト名
v
にinsecure-registries
が設定されている場合,m[v]
を初期化したうえで,m[v].PlainHTTP
をtrue
にする. - Pull するイメージがおかれているレジストリのホスト名
v
をhost
に代入する. 明示的な指定がない場合,host
にデフォルトのホスト名docker.io
を使用する. def
をResolverOptions
として初期化. すべてのプロパティにnil
を設定.m[host].Mirrors
が空でない場合,m[host].Mirrors
からひとつミラーをランダムに選択し, ミラーのホスト名をdef.Host
に代入.def.PlainHTTP
にm[host].PlainHTTP
(デフォルトでnil
) を代入.def
を返す.
-
containerd
で定義されているdockerResolver.base
はイメージ名とResolverOptions
を受け取って以下の順に動作し API コールのための URL オブジェクトbase
を生成する.https://github.com/moby/moby/blob/v19.03.13/vendor/github.com/containerd/containerd/remotes/docker/resolver.go#L146-L148 https://github.com/moby/moby/blob/v19.03.13/vendor/github.com/containerd/containerd/remotes/docker/resolver.go#L365-L377
- Pull するイメージ名をパーズして得られたホスト名の部分を
base.Host
に設定する. ResolverOptions
にHost
が設定されている場合, その値をbase.Host
に設定する. (この時点でHost
はミラーのホスト名になっていることに注目.)ResolverOptions
にPlainHTTP
が設定されている場合,base.Scheme
をhttp
に設定する. (PlainHTTP
の値は上記daemon.NewResolveOptionsFunc()
に由来してdocker.io
の設定が使われる.)
- Pull するイメージ名をパーズして得られたホスト名の部分を
したがって,
- そもそも, BuildKit の世界ではミラーはランダムに選択される. (ふつうの
docker pull
とは挙動が異なる.) insecure-registries
にdocker.io
を代入しない限り, ミラーへの通信が HTTP になることはない.- しかし,
insecure-registries
にdocker.io
を代入すると, ミラーの設定がなかったことにされる. そのため,docker.io
への通信が平文 HTTP で発生することになり, 結果エラーとなる.
実際に試してみると上記のような挙動になっている.
-
BuildKit の
RegistryHosts
(ここにホスト名やミラーの情報を格納する) はdaemon.RegistryHosts
により作られる.https://github.com/moby/moby/blob/v20.10.0-beta1/cmd/dockerd/daemon.go#L293
-
daemon.RegistryHosts
は以下の順に動作する.https://github.com/moby/moby/blob/v20.10.0-beta1/daemon/daemon.go#L154-L205
-
registry-mirrors
が設定されている場合、m["docker.io"].Mirrors
にミラーの一覧を追加する. -
insecure-registries
を走査し, 要素が正規のhttp
スキームの URL だった場合 (つまりhttp://`v`
だった場合),m[v]
を初期化したうえで,m[v].PlainHTTP
をtrue
にする. -
証明書が保存されているディレクトリを走査し, 見つかった証明書の Subject
fiName
すべてに対しm[fiName].TLSConfigDir
に証明書のパスを代入する処理を実行する. -
完成した
m
を引数としてresolver.NewRegistryConfig(m)
を実行する.resolver.NewRegistryConfig(m)
はdocker.Registries
を経由して以下の順に動作する.https://github.com/moby/moby/blob/v20.10.0-beta1/vendor/github.com/moby/buildkit/util/resolver/resolver.go#L100-L150 https://github.com/moby/moby/blob/v20.10.0-beta1/vendor/github.com/containerd/containerd/remotes/docker/registry.go#L89-L108 https://github.com/moby/moby/blob/v20.10.0-beta1/vendor/github.com/moby/buildkit/util/resolver/resolver.go#L25-L48
-
返り値として配列
out
を定義. -
Pull するイメージ名をパーズして得られたホスト名の部分を
host
に代入. この時,host
は必ず, ミラーでない大元のホストのホスト名が入っている. -
m[host]
をc
に代入. -
c.Mirrors
(ミラーの一覧の配列) が空でない場合,c.Mirrors
のそれぞれの各要素に対し下記の処理を実行.-
docker.RegistryHost
(単数形) としてh
を初期化. -
h.Host
にミラーのホスト名を代入. -
fillInsecureOpts
関数を実行し,insecure-registries
にミラーのホスト名が含まれており, かつ対象のホストが HTTP で動作している場合,h.Scheme
にhttp
を代入する. -
できあがった
h
をout
の末尾に追加.
-
-
host
そのもののためのdocker.RegistryHost
を作成しout
の末尾に追加.
-
-
(以下の処理省略, ざっくりいうと out
を前から順に走査してアクセスする. たぶんこのへん.)
したがって, 20.10 以降, insecure-registries
にミラーの URL (http
などのスキームも含む正規の URL である必要がある) を指定しておくことで, registry-mirrors
に平文 HTTP なミラーを設定しても問題なく HTTP で通信できるようになるらしい.
なお, https://github.com/moby/moby/blob/v20.10.0-beta1/daemon/daemon.go#L172-L174 から, insecure-registries
は 20.10 以降正規の URL を指定しないといけないと思う (この動作は 19.03 からの変更になる) が, これに関する言及はどこにもない気がするな...... あと引き続き insecure-registries
に docker.io
とか指定するとよくわからない動作になるとみられる.