docker distritubion源码分析之二:storage driver详解(基于2.6.0版本)

来源:互联网 发布:c语言实验交换字母 编辑:程序博客网 时间:2024/05/01 00:59

在上一篇文章中,分析了docker distribution的启动过程,本篇着重分析distribution使用storage driver的原理。


在NewApp函数中,会初始化app.driver:

app.driver, err = factory.Create(config.Storage.Type(), storageParams)if err != nil {// TODO(stevvooe): Move the creation of a service into a protected// method, where this is created lazily. Its status can be queried via// a health check.panic(err)}

Create函数在registry/storage/factory/factory.go中,它通过config.Storage的Type从driverFactories这个数组缓存中取出相对应的driverFactory,然后调用该driverFactory的Create函数,创建对应的StorageDriver:

func Create(name string, parameters map[string]interface{}) (storagedriver.StorageDriver, error) {driverFactory, ok := driverFactories[name]if !ok {return nil, InvalidStorageDriverError{name}}return driverFactory.Create(parameters)}

而driverFactories数组是通过各个storage driver在启动时自动执行的init()函数中调用factory.Registry函数来初始化的:

func Register(name string, factory StorageDriverFactory) {if factory == nil {panic("Must not provide nil StorageDriverFactory")}_, registered := driverFactories[name]if registered {panic(fmt.Sprintf("StorageDriverFactory named %s already registered", name))}driverFactories[name] = factory}

以s3 driver为例,在main函数执行之前,就会先执行registry/storage/s3-aws/s3.go中的init函数,把自己注册到driverFactories数组中:

func init() {
……// Register this as the default s3 driver in addition to s3awsfactory.Register("s3", &s3DriverFactory{})factory.Register(driverName, &s3DriverFactory{})}

这样,如果在配置文件中配置了s3 driver的话,调用driverFactory.Create函数就会调用到s3-aws/s3.go中的Create函数,进而调用到FromParameters函数:

func (factory *s3DriverFactory) Create(parameters map[string]interface{}) (storagedriver.StorageDriver, error) {return FromParameters(parameters)}

在FromParameters函数中,会根据配置文件中配置的s3的accessKey、regionName、bucket等一系列参数来完成初始化工作,最后调用New(params)函数来创建并返回最终的s3 storage driver:

// New constructs a new Driver with the given AWS credentials, region, encryption flag, and// bucketNamefunc New(params DriverParameters) (*Driver, error) {……d := &driver{S3:        s3obj,Bucket:    params.Bucket,ChunkSize: params.ChunkSize,Encrypt:   params.Encrypt,KeyID:     params.KeyID,MultipartCopyChunkSize:      params.MultipartCopyChunkSize,MultipartCopyMaxConcurrency: params.MultipartCopyMaxConcurrency,MultipartCopyThresholdSize:  params.MultipartCopyThresholdSize,RootDirectory:               params.RootDirectory,StorageClass:                params.StorageClass,ObjectACL:                   params.ObjectACL,}return &Driver{baseEmbed: baseEmbed{Base: base.Base{StorageDriver: d,},},}, nil}

这样,就完成了storage driver的初化化工作,driver最终保存在了app.driver变量中。

下面,以manifest的put为例,讲述registry镜像至storage的过程。

通过NewApp函数中的app.register(v2.RouteNameManifest, manifestDispatcher)这段代码,所有manifest的API请求都会registry/handlers/manifests.go中的manifestDispatcher这个函数来处理。在这个函数中,定义了http router的处理handler:

mhandler := handlers.MethodHandler{"GET":  http.HandlerFunc(manifestHandler.GetManifest),"HEAD": http.HandlerFunc(manifestHandler.GetManifest),}if !ctx.readOnly {mhandler["PUT"] = http.HandlerFunc(manifestHandler.PutManifest)mhandler["DELETE"] = http.HandlerFunc(manifestHandler.DeleteManifest)}

manifest的PUT请求由manifestHandler.PutManifest来处理。

在PutManifest函数中,首先会调用imh.Repository.Manifests函数生成manifestService:

manifests, err := imh.Repository.Manifests(imh)if err != nil {imh.Errors = append(imh.Errors, err)return}

其中,imh.Repository变量是由registry启动时构建在context中的,这段代码会调用到registry/storage/registry.go中的Manifests函数,返回manifestStore结构体变量,manifestStore实现了manifests.go中的ManifestService接口。

之后,通过调用manifests.Put,调用到registry/storage/manifeststore.go中的Put函数。

_, err = manifests.Put(imh, manifest, options...)if err != nil {

在该Put函数中,会根据manifest的type是schemal1还是schema2,调用其相应的Put函数。以schema2为例,调用到registry/storage/schema2manifesthandler.go中的Put函数。

在这个Put函数中,进一步会调用到ms.blobStore.Put函数:

revision, err := ms.blobStore.Put(ctx, mt, payload)if err != nil {context.GetLogger(ctx).Errorf("error putting payload into blobstore: %v", err)return "", err}

接下来,在registry/storage/blobstore.go中最终会调用到bs.driver.PutContent函数:

return distribution.Descriptor{Size: int64(len(p)),// NOTE(stevvooe): The central blob store firewalls media types from// other users. The caller should look this up and override the value// for the specific repository.MediaType: "application/octet-stream",Digest:    dgst,}, bs.driver.PutContent(ctx, bp, p)

如果storage driver是s3,那么会调用到registry/storage/driver/s3-aws/s3.go中的PutContent函数,在这个函数中,最终会调用s3 sdk的PutObject接口,完成数据的上传工作:

// PutContent stores the []byte content at a location designated by "path".func (d *driver) PutContent(ctx context.Context, path string, contents []byte) error {_, err := d.S3.PutObject(&s3.PutObjectInput{Bucket:               aws.String(d.Bucket),Key:                  aws.String(d.s3Path(path)),ContentType:          d.getContentType(),ACL:                  d.getACL(),ServerSideEncryption: d.getEncryptionMode(),SSEKMSKeyId:          d.getSSEKMSKeyID(),StorageClass:         d.getStorageClass(),Body:                 bytes.NewReader(contents),})return parseError(path, err)}

0 0
原创粉丝点击