DOCKER LEARNING III
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
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
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
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 EXITcat > Dockerfile # create DockerfileFROM alpine:latest # assign alpine as base image
COPY betik.sh / # included betik.sh file to imagedocker 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.
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
- 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.