Автоматизація інфраструктури AWS та розгортання за допомогою Terraform і Ansible

текст перекладу
У цій статті я розкажу вам, як я автоматизував розгортання надійної інфраструктури AWS за допомогою Terraform та налаштував розгортання додатків за допомогою Ansible. Цей проєкт підкреслює синергію між інфраструктурою як кодом (IaC) та інструментами для керування конфігураціями, щоб досягти масштабованих, повторюваних та ефективних робочих процесів.

Огляд проєкту

Проєкт включав наступне:

  1. Автоматизація інфраструктури AWS за допомогою Terraform для створення:
  • Віртуальної приватної мережі (VPC) з публічними підмережами в кількох зонах доступності.
  • Балансувальника навантаження (ALB) для розподілу навантаження.
  • EC2 екземплярів, налаштованих для хостингу статичного вебсайту.
  • Серверу Ansible для керування конфігурацією.
  1. Розгортання та налаштування додатків за допомогою Ansible для:
  • Встановлення та налаштування Apache на веб-серверах.
  • Розгортання файлів статичного сайту на веб-серверах.

Ось діаграма архітектури інфраструктури на високому рівні:

pic

Архітектура проєкту

Крок 1: Налаштування інфраструктури AWS за допомогою Terraform

Terraform було використано для визначення та створення всієї інфраструктури AWS. Ось огляд ресурсів Terraform:

Визначені ресурси Terraform:

  1. Провайдер, VPC та підмережі
provider "aws" {  
 region = "us-east-1"  
}  

# Створення VPC   
resource "aws_vpc" "project_vpc" {  
 cidr_block = "10.0.0.0/16"  
 instance_tenancy = "default"  
 enable_dns_support = true  
 enable_dns_hostnames = true  

 tags = {  
 Name = "project_vpc"  
 }  
}  

# Створення інтернет-шлюзу  
resource "aws_internet_gateway" "project_igw" {  
 vpc_id = aws_vpc.project_vpc.id  

 tags = {  
 Name = "project_igw"  
 }  
}  

# Створення публічної підмережі 1  
resource "aws_subnet" "public_subnet_1" {  
 vpc_id = aws_vpc.project_vpc.id  
 cidr_block = "10.0.1.0/24"  
 availability_zone = "us-east-1a"  
 map_public_ip_on_launch = true  

 tags = {  
 Name = "public_subnet_1"  
 }  
}  

# Створення публічної підмережі 2  
resource "aws_subnet" "public_subnet_2" {  
 vpc_id = aws_vpc.project_vpc.id  
 cidr_block = "10.0.2.0/24"  
 availability_zone = "us-east-1b"  
 map_public_ip_on_launch = true  

 tags = {  
 Name = "public_subnet_2"  
 }  
}

2.
текст перекладу
Групи безпеки

  • Дозволити доступ по SSH та HTTP до екземплярів і ALB.
# група безпеки та правило  
resource "aws_security_group" "instance_security_group" {  
 name = "instance_security_group"  
 description = "Allow security rules for ec2 instance"  
 vpc_id = aws_vpc.project_vpc.id  

 tags = {  
 Name = "Allow inbound and outbound rules"  
 }  
}  

# Правила безпеки для екземпляра  
resource "aws_vpc_security_group_ingress_rule" "allow_ssh_from_my_ip" {  
 security_group_id = aws_security_group.instance_security_group.id  
 cidr_ipv4 = "175.157.23.47/32"  
 from_port = 22  
 ip_protocol = "tcp"  
 to_port = 22  

 tags = {  
 Name = "Allow SSH from my ip"  
 }  
}  

# Дозволити SSH з групи безпеки Ansible  
resource "aws_security_group_rule" "allow_ssh_from_ansible_sg" {  
 type = "ingress"  
 from_port = 22  
 to_port = 22  
 protocol = "tcp"  
 security_group_id = aws_security_group.instance_security_group.id  
 source_security_group_id = aws_security_group.ansible_sg.id  

 description = "Allow SSH from Ansible security group"  
}  

resource "aws_vpc_security_group_ingress_rule" "allow_http" {  
 security_group_id = aws_security_group.instance_security_group.id  
 cidr_ipv4 = "0.0.0.0/0"  
 from_port = 80  
 ip_protocol = "tcp"  
 to_port = 80  

 tags = {  
 Name = "Allow HTTP"  
 }  
}  

resource "aws_vpc_security_group_ingress_rule" "allow_icmp" {  
 security_group_id = aws_security_group.instance_security_group.id  
 cidr_ipv4 = "0.0.0.0/0"  
 from_port = -1  
 to_port = -1  
 ip_protocol = "icmp"  

 tags = {  
 Name = "Allow ICMP"  
 }  
}  

