TL; DR
答えは、docker
コマンドを実行するOS/ユーザ です。
より詳細な仕組みを知りたい方は以下を読んでください。
dockerコマンドは3種類ある
はじめに docker
コマンドは一つでないという話からはじめます。
ホストOSがLinux以外の場合、
dockerデーモンは仮想OS (macOSならHyperKit, WindowsならHyper-VまたはWSL2)上のLinuxで実行されています。
dockerコマンドは以下の三ヶ所から呼び出すことができます
- ホストOS
- 仮想OS
- コンテナ内部(ソケットマウント方式でdocker in dockerしている場合)
それぞれで実行されるdockerコマンドは実行されるOS上の普通のプログラムで、
dockerデーモンに対して通信をすることで実際のコンテナを実行します。
つまり、ホストOS上のdocker
コマンドと仮想OS上のdocker
コマンドは
全く別のバイナリということになります。(当たり前ですが)
docker login
docker login
はDocker HubやGCR, ECRなどのコンテナレジストリにログインするコマンドです。
ログインすることで、コンテナのpushやprivate レポジトリからのpullができるようになります。
さてログイン処理はどのように実行されるのでしょうか。筆者が調べた限りでは以下のような仕様のようです。
- (dockerデーモンではなく)dockerコマンドを実行したOSで実行される
- 認証情報(の設定)は
$HOME/.docker/config.json
に保存される。
したがって以下のことに気をつける必要があります。
-
ホストOS上でログイン状態は、root以外の別のユーザあるいは仮想OS上あるいはコンテナ内のdockerからは利用できません。
- ホストOS上で
docker login
しておいても、 仮想OS上のdockerからその認証情報を用いたpush/pullはできません。 - ホストOS上の別ユーザからもpush/pullはできません。(例外として
sudo
によるpush/pullは可能です。これはsudo
では環境変数(特に$HOME
)がユーザのものが引き継がれ、かつrootは~/.docker/config.json
が読み出し可能だからです。)- OK:
sudo docker pull ${private_image}
- NG:
echo docker pull ${private_image} | sudo su root
- OK:
- ホストOS上で
-
docker login
コマンドをsudo
で実行すると$HOME/.docker/config.json
の所有者がrootとなります。
(ドキュメントにはsudo docker login
した場合は/root/.docker/config.json
に保存されると書いてありますが、少なくともmacOS上では$HOME/.docker/config.json
に保存されることを確認しました。)
credential helper
docker login
の認証状態をいい感じに管理してくれるのがcredential helperと呼ばれるプログラムです。
これを使うと、docker login
のパスワードをOSのキーチェーンツールに保存したり、
AWSやGCPの認証コマンドを用いる事ができます。
~/.docker/config.json
に設定を書くと利用できます。以下の例ではデフォルトのhelperとして
desktop
を使い、gcr.io
など特定のサイトでは gloud
を使うという設定です。
{
"credsStore": "desktop",
"credHelpers": {
"asia.gcr.io": "gcloud",
"eu.gcr.io": "gcloud",
"gcr.io": "gcloud",
"marketplace.gcr.io": "gcloud",
"staging-k8s.gcr.io": "gcloud",
"us.gcr.io": "gcloud"
}
}
credential helperはdocker-credential-
のprefixがついた普通のプログラムです。
$ docker-credential-
docker-credential-desktop docker-credential-gcloud docker-credential-osxkeychain
仕組みも非常に簡単で、引数にget
、標準入力にログインしたいレポジトリのURLを渡すと認証情報を返してくれます。
$ echo https://gcr.io | docker-credential-gcloud get
{
"Secret": "{ここは認証トークンなのでマスクしました}",
"Username": "_dcgcloud_token"
}
したがって、こちらの設定・状態もdockerコマンドを実行するOSやユーザごとに独立しています。
docker in dockerで認証情報を共有したい場合
上記の理由から、dockerの認証情報は実行OS,ユーザごとに独立であるという事がわかりました。
したがって、docker in dockerを実現したい場合に、ホストLinuxの認証情報を共有した場合は
以下のようにする必要があります。
- コンテナ実行時に
$HOME
環境変数を適切に設定します。 - credential helperコンテナ内部のPATH上にマウントします
-v $(which docker-credential-gloud:/usr/local/bin/docker-credential-gcloud)
- ホストOSの
$HOME/.docker/config.json
をコンテナ内にマウントします。 - credential helperが使う認証情報をコンテナ内部からアクセスできるようにします。(環境変数で渡すか鍵ファイルをマウントします)