Why push your own image?
After using docker for a while you may find that you want more control over the images you want to base your containers on.
If you have a Dockerfile, you can always use it to build an image locally using
docker build .
Alternatively if you want the image to have a tag name to make it easier to recognise
docker build -t myimage .
After the base image has downloaded and all the commands in the Docker file have run you’ll have an image locally.
This is great as it gives you the ability to spin up a container based on the image and run a command there, such as to kick off your micro-service.
# find the correct image id $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE <none> myimage 5f157f802a51 2 minutes ago 533 MB ubuntu xenial-20160914 45bc58500fa3 4 months ago 127 MB # start the container and ls the home dir as an example rather than start # my super-cool microservice $ docker run --name mycont1 5f157f802a51 ls
A potential issue with the above process is that if I want a co-worker to kick off his micro service, or we want to run it in multiple “environments” then he will have to run the docker build first and then run it.
This takes some time
Imagine how long it would take if your container was based on ubuntu
and in the Dockerfile you ran
apt-get update and
apt-get upgrade -y, not to mention the time it takes to install
necessary software such as Java, Mono, Python or Ruby. The whole process could easily take 10 minutes or more to run the build.
But that isn’t the biggest problem. What if a Python dependency or Ruby Gem had changes since you ran your build? Not only could the install fail because, in this case, other different dependencies would need to be pre-installed but also your co-worker’s build will now be different to yours.
All your version controlled guaranties are now moot.
Clearly we want him to have the same exact image as us.
Create an image from your container
The way to do this is to create an image from your container. In Docker-speak we will
commit the image.
Think of it like committing all the changes to the layered file system that you have made in the container after starting it from an image.
If you run up your container as described above, then you need to find out its container ID.
If it is still running use:
$ docker ps
If it has stopped use:
$ docker ps -a
You will see info about your container, this is where naming the container using the
-name flag, see above, will be useful. For example this is what I see:
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2fdc41c14fc6 5f157f802a51 "/bin/sh ls" 7 minutes ago Exited (137) 13 seconds ago mycont1
So the container Id for
2fdc41c14fc6. I can now use this to commit an image. Note that you can even cut an image if the container is running because by default it will pause the container before committing, see
man docker commit
Now you can create the image
$ docker commit -m "my microservice added to ubuntu xenial" -a "Karl" 2fdc41c14fc6 ubuntu-xenial-mymicro
You can see the newly minted image as before
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu-xenial-mymicro latest d2c713fdb832 10 seconds ago 795 MB ubuntu xenial-20160914 45bc58500fa3 4 months ago 127 M
Push to a repository
Now we have an image we want to push it to our repository so our co-workers can pull and run up a container from it.
The trick to all of this is that Docker uses the image tag name in a special way. When you pull or run an image the name you give it is actually a location (URI) that also refers to the repository host. By default if no host is specified then the Docker hub repo is assumed.
Therefore if you wanted to push your image to Docker Hub, you would first create an account to get a Docker ID that also maps to a “repo” in Docker Hub,
e.g. if my Docker ID was
karlcode I would create an image tag that referenced my repo in Docker Hub. Remember that “Docker Hub” is assumed so I could do this:
docker tag ubuntu-xenial-mymicro karlcode/ubuntu-xenial-mymicro:latest docker push karlcode/ubuntu-xenial-mymicro:latest
This creates a tag of my image, you can use
docker image ls to confirm this, and then uses the tag to push the image to the repository host/repo of the same name as the tag.
Of course you would need to let docker know how to login to your docker hub account in order to run the push.
This is done with the
docker login command.
It asks for your Docker Hub Docker ID and password and stores a token in your HOME directory at
~/.docker/config.json if you have not run
docker login before, so you don’t need to login every time you push or pull.
Push to your private repository
The same principle applies to push to a private repository such as your company’s own Docker repository. The only difference is that you need to specify the repository host in the tag name.
Lets say that my repository was running at
docker.owtelse.com running on port
443 and that my project is called
magicmicro I may choose to do this:-
$ docker login docker.owtelse.com:443 $ docker tag ubuntu-xenial-mymicro docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro:latest $ docker tag ubuntu-xenial-mymicro docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro:20170125
I would then have local images which we can see like:-
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro 20170125 d2c713fdb832 10 minutes ago 795 MB docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro latest d2c713fdb832 10 minutes ago 795 MB ubuntu-xenial-mymicro latest d2c713fdb832 10 minutes ago 795 MB ubuntu xenial-20160914 45bc58500fa3 4 months ago 127 M
You may notice that I have two alias for my image with two tags one with the date and the other with the
Images with the
latest tag are pulled by default if the tag is not specified.
This allows a user to easily get the latest version by not specifying a preference or by picking a specific release, e.g. for debugging a particular version or for a production environment.
Now to push it:-
$ docker push docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro:latest $ docker push docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro:20170125
And that is it!
To prove this to yourself, delete the local images, remember to use your own image ID in the command below :-
$ docker rmi -f docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro $ docker rmi -f d2c713fdb832
Then you can pull the image from your private repo and use
docker image ls to confirm you have it
$ docker pull docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro:latest
Alternatively you and you co-worker can simply try to run it. If you have already run
docker login docker.owtelse.com:443 the image will download and run, when you type:
$ docker run --name mymicro docker.owtelse.com:443/magicmicro/ubuntu-xenial-mymicro:latest
For more info see the man page
man docker push.
I hope you find this information useful and you are now able take more advantage of Docker in both the development and production environment.