AI 年度盘点与2025发展趋势展望,50+案例解析亮相AICon 了解详情
写点什么

基于 Amazon EC2 Container Service 构建安全高可用的 Docker 私有库

  • 2019-11-13
  • 本文字数:6191 字

    阅读完需:约 20 分钟

基于Amazon EC2 Container Service构建安全高可用的Docker私有库

1. 背景

Docker hub 作为 docker 官方镜像仓库,提供了大量 Docker 镜像的托管服务。但使用它来托管企业私有 Docker 镜像存在一些问题,比如:


(1)Docker hub 托管私有镜像的服务目前只面对收费账户;


(2)使用 Docker hub 托管私有镜像并不适合一些特殊场景,比如工作环境网络是内网,不允许访问外网,那就更不可能到 Docker hub 去下载镜像。


在这种情况下,如果能构建一个安全可靠的 Docker 私有库,将会是一个更好的选择。本文将介绍在 Amazon EC2 Container Service 基础上结合 AWS Elastic LoadBalancer、AWS Autoscaling Group、AWS S3 及 Docker 官方提供的 registry 镜像构建安全、高可用的 Docker 私有库的方案,帮助您轻构实现这一需求。

2. 方案详解

我们会使用 AWS CloudFormation 服务,使用自定义的模板脚本声明所需的资源,实现自动化构建。接下来结合我们的模板脚本对本方案进行详细介绍。


注意:以下内容与代码相关部分只贴出主要代码,部分代码用…表示省略;红字部分请替换成您自己账号相关的信息。


完整模板代码地址:https://s3-us-west-2.amazonaws.com/blog.leonli.org/registry.yml



或者点击按钮直接在控制台中运行:

2.1 架构图


根据以上架构图,基本数据传输过程为:


(1)Docker 客户端向镜像仓库发送的 pull/push 等命令事实上都是通过 docker daemon 转换成 restful 请求的形式再发送给镜像仓库的。在本架构中,我们利用 AWS Elastic LoadBalancer(简称 ELB)接收客户端发来的请求,作为整个架构的接入层。由于我们要求数据是通过 TLS 加密传输的,所以我们需要使用 AWS IAM 中的 server certificate(由 AWS IAM 账户上传的 TLS 证书)与 ELB 关联,实现对客户端发来的请求进行加密。


(2)ELB 会将请求反向代理给后端分布在不同可用区的两台 Container Instance(安装了 Docker 运行环境的 EC2 实例),Container Instance 中运行了 Docker registry 服务。当请求到达 registry 时,我们需要首先使用内置在 registry 中的用户认证文件(比如本架构中使用 apache htpasswd 创建的基本用户名密码保护文件),进行用户认证,认证不通过,则驳回请求,认证通过,才可以读写数据。


(3)我们将数据统一存储在一个只供创建者使用的 S3 Bucket 中。

2.2 基于 AWS ECS 运行 Docker Registry 服务

Amazon EC2 Container Service (ECS) 是一项高度可扩展的高性能容器管理服务,它让您能够在托管的 Amazon EC2 实例群集上轻松运行 Docker 应用程序。 Amazon ECS 主要有以下几个组件:ECS Cluster、 Container Instance、Task , ECS Service。这里我们基于 ECS 运行了 Docker registry 服务,架构如下:



(1)首先我们在模板中定义了一个 ECS Cluster,用来管理相关的 Container Instance。ECS 提供了 ECS-Optimize AMI 来创建 EC2 实例作为 Container Instance,ECS-Optimize AMI 已经内置 Docker 运行环境和 Container Agent 代理,可以为我们节省安装这些环境所需的时间。Container Instance 在启动时可以由 Container Agent 根据配置文件/etc/ecs/ecs.config 中的 ClusterName 属性的值知道需要将实例注册到哪个 ECS Cluster 上。


因为我们要使用 Auto Scaling 服务实现对 EC2 实例的伸缩控制。所以我们使用 Auto Scaling 的 Launch Config 组件声明我们的 Container Instance。并通过 UserData 传入 Shell 脚本,此脚本主要完成以下三件事:


– 调用 echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config ,将 Container Instance 注册到我们的 ECS Cluster 中。


– 创建/docker-registry/certs 目录和/docker-registry/auth 目录,并调用 aws s3 copy 命令从指定的 S3 Bucket 中复制 TLS 证书文件和 htpasswd 用户认证文件。这些文件将在运行 Docker Registry 时使用到。


– 调用 cfn-signal 命令,通知 AutoScaling Group 资源 EC2 实例已经启动完毕。


Container Instance 相关的主要模板代码如下:


(2)然后我们定义了一个 TaskDefinition 来声明我们要运行的容器及其相关配置。这里我们运行的是 Docker registry 镜像的容器,它是官方提供的用于构建镜像仓库服务的镜像文件。

col 1

ContainerInstances:


Type: AWS::AutoScaling::LaunchConfiguration


Properties:



UserData:


Fn::Base64: !Sub |


#!/bin/bash -xe


echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config


yum install -y aws-cfn-bootstrap


yum install -y aws-cli


sudo rm -rf /docker-registry


sudo mkdir -p /docker-registry/certs


sudo chmod 777 /docker-registry/certs


sudo mkdir -p /docker-registry/auth


sudo chmod 777 /docker-registry/auth


aws s3 cp s3://{SSLCertificateFileName} /docker-registry/certs/domain.crt


aws s3 cp s3://{SSLKeyFileName} /docker-registry/certs/domain.key


aws s3 cp s3://{HtpasswdFileName} /docker-registry/auth/htpasswd


/opt/aws/bin/cfn-signal -e {AWS::StackId} –resource ECSAutoScalingGroup –region ${AWS::Region}


– 配置环境变量 REGISTRY_AUTH、REGISTRY_AUTH_HTPASSWD_REALM、REGISTRY_AUTH_HTPASSWD_PATH 指定宿主机目录/auth/htpasswd 文件作为 Basic Authentication 基础用户认证文件,从而实现用户授权认证。


– 配置环境变量 REGISTRY_HTTP_TLS_CERTIFICATE、REGISTRY_HTTP_TLS_KEY 指定宿主机目录/certs/中存放的 domain.crt 作为 TLS 证书文件,domain.key 作为 TLS 秘钥,从而实现 TLS 传输加密。


– 通过配置环境变量 REGISTRY_STORAGE 指定 registry 的存储驱动为 AWS S3,配置 REGISTRY_STORAGE_S3_REGION 为存储的 S3 所在 Region,配置 REGISTRY_STORAGE_S3_BUCKET 为存储的 Bucket。从而实现将镜像文件存储到 AWS S3 指定的 Bucket 中。


关于构建私有库的更多细节和更多配置可以通过 Docker 官方文档进行了解:Deploy a registry server


TaskDefinition 相关的主要模板代码如下:

col 1

RegistryTaskDefinition:


Type: AWS::ECS::TaskDefinition


Properties:


NetworkMode: bridge


ContainerDefinitions:


– Name: RegistryContainer


Image: registry:2



PortMappings:


– ContainerPort: 443


HostPort: 443



Environment:


– Name: REGISTRY_AUTH


Value: htpasswd


– Name: REGISTRY_AUTH_HTPASSWD_REALM


Value: “Registry Realm”


– Name: REGISTRY_AUTH_HTPASSWD_PATH


Value: /auth/htpasswd


– Name: REGISTRY_HTTP_TLS_CERTIFICATE


Value: /certs/domain.crt


– Name: REGISTRY_HTTP_TLS_KEY


Value: /certs/domain.key


– Name: REGISTRY_HTTP_ADDR


Value: 0.0.0.0:443


– Name: REGISTRY_STORAGE


Value: s3


– Name: REGISTRY_STORAGE_S3_REGION


Value: !Ref AWS::Region


– Name: REGISTRY_STORAGE_S3_BUCKET


Value: !GetAtt StorageBucket.DomainName



(3)最后我们定义了一个 ECS Service,指定 TaskDefinition、Cluster 和所需运行的任务个数 DesiredCount。这样,我们就构建了一个运行着 docker registry 镜像的 ECS 服务了。

2.2 如何实现高可用性

(1) 跨可用区部署服务


– 首先,我们在模板中声明了一个 VPC 和两个私有子网 PrivateSubnet1 和 PrivateSubnet2,这两个子网是分别部署在不同可用区的。


– 其次,我们的 ECS 服务是通过 Elastic Load Balancing(ELB)来平衡多个容器的负载,ELB 是高可用且自动伸缩的。我们在模板中定义了一个命名为 RegistryELB 的 ELB 组件,指定它是 internet-facing 模式可供外网访问、并且是跨可用区的。ELB 接收外网的请求,并且将请求代理给 Container Instance 中的容器。


– 最后,我们在模板中声明了一个 Auto Scaling Group,指定 VPCZoneIdentifier 为跨可用区的两个子网 PublicSubnet1 和 PublicSubnet2,由 RegistryELB 代理请求,从而实现跨可用区部署服务。


(2) 利用 Auto Scaling 保障可用实例数量


当服务遇到一些突发或者预期的高流量时,或者您的服务出现某些异常时,可以利用 Auto Scaling 服务保障可用实例数量。比如某台 Container Instance 宕机了,那么可以利用 Auto Scaling 自动启动相同配置的另一台 Container Instance 代理宕机的实例继续提供服务。


大部分情况下,企业 Docker 私有库承受的流量负载不会太大,所以本方案不介绍 Auto Scaling 的扩展策略,当然您也可以根据自己的业务需要修改模板代码,实现此功能。本方案使用 Auto Scaling 主要是为了保障可用实例数量一直维持在 DesiredCapacity,这个参数是我们通过模板的参数传入的。


Auto Scaling Group 相关的主要模板代码如下:

col 1

ECSAutoScalingGroup:


Type: AWS::AutoScaling::AutoScalingGroup



Properties:



LaunchConfigurationName: !Ref ‘ContainerInstances’


MinSize: !Ref MinSize


MaxSize: !Ref MaxSize


DesiredCapacity: !Ref DesiredCapacity



(3) 利用 s3 确保数据完整性


Amazon Simple Storage Service (Amazon S3) 是 AWS 提供的对象存储服务,它可用于在 Web 上的任何位置存储和检索任意数量的数据,能够提供 99.999999999% 的持久性,使用 S3 来存储 Docker 私有库的镜像文件,可以确保数据完整。Docker registry 镜像支持使用 S3 作为存储驱动,只需传入存储所在 Bucket 和所在 Region 即可。我们在模板中声明了一个 Bucket 用来存储镜像数据。并且这个 Bucket 只能由创建者进行控制。

2.3 如何实现安全性

(1) 利用 TLS 加密传输


Docker 官方建议与私有库通信的所有数据传输皆使用 TLS 加密,我们通过上传 IAM server certificate 证书并将其与 ELB 关联,ELB 的 Listener 使用 SSL 安全监听 443 端口,并将请求代理给实例的 443 端口,实例上也需要安装 TLS 证书。从而实现全链路的安全传输。


(2)利用 apache htpasswd 实现基本用户认证


如果我们创建的私有库没有用户认证机制,那么无论是谁只要知道私有库链接,就可以肆无忌惮地访问和操作我们托管在私有库的文件,这显然不是我们想要看到的。所以需要实现用户认证,只有通过认证的用户,才有权进行相关操作。


这里,我们使用 apache htpasswd 实现基本用户认证。这也是 Docker registry 镜像默认支持的认证方式。

3. 构建过程

3.1 准备工作

(1) 域名


您必须拥有一个用来指向 registry 的域名,这样您才可以通过域名访问您的私有库。


(2)TLS 证书

col 1

yourcertificate.crt intermediate-certificates.pem > yourcertificate.crt


Docker 官方建议私有库数据传输基于 TLS,这样您还需要为您的域名申请 CA 认证,得到 TLS 证书和秘钥文件。有以下两种方式:


向 CA 供应商购买。


利用 Let’s Encrypt 生成免费的证书,具体操作参考letsencrypt官网。


另外,如果您的证书供应商还提供给你 intermedia 证书,那么您需要将它与你的证书进行合并,运行如下命令可以进行合并

col 1

