Kubernetes Basics

Kubernetes Основи

Підтримати HackTricks

Оригінальний автор цієї сторінки Хорхе (читайте його оригінальний пост тут)

Архітектура та Основи

Що робить Kubernetes?

  • Дозволяє запускати контейнери в контейнерному двигуні.

  • Планування дозволяє ефективно виконувати місії контейнерів.

  • Підтримує контейнери в активному стані.

  • Дозволяє комунікацію між контейнерами.

  • Дозволяє техніки розгортання.

  • Обробляє обсяги інформації.

Архітектура

  • Вузол: операційна система з подом або подами.

  • Под: обгортка навколо контейнера або кількох контейнерів. Под повинен містити лише один додаток (тому зазвичай под запускає лише 1 контейнер). Под є способом, яким Kubernetes абстрагує технологію контейнерів.

  • Сервіс: Кожен под має 1 внутрішню IP-адресу з внутрішнього діапазону вузла. Однак його також можна відкрити через сервіс. Сервіс також має IP-адресу і його мета - підтримувати зв'язок між подами, тому якщо один з них помре, новий замінник (з іншою внутрішньою IP) буде доступний за тою ж IP-адресою сервісу. Його можна налаштувати як внутрішній або зовнішній. Сервіс також діє як балансувальник навантаження, коли 2 поди підключені до одного сервісу. Коли сервіс створюється, ви можете знайти кінцеві точки кожного сервісу, запустивши kubectl get endpoints

  • Kubelet: Основний агент вузла. Компонент, який встановлює зв'язок між вузлом і kubectl, і може запускати лише поди (через API-сервер). Kubelet не керує контейнерами, які не були створені Kubernetes.

  • Kube-proxy: це сервіс, відповідальний за комунікацію (сервіси) між apiserver і вузлом. Основою є IPtables для вузлів. Найбільш досвідчені користувачі можуть встановити інші kube-proxy від інших постачальників.

  • Контейнер Sidecar: Контейнери Sidecar - це контейнери, які повинні працювати разом з основним контейнером у поді. Цей шаблон Sidecar розширює та покращує функціональність поточних контейнерів без їх зміни. Сьогодні ми знаємо, що використовуємо технологію контейнерів, щоб обернути всі залежності для запуску додатка в будь-якому місці. Контейнер виконує лише одну задачу і робить це дуже добре.

  • Головний процес:

  • Api Server: Це спосіб, яким користувачі та поди спілкуються з головним процесом. Дозволяються лише автентифіковані запити.

  • Планувальник: Планування означає забезпечення того, щоб поди відповідали вузлам, щоб Kubelet міг їх запускати. Він має достатньо інтелекту, щоб вирішити, який вузол має більше доступних ресурсів, і призначити новий под. Зверніть увагу, що планувальник не запускає нові поди, він лише спілкується з процесом Kubelet, що працює всередині вузла, який запустить новий под.

  • Kube Controller manager: Він перевіряє ресурси, такі як набори реплік або розгортання, щоб перевірити, чи, наприклад, працює правильна кількість подів або вузлів. У разі відсутності пода він зв'яжеться з планувальником, щоб запустити новий. Він контролює реплікацію, токени та облікові сервіси для API.

  • etcd: Сховище даних, постійне, узгоджене та розподілене. Це база даних Kubernetes і сховище ключ-значення, де зберігається повний стан кластерів (кожна зміна тут реєструється). Компоненти, такі як планувальник або менеджер контролера, залежать від цих даних, щоб знати, які зміни відбулися (доступні ресурси вузлів, кількість запущених подів...)

  • Cloud controller manager: Це специфічний контролер для управління потоками та додатками, тобто: якщо у вас є кластери в AWS або OpenStack.

Зверніть увагу, що оскільки може бути кілька вузлів (які запускають кілька подів), також може бути кілька головних процесів, доступ до яких до API-сервера збалансований, а їх etcd синхронізовані.

Томи:

Коли под створює дані, які не повинні бути втрачені, коли под зникне, їх слід зберігати в фізичному томі. Kubernetes дозволяє прикріпити том до пода для збереження даних. Том може бути на локальному комп'ютері або в віддаленому сховищі. Якщо ви запускаєте поди на різних фізичних вузлах, вам слід використовувати віддалене сховище, щоб усі поди могли до нього отримати доступ.

Інші конфігурації:

  • ConfigMap: Ви можете налаштувати URL-адреси для доступу до сервісів. Под отримає дані звідси, щоб знати, як спілкуватися з іншими сервісами (поди). Зверніть увагу, що це не рекомендоване місце для збереження облікових даних!

  • Secret: Це місце для зберігання секретних даних, таких як паролі, API-ключі... закодованих у B64. Под зможе отримати доступ до цих даних для використання необхідних облікових даних.

  • Deployments: Це місце, де вказуються компоненти, які будуть запущені Kubernetes. Користувач зазвичай не працює безпосередньо з подами, поди абстраговані в ReplicaSets (кількість однакових подів, що реплікуються), які запускаються через розгортання. Зверніть увагу, що розгортання призначені для безстанційних додатків. Мінімальна конфігурація для розгортання - це ім'я та образ для запуску.

  • StatefulSet: Цей компонент призначений спеціально для додатків, таких як бази даних, які потребують доступу до одного й того ж сховища.

  • Ingress: Це конфігурація, яка використовується для публічного відкриття додатка з URL-адресою. Зверніть увагу, що це також можна зробити за допомогою зовнішніх сервісів, але це правильний спосіб відкрити додаток.

  • Якщо ви реалізуєте Ingress, вам потрібно буде створити Ingress Controllers. Ingress Controller - це под, який буде кінцевою точкою, що отримуватиме запити, перевірятиме їх і балансуватиме навантаження на сервіси. Ingress controller направить запит на основі налаштованих правил ingress. Зверніть увагу, що правила ingress можуть вказувати на різні шляхи або навіть піддомени для різних внутрішніх сервісів Kubernetes.

  • Кращою практикою безпеки буде використання хмарного балансувальника навантаження або проксі-сервера як точки входу, щоб жодна частина кластера Kubernetes не була відкрита.

  • Коли отримується запит, який не відповідає жодному правилу ingress, контролер ingress направить його на "Default backend". Ви можете describe контролер ingress, щоб отримати адресу цього параметра.

  • minikube addons enable ingress

PKI інфраструктура - Центр сертифікації CA:

  • CA є надійним коренем для всіх сертифікатів у кластері.

  • Дозволяє компонентам перевіряти один одного.

  • Усі сертифікати кластера підписані CA.

  • ETCd має свій власний сертифікат.

  • типи:

  • сертифікат apiserver.

  • сертифікат kubelet.

  • сертифікат планувальника.

Основні дії

Minikube

Minikube можна використовувати для виконання деяких швидких тестів на Kubernetes без необхідності розгортання цілого середовища Kubernetes. Він запустить головні та вузлові процеси на одному комп'ютері. Minikube використовуватиме virtualbox для запуску вузла. Дивіться тут, як його встановити.

$ minikube start
😄  minikube v1.19.0 on Ubuntu 20.04
✨  Automatically selected the virtualbox driver. Other choices: none, ssh
💿  Downloading VM boot image ...
> minikube-v1.19.0.iso.sha256: 65 B / 65 B [-------------] 100.00% ? p/s 0s
> minikube-v1.19.0.iso: 244.49 MiB / 244.49 MiB  100.00% 1.78 MiB p/s 2m17.
👍  Starting control plane node minikube in cluster minikube
💾  Downloading Kubernetes v1.20.2 preload ...
> preloaded-images-k8s-v10-v1...: 491.71 MiB / 491.71 MiB  100.00% 2.59 MiB
🔥  Creating virtualbox VM (CPUs=2, Memory=3900MB, Disk=20000MB) ...
🐳  Preparing Kubernetes v1.20.2 on Docker 20.10.4 ...
▪ Generating certificates and keys ...
▪ Booting up control plane ...
▪ Configuring RBAC rules ...
🔎  Verifying Kubernetes components...
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by defaul

$ minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

---- ONCE YOU HAVE A K8 SERVICE RUNNING WITH AN EXTERNAL SERVICE -----
$ minikube service mongo-express-service
(This will open your browser to access the service exposed port)

