Создание кластера Kubernetes 1.10 с помощью Kubeadm в CentOS 7

Kubernetes – это система управления контейнерами. Первоначально разработанный компанией Google на основе опыта работы с контейнерами в среде производства, Kubernetes распространяется с открытым исходным кодом и активно развивается сообществом по всему миру.

Kubeadm автоматизирует установку и настройку компонентов Kubernetes, таких как сервер API, менеджер контроллеров и Kube DNS. Однако он не создает пользователей и не обрабатывает установку и конфигурацию зависимостей на уровне операционной системы. Для этих задач можно использовать инструмент управления конфигурацией, например Ansible или SaltStack. Эти инструменты позволяют создавать новые или воссоздавать существующие кластеры намного быстрее и с меньшим количеством ошибок.

Этот мануал поможет создать новый кластер Kubernetes с помощью Ansible и Kubeadm и развернуть в нем контейнеризованное приложение Nginx.

Для этого нужна одна главная и две рабочих ноды.

Примечание: В терминологии Kubernetes нода – это сервер.

Главная нода отвечает за управление состоянием кластера. Она запускает Etcd, где хранятся данные кластера, а также управляет компонентами, которые планируют рабочие нагрузки остальных нод.

Рабочие ноды – это серверы, на которых будут выполняться рабочие нагрузки (например, контейнеризованные приложения и сервисы). Рабочая нода будет обрабатывать присвоенную ей рабочую нагрузку, даже если главная нода прекратит работу после планирования. Мощность кластера можно увеличить за счет добавления новых рабочих нод.

Выполнив этот мануал, вы получите кластер, готовый запускать контейнеризованные приложения (при условии, что серверы в кластере имеют достаточно CPU и RAM для работы приложений). Почти любое традиционное приложение Unix, включая веб-приложения, базы данных, демоны и инструменты командной строки, можно контейнеризировать и запустить в кластере. Сам кластер будет потреблять около 300-500 МБ памяти и 10% CPU каждой ноды.

После создания кластера вы сможете развернуть веб-сервер Nginx, чтобы убедиться, что рабочая нагрузка распределяется правильно.

Требования

1: Настройка рабочего пространства и инвентаря Ansible

Сначала нужно создать на локальной машине каталог, который будет служить рабочим пространством. Также нужно настроить локальный экземпляр Ansible, чтобы он мог взаимодействовать с командами на удаленных серверах и выполнять их. Для этого создайте файл hosts, содержащий информацию об инвентаре (IP-адреса серверов и группы, к которым принадлежит каждый сервер).

Примечание: В этом мануале используется условный IP-адрес главной ноды master_ip и адреса рабочих нод worker_1_ip и worker_2_ip.

На локальной машине в домашнем каталоге создайте каталог ~/kube-cluster:

mkdir ~/kube-cluster
cd ~/kube-cluster

Этот каталог будет вашим рабочим местом в течение всего мануала, где будут находиться все плейбуки Ansible. Также внутри этого каталога вы будете запускать все локальные команды.

Создайте файл ~/kube-cluster/hosts:

vi ~/kube-cluster/hosts

Нажмите i, чтобы вставить в файл следующий текст, в котором будут сведения о логической структуре кластера:

[masters]
master ansible_host=master_ip ansible_user=root
[workers]
worker1 ansible_host=worker_1_ip ansible_user=root
worker2 ansible_host=worker_2_ip ansible_user=root

Нажмите ESC и :wq, чтобы сохранить и закрыть файл.

Возможно, вы помните, что файлы инвентаря в Ansible используются для указания информации о сервере (это IP-адреса, удаленные пользователи и группы серверов, которые позволяют объединять ноды в единый блок для выполнения команд). Файл ~/kube-cluster/hosts будет этим файлом инвентаря, сейчас в нем есть две группы Ansible (masters и workers), в которых указывается логическая структура кластера.

В группе masters есть запись сервера master, которая содержит IP-адрес главной ноды (master_ip) и указывает, что Ansible должен запускать удаленные команды в качестве пользователя root.

Точно так же в группе workers есть две записи о рабочих нодах, где указаны их адреса (worker_1_ip и worker_2_ip). Также здесь указано, что ansible_user – это пользователь root.

2: Установка зависимостей Kubernetes

Теперь нужно установить общесистемные пакеты, необходимые Kubernetes. Это можно сделать с помощью менеджера пакетов yum. Вам нужно установить:

  • Docker – система управления контейнерами. Она и будет запускать ваши контейнеры в кластере. Поддержка других подобных систем (например rkt) активно разрабатывается командой Kubernetes.
  • kubeadm – инструмент CLI, который позволяет стандартным образом установить и настроить множество различных компонентов кластера.
  • kubelet – системный сервис, который запускает все ноды и управляет операциями на уровне нод.
  • kubectl – инструмент CLI для запуска команд в кластере через сервер API.

