Docker20.10のリリースに伴う変更点

須田瑛大氏:改めまして、NTTの須田と申します。もう半年近く前のニュースですが、Docker20.10がリリースされたので、その新機能について紹介します。

まず簡単に自己紹介をしたいと思います。私は、コンテナ関連オープンソースのコミッタをやっていて、オープンソース版のDockerのことをMobyと言うのですが、そのMobyのコミッタとか、containerdのコミッタとかをやっています。

それと2020年の話になるのですが、コンテナのセキュリティに関する本を書いています。『Docker/Kubernetes開発・運用のためのセキュリティ実践ガイド』という本です。そのほかにいろいろとオープンソースの活動をやっています。

本日紹介するDocker20.10ですが、2020年の12月にリリースされたバージョンです。バージョン20.10と書いてあるのですが、2020年の10月には結局間に合わなくて12月にずれ込んでいます。

その前のバージョンはDocker19.03だったのですが、19.03が出たのは2019年の7月だったので、約1年半ぶりのリリースになります。

Docker 20.10の変更点ですが、RHEL8やCentOS8などのOSや、Fedoraでもデフォルトで動くようになったことが一番大きい点だと言えます。

Docker 19.03は、RHEL8、CentOS8、Fedoraではデフォルトで動かなかったので、Red Hatが作っているPodmanにだいぶユーザーが流れてしまった感じがしますが、Docker20.10ではデフォルトで動くようになったので、またユーザーが戻って来るんじゃないかなと思います。このバージョンのDockerとPodmanは共存できます。

あとDocker19.03ではexperimentalだった機能が、Docker20.10では正式な機能に昇格しました。セキュリティを強化する機能であるRootlessモードという機能や、ビルドを強化するBuildXという機能が正式な機能に昇格しました。

また、Docker SwarmがJobsに対応しました。このJobsは従来のサービスのようにずっと動きつづけるコンテナではなくて、いずれ終わりが来るバッチジョブのコンテナをもつ機能です。これはKubernetesのJobsと同じような機能です。

新バージョンリリースにより「RHEL8」「CentOS8」「Fedora」でデフォルトで動くようになった

変更点について細かく見ていきます。まずはRHEL8です。CentOS8などを含めてRHEL8をベースとすれば、Docker19.03ではデフォルトでは動きませんでした。まったく動かないというわけではなかったのですが、コンテナの中からホストの名前を解決できなかったり、docker run -pでポートを公開できないとか問題があったりして、ほとんど使い物になりませんでした。これはDocker19.03がfirewalldというデーモンに対応していなかったのが原因です。Docker20.10ではfirewalldに対応したので、RHEL8やCentOS8などのOSのデフォルトで動くようになりました。

ただし、RedHat社が作っている公式のパッケージからDockerは削除されたままです。そして、Docker社からもRHEL8向けのパッケージは提供されていません。ただしCentOS8のパッケージは提供されています。

みなさんご存知だと思うのですが、CentOS8の開発は2021年の年末で終了することになっています。CentOS Streamというプロジェクトは続きますが、従来みなさんがご存知だったCentOSは終了します。

CentOSの後継としては、Alma LinuxやRocky LinuxといったOSが出てきています。Alma LinuxやRocky LinuxもCentOSのバイナリ互換なので、Docker社が作っているCentOSのパッケージをそのまま使えます。ちなみにAlma LinuxやRocky LinuxのほかにOracle LinuxやVzLinuxなどCentOS8に似たようなOSがいろいろと出てきています。

次はFedoraの話です。Docker19.03ではFedoraの最近のバージョンも動きませんでした。これは先ほどお話ししたfirewalldの問題もありますが、主にcgroupの問題です。

このcgroupは、Linuxカーネルがもっている機能で、CPUやメモリなどリソースの制御に使われている機能です。Fedora 31ではcgroupのバージョンが1から2に上がったのですが、Docker19.03はcgroupのバージョン2に対応していなかったので、cgroupのバージョンを1に下げる設定をしないと、Dockerがまったく動かないという問題がありました。これもあって、FedoraユーザーがだいぶPodmanに流れてしまった感じがします。

