Browse code

merge existing config when committing

Fixes #1141

Docker-DCO-1.1-Signed-off-by: Wes Morgan <cap10morgan@gmail.com> (github: cap10morgan)

Wes Morgan authored on 2014/01/31 04:00:18
Showing 3 changed files
... ...
@@ -83,7 +83,7 @@ Commands
83 83
       -v, --version=false: Print version information and quit
84 84
       --mtu=0: Set the containers network MTU; if no value is provided: default to the default route MTU or 1500 if no default route is available
85 85
 
86
-The Docker daemon is the persistent process that manages containers.  Docker uses the same binary for both the 
86
+The Docker daemon is the persistent process that manages containers.  Docker uses the same binary for both the
87 87
 daemon and client.  To run the daemon you provide the ``-d`` flag.
88 88
 
89 89
 To force Docker to use devicemapper as the storage driver, use ``docker -d -s devicemapper``.
... ...
@@ -93,10 +93,10 @@ To set the DNS server for all Docker containers, use ``docker -d -dns 8.8.8.8``.
93 93
 To run the daemon with debug output, use ``docker -d -D``.
94 94
 
95 95
 The docker client will also honor the ``DOCKER_HOST`` environment variable to set
96
-the ``-H`` flag for the client.  
96
+the ``-H`` flag for the client.
97 97
 
98 98
 ::
99
- 
99
+
100 100
         docker -H tcp://0.0.0.0:4243 ps
101 101
         # or
102 102
         export DOCKER_HOST="tcp://0.0.0.0:4243"
... ...
@@ -130,7 +130,7 @@ You can find examples of using systemd socket activation with docker and systemd
130 130
 
131 131
 You can detach from the container again (and leave it running) with
132 132
 ``CTRL-c`` (for a quiet exit) or ``CTRL-\`` to get a stacktrace of
133
-the Docker client when it quits.  When you detach from the container's 
133
+the Docker client when it quits.  When you detach from the container's
134 134
 process the exit code will be returned to the client.
135 135
 
136 136
 To stop a container, use ``docker stop``.
... ...
@@ -292,7 +292,7 @@ by using the ``git://`` schema.
292 292
 
293 293
       -m, --message="": Commit message
