基于OSS搭建跨区域部署的分布式Docker镜像仓库

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 大规模分布式Docker应用需要部署在在不同的地域(region)中。为了提升部署速度并节省网络成本,需要在每个region部署Docker Registry。本文将结合阿里云OSS的新特性来介绍跨区域部署的分布式Docker镜像仓库方案。

基于OSS搭建跨区域部署的分布式Docker镜像仓库

Docker镜像是Docker的核心价值之一,Docker镜像仓库(Registry)是用于Docker镜像的管理和分发的基础设施。现在已经有了Docker Hub等多家公有镜像管理服务供应商,阿里云容器Hub服务也是您在云端的一个非常好的选择。但是有些情况,为了更加灵活的部署控制和一些管控要求,您也许会考虑在云端的部署一个私有镜像仓库。

为了满足异地容灾和就近访问等需求,需要在不同的区域(region)部署分布式Docker应用;在不同的region中,为了提升部署速度并节省网络成本,需要在每个region部署私有Docker Registry。然而,这就会给分布式部署中的镜像管理带来很多挑战。本文将结合阿里云OSS的新特性来介绍跨域部署的Docker镜像仓库的解决方案。

14572203169236

阿里云搭建Docker Registry入门

Docker Registry是存储和网络密集型应用。Docker镜像存储需要使用大量的存储资源,采用本地存储无法满足用户对容量和可用性的需求;同时镜像的上传,下载需要高速的网络带宽。Docker Registry自从2.1版本开始,就已经加入了对阿里云开放存储服务(OSS)的正式支持。这为Docker Registry提供一个支持海量存储,高性能访问,高可用,安全,低成本,无需运维的存储后端。而且利用ECS构建私有仓库可以使用OSS内部数据流量,降低公网网络流量成本。在集团内部和阿里云的镜像仓库服务,我们都采用了OSS的对象存储服务,来支持对内和对外的Docker镜像管理和分发。

在阿里云上ECS上搭建一个Docker Registry是非常方便的,最方便的方法是利用Docker镜像的方式来进行安装。

首先我们要在ECS上有一个Docker运行环境,你可以手工安装Docker Engine到已有的ECS实例上;或者,利用Docker Machine的ECS驱动方便的创建一个新的Docker就绪的ECS实例。请参见入门指南

启动一个使用OSS的存储的Docker Registry也是非常简单的,我推荐的方法是利用Docker Compose的方式配置和启动:

一个包含最简单的配置的docker-compose.yml如下

registry:
  restart: always
  image: "registry:2.3"
  ports:
    - 5000:5000
  environment:
    - REGISTRY_STORAGE=oss
    - REGISTRY_STORAGE_OSS_ACCESSKEYID=******
    - REGISTRY_STORAGE_OSS_ACCESSKEYSECRET=******
    - REGISTRY_STORAGE_OSS_REGION=oss-cn-beijing
    - REGISTRY_STORAGE_OSS_BUCKET=aliyungo-beijing
    - REGISTRY_STORAGE_OSS_INTERNAL=true
    - REGISTRY_STORAGE_OSS_SECURE=false

这里,我们将利用Docker Registry 2.3官方镜像创建一个私有镜像仓库,通过环境变量的方式配置了OSS的Access Key ID, Access Key Secret, Region, Bucket等信息。关于OSS配置的详细信息请参见官方文档

然后执行 docker-compose up -d 命令, 私有镜像就启动成功了。

我们可以在ECS实例上执行下面命令来验证相关工作

docker pull node:5.7
docker tag node:5.7 127.0.0.1:5000/node:5.7
docker push 127.0.0.1:5000/node:5.7

执行结果如下,已经成功将镜像推送成功

[root@iZ25cz6gdslZ ~]# docker pull node:5.7
5.7: Pulling from library/node
fdd5d7827f33: Already exists 
a3ed95caeb02: Pull complete 
0f35d0fe50cc: Already exists 
627b6479c8f7: Already exists 
67c44324f4e3: Already exists 
b52090f6ca00: Pull complete 
1df855d9e713: Pull complete 
Digest: sha256:cde7a4fca0a3dd2330977078c3773164b172a0ec582bafced6db955dca02a5c4
Status: Downloaded newer image for node:5.7
[root@iZ25cz6gdslZ ~]# docker tag node:5.7 127.0.0.1:5000/node:5.7
[root@iZ25cz6gdslZ ~]# docker push 127.0.0.1:5000/node:5.7
The push refers to a repository [127.0.0.1:5000/node]
5f70bf18a086: Mounted from ubuntu 
1967867932fe: Pushed 
6b4fab929601: Pushed 
550f16cd8ed1: Mounted from python 
44267ec3aa94: Mounted from java 
bd750002938c: Mounted from java 
917c0fc99b35: Mounted from java 
5.7: digest: sha256:64413fb300f4dd491397dbf16edbc8499c521640ac52e68bdfee8241a8d0dafe size: 2389

注意:一定要配置Docker Hub加速器呀,要不会有欲哭无泪的赶脚。

在生产环节中使用,您还需要添加Nginx等组件来增加TLS访问,认证授权,负载均衡等能力。详见官方参考),本文不再详述。

分布式跨区域Docker Registry方案讨论

回到正题,为了支持多区域部署Docker应用的需求,我们需要在每个region部署Docker Registry。然而如何在分布式的Docker Registry之间实现内容同步?我们有以下几种可能的方案

  1. 当客户端推送镜像时,分别向不同region的Docker Registry推送。

    • 好处:没有任何外部依赖
    • 不足:手工同步导致客户端逻辑复杂;当扩展region之后需要手工同步已有镜像
  2. 利用Docker Registry的通知机制,实现Web Hook;当一个Docker Registry收到镜像推送完成事件之后,由Web Hook的实现向其他region的Docker Registry推送刚完成的镜像

    • 好处:没有任何外部依赖,自动化同步
    • 不足:基于事件的同步逻辑实现复杂,需要考虑网络中断,region变更等多种边界情况
  3. 利用存储复制的机制,实现不同region的镜像复制

    • 好处:自动化同步,实现简单
    • 不足:需要底层存储驱动支持

由于Docker Registry本身是无状态的应用,非常适合采用数据复制的方案实现分布式部署。去年一系列公司提出了分布式Docker Registry的解决方案,大多基于其商业化的数据复制技术,比如NetApp在DockerCon的演讲。

然而利用阿里云OSS的新特性,Bucket跨区域复制和回源设置,我们也可以轻松实现一个大规模分布式的镜像仓库。在下面示例中:我们会把北京registry作为主registry,允许用户推送、拉取镜像;创建上海registry作为从registry,允许用户拉取镜像。其高层架构图如下:

14571909981240

利用OSS跨区域复制轻松实现分布式镜像仓库

OSS的Bucket Cross-Region Replication是跨不同区域数据中心的自动化、异步复制技术。它会将对源Bucket中的对象的改动(新建、覆盖、删除等)同步到目标Bucket。详细信息请参见帮助文档

首先,我们创建一个上海region的bucket,作为目标bucket

14571876877887

然后选择北京region的bucket作为源bucket; 并配置跨区域复制规则到目标bucket
14571885643390

14571886754062

同步规则配置完成之后,等待几分钟同步完成的效果如下
14571877603740

在上海region的ECS实例上,我们利用上文的方法也创建一个Docker Registry,"docker-compose.yml"的配置如下,并配置上海region的OSS Bucket作为镜像存储

registry:
  restart: always
  image: registry:2.3
  ports:
    - 127.0.0.1:5000:5000
  environment:
    - REGISTRY_STORAGE=oss
    - REGISTRY_STORAGE_OSS_ACCESSKEYID=******
    - REGISTRY_STORAGE_OSS_ACCESSKEYSECRET=******
    - REGISTRY_STORAGE_OSS_REGION=oss-cn-shanghai
    - REGISTRY_STORAGE_OSS_BUCKET=aliyungo-shanghai
    - REGISTRY_STORAGE_OSS_INTERNAL=true
    - REGISTRY_STORAGE_OSS_SECURE=false

然后执行docker-compose up -d命令启动Docker Registry

我们可以通过下面的命令来验证镜像复制是否成功