В своем рабочем пространстве создайте файл ~/kube-cluster/kube-dependencies.yml:

vi ~/kube-cluster/kube-dependencies.yml

Добавьте в него следующий плейбук, который установит все нужные пакеты на серверы:

- hosts: all
become: yes
tasks:
- name: install Docker
yum:
name: docker
state: present
update_cache: true
- name: start Docker
service:
name: docker
state: started
- name: disable SELinux
command: setenforce 0
- name: disable SELinux on reboot
selinux:
state: disabled
- name: ensure net.bridge.bridge-nf-call-ip6tables is set to 1
sysctl:
name: net.bridge.bridge-nf-call-ip6tables
value: 1
state: present
- name: ensure net.bridge.bridge-nf-call-iptables is set to 1
sysctl:
name: net.bridge.bridge-nf-call-iptables
value: 1
state: present
- name: add Kubernetes' YUM repository
yum_repository:
name: Kubernetes
description: Kubernetes YUM repository
baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
gpgkey: https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
gpgcheck: yes
- name: install kubelet
yum:
name: kubelet
state: present
update_cache: true
- name: install kubeadm
yum:
name: kubeadm
state: present
- name: start kubelet
service:
name: kubelet
enabled: yes
state: started
- hosts: master
become: yes
tasks:
- name: install kubectl
yum:
name: kubectl
state: present

Первый плей в плейбуке делает следующее:

  • Устанавливает Docker.
  • Запускает сервис Docker.
  • Отключает SELinux, поскольку он еще не полностью поддерживается Kubernetes.
  • Устанавливает несколько значений sysctl, связанных с netfilter и необходимых для работы в сети. Это позволит Kubernetes устанавливать правила iptables для получения нодами сетевого трафика IPv4 и IPv6.
  • Добавляет YUM репозиторий Kubernetes в списки репозиториев удаленных серверов.
  • Устанавливает kubelet и kubeadm.

Второй плей состоит из одной задачи, которая устанавливает kubectl на главную ноду.

Запустите плейбук:

ansible-playbook -i hosts ~/kube-cluster/kube-dependencies.yml

Вы увидите такой вывод:

