前置き
掲題の件について、いろいろな記事で既出ではありますが、いくつかのオプション指定をできるようにして、Dockerホスト上でdockerコマンドのように簡単に利用できるようにしたので、そのメモです。
正直、公式のdockerコマンドの一部に含めてほしい。。。
必要なもの
以下、DockerホストOS上にインストールされていない場合はyum、apt、homebrewなどで適宜インストールしてください。
- curl(普通は入っている)
- jq
※実行シェルはCentOS7.6(bash)を前提としています。
おうちのDocker for Macでも動作確認できています。
他のOSでも動くとは思いますが、CoreOSとかは試していないので指摘があれば改造を検討します。。。
使い方
GitHubに置いたスクリプトをPATHの取った場所に置くとか、aliasを作ったりするとか適宜実行できる環境においてください。
なお、レスポンスのJSONを解析する過程で、/tmp配下に一時ディレクトリやファイルを作成していますので、/tmp配下の書き込み権限が必要です。
※"/tmp"は環境変数${TMPDIR}
で変更可能です。
シンプル実行
結果からdocker pull
コマンドの引数に流せるように{イメージ名}:{タグ名}
の形式で出力するようにしてあります。
[docker@docker-host ~]$ docker-tags centos
centos:latest
centos:centos7.6.1810
centos:centos7.5.1804
centos:centos7.4.1708
centos:centos7.3.1611
centos:centos7.2.1511
centos:centos7.1.1503
centos:centos7.0.1406
centos:centos7
centos:centos6.9
centos:centos6.8
centos:centos6.7
centos:centos6.6
centos:centos6.10
centos:centos6
centos:centos5.11
centos:centos5
centos:7.6.1810
centos:7.5.1804
centos:7.4.1708
centos:7.3.1611
centos:7.2.1511
centos:7.1.1503
centos:7.0.1406
centos:7
centos:6.9
centos:6.8
centos:6.7
centos:6.6
centos:6.10
centos:6
centos:5.11
centos:5
[docker@docker-host ~]$
詳細(表形式出力)
詳細表示版は、サイズと最終更新日時を付けて表形式(tsv)で出力するようにしています。
[docker@docker-host ~]$ docker-tags --detail --reverse --output-file ${HOME}/result.tsv centos
[docker@docker-host ~]$ cat ${HOME}/result.tsv
tag size last_updated
5 87342331 2017-04-06T20:16:25.879532Z
5.11 87094724 2017-04-06T20:17:31.013272Z
6 69835815 2019-05-11T01:12:16.895622Z
6.10 69800401 2019-05-11T01:12:19.263911Z
6.6 73689716 2019-05-11T01:12:22.647196Z
6.7 67814264 2019-05-11T01:12:25.385696Z
6.8 70226281 2019-05-11T01:12:27.462311Z
6.9 70181649 2019-05-11T01:12:31.078690Z
7 75403831 2019-05-11T01:12:34.106340Z
7.0.1406 76789367 2019-05-11T01:12:38.015816Z
7.1.1503 77375353 2019-05-11T01:12:40.019129Z
7.2.1511 71553381 2019-05-11T01:12:43.286737Z
7.3.1611 72170894 2019-05-11T01:12:45.185299Z
7.4.1708 73358335 2019-05-11T01:12:49.971649Z
7.5.1804 74692733 2019-05-11T01:12:52.848602Z
7.6.1810 75161332 2019-05-11T01:12:56.206570Z
centos5 87342331 2017-04-06T20:16:24.015937Z
centos5.11 87094724 2017-04-06T20:17:29.333542Z
centos6 69835815 2019-05-11T01:12:57.598615Z
centos6.10 69800401 2019-05-11T01:13:00.432911Z
centos6.6 73689716 2019-05-11T01:13:03.407549Z
centos6.7 67814264 2019-05-11T01:13:06.308806Z
centos6.8 70226281 2019-05-11T01:13:08.989816Z
centos6.9 70181649 2019-05-11T01:13:10.722926Z
centos7 75403831 2019-05-11T01:13:15.423566Z
centos7.0.1406 76789367 2019-05-11T01:13:18.660373Z
centos7.1.1503 77375353 2019-05-11T01:13:22.710971Z
centos7.2.1511 71553381 2019-05-11T01:13:26.586999Z
centos7.3.1611 72170894 2019-05-11T01:13:27.403263Z
centos7.4.1708 73358335 2019-05-11T01:13:29.557664Z
centos7.5.1804 74692733 2019-05-11T01:13:34.033772Z
centos7.6.1810 75161332 2019-05-11T01:13:36.617627Z
latest 75403831 2019-05-11T01:13:40.692601Z
[docker@docker-host ~]$
実行オプション一覧
-
-o
or--output-file
デフォルトでは標準出力に結果を出力しますが、このオプションを指定するとオプションで指定したファイルに出力します。(結果のみ) -
-r
or--reverse
デフォルトではタグ名の降順に出力しますが、このオプションを指定するとタグ名の昇順になります。 -
-d
or--detail
デフォルトでは{イメージ名}:{タグ名}
の形式で出力しますが、このオプションを付けると、タグの名前、イメージサイズ、最終更新日時をtsv形式で出力します。 -
-v
or--verbose
APIの処理性能上、タグ数が多い場合、待たされることがあるので、curlコマンドの処理経過などを表示するためのオプションです。 -
-h
or--help
コマンドの実行方法(Usage)を表示します。
備忘録:スクリプトの処理概要
全体像は、GitHubを参照ください。
DockerHubのAPIからタグ一覧を取得する。
以下のURLにGETリクエストを投げることでタグの一覧をJSON形式で取得できます。
特に認証や特殊ヘッダーを不要する必要はありません。
https://registry.hub.docker.com/v2/repositories/{USER}/{IMAGE}/tags/
※公式イメージの場合、ユーザ名?の部分に相当する部分がlibrary
になるようなので以下のように処理をしています。
TARGET_URL="https://registry.hub.docker.com/v2/repositories"
if [[ ! "${IMAGE}" =~ ^.+/.+$ ]]; then
# For official images.
TARGET_URL="${TARGET_URL}/library"
fi
TARGET_URL="${TARGET_URL}/${IMAGE}/tags/"
公式イメージ以外の場合は引数自体を"gitbucket/gitbucket"みたいに指定してください。
DockerHubのタグリストAPIのレスポンス
レスポンスは以下のような形式になっています。
ちゃんと調べたわけではないですが、ざっくりいうと、
- count:全体タグの件数
- next:次のページのエンドポイントURL(クエリパラメータで
?page={ページ番号}
が付いただけ - previous:2ページ目以降の場合の前のページのURL
- results:タグ情報リスト
- name: タグの名前
- full_size:当該タグ全体のイメージ
- images:ツリー構造になっている子イメージ?とかのことだと思われます。(
docker iamges -a
で表示されるやつ?) - last_updated:とうがいタグの最終更新日時(nullのケースもありました)
その他は特に今回は利用しないので無視します。。。
{
"count": 33,
"next": "https://registry.hub.docker.com/v2/repositories/library/centos/tags/?page=2",
"previous": null,
"results": [
{
"name": "latest",
"full_size": 75403831,
"images": [
{
"size": 75403831,
"architecture": "amd64",
"variant": null,
"features": null,
"os": "linux",
"os_version": null,
"os_features": null
},
{
"size": 76787221,
"architecture": "ppc64le",
"variant": null,
"features": null,
"os": "linux",
"os_version": null,
"os_features": null
},
{
"size": 75654099,
"architecture": "386",
"variant": null,
"features": null,
"os": "linux",
"os_version": null,
"os_features": null
},
{
"size": 74163767,
"architecture": "arm64",
"variant": "v8",
"features": null,
"os": "linux",
"os_version": null,
"os_features": null
},
{
"size": 70029389,
"architecture": "arm",
"variant": "v7",
"features": null,
"os": "linux",
"os_version": null,
"os_features": null
}
],
"id": 2107,
"repository": 54,
"creator": 7,
"last_updater": 1156886,
"last_updated": "2019-05-11T01:13:40.692601Z",
"image_id": null,
"v2": true
},
{
"name": "centos7.6.1810",
"full_size": 75161332,
"images": [
{
"size": 75161332,
"architecture": "amd64",
"variant": null,
"features": null,
"os": "linux",
"os_version": null,
"os_features": null
},
{
"size": 76454310,
"architecture": "ppc64le",
"variant": null,
"features": null,
"os": "linux",
"os_version": null,
"os_features": null
}
],
"id": 41612723,
"repository": 54,
"creator": 1156886,
"last_updater": 1156886,
"last_updated": "2019-05-11T01:13:36.617627Z",
"image_id": null,
"v2": true
},
・・・省略・・・
]
}
2ページ目以降の取得
前述の通り、一度のリクエストで全件取得できないため、レスポンスJSONのnext
が"null"になるまでループします。
# 先頭ページのURL定義
TARGET_URL="https://registry.hub.docker.com/v2/repositories"
if [[ ! "${IMAGE}" =~ ^.+/.+$ ]]; then
# For official images.
TARGET_URL="${TARGET_URL}/library"
fi
TARGET_URL="${TARGET_URL}/${IMAGE}/tags/"
PAGE_NO=1
# 次ページ(next)がnullになるまでループ。
while [ "${TARGET_URL}" != "null" ]; do
RESPONSE_BODY_FILE=${TMP_FILE_DIR}/RESBODY_PAGE_${PAGE_NO}.json
# Calling docker hub api.
if "${IS_VERBOSE}"; then
echo "Getting tag list from docker hub at page ${PAGE_NO}..."
fi
# ここでcurlコマンドでAPIから情報を取得します。
call_api ${TARGET_URL} ${RESPONSE_BODY_FILE}
# ここでjqコマンドでresults(タグ情報一覧)が取得できるかパースします。
JSON_FILE=${TMP_FILE_DIR}/RESULT_PAGE_${PAGE_NO}.json
jq -c '.results' ${RESPONSE_BODY_FILE} > ${JSON_FILE} 2>&1
STATUS=$?
if [ ${STATUS} -ne 0 ]; then
output_error "Failure parse response."
cat ${RESPONSE_BODY_FILE}
echo ""
_claen
exit ${STATUS}
fi
# レスポンスのresultsを全体処理結果ファイルにマージします。
if [ -f "${RESULT_JSON_FILE}" ]; then
# 2回目以降はjqコマンドでマージします。
mv -f "${RESULT_JSON_FILE}" "${RESULT_JSON_FILE}_org"
jq -s add "${RESULT_JSON_FILE}_org" "${JSON_FILE}" > "${RESULT_JSON_FILE}"
else
# 初回はリネームのみ。
mv ${JSON_FILE} ${RESULT_JSON_FILE}
fi
# レスポンスボディの`next`要素を取得します。
TARGET_URL=$(jq -r .next ${RESPONSE_BODY_FILE})
STATUS=$?
if [ ${STATUS} -ne 0 -o -z "${TARGET_URL}" ]; then
output_error "Failure getting next page url."
cat ${RESPONSE_BODY_FILE}
_claen
exit ${STATUS}
fi
PAGE_NO=$(echo ${TARGET_URL} | sed -e 's/^\(http.\+\)\(\?\)\(\page=\)\([[:digit:]]\+\)$/\4/')
# GNU系だと上の正規表現ではダメみたいなので以下に差し替えてください。
# PAGE_NO=$(echo ${TARGET_URL} | sed -E -e 's|^https?://.+\?page=([[:digit:]]+)$|\1|')
done
jsonデータの整形出力
↑の処理でマージし終わったresults(タグ情報一覧)をjqコマンドを利用して整形します。
細かい部分はスクリプト本体を見てもらうとして、以下の2パターンで解説。
シンプル表示の場合
jq -r 'sort_by(.name) | reverse | map_values(\"${IMAGE}:\"+.name) | .[]
- results[].nameでソートします。
- 降順の方がうれしいのでオプション指定がない場合は降順になるようにreverseを指定。
- タグ一覧を表示してどうしたいかというと
docker pull
したいことがおおいはずなので、docker pull ${image}:${tag}
にコピペしやすいようにmap_values
で"イメージ名:タグ名"となるように整形しています。 - 最後の
.[]
はテキスト出力用。
なお、-r
オプションはテキストのダブルクォーテーションの除去などを目的にしたものです。
詳細表示オプション付き(--detail)の場合
jq -r 'sort_by(.name) | reverse | map({tag: .name, size: .full_size, last_updated: .last_updated}) | .[] | [.tag, .size, .last_updated] | @tsv
- results[].nameでソートします。
- 降順の方がうれしいのでオプション指定がない場合は降順になるようにreverseを指定。(ここまではシンプル版と同じ)
- table変換する前に必要な要素のみを抜粋したオブジェクト配列型にmapで変換します。
タグの名前をname
⇒tag
,full_size
⇒size
に変換していますが、特に深い意味はありません。(こんなこともできるようという記録だと思ってください)
[
{
"name: "xxxx",
"full_size": 99999,
"last_updated": "2019-05-11T01:13:36.617627Z",
・・・その他要素は割愛・・・
},
・・・要素数分続く・・・
]
[
{
"tag: "xxxx",
"size": 99999,
"last_updated": "2019-05-11T01:13:36.617627Z"
},
・・・要素数分続く・・・
]
-
.[]
は変換した↑のものから配列として取り出す。(既に配列じゃないかという突っ込みがあると思いますが、jqコマンドの内部的には違う) -
[.tag, .size, .last_updated]
は後続の"@tsv"に渡すテーブルの列要素の一覧になります。 - 最後の
@tsv
でtsv形式にしてくれます。jqコマンドは他にも@csv
,@text
,@html
などの対応もありますが、csvかtsv以外はあまり有用な用途はわかりませんでした。