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
- Elasticsearch master node - 1
- Elasticsearch data node - 2
- Nginx web server - 1
Prerequisites:
# 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
- 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: