Книга Облачная экосистема - читать онлайн бесплатно, автор Евгений Сергеевич Штольц. Cтраница 8
bannerbanner
Вы не авторизовались
Войти
Зарегистрироваться
Облачная экосистема
Облачная экосистема
Добавить В библиотекуАвторизуйтесь, чтобы добавить
Оценить:

Рейтинг: 0

Добавить отзывДобавить цитату

Облачная экосистема

Наши контейнера отлично работают. Добавим в них трафик:

controlplane $ kubectl expose deploy readiness \

–-type=LoadBalancer \

–-name=readiness \

–-port=9000 \

–-target-port=9000

service/readiness exposed


controlplane $ kubectl get svc readiness

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

readiness LoadBalancer 10.98.36.51 < pending> 9000:32355/TCP 98s


controlplane $ curl localhost:9000


controlplane $ for i in {1..5}; do curl $IP:9000/health; done

1

2

3

4

5

Каждый контейнер имеет задержку. Проверим, что будет, если один из контейнеров перезапустить – будет ли на него перенаправляться трафик:

controlplane $ kubectl get pods

NAME READY STATUS RESTARTS AGE

readiness-5dd64c6c79-9vq62 0/1 CrashLoopBackOff 6 15m

readiness-5dd64c6c79-sblvl 0/1 CrashLoopBackOff 6 15m


kubectl exec -it .... -c .... bash -c "rm -f healt"


controlplane $ for i in {1..5}; do echo $i; done

1

2

3

4

5


controlplane $ kubectl delete deploy readiness

deployment.apps "readiness" deleted

Рассмотрим ситуацию, когда контейнер становится временно недоступен для работы:

(hostname > health) && (python -m http.server 9000 &) && sleep 60 && rm health && sleep 60 && (hostname > health) sleep 6000

/bin/sh -c sleep 60 && (python -m http.server 9000 &) && PID=$! && sleep 60 && kill -9 $PID

По умолчанию, в состояние Running контейнер переходит по завершения выполнения скриптов в Dockerfile и запуску скрипта, заданного в инструкции CMD, если он переопределён в конфигурации в разделе Command. Но, на практике, если у нас база данных, ей нужно ещё подняться (прочитать данные и перенести их оперативную память и другие действия), а это может занять значительно время, при этом она не будет отвечать на соединения, и другие приложения, хотя и прочитают в состоянии готовность принимать соединения не смогут этого сделать. Также, контейнер переходи в состояние Feils, когда падает главный процесс в контейнере. В случае с базой данных, она может бесконечно пытаться выполнить неправильный запрос и не сможет отвечать на приходящие запросы, при этом контейнер не буде перезапущен, так как формально демон (сервер) базы данных не упал. Для этих случаев и придуманы два идентификатора: readinessProbe и livenessProbe, проверяющих по кастомному скрипту или HTTP запросу переход контейнера в рабочее состояние или его неисправность.

esschtolts@cloudshell:~/bitrix (essch)$ cat health_check.yaml

apiVersion: v1

kind: Pod

metadata:

labels:

test: healtcheck

name: healtcheck

spec:

containers:

– name: healtcheck

image: alpine:3.5

args:

– /bin/sh

– -c

– sleep 12; touch /tmp/healthy; sleep 10; rm -rf /tmp/healthy; sleep 60

readinessProbe:

exec:

command:

– cat

– /tmp/healthy

initialDelaySeconds: 5

periodSeconds: 5

livenessProbe:

exec:

command:

– cat

– /tmp/healthy

initialDelaySeconds: 15

periodSeconds: 5

Контейнер стартует через 3 секунды и через 5 секунд начинается проверка на готовность каждые 5 секунд. На второй проверке (на 15 секунде жизни) проверка на готовность cat /tmp/healthy увенчается успехом. В это время начинает осуществляться проверка на работоспособность livenessProbe и на второй проверке (на 25 секунде) заканчивается ошибкой, после чего контейнер признаётся не рабочим и пересоздается.

esschtolts@cloudshell:~/bitrix (essch)$ kubectl create -f health_check.yaml && sleep 4 && kubectl get

pods && sleep 10 && kubectl get pods && sleep 10 && kubectl get pods

pod "liveness-exec" created

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 Running 0 5s

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 Running 0 15s

NAME READY STATUS RESTARTS AGE

liveness-exec 1/1 Running 0 26s

esschtolts@cloudshell:~/bitrix (essch)$ kubectl get pods

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 Running 0 53s

esschtolts@cloudshell:~/bitrix (essch)$ kubectl get pods

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 Running 0 1m

esschtolts@cloudshell:~/bitrix (essch)$ kubectl get pods

NAME READY STATUS RESTARTS AGE

liveness-exec 1/1 Running 1 1m

