Предисловие переводчика: Эта статья — комбинация из перевода двух материалов от проекта CoreOS (см. ссылки в конце публикации), посвящённых работе с консольным инструментом для выполнения команд на кластерах Kubernetes — kubectl. Листинг, приведённый автором оригинала для Mac OS X, был адаптирован под Linux, в других листингах было исправлено форматирование YAML, а для удобства чтения всего материала в него были добавлены подзаголовки.

Kubectl — инструмент, который знаком пользователям Kubernetes и обладает широкими функциональными возможностями. Овладение ими занимает время, но позволяет увидеть, что это более мощный инструмент, чем многие предполагали. Представляю набор советов, позволяющих улучшить ваши возможности при работе с kubectl. Не забудьте также посмотреть на cheat sheet в секции официальной документации Kubernetes!

Автоматическое дополнение в shell


В kubectl есть отличное встроенное автодополнение для bash и zsh, что значительно упрощает работу с командами, флагами и объектами вроде пространств имён и названий подов. В документации есть готовые инструкции по его включению. А GIF-анимация ниже показывает, как автодополнение работает:



# Подключить код автодополнения для текущего сеанса в Bash
source <(kubectl completion bash)
# … или добавить код автодополнения в файл и подключить его к .bashrc
mkdir ~/.kube
kubectl completion bash > ~/.kube/completion.bash.inc
printf "\n# Kubectl shell completion\nsource '$HOME/.kube/completion.bash.inc'\n" >> $HOME/.bashrc
source $HOME/.bashrc
# Альтернатива — подключить код автодополнения для текущего сеанса в Zsh
source <(kubectl completion zsh)

Слияние конфигов с контекстами через KUBECONFIG


Слияние конфигураций Kubernetes — популярный паттерн, если вы взаимодействуете со множеством кластеров Kubernetes. При работе с разными конфигами используется концепция контекста (context), указывающего на параметры, которые kubectl будет использовать для поиска конкретного, целевого кластера. Но добиться нужного результата с контекстами бывает сложно. Чтобы упростить себе жизнь, воспользуйтесь переменной окружения KUBECONFIG — она позволяет указать на конфигурационные файлы, которые используются при слиянии. Подробнее о KUBECONFIG можно прочитать в официальной документации.

Например, у вас есть два конфига Kubernetes для разных кластеров, и требуется провести их слияние.

Конфиг первого кластера:

$ kubectl config view --minify > cluster1-config

apiVersion: v1
clusters:
- cluster:
    certificate-authority: cluster1_ca.crt
    server: https://cluster1
  name: cluster1
contexts:
- context:
    cluster: cluster1
    user: cluster1
  name: cluster1
current-context: cluster1
kind: Config
preferences: {}
users:
- name: cluster1
  user:
    client-certificate: cluster1_apiserver.crt
    client-key: cluster1_apiserver.key

Конфиг второго кластера:

$ cat cluster2-config

apiVersion: v1
clusters:
- cluster:
    certificate-authority: cluster2_ca.crt
    server: https://cluster2
  name: cluster2
contexts:
- context:
    cluster: cluster2
    user: cluster2
  name: cluster2
current-context: cluster2
kind: Config
preferences: {}
users:
- name: cluster2
  user:
    client-certificate: cluster2_apiserver.crt
    client-key: cluster2_apiserver.key

Их слияние можно выполнить с помощью KUBECONFIG. Преимуществом такого слияния станет возможность динамически переключаться между контекстами. Контекст — это «сопоставление» (map), включающее в себя описания кластера и пользователя, а также название, с помощью которого на конфигурацию можно ссылаться для аутентификации кластера и взаимодействия с ним. Флаг --kubeconfig позволяет посмотреть на контекст для каждого файла:

$ kubectl --kubeconfig=cluster1-config config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster1 cluster1 cluster1
$ kubectl --kubeconfig=cluster2-config config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster2 cluster2 cluster2

У каждого конфигурационного файла есть единственный контекст, так что они не конфликтуют между собой. Слияние двух файлов через KUBECONFIG показывает оба контекста. Для сохранения текущего контекста создайте новый пустой файл с названием cluster-merge:

$ export KUBECONFIG=cluster-merge:cluster-config:cluster2-config
dcooley@lynx ~
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster1 cluster1 cluster1
cluster2 cluster2 cluster2

Список файлов, экспортируемых с KUBECONFIG, загружается в строгом порядке. Поэтому контекст, который выбирается, соответствует указанному как current-context в первом конфиге. Изменение контекста на cluster2 смещает знак текущего (*) к этому контексту в списке, и команды kubectl начинают применяться к этому (второму) контексту:

$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster1 cluster1 cluster1
cluster2 cluster2 cluster2
$ kubectl config use-context cluster2
Switched to context "cluster2".
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
cluster1 cluster1 cluster1
* cluster2 cluster2 cluster2
$ cat cluster-merge

apiVersion: v1
clusters: []
contexts: []
current-context: cluster2
kind: Config
preferences: {}
users: []

Остаётся только поддерживать правильное значение current-context. Использовать контексты Kubernetes и осуществлять их слияние можно разными способами. Например, вы можете создать контекст (cluster1_kube-system), который будет определять пространство имён (kube-system) для всех исполняемых команд kubectl:

$ kubectl config set-context cluster1_kube-system --cluster=cluster1 --namespace=kube-system --user=cluster1
Context "cluster1_kube-system" set.
$ cat cluster-merge

apiVersion: v1
clusters: []
contexts:
- context:
    cluster: cluster1
    namespace: kube-system
    user: cluster1
  name: cluster1_kube-system
current-context: cluster2
kind: Config
preferences: {}
users: []

Новый контекст можно использовать так:

$ kubectl config use-context cluster1_kube-system
Switched to context "cluster1_kube-system".
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
default-http-backend-fwx3g 1/1 Running 0 28m
kube-addon-manager-cluster 1/1 Running 0 28m
kube-dns-268032401-snq3h 3/3 Running 0 28m
kubernetes-dashboard-b0thj 1/1 Running 0 28m
nginx-ingress-controller-b15xz 1/1 Running 0 28m

Изучение Kubernetes API


Чтобы узнать больше о возможностях, предоставляемых Kubernetes API, запросите файл swagger.json:

$ kubectl proxy
$ curl -O 127.0.0.1:8001/swagger.json

Можно также зайти на http://localhost:8001/api/ и посмотреть на имеющиеся в Kubernetes API пути.

Поскольку swagger.json — это документ в формате JSON, можно его просмотреть с помощью jq. Утилита jq — лёгкий обработчик JSON-файлов, позволяющий выполнять сравнения и другие операции. Подробнее читайте здесь.

Просмотр swagger.json поможет понять Kubernetes API. Это сложный API, функции в котором разбиты на группы, что затрудняет его восприятие:

$ cat swagger.json | jq '.paths | keys[]'
"/api/"
"/api/v1/"
"/api/v1/configmaps"
"/api/v1/endpoints"
"/api/v1/events"
"/api/v1/namespaces"
"/api/v1/nodes"
"/api/v1/persistentvolumeclaims"
"/api/v1/persistentvolumes"
"/api/v1/pods"
"/api/v1/podtemplates"
"/api/v1/replicationcontrollers"
"/api/v1/resourcequotas"
"/api/v1/secrets"
"/api/v1/serviceaccounts"
"/api/v1/services"
"/apis/"
"/apis/apps/"
"/apis/apps/v1beta1/"
"/apis/apps/v1beta1/statefulsets"
"/apis/autoscaling/"
"/apis/batch/"
"/apis/certificates.k8s.io/"
"/apis/extensions/"
"/apis/extensions/v1beta1/"
"/apis/extensions/v1beta1/daemonsets"
"/apis/extensions/v1beta1/deployments"
"/apis/extensions/v1beta1/horizontalpodautoscalers"
"/apis/extensions/v1beta1/ingresses"
"/apis/extensions/v1beta1/jobs"
"/apis/extensions/v1beta1/networkpolicies"
"/apis/extensions/v1beta1/replicasets"
"/apis/extensions/v1beta1/thirdpartyresources"
"/apis/policy/"
"/apis/policy/v1beta1/poddisruptionbudgets"
"/apis/rbac.authorization.k8s.io/"
"/apis/storage.k8s.io/"
"/logs/"
"/version/"

А вот следующая команда описывает API, доступные в кластере Kubernetes и к которым у вас есть доступ. Команда в примере ниже выполнена под пользователем-администратором. Если у вас включён контроль доступа по RBAC, вывод может отличаться:

$ kubectl api-versions
apps/v1beta1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1beta1
autoscaling/v1
batch/v1
batch/v2alpha1
certificates.k8s.io/v1alpha1
coreos.com/v1
etcd.coreos.com/v1beta1
extensions/v1beta1
oidc.coreos.com/v1
policy/v1beta1
rbac.authorization.k8s.io/v1alpha1
storage.k8s.io/v1beta1
v1

Команда kubectl explain помогает лучше понять, что делают разные компоненты API:

$ kubectl explain
You must specify the type of resource to explain. Valid resource types include:
* all
* certificatesigningrequests (aka 'csr')
* clusters (valid only for federation apiservers)
* clusterrolebindings
* clusterroles
* componentstatuses (aka 'cs')
* configmaps (aka 'cm')
* daemonsets (aka 'ds')
* deployments (aka 'deploy')
* endpoints (aka 'ep')
* events (aka 'ev')
* horizontalpodautoscalers (aka 'hpa')
* ingresses (aka 'ing')
* jobs
* limitranges (aka 'limits')
* namespaces (aka 'ns')
* networkpolicies
* nodes (aka 'no')
* persistentvolumeclaims (aka 'pvc')
* persistentvolumes (aka 'pv')
* pods (aka 'po')
* poddisruptionbudgets (aka 'pdb')
* podsecuritypolicies (aka 'psp')
* podtemplates
* replicasets (aka 'rs')
* replicationcontrollers (aka 'rc')
* resourcequotas (aka 'quota')
* rolebindings
* roles
* secrets
* serviceaccounts (aka 'sa')
* services (aka 'svc')
* statefulsets
* storageclasses
* thirdpartyresources
error: Required resource not specified.
See 'kubectl explain -h' for help and examples.

Попробуйте выполнить kubectl explain deploy. Команда explain работает с разными уровнями вложенности, что позволяет вам также ссылаться на зависимые объекты:

$ kubectl explain deploy.spec.template.spec.containers.livenessProbe.exec
RESOURCE: exec <Object>
DESCRIPTION:
One and only one of the following should be specified. Exec specifies the
action to take.
ExecAction describes a "run in container" action.
FIELDS:
command <[]string>
Command is the command line to execute inside the container, the working
directory for the command is root ('/') in the container's filesystem. The
command is simply exec'd, it is not run inside a shell, so traditional shell
instructions ('|', etc) won't work. To use a shell, you need to explicitly
call out to that shell. Exit status of 0 is treated as live/healthy and
non-zero is unhealthy.

Операции с подами через kubectl


Все последующие примеры используют Kubernetes API, чтобы узнать что-либо о подах. Одним из способов получения нужных данных — построить запрос и понять, какое его выражение потребуется в терминах jsonpath. Например, можно выполнить kubectl get pods --all-namespaces -o json, чтобы увидеть весь вывод, из которого мы можем потом отфильтровать нужные данные для примера с сортировкой подов по времени (см. ниже).

Если у вас нет запущенного приложения, для знакомства с примерами можно создать поды с лейблом run=shop и запустить их как сервис на порту 80:

$ kubectl run shop --replicas=2 --image quay.io/coreos/example-app:v1.0 --port 80 --expose

Теперь можно посмотреть, что мы будем делать с jsonpath. Более подробную информацию по нему можно получить из официальной документации.

