Kubernetes - руководство оператора
Введение
Kubernetes - лидер технологии облачных сред, поддерживающих концепцию IaC - инфраструктура, как код.
Управляющий уровень состоит из нескольких компонентов.
- kube-apiserver - внешний сервер для управляющего уровня, который обрабатывает API-запросы.
- etcd - база данных, в которой Kubernetes хранит всю информацию о существующих узлах, ресурсах кластера и т. д.
- kube-scheduler планирует и управляет запуском pod-оболочек.
- kube-controller-manager отвечает за запуск контроллеров ресурсов, таких как развертывания (deployments).
- cloud-controller-manager взаимодействует с облачным провайдером (в облачных кластерах), управляя такими ресурсами, как балансировщики нагрузки и дисковые тома.
Участники кластера, которые выполняют компоненты управляющего уровня, называются ведущими узлами.
Участники кластера, которые выполняют пользовательские рабочие задания, называются рабочими узлами.
Каждый рабочий узел в кластере Kubernetes отвечает за следующие компоненты.
- kubelet отвечает за управление средой выполнения контейнера, в которой запускаются рабочие задания, запланированные для узла, а также за мониторинг их состояния.
- kube-proxy занимается сетевой магией, которая распределяет запросы между pod-оболочками на разных узлах, а также между pod-оболочками и Интернетом.
- среда выполнения контейнеров запускает и останавливает контейнеры, а также отвечает за их взаимодействие. Обычно это CRI-O, хотя Kubernetes поддерживает и другие среды выполнения контейнеров, такие как containerd, rkt, docker. Kubernetes отказался от Docker, как среды управления контейнерами после версии 1.20 ( deprecating Docker ).
Немного терминов
Pod-оболочка — это фундаментальная единица работы в Kubernetes, которая определяет один или несколько контейнеров, взаимодействующих между собой и запланированных к одновременному выполнению.
Развертывание (deployment) - высокоуровневый ресурс Kubernetes, который декларативным образом управляет pod-оболочками, их доставкой, планированием, обновлением и перезапуском, когда это необходимо.
Cервис в Kubernetes - это эквивалент балансировщика нагрузки или прокси, который направляет трафик к подходящим pod-оболочкам через единый, публичный и долгосрочный IP-адрес или доменное имя.
Планировщик Kubernetes ищет pod-оболочки, которые еще нигде не выполняются, находит для них подходящие узлы и приказывает утилите kubelet запустить эти pod-оболочки на найденных узлах.
Манифест - это объявление желаемого состояния ресурса. Такие ресурсы, как развертывания, представлены записями во внутренней базе данных Kubernetes. Внешне эти ресурсы могут иметь форму текстовых файлов (известных как манифесты) в формате YAML.
Kubectl - основной инструмент для взаимодействия с Kubernetes, который позволяет применять манифесты, запрашивать данные о ресурсах, вносить изменения, удалять ресурсы и многое другое. Ее можно использовать либо императивно (например, для запуска публичных образов контейнеров с явным выделением необходимых ресурсов Kubernetes), либо декларативно, чтобы применять конфигурацию Kubernetes в виде манифестов формата YAML.
Helm - это диспетчер пакетов для Kubernetes. Он упрощает конфигурацию и развертывание приложений, позволяя генерировать YAML-файлы с помощью группы шаблонов и единого набора значений (таких как имя приложения или порт, который оно прослушивает), вмест того чтобы писать эти файлы вручную.
Пространство имен - предоставляет способ разделения кластера на отдельные части в тех или иных целях. Является полезным механизмом контроля за потреблением ресурсов в вашем кластере.
Dashboard
Kubernetes Dashboard - это универсальный веб-интерфейс для кластеров Kubernetes. Он позволяет пользователям управлять приложениями, работающими в кластере, и устранять их неполадки, а также управлять самим кластером.
Прежде всего вам необходимо получить токен для доступа к кластеру. Это можно сделать с помощью kubectl.
kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}" | tee token
Открыть браузер и перейти по ссылке:
-
В открывшемся окне нужно выбрать опцию «Token».
-
Вставить токен из файла token и нажать «Sign In».
-
Откроется окно Kubernetes Dashboard с правами администратора.
Справочник команд
Common
Список ресурсов API:
$ kubectl api-resources
# вывод команды дает большой список (у меня 58 строк), привожу несколько для примера
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
nodes no v1 false Node
...
apiservices apiregistration.k8s.io/v1 false APIService
controllerrevisions apps/v1 true ControllerRevision
...
roles rbac.authorization.k8s.io/v1 true Role
priorityclasses pc scheduling.k8s.io/v1 false PriorityClass
...
storageclasses sc storage.k8s.io/v1 false StorageClass
volumeattachments storage.k8s.io/v1 false VolumeAttachment
$ kubectl get apiservices
NAME SERVICE AVAILABLE AGE
v1. Local True 28h
v1.admissionregistration.k8s.io Local True 28h
v1.apiextensions.k8s.io Local True 28h
v1.apps Local True 28h
v1.authentication.k8s.io Local True 28h
v1.authorization.k8s.io Local True 28h
v1.autoscaling Local True 28h
v1.batch Local True 28h
v1.certificates.k8s.io Local True 28h
v1.coordination.k8s.io Local True 28h
v1.discovery.k8s.io Local True 28h
v1.events.k8s.io Local True 28h
v1.networking.k8s.io Local True 28h
v1.node.k8s.io Local True 28h
v1.policy Local True 28h
v1.rbac.authorization.k8s.io Local True 28h
v1.scheduling.k8s.io Local True 28h
v1.storage.k8s.io Local True 28h
v1beta1.admissionregistration.k8s.io Local True 28h
v1beta1.apiextensions.k8s.io Local True 28h
v1beta1.authentication.k8s.io Local True 28h
v1beta1.authorization.k8s.io Local True 28h
v1beta1.batch Local True 28h
v1beta1.certificates.k8s.io Local True 28h
v1beta1.coordination.k8s.io Local True 28h
v1beta1.discovery.k8s.io Local True 28h
v1beta1.events.k8s.io Local True 28h
v1beta1.extensions Local True 28h
v1beta1.flowcontrol.apiserver.k8s.io Local True 28h
v1beta1.networking.k8s.io Local True 28h
v1beta1.node.k8s.io Local True 28h
v1beta1.policy Local True 28h
v1beta1.rbac.authorization.k8s.io Local True 28h
v1beta1.scheduling.k8s.io Local True 28h
v1beta1.storage.k8s.io Local True 28h
v2beta1.autoscaling Local True 28h
v2beta2.autoscaling Local True 28h
Просмотр конфигурации кластера:
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.0.128.114:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
Namespaces
Просмотр пространств имен:
$ kubectl get namespaces
NAME STATUS AGE
default Active 151m
kube-node-lease Active 151m
kube-public Active 151m
kube-system Active 151m
kubernetes-dashboard Active 94m
Создание пространства имен:
Удаление пространства имен:
Надо помнить, что при удалении namespace Kubernetes самостоятельно удалит все компоненты (applications, pods and etc.) в нужной последовательности и освободит ресурсы.
Endpoints
Посмотреть точки входа сервисов:
$ kubectl get endpoints
NAME ENDPOINTS AGE
grafana <none> 3h21m
kubernetes 10.0.128.114:6443,10.0.128.223:6443 28h
mysql <none> 21h
mysql-1625151580 <none> 19h
mysql-1625151580-headless <none> 19h
Services
Посмотреть список сервисов:
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana LoadBalancer 10.109.195.235 <pending> 3000:31046/TCP 3h26m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 28h
mysql ClusterIP None <none> 3306/TCP 21h
mysql-1625151580 ClusterIP 10.97.109.151 <none> 3306/TCP 20h
mysql-1625151580-headless ClusterIP None <none> 3306/TCP 20h
Описание сервиса:
$ kubectl describe service grafana
Name: grafana
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=grafana
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.109.195.235
IPs: 10.109.195.235
Port: <unset> 3000/TCP
TargetPort: http-grafana/TCP
NodePort: <unset> 31046/TCP
Endpoints: <none>
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
Редактирование сервиса:
$ kubectl describe service grafana
Name: grafana
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=grafana
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.109.195.235
IPs: 10.109.195.235
Port: <unset> 3000/TCP
TargetPort: http-grafana/TCP
NodePort: <unset> 31046/TCP
Endpoints: <none>
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
Nodes
Ноды - это серверы, на которых установлено ПО кластера Kubernetes.
В нашем случае, это четыре виртуальных машины, созданных в отдельном проекте rgpu/k8s, две из которых являются ведущими нодами (kuber-1, kuber-2) и еще две рабочими нодами (kuber-3, kuber-4).
Get
Посмотреть список нод (узлов):
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
kuber-1 Ready control-plane,master 27h v1.21.2
kuber-2 Ready control-plane,master 26h v1.21.2
kuber-3 Ready <none> 26h v1.21.2
kuber-4 Ready <none> 26h v1.21.2
Delete
Удалить ноду:
Join
Присоединить новый узел в кластер можно с помощью, расположенного в папке kuber-1:/home/ubuntu/k8s/k8s-join
#!/bin/bash
LBA='10.0.128.114'
KT='h7eyg0.i77scifkhuyxl7l7'
KH='sha256:9ffb28f76e329995e42e06722484f6cbf54395521c40d92659783167460331e2'
CPI='--control-plane'
CRI='--cri-socket /var/run/crio/crio.sock'
function usage() {
echo 'Usage: '$0' 1 (master) or 2 (worker)'
}
function pki_get() {
mkdir -p /etc/kubernetes/pki/etcd
scp -rp ubuntu@kuber-1:/etc/kubernetes/pki/sa.* /etc/kubernetes/pki
scp -rp ubuntu@kuber-1:/etc/kubernetes/pki/front* /etc/kubernetes/pki
scp -rp ubuntu@kuber-1:/etc/kubernetes/pki/etcd/ca.* /etc/kubernetes/pki/etcd
scp -rp ubuntu@kuber-1:/etc/kubernetes/pki/etcd/healthcheck* /etc/kubernetes/pki/etcd
}
case $1 in
1)
pki_get
scp -rp ubuntu@kuber-1:/etc/kubernetes/pki/ca.* /etc/kubernetes/pki
/usr/bin/kubeadm join ${LBA}:6443 --token $KT --discovery-token-ca-cert-hash $KH $CRI $CPI
echo 'Master node joined to cluster'
;;
2)
pki_get
/usr/bin/kubeadm join ${LBA}:6443 --token $KT --discovery-token-ca-cert-hash $KH $CRI
echo 'Worker node joined to cluster'
;;
*)
usage
;;
esac
Эту программу надо запустить на добавляемом узле, а в качестве единственного параметра указать 1 - если тип узла ведущий, или 2 - если тип ноды рабочая. Предварительно на ВМ должно быть установлено все необходимое ПО.
Describe
Детальная информация о ноде:
# kubectl describe node kuber-1
Name: kuber-1
Roles: control-plane,master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=kuber-1
kubernetes.io/os=linux
node-role.kubernetes.io/control-plane=
node-role.kubernetes.io/master=
node.kubernetes.io/exclude-from-external-load-balancers=
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/crio/crio.sock
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Thu, 01 Jul 2021 06:15:38 +0000
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:
HolderIdentity: kuber-1
AcquireTime: <unset>
RenewTime: Fri, 02 Jul 2021 10:06:51 +0000
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
MemoryPressure False Fri, 02 Jul 2021 10:05:46 +0000 Thu, 01 Jul 2021 06:15:33 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Fri, 02 Jul 2021 10:05:46 +0000 Thu, 01 Jul 2021 06:15:33 +0000 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Fri, 02 Jul 2021 10:05:46 +0000 Thu, 01 Jul 2021 06:15:33 +0000 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Fri, 02 Jul 2021 10:05:46 +0000 Thu, 01 Jul 2021 06:15:55 +0000 KubeletReady kubelet is posting ready status. AppArmor enabled
Addresses:
InternalIP: 10.0.128.114
Hostname: kuber-1
Capacity:
cpu: 16
ephemeral-storage: 243720360Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 32885824Ki
pods: 110
Allocatable:
cpu: 16
ephemeral-storage: 224612683405
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 32783424Ki
pods: 110
System Info:
Machine ID: 4ad6c322b93b4130982caf7036043d5f
System UUID: 4ad6c322-b93b-4130-982c-af7036043d5f
Boot ID: b1a5950b-6f20-4220-a58a-eed9bfa43613
Kernel Version: 5.4.0-74-generic
OS Image: Ubuntu 20.04.2 LTS
Operating System: linux
Architecture: amd64
Container Runtime Version: cri-o://1.21.1
Kubelet Version: v1.21.2
Kube-Proxy Version: v1.21.2
PodCIDR: 10.85.0.0/24
PodCIDRs: 10.85.0.0/24
Non-terminated Pods: (8 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
kube-system coredns-558bd4d5db-5wh5f 100m (0%) 0 (0%) 70Mi (0%) 170Mi (0%) 27h
kube-system coredns-558bd4d5db-kwpsm 100m (0%) 0 (0%) 70Mi (0%) 170Mi (0%) 27h
kube-system etcd-kuber-1 100m (0%) 0 (0%) 100Mi (0%) 0 (0%) 27h
kube-system kube-apiserver-kuber-1 250m (1%) 0 (0%) 0 (0%) 0 (0%) 27h
kube-system kube-controller-manager-kuber-1 200m (1%) 0 (0%) 0 (0%) 0 (0%) 27h
kube-system kube-proxy-8twws 0 (0%) 0 (0%) 0 (0%) 0 (0%) 27h
kube-system kube-scheduler-kuber-1 100m (0%) 0 (0%) 0 (0%) 0 (0%) 27h
weave weave-scope-agent-k26hm 100m (0%) 0 (0%) 100Mi (0%) 2000Mi (6%) 24h
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 950m (5%) 0 (0%)
memory 340Mi (1%) 2340Mi (7%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
Events: <none>
Cordon
Пометить ноду как поддерживающую планировщик
Пометить ноду как не поддерживающую планировщик
Pods
Под является минимальной вычислительной единицей в терминологии Kubernetes. Под - группа из одного или нескольких контейнеров приложений, включающая общие используемые хранилище (тома), IP-адрес и информацию по их запуску.
В Kubernetes есть два основных пути использования подов:
- Под запускающий единственный контейнер. Модель “один-контейнер-на-один-под” является более распространенной в Kubernetes и в данном кейсе можно считать, что под является обёрткой для контейнера. Нужно помнить, что Kubernetes управляет именно подами, а не контейнерами напрямую.
- Под запускающий несколько контейнеров внутри себя. Под может содержать в себе приложение состоящее из нескольких контейнеров, взаимодействие которых тесно связано и есть необходимость разделять ресурсы. Например контейнер-1, являющийся веб-сервером, отдаёт данные с общего диска “во вне”, и есть контейнер-2, который обновляет и изменяет эти данные на диске.
Второй способ, с группировкой нескольких контейнеров внутри одного пода, является довольно специфичным случаем. Не рекомендуется его использовать без явной необходимости.
Каждый под представляет из себя одиночный инстанс (экземпляр) запущенного приложения. Если возникает необходимость в горизонтальном масштабировании, чтобы предоставить больше ресурсов за счет запуска большего количества инстансов, следует запускать множество подов, по одному на каждый инстанс приложения.
В Kubernetes это обычно называется репликацией. Реплицированные поды обычно создаются и управляются объектами Kubernetes, вроде Deployment или Job.
Редко когда возникает необходимость создавать отдельные поды непосредственно в Kubernetes. Это связано с тем, что поды разработаны как относительно эфемерные и одноразовые объекты.
Run
Запуск приложения:
Теперь создадим под и запустим в нем интерактивный шелл:
Get
Просмотр приложений (подов):
Просмотр подов в пространстве имен с отображением изменений в реальном режиме времени:
$ kubectl get pod -n kube-system -w
NAME READY STATUS RESTARTS AGE
coredns-558bd4d5db-9q5dl 1/1 Running 0 68m
coredns-558bd4d5db-bhjb4 1/1 Running 0 68m
etcd-kuber-0 1/1 Running 0 69m
etcd-kuber-1 1/1 Running 0 42m
etcd-kuber-2 1/1 Running 0 37m
kube-apiserver-kuber-0 1/1 Running 0 69m
kube-apiserver-kuber-1 1/1 Running 0 42m
kube-apiserver-kuber-2 1/1 Running 0 37m
kube-controller-manager-kuber-0 1/1 Running 1 69m
kube-controller-manager-kuber-1 1/1 Running 0 42m
kube-controller-manager-kuber-2 1/1 Running 0 37m
kube-proxy-fbv4j 1/1 Running 0 22m
kube-proxy-np29j 1/1 Running 0 37m
kube-proxy-wr5fp 1/1 Running 0 68m
kube-proxy-wv8c6 1/1 Running 0 42m
kube-scheduler-kuber-0 1/1 Running 1 69m
kube-scheduler-kuber-1 1/1 Running 0 42m
kube-scheduler-kuber-2 1/1 Running 0 37m
Delete
Удаление pod:
Describe
Подробное описание пода:
~$ kubectl describe pod etcd-kuber-1 -n kube-system
Name: etcd-kuber-1
Namespace: kube-system
Priority: 2000001000
Priority Class Name: system-node-critical
Node: kuber-1/10.0.128.114
Start Time: Thu, 01 Jul 2021 09:15:46 +0300
Labels: component=etcd
tier=control-plane
Annotations: kubeadm.kubernetes.io/etcd.advertise-client-urls: https://10.0.128.114:2379
kubernetes.io/config.hash: ca362061057becc1426410d2709de7b7
kubernetes.io/config.mirror: ca362061057becc1426410d2709de7b7
kubernetes.io/config.seen: 2021-07-01T06:15:41.992252994Z
kubernetes.io/config.source: file
Status: Running
IP: 10.0.128.114
IPs:
IP: 10.0.128.114
Controlled By: Node/kuber-1
Containers:
etcd:
Container ID: cri-o://2e841ce5fbd4261549ba1796c2ccd14d2e2a02878ffe94d6f9ea5d9e4a45f19b
Image: k8s.gcr.io/etcd:3.4.13-0
Image ID: k8s.gcr.io/etcd@sha256:4ad90a11b55313b182afc186b9876c8e891531b8db4c9bf1541953021618d0e2
Port: <none>
Host Port: <none>
Command:
etcd
--advertise-client-urls=https://10.0.128.114:2379
--cert-file=/etc/kubernetes/pki/etcd/server.crt
--client-cert-auth=true
--data-dir=/var/lib/etcd
--initial-advertise-peer-urls=https://10.0.128.114:2380
--initial-cluster=kuber-1=https://10.0.128.114:2380
--key-file=/etc/kubernetes/pki/etcd/server.key
--listen-client-urls=https://127.0.0.1:2379,https://10.0.128.114:2379
--listen-metrics-urls=http://127.0.0.1:2381
--listen-peer-urls=https://10.0.128.114:2380
--name=kuber-1
--peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
--peer-client-cert-auth=true
--peer-key-file=/etc/kubernetes/pki/etcd/peer.key
--peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
--snapshot-count=10000
--trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
State: Running
Started: Thu, 01 Jul 2021 09:15:32 +0300
Ready: True
Restart Count: 0
Requests:
cpu: 100m
memory: 100Mi
Liveness: http-get http://127.0.0.1:2381/health delay=10s timeout=15s period=10s #success=1 #failure=8
Startup: http-get http://127.0.0.1:2381/health delay=10s timeout=15s period=10s #success=1 #failure=24
Environment: <none>
Mounts:
/etc/kubernetes/pki/etcd from etcd-certs (rw)
/var/lib/etcd from etcd-data (rw)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
etcd-certs:
Type: HostPath (bare host directory volume)
Path: /etc/kubernetes/pki/etcd
HostPathType: DirectoryOrCreate
etcd-data:
Type: HostPath (bare host directory volume)
Path: /var/lib/etcd
HostPathType: DirectoryOrCreate
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: :NoExecute op=Exists
Events: <none>
Logs
Просмотр лога конкретного пода:
$ kubectl logs pod grafana-6fd7f9f87f-gxtcb
Error from server (NotFound): pods "pod" not found
ubuntu@kuber-2:~$ kubectl logs pod/grafana-6fd7f9f87f-gxtcb
ubuntu@kuber-2:~$ kubectl logs pod/nginx-deployment-674454969-85hpt
10.254.0.94 - - [01/Jul/2021:08:16:12 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" "-"
2021/07/01 08:16:13 [error] 7#7: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.254.0.94, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "10.0.128.195:8888", referrer: "http://10.0.128.195:8888/"
10.254.0.94 - - [01/Jul/2021:08:16:13 +0000] "GET /favicon.ico HTTP/1.1" 404 169 "http://10.0.128.195:8888/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" "-"
10.254.0.96 - - [02/Jul/2021:11:10:24 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" "-"
2021/07/02 11:10:24 [error] 7#7: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.254.0.96, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "10.0.128.195:8888", referrer: "http://10.0.128.195:8888/"
10.254.0.96 - - [02/Jul/2021:11:10:24 +0000] "GET /favicon.ico HTTP/1.1" 404 169 "http://10.0.128.195:8888/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" "-"
10.254.0.96 - - [02/Jul/2021:11:10:25 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" "-"
10.254.0.96 - - [02/Jul/2021:11:10:25 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" "-"
Annotate
Установить аннотацию для приложения:
Label
Поставить метку:
Deployments
Get
Просмотр развертываний:
Describe
Детальная информация о развертывании:
Apply
Запуск приложения из файла описания (YAML, JSON):
Еще примеры см. в пункте “Манифесты ресурсов”
Autoscale
Задать параметры масштабирования для приложения:
$ kubectl autoscale deployment nginx-deployment --min=2 --max=5
horizontalpodautoscaler.autoscaling/nginx-deployment autoscaled
LimitRange
Set
Создаем манифест с типом (kind) LimitRange:
---
apiVersion: v1
kind: LimitRange
metadata:
name: sock-limitrange
spec:
limits:
- default:
cpu: "500m"
memory: "256Mi"
defaultRequest:
cpu: "200m"
memory: "128Mi"
type: Container
Применяем его к пространству имен:
Проверим, что лимит установлен:
Describe
Просмотрим подробнее, какие лимиты установлены:
$ kubectl describe limitrange -n sock-shop
Name: sock-limitrange
Namespace: sock-shop
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container cpu - - 200m 500m -
Container memory - - 128Mi 256Mi -
Edit
Отредактировать лимиты оперативно (без файла манифеста):
Images
Images (list)
Список образов:
$ crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/dsagkomega/omegabi_angular latest 01c4c9b8e5164 477MB
k8s.gcr.io/coredns/coredns v1.8.0 296a6d5035e2d 42.6MB
k8s.gcr.io/etcd 3.4.13-0 0369cf4303ffd 255MB
k8s.gcr.io/kube-apiserver v1.21.2 106ff58d43082 127MB
k8s.gcr.io/kube-controller-manager v1.21.2 ae24db9aa2cc0 121MB
k8s.gcr.io/kube-proxy v1.21.2 a6ebd1c1ad981 133MB
k8s.gcr.io/kube-scheduler v1.21.2 f917b8c8f55b7 51.9MB
k8s.gcr.io/pause 3.4.1 0f8457a4c2eca 690kB
k8s.gcr.io/pause 3.5 ed210e3e4a5ba 690kB
Еще один вариант для получения списка образов
$ kubeadm config images list
k8s.gcr.io/kube-apiserver:v1.21.2
k8s.gcr.io/kube-controller-manager:v1.21.2
k8s.gcr.io/kube-scheduler:v1.21.2
k8s.gcr.io/kube-proxy:v1.21.2
k8s.gcr.io/pause:3.4.1
k8s.gcr.io/etcd:3.4.13-0
k8s.gcr.io/coredns/coredns:v1.8.0
Pull (create)
Скачивается из репозитория и устанавливается образ контейнера
Rmi (delete)
Volumes
Том emptyDir идеально подходит для кэширования и обмена временными файлами, однако некоторым приложениям — например, базам данных необходимо хранить постоянную информацию. Постоянное хранение данных значительно усложняет конфигурацию Kubernetes для вашего приложения, потому что использует дополнительные облачные ресурсы и требует наличия резервного копирования. Но если вам в Kubernetes нужны постоянные тома, ресурс PersistentVolume - это то, что вы ищете. Больше о PersistentVolume можно почитать в документации Kubernetes (kubernetes.io/docs/concepts/storage/persistent-volumes).
Create
Создаем манифест для PVC pvc-add-new.yaml
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: rgpu-pv
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /data
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- rgpu-node
Создаем PersistentVolume
Get
Вывести постоянные тома (PersistentVolumes), отсортированные по емкости
Получить метку версии всех подов с меткой app=cassandra:
Describe
$ kubectl describe pv/rgpu-pv
Name: rgpu-pv
Labels: <none>
Annotations: <none>
Finalizers: [kubernetes.io/pv-protection]
StorageClass: local-storage
Status: Available
Claim:
Reclaim Policy: Delete
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 100Gi
Node Affinity:
Required Terms:
Term 0: kubernetes.io/hostname in [rgpu-node]
Message:
Source:
Type: LocalVolume (a persistent volume backed by local storage on a node)
Path: /data
Events: <none>
Манифесты ресурсов
Использование команды kubectl run для создания развертываний хоть и полезно, но имеет ограничения. Представьте, что вам хочется что-то поменять в спецификации развертывания: скажем, имя или версию образа. Вы могли бы удалить существующий объект Deployment (с помощью kubectl delete) и создать новый с подходящими полями. Но есть лучший способ.
Поскольку система Kubernetes по своей природе является декларативной и непрерывно согласовывает реальное состояние с желаемым, вам достаточно лишь поменять последнее (спецификацию развертывания), и Kubernetes все сделает за вас. Как это достигается?
Все ресурсы Kubernetes, такие как развертывания и pod-оболочки, представлены записями во внутренней базе данных. Цикл согласования следит за любыми изменениями в записях и предпринимает соответствующие действия. На самом деле команда kubectl run лишь добавляет в базу данных новую запись о развертывании, а система делает все остальное. Но для взаимодействия с Kubernetes вовсе не обязательно использовать команду kubectl run — вы можете создавать манифесты ресурсов (спецификацию их желаемого состояния) напрямую. Если хранить файл манифеста в системе контроля версий, то вместо выполнения императивных команд можно просто подменить этот файл и затем заставить Kubernetes прочитать обновленные данные.
Итак, приступим.
Сначала смотрим какая версия API применима для деплоя.
Посмотреть документацию по манифестам подов
$ kubectl explain pods
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is
created by clients and scheduled onto hosts.
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
spec <Object>
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
status <Object>
Most recently observed status of the pod. This data may not be up to date.
Populated by the system. Read-only. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
Теперь создадим файл манифеста application/deployment.yaml
apiVersion: apps/v1 # до версии 1.9.0 нужно использовать apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # запускает 2 пода, созданных по шаблону
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Запускаем приложение:
Смотрим подробности:
$ kubectl describe deployments
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 29 Jun 2021 14:58:22 +0300
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 0 available | 2 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.14.2
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available False MinimumReplicasUnavailable
Progressing False ProgressDeadlineExceeded
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-66b6c48dd5 (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-66b6c48dd5 to 2
Видим, что “Host Port” не назначен.
Исправим конфигурацию пода, назначив ему порт 8888 на хосте:
containers:
- image: nginx:1.14.2
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
hostPort: 8888
protocol: TCP
После этого, убедимся, что на рабочем узле порт 8888 открылся:
root@kuber-3:/home/ubuntu# sudo netstat -tulpn | grep 8888
tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN 761/crio
tcp6 0 0 :::8888 :::* LISTEN 761/crio
Теперь можно посмотреть работу приложения:
Пример приложения
В качестве примера, как это сделано в официальной документации, предлагаю вам запустить тестовое микросервисное приложение sock-shop (Интернет-магазин носков).
Создаем отдельное пространство имен:
Запускаем приложение:
$ kubectl apply -n sock-shop -f "https://github.com/microservices-demo/microservices-demo/blob/master/deploy/kubernetes/complete-demo.yaml?raw=true"
Следим за созданием подов:
$ kubectl get pods -n sock-shop
NAME READY STATUS RESTARTS AGE
carts-b4d4ffb5c-ztrgk 0/1 ContainerCreating 0 88s
carts-db-6c6c68b747-rmhtj 0/1 ContainerCreating 0 88s
catalogue-759cc6b86-62dpf 0/1 ContainerCreating 0 88s
catalogue-db-96f6f6b4c-wmwtt 0/1 ContainerCreating 0 88s
front-end-5c89db9f57-qlvm9 0/1 ContainerCreating 0 88s
orders-7664c64d75-44lr6 0/1 ContainerCreating 0 87s
orders-db-659949975f-5dd5l 0/1 ContainerCreating 0 87s
payment-7bcdbf45c9-v8xqv 0/1 ContainerCreating 0 87s
queue-master-5f6d6d4796-xvt5j 0/1 ContainerCreating 0 87s
rabbitmq-5bcbb547d7-tvcc5 0/2 ContainerCreating 0 87s
session-db-7cf97f8d4f-98jch 0/1 ContainerCreating 0 87s
shipping-7f7999ffb7-4fv7d 0/1 ContainerCreating 0 86s
user-68df64db9c-7mvbr 0/1 ContainerCreating 0 86s
user-db-6df7444fc-zkmqf 0/1 ContainerCreating 0 86s
Как только все контейнеры будут запущены, необходимо выяснить, на каком порту опубликовано это приложение.
Для этого используем команду:
$ kubectl describe svc front-end -n sock-shop
Name: front-end
Namespace: sock-shop
Labels: name=front-end
Annotations: prometheus.io/scrape: true
Selector: name=front-end
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.110.238.210
IPs: 10.110.238.210
Port: <unset> 80/TCP
TargetPort: 8079/TCP
NodePort: <unset> 30001/TCP
Endpoints: 10.85.3.160:8079
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
Здесь видно, что frontend-приложение запущено по адресу http://10.0.128.233:30001
$ kubectl get svc -n sock-shop
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
carts ClusterIP 10.107.94.25 <none> 80/TCP 69m
carts-db ClusterIP 10.108.113.150 <none> 27017/TCP 69m
catalogue ClusterIP 10.99.209.178 <none> 80/TCP 69m
catalogue-db ClusterIP 10.98.178.199 <none> 3306/TCP 69m
front-end NodePort 10.110.238.210 <none> 80:30001/TCP 69m
orders ClusterIP 10.98.139.44 <none> 80/TCP 69m
orders-db ClusterIP 10.108.171.149 <none> 27017/TCP 69m
payment ClusterIP 10.108.155.212 <none> 80/TCP 69m
queue-master ClusterIP 10.96.95.92 <none> 80/TCP 69m
rabbitmq ClusterIP 10.96.104.171 <none> 5672/TCP,9090/TCP 69m
session-db ClusterIP 10.104.88.145 <none> 6379/TCP 69m
shipping ClusterIP 10.98.104.222 <none> 80/TCP 69m
user ClusterIP 10.109.61.179 <none> 80/TCP 69m
user-db ClusterIP 10.106.92.76 <none> 27017/TCP 69m