Предоставление доступа на несколько namespace
С помощью данной инструкции вы сможете дать доступ к одному или нескольким Namespace’ам одного Kubernetes-кластера.
Дополнительно мы будем устанавливать лимиты по CPU и RAM на каждый Namespace
В примерах будет использоваться пользователь kube - данный пользователь является админом в кластере и от его имени будут запускаться несколько команд
Для выполнения необходимо повышение прав
sudo -u kube kubectl config view
sudo -u kube kubectl create namespace*
sudo mkdir /etc/kubernetes/pki/teams/
sudo openssl genrsa -out /etc/kubernetes/pki/teams/*
sudo openssl req -new -key /etc/kubernetes/pki/teams/*
sudo openssl x509 -req -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key*
sudo -u kube kubectl config set-credentials*
sudo -u kube kubectl config set-context*
sudo -u kube kubectl apply -f*
sudo chmod 600 /etc/kubernetes/pki/teams/*
sudo grep certificate-authority-data /etc/kubernetes/admin.conf
Настройка
Все действия выполняем на Мастер-сервере Kubernetes. Для начала настройки необходимо задать несколько параметров в перенные
TEAM=demo-team # Название пользвателя
NAMESPACE=dev # Название Namespace'а, на который мы будем давать права
IP=`ifconfig ens192 | grep inet | sed 's/\ \{1,\}/ /g' | cut -d' ' -f 3` # IP-адрес Мастер-сервера (убедитесь, что сетевой интерфейс "ens192" существует)
CPU=4 # Лимит на вышеуказанный Namespace в CPU
RAM=8 # Лимит на вышеуказанный Namespace в ГБ RAM
Первым делом проверьте, что пользователя не существует
sudo -u kube kubectl config view
...
contexts:
- context:
cluster: kubernetes
namespace: dev
user: test-team
name: test-team-dev-admin-context
- context:
cluster: kubernetes
namespace: test-func
user: test-team
name: test-team-test-fync-admin-context
Если Вы увидите, что данному пользователю присвоены некоторые Context’ы переходите сразу к переходите сразу к Добавление новых Namespace к существующему пользователю. Не вздумайте продолжать следующие команды - Вы загубите существующих пользователей.
Если пользователя нет - начнём с его создания
Создаём новые namespace’ы
sudo -u kube kubectl create namespace ${NAMESPACE}
Создаём каталог для хранения сертификатов (если уже существует - ничего страшного
sudo mkdir /etc/kubernetes/pki/teams/
Создаём на Kubernetes Master сертификат и приватный ключ для пользователя, которому требуется предоставить доступ на Namespace(ы)
sudo openssl genrsa -out /etc/kubernetes/pki/teams/${TEAM}.key 2048
sudo openssl req -new -key /etc/kubernetes/pki/teams/${TEAM}.key -out /etc/kubernetes/pki/teams/${TEAM}.csr -subj "/CN=${TEAM}/O=namespace-admins"
sudo openssl x509 -req -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -in /etc/kubernetes/pki/teams/${TEAM}.csr -out /etc/kubernetes/pki/teams/${TEAM}.crt -days 1024
Создаём на Kubernetes пользователя и присваем ему недавно созданные сертификаты и ключи
sudo -u kube kubectl config set-credentials ${TEAM} --client-certificate=/etc/kubernetes/pki/teams/${TEAM}.crt --client-key=/etc/kubernetes/pki/teams/${TEAM}.key
Далее создаём Context - идентификатор для команд kubectr
sudo -u kube kubectl config set-context ${TEAM}-${NAMESPACE}-admin-context --cluster=kubernetes --namespace=${NAMESPACE} --user=${TEAM}
Создайте пары Role и RoleBinding для Namespace’а. Тут же задаём лимиты по ресурсам.
cat > /tmp/${TEAM}-${NAMESPACE}.yml << END
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: ${NAMESPACE}
name: ${TEAM}-namespace-manager
rules:
- apiGroups: ["", "extensions", "apps"]
resources:
- componentstatuses
- configmaps
- daemonsets
- deployments
- deployments/scale
- events
- endpoints
- horizontalpodautoscalers
- ingress
- ingresses
- ingresses.status
- jobs
- limitranges
- namespaces
- nodes
- pods
- pods/exec ##### Addinal #####
- pods/attach ##### Permissions #####
- pods/log
- pods/portforward
- persistentvolumes
- persistentvolumeclaims
- replicasets
- replicationcontrollers
- secrets
- serviceaccounts
- services
verbs: ["*"]
- apiGroups: [""]
resources:
- resourcequotas
verbs: ["get", "watch", "list"]
- apiGroups: ["batch"]
resources:
- jobs
- cronjobs
verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: ${TEAM}-namespace-manager-binding
namespace: ${NAMESPACE}
subjects:
- kind: User
name: ${TEAM}
apiGroup: ""
roleRef:
kind: Role
name: ${TEAM}-namespace-manager
apiGroup: ""
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: ${TEAM}-quota
namespace: ${NAMESPACE}
spec:
hard:
requests.cpu: "2"
requests.memory: 4Gi
limits.cpu: "${CPU}"
limits.memory: ${RAM}Gi
END
Применяем файл в Kubernetes’е
sudo -u kube kubectl apply -f /tmp/${TEAM}-${NAMESPACE}.yml
Создаем папки для YAML-файлов и дисковых разделов.
sudo -u kube mkdir -m 777 /kuber/yamls/dep-create/${NAMESPACE}
sudo chgrp admsk /kuber/yamls/dep-create/${NAMESPACE}
sudo -u kube mkdir -m 777 /kuber/volumes/${NAMESPACE}
sudo chgrp admsk /kuber/volumes/${NAMESPACE}
Формируем ~/.kube/config для пользователя, файл настроек для клиента kubectl
CAD=`sudo grep certificate-authority-data /etc/kubernetes/admin.conf`
cat > config << END
apiVersion: v1
clusters:
- cluster:
${CAD}
server: https://${IP}:6443
name: kubernetes
current-context:
kind: Config
preferences: {}
users:
- name: ${TEAM}
user:
client-certificate: ${TEAM}.crt
client-key: ${TEAM}.key
contexts:
- context:
cluster: kubernetes
namespace: ${NAMESPACE}
user: ${TEAM}
name: ${TEAM}-${NAMESPACE}-admin-context
END
Прячем сертификаты и удаляем старый yml-файл
sudo -u kube kubectl apply -f /tmp/${TEAM}-${NAMESPACE}.yml
rm -f /tmp/${TEAM}-${NAMESPACE}.yml
Запакуйте сертификаты и конфиг в zip-файл с паролем
sudo zip -j -e ${TEAM}.zip /etc/kubernetes/pki/teams/${TEAM}.crt /etc/kubernetes/pki/teams/${TEAM}.key config
Передайте zip-архив пользователю. Теперь он может распаковать его
mkdir ~/.kube
unzip *.zip
cp config *.crt *.key ~/.kube
и взаимодействовать со своим Namespace’ом через –context
kubectl --context=demo-team-test-dev-admin-context -n dev get pods
No resources found.
Не обязательно сохранять связку Context == Namespace при работе с kubectl
То есть после данного примера успешно работают все перечисленные Namespace’ы с указанием одного из Context’а (но не дальше перечисленных).
Пример
kubectl --context=demo-dev-admin-context -n demo-dev get services
No resources found.
kubectl --context=demo-dev-admin-context -n demo-dev-security get services
No resources found.
kubectl --context=demo-dev-admin-context -n test get services
Error from server (Forbidden): pods is forbidden: User "demo-dev" cannot list resource "services" in API group "" in the namespace "test"
Полезные команды для пользователя для просмотра конфига и переключение контекста:
kubectl config view
kubectl config use-context
Добавление новых Namespace к существующему пользователю
Если выяснилось, что пользователь под команду уже существует, но к нужно добавить ещё несколько Namespace’ов - выполните следущующие (урезанные) действия.
Снова задайте параметры, изменив название Namespace’ов и лимиты
TEAM=demo-team # Название пользвателя
NAMESPACE=dev-dmz # Название Namespace'а, на который мы будем давать права
CPU=2 # Лимит на вышеуказанный Namespace в CPU
RAM=4 # Лимит на вышеуказанный Namespace в ГБ RAM
Создайте Namespace
sudo -u kube kubectl create namespace ${NAMESPACE}
Создайте Context
sudo -u kube kubectl config set-context ${TEAM}-${NAMESPACE}-admin-context --cluster=kubernetes --namespace=${NAMESPACE} --user=${TEAM}
Создайте пары Role и RoleBinding для Namespace’а, а также лимиты
cat > /tmp/${TEAM}-${NAMESPACE}.yml << END
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: ${NAMESPACE}
name: ${TEAM}-namespace-manager
rules:
- apiGroups: ["", "extensions", "apps"]
resources:
- componentstatuses
- configmaps
- daemonsets
- deployments
- events
- endpoints
- horizontalpodautoscalers
- ingress
- ingresses
- ingresses.status
- jobs
- limitranges
- namespaces
- nodes
- pods
- pods/log
- pods/exec
- pods/attach
- pods/portforward
- persistentvolumes
- persistentvolumeclaims
- replicasets
- replicationcontrollers
- secrets
- serviceaccounts
- services
verbs: ["*"]
- apiGroups: [""]
resources:
- resourcequotas
verbs: ["get", "watch", "list"]
- apiGroups: ["batch"]
resources:
- jobs
- cronjobs
verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: ${TEAM}-namespace-manager-binding
namespace: ${NAMESPACE}
subjects:
- kind: User
name: ${TEAM}
apiGroup: ""
roleRef:
kind: Role
name: ${TEAM}-namespace-manager
apiGroup: ""
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: ${TEAM}-quota
namespace: ${NAMESPACE}
spec:
hard:
requests.cpu: "2"
requests.memory: 4Gi
limits.cpu: "${CPU}"
limits.memory: ${RAM}Gi
END
Примените и удалите вышесозданный файл
sudo -u kube kubectl apply -f /tmp/${TEAM}-${NAMESPACE}.yml
rm -f /tmp/${TEAM}-${NAMESPACE}.yml
Добавьте новый Namespace в config-файл для пользователя.
cat >> config << END
- context:
cluster: kubernetes
namespace: ${NAMESPACE}
user: ${TEAM}
name: ${TEAM}-${NAMESPACE}-admin-context
END
Повторите вышеуказанные действия, если у Вас есть ещё недосозданные Namespace’ы. После продолжайте.
Если старый config-файл не сохранился - передайте ему данные дополнительные настройки и попросите самостоятельно прописать его в конец своего файла ~/.kube/config
Если сохранился - можете передать весь файл цельно.
Сертификаты, ключи передавать не нужно, ровно как и шифровать файлы нет смысла.
Полезные команды для пользователя для просмотра конфига и переключение контекста:
kubectl config view
kubectl config use-context
Удаление пользователя
Для удаления пользователя выполните:
kubectl config unset "users.${TEAM}"
Добавление прав
Если пользователи наткнулись на ошибку недостаточности прав, у Вас есть возможность дополнить уже существующий Namespace недостающими правами.
Пример ошибки:
kubectl attach dev-k8s-6c8db775f7-mfgtb -n dev
Error from server (Forbidden): pods "dev-k8s-6c8db775f7-mfgtb" is forbidden:
User "demo-team" cannot create resource "pods/attach" in API group "" in the namespace "dev"
kubectl exec -it dev-k8s-6c8db775f7-mfgtb sh -n dev
Error from server (Forbidden): pods "dev-k8s-6c8db775f7-mfgtb" is forbidden:
User "demo-team" cannot create resource "pods/exec" in API group "" in the namespace "dev"
В сообщении ошибки всегда видно, какому пользователю (demo-team), каких прав (pods/attach и pods/exec) на какой Namespace (dev) не хватает.
На основании данного примера мы добавим права.
Копируем yaml-раздел по созданию Role и вносим в него данные из ошибки:
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: dev ##### NAMESPACE #####
name: demo-team-namespace-manager ##### USER'S ROLENAME
rules:
- apiGroups: ["", "extensions", "apps"]
resources:
- componentstatuses
- configmaps
- daemonsets
- deployments
- events
- endpoints
- horizontalpodautoscalers
- ingress
- ingresses
- ingresses.status
- jobs
- limitranges
- namespaces
- nodes
- pods
- pods/log
- pods/exec ##### Addinal #####
- pods/attach ##### Permissions #####
- pods/portforward
- persistentvolumes
- persistentvolumeclaims
- replicasets
- replicationcontrollers
- secrets
- serviceaccounts
- services
verbs: ["*"]
- apiGroups: [""]
resources:
- resourcequotas
verbs: ["get", "watch", "list"]
- apiGroups: ["batch"]
resources:
- jobs
- cronjobs
verbs: ["*"]
Применяем данные настройки в Kubernetes
sudo -u kube kubectl apply -f /tmp/demo-team-add.yml
rm -f /tmp/demo-team-add.yml
Готово
Увеличение квоты
Если пользователь упёрся в лимит - у него перестанут запускаться новые контейнеры (внимание на web)
kubectl --context demo-dev-dmz-admin-context -n demo-dev get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
db 1 1 1 1 3h29m
sec 2 2 1 2 10m
web 2 0 0 0 10m
kubectl --context demo-team-ngenie-dev-dmz-admin-context -n demo-dev get pods
NAME READY STATUS RESTARTS AGE
db-8499854f49-54fc4 1/1 Running 0 164m
sec-54f8c97778-45skj 1/1 Running 0 5m16s
sec-5cb8999df8-cdpnv 1/1 Running 0 10m
Ошибку можно посмотреть следующим образом
kubectl --context demo-team-dev-dmz-admin-context -n dev describe deploy web
Name: web
Namespace: dev
CreationTimestamp: Thu, 04 Apr 2019 16:36:17 +0300
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 2
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"web","namespace":"ndev"},"spec":{"replicas":2,"sele...
Selector: name=web
Replicas: 2 desired | 0 updated | 0 total | 0 available | 3 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: name=web
Containers:
web:
Image: hub.docker.com/web:3.0.2
Port: 8081/TCP
Host Port: 0/TCP
Limits:
cpu: 1
memory: 1Gi
Requests:
cpu: 1
memory: 1Gi
Environment: <none>
Mounts:
/opt/conf from dev-volume (rw)
Volumes:
dev-volume:
Type: HostPath (bare host directory volume)
Path: /kuber/volumes/dev/conf/
HostPathType:
Conditions:
Type Status Reason
---- ------ ------
Available False MinimumReplicasUnavailable
ReplicaFailure True FailedCreate
Progressing False ProgressDeadlineExceeded
OldReplicaSets: web-74f7565dcf (0/2 replicas created)
NewReplicaSet: web-66c5c6d979 (0/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 10m deployment-controller Scaled up replica set web-74f7565dcf to 2
Normal ScalingReplicaSet 5m33s deployment-controller Scaled up replica set web-66c5c6d979 to 1
kubectl --context demo-team-dev-dmz-admin-context -n dev describe replicaset web-66c5c6d979
Name: web-66c5c6d979
Namespace: dev
Selector: name=web,pod-template-hash=66c5c6d979
Labels: name=web
pod-template-hash=66c5c6d979
Annotations: deployment.kubernetes.io/desired-replicas: 2
deployment.kubernetes.io/max-replicas: 3
deployment.kubernetes.io/revision: 2
Controlled By: Deployment/web
Replicas: 0 current / 1 desired
Pods Status: 0 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: name=web
pod-template-hash=66c5c6d979
Containers:
web:
Image: hub.docker.com/web:3.0.2
Port: 8081/TCP
Host Port: 0/TCP
Limits:
cpu: 1
memory: 1Gi
Requests:
cpu: 1
memory: 1Gi
Environment: <none>
Mounts:
/opt/conf from dev-volume (rw)
Volumes:
dev-volume:
Type: HostPath (bare host directory volume)
Path: /kuber/volumes/dev/conf/
HostPathType:
Conditions:
Type Status Reason
---- ------ ------
ReplicaFailure True FailedCreate
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedCreate 5m46s replicaset-controller Error creating: pods "web-66c5c6d979-bclmd" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 5m46s replicaset-controller Error creating: pods "web-66c5c6d979-4xfvs" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 5m46s replicaset-controller Error creating: pods "web-66c5c6d979-6xgwb" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 5m46s replicaset-controller Error creating: pods "web-66c5c6d979-btdj6" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 5m46s replicaset-controller Error creating: pods "web-66c5c6d979-fr5cm" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 5m46s replicaset-controller Error creating: pods "web-66c5c6d979-z68jp" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 5m46s replicaset-controller Error creating: pods "web-66c5c6d979-2btrr" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 5m46s replicaset-controller Error creating: pods "web-66c5c6d979-wkd66" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 5m45s replicaset-controller Error creating: pods "web-66c5c6d979-x4tc2" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Warning FailedCreate 19s (x8 over 5m44s) replicaset-controller (combined from similar events): Error creating: pods "web-66c5c6d979-rpjq6" is forbidden: exceeded quota: demo-team-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4
Как видно по сообщению, на demo-team-quota используется requests.cpu=4, хочет использоваться ещё requests.cpu=1, но он уже не лезет в лимит request.cpu=4. Приблизительно такое сообщение может появиться по RAM, а также по hard-ограничению.
Можно попросить пользователя уменьшить потребляемые лимиты контейнеров, а можно - увеличить квоту. Последним мы и займёмся - увеличим request.cpu и hard.cpu до 8
vim /tmp/demo-team-quota.yml
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: demo-team-quota
namespace: dev
spec:
hard:
requests.cpu: "8"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 8Gi
Применяем и удаляём файл
sudo -u kube kubectl apply -f /tmp/demo-team-quota.yml
rm -f /tmp/demo-team-quota.yml
Просим пользователей пересоздать проблемный deployment и готово
kubectl --context demo-team-dev-dmz-admin-context -n dev get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
db 1 1 1 1 3h40m
sec 2 2 1 2 21m
web 2 0 0 0 21m
kubectl --context demo-team-dev-dmz-admin-context -n dev delete deploy web
deployment.extensions "web" deleted
kubectl --context demo-team-ngenie-dev-dmz-admin-context apply -f secweb.yml
deployment.apps/sec unchanged
service/sec unchanged
deployment.apps/web created
service/web unchanged
kubectl --context demo-team-dev-dmz-admin-context -n dev get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
db 1 1 1 1 3h40m
sec 2 2 1 2 22m
web 2 2 2 2 13s
kubectl --context demo-team-ngenie-dev-dmz-admin-context -n dev get pods
NAME READY STATUS RESTARTS AGE
db-8499854f49-54fc4 1/1 Running 0 176m
sec-54f8c97778-45skj 1/1 Running 0 16m
sec-5cb8999df8-cdpnv 1/1 Running 0 22m
web-66c5c6d979-qbdtf 1/1 Running 0 10s
web-66c5c6d979-skffb 1/1 Running 0 10s