<style> .present { text-align: left; } </style> # Docker Images and Dockerfiles ## Week 19 Day 3 --- ## Lecture Videos 1 (22 minutes) Watch: - Docker Images and Layers (5:00) - Docker Building and Pushing (12:00) --- ### Docker images Docker images are the templates that we use to run containers. Every time you run a container, you specify an image name. All images are created from Dockerfiles, which are the instructions for building the image. But you can also make your own images, by writing a custom Dockerfile. --- ### Docker image commands | Command | Description | | --------------------------------- | ----------------------------------- | | `docker image ls` | list all images currently on machine | | `docker image history <IMAGE NAME>` | show the layers in an image | | `docker image inspect <IMAGE NAME>` | show all of the metadata associated with an image | | `docker image rm <IMAGE NAME>` | remove a cached image from your system | | `docker image push <IMAGE NAME>` | push an image (that is already built) to dockerhub | | `docker image build [OPTIONS] <PATH>` | build an image from a Dockerfile based on the path | --- ### Composing Dockerfiles Each line of execution in a Dockerfile will have its own image layer. Each line contains an instruction, which must begin with a keyword. --- ### Dockerfile Keywords: `FROM` ([Official documentation](https://docs.docker.com/engine/reference/builder/#from)) All Dockerfiles begin with a `FROM` statement. In this statement you specify the parent image to start from. For example, if I wanted to run a Flask server, I might start with a parent image that is the official Python image. Usage: ```dockerfile= FROM <IMAGE NAME> ``` --- ### Dockerfile Keywords: `WORKDIR` ([Official documentation](https://docs.docker.com/engine/reference/builder/#workdir)) `WORKDIR` changes the working directory in the image, sort of like using `cd` at the command line. That means any subsequent commands will take place in that directory. Additionally, `WORKDIR` will create a directory if it does not exist yet. Usage: ```dockerfile= WORKDIR <DIRECTORY PATH> ``` --- ### Dockerfile Keywords: `COPY` ([Official documentation](https://docs.docker.com/engine/reference/builder/#copy)) `COPY` moves a file, files, or directory from your host machine to a location on the image. Usage: ```dockerfile= COPY <LOCAL DIR PATH> <IMAGE DIR PATH> ``` --- ### Dockerfile Keywords: `ENV` ([Official documentation](https://docs.docker.com/engine/reference/builder/#env)) `ENV` lets you set environment variables in the image. Usage: ```dockerfile= ENV <ENV VARIABLE>=<VALUE> ``` --- ### Dockerfile Keywords: `EXPOSE` ([Official documentation](https://docs.docker.com/engine/reference/builder/#expose)) `EXPOSE` indicates the port that should be exposed. Note that this does not actually publish the port—when you run a container based on the image you would still have to use the `-p external_port:internal_port` flag. The command just sets the intended port in the image's metadata. Usage: ```dockerfile= EXPOSE <PORT NUMBER> ``` --- ### Dockerfile Keywords: `RUN` ([Official documentation](https://docs.docker.com/engine/reference/builder/#run)) `RUN` executes a command on the image. Usage: ```dockerfile= RUN <COMMAND> ``` --- ### Dockerfile Keywords: `CMD` ([Official documentation](https://docs.docker.com/engine/reference/builder/#cmd)) `CMD` specifies the default process that a container based on the image should execute. An image can only have one `CMD`—if more than one is specified, only the latter will be used. If you include a command after the image name when running a container with `docker container run ...`, that will replace the CMD. Usage: ```dockerfile= CMD ["<COMMAND>"] ``` --- ### Dockerfile demo Let's use a Dockerfile to create an image for a simple express server, and then push it to Docker hub. First we'll need a Dockerfile, so create a file named "Dockerfile" inside our demo directory --- ### Dockerfile demo Let's start with a base image, and let's include a specific version tag. We want to run an express server, so let's use an official Node image. --- ### Dockerfile demo Let's add an `EXPOSE` to indicate the port where we will be serving content. ```dockerfile= FROM node:15-alpine3.10 # add an EXPOSE ``` --- ### Dockerfile demo Next, let's create a folder called "app" and set it as our working directory so we can build our server. ```dockerfile= FROM node:15-alpine3.10 EXPOSE 3000 # add a WORKDIR ``` --- ### Dockerfile demo Now we can copy our package.json and package-lock.json to /app—just the files we need to do install dependencies ```dockerfile= FROM node:15-alpine3.10 EXPOSE 3000 WORKDIR /app # copy overpackage installation files ``` --- ### Dockerfile demo And now we can install those dependencies. ```dockerfile= FROM node:15-alpine3.10 EXPOSE 3000 WORKDIR /app COPY package*.json ./ # install dependencies ``` --- ### Dockerfile demo Then we can copy over the rest of the application files. ```dockerfile= FROM node:15-alpine3.10 EXPOSE 3000 WORKDIR /app COPY package*.json ./ RUN npm install # copy files ``` --- ### Dockerfile demo And provide a command to start the application ```dockerfile= FROM node:15-alpine3.10 EXPOSE 3000 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . # run app ``` --- ### Dockerfile demo ```dockerfile= FROM node:15-alpine3.10 EXPOSE 3000 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . CMD ["npm", "start"] ``` --- ### .dockerignore Next, we'll need to create a .dockerignore file. - Why do we ignore node_modules when we're going to npm install anyway? - We want the build process to take care of all setup for us, so it should create node_modules - we don't want anything about the build to depend on the host machine (you might not have node installed, modules might be gitignored) ``` node_modules *Dockerfile* ``` --- ## Building and pushing the container ```bash= # log in to dockerhub docker login # build from the dockerfile located in our current directory # and tag with your dockerhub username docker build -t your-dockerhub-username/my_demo_app . # push the image to dockerhub docker image push your-dockerhub-username/my_demo_app # you can remove the local version of the image docker image rm your-dockerhub-username/my_demo_app # make a container based on the image—because it does not exist locally, # it will pull down the image from your dockerhub docker container run -p 3000:3000 --name demo your-dockerhub-username/my_demo_app ```