Dockerfile

Dockerfile


1. Automatic image construction: Dockerfile

Overview
  • A build recipe for a container image.
  • Contains a series of instructions telling Docker/Podman how an image is to be constructed.
  • The docker build command builds an image from a Dockerfile.
Hands on: writing the first Dockerfile
  • The following commands are done in the terminal (Ubuntu WSL on Windows/Mac Terminal).
1
2
3
4
cd
mkdir myimage
cd myimage
nano Dockerfile
  • Type the following contents into the nano editor.
    • To save and quit nano, press Ctrl-X (or Control-X for Mac)
    • Type Y when asked to Save modified buffer
    • Press Enter.
  • Content of the above Dockerfile
    • FROM: the base image for the build
    • RUN: represents one layer of execution.
    • RUN commands must be non-interactive.
  • To build the image, you can run the following commands:
    • Assumption: you are still inside myimage
    • This could be checked with pwd.
1
2
3
pwd
ls
docker build -t linhbngo/ubuntu_figlet:2.0 .
  • -t indicates a tag named figlet will be applied to the image.
  • . indicates that the Dockerfile file is in the current directory.
  • Running docker image ls and examining the GUI’s Image tab, you will see that there are now two tags for the same repository name. If you run docker push and check your Docker Hub repo, you will see the second tag now stored in the same repository
1
docker push linhbngo/ubuntu_figlet:2.0
Exercise: test new image
  • Test run the new ubuntu_figlet image by launching an interactive container using this image, then immediately run figlet hello world.
Solution
  • Replace linhbngo with your own DockerHub account
1
2
3
docker run -it linhbngo/ubuntu_figlet:2.0 /bin/bash
figlet hello world
exit

2. Infrastructure as Code

Overview
  • Containers can be customized to run as programs/services
    • Barebone containers with just enough dependencies packages
  • Customizable parameters to feed to containers at start time
  • Ephemeral/persistent storages
  • Network infrastructures
CMD and ENTRYPOINT
  • Both commands enable containers to run a default program or script.
  • CMD executes a default program or script with a predefined set of parameters.
    • To be run if the container is invoked without any command.
  • ENTRYPOINT defines a default program or script with a predefined set of parameters, but also allows users to append additional parameters to docker run call.
Hands on: CMD
  • Edit your Dockerfile so that it has the following content
  • Rebuild the image with the tag linhbngo/ubuntu_figlet:3.0.
  • Run the following command
1
2
3
4
cd
cd myimage
docker build -t linhbngo/ubuntu_figlet:3.0 .
docker run -it linhbngo/ubuntu_figlet:3.0
Exercise: storage consumption
  • Run the following commands
1
docker image ls
  • Did we use any additional storage for this new image?
    • Hint: Try running docker system df
Hands on: ENTRYPOINT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- Edit `Dockerfile` as follows:

<script src="https://gist.github.com/linhbngo/b9f794bed306562f2eb85da310ae7b5e.js?file=Dockerfile.3"></script>

- Rebuild the image with the tag `linhbngo/ubuntu_figlet:4.0`.  
- Run the followings:

~~~bash
docker build -t linhbngo/ubuntu_figlet:4.0 .
docker run linhbngo/ubuntu_figlet:4.0
docker run linhbngo/ubuntu_figlet:4.0 golden rams
~~~

- Notice that the first `docker run`, without any input parameters, does not generate any text. 
- The second `docker run` takes `golden rams` and feeds it to the figlet command specified by `ENTRYPOINT`. 
Hands on: Using both ENTRYPOINT and CMD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- `ENTRYPOINT` and `CMD` can be used together. 
- The command line arguments are appended to those parameters. 
- Edit `Dockerfile` as follows:

<script src="https://gist.github.com/linhbngo/b9f794bed306562f2eb85da310ae7b5e.js?file=Dockerfile.4"></script>

- Rebuild the image with the tag `linhbngo/ubuntu_figlet:5.0`. 
- Run the followings:

~~~bash
docker build -t linhbngo/ubuntu_figlet:5.0 .
docker run linhbngo/ubuntu_figlet:5.0
docker run linhbngo/ubuntu_figlet:5.0 golden rams
~~~
1
2
3
4
5
6
7
8
- Caveat with `ENTRYPOINT`: `/bin/bash` does not work as expected.  
    - Need to override with `--entrypoint` flag.

~~~bash
docker run -it linhbngo/ubuntu_figlet:5.0
docker run -it --entrypoint bash linhbngo/ubuntu_figlet:5.0
exit
~~~

Infrastructure as Code: Storage

Overview
  • Docker images are immutable (read-only)
  • Docker containers are mutable, but are available only for the running duration of the containers.
    • Once containers are shutdown, to retain modifications, they need to be made immutable.
  • How do we reconcile new data into Docker images/containers?
    • Copy data into images during the building process
    • Mount storage directory from host machines into containers at run time
COPY
  • COPY src dst
  • Copy contents into the image prior to the installation steps.
  • Need to be done prior to RUN statements.
Hands on: Importing and building external code using COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- Inside the `myimage` directory
- Create the following file called `hello.c`:

<script src="https://gist.github.com/linhbngo/b9f794bed306562f2eb85da310ae7b5e.js?file=hello.c"></script>

- Create the following Dockerfile called `Dockerfile.hello`:

<script src="https://gist.github.com/linhbngo/b9f794bed306562f2eb85da310ae7b5e.js?file=Dockerfile.5"></script>

- You can build an image with a specific Dockerfile

~~~bash
docker build -t linhbngo/hello:1.0 -f Dockerfile.hello .
docker run linhbngo/hello:1.0
~~~
Hands on: Mounting external storage to running containers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- Create a directory called `src` inside `myimage`.
- Copy `hello.c` into this directory.

~~~bash
mkdir src
cp hello.c src/
~~~

- Create the following Dockerfile called `Dockerfile.gcc`:

<script src="https://gist.github.com/linhbngo/b9f794bed306562f2eb85da310ae7b5e.js?file=Dockerfile.8"></script>

~~~bash
docker build -t linhbngo/gcc:1.0 -f Dockerfile.gcc .
docker run -it -v ./src:/ext_src linhbngo/gcc:1.0
~~~

- From the screenshot below, notice that after exiting out of the container, the newly 
created binary file `hello` still persists.