DOCKER LEARNING III

Hasan Özdemir
9 min readDec 6, 2021

Contents

  • Docker Images
  • Dockerfile and Instructions
  • How to create Docker Images
  • Dockerhub Basics

Base and Parent Image

Most Dockerfiles start from a parent image. If you need to completely control the contents of your image, you might need to create a base image

  • Base Image : Images that are not from in the DockerFiles are called. A base image has FROM scratch in its DockerFile. A scratch image is a blank image with nothing in it. Based on this we can add whatever we want on it and create our own images.
  • Parent Image : Images other than scratch are parent images. You can create with FROM keyword as well.

DockerFile Detailed

Each line in Dockerfile is a instruction. When creating image a new layer is created for each instruction. Therefore, the number of layers increases in every instruction we write.

When starting the instruction it works on the previous layer and the changes are saved as a new layer and passed to the new instruction. and so on until the instruction are finished.

Let’s make it simple example.

mkdir context_example # create foldercd context_example # go to folderdd if=/dev/zero of=freefile bs=10M count=1 # create a 10 MB file

Let’s create a DockerFile and assign as parent image busybox

cat > Dockerfile # create docker file
FROM busybox # save and exit

Let’s create and image on Dockerfile

docker build -t contextexample . # create image 
Image has created

NOTE : If you investigate the output you can see that context sent to Docker daemon and size is 10.49 MB. Which mean even if we did not add any file to image all files in the directory will be send to Docker daemon. It will be problem for big projects and soon we will see how to handle with this.

Let’s before start to solve this problem delete freefile and create image and see changes.

rm freefile # delete freefile docker build -t contextexample . # create image 
2.048 KB

You can see that context size changed from 10.49 MB to 2.048 KB.

Let’s determine which of the files are included or not and solve the problem.

We will create DockerIgnore file to handle with this problem.

dd if=/dev/zero of=freefile bs=10M count=1 # create 10 MB filecat > .dockerignore # create .dockerignore file
freefile # file we don't want to include
-> SAVE AND EXIT

NOTE : If you want to see DockerIgnore file, ls command cannot work thefore run ls -a command to see hidden files.

docker build -t contextexample . # create image
3.072 KB

NOTE : freefile ignored and file size is decreased. We use to ignore this file DockerIgnore file

DockerIgnore allow us to ignore unnecessary files such as log, settings, passwords, test files.

COMMENTS

If you want to use informative comments in Dockerfile use # sign in file.

cat > Dockerfile
# based on alpine parent image
FROM alpine:latest

If we want to create image with this file all will work as before. It’s just an informative text for developers.

docker build .

FROM instruction

FROM instruction used to specify base DockerFile image.

Let’s see usage of FROM instruction

cat > betik.sh # create new shell scriptecho 'Hello World'
# SAVE AND EXIT
cat > Dockerfile # create DockerfileFROM alpine:latest # assign alpine as base image
COPY betik.sh / # included betik.sh file to image
docker build -t betik . # created Docker image

RUN Instruction

Used to write commands to run on the previous layer while creating an image.

run command is used in two ways on Dockerfile.

shell ; shell type run format are run on command line

exec ; exec type run format are run directly. Command line won’t run

NOTE : Environment variables cannot be passed in exec format so you have to start a shell and get the variables from there

$ cat > Dockerfile
FROM alpine:latest
RUN apk add --no-cache git
RUN ["git", "clone", "https://github.com/xyzuser/BuildFromGit.git"]

CMD Instruction

The CMD command does not make any changes to the image other than adding a layer.When the container is created from the image, it serves to determine what will run by default if the user does not say what user likes to run.

$ cat > Dockerfile
FROM alpine:latest
RUN apk add --no-cache python # installed python
CMD python -m SimpleHTTPServer 8888 # started HTTP Server

LABEL Instruction

If there are tags and definitions that we want to specify in the image we created, label instruction is used.

$ cat > Dockerfile
FROM stracth
LABEL maintainer='hasan@hasan.com"

EXPOSE Instruction

Applications that we run inside the container often listen on one or more ports. EXPOSE is used to indicate which of these ports it is listening on

Let’s make a simple example

$ cat > index.html
<html>
<body> <h1> Hello I am Hasan </h1></body>
</html>

We have created our index.html file

$ cat > Dockerfile
FROM python:2
EXPOSE 80
COPY index.html /
CMD python -m SimpleHTTPServer 80

We stated that we will open port 80 in Dockerfile.

$ docker build -t exposeexample .

We have created image.

docker run --name expose -d -p 80:80 exposeexample

If you run localhost:80 in your browser you will see that index.html file is running.

localhost:80 output

Let’s delete this container and see the main function of expose command

docker rm -f expose # delete expose container
docker ps # show existed containers

Let’s give the -P parameter instead of -p. It automatically opens all ports next to this expose command to the outside world

docker run --name expose -d -P exposeexample

Default TCP port will be opened after above command.

NOTE : If we want to open more than 1 port we can use like below

EXPOSE 80/tcp 53/udp

ENV Instruction

This instruction used to assign environment variables.

$ cat > Dockerfile
FROM busybox
ENV Hasan Ozdemir
ENV name=Hasan surname=Ozdemir

NOTE : If you want to see environment variables, you should write this command after you created your image.

docker run image_name env

ADD and COPY Instructions

You can add file & files to the any index you want with ADD instruction.

COPY instruction is used to copy file & files inside the container, but you cannot use COPY with URLs. In other side if you want to copy files from old build you must use COPY instruction

How to use -> ADD resource1 target

$ cat > Dockerfile
FROM python:2
ADD main.py /main.py
CMD python /main.py

NOTE : If you want to add more than one file you just need to write it.

For example ; ADD res1 res2 res3 target

ENTRYPOINT Instruction

This instruction is used to specify which programs run when the container runs. During creation of container you can change the value of ENTRYPOINT with parameters.

It works as CMD. It can in work two different way, in shell or exec format.

!! Major difference between shell and exec about parameters. In exec format it takes into consider parameters which is written after image name. In shell format it does not take into consider params after image name.

Let’s look at our example

$ cat > Dockerfile
FROM python:2
ENTRYPOINT python
CMD -m SimpleHTTPServer 80

Let’s build our image

$ docker build -t entryxample

When we run this image it will work in shell mode and run only ‘sh -c python’ command. Therefore SimpleHTTPServer part will not work. Even if we pass parameters it doesn’t change result because of character of shell mode

So how we can run this part of code. First option is to overwrite entrypoint during creation of build.

$ docker run --rm -it -entrypoint python entrypointexample -m SimpleHTTPServer 80

Second option is work in exec mode to handle with this problem.

VOLUME Instruction

This instruction is used to specify data in the working image that may need to persist later. Database files, static files can be some of examples.

cat > Dockerfile
FROM busybox
VOLUME /code

Let’s build and run our image

$ docker build -t volexample .
$ docker run -d --name vol volexample sleep 5000

Here VOLUME /code instruction allow us to create a volume and connect this to container. This volume will be there till user go the current folder and clear the files.

If you want to see destination of /code folder just write this from CMD

$ docker inspect volexample

USER Instruction

This instruction is used to change UID (user ID) and GID (group id) which is in namespace.

$ cat > Dockerfile
FROM ubuntu:16.04
RUN useradd user1
USER user1
CMD whoami

In this example we are starting to create image with root user and during this process we are adding user to the system and continue as this user. Also we added whoami command to see who is running the process.

WORKDIR Instruction

The instructino is used to define the working directory of a Docker container at any given time.

If the workdir command is not written, it will automatically be created by the Docker compiler.

ARG Instruction

This instruction is used to specify parameters of docker build command during image creation. If you want you can pass also default value of each params.

$ cat > Dockerfile
FROM python:2
ARG CYTHON_VERSION
RUN pip install Cython==${CYTHON_VERSION}
CMD python -V

Let’s create our image and pass the params and run the container

$ docker build — build-arg CYTHON_VERSION=0.20 -t argexample .
$ docker run -rm argexample

NOTE : If you want to pass the default value only thing you need to is this

ARG CYTHON_VERSION=0.20

TBD (53–60)

Docker Images Layer Structure

Docker images consist of layers. If we want we can observe this layers. There is to possible way to observe this layers. We can check it out from command line or from web interface.

$ docker history
$ docker history --not trunc imagename

NOTE : This instruction shows every detail therefore never pass any authenticaion data to Dockerfile.

Second way to see layers to use this website imagelayers.io

You can follow the link and write image name which is hosted in Docker hub will be enough to monitor layers.

Creating a Docker Image

Let’s discuss firstly challenges. First challenge is versioning of Docker image. If we want to install image to our computer with pull command there is to way. Pass the version or not and this will be download which is tagged as latest.

However there may be no version information for images and it can cause errors. If you want to add version information use this structure

$ docker pull username/imagename:version
$ docker pull hasan/learndocker:0.1
$ docker pull hasan/learndocker:latest

Then you can run this command to monitor versions

$ docker image ls 
  1. Prepare a Dockerfile
$ cat > Dockerfile
FROM busybox
CMD echo 'Hello'

2. Create an image

$ docker build -t exampleimage .

3. Specify version of image

$ docker tag exampleimage exampleimage:1.0

4. Create an account dockerhub

If you have already account just login and if you don’t have please sign up.

After you created your account we can continue from terminal

$ docker login

Then write your username and password to sign in the dockerhub.

5. Upload docker image

We will see how to upload image to dockerhub.

$ docker tag exampleimage hasan/exampleimage:1.0

and to upload to dockerhub

$ docker push hasan/exampleimage:1.0

NOTE: If you want to upload some other platform you should use like this

$ docker tag exampleimage hasan.com/hasan/exampleimage:1.0 

NOTE : Sometimes to create docker image with so many layers can be expensive and not complicating. If you want you can create a docker image only with one layer.

$ docker build --squash -t onelayerexample .

Thank you for paying attention till here and reading my blog. Feel free to leave me comment. See you in my next Docker blog.

Stay healthy.

--

--