Why Odoo 18 Docker Compose is a Game-Changer for Developers
In the realm of software development, especially with intricate systems like Odoo, a consistent, stable, and reproducible development environment is absolutely crucial. Traditionally, setting up such an environment has often been a source of headaches: version conflicts, manual configurations, and the infamous “it works on my machine” dilemma. Fortunately, Odoo 18 Docker Compose provides a powerful solution to these challenges, transforming how you approach Odoo development.
Let’s dive into the core advantages that make a Dockerized Odoo environment indispensable:
- Consistency and Reproducibility: The “it works on my machine” problem is a relic of the past. With a Dockerized Odoo setup, your environment behaves identically, whether you’re on Linux, Windows, or macOS. Share your project with a colleague, deploy it to a staging server, or push it to production—the application will perform consistently, requiring only minor configuration adjustments across different environments.
- Isolation for Seamless Development: Imagine effortlessly running multiple Odoo versions (e.g., Odoo 16, Odoo 17, Odoo 18, and even future versions) on the same machine without any conflicts. Docker’s containerization capabilities provide this isolation, ensuring each Odoo instance operates independently without interfering with others. This is a massive boon for developers working on diverse projects or supporting clients on various Odoo releases.
- Streamlined Configuration and Deployment: Your local Odoo 18 Docker Compose setup is highly portable. The same configuration you use for development can be adapted for testing or even production environments with minimal effort. This consistency across the development lifecycle saves significant time and reduces deployment errors.
- Optimized Resource Utilization: Unlike traditional virtual machines that require dedicated resources for each guest OS, Docker containers share the host operating system’s kernel. This makes them significantly lighter and more efficient, reducing the demand on your system’s RAM and CPU. You can run more isolated environments without bogging down your machine.
Demystifying Docker: Images and Containers
If you’re new to Docker, let’s break down its fundamental concepts using a simple analogy. Imagine you’re moving houses. Your “house” is your Odoo application, complete with all its “furniture” (Python libraries, binaries, configurations, PostgreSQL database). Traditionally, moving would mean unpacking everything, reinstalling, and reconfiguring each item in your new home—a lengthy and error-prone process.
This is where Docker steps in.
- Docker Image: Think of a Docker image as a standardized, self-contained moving box. This box is a blueprint or a template that holds your entire Odoo application and all its dependencies, perfectly pre-configured. It’s immutable, meaning it won’t change once created. Odoo, for instance, provides pre-built images for each of its versions (like
odoo:18.0), saving you the hassle of building from scratch. - Docker Container: When you want your “house” (your Odoo application) to function, you tell Docker to “open that box and make it run.” Docker creates an instance of that image and executes it. This running instance of the standardized box is called a Docker container. Containers are isolated, lightweight, and can be started, stopped, and removed quickly. You can have multiple containers running simultaneously from the same image or different images.
- Docker Platform: At its core, Docker is the platform that enables you to build, run, and manage these images and containers. It’s the efficient moving company that handles all the logistics for your applications.
Orchestrating Power: Understanding Docker Compose for Odoo
While Docker is excellent for managing individual containers, Odoo is not a standalone application; it critically depends on a database, typically PostgreSQL. For such multi-service applications, trying to manage individual containers manually becomes cumbersome. This is where Docker Compose shines.
- The Conductor of Containers: Docker Compose acts as an orchestrator, or like the “foreman” of your moving operation. Instead of managing one box, it helps you organize and launch multiple interconnected boxes (containers) with a single command. It ensures that services like Odoo and PostgreSQL can communicate seamlessly within a defined network.
- The
docker-compose.ymlFile: The magic of Docker Compose lies in a simple YAML file, typically nameddocker-compose.yml. This file is where you define all the services (like your Odoo web application and your PostgreSQL database), their images, ports, volumes, and dependencies. It’s a declarative way to describe your entire application stack, making it easy to version control and share. - Simplified Management: With a properly configured
docker-compose.ymlfile, starting your entire Odoo development environment (including its database) is as simple as runningdocker compose up. This command reads your YAML definition, pulls necessary images, creates containers, sets up networks, and starts all services in the correct order.
Ensuring Data Persistence: Docker Volumes
One crucial aspect of containerized environments is data persistence. By default, Docker containers are ephemeral: if a container is stopped or deleted, any data written inside it is lost. For applications like Odoo, where database information, uploaded files, and session data are vital, this ephemeral nature presents a challenge.
The solution comes in the form of Docker Volumes. Volumes allow you to store data outside the container’s lifecycle, ensuring your data persists even if the container is removed or replaced.
There are two primary types of volumes you’ll use in your Odoo 18 Docker Compose setup:
- Named Volumes: These volumes are entirely managed by Docker. They are ideal for persistent data that doesn’t need to be directly accessed or modified by your host machine’s file system, such as PostgreSQL database files or Odoo’s session and attachment data. Docker handles their creation, management, and storage location.
- Bind Mounts: Bind mounts link a directory on your host machine directly into a directory inside the container. This is particularly useful for development workflows. For instance, you can map your local
addonsfolder to the Odoo container’s addons path. Any changes you make to your custom modules in your local code editor will instantly reflect inside the running Odoo container, accelerating your development cycle.
Step-by-Step Tutorial: Setting Up Your Odoo 18 Docker Compose Environment
Now that we understand the foundational concepts, let’s get hands-on and build your Odoo 18 Docker Compose development environment.
Prerequisites: Installing Docker and Docker Compose
Before you begin, ensure Docker and Docker Compose are installed on your system.
-
Install Docker Engine and Docker Compose: Visit the official Docker documentation website for detailed installation instructions tailored to your operating system: https://docs.docker.com/get-docker/
- For Ubuntu/Debian users, the process typically involves updating your package index, adding Docker’s official GPG key, setting up the stable repository, and then installing
docker-ce,docker-ce-cli,containerd.io, anddocker-compose-plugin. - Windows and macOS users can download Docker Desktop, which bundles Docker Engine, Docker CLI, Docker Compose, and Kubernetes.
- For Ubuntu/Debian users, the process typically involves updating your package index, adding Docker’s official GPG key, setting up the stable repository, and then installing
-
Verify Installation: Once installed, open your terminal or command prompt and run the following commands to confirm they are working:
docker --version docker compose versionYou should see version information for both, indicating a successful installation. If you encounter permission errors, especially on Linux, you might need to run Docker commands with
sudoor add your user to thedockergroup.
Project Structure: Laying the Foundation
Let’s create the necessary directories and files for your Odoo project.
-
Create Your Main Project Directory:
mkdir odoo18_dev_environment cd odoo18_dev_environment(You can name this directory anything you prefer.)
-
Create Essential Subdirectories:
mkdir config addonsconfig: This directory will hold yourodoo.conffile, which contains Odoo-specific configurations.addons: This is where you’ll place all your custom Odoo modules and third-party addons.
-
Create Core Configuration Files:
touch docker-compose.yml .env config/odoo.confdocker-compose.yml: Defines your Odoo and PostgreSQL services..env: Stores environment variables, keeping sensitive information out of your main Docker Compose file.config/odoo.conf: The Odoo configuration file.
Configuration Files: The Heart of Your Setup
Now, let’s populate these files with the necessary configurations.
-
docker-compose.yml(Service Orchestration):
Opendocker-compose.ymland add the following content. This file defines two services:web(for Odoo) anddb(for PostgreSQL).version: "3.9" services: web: image: odoo:18.0 # Specifies the Odoo 18 image from Docker Hub container_name: ${WEB_HOST} # Name the container using .env variable depends_on: - db # Ensures the DB container starts before Odoo ports: - "${WEB_PORT}:8069" # Maps host port to Odoo's default port - "${WEB_PORT_HTTPS}:8072" # Maps host port to Odoo's live chat port volumes: - odoo_web_data:/var/lib/odoo # Named volume for Odoo data persistence - ./config:/etc/odoo # Bind mount for odoo.conf - ./addons:/mnt/extra-addons # Bind mount for custom modules entrypoint: /usr/bin/odoo -c /etc/odoo/odoo.conf # Command to start Odoo with config db: image: postgres:15 # Specifies the PostgreSQL 15 image container_name: ${DB_HOST} # Name the DB container using .env variable environment: POSTGRES_USER: ${DB_USER} # DB username from .env POSTGRES_PASSWORD: ${DB_PASSWORD} # DB password from .env POSTGRES_DB: ${DB_NAME} # Default DB name from .env ports: - "5432:5432" # Maps host port to PostgreSQL's default port volumes: - odoo_db_data:/var/lib/postgresql/data # Named volume for PostgreSQL data persistence volumes: # Define named volumes used by services odoo_web_data: odoo_db_data:Self-note: I’ve included comments in the YAML to explain each line, enhancing the tutorial aspect.
-
.env(Environment Variables):
Open.envand define your environment-specific variables. These values will be picked up bydocker-compose.yml.WEB_HOST=odoo18_web_dev WEB_PORT=8001 WEB_PORT_HTTPS=8002 DB_HOST=odoo18_postgres_db DB_USER=odoo DB_PASSWORD=odoo_password DB_NAME=my_odoo_dbSecurity Note: For production environments, never use simple passwords like
odoo_password. Always use strong, randomly generated passwords. This setup is for a local development environment. -
config/odoo.conf(Odoo Configuration):
Openconfig/odoo.confand add the following Odoo-specific settings. These parameters allow Odoo to connect to the PostgreSQL database and locate your custom modules.[options] admin_passwd = my_master_password # IMPORTANT: Change this password for security! db_host = odoo18_postgres_db # Matches DB_HOST in .env db_port = 5432 db_user = odoo # Matches DB_USER in .env db_password = odoo_password # Matches DB_PASSWORD in .env addons_path = /mnt/extra-addons # Path inside the container for custom modulesNote: The
db_hostvalue here must match thecontainer_nameof yourdbservice as defined in your.envfile (DB_HOST). This is how the Odoo container knows how to find its database counterpart within the Docker network.
Bringing Odoo to Life: Launching Your Environment
With all the configuration files in place, you’re ready to launch your Odoo 18 Docker Compose development environment.
-
Navigate to Your Project Directory: Ensure your terminal is in the
odoo18_dev_environmentdirectory (or whatever you named it) where yourdocker-compose.ymlfile resides. -
Start the Services: Execute the following command:
sudo docker compose up -dsudo: May be required on Linux systems if your user isn’t part of thedockergroup.docker compose up: This command tells Docker Compose to build, create, start, and attach to containers for all the services defined indocker-compose.yml.-d: Runs the containers in “detached” mode, meaning they will run in the background, freeing up your terminal.
The first time you run this, Docker will download the
odoo:18.0andpostgres:15images from Docker Hub. This might take a few minutes depending on your internet connection. Once downloaded, Docker Compose will create the network, volumes, and then start thedbandwebcontainers. You’ll see logs indicating their startup process.
First Run & Database Creation
Once your containers are up and running, it’s time to access Odoo and set up your initial database.
- Open Your Web Browser:
-
Navigate to Your Odoo Instance: Go to
http://localhost:8001(or theWEB_PORTyou specified in your.envfile). -
Create Your Odoo Database: You should be greeted by the Odoo database creation screen. Fill in the details:
- Master Password: Enter the
admin_passwdyou set inconfig/odoo.conf(e.g.,my_master_password). - Database Name: Choose a name for your Odoo database (e.g.,
my_first_odoo_db). - Email:
admin(or any email for the admin user). - Password:
admin(or any password for the admin user). - Language & Country: Select your preferences.
- Load Demonstration Data: (Optional, useful for testing).
- Click “Create database.”
Odoo will then install the base modules and create your database. This process might take a few minutes, during which you can observe the logs in your terminal if you ran
docker compose upwithout-d, or by runningdocker compose logs -fin a new terminal. Once complete, you’ll be redirected to the Odoo login page. Log in with theEmailandPasswordyou just set for the admin user. Congratulations! You now have a fully functional Odoo 18 Docker Compose development environment. - Master Password: Enter the
Troubleshooting Common Issues
- Permissions Errors (
sudo): Ifdocker compose upfails with permission denied errors, ensure you’ve usedsudo. On Linux, adding your user to thedockergroup (and logging out/in) can resolve this permanently:sudo usermod -aG docker $USER. - Port Conflicts: If
portsindocker-compose.ymlreports an error like “port already in use,” it means another application on your system is using8001or8002. Simply changeWEB_PORTandWEB_PORT_HTTPSin your.envfile to different, unused ports (e.g.,8003,8004). -
Report URL / Missing CSS: Odoo reports might render without proper styling (CSS) in a Dockerized setup. This is a common issue. To fix it:
- Log in to Odoo.
- Activate Developer Mode (Settings -> Activate the developer mode).
- Go to Technical -> Parameters -> System Parameters.
- Add or modify the
report.urlparameter with the valuehttp://localhost:8069. This tells Odoo where to find its own report rendering service within the Docker network. Remember, while you access Odoo via8001on your host, Odoo itself operates on8069inside its container.
Beyond Setup: Customizing Odoo 18 Reports with Best Practices
A crucial part of Odoo development involves customizing existing functionalities, especially reports. While Odoo allows direct modification of QWeb views through the interface (as shown in the source tutorial for academic purposes), the best practice, particularly for Odoo 18 Docker Compose environments, is to create a dedicated custom module. This modular approach ensures your customizations are maintainable, easily upgradeable, and don’t directly alter Odoo’s core code.
The Power of Extension
Modifying core Odoo code or existing views directly through the interface is generally discouraged for production environments because:
- It makes upgrades difficult.
- It complicates version control.
- It can lead to unexpected behavior if Odoo’s core changes.
Instead, Odoo provides robust extension mechanisms. You can inherit from existing views and apply specific changes (add, remove, replace elements) using XPath expressions. This is exactly what we’ll do.
Hands-On: Modifying a Sales Report via Module Extension
Let’s say you want to modify the sales quotation report to include a product image column and hide the taxes column.
-
Locate the Target Report: In Odoo, go to Technical > Reports. Search for “Quotation / Order” and note its external ID, which is typically
sale.report_saleorder_document. This is the view we will extend. -
Create Your Custom Module:
Inside yourodoo18_dev_environment/addonsdirectory, create a new directory for your custom module, e.g.,custom_sale.cd addons mkdir custom_sale cd custom_sale -
Create
__manifest__.py:
This file defines your module’s metadata and tells Odoo how to load it. Createcustom_sale/__manifest__.py:{ 'name': 'Custom Sales Order Report', 'version': '1.0', 'depends': ['sale'], # This module depends on the 'sale' module 'data': [ 'views/report_saleorder_inherit.xml', # Path to your view modification file ], 'installable': True, 'application': False, 'license': 'LGPL-3', # Good practice to include a license } -
Create
viewsDirectory andreport_saleorder_inherit.xml:
Insidecustom_sale, create aviewsdirectory, and insideviews, createreport_saleorder_inherit.xml.mkdir views touch views/report_saleorder_inherit.xmlOpen
custom_sale/views/report_saleorder_inherit.xmland add the following XML:<odoo> <data> <!-- Inherit the existing sale order report document view --> <record id="custom_sale_report_saleorder_inherit" model="ir.ui.view"> <field name="name">custom_sale_report_saleorder_inherit</field> <field name="model">sale.order</field> <field name="inherit_id" ref="sale.report_saleorder_document"/> <field name="arch" type="xml"> <!-- Add a new table header for 'Image' before 'Description' --> <xpath expr="//th[@name='th_description']" position="before"> <th>Image</th> </xpath> <!-- Add a new table data cell for product image before 'Description' --> <xpath expr="//td[@name='td_name']" position="before"> <td> <img t-if="line.product_id.image_128" # Check if product has an image t-att-src="image_data_uri(line.product_id.image_128)" # Get image data URI style="max-width: 50px; max-height: 50px;"/> # Style image size </td> </xpath> <!-- Replace the 'Taxes' table header with an empty string (effectively removing it) --> <xpath expr="//th[@name='th_taxes']" position="replace"> </xpath> <!-- Replace the 'Taxes' table data cell with an empty string (effectively removing it) --> <xpath expr="//td[@name='td_taxes']" position="replace"> </xpath> </field> </record> </data> </odoo>Explanation of XPath and Positions:
inherit_id="sale.report_saleorder_document": This crucial line tells Odoo that your view extends the standard sales order document report.xpath expr="//th[@name='th_description']" position="before": This XPath expression targets the<th>(table header) element that has thenameattribute set toth_description. Theposition="before"attribute tells Odoo to insert the new<th>Image</th>before the targeted element.position="replace": This attribute is used to completely replace the targeted element with the content provided within the<xpath>tags. By providing an empty tag (<xpath>...</xpath>with no content), you effectively remove the element.
-
Install Your Custom Module:
After creating the module files, Odoo needs to know about them.- Go to Odoo (in your browser) -> Apps.
- Click “Update Apps List” (you might need to enable developer mode first).
- In the Apps search bar, type “Custom Sales Order Report” (or the name you gave in
__manifest__.py). - Click “Activate” (or “Install”) next to your module.
Once installed, regenerate a sales quotation PDF. You should now see the “Image” column for products with images and the “Taxes” column should be hidden. This demonstrates a proper, modular approach to Odoo customization in your Odoo 18 Docker Compose environment.
Conclusion
Setting up your Odoo 18 Docker Compose development environment is a pivotal step towards efficient and enjoyable Odoo development. By leveraging Docker’s containerization and Docker Compose’s orchestration capabilities, you gain unparalleled consistency, isolation, and portability. We’ve walked through the installation, configuration, and launch of your Odoo environment, even covering essential troubleshooting and best practices for module extension.
Embrace this modern approach to Odoo development, and you’ll find yourself spending less time wrestling with environment issues and more time building powerful Odoo applications. Continue exploring Odoo’s vast functionalities and strengthen your development skills to become a proficient Odoo consultant. Happy coding!
Discover more from teguhteja.id
Subscribe to get the latest posts sent to your email.

