Skip to content

Commit b0b6d9a

Browse files
committed
Add support for using a host registry dir in cri
This will be used instead of the cri registry config in the main config toml. --- Also pulls in changes from containerd/cri@d0b4eec Signed-off-by: Brian Goff <[email protected]>
1 parent 1fd99e2 commit b0b6d9a

4 files changed

Lines changed: 115 additions & 5 deletions

File tree

docs/cri/config.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ version = 2
237237

238238
# 'plugins."io.containerd.grpc.v1.cri".registry' contains config related to the registry
239239
[plugins."io.containerd.grpc.v1.cri".registry]
240+
# Specifies a directory to look for registry configs in.
241+
# Dir can be used just like /etc/docker/certs.d OR can contain a hosts.toml with more specific configurations.
242+
#
243+
# NOTE: Specifying this will cause the cri plugin to ignore any other registry configs specified in this configuration file.
244+
config_path = "/etc/containerd/certs.d"
240245

241246
# 'plugins."io.containerd.grpc.v1.cri.registry.headers sets the http request headers to send for all registry requests
242247
[plugins."io.containerd.grpc.v1.cri".registry.headers]

pkg/cri/config/config.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,21 @@ type TLSConfig struct {
145145

146146
// Registry is registry settings configured
147147
type Registry struct {
148+
// ConfigPath is a path to the root directory containing registry-specific
149+
// configurations.
150+
// If ConfigPath is set, the rest of the registry specific options are ignored.
151+
ConfigPath string `toml:"config_path" json:"configPath"`
148152
// Mirrors are namespace to mirror mapping for all namespaces.
153+
// This option will not be used when ConfigPath is provided.
154+
// DEPRECATED: Use ConfigPath instead. Remove in containerd 1.7.
149155
Mirrors map[string]Mirror `toml:"mirrors" json:"mirrors"`
150156
// Configs are configs for each registry.
151157
// The key is the domain name or IP of the registry.
158+
// This option will be fully deprecated for ConfigPath in the future.
152159
Configs map[string]RegistryConfig `toml:"configs" json:"configs"`
153-
154160
// Auths are registry endpoint to auth config mapping. The registry endpoint must
155161
// be a valid url with host specified.
156-
// DEPRECATED: Use Configs instead. Remove in containerd 1.4.
162+
// DEPRECATED: Use ConfigPath instead. Remove in containerd 1.6.
157163
Auths map[string]AuthConfig `toml:"auths" json:"auths"`
158164
// Headers adds additional HTTP headers that get sent to all registries
159165
Headers map[string][]string `toml:"headers" json:"headers"`
@@ -165,6 +171,8 @@ type RegistryConfig struct {
165171
Auth *AuthConfig `toml:"auth" json:"auth"`
166172
// TLS is a pair of CA/Cert/Key which then are used when creating the transport
167173
// that communicates with the registry.
174+
// This field will not be used when ConfigPath is provided.
175+
// DEPRECATED: Use ConfigPath instead. Remove in containerd 1.7.
168176
TLS *TLSConfig `toml:"tls" json:"tls"`
169177
}
170178

@@ -351,6 +359,27 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error {
351359
}
352360
}
353361

362+
useConfigPath := c.Registry.ConfigPath != ""
363+
if len(c.Registry.Mirrors) > 0 {
364+
if useConfigPath {
365+
return errors.Errorf("`mirrors` cannot be set when `config_path` is provided")
366+
}
367+
log.G(ctx).Warning("`mirrors` is deprecated, please use `config_path` instead")
368+
}
369+
var hasDeprecatedTLS bool
370+
for _, r := range c.Registry.Configs {
371+
if r.TLS != nil {
372+
hasDeprecatedTLS = true
373+
break
374+
}
375+
}
376+
if hasDeprecatedTLS {
377+
if useConfigPath {
378+
return errors.Errorf("`configs.tls` cannot be set when `config_path` is provided")
379+
}
380+
log.G(ctx).Warning("`configs.tls` is deprecated, please use `config_path` instead")
381+
}
382+
354383
// Validation for deprecated auths options and mapping it to configs.
355384
if len(c.Registry.Auths) != 0 {
356385
if c.Registry.Configs == nil {
@@ -370,7 +399,7 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error {
370399
config.Auth = &auth
371400
c.Registry.Configs[endpoint] = config
372401
}
373-
log.G(ctx).Warning("`auths` is deprecated, please use registry`configs` instead")
402+
log.G(ctx).Warning("`auths` is deprecated, please use `configs` instead")
374403
}
375404

376405
// Validation for stream_idle_timeout

pkg/cri/config/config_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,46 @@ func TestValidateConfig(t *testing.T) {
320320
},
321321
expectedErr: "invalid stream idle timeout",
322322
},
323+
"conflicting mirror registry config": {
324+
config: &PluginConfig{
325+
ContainerdConfig: ContainerdConfig{
326+
DefaultRuntimeName: RuntimeDefault,
327+
Runtimes: map[string]Runtime{
328+
RuntimeDefault: {
329+
Type: "default",
330+
},
331+
},
332+
},
333+
Registry: Registry{
334+
ConfigPath: "/etc/containerd/conf.d",
335+
Mirrors: map[string]Mirror{
336+
"something.io": {},
337+
},
338+
},
339+
},
340+
expectedErr: "`mirrors` cannot be set when `config_path` is provided",
341+
},
342+
"conflicting tls registry config": {
343+
config: &PluginConfig{
344+
ContainerdConfig: ContainerdConfig{
345+
DefaultRuntimeName: RuntimeDefault,
346+
Runtimes: map[string]Runtime{
347+
RuntimeDefault: {
348+
Type: "default",
349+
},
350+
},
351+
},
352+
Registry: Registry{
353+
ConfigPath: "/etc/containerd/conf.d",
354+
Configs: map[string]RegistryConfig{
355+
"something.io": {
356+
TLS: &TLSConfig{},
357+
},
358+
},
359+
},
360+
},
361+
expectedErr: "`configs.tls` cannot be set when `config_path` is provided",
362+
},
323363
} {
324364
t.Run(desc, func(t *testing.T) {
325365
err := ValidatePluginConfig(context.Background(), test.config)

pkg/cri/server/image_pull.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"net"
2626
"net/http"
2727
"net/url"
28+
"path/filepath"
2829
"strings"
2930
"time"
3031

@@ -35,6 +36,7 @@ import (
3536
"github.com/containerd/containerd/log"
3637
distribution "github.com/containerd/containerd/reference/docker"
3738
"github.com/containerd/containerd/remotes/docker"
39+
"github.com/containerd/containerd/remotes/docker/config"
3840
"github.com/containerd/imgcrypt"
3941
"github.com/containerd/imgcrypt/images/encryption"
4042
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -100,7 +102,7 @@ func (c *criService) PullImage(ctx context.Context, r *runtime.PullImageRequest)
100102
var (
101103
resolver = docker.NewResolver(docker.ResolverOptions{
102104
Headers: c.config.Registry.Headers,
103-
Hosts: c.registryHosts(r.GetAuth()),
105+
Hosts: c.registryHosts(ctx, r.GetAuth()),
104106
})
105107
isSchema1 bool
106108
imageHandler containerdimages.HandlerFunc = func(_ context.Context,
@@ -311,8 +313,42 @@ func (c *criService) getTLSConfig(registryTLSConfig criconfig.TLSConfig) (*tls.C
311313
return tlsConfig, nil
312314
}
313315

316+
func hostDirFromRoots(roots []string) func(string) (string, error) {
317+
rootfn := make([]func(string) (string, error), len(roots))
318+
for i := range roots {
319+
rootfn[i] = config.HostDirFromRoot(roots[i])
320+
}
321+
return func(host string) (dir string, err error) {
322+
for _, fn := range rootfn {
323+
dir, err = fn(host)
324+
if (err != nil && !errdefs.IsNotFound(err)) || (dir != "") {
325+
break
326+
}
327+
}
328+
return
329+
}
330+
}
331+
314332
// registryHosts is the registry hosts to be used by the resolver.
315-
func (c *criService) registryHosts(auth *runtime.AuthConfig) docker.RegistryHosts {
333+
func (c *criService) registryHosts(ctx context.Context, auth *runtime.AuthConfig) docker.RegistryHosts {
334+
paths := filepath.SplitList(c.config.Registry.ConfigPath)
335+
if len(paths) > 0 {
336+
hostOptions := config.HostOptions{}
337+
hostOptions.Credentials = func(host string) (string, string, error) {
338+
hostauth := auth
339+
if hostauth == nil {
340+
config := c.config.Registry.Configs[host]
341+
if config.Auth != nil {
342+
hostauth = toRuntimeAuthConfig(*config.Auth)
343+
}
344+
}
345+
return ParseAuth(hostauth, host)
346+
}
347+
hostOptions.HostDir = hostDirFromRoots(paths)
348+
349+
return config.ConfigureHosts(ctx, hostOptions)
350+
}
351+
316352
return func(host string) ([]docker.RegistryHost, error) {
317353
var registries []docker.RegistryHost
318354

0 commit comments

Comments
 (0)