$ minikube delete
🔥  Deleting "minikube" in virtualbox ...
💀  Removed all traces of the "minikube" cluster

Kubectl Основи

Kubectl - це інструмент командного рядка для кластерів kubernetes. Він спілкується з Api сервером головного процесу для виконання дій у kubernetes або для запиту даних.

kubectl version #Get client and server version
kubectl get pod
kubectl get services
kubectl get deployment
kubectl get replicaset
kubectl get secret
kubectl get all
kubectl get ingress
kubectl get endpoints

#kubectl create deployment <deployment-name> --image=<docker image>
kubectl create deployment nginx-deployment --image=nginx
#Access the configuration of the deployment and modify it
#kubectl edit deployment <deployment-name>
kubectl edit deployment nginx-deployment
#Get the logs of the pod for debbugging (the output of the docker container running)
#kubectl logs <replicaset-id/pod-id>
kubectl logs nginx-deployment-84cd76b964
#kubectl describe pod <pod-id>
kubectl describe pod mongo-depl-5fd6b7d4b4-kkt9q
#kubectl exec -it <pod-id> -- bash
kubectl exec -it mongo-depl-5fd6b7d4b4-kkt9q -- bash
#kubectl describe service <service-name>
kubectl describe service mongodb-service
#kubectl delete deployment <deployment-name>
kubectl delete deployment mongo-depl
#Deploy from config file
kubectl apply -f deployment.yml

Minikube Dashboard

Дашборд дозволяє вам легше бачити, що виконує minikube, ви можете знайти URL для доступу до нього в:

minikube dashboard --url


🔌  Enabling dashboard ...
▪ Using image kubernetesui/dashboard:v2.3.1
▪ Using image kubernetesui/metrics-scraper:v1.0.7
🤔  Verifying dashboard health ...
🚀  Launching proxy ...
🤔  Verifying proxy health ...
http://127.0.0.1:50034/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/

YAML конфігураційні файли приклади

Кожен конфігураційний файл має 3 частини: метадані, специфікація (що потрібно запустити), статус (бажаний стан). Всередині специфікації файлу конфігурації розгортання ви можете знайти шаблон, визначений з новою структурою конфігурації, що визначає образ для запуску:

Приклад розгортання + служби, оголошених в одному конфігураційному файлі (з тут)

Оскільки служба зазвичай пов'язана з одним розгортанням, можливо оголосити обидва в одному конфігураційному файлі (служба, оголошена в цій конфігурації, доступна лише внутрішньо):

apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb-deployment
labels:
app: mongodb
spec:
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-username
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-password
---
apiVersion: v1
kind: Service
metadata:
name: mongodb-service
spec:
selector:
app: mongodb
ports:
- protocol: TCP
port: 27017
targetPort: 27017

Приклад конфігурації зовнішнього сервісу

Цей сервіс буде доступний зовні (перевірте атрибути nodePort та type: LoadBlancer):

---
apiVersion: v1
kind: Service
metadata:
name: mongo-express-service
spec:
selector:
app: mongo-express
type: LoadBalancer
ports:
- protocol: TCP
port: 8081
targetPort: 8081
nodePort: 30000

Це корисно для тестування, але для продуктивного середовища у вас повинні бути лише внутрішні сервіси та Ingress для відкриття додатку.

Приклад конфігураційного файлу Ingress

Це відкриє додаток за адресою http://dashboard.com.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dashboard-ingress
namespace: kubernetes-dashboard
spec:
rules:
- host: dashboard.com
http:
paths:
- backend:
serviceName: kubernetes-dashboard
servicePort: 80

Приклад конфігураційного файлу секретів

Зверніть увагу, як паролі закодовані в B64 (що не є безпечним!)

apiVersion: v1
kind: Secret
metadata:
name: mongodb-secret
type: Opaque
data:
mongo-root-username: dXNlcm5hbWU=
mongo-root-password: cGFzc3dvcmQ=

Приклад ConfigMap

