Docker Crash Course: From Basics to Deployment

·

5 min read

Docker Crash Course: From Basics to Deployment

What is Docker?

Docker is a platform for developing, shipping, and running applications in isolated environments called containers. It allows you to package an application with all its dependencies into a standardized software development and deployment unit.

Key benefits of Docker include:

  • Consistency across development, testing, and production environments

  • Easier application deployment and scaling

  • Improved resource utilization compared to traditional virtual machines

In this post, I will take you from the intro to ready-to-use docker. You will know everything you need to get started and work with docker. We will be understanding core concepts to creating and running your own containerized applications.

Core Concepts: Images and Containers

What is a Docker Image?

A Docker image is a lightweight, standalone, and executable package that includes everything needed to run a piece of software. This includes the code, runtime, system tools, libraries, and settings.

Think of an image as a blueprint or a snapshot of your application at a specific point in time. Images are the actual application artefacts that you can move around and share with others.

These images depend on other images, and they are stacked in that way. For example, a Node image might depend on Linux distribution such as a version of Alpine. When we pull another version of the same image we will see that the other image on which these images depend will not be pulled because they may have been pulled already for some other versions and support the current version we are pulling.

What is a Docker Container?

A container is a runtime instance of the image. Containers are the environments in which the images run.

When we say "docker run image-name", what's happening is:

  1. Docker pulls the specified image (if it's not already available locally)

  2. Docker creates a new container based on that image

  3. Docker starts the container, which runs the application defined in the image

Each container has a unique container ID, which you can use to manage it.

Running Docker Images

Let's dive into how to run Docker images:

Pulling an Image

Before running an image, you need to pull it to your local machine:

docker pull image-name:tag

Replace image-name with the name of the image you want to pull, and tag with the specific version you need (if omitted, Docker will use the 'latest' tag). Docker will pull these images from a publicly hosted docker registry and for that, you will not need to log in. If you want to pull an image that is hosted in some private registry then you first need to log in and then run the above command.

Running an Image

To run an image and create a new container:

docker run image-name:tag

This command pulls the image (if not already present), creates a new container, and starts it.

Restarting a Stopped Container

If you have a stopped container that you want to restart:

docker start container-id

Replace container-id with the ID of the stopped container.

Port Mapping

Often, you'll want access to the ports of the running container in docker. For that, you need to do the port mapping from the host (your local machine) to the container. To do that you will use the following command.

docker run -p host-port:container-port image-name:tag

For example, to map port 8080 on your host to port 80 in the container:

docker run -p 8080:80 nginx

Docker Compose

When your application consists of multiple services (like a web app, database, and cache), managing them individually can become cumbersome. This is where Docker Compose comes in handy.

Docker Compose allows you to define and run multi-container Docker applications. You use a YAML file to configure your application's services, networks, and volumes. Then, with a single command, you create and start all the services from your configuration.

Here's a simple example of a docker-compose.yml file:

version: '3'
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: my-secret-pw

This file defines two services: a web server using the latest Nginx image, and a MySQL database.

To run your Docker Compose file:

docker-compose -f file-name.yml up

If your file is named docker-compose.yml, you can simply run:

docker-compose up

To stop the running container you can do

docker-compose down

The above command will stop the running container and remove the image from your host as well.

This command builds, (re)creates, starts, and attaches to containers for a service.

Dockerfile: Building Your Images

While using pre-built images is convenient, you'll often need to create custom images for your applications. This is where Dockerfiles come in.

A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Here's a simple example:

FROM node:14
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

This Dockerfile:

  1. Starts from the official Node.js 14 image

  2. Sets the working directory in the container

  3. Copies package.json and package-lock.json

  4. Installs dependencies

  5. Copies the rest of the application code

  6. Exposes port 3000

  7. Specifies the command to run when the container starts

To build an image from your Dockerfile:

docker build -t my-app:version .

This command builds an image named my-app with the tag version using the Dockerfile in the current directory (.).

You can push your docker-compose file and Dockerfile to the version control host service you're using and anybody can easily run your application on their machine without any dependency on the machine they are using.

Conclusion

Docker provides a powerful set of tools for developing, shipping, and running applications. By understanding images, containers, Docker Compose, and Dockerfiles, you're well on your way to leveraging Docker in your development workflow.

Remember, practice makes perfect. Start small, perhaps by containerizing a simple application, and gradually work your way up to more complex setups. Happy Dockerizing!