Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
Из соображений наглядности, я создал большую брешь в безопасности я поместил токен в конфигурационный файл, а значит и в репозиторий, и теперь любой, кото может получить доступ к нему сможет удалить все репозитории. Terraform предоставляет несколько способов задания переменных, кроме использованного. Я же просто пересоздам токен и перекрою его переданным в командной строке:
(agile-aleph-203917)$ rm variables.tf
(agile-aleph-203917)$ sed -i 's/terraform-repo2/terraform-repo3/' main.tf
./terraform apply -var="github_token=f7602b82e02efcbae7fc915c16eeee518280cf2a"
Создание инфраструктуры в GCP с Terraform
Каждые облака имеют свои наборы сервисов, свои API для них. Чтобы упростить переход с одного облака как для сотрудников с точки зрения изучения, так и точки зрения переписывания существуют универсальные библиотеки, реализующие паттерн Фасад. Под фасадом понимаются универсальный API, срывающий особенности систем, лежащих за ним.
Одним из представителем фасадов API облаков является KOPS. KOPS тулза для деплоя Kubernetes в GCP, AWS и Azure. KOPS похож на Kubectl представляет из себя бинарника, может создавать как командами, так и по YML-конфигу, имеет схожий синтаксис, но в отличии от Kubectl создаёт не POD, а нод кластера. Другим примером, является Terraform, специализирующийся именно на развёртывании по конфигурации для придерживания концепции IasC.
Для создания инфраструктуры нам понадобится токен, его создаётся в GCP для сервисного аккаунта, которому выдаются доступы. Для этого я перешёл по пути: IAM и администрирование > Сервисные аккаунты > Создать сервисный аккаунт и при создании выбыла роль Владелец (полный доступ для тестовых целей), создал ключ кнопкой Создать ключ в JSON формате и скачанный ключ я переименовал в Key. JSON. Для описания инфраструктуры я воспользовался документацией www.terraform.io/docs/providers/google/index.html:
(agil7e-aleph-20391)$ cat main.tf
provider "google" {
credentials = "${file("key.json")}"
project = "agile-aleph-203917"
region = "us-central1"
}
resource "google_compute_instance" "terraform" {
name = "terraform"
machine_type = "n1-standard-1"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-cloud/debian-9"
}
}
network_interface {
network = "default"
}
}
Проверим права пользователя:
(agile-aleph-203917)$ gcloud auth list
Credentialed Accounts
ACTIVE ACCOUNT
* esschtolts@gmail.com
To set the active account, run:
$ gcloud config set account `ACCOUNT`
Выберем проект в качестве текущего (можно составить текущий по умолчанию):
$ gcloud config set project agil7e-aleph-20391;
(agil7e-aleph-20391)$ ./terraform init | grep success
Terraform has been successfully initialized!
Теперь создам один инстанс в WEB-консоли, предварительно скопировав ключ в файл key.json в каталог с Terraform:
machine_type: "" => "n1-standard-1"
metadata_fingerprint: "" => "<computed>"
name: "" => "terraform"
network_interface.#: "" => "1"
network_interface.0.address: "" => "<computed>"
network_interface.0.name: "" => "<computed>"
network_interface.0.network: "" => "default"
network_interface.0.network_ip: "" => "<computed>"
network_interface.0.network: "" => "default"
project: "" => "<computed>"
scheduling.#: "" => "<computed>"
self_link: "" => "<computed>"
tags_fingerprint: "" => "<computed>"
zone: "" => "us-central1-a"
google_compute_instance.terraform: Still creating (10s elapsed)
google_compute_instance.terraform: Still creating (20s elapsed)
google_compute_instance.terraform: Still creating (30s elapsed)
google_compute_instance.terraform: Still creating (40s elapsed)
google_compute_instance.terraform: Creation complete after 40s (ID: terraform)
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Все, мы создали инстанс сервера. Теперь удалим его:
~/terraform (agil7e-aleph-20391)$ ./terraform apply
google_compute_instance.terraform: Refreshing state (ID: terraform)
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
destroy
Terraform will perform the following actions:
google_compute_instance.terraform
Plan: 0 to add, 0 to change, 1 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
google_compute_instance.terraform: Destroying (ID: terraform)
google_compute_instance.terraform: Still destroying (ID: terraform, 10s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 20s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 30s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 40s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 50s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 1m0s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 1m10s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 1m20s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 1m30s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 1m40s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 1m50s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 2m0s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 2m10s elapsed)
google_compute_instance.terraform: Still destroying (ID: terraform, 2m20s elapsed)
google_compute_instance.terraform: Destruction complete after 2m30s
Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
Создание инфраструктуры в AWS
Для создания конфигурации AWS кластера, создадим под него отдельную папку, а предыдущую в параллельную:
esschtolts@cloudshell:~/terraform (agil7e-aleph-20391)$ mkdir gcp
esschtolts@cloudshell:~/terraform (agil7e-aleph-20391)$ mv main.tf gcp/main.tf
esschtolts@cloudshell:~/terraform (agil7e-aleph-20391)$ mkdir aws
esschtolts@cloudshell:~/terraform (agil7e-aleph-20391)$ cd aws
Role аналог пользователя, только не для людей, а для сервисов, таких как AWS, а в нашем случае это сервера EKS. Но мне видится аналогом ролей не пользователи, а группы, например, группа создания кластера, группа работы с БД и т.д. К серверу можно прикрепить только одну роль, при этом роль может содержать множество прав (Polices). В результате нам не нужно работать ни с логинами и паролями, ни с токенами, ни с сертификатами: хранить, передавать, ограничивать доступ, передавать мы только указываем в WEB панели инструментов (IMA) или с помощью API (а производно в конфигурации) права. Нашему кластеру необходимы эти права, чтобы он смог само настраиваться и реплицироваться, так как он состоит из стандартных сервисов AWS. Для управления самими компонентами кластера AWS EC2 (сервера), AWS ELB (Elastic Load Balancer, балансировщик) и AWS KMS (Key Management Service, менеджер и шифрование ключей) нужен доступ AmazonEKSClusterPolicy, для мониторинга AmazonEKSServicePolicy с помощью компонентов CloudWatch Logs (мониторинг по логам), Route 53 (создание сети в зоне), IAM (управления правами). Я не стал описывать роль в конфиге и создал её через IAM по документации: https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role. html #create-service-role.
Для большей надёжности ноды Kubernetes кластера должны располагаться в разных зонах, то есть дата центрах. В каждом регионе, содержится несколько зон для поддержания отказоустойчивости, при этот сохраняя минимальных летенси (время ответа сервера) для местного населения. Важно заметить, что некоторые регионы могут быть представлены в нескольких экземплярах в рамках одной страны, например, US-east-1 в US East (N. Virginia) и US-east-2 в US East (Ohio) обозначение регионов ведётся цифрами. Пока создание кластера EKS доступно только US-east зоне.
VPC для разработчика, простейшем варианте, сводится к наименованию подсети как конкретный ресурс.
Напишем конфигурацию в соответствии с документацией www.terraform.io/docs/providers/aws/r/eks_cluster. html :
esschtolts@cloudshell:~/terraform/aws (agile-aleph-203917)$ cat main.tf
provider "aws" {
access_key = "${var.token}"
secret_key = "${var.key}"
region = "us-east-1"
}
# Params
variable "token" {
default = ""
}
variable "key" {
default = ""
}
# EKS
resource "aws_eks_cluster" "example" {
enabled_cluster_log_types = ["api", "audit"]
name = "exapmle"
role_arn = "arn:aws:iam::177510963163:role/ServiceRoleForAmazonEKS2"
vpc_config {
subnet_ids = ["${aws_subnet.subnet_1.id}", "${aws_subnet.subnet_2.id}"]
}
}
output "endpoint" {
value = "${aws_eks_cluster.example.endpoint}"
}
output "kubeconfig-certificate-authority-data" {
value = "${aws_eks_cluster.example.certificate_authority.0.data}"
}
# Role
data "aws_iam_policy_document" "eks-role-policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["eks.amazonaws.com"]
}
}
}
resource "aws_iam_role" "tf_role" {
name = "tf_role"
assume_role_policy = "${data.aws_iam_policy_document.eks-role-policy.json}"
tags = {
tag-key = "tag-value"
}
}
resource "aws_iam_role_policy_attachment" "attach-cluster" {
role = "tf_role"
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
}
resource "aws_iam_role_policy_attachment" "attach-service" {
role = "tf_role"
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy"
}
# Subnet
resource "aws_subnet" "subnet_1" {
vpc_id = "${aws_vpc.main.id}"
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
tags = {
Name = "Main"
}
}
resource "aws_subnet" "subnet_2" {
vpc_id = "${aws_vpc.main.id}"
cidr_block = "10.0.2.0/24"
availability_zone = "us-east-1b"
tags = {
Name = "Main"
}
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
Через 9 минут 44 секунды я получил готовую самоподдерживающуюся инфраструктуру для кластера Kubernetes:
esschtolts@cloudshell:~/terraform/aws (agile-aleph-203917)$ ./../terraform apply -var="token=AKIAJ4SYCNH2XVSHNN3A" -var="key=huEWRslEluynCXBspsul3AkKlinAlR9+MoU1ViY7"
Теперь удалим (у меня заняло 10 минуты 23 секунды):
esschtolts@cloudshell:~/terraform/aws (agile-aleph-203917)$ ./../terraform destroy -var="token=AKIAJ4SYCNH2XVSHNN3A" -var="key=huEWRslEluynCXBspsul3AkKlinAlR9+MoU1ViY7"
Destroy complete! Resources: 7 destroyed.
Налаживание процесса CI/CD
Amazon предоставляет (aws.amazon.com/ru/devops/) большой спектр DevOps инструментов, оформленных в облачную инфраструктуру:
* AWS Code Pipeline сервис позволяет создать из набора сервисов в визуальном редакторе цепочку этапов, через которые должен пройти код, прежде чем он попадёт на продакшн, например, сборку и тестирование.
* AWS Code Build сервис предоставляет авто масштабирующую очередь сборки, что может потребоваться для компилируемых языков программирования, когда при добавлении фич или внесения изменений необходимо длительная пере компиляция всего приложения, при использовании одного сервера становится узким местом при выкатке изменений.