https://ansilh.com/01-introduction/
https://ansilh.com/15-k8s_from_sratch/
Материалов про kubernetes очень много. В процессе обучения просто я фиксирую для себя то что считаю важным. Это не тутораил и не гайд. Это просто мои заметки.
https://kubernetes.io/docs/reference/kubectl/cheatsheet/
Docker
Сборка контейнера docker
Создаем файл Dockerfile:
FROM node:7 ADD app.js /app.js ENTRYPOINT ["node", "app.js"]
В одной директории с Dockerfile размещаем файл приложения app.js и собираем:
docker build -t kubia .
Смотрим что контейнер собрался:
docker images
Запуск контейнера вручную в локальном Docker
docker run --name kubia-container -p 8080:8080 -d kubia
В результате будет запущен новый контейнер с именем kubia-container из образа kubia. Контейнер будет отсоединен от консоли (флаг -d), а порт 8080 на локальной машине будет увязан с портом 8080 внутри контейнера.
Список всех запущенных контейнеров docker
docker ps
Получение дополнительной информации о контейнере docker
docker inspect kubia-container
Запуск bash shell внутри существующего контейнера docker
docker exec -it kubia-container bash * **-i** убеждается, что STDIN держится открытым для ввода команд в оболочку; * **-t** выделяет псевдотерминал (TTY).
Остановка и удаление контейнера docker
docker stop kubia-container docker rm kubia-container
Тегирование образа тегом docker
Образ контейнера может иметь несколько тегов:
docker tag kubia luksa/kubia
Передача образа контейнера docker в хранилище docker hub
docker push luksa/kubia
Запуск образа контейнера docker на другой машине
docker run -p 8080:8080 -d luksa/kubia
Просмотр журналов контейнера docker
docker logs <container_ID>
Запуск приложения в среде kubernetes
kubectl run kubia --image=luksa/kubia --port=8080 --generator=run/v1
kubectl run создаст все необходимые компоненты без необходимости декларировать компоненты с помощью JSON или YAML.
–generator=run/v1 - нужен для того, чтобы текущая версия kubernetes не создавала Deployment, а создала ReplicationController.
В результате будет создан Pod с одним контейнером kubia.
При выполнении команды произошло следующее:
- команда kubectl создала в кластере новый объект контроллера репликации (ReplicationController)
- контроллер репликации создал новый Pod, который планировщик запланировал для одного из рабочих узлов.
- Агент Kubelet на этом узле увидел, что модуль был назначен рабочему узлу, и поручил платформе Docker выгрузить указанный образ из хранилища, После скачивания образа платформа Docker создала и запустила контейнер.
Получение списка pods
Список pods в дефолтном namespace:
kubectl get pods
Список pods в заданном namespace:
kubectl -n nsname get po
Список pods во всех неймспейсах:
kubectl get po -A
Вывод списка Pod'ов с дополнительной информацией:
kubectl get pods -o wide
Доступа к приложению в контейнере kubernetes по сети
Для доступа к приложению используются объекты Service. Они привязывают динамически разворачиваемые экземпляры приложения к статичным IP-адресам и портам:
kubectl expose rc kubia --type=LoadBalancer --name kubia-http
В данном случае - создается объект Service с именем kubia-http типа LoadBalancer, который указывает на экземпляры приложения, за которыми следит ReplicatioController (rc) с именем kubia.
Вывод списка kubernetes Services
kubectl get services
или
kubectl get svc
Увеличение количества реплик pod'a
Увеличить количество запущенных реплик Pod'а на контроллере репликации:
kubectl scale rc kubia --replicas=3
Получение полного описания объекта kubernetes
kubectl describe rc kubia
Создание объекта kubernetes с помощью файла описания
kubectl create -f filename.yml
Сеть
Внутри кластера kubernetes между подами (Pods) сеть плоская. Без шлюзов и трансляциий (nat-snat).
Под - Pod
Базовое описание pod'а
apiVersion: v1 # Версия API kind: Pod # Тип объекта - pod metadata: # Начало секции метаданных name: kubia-manual # имя Pod'a spec: # начало секции спецификации containers: # начало секции, описывающей контейнеры pod'а – image: luksa/kubia # начало описания первого контейнера. используется образ luksa/kubia name: kubia # Имя контейнера в pod'е ports: # секция портов, используемых приложением в контейнере – containerPort: 8080 # номер порта protocol: TCP # используемый протокол
Создание pod'а с помощью файла описания
kubectl create -f kubia-manual.yaml
Удаление pod'ов
kubectl delete po kubia-gpu
Или с помощью селектора по метке:
kubectl delete po -l creation_method=manual
Просмотр логов pod'а
kubectl logs kubia-manual
Если в pod'е больше одного контейнера, то увидеть логи конкретного контейнера можно так:
kubectl logs kubia-manual -c kubia
Маппинг локального порта на порт в pod'е без использования service
Иногда для отладки нужно просто сделать так, чтобы порт pod'а стал доступен на локальной машине. Без создания service. Это делается так:
kubectl port-forward kubia-manual 8888:8080
В результате приложение pod'а (порт 8080) станет доступно на локальной машине на порте 8888.
Метки
Метки могут быть созданы для многих объектов. В примерах рассматриваются pod'ы.
Создание и изменение меток (labels)
Метки позволяют разделять pod'ы по некоторому признаку и обращаться к ним.
kubectl label po kubia-manual creation_method=manual
Метки могут быть прописаны в секции метаданных:
apiVersion: v1 kind: Pod metadata: name: kubia-manual-v2 labels: creation_method: manual env: prod
При изменении существующих меток нужно использовать параметр –overwrite.
kubectl label po kubia-manual-v2 env=debug --overwrite
Список всех pod'ов и их меток
kubectl get po --show-labels
Список pod'ов у которых (не)установлены заданные метки
kubectl get po -l creation_method,env kubectl get po -l '!env',creation_method
Список pod'ов с заданными значениями меток
kubectl get po -l creation_method=manual
Список pod'ов со значениями меток отличными от заданного
kubectl get po -l creation_method!=manual
Установка метки на узел (node) и привязка pod'а к нему
Устанавливаем метку на узел:
kubectl label node gke-kubia-85f6-node-0rrx gpu=true
Описываем привязку в декларации pod'а:
apiVersion: v1 kind: Pod metadata: name: kubia-gpu spec: nodeSelector: gpu: "true" #селектор узла с меткой gpu containers: – image: luksa/kubia name: kubia
Или к узлу с заданным именем:
apiVersion: v1 kind: Pod metadata: name: kubia-gpu spec: nodeSelector: kubernetes.io/hostname: "desired.node.hostname" #селектор узла по его hostname containers: – image: luksa/kubia name: kubia
Пространства имен (namespaces)
Список доступных пространств имен (неймспейсов)
kubectl get ns
Список pod'ов неймспейса
kubectl get po --namespace kube-syste
Создание неймспейсов
kubectl create namespace custom-namespace
Или декларативно с помощью файла yaml:
apiVersion: v1 kind: Namespace metadata: name: custom-namespace
и затем
kubectl create -f custom-namespace.yaml
Создание объектов в заданном неймспейсе
kubectl create -f kubia-manual.yaml -n custom-namespace
Переключение между неймспейсами
kubectl config set-context $(kubectl config currentcontext) --namespace custom-namespace
или для быстрого переключения на другое пространство имен можно создать алиас:
alias kcd='kubectl config set-context $(kubectl config currentcontext) --namespace '
прописать его в ~/.bash.rc и затем переключаться между пространствами имен с помощью
kcd some-namespace
Удаление неймспейса со всем содержимым
kubectl delete ns custom-namespace
Удаление содержимого неймспейса с сохранением неймспейса
Удаление pod'ов
kubectl delete po --all
Удаление почти всех ресурсов из неймспейса:
kubectl delete all --all
Глоссарий
- Kubernetes - система оркестрации контейнеров docker.
- Namespace - это способ логического деления запускаемых в кластере сущностей.
- Nodes (node.md): Нода это машина в кластере Kubernetes.
- Pods (pods.md): Pod это группа контейнеров с общими разделами, запускаемых как единое целое. Обычно Pod объединет контейнеры, которые всместе выполняют некоторую функцию и не имеют смысла друг без друга. Например, в рамках pod'а процессы разных контейнеров могут общаться друг с другом по сети, используя адреса 127.0.0.1:port. То есть процессы различных контейнеров работают в едином сетевом неймспейсе pod'а.
- ReplicaSet - набор экземпляров (реплик) какого-то pod'а. ReplicaSet - это более функциональные Replication Controllers. Сейчас они сосуществуют, но в дальнейшем останутся только ReplicaSet.
- Deployment - набор экземпляров pod'а, для которого можно произвести обновление. При обновлении экземпляры будут по одному замещаться новыми версиями (rolling update). Таким образом реализуется zero downtime при обновлениях. Описывается с помощью yml-файла, содержащего спецификации (spec).
- Services (services.md): Сервис в Kubernetes это абстракция (описывается yml-файлом) которая определяет логический объединённый набор pod и политику доступа к ним. Например - сервис типа LoadBalancer балансирует нагрузку между подами деплоймента. В простейшем случае - сервис просто пробрасывает порт для доступа к приложению.
- Volumes (volumes.md): Volume(раздел) это директория, возможно, с данными в ней, которая доступна в контейнере.
- Labels (labels.md): Label'ы это пары ключ/значение которые прикрепляются к объектам, например pod'ам. Label'ы могут быть использованы для создания и выбора наборов объектов.
- Kubectl Command Line Interface (kubectl.md): kubectl интерфейс командной строки для управления Kubernetes.
- Config Map - yml-файлик, содержащий некоторую конфигурационную информацию (например описание сервера nginx). В дальнейшем, в описании контейнера прописывается volumeMount, с указанием куда смонтируется volume, а также сам Volume, который ссылается на configmap. В результате - содержимое Config Map монтируется в контейнер в файлик в заданную директорию. Инструкции для монтирования содержатся в описании deployment'а или pod'а.
Архитектура
Программыне компоненты Kubernetes можно разделить на две части:
- kubelet - компоненты, которые работают на нодах кластера и обеспечивают запуск сервисов на них.
- master components - компоненты, необходимые для управления кластером (APIs, scheduler, etc).
Deployment в кластер kubernetes
Для деплоймента в кластер kubernetes нужно описать в docker-файлах сервисы Pod'а. Порядок такой:
- создаем docker-файлик.
- собираем контейнер
- помещаем (push) контейнер в репозиторий контейнеров docker (cloud.docker.com)
В кластере kubernetes создаем namespace (логичекий контейнер для pod'ов, деплойментов (deployments) и т.д.)
kubectl create namespace _name_
Для деплоймента в kubernetes нужно описать три сущности:
- Сам deployment, в котором описано какие docker-контейнеры нужно загрузить в pod, сколько таких pod'ов создать, а также какую конфигурацию применить к контейнерам (с помощью ConfigMap'ов).
- ConfigMap'ы, которые содержат конфигурационные файлы, необходимые для работы приложений контейнерах. Например - конфигурация nginx для контейнера с nginx.
- Service - способ доступа к приложениям в контейнерах (балансировка и проброс портов).
Ход обновления:
- клонируем исходник из git.
- собираем его.
- собираем docker-контейнер с новым тегом версии, содержащий файлы приложения (docker build)
- помещаем docker-контейнер в docker registry (docker push)
- указываем в деплойменте тег новой версии контейнера.
- применяем deployment (kubectl apply) в результате чего обновятся pod'ы.
Для автоматизации с помощью GitLab:
- в свойствах проекта создаем Runner
- по инструкци устанавливаем gitlab-runner и добавляем пользователя gitlab-runner в группу докера, для того, чтобы раннер мог запускать деплоймент.
- после установки gitlab-runner его нужно зарегистрировать (gitlab-runner register)
- В конфиге раннера прописываются стадии: build и deploy. build включает в себя создание докерконтейнера, пригодного для деплоя.
Доступ к private registry с паролем
У меня есть private registry на базе Nexus 3. Доступ туда осуществляется по логину-паролю (учетка из Active Directory).
Для того чтобы образы можно было забирать из частного запароленного репозитория нужно:
- залогиниться в него:
docker login -u _username_ -p _password_ registry.domain.com
- в результате в файлике ~/.docker/config.json окажутся учетные данные, необходимые для работы.
- сделать из этого файлика секрет:
kubectl create secret generic registry-credentials -n namespace-name --from-file=.dockerconfigjson=<path_to_home>/.docker/config.json --type=kubernetes.io/dockerconfigjson
- и в дальнейшем использовать этот секрет:
apiVersion: v1 kind: Pod metadata: name: private-reg namespace: namespace-name spec: containers: - name: private-reg-container image: <your-private-image> imagePullSecrets: - name: registry-credentials
- Стоит обратить внимание на то, что секреты изолированы на уроне неймспейсов и в каджом неймспейсе должна быть копия секрета для доступа к registry.
Патчинг конфигурации из командной строки
https://stupefied-goodall-e282f7.netlify.com/contributors/devel/strategic-merge-patch/
http://jsonpatch.com/
Иногда нужно отредактировать объекты из скрипта, не запуская редактор.
Для этого у kubectl есть команда patch.
Удаление раздела из конфигурации
kubectl patch PersistentVolume elasticsearch-data --type=json -p='[{"op": "remove", "path": "/spec/claimRef"}]' kubectl patch PersistentVolume my-pv-name-123465789 -p '{"spec":{"claimRef": null}}' kubectl patch deployment es-master --type=json -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/resources"}]'
Очистка раздела, но не удаление его
kubectl patch PersistentVolume elasticsearch-data -p '{"spec":{"claimRef":{"$patch": "delete"}}}'
Изменение значения параметра
kubectl -n kubernetes-dashboard patch service kubernetes-dashboard -p '{"spec":{"type":"NodePort"}}'
в данном случае - редактируем элемент номер 0 списка containers:
kubectl -n elasticsearch patch deployment es-master --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/cpu", "value":1}]' kubectl -n elasticsearch patch deployment es-master --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/env/2", "value":{"name": "NUMBER_OF_MASTERS", "value": "1"}}]'
Добавление объекта
kubectl patch pod alpine-correct --type='json' -p='[{"op":"add","path":"/metadata/annotations", "value":{"testone.annotation.io":"test-one","testtwo.annotation.io":"test-two","testthree.annotation.io":"test-three"}}]'
В список:
kubectl -n elasticsearch patch sts es-data --type=json -p='[{"op": "add", "path": "/spec/template/spec/tolerations", "value":[{"effect":"NoSchedule","key":"node.kubernetes.io/rrr","operator":"Exists"}]}]'
Добавляем порт для контейнера в Deployment:
kubectl patch deployment mcs-api --type=json -p='[{"op": "add", "path": "/spec/template/spec/containers/0/ports", "value":[{"containerPort": 5000}]}]'
Патчинг нескольких значений за раз
kubectl patch ns default --type=json -p '[ {"op":"add","path":"/metadata/annotations","value":{"a":"1","b":"2"}}, {"op":"add","path":"/metadata/labels","value":{"c":"3"}} ]'
Отвязать PersistentVolume от заявки PersistentVolumeClaim
kubectl patch PersistentVolume elasticsearch-data --type=json -p='[{"op": "remove", "path": "/spec/claimRef"}]'
Найти все объекты kubernetes во всех неймспейсах
while read -r line; do echo "=============== $line =================="; kubectl get $line -A; done < <(kubectl api-resources | grep -v NAME | cut -d ' ' -f1)
Удобное редактирование секретов kubernetes
https://github.com/lbolla/kube-secret-editor
sudo apt-get -y install python3-pip python-pip sudo pip install PyYaml sudo pip3 install PyYaml sudo wget https://raw.githubusercontent.com/lbolla/kube-secret-editor/master/kube-secret-editor.py -O /usr/local/bin/kube-secret-editor.py sudo chmod a+x /usr/local/bin/kube-secret-editor.py alias kedit-secret="EDITOR=nano KUBE_EDITOR=/usr/local/bin/kube-secret-editor.py kubectl edit secret" sudo awk -v line='alias kedit-secret="EDITOR=nano KUBE_EDITOR=/usr/local/bin/kube-secret-editor.py kubectl edit secret"' 'FNR==NR && line==$0{f=1; exit} END{if (!f) print line >> FILENAME}' /etc/bash.bashrc
После перелогина (или нового запуска/перезапуска) bash станет доступен alias kedit-secret и отредактировать секрет можно будет так:
kedit-secret -n nsname secret-name
Предоставление ограниченного доступа в кластер с помощью RBAC и сертификатов
https://medium.com/better-programming/k8s-tips-give-access-to-your-clusterwith-a-client-certificate-dfb3b71a76fe
Что нужно понимать.
- В кубернетесе НЕ существует базы данных с Пользователями и Группами.
- Аутентификация при доступе к кластеру осуществляется с помощью сертификатов. Фактически CN в сертификате - это имя субъекта (пользователя), обращающегося к кластеру. O в сертификате - это имя группы, в которую включе пользователь.
- При использовании аутентификации по сертификатам нужно сгенерировать запрос на сертификат, на основании которого кластер может выпустить клиентский сертификат, с некоторым значением полей CN и O.
- Привилегии раздаются с помощью ролей. Role - это набор привилегий для субъекта (пользователя или группы).
- Для того, чтобы дать права владельцу сертификата нужно создать RoleBinding, которая свяжет роль с тем что написано в сертификате. Если даем права пользователю, то имя пользователя в RoleBinding должно совпадать со значением поля CN в сертификате. Если даем права группе, то имя группы в RoleBinding должно совпадать со значение поля O в сертификате.
Конкретная задача формулируется следующим образом:
- Для обращений к api-серверу используется аутентификация по сертикатам.
- Разработчику нужно предоставить доступ на просмотр объектов в заданном неймспейсе.
- В перспективе аналогичные права понадобятся другим разработчикам. То есть - права будем выдавать на группу.
Скрипт
#!/bin/bash set -e KUB_CONTEXT='kubernetes-admin@kubernetes' KUB_USERNAME='developer-ro' KUB_USERGROUP='mcs-ro' #cluster or ns (namespace) #AUTH_SCOPE='cluster' AUTH_SCOPE='ns' # If AUTH_SCOPE = ns then we need namespace name KUB_NAMESPACE='default' KUB_ROLE_NAME="${KUB_USERGROUP}-role" # Comma separated quoted - '"get", "list"'. For all use "*" KUB_ROLE_APIGROUPS='"*"' KUB_ROLE_RESOURCES='"*"' #KUB_ROLE_VERBS='"get", "list"' KUB_ROLE_VERBS='"*"' echo "Switching to context '${KUB_CONTEXT}'..." kubectl config use-context $KUB_CONTEXT echo "Get Kubernetes Cluster Details..." CLUSTER_NAME=${KUB_CONTEXT}-cluster CLUSTER_ENDPOINT=`kubectl get po -n kube-system -o jsonpath="{.items[?(@.metadata.labels.component==\"kube-apiserver\")].metadata.annotations.kubeadm\.kubernetes\.io\/kube-apiserver\.advertise-address\.endpoint}" | cut -d' ' -f 1` [ -z "$CLUSTER_ENDPOINT" ] && CLUSTER_ENDPOINT=`kubectl cluster-info | grep 'control plane' | awk '{print $NF}' | sed 's/^.*\/\///' | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g"` KUB_SYSTEM_TOKEN_SECRET=`kubectl get secret -n kube-system -o name | grep default-token | cut -d'/' -f 2` CLUSTER_CA=`kubectl get secret -n kube-system $KUB_SYSTEM_TOKEN_SECRET -o jsonpath={".data.ca\.crt"}` if [ ! -f ./${KUB_USERNAME}.key ]; then openssl genrsa -out ./${KUB_USERNAME}.key 4096 fi echo "Create CSR config file ${KUB_USERNAME}.csr.cnf..." cat <<EOF > ./${KUB_USERNAME}.csr.cnf [ req ] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn [ dn ] CN = ${KUB_USERNAME} O = ${KUB_USERGROUP} [ v3_ext ] authorityKeyIdentifier=keyid,issuer:always basicConstraints=CA:FALSE keyUsage=keyEncipherment,dataEncipherment extendedKeyUsage=serverAuth,clientAuth EOF echo "Create CSR file ${KUB_USERNAME}.csr..." openssl req -config ./${KUB_USERNAME}.csr.cnf -new -key ${KUB_USERNAME}.key -nodes -out ${KUB_USERNAME}.csr echo "Create CertificateSigningRequest in ${KUB_CONTEXT} cluster..." export BASE64_CSR=$(cat ./${KUB_USERNAME}.csr | base64 | tr -d '\n') kubectl apply -f - <<EOF apiVersion: certificates.k8s.io/v1beta1 kind: CertificateSigningRequest metadata: name: ${KUB_USERNAME}_csr spec: groups: - system:authenticated request: ${BASE64_CSR} #signerName: kubernetes.io/kube-apiserver-client usages: - client auth EOF echo "Check if CSR created successfully..." kubectl get csr ${KUB_USERNAME}_csr echo "Approving CSR created..." kubectl certificate approve ${KUB_USERNAME}_csr echo "Download certificate for user ${KUB_USERNAME} to ${KUB_USERNAME}.crt file..." kubectl get csr ${KUB_USERNAME}_csr -o jsonpath='{.status.certificate}' | base64 --decode > ${KUB_USERNAME}.crt if [ "$AUTH_SCOPE" = "cluster" ]; then echo "Create Cluster Role..." kubectl apply -f - <<EOF kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: ${KUB_ROLE_NAME} rules: - apiGroups: [${KUB_ROLE_APIGROUPS}] resources: [${KUB_ROLE_RESOURCES}] verbs: [${KUB_ROLE_VERBS}] EOF echo "Create Cluster Role Binding for group ${KUB_USERGROUP}..." kubectl apply -f - <<EOF kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: ${KUB_ROLE_NAME}-${KUB_USERGROUP} subjects: - kind: Group name: ${KUB_USERGROUP} apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: ${KUB_ROLE_NAME} apiGroup: rbac.authorization.k8s.io EOF fi if [ "$AUTH_SCOPE" = "ns" ]; then kubectl apply -f - <<EOF kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: ${KUB_NAMESPACE} name: ${KUB_ROLE_NAME} rules: - apiGroups: [${KUB_ROLE_APIGROUPS}] resources: [${KUB_ROLE_RESOURCES}] verbs: [${KUB_ROLE_VERBS}] EOF kubectl apply -f - <<EOF kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: ${KUB_ROLE_NAME}-${KUB_USERGROUP} namespace: ${KUB_NAMESPACE} subjects: - kind: Group name: ${KUB_USERGROUP} apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: ${KUB_ROLE_NAME} apiGroup: rbac.authorization.k8s.io EOF fi CLIENT_CERTIFICATE_DATA=$(kubectl get csr ${KUB_USERNAME}_csr -o jsonpath='{.status.certificate}') CLIENT_KEY_DATA=$(cat ./${KUB_USERNAME}.key | base64 | tr -d '\n' ) cat <<EOF > ./kubeconfig_${KUB_USERNAME}_${CLUSTER_NAME} apiVersion: v1 kind: Config clusters: - cluster: certificate-authority-data: ${CLUSTER_CA} server: https://${CLUSTER_ENDPOINT} #insecure-skip-tls-verify: true name: ${CLUSTER_NAME} users: - name: ${KUB_USERNAME}-${CLUSTER_NAME} user: client-certificate-data: ${CLIENT_CERTIFICATE_DATA} client-key-data: ${CLIENT_KEY_DATA} contexts: - context: cluster: ${CLUSTER_NAME} user: ${KUB_USERNAME}-${CLUSTER_NAME} name: ${KUB_USERNAME}-${CLUSTER_NAME} current-context: ${KUB_USERNAME}-${CLUSTER_NAME} EOF kubectl delete certificatesigningrequests ${KUB_USERNAME}_csr
Создание закрытого ключа пользователя и запроса сертификата
Генерируем закрытый ключ:
openssl genrsa -out mike.key 4096
Для генерации закрытого ключа пользователя нужно подготовить файлик mike.csr.cnf, в котором указать имя пользователя и группу, которой мы дадим права:
[ req ] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn [ dn ] CN = mike O = development [ v3_ext ] authorityKeyIdentifier=keyid,issuer:always basicConstraints=CA:FALSE keyUsage=keyEncipherment,dataEncipherment extendedKeyUsage=serverAuth,clientAuth
Тут:
- CN - имя пользователя
- O - имя группы
И дальше генерируем запрос сертификата:
openssl req -config ./mike.csr.cnf -new -key mike.key -nodes -out mike.csr
В итоге - получаем файл запроса сертификата - mike.csr.
Создание сертификата
Теперь нужно отправить запрос в кластер, чтобы на его основе был сгенерирован сертификат.
Создаем переменную окружения, в которую помещаем наш запрос сертификата в кодировке base64:
export BASE64_CSR=$(cat ./mike.csr | base64 | tr -d '\n')
И загоняем манифест в кластер, попутно подставляя в него значение созданной переменной:
kubectl apply -f - <<EOF apiVersion: certificates.k8s.io/v1 kind: CertificateSigningRequest metadata: name: csr spec: groups: - system:authenticated request: ${BASE64_CSR} usages: - digital signature - key encipherment - server auth - client auth EOF
Убеждаемся, что запрос создан:
$ kubectl get csr NAME AGE REQUESTOR CONDITION csr 31s kubernetes-admin Pending
И выпускаем сертификат:
kubectl certificate approve csr
Если при аппруве появляется ошибка типа:
error: no kind "CertificateSigningRequest" is registered for version "certificates.k8s.io/v1" in scheme "k8s.io/kubectl/pkg/scheme/scheme.go:28"
то скорее всего делл в том, что в кластере несколько версий API для ресурса certifictes, либо версия kubectl отстает от версии кластера. Проверяем это:
kubectl get apiservice | grep certificates kubectl version --short
Если там две версии API для ресурса certifictes, то удаляем старую, а также обновляем kubectl при необходимости:
kubectl delete apiservice v1beta1.certificates.k8s.io
А теперь - извлекаем его:
kubectl get csr csr -o jsonpath='{.status.certificate}' | base64 --decode > mike.crt
Создаем роль для ограничения прав в неймспейсе
kubectl apply -f - <<EOF kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: development name: dev rules: - apiGroups: [""] resources: ["pods", "services"] verbs: ["get", "list"] EOF
Даем права пользователю или группе
Привязываем пользователя к роли (по имени):
kubectl apply -f - <<EOF kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: dev namespace: development subjects: - kind: User name: mike apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: dev apiGroup: rbac.authorization.k8s.io EOF
Либо к группе:
kubectl apply -f - <<EOF kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: dev namespace: development subjects: - kind: Group name: development apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: dev apiGroup: rbac.authorization.k8s.io EOF
Создание файлика kubeconfig
Теперь для доступа к кластеру пользователю нужен файл, конфигурации, который будет содержать ссылку на api-сервер кластера, а также сертификаты.
Зададим значения переменных, которые будут подставлены в шаблон:
export USER="mike" export CLUSTER_NAME=$(kubectl config view --minify -o jsonpath={.clusters[0].name}) export CLUSTER_ENDPOINT=$(kubectl config view --raw -o json | jq -r ".clusters[] | select(.name == \"$CLUSTER_NAME\") | .cluster.server") export CLIENT_CERTIFICATE_DATA=$(kubectl get csr mycsr -o jsonpath='{.status.certificate}') export CLIENT_KEY_DATA=$(cat ./mike.key | base64 | tr -d '\n') export CLUSTER_CA=$(kubectl get secret -o jsonpath="{.items[?(@.type==\"kubernetes.io/service-account-token\")].data['ca\.crt']}")
И создадим файлик, в который подставим эти значения параметров:
cat <<EOF > kubeconfig apiVersion: v1 kind: Config clusters: - cluster: certificate-authority-data: ${CLUSTER_CA} server: ${CLUSTER_ENDPOINT} #insecure-skip-tls-verify: true name: ${CLUSTER_NAME} users: - name: ${USER} user: client-certificate-data: ${CLIENT_CERTIFICATE_DATA} client-key-data: ${CLIENT_KEY_DATA} contexts: - context: cluster: ${CLUSTER_NAME} user: ${USER} name: ${USER}-${CLUSTER_NAME} current-context: ${USER}-${CLUSTER_NAME} EOF
Предоставление ограниченного доступа в кластер с помощью RBAC и Service Accounts
#!/bin/bash set -e KUB_CONTEXT='anima-lightning2-dev' KUB_USERNAME='dashboard-ro' KUB_NAMESPACES=('lightning-dev' 'lightning-tst') ######KUB_USERGROUP='mcs-ro' #cluster or ns (namespace) #AUTH_SCOPE='cluster' AUTH_SCOPE='ns' # If AUTH_SCOPE = ns then we need namespace name #KUB_NAMESPACES=('default') # Comma separated quoted - '"get", "list"'. For all use "*" KUB_ROLE_APIGROUPS='"*"' KUB_ROLE_RESOURCES='"*"' #KUB_ROLE_VERBS='"get", "list"' KUB_ROLE_VERBS='"get", "list"' echo "Switching to context '${KUB_CONTEXT}'..." kubectl config use-context $KUB_CONTEXT echo "Get Kubernetes Cluster Details..." CLUSTER_NAME=${KUB_CONTEXT}-cluster CLUSTER_ENDPOINT=`kubectl get po -n kube-system -o jsonpath="{.items[?(@.metadata.labels.component==\"kube-apiserver\")].metadata.annotations.kubeadm\.kubernetes\.io\/kube-apiserver\.advertise-address\.endpoint}" | cut -d' ' -f 1` [ -z "$CLUSTER_ENDPOINT" ] && CLUSTER_ENDPOINT=`kubectl cluster-info | grep 'control plane' | awk '{print $NF}' | sed 's/^.*\/\///' | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g"` KUB_SYSTEM_TOKEN_SECRET=`kubectl get secret -n kube-system -o name | grep default-token | cut -d'/' -f 2` CLUSTER_CA=`kubectl get secret -n kube-system $KUB_SYSTEM_TOKEN_SECRET -o jsonpath={".data.ca\.crt"}` kubectl create serviceaccount ${KUB_USERNAME}-sa -n kube-system || true echo "Create ClusterRole '${KUB_USERNAME}-ns-cluster-role' to List Namespaces..." kubectl apply -f - <<EOF kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: ${KUB_USERNAME}-ns-cluster-role rules: - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "list"] EOF echo "Create Cluster Role Binding for group '${KUB_USERNAME}-ns-cluster-role' to List Namespaces..." kubectl apply -f - <<EOF kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: ${KUB_USERNAME}-ns-cluster-rolebinding subjects: - kind: ServiceAccount name: ${KUB_USERNAME}-sa namespace: kube-system roleRef: kind: ClusterRole name: ${KUB_USERNAME}-ns-cluster-role apiGroup: rbac.authorization.k8s.io EOF if [ "$AUTH_SCOPE" = "ns" ]; then for KUB_NAMESPACE in ${KUB_NAMESPACES[@]}; do kubectl create ns ${KUB_NAMESPACE} || true echo "Creating Role - '${KUB_USERNAME}-role' in the namespace '${KUB_NAMESPACE}'..." kubectl replace -f - <<EOF kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: ${KUB_NAMESPACE} name: ${KUB_USERNAME}-role rules: - apiGroups: [${KUB_ROLE_APIGROUPS}] resources: [${KUB_ROLE_RESOURCES}] verbs: [${KUB_ROLE_VERBS}] EOF echo "Creating RoleBinding for the '${KUB_USERNAME}-role' in the namespace '${KUB_NAMESPACE}'..." kubectl replace -f - <<EOF kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: ${KUB_USERNAME} namespace: ${KUB_NAMESPACE} subjects: - kind: ServiceAccount name: ${KUB_USERNAME}-sa namespace: kube-system roleRef: kind: Role name: ${KUB_USERNAME}-role apiGroup: rbac.authorization.k8s.io EOF done fi if [ "$AUTH_SCOPE" = "cluster" ]; then echo "Creating ClusterRole '${KUB_USERNAME}-cluster-role' to access resources..." kubectl apply -f - <<EOF kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: ${KUB_USERNAME}-cluster-role rules: - apiGroups: [${KUB_ROLE_APIGROUPS}] resources: [${KUB_ROLE_RESOURCES}] verbs: [${KUB_ROLE_VERBS}] EOF echo "Create Cluster Role Binding for group '${KUB_USERNAME}-cluster-role' to access resources..." kubectl apply -f - <<EOF kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: ${KUB_USERNAME}-cluster-rolebinding subjects: - kind: ServiceAccount name: ${KUB_USERNAME}-sa namespace: kube-system roleRef: kind: ClusterRole name: ${KUB_USERNAME}-cluster-role apiGroup: rbac.authorization.k8s.io fi EOF fi kubectl apply -f - <<EOF apiVersion: v1 kind: Secret metadata: name: ${KUB_USERNAME}-sa-token namespace: kube-system annotations: kubernetes.io/service-account.name: ${KUB_USERNAME}-sa type: kubernetes.io/service-account-token EOF SA_TOKEN=`echo "kubectl get secrets -n kube-system -o jsonpath=\"{.items[?(@.metadata.annotations['kubernetes\\.io/service-account\\.name']=='${KUB_USERNAME}-sa')].data.token}\" | base64 --decode" | /bin/bash` cat <<EOF > ./kubeconfig_${KUB_USERNAME}_${CLUSTER_NAME} apiVersion: v1 kind: Config clusters: - cluster: certificate-authority-data: ${CLUSTER_CA} server: https://${CLUSTER_ENDPOINT} #insecure-skip-tls-verify: true name: ${CLUSTER_NAME} users: - name: ${KUB_USERNAME}-${CLUSTER_NAME} user: token: ${SA_TOKEN} contexts: - context: cluster: ${CLUSTER_NAME} user: ${KUB_USERNAME}-${CLUSTER_NAME} name: ${KUB_USERNAME}-${CLUSTER_NAME} current-context: ${KUB_USERNAME}-${CLUSTER_NAME} EOF
Bash-скрипты в init-контейнерах при деплойменте с помощью helm
В чарте в директории files я имею просто скрипт, который должне запуститься в init-контейнере.
Я поменщаю этот скрипт в секрет с помощью такого манифеста:
apiVersion: v1 kind: Secret metadata: name: files type: Opaque data: {{ (.Files.Glob "files/*").AsSecrets | indent 2 }}
В деплойменте я запускаю init-контейнер, в котором монтируется секрет с этим скриптом и выполняется этот скрипт:
... initContainers: - name: copy-files image: docker.rdleas.ru/busybox command: - "sh" - "-c" - "cp /tmp/files/init-script.sh /tmp/ && chmod u+x /tmp/init-script.sh && /tmp/init-script.sh" volumeMounts: - name: files mountPath: /tmp/files/ ... volumes: - name: files secret: secretName: files
то есть мне надо сделать скрипт исполняемым (дать соотвествующие разрешения), но смонтирован он как read-only, поэтому я предварительно копирую его. А после того, как разрешено его исполнение - запускаю скрипт.
Обновление сертификатов
https://github.com/kubernetes/kubeadm/issues/581#issuecomment-471575078
Обновление сертификатов (даже просроченных) на мастерах.
Проверить валидность:
kubeadm certs check-expiration
Обновить все сразу:
kubeadm certs renew all
Обновить по одному:
kubeadm certs renew apiserver kubeadm certs renew apiserver-kubelet-client kubeadm certs renew front-proxy-client kubeadm certs renew admin.conf
Просроченный сертификат ноды в kubelet.conf
Проблема
На ноде не стартует kubelet, при старте в /var/log/syslog такое:
Nov 22 15:10:08 kub-master01 systemd[1]: Started Kubernetes systemd probe. Nov 22 15:10:08 kub-master01 kubelet[6927]: I1122 15:10:08.032987 6927 server.go:411] Version: v1.19.3 Nov 22 15:10:08 kub-master01 kubelet[6927]: I1122 15:10:08.033277 6927 server.go:831] Client rotation is on, will bootstrap in background Nov 22 15:10:08 kub-master01 kubelet[6927]: E1122 15:10:08.035302 6927 bootstrap.go:265] part of the existing bootstrap client certificate is expired: 2020-11-20 08:19:12 +0000 UTC Nov 22 15:10:08 kub-master01 kubelet[6927]: F1122 15:10:08.035329 6927 server.go:265] failed to run Kubelet: unable to load bootstrap kubeconfig: stat /etc/kubernetes/bootstrap-kubelet.conf: no such file or directory
Проблема усугубляется тем, что это однонодовый кластер и просто сделать kubeadm join не выйдет.
Диагностика
Вот такой конвейер позвоялет увидеть дату окончания сертификата ноды, который хранится в kubelet.conf.
cat /etc/kubernetes/kubelet.conf | grep 'client-certificate-data:' | cut -d':' -f2 | sed 's/\s*//g' | base64 -d | openssl x509 -noout -enddate notAfter=Nov 20 08:19:12 2020 GMT
Обновляем сертификат
Извлекаем сертификат:
cat /etc/kubernetes/kubelet.conf | grep 'client-certificate-data:' | cut -d':' -f2 | sed 's/\s*//g' | base64 -d > ./node.crt.pem
Извлекаем ключ:
cat /etc/kubernetes/kubelet.conf | grep 'client-key-data:' | cut -d':' -f2 | sed 's/\s*//g' | base64 -d > ./node.key.pem
Генерируем запрос:
openssl x509 -x509toreq -signkey ./node.key.pem -in ./node.crt.pem -out ./node.csr
Проверяем запрос:
openssl req -text -noout -verify -in ./node.csr
Создаем новый сертификат
openssl x509 -req -in node.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -set_serial 10 -out ./new_node.crt.pem
Кодируем новый сертификат в base64
base64 -w 0 ./new_node.crt.pem
И затем подставляем в поле client-certificate-data: в файлике /etc/kubernetes/kubelet.conf
Kubernetes LDAP Auth
LDAP-аутентификацию к кластеру kubernetes можно прикрутить с помощью различных средств, но все они используют один подход и схожие по назначению компоненты:
- Служба каталога с поддрежкой протокола LDAP. Например - Active Directory
- Провайдер OpenID Connect, с которым взаимодействует кластер kubernetes. OIDC - это приложение, которое аутентифицирует пользователей в LDAP и сообщает кластеру Kubernetes сведения о нем, чтобы kubernetes мог сгенерировать сертификат.
- Некое web-приложение, с которым взаимодействует пользователи. Оно перенапрявляет пользователя на OpenID Connector, получает от кластера kubernetes сертификат и генерирует конфиг для kubectl.
OIDC Providers
- Dex
- Keycloak
WebApps
- Kuberos - https://github.com/negz/kuberos (не поддерживается с 2019 года)
- GangWay
- Dex K8s Authenticator
Keycloak + kubelogin
Мне понравился такой вариант - Keycloak в качестве OIDC-провайдера и kubelogin в качестве способа получения токена.
Настройка client в keycloak
В параметры клиента в keycloak в valid redirect uris нужно прописать http://localhost:8000 (или *)
Настройка кластера kubernetes
На каждой мастер-ноде редактируем файл /etc/kubernetes/manifests/kube-apiserver.yaml и добавляем туда такие параметры:
- --oidc-ca-file=/etc/ssl/certs/RDLeas_Root_CARDleas-SRV-DC02-CA.pem - --oidc-client-id=kubernetes - --oidc-groups-claim=groups - --oidc-issuer-url=https://sso.rdleas.ru/auth/realms/rdleas - --oidc-username-claim=email
Редактируем Configmap и также добавляем туда эти параметры:
kubectl edit cm -n kube-system kubeadm-config
data: ClusterConfiguration: | apiServer: ... extraArgs: authorization-mode: Node,RBAC oidc-ca-file: /etc/ssl/certs/RDLeas_Root_CARDleas-SRV-DC02-CA.pem oidc-client-id: kubernetes oidc-groups-claim: groups oidc-issuer-url: https://sso.rdleas.ru/auth/realms/rdleas oidc-username-claim: email
Настройка клиентской машины
Устанавливаем плагин kubelogin.
Скачиваем бинарник https://github.com/int128/kubelogin/releases
Извлекаем его куда-то в $PATH, например - /usr/local/bin/kubelogin
В ~/.kube/config прописываем пользователя:
- name: oidc user: exec: apiVersion: client.authentication.k8s.io/v1beta1 args: - get-token - --oidc-issuer-url=https://sso.rdleas.ru/auth/realms/rdleas - --oidc-client-id=kubernetes command: kubelogin env: null provideClusterInfo: false
И контекст с его участием:
- context: cluster: sbl-apps-dev user: oidc name: sbl-apps-dev-oidc
Назначение привилегий в кластере
Название групп в манифестах должно быть точно таким же как и в токене. В моей инсталляции в начале названия группы есть слеш.
Права на неймспейс (в даннос лучае - default) выдаем так:
NAMESPACE=default GROUP='/Kubernetes_Default_Ns_Admins' kubectl apply -f - <<EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: ${NAMESPACE}-admins namespace: ${NAMESPACE} rules: - apiGroups: - '*' resources: - '*' verbs: - '*' --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: kubernetes-${NAMESPACE}-namespace-admins namespace: ${NAMESPACE} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: ${NAMESPACE}-admins subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: ${GROUP} EOF
Права на весь кластер выдаем так:
GROUP='/Kubernetes_Cluster_Admins' kubectl apply -f - <<EOF apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cluster-admins-oidc roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: ${GROUP} EOF
Разрешение проблем
Поглядеть текущий токен можно так:
kubelogin get-token --oidc-issuer-url=https://sso.rdleas.ru/auth/realms/rdleas --oidc-client-id=kubernetes
Расшифровать его (и увидеть список групп в нем) можно тут: https://jwt.io/
invalid bearer token, oidc: email not verified
В логе kube-apiserver ошибка
Unable to authenticate the request due to an error: [invalid bearer token, oidc: email not verified]
В токене такое:
"email_verified": false
Нужно выключить верификацию email на keycloak (поле email_verified не будет появляться в токене).
В Keycloak идем: Client Scopes → Email → Mappers и удаляем Email verified.
Поглядеть подробный лог можно так:
kubectl --token=$token --server=https://192.168.1.2:6443 --insecure-skip-tls-verify get po --v=10
Dex + Dex K8s authenticator
https://uni.dtln.ru/digest/autentifikaciya-v-kubernetes-s-pomoshchyu-dex-prikruchivaem-ldap
https://habr.com/ru/post/436238/
https://habr.com/ru/company/dataline/blog/497482/
https://github.com/mintel/dex-k8s-authenticator
Keycloak + Gangway
Dex + GangWay
JWT-Токены для аутентификации
Ссылки
Отмена удаления PersistentVolume
Если так случайно вышло, что вы удалили PersistentVolume, то не отчаивайтесь! Он будет находитьтся в состоянии Terminating до тех пор, пока существуют pod, куда он смонтирован и PersistentVolumeClaim, которая породила этот PV и удаление можно отменить.
На помощь приходит специальная утилитка: https://github.com/jianz/k8s-reset-terminating-pv
git clone https://github.com/jianz/k8s-reset-terminating-pv.git cd k8s-reset-terminating-pv go build -o resetpv
Собранный бинарник: resetpv.tar.gz
Заходим на мастер-ноду, архивируем сертификаты и смотрим какой сертификат за что отвечает:
ssh user@master-node sudo -H tar -cvzf ~/etcd-pki.tar.gz /etc/kubernetes/pki/etcd sudo docker ps --no-trunc | grep etcd exit
В выводе среди всего прочего будет такое:
--advertise-client-urls=https://10.77.68.1:2379 --cert-file=/etc/kubernetes/pki/etcd/server.crt --key-file=/etc/kubernetes/pki/etcd/server.key --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
В вашей инсталляции имена, пути и порты могут быть иными.
И забираем с мастер-ноды кластера архив с сертификатами, которые необходимы для подключения к etcd кластера:
scp user@master-node:/home/user/etcd-pki.tar.gz ./ tar -xvf ./etcd-pki.tar.gя mv ./etc/kubernetes/pki/etcd/* ./
И дальше применяем утилиту:
./resetpv --etcd-ca ./ca.crt --etcd-cert ./server.crt --etcd-key ./server.key --etcd-host 10.77.68.1 --etcd-port 2379 pv-name
Если вдруг так вышло, что вы удалили все PV в кластере (как я - хотел удалить pvc в неймспейсе но просто опечатался и вместо pvc ввел pv):
kubectl delete -n namespace pv --all
то чтобы отменить удаление всех PV делаем так:
PVs=`kubectl get pv | grep Terminating | awk '{print $1}' | grep -v NAME` for pv in $PVs; do ./resetpv --etcd-ca ./ca.crt --etcd-cert ./server.crt --etcd-key ./server.key --etcd-host 10.77.68.1 --etcd-port 2379 $pv; done
Распределить поды деплоймента по разным нодам кластера
apiVersion: apps/v1 kind: Deployment metadata: name: my-service labels: app: my-service spec: replicas: 2 selector: matchLabels: app: my-service template: metadata: labels: app: my-service spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: my-service
Либо:
affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - {{ .Release.Name }}-logstash topologyKey: kubernetes.io/hostname
Разница между этими подходами описана тут: https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/#comparison-with-podaffinity-podantiaffinity
В двух словах - podAntiAffinity более старый и простой способ и в будущем - предпочтительно пользоваться topologySpreadConstraints, который поддерживает не только распределение по нодам, но и по зонам доступности в облаках.
Headless Services для Stafullset
И другие вопросы про то как давать доступ к индивидуальным подам реплик стейтфуллсетов.
https://www.tigera.io/blog/exposing-statefulsets-in-kubernetes/
Обычно сервисы используются в k8s для балансировки запросов на все реплики микросервиса, однако, в слуаче со statefull-приложениями может понадобиться доступ к конкретной реплике. Для этого в k8s существуют Statefullset'ы и связанные с ними Headless-сервисы.
Что такое Statefullset - это способ создать набор именованных реплик сервиса, каждая из которых будет сохранять свое имя и после перезапуска.
Что такое Headless Service - это сервис, который НЕ имеет адреса в кластере (ClusterIP: None) и НЕ выполняет балансировку подключний по эндпоинтам, а просто является списком эндпоинтов для именованных реплик, управляемых Statefullset'ом. А для доступа к именованным репликам в DNS кластера генерируются имена:
<StatefulSet>-<Ordinal>.<Service>.<Namespace>.svc.cluster.local
например:
app-0.myapp.default.svc.cluster.local.
Вопрос - а как же можно опубликовать именованную реплику в составе Statefullset'а, например через Ingress?? Ведь для этого надо как-то сослаться на сервис, который будет связан с портом на конкретной реплике!
Все просто - каждый под, управляеый Statefullset'ом имеет уникальну метку (примерно такую - statefulset.kubernetes.io/pod-name: app-0 ), которую можно использовать в качестве селектора в сервисе:
apiVersion: v1 kind: Service metadata: name: app-0 spec: type: LoadBalancer selector: statefulset.kubernetes.io/pod-name: app-0 ports: - protocol: TCP port: 80 targetPort: 80
Как скопировать секрет из одного неймспейса в другой
kubectl get secret my-tlssecret --namespace=nginx-ns -o yaml | sed 's/namespace: .*/namespace: default/' | kubectl apply -f -
Список и спецификации СustomResourceDefinitions
Список существующих в кластере Сustom Resource Definitions
kubectl get customresourcedefinitions
или
kubectl get crd
ну и посмотреть спецификацию:
kubectl describe crd <crd_name>
Плавный рестарт подиков в деплойментах
В общем случае плавно рестартить можно так:
kubectl rollout restart deployment my-app
А для всех деплойментов в неймспейсе:
ns=namespacename; for deployment in `kubectl get deployment -n ${ns} | grep -v NAME | awk '{print $1}'`; do kubectl -n ${ns} rollout restart deployment ${deployment}; done
Плавный рестарт всех подиков во всех деплойментах во всех неймспейсах:
for ns in `kubectl get ns | grep -v NAME | awk '{print $1}'`; do for deployment in `kubectl get deployment -n ${ns} | grep -v NAME | awk '{print $1}'`; do kubectl -n ${ns} rollout restart deployment ${deployment}; done; done
/etc/resolve.conf в подиках
При старте подика формируется файл /etc/resolve.conf в котором прописано как будут резолвиться имена.
Важным параметром является options ndots:5
Этот параметр задает то, сколько МИНИМУМ точек должно быть точек в имени, чтобы рассмастривать его как FQDN и не пытаться искать это имя с суффиксами из search.
Изменить его значение можно с помощью специального раздела конфигурации подика:
apiVersion: v1 kind: Pod metadata: namespace: default name: dns-example spec: containers: - name: test image: nginx dnsConfig: options: - name: ndots value: "1"
Discussion