How can I run a docker container and commit the changes once a script completes?

13,291

Solution 1

Run it in the foreground, not as daemon. When it ends the script that launched it takes control and commits/push it

Solution 2

There are following ways to persist container data:

  1. Docker volumes

  2. Docker commit

    a) create container from ubuntu image and run a bash terminal.

       $ docker run -i -t ubuntu:14.04 /bin/bash
    

    b) Inside the terminal install curl

       # apt-get update
       # apt-get install curl
    

    c) Exit the container terminal

       # exit
    

    d) Take a note of your container id by executing following command :

       $ docker ps -a
    

    e) save container as new image

       $ docker commit <container_id> new_image_name:tag_name(optional)
    

    f) verify that you can see your new image with curl installed.

       $ docker images           
    
       $ docker run -it new_image_name:tag_name bash
          # which curl
            /usr/bin/curl
    

Solution 3

I didn't find any of these answers satisfying, as my goal was to 1) launch a container, 2) run a setup script, and 3) capture/store the state after setup, so I can instantly run various scripts against that state later. And all in a local, automated, continuous integration environment (e.g. scripted and non-interactive).

Here's what I came up with (and I run this in Travis-CI install section) for setting up my test environment:

#!/bin/bash

# Run a docker with the env boot script
docker run ubuntu:14.04 /path/to/env_setup_script.sh

# Get the container ID of the last run docker (above)
export CONTAINER_ID=`docker ps -lq`

# Commit the container state (returns an image_id with sha256: prefix cut off)
# and write the IMAGE_ID to disk at ~/.docker_image_id
(docker commit $CONTAINER_ID | cut -c8-) > ~/.docker_image_id

Note that my base image was ubuntu:14.04 but yours could be any image you want.

With that setup, now I can run any number of scripts (e.g. unit tests) against this snapshot (for Travis, these are in my script section). e.g.:

docker run `cat ~/.docker_image_id` /path/to/unit_test_1.sh
docker run `cat ~/.docker_image_id` /path/to/unit_test_2.sh

Solution 4

Try this if you want an auto commit for all which are running. Put this in a cron or something, if this helps

#!/bin/bash
for i in `docker ps|tail -n +2|awk '{print $1}'`; do docker commit -m "commit new change" $i; done
Share:
13,291
mrdziuban
Author by

mrdziuban

Updated on June 04, 2022

Comments

  • mrdziuban
    mrdziuban almost 2 years

    I want to set up a cron job to run a set of commands inside a docker container and then commit the changes to the docker image. I'm able to run the container as a daemon and get the container ID using this command:

    CONTAINER_ID=$(sudo docker run -d my-image /bin/sh -c "sleep 10")

    but I'm having trouble with the second part--committing the changes to the image once the sleep 10 command completes. Is there a way for me to tell when the docker container is about to be killed and run another command before it is?

    EDIT: As an alternative, is there a way to trigger ctrl-p-q via a shell script in the container to leave the container running but return to the host?

  • mrdziuban
    mrdziuban almost 9 years
    Thanks for the reply. I'm still unable to commit before the container is killed though. Is there a way to run a command before it's killed? Or is there a way to send the ctrl-p-q signal from a shell script to leave the container running but to return to the host?
  • gmuslera
    gmuslera almost 9 years
    The container ends, but is not deleted, you can commit that container id with a repository or system name.
  • mrdziuban
    mrdziuban almost 9 years
    Awesome, thanks! I didn't know you could commit a container after it's been stopped.
  • user239558
    user239558 over 6 years
    This answer needs commands to how how the container id etc is obtained.
  • Granitosaurus
    Granitosaurus over 5 years
    This doesn't seem to be working when it comes to changing environment variables. export FOO="bar" will not persist in a commit for some reason.
  • Daniel Santos
    Daniel Santos about 5 years
    @Granitosaurus That's because you are exporting it in the shell currently running and then you exit the shell. This isn't saving memory, only your storage. If you want that saved you'll have to put it in your ~/.bashrc, /etc/profile, etc.
  • Daniel Santos
    Daniel Santos about 5 years
    When automating this I don't want to look at the output of docker ps -a, so it looks like spitting it out from the process works: docker run -i -t ubuntu:14.04 /bin/bash -c echo "MY_CONTAINER_ID=$HOSTNAME'". Then I can just grep '^MY_CONTAINER_ID=' to get the container id I (may or may not) want to commit.