Фильтрация подов Kubernetes по времени их создания


$ kubectl get pods --all-namespaces --sort-by='.metadata.creationTimestamp' -o jsonpath='{range .items[*]}{.metadata.name}, {.metadata.creationTimestamp}{"\n"}{end}'

Поиск пода Kubernetes по селектору лейбла и просмотр его логов


Укажите пространство имён (your-namespace) и свой запрос на наличие лейбла, который поможет найти нужные поды, и получите логи этих подов. Если под не единственный, логи будут получены из всех подов параллельно:

$ ns='<your-namespace>' label='<yourkey>=<yourvalue>' kubectl get pods -n $ns -l $label -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' | xargs -I {} kubectl -n $ns logs {}

Поиск пода Kubernetes по селектору лейбла и подключение к нему


Укажите пространство имён (your-namespace) и свой запрос на наличие лейбла, который поможет найти нужные поды, и подключитесь к нему по имени (к первому из найденных подов). Замените 8080 на нужный порт пода:

$ ns='<your-namespace>' label='<yourkey>=<yourvalue>' kubectl -n $ns get pod -l $label -o jsonpath='{.items[1].metadata.name}' | xargs -I{} kubectl -n $ns port-forward {} 8080:80

Операции с узлами (нодами) через kubectl


Комбинация jq и JSON-вывода kubectl позволяет делать сложные запросы, такие как фильтрация всех ресурсов по времени их создания.

Подсчёт количества подов в узле Kubernetes


Зачастую высокоуровневая статистика помогает в отладке. Эта команда подсчитает количество всех подов на каждом из узлов:

$ kubectl get pods --all-namespaces -o json | jq '.items[] | .spec.nodeName' -r | sort | uniq -c

Фильтрация узлов по лейблу


Запросы с лейблами можно использовать и для узлов. Такой подход часто применяется при конфигурации deployments, нуждающихся в определённых ограничениях. Для получения подробной информации о селекторах смотрите вывод kubectl explain deployment.spec.selector.

$ kubectl get nodes -l 'master' or kubectl get nodes -l '!master'

Вывести все лейблы можно с помощью аргумента --show-labels для любого объекта Kubernetes:

$ kubectl get nodes --all-namespaces --show-labels

Список всех подов для каждого узла


Генерируется JSON-документ с названием узла Kubernetes и список всех названий подов, запущенных на этом узле. Очень полезная команда при отладке:

$ kubectl get pods --all-namespaces -o json | jq '.items | map({podName: .metadata.name, nodeName: .spec.nodeName}) | group_by(.nodeName) | map({nodeName: .[0].nodeName, pods: map(.podName)})'

Получение внешних IP для узлов Kubernetes


$ kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name} {.status.addresses[?(@.type=="ExternalIP")].address}{"\n"}{end}'

Примечание: Читайте в нашем блоге перевод другой статьи от CoreOS про работу с Kubernetes из консоли: «Автоматизация SSH-доступа к нодам Kubernetes с помощью Fabric и интеграции от CoreOS», а также заметку «Полезные утилиты при работе с Kubernetes» (в ней представлены преимущественно консольные инструменты).

Источники


Поделиться с друзьями
-->

Комментарии (1)


  1. badc0de
    24.07.2017 19:32
    +3

    Мы еще используем ReplicaSets для понимания того, какие Docker образы используются (или могут быть использованы) в рамках конкретного кластера.


    Делаем мы это не через bash/jq, но можно и через bash:


    kubectl get replicasets -o json | jq '.items[] | .spec.template.spec.containers[].image'

    При использовании Private Registry — эта информация может быть полезна для удаления старых образов. Указывая глубину возможных откатов через revisionHistoryLimit, мы по каждому деплою приблизительно (из-за слоев докера и частотой запуска garbage collector) ограничиваем количество образов сохраненных в Registry.


    Однако, тут есть ньюанс: в Registry несколько тэгов (tags) могут указывать на один образ (image), и поэтому очень важно выполнять дополнительные проверки перед удалением.