loading...
Cover image for The missing Docker Cheatsheet
Emarsys Craftlab

The missing Docker Cheatsheet

blacksonic profile image Gábor Soós ・5 min read

Development with Docker (3 Part Series)

1) Frontend Development with Docker simplified 2) A simple Node.js Docker workflow 3) The missing Docker Cheatsheet

Docker is becoming increasingly popular among software developers as a container platform. Containers package software in a format that can run isolated on a host operating system. Bundled with only essential libraries and settings, Docker renders lightweight, efficient, self-contained systems that run identically wherever deployed. In this cheat sheet, we'll take a use-case oriented approach: building the image, starting it, and in the end, stopping it and cleaning up after ourselves.

Creating your container

To follow along with the commands, I've borrowed an application with its Dockerfile from my repository representing an ideal Node.js Docker workflow.

# Dockerfile.short
FROM node:12-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

EXPOSE 3000

CMD npm start

The application is an Express web server that responds to incoming HTTP requests.

const express = require('express');
const port = process.env.PORT || 3000;
const app = express();

app.get('/', (req, res) => res.send('Hello World!'));

app.listen(port, () => console.log(`App listening on port ${port}!`));

We'll build and run this file with the upcoming commands.

docker build -f <docker filename> -t <image name> <build context>

Pulls the base image, builds the image inside Dockerfile.short, and names it as express. We can use this name when running the image. The name can contain a tag (express:1): by default, it gets the latest tag. Specifying the name of the Dockerfile is only necessary when it defers from Dockerfile. The dot at the end tells that the build context is the current directory.

docker build -f Dockerfile.short -t express .
Sending build context to Docker daemon  180.7kB
Step 1/7 : FROM node:12-alpine
12-alpine: Pulling from library/node
c9b1b535fdd9: Pull complete 
750cdd924064: Pull complete 
2078ab7cf9df: Pull complete 
02f523899354: Pull complete 
Digest: sha256:e280e51eaa6e626e4df58a5c1f141e453807c30596179330992c55a0bf4114ca
Status: Downloaded newer image for node:12-alpine
 ---> afd897e3184b
Step 2/7 : WORKDIR /app
 ---> Running in c8f379e36c32
Removing intermediate container c8f379e36c32
 ---> a11ced1bd480
Step 3/7 : COPY package*.json ./
 ---> e811deacf584
Step 4/7 : RUN npm ci --only=production
 ---> Running in 401bdc088d44
added 50 packages in 1.395s
Removing intermediate container 401bdc088d44
 ---> 644c8661eff7
Step 5/7 : COPY . .
 ---> 270057bb701a
Step 6/7 : EXPOSE 3000
 ---> Running in cd9d70daad58
Removing intermediate container cd9d70daad58
 ---> 4c6eb54071d1
Step 7/7 : CMD npm start
 ---> Running in fc2a7b3e7e11
Removing intermediate container fc2a7b3e7e11
 ---> d85b87f880e3
Successfully built d85b87f880e3
Successfully tagged express:latest

docker images

Shows all the runnable images on the host machine. We'll see our application with the name express.

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
express             latest              d85b87f880e3        3 minutes ago       87.6MB
node                12-alpine           afd897e3184b        3 days ago          85.2MB

docker run -p <host port>:<container port> <image name>

Runs the built image and connects the containers port with the host machines port (-p 3000:3000). The result is the application is available on http://localhost:3000. If we don't want to block the terminal, we can run the image in detached mode -d. If we're going to have live-reload on file changes, for example, with Nodemon, we can attach the local folder as a volume -v $(pwd):/app.

docker run -p 3000:3000 -v $(pwd):/app express

docker ps -a

Lists the running containers. After docker run, we'll see the application here.

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
ec40c8347a43        express             "docker-entrypoint.s…"   6 seconds ago       Up 5 seconds        0.0.0.0:3000->3000/tcp   hardcore_vaughan

The -a flag shows all the containers, not just the running ones.

docker logs -f -t <image id>

Shows the standard output with timestamps from the running container.

docker logs -f -t ec40c8347a43
2020-02-10T18:22:07.672710300Z
2020-02-10T18:22:07.672788300Z > node-docker-workflow@1.0.0 start /app
2020-02-10T18:22:07.672825700Z > node src/index.js
2020-02-10T18:22:07.672850600Z
2020-02-10T18:22:07.917358100Z App listening on port 3000!

The -f flag tells the command to listen for new logs. If all the records are too much, you can restrict it to only some lines --tail 100.

Publishing the image

Our application is running fine on our local computer, but we can't deploy it anywhere. For deployment, we have to publish it to a repository. For demonstration purposes, we'll use the default DockerHub repository.

docker login

Logs in to the repository, by default to Dockerhub. We need a Dockerhub account before this to work. You can do the registration here.

Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: blacksonic
Password: 
Login Succeeded

docker tag <source image name>:<target tag name> <target image name>:<target tag name>

Names the image with a tag that we will use when uploading the image.

docker tag express:latest blacksonic/express:latest

We have to prefix the image name before uploading it to Dockerhub (blacksonic is my username).

docker push <image name>:<tag name>

Uploads the image to the repository. You can see the uploaded image now on the site https://hub.docker.com/r/blacksonic/express.

docker push blacksonic/express:latest
The push refers to repository [docker.io/blacksonic/express]
d93ac2ab321f: Pushed 
5216338b40a7: Pushed 
latest: digest: sha256:8b418f814535e24906fcb412f8e564ced393e4976586d710bbff60b5fdb2d11c size: 1993

Cleaning it up

We've started and pushed our container successfully. It's time to clean up after ourselves.

docker stop <container id>

Stops the running container. The container won't be deleted.

docker stop ec40c8347a43

docker rm <container id>

Deletes the container, you won't be able to start it again.

docker rm ec40c8347a43

docker rmi <image id>

Deletes the image: you'll have to build it again to start it as a container.

docker rmi d85b87f880e3

docker stop $(docker ps -a -q)

Stops all processes from running containers. After this, docker ps -a will return empty results.

docker rm $(docker ps -a -q)

Removes all the containers.

docker rmi $(docker images -q)

Removes all the images. After this, docker images will return empty results.

docker image prune --all

Removes all unused images. Unused means no running containers exist based on the image.

Summary

Encountering containerization can be hard for the first time, but can be simplified by knowing the right commands which can tell what's happening. With an example configuration, you can try them, and you realize that developing with containers can be as easy as doing it on your local machine.

Development with Docker (3 Part Series)

1) Frontend Development with Docker simplified 2) A simple Node.js Docker workflow 3) The missing Docker Cheatsheet

Posted on by:

blacksonic profile

Gábor Soós

@blacksonic

Enthusiastic full-stack JavaScript developer/lead, tech writer, speaker at Emarsys

Emarsys Craftlab

We love developing, do you share our passion?

Discussion

markdown guide
 

Awesome, thanks. It's is nice overview for the most used commands.

Just want to mention that some commands are actually the old syntax. Yes, they are shorter but I prefer the newer syntax, since they make more sense to me and are more descriptive. Examples:

docker image build # instead of docker build
docker container ls # instead of docker ps
docker container stop # instead of docker stop

Maybe you want to mention that 🆒

 

Thanks for the feedback, obviously more descriptive than the old ones 👍