mirror of https://github.com/docker/compose.git
introduce --resolve-image-digests for publish to seal service images by digest
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
5661fd1bfe
commit
6727908803
|
@ -25,11 +25,16 @@ import (
|
||||||
"github.com/docker/compose/v2/pkg/api"
|
"github.com/docker/compose/v2/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type publishOptions struct {
|
||||||
|
*ProjectOptions
|
||||||
|
resolveImageDigests bool
|
||||||
|
}
|
||||||
|
|
||||||
func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||||
opts := pushOptions{
|
opts := publishOptions{
|
||||||
ProjectOptions: p,
|
ProjectOptions: p,
|
||||||
}
|
}
|
||||||
publishCmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "publish [OPTIONS] [REPOSITORY]",
|
Use: "publish [OPTIONS] [REPOSITORY]",
|
||||||
Short: "Publish compose application",
|
Short: "Publish compose application",
|
||||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||||
|
@ -37,14 +42,18 @@ func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||||
}),
|
}),
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
}
|
}
|
||||||
return publishCmd
|
flags := cmd.Flags()
|
||||||
|
flags.BoolVar(&opts.resolveImageDigests, "resolve-image-digests", false, "Pin image tags to digests.")
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pushOptions, repository string) error {
|
func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Service, opts publishOptions, repository string) error {
|
||||||
project, err := opts.ToProject(dockerCli, nil)
|
project, err := opts.ToProject(dockerCli, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return backend.Publish(ctx, project, repository, api.PublishOptions{})
|
return backend.Publish(ctx, project, repository, api.PublishOptions{
|
||||||
|
ResolveImageDigests: opts.resolveImageDigests,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,10 @@ Publish compose application
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
|:------------|:-----|:--------|:--------------------------------|
|
|:--------------------------|:-----|:--------|:--------------------------------|
|
||||||
| `--dry-run` | | | Execute command in dry run mode |
|
| `--dry-run` | | | Execute command in dry run mode |
|
||||||
|
| `--resolve-image-digests` | | | Pin image tags to digests. |
|
||||||
|
|
||||||
|
|
||||||
<!---MARKER_GEN_END-->
|
<!---MARKER_GEN_END-->
|
||||||
|
|
|
@ -4,6 +4,17 @@ long: Publish compose application
|
||||||
usage: docker compose alpha publish [OPTIONS] [REPOSITORY]
|
usage: docker compose alpha publish [OPTIONS] [REPOSITORY]
|
||||||
pname: docker compose alpha
|
pname: docker compose alpha
|
||||||
plink: docker_compose_alpha.yaml
|
plink: docker_compose_alpha.yaml
|
||||||
|
options:
|
||||||
|
- option: resolve-image-digests
|
||||||
|
value_type: bool
|
||||||
|
default_value: "false"
|
||||||
|
description: Pin image tags to digests.
|
||||||
|
deprecated: false
|
||||||
|
hidden: false
|
||||||
|
experimental: false
|
||||||
|
experimentalcli: false
|
||||||
|
kubernetes: false
|
||||||
|
swarm: false
|
||||||
inherited_options:
|
inherited_options:
|
||||||
- option: dry-run
|
- option: dry-run
|
||||||
value_type: bool
|
value_type: bool
|
||||||
|
|
|
@ -363,6 +363,7 @@ type PortOptions struct {
|
||||||
|
|
||||||
// PublishOptions group options of the Publish API
|
// PublishOptions group options of the Publish API
|
||||||
type PublishOptions struct {
|
type PublishOptions struct {
|
||||||
|
ResolveImageDigests bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Event) String() string {
|
func (e Event) String() string {
|
||||||
|
|
|
@ -63,37 +63,24 @@ func (s *composeService) publish(ctx context.Context, project *types.Project, re
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Event(progress.Event{
|
layer, err := s.pushComposeFile(ctx, file, f, resolver, named)
|
||||||
ID: file,
|
if err != nil {
|
||||||
Text: "publishing",
|
return err
|
||||||
Status: progress.Working,
|
|
||||||
})
|
|
||||||
layer := v1.Descriptor{
|
|
||||||
MediaType: "application/vnd.docker.compose.file+yaml",
|
|
||||||
Digest: digest.FromString(string(f)),
|
|
||||||
Size: int64(len(f)),
|
|
||||||
Annotations: map[string]string{
|
|
||||||
"com.docker.compose.version": api.ComposeVersion,
|
|
||||||
"com.docker.compose.file": filepath.Base(file),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
layers = append(layers, layer)
|
layers = append(layers, layer)
|
||||||
err = resolver.Push(ctx, named, layer, f)
|
}
|
||||||
if err != nil {
|
|
||||||
w.Event(progress.Event{
|
|
||||||
ID: file,
|
|
||||||
Text: "publishing",
|
|
||||||
Status: progress.Error,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
if options.ResolveImageDigests {
|
||||||
|
yaml, err := s.generateImageDigestsOverride(ctx, project)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Event(progress.Event{
|
layer, err := s.pushComposeFile(ctx, "image-digests.yaml", yaml, resolver, named)
|
||||||
ID: file,
|
if err != nil {
|
||||||
Text: "published",
|
return err
|
||||||
Status: progress.Done,
|
}
|
||||||
})
|
layers = append(layers, layer)
|
||||||
}
|
}
|
||||||
|
|
||||||
emptyConfig, err := json.Marshal(v1.ImageConfig{})
|
emptyConfig, err := json.Marshal(v1.ImageConfig{})
|
||||||
|
@ -157,3 +144,61 @@ func (s *composeService) publish(ctx context.Context, project *types.Project, re
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *composeService) generateImageDigestsOverride(ctx context.Context, project *types.Project) ([]byte, error) {
|
||||||
|
project.ApplyProfiles([]string{"*"})
|
||||||
|
err := project.ResolveImages(func(named reference.Named) (digest.Digest, error) {
|
||||||
|
auth, err := encodedAuth(named, s.configFile())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
inspect, err := s.apiClient().DistributionInspect(ctx, named.String(), auth)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return inspect.Descriptor.Digest, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
override := types.Project{}
|
||||||
|
for _, service := range project.Services {
|
||||||
|
override.Services = append(override.Services, types.ServiceConfig{
|
||||||
|
Name: service.Name,
|
||||||
|
Image: service.Image,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return override.MarshalYAML()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *composeService) pushComposeFile(ctx context.Context, file string, content []byte, resolver *imagetools.Resolver, named reference.Named) (v1.Descriptor, error) {
|
||||||
|
w := progress.ContextWriter(ctx)
|
||||||
|
w.Event(progress.Event{
|
||||||
|
ID: file,
|
||||||
|
Text: "publishing",
|
||||||
|
Status: progress.Working,
|
||||||
|
})
|
||||||
|
layer := v1.Descriptor{
|
||||||
|
MediaType: "application/vnd.docker.compose.file+yaml",
|
||||||
|
Digest: digest.FromString(string(content)),
|
||||||
|
Size: int64(len(content)),
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"com.docker.compose.version": api.ComposeVersion,
|
||||||
|
"com.docker.compose.file": filepath.Base(file),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := resolver.Push(ctx, named, layer, content)
|
||||||
|
w.Event(progress.Event{
|
||||||
|
ID: file,
|
||||||
|
Text: "published",
|
||||||
|
Status: statusFor(err),
|
||||||
|
})
|
||||||
|
return layer, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusFor(err error) progress.EventStatus {
|
||||||
|
if err != nil {
|
||||||
|
return progress.Error
|
||||||
|
}
|
||||||
|
return progress.Done
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue