Преглед изворни кода

Strip reserved (com.docker. io.docker, org.dockerproject) labels on docker commit

Docker uses reserved label namespaces on containers to store runtime information.
For example, when creating a service (`docker service create`), deploying a stack
(`docker stack deploy`), or running a compose project (`docker-compose up`),
docker respectively adds `com.docker.swarm`, `com.docker.stack`, and
`com.docker.compose` labels to store metadata used at runtime.

These labels are not set by users, but when commiting such a container, they
currently end up in the image that was committed.

This patch updates `CreateImageFromContainer` to remove labels in the reserved
namespace.

Some remarks should be made to this change:

- This patch only accounts for `docker commit`; `docker build` still allows
  committing labels in the reserved namespaces
- Because of the above, committing a container that was started from an image
  that has labels in the reserved namespaces, will strip these labels, and
  thus remove the labels from the image that is created.
- Other actions (`docker run`, `docker create`) still allow these labels to be
  set, and also inherit these labels if they're started from an image that
  has labels in the reserved namespaces.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn пре 4 година
родитељ
комит
13edc7f4f1
3 измењених фајлова са 24 додато и 7 уклоњено
  1. 10 2
      daemon/commit.go
  2. 1 1
      daemon/create.go
  3. 13 4
      daemon/daemon_test.go

+ 10 - 2
daemon/commit.go

@@ -10,15 +10,20 @@ import (
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/builder/dockerfile"
 	"github.com/docker/docker/errdefs"
+	"github.com/docker/docker/opts"
 	"github.com/pkg/errors"
 )
 
+type mergeOptions struct {
+	keepReservedLabels bool
+}
+
 // merge merges two Config, the image container configuration (defaults values),
 // and the user container configuration, either passed by the API or generated
 // by the cli.
 // It will mutate the specified user configuration (userConf) with the image
 // configuration where the user configuration is incomplete.
-func merge(userConf, imageConf *containertypes.Config) error {
+func merge(userConf, imageConf *containertypes.Config, options mergeOptions) error {
 	if userConf.User == "" {
 		userConf.User = imageConf.User
 	}
@@ -60,6 +65,9 @@ func merge(userConf, imageConf *containertypes.Config) error {
 		userConf.Labels = map[string]string{}
 	}
 	for l, v := range imageConf.Labels {
+		if !options.keepReservedLabels && opts.IsReservedLabelNamespace(l) {
+			continue
+		}
 		if _, ok := userConf.Labels[l]; !ok {
 			userConf.Labels[l] = v
 		}
@@ -150,7 +158,7 @@ func (daemon *Daemon) CreateImageFromContainer(name string, c *backend.CreateIma
 	if err != nil {
 		return "", err
 	}
-	if err := merge(newConfig, container.Config); err != nil {
+	if err := merge(newConfig, container.Config, mergeOptions{}); err != nil {
 		return "", err
 	}
 

+ 1 - 1
daemon/create.go

@@ -293,7 +293,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
 
 func (daemon *Daemon) mergeAndVerifyConfig(config *containertypes.Config, img *image.Image) error {
 	if img != nil && img.Config != nil {
-		if err := merge(config, img.Config); err != nil {
+		if err := merge(config, img.Config, mergeOptions{keepReservedLabels: true}); err != nil {
 			return err
 		}
 	}

+ 13 - 4
daemon/daemon_test.go

@@ -237,6 +237,7 @@ func TestMerge(t *testing.T) {
 		ExposedPorts: portsImage,
 		Env:          []string{"VAR1=1", "VAR2=2"},
 		Volumes:      volumesImage,
+		Labels:       map[string]string{"com.docker.foo": "bar", "my-label": "my-value"},
 	}
 
 	portsUser := make(nat.PortSet)
@@ -250,7 +251,7 @@ func TestMerge(t *testing.T) {
 		Volumes:      volumesUser,
 	}
 
-	if err := merge(configUser, configImage); err != nil {
+	if err := merge(configUser, configImage, mergeOptions{keepReservedLabels: true}); err != nil {
 		t.Error(err)
 	}
 
@@ -284,22 +285,30 @@ func TestMerge(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
+
+	assert.DeepEqual(t, configUser.Labels, configImage.Labels)
+
 	configImage2 := &containertypes.Config{
 		ExposedPorts: ports,
+		Labels:       map[string]string{"com.docker.foo": "bar", "my-label": "my-value"},
+	}
+	configUser2 := &containertypes.Config{
+		ExposedPorts: portsUser,
 	}
 
-	if err := merge(configUser, configImage2); err != nil {
+	if err := merge(configUser2, configImage2, mergeOptions{}); err != nil {
 		t.Error(err)
 	}
 
-	if len(configUser.ExposedPorts) != 4 {
+	if len(configUser2.ExposedPorts) != 4 {
 		t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
 	}
-	for portSpecs := range configUser.ExposedPorts {
+	for portSpecs := range configUser2.ExposedPorts {
 		if portSpecs.Port() != "0" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
 			t.Fatalf("Expected %q or %q or %q or %q, found %s", 0, 1111, 2222, 3333, portSpecs)
 		}
 	}
+	assert.DeepEqual(t, configUser2.Labels, map[string]string{"my-label": "my-value"})
 }
 
 func TestValidateContainerIsolation(t *testing.T) {