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 とか指定するとよくわからない動作になるとみられる.