Loading [MathJax]/jax/output/HTML-CSS/config.js

11 листопада 2018

Kubernetes кластер на Raspberry PI (кінцеві налаштування)

Минулого разу ми завершили на налаштуванні мережі нашого майбутнього кластеру. Основну кількість роботи ми зробили на мастері, а на нодах у вас повинно працювати автоматично. Сьогодні ми встановимо основні Kubernetes компоненти на мастері і всіх нодах і тим самим запустимо наш невеличкий кластер на Raspberry PI.

Майже всі кроки (крім кількох останніх) будуть аналогічні як на мастері так і на кожному ноді, тому загалом непогана ідея записати це все в маленький скрипт який можна буде запустити на кожному вузлі окремо, але цю вправу я залишу вам на домашнє завдання.

Перш за все нам необхідно встановити рантайм для майбутніх контейнерів. В цій статті я опишу встановлення докера, мабуть, найпопулярнішого рішення на сьогодні, а в майбутньому підготую окрему статтю про containerd та його переваги і недоліки. Для встановлення Докера я скористаюся офіційним скриптом, який здійснить всю необхідну конфігурацію:
$ curl -sSL get.docker.com | sh && sudo usermod pi -aG docker
На жаль, в подальшому у вас можуть виникнути труднощі. Проблема в тому, що цей скрипт встановлює останню версію, а Kubernetes з великою ймовірністю не був протестований на ній. Тому я вирішив встановити старшу версію, яка офіційна підтримується Kubernetes (зауважте, що на момент прочитання цієї статті, версія може змінитися). Для версії Kubernetes 1.12.2 найновіша версія докера це 18.06, тому я скористався наступними командами для перевстановлення:
$ sudo apt-get -y remove docker-ce docker-engine$ sudo apt-get -y install docker-ce=18.06.1~ce~3-0~raspbian
Далі для коректтної роботи kubelet (один з базових компонентів) необхідно відключити на лінуксі swap, цього можна досягти з допомогою наступних команд:
$ sudo dphys-swapfile swapoff
$ sudo dphys-swapfile uninstall
$ sudo update-rc.d dphys-swapfile remove
І останній з конфігураційних кроків це налаштування cgroups (коротко це те, що дозволяє запускати контейнери на лінуксі):
$ orig="$(head -n1 /boot/cmdline.txt) cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1"
$ echo $orig | sudo tee /boot/cmdline.txt
Далі необхідно перезапустити малину:
$ sudo reboot
Тепер приступаємо до встановлення компонентів Kubernetes. Перш за все створюємо файл /etc/apt/sources.list.d/kubernetes.list і до нього добавляємо одну лінійку:
deb https://apt.kubernetes.io/ kubernetes-xenial main
Після цього можна встановити все за допомогою apt-get:
$ sudo apt-get update
$ sudo apt-get install -y kubelet kubeadm kubectl
$ sudo apt-mark hold kubelet kubeadm kubectl
Всі кроки, які ми виконали до цього моменту були спільні для всіх вузлів. Тепер переходимо конкретно на мастер і запускаємо наступну команду:
$ sudo kubeadm init --pod-network-cidr 10.244.0.0/16 --apiserver-advertise-address 10.0.0.1
Тут мушу вас засмутити, швидше за все через кілька хвилин ви отримаєте повідомлення про помилку. Перед тим як продовжити необхідно буде очистити все від сміття, для цього може скористатися командою:
$ sudo kubeadm reset
А тепер я спробую пояснити в чому проблема. Якщо коротко то kubelet кожних 15 секунд перевіряє kube-apiserver, чи йому вдалося нормально запуститися, а після 8 невдалих спроб він його вбиває і знову запускає. Але проблема в тому що двох хвилин явно замало на комп'ютері з 1Гб оперативної пам'яті, тому ми отримуємо процес в якому kubelet весь час вбиває, майже готового kube-apiserver. Мені експериментальним шляхом вдалося знайти невеличкий хак, який допоможе вам обійти цю проблему. Для цього повторюємо ініціалізацію кластеру, як тільки в консолі появиться надпис: 
[init] this might take a minute or longer if the control plane images have to be pulled
Виконуємо в іншому терміналі наступні дві команди:
$ sed -i 's/failureThreshold: 8/failureThreshold: 20/g' /etc/kubernetes/manifests/kube-apiserver.yaml$ docker kill `docker ps | grep POD_kube-apiserver | awk '{ print $1 }'`
Першою командою ми переписуємо ліміт в 8 спроб на 20 (тобто даємо kube-apiserver приблизно 5 хвилин на старт), а наступною перезапускаємо kube-apiserver. Якщо все пройде успішно, то за кілька хвилин ви повинні побачити в консолі приблизно наступний текст:


Виконаємо наступні команди, для того щоб могли користуватися утилітою kubectl:
$ mkdir -p $HOME/.kube$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
Також копіюємо команду, яку ви бачите на кінці. Переходимо на кожен з нодів і запускаємо її. Ви повинні побачити в консолі текст наступного вмісту:


Тепер спробуємо отримати інформацію про підключені ноди нашого кластера. Для цього на мастері запускаємо команду:
$ kubectl get nodes
Ви повинні побачити що всі ваші ноди не готові:


Це пов'язано з тим, що для правильної роботи Kubernetes необхідна спеціальна конфігурація внутрішної мережі (між подами які ми будемо запускати в майбутньому). На превелике щастя цю конфігурацію ми можемо здійснити за допомогою одної команди:
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
Якщо ви повторите через кілька хвилин команду kubectl get nodes то тепер статус нодів має змінитися на Ready.

Ну і як підсумок. Загалом процедура встановлення не є дуже складною. Багато шаманства пішло на конфігурацію мережі, а при запуску кластера необхідно було догадатися переписати одну змінну, але це проблема, яка не повинна виникнути при використанні більш потужніших машин. У випадку нодів нашаштування взагалі зайняло кілька хвилин і то більшість з них можна автоматизувати за допомогою невеличкого скрипта. В наступних статтях я постараюся детальніше пояснити архітектуру кластеру і для чого необхідний кожен з компонентів.

04 листопада 2018

Kubernetes кластер на Raspberry PI (налаштування мережі)

Цією публікацією я б хотів розпочати цикл статей по Kubernetes. Очевидно, що найкраще розказувати про цю технологію за допомогою прикладів на справжньому кластері. У вас до вибору є велика кількість хмарних провайдерів, які дозволять вам створити кластер (GKE, AKS, EKS тощо). Також можна зпустити певну імітацію кластера за допомогою Minikube, але це лише симуляція справжнього кластера. Я вибрав трохи інший підхід, який дозволить мені повністю контролювати все що відбувається у кластері, а саме зліпив його сам з кількох плат Raspberry PI. І перші дві статті я присвячую конфігурації цього кластера.

Розпочнемо, мабуть, зі списку необхідного оснащення:
  • Плата Raspberry PI 3B+. Мінімум 2 штуки, хоча я особисто не бачу великого сенсу в цьому. Щоб на повну вивчити можливості Kubernetes моя рекомендація це мінімум 4 плати. Також теоретично можна використати Raspberry PI 3B, все би мало працювати і там.
  • Ethernet Switch. Головна вимога кількість портів має бути більшою за кількість плат у вашому кластері. Я використав TP Link SF1008D.
  • USB power hub. Тут слід звернути увагу, що загальна потужність повинна бути хоча б 60W в іншому випадку через мале живлення малини просто не запустяться. Я взяв Unitek Y-P535.
  • MicroSD cards 8GB мінімум. Ніобхідно по одній на кожну плату. Зверніть увагу щоб клас швидкості був хоча б .U1
  • Мережеві кабелі - по одному на кожну клату.
  • Usb micro B кабелі - по одному на кожну плату (для зарядки).
Також звертаю увагу, що я користуюся лінуксом, тому деякі кроки, особливо на початку статті, можуть відрізнятися.

Для початку скачаємо образ операційної системи, яку запишемо на карти пам'яті. Для цього на офіційній сторінці вибираємо Raspbian Stretch Lite (в моєму випадку версія від 2018-10-09). Можна звичайно вибрати повну версію з графічним інтерфейсом, але не бачу в цьому жодної потреби - всю конфігурацю ми і так будемо здійснювати через консоль, а UI це додаткові ресурси, яких в нас і так малувато на нашому міні-комп'ютері.

Завантаживши архів, необхідно його розархівувати:
$ unzip 2018-06-27-raspbian-stretch-lite.zip
Тепер можна записати образ на одну з MicroSD карт. Я би рекомендував скористуватися програмкою Etcher (є версії для всіх операційних систем) або через консоль. Ця процедура повинна зайняти не більше кількох хвилин:


Також я рекомендую почати лише з двох карт (одну для master, інша для node). Після того як все буде сконфігуровано і працюватиме з двома, можна легко записати образи на інші.

Якщо у вас є додатковий монітор і клавіатура то можна їх підключити до Raspberry PI і тим самим уникнути розблокування доступу до малини через SSH (в останніх версіях системи, цей дозвіл є відключений по замовчуванню). Якщо ж ви бажаєте підключатися до всіх вузлів за допомогою свого комп'ютера то вам необхідно створити пустий файл з назвою "ssh" в boot розділі карти. У моєму випадку набір команд виглядав наступним чином:
$ sudo mkdir /media/sdcard
$ sudo mount /dev/sdc1 /media/sdcard
$ sudo touch /media/sdcard/ssh
$ sudo umount /media/sdcard
За допомогою перших двох команд я підключив карту до комп'ютера, далі створюю пустий файл і в кінці від'єднюю карту.

На цьому приготування системи для малини завершено. Виймаємо карту з вашого комп'ютера і запихаємо в одну з плат. Невеличка рекомендація від мене - позначити плату мастера (наприклад приклеїти радіатори іншим чином, використовувати кабелі інших кольорів, тощо) На даному етапі ми можемо забути на певний час про наш головний комп'ютер, надалі будемо працювати з малиною. Тут є два варіанти:
  1. Підключити до Raspberry PI клавіатуру та монітор.
  2. Підключити Raspberry PI до вашого роутера і залогінитися з допомогою SSH. 
В обох випадках необхідно буде ввести логін і пароль, за замовчуванням це pi та raspberry.

Якщо ви вибрали другий варіант, то необхідно підключити switch до вашого основного роутера і знайти IP-адрес малини. Для цього рекомендую зкористатися утилітою nmap. В моєму випадку команда виглядала наступним чином:
$ nmap -sP 192.168.1.0/24 | grep raspberrypi
Ця команда повинна вивести вам IP-адрес який ми використаємо для з'єднання:
$ sudo ssh pi@192.168.1.185
pi - це назва користувача по замовчуванню, а IP адреса взята з попереднього кроку. Далі буде необхідно ввести пароль (raspberry). Якщо ви все зробите правильно то повинні побачити в консолі приблизно наступний вміст:


Розпочнемо ми зі загальних налаштувань, вводимо:
$ sudo raspi-config
Перед вами появиться наступне меню, яке дозволяє поміняти базові налаштування:


Я би рекомендував пройтися по наступним пунктам:

