网站首页 > 技术文章 正文
简要:本文主要是对镜像结构及Registry API使用进行了总结,对registry启动GC和Serve命令做出了解析。
当我们使用Docker命令时,Push和Pull镜像操作会将镜像从哪里推送和拉取,镜像的结构是什么,为什么不能简单的用云盘这样的存储直接存储镜像?看完这篇文章,就能有个大概的了解了。
一、API V2
Docker Registry HTTP API是镜像到镜像仓库的协议,它与管理docker镜像和启用分布式的镜像仓库实例相互交互。而我们正在用的正是Docker Registry HTTP API V2。
虽然V1版本仍可用,但是和最新版本有整体架构上的问题,主要是因为V2改变了镜像的格式,详见docker/docker#8093
新的镜像manifest简化了镜像定义和提升了安全性。而API V2正是工作在新的manifest基础上,提高性能、减少带宽使用和减少后端故障的可能性。
这个特性是在release v1.3.0版本开始实现,只不过我们现在提到的V2是指Docker Manifest V2 schema 2,主要实现两点:
- 允许多平台镜像,特定平台版本的镜像元数据
- 支持将Docker引擎指向可寻址的内容镜像,通过支持镜像配置被Hash成镜像ID的镜像模型
1.1、媒体类型
- application/vnd.docker.distribution.manifest.v1+json: schema1 (existing manifest format)
- application/vnd.docker.distribution.manifest.v2+json: New image manifest format (schemaVersion = 2)
- application/vnd.docker.distribution.manifest.list.v2+json: Manifest list, aka “fat manifest”
- application/vnd.docker.container.image.v1+json: Container config JSON
- application/vnd.docker.image.rootfs.diff.tar.gzip: “Layer”, as a gzipped tar
- application/vnd.docker.image.rootfs.foreign.diff.tar.gzip: “Layer”, as a gzipped tar that should never be pushed
- application/vnd.docker.plugin.v1+json: Plugin config JSON
1.2、元数据(manifest)列表
举个栗子
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 7143,
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
"platform": {
"architecture": "ppc64le",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 7682,
"digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
"platform": {
"architecture": "amd64",
"os": "linux",
"features": [
"sse4"
]
}
}
]
}
- schemaVersion(int):镜像元数据的架构版本,现在是2
- mediaType(string):元数据列表的MIME类型,应该被设置为application/vnd.docker.distribution.manifest.list.v2+json
- manifests(array):包括多平台的元数据列表 mediaType:对象的MIME类型,通常是application/vnd.docker.distribution.manifest.v2+json,但如果支持 Schema 1,也能支持application/vnd.docker.distribution.manifest.v1+json size:对象大小,客户端在验证之前可以比较大小,如果大小不符,则内容不能被信任 digest:对象的摘要 platform:描述了元数据中镜像的运行平台
1.3、镜像元数据(manifest)
举个栗子
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 7023,
"digest": "sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 32654,
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 16724,
"digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 73109,
"digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736"
}
]
}
- schemaVersion:元数据版本
- mediaType:元数据列表的MIME类型,应该被设置为application/vnd.docker.distribution.manifest.v2+json
- config:通过摘要引用容器的配置对象,是runtime用来设置容器的Blob。 mediaType:指定对象的MIME类型,应该被设置为application/vnd.docker.container.image.v1+json size:对象的大小 digest:对象的摘要
- layer:图层列表从base镜像开始(与Schmea 1相反) mediaType:指定对象的MIME类型,通常被设置为application/vnd.docker.image.rootfs.diff.tar.gzip,如果设置为application/vnd.docker.image.rootfs.foreign.diff.tar.gzip,会从远程拉取 size:对象大小 digest:对象摘要 urls:提供可以从中获取内容的 URL 列表。 必须根据 digest 和 size 验证内容。 此字段是可选的且不常见。
1.4、小结
到这里,我们能大概知道了docker的API升级了,现在在用的API V2,底层用的元数据是Manifest V2 schema 2,了解了MIME类型在镜像中的区别和应用。
二、启动流程
在cmd/registry/main.go文件中有启动registry的命令
func main() {
registry.RootCmd.Execute()
}
在RootCmd命令下有两个子命令:
- ServeCmd:服务监听
- GCCmd:垃圾回收
2.1、GC
2.1.1、背景知识
docker镜像是分层的,registry在存储镜像时,将docker镜像分成2个部分:
- 镜像元数据(manifest):存储在docker/registry/v2/repositories目录中,在这里能看到registry上的目录、项目中的镜像、镜像到layer的索引信息
- blobs:存储在docker/registry/v2/blobs目录中,在这里按照00-ff分目录存储了所有镜像的layer。
例如有2个镜像使用了同一个基础镜像,那么在registry上存储时,blobs只有一份数据,而镜像的元数据的部分索引会指向相同的layer
举个栗子:
初始状态,A、B两个镜像,都是基于layer b所做的镜像,A引用a、b;B引用b、c
A -----> b <----- B
| |
|---->a c<----|
之后删除镜像B
A -----> b B
|
|---->a c
此时layer c实际上没有在用了,但是registry在删除镜像B时,只是会删除B的元数据,并不会主动删除layer c,所以需要GC。
2.1.2、GC过程
registry的GC使用“标记-清理”法
1、标记:registry扫描元数据,元数据能索引到的blob标记为不能删除
2、清理:registry扫描所有的blobs,如果blobs没有被标记,则删除
2.2、Serve
服务启动需要配置文件,这部分就不提了,配置内容包括日志、存储、验证方式、消息通知、监控、监听地址等。
// setup context
ctx := dcontext.WithVersion(dcontext.Background(), version.Version)
// 1、从参数或环境变量解析配置文件
config, err := resolveConfiguration(args)
if err != nil {
fmt.Fprintf(os.Stderr, "configuration error: %v\n", err)
cmd.Usage()
os.Exit(1)
}
if config.HTTP.Debug.Addr != "" {
go func(addr string) {
logrus.Infof("debug server listening %v", addr)
if err := http.ListenAndServe(addr, nil); err != nil {
logrus.Fatalf("error listening on debug interface: %v", err)
}
}(config.HTTP.Debug.Addr)
}
// 2、通过配置文件注册registry
registry, err := NewRegistry(ctx, config)
if err != nil {
logrus.Fatalln(err)
}
// 3、如果有监控,则启动prometheus
if config.HTTP.Debug.Prometheus.Enabled {
path := config.HTTP.Debug.Prometheus.Path
if path == "" {
path = "/metrics"
}
logrus.Info("providing prometheus metrics on ", path)
http.Handle(path, metrics.Handler())
}
// 4、启动registry
if err = registry.ListenAndServe(); err != nil {
logrus.Fatalln(err)
}
启动是初始化Registry实例
registry, err := NewRegistry(ctx, config)
2.2.1、初始化实例
func NewRegistry(ctx context.Context, config *configuration.Configuration) (*Registry, error) {
var err error
// 1、注册日志
ctx, err = configureLogging(ctx, config)
if err != nil {
return nil, fmt.Errorf("error configuring logger: %v", err)
}
configureBugsnag(config)
uuid.Loggerf = dcontext.GetLogger(ctx).Warnf
// 2、生成app实例
app := handlers.NewApp(ctx, config)
// 3、注册健康检查:对象存储、本地文件、http、tcp
app.RegisterHealthChecks()
// 4、配置reporter
handler := configureReporting(app)
// 5、注册接口 /
handler = alive("/", handler)
// 6、注册健康检查接口
handler = health.Handler(handler)
// 7、中间件recover
handler = panicHandler(handler)
if !config.Log.AccessLog.Disabled {
handler = gorhandlers.CombinedLoggingHandler(os.Stdout, handler)
}
server := &http.Server{
Handler: handler,
}
return &Registry{
app: app,
config: config,
server: server,
}, nil
}
健康检查配置是在配置文件中health中进行配置。
而初始化app实例这部分代码可以自己了解,里面主要做了注册API接口、账号的鉴权等
- 上一篇: ElasticSearch知识day04
- 下一篇: Axios API详细介绍及使用
猜你喜欢
- 2024-11-20 抖音 Android 性能优化系列:启动优化实践
- 2024-11-20 Restic设计原理
- 2024-11-20 前端必读榜——如何在JavaScript中用SpreadJS导入/导出Excel文件
- 2024-11-20 Axios API详细介绍及使用
- 2024-11-20 ElasticSearch知识day04
- 2024-11-20 详解Oracle 11g如何快速定位到lobsegment、lobindex对应的表
- 2024-11-20 前端必读:如何在 JavaScript 中使用SpreadJS导入和导出 Excel 文件
- 2024-11-20 前端文件下载的几种方式
- 2024-11-20 JavaScript奇淫技巧:20行代码,实现屏幕录像
- 2024-11-20 Axure高级教程:模拟Axure文件上传进度条效果
- 标签列表
-
- content-disposition (47)
- nth-child (56)
- math.pow (44)
- 原型和原型链 (63)
- canvas mdn (36)
- css @media (49)
- promise mdn (39)
- readasdataurl (52)
- if-modified-since (49)
- css ::after (50)
- border-image-slice (40)
- flex mdn (37)
- .join (41)
- function.apply (60)
- input type number (64)
- weakmap (62)
- js arguments (45)
- js delete方法 (61)
- blob type (44)
- math.max.apply (51)
- js (44)
- firefox 3 (47)
- cssbox-sizing (52)
- js删除 (49)
- js for continue (56)
- 最新留言
-