DEV Community

Ting Zhou
Ting Zhou

Posted on

Docker Basics

Penning down my learnings when going through the official docker getting started tutorial. Repository here for reference.

The purpose of Docker is to be machine-agnostic, where anyone with the source code will be able to run the application.

Docker allows us to create images, which we can then run in a container that Docker creates on our machine.

Creating an image
Docker Build Diagram

Running an image in a Docker container
Docker Run Diagram

To demonstrate, we have an express app running on port 3000, with an endpoint GET / that returns "Hello World!".

Dockerfile

The Dockerfile contains instructions on creating and running the image.

# Dockerfile, this line is a comment.
FROM node:12-alpine
COPY . my-wonderful-app
RUN cd my-wonderful-app && npm install
CMD ["node", "my-wonderful-app/app.js"]
Enter fullscreen mode Exit fullscreen mode

What does every line do?

FROM

FROM node:12-alpine | FROM <parent_image>:<image_version>

FROM specifies the parent image from which we are building, as specified here. In this case, our parent image is node, using the version 12-alpine.

What happens if we don't have this line: We will not be able to run any node or npm commands when inside the container.

COPY

COPY . my-wonderful-app | COPY <source_directory>:<destination_directory_in_docker_container>

COPY copies files from the current directory in the machine to the directory inside the docker container, more info here. This command is run when building the docker image.

In this case, we are copying the files from the current directory where the Dockerfile is, into the folder my-wonderful-app in the docker container.

What happens if we don't have this line: Our docker container will not contain our source code.

RUN

RUN cd my-wonderful-app && npm install | RUN <command>

RUN executes the command provided. This command is run when building the docker image. More information here.

In this case, we are changing the directory to my-wonderful-app and running npm install.

What happens if we don't have this line: Our app in the docker container will not have a node_modules folder.

CMD

CMD ["node", "my-wonderful-app/app.js"] | CMD ["executable","param1","param2"]

CMD provides instructions on running the container. More information here.

In this case, we are executing the command node my-wonderful-app/app.js when running the container.

What happens if we don't have this line: Our app will not be run.

Build image

Now that we have the instructions that Docker needs, we can build the image by running docker build -t myapp-image . More info on the docker build command here.

-t

-t <image_name:image_tag> | -t myapp-image

-t provides a name to the image. This allows us to identify the image more easily when we want to run the image. If the image_tag is not provided, the tag will be set to latest

What happens if we don't have this line: Not crucial, we can still run the image by its id.

PATH

. | PATH

Here, we specify . as our path as we are pointing to our current directory

What happens if we don't have this line: The command won't run.

Run image

After the image has been built, we can run the image. Docker will create a container in which the image will run. Run docker -d -p 1234:3000 run myapp-image.

-d

-d specifies that we run this image in detached mode, meaning run it in the background.

What happens if we don't have this line: The terminal used to run the command will be monitoring the image that is run.

-p

-p <MACHINE_PORT>:<CONTAINER_PORT> | -p 1234:3000

-p, which stands for publish, exposes a port on the local machine to a port on the container.

In this case, we are exposing port 1234 on the local machine to port 3000 on the docker container. Earlier, we specified in our app to run on port 3000.

Since the app is running on the container, the app will be using the container's port 3000. Making a call to localhost:1234 will be redirected to the container's port 3000.

How do I know it works

Open localhost:1234 on the browser. You should see "Hello World!".

Docker Compose

It would be very tedious to keep running the build and run commands, especially when there are more containers. That is where docker-compose comes in.

Instead of running the build and run commands, we can specify them in a docker-compose.yaml file instead.

# docker-compose.yaml, this line is a comment.
version: "3.7"

services:
  favourite-app:
    build:
      context: .
    ports:
      - 1234:3000
Enter fullscreen mode Exit fullscreen mode

What does every line do?

version

This is the version we specify to be compatible with the docker engine. The latest version is most commonly used, which can be found from the compatibility matrix here.

In this case, we are using "3.7".

services

These are the services that make up our application. One service will take up one container. Docker will create and run all the services that have been specified here. Examples of other services could be a database where we use the mongodb image.

In this case, we only have 1 service.

service_name:

This name will be reflected in the container name in the following format: <folder_name>_<service_name>_<number>

In this case, the folder name is myapp, the service name is favourite_app. The name of the container will be myapp_favourite-app_1. However, I don't know why there needs to be the number.

build:context:

build:
  context: .
Enter fullscreen mode Exit fullscreen mode

This is to specify where our Dockerfile is, which is needed to create and run the image.

In this case, our Dockerfile is at the current directory, which is why we use . as the context.

ports:

ports:
    - 1234:3000
Enter fullscreen mode Exit fullscreen mode

This is the publish flag that is used in the docker run command, which has been explained above.

How do I know it works

Run docker-compose up -d in the terminal. After the container is up and running, open localhost:1234 on the browser. You should see "Hello World!".

Top comments (0)