# Lesson 2: Introduction to Docker image builds 1. Clone this git repository. 1. Change directory into `lesson02`: $ cd lesson02 1. Why are containers useful? What are their advantages over a traditional server? - containers are light - containers are portable - containers are isolated - containers can be run "immutably" - containers are built hierarchically - developers can create applications without a full server-stack 1. What are some limitations of containers? - interaction is more difficult for multiple containers than for multiple server process (although Kubernetes helps) - some overhead so not quite as fast as "bare-metal" processes - there are several decades worth of server administration best practices and tools but only a few years for containers - not good for large tightly-integrated applications (e.g., Oracle database) 1. Question: what is the difference between an "image" and a "container"? (See also [this Stackoverflow question](https://stackoverflow.com/questions/23735149/what-is-the-difference-between-a-docker-image-and-a-container)). 1. Most Docker images are build on top of existing "base" images. These base containers are usually hosted in Docker Hub. For example, all Debian releases come as Docker images; see https://hub.docker.com/_/debian for a list of the base Debian Docker images. 1. Let's build a "Hello, world." Docker image. We will build it on a Debian buster base. First, pull the Docker image: $ docker pull debian:buster-slim # We pull the "slim" image to save disk space 1. Here is an application that echos "Hello, world." and then exits (this file is also in the current directory). #!/bin/sh echo "Hello, world." exit 0 1. Now we create a "Dockerfile" that tells the build process how to create the image. We use `debian:buster-slim` as the base and "add" the command `run.sh`. The first argument of `ADD` is the *local* copy of the file and the second argument is where we want the file to be in the image. # Dockerfile FROM debian:buster-slim LABEL maintainer="adamhl@stanford.edu" ADD run.sh /root/run.sh 1. We want to make sure that the script will run, so make it executable. # Dockerfile FROM debian:buster-slim LABEL maintainer="adamhl@stanford.edu" ADD run.sh /root/run.sh RUN chmod a+x /root/run.sh 1. Docker containers must be told which command to run. We do this with the `CMD` directive # Dockerfile FROM debian:buster-slim LABEL maintainer="adamhl@stanford.edu" ADD run.sh /root/run.sh RUN chmod a+x /root/run.sh CMD /root/run.sh 1. We are now ready to build the image: $ docker build . -t hello-world $ docker images | grep hello-world 1. Question: what is the purpose of `.` (dot) in the above `docker build` command? 1. Note that the tag is `latest` (the default). 1. Let's run this image in a container: $ docker run --rm hello-world 1. Did you see what you expected?