# docker pull 127.0.0.1:5000/node:5.7
5.7: Pulling from node
fdd5d7827f33: Already exists 
a3ed95caeb02: Pull complete 
0f35d0fe50cc: Already exists 
627b6479c8f7: Already exists 
67c44324f4e3: Already exists 
b52090f6ca00: Pull complete 
1df855d9e713: Pull complete 
Digest: sha256:64413fb300f4dd491397dbf16edbc8499c521640ac52e68bdfee8241a8d0dafe
Status: Downloaded newer image for 127.0.0.1:5000/node:5.7

大家可以看到,无需任何编程,我们已经简单地实现了分布式数据的Docker Registry的自动化数据同步。用户可以在北京registry上push新的镜像,在上海registry上pull镜像,没有任何的手工维护工作。

需要注意的是:OSS的bucket复制是单向的,所以我们要在部署方案中确定registry的主从关系。只有在主registry的镜像是可以读写的,而在从registry中,镜像应是只读的。本文中主registy在北京region,而从registry在上海region。

目前为止,这个方案还不够完美。由于Bucket复制是异步的,采用的是最终一致性。对象从源复制到目的bucket需要一定的时间,这取决于复制对象的大小。我们知道Docker镜像是采用分层存储机制,每个layer包含相应的blob对象,元数据和digest信息。其中layer的blob对象可能非常大,数据复制完成时间会比较长。

所以,当我们在上海registry拉取镜像时,如果blob对象没有复制完成,则我们会遇到如下"unknown blob"错误

# docker pull 127.0.0.1:5000/redis:2
2: Pulling from redis
fdd5d7827f33: Already exists 
a3ed95caeb02: Download complete 
3868e1e933d6: Pulling fs layer 
1d007c18c656: Pulling fs layer 
ad75a8697e9c: Waiting 
8de500daf5d7: Waiting 
788fee3bdabf: Waiting 
8f359895dbf8: Waiting 
unknown blob

目前实现对于时效性不敏感的场景,这个方案已经足够。当然,也需要应用层做一些调整,在镜像未复制完成之前,需要反复尝试等待复制完成。

如果用户希望能够立刻从上海region的registry访问刚在北京region推送的镜像,有没有更好的解决方案?

利用OSS回源设置实现镜像按需热迁移

对于上面的问题一个自然的想法就是:如果在上海registry请求尚未同步完成的Docker layer数据时,就从北京region的源bucket中读取对象,并返回。

为了减少开发的复杂度,我们尝试使用OSS的回源设置(详见帮助文档)来自动化这个过程。当上海region的bucket中所需blob对象不存在时,让OSS可以从北京region的bucket中自动进行回源读取;在将layer内容返回给Docker请求的同时,自动将内容复制到上海region的目标bucket。

我们在上海region的bucket上配置回源规则如下
14571903064338

这里我们使用镜像方式:将回源地址指向北京bucket的公网访问地址
14571903652298

当然我们还需要对registry中的OSS driver的Stat和URLFor实现做一些调整,当Registry检查到文件的元数据不存在时,强制通过回源方式返回北京registry中的内容。对Docker Registry的修改可以从Github访问

您也可以直接利用编译过的"registry.aliyuncs.com/denverdino/registry:2.3"镜像来替换官方镜像。只需修改上海region部署所用的"docker-compose.yml"的image值修改即可。

registry:
  restart: always
  image: registry.aliyuncs.com/denverdino/registry:2.3
  ports:
    - 127.0.0.1:5000:5000
  environment:
    - REGISTRY_STORAGE=oss
    - REGISTRY_STORAGE_OSS_ACCESSKEYID=******
    - REGISTRY_STORAGE_OSS_ACCESSKEYSECRET=******
    - REGISTRY_STORAGE_OSS_REGION=oss-cn-shanghai
    - REGISTRY_STORAGE_OSS_BUCKET=aliyungo-shanghai
    - REGISTRY_STORAGE_OSS_INTERNAL=true
    - REGISTRY_STORAGE_OSS_SECURE=false

再次尝试,我们已经近乎同时地从上海region的registry访问刚刚在北京region推送的Docker镜像了。在这里,我们将异步的对象复制,和同步的按需复制结合在一起,可以满足绝大多数场景对分布式镜像仓库的要求。

大功告成!

总结

跨区域部署的Docker Registry可以在不同数据中心的用户高效、简单的利用Docker镜像进行软件交付、部署和运维;可以支持异地容灾、分布式DevOps等场景。

在本文介绍的这个分布式、跨域部署的Docker Registry的方案中,无需额外的手工运维就可保证不同地域Docker镜像仓库的数据一致性。其技术要点如下:

  • 使用OSS作为Docker镜像存储实现,不同region的registry配置到本地region的bucket上
  • 利用OSS提供的跨区域bucket复制能力,在主从registry中实现自动数据复制
  • 在从registry中,如果镜像layer对象存在于本地的OSS bucket中,则直接利用bucket中对象返回;
    如果镜像layer对象还未同步成功,则回源到主registry的bucket中

感谢阿里云OSS团队一直以来的大力协助和支持。

欢迎大家使用阿里云容器服务阿里云Docker镜像仓库服务。它能帮助你大大加速云端Docker应用的交付流程。

相关实践学习
Docker镜像管理快速入门
本教程将介绍如何使用Docker构建镜像,并通过阿里云镜像服务分发到ECS服务器,运行该镜像。
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
2月前
|
Java 测试技术 Linux
jmeter-分布式部署之负载机的设置
jmeter-分布式部署之负载机的设置
208 2
|
2月前
|
Docker 容器 关系型数据库
【PolarDB-X从入门到精通】 第四讲:PolarDB分布式版安装部署(源码编译部署)
本期课程将于4月11日19:00开始直播,内容包括源码编译基础知识和实践操作,课程目标是使学员掌握源码编译部署技能,为未来发展奠定基础,期待大家在课程中取得丰富的学习成果!
【PolarDB-X从入门到精通】 第四讲:PolarDB分布式版安装部署(源码编译部署)
|
23天前
|
分布式计算 Java Hadoop
杨校老师课堂之分布式数据库HBase的部署和基本操作
杨校老师课堂之分布式数据库HBase的部署和基本操作
25 0
|
2月前
|
关系型数据库 MySQL 数据库
测试部署PolarDB-X 分布式与集中式
在本文中,作者详述了在CentOS 7.9上部署测试PolarDB-X分布式与集中式数据库的过程。PolarDB-X作为阿里云优化的分布式数据库,提供高稳定性和与MySQL的兼容性,是应对单体数据库扩展性和性能瓶颈的解决方案,同时也符合国产化需求。文章介绍了部署环境准备,包括关闭防火墙和SELinux,设置系统参数,安装Python3和Docker,以及配置MySQL客户端。接着,通过PXD工具部署了PolarDB-X的集中式和分布式版,遇到的问题包括阿里云镜像源异常导致的部署失败以及指定版本安装的困扰。最后,作者进行了初步的压力测试,并对文档完善、生态工具建设以及提供更多使用案例提出了建议。
47781 10
测试部署PolarDB-X 分布式与集中式
|
9天前
|
缓存 Devops 微服务
微服务01好处,随着代码越多耦合度越多,升级维护困难,微服务技术栈,异步通信技术,缓存技术,DevOps技术,搜索技术,单体架构,分布式架构将业务功能进行拆分,部署时费劲,集连失败如何解决
微服务01好处,随着代码越多耦合度越多,升级维护困难,微服务技术栈,异步通信技术,缓存技术,DevOps技术,搜索技术,单体架构,分布式架构将业务功能进行拆分,部署时费劲,集连失败如何解决
|
2月前
|
Java 大数据 流计算
使用Docker快速部署Flink分布式集群
使用Docker快速部署Flink分布式集群
218 0
|
2月前
|
SQL 消息中间件 存储
【一文看懂】使用hape部署分布式版Havenask
本次分享内容为使用hape部署分布式版Havenask,共2个部分组成(部署分布式版Havenask集群、 分布式相关问题排查),希望可以帮助大家更好了解和使用Havenask。
165059 6
|
2月前
使用JWT的服务分布式部署之后报错:JWT Check Failure:
使用JWT的服务分布式部署之后报错:JWT Check Failure:
66 1
|
2月前
|
SQL 调度 数据库
Docker部署Xxl-Job分布式任务调度中心(超详细)
Docker部署Xxl-Job分布式任务调度中心(超详细)
|
2月前
|
存储 分布式计算 Hadoop
基于Hadoop分布式数据库HBase1.0部署及使用
基于Hadoop分布式数据库HBase1.0部署及使用

相关产品

  • 容器镜像服务