Deploy Odoo with Ansible

Posted on March 10, 2015 in blog

Intro

Installing Odoo manually is very time consuming, it implies a lot of steps. Here's a subset of them:

  • install and configure a PostgreSQL server ;
  • create a PostgreSQL user with just the required permissions ;
  • creating a system user to run the Odoo application ;
  • install all the dependencies, either from the distribution repositories, or from PyPI ;
  • configure log access ;
  • configure Odoo itself (admin password, addons paths, workers...) ;
  • start the application at boot (init script/systemd unit...) ;

Once it is done, a doubt could remain... are you sure you did not forget a step? A package to install? So you will check again, spending some more time on it.

Now it is configured, you are ready to repeat this work again to have at least a production, a staging and one or several development environments if you work in a team. And maybe you will do some mistakes here and there because you are tired (for instance you will realize later that the configured locales in the production/stating/development environments are not identical, generating errors in your reports depending on the environment).

This isn't actually productive work, nor an interesting task. All this work should be done automatically to reduce human errors and make the life easier, either by writing home-made scripts or by using modern tools to deploy your applications in an efficient, reproductible and scalable manner.

The second option is by far the best, as we'll see in this article by using Ansible, a great tool to automate your tasks. As they say: "DEPLOYING APPS SHOULDN'T BE SO HARD".

+

Ansible?

Quoted from their GitHub repository:

Ansible is a radically simple IT automation platform that makes your applications and systems easier to deploy. Avoid writing scripts or custom code to deploy and update your applications— automate in a language that approaches plain English, using SSH, with no agents to install on remote systems.

Fine! As it is a Python software, we can install it with pip. On an Ubuntu workstation, just type:

$ sudo pip install ansible

Vocabulary to know about Ansible:

  • Hosts are listed in an inventory file
  • a playbook defines a list of roles and tasks applied to one or several hosts
  • a role is a composition of tasks (for a well-defined objective)
  • Each task uses an Ansible module, but we don't care about that in this article.

Here we will deploy Odoo on a Debian system (works well on Ubuntu too), and we will use two roles for this purpose:

  • postgresql: to install and configure the PostgreSQL server
  • odoo: to install and configure Odoo

So let's install them on your workstation:

$ sudo ansible-galaxy install ANXS.postgresql
$ sudo ansible-galaxy install sebalix.odoo

Configuration - Inventory

I assume you already have a host with SSH root access on which you want to install Odoo. The following packages must be installed on it:

  • python (required by Ansible)
  • python-apt (required by the Ansible APT module)

On your workstation, create a folder which will contain your Ansible configuration:

$ mkdir ~/ansible-test
$ cd ~/ansible-test

Add the host in an inventory file:

$ cat >> inventory <<EOF
my_odoo     ansible_ssh_host=HOST_IP
EOF

The INI format is used for the inventory file. You can group your hosts by defining sections if you wish:

[test]
my_odoo     ansible_ssh_host=HOST_IP

If your host listens on another SSH port, just set the ansible_ssh_port option:

[test]
my_odoo     ansible_ssh_host=HOST_IP ansible_ssh_port=2242

See http://docs.ansible.com/intro_inventory.html for details regarding the inventory.

Configuration - Playbook

Now, we will create a playbook file to define the roles to apply on the host. In this example, PostgreSQL and Odoo will be installed on the same host, but you can have them on different machines without any problems (the above roles support this configuration as well).

Create a YAML file and apply the PostgreSQL role to the host:

$ vim playbook.yml
- name: My Odoo
  hosts: my_odoo
  roles:
    - ANXS.postgresql
  vars:
    - postgresql_version: 9.3

That's all. Currently, the ANXS.postgresql role only supports the version 9.3, but we will be able to install any version soon (see this pull request) as the role uses the PostgreSQL APT repository by default (it is safe and production ready, the packages are identical to the ones available in Debian and Ubuntu official repositories).

The role supports a very large set of parameters to tune PostgreSQL as you wish:

- name: My Odoo
  hosts: my_odoo
  roles:
    - ANXS.postgresql
  vars:
    - postgresql_version: 9.3

We could already deploy that, but the main advantage of Ansible is to create complete recipes to deploy the configuration all at once. So, add the Odoo part to this playbook:

- name: My Odoo
  hosts: my_odoo
  roles:
    - ANXS.postgresql
    - sebalix.odoo
  vars:
    # [postgresql]
    - postgresql_version: 9.3
    # [odoo]
    - odoo_version: 8.0
    - odoo_config_unaccent: True

The Odoo role supports a lot of parameters too - all parameters available in the configuration file actually, see https://github.com/osiell/ansible-odoo#variables - such as unaccent. This option will not just set the unaccent parameter to True, it will also initialize the unaccent extension in PostgreSQL. This is the kind of task which is easily performed by a tool like Ansible, helping you to save time and improve the reliability of your installations.

For a simple installation this is all we need, it is up to you to adapt the above configuration. By default Odoo is downloaded from their GitHub repository (the branch 8.0 here), but you can change that to checkout a specific commit, or even clone your own Mercurial/Git repository (have a look on the odoo_repo_* options).

Deploy

Now we are ready to deploy! Invoke the ansible-playbook command with your inventory and playbook files:

$ ansible-playbook -i inventory playbook.yml -e "ansible_ssh_user=root" -k

Let's explain a bit the command above:

The -e "ansible_ssh_user=root" tells Ansible what user account to use for the SSH connection combined with -k to ask you the password, especially useful for the first deployment. You could add it to your inventory file as well.

I encourage you to configure a sudoer user account on the system instead of using root for next deployments/updates, and disable this one from SSH. And why not create a role to do this? This is quite common to make a *cough* common role where you will define the minimal configuration to apply on the hosts you manage (install useful packages, configure a sudoer user, set SSH keys of your team, etc).

After that, you could tell Ansible to use your sudoer user by default, for all your hosts (global scope):

$ mkdir group_vars
$ echo 'ansible_ssh_user: USER' >> group_vars/all

And/or just set it at the host level in the inventory file:

$ cat >> inventory <<EOF
my_odoo     ansible_ssh_host=HOST_IP ansible_ssh_user=USER
EOF

Then the command will become:

$ ansible-playbook -i inventory playbook.yml

The main goal is to be able to run on a regular basis your Ansible configuration - without human intervention - ensuring that your hosts are in a well-defined state. You could also perform a dry-run and report a diff about files changed. For instance, update your playbook to configure Odoo workers:

- name: My Odoo
  hosts: my_odoo
  roles:
    - ANXS.postgresql
    - sebalix.odoo
  vars:
    # [postgresql]
    - postgresql_version: 9.3
    # [odoo]
    - odoo_version: 8.0
    - odoo_config_unaccent: True
    - odoo_config_workers: 9

Check this new configuration:

$ ansible-playbook -i inventory playbook.yml -e "ansible_ssh_user=root" -k --diff --check

You should see the following result:

--- before: /home/odoo/odoo.conf
+++ after: /etc/ansible/roles/sebalix.odoo/templates/odoo-server-v80.conf
@@ -46,18 +46,18 @@
 smtp_user = False
 syslog = False
 test_commit = False
 test_enable = False
 test_file = False
 test_report_directory = False
 timezone = False
 translate_modules = ['all']
 unaccent = True
 without_demo = False
-workers = 0
+workers = 9
 xmlrpc = True
 xmlrpc_interface = 
 xmlrpc_port = 8069
 xmlrpcs = True
 xmlrpcs_interface = 
 xmlrpcs_port = 8071

Apply the new configuration:

$ ansible-playbook -i inventory playbook.yml -e "ansible_ssh_user=root" -k

Voilà! Your Odoo instance is running on http://HOST_IP:8069. Pretty cool, isn't it?

Conclusion

It has become very easy nowadays to deploy a complex application such as Odoo with this kind of tool. We just saw the PostgreSQL and Odoo parts, however we can go further and configure backups, PostgreSQL replication (failover), reverse proxy, monitoring and other specific installation required by your Odoo integration (e.g. configure CUPS to print labels or installing extra packages required by your custom developments).

At some point your Ansible configuration will not longer be just a tool, but an up-to-date documentation for your installations, if you run it regularly.

Feedback and contributions are welcome!

Links