---
# You can also start simply with 'default'
theme: seriph
# random image from a curated Unsplash collection by Anthony
# like them? see https://unsplash.com/collections/94734566/slidev
background: https://cover.sli.dev
# some information about your slides (markdown enabled)
title: Welcome to Slidev
info: |
## Slidev Starter Template
Presentation slides for developers.
Learn more at [Sli.dev](https://sli.dev)
# apply unocss classes to the current slide
class: text-center
# https://sli.dev/features/drawing
drawings:
persist: false
# slide transition: https://sli.dev/guide/animations.html#slide-transitions
transition: slide-left
# enable MDC Syntax: https://sli.dev/features/mdc
mdc: true
# open graph
# seoMeta:
# ogImage: https://cover.sli.dev
---
# Demystifying Docker
Mike Conrad - SCS 2025
Press Space for next page
---
transition: fade-out
layout: center
---
## Why Containers?
- "It works on my machine" is a thing of the past
- Containers are lightweight and portable
- Boot in milliseconds
- Ideal for reproducible dev environments
---
transition: fade-out
layout: center
---
## Containers vs Virtual Machines
| Feature | VM | Container |
|------------------|----------------|------------------|
| Boot time | Minutes | Seconds |
| Resource usage | Heavy | Lightweight |
| Isolation | Strong | Process-level |
| Portability | Medium | Very High |
In reality we often use containers and vm's together. Containers run inside of VM's for better security and isolation, especially in cloud and multi tenant environments.
---
transition: fade-out
layout: center
---
## What is Docker?
- A tool to build and run containers
- Docker engine runs containers using OS features:
- Namespaces
- cgroups
- Union file systems
- Uses images layered from base -> app code
---
transition: fade-out
layout: center
---
---
transition: fade-out
layout: center
---
## Docker Architecture
Docker Engine (Server) <-- REST API --> Docker CLI (Client)
---
transition: fade-out
layout: center
---
## Docker Under the Hood
- **Namespaces**: isolate PID, net, mount, etc.
- **cgroups**: control CPU, memory, IO
- **UnionFS**: layered filesystem (AUFS, OverlayFS)

---
transition: fade-out
layout: center
---
## Anatomy of a Dockerfile
```dockerfile
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
```
- Starts with a base image
- Copy files and install deps
- Set default command
---
transition: fade-out
layout: center
---
## Dockerfile Best Practices
```dockerfile
# Stage 1: Build the Go binary
FROM golang:1.24.2-alpine AS builder
# Set working directory inside the build container
WORKDIR /app
COPY go.mod ./
RUN go mod download
COPY . .
# Build the Go binary statically
RUN CGO_ENABLED=0 GOOS=linux go build -o docker-api-proxy .
# Stage 2: Run binary in minimal container
FROM scratch
# Copy binary from builder
COPY --from=builder /app/docker-api-proxy /usr/local/bin/docker-api-proxy
# Run binary
ENTRYPOINT ["docker-api-proxy"]
EXPOSE 80
```
- Use specific versions, not `latest`
- Combine commands to reduce layers
- Use `.dockerignore`
- Prefer slim or alpine images
- Run as non-root user if possible
---
transition: fade-out
layout: center
---
## What is Docker Compose?
- Define multi-container apps in one file
- Great for local dev and staging (and production!)
```yaml
name: traefik_secure
services:
socket-proxy:
image: git.hackanooga.com/mikeconrad/docketproxy:latest
container_name: socket-proxy
networks:
- traefik
- socket_proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
restart: unless-stopped
environment:
- ALLOWED_NETWORKS=traefik_secure_traefik
traefik:
image: traefik:latest
container_name: traefik
command:
- "--log.level=INFO"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--providers.docker=true"
- "--providers.docker.endpoint=tcp://socket-proxy:8000"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.traefik.address=:8080"
- "--api.insecure=true"
- "--api.dashboard=true"
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`traefik.docker.localhost`)"
- "traefik.http.routers.api.entrypoints=web"
- "traefik.http.routers.api.service=api@internal"
ports:
- "80:80"
- "8080:8080"
networks:
- traefik
- socket_proxy
depends_on:
- socket-proxy
restart: unless-stopped
whoami:
image: traefik/whoami
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
networks:
traefik: {}
socket_proxy:
driver: bridge
internal: true
enable_ipv6: false
```