25、运行定制化的 Docker 注册表

运行定制化的 Docker 注册表

1. 运行个人注册表

1.1 重新引入镜像

对于刚开始使用或者用于开发目的的情况,启动个人注册表是个不错的选择。在这个过程中,我们会多次启动和重新启动提供注册表的容器,每次都会使用 registry:2 仓库提供的 Distribution 项目的特定版本。

个人注册表很少需要定制,在这种情况下,可以使用官方镜像。拉取镜像并启动个人注册表:

docker run -d --name personal_registry \
    -p 5000:5000 --restart=always \
    registry:2

需要注意的是,在编写本文时, latest 标签指的是实现 V1 注册表 API 的注册表的最后一个版本,而本章的示例除非另有说明,否则都需要 V2 API。

Distribution 项目运行在端口 5000 上,但客户端不会对位置做任何假设,默认会尝试连接端口 80(HTTP)。可以将主机上的端口 80 映射到容器上的端口 5000,但在这种情况下,应该直接映射端口 5000。每次连接到注册表时,都需要明确指定注册表运行的端口。

从注册表镜像启动的容器会将发送给它的仓库数据存储在挂载在 /var/lib/registry 的托管卷中,这意味着不必担心数据存储在主分层文件系统上。

一个空的注册表有点无趣,所以在继续之前,标记并推送一个镜像到其中。这里使用注册表镜像本身,但为了区分示例,使用不同的仓库名称:

docker tag registry:2 localhost:5000/distribution:2
docker push localhost:5000/distribution:2

push 命令会为上传到注册表的每个镜像层输出一行信息,最后输出镜像的摘要。如果愿意,可以删除本地的 localhost:5000/distribution:2 标签,然后尝试从注册表中拉取:

docker rmi localhost:5000/distribution:2
docker pull localhost:5000/distribution:2

1.2 介绍 V2 API

V2 注册表 API 是 RESTful 的。如果不熟悉 RESTful API,简单来说,RESTful API 是对超文本传输协议(HTTP)及其原语的一种模式化使用,用于访问和操作远程资源。关于这个主题有很多优秀的在线资源和书籍。在 Docker 注册表的情况下,这些资源包括标签、清单、Blob 和 Blob 上传。可以在 https://docs.docker.com/registry/spec/api/ 找到完整的注册表规范。

由于 RESTful API 使用 HTTP,可能需要花一些时间熟悉该协议的细节。本章的示例是完整的,不需要对 HTTP 有深入的了解也能跟上,但如果对背后的原理感到熟悉,会从这个过程中获得更多收获。

为了使用任何 RESTful 服务,需要一个 HTTP 客户端。一些经验丰富的读者可能知道如何使用原始 TCP 连接来发出 HTTP 请求,但大多数人不想处理协议的底层细节。虽然 Web 浏览器能够发出 HTTP 请求,但命令行工具将让你有能力充分使用 RESTful API。

本章的示例使用 cURL 命令行工具。因为这涉及到 Docker,所以应该在容器内部使用 cURL。这样使用 cURL 对 Docker 原生用户和 Boot2Docker 用户都适用。为此准备一个镜像(同时也可以练习 Dockerfile 技能):

FROM gliderlabs/alpine:latest
LABEL source=dockerinaction
LABEL category=utility
RUN apk --update add curl
ENTRYPOINT ["curl"]
CMD ["--help"]

构建镜像:

docker build -t dockerinaction/curl -f curl.df .

有了新的 dockerinaction/curl 镜像,就可以在示例中发出 cURL 命令,而不必担心 cURL 是否安装或安装的版本。使用新镜像并通过向运行的注册表发出一个简单请求来开始使用注册表 API:

docker run --rm --net host dockerinaction/curl -Is \
    http://localhost:5000/v2/ 

该请求将产生以下输出:

HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0

这个命令用于验证注册表是否正在运行 V2 注册表 API,并在 HTTP 响应头中返回特定的 API 版本。该请求的最后一部分 /v2/ 是 V2 API 上每个资源的前缀。

如果不小心向运行 V1 API 的注册表发出此请求,输出将如下所示:

HTTP/1.1 404 NOT FOUND
Server: gunicorn/19.1.1
Connection: keep-alive
Content-Type: text/html
Content-Length: 233

这个命令使用了 HTTP HEAD 请求来仅检索响应头。对该资源的成功 GET 请求将返回相同的头和空文档的响应体。

现在已经使用 cURL 验证了注册表确实在使用 V2 API,接下来可以做一些更有趣的事情。下一个命令将检索注册表中 distribution 仓库的标签列表:

docker run --rm -u 1000:1000 --net host \
    dockerinaction/curl -s http://localhost:5000/v2/distribution/tags/list

运行该命令应该会显示如下结果:

{"name":"distribution","tags":["2"]}

可以看到,注册表以 JSON 文档的形式响应了请求,该文档列出了 distribution 仓库中的标签。在这种情况下,只有一个标签 2 。JSON 文档是一种键值对的结构化文档,它使用花括号表示对象(包含另一组键值对),方括号表示列表,引号字符串用于标记元素和表示字符串值。

再次运行这个示例,但这次向仓库添加另一个标签以获得更有趣的结果:

docker tag \
    localhost:5000/distribution:2 \
    localhost:5000/distribution:two 
docker push localhost:5000/distribution:two
docker run --rm \
    -u 1000:1000 \ 
    --net host \ 
    dockerinaction/curl \
    -s http://localhost:5000/v2/distribution/tags/list

cURL 命令将返回如下输出:

{"name":"distribution","tags":["2","two"]}

从输出中可以清楚地看到,仓库包含了定义的两个标签。推送到该注册表中此仓库的每个不同标签都将在此列出。

1.3 定制镜像

后续内容将解释如何在注册表镜像的基础上进行扩展,从个人注册表发展到更高级的用例。在进行这些操作之前,需要对注册表镜像本身有更多了解。

这里将使用 Dockerfile 对注册表镜像进行定制。如果不熟悉 Dockerfile 语法,应该查看在线文档 https://docs.docker.com/reference/builder

关于该镜像,需要了解以下关键组件:
- 注册表的基础镜像是 Debian,并且已经更新了依赖项。
- 主程序名为 registry ,并且可以在 PATH 中找到。
- 默认配置文件是 config.yml

不同的项目维护者对最佳基础镜像有不同的看法。在 Docker 的情况下,Debian 是一个常见的选择。Debian 作为一个功能齐全的发行版,占用空间很小,在硬盘上只占用大约 125 MB。它还附带了一个流行的包管理器,因此安装或升级依赖项应该不会有问题。

主程序 registry 被设置为镜像的入口点。这意味着从该镜像启动容器时,可以省略任何命令参数以采用默认行为,或者直接在 docker run 命令的末尾添加自己的参数。

和所有 Docker 项目一样,Distribution 项目旨在提供合理的默认配置。该默认配置位于名为 config.yml 的文件中。顾名思义,配置是用 YAML 编写的。如果不熟悉 YAML,也不用担心,YAML 的设计旨在最大限度地提高人类可读性。如果感兴趣,可以在 http://yaml.org 找到几个 YAML 资源。

这个配置文件是本章的重点。有几种方法可以将自己的配置注入到镜像中。可以直接修改包含的文件,也可以使用绑定挂载卷用自己编写的文件覆盖该文件。在这种情况下,将自己的文件复制到另一个位置,并为新镜像设置一个新的默认命令。

