|
|
@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
# 3. Building Docker Images
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## What are Dockerfile?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Dockerfile**:
|
|
|
|
|
|
|
|
* is a small "program" to create an image
|
|
|
|
|
|
|
|
* Run Dockerfile using `docker build -t name_of_container .`
|
|
|
|
|
|
|
|
* where `.` means Dockerfile is here
|
|
|
|
|
|
|
|
* `-t name_of_contain` mean tag the container
|
|
|
|
|
|
|
|
* When finished, the result will be in local docker registry, ready to be run
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Producing the Next Image with Each Step
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Each line (step) in Dockerfile takes the image from the previous line and make another image
|
|
|
|
|
|
|
|
* The previous images is unchanged
|
|
|
|
|
|
|
|
* state is not carried forward from line to line
|
|
|
|
|
|
|
|
* Multiple command in oneline is different from multiple commands in separate line
|
|
|
|
|
|
|
|
* Hence, you don't want large files to span lines, otherwise, the image is too large
|
|
|
|
|
|
|
|
* e.g. Download a large file, edit it, and delete it; If done in oneline, the image is small, otherwise, it's big
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Details of working with Dockerfile are available in [Dockerfile reference](https://docs.docker.com/engine/reference/builder/)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Caching with Each Step
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `docker build` using Dockerfile will save output of each step in cache
|
|
|
|
|
|
|
|
* Watch build output for "using cache"
|
|
|
|
|
|
|
|
* Docker will skips lines that have not changed since the last build. Time/resource saved
|
|
|
|
|
|
|
|
* Caching saves huge amounts of time
|
|
|
|
|
|
|
|
* Tip of editing Dockerfile: always put the parts that make change at the end of Dockerfile
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Dockerfile != Shell Scripts
|
|
|
|
|
|
|
|
* Dockerfiles look like shell scripts
|
|
|
|
|
|
|
|
* But they are not same
|
|
|
|
|
|
|
|
* Process in one line won't be running on next line
|
|
|
|
|
|
|
|
* Each line run for the duration of that container, then container gets shutdown, saved into an image. Fresh start on next line
|
|
|
|
|
|
|
|
* If two programs need passing values in same container, they have to be in same line
|
|
|
|
|
|
|
|
* Environment variables can be passed to next line using `ENV` cmd
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Summary to notify: each line in Dockerfile is its own call to `docker run`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Building Dockerfiles
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The Most Basic Dockerfile
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Create a simple Dockerfile with following lines
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```dockerfile
|
|
|
|
|
|
|
|
FROM busybox
|
|
|
|
|
|
|
|
RUN echo "building simple docker images."
|
|
|
|
|
|
|
|
CMD echo "Hello Container"
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Build image using this Dockerfile `docker build -t hello .`, result in build output as shown below:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
Sending build context to Docker daemon 2.048kB
|
|
|
|
|
|
|
|
Step 1/3 : FROM busybox
|
|
|
|
|
|
|
|
latest: Pulling from library/busybox
|
|
|
|
|
|
|
|
5f5dd3e95e9f: Pull complete
|
|
|
|
|
|
|
|
Digest: sha256:9f1c79411e054199210b4d489ae600a061595967adb643cd923f8515ad8123d2
|
|
|
|
|
|
|
|
Status: Downloaded newer image for busybox:latest
|
|
|
|
|
|
|
|
---> dc3bacd8b5ea
|
|
|
|
|
|
|
|
Step 2/3 : RUN echo "building simple docker image"
|
|
|
|
|
|
|
|
---> Running in 1990ae4f8398
|
|
|
|
|
|
|
|
building simple docker image
|
|
|
|
|
|
|
|
Removing intermediate container 1990ae4f8398
|
|
|
|
|
|
|
|
---> cf5a3650fa24
|
|
|
|
|
|
|
|
Step 3/3 : CMD echo "hello container"
|
|
|
|
|
|
|
|
---> Running in 3e3b64874c2c
|
|
|
|
|
|
|
|
Removing intermediate container 3e3b64874c2c
|
|
|
|
|
|
|
|
---> 4a0a8c1c2d1b
|
|
|
|
|
|
|
|
Successfully built 4a0a8c1c2d1b
|
|
|
|
|
|
|
|
Successfully tagged hello:latest
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
1. In step 1/3, a image `dc3bac...` is created.
|
|
|
|
|
|
|
|
2. In step 2/3, a container `1990ae...` is created using the image as shown; And `echo "building ..."` is executed using `RUN` command.
|
|
|
|
|
|
|
|
1. The container is also removed at the end of Step 2/3 as no body is using this container any more.
|
|
|
|
|
|
|
|
3. In step 3/3, a new container `3e3b...` is created, added command `echo` using `CMD`, which is then saved as new image `4a0a...`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Running the image `4a0a...` via: `docker run --rm hello`, will print "hello container"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Installing a Program with Docker Build
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Create a new Dockerfile:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```Dockerfile
|
|
|
|
|
|
|
|
FROM debian:sid
|
|
|
|
|
|
|
|
RUN apt-get -y update
|
|
|
|
|
|
|
|
RUN apt-get -y upgrade
|
|
|
|
|
|
|
|
RUN apt-get -y install nano
|
|
|
|
|
|
|
|
CMD "nano" "/tmp/notes"
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Adding a File through Docker Build
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Start from previous built image
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```Dockerfile
|
|
|
|
|
|
|
|
FROM example/nanoer
|
|
|
|
|
|
|
|
ADD notes.txt /notes.txt
|
|
|
|
|
|
|
|
CMD "nano" "/notes.txt"
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In the same directory, create a notes.txt with inputted words. This dockerfile will add required file into image
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Dockerfile syntax
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The FROM statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Indicate which image to download and start from
|
|
|
|
|
|
|
|
* Must be the first cmd in Dockerfile
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The MAINTAINER Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Defines the author of this Dockerfile
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```Dockerfile
|
|
|
|
|
|
|
|
MAINTAINER Firstname Lastname <email@example.com>
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The RUN Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Runs the command line, waits for it to finish, and saves the result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```Dockerfile
|
|
|
|
|
|
|
|
RUN unzip install.zip /opt/install/
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The ADD Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Adds local files `ADD run.sh /run.sh`
|
|
|
|
|
|
|
|
* Adds the contents of tar archives
|
|
|
|
|
|
|
|
* `ADD project.tar.gz /install/`, it will un-compress tar.gz and add to container
|
|
|
|
|
|
|
|
* Works with URLs as well
|
|
|
|
|
|
|
|
* `ADD https://project.example.com/download/1.0/project.rpm /project/`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The ENV Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Sets environment variables
|
|
|
|
|
|
|
|
* Both during the build and when running the image
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```Dockerfile
|
|
|
|
|
|
|
|
ENV DB_HOST=db.production.example.com
|
|
|
|
|
|
|
|
ENV DB_PORT=5432
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The ENTRYPOINT and CMD Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* **ENTRYPOINT** specifies the start of the command to run
|
|
|
|
|
|
|
|
* **CMD** specifies the whole command to run
|
|
|
|
|
|
|
|
* If container acts like a cmd-line program, you can use ENTRYPOINT
|
|
|
|
|
|
|
|
* If you are unsure, CMD is more used
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Shell Form vs. Exec FORM
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* ENTRYPOINT & CMD can use both forms
|
|
|
|
|
|
|
|
* **Shell form** looks like normal shell script:
|
|
|
|
|
|
|
|
* `nano notes.txt`
|
|
|
|
|
|
|
|
* **Exec form** looks like:
|
|
|
|
|
|
|
|
* `["/bin/nano", "notes.txt"]`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The EXPOSE Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Maps a port into the container
|
|
|
|
|
|
|
|
* `EXPOSE 8080`, same as `-p 8080` in `docker run`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### VOLUME Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Defines shared or ephemeral volumes
|
|
|
|
|
|
|
|
* `VOLUME ["/host/path/" "/container/path/"]` map host path to container
|
|
|
|
|
|
|
|
* `VOLUME ["/shared-data"` create a volumes can be inherited by later containers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Tips: Avoid defining shared folders in Dockerfile, as it makes Dockerfile only work with the current computer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### WORKDIR Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Sets the directory the container starts in after `docker run`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```dockerfile
|
|
|
|
|
|
|
|
WORKDIR /install/
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### The USER Statement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Sets which user the container will run as
|
|
|
|
|
|
|
|
* Useful when have a shared network directory involved a fixed username/number
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```dockerfile
|
|
|
|
|
|
|
|
USER arthur
|
|
|
|
|
|
|
|
USER 1000
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### TODO: Read docker reference guid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Multi-project Docker files
|
|
|
|
|
|
|
|
|