Рассмотрим несколько основных ресурсов/объектов в Kubernetes
Ресурс/Объект Pod
Pod — минимальная базовая единица Kubernetes, представляет собой группу из одного или нескольких контейнеров (например, контейнеров Docker) с общим хранилищем / сетью и спецификацией для запуска контейнеров
Сам по себе не может перезапускаться автоматически при ручном или аварийном завершении своей работы. Поэтому выше над Pod-ом существуют другие ресурсы,которые позволяют отслеживать и перезапускать поды(ReplicaSet/Deployment)
1 |
# nano pod.yml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
apiVersion: v1 kind: Pod metadata: name: nginx labels: name: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "250m" |
Создание пода
1 |
# kubectl apply -f pod.yml |
1 |
pod/nginx created |
Просмотр наличия созданного пода
1 |
# kubectl get pod nginx |
1 2 |
NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 13s |
Просмотр детального описания созданного пода
1 |
# kubectl describe pod nginx |
Ресурс/Объект ReplicaSet
ReplicaSet следит и поддерживает желаемое кол-во запущенных реплик Pod-ов в любой момент времени
Как правило,самостоятельно ReplicaSet не используется в виду того,что не поддерживает некоторые полезные возможности, которые релизованы/поддерживаются в ресурсе Deployment, который включает в себя и управляет в том числе ReplicaSet-ом
Например, при обновлении приложения ReplicaSet удаляет все свои реплики, а потом создает новые реплики с новым приложением без контроля порядка запуска и какой-либо гарантии успешного запуска, что приводит к недоступности приложения при его обновлении
Ресурс Deployment позволяет определить условия/порядок/политики очередности удаления и создания реплик для того, чтобы поддерживать необходимое кол-во реплик всегда в запущенном виде и таким образом гарантировать ,что приложение всегда было доступно(т.е. zero-downtime обновление)
1 |
# nano replicaset.yml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
apiVersion: extensions/v1beta1 kind: ReplicaSet metadata: name: nginx-rs spec: replicas: 3 template: metadata: labels: app: nginx tier: frontend spec: containers: - name: nginx image: nginx resources: requests: cpu: 256m memory: 100Mi ports: - containerPort: 80 |
1 |
# kubectl apply -f replicaset.yml |
1 |
# kubectl get pods |
1 2 3 4 |
NAME READY STATUS RESTARTS AGE nginx-rs-4cnck 1/1 Running 0 26s nginx-rs-b29vc 1/1 Running 0 26s nginx-rs-sx74t 1/1 Running 0 22h |
1 |
# kubectl get rs |
1 2 |
NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-rs 3 3 3 22h |
Ресурс/Объект horizontalpodautoscaler
Автоматическое регулирование кол-ва подов в зависимости от нагрузки процессора(добавление пода/подов при нагрузке CPU от 80%)
Минимальное кол-во подов-1
Максимальное кол-во подов-10
После выполнения этой команды(до этого было 3 запущенных пода) останется запущенным только 1 под(2 пода будут автоматически удалены) т.к. нагрузка на процессор маленькая и происходит автоудаление кол-во подов до минимального кол-ва, которого достаточно, чтобы нагрузка на процессоре не выходила за установленные пределы
1 |
# kubectl autoscale replicaset nginx-rs --max=10 |
1 |
# kubectl get horizontalpodautoscaler |
1 2 |
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-rs ReplicaSet/nginx-rs 0%/80% 1 10 1 3m |
1 |
# kubectl get rs |
1 2 |
NAME DESIRED CURRENT READY AGE nginx-rs 1 1 1 22h |
1 |
# kubectl get pods |
1 2 |
NAME READY STATUS RESTARTS AGE nginx-rs-sx74t 1/1 Running 0 22h |
Декларативным способ создания horizontalpodautoscaler с помощью yaml-файла
1 |
# nano horizontalpodautoscaler.yml |
1 2 3 4 5 6 7 8 9 10 11 |
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: nginx-hpa spec: maxReplicas: 10 minReplicas: 1 scaleTargetRef: kind: ReplicaSet name: nginx-rs targetCPUUtilizationPercentage: 80 |
1 |
# kubectl apply -f horizontalpodautoscaler.yml |
1 |
horizontalpodautoscaler.autoscaling/nginx-hpa created |
Ресурс/Объект Deployment
Deployment включает в себя ReplicaSet и Pod и позволяет устанавливать политики/правила для zero-downtime автоматического обновления/отката приложений, запущенных в контейнерах
Создание Deployment
1 |
# nano deployment.yml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 1 replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx resources: requests: cpu: 256m memory: 100Mi ports: - containerPort: 80 |
1 |
# kubectl apply -f deployment.yml --record |
1 |
deployment.apps/nginx-deployment configured |
Если установлена опция —record, то текущая kubectl команда будет записана в аннотацию ресурса(деплоймента)
1 |
# kubectl describe deployments nginx-deployment | grep -i annotations |
1 2 |
Annotations: deployment.kubernetes.io/revision: 1 {"apiVersion":"apps/v1beta1","kind":"Deployment","metadata":{"annotations":{"kubernetes.io/change-cause":"kubectl apply --filename=deploym... |
Кроме того такая команда также будет присутствовать в истории обновлений
1 |
# kubectl rollout history deployment nginx-deployment |
1 2 3 4 |
deployment.extensions/nginx-deployment REVISION CHANGE-CAUSE 0 <none> 1 kubectl apply --filename=deployment.yml --record=true |
Все дальнейшие команды по этому деплойменту также будут присутствовать в истории
1 |
# kubectl get deployment |
1 2 |
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 57s |
1 |
# kubectl get pod |
1 2 3 4 |
NAME READY STATUS RESTARTS AGE nginx-deployment-78dc5754fb-776zh 1/1 Running 0 1m nginx-deployment-78dc5754fb-82b8v 1/1 Running 0 1m nginx-deployment-78dc5754fb-glg2t 1/1 Running 0 1m |
Посмотрим как происходит процесс обновления приложения
Обновим образ, с которого запускаются контейнеры в подах в деплойменте nginx-deployment
1 |
# kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 |
1 |
deployment.extensions/nginx-deployment image updated |
И посмотрим,как происходит замена replicaset-ов(соответственно и подов ,принадлежащих этой replicaset) на новый replicaset
1 |
# kubectl describe deployments nginx-deployment |
1 2 3 4 5 6 |
…… OldReplicaSets: nginx-deployment-78dc5754fb (1/1 replicas created) NewReplicaSet: nginx-deployment-57d896dbfc (3/3 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- |
Это то,что было до выполнения команды по обновлению образа
1 2 |
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-78dc5754fb to 3 Normal ScalingReplicaSet 12m deployment-controller Scaled down replica set nginx-rs to 0 |
После обновления образа кол-во реплик в новой ReplicaSet(nginx-deployment-57d896dbfc) увеличивается на 1(с 0 на 1), после чего кол-во реплик в старой ReplicaSet(nginx-deployment-78dc5754fb) уменьшается на 1 (с 3 до 2)
Т.к. в настройках RollingUpdate выставлены следующие параметры
1 2 3 4 |
type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 1 |
Максимальное кол-во недоступных подов состовляет 0 (параметр maxUnavailable ) и максимальное кол-во подов, которые может быть создано за раз составляет 1(параметр maxSurge)
т.е. при кол-ве реплик 3, сначала создается первый новый под с новым образом(первая реплика новой ReplicaSet)(но в сумме он уже является четвертым), потом удаляется один под со старым образом(удаляется первая реплика старой ReplicaSet)(таким образом общее кол-во подов уменьшается до 3-х)
Так происходит до тех пор, пока все поды не обновляться со старого образа на новый
1 2 3 4 5 |
Normal ScalingReplicaSet 36s deployment-controller Scaled up replica set nginx-deployment-57d896dbfc to 1 Normal ScalingReplicaSet 23s deployment-controller Scaled down replica set nginx-deployment-78dc5754fb to 2 Normal ScalingReplicaSet 23s deployment-controller Scaled up replica set nginx-deployment-57d896dbfc to 2 Normal ScalingReplicaSet 15s deployment-controller Scaled down replica set nginx-deployment-78dc5754fb to 1 Normal ScalingReplicaSet 15s deployment-controller Scaled up replica set nginx-deployment-57d896dbfc to 3 |
Просмотр кол-ва новой(nginx-deployment-57d896dbfc) и старой(nginx-deployment-78dc5754fb) ReplicaSet-ов
1 |
# kubectl get rs |
1 2 3 |
NAME DESIRED CURRENT READY AGE nginx-deployment-57d896dbfc 3 3 3 21m nginx-deployment-78dc5754fb 0 0 0 33m |
Посмотрим как происходит процесс отката приложения(rollback) на более раннюю версию
Откатимся к предыдущей версии приложения
1 |
# kubectl rollout undo deployment nginx-deployment |
1 |
deployment.extensions/nginx-deployment rolled back |
Проверим, что старая ReplicaSet(nginx-deployment-78dc5754fb) снова имеет 3 реплики, а новая(nginx-deployment-57d896dbfc) ReplicaSet-0
1 |
# kubectl get rs |
1 2 3 |
NAME DESIRED CURRENT READY AGE nginx-deployment-57d896dbfc 0 0 0 26m nginx-deployment-78dc5754fb 3 3 3 37m |
Соответственно и поды запущенные со старой ReplicaSet
1 |
# kubectl get pod |
1 2 3 4 |
NAME READY STATUS RESTARTS AGE nginx-deployment-78dc5754fb-96xnr 1/1 Running 0 25m nginx-deployment-78dc5754fb-t2fmv 1/1 Running 0 25m nginx-deployment-78dc5754fb-zdxxr 1/1 Running 0 25m |
Ресурс/Объект Service
Service – это абстракция, которая определяет логический набор Pod-ов и политику доступа к ним
Т.к. IP-адреса подов действительны только на протяжении жизни пода и авто/ручное масштабирование подразумевает увеличение/уменьшение кол-ва запущенных подов, да и просто под может быть автоматичеки перезапущен deployment-ом/replicaset-ом в случае проблем с ним, то для доступа к группе подов используют единую точку доступа – Service
Объект Service с типом ClusterIP
Сервисе с типом CusterIP доступен только внутри кластера для любого пода, запущенного в этом кластере
1 |
# nano service.yml |
1 2 3 4 5 6 7 8 9 10 11 12 |
kind: Service apiVersion: v1 metadata: name: nginx-service spec: type: ClusterIP selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 |
1 |
# kubectl apply -f service.yml |
1 |
service/nginx-service created |
Проверим наличие созданного объекта Service
1 |
# kubectl get service nginx-service |
1 2 |
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service ClusterIP 10.7.251.234 <none> 80/TCP 38s |
Просмотрим детальное описание сервиса nginx-service, его Endpoints – поды, на которые перенаправляются запросы поступившие на этот под
Т.е. запросы на сервис nginx-service( на кластерный IP-адрес сервиса 10.7.251.234 и Port(80) протокол(TCP) будут перенаправляться на поды 10.4.0.15, 10.4.1.12, 10.4.2.9 на порт 80
1 |
# kubectl describe service nginx-service |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Name: nginx-service Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx-service","namespace":"default"},"spec":{"ports":[{"port":80... Selector: app=nginx Type: ClusterIP IP: 10.7.251.234 Port: <unset> 80/TCP TargetPort: 80/TCP Endpoints: 10.4.0.15:80,10.4.1.12:80,10.4.2.9:80 Session Affinity: None Events: <none> |
Кластерный IP-адрес у Service — 10.7.251.234
Kubernetes поддерживает 2 основных способа/метода разименования Service(получение IP-адреса и порта, который соответствует данному имени сервиса)
— DNS
— переменные окружения
Рассмотрим рекомендуемый способ/метод разименования — DNS
Благодаря встроенному в Kubernetes Service Discovery (Etcd) и DNS-серверам в кластере(KubeDNS или CoreDNS), имя сервиса nginx-service резолвится в кластерный IP-адрес(10.7.251.234), который доступен со всех подов кластера
Например, создадим Pod с именем busybox на основе образа busybox
Подключимся внутрь контейнера, запущенного в этом Pod-е и проверим доступность сервиса nginx-service внутри этого пода
1 |
# kubectl run -it busybox --image=busybox --restart=Never -- sh |
1 |
If you don't see a command prompt, try pressing enter. |
Просмотр содержимого фалйа /etc/resolv.conf внутр. Контейнера с busybox
1 |
# cat /etc/resolv.conf |
1 2 3 |
nameserver 10.7.240.10 search default.svc.cluster.local svc.cluster.local cluster.local europe-west1-b.c.mydemoproject-231415.internal c.mydemoproject-231415.internal google.internal options ndots:5 |
Как видно, в файле /etc/resolv.conf внутри контейнера указаны DNS-сервер/IP-адрес 10.7.240.10
На самом деле этот IP-адрес 10.7.240.10 — это кластерный IP-адрес Service kube-dns
1 |
# kubectl get service kube-dns -n kube-system |
1 2 |
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.7.240.10 <none> 53/UDP,53/TCP 3d |
Этот Service kube-dns имеет под собой endpoint-ы – поды с запущенной DNS-службой кластера, куда и перенаправляет запросы, поступивший от нашего пода busybox
1 |
# kubectl describe service kube-dns -n kube-system | grep Endpoints |
1 |
Endpoints: 10.4.0.7:53,10.4.2.3:53 |
Просмотр подов,которым принадлежат эти IP-адреса
1 |
# kubectl get pod -n kube-system | grep kube-dns |
1 2 |
kube-dns-7df4cb66cb-h2jk8 4/4 Running 0 3d kube-dns-7df4cb66cb-x42bn 4/4 Running 0 3d |
1 |
# kubectl describe pod kube-dns-7df4cb66cb-h2jk8 -n kube-system | grep IP |
1 |
IP: 10.4.2.3 |
1 |
# kubectl describe pod kube-dns-7df4cb66cb-x42bn -n kube-system | grep IP |
1 |
IP: 10.4.0.7 |
Вот так выглядит цепочка прохождения запроса от кластерного IP-адреса сервиса с типом ClusterIP(10.7.240.10) до одного из активных/запущенных подов, используемых как endpoint-ы для этого сервиса
1 |
# iptables -t nat -S | grep 10.7.240.10 |
1 2 |
-A KUBE-SERVICES -d 10.7.240.10/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp cluster IP" -m tcp --dport 53 -j KUBE-SVC-ERIFXISQEP7F7OF4 -A KUBE-SERVICES -d 10.7.240.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU |
1 |
# iptables -t nat -S | grep KUBE-SVC-TCOU7JCQXEZGVUNU |
1 2 |
-A KUBE-SVC-TCOU7JCQXEZGVUNU -m comment --comment "kube-system/kube-dns:dns" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-WXUE6X3P23KLLLFX -A KUBE-SVC-TCOU7JCQXEZGVUNU -m comment --comment "kube-system/kube-dns:dns" -j KUBE-SEP-IGGMPJYRK3FAVK6I |
1 |
# iptables -t nat -S | grep KUBE-SEP-WXUE6X3P23KLLLFX |
1 |
-A KUBE-SEP-WXUE6X3P23KLLLFX -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.4.0.7:53 |
1 |
# iptables -t nat -S | grep KUBE-SEP-IGGMPJYRK3FAVK6I |
1 |
-A KUBE-SEP-IGGMPJYRK3FAVK6I -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.4.2.3:53 |
Т.е. каждый первый запрос перенаправляется на под с адресом 10.4.0.7
каждый второй запрос перенаправляется на под с адресом 10.4.2.3
т.е. равномерное распределение запросов на все поды(в данном случае на два пода)
Выполним проверку на разименование имени сервиса nginx-service в кластерный IP-адрес сервиса nginx-service (10.7.251.234)
Делаем запрос на получение IP-адреса, на котором доступен сервис nginx-service(10.7.251.234)
1 |
# nslookup nginx-service |
1 2 3 4 5 |
Server: 10.7.240.10 Address: 10.7.240.10:53 Name: nginx-service.default.svc.cluster.local Address: 10.7.251.234 |
Т.е. контейнер с busybox корректно получил кластерный IP-адрес сервиса nginx-service(10.7.251.234)
Рассмотрим альтернативный способ/метод разименования имени сервиса в IP-адрес — через переменные окружения
Внутри контейнера с busybox также доступны следующие переменные относительно nginx-service
Наполнение контейнера переменными происходит при старте контейнера
Если изменяется Service, то новые настройки Service будут доступны внутри контейнера только после рестарта контейнера
Также это накладывает ограничения на порядок создания сервисов и подов — любой сервис, к которому должен обращаться под
должен быть создан ДО содания самого пода, иначе переменные по сервису будут отсутствовать в этом поде
DNS-способ разименования сервиса лишен такого недостатка
1 |
# env | grep -i nginx_service |
1 2 3 4 5 6 7 |
NGINX_SERVICE_PORT_80_TCP=tcp://10.7.251.234:80 NGINX_SERVICE_SERVICE_HOST=10.7.251.234 NGINX_SERVICE_SERVICE_PORT=80 NGINX_SERVICE_PORT=tcp://10.7.251.234:80 NGINX_SERVICE_PORT_80_TCP_ADDR=10.7.251.234 NGINX_SERVICE_PORT_80_TCP_PORT=80 NGINX_SERVICE_PORT_80_TCP_PROTO=tcp |
Объект Service с типом LoadBalancer
Service c типом LoadBalancer позволяется опубликовать/выставить порты наружу для возможности подключения к приложению снаружи кластера
Сервис с типом ClusterIP, на которую будет пернаправляться запросы с внешнего лоадбалансера, создается автоматически
1 |
# nano service-lb.yml |
1 2 3 4 5 6 7 8 9 10 11 12 |
kind: Service apiVersion: v1 metadata: name: nginx-service-lb spec: type: LoadBalancer selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 |
Проверим наличие созданного объекта Service
1 |
# kubectl get service nginx-service-lb |
1 2 |
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service-lb LoadBalancer 10.7.251.199 <pending> 80:30960/TCP 22s |
Через 1-2 минуты проверим наличие внешнего IP-адреса, который выдал нам облачным провайдер(в данном случае Google Cloud)
1 |
# kubectl get service nginx-service-lb |
1 2 |
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service-lb LoadBalancer 10.7.251.199 35.195.161.174 80:30960/TCP 1m |
Внешний IP-адрес у Service — 35.195.161.174
На этот адрес приходят клиентские запросы на приложение
Т.е. curl http://35.195.161.174/ отдаст дефолтную страницу nginx одного из контейнеров, запущенных на одном из трех подов в кластере
1 |
# kubectl describe service nginx-service-lb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Name: nginx-service-lb Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx-service-lb","namespace":"default"},"spec":{"ports":[{"port"... Selector: app=nginx Type: LoadBalancer IP: 10.7.251.199 LoadBalancer Ingress: 35.195.161.174 Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 30960/TCP Endpoints: 10.4.0.15:80,10.4.1.12:80,10.4.2.9:80 Session Affinity: None External Traffic Policy: Cluster Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal EnsuringLoadBalancer 2m59s service-controller Ensuring load balancer Normal EnsuredLoadBalancer 2m2s service-controller Ensured load balancer |
Приведенные команды и их вывод позволяет отследить путь прохождения пакета по цепочкам таблицы nat для того, чтобы лучше понять, как пакет от клиента достигает одного из подов кластера
Часть вывода команд не релевантного с путем прохождения пакетов была удалена, с целью сделать цепочку прохождения пакета более прозрачнее/нагляднее
Service с типом LoadBalancer(внешний IP-адрес 35.195.161.174)
1 |
# iptables -t nat -S | grep 35.195.161.174 |
1 |
-A KUBE-SERVICES -d 35.195.161.174/32 -p tcp -m comment --comment "default/nginx-service-lb: loadbalancer IP" -m tcp --dport 80 -j KUBE-FW-CSBU7TIZCSDDORIJ |
1 |
# iptables -t nat -S | grep KUBE-FW-CSBU7TIZCSDDORIJ |
1 |
-A KUBE-FW-CSBU7TIZCSDDORIJ -m comment --comment "default/nginx-service-lb: loadbalancer IP" -j KUBE-SVC-CSBU7TIZCSDDORIJ |
1 |
# iptables -t nat -S | grep KUBE-SVC-CSBU7TIZCSDDORIJ |
1 2 3 |
-A KUBE-SVC-CSBU7TIZCSDDORIJ -m comment --comment "default/nginx-service-lb:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-AS3IGE6XRMJNFXBT -A KUBE-SVC-CSBU7TIZCSDDORIJ -m comment --comment "default/nginx-service-lb:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-BPP6AQRTTNGZWXC5 -A KUBE-SVC-CSBU7TIZCSDDORIJ -m comment --comment "default/nginx-service-lb:" -j KUBE-SEP-ZY62GXQYVTAS7DDC |
1 |
# iptables -t nat -S | grep KUBE-SEP-AS3IGE6XRMJNFXBT |
1 |
-A KUBE-SEP-AS3IGE6XRMJNFXBT -p tcp -m comment --comment "default/nginx-service-lb:" -m tcp -j DNAT --to-destination 10.4.0.15:80 |
1 |
# iptables -t nat -S | grep KUBE-SEP-BPP6AQRTTNGZWXC5 |
1 |
-A KUBE-SEP-BPP6AQRTTNGZWXC5 -p tcp -m comment --comment "default/nginx-service-lb:" -m tcp -j DNAT --to-destination 10.4.1.12:80 |
1 |
# iptables -t nat -S | grep KUBE-SEP-ZY62GXQYVTAS7DDC |
1 |
-A KUBE-SEP-ZY62GXQYVTAS7DDC -p tcp -m comment --comment "default/nginx-service-lb:" -m tcp -j DNAT --to-destination 10.4.2.9:80 |
1 |
# kubectl get pod -o wide | grep nginx-deployment |
1 2 3 |
nginx-deployment-78dc5754fb-96xnr 1/1 Running 0 2d 10.4.2.9 gke-standard-cluster-1-default-pool-737b59bf-dt6k <none> nginx-deployment-78dc5754fb-t2fmv 1/1 Running 0 2d 10.4.1.12 gke-standard-cluster-1-default-pool-737b59bf-c3x9 <none> nginx-deployment-78dc5754fb-zdxxr 1/1 Running 0 2d 10.4.0.15 gke-standard-cluster-1-default-pool-737b59bf-x6s5 <none> |
т.е. каждый третий пакет идет на под с адресом 10.4.0.15
каждый второй пакет от оставшихся 2/3 пакетов(т.е. половина из оставшихся) идет на под с адресом 10.4.1.12
все остальные оставшиеся пакеты(это 1/3) идут на под с адресом 10.4.2.9
Тем самым достигается равномерное распределение запросов на все 3 пода
Service с типом Node Port
Аналогичная ситуация с прохождением пакеты по сервису с типом NodePort(на всех нодах кластера открывается средствами запущенного на каждой ноде kube-proxy рандомный порт (если не указано принудительно) из диапазона 30000-32767) и на этот порт можно направлять запросы на любую из нод(независимо от того, запущен ли на этой ноде нужный под или нет)
Сервис с типом ClusterIP, на которую будет пернаправляться запросы с service NodePort, создается автоматически
Например, сервис с типом NodePort можно использовать, когда перед нодами кластерами стоит собственный(не облачный) лоадбалансер(например, Haproxy)
1 |
# iptables -t nat -S | grep 30960 |
1 |
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-service-lb:" -m tcp --dport 30960 -j KUBE-SVC-CSBU7TIZCSDDORIJ |
Далее цепочка прохождения пакетов аналогично варианту с типом Service LoadBalancer
Начиная с команды
1 |
# iptables -t nat -S | grep KUBE-FW-CSBU7TIZCSDDORIJ |
Взаимодействие компонентов кластера при сервисе типа ClusterIP и сервисы типа LoadBalancer указаны на схеме
Ресурс/Объект Secret
Создание файлов, из которых будем создавать Secret
1 |
# cat secret1.txt |
1 |
This is a secret |
1 |
# cat secret2.txt |
1 |
This is another secret |
Создание Secret из файлов императивным способом
1 |
# kubectl create secret generic my-secrets --from-file=./secret1.txt --from-file=./secret2.txt |
1 |
secret/my-secrets created |
Проверка наличия созданного секрета
1 |
# kubectl get secret my-secrets |
1 2 |
NAME TYPE DATA AGE my-secrets Opaque 2 1m |
Просмотр детальной информации о секрете
1 |
# kubectl describe secret my-secrets |
1 2 3 4 5 6 7 8 9 10 11 |
Name: my-secrets Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== secret1.txt: 16 bytes secret2.txt: 22 bytes |
Создание Secret из файлов декларативным способом(из yaml-файла)
Для этого получим base64-код содержимого файлов, из которых создаем Secret
1 |
# cat secret1.txt | base64 |
1 |
VGhpcyBpcyBhIHNlY3JldA== |
1 |
# cat secret2.txt | base64 |
1 |
VGhpcyBpcyBhbm90aGVyIHNlY3JldA== |
YAML-файл для создания Secret имеет вид
1 |
# nano secret.yaml |
1 2 3 4 5 6 7 8 |
apiVersion: v1 kind: Secret metadata: name: my-secret-yaml type: Opaque data: secret1: VGhpcyBpcyBhIHNlY3JldA== secret2: VGhpcyBpcyBhbm90aGVyIHNlY3JldA== |
Создадим Secret применяя данный файл
1 |
# kubectl create -f secret.yml |
1 |
secret/my-secret-yaml created |
1 |
# kubectl get secret my-secret-yaml |
1 2 |
NAME TYPE DATA AGE my-secret-yaml Opaque 2 19s |
1 |
# kubectl describe secret my-secret-yaml |
1 2 3 4 5 6 7 8 9 10 11 |
Name: my-secret-yaml Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== secret2: 22 bytes secret1: 16 bytes |
Монтирование Secret-ов внутри пода с помощью volume(тома) для доступа контейнеров к Secret-ам
Например, создадам Pod через yaml-файл с примонтированным внутри контейнера (в каталог /secrets) секретом my-secrets, который был создан ранее
Файл для создания ресурса Pod с монтированием секретов
1 |
# nano pod-secrets.yml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
apiVersion: v1 kind: Pod metadata: name: nginx labels: name: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "250m" volumeMounts: - name: secrets mountPath: /secrets readOnly: true volumes: - name: secrets secret: secretName: my-secrets |
Проверка синтаксиса созданного файла pod-secrets.yml
1 |
# kubectl apply --dry-run --validate=true -f pod-secrets.yml |
1 |
pod/nginx created (dry run) |
Создание пода и проверка наличия созданного пода, а также наличия секретов внутри контейнера в поде
1 |
# kubectl apply -f pod-secrets.yml |
1 |
pod/nginx created |
1 |
# kubectl get pod nginx |
1 2 |
NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 3m |
1 |
# kubectl exec -it nginx -- ls -l /secrets |
1 2 3 |
total 0 lrwxrwxrwx 1 root root 18 Mar 31 16:12 secret1.txt -> ..data/secret1.txt lrwxrwxrwx 1 root root 18 Mar 31 16:12 secret2.txt -> ..data/secret2.txt |
1 |
# kubectl exec -it nginx -- cat /secrets/secret1.txt |
1 |
This is a secret |
1 |
# kubectl exec -it nginx -- cat /secrets/secret2.txt |
1 |
This is another secret |
Ресурс/Объект ConfigMap
Ключевые особенности/преимущества ConfigMap-ов
а) могут содержать пары ключ/значение
б) могут использоваться множеством подов одновременно
в) могут быть обновлены не зависимо от пода
Наполнение переменных окружения пода с помощью Configmap
Создание Configmap с помощью императивного способа
ConfigMap-ы могут быть
А)созданы из файлов с переменными(эти файлы должны содержать информацию в формате ключ=значение по одному на строку, пустые строки и строки, начинающиеся с символа # игнорируются.)
1 |
# cat my-env-file |
1 2 3 |
var1=25 var2="myvalue" var3="true" |
1 |
# kubectl create configmap myconfigmap --from-env-file=my-env-file |
Следует заметить, что при передаче нескольких параметров —from-env-file для создания конфигмапа, будет использован только последний из указанных файлов.
Б)c указанием переменных непосредственно в команде
1 |
# kubectl create configmap myconfigmap2 --from-literal=var1=25 --from-literal=var2=myvalue --from-literal=var3=true |
Создание Configmap с помощью декларативного способа(из yaml-файла)
В) Создание из yaml-файлов
Значения переменных, которые берутся из Configmap наполняются в поде при старте пода.
Если после запуска пода изменилось значение в ConfigMap, то для того, чтобы под применил такое изменение, под должен быть перезапущен
Например, файл описания сonfimap имеет вид
1 |
# cat configmap.yml |
1 2 3 4 5 6 7 |
apiVersion: v1 kind: ConfigMap metadata: name: my-configmap data: someVariable: some value someOtherVariable: "true" |
Создадим его и проверим его наличие
1 |
# kubectl apply -f configmap.yml |
1 |
# kubectl get configmap my-configmap |
1 2 |
NAME DATA AGE my-configmap 2 134m |
Файл описания пода имеет вид
1 |
# cat pod.yml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: app image: alpine command: ["sleep", "3600"] env: - name: SOME_VARIABLE valueFrom: configMapKeyRef: name: my-configmap key: someVariable |
Создадим под и проверим наличие корректного значения переменной someVariable внутри этого пода.
1 |
# kubectl apply -f pod.yml |
1 |
# kubectl exec -it my-pod printenv | grep -i some |
1 |
SOME_VARIABLE=some value |
Изменим значение переменной someVariable в configmap c «some value2» на «some value2» в действующем конфигмапе
1 |
# kubectl edit configmap my-configmap |
1 |
# kubectl describe configmap | grep -i 'some value' |
1 |
some value2 |
Но в поде остается старое значение переменной
1 |
# kubectl exec -it my-pod printenv | grep -i some |
1 |
SOME_VARIABLE=some value |
Для того,чтобы в поде появилось новое значение, под нужно перезапустить
1 |
# kubectl delete pod my-pod |
1 |
# kubectl apply -f pod.yml |
1 |
# kubectl exec -it my-pod printenv | grep -i some |
1 |
SOME_VARIABLE=some value2 |
В описании пода(файле pod.yml) мы явно указываем, значения каких ключей необходимо брать(в данном случае значение переменной someVariable)
1 2 3 4 5 6 |
env: - name: SOME_VARIABLE valueFrom: configMapKeyRef: name: my-configmap key: someVariable |
Если нужно все переменные получить доступными в поде из конфигмапа, тогда описание пода относительно получения всех доступных в конфигмапе переменных может иметь вид
1 2 3 4 5 |
…… command: ["sleep", "3600"] envFrom: - configMapRef: name: my-configmap |
Конфигурации приложения, запущенного в поде с помощью Configmap
Создания configmap-ов из файлов с конфигурацией, которая используется приложением, запущенным в поде
Либо с одного файла
1 |
# kubectl create configmap myconfigmap --from-file=my-config-file |
Либо с нескольких файлов
1 |
# kubectl create configmap myconfigmap --from-file=my-config-file --from-file=my-config-file2 |
Либо с нескольких файлов, находящихся внутри одной директории
1 |
# kubectl create configmap myconfigmap --from-file=mydir/ |
Например, создадим configmap из файлов,находящихся внутри каталога config
1 |
# ls -l config/ |
1 2 3 |
total 8 -rw-r--r-- 1 root root 46 Jun 25 2018 config.ini -rw-r--r-- 1 root root 39 Jun 25 2018 database.ini |
1 |
# cat config/config.ini |
1 2 |
some_variable = foo some_other_variable = baz |
1 |
# cat config/database.ini |
1 |
uri = mongodb://my-database:27017/test |
1 |
# kubectl create configmap my-configmap --from-file=config/ |
1 |
configmap/my-configmap created |
1 |
# kubectl get configmap |
1 2 |
NAME DATA AGE my-configmap 2 18s |
1 |
# kubectl describe configmap |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Name: my-configmap Namespace: default Labels: <none> Annotations: <none> Data ==== config.ini: ---- some_variable = foo some_other_variable = baz database.ini: ---- uri = mongodb://my-database:27017/test Events: <none> |
Файл описания пода имеет вид
Смонтируем внутри каталога /etc/config в контейнере файлы, содержащиеся в configmap-е my-configmap
1 |
# cat pod.yml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: app image: alpine command: ["sleep", "3600"] volumeMounts: - name: config mountPath: /etc/config volumes: - name: config configMap: name: my-configmap |
1 |
# kubectl apply -f pod.yml |
1 |
pod/my-pod created |
Проверим наличие файлов внутри контейнера в каталоге,куда смонтирован configmap
1 |
# kubectl exec -it my-pod -- ls /etc/config/ |
1 2 3 |
total 0 lrwxrwxrwx 1 root root 17 Apr 15 16:36 config.ini -> ..data/config.ini lrwxrwxrwx 1 root root 19 Apr 15 16:36 database.ini -> ..data/database.ini |
1 |
# kubectl exec -it my-pod -- cat /etc/config/config.ini |
1 2 |
some_variable = foo some_other_variable = baz |
1 |
# kubectl exec -it my-pod -- cat /etc/config/database.ini |
1 |
uri = mongodb://my-database:27017/test |
При обновлении Configmap-а, kubernetes автоматически обновит смонтированные внутри контейнера файлы без необходимости перезапуска пода