Обзор
Недавно я провел два воркшопа по внутреннему устройству Kubernetes (k8s), решил сделать текстовую заметку по простой части.
Kubernetes это 5 бинарей
Такую фразу можно часто услышать в DevOps комьюнити, её сарказм в том, что k8s выглядит простым, но на деле является очень сложным продуктом, с большим количеством вариантов запуска и конфигурирования конкретного кластера.
Работу с k8s можно разделить на две части: запуск и поддержка самого кластера/кластеров и работа с кластером в качестве клиента. Мы сейчас больше говорим про первую часть. Потому что прежде чем начать работать с кластером, нужно его запустить и настроить.
Обобщенная схема k8s выглядит примерно так.
Компоненты делятся на компоненты мастер нод и компоненты воркер нод. К компонентам мастера относятся:
- etcd - key/value база данных, single source of truth
- kube-apiserver - центральный “роутер”, единственный компонент который может писать и читать etcd
- kube-controller-manager - набор лупов, которые периодически просыпаются и обрабатывают конкретные сущности
- kube-scheduler - гранд-мастер тетриса, решает на какой ноде какой под запустить
К компонентам воркер нод, относятся:
- kubelet - связующее звено между apiserver и непосредственно container runtime
- kube-proxy - сетевая прокси, необходимая для работы service
Установка зависимостей
Для начала нам нужно два сервера с linux, я использовал Ubuntu 18.04. Хотя в самом минимальном случае хватит и одного сервера. Перед началом нужно установить все зависимости.
Docker
установим необходимые пакеты
теперь добавим gpg ключ APT репозитория docker в нашу систему
ну и добавим сам репозиторий:
теперь можем установить собственно докер
docker является container runtime и должен быть установлен на всех серверах, которые мы хотим использовать в качестве worker node
Etcd
Установка Etcd одна из самых простых, из компонентов, необходимых нам. Cкачиваем последний доступный релиз с github
создаем временную папку
разархивируем релиз во временную папку
переносим исполняемый файл etcd в каталог исполняемых файлов
удаляем временную папку
Kubernetes
Теперь нам осталось только скачать исполняемые файлы Kubernetes, cкачиваем архив с релизом
разархивируем его
переходим в папку с файлами и выполняем скрипт, который достанет нам клиентский исполняемый файл - kubectl
теперь разархивируем серверные компоненты
так же как и с Etcd, перенесем все наши исполняемый файлы в общесистемный каталог, чтобы они заработали
kubelet и kube-proxy также нужно скопировать на все серверы, которые мы хотим использовать в качестве worker node
теперь у нас есть все необходимые и мы можем приступить.
Собираем кластер
Будем запускать все компоненты в foreground, поэтому я использую разные вкладки в терминале, но с таким же успехом можно использовать screen.
Docker
для начала убедимся, что docker запущен
если статус не running, то запустим его
Etcd
теперь, вспоминаем схему компонентов k8s, единственным источником правды и хранилищем является Etcd, без него ничего работать не будет, запустим его
Apiserver
Ну а единственным, кто может общаться с Etcd является apiserver, запустим и его
упс, ошибочка, apiserver должен знать где Etcd, поэтому используем флаг –etcd-servers
теперь, попробуем выполнить команду
если сделали все правильно, мы должны увидеть что-то вроде
Controller-manager
Но нас интересует не deployment, а запущенный контейнер, чтобы этого добиться, запустим controller-manager, который создаст replicaSet и pods для нас
controller-manager тоже не желает запускаться просто так и ему нужно указать где apiserver
и вроде бы все неплохо, но если в читаться в логи controller-manager, мы увидим ошибку, говорящую что-то про service account и tokens, у нас нет времени с этим разбираться, поэтому просто выполним
и добавим в открывшийся файл в конец, с начала строки:
ошибки в controller-manager должны уйти, но на всякий случай мы можем остановить его (ctrl+C) и запустить заново
мы можем посмотреть состояние в нашем кластере с помощью команды
Scheduler
Cледующим компонентом мы запустим scheduler, ему также нужно знать где apiserver
но подождите, scheduler может назначить pod на какой-нибудь сервер, только если он у нас есть, чтобы проверить это выполним
Kubelet
У нас сейчас нет ни одной ноды, потому что мы не запустили kubelet, сделаем это командой
и если вам покажется что все заработало, не обольщайтесь, если запустить kubelet без параметров, он запустится в standalone режиме, т.е. не будет подключен ни к какому кластеру а это не наш случай, остановим его и попробуем передать ему apiserver как с другими компонентами
упс, так не работает, kubelet воспринимает только конфиг в файле, чтобы сгенерить его используем команды
таким образом мы получим конфиг по умолчанию, указывающий на то, что apiserver работает на 127.0.0.1 на порту 8080, чтобы использовать этот конфиг запустим kubelet c параметром –kubeconfig
теперь, команда kubectl get nodes, должна возвращать нашу ноду в статусе Ready, а спустя некоторое время, наш pod должен перейти в статус running
Kube-proxy
мы даже можем попробовать обратиться в наш pod, для этого создадим service
теперь посмотрим какой ip адрес был выдан нашему service
допустим это адрес 10.0.0.241, попробуем выполнить curl на него
этот запрос не выполнится, можете не ждать. Для того, чтобы service заработал, нужно запустить kube-proxy, в новой вкладке выполним
теперь повторим наш curl, он должен выполниться и мы получим html страницы по умолчанию веб-сервера nginx
если вы дошли до этого шага, это уже можно считать успехом. Но если у вас есть второй сервер, можем попробовать добавить его как вторую worker node.
Добавление второй ноды
Для этого скопируем наш конфиг на второй сервер
и внесем в него исправление, вместо 127.0.0.1 нам нужно использовать IP адрес нашего первого сервера, его можно найти используя команду ifconfig или ip.
попробуем запустить наш kubelet на втором сервере командой
и тут мы столкнемся с ошибкой, потому что apiserver запущен на локальном интерфейсе 127.0.0.1. Давайте вернемся во вкладку на первом сервере в которой запущен apiserver, остановим его и запустим снова но уже командой
при этом controller-manager и scheduler автоматически остановятся, запустим их заново
снова попробуем запустить kubelet на втором сервере
теперь команда kubectl get nodes должна возвращать оба сервера в статусе Ready, ну и чтобы проверить что pods запускаются на обоих серверах, запустим простой сервис
посмотрим на каких нодах запустились pods командой
pods должны быть распределены по нодам примерно одинаково. Посмотрим какой IP адрес получил наш service
допустим это 10.0.0.74, попробуем обратиться на него через curl
мы должны получать ответы от подов запущенных на той же ноде, на которой выполняется команда curl, но не будем получать ответ от подов запущенных на другой ноде, дело в том, что сети наших kubelet изолированы друг от друга, но это уже тема следующего воркшопа.
#DevOps #Kubernetes #TechAndDevЕсли у вас есть вопросы, предложения или вы нашли ошибку, можете смело писать мне в Twitter или на почту (ссылки слева под аватаркой).