本記事は、 Docker/コンテナ仮想環境 Advent Calendar 2024 - Qiita 5日目の記事だ。
Linux で docker をインストールする場合、どのようにしているだろうか?
OS 標準のパッケージマネージャーからのインストールが一般的?
それとも、 Docker 公式のリポジトリ (Install - Docker Docs) を使っているだろうか?
そんな docker インストールする方法のひとつに Snap (Snapcraft) がある。
Snap (Snapcraft) とは
Snap (Snapcraft) は、Canonical が開発・管理している、アプリケーションをパッケージ化して配布するためのシステムのひとつだ。 Canonical は Ubuntu を支援している企業だが、 Ubuntu 以外の多くの主要なディストリビューションでも Snap を利用できる。
依存関係を含む一式がコンテナ化されており、異なる Linux ディストリビューション間で共通のパッケージで動作するのが特徴だ。 サンドボックス化したファイルシステム内でインストールしたアプリケーションを動かすという、セキュリティ面の特徴もある。
snap 版 docker は、 /home/
以下のファイルしか参照できない強い制限 1 や、インストール時に docker グループを作成してくれない制限があるが、それ以外はわりと問題なく動く。
Snap 版 docker に於けるプロキシ設定手順
プロキシの設定さえ適切に行えば、 snap 版 docker もプロキシ環境下で動作する。
基本的な設定箇所は、 Docker Daemon と Docker CLI の設定と同じだが、前述のサンドボックス化の関係で、記述するファイルの場所が異なる。
具体的には
/etc/docker/daemon.json
の替わりに/var/snap/docker/current/config/daemon.json
~/.docker/config.json
の替わりに~/snap/docker/current/.docker/config.json
をそれぞれ書き換える。
特に後者 (~/snap/docker/current/*
以下) については、一度そのユーザーで何らかの docker
コマンド (後述の例では docker info
) を実行してから設定しなくてはならない。
そうしないと、フォルダが Snap サンドボックスへマッピングが行われないからだ。
では、インストールからの手順を追ってみよう
- docker グループを作成する
sudo addgroup --system docker sudo adduser $USER docker newgrp docker
- Snap のプロキシ設定と docker のインストール
sudo snap set system proxy.https=http://proxy.example.com:8080 sudo snap install docker
- docker daemon と docker CLI のプロキシ設定を行う
sudo tee /var/snap/docker/current/config/daemon.json << 'EOF' > /dev/null { "log-level": "error", "proxies": { "http-proxy": "http://proxy.example.com:8080", "https-proxy": "http://proxy.example.com:8080", "no-proxy": "localhost,127.0.0.1,host.docker.internal,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.internal" } } EOF sudo snap restart docker docker info mkdir ~/snap/docker/current/.docker/ cat << 'EOF' > ~/snap/docker/current/.docker/config.json { "proxies": { "default": { "httpProxy": "http://proxy.example.com:8080", "httpsProxy": "http://proxy.example.com:8080", "noProxy": "localhost,127.0.0.1,host.docker.internal,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.internal" } } } EOF export http_proxy=http://proxy.example.com:8080; export https_proxy=$http_proxy
これで完成だ。
なお、 docker daemon のプロキシ設定手段は、上述の daemon.json
を設定する方法の他、 systemd の unit ファイルで設定する方法 も存在する。
その場合も、 /etc/systemd/system/docker.service.d/http-proxy.conf
の替わりに /etc/systemd/system/snap.docker.dockerd.service.d/http-proxy.conf
を書き換えれば OK だ。
プロキシが機能していることの確認
daemon.json
の設定によって daemon にプロキシが通っているので pull もできる。
$ docker pull alpine:3.19
3.19: Pulling from library/alpine
a7cd7d9a2144: Pull complete
Digest: sha256:7a85bf5dc56c949be827f84f9185161265c58f589bb8b2a6b6bb6d3076c1be21
Status: Downloaded newer image for alpine:3.19
docker.io/library/alpine:3.19
$
.../.docker/config.json
の設定によって 起動したコンテナの環境変数にもプロキシが通っているので、 apk も使える。
$ docker run -it --rm alpine:3.19
/ # printenv | grep "proxy"
HTTPS_PROXY=http://proxy.example.com:8080
no_proxy=localhost,127.0.0.1,host.docker.internal,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.internal
https_proxy=http://proxy.example.com:8080
http_proxy=http://proxy.example.com:8080
HTTP_PROXY=http://proxy.example.com:8080
/ # apk add curl
fetch https://dl-cdn.alpinelinux.org/alpine/v3.19/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.19/community/x86_64/APKINDEX.tar.gz
(1/8) Installing ca-certificates (20240226-r0)
...
(8/8) Installing curl (8.9.1-r1)
Executing busybox-1.36.1-r19.trigger
Executing ca-certificates-20240226-r0.trigger
OK: 12 MiB in 23 packages
/ # exit
$
勿論 Dockerfile
のビルドコンテナでも。
$ cat << 'EOF' > Dockerfile
FROM alpine:3.20
RUN printenv | grep "proxy" | cat
RUN apk add curl
EOF
$ docker build .
[+] Building 3.6s (7/7) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 105B 0.0s
=> [internal] load metadata for docker.io/library/alpine:3.20 0.8s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/3] FROM docker.io/library/alpine:3.20@sha256:1e42bbe2508154c9126d48c2b8a7542 0.0s
=> CACHED [2/3] RUN printenv | grep "proxy" | cat 0.0s
=> [3/3] RUN apk add curl 2.4s
=> exporting to image 0.2s
=> => exporting layers 0.1s
=> => writing image sha256:b4d3285b3df88a27d93b5cb8f2356e9b060e9d495b05d8020f4d42f 0.0s
$
…ところが。
docker compose でプロキシが効かない
同じ Dockerfile
を docker compose
からビルドしようとすると、 pull までは成功するのだが apk add
で失敗する。
(…ことが多い。後述の原因のため若干ランダム性があるかもしれない。)
$ cat << 'EOF' > Dockerfile
FROM alpine:3.20
RUN printenv | grep "proxy" | cat
RUN apk add curl
EOF
$ cat << 'EOF' > compose.yaml
services:
test:
build:
context: ./
restart: "no"
EOF
$ docker compose up --build
[+] Building 40.9s (6/6) FINISHED docker:default
=> [test internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 105B 0.0s
=> [test internal] load metadata for docker.io/library/alpine:3.20 0.9s
=> [test internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> CACHED [test 1/3] FROM docker.io/library/alpine:3.20@sha256:1e42bbe2508154c9126 0.0s
=> [test 2/3] RUN printenv | grep "proxy" | cat 0.3s
=> ERROR [test 3/3] RUN apk add curl 39.5s
------
> [test 3/3] RUN apk add curl:
0.315 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/x86_64/APKINDEX.tar.gz
14.76 WARNING: updating and opening https://dl-cdn.alpinelinux.org/alpine/v3.20/main: Permission denied
14.76 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/x86_64/APKINDEX.tar.gz
39.40 WARNING: updating and opening https://dl-cdn.alpinelinux.org/alpine/v3.20/community: Permission denied
39.40 ERROR: unable to select packages:
39.40 curl (no such package):
39.40 required by: world[curl]
------
failed to solve: process "/bin/sh -c apk add curl" did not complete successfully: exit code: 1
はて?
原因
問題を深堀する為に、 --progress=plain
をつけてビルドしてみる。
$ docker compose --progress=plain build
#0 building with "default" instance using docker driver
...
#4 [test 1/3] FROM docker.io/library/alpine:3.20@sha256:1e42bbe2508154c9126d48c2b8a75420c3544343bf86fd041fb7527e017a4b4a
...
#4 DONE 1.0s
#5 [test 2/3] RUN printenv | grep "proxy" | cat
#5 0.286 no_proxy=localhost,127.0.0.1,host.docker.internal,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.internal
#5 0.286 https_proxy=localhost,127.0.0.1,host.docker.internal,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.internal
#5 0.286 http_proxy=localhost,127.0.0.1,host.docker.internal,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.internal
#5 DONE 0.3s
#6 [test 3/3] RUN apk add curl
#6 0.322 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/x86_64/APKINDEX.tar.gz
#6 14.72 WARNING: updating and opening https://dl-cdn.alpinelinux.org/alpine/v3.20/main: Permission denied
#6 14.72 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/x86_64/APKINDEX.tar.gz
#6 40.39 WARNING: updating and opening https://dl-cdn.alpinelinux.org/alpine/v3.20/community: Permission denied
#6 40.39 ERROR: unable to select packages:
#6 40.39 curl (no such package):
#6 40.39 required by: world[curl]
#6 ERROR: process "/bin/sh -c apk add curl" did not complete successfully: exit code: 1
------
> [test 3/3] RUN apk add curl:
0.322 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/x86_64/APKINDEX.tar.gz
14.72 WARNING: updating and opening https://dl-cdn.alpinelinux.org/alpine/v3.20/main: Permission denied
14.72 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/x86_64/APKINDEX.tar.gz
40.39 WARNING: updating and opening https://dl-cdn.alpinelinux.org/alpine/v3.20/community: Permission denied
40.39 ERROR: unable to select packages:
40.39 curl (no such package):
40.39 required by: world[curl]
------
failed to solve: process "/bin/sh -c apk add curl" did not complete successfully: exit code: 1
おわかりいただけるだろうか?
http_proxy
と https_proxy
の環境変数に no_proxy
の内容が入っていることに。
実はコレ、厳密には snap の問題では無く docker-compose v2 プラグイン の問題だ。
クロージャで変数のキャプチャ範囲を間違えるという、非っ常~~にありがちな不具合だ。
で、この不具合は 2023年8月リリースの v2.21.0 でとっくに修正されているのだが、 snap docker に同梱しているプラグインが古いままのため、問題になっているのだ。
$ docker --version
Docker version 27.2.0, build 3ab4256
$ docker compose version
Docker Compose version v2.20.3
docker 本体は 27.2 まで更新されているのにね。
docker-snap のリポジトリには Issue を投げているので、近いうちにプラグインのバージョンが更新されることを願う。
Issue に サムアップ しておいてもらえると、対応が早まるかもしれない。
ワークアラウンド
Snap パッケージ側の修正を待てない場合のワークアラウンドについて。
上述の通り docker-compose
プラグインの問題なので、ユーザー単位のプラグインフォルダに更新した docker-compose v2
をダウンロードしてしまえば良い。
mkdir ~/snap/docker/current/.docker/cli-plugins
# 動作中の CPU のアーキテクチャ次第で、ダウンロードするファイルは変わるので注意
curl -SL https://github.com/docker/compose/releases/download/v2.29.7/docker-compose-linux-x86_64 -o ~/snap/docker/current/.docker/cli-plugins/docker-compose
chmod u=rwx,g=rx,o=rx ~/snap/docker/current/.docker/cli-plugins/docker-*
ダウンロードするバージョンは v2.21.0 以降なら何でも良いが、現在の snap パッケージ内の docker のバージョン (27.2.0) との組み合わせでテストされている v2.29.7 あたりがいいんじゃなかろうか。
この状態で改めて compose の build すると、以下の通り http_proxy
, https_proxy
, HTTP_PROXY
, HTTPS_PROXY
の各環境変数が期待通り .../.docker/config.json
で設定したものになっており、 apk add
も含めビルドが成功することがわかる。
$ docker compose --progress=plain build
#0 building with "default" instance using docker driver
...
#4 [test 1/3] FROM docker.io/library/alpine:3.20@sha256:1e42bbe2508154c9126d48c2b8a75420c3544343bf86fd041fb7527e017a4b4a
...
#4 DONE 0.9s
#5 [test 2/3] RUN printenv | grep "proxy" | cat
#5 0.309 HTTPS_PROXY=http://proxy.example.com:8080
#5 0.309 no_proxy=localhost,127.0.0.1,host.docker.internal,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.internal
#5 0.309 https_proxy=http://proxy.example.com:8080
#5 0.309 http_proxy=http://proxy.example.com:8080
#5 0.309 HTTP_PROXY=http://proxy.example.com:8080
#5 DONE 0.3s
#6 [test 3/3] RUN apk add curl
#6 0.308 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/x86_64/APKINDEX.tar.gz
#6 0.960 fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/x86_64/APKINDEX.tar.gz
#6 2.036 (1/10) Installing ca-certificates (20240705-r0)
...
#6 DONE 2.8s
#7 [test] exporting to image
#7 exporting layers 0.2s done
#7 writing image sha256:e80c51d304a37734fab6a0506616fd2ef5bfd56d20658aec988958a7d342a099 done
#7 naming to docker.io/library/myubuntu-test 0.0s done
#7 DONE 0.2s
#8 [test] resolving provenance for metadata file
#8 DONE 0.0s
その他のトラブルシューティング
ユーザーに docker
グループを割り当てているのにもかかわらず、 docker
コマンド実行時に dial unix /var/run/docker.sock: connect: permission denied
となってしまう場合、
$ groups
myubuntu adm cdrom sudo dip plugdev lxd docker
$ docker info
Client:
...
Server:
ERROR: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.47/info": dial unix /var/run/docker.sock: connect: permission denied
errors pretty printing info
docker
グループ作成前に snap パッケージをインストールしてしまったせいで、 /var/run/docker.sock
のグループパーミッションが root
になってしまっている可能性がある。
$ ls -la /var/run/docker.sock
srw-rw---- 1 root root 0 Dec 4 15:03 /var/run/docker.sock
このため、 chgrp
や chown
を使って管理グループを docker
に変更してやれば解決する。
$ sudo chgrp docker /var/run/docker.sock
$ ls -la /var/run/docker.sock
srw-rw---- 1 root docker 0 Dec 4 15:03 /var/run/docker.sock
$ docker infoinfo
Client:
...
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
...
snap 版ではない docker では、インストール時に自動的に docker グループを作成してくれるので、それに慣れているとハマってしまいがちだ。
-
/var/run/docker.sock
のマウントはできるので、 DooD は可能。 ↩