294 294
       -a, --author="": Author (eg. "John Hannibal Smith <hannibal@a-team.com>"
295
-      --run="": Configuration to be applied when the image is launched with `docker run`.
295
+      --run="": Configuration changes to be applied when the image is launched with `docker run`.
296 296
                (ex: -run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
297 297
 
298 298
 .. _cli_commit_examples:
... ...
@@ -304,14 +304,14 @@ Commit an existing container
304 304
 
305 305
 	$ sudo docker ps
306 306
 	ID                  IMAGE               COMMAND             CREATED             STATUS              PORTS
307
-	c3f279d17e0a        ubuntu:12.04        /bin/bash           7 days ago          Up 25 hours                             
308
-	197387f1b436        ubuntu:12.04        /bin/bash           7 days ago          Up 25 hours                             
307
+	c3f279d17e0a        ubuntu:12.04        /bin/bash           7 days ago          Up 25 hours
308
+	197387f1b436        ubuntu:12.04        /bin/bash           7 days ago          Up 25 hours
309 309
 	$ docker commit c3f279d17e0a  SvenDowideit/testimage:version3
310 310
 	f5283438590d
311 311
 	$ docker images | head
312 312
 	REPOSITORY                        TAG                 ID                  CREATED             VIRTUAL SIZE
313 313
 	SvenDowideit/testimage            version3            f5283438590d        16 seconds ago      335.7 MB
314
-	
314
+
315 315
 Change the command that a container runs
316 316
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
317 317
 
... ...
@@ -333,11 +333,40 @@ run ``ls /etc``.
333 333
         apt                     host.conf        lsb-base             rc2.d
334 334
         ...
335 335
 
336
+Merged configs example
337
+......................
338
+
339
+Say you have a Dockerfile like so:
340
+
341
+.. code-block:: bash
342
+
343
+        ENV MYVAR foobar
344
+        RUN apt-get install openssh
345
+        EXPOSE 22
346
+        CMD ["/usr/sbin/sshd -D"]
347
+        ...
348
+
349
+If you run that, make some changes, and then commit, Docker will merge the environment variable and exposed port configuration settings with any that you specify in the -run= option. This is a change from Docker 0.8.0 and prior where no attempt was made to preserve any existing configuration on commit.
350
+
351
+.. code-block:: bash
352
+
353
+        $ docker build -t me/foo .
354
+        $ docker run -t -i me/foo /bin/bash
355
+        foo-container$ [make changes in the container]
356
+        foo-container$ exit
357
+        $ docker commit -run='{"Cmd": ["ls"]}' [container-id] me/bar
358
+        ...
359
+
360
+The me/bar image will now have port 22 exposed, MYVAR env var set to 'foobar', and its default command will be ["ls"].
361
+
362
+Note that this is currently a shallow merge. So, for example, if you had specified a new port spec in the -run= config above, that would have clobbered the 'EXPOSE 22' setting from the parent container.
363
+
336 364
 Full -run example
337 365
 .................
338 366
 
339 367
 The ``--run`` JSON hash changes the ``Config`` section when running ``docker inspect CONTAINERID``
340
-or ``config`` when running ``docker inspect IMAGEID``.
368
+or ``config`` when running ``docker inspect IMAGEID``. Existing configuration key-values that are
369
+not overridden in the JSON hash will be merged in.
341 370
 
342 371
 (Multiline is okay within a single quote ``'``)
343 372
 
... ...
@@ -653,7 +682,7 @@ Displaying image hierarchy
653 653
 
654 654
     Usage: docker import URL|- [REPOSITORY[:TAG]]
655 655
 
656
-    Create an empty filesystem image and import the contents of the tarball 
656
+    Create an empty filesystem image and import the contents of the tarball
657 657
     (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.
658 658
 
659 659
 At this time, the URL must start with ``http`` and point to a single
... ...
@@ -918,7 +947,7 @@ Running ``docker ps`` showing 2 linked containers.
918 918
 
919 919
     $ docker ps
920 920
     CONTAINER ID        IMAGE                        COMMAND                CREATED              STATUS              PORTS               NAMES
921
-    4c01db0b339c        ubuntu:12.04                 bash                   17 seconds ago       Up 16 seconds                           webapp              
921
+    4c01db0b339c        ubuntu:12.04                 bash                   17 seconds ago       Up 16 seconds                           webapp
922 922
     d7886598dbe2        crosbymichael/redis:latest   /redis-server --dir    33 minutes ago       Up 33 minutes       6379/tcp            redis,webapp/db
923 923
     fd2645e2e2b5        busybox:latest               top                    10 days ago          Ghost                                   insane_ptolemy
924 924
 
... ...
@@ -1022,7 +1051,7 @@ containers will not be deleted.
1022 1022
     Remove one or more images
1023 1023
 
1024 1024
       -f, --force=false: Force
1025
-    
1025
+
1026 1026
 Removing tagged images
1027 1027
 ~~~~~~~~~~~~~~~~~~~~~~
1028 1028
 
... ...
@@ -1101,8 +1130,8 @@ Once the container is stopped it still exists and can be started back up.  See `
1101 1101
 The ``docker run`` command can be used in combination with ``docker commit`` to
1102 1102
 :ref:`change the command that a container runs <cli_commit_examples>`.
1103 1103
 
1104
-See :ref:`port_redirection` for more detailed information about the ``--expose``, 
1105
-``-p``, ``-P`` and ``--link`` parameters, and :ref:`working_with_links_names` for 
1104
+See :ref:`port_redirection` for more detailed information about the ``--expose``,
1105
+``-p``, ``-P`` and ``--link`` parameters, and :ref:`working_with_links_names` for
1106 1106
 specific examples using ``--link``.
1107 1107
 
1108 1108
 Known Issues (run -volumes-from)
... ...
@@ -1182,8 +1211,8 @@ starting your container.
1182 1182
 
1183 1183
    $ sudo docker run -t -i -v /var/run/docker.sock:/var/run/docker.sock -v ./static-docker:/usr/bin/docker busybox sh
1184 1184
 
1185
-By bind-mounting the docker unix socket and statically linked docker binary 
1186
-(such as that provided by https://get.docker.io), you give the container 
1185
+By bind-mounting the docker unix socket and statically linked docker binary
1186
+(such as that provided by https://get.docker.io), you give the container
1187 1187
 the full access to create and manipulate the host's docker daemon.
1188 1188
 
1189 1189
 .. code-block:: bash
... ...
@@ -219,6 +219,63 @@ func TestCommit(t *testing.T) {
219 219
 	}
220 220
 }
221 221
 
222
+func TestMergeConfigOnCommit(t *testing.T) {
223
+	eng := NewTestEngine(t)
224
+	runtime := mkRuntimeFromEngine(eng, t)
225
+	defer runtime.Nuke()
226
+
227
+	container1, _, _ := mkContainer(runtime, []string{"-e", "FOO=bar", unitTestImageID, "echo test > /tmp/foo"}, t)
228
+	defer runtime.Destroy(container1)
229
+
230
+	config, _, _, err := runconfig.Parse([]string{container1.ID, "cat /tmp/foo"}, nil)
231
+	if err != nil {
232
+		t.Error(err)
233
+	}
234
+
235
+	job := eng.Job("commit", container1.ID)
236
+	job.Setenv("repo", "testrepo")
237
+	job.Setenv("tag", "testtag")
238
+	job.SetenvJson("config", config)
239
+	var newId string
240
+	job.Stdout.AddString(&newId)
241
+	if err := job.Run(); err != nil {
242
+		t.Error(err)
243
+	}
244
+
245
+	container2, _, _ := mkContainer(runtime, []string{newId}, t)
246
+	defer runtime.Destroy(container2)
247
+
248
+	job = eng.Job("inspect", container1.Name, "container")
249
+	baseContainer, _ := job.Stdout.AddEnv()
250
+	if err := job.Run(); err != nil {
251
+		t.Error(err)
252
+	}
253
+
254
+	job = eng.Job("inspect", container2.Name, "container")
255
+	commitContainer, _ := job.Stdout.AddEnv()
256
+	if err := job.Run(); err != nil {
257
+		t.Error(err)
258
+	}
259
+
260
+	baseConfig := baseContainer.GetSubEnv("Config")
261
+	commitConfig := commitContainer.GetSubEnv("Config")
262
+
263
+	if commitConfig.Get("Env") != baseConfig.Get("Env") {
264
+		t.Fatalf("Env config in committed container should be %v, was %v",
265
+			baseConfig.Get("Env"), commitConfig.Get("Env"))
266
+	}
267
+
268
+	if baseConfig.Get("Cmd") != "[\"echo test \\u003e /tmp/foo\"]" {
269
+		t.Fatalf("Cmd in base container should be [\"echo test \\u003e /tmp/foo\"], was %s",
270
+			baseConfig.Get("Cmd"))
271
+	}
272
+
273
+	if commitConfig.Get("Cmd") != "[\"cat /tmp/foo\"]" {
274
+		t.Fatalf("Cmd in committed container should be [\"cat /tmp/foo\"], was %s",
275
+			commitConfig.Get("Cmd"))
276
+	}
277
+}
278
+
222 279
 func TestRestartKillWait(t *testing.T) {
223 280
 	eng := NewTestEngine(t)
224 281
 	srv := mkServerFromEngine(eng, t)
... ...
@@ -1043,12 +1043,17 @@ func (srv *Server) ContainerCommit(job *engine.Job) engine.Status {
1043 1043
 	if container == nil {
1044 1044
 		return job.Errorf("No such container: %s", name)
1045 1045
 	}
1046
-	var config runconfig.Config
1047
-	if err := job.GetenvJson("config", &config); err != nil {
1046
+	var config = container.Config
1047
+	var newConfig runconfig.Config
1048
+	if err := job.GetenvJson("config", &newConfig); err != nil {
1048 1049
 		return job.Error(err)
1049 1050
 	}
1050 1051
 
1051
-	img, err := srv.runtime.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), &config)
1052
+	if err := runconfig.Merge(&newConfig, config); err != nil {
1053
+		return job.Error(err)
1054
+	}
1055
+
1056
+	img, err := srv.runtime.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), &newConfig)
1052 1057
 	if err != nil {
1053 1058
 		return job.Error(err)
1054 1059
 	}