make an image in docker

By | September 10, 2020

Up to this point we have created containers using images pulled down from the internet. Then made changes to those containers. As long we didn’t delete the containers the changes persisted. We can also save the container permanently to images.

To demonstrate this let’s create a container using docker run --name myWeb1 -p 8080:80 -it ubuntu which will launch a shell in our container.

docker run --name myWeb1 -p 8080:80 -it ubuntu

Once in the shell install the following.

apt-get update
apt-get install curl -y
apt-get install vim -y
apt-get install apache2 -y
service apache2 start
// you can chain items together by putting && between them as follows
apt-get update && apt-get install curl -y && apt-get install vim -y && apt-get install apache2 -y && service apache2 start

Modify the default index.html file by entering vim var/www/html/index.html.

Once in vim press “1000dd” to delete all the content.

Then press “i” to insert your own html. Press “esc” and “:wq” to save.

Finally press ctrl+p and ctrl+q to exit to the command line while still leaving the container running.

vim var/www/html/index.html

Navigate to localhost:8080 and you will see your changes.

Next save the changes to an image using docker commit [CONTAINER] [REPOSITORY[:TAG]]

docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
476ddd6b0f5f        ubuntu              "/bin/bash"         5 minutes ago       Up 5 minutes        0.0.0.0:8080->80/tcp   myWeb1
docker commit myWeb1 my_web1_image
sha256:e585e109dc42fa56cdd5408bd1d0332f06ebfb368df3901557aa525a012bb72b

Now that we have created our own image we can use it instead of ubunto. Create another container using docker run --name myWeb2 -p 8081:80 -t -i my_web1_image

This will launch your containers shell. Once again start the apache server by entering service apache2 start .

Press ctrl+p and ctrl+q to exit to the command line while still leaving the container running.

Navigate to localhost:8081 and notice all your changes are in the new container. Cool!

Dockerfile

Making changes to a container and creating an image from it is one way to create a custom image, but there is a better way using a “Dockerfile”. Find full documentation on Dockerfiles here.

First create a directory to put your Dockerfile in as well as any source files. Navigate to that directory and create a “Dockerfile” with vim.

mkdir docker_file_example
cd docker_file_example
vim Dockerfile

Once in vim use the following code for your “Dockerfile”. The file contains the following: FROM pulls the latest ubuntu image down, RUN runs shell commands. ARG DEBIAN_FRONTEND=noninteractive turns off the questions that were asked about location and timezone for an Apache installation. Then we set a WORKDIR to copy our source files to. Finally the remaining command starts the Apache server.

#get an image you want
FROM ubuntu:latest

#install all the tools you might want to use in your container
RUN apt-get update
RUN apt-get install curl -y
RUN apt-get install vim -y
#the following ARG turns off the questions normally asked for location and timezone for Apache
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get install apache2 -y

#change working directory to root of apache webhost
WORKDIR var/www/html

#copy your files, if you want to copy all use COPY . .
COPY index.html index.html

#now start the server
CMD ["apachectl", "-D", "FOREGROUND"]

Third create an index.html file in the same directory and add whatever html you want to serve.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Dude your first Dockerfile example</title>
</head>
<body>
  <h2>You did it dude!</h2>
      <p>This is to inform you that you successfully created a container with ubuntu, curl, vim, apache server, a custom html file and started the server.  Congratulations!</p>
</body>
</html>

Forth build your image as follows.

// build image using the "Dockerfile"
docker image build -t my_dockerfile_image . 

And finally use your image to create a new container. After it is built navigate to localhost:8082 to see your results.

//then use the image to create new container
docker container run --name myWeb3 -d -p 8082:80 my_dockerfile_image
dbdbf8236112a88bd8224fbde5ee7488d88d9b4b283c944b985e3ed38b7b53db

We can now save this image to our docker hub account. First we will rename it by entering the following docker image tag [imageName:tag] [dockerHubAccount/imageName:tag] then we will push it to our docker hub account. Before pushing make sure you are logged into docker hub.

Note: If you don’t have a docker hub account your get one here for free.

docker image tag my_dockerfile_image:latest jimmysoftllc/my_dockerfile_image:latest
docker push jimmysoftllc/my_dockerfile_image:latest

Then we can create another container using our image from docker hub.

docker container run --name myWeb4 -d -p 8083:80 jimmysoftllc/my_dockerfile_image:latest
docker container ls
CONTAINER ID        IMAGE                                     COMMAND                  CREATED             STATUS              PORTS                  NAMES
2396543017a9        jimmysoftllc/my_dockerfile_image:latest   "apachectl -D FOREGR…"   5 seconds ago       Up 5 seconds        0.0.0.0:8083->80/tcp   myWeb4
dbdbf8236112        my_dockerfile_image                       "apachectl -D FOREGR…"   4 minutes ago       Up 4 minutes        0.0.0.0:8082->80/tcp   myWeb3
21169bd38d00        my_web1_image                             "/bin/bash"              21 minutes ago      Up 21 minutes       0.0.0.0:8081->80/tcp   myWeb2
476ddd6b0f5f        ubuntu                                    "/bin/bash"              29 minutes ago      Up 29 minutes       0.0.0.0:8080->80/tcp   myWeb1

Inspect the image

