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>
This commit is contained in:
parent
693c2b0c43
commit
13edc7f4f1
3 changed files with 24 additions and 7 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue