Сегодня будем запускать Kubernetes Федерацию на Google Cloud Platform
Что такое Kubernetes Federation:
Федерация позволяет объединять несколько kubernetes кластеров и управлять через один control plane.
Благодаря Федерации мы можем:
- Синхронизировать ресурсы на всех кластерах
- Уменьшить время ответа для запросов разных континентов
- Получить высокую доступность, так как кластера могут находится в разных частях мира
В нашем примере мы будем использовать Google Kubernetes Engine
DNS
Создаем зону:
1 2 3 |
$ gcloud dns managed-zones create federation \ --description "Kubernetes Federation Zone" \ --dns-name federation.com |
Проверяем:
1 |
$ gcloud dns managed-zones describe federation |
Вывод:
1 2 3 4 5 6 7 8 9 10 11 |
creationTime: '2018-08-28T10:33:49.424Z' description: Kubernetes Federation Zone dnsName: federation.com. id: '8875495119636580191' kind: dns#managedZone name: federation nameServers: - ns-cloud-e1.googledomains.com. - ns-cloud-e2.googledomains.com. - ns-cloud-e3.googledomains.com. - ns-cloud-e4.googledomains.com. |
Кластеры
Создаем кластер в Азии
1 2 3 |
$ gcloud container clusters create asia \ --zone asia-southeast1-a \ --scopes "cloud-platform,storage-ro,logging-write,monitoring-write,service-control,service-management,https://www.googleapis.com/auth/ndev.clouddns.readwrite" |
Вывод:
1 2 3 4 |
Creating cluster asia...⠹ kubeconfig entry generated for asia. NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS asia asia-southeast1-a 1.9.7-gke.6 35.197.139.197 n1-standard-1 1.9.7-gke.6 3 RUNNING |
Получаем данные для подключения:
1 2 |
$ gcloud container clusters get-credentials asia \ --zone asia-southeast1-a |
Вывод:
1 2 |
Fetching cluster endpoint and auth data. kubeconfig entry generated for asia. |
Даем права пользователю:
1 2 |
$ kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin --user $(gcloud config get-value account) |
Вывод:
1 2 |
Fetching cluster endpoint and auth data. kubeconfig entry generated for asia. |
Создаем кластер в Европе:
1 2 3 |
$ gcloud container clusters create europe \ --zone europe-west2-a \ --scopes "cloud-platform,storage-ro,logging-write,monitoring-write,service-control,service-management,https://www.googleapis.com/auth/ndev.clouddns.readwrite" |
Получаем данные для подключения:
1 2 |
$ gcloud container clusters get-credentials europe \ --zone europe-west2-a |
Даем права пользователю:
1 2 |
$ kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin --user $(gcloud config get-value account) |
Создаем кластер в США:
1 2 3 |
$ gcloud container clusters create america \ --zone us-central1-a \ --scopes "cloud-platform,storage-ro,logging-write,monitoring-write,service-control,service-management,https://www.googleapis.com/auth/ndev.clouddns.readwrite" |
Получаем данные для подключения:
1 2 |
$ gcloud container clusters get-credentials america \ --zone us-central1-a |
Даем права пользователю:
1 2 |
$ kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin --user $(gcloud config get-value account) |
Повторим те же действия для еще 2 кластеров в Европе и Азии:
1 2 3 4 5 6 7 8 9 10 |
$ gcloud container clusters create asia-2 \ --zone asia-east1-a \ --scopes "cloud-platform,storage-ro,logging-write,monitoring-write,service-control,service-management,https://www.googleapis.com/auth/ndev.clouddns.readwrite" $ gcloud container clusters get-credentials asia-2 \ --zone asia-east1-a $ kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin --user $(gcloud config get-value account) |
1 2 3 4 5 6 7 8 9 |
$ gcloud container clusters create europe-2 \ --zone europe-north1-a \ --scopes "cloud-platform,storage-ro,logging-write,monitoring-write,service-control,service-management,https://www.googleapis.com/auth/ndev.clouddns.readwrite" $ gcloud container clusters get-credentials europe-2 \ --zone europe-north1-a $ kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin --user $(gcloud config get-value account) |
После выполнения всех действий проверяем:
1 |
$ gcloud container clusters list |
Вывод:
1 2 3 4 5 6 |
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS asia-2 asia-east1-a 1.9.7-gke.6 35.221.221.46 n1-standard-1 1.9.7-gke.6 3 RUNNING asia asia-southeast1-a 1.9.7-gke.6 35.197.139.197 n1-standard-1 1.9.7-gke.6 3 RUNNING europe-2 europe-north1-a 1.9.7-gke.6 35.228.203.204 n1-standard-1 1.9.7-gke.6 3 RUNNING europe europe-west2-a 1.9.7-gke.6 35.242.178.241 n1-standard-1 1.9.7-gke.6 3 RUNNING america us-central1-a 1.9.7-gke.6 35.188.203.7 n1-standard-1 1.9.7-gke.6 3 RUNNING |
Или в консоли GCP:
Федерация
Federation control plane управляет состоянием всех ваших кластеров. Панель управления может быть размещена внутри одного из ваших кластеров Kubernetes.
Даже если кластер c Control Plane не будет работать, другие кластеры независимы, поэтому они будут продолжать функционировать до тех пор, пока не вернется панель управления. Вы можете управлять кластерами отдельно! Это означает, что вам не нужно беспокоиться об одной точке отказа.
Теперь посмотрим какие контексты используются:
1 |
$ kubectl config get-contexts |
Вывод:
1 2 |
gke_federation_asia-east1-a_asia-2 gke_federation_asia-east1-a_asia-2 gke_federation_asia-east1-a_asia-2 * gke_federation_europe-north1-a_europe-2 gke_federation_europe-north1-a_europe-2 gke_federation_europe-north1-a_europe-2 |
Kubernetes Federation использует имя контекста для создания федерации, но она должна соответствовать спецификации RFC1123. Это означает, что вам нужно переименовать контекст. Вы можете сделать это со следующими командами:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
$ kubectl config set-context asia \ --cluster gke_federation_asia-southeast1-a_asia \ --user gke_federation_asia-southeast1-a_asia $ kubectl config delete-context \ gke_federation_asia-southeast1-a_asia $ kubectl config set-context europe \ --cluster gke_federation_europe-west2-a_europe \ --user gke_federation_europe-west2-a_europe $ kubectl config delete-context \ gke_federation_europe-west2-a_europe $ kubectl config set-context america \ --cluster gke_federation_us-central1-a_america \ --user gke_federation_us-central1-a_america $ kubectl config delete-context \ gke_federation_us-central1-a_america $ kubectl config set-context asia-2 \ --cluster gke_federation_asia-east1-a_asia-2 \ --user gke_federation_asia-east1-a_asia-2 $ kubectl config delete-context \ gke_federation_asia-east1-a_asia-2 $ kubectl config set-context europe-2 \ --cluster gke_federation_europe-north1-a_europe-2 \ --user gke_federation_europe-north1-a_europe-2 $ kubectl config delete-context \ gke_federation_europe-north1-a_europe-2 |
Проверяем контекст:
1 |
$ kubectl config get-contexts |
Вывод:
1 2 3 4 5 6 |
CURRENT NAME CLUSTER AUTHINFO NAMESPACE america gke_federation_us-central1-a_america gke_federation_us-central1-a_america asia gke_federation_asia-southeast1-a_asia gke_federation_asia-southeast1-a_asia asia-2 gke_federation_asia-east1-a_asia-2 gke_federation_asia-east1-a_asia-2 europe gke_federation_europe-west2-a_europe gke_federation_europe-west2-a_europe europe-2 gke_federation_europe-north1-a_europe-2 gke_federation_europe-north1-a_europe-2 |
Для создания федерации будем использовать kubefed. Но он работает только на линукс, на маке он не запускается, исправляем эту проблему с помощью docker
Для авторизации в kubernetes на google cloud используется google sdk. ~/.kube/config:
1 2 3 4 5 6 7 8 9 10 11 |
- name: gke_krusche-federation_asia-southeast1-a_asia user: auth-provider: config: access-token: ya29.GlwHBt-fKASzD91Uxp-mtfbMMHz94w cmd-args: config config-helper --format=json cmd-path: /Users/roman/work/google-cloud-sdk/bin/gcloud expiry: 2018-08-28 15:03:09 expiry-key: '{.credential.token_expiry}' token-key: '{.credential.access_token}' name: gcp |
В моем случае бинарный файл находится в моей домашней директории, kubefed использует те же конфигурационные файлы. Поэтому будем монтировать всю домашнюю директорию в docker контейнер:
Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 |
FROM centos:7 COPY bin/kubefed /usr/local/bin COPY repo/kubernetes.repo /etc/yum.repos.d/ RUN mkdir -p /Users/roman \ && yum install -y kubectl ENV HOME /Users/roman WORKDIR /Users/roman ENTRYPOINT ["kubefed"] |
Собираем docker image:
1 |
$ docker build --no-cache --rm -t k8s/kubefed . |
Прописываем alias:
1 |
alias kubefed='docker run -v "$HOME":/Users/roman k8s/kubefed' |
Инициализируем Федерацию:
1 2 3 4 |
$ kubefed init kfed \ --host-cluster-context=america \ --dns-zone-name="federation.com." \ --dns-provider="google-clouddns" |
Вывод:
1 2 3 4 5 6 7 |
Creating a namespace federation-system for federation system components... done Creating federation control plane service............. done Creating federation control plane objects (credentials, persistent volume claim)... done Creating federation component deployments... done Updating kubeconfig... done Waiting for federation control plane to come up................. done Federation API server is running at: 104.154.131.222 |
Подключаем кластеры к federation control plane:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
kubefed --context=kfed join asia \ --cluster-context=asia \ --host-cluster-context=america kubefed --context=kfed join europe \ --cluster-context=europe \ --host-cluster-context=america kubefed --context=kfed join america \ --cluster-context=america \ --host-cluster-context=america kubefed --context=kfed join asia-2 \ --cluster-context=asia-2 \ --host-cluster-context=america kubefed --context=kfed join europe-2 \ --cluster-context=europe-2 \ --host-cluster-context=america |
Вывод:
1 2 3 4 5 |
cluster "asia" created cluster "europe" created cluster "america" created cluster "asia-2" created cluster "europe-2" created |
Проверяем:
1 |
$ kubectl --context kfed get cluster |
Вывод:
1 2 3 4 5 6 |
NAME AGE america 58s asia 2m asia-2 46s europe 1m europe-2 36s |
Создаем default namespace:
1 |
$ kubectl --context=kfed create ns default |
Настройка и запуск приложения
Создаем глобальный статический IP адрес:
1 |
$ gcloud compute addresses create ingress --global |
Запускаем NGINX:
1 2 |
$ kubectl --context=kfed create deployment nginx --image=nginx:stable \ && kubectl --context=kfed scale deployment nginx --replicas=12 |
Проверяем:
Создаем NGINX Service:
1 2 |
$ kubectl --context=kfed create service nodeport nginx \ --tcp=80:80 --node-port=30036 |
Создаем файл ingress.yaml:
1 2 3 4 5 6 7 8 9 10 |
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: nginx annotations: kubernetes.io/ingress.global-static-ip-name: ingress spec: backend: serviceName: nginx servicePort: 80 |
Теперь развернем ingress:
1 |
kubectl --context=kfed create -f ingress.yaml |
Тогда создаем балансировщик руками:
Если все хорошо то должен открыться наш nginx.
Теперь напишем простенький веб-сайт, с картой мира что б проверить какой кластер нам отвечает. Можно из контейнеров проверять внешний IP но у Google все IP принадлежать Америке. Поэтому будем брать регион из названия кластера
Создаем location.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php $a = $_ENV[MY_NODE_NAME]; if (strpos($a, 'asia') !== false) { $continent = 'asia'; $image = 'asia.png'; } elseif (strpos($a, 'europe') !== false) { $continent = 'europe'; $image = 'europe.png'; } elseif (strpos($a, 'america') !== false) { $continent = 'North America'; $image = 'america.png'; } ?> |
Dockerfile:
1 2 3 4 |
FROM php:7.0-apache-stretch ADD data /data RUN cp -R /data/* /var/www/html \ && chown www-data -R /var/www/html/ |
Собираем image:
1 |
docker build --no-cache --rm -t wacken/location:nodename . |
Создаем deployment.yaml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx labels: app: nginx spec: replicas: 20 template: metadata: labels: app: nginx spec: containers: - env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName name: nginx image: "wacken/location:nodename" imagePullPolicy: IfNotPresent ports: - containerPort: 80 |
Применяем:
1 |
$ kubectl --context=kfed apply -f deployment.yaml |
Проверяем:
Теперь откроем наш балансировщик:
На этом все, спасибо за внимание