Kubernetes предоставляет ещё и startup, переделяющий момент, когда можно включить readiness и liveness пробы в работу. Это полезно в том случае, если, к примеру, мы скачиваем приложение. Рассмотрим более подробно. Для эксперимента возьмём www.katacoda.com/courses/Kubernetes/playground и Python. Существует TCP, EXEC и HTTP, но лучше использовать HTTP, так как EXEC порождает процессы и может оставлять их в виде "зомби процессов". К тому же, если сервер обеспечивает взаимодействие по HTTP, то именно по нему и нужно проверять (https://www.katacoda.com/courses/kubernetes/playground):

controlplane $ kubectl version –short

Client Version: v1.18.0

Server Version: v1.18.0


cat << EOF > job.yaml

apiVersion: v1

kind: Pod

metadata:

name: healt

spec:

containers:

– name: python

image: python

command: ['sh', '-c', 'sleep 60 && (echo "work" > health) && sleep 60 && python -m http.server 9000']

readinessProbe:

httpGet:

path: /health

port: 9000

initialDelaySeconds: 3

periodSeconds: 3

livenessProbe:

httpGet:

path: /health

port: 9000

initialDelaySeconds: 3

periodSeconds: 3

startupProbe:

exec:

command:

– cat

– /health

initialDelaySeconds: 3

periodSeconds: 3

restartPolicy: OnFailure

EOF


controlplane $ kubectl create -f job.yaml

pod/healt


controlplane $ kubectl get pods # ещё не загружен

NAME READY STATUS RESTARTS AGE

healt 0/1 Running 0 11s


controlplane $ sleep 30 && kubectl get pods # ещё не загружен, но образ уже стянут

NAME READY STATUS RESTARTS AGE

healt 0/1 Running 0 51s


controlplane $ sleep 60 && kubectl get pods

NAME READY STATUS RESTARTS AGE

healt 0/1 Running 1 116s


controlplane $ kubectl delete -f job.yaml

pod "healt" deleted

Самодиагностика микро сервисного приложения

Рассмотрим работу probe на примере микро сервисного приложения bookinfo, входящего в состав Istio как пример: https://github.com/istio/istio/tree/master/samples/bookinfo. Демонстрация будет в www.katacoda.com/courses/istio/deploy-istio-on-kubernetes. После разворачивания будет доступны

Управление инфраструктурой

Хотя, и у Kubernetes есть свой графический интерфейс – UI-дашборд, но кроме мониторинга и простейших действий не предоставляет. Больше возможностей даёт OpenShift, предоставляя совмещения графического и текстового создания. Полноценный продукт с сформированной экосистемой Google в Kubernetes не предоставляет, но предоставляет облачное решение – Google Cloud Platform. Однако, существуют и сторонние решения, такие как Open Shift и Rancher, позволяющие пользоваться полноценно через графический интерфейс на своих мощностях. При желании, конечно, можно синхронизироваться с облаком.

Каждый продукт, зачастую, не совместим с друг другом по API, единственным известным исключением является Mail. Cloud, в котором заявляется поддержка Open Shift. Но, существует стороннее решение, реализующее подход "инфраструктура как код" и поддерживающее API большинства известных экосистем – Terraform. Он, так же как Kubernetes, применяет концепция инфраструктура как код, но только не к контейнеризации, а к виртуальным машинам (серверам, сетям, дискам). Принцип Инфраструктура как код подразумевает наличии декларативной конфигурации – то есть описания результата без явного указания самих действий. При активации конфигурация (в Kubernetes это kubectl apply -f name_config .yml, а в Hashicorp Terraform – terraform apply) системы приводится в соответствие с конфигурационными файлами, при изменении конфигурации или инфраструктуры, инфраструктура, в конфликтующих частях с её декларацией приводится в соответствие, при этом сама система решает, как этого достичь, причём поведение может быть различным, например, при изменении метаинформации в POD – она будет изменена, а при изменении образа – POD будет удалён и создан уже новым. Если, до этого мы создавали серверную инфраструктуру для контейнеров в императивном виде с помощью команды gcloud публичного облака Google Cloud Platform (GCP), то теперь рассмотрим, как создать аналогичное с помощью конфигурация в декларативном описании паттерна инфраструктура как код с помощью универсального инструмента Terraform, поддерживающего облако GCP.

Terraform не возник на пустом месте, а стал продолжением длинной истории появления программных продуктов конфигурирования и управления серверной инфраструктуры, перечислю в прядке появления и перехода:

** CFN;

** Pupet;

** Chef;

** Ansible;

** Облачные AWS API, Kubernetes API;

* IasC: Terraform не зависит от типа инфраструктуры (поддерживает более 120 провайдеров, среди которых не только облака), в отличии от ведровых аналогов, поддерживающих только себя: CloudFormation для Amazon WEB Service, Azure Resource Manager для Microsoft Azure, Google Cloud Deployment Manager от Google Cloud Engine.

CloudFormation создан Amazon и предназначен для негоже, также полностью интегрирован в CI/CD его инфраструктуры размещением на AWS S3, что усложняет версионирование через GIT. Мы рассмотрим платформой независимый Terraform: синтаксис базовой функциональности един, а специфичная подключается через сущности Провайдеры (https://www.terraform.io/docs/providers/index. html). Terraform – один бинарный файл, поддерживает огромное количество провайдеров, и, конечно же, таких как AWS и GCE. Terraform, как и большинство продуктов от Hashicorp написаны на Go и представляют из себя один бинарный исполняемый файл, не требует установки, достаточно просто скачать его в папку Linux:

(agile-aleph-203917)$ wget https://releases.hashicorp.com/terraform/0.11.13/terraform_0.11.13_linux_amd64.zip

(agile-aleph-203917)$ unzip terraform_0.11.13_linux_amd64.zip -d .

(agile-aleph-203917)$ rm -f terraform_0.11.13_linux_amd64.zip

(agile-aleph-203917)$ ./terraform version

Terraform v0.11.13

Он поддерживает разбиение на модули, которые можно написать самому или использовать готовые (https://registry.terraform.io/browse?offset=27&provider=google). Для оркестрации и поддержки изменений в зависимостях можно воспользоваться Terragrunt (https://davidbegin.github.io/terragrunt/), например:

terragrant = {

terraform {

source = "terraform-aws-modules/…"

}

dependencies {

path = ["..network"]

}

}

name = "…"

ami = "…"

instance_type = "t3.large"

Единая семантика для разных провайдеров (AWS, GCE, Яндекс. Облако и многих других) конфигураций, что позволяет создать трансцендентную инфраструктуру, например, постоянные нагруженные сервисы расположить для экономии на собственных мощностях, а переменно нагружены (например, в период акций) в публичных облаках. Благодаря тому, что управление декларативно и может быть описана файлами (IaC, инфраструктура как код), создание инфраструктуры можно добавить в pipeline CI/CD (разработка, тестирование, доставка, всё автоматически и с контролем версий). Без CI/CD поддерживается блокировка файла конфигурации для предотвращения конкурентного его редактирования при совместной работе. инфраструктура создаётся не скриптом, а приводится в соответствие с конфигурацией, которая декларативна и не может содержать логики, хотя, можно и внедрить в неё BASH- скрипты и использовать Conditions (термальный оператор) для разных окружений.

Terraform будет читать все файлы в текущем каталоге с расширением .tf в Hachiсort Configuraiton Language (HCL) формате или .tf. json в JSON формате. Часто, вместо одного файл его разделяют на несколько, как минимум на два: первый содержащий конфигурацию, второй – приватные данные, вынесенные в переменными.

Для демонстрации возможностей Terraform мы создадим репозиторий GitHub из-за его простоты авторизации и API. Сперва получим токен, сгенерирована в WEB-интерфейсе: SettingsDeveloper sittings -> Personal access token –> Generate new token и установив разрешения. Ничего не будем создавать, просто проверим подключение:

(agile-aleph-203917)$ ls *.tf

main.tf variables.tf


$ cat variables.tf

variable "github_token" {

default = "630bc9696d0b2f4ce164b1cabb118eaaa1909838"

}

$ cat main.tf

provider "github" {

token = "${var.github_token}"

}


(agile-aleph-203917)$ ./terraform init

(agile-aleph-203917)$ ./terraform apply


Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Теперь, создадим управляющий аккаунт Settings –> Organizations –> New organization –> Create organization.. Используя: API Terraform по создания репозитория www.terraform.io/docs/providers/github/r/repository. html добавим в конфиг описание репозитория:

(agile-aleph-203917)$ cat main.tf

provider "github" {

token = "${var.github_token}"

}

resource "github_repository" "terraform_repo" {

name = "terraform-repo"

description = "my terraform repo"

auto_init = true

}

Теперь осталось применить, посмотреть с планом создания репозитория, согласиться с ним:

(agile-aleph-203917)$ ./terraform apply

provider.github.organization

The GitHub organization name to manage.


Enter a value: essch2


An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

+ create


Terraform will perform the following actions:


+ github_repository.terraform_repo

id:

allow_merge_commit: "true"

allow_rebase_merge: "true"

allow_squash_merge: "true"

archived: "false"

auto_init: "true"

default_branch:

description: "my terraform repo"

etag:

full_name:

git_clone_url:

html _url:

http_clone_url:

name: "terraform-repo"

ssh_clone_url:

svn_url:


Plan: 1 to add, 0 to change, 0 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


github_repository.terraform_repo: Creating…

allow_merge_commit: "" => "true"

allow_rebase_merge: "" => "true"

allow_squash_merge: "" => "true"

archived: "" => "false"

auto_init: "" => "true"

default_branch: "" => ""

description: "" => "my terraform repo"

etag: "" => ""

full_name: "" => ""

git_clone_url: "" => ""

html_url: "" => ""

http_clone_url: "" => ""

name: "" => "terraform-repo"

ssh_clone_url: "" => ""

svn_url: "" => ""

github_repository.terraform_repo: Creation complete after 4s (ID: terraform-repo)


Apply complete! Resources: 1 added, 0 changed, 0 destroyed

Теперь можно наблюдать пустой репозиторий terraform-repo в WEB-интерфейсе. При повторном применении репозиторий не будет создан, так как Terraform применяет только изменения, который не было:

(agile-aleph-203917)$ ./terraform apply

provider.github.organization

The GITHub organization name to manage.

Enter a value: essch2

github_repository.terraform_repo: Refreshing state… (ID: terraform-repo)

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

А вот если я изменю название, то Terraform постарается применить изменения название через удаление и создание нового с актуальным названием. Важно заметить, что любые данные, которые мы бы запушили бы в этот репозиторий после смены названия были бы удалены. Для проверки, как будет производиться обновления можно предварительно спросить перечень производимых действий командой ./Terraform plane. И так, приступим:

(agile-aleph-203917)$ cat main.tf

provider "github" {

token = "${var.github_token}"

}

resource "github_repository" "terraform_repo" {

name = "terraform-repo2"

description = "my terraform repo"

auto_init = true

}


(agile-aleph-203917)$ ./terraform plan

provider.github.organization

The GITHub organization name to manage.


Enter a value: essch


Refreshing Terraform state in-memory prior to plan…

The refreshed state will be used to calculate this plan, but will not be

persisted to local or remote state storage.


github_repository.terraform_repo: Refreshing state… (ID: terraform-repo)


-–


An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

+ create


Terraform will perform the following actions:


+ github_repository.terraform_repo

id:

allow_merge_commit: "true"

allow_rebase_merge: "true"

allow_squash_merge: "true"

archived: "false"

auto_init: "true"

default_branch:

description: "my terraform repo"

etag:

full_name:

git_clone_url:

html_url:

http_clone_url:

name: "terraform-repo2"

ssh_clone_url:

svn_url:


"terraform apply" is subsequently run.

esschtolts@cloudshell:~/terraform (agile-aleph-203917)$ ./terraform apply

provider.github.organization

The GITHub organization name to manage.

Enter a value: essch2

github_repository.terraform_repo: Refreshing state… (ID: terraform-repo)

An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

–/+ destroy and then create replacement

Terraform will perform the following actions:

–/+ github_repository.terraform_repo (new resource required)

id:"terraform-repo" => (forces new resource)

allow_merge_commit: "true" => "true"

allow_rebase_merge: "true" => "true"

allow_squash_merge: "true" => "true"

archived: "false" => "false"

auto_init: "true" => "true"

default_branch: "master" =>

description: "my terraform repo" => "my terraform repo"

etag: "W/\"a92e0b300d8c8d2c869e5f271da6c2ab\"" =>

full_name: "essch2/terraform-repo" =>

git_clone_url: "git://github.com/essch2/terraform-repo.git" =>

html_url: "https://github.com/essch2/terraform-repo" =>

http_clone_url: "https://github.com/essch2/terraform-repo.git" =>

name: "terraform-repo" => "terraform-repo2" (forces new resource)

ssh_clone_url: "git@github.com:essch2/terraform-repo.git" =>

svn_url: "https://github.com/essch2/terraform-repo" =>

Plan: 1 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

github_repository.terraform_repo: Destroying… (ID: terraform-repo)

github_repository.terraform_repo: Destruction complete after 0s

github_repository.terraform_repo: Creating…

allow_merge_commit: "" => "true"

allow_rebase_merge: "" => "true"

allow_squash_merge: "" => "true"

archived: "" => "false"

auto_init: "" => "true"

default_branch: "" => ""

description: "" => "my terraform repo"

etag: "" => ""

full_name: "" => ""

git_clone_url: "" => ""

html_url: "" => ""

http_clone_url: "" => ""

name: "" => "terraform-repo2"

ssh_clone_url: "" => ""

svn_url: "" => ""

github_repository.terraform_repo: Creation complete after 5s (ID: terraform-repo2)

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: "" => ""

name: "" => "terraform"

network_interface.#: "" => "1"

network_interface.0.address: "" => ""

network_interface.0.name: "" => ""

network_interface.0.network: "" => "default"

network_interface.0.network_ip: "" => ""

network_interface.0.network: "" => "default"

project: "" => ""

scheduling.#: "" => ""

self_link: "" => ""

tags_fingerprint: "" => ""

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: