Deploying HashiCorp Consul Using Ansible

  ·   4 min read

HashiCorp Consul is a powerful tool for service discovery, configuration, and segmentation. Deploying Consul in a consistent and automated manner can significantly enhance your infrastructure’s reliability and scalability. In this article, we’ll walk through deploying Consul using Ansible, a popular open-source automation tool. We’ll create an Ansible role to streamline the deployment process, ensuring that Consul is installed and configured correctly across your infrastructure.

Prerequisites

Before we begin, ensure you have the following:

  1. Ansible: Ensure Ansible is installed on your control machine. You can install it using pip:

    pip install ansible
    
  2. SSH Access: Ensure you have SSH access to the target machines where Consul will be deployed.

  3. Inventory File: Create an Ansible inventory file listing the target machines.

  4. Consul Binary: Download the latest Consul binary from the official HashiCorp releases page.

Creating the Ansible Role

Ansible roles allow you to organize your playbooks and automate complex tasks. We’ll create a role named consul to handle the installation and configuration.

Step 1: Create the Role Directory Structure

Use the following command to create the role structure:

ansible-galaxy init consul

This command creates a directory structure like this:

consul/
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

Step 2: Define Variables

Edit defaults/main.yml to define default variables for the Consul installation:

consul_version: "1.14.0"
consul_user: "consul"
consul_group: "consul"
consul_data_dir: "/opt/consul"
consul_config_dir: "/etc/consul.d"

Step 3: Download and Install Consul

Edit tasks/main.yml to include tasks for downloading and installing Consul:

---
- name: Create Consul user and group
  ansible.builtin.user:
    name: "{{ consul_user }}"
    group: "{{ consul_group }}"
    create_home: no
    shell: /usr/sbin/nologin

- name: Create Consul directories
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    owner: "{{ consul_user }}"
    group: "{{ consul_group }}"
    mode: '0755'
  loop:
    - "{{ consul_data_dir }}"
    - "{{ consul_config_dir }}"

- name: Download Consul
  ansible.builtin.get_url:
    url: "https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version }}_linux_amd64.zip"
    dest: "/tmp/consul.zip"
    mode: '0644'

- name: Unzip Consul binary
  ansible.builtin.unarchive:
    src: "/tmp/consul.zip"
    dest: "/usr/local/bin/"
    remote_src: yes

- name: Set Consul binary permissions
  ansible.builtin.file:
    path: "/usr/local/bin/consul"
    owner: root
    group: root
    mode: '0755'

Step 4: Configure Consul

Create a template file templates/consul.hcl.j2 for the Consul configuration:

datacenter = "dc1"
data_dir = "{{ consul_data_dir }}"
log_level = "INFO"
node_name = "{{ inventory_hostname }}"
server = true
bootstrap_expect = 1

Add a task in tasks/main.yml to deploy this configuration:

- name: Deploy Consul configuration
  ansible.builtin.template:
    src: "consul.hcl.j2"
    dest: "{{ consul_config_dir }}/consul.hcl"
    owner: "{{ consul_user }}"
    group: "{{ consul_group }}"
    mode: '0644'

Step 5: Manage Consul Service

Add handlers in handlers/main.yml to manage the Consul service:

---
- name: restart consul
  ansible.builtin.systemd:
    name: consul
    state: restarted
    enabled: yes

Add a task in tasks/main.yml to create a systemd service file and start Consul:

- name: Create systemd service file for Consul
  ansible.builtin.template:
    src: "consul.service.j2"
    dest: "/etc/systemd/system/consul.service"
    mode: '0644'
  notify: restart consul

- name: Start Consul service
  ansible.builtin.systemd:
    name: consul
    state: started
    enabled: yes

Create a template templates/consul.service.j2 for the systemd service:

[Unit]
Description=Consul Agent
Requires=network-online.target
After=network-online.target

[Service]
User={{ consul_user }}
Group={{ consul_group }}
ExecStart=/usr/local/bin/consul agent -config-dir={{ consul_config_dir }}
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Running the Playbook

Create a playbook deploy-consul.yml to apply the role:

---
- hosts: all
  become: yes
  roles:
    - consul

Run the playbook using the following command:

ansible-playbook -i inventory deploy-consul.yml

Conclusion

By creating an Ansible role for deploying HashiCorp Consul, you can automate the installation and configuration process, ensuring consistency across your infrastructure. This approach not only saves time but also reduces the risk of human error. As your infrastructure grows, you can easily scale your Consul deployment by simply updating your inventory and running the playbook.

For further reading and resources, consider the following:

By leveraging open-source tools like Ansible and Consul, you can build a robust and scalable infrastructure that meets your organization’s needs.