2023/07/04追記: 現在はRacher Desktopがおすすめ
Rancher Desktopの登場により、この記事でやろうとしている環境構築を簡単に実現できるようになっています。設定でコンテナランタイムをdockerd (moby)
に設定すれば、Dockerを利用することができます。
はじめに
昨年のPull Limitに引き続き、Docker社が再び動きました。
今後Docker Desktopを使用する場合、中規模以上の企業では有料プランを使用する必要があります。ただし有料プランで提供されるサービスは開発者にとってはあまり価値がないものですし、この有料プランを全社的に導入するという話を進めるのも中々骨が折れるでしょう。
NOTE: Docker Desktopの有料プラン移行には2022年1月31日までの猶予期間があります
既に一部ではDocker Desktopの代替手段を求める動きがあり、例えば以下のようなnerdctl, podmanによる代替手段を紹介している記事がいくつか挙がっています。
しかしこれらのアプローチはDocker CLIやDocker REST API(Docker Engine API)の制限が色々とあるため、後述する私のDocker利用用途では多くの問題が発生します。
特にDockerのBuildkitを活用(ex. docker buildの--ssh
, --secret
オプション)したり、Docker CLIやDocker REST API(Docker Engine API)の操作を行っているようなツールやライブラリ等(ex. kind, Testcontainers)を使用している場合は実用性の観点では極めて厳しいというのが正直な感想です。
このため本記事ではDocker CLIとDocker REST API (Docker Engine API)を利用できるアプローチであるlima + Dockerによる実用的な代替手段について紹介します。
主な用途
私はローカル環境上の開発で以下のような用途でDocker Desktopを使用しています。このためこれらのユースケースを一通りカバーできる必要があります。
-
docker build
コマンドでDockerイメージのビルドを行う。- ビルドの際にはBuildKitを利用して、
--ssh
や--secret
等のオプションも活用するプロジェクトもある。
- ビルドの際にはBuildKitを利用して、
-
docker run
コマンドでDockerコンテナの動作検証などを行う。- 必要に応じて
-p
オプションを指定してlocalhost:8080
にアクセスすることもある。
- 必要に応じて
- KubernetesのController, Operatorの開発や検証を行うため、
kind
コマンドでKinDクラスタを立ち上げる。- クラスタにPodをデプロイし、
kubectl port-forward
コマンドでPod等のエンドポイントにアクセスすることもある。
- クラスタにPodをデプロイし、
基本的にdocker build
やdocker run
等のDocker CLI + Docker Engine Serverの部分のみを使用しているため、Docker Desktopが提供しているUI等は一切使用していません。
そういったUIが必要な人はVisual Studio CodeのDockerプラグインあたりを試すことをお勧めします。
lima + Dockerの基本構成
本記事で紹介するlima + Dockerのアプローチは、macOSホストとLinux VMで以下のような構成をとります。
- macOSにDocker CLIを配置し、
docker
コマンドを実行可能にする。 - Linux VM上にDocker Engine Server (Docker Daemonとも呼ぶ)を配置する。
- macOSのDocker CLIがlocalhost経由のTCP通信でLinux VM上のDocker Engine Serverにアクセスできるように設定する。
これによりmacOSホストからdocker
コマンドを実行すると、そのリクエストおよびDocker Context(COPY等に使えるファイル等)がLinux VM上のDocker Engine Serverに転送され、Docker Engine Serverでdocker build
, docker run
等の処理が動きます。
構成図にするようと次のようになります。
NOTE: 何故Linux VMが必要なのか?
Docker CLIはLinux以外でも動作しますが、Docker Engine Serverについては基本的にLinux上でしか動作しません。(Windowsコンテナは事情が違いますが、話がややこしくなるのでここでは除外します)
Docker DesktopではDocker Engine ServerをWindowsやmacOSで動かしているように見えます、これは裏でLinux VMを立ち上げてVM上でDocker Engine Serverを起動することにより実現しています。
limaとは?
limaはmacOS上でLinux VMの作成&起動を実現するOSSプロジェクトです。
VirtualBoxと比較すると以下のような利点があるため、今回はこちらを使用します。
- limaのツールの導入が簡単。(
brew install lima
) - Linux VMのセットアップが簡単。(
limactl start
コマンドだけでUbuntuログイン可能な状態まで) - 標準でmacOSホストのファイルシステム、ネットワーク(localhost)がLinux VMと共有されているため、
Host <-> Guest
のシームレスな連携が可能。
NOTE: 一応もう一つの利点として「containerd + nerdctlが同梱しているため、初めからコンテナのイメージ作成や稼働ができる」というのもありますが、前述した通り今回はそもそもそれを使わずDockerを使用します。
ここではlimaに関する説明は割愛するため、興味がある人は公式レポジトリのExampleなどを確認してください。
NOTE: limaについては細かい説明はしませんが、
lima <コマンド文字列>
を実行すると「lima VM上でコマンド文字列の内容を実行する」ことになります。このためlima <コマンド文字列>
の部分はlima VM上で作業していることになります。
セットアップ手順
macOSホストへのDocker CLI導入
まずはmacOSホスト側にDocker CLIを導入します。
Docker Desktopを入れないとmacOSにDocker CLIを導入できないと思っている人もいるようですが、実は以下のURLからダウンロードできるファイルに含まれてます。Docker Engineも現時点の最新版を導入することになるため、Docker CLIも最新版をダウンロードします。
ダウンロードが完了したらtgzファイルと解凍してdocker/docker
のバイナリをPATHが通っているディレクトリに配置してください。
以下に$HOME/bin
にIntel Mac Binaryをインストールする例を示します。
# Download binary
curl -OL https://download.docker.com/mac/static/stable/x86_64/docker-20.10.8.tgz
# Install Docker CLI
mkdir -p $HOME/bin
tar xzvf docker-20.10.8.tgz
mv docker/docker $HOME/bin/.
chmod 755 $HOME/bin/docker
# Check appropriate docker binary is used
which docker
# Check CLI works
docker version
docker versionコマンドでClientの情報が表示されればOKです。(Serverの情報はエラーで表示されません)
最後にlima VM上のDocker EngineとTCP通信できるように、macOSホスト側にDockerの環境変数を設定します。ここでは$HOME/.profileにDOCKER_HOSTの設定を追加しています。
NOTE: 以降でセットアップするlima VM上のDocker Engine Serverでは、macOS上からlocalhost(127.0.0.1)経由でアクセスできるようにDocker Daemonの設定を行います。
echo "export DOCKER_HOST='tcp://127.0.0.1:2375'" >> $HOME/.profile
source $HOME/.profile
lima VM + Docker Engine Serverのセットアップ
NOTE: lima VMとはlimaで作成したLinux VMのことを指す
lima VMの準備
まずはlimaでLinux VMを作成&起動し、lima VM上にDocker Engineをセットアップします。
Homebrewでlimaをインストールし、lima VMを立ち上げます。
# Install lima
brew install lima
# Create & start lima VM
# NOTE: Select 'Open an editor to override the configuration' to change resource setting if necessary.
limactl start
# Running command in VM with `lima`
lima uname -r
NOTE: ちなみにデフォルト設定だとVMに確保されるリソースはやや多め(ex. CPU 4コア、メモリ4GB)となっているため、設定を変更したい場合は
limactl start
を実行した時にOpen an editor to override the configuration
を選択してYAMLコンフィグを修正してください。(Link)
これでlima VMの作成と起動が完了しました。
なおlima VMはmacOS起動時に立ち上がらないので、自動起動が必要な場合は必要に応じて設定を行う必要があります。
lima VM上のDocker Engine Serverインストール
次にlima VMにDocker Engine Serverをインストールします。
# Install Docker on lima VM
curl -fsSL https://get.docker.com | lima
# Setup docker user to run without sudo (Need to restart lima VM; restarting dockerd won't work)
lima sudo gpasswd -a $USER docker
limactl stop; sleep 5; limactl start
# Check docker command works on macOS Host
lima docker version
lima docker versionコマンドの結果でClientとServerの情報が両方ともエラー無く表示されていればOKです。
macOSのDocker CLIと通信するための設定
最後にmacOSホスト側のDocker CLIからDocker Engine ServerのAPIにアクセスできるようにTCP通信を受け付けられるように設定します。
lima VM上に/etc/docker/daemon.json
をエディタで開いて作成します。ここではvimを使った例を示します。
lima sudo vim /etc/docker/daemon.json
上記のJSONファイル内容を以下のよう記述して保存します。(TCP通信とUnixソケットの両方を受け付けるように設定)
{"hosts": ["tcp://127.0.0.1:2375", "unix:///var/run/docker.sock"]}
上記の設定はデフォルトのDocker Daemonの引数と衝突するため、これを回避するためにsystemdの上書き設定用のファイルを作成します。ここでもvimを使った例を示します。
lima sudo mkdir -p /etc/systemd/system/docker.service.d/
lima sudo vim /etc/systemd/system/docker.service.d/override.conf
上記のoverride.confのファイル内容を以下のように記述して保存します。
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
最後に設定を反映します。
lima sudo systemctl daemon-reload
lima sudo systemctl restart docker.service
これでlima VMのDocker Engine Serverの設定も完了です。
動作確認
これでmacOSホスト側およびlima VMのセットアップが完了しました。
最後にmacOSホスト上で以下のコマンドを実行し、ClientとServerの情報が両方とも正常に表示されることを確認します。
docker version
正常に動作することを確認できれば、初めに紹介した「主な用途」にあるようなユースケースでは問題なく利用できます。
またDocker Engine APIにもアクセスできるようになっているため、こちらは未確認ですがJavaのTestcontainersライブラリ等もmacOSホスト上から利用できると思います。
もちろん全てのdockerコマンドやオプションについて動作確認をしているわけではないため、もしdockerコマンドやオプション等で正常に動作しないケースなどがあればコメントで情報を共有いただければと思います。
おまけ
docker-composeを使いたい人へ
私はdocker-composeを使用していないため、セットアップ手順にdocker-composeのインストール手順は含めませんでした。
しかしdocker-composeのバイナリはGitHubレポジトリのReleaseページからダウンロードできるようになっているため、こちらから適切なMac BinaryをダウンロードしてPATHが通っているディレクトリに配置すれば利用できるようになります。
(簡単なサンプルを用いたdocker-compose up
は正常動作することを確認済み)
何故podmanやnerdctlでは駄目なのか?
これを機にCLIをpodmanやnerdctlに完全に置き換えようとする人もいると思いますが、podmanやnerdctlはDocker CLI、Docker REST API (Docker Engine API)、BuildKitなどの互換性や対応は完璧ではありません。
このためDockerのBuildkit等を活用していたり、Docker REST API(Docker Engine API)を活用しているTestcontainersのようなライブラリを使用している場合はpodman, nerdctlに置き換えるのは不可能ではないかもしれませんが非常に厳しいです。
例えばDocker CLIやBuildKitの互換性の問題の例としては以下のようなものが挙げられます。
- podmanではBuildKitが使えないため、docker buildにおける
--ssh
などのオプションが使えない。- Issueなどを見る限りは対応も進んでいるように見るが、対応時期や互換性がどこまであるかが不明。
- nerdctlはdocker psにおける--filterなどのオプションが使えない。kind CLIではこういったオプションも使用しているため、正常にKinDクラスタの操作ができない問題がある。
将来的にはDockerに依存しないエコシステムになると思いますが、現在は過渡期のためDockerにある程度は頼らざるを得ません。
Virtual Boxでは駄目なのか?
Virtual BoxでLinux VMを作成し、そのVM上で全ての作業を行うのであればVirtual Boxでも良いと思います。しかしその場合はエディタやIDE等のGUIも含めてLinux VM上で動かすためパフォーマンスやバッテリー面で不満があるので個人的にはNGです。
別のやり方として「コーディング等の作業をmacOS上、docker build等をLinux VM上で行う」といった役割分担をすることも可能です。しかしこの場合はホストとVMの間でファイル同期するように設定を行う必要がありますし、ssh鍵などのSecret情報も同期したりする必要があります。
本格的に開発や検証を行う用途の場合はVirtual BoxでもOKですが、保守運用などの作業メンバーがちょっとした作業のためにDockerが必要なユースケースの場合にはVirtual Boxはあまりにも仰々しくてお勧めしづらい側面があります。
(今回の記事を書いたのも、実用的、かつ敷居の低い代替手段が必要だったためです)