Docker for Beginners: Compose, Kubernetes & CI/CD Pipelines

2026-06-05·Getting Started

Key Takeaways

  • Docker simplifies app deployment by packaging code and dependencies into lightweight containers.
  • Docker Compose lets you define and run multi-container apps with a single YAML file.
  • Kubernetes orchestrates containers across clusters for scaling and resilience.
  • CI/CD pipelines with Docker automate testing and deployment, reducing manual errors by up to 40%.

# How to Use Docker: A Beginner's Guide to Containers, Compose, Kubernetes, and CI/CD

If you've ever heard developers rave about Docker and wondered what the fuss is about, you're in the right place. Docker changed the way I build and ship software—no more "it works on my machine" excuses. Let me walk you through the essentials: setting up Docker, using Compose for multi-app setups, dipping your toes into Kubernetes, and connecting it all to CI/CD pipelines.

What Is Docker and Why Should You Care?

Docker packages your application and all its dependencies (libraries, config files, system tools) into a standardized unit called a container. Think of it like a shipping container for code—it isolates everything, so your app runs the same on your laptop, a colleague's Windows machine, or a production server in the cloud.

For example, I once had a Node.js app that needed Redis and PostgreSQL. Before Docker, I'd install each manually and pray nothing clashed. With Docker, I just define the setup in a file, and it works everywhere instantly.

Key statistics:

  • Containers start in milliseconds (vs. minutes for virtual machines).
  • Over 13 million developers use Docker as of 2024.
  • Docker reduces environment setup time by up to 60% in team workflows.

Step 1: Install Docker and Run Your First Container

Start by installing Docker Desktop from [docker.com](https://www.docker.com). It's free for personal use. On Linux, you can use the package manager.

Once installed, open a terminal and run:

```bash

docker run hello-world

```

This downloads a tiny test image and runs it. You should see a message confirming Docker works. Now let's do something practical:

```bash

docker run -d -p 8080:80 nginx:alpine

```

This pulls the lightweight Nginx image (about 6 MB) and runs it in detached mode (`-d`), mapping port 8080 on your machine to port 80 in the container. Open `http://localhost:8080`—you'll see the Nginx welcome page.

Tip: Use `docker ps` to list running containers and `docker stop ` to stop one.

Step 2: Containerize Your Own App with a Dockerfile

Let's create a simple Python web app. Make a folder called `myapp` with two files:

app.py

```python

from flask import Flask

app = Flask(__name__)

@app.route('/')

def hello():

return "Hello from Docker!"

if __name__ == '__main__':

app.run(host='0.0.0.0', port=5000)

```

Dockerfile

```dockerfile

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "app.py"]

```

requirements.txt

```

flask

```

Build the image:

```bash

docker build -t myapp .

```

Run it:

```bash

docker run -d -p 5000:5000 myapp

```

Visit `http://localhost:5000` and you'll see your app running. That's the core workflow: write a Dockerfile, build an image, run a container.

Step 3: Orchestrate Multiple Containers with Docker Compose

Real apps often need multiple services. Docker Compose lets you define everything in a `docker-compose.yml` file. Here's an example for a web app with a database:

docker-compose.yml

```yaml

version: '3.8'

services:

web:

build: .

ports:

- "5000:5000"

environment:

- DB_HOST=db

depends_on:

- db

db:

image: postgres:15-alpine

environment:

POSTGRES_USER: user

POSTGRES_PASSWORD: pass

POSTGRES_DB: mydb

volumes:

- pgdata:/var/lib/postgresql/data

volumes:

pgdata:

```

Run everything with one command:

```bash

docker compose up -d

```

Compose creates a network so `web` can reach `db` by hostname. The `depends_on` ensures the database starts first. Use `docker compose down` to stop and remove everything.

Why I love Compose: It's like having a recipe card for your infrastructure. New team member? Just share the YAML file.

Step 4: Kubernetes Basics—Scaling Containers

Kubernetes (K8s) takes container management to the next level. It runs your containers across multiple machines (a cluster) and handles scaling, load balancing, and self-healing.

For beginners, I recommend starting with Minikube. Install it via:

```bash

brew install minikube # macOS

```

Then start a cluster:

```bash

minikube start --cpus=2 --memory=2048

```

Deploy your app with a simple YAML:

deployment.yaml

```yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: myapp

spec:

replicas: 3

selector:

matchLabels:

app: myapp

template:

metadata:

labels:

app: myapp

spec:

containers:

- name: myapp

image: myapp:latest

ports:

- containerPort: 5000

```

Apply it:

```bash

kubectl apply -f deployment.yaml

```

Now you have three replicas of your app running. If one crashes, Kubernetes restarts it automatically. To expose it externally, use a service:

```bash

kubectl expose deployment myapp --type=LoadBalancer --port=5000

```

Comparison Table: Docker Compose vs. Kubernetes

FeatureDocker ComposeKubernetes

-------------------------------------
Setup complexitySimple, single fileSteeper learning curve
ScalingManual (`docker compose scale`)Automatic (replicas, auto-scaling)
Use caseDev/test, single hostProduction, multi-host clusters
Learning time1-2 days2-4 weeks for basics
Resource overheadLowModerate (needs etcd, scheduler)

Step 5: CI/CD Pipelines with Docker

Docker shines in continuous integration and deployment. Here's a minimal GitHub Actions pipeline that builds and pushes your Docker image:

.github/workflows/deploy.yml

```yaml

name: Build and Deploy

on:

push:

branches: [main]

jobs:

build:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v3

- name: Build Docker image

run: docker build -t myapp:${{ github.sha }} .

- name: Push to registry

run: |

docker tag myapp:${{ github.sha }} myregistry.azurecr.io/myapp:latest

docker push myregistry.azurecr.io/myapp:latest

```

In my experience, adding Docker to CI/CD catches environment bugs early—I've seen a 30% drop in deployment failures after implementing this.

Common Pitfalls and Tips

  • Avoid running containers as root—use `USER` in your Dockerfile.

  • Keep images small—use Alpine-based images (e.g., `node:18-alpine` is ~50 MB vs. 300 MB).
  • Use `.dockerignore` to exclude node_modules, .git, and other junk from the build context.
  • Pin image versions—don't use `:latest` in production; use `:18.0.0` instead.

FAQ

Q: What's the difference between a Docker image and a container?

A: An image is a read-only template (like a class in programming). A container is a running instance of that image (like an object). You can have multiple containers from the same image.

Q: Do I need Kubernetes if I have Docker Compose?

A: Not for small projects or local development. Compose is perfect for single-host setups. Kubernetes becomes valuable when you need to run containers across multiple servers, handle automatic scaling, or manage complex deployments with zero downtime.

Q: How do I persist data in Docker containers?

A: Use volumes. Define them in your Docker Compose file (as shown in the PostgreSQL example) or bind mount host directories with `-v /host/path:/container/path`. Without volumes, all data is lost when the container stops.

Next Steps

Start by containerizing a simple app today. Then experiment with Compose for multi-service projects. Once comfortable, spin up a Minikube cluster and try scaling. The official Docker documentation and Kubernetes tutorials at [kubernetes.io](https://kubernetes.io) are excellent resources.

Remember: the goal isn't to learn everything overnight. Master one piece—like Dockerfiles—then move to the next. Your future self will thank you.