镜像仓库服务是docker对镜像仓库操作(如:拉取,提交,搜索等)的接口抽象,实现主要在docker目录下的registry包,下面是Service接口的定义,实现在docker\registry\service.go:

// Service is the interface defining what a registry service should implement.
type Service interface {
    Auth(ctx context.Context, authConfig *types.AuthConfig, userAgent string) (status, token string, err error)
    LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error)
    LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error)
    ResolveRepository(name reference.Named) (*RepositoryInfo, error)
    ResolveIndex(name string) (*registrytypes.IndexInfo, error)
    Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error)
    ServiceConfig() *registrytypes.ServiceConfig
    TLSConfig(hostname string) (*tls.Config, error)
}

该接口有一个默认实现类(有一个config成员),同时也有一个返回该类对象的工厂函数NewService:

// DefaultService is a registry service. It tracks configuration data such as a list
// of mirrors.
type DefaultService struct {
    config *serviceConfig
}
// NewService returns a new instance of DefaultService ready to be
// installed into an engine.
//在docker\cmd\dockerd\daemon.go的start被调用
func NewService(options ServiceOptions) *DefaultService {
    return &DefaultService{
        config: newServiceConfig(options),
    }
}

下面是docker的deamon程序初始化一个镜像仓库服务的函数调用过程:
这里写图片描述
可以发现在registry包下config.go的InstallCliFlags函数和service.go的NewService函数共同完成镜像服务对象的初始化,InstallCliFlags获取选项参数ServiceOptions对象被作为调用NewService的参数,并初始化DefaultService的config成员。我们看下docker\registry\config.go下的InstallCliFlags函数:

// InstallCliFlags adds command-line options to the top-level flag parser for
// the current process.
func (options *ServiceOptions) InstallCliFlags(flags *pflag.FlagSet) {
    mirrors := opts.NewNamedListOptsRef("registry-mirrors", &options.Mirrors, ValidateMirror)
    insecureRegistries := opts.NewNamedListOptsRef("insecure-registries", &options.InsecureRegistries, ValidateIndexName)

    flags.Var(mirrors, "registry-mirror", "Preferred Docker registry mirror")
    flags.Var(insecureRegistries, "insecure-registry", "Enable insecure registry communication")

    options.installCliPlatformFlags(flags)
}

// installCliPlatformFlags handles any platform specific flags for the service.
func (options *ServiceOptions) installCliPlatformFlags(flags *pflag.FlagSet) {
    flags.BoolVar(&options.V2Only, "disable-legacy-registry", false, "Disable contacting legacy registries")
}

我们在看下ServiceOption:

// ServiceOptions holds command line options.
type ServiceOptions struct {
    Mirrors            []string `json:"registry-mirrors,omitempty"`
    InsecureRegistries []string `json:"insecure-registries,omitempty"`

    // V2Only controls access to legacy registries.  If it is set to true via the
    // command line flag the daemon will not attempt to contact v1 legacy registries
    V2Only bool `json:"disable-legacy-registry,omitempty"`
}

如果熟悉docker的这个几个选项参数就知道通过registry-mirrors可以传入仓库镜像地址,insecure-registry可以传入私有仓库地址,disable-legacy-registry可以禁用V1仓库。
我们回到NewService,可以看到以ServiceOptions为参数,调用newServiceConfig,返回的对象初始化DefaultService的config成员,config是个serviceConfig对象:

// ServiceConfig stores daemon registry services configuration.
type ServiceConfig struct {
    InsecureRegistryCIDRs []*NetIPNet           `json:"InsecureRegistryCIDRs"`
    IndexConfigs          map[string]*IndexInfo `json:"IndexConfigs"`
    Mirrors               []string
}
// serviceConfig holds daemon configuration for the registry service.
type serviceConfig struct {
    registrytypes.ServiceConfig
    V2Only bool
}

注释直译过来就是镜像仓库服务的配置,存储的是镜像仓库索引信息和仓库地址镜像,我们看下newServiceConfig是如何初始化这个ServiceConfig对象的:


var (
    // DefaultNamespace is the default namespace
    DefaultNamespace = "docker.io"
    // DefaultRegistryVersionHeader is the name of the default HTTP header
    // that carries Registry version info
    DefaultRegistryVersionHeader = "Docker-Distribution-Api-Version"

    // IndexServer is the v1 registry server used for user auth + account creation
    IndexServer = DefaultV1Registry.String() + "/v1/"
    // IndexName is the name of the index
    IndexName = "docker.io"

    // NotaryServer is the endpoint serving the Notary trust server
    NotaryServer = "https://notary.docker.io"

    // DefaultV1Registry is the URI of the default v1 registry
    DefaultV1Registry = &url.URL{
        Scheme: "https",
        Host:   "index.docker.io",
    }

    // DefaultV2Registry is the URI of the default v2 registry
    DefaultV2Registry = &url.URL{
        Scheme: "https",
        Host:   "registry-1.docker.io",
    }
)
// newServiceConfig returns a new instance of ServiceConfig
func newServiceConfig(options ServiceOptions) *serviceConfig {
    // Localhost is by default considered as an insecure registry
    // This is a stop-gap for people who are running a private registry on localhost (especially on Boot2docker).
    //
    // TODO: should we deprecate this once it is easier for people to set up a TLS registry or change
    // daemon flags on boot2docker?
    options.InsecureRegistries = append(options.InsecureRegistries, "127.0.0.0/8")

    config := &serviceConfig{
        ServiceConfig: registrytypes.ServiceConfig{
            InsecureRegistryCIDRs: make([]*registrytypes.NetIPNet, 0),
            IndexConfigs:          make(map[string]*registrytypes.IndexInfo, 0),
            // Hack: Bypass setting the mirrors to IndexConfigs since they are going away
            // and Mirrors are only for the official registry anyways.
            Mirrors: options.Mirrors,
        },
        V2Only: options.V2Only,
    }
    // Split --insecure-registry into CIDR and registry-specific settings.
        //私有仓库,私有仓库是没有镜像的
    for _, r := range options.InsecureRegistries {
        // Check if CIDR was passed to --insecure-registry
        _, ipnet, err := net.ParseCIDR(r)
        if err == nil {
            // Valid CIDR.
            config.InsecureRegistryCIDRs = append(config.InsecureRegistryCIDRs, (*registrytypes.NetIPNet)(ipnet))
        } else {
            // Assume `host:port` if not CIDR.
            config.IndexConfigs[r] = &registrytypes.IndexInfo{
                Name:     r,
                Mirrors:  make([]string, 0),
                Secure:   false,
                Official: false,
            }
        }
    }

    // Configure public registry.
    //官方仓库
    config.IndexConfigs[IndexName] = &registrytypes.IndexInfo{
        Name:     IndexName,
        Mirrors:  config.Mirrors,
        Secure:   true,
        Official: true,
    }

    return config
}

可以看到如果没有配置私有仓库,也没有配置仓库镜像地址,config的IndexConfigs只有一个对象,以docker.io为key的官方仓库IndexInfo;如果配置了私有仓库地址,将添加以私有仓库地址为key的IndexInfo。如果配置了镜像,会初始化官方仓库IndexInfo的Mirrors字段。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