Skip to content

Docker Registry + Odoo: CI/CD Deployment Pipeline Guide

DeployMonkey Team · March 22, 2026 13 min read

Why Docker CI/CD for Odoo?

Manual Odoo deployments (SSH, git pull, restart) are error-prone and cause downtime. A Docker-based CI/CD pipeline provides: reproducible builds, automated testing, zero-downtime deployments, instant rollback, and consistent environments across dev/staging/production.

Architecture

Developer → Git Push → CI/CD Pipeline
    → Build Docker Image (Odoo + custom addons)
    → Push to Registry (Docker Hub / ECR / GHCR)
    → Deploy to Server (docker compose pull && up)
    → Health Check → Route Traffic
    → (If fail → Rollback to previous image)

Custom Odoo Dockerfile

# Dockerfile
FROM odoo:19

# Copy custom addons
COPY ./custom-addons /mnt/extra-addons

# Install Python dependencies for custom modules
COPY requirements.txt /tmp/requirements.txt
RUN pip3 install --no-cache-dir -r /tmp/requirements.txt

# Copy custom odoo.conf
COPY config/odoo.conf /etc/odoo/odoo.conf

# Set permissions
RUN chown -R odoo:odoo /mnt/extra-addons

Build and Push

# Build the image
docker build -t mycompany/odoo:19-$(git rev-parse --short HEAD) .
docker tag mycompany/odoo:19-$(git rev-parse --short HEAD) mycompany/odoo:latest

# Push to Docker Hub
docker push mycompany/odoo:19-$(git rev-parse --short HEAD)
docker push mycompany/odoo:latest

# Or push to GitHub Container Registry
docker tag mycompany/odoo:latest ghcr.io/mycompany/odoo:latest
docker push ghcr.io/mycompany/odoo:latest

GitHub Actions CI/CD

# .github/workflows/deploy.yml
name: Deploy Odoo
on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build Docker image
        run: |
          docker build -t ghcr.io/${{ github.repository }}/odoo:${{ github.sha }} .
          docker tag ghcr.io/${{ github.repository }}/odoo:${{ github.sha }} \
                     ghcr.io/${{ github.repository }}/odoo:latest

      - name: Push to GHCR
        run: |
          echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
          docker push ghcr.io/${{ github.repository }}/odoo:${{ github.sha }}
          docker push ghcr.io/${{ github.repository }}/odoo:latest

      - name: Deploy to server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: deploy
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /opt/odoo
            docker compose pull odoo
            docker compose up -d odoo
            sleep 10
            curl -f http://localhost:8069/web/health || (docker compose rollback && exit 1)

Zero-Downtime Deployment

# Strategy 1: Rolling update with health check
# docker-compose.yml:
services:
  odoo:
    image: ghcr.io/mycompany/odoo:latest
    deploy:
      update_config:
        parallelism: 1
        delay: 30s
        order: start-first  # Start new before stopping old
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8069/web/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

# Strategy 2: Blue-green with nginx
# Run two containers (blue on 8069, green on 8070)
# Switch nginx upstream after health check passes
# Rollback: switch back to previous container

Rollback

# Quick rollback to previous version:
docker compose down odoo

# Set previous image tag:
# In docker-compose.yml or .env:
# ODOO_IMAGE=ghcr.io/mycompany/odoo:previous-sha

docker compose up -d odoo

# Or use specific tag:
docker compose pull odoo  # pulls :latest which is previous
docker compose up -d odoo

Module Upgrade in Pipeline

# After deploying new image, upgrade modules:
docker compose exec odoo odoo -d production -u my_module --stop-after-init

# For automated upgrades:
# deploy.sh:
#!/bin/bash
set -e
docker compose pull odoo
docker compose stop odoo
docker compose run --rm odoo odoo -d production -u my_module --stop-after-init
docker compose up -d odoo
# Health check
sleep 15
curl -f http://localhost:8069/web/health || exit 1
echo "Deployment successful!"

Private Registry Options

RegistryFree TierBest For
GitHub Container RegistryFree (public)GitHub repos
Docker Hub1 private repoSimple setup
AWS ECR500MB freeAWS deployments
HarborSelf-hosted (free)Full control
GitLab RegistryFree with GitLabGitLab users

DeployMonkey

DeployMonkey provides Git-integrated deployments with Docker. Push to your repo, DeployMonkey builds, tests, and deploys automatically. Zero-downtime with automatic rollback on health check failure. No CI/CD pipeline to maintain.