How to Create Your First Docker Image
Building your first Docker image might seem intimidating at first, but it’s an essential skill for leveraging the full potential of containerized environments. This guide will walk you through the basics of creating a Docker image using a Dockerfile.
Prerequisites
Before you start, make sure you have the following installed:
- Docker: Install Docker if it’s not already on your system.
- A basic understanding of containers and images (this post will help you).
Step-by-Step: Creating Your First Docker Image
Create a simple Python application and containerize it.
-
Set Up Your Project Directory
Create a project directory for your application:
mkdir my-docker-app
cd my-docker-appInside this directory, create the following files:
app.py# A simple Python application
print("Hello, Docker!")requirements.txt# No dependencies for this simple example -
Create a Dockerfile
A
Dockerfileis a text document that contains the instructions to assemble a Docker image. Here's a basic example:Dockerfile# Use an official Python runtime as the base image
FROM python:3.9-slim
# Set the working directory inside the container
WORKDIR /app
# Copy the requirements file and install dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy the application code into the container
COPY app.py ./
# Define the command to run the application
CMD ["python", "app.py"] -
Build the Docker Image
Run the following command in your project directory to build the image:
docker build -t my-docker-app .Here’s what happens:
-t my-docker-app: Tags the image with the name my-docker-app..: Specifies the current directory as the build context.
-
Run the Docker Container
Once the image is built, you can create and start a container using the following command:
docker run my-docker-appYou should see the output:
Hello, Docker! -
Verify Your Image
To list your Docker images, use:
docker imagesYou'll see something like:
REPOSITORY TAG IMAGE ID CREATED SIZE
my-docker-app latest abc12345defg 1 minute ago 29MB
Security Enhancements for Docker Images
Use Minimal Base Images: Replace general-purpose base images with minimal alternatives to reduce attack surface:
# Instead of python:3.9
FROM python:3.9-slim
# Or even better, use Alpine
FROM python:3.9-alpine
# For production, consider distroless
FROM gcr.io/distroless/python3
Run as Non-Root User: Create and use a dedicated user instead of running as root:
FROM python:3.9-slim
WORKDIR /app
# Create non-root user
RUN addgroup --system appgroup && \
adduser --system --ingroup appgroup appuser
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py ./
# Switch to non-root user
USER appuser
CMD ["python", "app.py"]
Multi-Stage Builds: Separate build dependencies from runtime to minimize final image size:
# Build stage
FROM python:3.9 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Runtime stage
FROM python:3.9-slim
WORKDIR /app
# Copy only necessary files from builder
COPY --from=builder /root/.local /root/.local
COPY app.py .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
Scan for Vulnerabilities: Integrate security scanning into your build process:
# Build image
docker build -t my-docker-app .
# Scan for vulnerabilities
trivy image my-docker-app
# Block deployment if critical vulnerabilities found
trivy image --severity CRITICAL --exit-code 1 my-docker-app
Pin Dependency Versions: Specify exact versions in requirements.txt to ensure reproducible builds:
flask==2.3.2
psycopg2==2.9.6
Use .dockerignore: Exclude unnecessary files from the build context:
.git
.gitignore
.env
.env.local
*.md
__pycache__
*.pyc
tests/
.vscode/
.idea/
Add Health Checks: Enable Docker to monitor container health:
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py ./
HEALTHCHECK --interval=30s --timeout=3s \
CMD python -c "import requests; requests.get('http://localhost:5000/health')"
CMD ["python", "app.py"]
Set Proper Labels: Add metadata for tracking and management:
LABEL maintainer="your.email@example.com"
LABEL version="1.0.0"
LABEL description="Python application"
LABEL org.opencontainers.image.source="https://github.com/user/repo"
Optimize Layer Caching: Order instructions from least to most frequently changing:
FROM python:3.9-slim
WORKDIR /app
# These change rarely, cache them
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Application code changes frequently, copy last
COPY . .
CMD ["python", "app.py"]
Best Practices Summary
Security Checklist:
- Use minimal, specific base images with version tags
- Run containers as non-root users
- Scan images for vulnerabilities before deployment
- Never include secrets in images
- Use multi-stage builds to minimize attack surface
- Implement health checks for reliability
- Keep dependencies updated and pinned
- Use .dockerignore to exclude sensitive files
Image Management:
- Tag images with semantic versions, not just latest
- Push images to private registries with access controls
- Enable image signing and verification
- Regularly rebuild images to incorporate security patches
- Remove unused images to save space and reduce confusion
Testing:
- Test images in isolated environments before production
- Verify security scan results
- Validate health check functionality
- Test resource limits and constraints
- Confirm proper user permissions