В данной статье я хотел бы рассказать об установке Kubernetes на Hetzner Cloud.
На моем рабочем компьютере установлен Ubuntu Linux 18.04 и все примеры будут подразумевать использование данной операционной системы.
Для работы с Hetzner Cloud и построения кластера Kubernetes мы будем использовать утилиту hetzner-kube. Установим ее на свой локальный компьютер.
Для работы утилиты hetzner-kube и ее авторизации в Hetzner Cloud необходимо создать API Token через Hetzner Cloud Console https://console.hetzner.cloud. Вверху выбираем Select a project -> Default, в левом меню выбираем пункт Access, далее переходим в раздел API tokens, нажимаем на кнопку Generate API Token.
В результате будет сгенерирован API Token и его необходимо будет указать в конфигурации утилиты hetzner-kube.
Далее нам необходимо сгенерировать SSH ключ, который будет использоваться для доступа к серверам в Hetzner Cloud. Для этого воспользуемся утилитой ssh-keygen:
В результате в вашем домашнем каталоге будет создано два файла ~/.ssh/id_rsa (приватный ключ) и ~/.ssh/id_rsa.pub (публичный ключ).
Добавим публичный ssh ключ в Hetzner Cloud:
Непосредственно построение кластера Kubernetes выполняется очень легко:
Данная команда автоматически создаст виртуальные сервера в Hetzner Cloud и установит на них указанное количество master/worker нод кластера Kubernetes. По-умолчанию, будут использованы CX11 виртуальные сервера.
В дальнейшем, с помощью утилиты hetzner-kube, также легко изменить конфигурацию кластера Kubernetes добавляя worker ноды. Например, добавим 2 worker ноды:
К сожалению, изменить конфигурацию master нод с помощью утилиты hetzner-kube без полного пересоздания кластера Kubernetes на данный момент времени не представляется возможным.
Для работы с Kubernetes кластером используется утилита kubectl. Подробную инструкцию по ее установке для разных операционных систем можно найти по следующей ссылке.
Для того, чтобы работать с созданным кластером Kubernetes с помощью команды kubectl, необходимо сохранить локально конфигурацию созданного кластера следующим образом:
Файл с конфигурацией сохраняется в ~/.kube/config.
Теперь переходим к самому интересному — конфигурированию полученного кластера Kubernetes.
Для начала создадим базовые ресурсы необходимые для будущего развертывания приложений. Более подробную информацию вы сможете найти по следующей ссылке.
Добавляем сервис ingress-nginx, который будет обрабатывать запросы на портах 80 (http) и 443 (https) и перенаправлять их дальше на наше приложение. Вместо X.X.X.X указываем список внешних IP наших нод в кластере Kubernetes, которые будут обрабатывать запросы из Интернета (это могут быть как master, так и worker ноды, поскольку LoadBalancer в Hetzner Cloud на данный момент времени отсутствует).
Создаем файл с именем ingress-nginx.yaml и следующим содержимым:
Проверяем что nginx-ingress-controller и default-http-backend поды запущены.
Добавляем А записи в ваш домен и ждем пока информация о них появится в ДНС. Например:
Если в ingress-nginx.yaml вы указали несколько внешних IP адресов, то можно создать несколько одинаковых DNS записей с этими IP адресами. В этом случае запросы на ваш домен будут распределяться между этими IP адресами и будет происходить балансировка нагрузки.
В данном примере для работы https сгенерируем самоподписанный SSL сертификат.
Теперь добавляем наше приложение. В качестве примера выбран простой echoserver. Создаем файл с именем app.yaml и следующим содержимым:
На этом все )) Проверяем результат:
На моем рабочем компьютере установлен Ubuntu Linux 18.04 и все примеры будут подразумевать использование данной операционной системы.
Для работы с Hetzner Cloud и построения кластера Kubernetes мы будем использовать утилиту hetzner-kube. Установим ее на свой локальный компьютер.
$ wget https://github.com/xetys/hetzner-kube/releases/download/0.3.1/hetzner-kube-linux-amd64
$ chmod a+x ./hetzner-kube-linux-amd64
$ sudo mv ./hetzner-kube-linux-amd64 /usr/local/bin/hetzner-kube
Для работы утилиты hetzner-kube и ее авторизации в Hetzner Cloud необходимо создать API Token через Hetzner Cloud Console https://console.hetzner.cloud. Вверху выбираем Select a project -> Default, в левом меню выбираем пункт Access, далее переходим в раздел API tokens, нажимаем на кнопку Generate API Token.
В результате будет сгенерирован API Token и его необходимо будет указать в конфигурации утилиты hetzner-kube.
$ hetzner-kube context add k8s
Token: <PASTE TOKEN HERE>
added context 'k8s'
Далее нам необходимо сгенерировать SSH ключ, который будет использоваться для доступа к серверам в Hetzner Cloud. Для этого воспользуемся утилитой ssh-keygen:
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (~/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ~/.ssh/id_rsa.
Your public key has been saved in ~/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:1bwptZ8lPiAhtA37/2U1G7HsC+aE7qMVCtVIfN3OLzk lx4241@LX4241-LINUX
The key's randomart image is:
+---[RSA 2048]----+
| +. . . |
| ..*o+ . . |
| +o=.+ o. |
| .+ o +.oo|
| .S +.= .*+|
| . .+o+E+*|
| . o.+==o|
| o.+..+.|
| .oo.... |
+----[SHA256]-----+
В результате в вашем домашнем каталоге будет создано два файла ~/.ssh/id_rsa (приватный ключ) и ~/.ssh/id_rsa.pub (публичный ключ).
Добавим публичный ssh ключ в Hetzner Cloud:
$ hetzner-kube ssh-key add --name k8s
sshKeyAdd called
SSH key k8s(95430) created
Непосредственно построение кластера Kubernetes выполняется очень легко:
$ hetzner-kube cluster create --name k8s --ssh-key k8s --master-count 1 --worker-count 1
2018/08/02 13:57:57 Creating new cluster
NAME:k8s
MASTERS: 1
WORKERS: 1
ETCD NODES: 0
HA: false
ISOLATED ETCD: false
2018/08/02 13:57:58 creating server 'k8s-master-01'...
--- [======================================] 100%
2018/08/02 13:58:18 Created node 'k8s-master-01' with IP 159.69.54.228
2018/08/02 13:58:18 creating server 'k8s-worker-01'...
--- [======================================] 100%
2018/08/02 13:58:37 Created node 'k8s-worker-01' with IP 159.69.51.140
2018/08/02 13:58:37 sleep for 10s...
k8s-master-01 : complete! 100.0% [==============]
k8s-worker-01 : complete! 100.0% [==============]
2018/08/02 14:02:50 Cluster successfully created!
Данная команда автоматически создаст виртуальные сервера в Hetzner Cloud и установит на них указанное количество master/worker нод кластера Kubernetes. По-умолчанию, будут использованы CX11 виртуальные сервера.
В дальнейшем, с помощью утилиты hetzner-kube, также легко изменить конфигурацию кластера Kubernetes добавляя worker ноды. Например, добавим 2 worker ноды:
$ hetzner-kube cluster add-worker --name k8s --nodes 2
К сожалению, изменить конфигурацию master нод с помощью утилиты hetzner-kube без полного пересоздания кластера Kubernetes на данный момент времени не представляется возможным.
Для работы с Kubernetes кластером используется утилита kubectl. Подробную инструкцию по ее установке для разных операционных систем можно найти по следующей ссылке.
Для того, чтобы работать с созданным кластером Kubernetes с помощью команды kubectl, необходимо сохранить локально конфигурацию созданного кластера следующим образом:
$ hetzner-kube cluster kubeconfig k8s
create file
kubeconfig configured
Файл с конфигурацией сохраняется в ~/.kube/config.
Теперь переходим к самому интересному — конфигурированию полученного кластера Kubernetes.
Для начала создадим базовые ресурсы необходимые для будущего развертывания приложений. Более подробную информацию вы сможете найти по следующей ссылке.
$ curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml | kubectl apply -f -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 6170 100 6170 0 0 13987 0 --:--:-- --:--:-- --:--:-- 14022
namespace "ingress-nginx" created
deployment "default-http-backend" created
service "default-http-backend" created
configmap "nginx-configuration" created
configmap "tcp-services" created
configmap "udp-services" created
serviceaccount "nginx-ingress-serviceaccount" created
clusterrole "nginx-ingress-clusterrole" created
role "nginx-ingress-role" created
rolebinding "nginx-ingress-role-nisa-binding" created
clusterrolebinding "nginx-ingress-clusterrole-nisa-binding" created
deployment "nginx-ingress-controller" created
Добавляем сервис ingress-nginx, который будет обрабатывать запросы на портах 80 (http) и 443 (https) и перенаправлять их дальше на наше приложение. Вместо X.X.X.X указываем список внешних IP наших нод в кластере Kubernetes, которые будут обрабатывать запросы из Интернета (это могут быть как master, так и worker ноды, поскольку LoadBalancer в Hetzner Cloud на данный момент времени отсутствует).
Создаем файл с именем ingress-nginx.yaml и следующим содержимым:
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
spec:
type:
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
- name: https
port: 443
targetPort: 443
protocol: TCP
selector:
app: ingress-nginx
externalIPs:
- X.X.X.X
- X.X.X.X
$ kubectl apply -f ingress-nginx.yaml
service "ingress-nginx" configured
Проверяем что nginx-ingress-controller и default-http-backend поды запущены.
$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
default-http-backend-55c6c69b88-hvl4x 1/1 Running 0 51m
nginx-ingress-controller-6658c97f58-d6jkg 1/1 Running 0 51m
Добавляем А записи в ваш домен и ждем пока информация о них появится в ДНС. Например:
Type: A
Name: echo.example.com
Value: X.X.X.X
Если в ingress-nginx.yaml вы указали несколько внешних IP адресов, то можно создать несколько одинаковых DNS записей с этими IP адресами. В этом случае запросы на ваш домен будут распределяться между этими IP адресами и будет происходить балансировка нагрузки.
В данном примере для работы https сгенерируем самоподписанный SSL сертификат.
$ openssl req -newkey rsa:2048 -nodes -keyout echo.example.com.key -x509 -days 365 -out echo.example.com.crt
Generating a 2048 bit RSA private key
..+++
.............+++
writing new private key to 'echo.example.com.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:UA
State or Province Name (full name) [Some-State]:Kyiv
Locality Name (eg, city) []:Kyiv
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Super Company Ltd
Organizational Unit Name (eg, section) []:echo.example.com
Common Name (e.g. server FQDN or YOUR name) []:echo.example.com
Email Address []:info@echo.example.com
$ cat echo.example.com.key | base64 | tr -d '\n'
<YOUR PRIVATE KEY>
$ cat echo.example.com.crt | base64 | tr -d '\n'
<YOUR CERTIFICATE>
Теперь добавляем наше приложение. В качестве примера выбран простой echoserver. Создаем файл с именем app.yaml и следующим содержимым:
apiVersion: v1
kind: Namespace
metadata:
name: echoserver
---
kind: Secret
metadata:
name: echo.example.com-tls
namespace: echoserver
type: kubernetes.io/tls
data:
tls.crt: <YOUR CERTIFICATE>
tls.key: <YOUR PRIVATE KEY>
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: echoserver
namespace: echoserver
spec:
replicas: 1
template:
metadata:
labels:
app: echoserver
spec:
containers:
- image: gcr.io/google_containers/echoserver:1.0
imagePullPolicy: Always
name: echoserver
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: echoserver
namespace: echoserver
spec:
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
selector:
app: echoserver
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echoserver
namespace: echoserver
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- echo.example.com
secretName: echo.example.com-tls
rules:
- host: echo.example.com
http:
paths:
- path: /
backend:
serviceName: echoserver
servicePort: 80
$ kubectl apply -f app.yaml
namespace "echoserver" configured
deployment "echoserver" unchanged
service "echoserver" configured
ingress "echoserver" unchanged
На этом все )) Проверяем результат:
$ curl https://echo.example.com/
CLIENT VALUES:
client_address=('10.244.3.2', 32860) (10.244.3.2)
command=GET
path=/
real path=/
query=
request_version=HTTP/1.1
SERVER VALUES:
server_version=BaseHTTP/0.6
sys_version=Python/3.5.0
protocol_version=HTTP/1.0
HEADERS RECEIVED:
Accept=*/*
Connection=close
Host=echo.example.com
User-Agent=curl/7.58.0
X-Forwarded-For=10.244.0.0
X-Forwarded-Host=echo.example.com
X-Forwarded-Port=80
X-Forwarded-Proto=http
X-Original-URI=/
X-Real-IP=10.244.0.0
X-Request-ID=7a4f4aabf9a0043ea2b1ca91bd1a3adf
X-Scheme=http
de1m
А как там со storag'oм, я как понял, общего нету?
AlexeiPotocki Автор
К сожалению, пока нету, но думаю появится в скором времени. Ну и цена конечно очень вкусная что перекрывает все остальное )
de1m
По идее можно запустить сeph в контейнерах. У нас там тоже четыре сервера с k8s стоят, но я их сам устанавливал и на них ceph стоит, гигабитной сети пока хватает.