Docker は様々な仮想マシンを用いるためのソフトです。この様々な仮想マシンは自分で作るのみでなく DockerHub というところに大量に置かれています。この DockerHub から仮想マシン定義であるイメージを取得するのが常道なのですが、この DockerHub には以下のレートリミットがかかっており、過剰なイメージのダウンロードはできません。もし無制限にするならば課金の必要があります。
Docker Hub
Download rate limit | Docker Documentation
具体的なレートリミットは次のアカウントの内容説明にあります。この記事を作った時点では以下です。
Docker Pricing & Monthly Plan Details | Docker
アカウント種類 | レートリミット |
---|---|
匿名アカウント | 100回 / 6時間 |
無料アカウント | 200回 / 6時間 |
Pro | 5000回 / 1日 |
Team | 5000回 / 1日 この制限より更に上の制限を購入可能 |
Pro | 5000回 / 1日 この制限より更に上の制限を購入可能 |
制限があるとはいえ、個人で使うならば無料アカウントどころか匿名アカウントでも十分なくらいです(匿名アカウントはネットワーク単位で匿名ですので大人数で匿名で Docker を使う状況は足りなくなるやも)。とはいえレートリミットの残量が気になる時もあります。何がしかの理由で大量にダウンロードし、いざという時にダウンロードし過ぎと DockerHub に拒否される様な状況が起こると面倒なことになります。先述の Download rate limit のページにある API の利用によって具体的な残量を知れます。
jq と curl が使える Linux マシンならばページにある次の 2 コマンドで十分です。
TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token) curl --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest
このレスポンスが次の様になっており、レートリミット最大値(ratelimit-limit)とその残量(ratelimit-remaining)を知れます。
HTTP/1.1 200 OK content-length: 2782 content-type: application/vnd.docker.distribution.manifest.v1+prettyjws docker-content-digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx docker-distribution-api-version: registry/2.0 etag: "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" date: Wed, 12 Jan 2022 07:38:29 GMT strict-transport-security: max-age=31536000 ratelimit-limit: 100;w=21600 ratelimit-remaining: 80;w=21600 docker-ratelimit-source: 000.000.000.000
よくある Docker 実行環境ならばこれで良いのですが Windows であったり、jq をインストールするのに許しが必要で申請が手間だったりする環境があります。そういった時、何がしかの代替手段が欲しくなります。Node.js を使って Docker のレートリミット残量を知るスクリプトは次で書けます。実行環境は Node.js 14.17.3 です。 https モジュールの基本機能しか使っていないので結構広い環境で使えそうな気がします。
const https = require('https'); // Node 組み込みの https モジュール でトークン取得 API を叩く https.get( 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull', (res) => { // トークン取得 API 結果をコールバックで処理 res.on('data', (d) => { // トークン取得 API のレスポンスからトークン部を抜き出し const token = JSON.parse(d.toString()).token; // トークン取得APIの結果を受けて認証付きでレートリミット確認APIを実行 https.get( `https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest`, { method: 'HEAD', headers: { Authorization: `Bearer ${token}`, }, }, (res) => { // 知りたい内容はヘッダーに格納されて送られてくるので次の様にレスポンスのヘッダーを表示 console.log(res.headers); } ); }); } ); /* PS C:\xxx> node xxx.js { 'content-length': '2782', 'content-type': 'application/vnd.docker.distribution.manifest.v1+prettyjws', 'docker-content-digest': 'sha256:xxxx', 'docker-distribution-api-version': 'registry/2.0', etag: '"sha256:xxxx"', date: 'Wed, 12 Jan 2022 08:15:01 GMT', 'strict-transport-security': 'max-age=31536000', 'ratelimit-limit': '100;w=21600', 'ratelimit-remaining': '80;w=21600', 'docker-ratelimit-source': '000.000.000.000', connection: 'close' } */
ヘッダーが実質的なレスポンスのボディのため少々奇妙なコードですが例の様に結果を得られます。