Облачная экосистема - Евгений Сергеевич Штольц 22 стр.


initial_node_count = 1

}


resource "google_container_node_pool" "node-ks-pool" {

name = "node-ks-pool"

cluster = "${google_container_cluster.node-ks.name}"

location = "europe-north1-a"

node_count = "1"


node_config {

machine_type = "n1-standard-1"

}


autoscaling {

min_node_count = 1

max_node_count = 2

}

}

Посмотрим, что получалось и поищем IP- адрес точки входа в кластер:

essh@kubernetes-master:~/node-cluster/Kubernetes$ gcloud container clusters list

NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS

node-ks europe-north1-a 1.12.8-gke.6 35.228.20.35 n1-standard-1 1.12.8-gke.6 6 RECONCILING


essh@kubernetes-master:~/node-cluster/Kubernetes$ gcloud container clusters describe node-ks | grep '^endpoint'

endpoint: 35.228.20.35


essh@kubernetes-master:~/node-cluster/Kubernetes$ ping 35.228.20.35 -c 2

PING 35.228.20.35 (35.228.20.35) 56(84) bytes of data.

64 bytes from 35.228.20.35: icmp_seq=1 ttl=59 time=8.33 ms

64 bytes from 35.228.20.35: icmp_seq=2 ttl=59 time=7.09 ms


- 35.228.20.35 ping statistics

2 packets transmitted, 2 received, 0% packet loss, time 1001ms

rtt min/avg/max/mdev = 7.094/7.714/8.334/0.620 ms

Добавив переменные, которые я выделил в отдельный файл только для наглядности, которые параметризуют наш конфиг под разное использование, мы сможем его использовать, например, для создания тестового и рабочего кластеров. Добавлять переменные можно как var.name_value, а вставлять в текст аналогично JS: ${var.name_value}, а также path.root.

essh@kubernetes-master:~/node-cluster/Kubernetes$ cat variables.tf

variable "region" {

default = "europe-north1"

}


variable "project_name" {

type = string

default = ""

}


variable "gce_key" {

default = "./kubernetes_key.json"

}


variable "node_count_zone" {

default = 1

}

Передать их можно через ключ -var, например: sudo ./terraform apply -var="project_name=node-cluster-243923".

essh@kubernetes-master:~/node-cluster/Kubernetes$ cp ../kubernetes_key.json .

essh@kubernetes-master:~/node-cluster/Kubernetes$ sudo ../terraform apply -var="project_name=node-cluster-243923"

Наш проект в папке является не только проектом, но и модулем, готовым к использованию:

essh@kubernetes-master:~/node-cluster/Kubernetes$ cd ..

essh@kubernetes-master:~/node-cluster$ cat main.tf

module "Kubernetes" {

source = "./Kubernetes"

project_name = "node-cluster-243923"

}

essh@kubernetes-master:~/node-cluster$ sudo ./terraform apply

Или же загрузить в публичный репозиторий:

essh@kubernetes-master:~/node-cluster/Kubernetes$ git init

Initialized empty GIT repository in /home/essh/node-cluster/Kubernetes/.git/

essh@kubernetes-master:~/node-cluster/Kubernetes$ echo "terraform.tfstate" >> .gitignore

essh@kubernetes-master:~/node-cluster/Kubernetes$ echo "terraform.tfstate.backup" >> .gitignore

essh@kubernetes-master:~/node-cluster/Kubernetes$ echo ".terraform/" >> .gitignore

essh@kubernetes-master:~/node-cluster/Kubernetes$ rm -f kubernetes_key.json

essh@kubernetes-master:~/node-cluster/Kubernetes$ git remote add origin https://github.com/ESSch/terraform-google-kubernetes.git

essh@kubernetes-master:~/node-cluster/Kubernetes$ git add .

essh@kubernetes-master:~/node-cluster/Kubernetes$ git commit -m 'create a k8s Terraform module'

[master (root-commit) 4f73c64] create a Kubernetes Terraform module

3 files changed, 48 insertions(+)

create mode 100644 .gitignore

create mode 100644 main.tf

create mode 100644 variables.tf

essh@kubernetes-master:~/node-cluster/Kubernetes$ git push -u origin master

essh@kubernetes-master:~/node-cluster/Kubernetes$ git tag -a v0.0.2 -m 'publish'

essh@kubernetes-master:~/node-cluster/Kubernetes$ git push origin v0.0.2

После публикации в реестре модулей https://registry.terraform.io/, выполнив требования, такие как наличие описания, мы можем его использовать:

essh@kubernetes-master:~/node-cluster$ cat main.tf

module "kubernetes" {

# source = "./Kubernetes"

source = "ESSch/kubernetes/google"

version = "0.0.2"


project_name = "node-cluster-243923"

}

essh@kubernetes-master:~/node-cluster$ sudo ./terraform init

essh@kubernetes-master:~/node-cluster$ sudo ./terraform apply

При очередном создании кластера у меня возникла ошибка ZONE_RESOURCE_POOL_EXHAUSTED "does not have enough resources available to fulfill the request. Try a different zone, or try again later", говорящая о том, что в данном регионе нет нужных серверов. Для меня это не проблема и мне не нужно править код модуля, ведь я параметризовал модуль регионом, и если я просто передам модулю в качестве параметра регионregion = "europe-west2", terraform после команды обновления и инициализации ./terrafrom init и команды применения ./terraform apply перенесёт мой кластер в указный регион. Ещё немного улучшим наш модуль тем, что вынесем провайдер (provider) из дочернего модуля Kubernetes в главный модуль (основной скрипт также является модулем). Вынеся в главный модуль, мы сможем использовать ещё один модуль, в противном случае провайдер в одном модуле будет конфликтовать с провайдером в другом. Наследование из главного модуля в дочерние и их прозрачность относится только к провайдерам. Остальные же данные для передачи из дочернего в родительский придётся использовать внешние переменные, а из родительского в дочерний параметризовать родительский, но это позже, когда мы будем создавать ещё один модель. Также, вынесение провайдера в родительский модуль, будет полезно при создании следующего модуля, который мы создадим, так как он будет создавать элементы Kubernetes, которые не зависят от провайдера, и мы сможем тем самым отвязать провайдера Google от нашего модуля и его можно будет использовать с другими провайдерами, поддерживающим Kubernetes. Теперь нам не нужна передавать в переменной название проекта он задан в провайдере. Для удобства разработки я буду пока использовать локальное подключение модуля. Я создал папку и файл нового модуля:

essh@kubernetes-master:~/node-cluster$ ls nodejs/

main.tf


essh@kubernetes-master:~/node-cluster$ cat main.tf

//module "kubernetes" {

// source = "ESSch/kubernetes/google"

// version = "0.0.2"

//

// project_name = "node-cluster-243923"

// region = "europe-west2"

//}


provider "google" {

credentials = "${file("./kubernetes_key.json")}"

project = "node-cluster-243923"

region = "europe-west2"

}


module "Kubernetes" {

source = "./Kubernetes"

project_name = "node-cluster-243923"

region = "europe-west2"

}


module "nodejs" {

source = "./nodejs"

}

essh@kubernetes-master:~/node-cluster$ sudo ./terraform init

essh@kubernetes-master:~/node-cluster$ sudo ./terraform apply

Теперь передадим данные из инфраструктурного модуля Kubernetes в модуль приложений:

essh@kubernetes-master:~/node-cluster$ cat Kubernetes/outputs.tf

output "endpoint" {

value = google_container_cluster.node-ks.endpoint

sensitive = true

}


output "name" {

value = google_container_cluster.node-ks.name

sensitive = true

}


output "cluster_ca_certificate" {

value = base64decode(google_container_cluster.node-ks.master_auth.0.cluster_ca_certificate)

}

essh@kubernetes-master:~/node-cluster$ cat main.tf

//module "kubernetes" {

// source = "ESSch/kubernetes/google"

// version = "0.0.2"

//

// project_name = "node-cluster-243923"

// region = "europe-west2"

//}


provider "google" {

credentials = file("./kubernetes_key.json")

project = "node-cluster-243923"

region = "europe-west2"

}


module "Kubernetes" {

source = "./Kubernetes"

project_name = "node-cluster-243923"

region = "europe-west2"

}


module "nodejs" {

source = "./nodejs"

endpoint = module.Kubernetes.endpoint

cluster_ca_certificate = module.Kubernetes.cluster_ca_certificate

}

essh@kubernetes-master:~/node-cluster$ cat nodejs/variable.tf

variable "endpoint" {}


variable "cluster_ca_certificate" {}

Для проверки балансировки трафика со всех нод запустим NGINX, заменив стандартную страницу на имя хоста. Заменим мы простым вызовом команды и возобновим работу сервера. Для запуска сервера посмотрим в Dockerfile его вызов: CMD ["Nginx", "-g", "daemon off;"], что равносильно вызову Nginx -g 'daemon off;' в командной строке . Как видим, в Dockerfile не используется BASH в качестве среды для запуска, а запускается непосредственно сам сервер, что позволяет в случае в случае падения процесса оболочка будет жить, не давая контейнеру упасть и создаться заново. Но для наших экспериментов вполне подойдёт BASH:

essh@kubernetes-master:~/node-cluster$ sudo docker run -it Nginx:1.17.0 which Nginx

/usr/sbin/Nginx

sudo docker run -it rm -p 8333:80 Nginx:1.17.0 /bin/bash -c "echo \$HOSTNAME > /usr/share/Nginx/html/index2.html && /usr/sbin/Nginx -g 'daemon off;'"

Теперь создадим наши POD в трёх экземплярах с NGINX, которые Kubernetes будут стараться распределить на разные сервера по умолчанию. Также добавим сервис в качестве балансировщика:

essh@kubernetes-master:~/node-cluster$ cat nodejs/main.tf

terraform {

required_version = ">= 0.12.0"

}


data "google_client_config" "default" {}


provider "kubernetes" {

host = var.endpoint


token = data.google_client_config.default.access_token

cluster_ca_certificate = var.cluster_ca_certificate


load_config_file = false

}


essh@kubernetes-master:~/node-cluster$ cat nodejs/main.tf

resource "kubernetes_deployment" "nodejs" {

metadata {

name = "terraform-nodejs"

labels = {

app = "NodeJS"

}

}

spec {

replicas = 3

selector {

match_labels = {

app = "NodeJS"

}

}

template {

metadata {

labels = {

app = "NodeJS"

}

}

spec {

container {

image = "Nginx:1.17.0"

name = "node-js"

command = ["/bin/bash"]

args = ["-c", "echo $HOSTNAME > /usr/share/Nginx/html/index.html && /usr/sbin/Nginx -g 'daemon off;'"]

}

}

}

}

}


resource "kubernetes_service" "nodejs" {

metadata {

name = "terraform-nodejs"

}

spec {

selector = {

app = kubernetes_deployment.nodejs.metadata.0.labels.app

}

port {

port = 80

target_port = var.target_port

}


type = "LoadBalancer"

}

Проверим работу с помощью kubectl, для этого передадим секреты от gcloud к kubectl.

essh@kubernetes-master:~/node-cluster$ sudo ./terraform apply


essh@kubernetes-master:~/node-cluster$ gcloud container clusters get-credentials node-ks region=europe-west2-a

Fetching cluster endpoint and auth data.

kubeconfig entry generated for node-ks.


essh@kubernetes-master:~/node-cluster$ kubectl get deployments -o wide

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR

terraform-nodejs 3 3 3 3 25m node-js Nginx:1.17.0 app=NodeJS


essh@kubernetes-master:~/node-cluster$ kubectl get pods -o wide

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE

terraform-nodejs-6bd565dc6c-8768b 1/1 Running 0 4m45s 10.4.3.15 gke-node-ks-node-ks-pool-07115c5b-bw15 none>

terraform-nodejs-6bd565dc6c-hr5vg 1/1 Running 0 4m42s 10.4.5.13 gke-node-ks-node-ks-pool-27e2e52c-9q5b none>

terraform-nodejs-6bd565dc6c-mm7lh 1/1 Running 0 4m43s 10.4.2.6 gke-node-ks-default-pool-2dc50760-757p none>


esschtolts@gke-node-ks-node-ks-pool-07115c5b-bw15 ~ $ docker ps | grep node-js_terraform

152e3c0ed940 719cd2e3ed04

"/bin/bash -c 'ech" 8 minutes ago Up 8 minutes

Kubernetes_node-js_terraform-nodejs-6bd565dc6c-8768b_default_7a87ae4a-9379-11e9-a78e-42010a9a0114_0


esschtolts@gke-node-ks-node-ks-pool-07115c5b-bw15 ~ $ docker exec -it 152e3c0ed940 cat /usr/share/Nginx/html/index.html

terraform-nodejs-6bd565dc6c-8768b


esschtolts@gke-node-ks-node-ks-pool-27e2e52c-9q5b ~ $ docker exec -it c282135be446 cat /usr/share/Nginx/html/index.html

terraform-nodejs-6bd565dc6c-hr5vg


esschtolts@gke-node-ks-default-pool-2dc50760-757p ~ $ docker exec -it 8d1cf9ef44e6 cat /usr/share/Nginx/html/index.html

terraform-nodejs-6bd565dc6c-mm7lh


esschtolts@gke-node-ks-node-ks-pool-07115c5b-bw15 ~ $ curl 10.4.2.6

terraform-nodejs-6bd565dc6c-mm7lh

esschtolts@gke-node-ks-node-ks-pool-07115c5b-bw15 ~ $ curl 10.4.5.13

terraform-nodejs-6bd565dc6c-hr5vg

esschtolts@gke-node-ks-node-ks-pool-07115c5b-bw15 ~ $ curl 10.4.3.15

terraform-nodejs-6bd565dc6c-8768b

Назад Дальше