Предисловие переводчика: Эта статья — комбинация из перевода двух материалов от проекта 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 completionnsource '$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» (в ней представлены преимущественно консольные инструменты).
Источники
- «Kubernetes kubectl Tips and Tricks» (Duffie Cooley из CoreOS, 15 мая 2017 г.)
- «Kubectl Unix Pipes: Manage Multiple Clusters With Ease» (Duffie Cooley из CoreOS, 8 июня 2017 г.)
Автор: Флант