In this article, we will look at the process of creating image, running into container and modifying image and finally distributing the image using public repository and file-based approach.
As part of Software development process, sometimes we need to configure containerize solution and create iterative improvement. In this process, a docker image is started with base image, and phase wise improvement is made by adding all the needed component to the image before finalizing the package. In that case, we start with bare metal image and continuously add additional layer in the process and pass the intermediate product to as different version. In this process, we must create image from a container after modifying the image and then pass the image along for further modification. In this article, we are going to look at the process of creating image, running into container and modifying image and finally distributing the image using public repository and file-based approach.
In addition to a will to go through this technical jargon, the following is needed to do hands on.
- A Docker Hub account – A free registry account can be created at https://hub.docker.com/
- Docker – Docker Desktop available at https://www.docker.com/products/docker-desktopcan be installed.
- Terminal (e.g. PowerShell) - Any terminal can be used to execute docker command. In the example, we will be using PowerShell. In the PowerShell, $ is used to define a variable and # is used to start a comment
The command and example in these articles were made on Windows 10 machine with Windows PowerShell and Docker version 20.10.2.
Login to Docker Hub
Once the docker starts, we can login to the docker using
DockerID can be used as username while authenticating to a Docker registry for docker images. Docker client can be asked to connect to the registry to download or upload images. Docker Hub is one of the registries. An account can be created at https://hub.docker.com/.
Let’s start a PowerShell or Terminal window and log on using:
docker login --username benktesh #password will be entered in the prompt
When the above command is run and user is authenticated, a successful login prompt show.
Create Docker Image
Docker image can be created from scratch or we can use a publicly available image to get started. Here we are going to get an Ubuntu 18.04 image from Docker Hub with a pull command. Note that images can be created from the scratch. Please Creating Docker Image for an illusration about creating image.
Docker pull ubuntu:18.04
After the image has been pulled, we can verify that the image exists by executing image ls command.
Docker image ls
At the same time, if the docker desktop is installed, the list of images shows the existence of the image.
Run Image as Container
So far in the process, we have downloaded an image of Ubuntu 18.04 locally. This is similar to a situation we have got a Virtual Machine but is not running. To run this image, we need to run inside a container. The image can be run as container with the following command by specifying a name of the container suchas ‘
ubuntu_container’ based on image ‘
ubuntu’ with tag ’
18.04’ as below:
docker run -d --name ubuntu_container -i -t ubuntu:18.04
--name argument is defining the name of the container and ubuntu:1804 is represent repository:tag information of the image. Argument
-d ensures the container runs in detached mode. The above command can be made reusable by using variables. For example, in the PowerShell, we can define a variable for container name and image and use it.
$container = "ubuntu_container" #defines variable for container name
$image = "ubuntuL18:04" #defines a variable for image label
After such variables are defined, the command can use the variables as below:
docker run -d --name $container -i -t $image
The above command returns runs a container and returns the id of the container. We can check to see what is inside the container. To do this, we can open a bash shell in the container by executing
docker exec -it $container bash
which opens the bash prompt where we can execute
cat /etc/os-release command to find out the release information on of the Ubuntu image that is running in the container. The result showed that we are running Version 18.04.5 (Bionic Beaver) of Ubuntu.
We verified that we Ubuntu 1804 is locally running as a container. Issuing exit command gets us out of the bash.
Modify Docker Image
After we have container running, we do ‘stuffs’ on it. For example, we add more layers and application to the container to make it more useful. For example, we could add one application and distribute the image with application to customers or provide it as a value-added image for later use. To mimic this, we are going to modify this container and create a new image out of this container and save to docker repository for public distribution.
For illustration, in the current container when we execute lsb_release -a, the response is that ‘command not found’ that means the container does not provide features for lsb_release. Next, we will update this container by adding lsb_release and make it re-usable for all the applications.
As part of the modification, we will update the base version, and install lsb_release package and mark the modification complete. We will first update the Ubuntu with apt update. Then we will install the lsb-core using apt install lsb-core. After the install completes, we can execute lsb_release -a to find the latest information about the Ubuntu.
We can now see that lsb_release -a is available. So essentially, we have made small update to the base Ubuntu image.
Like we installed lsb-core, applications can be installed in this image as part of the containerized solutions. To this document, we consider that we have now updated our image that can be reused by others thus is ready for distribution.
Create a New Image From Modified Container for Distribution
So far, we have got one image which is Ubuntu 18.04 that was pulled from the docker repository. We created a container and updated the images and installed lsb-core into that container. We inspect the status of images by executing docker images and status of container executing docker ps -a to see the list of images and containers, respectively. Note that ps stands for process status.
We can create a new image out of the currently running container image which includes the updates we have made by executing docker commit $container which returns sha256 string of the created image id. Executing docker images shows the newly created image with id of returned sha256. At this time, we have created a new image based on the updated container image.
We can tag the newly created image by providing an appropriate name. We will create a variable to store a new name ‘ubuntu_modified:18.04”
$newImage = "ubuntu_modified:18.04"
We will now commit to create a new image named ‘ubuntu_modified:18:04’.
docker commit $container $newImage
The command returns a sha hash to indicate the id of the newly created image. This image can be seen with docker images command
In the list we can see the newly created image named ‘ubuntu_modified’ with image id matching the sha256 identified and shows the time of creation. Note the size of the image – for new container – which is larger than the original image because we had installed new update to the image.
Now that we have created a fresh image out of the modified container, the older container can be removed. Frist we will stop the container and then remove it.
docker stop $container
docker rm $container
We will verify that the container indeed is removed by running docker ps command.
Now that we have deleted old container, we are going to create a new container named “modified_container” from the modified image. We can now run another container with newly created image. Let us create a new variable for new container
$newContainer = "modified_container"
Start a new container with:
docker run -d --name $newContainer -i -t $newImage
Open a bash shell on the newly created container.
docker exec -it $newContainer bash
After we execute lsb_release -acommand, note that the command returned the result without having to need for an update. Executing exit will get us out of the bash.
As before, lets stop and remove the newly created container as we do not need it.
docker stop $newContainer
docker rm $newContainer
Distributing Docker Image
Now that we have container image created, we are ready for distribution of the image. There are two ways to distribute the image. We can distribute it by pushing the image to public or private repository. For illustration, we are going to use Docker Hub Repository (https://hub.docker.com/repositories) to place the image for distribution.
Distribute using repository
First, we will tag the image to add the repository information. The docker.io is default repository. We will create a variable $repositoryTag to have a value of benktesh/ubuntu:1804 and tag the latest image and execute docker push command
$repositoryTag = "benktesh/ubuntu:18.04"
docker tag $newImage $repositoryTag
docker push $repositoryTag
and a simple docker push will the content to the outside world as it is publicly available in the repository which we can verify by going to the Docker Hub at navigating to benktesh/ubuntu(https://hub.docker.com/repository/docker/benktesh/ubuntu).
Now the file is in repository docker pull command can be used to get an image for further use.
Distribute by Creating Tar File
Another way is to create a tar file from either image or container. Here We are going to look at option where docker image can be saved as tar file.
docker save -o ubuntu.tar $repositoryTag
Command above creates a file ubuntu.tar with a tag defined in variable $repositoryTag which can distributed. The tar file can be loaded into docker to generate image with simple docker command as below:
docker load -i ubuntu.tar
Now the file is loaded, it can be used.
In this post, we illustrated how to create a docker image by using a base image from public repository, run that image in a container, and update the container with necessary installs and upgrades and then create an updated image from the containerized image modification. We also showed how to push the image to registry for distribution and looked at file-based approach to save and load images tar file.