Skip to main content
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:
FROM python:3
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:
COPY . .
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:
  • Python
  • Node.js
  • Go
  • Java
FROM python:3.11
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

EXPOSE - Open Ports

Opens ports for external access:
EXPOSE <app_port>
Example:
EXPOSE 8080
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:
  • Python
  • Node.js
  • Go
  • Java
CMD ["python", "app.py"]

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:
qovery run
This builds and runs your application locally, simulating the Qovery environment.

Best Practices

# ✅ Good
FROM python:3.11-slim

# ❌ Avoid
FROM python:latest
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: