IBM Cloud Privateのプライベートレジストリに登録されているイメージをCLIで確認する方法と削除する方法のメモ。ICP 2.1.0.3 FP1と3.1.0で確認。
以下の方法がありそう。
- kubectl
- イメージ管理API
- Docker Registry API
特定のタグを削除したい場合はDocker Registry APIが必要と思われる。
いずれの方法の場合もソフト削除となり、ファイルの実体を削除するには別途ガベッジコレクションが必要。
(2.1.0.3)consoleからのイメージの削除
(3.1.0)consoleからのイメージの削除
Garbage collection
kubectl
イメージの確認
ICP独自のCRDであるkind: Image
が定義されており、kubectl
コマンドでイメージを確認できる。
$ kubectl get images --all-namespaces
NAMESPACE NAME AGE
default infra-test-18.0.0.3 26d
ibmcom alertmanager-amd64 26d
ibmcom calico-cni-amd64 26d
ibmcom calico-kube-controllers-amd64 26d
(省略)
ibmcom usncrawler-amd64 26d
ibmcom vulnerability-annotator-amd64 26d
sugi alpine 13d
sugi busybox 13d
sugi liberty-test 16d
sugi nginx 13d
sugi stress 13d
sugi ubuntu 13d
sugi websphere-liberty 16d
$
表示されているのはイメージではなくリポジトリであり、リポジトリに複数のタグがあっても確認できない。
$ kubectl get images -n sugi websphere-liberty -o yaml
apiVersion: icp.ibm.com/v1
kind: Image
metadata:
creationTimestamp: 2018-11-26T07:29:24Z
generation: 1
name: websphere-liberty
namespace: sugi
resourceVersion: "1953143"
selfLink: /apis/icp.ibm.com/v1/namespaces/sugi/images/websphere-liberty
uid: 0002ff21-f14d-11e8-a626-fa163e2fb2ab
spec:
scope: namespace
$
イメージの削除
削除コマンドで特定のタグを指定できないため、リポジトリ全体を削除することになる。
kubectl delete image -n sugi websphere-liberty
イメージ管理API
(2.1.0.3)イメージ管理 API
(3.1.0)イメージ管理 API
トークンの取得
以下のリンク先に従いトークンを取得して変数に入れておく。
(2.1.0.3)コンポーネント API コマンドまたは管理 API コマンドを実行するための準備
(3.1.0)コンポーネント API コマンドまたは管理 API コマンドを実行するための準備
bx pr
の場合は以下。
# 2.1.0.3
bx pr login -a https://mycluster.icp:8443 --skip-ssl-validation
ID_TOKEN=$(LANG=C bx pr tokens | grep "ID token:" | awk '{print $3}')
# 3.1.0
# cloudctl login -a https://mycluster.icp:8443 --skip-ssl-validation
# ID_TOKEN=$(LANG=C cloudctl tokens | grep "ID token:" | awk '{print $3}')
curl
でユーザーとパスワードを直接渡す場合は以下。レスポンスのjsonをjq
コマンドで処理する。
USERNAME="admin"
PASSWORD="admin"
ID_TOKEN=$(curl -s -k -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" \
-d "grant_type=password&username=${USERNAME}&password=${PASSWORD}&scope=openid" \
https://mycluster.icp:8443/idprovider/v1/auth/identitytoken | jq -r '.id_token')
イメージの確認
Authorization: Bearer $ID_TOKEN
ヘッダをつけてAPIを叩いてレスポンスのjsonをjq
コマンドで整形する。
curl -s -k -H "Authorization: Bearer ${ID_TOKEN}" \
https://mycluster.icp:8443/image-manager/api/v1/repositories \
| jq -r '.repositories[] | .name + " (" + .scope + ")"'
root@icpcemng:~# curl -s -k -H "Authorization: Bearer ${ID_TOKEN}" \
> https://mycluster.icp:8443/image-manager/api/v1/repositories \
> | jq -r '.repositories[] | .name + " (" + .scope + ")"'
default/infra-test-18.0.0.3 (namespace)
ibmcom/alertmanager-amd64 (namespace)
ibmcom/calico-cni-amd64 (namespace)
ibmcom/calico-kube-controllers-amd64 (namespace)
(省略)
ibmcom/usncrawler-amd64 (namespace)
ibmcom/vulnerability-annotator-amd64 (namespace)
sugi/alpine (namespace)
sugi/busybox (namespace)
sugi/nginx (namespace)
sugi/stress (namespace)
sugi/ubuntu (namespace)
sugi/websphere-liberty (namespace)
$
(補足)
image-managerのパッチを適用したところ、イメージ管理APIでタグがnull
になるようになってしまい、以下のようにタグも含めて表示することができなくなった。3.1.0も同様。image-managerのバグ?
curl -s -k -H "Authorization: Bearer ${ID_TOKEN}" \
https://mycluster.icp:8443/image-manager/api/v1/repositories \
| jq -r '.repositories[] | .name + ":" + .tags[].name + " (" + .scope + ")"'
$ curl -s -k -H "Authorization: Bearer ${ID_TOKEN}" https://mycluster.icp:8443/image-manager/api/v1/repositories | jq -r '.repositories[] | .name + ":" + .tags[].name + " (" + .scope + ")"'
higu/mysql/mysql-server:ICP (global)
higu/zabbix/zabbix-agent:ICP (global)
higu/zabbix/zabbix-server-mysql:ICP (global)
higu/zabbix/zabbix-web-nginx-mysql:ICP (global)
nogu/ibmcom/db2express-c:ICP (global)
nogu/snoop:ICP (namespace)
sugi/websphere-liberty:beta (namespace)
sugi/websphere-liberty:kernel (namespace)
wordpressdemo/mysql/mysql-server:ICP (global)
wordpressdemo/wordpress:ICP (global)
$
イメージの削除
この方法の場合も、削除は特定のタグのイメージではなくリポジトリ全体となる。ちなみにブラウザでICPコンソールから削除する場合も同様にリポジトリごと削除になる。
curl -k -XDELETE -H "Authorization:Bearer ${ID_TOKEN}" \
https://mycluster.icp:8443/image-manager/api/v1/repositories/sugi/ubuntu
Docker Registry API
(2.1.0.3)Docker Registry V2 API
(3.1.0)Docker Registry V2 API
必要なトークンの確認
Docker Registry APIではイメージ管理APIで使用したトークンとは別のトークンが必要になる。トークンはイメージ管理APIで取得するが、スコープを指定する必要がある。
トークンなしでAPIを叩いてみると、Unauthorizedとなる。このとき、レスポンスのWww-Authenticate
ヘッダからAPIの実行に必要なトークンのスコープが確認できる。
curl -v -s -k https://mycluster.icp:8500/v2/_catalog 2>&1 | grep -i Www-Authenticate
$ curl -v -s -k https://mycluster.icp:8500/v2/_catalog 2>&1 | grep -i Www-Authenticate
< Www-Authenticate: Bearer realm="https://mycluster.icp:8600/image-manager/api/v1/auth/token",service="token-service",scope="registry:catalog:*"
$
この場合はscope="registry:catalog:*"
のトークンが必要なことがわかる。
トークンの取得
イメージ管理APIでscope="registry:catalog:*"
を指定してトークンを取得する。
bx pr tokens
等で取得したIDトークンを使ってJWTトークンを取得する。
CATALOG_TOKEN=$(curl -s -k -H "Authorization: Bearer ${ID_TOKEN}" \
"https://mycluster.icp:8443/image-manager/api/v1/auth/token?service=token-service&scope=registry:catalog:*" \
| jq -r '.token')
ユーザーとパスワードを直接渡してJWTトークンを取得することもできる。
USERNAME="admin"
PASSWORD="admin"
CATALOG_TOKEN=$(curl -s -k -u ${USERNAME}:${PASSWORD} \
"https://mycluster.icp:8443/image-manager/api/v1/auth/token?service=token-service&scope=registry:catalog:*" \
| jq -r '.token')
イメージの確認
トークンを使ってリポジトリを表示するAPIを叩く。ICPでは結果がデフォルトで100で制限されるようなので、"n=10000"を指定している。
curl -s -k -H "Authorization: Bearer ${CATALOG_TOKEN}" \
"https://mycluster.icp:8500/v2/_catalog?n=10000" | jq -r '.repositories[]'
$ curl -s -k -H "Authorization: Bearer ${CATALOG_TOKEN}" \
> "https://mycluster.icp:8500/v2/_catalog?n=10000" | jq -r '.repositories[]'
default/infra-test-18.0.0.3
ibmcom/alertmanager
ibmcom/alertmanager-amd64
ibmcom/calico-cni
ibmcom/calico-cni-amd64
(省略)
ibmcom/usncrawler
ibmcom/usncrawler-amd64
ibmcom/vulnerability-annotator
ibmcom/vulnerability-annotator-amd64
sugi/alpine
sugi/busybox
sugi/liberty-test
sugi/nginx
sugi/stress
sugi/ubuntu
sugi/websphere-liberty
$
(補足)
イメージ管理APIと同じリストを返していないようだ。-amd64
のついたイメージはイメージ管理APIからは返されなかった。またイメージ管理APIから削除したsugi/ubuntu
が残っている。
特定のリポジトリのイメージのタグは確認するAPIは、別のスコープのトークンが必要になる。
REPO_NAME="sugi/alpine"
curl -v -s -k -H "Authorization: Bearer ${CATALOG_TOKEN}" \
"https://mycluster.icp:8500/v2/${REPO_NAME}/tags/list" 2>&1 | grep -i Www-Authenticate
$ REPO_NAME="sugi/alpine"
$ curl -v -s -k -H "Authorization: Bearer ${CATALOG_TOKEN}" \
> "https://mycluster.icp:8500/v2/${REPO_NAME}/tags/list" 2>&1 | grep -i Www-Authenticate
< Www-Authenticate: Bearer realm="https://mycluster.icp:8600/image-manager/api/v1/auth/token",service="token-service",scope="repository:sugi/alpine:pull",error="insufficient_scope"
$
scope="repository:sugi/alpine:pull"
のトークンが必要なことがわかるので、このトークンを取得する。
REPO_TOKEN=$(curl -s -k -u ${USERNAME}:${PASSWORD} \
"https://mycluster.icp:8443/image-manager/api/v1/auth/token?service=token-service&scope=repository:${REPO_NAME}:pull" \
| jq -r '.token')
タグのリストを実行。
curl -s -k -H "Authorization: Bearer ${REPO_TOKEN}" \
"https://mycluster.icp:8500/v2/${REPO_NAME}/tags/list" | jq -r '.tags[]'
$ curl -s -k -H "Authorization: Bearer ${REPO_TOKEN}" \
> "https://mycluster.icp:8500/v2/${REPO_NAME}/tags/list" | jq -r '.tags[]'
3.8
3.7
3.6
$
(参考)DockerHubに対しては以下でタグが取得できる。APIのURLが少し違う。
curl -s -k 'https://hub.docker.com/v2/repositories/library/websphere-liberty/tags/?page_size=10000' \
| jq -r '.results[].name'
$ curl -s -k 'https://hub.docker.com/v2/repositories/library/websphere-liberty/tags/?page_size=10000' \
> | jq -r '.results[].name'
javaee7
18.0.0.3-javaee7
webProfile7
18.0.0.3-webProfile7
(省略)
8.5.5.6-common
8.5.5.6-kernel
$
イメージの削除
特定のタグを削除する場合は、削除はscope="repository:kiban/alpine:*"
のJWTトークンが必要。先ほど取得したpull
ではなく*
が必要なため再取得する。
REPO_TOKEN=$(curl -s -k -u ${USERNAME}:${PASSWORD} \
"https://mycluster.icp:8443/image-manager/api/v1/auth/token?service=token-service&scope=repository:${REPO_NAME}:*" \
| jq -r '.token')
削除の場合はタグを指定するのではなくダイジェストを指定する必要がある。
タグを指定してmanifestを取得し、そこからダイジェストを取得する。このときAccept: application/vnd.docker.distribution.manifest.v2+json
ヘッダを付ける必要があり、また、ダイジェストはレスポンス本文にはなく、ヘッダにある。
TAG_NAME="3.6"
DIGEST=$(curl -s -k -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Bearer ${REPO_TOKEN}" \
"https://mycluster.icp:8500/v2/${REPO_NAME}/manifests/${TAG_NAME}" -v 2>&1 \
| grep -i Docker-Content-Digest | awk '{print $3}')
ダイジェストを指定して削除する。変数に改行が入ってしまってcurlが失敗したので変数展開で改行を除去している。
curl -k -XDELETE -H "Authorization: Bearer ${REPO_TOKEN}" \
"https://mycluster.icp:8500/v2/${REPO_NAME}/manifests/${DIGEST%$'\r'}"
追記
skopeo
も使えました。
$ skopeo inspect docker://mycluster.icp:8500/sugi/stress:1.0 --tls-verify=false --creds=admin:admin
{
"Name": "mycluster.icp:8500/sugi/stress",
"Digest": "sha256:22455cc70fd015398d5417e1af47412a204d36fc7671e6de8d432f6e6040cce1",
"RepoTags": [
"1.0"
],
"Created": "2019-03-15T09:46:49.1182882Z",
"DockerVersion": "18.09.2",
"Labels": null,
"Architecture": "amd64",
"Os": "linux",
"Layers": [
"sha256:898c46f3b1a1f39827ed135f020c32e2038c87ae0690a8fe73d94e5df9e6a2d6",
"sha256:63366dfa0a5076458e37ebae948bc7823bab256ca27e09ab94d298e37df4c2a3",
"sha256:041d4cd74a929bc4b66ee955ab5b229de098fa389d1a1fb9565e536d8878e15f",
"sha256:6e1bee0f8701f0ae53a5129dc82115967ae36faa30d7701b195dfc6ec317a51d",
"sha256:ebd146c9c88d8bf9326e58c0454b18a1137e8b0e30bd8f032a444176f43ba956"
]
}
$ skopeo delete docker://mycluster.icp:8500/sugi/stress:1.0 --tls-verify=false --creds=admin:admin
$ skopeo inspect docker://mycluster.icp:8500/sugi/stress:1.0 --tls-verify=false --creds=admin:admin
FATA[0000] Error reading manifest 1.0 in mycluster.icp:8500/sugi/stress: manifest unknown: manifest unknown
$