Здравствуйте уважаемые читатели Хабра!
Этой публикацией я хочу начать цикл статей про развертывание полноценной среды оркестрации контейнерами Kubernetes, которая будет готова к эксплуатации и запуску приложений.
Я хочу рассказать не просто про то, как развернуть кластер Kubernetes, но и про то, как настроить кластер после установки, как добавить в него удобных инструментов и дополнений для использования микросервисной архитектуры.
Данный цикл будет состоять минимум из четырех статей:
- В первой из них я расскажу, как на голое железо установить отказоустойчивый кластер kubernetes, как установить стандартный дашборд и настроить доступ к нему, как установить ingress контроллер.
- Во второй статье я расскажу, как развернуть отказоустойчивый кластер Ceph и как начать использовать RBD тома в нашем кластере Kubernetes. Также немного затрону остальные виды стораджей (storages) и более подробно рассмотрю local-storage. Дополнительно расскажу, как на базе созданного кластера CEPH организовать отказоустойчивое хранилище S3
- В третьей статье я расскажу, как в нашем кластере Kubernetes развернуть отказоустойчивый кластер MySql, а именно — Percona XtraDB Cluster on Kubernetes. И также опишу все проблемы с которыми мы столкнулись, когда решили перенести БД в kubernetes.
- В четвертой статье я постараюсь собрать все вместе и рассказать, как задеплоить и запустить приложение, которое будет использовать БД и тома ceph. Расскажу, как настроить ingress контроллер для доступа к нашему приложению извне и сервис автоматического заказа сертификатов от Let's Encrypt. Еще — как автоматически поддерживать данные сертификаты в актуальном состоянии. Также немного затронем тему RBAC в контексте доступа до панели управления. Расскажу в двух словах про Helm и его установку.
Если Вам интересна информация данных публикаций, то — добро пожаловать !
Вступление:
Для кого предназначены данные статьи? В первую очередь, для тех, кто только начинает свой путь в изучении Kubernetes. Также данный цикл будет полезен для инженеров, которые думают переходить от монолита к микросервисам. Все описанное — это мой опыт, в том числе полученный и при переводе нескольких проектов из монолита в Kubernetes. Возможно, что какие-то части публикаций будут интересны и опытным инженерам.
Что я не буду подробно рассматривать в данной серии публикаций:
- подробно объяснять, что такое примитивы kubernetes, такие как: pod, deployment, service, ingress и тд.
- CNI (Container Networking Interface) я рассмотрю очень поверхностно, мы используем callico поэтому другие решения, я только перечислю.
- процесс сборки docker образов.
- процессы CI\CD. (Возможно отдельной публикацией, но после всего цикла)
- helm; про него написано уже достаточно много, я затрону лишь процесс его инсталляции в кластер и настройку клиента.
Что я хочу рассмотреть подробно:
- пошаговый процесс развертывания кластера Kubernetes. Я буду использовать kubeadm. Но при этом я подробно шаг за шагом рассмотрю процесс инсталляции кластера на голое железо, различные виды инсталляции ETCD, составление конфигфайлов для kube admina. Постараюсь разъяснить все варианты балансировки для Ingress контроллера и отличие в разнообразных схемах доступа worknodes до api сервера.
Я знаю, что сегодня для развертывания kubernetes есть много прекрасных инструментов, например, kubespray или тот же rancher. Возможно, кому-то будет более удобно использовать их. Но, я думаю, найдется немало инженеров которые захотят рассмотреть вопрос более детально. - терминологию CEPH и пошаговую инсталляцию кластера CEPH, а также пошаговую инструкцию подключение хранилища ceph к созданному Kubernetes кластеру.
- local-storages, подключение к кластеру kubernetes, а также отличия от подключений типа hostpath и тд.
- kubernetes операторы и развертывание Percona XtraDB Cluster с помощью оператора, а также постараюсь рассказать про плюсы и минусы такого решения после полугодового опыта использования в продакшене. А также немного поделюсь планами по доработке оператора от percona.
Оглавление:
- Cписок хостов, ресурсы хостов, версии ОС и ПО
- Схема HA кластера kubernetes
- До начала работы или before you begin
- Заполняем файл create-config.sh
- Обновление ядра ОС
- Подготовка нод Установка Kubelet, Kubectl, Kubeadm и docker
- Установка ETCD (различные варианты)
- Запуск первого мастера kubernetes
- Установка CNI Callico
- Запуск второго и третьего мастера kubernetes
- Добавляем worker нод в кластер
- Устанавливаем haproxy на worker ноды для HA
- Установка Ingress контроллера
- Установка Web UI (Dashboard)
Список и назначение хостов
Все ноды моего кластера будут располагаться на виртуальных машинах с предустановленной системой Debian 9 stretch c ядром 4.19.0-0.bpo.5-amd64. Для виртуализации я использую Proxmox VE.
Таблица ВМ и их ТТХ:
Name | IP адрес | Comment | CPU | MEM | DISK1 | DISK2 |
---|---|---|---|---|---|---|
master01 | 10.73.71.25 | master node | 4vcpu | 4Gb | HDD | --- |
master02 | 10.73.71.26 | master node | 4vcpu | 4Gb | HDD | --- |
master03 | 10.73.71.27 | master node | 4vcpu | 4Gb | HDD | --- |
worknode01 | 10.73.75.241 | work node | 4vcpu | 4Gb | HDD | SSD |
worknode02 | 10.73.75.242 | work node | 4vcpu | 4Gb | HDD | SSD |
worknode03 | 10.73.75.243 | work node | 4vcpu | 4Gb | HDD | SSD |
Не обязательно, что у Вас должна быть именно такая конфигурация машин, но все таки я советую придерживаться рекомендациям официальной документации, а для мастеров увеличить количество оперативной памяти минимум до 4Гб. Забегая вперед скажу, что при более маленьком количестве, я ловил глюки в работе CNI Callico
Ceph тоже достаточно прожорлив к памяти и производительности дисков.
Наши продакшн инсталляции работают без виртуализации на голом железе, но я знаю много примеров, где хватало и виртуальных машин с достаточно скромными ресурсами. Все зависит от ваших потребностей и нагрузок.
Список и версии ПО
Name | Version |
---|---|
Kubernetes | 1.15.1 |
Docker | 19.3.1 |
Kubeadm, начиная с версии 1.14, перестал поддерживать API версии v1alpha3 и полностью перешел на API версии v1beta1, которую будет поддерживать в ближайшем будущем, поэтому в статье я буду рассказывать только про v1beta1.
Итак, мы считаем, что у Вы подготовили машины для kubernetes кластера. Они все доступны друг другу по сети, имеют "выход" в интернет и на них установлена "чистая" операционная система.
Для каждого шага установки я буду уточнять, на каких именно машинах выполняется команда или блок команд. Все команды выполнять из-под пользователя root, если не указано иного.
Все файлы конфигурации, а также скрипт для их подготовки доступны для скачивания в моем github
Итак, начнем.
Схема HA кластера kubernetes
Примерная схема HA кластера. Художник из меня так себе, если честно, но постараюсь объяснить в двух словах и достаточно упрощенно, особо не углубляясь в теорию.
Итак, наш кластер будет состоять из трех master нод и трех worker нод. На каждой master ноде kubernetes у нас будет работать etcd (на схеме зеленые стрелочки) и служебные части kubernetes; назовем их обобщенно — kubeapi.
Через кластер etcd master ноды обмениваются состоянием кластера kubernetes. Эти же адреса я укажу как точки входа ingress контроллера для внешнего трафика (на схеме красные стрелочки)
На worker нодах у нас работает kubelet, который связывается с api сервером kubernetes через haproxy установленным локально на каждой worker ноде. В качестве адреса api сервера для kubelet я буду использовать локалхост 127.0.0.1:6443, а haproxy по roundrobin будет раскидывать запросы по трем master нодам, также он будет проверять доступность master нод. Данная схема позволит нам создать HA, и в случае выхода из строя одной из master нод, worker ноды будут спокойно посылать запросы на две оставшихся в живых master ноды.
Перед началом работы
Перед началом работы на каждую ноду кластера поставим пакеты, которые нам понадобятся для работы:
apt-get update && apt-get install -y curl apt-transport-https git
На master ноды скопируем репозиторий с шаблонами конфигов
sudo -i
git clone https://github.com/rjeka/kubernetes-ceph-percona.git
Проверим, что ip адрес хостов на мастерах соответствует тому, на котором будет слушать API сервер kubernetes
hostname && hostname -i
master01
10.73.71.25
и так для всех master нод.
Обязательно отключите SWAP, иначе kubeadm будет выдавать ошибку
[ERROR Swap]: running with swap on is not supported. Please disable swap
Отключить можно командой
swapoff -a
Не забудьте закомментировать в файле /etc/fstab
Заполняем файл create-config.sh
Для автоматического заполнения конфигов, нужных для установки кластера kubernetes, я накидал небольшой скриптик create-config.sh. Вам нужно заполнить в нем буквально 8 строчек. Указать IP адреса и hostname своих мастеров. А также указать etcd tocken, можете его не менять. Я приведу ниже ту часть скрипта в которой нужно сделать изменения.
#!/bin/bash
#######################################
# all masters settings below must be same
#######################################
# master01 ip address
export K8SHA_IP1=10.73.71.25
# master02 ip address
export K8SHA_IP2=10.73.71.26
# master03 ip address
export K8SHA_IP3=10.73.71.27
# master01 hostname
export K8SHA_HOSTNAME1=master01
# master02 hostname
export K8SHA_HOSTNAME2=master02
# master03 hostname
export K8SHA_HOSTNAME3=master03
#etcd tocken:
export ETCD_TOKEN=9489bf67bdfe1b3ae077d6fd9e7efefd
#etcd version
export ETCD_VERSION="v3.3.10"
Обновление ядра ОС
Данный шаг является необязательным, так как ядро нужно будем обновлять из back портов, и делаете Вы это на свой страх и риск. Возможно, Вы никогда столкнетесь с данной проблемой, а если и столкнетесь, то обновить ядро можно и после разворачивания kubernetes. В общем, решать Вам.
Обновление ядра требуется для устранения старого бага docker, который исправили только в ядре linux версии 4.18. Более подробно про этот баг можно почитать вот здесь. Выражался баг в периодическом зависании сетевого интерфейса на нодах kubernetes c ошибкой:
waiting for eth0 to become free. Usage count = 1
У меня после установки ОС было ядро версии 4.9
uname -a
Linux master01 4.9.0-7-amd64 #1 SMP Debian 4.9.110-3+deb9u2 (2018-08-13) x86_64 GNU/Linux
На каждой машине для kubernetes выполняем
Шаг №1
Добавляем back ports в source list
echo deb http://ftp.debian.org/debian stretch-backports main > /etc/apt/sources.list
apt-get update
apt-cache policy linux-compiler-gcc-6-x86
Шаг №2
Установка пакетов
apt install -y -t stretch-backports linux-image-amd64 linux-headers-amd64
Шаг №3
Перезагрузка
reboot
Проверяем что все ОК
uname -a
Linux master01 4.19.0-0.bpo.5-amd64 #1 SMP Debian 4.19.37-4~bpo9+1 (2019-06-19) x86_64 GNU/Linux
Подготовка нод Установка Kubelet, Kubectl, Kubeadm и docker
Установка Kubelet, Kubectl, Kubeadm
Ставим на все ноды кластера, согласно документации kubernetes
apt-get update && apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
Установка Docker
Устанавливаем docker по инструкции из документации
apt-get remove docker docker-engine docker.io containerd runc
apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
apt-key fingerprint 0EBFCD88
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io
git clone https://github.com/rjeka/kubernetes-ceph-percona.git
cd kubernetes-ceph-percona/playbooks
vim masters.ini
В группе masters прописываем ip мастеров.
В группе workers прописываем ip рабочих нод.
#Если sudo c паролем
ansible-playbook -i hosts.ini kubelet.yaml -K
ansible-playbook -i hosts.ini docker.yaml -K
#Если sudo безпарольный
ansible-playbook -i hosts.ini kubelet.yaml
ansible-playbook -i hosts.ini docker.yaml
Если Вы по каким либо причинам не хотите использовать docker, есть возможность использовать любые CRI. Почитать об этом можно, например тут, но эта тема выходит за рамки данной статьи.
Установка ETCD
Не буду сильно углубляться в теорию, в двух словах: etcd — это распределенное хранилище типа «ключ-значение» c открытым исходным кодом. etcd написан на GO и используется в kubernetes фактически, как база данных для хранения состояния кластера. Для более подробного ознакомления можно почитать в документации kubernetes.
etcd можно устанавливать многими способами. Можно устанавливать локально и запускать, как демона, можно запускать в docker контейнерах, можно устанавливать даже как поды кубернетеса. Можно устанавливать руками, а можно установить с помощью kubeadm (я данный способ не пробовал). Можно устанавливать на машины кластера или отдельные сервера.
Я буду устанавливать etcd локально на master ноды и запускать, как демон, через systemd, а также рассмотрю установку в докере. Я использую etcd без TLS, если вам нужен TLS обратитесь к документации самого etcd или kubernetes
Также в моем github будет выложен ansible-playbook для установки etcd с запуском через systemd.
Вариант №1
Установка локально, запуск через systemd
На всех мастерах: (на рабочих нодах кластера этот шаг выполнять не нужно)
Шаг №1
Скачиваем и распаковываем архив с etcd:
mkdir archives
cd archives
export etcdVersion=v3.3.10
wget https://github.com/coreos/etcd/releases/download/$etcdVersion/etcd-$etcdVersion-linux-amd64.tar.gz
tar -xvf etcd-$etcdVersion-linux-amd64.tar.gz -C /usr/local/bin/ --strip-components=1
Шаг №2
Создаем конфиг файл для ETCD
cd ..
./create-config.sh etcd
Скрипт принимает на вход значение etcd, и формирует конфиг файл в каталоге etcd. После работы скрипта готовый конфиг файл будет находится в каталоге etcd.
Для всех других конфигов, скрипт работает по тому же принципу. Принимает на вход какое-то значение и создает конфиг в определенном каталоге.
Шаг №3
Запускаем etcd кластер и проверяем его работоспособность
systemctl start etcd
Проверяем работоспособность демона
systemctl status etcd
● etcd.service - etcd
Loaded: loaded (/etc/systemd/system/etcd.service; disabled; vendor preset: enabled)
Active: active (running) since Sun 2019-07-07 02:34:28 MSK; 4min 46s ago
Docs: https://github.com/coreos/etcd
Main PID: 7471 (etcd)
Tasks: 14 (limit: 4915)
CGroup: /system.slice/etcd.service
└─7471 /usr/local/bin/etcd --name master01 --data-dir /var/lib/etcd --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --advertise-client-urls http://10.73.71.25:2379,http://10.73.71.
Jul 07 02:34:28 master01 etcd[7471]: b11e73358a31b109 [logterm: 1, index: 3, vote: 0] cast MsgVote for f67dd9aaa8a44ab9 [logterm: 2, index: 5] at term 554
Jul 07 02:34:28 master01 etcd[7471]: raft.node: b11e73358a31b109 elected leader f67dd9aaa8a44ab9 at term 554
Jul 07 02:34:28 master01 etcd[7471]: published {Name:master01 ClientURLs:[http://10.73.71.25:2379 http://10.73.71.25:4001]} to cluster d0979b2e7159c1e6
Jul 07 02:34:28 master01 etcd[7471]: ready to serve client requests
Jul 07 02:34:28 master01 etcd[7471]: serving insecure client requests on [::]:4001, this is strongly discouraged!
Jul 07 02:34:28 master01 systemd[1]: Started etcd.
Jul 07 02:34:28 master01 etcd[7471]: ready to serve client requests
Jul 07 02:34:28 master01 etcd[7471]: serving insecure client requests on [::]:2379, this is strongly discouraged!
Jul 07 02:34:28 master01 etcd[7471]: set the initial cluster version to 3.3
Jul 07 02:34:28 master01 etcd[7471]: enabled capabilities for version 3.3
lines 1-19
И работоспособность самого кластера:
etcdctl cluster-health
member 61db137992290fc is healthy: got healthy result from http://10.73.71.27:2379
member b11e73358a31b109 is healthy: got healthy result from http://10.73.71.25:2379
member f67dd9aaa8a44ab9 is healthy: got healthy result from http://10.73.71.26:2379
cluster is healthy
etcdctl member list
61db137992290fc: name=master03 peerURLs=http://10.73.71.27:2380 clientURLs=http://10.73.71.27:2379,http://10.73.71.27:4001 isLeader=false
b11e73358a31b109: name=master01 peerURLs=http://10.73.71.25:2380 clientURLs=http://10.73.71.25:2379,http://10.73.71.25:4001 isLeader=false
f67dd9aaa8a44ab9: name=master02 peerURLs=http://10.73.71.26:2380 clientURLs=http://10.73.71.26:2379,http://10.73.71.26:4001 isLeader=true
С github клонируем репозиторий с кодом на машину, с которой вы будете запускать плейбук. Данная машина должна иметь доступ ssh по ключу на мастера нашего будущего кластера.
git clone https://github.com/rjeka/kubernetes-ceph-percona.git
cd kubernetes-ceph-percona/playbooks
vim masters.ini
В группе masters прописываем ip мастеров.
etcd_version — версия etcd. Посмотреть можно на страничке etcd в github. На момент написания статьи была версия v3.3.13 я использую v3.3.10.
etcdToken — можете оставить такой же, или сгенерировать свой.
Запускаем плейбук командой
#Если sudo c паролем
ansible-playbook -i hosts.ini -l masters etcd.yaml -K
BECOME password: <sudo пароль>
#Если sudo безпарольный
ansible-playbook -i hosts.ini -l masters etcd.yaml
Если вы хотите запустить etcd в докере, то под спойлером инструкция.
Данные команды нужно выполнить на всех мастер нодах кластера.
С github клонируем репозиторий с кодом
git clone https://github.com/rjeka/kubernetes-ceph-percona.git
cd kubernetes-ceph-percona
etcd_version — версия etcd. Посмотреть можно на страничке etcd в github. На момент написания статьи была версия v3.3.13 я использую v3.3.10.
etcdToken — можете оставить такой же, или сгенерировать свой.
Ставим docker-compose
apt-get install -y docker-compose
Генерируем конфиг
./create-config.sh docker
Запускаем установку кластера etcd в докере
docker-compose --file etcd-docker/docker-compose.yaml up -d
Проверяем что контейнеры поднялись
docker ps
И статус кластера etcd
root@master01:~/kubernetes-ceph-percona# docker exec -ti etcd etcdctl cluster-health
member 61db137992290fc is healthy: got healthy result from http://10.73.71.27:2379
member b11e73358a31b109 is healthy: got healthy result from http://10.73.71.25:2379
member f67dd9aaa8a44ab9 is healthy: got healthy result from http://10.73.71.26:2379
cluster is healthy
root@master01:~/kubernetes-ceph-percona# docker exec -ti etcd etcdctl member list
61db137992290fc: name=etcd3 peerURLs=http://10.73.71.27:2380 clientURLs=http://10.73.71.27:2379,http://10.73.71.27:4001 isLeader=false
b11e73358a31b109: name=etcd1 peerURLs=http://10.73.71.25:2380 clientURLs=http://10.73.71.25:2379,http://10.73.71.25:4001 isLeader=true
f67dd9aaa8a44ab9: name=etcd2 peerURLs=http://10.73.71.26:2380 clientURLs=http://10.73.71.26:2379,http://10.73.71.26:4001 isLeader=false
Если что то пошло не так то
docker logs etcd
Запуск первого мастера kubernetes
Первым делом нам нужно сгенерировать конфиг для kubeadmin
./create-config.sh kubeadm
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 10.73.71.25 #Адрес на котором слушает API-сервер
---
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: stable #Версия кластера которую мы будем устанавливать
apiServer: #Список хостов для которых kubeadm генерирует сертификаты
certSANs:
- 127.0.0.1
- 10.73.71.25
- 10.73.71.26
- 10.73.71.27
controlPlaneEndpoint: 10.73.71.25 #адрес мастера или балансировщика нагрузки
etcd: #адреса кластера etc
external:
endpoints:
- http://10.73.71.25:2379
- http://10.73.71.26:2379
- http://10.73.71.27:2379
networking:
podSubnet: 192.168.0.0/16 # подсеть для подов, у каждого CNI она своя.
Почитать про подсети CNI можно в документации kubernetes
Это минимально рабочий конфиг. Для кластера с тремя мастерами Вы можете изменять его под конфигурацию своего кластера. Например, если Вы хотите использовать 2 мастера, то просто укажите в certSANs два адреса.
Все параметра конфига можно найти в описании API kubeadm.
Инициируем первый мастер
kubeadm init --config=kubeadmin/kubeadm-init.yaml
Если kubeadm отработает без ошибок, то на выходе мы получим примерно следующий вывод:
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
kubeadm join 10.73.71.25:6443 --token ivwoap.259retezqf34amx8 \
--discovery-token-ca-cert-hash sha256:b5c93e32457c8e6478782ff62e8ef77acf72738dda59cd603cdf4821abe12ca3 \
--control-plane
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 10.73.71.25:6443 --token ivwoap.259retezqf34amx8 \
--discovery-token-ca-cert-hash sha256:b5c93e32457c8e6478782ff62e8ef77acf72738dda59cd603cdf4821abe12ca3
Установка CNI Calico
Пришло время установить сеть, в которой будут работать наши поды. Я использую calico, ее и будем ставить.
А для начала настроим доступ для kubelet. Все команды выполняем на master01
Если вы работаете из-под root
export KUBECONFIG=/etc/kubernetes/admin.conf
Если из-под простого пользователя
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Также Вы можете управлять кластером со своего ноутбука или любой локальной машины. Для этого скопируйте файл /etc/kubernetes/admin.conf на свой ноутбук или любую другую машину в $HOME/.kube/config
Ставим CNI согласно документации kubernetes
kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml
Ждем, пока все поды поднимутся
watch -n1 kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-kube-controllers-59f54d6bbc-psr2z 1/1 Running 0 96s
kube-system calico-node-hm49z 1/1 Running 0 96s
kube-system coredns-5c98db65d4-svcx9 1/1 Running 0 77m
kube-system coredns-5c98db65d4-zdlb8 1/1 Running 0 77m
kube-system kube-apiserver-master01 1/1 Running 0 76m
kube-system kube-controller-manager-master01 1/1 Running 0 77m
kube-system kube-proxy-nkdqn 1/1 Running 0 77m
kube-system kube-scheduler-master01 1/1 Running 0 77m
Запуск второго и третьего мастера kubernetes
Перед тем, как запустить master02 и master03, нужно с master01 скопировать сертификаты, которые сгенерировал kubeadm при создании кластера. Я буду копировать через scp
На master01
export master02=10.73.71.26
export master03=10.73.71.27
scp -r /etc/kubernetes/pki $master02:/etc/kubernetes/
scp -r /etc/kubernetes/pki $master03:/etc/kubernetes/
На master02 и master03
Создаем конфиг для kubeadm
./create-config.sh kubeadm
И добавляем в кластер master02 и master03
kubeadm init --config=kubeadmin/kubeadm-init.yaml
В продакшене я использую kubernetes v1.13.5 и calico v3.3. И у меня таких глюков не было.
Но при подготовке статьи и использовании версии stable (на момент написания статьи это была v1.15.1 kubernetes и версия 3.8 callico) я столкнулся с проблемой, которая выражалась в ошибки старта CNI
root@master01:~/kubernetes-ceph-percona# kubectl get pods -A -w
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-kube-controllers-658558ddf8-t6gfs 0/1 ContainerCreating 0 11s
kube-system calico-node-7td8g 1/1 Running 0 11s
kube-system calico-node-dthg5 0/1 CrashLoopBackOff 1 11s
kube-system calico-node-tvhkq 0/1 CrashLoopBackOff 1 11s
Это глюк calico daemon set, в том случае, когда у сервера несколько сетевых интерфейсов
На githab есть issue по данному глюку https://github.com/projectcalico/calico/issues/2720
Решается редактированием daemon set calico-node и добавлением в env параметра IP_AUTODETECTION_METHOD
kubectl edit -n kube-system ds calico-node
добавляем параметр IP_AUTODETECTION_METHOD с именем Вашего интерфейса, на котором работает мастер; в моем случае это ens19
- name: IP_AUTODETECTION_METHOD
value: ens19
Проверяем, что все ноды кластера стартовали и работают
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready master 28m v1.15.1
master02 Ready master 26m v1.15.1
master03 Ready master 18m v1.15.1
И что жива calica
# kubectl get pods -A -o wide | grep calico
kube-system calico-kube-controllers-59f54d6bbc-5lxgn 1/1 Running 0 27m
kube-system calico-node-fngpz 1/1 Running 1 24m
kube-system calico-node-gk7rh 1/1 Running 0 8m55s
kube-system calico-node-w4xtt 1/1 Running 0 25m
Добавляем worker ноды в кластер
На данный момент у нас работает кластер, в котором запущены три master ноды. Но master ноды — это машины, на которых работает api, scheduler и прочие сервисы кластера kubernetes. Для того, чтобы мы могли запускать свои поды, нам нужны так называемые worker ноды.
Если Вы ограничены в ресурсах, то можно запускать поды и на master нодах.Но я лично не советую так делать.
Для того, чтобы разрешить запуск подов на master нодах, выполните следующую команду на любом из мастеров
kubectl taint nodes --all node-role.kubernetes.io/master-
Устанавливаем на worker ноды kubelet, kubeadm, kubectl и докер как на master нодах
apt-get update && apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
Установка Docker
Устанавливаем docker по инструкции из документации
apt-get remove docker docker-engine docker.io containerd runc
apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
apt-key fingerprint 0EBFCD88
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io
git clone https://github.com/rjeka/kubernetes-ceph-percona.git
cd kubernetes-ceph-percona/playbooks
vim masters.ini
В группе masters прописываем ip мастеров.
В группе workers прописываем ip рабочих нод.
#Если sudo c паролем
ansible-playbook -i hosts.ini kubelet.yaml -K
ansible-playbook -i hosts.ini docker.yaml -K
#Если sudo безпарольный
ansible-playbook -i hosts.ini kubelet.yaml
ansible-playbook -i hosts.ini docker.yaml
Теперь пора время вернуться к той строчке, которую нам сгенерировал kubeadm при установке мастер ноды.
У меня она выглядит так.
kubeadm join 10.73.71.25:6443 --token ivwoap.259retezqf34amx8 \
--discovery-token-ca-cert-hash sha256:b5c93e32457c8e6478782ff62e8ef77acf72738dda59cd603cdf4821abe12ca3
Нужно выполнить данную команду на каждой worker ноде.
Если Вы не записали токен, то можно сгенерировать новый
kubeadm token create --print-join-command --ttl=0
После того, как kubeadm отработает, Ваша новая нода введена в кластер и готова для работы
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
Теперь посмотрим на результат
root@master01:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready master 10d v1.15.1
master02 Ready master 10d v1.15.1
master03 Ready master 10d v1.15.1
worknode01 Ready <none> 5m44s v1.15.1
worknode02 Ready <none> 59s v1.15.1
worknode03 Ready <none> 51s v1.15.1
Устанавливаем haproxy на worknodes
Теперь мы имеем рабочий кластер с тремя master нодами и тремя worker нодами.
Проблема в том, что сейчас наши worker ноды не имеют HA режима.
Если посмотреть на конфиг файл kubelet, то мы увидим, что наши worker ноды обращаются только к одной master ноде из трех.
root@worknode01:~# cat /etc/kubernetes/kubelet.conf | grep server:
server: https://10.73.71.27:6443
В моем случае это master03. При данной конфигурации, в случае падения master03, worker нода потеряет связь с API сервером кластера. Чтобы наш кластер стал полностью HA, мы установим на каждый из воркеров Load Balancer (Haproxy), который по round robin будет раскидывать запросы на три master ноды, а в конфигах kubelet на worker нодах мы поменяем адрес сервера на 127.0.0.1:6443
Для начала установим HAProxy на каждую worker ноду.
Есть неплохая шпаргалка по установке
curl https://haproxy.debian.net/bernat.debian.org.gpg | \
apt-key add -
echo deb http://haproxy.debian.net stretch-backports-2.0 main | \
tee /etc/apt/sources.list.d/haproxy.list
apt-get update
apt-get install haproxy=2.0.\*
После того, как HAproxy, установлен нам нужно создать для него конфиг.
Если на worker нодах нет каталога с конфиг файлами, то клонируем его
git clone https://github.com/rjeka/kubernetes-ceph-percona.git
cd kubernetes-ceph-percona/
И запускаем скрипт конфига с флагом haproxy
./create-config.sh haproxy
Скрипт сконфигурирует и перезапустит haproxy.
Проверим, что haproxy стал слушать порт 6443.
root@worknode01:~/kubernetes-ceph-percona# netstat -alpn | grep 6443
tcp 0 0 127.0.0.1:6443 0.0.0.0:* LISTEN 30675/haproxy
tcp 0 0 10.73.75.241:6443 0.0.0.0:* LISTEN 30675/haproxy
Теперь нам нужно сказать kubelet, чтобы он обращался на localhost вместо master ноды. Для этого нужно отредактировать значение server в файлах /etc/kubernetes/kubelet.conf и /etc/kubernetes/bootstrap-kubelet.conf на всех worker нодах.
vim /etc/kubernetes/kubelet.conf
vim /etc/kubernetes/bootstrap-kubelet.conf
Значение server должно принять вот такой вид:
server: https://127.0.0.1:6443
После внесения изменений нужно перезапустить службы kubelet и docker
systemctl restart kubelet && systemctl restart docker
Проверим, что все ноды работают исправно
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready master 29m v1.15.1
master02 Ready master 27m v1.15.1
master03 Ready master 26m v1.15.1
worknode01 Ready <none> 25m v1.15.1
worknode02 Ready <none> 3m15s v1.15.1
worknode03 Ready <none> 3m16s v1.15.1
Пока что у нас нет приложений в кластере, чтобы проверить работу HA. Но мы можем остановить работу kubelet на первой master ноде и убедится, что наш кластер остался дееспособным.
systemctl stop kubelet && systemctl stop docker
Проверяем со второй master ноды
root@master02:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 NotReady master 15h v1.15.1
master02 Ready master 15h v1.15.1
master03 Ready master 15h v1.15.1
worknode01 Ready <none> 15h v1.15.1
worknode02 Ready <none> 15h v1.15.1
worknode03 Ready <none> 15h v1.15.1
Все ноды функционируют нормально, кроме той, на которой мы остановили службы.
Не забываем включить обратно службы kubernetes на первой master ноде
systemctl start kubelet && systemctl start docker
Установка Ingress контроллера
Ingress контроллер — это дополнение Kubernetes, c помощью которого мы можем получить доступ до наших приложений снаружи. Подробное описание есть в документации Kuberbnetes. Ingress контролеров существует достаточное большое количество, я пользуюсь контроллером от Nginx. Про его установку я и буду рассказывать. Документацию по работе, настройке и установке Ingress контроллера от Nginx можно почитать на официальном сайте
Приступим к установке, все команды можно выполнять с master01.
Устанавливаем сам контроллер
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
А теперь — сервис, через который будет доступен ингресс
Для этого подготовим конфиг
./create-config.sh ingress
И отправим его в наш кластер
kubectl apply -f ingress/service-nodeport.yaml
Проверим, что наш Ingress работает на нужных адресах и слушает нужные порты
# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.99.35.95 10.73.71.25,10.73.71.26,10.73.71.27 80:31669/TCP,443:31604/TCP 10m
kubectl describe svc -n ingress-nginx ingress-nginx
Name: ingress-nginx
Namespace: ingress-nginx
Labels: app.kubernetes.io/name=ingress-nginx
app.kubernetes.io/part-of=ingress-nginx
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/name":"ingress-nginx","app.kubernetes.io/par...
Selector: app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/part-of=ingress-nginx
Type: NodePort
IP: 10.99.35.95
External IPs: 10.73.71.25,10.73.71.26,10.73.71.27
Port: http 80/TCP
TargetPort: 80/TCP
NodePort: http 31669/TCP
Endpoints: 192.168.142.129:80
Port: https 443/TCP
TargetPort: 443/TCP
NodePort: https 31604/TCP
Endpoints: 192.168.142.129:443
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
Установка Web UI (Dashboard)
У Kubernetes есть стандартный Web UI, через который иногда удобно быстро глянуть состояние кластера или отдельных его частей. Я в своей работе часто использую dashboard для первичной диагностики деплоя или состояния частей кластера.
Ссылка на документацию находится на сайте kubernetes
Установка. Я использую стабильную версию, 2.0 пока что не пробовал.
#Стабильная версия
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml
#Версия 2.0
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta1/aio/deploy/recommended.yaml
После того, как мы установили панель в наш кластер, панель стала доступна по адресу
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/.
Но для того, чтобы на нее попасть, нам нужно с локальной машины пробросить порты с помощью kubectl proxy. Для меня эта схема очень не удобная. Поэтому я изменю service панели управления, для того чтобы dashboard стал доступен на адресе любой ноды кластера на порту 30443. Есть еще другие способы получить доступ до дашборда, например, через ingress. Возможно, я рассмотрю этот способ в следующих публикациях.
Для изменения сервиса запустим деплой измененного сервиса
kubectl apply -f dashboard/service-nodeport.yaml
Осталось создать admin пользователя и token для доступа к кластеру через дашборд
kubectl apply -f dashboard/rbac.yaml
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')
После этого можно залогинится в панеле управления по адресу https://10.73.71.25:30443
Главный экран dashboard
Поздравляю! Если Вы дошли до этого шага, то у Вас есть работающий HA кластер kubernetes, который готов для деплоя Ваших приложений.
Kubernetes является костяком микросервисной инфраструктуру, на который требуется устанавливать различные дополнения. Про некоторые из них я планирую рассказать в следующих публикациях.
На все вопросы постараюсь ответить в комментариях, на GitHub, или в любых соцсетях, указанных в моем профиле.
C уважением, Евгений Родионов.