Docker Desktopを使うのが楽なのだが、仕事でAmazon Linuxのイメージでsystemdを動かしていたときに、systemdがv247以上じゃないと動かないというアップグレードに見舞われ、しばらくは4.2.0で頑張っていたが、Amazon Linuxのイメージが更新される兆しがないので、それ以来コマンドライン版を使っている。 動かなくなった時はほんとあせった。 現状のDocker Desktopがどうなっているかは使っていないので全くわからない。
MacのDockerはQEMU上のLinux仮想マシンで動くようになっていて、QEMUの設定が面倒らしいのだが、Lima(Linux Machines)というのを使うとその辺りをやってくれる。 さらにこの仮想マシン上でDockerを使う設定が必要だが、これはColima(container runtimes on macOS (and Linux) with minimal setup)というのが全部やってくれる。 ・・・なんとなくLinux on MacとContainer on Limaだと思ってたんだが。
もし入れてなければ。
Homebrewに書いてある指示に従う。
インストールの最後で.bash_profile
(zsh派ではなくbash派なので)に書く内容を吐き出すので書き込んでおく。
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> .bash_profile
終わったら.bash_profile
の内容を反映させる。
source
してもよいが、個人的にはシェルを再起動する派。
brew install colima docker
QEMU・LimaはColimaの依存で自動的に入る。
colima start
これでコマンドラインでDockerが使えるようになっている。
colima stop
colima list
colima status
でもよいが、list
の方が見やすのと、クロスプラットフォームで使っている時に状況を把握しやすいので、最近はもっぱらlist
で見ている。
colima list
でSTATUS
がBroken
になっている場合。
colima stop --force
して、もう一度起動すればよい。
QEMU VMのプロキシ設定がおかしいと通信が異常に遅くなることがある。
Macのプロキシを切り替えた時に起こりがち。
Mac側のコマンドラインのプロキシ設定を確認してから、colima restart
とすれば直ることが多い。
~/.colima
を見ると情報を得られることが多い。
あとは
~/.lima/colima*
。
VMの仮想ディスクなどはこちらに入っている。
コンテナからのデタッチがデフォルトで
Ctrl+P
・
Ctrl+Q
というシーケンスになっているが、
Ctrl+P
がBashのヒストリを遡るショートカットと当たっていて、
Ctrl+P
を2回押さないと履歴が出ない(そしてふたつ遡るので
Ctrl+N
で戻すことになる)ので、
~/.docker/config.json
に次の1行を書き加えてある。
"detachKeys": "ctrl-\\,ctrl-q",
これでデタッチキーは Ctrl+\ ・ Ctrl+Q になる。
x86でARM、ARMでx86のバイナリを動かす。 カイシャの機械がM1 Macになったのだが、以前作成したDockerfileをdocker buildしたら、MySQL 5.7のARMのイメージがないらしく、起動できなかった。仕方なくx86エミュレーションで起動することに。 Google CloudのCloud Runなんかも現時点ではx86_64のイメージを要求されるので、この方法でイメージの動作確認ができる。
基本的にはこれだけ。
colima start -a x86_64 x86_64最初の
x86_64
は-a
オプションのパラメータで、起動するQEMUのアーキテクチャを指定している。
後ろのx86_64
はプロファイル名(設定名)で、指定しなければdefault
が使われるが-a
を指定する時はプロファイル名も指定しないとだいたい痛い目に遭う。
以後、Dockerのコマンドはx86_64側で動くようになる。
止める場合は
colima stop x86_64
プロファイルは起動時のオプションを覚えているので、次回以降は環境名だけ指定すればよい。
colima start x86_64
というか、アーキテクチャの指定は最初にプロファイルを作った時のみ正常に動く模様。
アーキテクチャ指定を忘れてしまった場合は、一度colima delete x86_64
のようにして、そのプロファイルを消して作り直せばよい。
このコマンドは仮想ディスクなんかも全部消す。
既存の環境に間違ってアーキテクチャを指定した場合は悲惨な結末が待っているので注意すること。
x86のVMが起動したところでcolima list
すると、ARMとx86が両方動いていることがわかる。
PROFILE STATUS ARCH CPUS MEMORY DISK RUNTIME ADDRESS default Running aarch64 2 2GiB 60GiB docker x86_64 Running x86_64 2 2GiB 60GiB docker
DockerはこのVM上で動くので、仮想ディスクなども全部別である。 当然コンテナもイメージもボリュームも全部別である。 共有は別途考える必要がある。
Dockerがどちらを使っているかは、Docker側のコマンドで分かる。
$ docker context ls NAME DESCRIPTION DOCKER ENDPOINT ERROR colima colima unix:///Users/ec2-user/.colima/default/docker.sock colima-x86_64 * colima [profile=x86_64] unix:///Users/ec2-user/.colima/x86_64/docker.sock default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
*
が付いているのが今使っている環境。
Colimaのデフォルトのプロファイルで起動したVMはcolima
になっている。
切り替えるにはdocker context use colima
のようにすればよい。
特に、どちらか一方のVMを
colima stop
で止めた時は、どのコンテキストに切り替わったか確認する必要があるだろう(そして、だいたいDocker側の
default
に切り替わっていて動かないわけだ)。
docker build
時などにSSH公開鍵で認証しているGitのリポジトリからデータを引っ張ってきたいことが割と頻繁に発生する。
そんな時のお話。
docker build
時でなければ(つまりdocker run
で動かしたコンテナの中ならば)、SSHデーモンを起動してしまい、エージェントフォワード有効で接続して使う、という手がある。
これならば既存の知識だけでエージェントフォワーディングが扱える。
とりあえず公開鍵を設定しないといけない。 ホストで適当に鍵を作る。
cd ~/.ssh ssh-keygen -f docker
たとえばUbuntuコンテナを起動して:
docker run -it --rm -p 2222:22 ubuntuコンテナ内で:
apt update apt install -y --no-install-recommends openssh-server ssh host.docker.inetrnal
--no-install-recommends
を付けないと、systemdから何から大量にインストールされてしまう。
逆に、Ubuntu限定かもしれないが、動作確認できる状態でsystemdを入れたいなら(
--no-install-recommends
を付けずに)openssh-serverをインストールするのが一番楽かもしれない。
bashの代わりに
/sbin/init
を起動した状態が、冒頭の「systemdを動かして」いる状態になる。
最後のSSHコマンドはホームに.ssh
ディレクトリを作っている。
接続先はSSHで接続できるホストならばどこでもよく、認証は失敗してよい。
host.docker.internal
は起動したホストを示すホスト名で、Dockerが自動的に設定している。
Macならばシステム設定・共有・リモートログインを有効にしていればSSHデーモンが起動している。
続いて鍵をコピーする。
cd ~/.ssh cat >> authorized_keysさっきホストで作った
ubuntu.pub
を貼り付ける。
コンテナでSSHデーモンを起動:
/usr/sbin/sshd -De
おっと、Missing privilege separation directory: /run/sshd
と言われる。
コンテナにはマニュアルがインストールされていないので、他のOpenSSHが入ったシステム、具体的にはMacのホスト側で適当にマニュアルを参照すると「The directory should not contain any files and must be owned by root and not group or world-writable」と書いてあるので、この通り作ってあげる。
mkdir -p -m 700 /run/sshd /usr/sbin/sshd -De
ちなみに-D
はデーモン化しない、-e
はログを標準エラー出力に出す。
Cygwinでsshサーバーで使ったのと同じ。
UNIXとその仲間たちはこういう知識が使い回せる。それに対してほんとWinなんちゃらっていうシステムは・・・。
ホスト側から接続:
ssh -p 2222 -i docker root@localhost
コンテナを作り直すとコンテナのSSHホスト鍵が変わってしまうので、一度
~/.ssh/known_hosts
から削除するか、ホスト鍵のキーをバックアップしておいて、コンテナを新しく作った時に送り込んでやればよい。
ホスト鍵はUbuntuなら
/etc/ssh
にある。
MacではデフォルトでSSHエージェントが起動しているので
ssh-add
すれば
-i
は不要になる。
また、
-A
でエージェントフォワーディングが有効になるので、ホスト側の適当な鍵を
ssh-add
しておけばその鍵をコンテナ内でも使えるようになる。
ssh-add docker ssh-add key-for-host-exampe-com ssh -p 2222 -A root@localhost
ssh-add -l ssh user@host.example.com
実はQEMUのVMにはSSHでアクセスできる。
colima ssh
プロファイルを指定しないとdefault
が使われる。
指定したい場合は
-p
を使う。
colima ssh -p x86_64 uname -m
x86_64
ということは、ホストからQEMUのVMにエージェントフォワードありで接続して、VM内のソケットをコンテナに教えてやればよい。
デフォルトではVMのエージェントフォワードが有効になっていないので、Colima起動時に
--ssh-agent
を指定する。
restart
では指定できないので、VMが起動している場合は一度止める。
colima stop
colima start --ssh-agent
colima ssh printenv SSH_AUTH_SOCK
/tmp/ssh-XXXXIdPBJp/agent.3555
オプションは一度設定すれば覚えている(
~/.colima/default
以下などに設定が書き込まれる)ので、次回以降は指定しなくてよい。
で、バインドマウントの方だが、DockerはホストではなくVMのディスクをマウントしている。
つまり、
-v
や
--mount
で指定したディレクトリは、VMのディレクトリとして解釈される。
ではなぜホストであるMacのホームディレクトリがマウントできるかというと、Colimaがホストの
/Users
をVMの
/Users
に見えるようにマウントしているからである。
colima ssh mount | grep /Users
:/Users/ec2-user on /Users/ec2-user type fuse.sshfs (rw,nosuid,nodev,relatime,user_id=501,group_id=1000,allow_other)
AWS EC2上の
mac2
ホストなんでユーザー名が
ec2-user
になってっけど。
こうなっているので、
docker run -v /Users/ec2-user/docker:/app
とすれば、VMの
/Users/ec2-user/docker
をマウントする=ホストの
/Users/ec2-user/docker
がマウントされるので、ホストのデータがコンテナからも見える。
逆にいうと、
/Users
の下にないホストディレクトリはマウントできない。
ホストとVMのルートディレクトリに適当にフォルダを作って、Dockerでバインドマウントしてフォルダがどう見えるか確認してみるとよい。
結局、VMの
SSH_AUTH_SOCK
に設定されているパスを、ホストのコマンドラインに直接指定してバインドマウントすればOKで、マウントしたパスをコンテナの
SSH_AUTH_SOCK
環境変数に設定してやればよい。
docker run -it --rm -v $(colima ssh printenv SSH_AUTH_SOCK):/tmp/ssh-auth.sock -e SSH_AUTH_SOCK=/tmp/ssh-auth.sock ubuntu
うまくいかないときは、
colima ssh
の中で
ssh-agent -l
してみるとよい。これで見えていなければVMがホストのソケットを見失っているので、
colima restart
でVMを再起動すればよい。
なお、VM内には
/run/host-services
というディレクトリがあって、その中に
ssh-auth.sock
というシンボリックリンクがあり、これがエージェントフォワードのソケットを示している。
一見、
/run/host-services
をバインドマウントすれば万事解決のように見えるが、シンボリックリンクなのでリンクが指してる先も同じ名前でマウントしないと動かない。
結局、ソケットのバインドマウントも作らなければならず、二度手間になる。
いまのところ、VMの
SSH_AUTH_SOCK
にはソケットの実体の方が設定されているので、現状では
colima ssh printenv SSH_AUTH_SOCK
を使った方が確実である。
/run/host-services
の流儀に合わせたいのなら、
colima ssh printenv SSH_AUTH_SOCK
の結果を
/run/host-services/ssh-auth.sock
にバインドマウントすればよい。
ただ、
SSH_AUTH_SOCK
環境変数にも同じパスを設定する必要があり、コマンドラインが長くなってしまうので、ここでは
/tmp/ssh-auth.sock
にマウントしている。
docker-buildx
が必要
brew install docker-buildx
docker-buildx
が仕込まれていたりする
docker-buildx build
のように使える
docker build
で使いたければ、Homebrewで
docker-buildx
をインストールしたときに最後に出てくる
mkdir -p ~/.docker/cli-plugins ln -sfn /opt/homebrew/opt/docker-buildx/bin/docker-buildx ~/.docker/cli-plugins/docker-buildx
をやっておく
docker-buildx
が動いているかどうかは
docker build
とやれば分かる。
ERROR: "docker buildx build" requires exactly 1 argument.
と怒られれば
docker-buildx
が動いている
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
と怒られた場合は古い
docker build
が動いている
docker buildx install
とかしてた気がするけど、今EC2のmac2で試してみたら、シンボリックリンク張った時点で
docker build
で
docker-buildx
が動いているようだ。
Dockerfile
の
RUN
に
--mount=type=ssh
を付ける
docker build
時に
--ssh=default
オプションを付ける
default
の意味が(うたた寝しながら)考えてみたけどよく分かんない
Dockerfile
の
RUN
コマンドと
docker build
のコマンドラインと、両方やる必要がある(よく片方を忘れて焦る)
git clone
などを実行する場合、ビルド中のイメージに
~/.ssh/known_hosts
がないので、ホストキー確認で端末入力が必要になり
docker build
に失敗する
COPY
で
known_hosts
をコピーしておくか、
cd ~ && mkdir -m 700 .ssh && ssh-keyscan host.example.com >> .ssh/known_hosts
する。
ssh-keyscan
便利。
Dockerfile
の中で
RUN --mount=type=ssh ssh-agent -l; false
としてみればよい
false
は強制終了させ、結果をキャッシュさせないために付けている
ssh-add
したキーが表示されれば成功
Copyright (C) 2023 akamoz.jp
$Id: mac-docker.htm,v 1.4 2023/10/24 14:50:23 you Exp $