配置文件包含九个顶级部分,每个部分定义了注册表的一个主要功能组件:
| 部分名称 | 功能描述 |
| — | — |
| version | 这是一个必需字段,指定配置版本(不是软件版本)。 |
| log | 此部分的配置控制 Distribution 项目产生的日志输出。 |
| storage | 存储配置控制图像的存储位置和方式。 |
| auth | 此配置控制注册表内的身份验证机制。 |
| middleware | 中间件配置是可选的,用于配置正在使用的存储、注册表或仓库中间件。 |
| reporting | 某些报告工具已与 Distribution 项目集成,包括 Bugsnag 和 NewRelic,此部分配置这些工具集。 |
| http | 此部分指定 Distribution 应如何在网络上提供服务。 |
| notifications | 与其他项目的 Webhook 式集成在此部分配置。 |
| redis | 最后,此部分提供 Redis 缓存的配置。 |

有了这些组件的了解,就可以通过定制注册表镜像来构建高级注册表用例了。需要记住的是,Distribution 项目正在快速发展。如果在按照说明操作时遇到问题,可以随时参考在线文档或查看项目本身 https://github.com/docker/distribution

2. 集中式注册表的增强功能

2.1 集中式注册表概述

启动未修改的注册表镜像的本地副本对于个人用途或测试很有效。当多个人需要访问同一个注册表时,就称为集中式注册表。接下来将介绍如何通过定制官方注册表镜像来实现集中式注册表。

为了让多个人能够访问注册表,它需要在网络上可用。可以通过将注册表容器映射到运行它的计算机的网络接口上的端口 80 来轻松实现这一点( docker run ... -p 80:5000 ... )。但引入对网络的依赖会带来一系列新的安全漏洞。从窥探到破坏镜像传输,中间人攻击可能会造成几个问题。添加传输层安全性将保护系统免受这些和其他攻击。

一旦客户端可以访问注册表,就需要确保只有合适的用户可以访问它,这就是身份验证。同时,任何服务所有者都会遇到的最不可避免的问题是客户端兼容性。当多个客户端连接到注册表时,需要考虑它们使用的 Docker 版本。支持多个客户端版本可能很棘手。

在进入下一种注册表类型之前,还会介绍生产注册表配置的最佳实践,包括强化和预防性维护步骤。大多数这些问题都集中在与客户端的交互上。虽然 Distribution 软件有一些工具来满足新的需求,但在系统中添加代理可以引入所需的灵活性来实现所有这些增强功能。

2.2 创建反向代理

使用合适的基础镜像和 Dockerfile 进行定制时,创建反向代理是一项快速的任务。反向代理配置将涉及两个容器,第一个将运行 NGINX 反向代理,第二个将运行注册表。反向代理容器将通过主机别名 registry 链接到注册表容器。

首先创建一个名为 basic-proxy.conf 的新文件,并包含以下配置:

upstream docker-registry {
  server registry:5000; 
}
server {
  listen 80; 
  # Use the localhost name for testing purposes
  server_name localhost;
  # A real deployment would use the real hostname where it is deployed
  # server_name mytotallyawesomeregistry.com;
  client_max_body_size 0;
  chunked_transfer_encoding on;
  # We’re going to forward all traffic bound for the registry
  location /v2/ { 
    proxy_pass                          http://docker-registry; 
    proxy_set_header  Host              $http_host;
    proxy_set_header  X-Real-IP         $remote_addr;
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
  }
}

NGINX 是一款复杂的软件,有很多专门介绍其使用的书籍,这里就不详细解释了。此配置中需要理解的部分已经进行了注释。这个配置将把端口 80 上、HTTP 主机为 localhost 且路径前缀为 /v2/ 的所有流量转发到 http://registry:5000 。这个配置将是后续对反向代理进行其他修改的基础。

有了反向代理配置后,需要构建一个新镜像。一个最小的 Dockerfile 就足够了,它应该从最新的 NGINX 镜像开始,并包含新的配置。基础 NGINX 镜像会处理所有标准的事情,比如暴露端口。创建一个名为 basic-proxy.df 的新文件,并粘贴以下 Dockerfile:

FROM nginx:latest
LABEL source=dockerinaction
LABEL category=infrastructure
COPY ./basic-proxy.conf /etc/nginx/conf.d/default.conf

在生产环境中,确实应该包含一个环境验证脚本,以确保容器已正确链接。但由于使用了 NGINX 的 upstream 指令,它会为你验证主机是否可以解析。

下面是一个 mermaid 流程图,展示了反向代理与注册表的关系:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    A[客户端]:::process -->|HTTP 请求| B(反向代理):::process
    B -->|转发请求 /v2/| C(注册表):::process
    C -->|响应| B
    B -->|返回响应| A

通过以上步骤,就可以创建一个反向代理来增强集中式注册表的功能。

2.3 集中式注册表的身份验证

在确保注册表可以通过网络被多客户端访问后,接下来要做的就是保证只有授权用户才能访问,这就需要进行身份验证。

2.3.1 身份验证的必要性

当注册表变为集中式供多人使用时,网络环境会变得复杂,安全风险增加。恶意用户可能会尝试非法访问注册表,获取或篡改镜像数据。身份验证可以有效防止这种情况发生,确保只有经过授权的用户能够进行操作。

2.3.2 实现身份验证的步骤

可以通过配置 config.yml 文件来实现身份验证。以下是一个简单的示例,假设使用基本的 HTTP 身份验证:

version: 0.1
log:
  level: debug
  formatter: text
  fields:
    service: registry
    environment: development
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
auth:
  htpasswd:
    realm: basic-realm
    path: /etc/docker/registry/htpasswd

在这个配置中, auth 部分指定了使用 htpasswd 进行身份验证。 realm 是身份验证的领域, path 是存储用户凭证的文件路径。

接下来,需要创建 htpasswd 文件并添加用户。可以使用 htpasswd 工具来完成这个任务:

htpasswd -Bbn username password > /etc/docker/registry/htpasswd

username password 替换为实际的用户名和密码。

最后,使用修改后的配置文件启动注册表容器:

docker run -d -p 5000:5000 --restart=always \
  -v /path/to/config.yml:/etc/docker/registry/config.yml \
  -v /path/to/htpasswd:/etc/docker/registry/htpasswd \
  registry:2

这样,当用户尝试访问注册表时,就需要提供正确的用户名和密码进行身份验证。

2.4 处理客户端兼容性问题

在集中式注册表环境中,多个客户端可能使用不同版本的 Docker,这就会带来客户端兼容性问题。以下是一种处理该问题的方法。

2.4.1 问题分析

不同版本的 Docker 客户端可能对注册表 API 的支持有所不同,例如某些旧版本的客户端可能不支持 V2 API,或者对某些 API 功能的实现存在差异。这可能导致客户端在与注册表交互时出现错误。

2.4.2 解决方案

可以通过配置反向代理来处理客户端兼容性问题。反向代理可以根据客户端的请求特征,将请求转发到不同版本的注册表 API 端点。例如,对于旧版本的客户端,可以将请求转发到支持 V1 API 的端点;对于新版本的客户端,将请求转发到支持 V2 API 的端点。

以下是修改后的 basic-proxy.conf 配置文件示例:

upstream docker-registry-v1 {
  server registry-v1:5000; 
}
upstream docker-registry-v2 {
  server registry-v2:5000; 
}
server {
  listen 80; 
  server_name localhost;
  client_max_body_size 0;
  chunked_transfer_encoding on;
  location /v1/ { 
    proxy_pass                          http://docker-registry-v1; 
    proxy_set_header  Host              $http_host;
    proxy_set_header  X-Real-IP         $remote_addr;
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
  }
  location /v2/ { 
    proxy_pass                          http://docker-registry-v2; 
    proxy_set_header  Host              $http_host;
    proxy_set_header  X-Real-IP         $remote_addr;
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
  }
}

在这个配置中,根据请求路径的前缀 /v1/ /v2/ ,将请求分别转发到不同版本的注册表。

