Automated MongoDB Standalone Setup Using Ansible Role

Automated MongoDB Standalone Setup Using Ansible Role

Table of contents

Nowadays almost every business is adopting digital technologies. Technologies are delivering our applications faster with efficiency which helps us to win. Historically, doing the same things required lots of manual effort and was time-consuming. But today, we have Ansible the powerful automation tool to drive complexity out of their environment and accelerate their work.

Ansible is an open-source tool used for multiple purposes like configuration management, application deployments, and infrastructure as code. It supports the YAML language. YAML language works on key-value pair format.

MongoDB: MongoDB is the document database, it stores data in JSON-like documents. It also stores the data in key-value pair format. Example: (name: abc) Here "name" is the key and "abc" is its value.

Ansible roles: Ansible roles are defined in a predefined directory structure in which we define a set of tasks to configure a host to serve a certain purpose. A role directory structure contains:- defaults, vars, handlers, templates, tasks, and meta.

Defaults and Vars: Defaults and vars both files contain variables used in the role but the key difference in both the files is precedence. E.g., if we take a variable "package_name" in both files and defaults we provide the value "httpd" and in vars, we provide "Nginx" then it will take the value Nginx because the precedence of the vars file is more than "defaults".

Handlers: Handlers are responsible for running only when a change is made on a machine. E.g. you may want to restart the service when the task made changes in the configuration file.

Templates: Templates are the files containing all configuration parameters and provide the privilege of providing dynamic values in the form of variables.

Tasks: Tasks are the main execution file in which we write what exactly we want to execute to achieve the goal. E.g. to install a web server and configure it according to the requirement.

Dependency: You must have Python in your system to run Ansible.

Let’s start Automating

  1. First, we need to initialize an Ansible role, you can use the name of the role of your choice. I chose MongoDB.
ansible-galaxy init mongodb
  1. After init, you will find the directory structure we discussed above. As we have discussed above that we have two variable files one defaults and the other is vars. So we will add these variables in the defaults directory. These are the variables that we will use in our role accordingly.
cd defaults/
vim main.yml

--- 
# defaults file for mongodb variables.
# Service file variables
mongo_service_user: mongod
mongo_service_group: mongod
# Config variables
mongo_log_path: /data/log/mongodb/mongod.log
mongo_dbpath: /data/db
mongo_pid_path_file: /var/run/mongodb/mongod.pid
timezone_info: /usr/share/zoneinfo
mongo_port: 27017
mongo_bind_address: 0.0.0.0
  1. After adding variables in the default file we will add other required variables in the vars file.
cd ../vars/
vim main.yml

# vars file for mongodb 

# Installation vars 
mongo_package: "mongodb-org-4.4.4-1.amzn2.x86_64" 
mongo_repo_version: 4.4
  1. Before proceeding to the task file for Installing the package we need to add some files in our templates directory. These are "Jinja (j2)" templates which accept variables dynamically. As we can see in the below code e.g., on the path we have given the variable mongo_log_path when it is copied to the destination it will put the values in the place of variables. We need to create 3 files:

    1. "mongo_repo.j2": Repository file to install the mongoDB package.

    2. "mongo_servicefile.j2": This is the service file of the mongoDB package.

    3. "mongo_init_config.j2": Config file of the mongoDB package.

cd templates/
vim mongo_repo.j2
[mongodb-org-{{ mongo_repo }}]     
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/{{ mongo_repo }}/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-{{ mongo_repo }}.asc
  1. The configuration file of MongoDB service (mongod.service)
vim mongo_init_config.j2
---
# mongod.conf 
systemLog: 
  destination: file 
  logAppend: true 
  path: {{ code }} 
# Where and how to store data. 
storage: 
  dbPath: {{ db_path }} 
  journal:
    enabled: true
  engine: wiredTiger
#  mmapv1:
#  wiredTiger:
# how the process runs
processManagement:
  fork: true 
  pidFilePath: {{ pid_path }}  
  timeZoneInfo: {{ time_zone }}
# network interfaces
net:
  port: {{ port }}
  bindIp: {{ bind_address }} 
#operationProfiling:
replication:
  replSetName: "rs0"
#sharding: 
## Enterprise-Only Options
#auditLog:
#snmp:
vim mongo_servicefile.j2

