砂漠の旅人(たびと)

UNIX / MS-DOS 時代から電脳砂漠を旅しています

【プロキシ対応】Docker Desktop for Windowsを使わず、WSL2 / Ubuntu に apt で Docker を入れる

こんにちは、たびとです。

Docker 初心者の頃、既存の WSL2/Ubuntu 環境に Docker Desktop for Windows をインストールし、Docker コンテナを構築するといったよくある使い方をしていました。

しかし、業務で使い込んでいるうちに思わぬ事故に何度も遭遇しました。このままでは実用には耐えられないなと思い、WSL2/Ubuntu 環境に直接 Dokcer をインストールしてみました。

この記事の対象者

  • WSL2/Linux の構築経験があり、最低限の Linux コマンドを知っている人
  • 業務で、Docker Desktop for Windows を使っている人、これから使いたい人
  • 自作で Dockerfile や docker-compose.yml を作って、ビルドを繰り返す人
  • Docker Desktop for Windows でディスク枯渇を経験し、何度も掃除するのが面倒だと思った人

Docker Desktop for Windowsを諦めた理由

AIのPoC開発で、Webサーバにnginx、APサーバにASP.NET Core(gRPC)、DBサーバにPostgreSQL、バッチサーバに.NET Core(Consoleアプリ)の環境を構成することになりました。

Docker Desktop for Windows採用

最初は VMwareHyper-V に構築していましたが、GUI だとディスクサイズが巨大になるので、WSL2/Ubuntu で作り直したりしていました。

ひとりで構築から開発までを担当していたので、サーバ構築を自動化してアプリ開発に集中したいと思い、流行りの Docker を採用してみました。 しかし、Docker 初心者のときは、Dockerfile と docker-compose.yml の違いも理解できず、ASP.NET Core や .NET Core のビルド、 ビルドに必要なライブラリのコンパイルをどのように Dockerfile に記述すれば良いのか、わからないことが多過ぎて、苦労の連続でした。

トラブル連発

そうやってコンテナ作りに試行錯誤していると、あるとき、Cドライブが枯渇してしまいビルドができなくなりました。 Docker 関連のイメージなど不要なモノは、こまめに削除していたので、何が領域を圧迫しているのか理解できず、原因究明に苦労することになりました。

詳しい方はご存じだと思いますが、Docker Desktop for Windows はイメージなどを削除してもディスク領域を解放しないという仕様(というかトラップ)があります。 当時は知る由もなく、散々悩んだ挙句に何とか原因を突き止めました。

また、Docker Desktop for Windows のアップデートが何度かあり、毎回軽い気持ちでアップデートしていました。 あるとき、アップデートの最中にクラッシュして、Docker Desktop for Windows が起動しなくなりました。 こうなっては、アンインストールしか方法はありません。データベースをコンテナ内に置いていたため、データも併せて全滅しました。

ただ、もしもに備えて複数の Docker 環境を作っていたため、データのバックアップがあったことは、 不幸中の幸いでした。この後、コンテナの外にデータを配置したのは言うまでもありません。

このクラッシュ現象には何度も遭遇しましたが、複数端末の全滅ではなく、特定の端末がダメになりました(ある一台に集中した訳ではありません)。ダメなときは、アンインストールして再インストールしてもダメでした。古い版数を使うか、次のアップデートを待つしかありません。クラッシュ時のリリースは割と早かったと記憶しています。

そして Docker Desktop for Windows を諦めた

このようなトラブル情報は、読んだ限りの Docker 本にもなく、インターネット上にも情報が少なかったので、Dokcer 初心者のたびとは散々な目に会いました。 今後、このような困った人が減るように記録を残しておきます。

よって、学習向けであれば Docker Desktop for Windows は最高に便利ですが、業務レベルでは実用に耐えれないなという認識です。 ただし、たびとが使っていたのは Docker Desktop for Windows V3 の時代だったので、現在のV4になって改善されている可能性はあります。