Docker20.10ではcgroupのバージョン2に対応したので、最新のFedora31でも簡単にインストールができます。ちなみに実装としては、2019年にはすでにcgroupバージョン2でも動くようにはなっていたのですが、Dockerのリリースにけっこう時間がかかったのでDocker20.10の2020年の年末までずれ込みました。

また、Docker20.10.0ではcgroupバージョン2はexperimental扱いだったのですが、Docker20.10.6で正式に対応しました。

Rootlessモードが正式な機能に昇格

次はRootlessモードが正式な機能になったという話です。RootlessモードはホストOSのrootの権限を使わずに、Dockerのデーモンやコンテナを動かしてセキュリティを強化する技術です。

Rootlessモードは2018年頃から動くようになっていて、2019年にDocker19.03にマージされました。19.03ではexperimental扱いだったのですが、今回リリースされた20.10で正式な機能に昇格しました。

Docker20.10のRootlessモードは、19.03と比べていろいろと改善されています。Docker19.03ではCPUやメモリの使用量にリミットをかけられなかったのですが、Docker20.10ではCPUとメモリにリミットをかけられるようになりました。

ただし、ホストOSがcgroupのバージョン2に対応している必要があります。cgroupバージョン1のホストではこのリミットはかけられないです。

また、Docker20.10からはapt-getとかdnfとかのパッケージマネージャでRootless版のDockerをインストールできるようになりました。パッケージ名はdocker-ce-rootless-extrasです。

ただし、apt-getやdnfを実行するにはroot権限が必要です。これはDockerの制約ではなくて、apt-getやdnf自体がこういったroot権限がいるという制約です。インストールもroot権限なしでやりたい場合には、従来のインストーラーを使う必要があります。こちらの従来のインストーラーは、get.docker.com/rootlessのURLで公開されています。

先ほどapt-getやdnfを実行するにはrootが必要と言いましたが、これはホストOSでapt-getやdnfを実行する時の話であって、コンテナ内でapt-getやdnfを実行する時の話ではありません。コンテナの内部ではapt-getもdnfもrootなしでほとんど実行できます。

Swarmではバッチジョブ型のコンテナも動かせる

次はSwarmの話です。最近はDocker Swarmの話をあまり聞かなくなりましたが、Docker Swarmも開発は続いています。Docker20.10のSwarmではバッチジョブ型のコンテナも動かせるようになりました。

このバッチジョブ型のコンテナは、従来のサービス型のコンテナのように動き続けるコンテナではなくて、いずれ終了するコンテナのことです。KubernetesのJobマニフェストに似ています。

ちなみに従来のサービス型のコンテナは、KubernetesのDeploymentマニフェストに似ていると言えます。ちなみにこれはKubernetesのDaemonSetのような使い方もできます。

SwarmのJobの例を示します。この例では、クラスタ内のすべてのノードのホストのファイルシステムに、/etc/some-fileというファイルを作成しています。このように、すべてのノードのホストの設定を書き換えたい場合などにJobsは便利です。

使い道はほかにもいろいろあると思います。例えばCIに使ったり、統計処理のバッチジョブを実行したり、機械学習のバッチジョブを実行したりなど、いろいろな使い道があると思います。

ビルド高速化に有効なRUN --mount構文も正式な機能に昇格

次はDockerfileのRUN --mount構文です。この構文はDocker18.06から18.09にかけてexperimentalとして入った機能ですが、Docker20.10でようやく正式な機能に昇格しました。

この構文を使うと、例えばapt-get、maven、npmなどのパッケージマネージャのキャッシュを保持したり、コンパイラのキャッシュを保持したりしてビルドを高速化できます。

また、ビルドを高速化するだけではなくて、セキュリティ面の強化もされていて、SSHやS3の認証情報を安全にマウントできます。

キャッシュ機能を使った場合のビルド時間のデータがあるので紹介します。この例だと、Docker18.03ではビルドに139秒かかっていました。BuildKitを有効にすると、それだけでビルド時間が32秒まで短くなります。

ここでさらにRUN --mount構文を使ってキャッシュを有効化すると、4秒以下になります。Docker18.03と比べると33倍以上速くなっています。ちなみに従来のBuildKitと比べても、8倍速くなっています。

この構文はDocker19.03まではexperimental扱いだったので、Dockerfileの先頭に# syntax=docker/dockerfile:experimentalという行を書く必要がありました。Docker20.10ではこの行は必要なくなりました。ただし、Docker19.03でも20.10でもBuildKitモードは有効にしておく必要があります。