PLAY [all] ****
TASK [Gathering Facts] ****
ok: [worker1]
ok: [worker2]
ok: [master]
TASK [install Docker] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [disable SELinux] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [disable SELinux on reboot] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [ensure net.bridge.bridge-nf-call-ip6tables is set to 1] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [ensure net.bridge.bridge-nf-call-iptables is set to 1] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [start Docker] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [add Kubernetes' YUM repository] *****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [install kubelet] *****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [install kubeadm] *****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [start kubelet] ****
changed: [master]
changed: [worker1]
changed: [worker2]
PLAY [master] *****
TASK [Gathering Facts] *****
ok: [master]
TASK [install kubectl] ******
ok: [master]
PLAY RECAP ****
master                     : ok=9    changed=5    unreachable=0    failed=0
worker1                    : ok=7    changed=5    unreachable=0    failed=0
worker2                    : ok=7    changed=5    unreachable=0    failed=0

После выполнения плейбука Docker, kubeadm и kubelet будут установлены на всех удаленных серверах. kubectl не является обязательным компонентом и необходим только для выполнения команд кластера. Устанавливать его только на главной ноде в этом контексте имеет смысл, так как вы будете запускать команды kubectl только с этого сервера. Однако обратите внимание, что команды kubectl можно запускать с любого из рабочих серверов или с любого компьютера, на котором он установлен и настроен (если он направлен на кластер).

3: Настройка главной ноды

Теперь нужно настроить главную ноду. Прежде чем приступить к созданию плейбука, нужно рассмотреть такие понятия как поды и сетевые плагины Kubernetes.

Под – это базовый элемент, который управляет одним или несколькими контейнерами. Эти контейнеры совместно используют ресурсы, такие как тома файлов и сетевые интерфейсы. Под – это основная единица планирования в Kubernetes: все контейнеры в поде работают на той же ноде, на которой запланирована работа пода.

Каждый под имеет свой собственный IP-адрес; под одной ноды должен иметь доступ к поду на другой ноде по IP-адресу. Контейнеры на одном узле могут легко связываться через локальный интерфейс. Однако связь между контейнерами сложнее, и для этого требуется отдельный сетевой компонент, который может легко маршрутизировать трафик пода на одной ноде к поду на другой.

Эту функцию выполняют сетевые плагины. Один из них, Flannel, будет использоваться в этом кластере.

Создайте плейбук master.yml на локальной машине.

vi ~/kube-cluster/master.yml

Добавьте в файл такой код, чтобы инициализировать кластер и установить Flannel:

- hosts: master
become: yes
tasks:
- name: initialize the cluster
shell: kubeadm init --pod-network-cidr=10.244.0.0/16 >> cluster_initialized.txt
args:
chdir: $HOME
creates: cluster_initialized.txt
- name: create .kube directory
become: yes
become_user: centos
file:
path: $HOME/.kube
state: directory
mode: 0755
- name: copy admin.conf to user's kube config
copy:
src: /etc/kubernetes/admin.conf
dest: /home/centos/.kube/config
remote_src: yes
owner: centos
- name: install Pod network
become: yes
become_user: centos
shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml >> pod_network_setup.txt
args:
chdir: $HOME
creates: pod_network_setup.txt

Этот файл делает следующее:

  • Первая задача инициализирует кластер, запустив kubeadm init. Аргумент —pod-network-cidr=10.244.0.0/16 указывает частную подсеть, из которой будут назначаться IP-адреса. Flannel использует указанную выше подсеть по умолчанию; теперь kubeadm тоже будет использовать эту подсеть.
  • Вторая задача создает каталог .kube в /home/centos. В нем будут храниться детали конфигурации (ключи админов, необходимые для подключения к кластеру, и API-адрес кластера).
  • Третья задача копирует файл /etc/kubernetes/admin.conf, сгенерированный командой kubeadm init, в домашний каталог не-root пользователя. Это позволяет использовать kubectl для доступа к кластеру.
  • Последняя задача запускает kubectl apply, чтобы установить Flannel. Синтаксис kubectl apply -f descriptor.[yml|json] позволяет kubectl создавать объекты, описанные в файле descriptor.[yml|json]. Файл kube-flannel.yml содержит описание объектов, необходимых для настройки Flannel в кластере.

Сохраните и закройте файл.

Запустите плейбук локально:

ansible-playbook -i hosts ~/kube-cluster/master.yml

Вы получите такой вывод:

PLAY [master] ****
TASK [Gathering Facts] ****
ok: [master]
TASK [initialize the cluster] ****
changed: [master]
TASK [create .kube directory] ****
changed: [master]
TASK [copy admin.conf to user's kube config] *****
changed: [master]
TASK [install Pod network] *****
changed: [master]
PLAY RECAP ****
master                     : ok=5    changed=4    unreachable=0    failed=0

Чтобы проверить состояние мастер-ноды, подключитесь к ней по SSH.

ssh centos@master_ip

Затем выполните команду:

kubectl get nodes

Вы должны увидеть:

NAME      STATUS    ROLES     AGE       VERSION
master    Ready     master    1d        v1.10.1

В выводе указано, что мастер-нода выполнила все задачи инициализации и находится в состоянии Ready, то есть может принимать рабочие ноды и выполнять задачи, отправленные на сервер API. Теперь вы можете добавить рабочие ноды.

4: Настройка рабочих нод

Чтобы добавить рабочие ноды, нужно выполнить на каждой из них одну команду. Эта команда включает в себя необходимую информацию о кластере (IP-адрес, порт сервера API-интерфейса мастера и токен). Только ноды, которые могут пройти токен, будут добавлены в кластер.

В рабочем пространстве создайте плейбук workers.yml:

vi ~/kube-cluster/workers.yml

Добавьте в него следующий код, чтобы подключить рабочие ноды к кластеру:

- hosts: master
become: yes
gather_facts: false
tasks:
- name: get join command
shell: kubeadm token create --print-join-command
register: join_command_raw
- name: set join command
set_fact:
join_command: "{{ join_command_raw.stdout_lines[0] }}"
- hosts: workers
become: yes
tasks:
- name: join cluster
shell: "{{ hostvars['master'].join_command }} >> node_joined.txt"
args:
chdir: $HOME
creates: node_joined.txt

Этот плейбук делает следующее:

  • Первый плей получает команду join, которая должна выполняться на рабочих нодах. Эта команда будет в следующем формате: kubeadm join —token <token> <master-ip>:<master-port> —discovery-token-ca-cert-hash sha256:<hash>. Как только он получит команду с соответствующими значениями токена и хэша, следующий плей сможет получить доступ к этой информации.
  • Второй плей содержит одну задачу, которая запускает команду join на всех рабочих нодах. В результате две ноды станут частью кластера.

Сохраните и закройте файл.

Выполните плейбук локально:

ansible-playbook -i hosts ~/kube-cluster/workers.yml

Он вернет:

PLAY [master] ****
TASK [get join command] ****
changed: [master]
TASK [set join command] *****
ok: [master]
PLAY [workers] *****
TASK [Gathering Facts] *****
ok: [worker1]
ok: [worker2]
TASK [join cluster] *****
changed: [worker1]
changed: [worker2]
PLAY RECAP *****
master                     : ok=2    changed=1    unreachable=0    failed=0
worker1                    : ok=2    changed=1    unreachable=0    failed=0
worker2                    : ok=2    changed=1    unreachable=0    failed=0

После добавления рабочих нод кластер будет полностью настроен, а рабочие ноды будут готовы к обработке нагрузок. Прежде чем планировать приложения, нужно убедиться, что кластер работает должным образом.

5: Тестирование кластера

Иногда кластер может выходить из строя во время настройки, потому что нода отключена или сетевое соединение между мастером и рабочей нодой установлено неправильно. Протестируйте кластер и убедитесь, что все ноды работают верно.

Вам нужно будет проверить текущее состояние кластера с мастер-ноды, чтобы убедиться, что все ноды готовы. Если вы отключились от мастер-ноды, вы можете создать новое подключение SSH с помощью следующей команды:

ssh centos@master_ip

Выполните эту команду:

kubectl get nodes

Вы получите такой результат:

NAME      STATUS    ROLES     AGE       VERSION
master    Ready     master    1d        v1.10.1
worker1   Ready     <none>    1d        v1.10.1
worker2   Ready     <none>    1d        v1.10.1

Если все ноды имеют значение Ready в столбце STATUS, это означает, что они являются частью кластера и готовы к обслуживанию рабочих нагрузок.

Однако если некоторые из нод имеют статус NotReady, это может означать, что рабочие ноды еще не завершили свою настройку. Подождите около пяти-десяти минут, а затем попробуйте перезапустить kubectl get node. Если несколько нод все еще имеют статус NotReady, возможно, вам придется проверить и повторно запустить команды в предыдущих разделах.

Теперь можно попробовать запустить приложение Nginx в кластере.

6: Запуск приложения в кластере

Теперь в своем кластере вы можете развернуть любое контейнеризованное приложение. Для примера можно попробовать развернуть Nginx с помощью развертываний и сервисов. Вы также можете использовать приведенные ниже команды для развертывания других приложений (для этого также измените имя образа Docker и все соответствующие флаги (например, ports и volumes)).

Оставаясь на мастере, запустите следующую команду, чтобы создать развертывание nginx:

kubectl run nginx --image=nginx --port 80

Развертывание – это объект Kubernetes, который гарантирует, что на определенном шаблоне всегда будет работать определенное минимальное количество подов (даже если под повреждается во время работы кластера). Вышеупомянутое развертывание создаст под с одним контейнером из образа Nginx Docker.

Затем запустите следующую команду, чтобы создать сервис nginx, который откроет приложению доступ к сети. Это будет сделано через NodePort, схему, которая сделает под доступным через произвольный порт, открытый на каждой ноде кластера:

kubectl expose deploy nginx --port 80 --target-port 80 --type NodePort

Сервисы – это еще один тип объектов Kubernetes, который раскрывает внутренние сервисы кластера для клиентов, как внутренних, так и внешних. Они также способны выполнять балансировку нагрузки на несколько подов и являются неотъемлемым компонентом Kubernetes, поскольку часто взаимодействуют с другими компонентами.

Запустите:

kubectl get services

Вы получите примерно такой вывод:

NAME         TYPE        CLUSTER-IP       EXTERNAL-IP           PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>                443/TCP        1d
nginx        NodePort    10.109.228.209   <none>                80:nginx_port/TCP   40m

В третьей строке вывода вы можете увидеть порт, на котором работает Nginx. Kubernetes автоматически присваивает случайный порт выше 30000, проверяя, что порт не занят другим сервисом.

Чтобы убедиться, что все работает, откройте на локальной машине в браузере:

http://worker_1_ip:nginx_port
или
http://worker_2_ip:nginx_port

Вы увидите стандартное приветствие Nginx.

Чтобы удалить приложение Nginx, сначала удалите сервис nginx с мастер-ноды.

kubectl delete service nginx

Запустите следующую команду, чтобы убедиться, что сервис удален:

kubectl get services
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP           PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>                443/TCP        1d

После удалите развертывание:

kubectl delete deployment nginx

Чтобы убедиться, что оно удалилось, введите:

kubectl get deployments
No resources found.

Заключение

Если вы не знаете, что делать с кластером дальше, когда он настроен, попробуйте развернуть в нем свои приложения и сервисы. Вот список ссылок, которые могут помочь вам в этом процессе:

  • На сайте Docker можно найти примеры, подробно описывающие, как контейнеризировать приложения.
  • Этот обзор подробно описывает, как работают поды, и объясняет их связь с другими объектами Kubernetes.
  • Этот обзор расскажет вам о развертываниях в Kubernetes. Понимать, как работают развертывания, очень важно, поскольку они часто используются для масштабирования и автоматического восстановления приложений.
  • По этой ссылке вы найдете обзор сервисов.

Kubernetes поддерживает много хороших функций. Официальная документация Kubernetes – лучшее место для изучения понятий, поиска руководств по конкретным задачам и ссылок API для различных объектов.

Tags: , , ,