python调用registry v2接口获取镜像Label

  1. 1. 背景
  2. 2. 获取docker token
  3. 3. 获取认证地址相关信息
  4. 4. 构造新的请求来获取token
  5. 5. 使用token来获取config信息

背景

来自一个奇奇怪怪的需求,要将一些changelog放在镜像的label中,姑且简单实现一下。

获取docker token

ps: 最简单的token获取方式,从.docker/config.json中拷贝。

开玩笑,需要docker token 可以使用如下命令生成

1
echo -n "$USERNAME:PASSWORD" | base64

获取认证地址相关信息

docker的客户端登陆使用的是比较简单的basic auth,简单发送请求获取Basic realm中提供的信息,他提供了docker认证地址和仓库的地址以及你申请的动作(pull,push 等)

1
2
3
4
5
auth_headers = {'Authorization': f'Basic {auth_token}', 'User-Agent': 'Docker-Client/19.03.2 (linux)'}
first_header = {"X-Docker-Token": "true"}
s = requests.get(registry_url, headers=first_header)
# 获取www-authenticate认证相关信息
parsed = www_authenticate.parse(s.headers['www-authenticate'])

构造新的请求来获取token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
auth_headers = {'Authorization': f'Basic {auth_token}', 'User-Agent': 'Docker-Client/19.03.2 (linux)'}        
if 'bearer' in parsed:
info = parsed['bearer']
scope = 'repository:' + f'{namespace}/{repo}' + ':' + ',*'
# 添加scope信息,包含命名空间/仓库:操作
url_parts = list(urlparse.urlparse(info['realm']))
query = urlparse.parse_qs(url_parts[4])
query.update({
'service': info['service'],
'scope': scope
})
url_parts[4] = urlencode(query, True)
url_parts[0] = 'https'
auth_url = urlparse.urlunparse(url_parts)
# 生成auth_url
token = f"Bearer {requests.get(auth_url,headers=auth_headers).json()['token']}"

使用token来获取config信息

1
2
3
4
5
6
7
new_header = {'Authorization': token, 'Accept': 'application/vnd.docker.distribution.manifest.v2+json'}
# 生成新的token,Accept用于简化返回信息,稍微提高效率
metadata = requests.get(f"{registry_url}/{namespace}/{repo}/manifests/{tag}", headers=new_header)
conf_digest = metadata.json()['config']['digest']
label = requests.get(f"{registry_url}/{namespace}/{repo}/blobs/{conf_digest}", headers=new_header).json()
msg = label['config']['Labels'][label]
return msg
完整代码点击这里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import requests
import www_authenticate
import urllib.parse as urlparse
from urllib.parse import urlencode
"""
本部分用于从镜像仓库获取镜像的提交信息。
提交信息通过docker镜像的label来加入镜像
调用Registry v2的api实现
参考链接:
https://docs.docker.com/registry/spec/api/
"""

auth_token = $YOUR_REGISTRY_URL
registry_url = $YOUR_AUTH_TOKEN
# 此部分从配置文件读取


def get_commit_msg(namespace, repo, tag,label):
try:
auth_headers = {'Authorization': f'Basic {auth_token}', 'User-Agent': 'Docker-Client/19.03.2 (linux)'}
first_header = {"X-Docker-Token": "true"}
s = requests.get(registry_url, headers=first_header)
# 获取www-authenticate认证相关信息
parsed = www_authenticate.parse(s.headers['www-authenticate'])
if 'bearer' in parsed:
info = parsed['bearer']
scope = 'repository:' + f'{namespace}/{repo}' + ':' + ',*'
# 添加scope信息,包含命名空间/仓库:操作
url_parts = list(urlparse.urlparse(info['realm']))
query = urlparse.parse_qs(url_parts[4])
query.update({
'service': info['service'],
'scope': scope
})
url_parts[4] = urlencode(query, True)
url_parts[0] = 'https'
auth_url = urlparse.urlunparse(url_parts)
# 生成auth_url
token = f"Bearer {requests.get(auth_url,headers=auth_headers).json()['token']}"
# 通过auth_url 来获取token
new_header = {'Authorization': token, 'Accept': 'application/vnd.docker.distribution.manifest.v2+json'}
# 生成新的token,Accept用于简化返回信息,稍微提高效率
metadata = requests.get(f"{registry_url}/{namespace}/{repo}/manifests/{tag}", headers=new_header)
conf_digest = metadata.json()['config']['digest']
label = requests.get(f"{registry_url}/{namespace}/{repo}/blobs/{conf_digest}", headers=new_header).json()
msg = label['config']['Labels'][label]
return msg
except Exception as e:
print(e)