Як розгорнути сервер Minecraft на AWS за допомогою Terraform (IaC)

pic

Щасливий хлопець, який створює IaC — Згенеровано за допомогою Midjourney

Якщо ви читаєте це, ймовірно, ви на шляху до того, щоб стати DevOps або Cloud інженером і вже зрозуміли, що знання IaC є поширеною вимогою для DevOps і/або Cloud інженерів.

У будь-якому випадку, цей блог допоможе вам освоїти основи Terraform | Інфраструктура як код (IaC).

Перш за все, як завжди, давайте розглянемо важливе питання «Чому» за Інфраструктурою як код (IaC).

Чому Інфраструктура як код (IaC)?

Інфраструктура як код дозволяє управляти та надавати інфраструктуру за допомогою коду. До IaC управління та надання інфраструктури було ручним процесом, що займало багато часу і було схильне до людських помилок та невідповідностей.

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

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

Чому Terraform?

Ще одне питання, яке ви, можливо, ставите, це чому ми використовуємо саме Terraform?

Існують інші інструменти IaC, які можна використовувати для створення та управління IaC, такі як Pulumi, OpenTofu та, звісно, рідний інструмент IaC AWS — CloudFormation.

Простою відповіддю є те, що я не знаю Pulimi або OpenTofu і не можу виправдати їх вивчення для створення цього блогу!

Професійною відповіддю є те, що Terraform є найпопулярнішим інструментом IaC, що дає низку ключових переваг, деякі з яких я навів нижче:

  • Terraform підтримує найбільшу кількість провайдерів
  • Terraform — це найпотрібніша навичка IaC в вакансіях DevOps та Cloud
  • Terraform є (можливо) найпростішим інструментом IaC для вивчення/використання

pic

Створення IaC з коду на ноутбуці — Згенеровано за допомогою IaC

Є й багато інших причин, чому вам слід вивчити Terraform, але думаю, що вищенаведене буде достатньо мотивацією.

Перший пункт про підтримку найбільшої кількості провайдерів може залишити вас збентеженими, якщо ви не знайомі з цією термінологією.

Що таке провайдер в Terraform?

За словами Hashicorp, творців Terraform:

Провайдери — це логічне абстрагування API верхнього рівня. Вони відповідають за розуміння взаємодій з API та надання ресурсів.

Простими словами, провайдер — це те, що перетворює вашу досить просту конфігурацію IaC в складні API-запити, які можуть зрозуміти API хмарних провайдерів і, відповідно, створити необхідні ресурси.

Наразі Terraform підтримує велику кількість провайдерів, тому ви можете створювати та управляти ресурсами на різних платформах за допомогою одного загального інструменту та мови конфігурації.

Ось поточний список підтримуваних провайдерів:

pic

pic

Джерело: https://registry.terraform.io/browse/providers

Стан Terraform:

Дуже важливою концепцією в сфері Terraform/IaC є стан. Стан визначає, як Terraform порівнює те, що визначено в вашій конфігурації, і те, що існує в обраній хмарній платформі.

Terraform використовує стан для визначення, які зміни потрібно внести до вашої інфраструктури.
Перед будь-якими операціями IaC, Terraform виконує оновлення, щоб оновити стан реальної інфраструктури.

Більше деталей про стан Terraform можна знайти @ https://developer.hashicorp.com/terraform/language/state

Що варто зазначити щодо стану, так це те, що Terraform використовує файл для зберігання стану, файл стану за замовчуванням зберігається локально на машині, яка виконує розгортання.

Я не рекомендую цей варіант, навіть для простих/лабораторних розгортань, оскільки файли легко можна втратити або пошкодити, і тоді оновлення вашого проекту IaC стане справжнім кошмаром.

Завжди рекомендується зберігати стан IaC у віддаленому бекенді, який має механізм блокування, щоб запобігти пошкодженню файлу, якщо/коли кілька людей намагаються одночасно виконувати розгортання IaC.

Одним з найбільш поширених варіантів для віддаленого зберігання стану Terraform є використання Amazon S3 для зберігання файлу та DynamoDB для блокування віддаленого файлу стану.

Я створю блог про те, як це зробити, але поки що ви можете звернутися до відмінного посібника з цього процесу @ https://spacelift.io/blog/terraform-s3-backend

Якщо ви створили ваш віддалений бекенд Terraform на S3, ми можемо почати будувати наш проект IaC, або ж ви можете вибрати зберігати файл стану локально — це залежить від вас.

Цікава частина:

Тепер давайте перейдемо до цікавої частини, фактичного створення IaC.

У цьому блозі ми не будемо використовувати стандартний і нудний підхід, який всі використовують, ми побудуємо щось, що включає елемент розваги.

Minecraft — це весело, тому ми будемо створювати сервер Minecraft за допомогою Terraform (IaC).

pic

Шедевр Minecraft

Більше деталей про те, що саме ми будуємо, можна знайти @ https://aws.amazon.com/blogs/gametech/setting-up-a-minecraft-java-server-on-amazon-ec2/

Розгортання сервера Minecraft за допомогою Terraform (IaC)

Попередні вимоги:

Якщо ви вирішили використовувати VSCode, я раджу також завантажити розширення для Terraform, вони допоможуть вам легко виявляти помилки синтаксису та спростити процес налагодження вашого IaC.

pic

Нарешті, давайте почнемо.

Оскільки ми розгортаємо IaC в AWS, нам потрібно налаштувати механізм аутентифікації.

Ви повинні були завантажити AWS CLI в рамках попередніх вимог, що дозволить нам легко налаштувати наші ключі доступу AWS.

Після встановлення AWS CLI ви повинні мати можливість виконати наступну команду:

aws configure

Це запитає у вас ваш AWS Access & Secret ключі, надайте їх і натискайте Enter двічі, можна залишити назву регіону та формат виводу за замовчуванням.

pic

Тепер давайте створимо наш каталог проекту, де ми зберігатимемо наш проект IaC.

mkdir tf-aws-minecraft-server && cd tf-aws-minecraft-server

Тепер, коли ми створили каталог проекту, давайте налаштуємо наш віддалений бекенд для проекту.

Припустимо, ви використали посібник @ https://spacelift.io/blog/terraform-s3-backend для створення вашого S3 бакету та DynamoDB таблиці для віддаленого бекенду, ваша конфігурація бекенду виглядатиме ось так:

terraform {
required_providers {  
 aws = {  
 source = "hashicorp/aws"  
 version = "~> 4.18.0"  
 }  
 }  

 backend "s3" {  
 bucket = "mycomponents-tfstate"  
 key = "state/terraform.tfstate"  
 region = "eu-central-1"  
 encrypt = true  
 dynamodb_table = "mycomponents_tf_lockid"  
 }

Окрім того, що версія трохи застаріла порівняно з останньою версією, яка наразі становить “5.83.1”, цього достатньо.

Давайте оновимо версію постачальника у вашому backend.tf на наступну:

terraform {  
 required_providers {  
 aws = {  
 source = "hashicorp/aws"  
 version = "~> 5.83.1"  
 }  
 }  

 backend "s3" {  
 bucket = "mycomponents-tfstate"  
 key = "state/terraform.tfstate"  
 region = "eu-central-1"  
 encrypt = true  
 dynamodb_table = "mycomponents_tf_lockid"

Тепер, коли наша конфігурація бекенду налаштована, давайте ініціалізуємо наш бекенд за допомогою наступної команди:

terraform init

Це повинно призвести до подібного виведення:

pic

Тепер давайте створимо VPC, який буде використовуватися для розміщення нашого сервера.

З допомогою Amazon Virtual Private Cloud (Amazon VPC) ви можете запускати ресурси AWS у логічно ізольованій віртуальній мережі, яку ви визначили.

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

REF = https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html

Наша конфігурація VPC може зберігатися в файлі, назва якого vpc.tf, щоб було легше зрозуміти та запам'ятати, що містить наш проект.

provider "aws" {  
 region = "eu-west-2"  
}  

resource "aws_vpc" "main" {  
 cidr_block = var.vpc_cidr_block  
 tags = {  
 Name = "Minecraft Server VPC"  
 Project = "Learning by doing"  
 }  
}

Це проста конфігурація VPC без додаткових аргументів, окрім cidr блоку, який є обов'язковим, щоб у VPC був діапазон CIDR, з якого IP-адреси можуть бути призначені ресурсам всередині.

Повні деталі всіх доступних аргументів при створенні VPC можна знайти @ https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc#argument-reference

Ви можете помітити, що ми вказали “var.vpccidrblock” як наш cidr блок, це змінна.

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

Добрею аналогією може бути футболка з комплектом форми, на якій на спині написано ім'я клієнта.

У цьому випадку код — це футболка, а змінна — це ім'я клієнта, який замовляє форму.

Змінні в Terraform зберігаються в окремому файлі — variables.tf.
Давайте створимо файл змінних:

touch variables.tf

Тепер давайте додамо нашу змінну “vpccidrblock” у файл variables.tf:

variable "vpc_cidr_block" {  
 description = "CIDR блок для VPC"  
 default = "10.0.0.0/16"  
}

Тепер у вас повинні бути підготовлені обидва файли vpc.tf та variables.tf. Ми можемо перевірити, чи правильно написана синтаксична конфігурація IaC за допомогою команди “terraform validate”, як це показано нижче:

pic

Тепер, коли ми перевірили правильність нашої конфігурації, давайте запустимо команду ‘terraform plan’, щоб Terraform створив план виконання та показав нам попередній перегляд того, що наша конфігурація створить.

Ось результат виконання terraform plan:

gandalf@abstract-vm:~/Documents/Projects/tf-aws-minecraft-server$ terraform plan  

Terraform використав обрані постачальники для генерації наступного плану виконання. Дії з ресурсами позначені наступними символами:  
 + create  

Terraform виконає наступні дії:  

 # aws_vpc.main буде створено  
 + ресурс "aws_vpc" "main" {  
 + arn = (відомо після застосування)  
 + cidr_block = "10.0.0.0/16"  
 + default_network_acl_id = (відомо після застосування)  
 + default_route_table_id = (відомо після застосування)  
 + default_security_group_id = (відомо після застосування)  
 + dhcp_options_id = (відомо після застосування)  
 + enable_dns_hostnames = (відомо після застосування)  
 + enable_dns_support = true  
 + enable_network_address_usage_metrics = (відомо після застосування)  
 + id = (відомо після застосування)  
 + instance_tenancy = "default"  
 + ipv6_association_id = (відомо після застосування)  
 + ipv6_cidr_block = (відомо після застосування)  
 + ipv6_cidr_block_network_border_group = (відомо після застосування)  
 + main_route_table_id = (відомо після застосування)  
 + owner_id = (відомо після застосування)  
 + tags = {  
 + "Name" = "Minecraft Server VPC"  
 + "Project" = "Learning by doing"  
 }  
 + tags_all = {  
 + "Name" = "Minecraft Server VPC"  
 + "Project" = "Learning by doing"  
 }  
 }  

План: 1 додати, 0 змінити, 0 знищити.  

─────────────────────────────────────────────────────────────────────────────────────────────────────  

Примітка: Ви не використовували параметр -out для збереження цього плану, тому Terraform не може гарантувати виконання саме цих дій, якщо ви зараз запустите "terraform apply".

Це означає, що Terraform збирається створити 1 ресурс, який є VPC з діапазоном CIDR “10.0.0.0/16”.

Давайте застосуємо цю конфігурацію і перевіримо, що було створено.

terraform apply

Це ще раз створить план виконання та запитає у вас підтвердження для виконання дій, введіть “yes” і натискайте Enter, як показано нижче:

pic

Через кілька секунд наш VPC буде створено.
Тепер давайте створимо файл змінних:

touch variables.tf

Тепер давайте додамо змінну “vpccidrblock” до файлу variables.tf:

variable "vpc_cidr_block" {  
 description = "CIDR блок для VPC"  
 default = "10.0.0.0/16"  
}

Тепер у вас повинні бути підготовлені файли vpc.tf та variables.tf. Ми можемо перевірити, чи правильна наша конфігурація IaC, за допомогою команди “terraform validate”, як показано нижче:

pic

Тепер, коли ми перевірили правильність конфігурації, давайте запустимо команду ‘terraform plan’, щоб Terraform створив план виконання та показав попередній перегляд того, що створить наша конфігурація.

Ось результат виконання terraform plan:

gandalf@abstract-vm:~/Documents/Projects/tf-aws-minecraft-server$ terraform plan  

Terraform використав обрані провайдери для генерації наступного плану виконання. Дії з ресурсами позначені такими символами:  
 + create  

Terraform виконає наступні дії:  

 # aws_subnet.public буде створено  
 + ресурс "aws_subnet" "public" {  
 + arn = (відомо після застосування)  
 + assign_ipv6_address_on_creation = false  
 + availability_zone = "eu-west-2a"  
 + availability_zone_id = (відомо після застосування)  
 + cidr_block = "10.0.4.0/24"  
 + enable_dns64 = false  
 + enable_resource_name_dns_a_record_on_launch = false  
 + enable_resource_name_dns_aaaa_record_on_launch = false  
 + id = (відомо після застосування)  
 + ipv6_cidr_block_association_id = (відомо після застосування)  
 + ipv6_native = false  
 + map_public_ip_on_launch = false  
 + owner_id = (відомо після застосування)  
 + private_dns_hostname_type_on_launch = (відомо після застосування)  
 + tags = {  
 + "Name" = "Minecraft-public-subnet"  
 + "Project" = "Learning by doing"  
 }  
 + tags_all = {  
 + "Name" = "Minecraft-public-subnet"  
 + "Project" = "Learning by doing"  
 }  
 + vpc_id = "vpc-0a3826becb3477a00"  
 }  

План: 1 додати, 0 змінити, 0 знищити.  

─────────────────────────────────────────────────────────────────────────────────────────────────────  

Примітка: Ви не використовували параметр -out для збереження цього плану, тому Terraform не може гарантувати виконання саме цих дій, якщо ви зараз запустите "terraform apply".

Це означає, що Terraform збирається створити 1 ресурс, який є VPC з діапазоном CIDR “10.0.0.0/16”.

Давайте застосуємо цю конфігурацію і перевіримо, що було створено.

terraform apply

Це ще раз створить план виконання та запитає у вас підтвердження для виконання дій, введіть “yes” і натискайте Enter, як показано нижче:

pic

Через кілька секунд наш VPC буде створено.
aws_subnet.public: Створення завершено через 1с [id=subnet-0a790f9b4bb8d8fe3]

Застосування завершено! Ресурси: 1 додано, 0 змінено, 0 знищено.
```

Давайте знову подивимося на консоль, щоб краще побачити, що було створено.

pic

Декілька інших ресурсів, які нам потрібні в нашій VPC:

Докладну інформацію про кожен з цих ресурсів можна знайти за наданими посиланнями, але загалом це ресурси, необхідні для того, щоб ресурси в нашій VPC могли підключатися до ресурсів/послуг в Інтернеті.

Давайте додамо ці ресурси до нашого файлу vpc.tf наступним чином:

resource "aws_internet_gateway" "main" {  
 vpc_id = aws_vpc.main.id  

 tags = {  
 Name = "Minecraft-igw"  
 Project = "Learning by doing"  
 }  
}  

resource "aws_route_table" "public" {  
 vpc_id = aws_vpc.main.id  

 route {  
 cidr_block = "0.0.0.0/0"  
 gateway_id = aws_internet_gateway.main.id  
 }  

 tags = {  
 Name = "Minecraft-public-route-table"  
 Project = "Learning by doing"  
 }  
}  


resource "aws_route_table_association" "public" {  
 subnet_id = aws_subnet.public.id  
 route_table_id = aws_route_table.public.id  
}  


resource "aws_vpc_dhcp_options" "main" {  
 domain_name_servers = ["8.8.8.8", "8.8.4.4"]  
}  

resource "aws_vpc_dhcp_options_association" "main" {  
 vpc_id = aws_vpc.main.id  
 dhcp_options_id = aws_vpc_dhcp_options.main.id  
}

Давайте перевіримо та застосуємо ці зміни.

Ось результат застосування цих змін, ви побачите, що було додано 5 нових ресурсів, що і очікувалося.

gandalf@abstract-vm:~/Documents/Projects/tf-aws-minecraft-server$ terraform apply  
aws_vpc.main: Оновлення стану... [id=vpc-0a3826becb3477a00]  
aws_subnet.public: Оновлення стану... [id=subnet-0a790f9b4bb8d8fe3]  

Terraform використав обрані провайдери для генерації наступного плану виконання.

Дії з ресурсами  
позначені наступними символами:  
 + створення  

Terraform виконає наступні дії:  

 # буде створено aws_internet_gateway.main  
 + ресурс "aws_internet_gateway" "main" {  
 + arn = (буде відомо після застосування)  
 + id = (буде відомо після застосування)  
 + owner_id = (буде відомо після застосування)  
 + tags = {  
 + "Name" = "Minecraft-igw"  
 + "Project" = "Learning by doing"  
 }  
 + tags_all = {  
 + "Name" = "Minecraft-igw"  
 + "Project" = "Learning by doing"  
 }  
 + vpc_id = "vpc-0a3826becb3477a00"  
 }  

 # буде створено aws_route_table.public  
 + ресурс "aws_route_table" "public" {  
 + arn = (буде відомо після застосування)  
 + id = (буде відомо після застосування)  
 + owner_id = (буде відомо після застосування)  
 + propagating_vgws = (буде відомо після застосування)  
 + route = [  
 + {  
 + cidr_block = "0.0.0.0/0"  
 + gateway_id = (буде відомо після застосування)  
 # (11 незмінних атрибутів сховано)  
 },  
 ]  
 + tags = {  
 + "Name" = "Minecraft-public-route-table"  
 + "Project" = "Learning by doing"  
 }  
 + tags_all = {  
 + "Name" = "Minecraft-public-route-table"  
 + "Project" = "Learning by doing"  
 }  
 + vpc_id = "vpc-0a3826becb3477a00"  
 }  

 # буде створено aws_route_table_association.public  
 + ресурс "aws_route_table_association" "public" {  
 + id = (буде відомо після застосування)  
 + route_table_id = (буде відомо після застосування)  
 + subnet_id = "subnet-0a790f9b4bb8d8fe3"  
 }  

 # буде створено aws_vpc_dhcp_options.main  
 + ресурс "aws_vpc_dhcp_options" "main" {  
 + arn = (буде відомо після застосування)  
 + domain_name_servers = [  
 + "8.8.8.8",  
 + "8.8.4.4",  
 ]  
 + id = (буде відомо після застосування)  
 + owner_id = (буде відомо після застосування)  
 + tags_all = (буде відомо після застосування)  
 }  

 # буде створено aws_vpc_dhcp_options_association.main  
 + ресурс "aws_vpc_dhcp_options_association" "main" {  
 + dhcp_options_id = (буде відомо після застосування)  
 + id = (буде відомо після застосування)  
 + vpc_id = "vpc-0a3826becb3477a00"  
 }  

План: 5 до додавання, 0 до змін, 0 до знищення.  

Бажаєте виконати ці дії?  
 Terraform виконає описані вище дії.  
 Лише 'yes' буде прийнято для підтвердження.  

 Введіть значення: yes  

aws_vpc_dhcp_options.main: Створення...  
aws_internet_gateway.main: Створення...  
aws_internet_gateway.main: Створено після 0с [id=igw-04075fbdf9c3d4f27]  
aws_vpc_dhcp_options.main: Створено після 0с [id=dopt-0bc87b2033f55690f]  
aws_route_table.public: Створення...  
aws_vpc_dhcp_options_association.main: Створення...  
aws_vpc_dhcp_options_association.main: Створено після 1с [id=dopt-0bc87b2033f55690f-vpc-0a3826becb3477a00]  
aws_route_table.public: Створено після 1с [id=rtb-090a7e933c402ca9b]  
aws_route_table_association.public: Створення...
aws_route_table_association.public: Створення завершено після 0с [id=rtbassoc-0d31b70a7ae1234c2]

Тепер, коли ми маємо нашу VPC і підмережу, давайте почнемо створювати інші необхідні ресурси відповідно до https://aws.amazon.com/blogs/gametech/setting-up-a-minecraft-java-server-on-amazon-ec2/ .

Ось проста архітектура, яку ми будуємо:

pic

Наступний крок — налаштувати групу безпеки для дозволу як вхідного, так і вихідного трафіку, оскільки нам потрібно підключитися до сервера Minecraft, а також серверу потрібно підключення до ресурсів в інтернеті.

Створимо файл з ім'ям sg.tf, в якому ми створимо нашу групу безпеки та правила.

resource "aws_security_group" "public" {  
 name = "public-inbound-allow"  
 description = "Allow TLS inbound traffic and all outbound traffic"  
 vpc_id = aws_vpc.main.id  

 tags = {  
 Name = "Minecraft_public-subnet-sg"  
 }  
}  

resource "aws_vpc_security_group_ingress_rule" "public_subnet_allow_ssh" {  
 security_group_id = aws_security_group.public.id  
 cidr_ipv4 = "0.0.0.0/0"  
 from_port = 22  
 ip_protocol = "tcp"  
 to_port = 22  
 tags = {  
 Name = "Minecraft_public_subnet_allow_ssh"  
 }  
}  

resource "aws_vpc_security_group_ingress_rule" "public_subnet_allow_minecraft_service" {  
 security_group_id = aws_security_group.public.id  
 cidr_ipv4 = "0.0.0.0/0"  
 from_port = 25565  
 ip_protocol = "tcp"  
 to_port = 25565  
 tags = {  
 Name = "public_subnet_allow_minecraft_service"  
 }  
}  

resource "aws_vpc_security_group_egress_rule" "public_subnet_allow_all_outbound_traffic_ipv4" {  
 security_group_id = aws_security_group.public.id  
 cidr_ipv4 = "0.0.0.0/0"  
 ip_protocol = "-1"   
 tags = {  
 Name = "minecraft_public_subnet_allow_all_outbound_traffic_ipv4"  
 }  
}

Тут ми визначили створення 4 ресурсів:

  1. Група безпеки security group, яка асоційована з VPC, яку ми створили раніше, і буде містити деякі правила групи безпеки.
  2. 2 правила Ingress security group, які дозволяють вхідний трафік через порти 22 для SSH з'єднань і 25565 для підключення до сервісу Minecraft.
  3. Правило egress security group, яке дозволяє весь вихідний трафік в інтернет.

Порада: Ніколи не надавайте доступ до SSH з Інтернету, це дуже небезпечно!

Краще надати доступ конкретно до вашої VPN-адреси або вашої публічної IP-адреси вдома, якщо у вас є статичний IP.

Ви можете знайти свою IP-адресу на https://whatismyipaddress.com/ або використати наступну команду:

curl -s ifconfig.me

Давайте перевіримо наш sg.tf файл і застосуємо зміни.

gandalf@abstract-vm:~/Documents/Projects/tf-aws-minecraft-server$ ls && terraform validate && terraform apply  
backend.tf sg.tf variables.tf vpc.tf  
Успішно! Конфігурація правильна.  

aws_vpc_dhcp_options.main: Оновлення стану... [id=dopt-0bc87b2033f55690f]  
aws_vpc.main: Оновлення стану... [id=vpc-0a3826becb3477a00]  
aws_subnet.public: Оновлення стану... [id=subnet-0a790f9b4bb8d8fe3]  
aws_internet_gateway.main: Оновлення стану... [id=igw-04075fbdf9c3d4f27]  
aws_vpc_dhcp_options_association.main: Оновлення стану... [id=dopt-0bc87b2033f55690f-vpc-0a3826becb3477a00]  
aws_route_table.public: Оновлення стану... [id=rtb-090a7e933c402ca9b]  
aws_route_table_association.public: Оновлення стану... [id=rtbassoc-0d31b70a7ae1234c2]  

Terraform використовував вибрані провайдери для створення наступного плану виконання.

Дії з ресурсами  
позначаються наступними символами:  
 + створити  

Terraform виконає наступні дії:  

 # буде створено aws_security_group.public  
 + ресурс "aws_security_group" "public" {  
 + arn = (відомо після застосування)  
 + опис = "Дозволити вхідний трафік TLS і весь вихідний трафік"  
 + egress = (відомо після застосування)  
 + id = (відомо після застосування)  
 + ingress = (відомо після застосування)  
 + ім'я = "public-inbound-allow"  
 + name_prefix = (відомо після застосування)  
 + owner_id = (відомо після застосування)  
 + revoke_rules_on_delete = false  
 + теги = {  
 + "Name" = "Minecraft_public-subnet-sg"  
 }  
 + tags_all = {  
 + "Name" = "Minecraft_public-subnet-sg"  
 }  
 + vpc_id = "vpc-0a3826becb3477a00"  
 }  

 # буде створено aws_vpc_security_group_egress_rule.public_subnet_allow_all_outbound_traffic_ipv4  
 + ресурс "aws_vpc_security_group_egress_rule" "public_subnet_allow_all_outbound_traffic_ipv4" {  
 + arn = (відомо після застосування)  
 + cidr_ipv4 = "0.0.0.0/0"  
 + id = (відомо після застосування)  
 + ip_protocol = "-1"  
 + security_group_id = (відомо після застосування)  
 + security_group_rule_id = (відомо після застосування)  
 + теги = {  
 + "Name" = "minecraft_public_subnet_allow_all_outbound_traffic_ipv4"  
 }  
 + tags_all = {  
 + "Name" = "minecraft_public_subnet_allow_all_outbound_traffic_ipv4"  
 }  
 }  

 # буде створено aws_vpc_security_group_ingress_rule.public_subnet_allow_minecraft_service  
 + ресурс "aws_vpc_security_group_ingress_rule" "public_subnet_allow_minecraft_service" {  
 + arn = (відомо після застосування)  
 + cidr_ipv4 = "0.0.0.0/0"  
 + from_port = 25565  
 + id = (відомо після застосування)  
 + ip_protocol = "tcp"  
 + security_group_id = (відомо після застосування)  
 + security_group_rule_id = (відомо після застосування)  
 + теги = {  
 + "Name" = "public_subnet_allow_minecraft_service"  
 }  
 + tags_all = {  
 + "Name" = "public_subnet_allow_minecraft_service"  
 }  
 + to_port = 25565  
 }  

 # буде створено aws_vpc_security_group_ingress_rule.public_subnet_allow_ssh  
 + ресурс "aws_vpc_security_group_ingress_rule" "public_subnet_allow_ssh" {  
 + arn = (відомо після застосування)  
 + cidr_ipv4 = "0.0.0.0/0"  
 + from_port = 22  
 + id = (відомо після застосування)  
 + ip_protocol = "tcp"  
 + security_group_id = (відомо після застосування)  
 + security_group_rule_id = (відомо після застосування)  
 + теги = {  
 + "Name" = "Minecraft_public_subnet_allow_ssh"  
 }  
 + tags_all = {  
 + "Name" = "Minecraft_public_subnet_allow_ssh"  
 }  
 + to_port = 22  
 }  

План: 4 додати, 0 змінити, 0 знищити.  

Бажаєте виконати ці дії?  
 Terraform виконає зазначені вище дії.  
 Для підтвердження введіть 'yes'.  

 Введіть значення: yes  

aws_security_group.public: Створення...  
aws_security_group.public: Створено після 2с [id=sg-01d0de14f08db7fe8]  
aws_vpc_security_group_ingress_rule.public_subnet_allow_ssh: Створення...  
aws_vpc_security_group_ingress_rule.public_subnet_allow_minecraft_service: Створення...  
aws_vpc_security_group_egress_rule.public_subnet_allow_all_outbound_traffic_ipv4: Створення...  

aws_vpc_security_group_ingress_rule.public_subnet_allow_minecraft_service: Створено після 0с [id=sgr-0926e68250e7ec7b8]  
aws_vpc_security_group_egress_rule.public_subnet_allow_all_outbound_traffic_ipv4: Створено після 0с [id=sgr-0583e56e4ed916c02]  
aws_vpc_security_group_ingress_rule.public_subnet_allow_ssh: Створено після 0с [id=sgr-0252a75969354c0c8]  

Застосування завершено! Додано ресурсів: 4, змінено: 0, знищено: 0

Тепер, коли наша група безпеки та правила застосовані, давайте перевіримо консоль AWS і поглянемо на карту ресурсів VPC. Це дасть нам уявлення про потік трафіку в межах VPC, яку ми щойно налаштували:

pic

Як видно, трафік спрямовується з нашої підмережі через нашу таблицю маршрутів до Інтернету за допомогою створеного нами інтернет-шлюзу.

Ми також можемо побачити нашу групу безпеки та налаштовані правила, як показано нижче:

pic

pic

Тепер давайте налаштуємо наш сервер Minecraft.

Створимо файл під назвою ec2.tf, в якому збережемо цю конфігурацію:

touch ec2.tf

Перед тим, як створити наш екземпляр EC2, нам потрібно налаштувати кілька допоміжних ресурсів.

  1. Пара ключів AWS — щоб дозволити нам підключатися до сервера через SSH.
  2. Еластична IP-адреса — не є обов'язковою, але дозволить зберегти ту ж IP-адресу та повторно підключити її до екземпляра, коли ми в кінцевому підсумку переналаштуємо чи переозброїмо його.

Давайте створимо ці ресурси.

По-перше, щоб створити ресурс AWS ключа, нам потрібно створити пару ключів.

Ми можемо використати команду ‘ssh-keygen’ для створення пари ключів, дивіться нижче:

pic

Тепер ми можемо використати публічну частину пари ключів для створення ресурсу AWS ключа.

pic

Ресурс AWS ключа в вашій конфігурації IaC буде використовувати вміст вашого файлу .pub, який був створений, коли ви виконали команду ‘ssh-keygen’.

Ось початкова частина мого файлу ec2.tf, в якому визначено awskeypair та aws_eip:

resource "aws_key_pair" "minecraft_ssh_key" {  
 key_name = "minecraft_ssh_key"  
 public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQBucbHN36nrirH6inKbsFYPb48yhxwhtYTfc7dc1jY gandalf@abstract-vm"  
}  

resource "aws_eip" "minecraft_server_eip" {  
 domain = "vpc"  

 tags = {  
 Name = "poc_minecraft_server_eip"  
 Project = "Learning by doing"  
 }  
}

Тепер давайте визначимо конфігурацію нашого екземпляра EC2:

resource "aws_instance" "minecraft_server" {  
 ami = "ami-0ed62eac7a7c3c410"  
 instance_type = "t3.medium"  
 subnet_id = aws_subnet.public.id   
 monitoring = true   
 vpc_security_group_ids = [aws_security_group.public.id]  
 key_name = "minecraft_ssh_key"  

 ebs_block_device {  
 device_name = "/dev/sda1"  
 volume_size = 100  
 volume_type = "gp2"   
 delete_on_termination = true  
 encrypted = true  
 }  


 tags = {  
 Name = "Minecraft Server"  
 Project = "Learning by doing"  
 }  
 user_data = file("user_data.tpl")  
}

Я встановив тип екземпляра як “t3.medium”, який не підходить для безкоштовного рівня, тому можете змінити його на “t2.micro”, якщо бажаєте.

Список всіх типів та розмірів екземплярів EC2 можна знайти на https://aws.amazon.com/ec2/instance-types/

Також я визначив блоковий пристрій ebs / віртуальний жорсткий диск розміром 100 ГБ, зашифрований, який буде видалено після завершення екземпляра.

AMI, яку я використав у своїй конфігурації, є однією з кастомних AMI, які я створив раніше. Дивіться https://medium.com/@Abstract_Labs/how-to-build-an-amazon-machine-image-using-hashicorp-packer-b2b05172700a, якщо ви хочете створити та налаштувати кастомну AMI за допомогою Packer.

Інакше ви можете знайти AMI Amazon Linux 2 ID у каталозі AMI в консолі AWS:

pic

Ще однією важливою частиною цього визначення EC2 є надання файлу даних користувача.

У файлі даних користувача ми можемо надати сценарій або серію команд для виконання після того, як екземпляр стане доступним.

У нашому випадку, сценарій налаштування Minecraft надано @ https://aws.amazon.com/blogs/gametech/setting-up-a-minecraft-java-server-on-amazon-ec2/, який ми можемо помістити у файл даних користувача.

Ось вміст мого user_data.tpl — цей сценарій був трохи змінений, оскільки наданий сценарій застарілий і призводить до помилки при запуску сервера.

#!/bin/bash  

# *** ВСТАВТЕ URL ДЛЯ СКАЧУВАННЯ СЕРВЕРА НИЖЧЕ ***  
# Не додавайте пробіли між вашим посиланням та "="; в іншому випадку це не працюватиме.

EG: MINECRAFTSERVERURL=https://urlexample  

MINECRAFTSERVERURL=https://piston-data.mojang.com/v1/objects/4707d00eb834b446575d89a61a11b5d548d8c001/server.jar  

# Завантаження Java  
cd /var/tmp  
wget https://download.oracle.com/java/21/archive/jdk-21.0.4_linux-x64_bin.rpm  
sudo yum install -y /var/tmp/jdk-21.0.4_linux-x64_bin.rpm  
# Встановлення MC Java сервера в створену нами директорію  
adduser minecraft  
mkdir /opt/minecraft/  
mkdir /opt/minecraft/server/  
cd /opt/minecraft/server  

# Завантаження jar файлу сервера з офіційного сайту Minecraft  
wget $MINECRAFTSERVERURL  

# Генерація файлів сервера Minecraft і створення скрипта  
chown -R minecraft:minecraft /opt/minecraft/  
touch eula.txt && echo 'eula=true' > eula.txt && chmod -w eula.txt  
java -Xmx1300M -Xms1300M -jar server.jar nogui  
sleep 40  
touch start  
printf '#!/bin/bash\njava -Xmx1300M -Xms1300M -jar server.jar nogui\n' >> start  
chmod +x start  
sleep 1  
touch stop  
printf '#!/bin/bash\nkill -9 $(ps -ef | pgrep -f "java")' >> stop  
chmod +x stop  
sleep 1  

# Створення системного скрипта для запуску сервера Minecraft після перезавантаження  
cd /etc/systemd/system/  
touch minecraft.service  
printf '[Unit]\nDescription=Minecraft Server on start up\nWants=network-online.target\n[Service]\nUser=minecraft\nWorkingDirectory=/opt/minecraft/server\nExecStart=/opt/minecraft/server/start\nStandardInput=null\n[Install]\nWantedBy=multi-user.target' >> minecraft.service  
sudo systemctl daemon-reload  
sudo systemctl enable minecraft.service  
sudo systemctl start minecraft.service  

# Кінець скрипта

Нарешті, після налаштування конфігурації нашого екземпляра EC2, нам потрібно асоціювати еластичний IP з екземпляром:

resource "aws_eip_association" "minecraft_server_eip_assoc" {  
 instance_id = aws_instance.minecraft_server.id  
 allocation_id = aws_eip.minecraft_server_eip.id  
 allow_reassociation = true  
}

Тепер давайте застосуємо наш оновлений проект IaC і перевіримо розгортання сервера.

Ось результат виконання команди terraform apply:

gandalf@abstract-vm:~/Documents/Projects/tf-aws-minecraft-server$ ls && terraform validate && terraform apply  
backend.tf ec2.tf sg.tf user_data.tpl variables.tf vpc.tf  
Success! The configuration is valid.  

aws_vpc.main: Refreshing state... [id=vpc-0a3826becb3477a00]  
aws_vpc_dhcp_options.main: Refreshing state... [id=dopt-0bc87b2033f55690f]  
aws_subnet.public: Refreshing state... [id=subnet-0a790f9b4bb8d8fe3]  
aws_security_group.public: Refreshing state... [id=sg-01d0de14f08db7fe8]  
aws_vpc_dhcp_options_association.main: Refreshing state... [id=dopt-0bc87b2033f55690f-vpc-0a3826becb3477a00]  
aws_internet_gateway.main: Refreshing state... [id=igw-04075fbdf9c3d4f27]  
aws_route_table.public: Refreshing state... [id=rtb-090a7e933c402ca9b]  
aws_route_table_association.public: Refreshing state... [id=rtbassoc-0d31b70a7ae1234c2]  

Terraform used the selected providers to generate the following execution plan.

Дії з ресурсами  
вказуються наступними символами:  
 + створити  

Terraform виконає наступні дії:  

 # aws_eip.minecraft_server_eip буде створено  
 + ресурс "aws_eip" "minecraft_server_eip" {  
 + allocation_id = (визначено після застосування)  
 + arn = (визначено після застосування)  
 + association_id = (визначено після застосування)  
 + carrier_ip = (визначено після застосування)  
 + customer_owned_ip = (визначено після застосування)  
 + domain = "vpc"  
 + id = (визначено після застосування)  
 + instance = (визначено після застосування)  
 + ipam_pool_id = (визначено після застосування)  
 + network_border_group = (визначено після застосування)  
 + network_interface = (визначено після застосування)  
 + private_dns = (визначено після застосування)  
 + private_ip = (визначено після застосування)  
 + ptr_record = (визначено після застосування)  
 + public_dns = (визначено після застосування)  
 + public_ip = (визначено після застосування)  
 + public_ipv4_pool = (визначено після застосування)  
 + теги = {  
 + "Name" = "poc_minecraft_server_eip"  
 + "Project" = "Learning by doing"  
 }  
 + tags_all = {  
 + "Name" = "poc_minecraft_server_eip"  
 + "Project" = "Learning by doing"  
 }  
 + vpc = (визначено після застосування)  
 }  

 # aws_eip_association.minecraft_server_eip_assoc буде створено  
 + ресурс "aws_eip_association" "minecraft_server_eip_assoc" {  
 + allocation_id = (визначено після застосування)  
 + allow_reassociation = true  
 + id = (визначено після застосування)  
 + instance_id = (визначено після застосування)  
 + network_interface_id = (визначено після застосування)  
 + private_ip_address = (визначено після застосування)  
 + public_ip = (визначено після застосування)  
 }  

 # aws_instance.minecraft_server буде створено  
 + ресурс "aws_instance" "minecraft_server" {  
 + ami = "ami-040bcdad653710fad"  
 + arn = (визначено після застосування)  
 + associate_public_ip_address = (визначено після застосування)  
 + availability_zone = (визначено після застосування)  
 + cpu_core_count = (визначено після застосування)  
 + cpu_threads_per_core = (визначено після застосування)  
 + disable_api_stop = (визначено після застосування)  
 + disable_api_termination = (визначено після застосування)  
 + ebs_optimized = (визначено після застосування)  
 + enable_primary_ipv6 = (визначено після застосування)  
 + get_password_data = false  
 + host_id = (визначено після застосування)  
 + host_resource_group_arn = (визначено після застосування)  
 + iam_instance_profile = (визначено після застосування)  
 + id = (визначено після застосування)  
 + instance_initiated_shutdown_behavior = (визначено після застосування)  
 + instance_lifecycle = (визначено після застосування)  
 + instance_state = (визначено після застосування)  
 + instance_type = "t3.medium"  
 + ipv6_address_count = (визначено після застосування)  
 + ipv6_addresses = (визначено після застосування)  
 + key_name = "minecraft_ssh_key"  
 + monitoring = true  
 + outpost_arn = (визначено після застосування)  
 + password_data = (визначено після застосування)  
 + placement_group = (визначено після застосування)  
 + placement_partition_number = (визначено після застосування)  
 + primary_network_interface_id = (визначено після застосування)  
 + private_dns = (визначено після застосування)  
 + private_ip = (визначено після застосування)  
 + public_dns = (визначено після застосування)  
 + public_ip = (визначено після застосування)  
 + secondary_private_ips = (визначено після застосування)  
 + security_groups = (визначено після застосування)  
 + source_dest_check = true  
 + spot_instance_request_id = (визначено після застосування)  
 + subnet_id = "subnet-0a790f9b4bb8d8fe3"  
 + теги = {  
 + "Name" = "Minecraft Server"  
 + "Project" = "Learning by doing"  
 }  
 + tags_all = {  
 + "Name" = "Minecraft Server"  
 + "Project" = "Learning by doing"  
 }  
 + tenancy = (визначено після застосування)  
 + user_data = "b2c37569277d30b721cd87b1106ccada5bee3802"  
 + user_data_base64 = (визначено після застосування)  
 + user_data_replace_on_change = false  
 + vpc_security_group_ids = [  
 + "sg-01d0de14f08db7fe8",  
 ]  

 + capacity_reservation_specification (визначено після застосування)  

 + cpu_options (визначено після застосування)  

 + ebs_block_device {  
 + delete_on_termination = true  
 + device_name = "/dev/sda1"  
 + encrypted = true  
 + iops = (визначено після застосування)  
 + kms_key_id = (визначено після застосування)  
 + snapshot_id = (визначено після застосування)  
 + tags_all = (визначено після застосування)

+ throughput = (визначено після застосування)  
 + volume_id = (визначено після застосування)  
 + volume_size = 100  
 + volume_type = "gp2"  
 }  

 + enclave_options (визначено після застосування)  

 + ephemeral_block_device (визначено після застосування)  

 + instance_market_options (визначено після застосування)  

 + maintenance_options (визначено після застосування)  

 + metadata_options (визначено після застосування)  

 + network_interface (визначено після застосування)  

 + private_dns_name_options (визначено після застосування)  

 + root_block_device (визначено після застосування)  
 }  

 # aws_key_pair.minecraft_ssh_key буде створено  
 + ресурс "aws_key_pair" "minecraft_ssh_key" {  
 + arn = (визначено після застосування)  
 + fingerprint = (визначено після застосування)  
 + id = (визначено після застосування)  
 + key_name = "minecraft_ssh_key"  
 + key_name_prefix = (визначено після застосування)  
 + key_pair_id = (визначено після застосування)  
 + key_type = (визначено після застосування)  
 + public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQBucbHN36nrirH6inKbsFYPb48yhxwhtYTfc7dc1jY gandalf@abstract-vm"  
 + tags_all = (визначено після застосування)  
 }  

План: 4 для додавання, 0 для зміни, 0 для знищення.
Ви хочете виконати ці дії?  
 Terraform виконає описані вище дії.  
 Тільки 'yes' буде прийнято для підтвердження.  

 Введіть значення: yes  

aws_key_pair.minecraft_ssh_key: Створення...  
aws_eip.minecraft_server_eip: Створення...  
aws_instance.minecraft_server: Створення...  
aws_key_pair.minecraft_ssh_key: Створено після 0с [id=minecraft_ssh_key]  
aws_eip.minecraft_server_eip: Створено після 1с [id=eipalloc-0157829c909389a45]  
aws_instance.minecraft_server: Все ще створюється... [10с минуло]  
aws_instance.minecraft_server: Створено після 13с [id=i-0692c4152edc55c67]  
aws_eip_association.minecraft_server_eip_assoc: Створення...  
aws_eip_association.minecraft_server_eip_assoc: Створено після 1с [id=eipassoc-0b13461c89a16f168]  

Застосування завершено! Ресурси: 4 додано, 0 змінено, 0 знищено.  

Тепер ми можемо побачити EC2 інстанс у консолі AWS:

pic

Спробуємо увійти на інстанс, використовуючи його публічну IP-адресу та наш ключ доступу:

ssh -i "ШЛЯХ ДО ВАШОГО ПРИВАТНОГО КЛЮЧА" “ІМ'Я КОРИСТУВАЧА”@"ПУБЛІЧНА IP-АДРЕСА EC2 ІНСТАНСУ"

pic

Ми увійшли на наш Minecraft сервер, тепер можемо перевірити журнали, щоб переконатися, що все працює як очікувалося:

Каталог журналів Minecraft: /opt/minecraft/server/logs/

Журнали cloud-init (надають деталі про виконаний скрипт user-data):

  • /var/log/cloud-init.log
  • /var/log/cloud-init-output.log

Я завантажив Minecraft на своєму локальному ПК і використовую його як клієнт для підключення до свого Minecraft сервера.

Деталі, як встановити Minecraft на вашому локальному ПК та налаштувати багатокористувацький режим, можна знайти за посиланнями нижче:

Встановлення Minecraft Launcher

Multiplayer Minecraft | Підключення до Minecraft сервера

Після того, як ви встановите Minecraft Launcher, підключіться до свого сервера, слідуючи наступним крокам:

  1. Натисніть “PLAY” у Minecraft Java Edition

pic

  1. Виберіть Multiplayer

pic

  1. Додати сервер

pic

  1. Введіть назву сервера на ваш вибір і введіть публічну IP-адресу вашого Minecraft сервера, потім натисніть “Done”.

Інформація: ви можете знайти публічну IP-адресу вашого Minecraft сервера в консолі AWS або виконавши команду “curl -s ifconfig.me” на сервері, оскільки ми не додавали жодних terraform outputs.

pic

5.
Як тільки ваш сервер знайдено, натискайте “Join Server”

pic

Ура, ми успішно розгорнули сервер Minecraft на AWS за допомогою Terraform (IaC).

Тепер ви можете створювати неймовірні речі в Minecraft і запрошувати своїх друзів приєднатися до вашого світу.

pic

Не соромтеся ознайомитися з документацією Minecraft, якщо ви хочете налаштувати свій сервер Minecraft:

[

Server.properties

server.properties — це файл, що зберігає всі налаштування для мультиплеєрного сервера (Minecraft або Minecraft Classic)…

minecraft.fandom.com

](https://minecraft.fandom.com/wiki/Server.properties?source=post_page-----b8691e87b55f--------------------------------)

[

Підручники/Налаштування сервера

Цей підручник проведе вас через етапи налаштування вашого серверу Java Edition за допомогою стандартного серверного програмного забезпечення…

minecraft.fandom.com

](https://minecraft.fandom.com/wiki/Tutorials/Settingupaserver?source=postpage-----b8691e87b55f--------------------------------)

Тепер, коли ви розгорнули щось круте за допомогою Terraform, чому б не розвинути цей проект IaC і не поглибити свої знання про Terraform/IaC?

Сподіваюся, що вам сподобався цей пост, залишайтеся з нами, оскільки я публікуватиму більше контенту на подібні теми.

pic

Перекладено з: How to deploy a Minecraft Server on AWS using Terraform (IaC)

Leave a Reply

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