提供界面的镜像仓库可以选择 SUSE 的 Portus 和 VMware 的 Harbor。我选择的是 Harbor。其实一开始是倾向于 Portus 的,因为 Application tokens 功能看起来很有用,但是尝试部署时总是报错,Ruby 程序就是这么难搞。只好去尝试 Harbor。用 OIDC 登录时,有个 CLI 密码,类似 Application tokens 的功能,不必将个人密码写到 .docker/config.json
中去。本文记录安装及使用 Harbor(1.9.0) 遇到的一些问题。
Contents
安装
直接使用 helm 安装到 Kubernetes 集群中,首先准备好 Postgres 和 Redis,使用 kubedb,参考 使用 kubedb 管理数据库 一文。然后提前创建配置文件中指定的 postgres
数据库,可以用 pgAdmin
创建。
coreDatabase: "registry"
clairDatabase: "clair"
notaryServerDatabase: "notary_server"
notarySignerDatabase: "notary_signer"
使用 helm 安装 Harbor。
# 更新仓库,使用最新版
helm repo update
# 测试环境
helm install cr harbor/harbor --version 1.2.0 --namespace dev -f ./values-test.yaml
# 生产环境
helm install cr harbor/harbor --version 1.2.0 --namespace intra -f ./values.yaml
values.yaml
中,配置外部 Postgres 和 外部 Redis,例如:
database:
type: external
external:
host: "ha-postgres.demo.svc.cluster.local"
port: "5432"
username: "postgres"
password: "password"
coreDatabase: "registry"
clairDatabase: "clair"
notaryServerDatabase: "notary_server"
notarySignerDatabase: "notary_signer"
sslmode: "disable"
maxIdleConns: 50
maxOpenConns: 100
podAnnotations: {}
redis:
type: external
external:
host: "redis-quickstart.demo.svc.cluster.local"
port: "6379"
coreDatabaseIndex: "0"
jobserviceDatabaseIndex: "1"
registryDatabaseIndex: "2"
chartmuseumDatabaseIndex: "3"
password: ""
podAnnotations: {}
测试环境证书
顺便提一下测试环境自签名证书问题,需要在 docker 客户端导入 CA 证书,把CA放到/etc/pki/ca-trust/source/anchors
,在命令行运行/bin/update-ca-trust
,这样证书就导入到系统中去了。然后重启 docker daemon。
OIDC
参考 使用dex实现OIDC Provider 一文。注意 oidc scope 要填 profile
,否则获取不到用户名等信息。
- oidc供应商: 随便填 (dex)
- oidc endpoint: https://oidc.xxx.com
- oidc 客户端标识:和 无状态服务 oidc 的设置保持一致(Harbor)
- oidc 密码:和 无状态服务 oidc 的设置保持一致(Harbor)
- oidc scope:openid,offline_access,profile
问题记录
push失败排查
- 报错
denied: requested access to the resource is denied
,可能是因为仓库不存在,检查project/image:tag
是否正确 - 报错
blob upload invalid
,可能是因为 s3 上传失败,检查 s3 nginx代理的client_max_body_size
,设置为足够大的值,比如5000m
Redis Cluster报错
2019-09-19T15:28:15Z [DEBUG] [/common/dao/project.go:149]: sql:=select distinct p.project_id, p.name, p.owner_id,
p.creation_time, p.update_time from project as p where p.deleted=false order by p.name, param= []
2019/09/19 15:28:15 [I] [asm_amd64.s:1337] http server Running on http://:8080
2019/09/19 15:28:41 [E] [server.go:2774] MOVED 5089 192.168.64.117:6379
2019/09/19 15:28:41 [D] [server.go:2774] | 10.112.33.205| 503 | 9.958842ms| nomatch| GET /api/ping
2019/09/19 15:28:41 [E] [server.go:2774] MOVED 13229 192.168.65.101:6379
2019/09/19 15:28:41 [D] [server.go:2774] | 10.112.33.205| 503 | 1.940507ms| nomatch| GET /api/ping
2019/09/19 15:28:51 [E] [server.go:2774] MOVED 3558 192.168.64.117:6379
2019/09/19 15:28:51 [D] [server.go:2774] | 10.112.33.205| 503 | 6.13463ms| nomatch| GET /api/ping
2019/09/19 15:28:51 [E] [server.go:2774] MOVED 10236 192.168.100.31:6379
2019/09/19 15:28:51 [D] [server.go:2774] | 10.112.33.205| 503 | 3.027112ms| nomatch| GET /api/ping
2019/09/19 15:29:01 [E] [server.go:2774] MOVED 938 192.168.64.117:6379
2019/09/19 15:29:01 [D] [server.go:2774] | 10.112.33.205| 503 | 1.920783ms| nomatch| GET /api/ping
2019/09/19 15:29:01 [E] [server.go:2774] MOVED 6511 192.168.100.31:6379
2019/09/19 15:29:01 [D] [server.go:2774] | 10.112.33.205| 503 | 2.258429ms| nomatch| GET /api/ping
2019-09-19T15:29:01Z [INFO] [/core/main.go:146]: capture system signal terminated, to close "closing" channel
2019-09-19T15:29:04Z [INFO] [/core/main.go:152]: Timeout waiting goroutines to exit
1.9.0 版本还不支持 Redis Cluster,改用单节点。
OIDC模式CLI密码失效
表现为隔一段时间未从浏览器登录 Harbor,则 docker login
会失败,从浏览器登录一次之后 docker login
又能成功了。怀疑是 OIDC provider 未正确实现 refresh_token
功能。验证及解决方案:调短 Dex idtoken 过期时间(比如1分钟) 来验证是否是 refresh_token
的问题,然后尝试修复 refresh_token
问题。
通过实现了 refresh_token
的测试 connector, 设置 idTokens
过期时间为 20s
,发现 docker login
20s 后依然可以登录。而使用线上未实现 refresh_token
的 connector, 则 20 s 后登录失效。
解决方案: 直接抄 github connector 的 refresh
代码即可。
S3 问题
Harbor 1.9.0 S3 不可用,镜像都是 0B,而且只显示第一个 repository。另外 S3 垃圾回收似乎也有问题。因此使用 ceph swift。用 Nginx 给 swift api 做代理时,需要 ceph.conf
设置 rgw swift url
,否则不能正确获取 X-Storage-Url
响应头:
[global]
...
rgw swift url = https://s3.com
使用 curl 测试:
# curl -i -H "X-Auth-User: test:swift" -H "X-Auth-Key: secret" https://s3.com/auth
HTTP/1.1 204 No Content
Date: Fri, 20 Sep 2019 08:27:15 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
X-Storage-Url: http://s3.com:443/swift/v1
X-Storage-Token: AUTH_rgwtk
X-Auth-Token: AUTH_rgwtk
X-Trans-Id: tx00000000000000000010c-005d848d63-2a62-default
X-Openstack-Request-Id: tx00000000000000000010c-005d848d63-2a62-default
Strict-Transport-Security: max-age=15724800; includeSubDomains
设置不正确时可能的报错,抓包可以看到 X-Storage-Url
被自动加上了 7480
端口,协议也变成了 HTTP:
swift --os-cacert /home/deca.pem -R=1 -A https://s3.play.cn/auth -U harbor -K secretkey list
HTTPConnectionPool(host='s3.play.cn', port=7480): Max retries exceeded with url: /swift/v1?format=json (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f4c0bfe1b00>: Failed to establish a new connection: [Errno 111] Connection refused',))
Kubernetes使用Harbor
由于 OIDC 模式可能存在 CLI 密码过期问题,会导致 Kubernetes 拉取镜像失败。Harbor 不像 Gitea 那样既支持数据库用户又支持 OIDC 用户,因此只能选择 admin 这个唯一的数据库用户来作为 Kubernetes imagePullSecret
的账号。需要考虑以 imagepullsecret 是否会暴露给用户。结论是 未通过 dashboard
暴露给用户,可以使用 admin 账号。
为每个 namespace 添加 imagePullSecret。
for id in `kubectl get ns |awk 'NR>1{print $1}'`;do kubectl -n $id apply -f cr-key.yaml;done
cr-key.yaml
格式如下:
apiVersion: v1
kind: Secret
metadata:
name: cr-image-pull-secret
data:
.dockerconfigjson: 包含admin账号的~/.docker/config.json的base64编码
type: kubernetes.io/dockerconfigjson
参考资料
1. https://github.com/goharbor/harbor/issues/8620
2. https://github.com/goharbor/harbor/issues/8121
3. https://goharbor.io/
4. http://lists.ceph.com/pipermail/ceph-users-ceph.com/2016-April/009213.html
5. https://wiki.annhe.net/02-工程实践/kubernetes/infrastructure/registry
6. https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
发表回复