resource "aws_vpc_security_group_egress_rule" "allow_all_outbound_traffic" {  
 security_group_id = aws_security_group.instance_security_group.id  
 cidr_ipv4 = "0.0.0.0/0"  
 ip_protocol = "-1"  

 tags = {  
 Name = "Allow all outbound traffic"  
 }  
}  


# група безпеки для балансувальника навантаження  
resource "aws_security_group" "alb_sg" {  
 name = "alb_sg"  
 description = "Allow security rules for application load balancer"  
 vpc_id = aws_vpc.project_vpc.id  

 ingress {  
 from_port = 80  
 to_port = 80  
 protocol = "tcp"  
 cidr_blocks = ["0.0.0.0/0"]  
 }  

 ingress {  
 from_port = 443  
 to_port = 443  
 protocol = "tcp"  
 cidr_blocks = ["0.0.0.0/0"]  
 }  

 egress {  
 from_port = 0  
 to_port = 0  
 protocol = "-1"  
 cidr_blocks = ["0.0.0.0/0"]  
 }  
}  

# група безпеки для Ansible  
resource "aws_security_group" "ansible_sg" {  
 name = "ansible_sg"  
 description = "Allow security rules for ansible"  
 vpc_id = aws_vpc.project_vpc.id  
}  

resource "aws_vpc_security_group_ingress_rule" "allow_ssh_my_ip" {  
 security_group_id = aws_security_group.ansible_sg.id  
 cidr_ipv4 = "175.157.23.47/32"  
 from_port = 22  
 ip_protocol = "tcp"  
 to_port = 22  

 tags = {  
 Name = "Allow SSH from my ip"  
 }  
}  

resource "aws_vpc_security_group_ingress_rule" "allow_http_ansible" {  
 security_group_id = aws_security_group.ansible_sg.id  
 cidr_ipv4 = "0.0.0.0/0"  
 from_port = 80  
 ip_protocol = "tcp"  
 to_port = 80  

 tags = {  
 Name = "Allow http ansible"  
 }  
}  

resource "aws_vpc_security_group_egress_rule" "allow_ansible_outbound" {  
 security_group_id = aws_security_group.ansible_sg.id  
 cidr_ipv4 = "0.0.0.0/0"  
 ip_protocol = "-1"  

 tags = {  
 Name = "Allow SSH from my ip"  
 }  
}

3.
текст перекладу
**Балансувальник навантаження додатків

# створення групи цілей для ALB  
resource "aws_lb_target_group" "target_group_alb" {  
 name = "load-balancer-target"  
 port = 80  
 protocol = "HTTP"  
 vpc_id = aws_vpc.project_vpc.id  

}  

# приєднання екземплярів до групи цілей  
resource "aws_lb_target_group_attachment" "attachment_1" {  
 target_group_arn = aws_lb_target_group.target_group_alb.arn  
 target_id = aws_instance.web01.id  
 port = 80  
}  

resource "aws_lb_target_group_attachment" "attachment_2" {  
 target_group_arn = aws_lb_target_group.target_group_alb.arn  
 target_id = aws_instance.web02.id  
 port = 80  
}  

# створення балансувальника навантаження додатка  
resource "aws_lb" "alb" {  
 name = "alb"  
 internal = false  
 load_balancer_type = "application"  
 security_groups = [aws_security_group.alb_sg.id]  
 subnets = [aws_subnet.public_subnet_1.id, aws_subnet.public_subnet_2.id]  

 tags = {  
 Environment = "production"  
 }  
}  

# створення слухача для ALB  
resource "aws_lb_listener" "alb_listener" {  
 load_balancer_arn = aws_lb.alb.arn  
 port = "80"  
 protocol = "HTTP"  

 default_action {  
 type = "forward"  
 target_group_arn = aws_lb_target_group.target_group_alb.arn  
 }  
}  

output "alb_dns_name" {  
 value = aws_lb.alb.dns_name  
}

4.
текст перекладу
EC2 Екземпляри

# сервер Ansible  
resource "aws_instance" "ansible_server" {  
 ami = "ami-0e2c8caa4b6378d8c"  
 instance_type = "t2.micro"  
 key_name = aws_key_pair.ec2_key_pair.key_name  
 subnet_id = aws_subnet.public_subnet_1.id  
 vpc_security_group_ids = [aws_security_group.ansible_sg.id]  

 tags = {  
 Name = "Ansible Server"  
 }  
}  

output "ansible_server_public_ip" {  
 value = aws_instance.ansible_server.public_ip  
}  

# web01  
resource "aws_instance" "web01" {  
 ami = "ami-0e2c8caa4b6378d8c"  
 instance_type = "t2.micro"  
 key_name = aws_key_pair.ec2_key_pair.key_name  
 subnet_id = aws_subnet.public_subnet_1.id  
 vpc_security_group_ids = [aws_security_group.instance_security_group.id]  

 tags = {  
 Name = "web01"  
 }  
}  

output "web01_public_ip" {  
 value = aws_instance.web01.public_ip  
}  


# web02  
resource "aws_instance" "web02" {  
 ami = "ami-0e2c8caa4b6378d8c"  
 instance_type = "t2.micro"  
 key_name = aws_key_pair.ec2_key_pair.key_name  
 subnet_id = aws_subnet.public_subnet_2.id  
 vpc_security_group_ids = [aws_security_group.instance_security_group.id]  

 tags = {  
 Name = "web02"  
 }  
}  

output "web02_public_ip" {  
 value = aws_instance.web02.public_ip  
}

Коли скрипти Terraform були готові, я виконав наступні команди для розгортання інфраструктури:

terraform init  
terraform plan  
terraform apply

Крок 2: Налаштування розгортання за допомогою Ansible

Після створення інфраструктури я використав Ansible для налаштування веб-серверів і розгортання статичного вебсайту.

Ansible.cfg

Конфігурація для Ansible

[defaults]  
host_key_checking = False  
inventory = ./inventory  
forks = 5  

[privilage_escalation]  
become = True  
become_method = sudo

Файл інвентаризації

Файл інвентаризації визначає цільові хости для Ansible:

all:  
 hosts:  
 web01:  
 ansible_host: 10.0.1.189  
 web02:  
 ansible_host: 10.0.2.195  

 children:  
 webservers:  
 hosts:  
 web01:  
 web02:

Playbook Ansible

Ось playbook для встановлення Apache і розгортання статичного вебсайту:

---  
- name: Provisioning webservers  
 hosts: webservers  
 become: yes  
 tasks:  
 - name: Instll Apache2  
 ansible.builtin.apt:  
 name: apache2  
 state: present  

 - name: Start Apache2 service  
 ansible.builtin.service:  
 name: apache2  
 state: started  
 enabled: yes  

 - name: Copy index.html file  
 ansible.builtin.copy:  
 src: 2137_barista_cafe/  
 dest: /var/www/html/

Виконання Playbook

Далі, відповідно до структури вашого проєкту, виконайте playbook.

Результат

Після успішного виконання playbook:

  • Вебсервер Apache було встановлено та запущено на обох EC2 екземплярах.
  • Файли статичного сайту було скопійовано до /var/www/html/.
  • Балансувальник навантаження додатка розподіляв трафік між двома веб-серверами.

Відвідування DNS-імені ALB у браузері показало розгорнутий статичний вебсайт.

Труднощі, з якими я зіткнувся

  1. Проблеми з підключенням по SSH: Спочатку SSH не працював через неправильні правила групи безпеки. Я переконався, що групі безпеки сервера Ansible дозволено доступ до групи безпеки веб-серверів.
  2. Помилки доступу: Під час завдання копіювання файлів виникли проблеми з правами доступу. Додавання директиви become: yes вирішило це.
  3. Управління станом Terraform: Для забезпечення консистентності файлів стану необхідна правильна конфігурація бекенду.

Основні висновки

  • Поєднання Terraform і Ansible є потужним підходом для керування хмарною інфраструктурою та конфігурацією.
  • Налагодження проблем з SSH і доступами вимагає глибокого розуміння правил груп безпеки та прав доступу користувачів.
  • Модульне розділення конфігурацій Terraform і Ansible підвищує повторне використання та зручність для читання.

Висновок

Цей проєкт демонструє, як інструменти IaC, такі як Terraform, і інструменти для керування конфігурацією, такі як Ansible, можуть спростити розгортання в хмарі.
текст перекладу
Автоматизуючи надання інфраструктури та налаштування конфігурації, ми можемо досягти масштабованих, ефективних і повторюваних робочих процесів для сучасних додатків.

Цей проєкт повністю хардкодований...

Не соромтесь поділитися своїми думками або задати питання в коментарях. Давайте з’єднаємось і обговоримо більше про автоматизацію та практики DevOps!

Перекладено з: Automating AWS Infrastructure and Deployment with Terraform and Ansible

Leave a Reply

Your email address will not be published. Required fields are marked *