This guide explains Docker as a container engine that builds and uses images for application deployment. A Dockerfile serves as the recipe for building application images.
Prerequisites
Qovery CLI installed
Code hosted on GitHub
Basic understanding of Docker concepts
Overview
The tutorial recommends creating both a Dockerfile at the project root and a .dockerignore file to exclude unnecessary files from your image.
Dockerfile Instructions
FROM - Base Image
The first line you’ll add in your Dockerfile is FROM .
This pulls an existing image from Docker Hub matching your application language:
FROM <image_name>:<image_version>
Example:
Choose specific version tags (e.g., python:3.11) instead of latest for reproducible builds.
WORKDIR - Working Directory
Sets the working directory within the container:
FROM python:3
WORKDIR /app
All subsequent commands will be executed from this directory.
COPY - Copy Source Code
Copies your source code into the image:
You can also specify specific source/destination paths using relative directories:
COPY ./src /app/src
COPY package.json /app/
RUN - Execute Commands
Executes commands for installing dependencies and building applications:
RUN echo "Installing or doing stuff."
RUN <my_command>
Examples:
FROM python:3.11
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE - Open Ports
Opens ports for external access:
Example:
Important: Your application must listen on all interfaces (0.0.0.0), not localhost (127.0.0.1), for the container to be accessible.
Correct binding examples:
Node.js/Express
Python/Flask
Go
// ✅ Correct
app . listen ( 8080 , '0.0.0.0' );
// ❌ Wrong
app . listen ( 8080 , 'localhost' );
CMD - Execute Application
Specifies how to execute the application:
CMD [ "<command>" , "<argument_1>" , "<argument_2>" ]
Examples:
Complete Dockerfile Examples
Python Flask Application
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Expose port
EXPOSE 8080
# Run application
CMD [ "python" , "app.py" ]
Node.js Express Application
FROM node:18-alpine
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm ci --only=production
# Copy application code
COPY . .
# Expose port
EXPOSE 3000
# Run application
CMD [ "node" , "server.js" ]
Multi-stage Go Application
# Build stage
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app
# Production stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/app .
EXPOSE 8080
CMD [ "./app" ]
.dockerignore File
Create a .dockerignore file to exclude unnecessary files:
# Git
.git
.gitignore
# CI/CD
.github
.gitlab-ci.yml
# Dependencies
node_modules
__pycache__
*.pyc
vendor
# Environment files
.env
.env.*
# IDE
.vscode
.idea
*.swp
# Build artifacts
dist
build
target
# Documentation
README.md
docs
# Tests
tests
*.test.js
Building Your Image
Local Testing
Test your Docker image locally:
cd ~/my/folder/where/my/code/is
docker build -t my-app:latest .
Testing with Qovery CLI
Test with Qovery CLI before deploying:
This builds and runs your application locally, simulating the Qovery environment.
Best Practices
Use specific base image tags
Combine RUN commands when possible: # ✅ Good
RUN apt-get update && \
apt-get install -y package1 package2 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# ❌ Avoid
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
Reduce final image size by separating build and runtime stages: FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
CMD [ "node" , "dist/index.js" ]
Copy dependency files before source code: # ✅ Good - dependencies cached
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# ❌ Inefficient - rebuilds deps on code change
COPY . .
RUN npm ci
Always create a .dockerignore file to exclude unnecessary files from your build context.
What’s Next
Once your Dockerfile is ready, you can deploy your application to Qovery: