Using Ansible to Install Node.js
In the first part of the DevOps series, I showed how to automatically create an AWS EC2 Spot instance with Terraform. You can read it again here: https://www.tderflinger.com/en/ec2-spot-with-terraform
DevOps skills are becoming more important for Node.js developers. With Ansible, you can configure your cloud servers automatically. Now, I explain to you how to automatically configure the created CentOS server with Node.js and Nginx. For that I use the open source tool Ansible. Ansible is a software configuration and deployment tool. It has been originally written by Michael DeHaan in 2012. The company behind Ansible was acquired in 2015 by Red Hat, now an IBM division.
Ansible allows you to automate the installation of software. Thus, it is an important piece in the Infrastructure as Code (IaC). With Ansible, you can ensure that the right packages are installed, the right configuration files in the correct place and the right services are running. You can also deploy your written software to the server with Ansible. Furthermore, Ansible allows for provisioning a new server, but I used Terraform for this task, as you can read in the previous article.
Ansible is a good tool for IaaS (Infrastructure as a Service) type of cloud computing environments. This includes AWS EC2 servers or Digital Ocean droplets. On this type of compute servers you need to configure the needed software yourself. This is in contrast to PaaS offerings, where everything is managed, you only upload the source code of your application. Heroku is an example of a PaaS offering.
When using Ansible, you will do most of your work in configuration files called playbooks. These are yml files that are DSL (Domain Specific Languages) and describe the functions to configure.
The great thing about Ansible is that you do not need to install anything on the target server. Everything works using port 22, via SSH. Only Python 2 or 3 needs to be available on the target machine. This distinguishes Ansible from tools like Chef or Puppet, where you need to install an agent.
Mock Server
For this example, I want to automatically install a Node.js mock server for testing purposes. For that, I use the NPM module json-server and add a bit of mockup code. Basically, the mock server is a REST server with mock data.
json-server-http.js
var fs = require('fs'),
jsonServer = require('json-server'),
server = jsonServer.create(),
router = jsonServer.router('db.json'),
middlewares = jsonServer.defaults()
const cors = require('cors')
const bodyParser = require('body-parser')
server.use(cors())
server.use(bodyParser.json())
server.use(middlewares)
server.use(router)
server.listen(3002, function() {
console.log('json-server started on port ' + 3002)
})
It loads some data from a JSON file and returns the data via the REST endpoint.
One requirement for this mock server is that it is available via HTTPS. Thus, I use the Nginx server as a proxy with a TLS connection. The necessary certificate and key files can be generated offline with this Ansible Playbook.
Generate TLS Certificate
First, you need to install Ansible on your computer.
The following Ansible playbook generates on your local computer the self-signed certificate and private key files. These files are later uploaded to the Nginx directories.
generate_certificate.yml
--
- name: Generate Nginx TLS certificates and keys
hosts: localhost
tasks:
- name: Generate OpenSSL private key
openssl_privatekey: path=files/nginx.key
- name: Generate OpenSSL Certificate Signing Request
openssl_csr: path=files/csr.csr privatekey_path=files/nginx.key common_name=www.someorg.org
- name: Generate Self-signed certificate
openssl_certificate: path=files/nginx.crt privatekey_path=files/nginx.key csr_path=files/csr.csr provider=selfsigned
You can run this playbook with the following command:
ansible-playbook generate_certificate.yml
Install Node.js and Nginx
The actual work of configuration happens with the installation of the required software. First, Node.js is needed in version 10.16. A good way to install Node.js on a Linux server is using the Node Version Manager (NVM). On GitHub, there is a ready-made Ansible playbook for installing NVM. We leverage that here and just invoke it in our script.
Then Nginx needs to be installed. The playbook looks something like this:
install_nodenginx.yml
---
- name: Install curl and wget
gather_facts: 'no'
hosts: mock
become: yes
remote_user: root
tasks:
- name: Install curl
yum:
name: curl
state: present
- name: Install wget
yum:
name: wget
state: present
- name: Create nvm
gather_facts: 'no'
hosts: mock
become: yes
remote_user: root
roles:
- role: ansible-role-nvm
nodejs_version: '10.16.0'
## Credits to John Lieske - https://www.ansible.com/blog/getting-started-writing-your-first-playbook
- name: Install Nginx
hosts: mock
become: yes
remote_user: root
tasks:
- name: Add epel-release repo
yum:
name: epel-release
state: present
- name: Install Nginx
yum:
name: nginx
state: present
- name: Start NGiNX
service:
name: nginx
state: started
Before running this playbook, you also need to specify your hosts file.
It can look like this, but you need to update the IP address with the server IP on which you like to install.
hosts
[default]
mock ansible_host=100.24.146.164
Then run the playbook script with:
ansible-playbook install_node_nginx.yml -i hosts
Ansible playbooks are idempotent. That means no matter how often you run, the result is always the same. You specify the outcome, like a file should be absent. Ansible then figures out how to achieve that.
Install the Mock Application
The next steps are copying the mock JavaScript files and the Nginx certification files over. For running the NodeJS mock application, we use the process manager PM2.
run_mock.yml
---
- name: Start mock and some other stuff
hosts: mock
become: true
remote_user: root
vars:
key_file: /etc/nginx/ssl/nginx.key
cert_file: /etc/nginx/ssl/nginx.crt
conf_file: /etc/nginx/nginx.conf
tasks:
- name: Copy files
copy: src=../../db.json dest=/home/centos
- name: Copy package.json
copy: src=../../package.json dest=/home/centos
- name: Copy json-server-https
copy: src=../../json-server-http.js dest=/home/centos
- name: NPM installation
shell: npm i
args:
chdir: /home/centos
- name: Install PM2
npm:
name: pm2
global: yes
- name: Create directories for certificates
file: path=/etc/nginx/ssl state=directory
- name: Copy TLS key
copy: src=files/nginx.key dest={{ key_file }} owner=root mode=0600
- name: Copy TLS certificate
copy: src=files/nginx.crt dest={{ cert_file }} owner=root mode=0600
- name: Copy Nginx config file
template: src=templates/nginx.conf.j2 dest={{ conf_file }}
- name: Remove nginx.default
file:
path: /etc/nginx/nginx.conf.default
state: absent
- name: Restart Nginx
service:
name: nginx
state: restarted
- name: Start Mock
shell: pm2 start json-server-http.js
args:
chdir: /home/centos
In this playbook, you can see the definition of variables. They are applied
with the interpolation of two curly braces {{ var }}
. Also, a
template is used for the generation of the Nginx configuration file.
Templates in Ansible are Jinja2 compatible, a Python
templating engine.
When everything is started, and you can go in your browser to your server IP using https. The browser will display a dangerous looking warning because the certificate is self-signed. You need to accept the certificate, and then you will see the Mock application.
One thing to note is that these Ansible scripts only work on CentOS Linux machines. Ansible does not abstract between Linux distros. Thus, if you would like to configure and deploy on Ubuntu, you would need to adapt the scripts.
Conclusion
If you have some experience with Linux system administration, understanding an Ansible playbook should not be too difficult. With Infrastructure as Code, it has become mandatory to automate these system administration tasks. Also, when you need to configure many servers, tools like Ansible are an obvious necessity. Thus, Ansible skills are valuable for Node.js developers in the context of DevOps.
Sources and Further Reading
-
Infrastructure as Code: Managing Servers in the Cloud, 2016, Kief Morris, O'Reilly Media
-
Ansible: Up and Running, 2nd edition, 2017, Rene Moser and Lorin Hochstein, O'Reilly Media
- Source code of this article: https://github.com/tderflinger/ansible-node-mock
Published
16 Jul 2019