ConfigMap - це конфігурація, яка надається подам, щоб вони знали, як знаходити та отримувати доступ до інших сервісів. У цьому випадку кожен под буде знати, що ім'я mongodb-service є адресою пода, з яким вони можуть спілкуватися (цей под буде виконувати mongodb):

apiVersion: v1
kind: ConfigMap
metadata:
name: mongodb-configmap
data:
database_url: mongodb-service

Тоді, всередині deployment config ця адреса може бути вказана наступним чином, щоб вона завантажувалася в середовище pod:

[...]
spec:
[...]
template:
[...]
spec:
containers:
- name: mongo-express
image: mongo-express
ports:
- containerPort: 8081
env:
- name: ME_CONFIG_MONGODB_SERVER
valueFrom:
configMapKeyRef:
name: mongodb-configmap
key: database_url
[...]

Приклад конфігурації обсягу

Ви можете знайти різні приклади конфігурації зберігання yaml файлів за посиланням https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes. Зверніть увагу, що обсяги не знаходяться всередині просторів імен

Простори імен

Kubernetes підтримує декілька віртуальних кластерів, які базуються на одному фізичному кластері. Ці віртуальні кластери називаються просторами імен. Вони призначені для використання в середовищах з багатьма користувачами, розподіленими по кількох командах або проектах. Для кластерів з кількома десятками користувачів вам не потрібно створювати або думати про простори імен. Ви повинні почати використовувати простори імен, щоб мати кращий контроль і організацію кожної частини програми, розгорнутої в kubernetes.

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

За замовчуванням є 4 простори імен, якщо ви використовуєте minikube:

kubectl get namespace
NAME              STATUS   AGE
default           Active   1d
kube-node-lease   Active   1d
kube-public       Active   1d
kube-system       Active   1d
  • kube-system: Це не призначено для використання користувачами, і вам не слід його чіпати. Це для процесів master і kubectl.

  • kube-public: Публічно доступні дані. Містить configmap, який містить інформацію про кластер.

  • kube-node-lease: Визначає доступність вузла.

  • default: Простір імен, який користувач буде використовувати для створення ресурсів.

#Create namespace
kubectl create namespace my-namespace

Зверніть увагу, що більшість ресурсів Kubernetes (наприклад, pods, services, replication controllers та інші) знаходяться в деяких просторах імен. Однак інші ресурси, такі як ресурси простору імен та низькорівневі ресурси, такі як nodes і persistentVolumes, не знаходяться в просторі імен. Щоб побачити, які ресурси Kubernetes є в просторі імен, а які ні:

kubectl api-resources --namespaced=true #In a namespace
kubectl api-resources --namespaced=false #Not in a namespace

Ви можете зберегти простір імен для всіх наступних команд kubectl у цьому контексті.

kubectl config set-context --current --namespace=<insert-namespace-name-here>

Helm

Helm - це менеджер пакетів для Kubernetes. Він дозволяє пакувати YAML файли та розповсюджувати їх у публічних і приватних репозиторіях. Ці пакети називаються Helm Charts.

helm search <keyword>

Helm також є шаблонним двигуном, який дозволяє генерувати конфігураційні файли з змінними:

Kubernetes секрети

Секрет - це об'єкт, який містить чутливі дані, такі як пароль, токен або ключ. Таку інформацію інакше можна було б помістити в специфікацію Pod або в образ. Користувачі можуть створювати Секрети, а система також створює Секрети. Ім'я об'єкта Секрету повинно бути дійсним DNS піддоменом. Читайте тут офіційну документацію.

Секрети можуть бути такими, як:

  • API, SSH ключі.

  • OAuth токени.

  • Облікові дані, паролі (в чистому вигляді або b64 + шифрування).

  • Інформація або коментарі.

  • Код підключення до бази даних, рядки… .

Існують різні типи секретів у Kubernetes

Вбудований типВикористання

Opaque

произвольні дані, визначені користувачем (за замовчуванням)

kubernetes.io/service-account-token

токен облікового запису служби

kubernetes.io/dockercfg

серіалізований файл ~/.dockercfg

kubernetes.io/dockerconfigjson

серіалізований файл ~/.docker/config.json

kubernetes.io/basic-auth

