Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: support registry mirrors #2874

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions ctrd/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,20 @@ func (c *Client) PushImage(ctx context.Context, ref string, authConfig *types.Au
return nil
}

// ResolveImage attempts to resolve the image reference into a name and descriptor.
func (c *Client) ResolveImage(ctx context.Context, ref string, authConfig *types.AuthConfig) (name string, desc ocispec.Descriptor, err error) {
resolver, err := c.getResolver(authConfig, ref, docker.ResolverOptions{})
if err != nil {
return "", ocispec.Descriptor{}, err
}

name, desc, err = resolver.Resolve(ctx, ref)
if err != nil {
err = errors.Wrapf(err, "failed to resolve reference %q", ref)
}
return
}

// FetchImage fetches image content from the remote repository.
func (c *Client) FetchImage(ctx context.Context, ref string, authConfig *types.AuthConfig, stream *jsonstream.JSONStream) (containerd.Image, error) {
wrapperCli, err := c.Get(ctx)
Expand Down
3 changes: 3 additions & 0 deletions ctrd/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/snapshots"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)

// APIClient defines common methods of containerd api client
Expand Down Expand Up @@ -79,6 +80,8 @@ type ImageAPIClient interface {
ListImages(ctx context.Context, filter ...string) ([]containerd.Image, error)
// FetchImage fetchs image content by the given reference.
FetchImage(ctx context.Context, ref string, authConfig *types.AuthConfig, stream *jsonstream.JSONStream) (containerd.Image, error)
// ResolveImage attempts to resolve the image reference into a name and descriptor.
ResolveImage(ctx context.Context, ref string, authConfig *types.AuthConfig) (name string, desc ocispec.Descriptor, err error)
// RemoveImage removes the image by the given reference.
RemoveImage(ctx context.Context, ref string) error
// ImportImage creates a set of images by tarstream.
Expand Down
4 changes: 2 additions & 2 deletions daemon/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ type Config struct {
// Default log configuration
DefaultLogConfig types.LogConfig `json:"default-log-config,omitempty"`

// RegistryService
RegistryService types.RegistryServiceConfig `json:"registry-service,omitempty" `
// RegistryMirrors is a list of registry URLs that act as a mirror for the default registry.
RegistryMirrors []string `json:"registry-mirrors,omitempty"`

// oom_score_adj for the daemon
OOMScoreAdjust int `json:"oom-score-adjust,omitempty"`
Expand Down
27 changes: 0 additions & 27 deletions daemon/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,33 +118,6 @@ func TestConfigValidate(t *testing.T) {
cfg = &Config{
DefaultRegistry: "registry.hub.docker.com",
DefaultRegistryNS: "library",
RegistryService: types.RegistryServiceConfig{
AllowNondistributableArtifactsCIDRs: []string{
"::1/128",
"127.0.0.0/8",
},
AllowNondistributableArtifactsHostnames: []string{
"registry.internal.corp.example.com:3000",
"[2001:db8:a0b:12f0::1]:443",
},
InsecureRegistryCIDRs: []string{
"insecure.hub.docker.com",
},
IndexConfigs: map[string]types.IndexInfo{
"127.0.0.1:5000": {
Name: "127.0.0.1:5000",
Mirrors: []string{
"https://hub-mirror.corp.example.com:5000/",
},
Secure: false,
Official: false,
},
},
Mirrors: []string{
"https://[2001:db8:a0b:12f0::1]/",
"https://hub-mirror.corp.example.com:5000/",
},
},
}
assert.Equal(nil, cfg.Validate())

Expand Down
79 changes: 72 additions & 7 deletions daemon/mgr/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"path"
"strings"
"time"

Expand Down Expand Up @@ -45,6 +46,9 @@ var acceptedImageFilterTags = map[string]bool{

// ImageMgr as an interface defines all operations against images.
type ImageMgr interface {
// LookupImageReferences find possible image reference list.
LookupImageReferences(ref string) []string

// PullImage pulls images from specified registry.
PullImage(ctx context.Context, ref string, authConfig *types.AuthConfig, out io.Writer) error

Expand Down Expand Up @@ -98,6 +102,9 @@ type ImageManager struct {
// DefaultNamespace is the default namespace used in DefaultRegistry.
DefaultNamespace string

// RegistryMirrors is a list of registry URLs that act as a mirror for the default registry.
RegistryMirrors []string

// client is a interface to the containerd client.
// It is used to interact with containerd.
client ctrd.APIClient
Expand All @@ -122,6 +129,7 @@ func NewImageManager(cfg *config.Config, client ctrd.APIClient, eventsService *e
mgr := &ImageManager{
DefaultRegistry: cfg.DefaultRegistry,
DefaultNamespace: cfg.DefaultRegistryNS,
RegistryMirrors: cfg.RegistryMirrors,

client: client,
localStore: store,
Expand All @@ -135,14 +143,45 @@ func NewImageManager(cfg *config.Config, client ctrd.APIClient, eventsService *e
return mgr, nil
}

// PullImage pulls images from specified registry.
func (mgr *ImageManager) PullImage(ctx context.Context, ref string, authConfig *types.AuthConfig, out io.Writer) error {
newRef := addDefaultRegistryIfMissing(ref, mgr.DefaultRegistry, mgr.DefaultNamespace)
namedRef, err := reference.Parse(newRef)
if err != nil {
return err
// LookupImageReferences find possible image reference list.
func (mgr *ImageManager) LookupImageReferences(ref string) []string {
var (
registry string
remainder string
)

// extract the domain field
idx := strings.IndexRune(ref, '/')
if idx != -1 && strings.ContainsAny(ref[:idx], ".:") {
registry, remainder = ref[:idx], ref[idx+1:]
} else {
remainder = ref
}

// create a list of reference name in order of RegistryMirrors, DefaultRegistry
// for partial reference like 'ns/ubuntu', 'ubuntu'
var fullRefs []string

// if the domain field is empty, concat the ref with registry mirror urls.
if registry == "" {
for _, reg := range mgr.RegistryMirrors {
fullRefs = append(fullRefs, path.Join(reg, ref))
}
registry = mgr.DefaultRegistry
}

// attach the default namespace if the registry match the default registry.
if registry == mgr.DefaultRegistry && !strings.ContainsAny(remainder, "/") {
remainder = mgr.DefaultNamespace + "/" + remainder
}

fullRefs = append(fullRefs, registry+"/"+remainder)

return fullRefs
}

// PullImage pulls images from specified registry.
func (mgr *ImageManager) PullImage(ctx context.Context, ref string, authConfig *types.AuthConfig, out io.Writer) error {
pctx, cancel := context.WithCancel(ctx)
stream := jsonstream.New(out, nil)

Expand All @@ -166,7 +205,33 @@ func (mgr *ImageManager) PullImage(ctx context.Context, ref string, authConfig *
closeStream()
}

namedRef = reference.TrimTagForDigest(reference.WithDefaultTagIfMissing(namedRef))
var (
namedRef reference.Named
err error
)

// find an available image which could be resolved.
fullRefs := mgr.LookupImageReferences(ref)
for _, newRef := range fullRefs {
namedRef, err = reference.Parse(newRef)
if err != nil {
logrus.Warnf("failed to parse image reference when trying to pull image %s, raw reference is %s: %v", newRef, ref, err)
continue
}
namedRef = reference.TrimTagForDigest(reference.WithDefaultTagIfMissing(namedRef))
_, _, err = mgr.client.ResolveImage(pctx, namedRef.String(), authConfig)

// got available one
if err == nil {
break
}
}

if err != nil {
writeStream(err)
return err
}

img, err := mgr.client.FetchImage(pctx, namedRef.String(), authConfig, stream)
if err != nil {
writeStream(err)
Expand Down
5 changes: 4 additions & 1 deletion daemon/mgr/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,10 @@ func (mgr *SystemManager) Info() (types.SystemInfo, error) {
OperatingSystem: OSName,
OSType: runtime.GOOS,
PouchRootDir: mgr.config.HomeDir,
RegistryConfig: &mgr.config.RegistryService,
RegistryConfig: &types.RegistryServiceConfig{
InsecureRegistryCIDRs: mgr.config.InsecureRegistries,
Mirrors: mgr.config.RegistryMirrors,
},
// RuncCommit: ,
Runtimes: mgr.config.Runtimes,
SecurityOptions: securityOpts,
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ func setupFlags(cmd *cobra.Command) {

// registry
flagSet.StringArrayVar(&cfg.InsecureRegistries, "insecure-registries", []string{}, "enable insecure registry")
flagSet.StringArrayVar(&cfg.RegistryMirrors, "registry-mirrors", []string{}, "preferred mirror registry list")

// buildkit
flagSet.BoolVar(&cfg.EnableBuilder, "enable-builder", false, "Enable buildkit functionality")
Expand Down