ただし、Docker Desktop for WindowsLinux コンテナとしては諦めましたが、アンインストールはせずに「Switch to Windows containers...」に切り替えて Windows コンテナとして利用しています。

WSL2/Ubuntu の準備 (20.04 or 22.04)

Windows Store から 好きな Ubuntu をインストールしてください。

インストール後、必ず wsl コマンドで、VERSIONが2であることを確認してください。 WSL2でない場合、WSL2に切り替えてください。

PS C:\> wsl -l -v
NAME                   STATE           VERSION
* Ubuntu-20.04           Running         2

Windows 11 または Windows 10 バージョン 2004 以降の場合、 wsl --install コマンドで WSL2 の Ubuntu を簡単にインストールすることができます。 ※ ただし、既に Linux をインストールしている場合、オプションが必要です。

詳細は、以下の記事を参考にしてください。

sabakunotabito.hatenablog.com

Ubuntu 版 Docker のインストール

それでは、WSL2 Ubuntu に Docker をインストールしていきます。

アップデート確認

apt update コマンドを確認後、アップデートがあれば apt upgrade してください。

$ sudo apt upadte
$ sudo apt upgrade

Dockerに必要なパッケージのインストール

Dokcerに必要なパッケージをインストールします。

$ sudo apt install -y apt-transport-https ca-certificates gnupg-agent software-properties-common

Dockerの公式GPGキーの取得と確認を行います。

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

$ sudo apt-key fingerprint 0EBFCD88
pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

リポジトリの設定を行います。

$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

Dockerのインストール

Dockerをインストールします。

$ sudo apt update
$ sudo apt install -y docker-ce docker-ce-cli containerd.io
$ docker --version
Docker version 20.10.8, build 3967b7d

最新版 docker-compose のインストール

apt でインストールした docker-compose は、バージョンが古くてビルドができない場合があるため、 最新版のdocker-compose を同じかどうかを確認します。

docker-compose バージョン確認

docker-compose のバージョンを確認します。

$ apt list | grep docker-compose
docker-compose/focal 1.25.0-1 all

docker-composeの版数が同じであれば、そのままインストールします。

$ sudo apt install docker-compose
$ docker-compose --version

既存の docker-compose 削除

apt からインストールした場合、remove オプションで削除します。

$ sudo apt remove docker-compose

直接インストールした場合、 本体はリネームし、シンボリックリンクのみを削除します。 版数は、自分の環境に合わせて変更してください。

$ sudo mv /usr/local/bin/docker-compose /usr/local/bin/docker-compose.1.29.2
$ sudo rm /usr/bin/docker-compose

docker-compose V2 インストール

最新版の docker-compose v2GitHub で確認します。 現時点の最新版 v2.10.0 を指定します。 このコマンドは上書き可能なので、最新リリース後に download/v数値 を最新の数値に変更して実行してください。

$ sudo curl -L "https://github.com/docker/compose/releases/download/v2.10.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/libexec/docker/cli-plugins/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 24.5M  100 24.5M    0     0  4042k      0  0:00:06  0:00:06 --:--:-- 5628k

次に、シンボリックを作っていきます。こちらは一度限りです。

$ sudo chmod +x /usr/libexec/docker/cli-plugins/docker-compose
$ sudo ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/bin/docker-compose

正常にインストールできたことを確認します。

$ docker-compose --version
Docker Compose version v2.10.0

