Friday, May 1, 2020

Automated deployment of ELK stack and Nginx on AWS ec2 using Terraform and Ansible in 1 hour

Summary:


This post will walk through steps about Automated deployment of ELK stack and Nginx on AWS ec2 instance using Terraform and Ansible in 1 hour.




Environment:

  • AWS ec2 instance

ELK Stack
  •     Elasticsearch master node - 1
  •     Elasticsearch data node - 2
  •     Nginx web server - 1

Jump host with Vagrant Centos 7 running on laptop


Prerequisites:
  • Install Ansible, Terraform, and git on jump host

# ansible --version
ansible 2.9.3
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /bin/ansible
  python version = 2.7.5 (default, Aug  7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]


# terraform version
Terraform v0.12.20



Download the Terraform IaC and Ansible playbook from git repository 

# git clone https://github.com/vdsridevops/aws-elk.git



# tree
.
├── ansible-playbook
│   ├── elk_post_setup.yml
│   ├── elk_setup.yml
│   ├── group_vars
│   │   └── env_variables
│   ├── hosts
│   ├── nginx.yml
│   ├── roles
│   │   ├── elasticsearch
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── elasticsearch-data
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   │   ├── elasticsearchConf.j2
│   │   │   │   ├── filebeatConf.j2
│   │   │   │   ├── filebeat-elasticsearchConf.j2
│   │   │   │   └── metricbeatConf.j2
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── elasticsearch-master
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   │   ├── elasticsearchConf.j2
│   │   │   │   ├── filebeatConf.j2
│   │   │   │   ├── filebeat-elasticsearchConf.j2
│   │   │   │   ├── filebeat-kibanaConf.j2
│   │   │   │   ├── filebeat-logstashConf.j2
│   │   │   │   └── metricbeatConf.j2
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── elk-post
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── elk-pre
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── java
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   ├── main.yml
│   │   │   │   └── main.yml.backup
│   │   │   ├── templates
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── kibana
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   │   └── kibanaConf.j2
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── kibana-proxy
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   │   └── kibanaproxyConf.j2
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── logstash
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   │   └── logstash-nginxConf.j2
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── nginx
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   ├── nginx-filebeat
│   │   │   ├── defaults
│   │   │   │   └── main.yml
│   │   │   ├── files
│   │   │   ├── handlers
│   │   │   │   └── main.yml
│   │   │   ├── meta
│   │   │   │   └── main.yml
│   │   │   ├── README.md
│   │   │   ├── tasks
│   │   │   │   └── main.yml
│   │   │   ├── templates
│   │   │   │   ├── filebeatConf.j2
│   │   │   │   └── nginxConf.j2
│   │   │   ├── tests
│   │   │   │   ├── inventory
│   │   │   │   └── test.yml
│   │   │   └── vars
│   │   │       └── main.yml
│   │   └── nginx-metricbeat
│   │       ├── defaults
│   │       │   └── main.yml
│   │       ├── files
│   │       ├── handlers
│   │       │   └── main.yml
│   │       ├── meta
│   │       │   └── main.yml
│   │       ├── README.md
│   │       ├── tasks
│   │       │   └── main.yml
│   │       ├── templates
│   │       │   └── metricbeatConf.j2
│   │       ├── tests
│   │       │   ├── inventory
│   │       │   └── test.yml
│   │       └── vars
│   │           └── main.yml
│   └── terraform.tfstate
├── ec2_private_ip
├── ec2_public_ip
├── main.tf
├── modules
│   ├── elk-data-compute
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── userdata.tpl
│   │   └── variables.tf
│   ├── elk-master-compute
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── userdata.tpl
│   │   └── variables.tf
│   ├── networking
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   └── nginx-compute
│       ├── main.tf
│       ├── main.tf.backup
│       ├── outputs.tf
│       ├── userdata.tpl
│       └── variables.tf
├── outputs.tf
├── README.md
├── terraform.tfvars
├── variables.tf
└── versions.tf



Terraform Modules used:

elk-master-compute
elk-data-compute
networking  
nginx-compute


Ansible playbook used:

elk_setup.yml
elk_post_setup.yml
nginx.yml


Ansible roles used:

java 
elk-pre  
elasticsearch
elasticsearch-master
elasticsearch-data 
kibana        
logstash  
nginx-filebeat
kibana-proxy  
nginx     
nginx-metricbeat
elk-post  


Automated deployment using Terraform:

# terraform init

# terraform plan

# terraform apply


Verification:

# terraform apply
module.nginx-compute.data.template_file.userdata[0]: Refreshing state...
module.elk-data-compute.data.template_file.userdata[0]: Refreshing state...
module.elk-master-compute.data.template_file.userdata[0]: Refreshing state...
module.elk-data-compute.data.template_file.userdata[1]: Refreshing state...
module.nginx-compute.data.aws_ami.server_ami: Refreshing state...
module.elk-data-compute.data.aws_ami.server_ami: Refreshing state...
module.elk-master-compute.data.aws_ami.server_ami: Refreshing state...
.
.
.
.
.
null_resource.ansible-play (local-exec): TASK [elk-post : Restart metricbeat.service] ***********************************
null_resource.ansible-play: Still creating... [48m10s elapsed]
null_resource.ansible-play: Still creating... [48m20s elapsed]
null_resource.ansible-play (local-exec): changed: [34.237.139.245]

null_resource.ansible-play (local-exec): PLAY RECAP *********************************************************************
null_resource.ansible-play (local-exec): 34.237.139.245             : ok=3    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

null_resource.ansible-play: Creation complete after 48m28s [id=6441365952312601129]

Apply complete! Resources: 15 added, 0 changed, 0 destroyed.

Outputs:

ELK_Data_Private_Instance_IPs = 10.123.1.111, 10.123.1.214
ELK_Data_Public_Instance_IDs = i-0ebd111d7e15307ba, i-00362d9b29fc9014a
ELK_Data_Public_Instance_IPs = 3.231.153.252, 34.205.45.150
ELK_Master_Private_Instance_IPs = 10.123.1.188
ELK_Master_Public_Instance_IDs = i-09fbf1695c39c7b18
ELK_Master_Public_Instance_IPs = 34.237.139.245
Nginx_Private_Instance_IPs = 10.123.1.168
Nginx_Public_Instance_IDs = i-03d72aff55185e704
Nginx_Public_Instance_IPs = 34.205.26.55
Public_Security_Group = sg-087dda768288d485d
Public_Subnets = subnet-07c90e18bce73ebec
Subnet_IPs = 10.123.1.0/24



Kibana UI: