M1 MacBook Pro 2021 に Lima + Docker 環境をインストールする
背景
まずは個人開発をすすめるべく、開発環境を整えていきます。
今回は以下の状況や条件を踏まえて Lima + Docker
の環境を作っていきます。
- Apple Silicon の M1 Macbook Pro を購入した
- Docker Desktop が有料化される(個人的には対象外ですが)
- Docker Desktop for Mac でのファイルシステムマウントが激遅なのを避けたい
- WSL (Windows Subsystem for Linux) のような Linux 仮想環境をつくりたい
環境
- MacBook Pro 2021
環境構築手順
Lima のインストール
brew でお手軽にインストールできます。
brew upgrade brew update brew install lima
Lima での ゲスト VM 作成
Lima の公式リポジトリ にはいろんな VM のサンプルが掲載されています。
その中から、docker-compose もインストールされるように 作られた VM の YAML ファイル を利用します。
cd ~/tmp mkdir lima && cd lima curl -o default.yaml https://raw.githubusercontent.com/chibiegg/lima-config/master/docker.yaml cat default.yaml # Example to use Docker instead of containerd & nerdctl # $ limactl start ./docker.yaml # $ limactl shell docker docker run -it -v $HOME:$HOME --rm alpine # Hint: To allow `docker` CLI on the host to connect to the Docker daemon running inside the guest, # add `NoHostAuthenticationForLocalhost yes` in ~/.ssh/config , and then run the following commands: # $ export DOCKER_HOST=ssh://localhost:60006 # $ docker ... # If ssh:// ... does not work, try the following commands: # $ ssh -f -N -p 60006 -i ~/.lima/_config/user -o NoHostAuthenticationForLocalhost=yes -L $HOME/docker.sock:/run/user/$(id -u)/docker.sock 127.0.0.1 # $ export DOCKER_HOST=unix://$HOME/docker.sock # $ docker ... images: # Hint: run `limactl prune` to invalidate the "current" cache - location: "https://cloud-images.ubuntu.com/hirsute/current/hirsute-server-cloudimg-amd64.img" arch: "x86_64" - location: "https://cloud-images.ubuntu.com/hirsute/current/hirsute-server-cloudimg-arm64.img" arch: "aarch64" mounts: - location: "~" writable: false - location: "/tmp/lima" writable: true ssh: localPort: 60006 # Load ~/.ssh/*.pub in addition to $LIMA_HOME/_config/user.pub , for allowing DOCKER_HOST=ssh:// . # This option is enabled by default. # If you have an insecure key under ~/.ssh, do not use this option. loadDotSSHPubKeys: true # containerd is managed by Docker, not by Lima, so the values are set to false here. containerd: system: false user: false provision: - mode: system script: | #!/bin/bash set -eux -o pipefail command -v docker >/dev/null 2>&1 && exit 0 export DEBIAN_FRONTEND=noninteractive curl -fsSL https://get.docker.com | sh # NOTE: you may remove the lines below, if you prefer to use rootful docker, not rootless systemctl disable --now docker apt-get install -y uidmap - mode: user script: | #!/bin/bash set -eux -o pipefail dockerd-rootless-setuptool.sh install docker context use rootless sudo apt install -y docker-compose qemu-system-x86 binfmt-support qemu-user qemu-user-static probes: - script: | #!/bin/bash set -eux -o pipefail if ! timeout 30s bash -c "until command -v docker >/dev/null 2>&1; do sleep 3; done"; then echo >&2 "docker is not installed yet" exit 1 fi if ! timeout 30s bash -c "until pgrep rootlesskit; do sleep 3; done"; then echo >&2 "rootlesskit (used by rootless docker) is not running" exit 1 fi hint: See "/var/log/cloud-init-output.log". in the guest
ゲスト VM の起動
limactl start default.yaml ? Creating an instance "default" Proceed with the default configuration INFO[0023] Attempting to download the image from "https://cloud-images.ubuntu.com/hirsute/current/hirsute-server-cloudimg-arm64.img" digest= 543.69 MiB / 543.69 MiB [-----------------------------------] 100.00% 9.21 MiB/s INFO[0084] Downloaded image from "https://cloud-images.ubuntu.com/hirsute/current/hirsute-server-cloudimg-arm64.img" INFO[0088] [hostagent] Starting QEMU (hint: to watch the boot progress, see "/Users/xxxxxx/.lima/default/serial.log") INFO[0088] SSH Local Port: 60006 INFO[0088] [hostagent] Waiting for the essential requirement 1 of 5: "ssh" INFO[0142] [hostagent] The essential requirement 1 of 5 is satisfied INFO[0142] [hostagent] Waiting for the essential requirement 2 of 5: "user session is ready for ssh" INFO[0142] [hostagent] The essential requirement 2 of 5 is satisfied INFO[0142] [hostagent] Waiting for the essential requirement 3 of 5: "sshfs binary to be installed" INFO[0143] [hostagent] The essential requirement 3 of 5 is satisfied INFO[0143] [hostagent] Waiting for the essential requirement 4 of 5: "/etc/fuse.conf to contain \"user_allow_other\"" INFO[0146] [hostagent] The essential requirement 4 of 5 is satisfied INFO[0146] [hostagent] Waiting for the essential requirement 5 of 5: "the guest agent to be running" INFO[0146] [hostagent] The essential requirement 5 of 5 is satisfied INFO[0146] [hostagent] Mounting "/Users/xxxxxx" INFO[0146] [hostagent] Mounting "/tmp/lima" INFO[0146] [hostagent] Waiting for the optional requirement 1 of 1: "user probe 1/1" INFO[0146] [hostagent] Forwarding "/run/lima-guestagent.sock" (guest) to "/Users/xxxxxx/.lima/default/ga.sock" (host) INFO[0146] [hostagent] Not forwarding TCP 127.0.0.53:53 INFO[0146] [hostagent] Not forwarding TCP 0.0.0.0:22 INFO[0146] [hostagent] Not forwarding TCP [::]:22 INFO[0173] [hostagent] The optional requirement 1 of 1 is satisfied INFO[0173] [hostagent] Waiting for the final requirement 1 of 1: "boot scripts must have finished" INFO[0214] [hostagent] Waiting for the final requirement 1 of 1: "boot scripts must have finished" INFO[0214] [hostagent] The final requirement 1 of 1 is satisfied INFO[0214] READY. Run `lima` to open the shell.
ホスト(macOS )に docker と docker-compose コマンドをインストールする
ホスト側である macOS から Lima のゲスト VM 上にあるコンテナを操作するため、docker と docker-compose コマンドをインストールします。
こちらも brew でかんたんにインストールできます。
brew install docker docker-compose
コマンドをインストールしただけではゲスト VM 上のコンテナにアクセスできませんので、SSH 経由でコマンドを実行できるようにします。
echo 'export DOCKER_HOST=ssh://limadocker:60006' >> ~/.zshrc cat << EOS >> ~/.ssh/config Host localhost HostName localhost User xxxxxx NoHostAuthenticationForLocalhost yes Port 60006 EOS source ~/.zshrc
うまくいくかと思ったら、SSH がうまく通っていないようでした。
docker version Client: Docker Engine - Community Version: 20.10.11 API version: 1.41 Go version: go1.17.2 Git commit: dea9396e18 Built: Wed Nov 17 23:49:46 2021 OS/Arch: darwin/arm64 Context: default Experimental: true error during connect: Get "http://docker.example.com/v1.24/version": command [ssh -p 60006 -- localhost docker system dial-stdio] has exited with exit status 255, please make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=xxxxxx@127.0.0.1: Permission denied (publickey).
調べてみると、SSH 設定を表示してくれるコマンドがある ようです。
limactl show-ssh --format=(cmd|args|options|config) INSTANCE
インスタンス名は default
、出力フォーマットは ~/.ssh/config
用に config
とします。
limactl show-ssh default --format=config Host lima-default IdentityFile "/Users/xxxxxx/.lima/_config/user" StrictHostKeyChecking no UserKnownHostsFile /dev/null NoHostAuthenticationForLocalhost yes GSSAPIAuthentication no PreferredAuthentications publickey Compression no BatchMode yes IdentitiesOnly yes Ciphers "^aes128-gcm@openssh.com,aes256-gcm@openssh.com" User xxxxxx ControlMaster auto ControlPath "/Users/xxxxxx/.lima/default/ssh.sock" ControlPersist 5m Hostname 127.0.0.1 Port 60006
表示された設定のうち、Host を lima-default
から docker コマンド実行エラー時に表示されていたホスト名 localhost
へ変えて ~/.ssh/config
に記載しておきます。
改めて docker コマンドを実行してみるとエラーが解消されました!
docker version Client: Docker Engine - Community Version: 20.10.11 API version: 1.41 Go version: go1.17.2 Git commit: dea9396e18 Built: Wed Nov 17 23:49:46 2021 OS/Arch: darwin/arm64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.11 API version: 1.41 (minimum version 1.12) Go version: go1.16.9 Git commit: 847da18 Built: Thu Nov 18 00:35:20 2021 OS/Arch: linux/arm64 Experimental: false containerd: Version: 1.4.12 GitCommit: 7b11cfaabd73bb80907dd23182b9347b4245eb5d runc: Version: 1.0.2 GitCommit: v1.0.2-0-g52b36a2 docker-init: Version: 0.19.0 GitCommit: de40ad0
ゲスト VM 上でのコンテナの起動と動作確認
ゲスト VM 上でコンテナを起動します。今回は nginx が実行されるコンテナを起動して確認します。
docker run -it -p 8080:80 nginx:latest /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh /docker-entrypoint.sh: Configuration complete; ready for start up 2021/12/06 08:50:34 [notice] 1#1: using the "epoll" event method 2021/12/06 08:50:34 [notice] 1#1: nginx/1.21.4 2021/12/06 08:50:34 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 2021/12/06 08:50:34 [notice] 1#1: OS: Linux 5.11.0-41-generic 2021/12/06 08:50:34 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576 2021/12/06 08:50:34 [notice] 1#1: start worker processes 2021/12/06 08:50:34 [notice] 1#1: start worker process 32 2021/12/06 08:50:34 [notice] 1#1: start worker process 33 2021/12/06 08:50:34 [notice] 1#1: start worker process 34 2021/12/06 08:50:34 [notice] 1#1: start worker process 35
起動後にホスト側から http://localhost:8080 にアクセスできれば成功です!