プロキシ環境の場合、環境変数にプロキシを設定していても、curlが失敗することがありました。 もし、失敗する場合、proxy オプション -x [http://proxy-server](http://proxy-server/):port を付けて実行してみてください。

プロキシ設定(プロキシ環境のみ)

エディタで/etc/default/dockerを開きます。

$ sudo vi /etc/default/docker

最終行にプロキシの情報を追加します。

# Set Proxy
export http_proxy='http://<user_id>:<password>@<host>:<port>'
export HTTP_PROXY="${http_proxy}"
export https_proxy="${http_proxy}"
export HTTPS_PROXY="${http_proxy}"
export no_proxy='127.0.0.1,localhost'
export NO_PROXY="${no_proxy}"

認証プロキシでユーザIDやパスワードに @ が含まれる場合、 URLエンコードする必要があります。 @%40に置き換え てください。

(例)tabito@xxxxx.com → tabito%40xxxxx.com

iptable をレガシーへ切り替える

iptable の設定がレガシーになっていないと、Docker サービスが起動したように見えて、 実際にステータスを確認すると起動できていない現象が発生します。

$ sudo service docker start
 * Starting Docker: docker                        [ OK ]
$ service docker status
 * Docker is not running   ※ 起動していない

個人的に Ubuntu 20.04 は大丈夫で、22.04 で発生しました。 しかし、環境によっては 20.04 でも発生するようです。

強制実行

面倒くさい人は、以下のコマンドを実行することで切り替えることができます。

$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

確認しながら切り替える

以下のコマンドで iptable の状況を確認・切り替えることができます。 レガシーになっていれば、そのまま Enter キーを押して終了します。 レガシーになっていなければ、レガシーの番号を指定して切り替えてください。

例はレガシーのため、そのまま Enter キーを押して終了します。

$ sudo update-alternatives --config iptables
There are 2 choices for the alternative iptables (providing /usr/sbin/iptables).

  Selection    Path                       Priority   Status
------------------------------------------------------------
* 0            /usr/sbin/iptables-legacy   20        auto mode
  1            /usr/sbin/iptables-legacy   20        manual mode
  2            /usr/sbin/iptables-nft      10        manual mode

Press <enter> to keep the current choice[*], or type selection number:

同様に IPv6 用も変更します。 例はレガシーのため、そのまま Enter キーを押して終了します。

$ sudo update-alternatives --config ip6tables
There are 2 choices for the alternative ip6tables (providing /usr/sbin/ip6tables).

  Selection    Path                        Priority   Status
------------------------------------------------------------
* 0            /usr/sbin/ip6tables-legacy   20        auto mode
  1            /usr/sbin/ip6tables-legacy   20        manual mode
  2            /usr/sbin/ip6tables-nft      10        manual mode

Press <enter> to keep the current choice[*], or type selection number:

サービス起動

Dockerサービスを起動します。

$ sudo service docker start

Dockerサービスが正常に動作していることを確認します。

$ service docker status
 * Docker is running

プロキシ確認(プロキシ環境のみ)

docker infoコマンドの実行結果にプロキシ情報が表示されることを確認します。

$ docker info | grep -i proxy
 HTTP Proxy: http://<user_id>:<password>@<host>:<port>
 HTTPS Proxy: http://<user_id>:<password>@<host>:<port>
 No Proxy: 127.0.0.1,localhost

動作確認

お決まりの hello-world を実行します。ここでは、dockerコマンドにsudoを付ける必要があります。

$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:9ade9cc2e26189a19c2e8854b9c8f1e14829b51c55a630ee675a5a9540ef6ccf
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Dockerインストール後の設定

Dockerを便利に使うためには、インストール後にも設定が必要となります。

sudoを付けないでdockerコマンドを使う

dockerコマンドにはsudoが必要になります。セキュリティ等の理由がなければ、sudoを付けなくても動作するように変更しましょう。

まずは、dockerグループを確認します。

$ cat /etc/group|grep docker
docker:x:999:

dockerグループに現在のユーザを参加させます。

$ sudo usermod -aG docker $USER

この設定を有効にするために、一度ログアウトします。

$ logout

Dockerコンテナ内からインターネット環境にアクセスする

Dockerコンテナ内からインターネットにアクセスするため、daemon.jsonファイルを新規に作成します。

$ sudo vi /etc/docker/daemon.json

Google Public DNSを設定します。

{
  "dns": ["8.8.8.8","8.8.4.4"]
}

DNS設定を有効にするため、Dockerサービスを再起動します。

$ sudo service docker restart
 * Stopping Docker: docker                    [ OK ]
 * Starting Docker: docker                    [ OK ]

プロキシ設定(プロキシ環境のみ)

エディタで ~/.docker/config.json ファイルを開きます。

$ vi ~/.docker/config.json

"proxies" 以下の行を追加します。 ただし、"auths" と "proxies" の区切りにカンマ,が必要となるため、忘れずに追加してください。

{
        "auths": {
                "https://index.docker.io/v1/": {
                        "auth": "ZmprdXNhbm86MDA0ODMxNzhARko="
                }
        },    ※ 行末のカンマを忘れずに付けてください!
        "proxies": {
                "default": {
                        "httpProxy": "http://<user_id>:<password>@<host>:<port>",
                        "httpsProxy": "http://<user_id>:<password>@<host>:<port>",
                        "noProxy": "127.0.0.1,localhost"
                }
        }
}

インターネットへの接続確認

インターネットの接続を確認するため、alpine Linuxをインストールし、akpでアップデートできるかを確認します。

$ docker run -it alpine /bin/ash
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
a0d0a0d46f8b: Pull complete
Digest: sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
Status: Downloaded newer image for alpine:latest
/ # apk update
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
v3.14.2-68-gbf3cc5c973 [https://dl-cdn.alpinelinux.org/alpine/v3.14/main]
v3.14.2-67-gf34feae70e [https://dl-cdn.alpinelinux.org/alpine/v3.14/community]
OK: 14938 distinct packages available

プロキシ確認(プロキシ環境のみ)

プロキシが反映されていることを確認します。

/ # printenv | grep -i proxy
HTTPS_PROXY=http://<user_id>:<password>@<host>:<port>
HTTP_PROXY=http://<user_id>:<password>@<host>:<port>
NO_PROXY=127.0.0.1,localhost
http_proxy=http://<user_id>:<password>@<host>:<port>
https_proxy=http://<user_id>:<password>@<host>:<port>
no_proxy=127.0.0.1,localhost
/ #

Docker Hubにログイン

dokcer login コマンドでDocker Hubへログインしてください。

$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: ユーザ名
Password:
WARNING! Your password will be stored unencrypted in /home/tabito/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

ログインしなくても、しばらくはイメージをダウンロードできますが、そのうちエラーが表示されます。 アカウントを未登録の方は、Docker Hub で無料アカウントを作成してください。

Windows起動時にdockerサービスが自動起動するようにする

ここでは、タスクスケジューラによる設定を記載します。

  1. タスクスケジューラを起動します。
  2. 「タスクの作成」をクリックし、全般タブ(デフォルト)を表示します。
  3. 名前(M)は「WSL2 Docker Service」、説明(D)に「WSL2(Ubuntu-20.04 Docker Serviceの自動起動」等、適当にラベリングしてください。
  4. 「ユーザがログオンしているかどうかにかかわらず実行する(W)」をチェックします。
  5. 「パスワードを保存しない(P)」をチェックします。
  6. 「トリガー」タブを選択し、「新規(N)」ボタンをクリックします。
  7. タスクの開始(G)で「スタートアップ時」を選択し、OKボタンをクリックします。
  8. 「操作」タブを選択し、「新規(N)」ボタンをクリックします。
  9. プログラム/スクリプト(P)に「wsl.exe」、引数の追加(オプション)(A)に「-u root — service docker start」と設定します。
  10. タスクを保存し、タスクスケジューラライブラリから「WSL2 Docker Service」を探して右クリックし、「実行する(R)」を選択します。
  11. WSL2 Ubuntu上で、「service docker status」で状態を確認します。起動(Docker is running)していればOKです。

まとめ

Docker Desktop for Windows V3とWSL2/Ubuntuの組合せで散々な目に会ったので、WSL2/Ubuntuに直接Dockerをインストールする方法を掲載しました。何かのお役に立てれば幸いです。

Docker Desktop for WindowsのようにGUIで管理したい方は、Portainerのインストールをお勧めします。 sabakunotabito.hatenablog.com

最後に参考サイトを掲載しておきます。

では、皆さん、よい旅を。

参考サイト

アプリ開発者にお薦め

インフラ構築者にお薦め(CentOS ベース)