облікові дані для базової аутентифікації

kubernetes.io/ssh-auth

облікові дані для SSH аутентифікації

kubernetes.io/tls

дані для TLS клієнта або сервера

bootstrap.kubernetes.io/token

дані токена завантаження

Тип Opaque є типом за замовчуванням, типовою парою ключ-значення, визначеною користувачами.

Як працюють секрети:

Наступний конфігураційний файл визначає секрет під назвою mysecret з 2 парами ключ-значення username: YWRtaW4= та password: MWYyZDFlMmU2N2Rm. Він також визначає pod під назвою secretpod, який матиме username та password, визначені в mysecret, доступними в змінних середовища SECRET_USERNAME __ та __ SECRET_PASSWOR. Він також монтує секрет username всередині mysecret за шляхом /etc/foo/my-group/my-username з правами 0640.

secretpod.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
---
apiVersion: v1
kind: Pod
metadata:
name: secretpod
spec:
containers:
- name: secretpod
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
volumeMounts:
- name: foo
mountPath: "/etc/foo"
restartPolicy: Never
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
mode: 0640
kubectl apply -f <secretpod.yaml>
kubectl get pods #Wait until the pod secretpod is running
kubectl exec -it  secretpod -- bash
env | grep SECRET && cat /etc/foo/my-group/my-username && echo

Secrets in etcd

etcd є послідовним і високодоступним сховищем ключ-значення, яке використовується як основне сховище Kubernetes для всіх даних кластера. Давайте отримати доступ до секретів, збережених в etcd:

cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd

Ви побачите сертифікати, ключі та URL-адреси, які розташовані у файловій системі. Як тільки ви їх отримаєте, ви зможете підключитися до etcd.

#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] health

ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] health

Якщо ви зможете встановити зв'язок, ви зможете отримати секрети:

#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] get <path/to/secret>

ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] get /registry/secrets/default/secret_02

Додавання шифрування до ETCD

За замовчуванням всі секрети зберігаються у відкритому тексті всередині etcd, якщо ви не застосуєте шар шифрування. Наступний приклад базується на https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/

encryption.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: cjjPMcWpTPKhAdieVtd+KhG4NN+N6e3NmBPMXJvbfrY= #Any random key
- identity: {}

Після цього вам потрібно встановити прапорець --encryption-provider-config на kube-apiserver, щоб вказати на місце розташування створеного конфігураційного файлу. Ви можете змінити /etc/kubernetes/manifest/kube-apiserver.yaml і додати наступні рядки:

containers:
- command:
- kube-apiserver
- --encriyption-provider-config=/etc/kubernetes/etcd/<configFile.yaml>

Прокрутіть униз у volumeMounts:

- mountPath: /etc/kubernetes/etcd
name: etcd
readOnly: true

Прокрутіть униз у volumeMounts до hostPath:

- hostPath:
path: /etc/kubernetes/etcd
type: DirectoryOrCreate
name: etcd

Перевірка, що дані зашифровані

Дані зашифровані при запису в etcd. Після перезапуску вашого kube-apiserver, будь-який новостворений або оновлений секрет повинен бути зашифрований при зберіганні. Щоб перевірити, ви можете використовувати програму командного рядка etcdctl, щоб отримати вміст вашого секрету.

  1. Створіть новий секрет під назвою secret1 у просторі імен default:

kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
  1. Використовуючи командний рядок etcdctl, прочитайте цей секрет з etcd:

ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C

де [...] повинні бути додаткові аргументи для підключення до сервера etcd. 3. Перевірте, що збережений секрет має префікс k8s:enc:aescbc:v1:, що вказує на те, що провайдер aescbc зашифрував отримані дані. 4. Перевірте, що секрет правильно розшифрований при отриманні через API:

kubectl describe secret secret1 -n default

повинен відповідати mykey: bXlkYXRh, mydata закодовано, перевірте декодування секрету, щоб повністю декодувати секрет.

Оскільки секрети зашифровані при запису, виконання оновлення секрету зашифрує цей вміст:

kubectl get secrets --all-namespaces -o json | kubectl replace -f -

Останні поради:

Посилання

Підтримайте HackTricks

Last updated