镜像仓库服务是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] = ®istrytypes.IndexInfo{
Name: r,
Mirrors: make([]string, 0),
Secure: false,
Official: false,
}
}
}
// Configure public registry.
//官方仓库
config.IndexConfigs[IndexName] = ®istrytypes.IndexInfo{
Name: IndexName,
Mirrors: config.Mirrors,
Secure: true,
Official: true,
}
return config
}
可以看到如果没有配置私有仓库,也没有配置仓库镜像地址,config的IndexConfigs只有一个对象,以docker.io为key的官方仓库IndexInfo;如果配置了私有仓库地址,将添加以私有仓库地址为key的IndexInfo。如果配置了镜像,会初始化官方仓库IndexInfo的Mirrors字段。