Docker - Images and Dockerfile

1.What is an image?

docker image ls shows all the images(repository, tag, ID, time, size) on you machine.

docker image history <image repository name> shows the history of an image (all the layers of an image, if you make a change on a image, it will create a new layer which is based on the original(source) layer. These two layers make up the image. If two images have the same layer, the layer will be cached. So there isn't two same layers existing on one machine.)

docker image inspect <image repository name> displays detailed information on one or more images.

docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] gives an image a new "name", but these two will use the same image ID.(If you specify the a new tag of an image, these two tag versions will stay together in the same image/repository)

docker login to login using you username and password of Docker account.

docker image pull <repository name> pulls an image or a repository from a registry

docker image push <repository name> pushes an image or a repository to a registry.

If you want to make your own image private on the Internet, you have to create a private repository on the website of Docker Hub. Then push your image through CLI.

2.Build an image

Dockerfile is actually a recipe for creating your image (figurative: a design drawing for a building). It's unique to Docker not like any other languages or scripts. The default name is Dockerfile with a capital D.

docker build -f <some-dockerfile> builds an image with a Dockerfile. You can use -f to specify a different file than a default.

This is an example of a Dockerfile. Each one of these stanzas(blocks/lines) is an actual layer in our Docker image. So the order of them actually matters, because it does work top down. The explanations are in comments.

# NOTE: this example is taken from the default Dockerfile for the official nginx Docker Hub Repo
# NOTE: This file is slightly different then the video, because nginx versions have been updated 
#       to match the latest standards from docker hub... but it's doing the same thing as the video
#       describes
FROM debian:stretch-slim
# all images must have a FROM
# usually from a minimal Linux distribution like debian or (even better) alpine
# If you truly want to start with an empty container, use FROM scratch. 
# One reason they were chosen as preferred way to inject key/value is they work everywhere, on every OS and config

ENV NGINX_VERSION 1.13.6-1~stretch
# optional environment variable that's used in later lines and set as envvar when container is running
# It is a way to set environment variables for container building and for running containers(here, it actually setting the version of Nginx)

RUN apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 \
    && \
    found=''; \
    for server in \ \
        hkp:// \
        hkp:// \ \
    ; do \
        echo "Fetching GPG key $NGINX_GPGKEY from $server"; \
        apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \
    done; \
    test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \
    apt-get remove --purge -y gnupg1 && apt-get -y --purge autoremove && rm -rf /var/lib/apt/lists/* \
    && echo "deb stretch nginx" >> /etc/apt/sources.list \
    && apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests -y \
                        nginx=${NGINX_VERSION} \
                        nginx-module-xslt=${NGINX_VERSION} \
                        nginx-module-geoip=${NGINX_VERSION} \
                        nginx-module-image-filter=${NGINX_VERSION} \
                        nginx-module-njs=${NJS_VERSION} \
                        gettext-base \
    && rm -rf /var/lib/apt/lists/*
# optional commands to run at shell inside container at build time
# this one adds package repo for nginx from and installs it
# You'll usually see run commands when you need to install software with a package repository, or you need to do some unzipping, or some file edits inside the container itself.
# run commands can also run shell scripts that you've copied in earlier in the file or any commands that you can access from inside the container
# the reason to use && here is to chain the commands one after another to ensure all these commands are fit into one single layer which saves time and space.

RUN ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log
# forward request and error logs to docker log collector
# pointing our log files to the stdout and stderr
# don't log in a log file, the better is to make sure that everything we want to be captured in the logs is spit to stdout and stderr.

EXPOSE 80 443
# expose these ports on the docker virtual network
# you still need to use -p or -P to open/forward these ports on host

CMD ["nginx", "-g", "daemon off;"]
# required: run this command when container is launched
# only one CMD allowed, so if there are multiple, last one wins