DEV Community

Cover image for Mastering Docker Basics: A Comprehensive Guide for Beginners
Tandap Noel Bansikah
Tandap Noel Bansikah

Posted on • Edited on

Mastering Docker Basics: A Comprehensive Guide for Beginners

Docker Basics for Beginners

Welcome to the world of Docker! This article provides a detailed overview of essential topics and commands to help you get started with containerization. Whether you're a developer, system administrator, or just curious about modern application deployment, this guide is tailored for you.


1. Introduction to Docker

What is Docker?

Docker is an open-source platform designed to simplify application development and deployment. It allows developers to package applications and their dependencies into lightweight, portable containers that can run consistently across various environments.

Why use Docker?

Docker has become a popular choice due to its numerous benefits:

  • Portability: Applications packaged in containers can run anywhere Docker is installed, from your laptop to a production server.
  • Efficiency: Containers use fewer resources compared to virtual machines, as they share the host system's OS kernel.
  • Scalability: With orchestration tools like Kubernetes, scaling containerized applications becomes straightforward.
  • Isolation: Each container runs independently, avoiding conflicts between applications.

2. Docker Installation

Steps to Install Docker

  1. Windows/MacOS:

    • Download and install Docker Desktop.
    • Ensure that virtualization is enabled on your machine.
  2. Linux:

     sudo apt update
     sudo apt install -y docker.io
     sudo systemctl start docker
     sudo systemctl enable docker
    
  3. Verify Installation:
    Run the following command to check the Docker version:

   docker --version
Enter fullscreen mode Exit fullscreen mode

3. Core Concepts

Understanding the core concepts is essential to using Docker effectively:

  • Images: Immutable templates that define how a container is built. Think of them as blueprints.
  • Containers: Running instances of Docker images. Containers are isolated and lightweight.
  • Dockerfile: A script that automates the creation of Docker images.
  • Volumes: Mechanisms for persisting data generated by containers.
  • Networks: Enable communication between containers.

4. Basic Docker Commands

Working with Images

  • Pull an Image: Download an image from Docker Hub or another registry.
  docker pull <image_name>
Enter fullscreen mode Exit fullscreen mode
  • List Images: View all downloaded images on your system.
  docker images
Enter fullscreen mode Exit fullscreen mode
  • Remove an Image: Delete unused images to save space.
  docker rmi <image_id>
Enter fullscreen mode Exit fullscreen mode

Working with Containers

  • Run a Container: Start a container from an image.
  docker run -d -p 8080:80 <image_name>
Enter fullscreen mode Exit fullscreen mode
  • -d: Run in detached mode.
  • -p: Map host ports to container ports.
    • List Running Containers:
  docker ps -a
Enter fullscreen mode Exit fullscreen mode
  • -a means list all containers
  • Stop a Container:
  docker stop <container_id>
Enter fullscreen mode Exit fullscreen mode
  • Remove a Container:
  docker rm <container_id>
Enter fullscreen mode Exit fullscreen mode
  • Execute Commands Inside a Container:
  docker exec -it <container_id> bash
Enter fullscreen mode Exit fullscreen mode

Inspecting and Managing Containers

  • Inspect a Container: View detailed information about a container.
  docker inspect <container_id>
Enter fullscreen mode Exit fullscreen mode
  • View Logs: Access logs for debugging.
  docker logs <container_id>
Enter fullscreen mode Exit fullscreen mode

5. Building Docker Images

What is a Dockerfile?

A Dockerfile is a text file containing a series of instructions to create a Docker image. It specifies the base image, the dependencies, and the commands required to run your application. Each instruction in the Dockerfile creates a layer in the image, which is cached and can be reused to speed up future builds.

Common Dockerfile Commands:

  • FROM: This is the first command in a Dockerfile. It sets the base image for the image you are building. Every Docker image starts from a base image, which could be something like ubuntu, node, or python, depending on your application's requirements. Example:
  FROM node:14
Enter fullscreen mode Exit fullscreen mode
  • RUN: This command is used to execute commands inside the container, like installing dependencies, running scripts, or building the app. Each RUN instruction creates a new layer. Example:
RUN npm install
Enter fullscreen mode Exit fullscreen mode
  • COPY: This command copies files or directories from your local system into the Docker image. Example:
COPY . /app
Enter fullscreen mode Exit fullscreen mode

. means copy all from root director into the /app direcotory inside the container.

  • ADD: Similar to COPY, but with additional functionality, such as automatically extracting compressed files or pulling files from a URL. Example:
ADD myapp.tar.gz /app
Enter fullscreen mode Exit fullscreen mode
  • CMD: This command specifies the default command to run when the container starts. It can be overridden by providing a command when running the container. Example:
CMD ["node", "app.js"]
Enter fullscreen mode Exit fullscreen mode
  • ENTRYPOINT: Sets the default executable for the container. Unlike CMD, ENTRYPOINT cannot be overridden by arguments provided at runtime. Example:
ENTRYPOINT ["python", "app.py"]
Enter fullscreen mode Exit fullscreen mode
  • EXPOSE: This command informs Docker that the container listens on a specific network port at runtime. It does not publish the port but acts as documentation for the container's expected network usage. Example:
EXPOSE 8080
Enter fullscreen mode Exit fullscreen mode
  • ENV: Defines environment variables in the container, which can be accessed by the application or any other processes inside the container. Example:
ENV NODE_ENV=production
Enter fullscreen mode Exit fullscreen mode
  • WORKDIR: Sets the working directory for the container. All subsequent commands will be run in this directory. Example:
WORKDIR /app
Enter fullscreen mode Exit fullscreen mode
  • VOLUME: Creates a mount point inside the container, allowing for persistent data storage across container restarts. Example:
VOLUME ["/data"]
Enter fullscreen mode Exit fullscreen mode
  • **USER: Sets the user name or UID to use when running the container. This can improve security by running the container with a non-root user. Example:
USER appuser
Enter fullscreen mode Exit fullscreen mode
  • MAINTAINER: This command allows you to specify the author or maintainer of the Docker image. This is useful for tracking who is responsible for the image. Example:
MAINTAINER John Doe <john.doe@example.com>
Enter fullscreen mode Exit fullscreen mode

The about are just the commonly used commands used in a dockerfile to build a particular image, you can always explore more on the docker official documentation

Example Dockerfile

This Dockerfile creates an image for a simple Node.js application:

# Use a base image
FROM node:16

# Set the working directory
WORKDIR /app

# Copy application files
COPY package.json ./
COPY . ./

# Install dependencies
RUN npm install

# Expose a port
EXPOSE 3000

# Start the application
CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

Build an Image

To build an image from the Dockerfile:

docker build -t my-app .
Enter fullscreen mode Exit fullscreen mode

6. Docker Volumes

What are Volumes?

Docker volumes allow you to persist data beyond the container's lifecycle.

Basic Volume Commands

  • Create a Volume:
  docker volume create <volume_name>
Enter fullscreen mode Exit fullscreen mode
  • Use a Volume in a Container:
  docker run -v <volume_name>:/path/in/container <image_name>
Enter fullscreen mode Exit fullscreen mode
  • List Volumes:
  docker volume ls
Enter fullscreen mode Exit fullscreen mode

7. Docker Networking

Networking Overview

Docker networks allow containers to communicate with each other and external systems.

Types of Networks

  • Bridge: Default network; containers on the same bridge can communicate.
  • Host: Uses the host’s network stack.
  • None: No network; fully isolated containers.

Common Commands

  • List Networks:
  docker network ls
Enter fullscreen mode Exit fullscreen mode
  • Create a Network:
  docker network create <network_name>
Enter fullscreen mode Exit fullscreen mode
  • Connect a Container to a Network:
  docker network connect <network_name> <container_id>
Enter fullscreen mode Exit fullscreen mode

8. Docker Compose

What is Docker Compose?

Docker Compose simplifies the management of multi-container applications using a YAML file.

Example Compose File

Here’s a docker-compose.yml for a web app and a MySQL database:

version: "3.8"
services:
  web:
    image: nginx
    ports:
      - "8080:80"
  db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: example
Enter fullscreen mode Exit fullscreen mode

Compose Commands

  • Start Services:
  docker-compose up or docker compose up -d
Enter fullscreen mode Exit fullscreen mode
  • -d to start containers in detatched mode
  • Stop Services:
  docker-compose down or docker-compose down -v
Enter fullscreen mode Exit fullscreen mode
  • -v means taking down the containers plus its volumes

9. Docker Hub

What is Docker Hub?

Docker Hub is a public repository for sharing container images.

Using Docker Hub

  • Search for Images:
  docker search <image_name>
Enter fullscreen mode Exit fullscreen mode
  • Push an Image:
  docker push <username>/<image_name>
Enter fullscreen mode Exit fullscreen mode
  • Pull an Image:
  docker pull <username>/<image_name>
Enter fullscreen mode Exit fullscreen mode

10. Troubleshooting Docker

Common Issues

  • Container Fails to Start: Check logs using:
  docker logs <container_id>
Enter fullscreen mode Exit fullscreen mode
  • Image Build Errors: Verify the Dockerfile syntax and paths.
  • Port Conflicts: Ensure no other services are using the same port.

11. Best Practices

  • Use small, efficient base images.
  • Minimize layers in Dockerfiles.
  • Avoid hardcoding sensitive data in images; use environment variables instead.
  • Regularly clean up unused images and containers.

12. Practical Examples: Building and Dockerizing Applications

1. Spring Boot Application

Application Setup:

Step 1: Create the Project

  1. Visit Spring Initializr.
  2. Configure the project:
    • Project: Maven
    • Language: Java
    • Spring Boot Version: 3.4.1
    • Dependencies: Spring Web
  3. Generate the project and unzip it.

Step 2: Project Structure

The generated structure includes:

.
├── Dockerfile
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── bansikah
    │   │           └── demoapp
    │   │               └── DemoAppApplication.java
                        |__ HelloController.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── bansikah
                    └── demoapp
                        └── DemoAppApplicationTests.java

14 directories, 8 files

Enter fullscreen mode Exit fullscreen mode
  • DemoAppApplication.java: The main entry point for the Spring Boot
package com.bansikah.demoapp;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoAppApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoAppApplication.class, args);
    }

}
Enter fullscreen mode Exit fullscreen mode

HelloController.java: Our demo controller we will use to test our application.

package com.bansikah.demoapp;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, Docker!";
    }
}
Enter fullscreen mode Exit fullscreen mode

Dockerfile:: Dockerize the spring applicaton so that we can run it as a docker container.

# Stage 1: Build
FROM maven:3.8.7-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests

# Stage 2: Run
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /app/target/demo-app-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

Enter fullscreen mode Exit fullscreen mode

Commands:

mvn clean install
docker build -t springboot-demo-app .

docker run -d -p 8080:8080 springboot-demo-app

curl http://localhost:8080/hello

Enter fullscreen mode Exit fullscreen mode

and when you test using curl you should see:

Image description


2. Python Flask Application

Application Setup:

mkdir flask-app && cd flask-app
Enter fullscreen mode Exit fullscreen mode

Project structure:

flask-app
├── app.py
├── Dockerfile
├── requirements.txt
Enter fullscreen mode Exit fullscreen mode
    1. Create app.py:
    from flask import Flask
    app = Flask(__name__)
    
    @app.route('/')
    def home():
        return "Hello, Docker!"
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=5000)
    

-2 Dockerfile:

# Use a lightweight Python base image
FROM python:3.10-slim

# Set the working directory in the container
WORKDIR /app

# Copy the application files
COPY app.py /app
COPY requirements.txt /app

# Install the Python dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Expose the port the Flask app runs on
EXPOSE 5000

# Run the Flask application
ENTRYPOINT ["python", "app.py"]

Enter fullscreen mode Exit fullscreen mode

Commands:

echo "flask" > requirements.txt
docker build -t flask-app .
docker run -p 5000:5000 flask-app
curl http://localhost:5000
Enter fullscreen mode Exit fullscreen mode

And you should see this :

Image description


3. Node.js Application

Application Setup:

  • 1. Set Up the Project Directory:
mkdir node-app && cd node-app
Enter fullscreen mode Exit fullscreen mode
  • 2. Initialize a New Node.js Project: Run the following command and follow the prompts:
npm init -y
Enter fullscreen mode Exit fullscreen mode
  • 3. Install Required Dependencies: For this example, we’ll use the Express framework:
npm install express
Enter fullscreen mode Exit fullscreen mode
  • 4. Create the Application Code: Create a file named server.js with the following content:
const express = require("express");
const app = express();

const PORT = process.env.PORT || 3000;

app.get("/", (req, res) => {
    res.send("Hello, Dockerized Node.js!");
});

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode
  • 5. Creating the Dockerfile Create a Dockerfile in the project root with the following content:
# Use Node.js base image
FROM node:18

# Set the working directory inside the container
WORKDIR /app

# Copy package.json and package-lock.json files
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy application files
COPY . .

# Expose the application port
EXPOSE 3000

# Command to run the application
CMD ["node", "server.js"]
Enter fullscreen mode Exit fullscreen mode
  • 6. Building the Docker Image
docker build -t node-app .
docker run -d -p 3003:3000 node-app
Enter fullscreen mode Exit fullscreen mode

We exposed the appliction port to be port 3000 but since i had already another application using that port externally on my computer i had to map the port to an external port 3003

  • 7. Test Application:
curl http://localhost:3003
Enter fullscreen mode Exit fullscreen mode

You should see:

Node application

Docker compose practical examples

Create a directory and file

mkdir docker-compose & cd docker-compose
touch docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

docker-compose.yml

version: '3.8'

services:
  frontend:
    image: nginx:alpine
    container_name: frontend
    volumes:
      - ./frontend:/usr/share/nginx/html:ro
    ports:
      - "80:80"
    networks:
      - webnet

  backend:
    image: node:14
    container_name: backend
    environment:
      - NODE_ENV=production
      - DB_HOST=db
      - DB_USER=admin
      - DB_PASS=secret
    volumes:
      - ./backend:/usr/src/app
    ports:
      - "3000:3000"
    depends_on:
      - db
    networks:
      - webnet

  db:
    image: postgres:13
    container_name: db
    environment:
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=appdb
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - webnet

networks:
  webnet:
    driver: bridge

volumes:
  db_data:
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Frontend Service: Uses the nginx image to serve static files, maps the local frontend directory to /usr/share/nginx/html, and exposes port 80.
  • Backend Service: Runs a Node.js app, connects to the database (db) with environment variables, exposes port 3000, and depends on the database service.
  • Database Service: Uses postgres image, creates appdb with credentials, and stores data in the db_data volume.
  • Networks: All services are connected to the webnet network for communication.

Conclusion:

Docker is a powerful tool for simplifying the process of building, shipping, and running applications in containers. It allows you to create isolated environments, making it easier to manage dependencies and deploy applications across various platforms. As you explore Docker, you'll see how it can streamline development workflows, enhance scalability, and improve the consistency of your applications.

Here you can find the link to all the code that has been used link to code

If you encounter any challenges or have questions while getting started with Docker, feel free to reach out! I am here to help you overcome any obstacles. Don't hesitate to post your queries, and I'll make sure to assist you.

For more information and resources, check out the following links:

Happy containerizing! 🚀

Top comments (0)