
Kubespray (ранее Kargo) — это набор Ansible ролей для установки и конфигурации системы оркестрации контейнерами Kubernetes. В качестве IaaS в этом случае могут выступать AWS, GCE, Azure, OpenStack или обычные виртуальные машины. Проект раньше назывался Kargo. Это проект с открытым исходным кодом и открытой моделью разработки, поэтому по желанию каждый может повлиять на его жизненный цикл.
На Хабре уже писали об установке Kubernetes с помощью Kubeadm, но в этом способе есть значительные недостатки: он до сих пор не поддерживает мультимастер конфигураций и, порой, не очень гибкий. Kubespray, хоть и использует Kubeadm под капотом, уже имеет функционал обеспечения высокой доступности как для мастера, так и для etcd на этапе инсталляции. О его сравнении с другими актуальными методами установки Kubernetes можно почитать по ссылке https://github.com/kubernetes-incubator/kubespray/blob/master/docs/comparisons.md
В этой статье мы создадим 5 серверов на ОС Ubuntu 16.04. В моем случае их перечень будет следующим:
192.168.20.10 k8s-m1.me 192.168.20.11 k8s-m2.me 192.168.20.12 k8s-m3.me 192.168.20.13 k8s-s1.me 192.168.20.14 k8s-s2.me
Добавляем их к /etc/hosts всех этих серверов, в том числе локальной системы, или же к dns-серверу. Фаервол и другие ограничения в сети этих хостов должны быть деактивированы. Кроме этого, необходимо разрешить IPv4 forwarding и каждый из хостов должен иметь свободный доступ к сети Интернет для загрузки docker-образов.
Копируем публичный rsa-ключ к каждому серверу из списка:
$ ssh-copy-id ubuntu@server.me
Указываем необходимого пользователя и ключ для подключения с локальной машины:
$ vim ~/.ssh/config ... Host *.me User ubuntu ServerAliveInterval 60 IdentityFile ~/.ssh/id_rsa
Где ubuntu — пользователь, от имени которого будет происходить подключение к серверу, a id_rsa — приватный ключ. Более того, этот пользователь нуждается в возможности выполнения команд sudo без пароля.
Клонируем репозиторий Kubespray:
$ git clone https://github.com/kubernetes-incubator/kubespray.git
После копируем директорию inventory для редактирования ее содержимого:
$ cp -r inventory my_inventory $ cd my_inventory
В качестве примера используем inventory.example:
$ mv inventory.example inventory
$ vim inventory k8s-m1.me ip=192.168.20.10 k8s-m2.me ip=192.168.20.11 k8s-m3.me ip=192.168.20.12 k8s-s1.me ip=192.168.20.13 k8s-s2.me ip=192.168.20.14 [kube-master] k8s-m1.me k8s-m2.me k8s-m3.me [etcd] k8s-m1.me k8s-m2.me k8s-m3.me [kube-node] k8s-s1.me k8s-s2.me [k8s-cluster:children] kube-node kube-master
Исходя из представленного выше, мы выполним установку HA инсталляции Kubernetes: etcd, хранилище параметров конфигурации кластера, будет состоять из 3-х узлов для присутствия кворума, а сервисы Kubernetes Master (kube-apiserver, controller-manager, scheduler и т.д.) будут продублированы трижды. Конечно, ничего не мешает вынести сервис etcd полностью отдельно.
На этом этапе хотелось бы немного подробнее рассказать о том, как реализован режим HA для мастеров. На каждом воркере Kubernetes (в нашем случае это k8s-s*.me) будет установлен Nginx в режиме балансировки, в upstream которого будут описаны все мастера Kubernetes:
stream { upstream kube_apiserver { least_conn; server kube-master_ip1:6443; server kube-master_ip2:6443; server kube-master_ip3:6443; } server { listen 127.0.0.1:6443; proxy_pass kube_apiserver; proxy_timeout 10m; proxy_connect_timeout 1s; }
Соответственно в случае падения одного из мастеров, Nginx исключит его из upstream и прекратит пересылать запросы на такой сервер.

Такая схема позволяет исключить единую точку отказа: в случае падения мастера его работу примет на себя другой мастер, а ответственный за переадресацию запросов Nginx работает на каждом воркере.
На этапе установки кластера есть возможность отключить этот внутренний балансировщик и уже заботиться обо всем самостоятельно. Это может быть, например, какой-то сторонний Nginx или HAProxy. Однако не стоит забывать, что для обеспечения высокой доступности они должны работать в паре, между членами которой при необходимости должен мигрировать Virtual IP. VIP может быть реализован с помощью различных технологий таких, как Keepalived, Heartbeat, Pacemaker и т.п.
На мастере kube-apiserver работает одновременно на 2-х портах: локальном 8080 без шифрования (для служб, работающих на одном сервере) и внешнем HTTPS 6443. Последний, как я уже упомянул, используется для связи с воркерами и может пригодиться, если сервисы одного мастера (kubelet, kube-proxy и др) необходимо вынести на другие хосты.
Продолжим работу по созданию тестового кластера. Отредактируем group_vars/all.yml:
$ vim group_vars/all.yml ... bootstrap_os: ubuntu ... kubelet_load_modules: true
Кроме Ubuntu 16.04 Kubespray также поддерживает инсталляцию на узлы с CoreOS, Debian Jessie, CentOS/RHEL 7, то есть на все основные актуальные дистрибутивы.
При необходимости следует также заглянуть в group_vars/k8s-cluster.yml, где можно указать необходимую версию Kubernetes, которая будет проинсталлирована, выбрать плагин для оверлейной сети (по-умолчанию это calico, но доступны и другие варианты), установить efk (elasticsearch/fluentd/kibana), helm, istio, netchecker и т.п.
Также рекомендую посмотреть roles/kubernetes/preinstall/tasks/verify-settings.yml. Здесь находятся базовые проверки, которые будут выполнены перед началом установки Kubernetes. Например, проверки наличия достаточного количества оперативной памяти (на данный момент, это не менее 1500MB для мастеров и 1000MB для нод), количества etcd серверов (для обеспечения кворума их должно быть нечетное количество) и прочее. В последних релизах Kubespray появилась дополнительное требование по swap-у: он должен быть выключен на всех узлах кластера.
Если Ansible еще отсутствует в локальной системе, установим его вместе с модулем netaddr:
# pip install ansible # pip install netaddr
Важно обратить внимание на то, что модуль netaddr и ansible должны работать с той же версией Python.
После этого можем приступать к установке кластера Kubernetes:
$ ansible-playbook -i my_inventory/inventory cluster.yml -b -v
Как вариант, rsa-ключ и пользователя для подключения можно передать аргументами, например:
$ ansible-playbook -u ubuntu -i my_inventory/inventory cluster.yml -b -v --private-key=~/.ssh/id_rsa
Обычно установка кластера занимает около 15-20 мин, но все зависит также от вашего железа. После мы можем проверить корректно ли все работает, для чего необходимо подключиться к любому хосту кластера и выполнить следующее:
root@k8s-m1:~# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-m1 Ready master 28m v1.8.4+coreos.0 k8s-m2 Ready master 28m v1.8.4+coreos.0 k8s-m3 Ready master 28m v1.8.4+coreos.0 k8s-s1 Ready node 28m v1.8.4+coreos.0 k8s-s2 Ready node 28m v1.8.4+coreos.0
root@k8s-m1:~# kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-node-2z6jz 1/1 Running 0 27m kube-system calico-node-6d6q6 1/1 Running 0 27m kube-system calico-node-96rgg 1/1 Running 0 27m kube-system calico-node-nld9z 1/1 Running 0 27m kube-system calico-node-pjcjs 1/1 Running 0 27m kube-system kube-apiserver-k8s-m1 1/1 Running 0 27m ... kube-system kube-proxy-k8s-s1 1/1 Running 0 26m kube-system kube-proxy-k8s-s2 1/1 Running 0 27m kube-system kube-scheduler-k8s-m1 1/1 Running 0 28m kube-system kube-scheduler-k8s-m2 1/1 Running 0 28m kube-system kube-scheduler-k8s-m3 1/1 Running 0 28m kube-system kubedns-autoscaler-86c47697df-4p7b8 1/1 Running 0 26m kube-system kubernetes-dashboard-85d88b455f-f5dm4 1/1 Running 0 26m kube-system nginx-proxy-k8s-s1 1/1 Running 0 28m kube-system nginx-proxy-k8s-s2 1/1 Running 0 28m
Как видим, по-умолчанию, сразу была установлена и веб-панель kubernetes-dashboard. Детали относительно ее работы можно найти по следующей ссылке https://github.com/kubernetes/dashboard
Исключительно для базовой проверки выльем под с двумя контейнерами:
$ vim first-pod.yaml apiVersion: v1 kind: Pod metadata: name: first-pod spec: containers: - name: sise image: mhausenblas/simpleservice:0.5.0 ports: - containerPort: 9876 resources: limits: memory: "64Mi" cpu: "500m" - name: shell image: centos:7 command: - "bin/bash" - "-c" - "sleep 10000"
$ kubectl apply -f first-pod.yaml pod "first-pod" created
$ kubectl get pods NAME READY STATUS RESTARTS AGE first-pod 2/2 Running 0 16s
$ kubectl exec first-pod -c sise -i -t -- bash [root@first-pod /]# curl localhost:9876/info {"host": "localhost:9876", "version": "0.5.0", "from": "127.0.0.1"}
Это было тестовое приложение на языке Python с ресурса http://kubernetesbyexample.com/.
Довольно странно, но в качестве системы контейнеризации был установлен Docker 17.03.1-ce, хотя в официальной документации упоминается, что лучше всего использовать именно версию 1.13. Версия Docker, которая будет установлена, описанная в roles/docker/defaults/main.yml и, теоретически, ее можно перезаписать в файлах конфигурации выше или передать значение аргументом.
Ansible скрипты Kubespray также поддерживают масштабирование к-ва узлов кластера. Для этого обновим inventory, в котором добавим новую ноду (worker):
$ vim my_inventory/inventory k8s-m1.me ip=192.168.20.10 k8s-m2.me ip=192.168.20.11 k8s-m3.me ip=192.168.20.12 k8s-s1.me ip=192.168.20.13 k8s-s2.me ip=192.168.20.14 k8s-s3.me ip=192.168.20.15 [kube-master] k8s-m1.me k8s-m2.me k8s-m3.me [etcd] k8s-m1.me k8s-m2.me k8s-m3.me [kube-node] k8s-s1.me k8s-s2.me k8s-s3.me [k8s-cluster:children] kube-node kube-master
Конечно, узел k8s-s3.me также должен быть соответствующим образом настроен, как и предыдущие ноды. Теперь можем запускать масштабирование кластера:
$ ansible-playbook -i my_inventory/inventory scale.yml -b -v
Согласно документации Kubespray, для этого можно использовать и предварительную процедуру с cluster.yml, однако с scale.yml это займет значительно меньше времени. В результате сейчас можем наблюдать новый узел через kubectl:
$ kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-m1 Ready master 6h v1.8.4+coreos.0 k8s-m2 Ready master 6h v1.8.4+coreos.0 k8s-m3 Ready master 6h v1.8.4+coreos.0 k8s-s1 Ready node 6h v1.8.4+coreos.0 k8s-s2 Ready node 6h v1.8.4+coreos.0 k8s-s3 Ready node 19m v1.8.4+coreos.0
Вот и все. Так же эту статью можно прочитать на украинском языке по адресу http://blog.ipeacocks.info/2017/12/kubernetes-part-iv-setup-ha-cluster.html
PS. Обо всех ошибках лучше сразу писать в приват — оперативно исправим.
Ссылки
kubespray.io
github.com/kubernetes-incubator/kubespray
github.com/kubernetes-incubator/kubespray/blob/master/docs/getting-started.md
github.com/kubernetes-incubator/kubespray/blob/master/docs/ansible.md
github.com/kubernetes-incubator/kubespray/blob/master/docs/ha-mode.md
dickingwithdocker.com/2017/08/deploying-kubernetes-vms-kubespray
medium.com/@olegsmetanin/how-to-setup-baremetal-kubernetes-cluster-with-kubespray-and-deploy-ingress-controller-with-170cdb5ac50d
github.com/kubernetes-incubator/kubespray
github.com/kubernetes-incubator/kubespray/blob/master/docs/getting-started.md
github.com/kubernetes-incubator/kubespray/blob/master/docs/ansible.md
github.com/kubernetes-incubator/kubespray/blob/master/docs/ha-mode.md
dickingwithdocker.com/2017/08/deploying-kubernetes-vms-kubespray
medium.com/@olegsmetanin/how-to-setup-baremetal-kubernetes-cluster-with-kubespray-and-deploy-ingress-controller-with-170cdb5ac50d
