小甲师兄

  • 主页
  • 所有文章
  • 标签
所有文章 友链 关于我

小甲师兄

  • 主页
  • 所有文章
  • 标签

听说你的harbor不能使用s3

2019-03-16

harbor

harbor主要是用来存储容器镜像的开源项目,也就是所谓的容器镜像仓库,跟OpenStack的glance功能类似,不同的是后者存放的是虚拟机镜像。
harbor除了可以存储容器镜像,还可以存储chart,chart是容器环境下的应用打包格式,类似于centos下的rpm包,ubuntu下的debian包。
下图是harbor的架构图
a
这两种资源都需要放在存储介质上,镜像和chart可以分开用不同的存储,也可以使用相同的存储后端,这里主要讨论一下镜像的存储。
从上图可以看到harbor对镜像的实际存储使用的是docker原生的registry,那研究harbor的镜像存储,就是研究docker registry的镜像存储。一般都存放在本地文件系统上,

即后端存储driver使用filesystem,由于harbor是跑在容器里的,此driver根据具体实现又可分为以下三种情况:

  • (1)服务器本地存储:这种方式就是把服务器本地文件目录挂载到容器中做为harbor存储镜像的位置
  • (2)ceph rbd pv:这种方式首先通过k8s的pvc申请一个ceph rbd卷,然后把rbd卷mount到服务器,最后再把这个目录挂载到容器中
  • (3)ceph cephfs pv:这种方式直接使用cephfs功能,通过pvc申请一个cephfs中的一个目录,然后mount到服务器,最后在把这个目录挂载到容器中

简单说明一下这三种:第一种不是共享存储,是harbor高可用的拦路虎;第二种ceph rbd卷出于数据一致性的考虑,不能同时挂载在对各宿主机上,也是harbor高可用的拦路虎;第三种cephfs是共享存储,通过文件系统是可以进行多挂载,同时读写,但是由于cephfs storageclass driver不是官方指定的,可能driver质量还不够高,同时cephfs本身也质疑比较多(不过社区一致在对cephfs投入很大)
好像没有一种比较十全十美的,那还有其他的driver吗?

ceph rgw可用否

ceph一共就三种应用,块、文件、对象,前两种都试过了,那ceph的rgw对象存储可以使用不,看了一下docker registry中的driver是用s3,ceph的rgw是支持s3的,那应该可以?!不过网上搜了一下好多人说,都有问题,一直卡主retry,比如一下连接:https://github.com/docker/distribution/issues/2189,
b
小甲以为这个问题应该解决了,毕竟这是2017的issue,先实验试一下

docker registry接ceph rgw s3实验

  • 版本:
    1
    2
    3
    harbor
    docker registry(distribution) 2.6.2
    aws-sdk-go

docker registry后来v2版改名叫distribution,上面表是实验使用的代码版本

  • 配置:
    distribution配置
    1
    2
    3
    4
    5
    6
    7
    s3:
    region: us-east-1
    bucket: gkkbucket1
    accesskey: tstackqwer666
    secretkey: tstackqwer666
    regionendpoint: http://10.85.46.87:8080
    secure: false

10.85.46.87:8080是ceph rgw的地址
docker的/etc/docker/daemon.json配置如下:

1
2
3
{
"insecure-registries": ["192.168.127.1:5000"]
}

192.168.127.1:5000是distribution服务的地址,也就是让docker使用私有镜像仓库

docker tag scratch:latest 192.168.127.1:5000/scratch:1.11

实验结果:registry接s3有问题

运行distribution,然后docker push私有镜像,实验表明确实还存在问题,一致在retry
假装有图。
网上没有解决办法,那就手撸一下。

调试及分析

  • 1.首先制作一个只有一层的镜像,要不然distribution调试的时候请求会很多,眼花缭乱,不要给自己添麻烦,
    这里使用如下命令制作一个只有一层的镜像

    1
    tar cv --files-from /dev/null | docker import - scratch
  • 2.设置tag

    1
    docker tag scratch:latest 192.168.127.1:5000/scratch:1.11

通过调试发现docker registry是先上传数据,最后再上传manifest,通过调试发现
c

1
2
3
4
5
6
192.168.127.133 - - [23/Mar/2019:20:30:45 +0800] "PUT /v2/docker.io/alpine/blobs/uploads/4f495fbb-876f-43b7-8aad-166701220985?_state=BbHh5XVtlX93j2I3vYVRWNluZ96_3wIhkMKd-9W3YeB7Ik5hbWUiOiJkb2NrZXIuaW8vYWxwaW5lIiwiVVVJRCI6IjRmNDk1ZmJiLTg3NmYtNDNiNy04YWFkLTE2NjcwMTIyMDk4NSIsIk9mZnNldCI6Mjc1NDcyOCwiU3RhcnRlZEF0IjoiMjAxOS0wMy0yM1QxMjozMDozNVoifQ%3D%3D&digest=sha256%3A6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0 HTTP/1.1" 201 0 "" "docker/1.13.1 go/go1.10.3 kernel/3.10.0-327.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/1.13.1 \\(linux\\))"
time="2019-03-23T20:30:47.8196001+08:00" level=debug msg="authorizing request" environment=development go.version=go1.11.5 http.request.host="192.168.127.1:5000" http.request.id=5ab88eed-272e-4c63-ac4e-4395284f1647 http.request.method=HEAD http.request.remoteaddr="192.168.127.133:34417" http.request.uri="/v2/docker.io/alpine/blobs/sha256:6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0" http.request.useragent="docker/1.13.1 go/go1.10.3 kernel/3.10.0-327.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/1.13.1 \\(linux\\))" instance.id=ea6a2d2d-5f9e-4a14-8e66-f373a70a9298 service=registry vars.digest="sha256:6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0" vars.name="docker.io/alpine" version="v2.6.2+unknown"
time="2019-03-23T20:30:47.8196001+08:00" level=debug msg=GetBlob environment=development go.version=go1.11.5 http.request.host="192.168.127.1:5000" http.request.id=5ab88eed-272e-4c63-ac4e-4395284f1647 http.request.method=HEAD http.request.remoteaddr="192.168.127.133:34417" http.request.uri="/v2/docker.io/alpine/blobs/sha256:6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0" http.request.useragent="docker/1.13.1 go/go1.10.3 kernel/3.10.0-327.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/1.13.1 \\(linux\\))" instance.id=ea6a2d2d-5f9e-4a14-8e66-f373a70a9298 service=registry vars.digest="sha256:6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0" vars.name="docker.io/alpine" version="v2.6.2+unknown"
time="2019-03-23T20:30:47.8196001+08:00" level=debug msg="s3aws.URLFor(\"/docker/registry/v2/blobs/sha256/6c/6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0/data\")" environment=development go.version=go1.11.5 http.request.host="192.168.127.1:5000" http.request.id=5ab88eed-272e-4c63-ac4e-4395284f1647 http.request.method=HEAD http.request.remoteaddr="192.168.127.133:34417" http.request.uri="/v2/docker.io/alpine/blobs/sha256:6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0" http.request.useragent="docker/1.13.1 go/go1.10.3 kernel/3.10.0-327.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/1.13.1 \\(linux\\))" instance.id=ea6a2d2d-5f9e-4a14-8e66-f373a70a9298 service=registry trace.duration=0s trace.file="D:/Go/src/github.com/docker/distribution/registry/storage/driver/base/base.go" trace.func="github.com/docker/distribution/registry/storage/driver/base.(*Base).URLFor" trace.id=83cf9b9e-46a4-43a3-9db2-095ece7dda28 trace.line=189 vars.digest="sha256:6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0" vars.name="docker.io/alpine" version="v2.6.2+unknown"
time="2019-03-23T20:30:47.8206001+08:00" level=info msg="response completed" environment=development go.version=go1.11.5 http.request.host="192.168.127.1:5000" http.request.id=5ab88eed-272e-4c63-ac4e-4395284f1647 http.request.method=HEAD http.request.remoteaddr="192.168.127.133:34417" http.request.uri="/v2/docker.io/alpine/blobs/sha256:6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0" http.request.useragent="docker/1.13.1 go/go1.10.3 kernel/3.10.0-327.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/1.13.1 \\(linux\\))" http.response.contenttype="application/octet-stream" http.response.duration=2ms http.response.status=307 http.response.written=0 instance.id=ea6a2d2d-5f9e-4a14-8e66-f373a70a9298 service=registry version="v2.6.2+unknown"
192.168.127.133 - - [23/Mar/2019:20:30:47 +0800] "HEAD /v2/docker.io/alpine/blobs/sha256:6c40cc604d8e4c121adcb6b0bfe8bb038815c350980090e74aa5a6423f8f82c0 HTTP/1.1" 307 0 "" "docker/1.13.1 go/go1.10.3 kernel/3.10.0-327.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/1.13.1 \\(linux\\))"

在这里卡主了,上面有一个url从定向,
ceph rgw的日志如下:
d
首先请求包认证错误,怎么会认证错误呢,再查看请求头发现这请求奇怪
e
rgw请求的s3 v4认证怎么在这个QUERY_STRING字段,这个字段一般是url后面的查询条件,小甲思考3秒,可能是url重定向导致,屡一下可能是这样

  • 1.docker向distribution发送了一个head请求
  • 2.distribution接收到请求之后,进行了url重定向,把signure认证放在了url查询部分,放在location中返回docker
  • 3.docker根据返回请求中location中的重定向的url,也就是上面ceph rgw的地址,然后发送请求,可是docker没有调用任何s3的sdk,所以不会进行s3的signure算法,直接head发给了ceph rgw
  • 4.ceph rgw接收到head请求,还是根据s3的v4认证,所以报错了。