1. Change User Password. Заради вашої ж безпеки, варто змінити пароль за замовчуванням.
2. Network Options > Hostname змінюємо на master (не обов'язково, але полегшить роботу).
3. Network Options > WiFi вибираємо країну, назву мережі і пароль. Теж бажано це зробити, щоб мастер міг комунікувати зі зовнішнім світом через інший канал зв'язку.
4. Localisation Options > Change Timezone. Виберіть свій часовий пояс.

Після цього вибираємо Finish і перезавантажуємо. Якщо ви були підключені через SSH то потрібно буде знову відновити з'єднання (використовуючи новий пароль).

Для перевірки WiFi можна скористатися командою iwconfig. Якщо ви побачите назву вашої точки доступу то значить все працює.

Наступний крок - встановлення редактора, яким вам найбільш до вподоби. В моєму випадку це був vim:
$ sudo apt-get install vim
Тепер можна приступити до налаштувань мережі. Перш за все я б виділив окрему статичну IP адресу для WiFi інтерфейсу. Цей крок загалом необовязковий якщо у вас буде постійний доступ до додаткової клавіатури та екрану, але якщо в майбутньому буде потреба залогінитися на master через SSH то ви зекономити собі час для пошуку IP адреси яку роутер надав йому. Отже відкриваємо файл /etc/dhcpcd.conf та додаємо до нього:
interface wlan0
static ip_address=192.168.1.151/24
static routers=192.168.1.1
static domain_name_servers=8.8.8.8
В цій конфігурації я "прошу" роутера за адресою 192.168.1.1 надати комп'ютеру IP адресу 192.168.1.151 через інтерфейс wlan0 (тобто WiFi). В останній лінійці я вписав IP адрес DNS сервера (стандартний від Google).

Наступний крок - встановлення DHCP сервера на мастері. Загалом без цього можна обійтися, але тоді прийдеться вручну прописувати IP адреси всіх нодів, а так це буде все здійснюватися автоматично.
$ sudo apt-get install isc-dhcp-server
На кінці процедури буде написано, що не вдалося запустити DHCP server, не переживайте так і має бути, оскільки ще нічого не було сконфігуровано. Для початку пропишемо статичну IP адресу для Ethernet порту, для цього додаємо до /etc/network/interfaces.d/eth0 (цілком можливо, що цей файл треба буде створити):
allow-hotplug eth0
iface eth0 inet static
  address 10.0.0.1
  netmask 255.255.255.0
  broadcast 10.0.0.255
  gateway 10.0.0.1

Наступне задаємо конфігурацію для dhcp сервера. Для цього відкриваємо файл /etc/dhcp/dhcpd.conf. Перш за все розкоментовуємо стрічку # authorative, і додаємо наступний блок:
subnet 10.0.0.0 netmask 255.255.255.0 {
  range 10.0.0.1 10.0.0.10;
  option subnet-mask 255.255.255.0;
  option broadcast-address 10.0.0.255;
  option routers 10.0.0.1;
  option domain-name "local-network";
  option domain-name-servers 8.8.8.8, 8.8.4.4;
}
І останній крок вказуємо для якого інтерфейсу буде працювати наш DHCP сервер. У файлі /etc/default/isc-dhcp-server необхідно задати значення: 
INTERFACEv4=”eth0”
Давайте тепер перезавантажемо комп'ютер, також рекомендую після цього відключити ваш switch від головного роутера, в іншому випадку наш мастер почне роздавати всім пристроям у вашій мережі IP адреси. Для під'єднання через SSH до мастера ми тепер можемо використати IP адресу, яку ми задали для інтерфейсу wlan0.

Тепер якщо ми під'єднаємо до нашого switch іншу малину мастер повинен автоматично надати їй IP адресу. Щоб її визначити необхідно знайти запис з client-hostname "raspberrypi" у файлі /var/lib/dhcp/dhcpd.leases:


Якщо ви хочете залогінитися через SSH на новий нод, то потрібно з мастера виконати наступну команду:
$ sudo ssh pi@10.0.0.4
Єдина проблема з цією нодою - відсутність доступу до інтернету. З цієї малини доступ буде лише до мастера:



Тобто нам потрібно налаштувати мастер подібно до роутера: всі пакети що приходять через один інтерфейс відправляються через інший в зовнішній світ. В нашому випадку всі пакети, що приходять через Ethernet порт, будуть запаковані і відправлені через WiFi. Для цього необхідно додати наступну конфігурацію до файлу /etc/rc.local (перед exit 0):
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
iptables -A FORWARD -i wlan0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i eth0 -o wlan0 -j ACCEPT
Також необхідно розкоментувати наступну лінійку в файлі /etc/sysctl.conf:
net.ipv4.ip_forward=1
На цьому конфігурація мережі мастера завершена. Перезавантажуємо його, логінимося на довільний нод і перевіряємо чи є у нас доступ до інтернету:



На цьому конфігурація мережі для нашого кластера завершена. Як ви мабуть замітили, основна робота полягала в правильній конфігурації мастера, а на всіх нодах все повинно працювати автоматично при підключенні їх до switch. В наступній частині ми встановимо Docker і необхідні компоненти для Kubernetes кластера на мастері і нодах.

30 липня 2018

Як NVIDIA знищує Linux

Це пост буде трохи невеличкою скаргою на те як лінивість компанії NVIDIA відлякує користувачів Linux.

Кілька днів назад вирішив побавитися з Tensorflow. Для того, щоб на повну використати його можливості, були необхідні додаткові бібліотеки від NVIDIA для CUDA. Перейшовши на офіційну сторінку по встановленню необхідних бібліотек, одним з перших рекомендованих кроків є оновлення драйверів. Мушу визнати, що сторінка зі скачуванням зроблена непогано якщо ти знаєш, яка в тебе карта і операційна система, то проблем зі скачуванням не буде.

Проблеми появляться при спробі встановити їх. Перш за все виникає помилка в якій вказано, що встановлення є неможливим при запущеному X сервері і нотаткою, що деталі можна знайти в README у них на сайті (який мені знайти не вдалося). Цілком очевидно, що на цьому кроці переважна більшість користувачів зупиниться. Але я людина не з лякливих, тому залогінився в консоль і вбив запущений на комп'ютері X server. А далі починається найцікавіше. Користувачам прийдеться працювати з інтерфейсом який нагадує старенький добрий MS-DOS. Під час встановлення будуть з'являтися питання про чи ви впевнені, що хочете замінити файл abracadabra.conf на новий, чи дійсно хочете переписати конфігурацію і тому подібне. Загалом слід очікувати не цілий десяток таких питань, які для 99% користувачів (число взято зі стелі) означає нічого. Чому не було зробити якусь default конфігурацію, яка задовільнить більшість користувачів, а решту опцій винести в advanced меню? Я вирішив не ризикувати, тим більш що я не є системним програмістом і всі ті попередження мені ніщо не говорили, тому тупо натискав Enter на всі питання.

За кілька хвилин після встановлення я з полегшенням бачу вікно входу в систему, вводжу свій логін і пароль і чую знайому мелодію. Думаєте це все? Якби ж то... За секунду я знову бачу вікно для входу в систему. Процедура безуспішно повторюється кілька разів. Плюнувши зі злості, йду гуглити на ноуті як відкотити драйвери NVIDIA. По кількості результатів, стає очевидно, що до останнього кроку добрався не тільки я і краще цієї процедури не повторювати. Запустивши кілька простих консольких команд (які працюють в рази надійніше за процедуру встановлення драйвера) я знову повертаюся до нормального робочого комп'ютера. Доведеться пробувати встановити бібліотеки для CUDA на поточний драйвер і надіятися, що все буде працювати.

Мораль - ніколи не перевстановлюйте драйвера NVIDIA, бо як сказала, колись одна розумна людина - NVIDIA, Fuck You!