K8s Q A Shell Operator: различия между версиями
Sirmax (обсуждение | вклад) |
Sirmax (обсуждение | вклад) |
||
| (не показано 11 промежуточных версий этого же участника) | |||
| Строка 1: | Строка 1: | ||
[[Категория:K8s]] |
[[Категория:K8s]] |
||
[[Категория:K8s_Вопросы_И_Ответы]] |
[[Категория:K8s_Вопросы_И_Ответы]] |
||
| − | [[Категория: |
+ | [[Категория:K8s_Operator]] |
| + | [[Категория:Shell Operator]] |
||
| − | |||
=Shell Operator= |
=Shell Operator= |
||
| Строка 19: | Строка 19: | ||
=Как это сделать= |
=Как это сделать= |
||
| + | Идея такая - на основании shell-operator написать свой скрипт, который подписывается на события в кластере, и при появлении нужного POD сохранит логи в доступном месте. |
||
| + | <BR> |
||
| + | В целом довольно костыльно - но задачу решает |
||
==Shell-Operator== |
==Shell-Operator== |
||
Shell-оператор это фреймворк для написания своих операторов на shell или python |
Shell-оператор это фреймворк для написания своих операторов на shell или python |
||
| Строка 125: | Строка 128: | ||
fi |
fi |
||
</PRE> |
</PRE> |
||
| + | ==Сборка образа== |
||
| − | ==11== |
||
| + | ===Dockerfile=== |
||
| + | Так-как это только оператор для единоразовой задачи - все максимально просто, помещаем скрипт в директорию <code>hooks</code> и все |
||
| + | <PRE> |
||
| + | FROM ghcr.io/flant/shell-operator:latest |
||
| + | ADD hooks /hooks |
||
| + | </PRE> |
||
| + | ===Build=== |
||
| + | Удалить старый, пересобрать заново, пушнуть на докерхаб |
||
| + | <PRE> |
||
| + | !/bin/bash |
||
| + | |||
| + | set -ex |
||
| + | |||
| + | for i in $(docker image ls | grep sirmax123/shell-operator-test | awk '{ print $3}'); |
||
| + | do |
||
| + | docker image rm ${i} |
||
| + | done |
||
| + | |||
| + | docker build . -t sirmax123/shell-operator-test:1 |
||
| + | docker push sirmax123/shell-operator-test:1 |
||
| + | </PRE> |
||
| + | |||
| + | =<code>RBAC</code>= |
||
| + | Для того что бы оператор мог получить доступ к событиям - нужно создать сервисный аккаунт и назначить на него соответствующие разрешения <BR> |
||
| + | (можно указать несколько объектов в одном файле) |
||
| + | ==<code>ServiceAccount</code>== |
||
| + | <PRE> |
||
| + | --- |
||
| + | apiVersion: v1 |
||
| + | kind: ServiceAccount |
||
| + | metadata: |
||
| + | name: monitor-events-acc |
||
| + | </PRE> |
||
| + | ==<code>ClusterRole</code>== |
||
| + | <PRE> |
||
| + | --- |
||
| + | apiVersion: rbac.authorization.k8s.io/v1 |
||
| + | kind: ClusterRole |
||
| + | metadata: |
||
| + | name: monitor-events |
||
| + | rules: |
||
| + | - apiGroups: ["events.k8s.io"] |
||
| + | resources: ["events"] |
||
| + | verbs: ["get", "watch", "list"] |
||
| + | |||
| + | - apiGroups: [""] |
||
| + | resources: ["pods", "pods/log"] |
||
| + | verbs: ["get", "watch", "list"] |
||
| + | </PRE> |
||
| + | |||
| + | ==<code>ClusterRoleBinding</code>== |
||
| + | <PRE> |
||
| + | --- |
||
| + | apiVersion: rbac.authorization.k8s.io/v1 |
||
| + | kind: ClusterRoleBinding |
||
| + | metadata: |
||
| + | name: monitor-events |
||
| + | roleRef: |
||
| + | apiGroup: rbac.authorization.k8s.io |
||
| + | kind: ClusterRole |
||
| + | name: monitor-events |
||
| + | subjects: |
||
| + | - kind: ServiceAccount |
||
| + | name: monitor-events-acc |
||
| + | namespace: stacklight |
||
| + | </PRE> |
||
| + | =Run Pod= |
||
| + | По-хорошему, на случай подения пода стоило бы завести его под какой-то контроллер, но учитывая что в данном случае это единоразовая задача, то я просто забил болт на надежность и запустил 1 POD |
||
| + | <PRE> |
||
| + | --- |
||
| + | apiVersion: v1 |
||
| + | kind: Pod |
||
| + | metadata: |
||
| + | name: shell-operator |
||
| + | spec: |
||
| + | containers: |
||
| + | - name: shell-operator |
||
| + | image: sirmax123/shell-operator-test:1 |
||
| + | imagePullPolicy: Always |
||
| + | serviceAccountName: monitor-events-acc |
||
| + | </PRE> |
||
Текущая версия на 20:02, 11 января 2024
Shell Operator
https://habr.com/ru/companies/flant/articles/447442/
Что нужно сделать
Есть cron-job которая
- Падает время от времени (но не всегда, а скорее редко)
- Подчищает за собой POD
- Хочется найти упавший под и собрать с него логи ДО того как под будет удален
- Не хочется сидеть и ждать такой под
- Доступа к централизованной системе логгирования нет (так бывает - логи пишутся централизованно в корпоративную систему)
Как это сделать
Идея такая - на основании shell-operator написать свой скрипт, который подписывается на события в кластере, и при появлении нужного POD сохранит логи в доступном месте.
В целом довольно костыльно - но задачу решает
Shell-Operator
Shell-оператор это фреймворк для написания своих операторов на shell или python
Hook
Для обработки событий использую вот такой скрипт, при запуске с параметром --configон должен выдать описания событий на которые нужно подписаться,
при запуске без параметров ему передается (чеерз переменную окружения ${BINDING_CONTEXT_PATH} путь к файлу который содержит данные события
#!/usr/bin/env bash
NAMESPACE="stacklight"
POD_NAME="elasticsearch-curator"
# Эта часть кода запускается при старте оператора, и
# определяет на какие именно события будет подписываться этот скрипт
# В частности - в каком именно неймспейсе
if [[ $1 == "--config" ]] ;
then
cat <<EOF
{
"configVersion":"v1",
"kubernetes":[
{
"apiVersion": "events.k8s.io/v1",
"kind": "Event",
"namespace": {
"nameSelector": {
"matchNames": ["${NAMESPACE}"]
}
},
"fieldSelector": {
"matchExpressions": [
{
"field": "metadata.namespace",
"operator": "Equals",
"value": "${NAMESPACE}"
}
]
}
}
]
}
EOF
else
# Сохранить содержимое BINDING_CONTEXT (для последующего анализа)
cat "${BINDING_CONTEXT_PATH}" >> /tmp/log2
echo ""
echo "[events-hook.sh] Starting HOOK"
echo "[events-hook.sh] ------------------------------------------"
# Вывести в лог (лог пода)
cat "${BINDING_CONTEXT_PATH}"
echo "[events-hook.sh] "
type=$(jq -r '.[0].type' ${BINDING_CONTEXT_PATH})
echo "[events-hook.sh] ------------------------------------------"
echo "[events-hook.sh] TYPE=${type}"
echo "------------------------------------------"
if [[ $type == "Event" ]] ; then
echo "[events-hook.sh] Got Event: "
echo "[events-hook.sh] ------------------------------------------"
jq '.[0].object' ${BINDING_CONTEXT_PATH}
echo "[events-hook.sh] ------------------------------------------"
podName=$(jq -r '.[0].object.metadata.name' $BINDING_CONTEXT_PATH)
echo "[events-hook.sh] Pod Name: '${podName}'"
echo "[events-hook.sh] ------------------------------------------"
else
echo "DATA: ${BINDING_CONTEXT_PATH}" >> /tmp/log
fi
#jq -r '.[0].object.note' ${BINDING_CONTEXT_PATH} >> /tmp/note.log
note=$(jq -r '.[0].object.note' ${BINDING_CONTEXT_PATH})
echo "[events-hook.sh] ------------------------------------------"
echo "[events-hook.sh] Got note: ${note}"
echo "[events-hook.sh] ------------------------------------------"
# Возможно на первой иттерации под не успеет стартовать, но
# если он упадет, то его логи будут получены при следующем запуске
# Cron Job
if [[ "${note}" == "Started container ${POD_NAME}" ]];
then
D=$(date +%Y%m%d-%H%M%S)
kubectl get pod | grep "${POD_NAME}"| grep -vE "Completed|Running|Pending|ContainerCreating" >> /tmp/list_pods_${D}
for failedPod in $(kubectl get pod | grep "${POD_NAME}" | grep -vE "Completed|Running|Pending|ContainerCreating" | awk '{ print $1 }' );
do
# Найти под и вывести в логи его описание, дескрайб и логи
echo "[events-hook.sh] Found failed POD: ${failedPod}"
describeFailedPod=$(kubectl describe pod ${failedPod})
echo "[events-hook.sh] POD Describe: ${describeFailedPod}"
echo "${describeFailedPod}" > /tmp/${failedPod}_describe_${D}
getFailedPodYaml=$(kubectl get pod ${failedPod} -o yaml)
echo "[events-hook.sh] POD Definition: ${getFailedPodYaml}"
echo "${getFailedPodYaml}" > /tmp/${failedPod}_yaml_${D}
failedPodLogs=$(kubectl \
logs -f ${failedPod} \
--all-containers 2>&1)
echo "${failedPodLogs}" > /tmp/${failedPod}_logs_${D}
echo "[events-hook.sh] POD Logs: ${failedPodLogs}"
done
fi
fi
Сборка образа
Dockerfile
Так-как это только оператор для единоразовой задачи - все максимально просто, помещаем скрипт в директорию hooks и все
FROM ghcr.io/flant/shell-operator:latest ADD hooks /hooks
Build
Удалить старый, пересобрать заново, пушнуть на докерхаб
!/bin/bash
set -ex
for i in $(docker image ls | grep sirmax123/shell-operator-test | awk '{ print $3}');
do
docker image rm ${i}
done
docker build . -t sirmax123/shell-operator-test:1
docker push sirmax123/shell-operator-test:1
RBAC
Для того что бы оператор мог получить доступ к событиям - нужно создать сервисный аккаунт и назначить на него соответствующие разрешения
(можно указать несколько объектов в одном файле)
ServiceAccount
--- apiVersion: v1 kind: ServiceAccount metadata: name: monitor-events-acc
ClusterRole
--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: monitor-events rules: - apiGroups: ["events.k8s.io"] resources: ["events"] verbs: ["get", "watch", "list"] - apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get", "watch", "list"]
ClusterRoleBinding
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: monitor-events
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: monitor-events
subjects:
- kind: ServiceAccount
name: monitor-events-acc
namespace: stacklight
Run Pod
По-хорошему, на случай подения пода стоило бы завести его под какой-то контроллер, но учитывая что в данном случае это единоразовая задача, то я просто забил болт на надежность и запустил 1 POD
---
apiVersion: v1
kind: Pod
metadata:
name: shell-operator
spec:
containers:
- name: shell-operator
image: sirmax123/shell-operator-test:1
imagePullPolicy: Always
serviceAccountName: monitor-events-acc