[Unit]
Description=MongoDB Database Server      
Documentation=https://docs.mongodb.org/manual
After=network.target
[Service]
User={{ mongo_user }}
Group={{ mongo_group }}
EnvironmentFile=/etc/default/mongod
ExecStart=/usr/bin/mongod --config /etc/mongod.conf
PIDFile=/var/run/mongodb/mongod.pid
# file size
LimitFSIZE=infinity
# cpu time
LimitCPU=infinity
# virtual memory size
LimitAS=infinity
# open files
LimitNOFILE=64000
# processes/threads
LimitNPROC=64000
# locked memory
LimitMEMLOCK=infinity
# total threads (user+kernel)
TasksMax=infinity
TasksAccounting=false
# Recommended limits for for mongod as specified in
# http://docs.mongodb.org/manual/reference/ulimit/#recommended-settings
[Install]
WantedBy=multi-user.target

Now we need to create a file install_mongo.yml file. In this file, we will write the code to get the prerequisites and install MongoDB.

cd ../tasks 
vim install_mongo.yml
---                               
- name: Updating cache
  yum:
    update_cache: yes

- name: Installing latest patches
  command: yum update -y
  args:
     warn: false

- name: Enable EPEL Repository
  yum:
    name: epel-release
    state: latest

- name: Installing PIP
  yum:
    name: python-pip
    state: present

- name: Installing MongoDB prerequisites      
  pip:
    name: pymongo
    state: present
  with_items:
    - pymongo
    - pyOpenSSL

- name: Adding MongoDB repository
  template:
    src: mongo_repo.j2
    dest: /etc/yum.repos.d/mongodb-org-4.4.repo
    mode: 0644

- name: Installing MongoDB package
  yum:
    name: "{{ mongo_package  }}"
    state: present

- name: Daemon Reload
  shell: systemctl daemon-reload

- name: Starting MongoDB service
  service:
    name: mongod
    state: started

Explanation of Install_mongo.yml file:

  • Installing the latest patches on the server.

  • Installing PIP to install Mongodb dependencies like pymongo.

  • Pymongo is required to run the queries on the Mongo shell.

  • Copying the Mongo repository in the repos directory to install the Mongo package.

  • Installing Mongo package with the version specified in the vars section.

  • Reloading daemon to get Mongodb service.

  • Starting MongoDB service

After installing the package we need to configure our mongo configuration according to our environment.

vim configure.yml

---                                               
- name: Adding MongoDB service file
  template:
    src: mongo_servicefile.j2
    dest: /usr/lib/systemd/system/mongod.service
    owner: root
    group: root
    mode: 0777
    force: yes
  notify:
    - daemon_reload

- name: Creating Log directory
  file:
    state: directory
    path: "{{ item }}"
    owner: mongod
    group: mongod
    mode: 0755
  loop:
    - /data
    - /data/log
    - /data/log/mongodb
    - /data/db
    - /var/run/mongodb/

- name: Adding MongoDB initialization config file
  template:
    src: mongo_init_config.j2
    dest: /etc/mongod.conf
    mode: 0644
    force: yes

- name: Restart mongod service
  service:
     name: mongod
     state: restarted

Explanation of configure.yml file:

  • Adding of Mongodb service file with the owner as root and permission.

  • Creation of directories as we mentioned in our config files.

  • Adding Mongodb initial config file.

Now we will edit main.yml. Ansible calls only main.yml in tasks. In main.yml we will include two files we created above.

vim main.yml

---                               
# tasks file for mongodb
- name: Installing MongoDB
  include_tasks: install_mongo.yml

- name: Configuring MongoDB
  include_tasks: configure.yml

At the end, we will add handlers to our role.

cd handlers
vim main.yml

---                         
# handlers file for mongodb
- name: daemon_reload
  systemd:
    daemon_reload: "yes"

- name: mongodb_restart
  service:
    name: mongod
    state: restarted

Finally, we have created all the required files to deploy MongoDB successfully. But we need to create one more file to run this setup. Go one directory back and create a mongo.yml. This is the file in which we will call the role and tell Ansible that where to deploy that code.

cd ../..
vim mongo.yml

---
- hosts: localhost
  roles:
    - mongodb 
  become: true
  any_errors_fatal: true

Explanation of mongo.yml

  • Hosts: In hosts, we will define the IPs where we want to deploy. If we want to deploy on the same server we will write localhost.

  • Role: In roles, we will define the path of the role.

  • Become: Become means run this role with sudo permission.

To run the ansible role we need to run the command.

ansible-playbook mongo.yml

Kudos, we have successfully completed our automated setup of the standalone MongoDB server. Now in the next blog (in continuation), I will show how to implement authentication and replication using ansible role.