You can inspect your image and see all the image metadata. In the metadata you will see all the configurations we did using the Dockerfile. Notice that our run command "Cmd": ["apachectl","-D","FOREGROUND"] is in the same format as in our Dockerfile. I was curious why it required such a strange format and now it makes sense that it is a key value pair.

docker image inspect jimmysoftllc/my_dockerfile_image
[
    {
        "Id": "sha256:fc63b4fc7ec94c3c8da763cc875910777dc5e8485969e3f3d73718913e2fb39d",
        "RepoTags": [
            "jimmysoftllc/my_dockerfile_image:latest",
            "my_dockerfile_image:latest"
        ],
        "RepoDigests": [
            "jimmysoftllc/my_dockerfile_image@sha256:4acbda1d663dd014cd2a3fe8419a2f32157bd93827064b690e053e8150374fbc"
        ],
        "Parent": "sha256:d91e550d121cd0e3931e41ce9f8d1fec587762dd7da9ea1a4e0263b9fcce69c2",
        "Comment": "",
        "Created": "2020-09-11T21:59:09.7469464Z",
        "Container": "2cccebf5bad8d1950aa5f2fce5487bb24e8c0e7e770d87ee00286307e1d209ae",
        "ContainerConfig": {
            "Hostname": "2cccebf5bad8",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"apachectl\" \"-D\" \"FOREGROUND\"]"
            ],
            "Image": "sha256:d91e550d121cd0e3931e41ce9f8d1fec587762dd7da9ea1a4e0263b9fcce69c2",
            "Volumes": null,
            "WorkingDir": "/var/www/html",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "19.03.12",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "apachectl",
                "-D",
                "FOREGROUND"
            ],
            "Image": "sha256:d91e550d121cd0e3931e41ce9f8d1fec587762dd7da9ea1a4e0263b9fcce69c2",
            "Volumes": null,
            "WorkingDir": "/var/www/html",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 267780583,
        "VirtualSize": 267780583,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/d6c0aa77c2c015f1f0d8db3ca27637a0a0aeb40e09f857b22e3f10e88975d74d/diff:/var/lib/docker/overlay2/81712967ed9f688fa658ae16bcba9605d86cc634c3f1111e2d17fc0697f80f71/diff:/var/lib/docker/overlay2/59d086fa0ba32d3a8ad78d8b5429defb885f8f947e49a74cd3ca02e1759230e7/diff:/var/lib/docker/overlay2/beb13ed69bb4d80eae4ecb1e390938eec7cd658d8616b72bcf6ecbcf401ea43e/diff:/var/lib/docker/overlay2/8ab00975f513c741e35b09cacdf92c3c13bf58c00b776ba8ebc423552559b688/diff:/var/lib/docker/overlay2/e9a47806a9829339ff81890da8a0e9e8463e0a6a749b5d6c0f1e3ae360db4f3d/diff:/var/lib/docker/overlay2/f9155ad7c789de4f6a5081aa2b24e31ac84982553c228861aaddaa22587e8d02/diff:/var/lib/docker/overlay2/ad3e2af0283da6a5626d3b6948d87c3759551320434ab871d5d1391b4d031473/diff",
                "MergedDir": "/var/lib/docker/overlay2/76482b35e706085f2a978bb4745620c3fa6c202c1571c271740db01592cc71eb/merged",
                "UpperDir": "/var/lib/docker/overlay2/76482b35e706085f2a978bb4745620c3fa6c202c1571c271740db01592cc71eb/diff",
                "WorkDir": "/var/lib/docker/overlay2/76482b35e706085f2a978bb4745620c3fa6c202c1571c271740db01592cc71eb/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:2ce3c188c38d7ad46d2df5e6af7e7aed846bc3321bdd89706d5262fefd6a3390",
                "sha256:ad44aa179b334bbf4aeb61ecef978c3c77a3bb27cb28bcb727f5566d7f085b31",
                "sha256:35a91a75d24be7ff9c68ce618dcc933f89fef502a59becac8510dbc3bf7a4a05",
                "sha256:a4399aeb9a0e1ddf9da712ef222fd66f707a8c7205ed2607c9c8aac0dbabe882",
                "sha256:28e65d7bf05221c2c1ead74135322b9d06ce2217b07d072b09dfe105d6b3609d",
                "sha256:2d1cba0b094a082547fff75183799f7fbbc58596cceba8d90223395f7101a2b3",
                "sha256:68dc2869f31711854e9dcc2966084b2fcaa8bc1a8ea92eb0a97e49238b249ac6",
                "sha256:98878591b454a11119fd1506a20deb81d304aaae05a4e2d8e3069dd27461ec93",
                "sha256:638631dfceb80ffe5d51febb2feb40cc1652ce537f1b61aba74e8c511b09838d"
            ]
        },
        "Metadata": {
            "LastTagTime": "2020-09-11T22:02:46.3520449Z"
        }
    }
]

Review what we did

So let’s review. The diagram below shows all the steps that we did in this article.

First we created a container using ubuntu. Docker pulled ubuntu down from DockerHub and placed it in our image store. Then it ran the container.

We made changes to our container then then committed it to the image store.

Next we created a new container using our newly committed image.

Next we created an image from a Dockerfile and created a new container from that.

Finally we renamed and pushed our Dockerfile created image to Docker Hub.