[DevOps, Kubernetes] Минимально жизнеспособный Kubernetes (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Перевод статьи подготовлен в преддверии старта курса «DevOps практики и инструменты».
Если вы это читаете, вероятно, вы что-то слышали о Kubernetes (а если нет, то как вы здесь оказались?) Но что же на самом деле представляет собой Kubernetes? Это “Оркестрация контейнеров промышленного уровня”? Или «Cloud-Native Operating System»? Что вообще это значит?
Честно говоря, я не уверен на 100%. Но думаю интересно покопаться во внутренностях и посмотреть, что на самом деле происходит в Kubernetes под его многими слоями абстракций. Так что ради интереса, давайте посмотрим, как на самом деле выглядит минимальный “кластер Kubernetes”. (Это будет намного проще, чем Kubernetes The Hard Way.)
Я полагаю, что у вас есть базовые знания Kubernetes, Linux и контейнеров. Все, о чем мы здесь будем говорить предназначено только для исследования/изучения, не запускайте ничего из этого в продакшене!
Обзор
Kubernetes содержит много компонент. Согласно википедии, архитектура выглядит следующим образом:
Здесь показано, по крайней мере, восемь компонент, но большинство из них мы проигнорируем. Я хочу заявить, что минимальная вещь, которую можно обоснованно назвать Kubernetes, состоит из трех основных компонент:
- kubelet
- kube-apiserver (который зависит от etcd — его базы данных)
- среда выполнения контейнера (в данном случае Docker)
Давайте посмотрим, что о каждом из них говорится в документации (рус., англ.). Сначала kubelet:
Агент, работающий на каждом узле в кластере. Он следит за тем, чтобы контейнеры были запущены в поде.
Звучит достаточно просто. Что насчет среды выполнения контейнеров (container runtime)?
Среда выполнения контейнера — это программа, предназначенная для выполнения контейнеров.
Очень информативно. Но если вы знакомы с Docker, то у вас должно быть общее представление о том, что он делает. (Детали разделения ответственностей между средой выполнения контейнеров и kubelet на самом деле довольно тонкие и здесь я не буду в них углубляться.)
И API-сервер?
Сервер API — компонент Kubernetes панели управления, который представляет API Kubernetes. API-сервер — это клиентская часть панели управления Kubernetes
Любому, кто когда-либо что-либо делал с Kubernetes, приходилось взаимодействовать с API либо напрямую, либо через kubectl. Это сердце того, что делает Kubernetes Kubernetes’ом — мозг, превращающий горы YAML, который мы все знаем и любим (?), в работающую инфраструктуру. Кажется очевидным, что API должен присутствовать в нашей минимальной конфигурации.
Предварительные условия
- Виртуальная или физическая машина Linux с root-доступом (я использую Ubuntu 18.04 на виртуальной машине).
- И это все!
Скучная установка
На машину, которую мы будем использовать необходимо установить Docker. (Я не собираюсь подробно рассказывать как работает Docker и контейнеры; если вам интересно, есть замечательные статьи). Давайте просто установим его с помощью apt:
$ sudo apt install docker.io
$ sudo systemctl start docker
После этого нам нужно получить бинарники Kubernetes. На самом деле для начального запуска нашего “кластера” нам нужен только kubelet, так как для запуска других серверных компонент мы сможем использовать kubelet. Для взаимодействия с нашим кластером после того как он заработает, мы также будем использовать kubectl.
$ curl -L https://dl.k8s.io/v1.18.5/kubernetes-server-linux-amd64.tar.gz > server.tar.gz
$ tar xzvf server.tar.gz
$ cp kubernetes/server/bin/kubelet .
$ cp kubernetes/server/bin/kubectl .
$ ./kubelet --version
Kubernetes v1.18.5
Что произойдет, если мы просто запустим kubelet?
$ ./kubelet
F0609 04:03:29.105194 4583 server.go:254] mkdir /var/lib/kubelet: permission denied
kubelet должен работать от root. Достаточно логично, так как ему надо управлять всем узлом. Давайте посмотрим на его параметры:
$ ./kubelet -h
<слишком много строк, чтобы разместить здесь>
$ ./kubelet -h | wc -l
284
Ого, как много опций! К счастью, нам понадобится только пара из них. Вот один из параметров, который нам интересен:
--pod-manifest-path string
Путь к каталогу, содержащему файлы для статических подов, или путь к файлу с описанием статических подов. Файлы, начинающиеся с точек, игнорируются. (УСТАРЕЛО: этот параметр следует устанавливать в конфигурационном файле, передаваемом в Kubelet через опцию --config. Для дополнительной информации см. kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)
Этот параметр позволяет нам запускать статические поды — поды, которые не управляются через Kubernetes API. Статические поды используются редко, но они очень удобны для быстрого поднятия кластера, а это именно то, что нам нужно. Мы проигнорируем это громкое предупреждение (опять же, не запускайте это в проде!) и посмотрим, сможем ли мы запустить под.
Сначала мы создадим каталог для статических подов и запустим kubelet:
$ mkdir pods
$ sudo ./kubelet --pod-manifest-path=pods
Затем в другом терминале/окне tmux/еще где-то, мы создадим манифест пода:
$ cat <<EOF > pods/hello.yaml
apiVersion: v1
kind: Pod
metadata:
name: hello
spec:
containers:
- image: busybox
name: hello
command: ["echo", "hello world!"]
EOF
kubelet начинает писать какие-то предупреждения и кажется, что ничего не происходит. Но это не так! Давайте посмотрим на Docker:
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c8a35e26663 busybox "echo 'hello world!'" 36 seconds ago Exited (0) 36 seconds ago k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
68f670c3c85f k8s.gcr.io/pause:3.2 "/pause" 2 minutes ago Up 2 minutes k8s_POD_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_0
$ sudo docker logs k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
hello world!
kubelet прочитал манифест пода и дал Docker’у команду запустить пару контейнеров в соответствии с нашей спецификацией. (Если вам интересно узнать про контейнер “pause”, то это хакерство Kubernetes — подробности смотрите в этом блоге.) Kubelet запустит наш контейнер busybox с указанной командой и будет перезапускать его бесконечно, пока статический под не будет удален.
Поздравьте себя. Мы только что придумали один из самых запутанных способов вывода текста в терминал!
Запускаем etcd
Нашей конечной целью является запуск Kubernetes API, но для этого нам сначала нужно запустить etcd. Давайте запустим минимальный кластер etcd, поместив его настройки в каталог pods (например, pods/etcd.yaml):
apiVersion: v1
kind: Pod
metadata:
name: etcd
namespace: kube-system
spec:
containers:
- name: etcd
command:
- etcd
- --data-dir=/var/lib/etcd
image: k8s.gcr.io/etcd:3.4.3-0
volumeMounts:
- mountPath: /var/lib/etcd
name: etcd-data
hostNetwork: true
volumes:
- hostPath:
path: /var/lib/etcd
type: DirectoryOrCreate
name: etcd-data
Если вы когда-либо работали с Kubernetes, то подобные YAML-файлы должны быть вам знакомы. Здесь стоит отметить только два момента:
Мы смонтировали папку хоста /var/lib/etcd в под, чтобы данные etcd сохранялись после перезапуска (если этого не сделать, то состояние кластера будет стираться при каждом перезапуске пода, что будет нехорошо даже для минимальной установки Kubernetes).
Мы установили hostNetwork: true. Этот параметр, что неудивительно, настраивает etcd для использования сети хоста вместо внутренней сети пода (это облегчит API-серверу поиск кластера etcd).
Простая проверка показывает, что etcd действительно запущен на localhost и сохраняет данные на диск:
$ curl localhost:2379/version
{"etcdserver":"3.4.3","etcdcluster":"3.4.0"}
$ sudo tree /var/lib/etcd/
/var/lib/etcd/
└── member
├── snap
│ └── db
└── wal
├── 0.tmp
└── 0000000000000000-0000000000000000.wal
Запуск API-сервера
Запустить API-сервер Kubernetes еще проще. Единственный параметр, который надо передать, --etcd-servers, делает то, что вы ожидаете:
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
- --etcd-servers=http://127.0.0.1:2379
image: k8s.gcr.io/kube-apiserver:v1.18.5
hostNetwork: true
Поместите этот YAML-файл в каталог pods, и API-сервер запустится. Проверка с помощью curl показывает, что Kubernetes API прослушивает порт 8080 с полностью открытым доступом — аутентификация не требуется!
$ curl localhost:8080/healthz
ok
$ curl localhost:8080/api/v1/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/pods",
"resourceVersion": "59"
},
"items": []
}
(Опять же, не запускайте это в продакшене! Я был немного удивлен, что настройка по умолчанию настолько небезопасна. Но я предполагаю, что это сделано для облегчения разработки и тестирования.)
И, приятный сюрприз, kubectl работает из коробки без каких-либо дополнительных настроек!
$ ./kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:47:41Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:39:24Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
$ ./kubectl get pod
No resources found in default namespace.
Проблема
Но если копнуть немного глубже, то кажется, что что-то идет не так:
$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.
Статические поды, которые мы создали, пропали! На самом деле, наш kubelet-узел вообще не обнаруживается:
$ ./kubectl get nodes
No resources found in default namespace.
В чем же дело? Если вы помните, то несколько абзацев назад мы запускали kubelet с чрезвычайно простым набором параметров командной строки, поэтому kubelet не знает, как связаться с сервером API и уведомлять его о своем состоянии. Изучив документацию, мы находим соответствующий флаг:
--kubeconfig string
Путь к файлу kubeconfig, в котором указано как подключаться к серверу API. Наличие --kubeconfig включает режим API-сервера, отсутствие --kubeconfig включает автономный режим.
Все это время, сами того не зная, мы запускали kubelet в «автономном режиме». (Если бы мы были педантичны, то можно было считать автономный режим kubelet как «минимально жизнеспособный Kubernetes», но это было бы очень скучно). Чтобы заработала «настоящая» конфигурация, нам нужно передать файл kubeconfig в kubelet, чтобы он знал, как общаться с API-сервером. К счастью, это довольно просто (так как у нас нет проблем с аутентификацией или сертификатами):
apiVersion: v1
kind: Config
clusters:
- cluster:
server: http://127.0.0.1:8080
name: mink8s
contexts:
- context:
cluster: mink8s
name: mink8s
current-context: mink8s
Сохраните это как kubeconfig.yaml, убейте процесс kubelet и перезапустите с необходимыми параметрами:
$ sudo ./kubelet --pod-manifest-path=pods --kubeconfig=kubeconfig.yaml
(Кстати, если вы попытаетесь обратиться к API через curl, когда kubelet не работает, то вы обнаружите, что он все еще работает! Kubelet не является «родителем» своих подов, подобно Docker’у, он больше похож на “управляющего демона”. Контейнеры, управляемые kubelet, будут работать, пока kubelet не остановит их.)
Через несколько минут kubectl должен показать нам поды и узлы, как мы и ожидаем:
$ ./kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
default hello-mink8s 0/1 CrashLoopBackOff 261 21h
kube-system etcd-mink8s 1/1 Running 0 21h
kube-system kube-apiserver-mink8s 1/1 Running 0 21h
$ ./kubectl get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
mink8s Ready <none> 21h v1.18.5 10.70.10.228 <none> Ubuntu 18.04.4 LTS 4.15.0-109-generic docker://19.3.6
Давайте на этот раз поздравим себя по-настоящему (я знаю, что уже поздравлял) — у нас получился минимальный «кластер» Kubernetes, работающий с полнофункциональным API!
Запускаем под
Теперь посмотрим на что способен API. Начнем с пода nginx:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
Здесь мы получим довольно интересную ошибку:
$ ./kubectl apply -f nginx.yaml
Error from server (Forbidden): error when creating "nginx.yaml": pods "nginx" is
forbidden: error looking up service account default/default: serviceaccount
"default" not found
$ ./kubectl get serviceaccounts
No resources found in default namespace.
Здесь мы видим насколько ужасающе неполна наша среда Kubernetes — у нас нет учетных записей для служб. Давайте попробуем еще раз, создав учетную запись службы вручную, и посмотрим, что произойдет:
$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
EOS
serviceaccount/default created
$ ./kubectl apply -f nginx.yaml
Error from server (ServerTimeout): error when creating "nginx.yaml": No API
token found for service account "default", retry after the token is
automatically created and added to the service account
Даже когда мы создали учетную запись службы вручную, токен аутентификации не создается. Продолжая экспериментировать с нашим минималистичным «кластером», мы обнаружим, что большинство полезных вещей, которые обычно происходят автоматически, будут отсутствовать. Сервер Kubernetes API довольно минималистичен, большая часть тяжелых автоматических настроек происходит в различных контроллерах и фоновых заданиях, которые еще не выполняются.
Мы можем обойти эту проблему, установив опцию automountServiceAccountToken для учетной записи службы (так как нам все равно не придется ее использовать):
$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
automountServiceAccountToken: false
EOS
serviceaccount/default configured
$ ./kubectl apply -f nginx.yaml
pod/nginx created
$ ./kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 0/1 Pending 0 13m
Наконец, под появился! Но на самом деле он не запустится, так как у нас нет планировщика(scheduler) — еще одного важного компонента Kubernetes. Опять же, мы видим, что API Kubernetes на удивление «глупый» — когда вы создаете под в API, он его регистрирует, но не пытается выяснить, на каком узле его запускать.
На самом деле для запуска пода планировщик не нужен. Можно вручную добавить узел в манифест в параметре nodeName:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
nodeName: mink8s
(Замените mink8s на название узла.) После delete и apply мы видим, что nginx запустился и слушает внутренний IP-адрес:
$ ./kubectl delete pod nginx
pod "nginx" deleted
$ ./kubectl apply -f nginx.yaml
pod/nginx created
$ ./kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 30s 172.17.0.2 mink8s <none> <none>
$ curl -s 172.17.0.2 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
Чтобы убедиться, что сеть между подами работает корректно, мы можем запустить curl из другого пода:
$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: curl
spec:
containers:
- image: curlimages/curl
name: curl
command: ["curl", "172.17.0.2"]
nodeName: mink8s
EOS
pod/curl created
$ ./kubectl logs curl | head -6
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
Довольно интересно покопаться в этом окружении и посмотреть, что работает, а что нет. Я обнаружил, что ConfigMap и Secret работают так, как и ожидается, а Service и Deployment нет.
Успех!
Этот пост становится большим, поэтому я собираюсь объявить о победе и заявить, что это жизнеспособная конфигурация, которую можно назвать “Kubernetes". Резюмируя: четыре бинарных файла, пять параметров командной строки и “всего лишь” 45 строк YAML (не так много по стандартам Kubernetes) и у нас работает немало вещей:
- Поды управляются с помощью обычного Kubernetes API (с несколькими хаками)
- Можно загружать публичные образы контейнеров и управлять ими
- Поды остаются живыми и автоматически перезапускаются
- Сеть между подами в рамках одного узла работает довольно хорошо
- ConfigMap, Secret и простейшее монтирование хранилищ работает как положено
Но большая часть из того, что делает Kubernetes по-настоящему полезным, все еще отсутствует, например:
- Планировщик подов
- Аутентификация / авторизация
- Несколько узлов
- Сеть сервисов
- Кластерный внутренний DNS
- Контроллеры для учетных записей служб, развертываний, интеграции с облачными провайдерами и большинство других “плюшек”, которые приносит Kubernetes
Так что же мы на самом деле получили? Kubernetes API, работающий сам по себе, на самом деле, является всего лишь платформой для автоматизации контейнеров. Он не делает много — это работа для различных контроллеров и операторов, использующих API, — но он обеспечивает консистентную среду для автоматизации.
Узнать подробнее о курсе на бесплатном вебинаре.
Читать еще:
- Зачем сисадминам, разработчикам и тестировщикам изучать DevOps практики?
- Thanos — масштабируемый Prometheus
- Как QA-команда GitLab использует GitLab Performance Tool
- Loki — сбор логов, используя подход Prometheus
- Один день из жизни DevOps
===========
Источник:
habr.com
===========
===========
Автор оригинала: Emanuel Evans
===========Похожие новости:
- [Open source, Openshift, Виртуализация, Учебный процесс в IT] НеНуАЧо – сами выпускаем OpenShift 4.5, сами гордимся
- [DevOps, Карьера в IT-индустрии, Системное администрирование] Как увлеличить доход сисадмина в 4 раза за три года
- [DevOps, Kubernetes, Серверное администрирование, Системное администрирование] Docker и все, все, все
- [Swift, Машинное обучение, Программирование, Разработка под iOS] Реализуем машинное обучение на iOS устройстве с использованием Core ML, Swift и Neural Engine (перевод)
- [DevOps, Карьера в IT-индустрии, Управление проектами, Управление разработкой] Анонс бесплатного вебинара «Фантастические Девопсы и где они обитают»
- [DevOps, Серверное администрирование] Триллер о настройке серверов без чудес с Configuration Management
- [DevOps, Kubernetes, Системное администрирование, Тестирование веб-сервисов] Canary Deployment в Kubernetes #2: Argo Rollouts (перевод)
- [Информационная безопасность, Программирование, Разработка под Linux] Побег из привилегированных Docker-контейнеров (перевод)
- [Облачные вычисления, Настройка Linux, DevOps, Серверное администрирование, Системное администрирование] Основы Ansible, без которых ваши плейбуки — комок слипшихся макарон, часть 3
- [DevOps, Kubernetes, Микросервисы, Системное администрирование] Сценарии использования service mesh (перевод)
Теги для поиска: #_devops, #_kubernetes, #_kuber, #_devops, #_kubectl, #_kubelet, #_blog_kompanii_otus._onlajnobrazovanie (
Блог компании OTUS. Онлайн-образование
), #_devops, #_kubernetes
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 00:29
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Перевод статьи подготовлен в преддверии старта курса «DevOps практики и инструменты». Если вы это читаете, вероятно, вы что-то слышали о Kubernetes (а если нет, то как вы здесь оказались?) Но что же на самом деле представляет собой Kubernetes? Это “Оркестрация контейнеров промышленного уровня”? Или «Cloud-Native Operating System»? Что вообще это значит? Честно говоря, я не уверен на 100%. Но думаю интересно покопаться во внутренностях и посмотреть, что на самом деле происходит в Kubernetes под его многими слоями абстракций. Так что ради интереса, давайте посмотрим, как на самом деле выглядит минимальный “кластер Kubernetes”. (Это будет намного проще, чем Kubernetes The Hard Way.) Я полагаю, что у вас есть базовые знания Kubernetes, Linux и контейнеров. Все, о чем мы здесь будем говорить предназначено только для исследования/изучения, не запускайте ничего из этого в продакшене! Обзор Kubernetes содержит много компонент. Согласно википедии, архитектура выглядит следующим образом: Здесь показано, по крайней мере, восемь компонент, но большинство из них мы проигнорируем. Я хочу заявить, что минимальная вещь, которую можно обоснованно назвать Kubernetes, состоит из трех основных компонент:
Давайте посмотрим, что о каждом из них говорится в документации (рус., англ.). Сначала kubelet: Агент, работающий на каждом узле в кластере. Он следит за тем, чтобы контейнеры были запущены в поде. Звучит достаточно просто. Что насчет среды выполнения контейнеров (container runtime)? Среда выполнения контейнера — это программа, предназначенная для выполнения контейнеров. Очень информативно. Но если вы знакомы с Docker, то у вас должно быть общее представление о том, что он делает. (Детали разделения ответственностей между средой выполнения контейнеров и kubelet на самом деле довольно тонкие и здесь я не буду в них углубляться.) И API-сервер? Сервер API — компонент Kubernetes панели управления, который представляет API Kubernetes. API-сервер — это клиентская часть панели управления Kubernetes Любому, кто когда-либо что-либо делал с Kubernetes, приходилось взаимодействовать с API либо напрямую, либо через kubectl. Это сердце того, что делает Kubernetes Kubernetes’ом — мозг, превращающий горы YAML, который мы все знаем и любим (?), в работающую инфраструктуру. Кажется очевидным, что API должен присутствовать в нашей минимальной конфигурации. Предварительные условия
Скучная установка На машину, которую мы будем использовать необходимо установить Docker. (Я не собираюсь подробно рассказывать как работает Docker и контейнеры; если вам интересно, есть замечательные статьи). Давайте просто установим его с помощью apt: $ sudo apt install docker.io
$ sudo systemctl start docker После этого нам нужно получить бинарники Kubernetes. На самом деле для начального запуска нашего “кластера” нам нужен только kubelet, так как для запуска других серверных компонент мы сможем использовать kubelet. Для взаимодействия с нашим кластером после того как он заработает, мы также будем использовать kubectl. $ curl -L https://dl.k8s.io/v1.18.5/kubernetes-server-linux-amd64.tar.gz > server.tar.gz
$ tar xzvf server.tar.gz $ cp kubernetes/server/bin/kubelet . $ cp kubernetes/server/bin/kubectl . $ ./kubelet --version Kubernetes v1.18.5 Что произойдет, если мы просто запустим kubelet? $ ./kubelet
F0609 04:03:29.105194 4583 server.go:254] mkdir /var/lib/kubelet: permission denied kubelet должен работать от root. Достаточно логично, так как ему надо управлять всем узлом. Давайте посмотрим на его параметры: $ ./kubelet -h
<слишком много строк, чтобы разместить здесь> $ ./kubelet -h | wc -l 284 Ого, как много опций! К счастью, нам понадобится только пара из них. Вот один из параметров, который нам интересен: --pod-manifest-path string
Путь к каталогу, содержащему файлы для статических подов, или путь к файлу с описанием статических подов. Файлы, начинающиеся с точек, игнорируются. (УСТАРЕЛО: этот параметр следует устанавливать в конфигурационном файле, передаваемом в Kubelet через опцию --config. Для дополнительной информации см. kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .) Этот параметр позволяет нам запускать статические поды — поды, которые не управляются через Kubernetes API. Статические поды используются редко, но они очень удобны для быстрого поднятия кластера, а это именно то, что нам нужно. Мы проигнорируем это громкое предупреждение (опять же, не запускайте это в проде!) и посмотрим, сможем ли мы запустить под. Сначала мы создадим каталог для статических подов и запустим kubelet: $ mkdir pods
$ sudo ./kubelet --pod-manifest-path=pods Затем в другом терминале/окне tmux/еще где-то, мы создадим манифест пода: $ cat <<EOF > pods/hello.yaml
apiVersion: v1 kind: Pod metadata: name: hello spec: containers: - image: busybox name: hello command: ["echo", "hello world!"] EOF kubelet начинает писать какие-то предупреждения и кажется, что ничего не происходит. Но это не так! Давайте посмотрим на Docker: $ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8c8a35e26663 busybox "echo 'hello world!'" 36 seconds ago Exited (0) 36 seconds ago k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4 68f670c3c85f k8s.gcr.io/pause:3.2 "/pause" 2 minutes ago Up 2 minutes k8s_POD_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_0 $ sudo docker logs k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4 hello world! kubelet прочитал манифест пода и дал Docker’у команду запустить пару контейнеров в соответствии с нашей спецификацией. (Если вам интересно узнать про контейнер “pause”, то это хакерство Kubernetes — подробности смотрите в этом блоге.) Kubelet запустит наш контейнер busybox с указанной командой и будет перезапускать его бесконечно, пока статический под не будет удален. Поздравьте себя. Мы только что придумали один из самых запутанных способов вывода текста в терминал! Запускаем etcd Нашей конечной целью является запуск Kubernetes API, но для этого нам сначала нужно запустить etcd. Давайте запустим минимальный кластер etcd, поместив его настройки в каталог pods (например, pods/etcd.yaml): apiVersion: v1
kind: Pod metadata: name: etcd namespace: kube-system spec: containers: - name: etcd command: - etcd - --data-dir=/var/lib/etcd image: k8s.gcr.io/etcd:3.4.3-0 volumeMounts: - mountPath: /var/lib/etcd name: etcd-data hostNetwork: true volumes: - hostPath: path: /var/lib/etcd type: DirectoryOrCreate name: etcd-data Если вы когда-либо работали с Kubernetes, то подобные YAML-файлы должны быть вам знакомы. Здесь стоит отметить только два момента: Мы смонтировали папку хоста /var/lib/etcd в под, чтобы данные etcd сохранялись после перезапуска (если этого не сделать, то состояние кластера будет стираться при каждом перезапуске пода, что будет нехорошо даже для минимальной установки Kubernetes). Мы установили hostNetwork: true. Этот параметр, что неудивительно, настраивает etcd для использования сети хоста вместо внутренней сети пода (это облегчит API-серверу поиск кластера etcd). Простая проверка показывает, что etcd действительно запущен на localhost и сохраняет данные на диск: $ curl localhost:2379/version
{"etcdserver":"3.4.3","etcdcluster":"3.4.0"} $ sudo tree /var/lib/etcd/ /var/lib/etcd/ └── member ├── snap │ └── db └── wal ├── 0.tmp └── 0000000000000000-0000000000000000.wal Запуск API-сервера Запустить API-сервер Kubernetes еще проще. Единственный параметр, который надо передать, --etcd-servers, делает то, что вы ожидаете: apiVersion: v1
kind: Pod metadata: name: kube-apiserver namespace: kube-system spec: containers: - name: kube-apiserver command: - kube-apiserver - --etcd-servers=http://127.0.0.1:2379 image: k8s.gcr.io/kube-apiserver:v1.18.5 hostNetwork: true Поместите этот YAML-файл в каталог pods, и API-сервер запустится. Проверка с помощью curl показывает, что Kubernetes API прослушивает порт 8080 с полностью открытым доступом — аутентификация не требуется! $ curl localhost:8080/healthz
ok $ curl localhost:8080/api/v1/pods { "kind": "PodList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/pods", "resourceVersion": "59" }, "items": [] } (Опять же, не запускайте это в продакшене! Я был немного удивлен, что настройка по умолчанию настолько небезопасна. Но я предполагаю, что это сделано для облегчения разработки и тестирования.) И, приятный сюрприз, kubectl работает из коробки без каких-либо дополнительных настроек! $ ./kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:47:41Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:39:24Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"} $ ./kubectl get pod No resources found in default namespace. Проблема Но если копнуть немного глубже, то кажется, что что-то идет не так: $ ./kubectl get pod -n kube-system
No resources found in kube-system namespace. Статические поды, которые мы создали, пропали! На самом деле, наш kubelet-узел вообще не обнаруживается: $ ./kubectl get nodes
No resources found in default namespace. В чем же дело? Если вы помните, то несколько абзацев назад мы запускали kubelet с чрезвычайно простым набором параметров командной строки, поэтому kubelet не знает, как связаться с сервером API и уведомлять его о своем состоянии. Изучив документацию, мы находим соответствующий флаг: --kubeconfig string Путь к файлу kubeconfig, в котором указано как подключаться к серверу API. Наличие --kubeconfig включает режим API-сервера, отсутствие --kubeconfig включает автономный режим. Все это время, сами того не зная, мы запускали kubelet в «автономном режиме». (Если бы мы были педантичны, то можно было считать автономный режим kubelet как «минимально жизнеспособный Kubernetes», но это было бы очень скучно). Чтобы заработала «настоящая» конфигурация, нам нужно передать файл kubeconfig в kubelet, чтобы он знал, как общаться с API-сервером. К счастью, это довольно просто (так как у нас нет проблем с аутентификацией или сертификатами): apiVersion: v1
kind: Config clusters: - cluster: server: http://127.0.0.1:8080 name: mink8s contexts: - context: cluster: mink8s name: mink8s current-context: mink8s Сохраните это как kubeconfig.yaml, убейте процесс kubelet и перезапустите с необходимыми параметрами: $ sudo ./kubelet --pod-manifest-path=pods --kubeconfig=kubeconfig.yaml
(Кстати, если вы попытаетесь обратиться к API через curl, когда kubelet не работает, то вы обнаружите, что он все еще работает! Kubelet не является «родителем» своих подов, подобно Docker’у, он больше похож на “управляющего демона”. Контейнеры, управляемые kubelet, будут работать, пока kubelet не остановит их.) Через несколько минут kubectl должен показать нам поды и узлы, как мы и ожидаем: $ ./kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE default hello-mink8s 0/1 CrashLoopBackOff 261 21h kube-system etcd-mink8s 1/1 Running 0 21h kube-system kube-apiserver-mink8s 1/1 Running 0 21h $ ./kubectl get nodes -owide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME mink8s Ready <none> 21h v1.18.5 10.70.10.228 <none> Ubuntu 18.04.4 LTS 4.15.0-109-generic docker://19.3.6 Давайте на этот раз поздравим себя по-настоящему (я знаю, что уже поздравлял) — у нас получился минимальный «кластер» Kubernetes, работающий с полнофункциональным API! Запускаем под Теперь посмотрим на что способен API. Начнем с пода nginx: apiVersion: v1
kind: Pod metadata: name: nginx spec: containers: - image: nginx name: nginx Здесь мы получим довольно интересную ошибку: $ ./kubectl apply -f nginx.yaml
Error from server (Forbidden): error when creating "nginx.yaml": pods "nginx" is forbidden: error looking up service account default/default: serviceaccount "default" not found $ ./kubectl get serviceaccounts No resources found in default namespace. Здесь мы видим насколько ужасающе неполна наша среда Kubernetes — у нас нет учетных записей для служб. Давайте попробуем еще раз, создав учетную запись службы вручную, и посмотрим, что произойдет: $ cat <<EOS | ./kubectl apply -f -
apiVersion: v1 kind: ServiceAccount metadata: name: default namespace: default EOS serviceaccount/default created $ ./kubectl apply -f nginx.yaml Error from server (ServerTimeout): error when creating "nginx.yaml": No API token found for service account "default", retry after the token is automatically created and added to the service account Даже когда мы создали учетную запись службы вручную, токен аутентификации не создается. Продолжая экспериментировать с нашим минималистичным «кластером», мы обнаружим, что большинство полезных вещей, которые обычно происходят автоматически, будут отсутствовать. Сервер Kubernetes API довольно минималистичен, большая часть тяжелых автоматических настроек происходит в различных контроллерах и фоновых заданиях, которые еще не выполняются. Мы можем обойти эту проблему, установив опцию automountServiceAccountToken для учетной записи службы (так как нам все равно не придется ее использовать): $ cat <<EOS | ./kubectl apply -f -
apiVersion: v1 kind: ServiceAccount metadata: name: default namespace: default automountServiceAccountToken: false EOS serviceaccount/default configured $ ./kubectl apply -f nginx.yaml pod/nginx created $ ./kubectl get pods NAME READY STATUS RESTARTS AGE nginx 0/1 Pending 0 13m Наконец, под появился! Но на самом деле он не запустится, так как у нас нет планировщика(scheduler) — еще одного важного компонента Kubernetes. Опять же, мы видим, что API Kubernetes на удивление «глупый» — когда вы создаете под в API, он его регистрирует, но не пытается выяснить, на каком узле его запускать. На самом деле для запуска пода планировщик не нужен. Можно вручную добавить узел в манифест в параметре nodeName: apiVersion: v1
kind: Pod metadata: name: nginx spec: containers: - image: nginx name: nginx nodeName: mink8s (Замените mink8s на название узла.) После delete и apply мы видим, что nginx запустился и слушает внутренний IP-адрес: $ ./kubectl delete pod nginx
pod "nginx" deleted $ ./kubectl apply -f nginx.yaml pod/nginx created $ ./kubectl get pods -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx 1/1 Running 0 30s 172.17.0.2 mink8s <none> <none> $ curl -s 172.17.0.2 | head -4 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> Чтобы убедиться, что сеть между подами работает корректно, мы можем запустить curl из другого пода: $ cat <<EOS | ./kubectl apply -f -
apiVersion: v1 kind: Pod metadata: name: curl spec: containers: - image: curlimages/curl name: curl command: ["curl", "172.17.0.2"] nodeName: mink8s EOS pod/curl created $ ./kubectl logs curl | head -6 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> Довольно интересно покопаться в этом окружении и посмотреть, что работает, а что нет. Я обнаружил, что ConfigMap и Secret работают так, как и ожидается, а Service и Deployment нет. Успех! Этот пост становится большим, поэтому я собираюсь объявить о победе и заявить, что это жизнеспособная конфигурация, которую можно назвать “Kubernetes". Резюмируя: четыре бинарных файла, пять параметров командной строки и “всего лишь” 45 строк YAML (не так много по стандартам Kubernetes) и у нас работает немало вещей:
Но большая часть из того, что делает Kubernetes по-настоящему полезным, все еще отсутствует, например:
Так что же мы на самом деле получили? Kubernetes API, работающий сам по себе, на самом деле, является всего лишь платформой для автоматизации контейнеров. Он не делает много — это работа для различных контроллеров и операторов, использующих API, — но он обеспечивает консистентную среду для автоматизации. Узнать подробнее о курсе на бесплатном вебинаре. Читать еще:
=========== Источник: habr.com =========== =========== Автор оригинала: Emanuel Evans ===========Похожие новости:
Блог компании OTUS. Онлайн-образование ), #_devops, #_kubernetes |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 00:29
Часовой пояс: UTC + 5