2.5 生产注册表配置的最佳实践

在生产环境中使用集中式注册表时,需要遵循一些最佳实践,以确保注册表的稳定性、安全性和性能。

2.5.1 强化安全措施
  • 使用 HTTPS :为了防止中间人攻击和数据泄露,应该使用 HTTPS 来加密客户端与注册表之间的通信。可以通过配置反向代理来实现 HTTPS,例如使用 Let’s Encrypt 免费证书。
  • 定期更新软件 :及时更新注册表软件和依赖项,以修复已知的安全漏洞。
  • 限制访问权限 :只允许必要的用户和服务访问注册表,并且根据用户角色分配不同的权限。
2.5.2 预防性维护
  • 数据备份 :定期备份注册表中的镜像数据,以防止数据丢失。可以使用外部存储设备或云存储来存储备份数据。
  • 监控和日志记录 :建立监控系统,实时监控注册表的性能和状态。同时,详细记录所有操作日志,以便在出现问题时进行排查。
  • 性能优化 :根据实际使用情况,调整注册表的配置参数,例如缓存大小、并发连接数等,以提高性能。

以下是一个生产注册表配置的检查清单:
| 项目 | 描述 |
| — | — |
| 启用 HTTPS | 确保客户端与注册表之间的通信加密 |
| 定期更新 | 保持软件和依赖项为最新版本 |
| 数据备份 | 定期备份镜像数据 |
| 监控和日志 | 建立监控系统并记录详细日志 |
| 性能优化 | 根据使用情况调整配置参数 |

2.6 集中式注册表的可扩展性配置

随着使用人数和镜像数量的增加,集中式注册表需要具备良好的可扩展性,以满足不断增长的需求。

2.6.1 水平扩展

可以通过增加注册表实例的数量来实现水平扩展。每个实例可以处理一部分请求,从而提高整体的处理能力。可以使用负载均衡器将客户端请求均匀地分配到各个注册表实例上。

以下是一个使用 Nginx 作为负载均衡器的示例配置:

upstream docker-registry-cluster {
  server registry-1:5000;
  server registry-2:5000;
  server registry-3:5000;
}
server {
  listen 80; 
  server_name localhost;
  client_max_body_size 0;
  chunked_transfer_encoding on;
  location /v2/ { 
    proxy_pass                          http://docker-registry-cluster; 
    proxy_set_header  Host              $http_host;
    proxy_set_header  X-Real-IP         $remote_addr;
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
  }
}
2.6.2 垂直扩展

垂直扩展是指增加单个注册表实例的硬件资源,例如 CPU、内存和存储。可以通过升级服务器硬件或调整云服务实例的规格来实现垂直扩展。

2.7 通过通知进行集成

注册表可以通过通知功能与其他系统进行集成,例如在镜像上传或删除时触发特定的操作。

2.7.1 通知的配置

可以在 config.yml 文件中配置通知功能。以下是一个示例:

notifications:
  endpoints:
    - name: webhook
      url: http://example.com/webhook
      headers:
        Authorization: [Bearer <token>]
      timeout: 500ms
      threshold: 5
      backoff: 1s
      disabled: false

在这个配置中,当注册表发生特定事件时,会向 http://example.com/webhook 发送通知。

2.7.2 通知的使用场景
  • 持续集成/持续部署(CI/CD) :当新镜像上传到注册表时,触发 CI/CD 流程,自动进行测试和部署。
  • 监控和报警 :当镜像删除或出现异常情况时,发送通知到监控系统,及时进行处理。

以下是一个 mermaid 流程图,展示了通知集成的过程:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    A(注册表):::process -->|事件触发| B(通知系统):::process
    B -->|发送通知| C(外部系统):::process
    C -->|处理通知| D(执行操作):::process

通过以上步骤和配置,可以构建一个功能强大、安全可靠且可扩展的集中式 Docker 注册表,满足不同场景下的使用需求。

基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值