后面调试代码发现问题确实是这样。

修改方法

那如何修改呢,其实修改很简单,只要把url直接抛异常就可以,这个filesystem也是这样处理的。小甲本来的想法是新建一个结构体,继承现有的s3 driver,然后重载URLFor函数就可以,但是发现s3的driver是包外不可见,这就无法继承,最后通过增加一个配置参数,是否是使用的ceph s3还是aws s3,在使用ceph s3的时候直接抛异常退出URLFor函数。

#等等还没结束
docker push和pull现在都可以正常了,但是镜像的删除也有问题,那镜像是怎么删除的呢?

  • 1.调用api删除
  • 2.distribution 运行garbage-collect命令
    发现有问题,ceph接受不到请求,调试了好久发现是distribution中vendor目录下的aws-sdk-go版本比较老,小甲用较高的版本就可以了
    这下应该结束了吧,no no no

distribution master问题

小甲又下载了distribution的master分支试了一下,发现前面的修改之后docker push/pull都ok,删除换了高版本的aws-sdk-go还是有问题,什么问题呢?

  • 1.空指针异常,What?
    f
    在doWalk函数中出现了空指针,这个函数在distribution 2.6.2中还没有
  • 2.代码分析从ceph返回来的
    ListObjectsV2Output这个对象的KeyCount这个成员是一个空指针,而代码中使用这个进行了运算导致了错误,看来distribution确实没有验证ceph
  • 3.修改也比较简单,通过之前加的一个ceph配置对ceph的请求情况做一下特殊处理就可以了。

修改代码后重新编译

编译修改后的代码成二进制可执行文件

重新制作harbor-registry镜像

使用dockerfile生成新的镜像

1
2
3
4
5
6
 FROM  test:v1.7.0

COPY ./registry /usr/bin
EXPOSE 5000
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/etc/registry/config.yml"]

chart配置修改

修改harbor/values.yaml文件

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
imageChartStorage:
# Specify the type of storage: "filesystem", "azure", "gcs", "s3", "swift",
# "oss" and fill the information needed in the corresponding section. The type
# must be "filesystem" if you want to use persistent volumes for registry
# and chartmuseum
type: s3
filesystem:
rootdirectory: /var/lib/registry
#maxthreads: 100
azure:
accountname: accountname
accountkey: base64encodedaccountkey
container: containername
#realm: core.windows.net
gcs:
bucket: bucketname
# TODO: support the keyfile of gcs
#keyfile: /path/to/keyfile
#rootdirectory: /gcs/object/name/prefix
#chunksize: "5242880"
s3:
region: us-east-1
bucket: gkkbucket2
accesskey: tstackqwer666
secretkey: tstackqwer666
regionendpoint: http://10.85.46.87:8080
secure: false
cephcompatible: true
#encrypt: false
#keyid: mykeyid
#v4auth: true
#chunksize: "5242880"
#rootdirectory: /s3/object/name/prefix
#storageclass: STANDARD

参考链接

http://dockone.io/article/93

赏

谢谢你请我吃糖果

  • harbor docker ceph s3

扫一扫,分享到微信

微信分享二维码
小甲师兄陪你一起看Ceph(osdc篇)
ceph talk(1)
© 2022 小甲师兄
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • Ceph
  • ceph 编译
  • openstack nova cinder
  • openstack lvm
  • openstack nova
  • ceph
  • Ceph rwl
  • cephfs
  • ceph rbd
  • C tcmu-runner
  • Linux 性能优化实践(5)
  • linux 性能
  • openstack dashboard horizon
  • openstack glance
  • openstack cinder glance
  • go
  • ceph osd
  • openstack horizon
  • python iscsi kernel
  • k8s 张磊
  • k8s configmap
  • k8s cephfs
  • openstack
  • openstack neutron
  • openstack nova ceph
  • rbd
  • rbd iscsi python
  • mysql
  • ceph iscsi rbd
  • libvirt
  • Openstack nova ceph
  • ceph coverage
  • nova periodic
  • ceph log
  • ceph auth
  • harbor docker ceph s3
  • openstack nova cinder glance
  • rbd openstack
  • Ceph Cephfs osdc
  • Ceph rbd
  • openstack nova glance
  • Ceph osd

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • iceyao
  • int32bit
鹅厂小猿一枚
记录成长点滴