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

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

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

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

Цели

Кластер будет состоять из таких физических ресурсов:

  • Одна мастер-нода

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

  • Две рабочие ноды

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

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

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

Требования

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

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

Примечание: IP-адрес мастер-ноды здесь определяется как master_ip, а IP-адреса рабочих нод — worker_1_ip и worker_2_ip. Их нужно будет заменить своими данными.

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

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

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

Создайте файл ~/kube-cluster/hosts, используя nano или другой текстовый редактор:

nano ~/kube-cluster/hosts

Добавьте в файл следующие строки (это информация о логической структуре кластера).

[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
[all:vars]
ansible_python_interpreter=/usr/bin/python3

Возможно, вы помните, что файлы инвентаря в 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.

Последняя строка файла говорит Ansible использовать интерпретаторы Python 3 удаленных серверов для выполнения своих операций управления.

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

2: Создание пользователей sudo на удаленных серверах

Теперь нужно создать не-root пользователей с привилегиями sudo на всех удаленных серверах, чтобы вы могли использовать SSH вручную в качестве непривилегированного пользователя. Это может быть полезно, например, если вам нужно будет получить системную информацию с помощью таких команд как top/htop, просмотреть список запущенных контейнеров или изменить файлы конфигурации, принадлежащие root. Эти операции обычно выполняются во время обслуживания кластера, а применение для таких задач пользователя без прав root минимизирует риск потери и повреждения важных файлов или случайного выполнения опасных операций.

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

nano ~/kube-cluster/initial.yml

Затем добавьте в файл следующий код, чтобы создать пользователя без полномочий root с привилегиями sudo на всех серверах. Плей в Ansible представляет собой набор действий, которые необходимо выполнить на целевых серверах и группах. Этот плей создаст пользователя sudo без полномочий root:

- hosts: all
become: yes
tasks:
- name: create the 'ubuntu' user
user: name=ubuntu append=yes state=present createhome=yes shell=/bin/bash
- name: allow 'ubuntu' to have passwordless sudo
lineinfile:
dest: /etc/sudoers
line: 'ubuntu ALL=(ALL) NOPASSWD: ALL'
validate: 'visudo -cf %s'
- name: set up authorized keys for the ubuntu user
authorized_key: user=ubuntu key="{{item}}"
with_file:
- ~/.ssh/id_rsa.pub

Этот плейбук:

  • Создает не-root пользователя по имени ubuntu.
  • Настраивает файл sudoers, чтобы предоставить пользователю ubuntu привилегии sudo без пароля.
  • Добавляет открытый ключ локальной машины (~/.ssh/id_rsa.pub) в список ключей удаленного пользователя ubuntu. Это позволит вам подключаться к серверам по SSH как пользователь ubuntu.

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

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

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

Команда будет выполняться в течение 2-5 минут. После этого вы увидите:

PLAY [all] ****
TASK [Gathering Facts] ****
ok: [master]
ok: [worker1]
ok: [worker2]
TASK [create the 'ubuntu' user] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [allow 'ubuntu' user to have passwordless sudo] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [set up authorized keys for the ubuntu user] ****
changed: [worker1] => (item=ssh-rsa AAAAB3...
changed: [worker2] => (item=ssh-rsa AAAAB3...
changed: [master] => (item=ssh-rsa AAAAB3...
PLAY RECAP ****
master                     : ok=5    changed=4    unreachable=0    failed=0
worker1                    : ok=5    changed=4    unreachable=0    failed=0
worker2                    : ok=5    changed=4    unreachable=0    failed=0

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

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

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

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

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

Добавьте в него следующие плеи, чтобы установить на серверы все зависимости.

- hosts: all
become: yes
tasks:
- name: install Docker
apt:
name: docker.io
state: present
update_cache: true
- name: install APT Transport HTTPS
apt:
name: apt-transport-https
state: present
- name: add Kubernetes apt-key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: add Kubernetes' APT repository
apt_repository:
repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
state: present
filename: 'kubernetes'
- name: install kubelet
apt:
name: kubelet
state: present
update_cache: true
- name: install kubeadm
apt:
name: kubeadm
state: present
- hosts: master
become: yes
tasks:
- name: install kubectl
apt:
name: kubectl
state: present

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

  • Устанавливает Docker.
  • Устанавливает apt-transport-https, что позволяет добавлять внешние источники HTTPS в список источников APT.
  • Добавляет apt-key репозитория Kubernetes.
  • Добавляет репозиторий APT Kubernetes в список источников APT удаленных серверов.
  • Устанавливает kubelet и kubeadm.

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

Теперь запустите плейбук локально:

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 [install APT Transport HTTPS] *****
ok: [master]
ok: [worker1]
changed: [worker2]
TASK [add Kubernetes apt-key] *****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [add Kubernetes' APT 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]
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 можно запускать с любой из рабочих нод или с любого компьютера, на котором его можно установить и подключить к кластеру.

4: Настройка мастер-ноды

Теперь нужно настроить мастер-ноду. Но для начала нужно рассмотреть такие понятия как поды и сетевые плагины Kubernetes.

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

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

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

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

nano ~/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: ubuntu
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/ubuntu/.kube/config
remote_src: yes
owner: ubuntu
- name: install Pod network
become: yes
become_user: ubuntu
shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml >> pod_network_setup_complete.txt
args:
chdir: $HOME
creates: pod_network_setup.txt

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

  • Первая задача инициализирует кластер, запустив kubeadm init. Аргумент —pod-network-cidr=10.244.0.0/16 указывает частную подсеть, из которой будут назначаться IP-адреса. Flannel использует указанную выше подсеть по умолчанию; теперь kubeadm тоже будет использовать эту подсеть.
  • Вторая задача создает каталог .kube в /home/ubuntu. В нем будут храниться детали конфигурации (ключи админов, необходимые для подключения к кластеру, и 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 ubuntu@master_ip

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

kubectl get nodes

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

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

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

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

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

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

nano ~/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

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

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

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

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

ssh ubuntu@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 в кластере.

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

Теперь в своем кластере вы можете развернуть любое контейнеризованное приложение. Для примера можно попробовать развернуть 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: , , , , ,
  • srihitha sri

    Hi,
    When i am testing cluster using

    kubectl get nodes

    i am facing error like

    «The connection to the server localhost:8080 was refused — did you specify the right host or port?

    can some one help me to resolve this