aws iam upload-server-certificate —server-certificate-name YourCertName —certificate-body file:///path/to/certificate.pem —certificate-chain file:///path/to/chained.pem —private-key file:///path/to/private_key.pem


(3)上传 IAM Server Certificate

col 1

{


“ServerCertificateMetadata”: {


“Path”: “/”,


“ServerCertificateName”: “MyRegistryCert”,


“ServerCertificateId”: “ASCAJHAWE3QRHEHH3L6KM”,


“Arn”: “arn:aws:iam::xxxxxxxxx:server-certificate/YourCertName”,


“UploadDate”: “2017-07-01T16:16:45.125Z”,


“Expiration”: “2017-09-26T12:15:00Z”


}


}

col 1

openssl x509 -inform DER -in Certificate.der -outform PEM -out Certificate.pem


当 Docker 客户端向我们的 ELB 发送请求时,出于安全考虑,需要对传输加密,这时可以利用 IAM Server Certificate,将我们的 TLS 证书、秘钥以及证书链文件上传,IAM 会帮我们自动生成一个 Server Certificate,再将它与 ELB 绑定即可。


可以使用 AWS CLI 按照以下命令上传:

col 1

openssl rsa -in PrivateKey.pem -out PrivateKey.pem


上传完成后,您会得到类似以下响应信息,将红字部分 ARN 记录下来,后面构建时需要它作为参数传入模板中。


注意:


– TLS 证书、秘钥及证书链必须都是 PEM 格式,如果不是,可以使用以下命令进行转换:


– AWS IAM 要求证书秘钥是不加密的,所以当您的秘钥是加密时,需要使用以下命令转换


– 如果您在上传 Server Certificate 过程中遇到问题,可参考 AWS 官网指南:


Working with Server Certificate


(4)htpasswd 用户认证文件


使用 apache htpasswd 来做基本认证,首先需要安装 httpd,安装完后运行以下命令可以生成一个包含 一条用户名和密码记录的 htpasswd 文件

col 1

htpasswd -c username password > htpasswdfile


后面如果需要加入更多条记录,只需将 -c 参数去除,运行上面相同的命令即可。


(5) 将证书、秘钥和认证文件上传到 S3


我们需要将前面几步生成好的 TLS 证书、秘钥、htpasswd 文件上传到 S3 中,Container Instance 启动后会从 S3 中将这些文件拷贝下来,通过映射到容器中供 registry 容器使用。


创建一个 S3 Bucket, 将这几个相关文件上传。

3.2 自动化构建

接下来,我们在 AWS Management Console 中使用 CloudFormation 指定我们的模板文件创建一个 Stack。如何使用 CloudFormation 创建 Stack,请参考 AWS CloudFormation 用户指南:CloudFormation入门


Stack 构建成功后,在输出栏会有输出值 RegistryELBDns,它是我们创建的 ELB 的 DNS 域名。我们需要将我们之前 TLS 证书签发的域名 DNS 解析(CName 解析)转发到这个 ELB 的 DNS 域名。这样就可以使用我们自己的域名访问我们的私有库了。

3.3 开始使用

构建完 Docker 私有库后,现在可以开始使用了。


首先,在 Docker 客户端,我们可以从 Docker Hub 上拉取一个 ubuntu 镜像。

col 1

docker pull ubuntu:16.04


然后 tag 这个镜像到我们自己的域名下

col 1

docker tag ubuntu:16.04 myregistrydomain.com/my-ubuntu


登录我们的私有库

col 1

docker login myregistrydomain.com


输入用户名,密码后,调用 push 命令将镜像上传

col 1

docker push myregistrydomain.com/my-ubuntu


上传完后,可以调用 pull 命令拉取镜像

col 1

docker pull myregistrydomain.com/my-ubuntu

4. 总结

本文介绍了如何利用 AWS ECS 及其他 AWS 服务构建一个高可用、安全可靠的 docker 私有库,通过本方案的详细介绍和构建实践,相信您对于 docker registry 以及 AWS Elastic LoadBalancer、AWS Autoscaling Group、AWS S3 及 AWS CloudFormation 有了更进一步的认识。接下来,您可以利用 AWS ECS 容器管理服务及 Docker 容器技术,更加轻松地构建和管理您的应用程序,发挥更大的效益。


作者介绍



李磊,AWS 解决方案架构师,负责基于 AWS 的云计算方案的架构设计,同时致力于 AWS 云服务在国内和全球的应用和推广。在大规模并发后台架构,电商系统,社交网络平台、互联网领域应用,DevOps 以及 Serverless 无服务器架构等领域有着广泛的设计与实践经验。在加入 AWS 之前超过十年的开发和架构设计经验, 带领团队攻克各种技术挑战,总是希望站在技术的最前沿。


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/using-amazon-ecs-to-build-private-docker-hub/


2019-11-13 08:00688

评论

发布
暂无评论
发现更多内容

软件需求分析报告完整版(软件项目套用原件)

金陵老街

软件设计 需求分析 软件需求设计

望繁信科技创始人索强出席2022福布斯中国·青年海归菁英100人评选颁奖典礼

望繁信科技

数字化转型 流程挖掘 流程资产 流程智能 望繁信科技

喜报丨时序数据库 IoTDB 荣获“创客北京 2024”创新创业大赛专项赛优胜奖

Apache IoTDB

软件测试学习笔记丨Selenium学习笔记:三种等待方式

测试人

软件测试

如何领导高级工程师团队

爱吃小舅的鱼

免费报名!第五届“医疗大数据学术交流及 Datathon 活动”诚邀您的参加

ModelWhale

Nacos改为MySQL数据源报错:No DataSource set

百度搜索:蓝易云

QCN9274-QCN6274: How Does 320MHz Bandwidth in the 6GHz Band Improve Data Transfer Speeds Compared to Previous WiFi Generations?

wallyslilly

qcn9274

微博热搜API:实时数据获取与处理

幂简集成

API 微博

低代码开发:数字化转型,轻松“点”到为止!

不在线第一只蜗牛

低代码

系统数据安全解决方案(医疗行业Word原件)

金陵老街

信息安全 数据安全 数据互联互通

HarmonyOS NEXT华为音乐焕新升级,打造高品质沉浸式“音乐厅”

最新动态

spring-kafka中ContainerProperties.AckMode详解

百度搜索:蓝易云

通过curl命令分析http接口请求各阶段的耗时等

百度搜索:蓝易云

第71期 | GPTSecurity周报

云起无垠

2025深圳国际耐火材料及工业陶瓷展会(6月)

秋硕展览

揭秘1024程序员节彩蛋:致敬鸿蒙生态一日千里的幕后英雄

最新动态

深入理解 JavaScript 中的剩余参数和扩展运算符

秃头小帅oi

可观测日北京|观测云:可观测性需要做到“三个一”

观测云

观测云

《使用Gin框架构建分布式应用》阅读笔记:p127-p142

codists

golang gin 编程人 codists

Ubuntu中设置代理的方式

百度搜索:蓝易云

Tomcat服务启动失败:java.lang.OutOfMemoryError: Java heap space

百度搜索:蓝易云

Apache Calcite 快速入门指南

端小强

Calcite

数据结构 - 树,三探之代码实现

EquatorCoco

Java 数据结构

Claude 大更新,AI 可模仿人类访问电脑;月之暗面招募微软亚研院谭旭,研发类 GPT- 4o 的端到端语音模型

声网

ETLCloud搭配MySQL | 让关系型数据库更智能

RestCloud

MySQL 数据库 sql ETL 数据集成

下一代 AI 陪伴 | 平等关系、长久记忆与情境共享 | 播客《编码人声》

声网

MatrixOne 助力 StoneCastle 打造高性能金融分析系统

MatrixOrigin

数据库 金融 HTAP

征程 6 环视快启 sample

地平线开发者

自动驾驶 算法

麦杰科技携手小伙伴,一起做那些“难而正确的事”

麦杰研究院

和鲸科技亮相重庆市医学会临床流行病学和循证医学分会 2024 学术年会,探索临床研究标准化新路径

ModelWhale

人工智能 大数据 大模型 临床医学

基于Amazon EC2 Container Service构建安全高可用的Docker私有库_语言 & 开发_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章