BuildKitモードの拡張版、buildxも正式な機能になった

このBuildKitはLinux版のDockerではデフォルトで有効ですが、Docker for MacとDocker for Windowsでは2020年の9月頃からデフォルトで有効になっています。Linux版では DOCKER_BUILDKIT と言う環境変数を設定する必要があります。

Docker20.10では、buildxも正式な機能に昇格しました。buildxはBuildKitモードがさらに拡張したモードで、BuildKitが本来もっている機能のほぼすべてを使えるものです。

例えばマルチプラットフォームイメージのビルドや、Kubernetesクラスタを使った分散ビルドなどdocker buildではできない機能がいろいろと備わっています。Docker20.10ではdocker-ce-cliというパッケージの一部としてbuildxコマンドが正式に入りました。

buildxを使ってマルチプラットフォームイメージをビルドする例を紹介します。この例だと、ローカルのAMD64のマシンからリモートのARM64マシンにSSHで接続して、これをbuildxのワーカーとして利用しています。こうしてイメージをビルドすると、AMD64でもARM64でも動くイメージを作ることができます。

この例ではリモートのARMのマシンを使っていますが、リモートのマシンを使わずにQEMUでエミュレートするものもあります。QEMUでエミュレートすると全部ローカルで完結できます。

また、buildxを使うとKubernetesを使ってイメージを分散ビルドできます。docker buildx createというコマンドの引数で、ドライバーとしてKubernetesを指定して、レプリカの数を3に指定するとbuildxがKubernetesのAPIを叩いて、BuildKitのpodを3つ作ります。この3つのpodで負荷を分散しながらイメージをビルドします。

Dockerfileを1つだけビルドしても負荷は分散されないのですが、複数のDockerfileを同時にビルドすると負荷が分散されるようになっています。

また、Docker20.10ではCOPY --chmod命令と、ADD --chmod命令という命令がありました。似ているものとして、--chownもあります。--chownはDockerの17.09から存在していましたが、chmodは今まで存在していませんでした。

--chmodを使わなくても、COPYしてからRUN命令でLinuxのchmodコマンドを実行すればミッションは変更できますが、それだとchmodする際にファイルのコピーが発生するのでイメージの容量が無駄に膨らむ問題がありました。今回導入されたCOPY --chmodを使うと、無駄なコピーをなくせます。

最後に紹介するのが、docker runコマンドに追加された--pullフラグです。これはKubernetesのimagePullPolicyに似ている機能です。例えば、確実に最新のイメージをpullしてから実行したい場合、--pull=alwaysを指定すると、pullしてからrunする手間を省けます。

コミュニティでは次回のバージョンリリースについても議論中

Docker20.10の紹介は以上です。コミュニティでは次のリリースについて議論しています。次のリリースでは、Swarmで分散ストレージを使えるようになる見込みです。Kubernetesと同様にCSI、Container Storage Interfaceを使って実装する方針です。

また、次のバージョンではlibnetworkのリポジトリがdockerdのリポジトリに統合される予定です。ユーザーに見える変化は特にないのですが、libnetworkにコントリビュートしたい人には作業しやすくなるという利点があると思います。

ほかにも、次のバージョン21に入るか、バージョン22になるかはわからないですが、Dockerfileでheredocという機能が使えるようになります。このheredocはシェルスクリプトに出てくる<<EOFみたいな書き方のことです。

<<EOFみたいな書き方を使うと、今画面に表示しているように複数行にまたがる命令を書きやすくなります。今までだと、いちいち行の最後にバックスラッシュを付けないといけなかったんですが、バックスラッシュを書かなくても付くようになるので、だいぶ書きやすくなると思います。

私は発表は以上となります。まとめると、RHEL8やCentOS8のデフォルトでもDockerが動くようになりました。Fedoraでも動くようになりました。また、Rootlessモードや、Docker Buildxがexperimentalから正式機能に昇格しました。ほかにもDocker SwarmがSwarm Jobsという機能に対応しました。

そのほかにも細かい点があります。細かい点は弊社のnttlabsブログにまとめたので、こちらも見ていただけたらと思います。ご清聴ありがとうございました。