Цей розділ містить набір ресурсів для виправлення проблем з контейнеризованими застосунками. Він охоплює такі речі, як загальні проблеми з ресурсами Kubernetes (наприклад, Pods, Services або StatefulSets), поради щодо розуміння повідомлень про припинення роботи контейнера та способи налагодження запущених контейнерів.
Це багатосторінковий друкований вигляд цього розділу. Натисність щоб друкувати.
Налагодження застосунків
- 1: Налагодження Podʼів
- 2: Налагодження Service
- 3: Налагодження StatefulSet
- 4: Визначення причини збою Podʼа
- 5: Налагодження контейнерів ініціалізації
- 6: Налагодження запущених Podʼів
- 7: Отримання доступу до оболонки запущеного контейнера
1 - Налагодження Podʼів
Цей посібник допоможе користувачам налагодити програми, які розгорнуті у Kubernetes та які поводяться некоректно. Це не настанова для людей, які хочуть налагоджувати свій кластер. Для цього вам слід ознайомитися з цим посібником.
Діагностика проблеми
Перший крок у розвʼязанні проблем — сортування. Що сталося? Проблема у ваших Podʼах, Контролері Реплікацій чи Service?
Налагодження Podʼів
Перший крок у налагоджені Podʼа — це його перевірка. Перевірте поточний стан Podʼа та останні події за допомогою наступної команди:
kubectl describe pods ${POD_NAME}
Огляньте стан контейнерів у Podʼі. Чи всі вони Running
(працюють)? Чи були нещодавні перезапуски?
Продовжуйте налагодження, виходячи зі стану Podʼів.
Мій Pod залишається в стані Pending
Якщо Pod застряг у стані Pending
, це означає, що його не можна запланувати на вузол. Зазвичай це відбувається через недостатні ресурси одного типу чи іншого, які заважають плануванню. Подивіться на вивід команди kubectl describe ...
вище. Там мають бути повідомлення від планувальника про причини, чому він не може запланувати ваш Pod. Причини включають:
У вас недостатньо ресурсів: Можливо, ви вичерпали запас CPU або памʼяті у вашому кластері, у цьому випадку вам потрібно видалити Podʼи, налаштувати запити на ресурси, або додати нові вузли до вашого кластера. Дивіться документ про обчислювальні ресурси для отримання додаткової інформації.
Ви використовуєте
hostPort
: Коли ви привʼязуєте Pod доhostPort
, існує обмежена кількість місць, де можна запланувати цей Pod. У більшості випадків,hostPort
не є необхідним, спробуйте використати обʼєкт Service для відкриття доступу вашому Podʼу. Якщо вам все ж потрібенhostPort
, то ви можете запланувати лише стільки Podʼів, скільки у вас вузлів у кластері Kubernetes.
Мій Pod залишається у стані Waiting
Якщо Pod застряг у стані Waiting
, то він був запланований на робочий вузол, але не може працювати на цій машині. Знову ж таки, вивід команди kubectl describe ...
має бути інформативним. Найпоширенішою причиною Podʼів у стані Waiting
є неможливість завантаження образу. Тут є три речі, які потрібно перевірити:
- Переконайтеся, що ви правильно вказали імʼя образу.
- Чи ви завантажили образ у реєстр?
- Спробуйте вручну завантажити образ, щоб перевірити, чи можна його завантажити. Наприклад, якщо ви використовуєте Docker на вашому ПК, виконайте
docker pull <image>
.
Мій Pod залишається у стані Terminating
Якщо Pod застряг у стані Terminating
(завершення), це означає, що було видано наказ про видалення Podʼа, але планпанель управління не може видалити обʼєкт Pod.
Це зазвичай відбувається, якщо у Podʼа є завершувач та встановлений вубхук допуску у кластері, який перешкоджає панелі управління видалити завершувач.
Щоб виявити цей сценарій, перевірте, чи у вашому кластері є вебхуки ValidatingWebhookConfiguration
або MutatingWebhookConfiguration
, які спрямовані на операції UPDATE
для ресурсів pods
.
Якщо вебхук надається стороннім вендором:
- Переконайтеся, що ви використовуєте останню версію.
- Вимкніть вебхук для операцій
UPDATE
. - Повідомте про проблему відповідного постачальника.
Якщо ви є автором вебхуку:
- Для мутуючого вебхуку переконайтеся, що він ніколи не змінює незмінні поля під час операцій
UPDATE
. Наприклад, зміни контейнерів зазвичай не дозволяються. - Для перевірки вебхуку переконайтеся, що ваші політики валідації застосовуються лише до нових змін. Іншими словами, ви повинні дозволяти Podʼам з наявними порушеннями пройти валідацію. Це дозволяє Podʼам, які були створені до встановлення вебхуку валідації, продовжувати працювати.
Мій Pod виходить з ладу або несправний іншим чином
Як тільки ваш Pod був запланований, методи, описані в Налагодження Запущених Подів, доступні для налагодження.
Мій Pod працює, але не робить те, що я йому сказав робити
Якщо ваш Pod не поводиться так, як ви очікували, це може бути повʼязано з помилкою у вашому описі Podʼа (наприклад, файл mypod.yaml
на вашому локальному компʼютері), і цю помилку було мовчки проігноровано під час створення Podʼа. Часто розділ опису Podʼа вкладено неправильно, або імʼя ключа набрано неправильно, і тому ключ ігнорується. Наприклад, якщо ви помилилися в написанні command
як commnd
, тоді Pod буде створено, але не використовуватиме командний рядок, який ви планували.
Перша річ, яку варто зробити, — видалити свій Pod і спробувати створити його знову з опцією --validate
. Наприклад, виконайте kubectl apply --validate -f mypod.yaml
. Якщо ви помилилися в написанні command
як commnd
, то отримаєте помилку на кшталт цієї:
I0805 10:43:25.129850 46757 schema.go:126] unknown field: commnd
I0805 10:43:25.129973 46757 schema.go:129] this may be a false alarm, see https://github.com/kubernetes/kubernetes/issues/6842
pods/mypod
Наступне, що варто перевірити, — чи відповідає Pod на апісервері Podʼу, який ви збиралися створити (наприклад, у файлі YAML на вашому локальному компʼютері). Наприклад, виконайте kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml
а потім вручну порівняйте оригінальний опис Podʼа, mypod.yaml
, з тим, який ви отримали з апісервера, mypod-on-apiserver.yaml
. Зазвичай деякі рядки в версії "апісервера" відсутні в оригінальній версії. Це очікувано. Однак, якщо є рядки в оригінальному описі, яких немає в версії апісервера, то це може свідчити про проблему з вашими специфікаціями Podʼа.
Налагодження Контролерів Реплікацій
Контролери реплікацій досить прості. Вони можуть або створювати Podʼи, або не можуть. Якщо вони не можуть створювати Podʼи, будь ласка, зверніться до інструкцій вище, щоб налагодити ваші Podʼи.
Ви також можете використовувати kubectl describe rc ${CONTROLLER_NAME}
для вивчення подій, що стосуються контролера реплікацій.
Налагодження Serviceʼів
Serviceʼи забезпечують балансування навантаження між набором Podʼів. Є кілька загальних проблем, які можуть призвести до неправильної роботи Serviceʼів. Наступні інструкції допоможуть дослідити проблеми з Serviceʼами.
Спочатку перевірте, що для Service є точки доступу. Для кожного обʼєкта Service апісервер робить ресурс endpoints
доступним.
Ви можете переглянути цей ресурс за допомогою:
kubectl get endpoints ${SERVICE_NAME}
Переконайтеся, що точки доступу відповідають кількості Podʼів, які ви очікуєте бачити в складі вашого Service. Наприклад, якщо ваш Service для контейнера nginx має 3 репліки, ви очікуєте побачити три різних IP-адреси у точках доступу Serviceʼу.
Мій Service відсутні точки доступу
Якщо вам не вистачає точок доступу, спробуйте передивитись перелік Podʼів за допомогою міток, які використовує Service. Уявіть, що у вас є Service, де є такі мітки:
...
spec:
- selector:
name: nginx
type: frontend
Ви можете використовувати:
kubectl get pods --selector=name=nginx,type=frontend
щоб отримати перелік Podʼів, які відповідають цьому селектору. Перевірте, чи список відповідає Podʼам, які ви очікуєте бачити у вашому Service. Перевірте, чи containerPort
Podʼа відповідає targetPort
Serviceʼа.
Мережевий трафік не переспрямовується
Будь ласка, див. налагодження Service для отримання додаткової інформації.
Що далі
Якщо жоден із вищезазначених методів не розвʼязує вашу проблему, слідкуйте інструкціям у документі про налагодження Serviceʼу щоб переконатися, що ваш Service
працює, має Endpoints
, і ваші Pod
ʼи фактично обслуговуються; DNS працює, встановлені правила iptables, і kube-proxy поводиться відповідно.
Ви також можете відвідати документ про налагодження для отримання додаткової інформації.
2 - Налагодження Service
Досить часто виникає проблема в нових інсталяціях Kubernetes, коли Service не працює належним чином. Ви запустили свої Podʼи за допомогою Deployment (або іншого контролера робочих навантажень) і створили Service, але не отримуєте відповіді при спробі отримати до нього доступ. Цей документ, сподіваємось, допоможе вам зрозуміти, що йде не так.
Виконання команд у Podʼі
Для багатьох кроків ви захочете побачити, що бачить Pod, який працює в кластері. Найпростіший спосіб зробити це — запустити інтерактивний Pod busybox:
kubectl run -it --rm --restart=Never busybox --image=gcr.io/google-containers/busybox sh
Примітка:
Якщо ви не бачите командний рядок, спробуйте натиснути enter.Якщо у вас вже є Pod, який ви хочете використовувати для цього, ви можете виконати команду у ньому за допомогою:
kubectl exec <ІМ'Я-ПОДА> -c <ІМ'Я-КОНТЕЙНЕРА> -- <КОМАНДА>
Підготовка
Для цілей цього огляду запустімо кілька Podʼів. Оскільки ви, швидше за все, налагоджуєте власний Service, ви можете використати свої власні дані, або ви можете слідувати разом із нами та отримати інші дані.
kubectl create deployment hostnames --image=registry.k8s.io/serve_hostname
deployment.apps/hostnames created
Команди kubectl
будуть виводити тип та імʼя створеного або зміненого ресурсу, які потім можна використовувати в наступних командах.
Масштабуймо Deployment до 3 реплік.
kubectl scale deployment hostnames --replicas=3
deployment.apps/hostnames scaled
Зверніть увагу, що це так само, якби ви запустили Deployment за допомогою наступного YAML:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: hostnames
name: hostnames
spec:
selector:
matchLabels:
app: hostnames
replicas: 3
template:
metadata:
labels:
app: hostnames
spec:
containers:
- name: hostnames
image: registry.k8s.io/serve_hostname
За допомогою kubectl create deployment
в значення мітки "app" автоматично встановлюється імʼя Deployment.
Ви можете підтвердити, що ваші Podʼи працюють:
kubectl get pods -l app=hostnames
NAME READY STATUS RESTARTS AGE
hostnames-632524106-bbpiw 1/1 Running 0 2m
hostnames-632524106-ly40y 1/1 Running 0 2m
hostnames-632524106-tlaok 1/1 Running 0 2m
Ви також можете підтвердити, що ваші Podʼи обслуговуються. Ви можете отримати список IP-адрес Podʼів та протестувати їх безпосередньо.
kubectl get pods -l app=hostnames \
-o go-template='{{range .items}}{{.status.podIP}}{{"\n"}}{{end}}'
10.244.0.5
10.244.0.6
10.244.0.7
Приклад контейнера, використаного для цього огляду, обслуговує своє власне імʼя хосту через HTTP на порті 9376, але якщо ви налагоджуєте свій власний застосунок, вам потрібно буде використовувати номер порту, на якому слухають ваші Podʼи.
З середини Podʼа:
for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
wget -qO- $ep
done
Ви маєте отримати щось на зразок:
hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok
Якщо ви не отримуєте очікувані відповіді на цьому етапі, ваші Pod\и можуть бути несправними або можуть не прослуховувати порт, який ви вважаєте. Можливо, kubectl logs
буде корисним для перегляду того, що відбувається, або, можливо, вам потрібно буде виконати kubectl exec
безпосередньо у вашому Podʼі та робити налагодження звідти.
Якщо все пройшло згідно з планом до цього моменту, ви можете почати розслідування того, чому ваш Service не працює.
Чи Service існує?
Уважний читач може зауважити, що ви фактично ще не створили Service — це навмисно. Це крок, який іноді забувають, і це перше, що треба перевірити.
Що станеться, якщо ви спробуєте отримати доступ до Service, що не існує? Якщо у вас є інший Pod, який використовує цей Service за іменем, ви отримаєте щось на зразок:
wget -O- hostnames
Resolving hostnames (hostnames)... failed: Name or service not known.
wget: unable to resolve host address 'hostnames'
Перше, що треба перевірити — це чи насправді існує цей Service:
kubectl get svc hostnames
No resources found.
Error from server (NotFound): services "hostnames" not found
Створімо Service. Як і раніше, це для цього огляду — ви можете використовувати свої власні дані Service тут.
kubectl expose deployment hostnames --port=80 --target-port=9376
service/hostnames exposed
І перевіримо:
kubectl get svc hostnames
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames ClusterIP 10.0.1.175 <none> 80/TCP 5s
Тепер ви знаєте, що Service існує.
Як і раніше, це те саме, якби ви запустили Service за допомогою YAML:
apiVersion: v1
kind: Service
metadata:
labels:
app: hostnames
name: hostnames
spec:
selector:
app: hostnames
ports:
- name: default
protocol: TCP
port: 80
targetPort: 9376
Щоб підкреслити повний спектр налаштувань, Service, який ви створили тут, використовує інший номер порту, ніж Podʼи. Для багатьох реальних Serviceʼів ці значення можуть бути однаковими.
Чи впливають будь-які правила Network Policy Ingress на цільові Podʼи?
Якщо ви розгорнули будь-які правила Network Policy Ingress, які можуть вплинути на вхідний трафік до hostnames-*
Pod, їх потрібно переглянути.
Будь ласка, зверніться до Мережевих політик для отримання додаткових відомостей.
Чи працює Service за DNS-іменем?
Один із найпоширеніших способів, яким клієнти використовують Service, — це через DNS-імʼя.
З Podʼа в тому ж Namespace:
nslookup hostnames
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
Якщо це не вдається, можливо, ваш Pod і Service знаходяться в різних Namespace, спробуйте використати імʼя з Namespace (знову ж таки, зсередини Podʼа):
nslookup hostnames.default
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
Якщо це працює, вам потрібно налаштувати свій застосунок на використання імені, яке входить у Namespace, або запустіть ваш застосунок та Service в тому ж Namespace. Якщо це все ще не працює, спробуйте повне імʼя:
nslookup hostnames.default.svc.cluster.local
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default.svc.cluster.local
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
Зверніть увагу на суфікс тут: "default.svc.cluster.local". "default" — це Namespace, в якому ви працюєте. "svc" позначає, що це Service. "cluster.local" — це ваш домен кластера, який МОЖЕ відрізнятися у вашому власному кластері.
Ви також можете спробувати це з вузла в кластері:
Примітка:
10.0.0.10 - це IP-адреса Service DNS кластера, ваша може бути іншою.nslookup hostnames.default.svc.cluster.local 10.0.0.10
Server: 10.0.0.10
Address: 10.0.0.10#53
Name: hostnames.default.svc.cluster.local
Address: 10.0.1.175
Якщо ви можете зробити пошук повного імені, але не відноснлшл, вам потрібно перевірити, чи правильний ваш файл /etc/resolv.conf
в Podʼі. Зсередини Podʼа:
cat /etc/resolv.conf
Ви повинні побачити щось на зразок:
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local example.com
options ndots:5
Рядок nameserver
повинен вказувати на Service DNS вашого кластера. Це передається в kubelet
з прапорцем --cluster-dns
.
Рядок search
повинен включати відповідний суфікс, щоб ви змогли знайти імʼя Serviceʼу. У цьому випадку він шукає Serviceʼи в локальному Namespace ("default.svc.cluster.local"), Serviceʼи у всіх Namespace ("svc.cluster.local"), і наостанок для імен в кластері ("cluster.local"). Залежно від вашого власного налаштування, у вас можуть бути додаткові записи після цього (до 6 загалом). Суфікс кластера передається в kubelet
з прапорцем --cluster-domain
. У цьому документі передбачається, що суфікс кластера — "cluster.local". У ваших власних кластерах це може бути налаштовано по-іншому, у такому випадку вам слід змінити це в усіх попередніх командах.
Чи працює будь-який Service за допомогою DNS-імені?
Якщо вищезазначене все ще не працює, DNS-запити не працюють для вашого Service. Ви можете зробити крок назад і побачити, що ще не працює. Service майстра Kubernetes повинен завжди працювати. Зсередини Podʼа:
nslookup kubernetes.default
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes.default
Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local
Якщо це не вдається, будь ласка, перегляньте розділ kube-proxy цього документа, або навіть поверніться до початку цього документа і почніть знову, але замість налагодження вашого власного Service, спробуйте Service DNS.
Чи працює Service за IP?
Припускаючи, що ви підтвердили, що DNS працює, наступне, що варто перевірити, — це чи ваш Service працює за його IP-адресою. З Podʼа в вашому кластері, зверніться до IP-адреси Service (з вищезазначеного виводу kubectl get
).
for i in $(seq 1 3); do
wget -qO- 10.0.1.175:80
done
Це має видати щось подібне:
hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok
Якщо ваш Service працює, ви повинні отримати правильні відповіді. Якщо ні, існує кілька можливих причин, через які це може не працювати. Дивіться далі.
Чи правильно визначений Service?
Це може звучати дивно, але ви справді повинні подеколи перевірити, що ваш Service вірний і відповідає порту вашого Podʼа. Перегляньте свій Service і перевірте його:
kubectl get service hostnames -o json
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "hostnames",
"namespace": "default",
"uid": "428c8b6c-24bc-11e5-936d-42010af0a9bc",
"resourceVersion": "347189",
"creationTimestamp": "2015-07-07T15:24:29Z",
"labels": {
"app": "hostnames"
}
},
"spec": {
"ports": [
{
"name": "default",
"protocol": "TCP",
"port": 80,
"targetPort": 9376,
"nodePort": 0
}
],
"selector": {
"app": "hostnames"
},
"clusterIP": "10.0.1.175",
"type": "ClusterIP",
"sessionAffinity": "None"
},
"status": {
"loadBalancer": {}
}
}
- Чи вказано порт Serviceʼу, який ви намагаєтеся отримати доступ в
spec.ports[]
? - Чи правильний
targetPort
для ваших Podʼів (деякі Podʼи використовують інший порт, ніж Service)? - Якщо ви мали на увазі використання числового порту, це число (9376) чи рядок "9376"?
- Якщо ви мали на увазі використання порту за іменем, чи ваші Podʼи використовують порт з тим самим імʼям?
- Чи правильний протокол порту для ваших Podʼів?
Чи має Service будь-які Endpoints?
Якщо ви дійшли до цього пункту, ви підтвердили, що ваш Service правильно визначений і його можна знайти через DNS. Тепер перевірмо, що Podʼи, які ви запустили, фактично вибираються Serviceʼом.
Раніше ви бачили, що Podʼи працюють. Ви можете перевірити це ще раз:
kubectl get pods -l app=hostnames
NAME READY STATUS RESTARTS AGE
hostnames-632524106-bbpiw 1/1 Running 0 1h
hostnames-632524106-ly40y 1/1 Running 0 1h
hostnames-632524106-tlaok 1/1 Running 0 1h
Аргумент -l app=hostnames
— це селектор міток, налаштований у Service.
Стовпець "AGE" вказує, що ці Podʼи працюють добре і не мали збоїв.
Стовпець "RESTARTS" вказує, що ці Podʼи не часто мають збої або не перезавантажуються. Часті перезапуски можуть призвести до періодичних проблем зі зʼєднанням. Якщо кількість перезапусків висока, прочитайте більше про те, як налагоджувати Podʼи.
У межах системи Kubernetes є цикл керування, який оцінює селектор кожного Service і зберігає результати відповідно до обʼєкта Endpoints.
kubectl get endpoints hostnames
NAME ENDPOINTS
hostnames 10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376
Це підтверджує, що контролер Endpoints знайшов правильні Podʼи для вашого Service. Якщо стовпець ENDPOINTS
має значення <none>
, вам слід перевірити, що поле spec.selector
вашого Service дійсно вибирає значення metadata.labels
у ваших Podʼах. Частою помилкою є наявність хибодруку або іншої помилки, наприклад, Service вибирає app=hostnames
, але Deployment вказує run=hostnames
, як у версіях до 1.18, де команда kubectl run
також могла бути використана для створення Deployment.
Чи працюють Podʼи?
На цьому етапі ви знаєте, що ваш Service існує і вибрав ваші Podʼи. На початку цього кроку ви перевірили самі Podʼи. Давайте ще раз перевіримо, що Podʼи дійсно працюють — ви можете оминути механізм Service і звернутися безпосередньо до Podʼів, які вказані в Endpoints вище.
Примітка:
Ці команди використовують порт Podʼа (9376), а не порт Service (80).З середини Podʼа:
for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
wget -qO- $ep
done
Це повинно показати щось на зразок:
hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok
Ви очікуєте, що кожний Pod в списку Endpoints поверне свій власний hostname. Якщо це не те, що відбувається (або будь-яка інша правильна поведінка для ваших власних Podʼів), вам слід дослідити, що відбувається там.
Чи працює kube-proxy?
Якщо ви дісталися до цього моменту, ваш Service працює, має Endpoints, і ваші Podʼи фактично обслуговують запити. На цьому етапі увесь механізм проксі Service під підозрою. Підтвердьмо це крок за кроком.
Стандартна реалізація Service, і та, яка використовується в більшості кластерів, — це kube-proxy. Це програма, яка працює на кожному вузлі і конфігурує один з невеликого набору механізмів для надання абстракції Service. Якщо ваш кластер не використовує kube-proxy, наступні розділи не застосовуються, і вам доведеться дослідити будь-яку реалізацію Service, яку ви використовуєте.
Чи запущено kube-proxy?
Підтвердіть, що kube-proxy
працює на ваших Вузлах. Запустіть команду безпосередньо на Вузлі, і ви повинні побачити щось на зразок такого:
ps auxw | grep kube-proxy
root 4194 0.4 0.1 101864 17696 ? Sl Jul04 25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2
Далі переконайтесь, що він не має явних проблем, таких як неможливість звʼязатися з майстром. Для цього вам доведеться переглянути логи. Доступ до логів залежить від вашої ОС Вузла. На деяких ОС це файл, наприклад /var/log/kube-proxy.log, тоді як на інших ОС використовується journalctl
для доступу до логів. Ви повинні побачити щось на зразок:
I1027 22:14:53.995134 5063 server.go:200] Running in resource-only container "/kube-proxy"
I1027 22:14:53.998163 5063 server.go:247] Using iptables Proxier.
I1027 22:14:54.038140 5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns-tcp" to [10.244.1.3:53]
I1027 22:14:54.038164 5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns" to [10.244.1.3:53]
I1027 22:14:54.038209 5063 proxier.go:352] Setting endpoints for "default/kubernetes:https" to [10.240.0.2:443]
I1027 22:14:54.038238 5063 proxier.go:429] Not syncing iptables until Services and Endpoints have been received from master
I1027 22:14:54.040048 5063 proxier.go:294] Adding new service "default/kubernetes:https" at 10.0.0.1:443/TCP
I1027 22:14:54.040154 5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns" at 10.0.0.10:53/UDP
I1027 22:14:54.040223 5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns-tcp" at 10.0.0.10:53/TCP
Якщо ви бачите повідомлення про помилки щодо неможливості звʼязатися з майстром, вам слід перевірити конфігурацію і кроки інсталяції вашого Вузла.
Одна з можливих причин невдачі коректної роботи kube-proxy
— неможливість знайти необхідний бінарний файл conntrack
. Це може статися на деяких Linux-системах, залежно від того, як ви встановлюєте кластер, наприклад, якщо ви встановлюєте Kubernetes з нуля. У цьому випадку вам потрібно вручну встановити пакунок conntrack
(наприклад, sudo apt install conntrack
на Ubuntu), а потім спробувати ще раз.
Kube-proxy може працювати в одному з декількох режимів. У вищенаведеному журналі рядок Using iptables Proxier
вказує на те, що kube-proxy працює в режимі "iptables". Ще один поширений режим — "ipvs".
Режим iptables
У режимі "iptables" ви повинні побачити щось на зразок наступного на Вузлі:
iptables-save | grep hostnames
-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR
Для кожного порту кожного Service повинно бути 1 правило у KUBE-SERVICES
і один ланцюжок KUBE-SVC-<хеш>
. Для кожного endpoint Podʼа повинна бути невелика кількість правил у цьому KUBE-SVC-<хеш>
і один ланцюжок KUBE-SEP-<хеш>
з невеликою кількістю правил. Точні правила будуть варіюватися залежно від вашої конфігурації (включаючи порти вузлів та балансувальники навантаження).
Режим IPVS
У режимі "ipvs" ви повинні побачити щось на зразок наступного на Вузлі:
ipvsadm -ln
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
...
TCP 10.0.1.175:80 rr
-> 10.244.0.5:9376 Masq 1 0 0
-> 10.244.0.6:9376 Masq 1 0 0
-> 10.244.0.7:9376 Masq 1 0 0
...
Для кожного порту кожного Service, плюс будь-які NodePorts, зовнішні IP-адреси та IP-адреси балансувальника навантаження, kube-proxy створить віртуальний сервер. Для кожного endpoint Podʼа він створить відповідні реальні сервери. У цьому прикладі служба hostnames(10.0.1.175:80
) має 3 endpoint (10.244.0.5:9376
, 10.244.0.6:9376
, 10.244.0.7:9376
).
Чи kube-proxy керує трафіком?
Якщо ви бачите один із вищезазначених випадків, спробуйте ще раз отримати доступ до вашого Service за допомогою IP з одного з ваших Вузлів:
curl 10.0.1.175:80
hostnames-632524106-bbpiw
Якщо це все ще не вдається, перегляньте логи kube-proxy
на наявність конкретних рядків, подібних до:
Setting endpoints for default/hostnames:default to [10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376]
Якщо ви не бачите цього, спробуйте перезапустити kube-proxy
з прапорцем -v
, встановленим на 4, і потім знову перегляньте логи.
Крайній випадок: Pod не може звернутися до себе за допомогою IP-адреси Service
Це може здатися малоймовірним, але це може трапитися і має працювати.
Це може статися, коли мережа не належним чином налаштована для "зачісування" трафіку, зазвичай коли kube-proxy
працює в режимі iptables
, а Podʼи підключені за допомогою мережі bridge. Kubelet
надає прапорець hairpin-mode
, який дозволяє точкам доступу Service балансувати навантаження поверненням до себе, якщо вони намагаються отримати доступ до своєї власної VIP-адреси Service. Прапорець hairpin-mode
має бути встановлено на значення hairpin-veth
або promiscuous-bridge
.
Загальні кроки для розвʼязання цього випадку мають бути такими:
- Підтвердіть, що
hairpin-mode
встановлено у значенняhairpin-veth
абоpromiscuous-bridge
. Можливий вигляд нижченаведеного. У наступному прикладіhairpin-mode
встановлено наpromiscuous-bridge
.
ps auxw | grep kubelet
root 3392 1.1 0.8 186804 65208 ? Sl 00:51 11:11 /usr/local/bin/kubelet --enable-debugging-handlers=true --config=/etc/kubernetes/manifests --allow-privileged=True --v=4 --cluster-dns=10.0.0.10 --cluster-domain=cluster.local --configure-cbr0=true --cgroup-root=/ --system-cgroups=/system --hairpin-mode=promiscuous-bridge --runtime-cgroups=/docker-daemon --kubelet-cgroups=/kubelet --babysit-daemons=true --max-pods=110 --serialize-image-pulls=false --outofdisk-transition-frequency=0
- Підтвердіть поточний
hairpin-mode
. Для цього вам потрібно переглянути логиkubelet
. Доступ до логів залежить від вашої операційної системи. На деяких ОС це файл, наприклад /var/log/kubelet.log, тоді як на інших ОС використовуєтьсяjournalctl
для доступу до логів. Зверніть увагу, що поточний режим hairpin може не відповідати прапорцю--hairpin-mode
через сумісність. Перевірте, чи є будь-які рядки в лозі з ключовим словомhairpin
в kubelet.log. Повинні бути рядки в лозі, які показують поточний режим hairpin, схожі на наступне:
I0629 00:51:43.648698 3252 kubelet.go:380] Hairpin mode set to "promiscuous-bridge"
- Якщо поточний режим hairpin —
hairpin-veth
, переконайтеся, щоKubelet
має дозвіл на роботу в/sys
на вузлі. Якщо все працює належним чином, ви побачите щось на зразок:
for intf in /sys/devices/virtual/net/cbr0/brif/*; do cat $intf/hairpin_mode; done
1
1
1
1
- Якщо поточний режим hairpin —
promiscuous-bridge
, переконайтеся, щоKubelet
має дозвіл на маніпулювання bridge в Linux на вузлі. Якщо bridgecbr0
використовується і налаштований належним чином, ви побачите:
ifconfig cbr0 |grep PROMISC
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1460 Metric:1
- Зверніться за допомогою, якщо жоден з вищезазначених методів не працює.
Пошук допомоги
Якщо ви дійшли до цього моменту, відбувається щось дуже дивне. Ваш Service працює, має точки доступу, і ваші Podʼи насправді обслуговують запити. DNS працює, і kube-proxy
схоже не діє неправильно. Проте ваш Service не працює. Будь ласка, дайте нам знати, що відбувається, щоб ми могли допомогти вам розслідувати цю проблему!
Звертайтеся до нас у Slack або на Форум чи у GitHub.
Що далі
Відвідайте документ про загальні відомості про усунення несправностей для отримання додаткової інформації.
3 - Налагодження StatefulSet
Ця задача показує, як усувати несправності у StatefulSet.
Перш ніж ви розпочнете
- Вам потрібен кластер Kubernetes, та інструмент командного рядка kubectl повинен бути налаштований на звʼязок з вашим кластером.
- Ви повинні мати запущений StatefulSet, який ви хочете дослідити.
Усунення несправностей у StatefulSet
Для того, щоб переглянути всі Podʼи, які належать до StatefulSet і мають мітку app.kubernetes.io/name=MyApp
на них, ви можете використовувати наступне:
kubectl get pods -l app.kubernetes.io/name=MyApp
Якщо ви помітили, що будь-які Podʼи вказані у стані Unknown
або Terminating
протягом тривалого періоду часу, зверніться до завдання Видалення Podʼів StatefulSet за інструкціями щодо дії з ними. Ви можете усувати несправності окремих Podʼів у StatefulSet, використовуючи Посібник з усунення несправностей Podʼів.
Що далі
Дізнайтеся більше про усунення несправностей контейнера ініціалізації.
4 - Визначення причини збою Podʼа
Ця сторінка показує, як записувати та читати повідомлення про припинення роботи контейнера.
Повідомлення про припинення роботи надають можливість контейнерам записувати інформацію про фатальні події у місце, звідки її можна легко витягти та показувати за допомогою інструментів, таких як інформаційні панелі та програмне забезпечення моніторингу. У більшості випадків інформацію, яку ви вводите у повідомлення про припинення роботи, також слід записати в логи Kubernetes.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Запис та читання повідомлення про припинення роботи
У цьому завданні ви створюєте Pod, який запускає один контейнер. У маніфесті для цього Podʼа вказано команду, яка виконується при запуску контейнера:
apiVersion: v1
kind: Pod
metadata:
name: termination-demo
spec:
containers:
- name: termination-demo-container
image: debian
command: ["/bin/sh"]
args: ["-c", "sleep 10 && echo Sleep expired > /dev/termination-log"]
Створіть Pod на основі конфігураційного файлу YAML:
kubectl apply -f https://k8s.io/examples/debug/termination.yaml
У файлі YAML у полях
command
таargs
ви можете побачити, що контейнер перебуває в стані очікування (спить) протягом 10 секунд, а потім записує "Sleep expired" у файл/dev/termination-log
. Після того, як контейнер записує повідомлення "Sleep expired", він завершує роботу.Покажіть інформацію про Pod:
kubectl get pod termination-demo
Повторіть попередню команду, доки Pod більше не буде запущений.
Покажіть детальну інформацію про Pod:
kubectl get pod termination-demo --output=yaml
Вивід містить повідомлення "Sleep expired":
apiVersion: v1 kind: Pod ... lastState: terminated: containerID: ... exitCode: 0 finishedAt: ... message: | Sleep expired ...
Використовуйте шаблон Go для фільтрування виводу так, щоб він містив лише повідомлення про припинення роботи контейнера:
kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"
Якщо у вас працює багатоконтейнерний Pod, ви можете використовувати шаблон Go, щоб включити імʼя контейнера. Таким чином, ви можете визначити, який з контейнерів несправний:
kubectl get pod multi-container-pod -o go-template='{{range .status.containerStatuses}}{{printf "%s:\n%s\n\n" .name .lastState.terminated.message}}{{end}}'
Налаштування повідомлення про припинення роботи
Kubernetes отримує повідомлення про припинення роботи з файлу повідомлення, вказаного в полі terminationMessagePath
контейнера, яке має стандартне значення /dev/termination-log
. Налаштувавши це поле, ви можете сказати Kubernetes використовувати інший файл. Kubernetes використовує вміст зазначеного файлу для заповнення повідомлення про стан контейнера як у випадку успіху, так і невдачі.
Повідомлення про припинення має бути коротким остаточним статусом, таким як повідомлення про помилку твердження. Kubelet обрізає повідомлення, які довше 4096 байтів.
Загальна довжина повідомлення по всіх контейнерах обмежена 12KiB і рівномірно розподілена між всіма контейнерами. Наприклад, якщо є 12 контейнерів (initContainers
або containers
), кожен має 1024 байти доступного простору для повідомлень про припинення роботи.
Стандартний шлях для повідомлення про припинення роботи — /dev/termination-log
. Ви не можете встановити шлях повідомлення про припинення роботи після запуску Podʼа.
У наступному прикладі контейнер записує повідомлення про завершення в /tmp/my-log
для отримання Kubernetes:
apiVersion: v1
kind: Pod
metadata:
name: msg-path-demo
spec:
containers:
- name: msg-path-demo-container
image: debian
terminationMessagePath: "/tmp/my-log"
Крім того, користувачі можуть налаштувати поле terminationMessagePolicy
контейнера для подальшої настройки. Типово це поле встановлене на "File
", що означає, що повідомлення про припинення роботи отримуються лише з файлу повідомлення про припинення роботи. Встановивши terminationMessagePolicy
на "FallbackToLogsOnError
", ви можете вказати Kubernetes використовувати останній фрагмент виводу контейнера, якщо файл повідомлення про припинення роботи порожній, і контейнер завершився з помилкою. Вивід логу обмежується 2048 байтами або 80 рядками, якщо вибірка менша.
Що далі
- Перегляньте поле
terminationMessagePath
в Контейнері. - Перегляньте ImagePullBackOff в Образах.
- Дізнайтеся про отримання логів.
- Дізнайтеся про шаблони Go.
- Дізнайтеся про стани Pod та фази Pod.
- Дізнайтеся про стани контейнера.
5 - Налагодження контейнерів ініціалізації
Ця сторінка показує, як розвʼязувати проблеми, повʼязані з запуском контейнерів ініціалізації. Приклади команд нижче вказують на Pod як <pod-name>
та на контейнери ініціалізації як <init-container-1>
та <init-container-2>
.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Для перевірки версії введітьkubectl version
.- Ви повинні бути знайомі з основами контейнерів ініціалізації.
- Ви повинні Налаштувати контейнер ініціалізації.
Перевірка стану контейнерів ініціалізації
Показ статусу вашого Podʼа:
kubectl get pod <pod-name>
Наприклад, статус Init:1/2
вказує на те, що один з двох контейнерів ініціалізації успішно завершено:
NAME READY STATUS RESTARTS AGE
<pod-name> 0/1 Init:1/2 0 7s
Дивіться Розуміння статусів Podʼа для отримання прикладів значень статусу та їх значень.
Отримання деталей про контейнери ініціалізації
Показ більш детальної інформації про виконання контейнерів ініціалізації:
kubectl describe pod <pod-name>
Наприклад, Pod з двома контейнерами ініціалізації може показати наступне:
Init Containers:
<init-container-1>:
Container ID: ...
...
State: Terminated
Reason: Completed
Exit Code: 0
Started: ...
Finished: ...
Ready: True
Restart Count: 0
...
<init-container-2>:
Container ID: ...
...
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
Started: ...
Finished: ...
Ready: False
Restart Count: 3
...
Ви також можете отримувати доступ до статусів контейнерів ініціалізації програмно, читаючи поле status.initContainerStatuses
у Pod Spec:
kubectl get pod nginx --template '{{.status.initContainerStatuses}}'
Ця команда поверне ту саму інформацію, що і вище у форматі JSON.
Отримання логів з контейнерів ініціалізації
Вкажіть імʼя контейнера ініціалізації разом з імʼям Podʼа, щоб отримати його логи.
kubectl logs <pod-name> -c <init-container-2>
Контейнери ініціалізації, що виконують скрипт оболонки, друкують команди в міру їх виконання. Наприклад, це можна зробити в Bash, запустивши set -x
на початку скрипта.
Розуміння статусів Podʼа
Статус Podʼа, що починається з Init:
, узагальнює стан виконання контейнерів ініціалізації. У таблиці нижче наведено деякі приклади значень статусу, які ви можете бачити під час налагодження контейнерів ініціалізації.
Статус | Значення |
---|---|
Init:N/M | Pod має M контейнерів ініціалізації, і N вже завершено. |
Init:Error | Контейнер ініціалізації не вдалося виконати. |
Init:CrashLoopBackOff | Контейнер ініціалізації неперервно виходить з ладу. |
Pending | Pod ще не розпочав виконувати контейнер ініціалізації. |
PodInitializing або Running | Pod вже завершив виконання контейнерів ініціалізації. |
6 - Налагодження запущених Podʼів
Ця сторінка пояснює, як налагоджувати Podʼи, що запущені (або зазнають збою) на вузлі.
Перш ніж ви розпочнете
- Ваш Pod вже повинен бути запланований та запущений. Якщо ваш Pod ще не запущений, почніть з Налагодження Podʼів.
- Для деяких з розширених кроків налагодження вам потрібно знати, на якому вузлі запущений Pod, і мати доступ до оболонки для виконання команд на цьому вузлі. Вам не потрібен такий доступ для виконання стандартних кроків налагодження, що використовують
kubectl
.
Використання kubectl describe pod
для отримання деталей про Podʼи
Для цього прикладу ми використовуватимемо Deployment для створення двох Podʼів, схожих на попередній приклад.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
Створіть Deployment, запустивши наступну команду:
kubectl apply -f https://k8s.io/examples/application/nginx-with-request.yaml
deployment.apps/nginx-deployment created
Перевірте статус Podʼа за допомогою наступної команди:
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-67d4bdd6f5-cx2nz 1/1 Running 0 13s
nginx-deployment-67d4bdd6f5-w6kd7 1/1 Running 0 13s
Ми можемо отримати більше інформації про кожен з цих Podʼів, використовуючи kubectl describe pod
. Наприклад:
kubectl describe pod nginx-deployment-67d4bdd6f5-w6kd7
Name: nginx-deployment-67d4bdd6f5-w6kd7
Namespace: default
Priority: 0
Node: kube-worker-1/192.168.0.113
Start Time: Thu, 17 Feb 2022 16:51:01 -0500
Labels: app=nginx
pod-template-hash=67d4bdd6f5
Annotations: <none>
Status: Running
IP: 10.88.0.3
IPs:
IP: 10.88.0.3
IP: 2001:db8::1
Controlled By: ReplicaSet/nginx-deployment-67d4bdd6f5
Containers:
nginx:
Container ID: containerd://5403af59a2b46ee5a23fb0ae4b1e077f7ca5c5fb7af16e1ab21c00e0e616462a
Image: nginx
Image ID: docker.io/library/nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 17 Feb 2022 16:51:05 -0500
Ready: True
Restart Count: 0
Limits:
cpu: 500m
memory: 128Mi
Requests:
cpu: 500m
memory: 128Mi
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-bgsgp (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-bgsgp:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: Guaranteed
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 34s default-scheduler Successfully assigned default/nginx-deployment-67d4bdd6f5-w6kd7 to kube-worker-1
Normal Pulling 31s kubelet Pulling image "nginx"
Normal Pulled 30s kubelet Successfully pulled image "nginx" in 1.146417389s
Normal Created 30s kubelet Created container nginx
Normal Started 30s kubelet Started container nginx
Тут ви можете побачити інформацію про конфігурацію контейнерів та Podʼа (мітки, вимоги до ресурсів і т. д.), а також інформацію про статус контейнерів та Podʼа (стан, готовність, кількість перезапусків, події й т.д.).
Стан контейнера може бути Waiting (очікування), Running (виконання) або Terminated (завершено). Залежно від стану, буде надано додаткову інформацію — наприклад, ви можете побачити, коли контейнер був запущений, якщо він перебуває в стані Running.
Ready показує, чи пройшов контейнер останню пробу готовності. (У цьому випадку контейнер не має налаштованої проби готовності; вважається, що контейнер готовий, якщо проба готовності не налаштована.)
Restart Count показує, скільки разів контейнер був перезапущений; ця інформація може бути корисною для виявлення циклів аварійного перезапуску в контейнерах, які налаштовані на перезапуск завжди ('always').
Наразі єдина умова, повʼязана з Podʼом, — це бінарна умова Ready, яка вказує, що Pod може обслуговувати запити та повинен бути доданий до пулів балансування навантаження всіх відповідних Serviceʼів.
Нарешті, ви бачите логи недавніх подій, що стосуються вашого Podʼа. "From" вказує на компонент, який реєструє подію. "Reason" та "Message" розповідають вам, що сталося.
Приклад: налагодження Podʼів у стані Pending
Одна з поширених ситуацій, яку ви можете виявити за допомогою подій, — це коли ви створили Pod, який не може бути розміщений на жодному вузлі. Наприклад, Pod може вимагати більше ресурсів, ніж вільно на будь-якому вузлі, або він може вказати селектор міток, який не відповідає жодному вузлу. Скажімо, ми створили Deployment з 5 репліками (замість 2) і вимагаємо 600 міліядер замість 500, на чотирьох вузловому кластері, де кожна (віртуальна) машина має 1 ЦП. У цьому випадку один з Podʼів не зможе бути запланованим. (Зауважте, що через надбудови кластера, такі як fluentd, skydns тощо, які працюють на кожному вузлі, якби ми запросили 1000 міліядер, то жоден з Podʼів не міг би бути запланованим.)
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-1006230814-6winp 1/1 Running 0 7m
nginx-deployment-1006230814-fmgu3 1/1 Running 0 7m
nginx-deployment-1370807587-6ekbw 1/1 Running 0 1m
nginx-deployment-1370807587-fg172 0/1 Pending 0 1m
nginx-deployment-1370807587-fz9sd 0/1 Pending 0 1m
Щоб дізнатися, чому Pod nginx-deployment-1370807587-fz9sd не працює, ми можемо використовувати kubectl describe pod
у Podʼі у стані Pending та переглянути його події:
kubectl describe pod nginx-deployment-1370807587-fz9sd
Name: nginx-deployment-1370807587-fz9sd
Namespace: default
Node: /
Labels: app=nginx,pod-template-hash=1370807587
Status: Pending
IP:
Controllers: ReplicaSet/nginx-deployment-1370807587
Containers:
nginx:
Image: nginx
Port: 80/TCP
QoS Tier:
memory: Guaranteed
cpu: Guaranteed
Limits:
cpu: 1
memory: 128Mi
Requests:
cpu: 1
memory: 128Mi
Environment Variables:
Volumes:
default-token-4bcbi:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-4bcbi
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 48s 7 {default-scheduler } Warning FailedScheduling pod (nginx-deployment-1370807587-fz9sd) failed to fit in any node
fit failure on node (kubernetes-node-6ta5): Node didn't have enough resource: CPU, requested: 1000, used: 1420, capacity: 2000
fit failure on node (kubernetes-node-wul5): Node didn't have enough resource: CPU, requested: 1000, used: 1100, capacity: 2000
Тут ви можете побачити подію, створену планувальником, яка говорить, що Pod не вдалося запланувати з причиною FailedScheduling
(і, можливо, інші). Повідомлення говорить нам, що на будь-якому з вузлів не було достатньо ресурсів для Podʼа.
Для виправлення цієї ситуації ви можете використовувати kubectl scale
, щоб оновити ваш Deployment та вказати чотири або менше реплік. (Або ви можете залишити один Pod у стані Pending, що нешкідливо.)
Події, такі як ті, які ви бачили в кінці kubectl describe pod
, зберігаються в etcd та надають високорівневу інформацію про те, що відбувається в кластері. Щоб переглянути всі події, ви можете використовувати
kubectl get events
але вам потрібно памʼятати, що події належать до простору імен. Це означає, що якщо вас цікавлять події для обʼєкта з простором імен (наприклад, що сталося з Podʼами в просторі імен my-namespace
), вам потрібно явно вказати простір імен для команди:
kubectl get events --namespace=my-namespace
Щоб побачити події з усіх просторів імен, ви можете використовувати аргумент --all-namespaces
.
Крім команди kubectl describe pod
, інший спосіб отримати додаткову інформацію про Pod (поза тим, що надає kubectl get pod
) — це передати прапорець формату виводу -o yaml
команді kubectl get pod
. Це надасть вам, у форматі YAML, ще більше інформації, ніж kubectl describe pod
— фактично всю інформацію, яку система має про Pod. Тут ви побачите такі речі, як анотації (це метадані ключ-значення без обмежень міток, які використовуються внутрішньо компонентами системи Kubernetes), політику перезапуску, порти та томи.
kubectl get pod nginx-deployment-1006230814-6winp -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2022-02-17T21:51:01Z"
generateName: nginx-deployment-67d4bdd6f5-
labels:
app: nginx
pod-template-hash: 67d4bdd6f5
name: nginx-deployment-67d4bdd6f5-w6kd7
namespace: default
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-deployment-67d4bdd6f5
uid: 7d41dfd4-84c0-4be4-88ab-cedbe626ad82
resourceVersion: "1364"
uid: a6501da1-0447-4262-98eb-c03d4002222e
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
protocol: TCP
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 500m
memory: 128Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-bgsgp
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: kube-worker-1
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: kube-api-access-bgsgp
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2022-02-17T21:51:01Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2022-02-17T21:51:06Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2022-02-17T21:51:06Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2022-02-17T21:51:01Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: containerd://5403af59a2b46ee5a23fb0ae4b1e077f7ca5c5fb7af16e1ab21c00e0e616462a
image: docker.io/library/nginx:latest
imageID: docker.io/library/nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
lastState: {}
name: nginx
ready: true
restartCount: 0
started: true
state:
running:
startedAt: "2022-02-17T21:51:05Z"
hostIP: 192.168.0.113
phase: Running
podIP: 10.88.0.3
podIPs:
- ip: 10.88.0.3
- ip: 2001:db8::1
qosClass: Guaranteed
startTime: "2022-02-17T21:51:01Z"
Перегляд логі Podʼа
Спочатку перегляньте журнали ураженого контейнера:
kubectl logs ${POD_NAME} ${CONTAINER_NAME}
Якщо ваш контейнер раніше впав, ви можете отримати доступ до попереднього логу аварії контейнера за допомогою:
kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}
Налагодження за допомогою виконання команд у контейнері
Якщо образ контейнера містить утиліти для налагодження, як це трапляється в образах, побудованих на основі базових образів операційних систем Linux і Windows, ви можете виконати команди всередині конкретного контейнера за допомогою kubectl exec
:
kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}
Примітка:
-c ${CONTAINER_NAME}
є необовʼязковим. Ви можете опустити його для Podʼів, які містять лише один контейнер.Наприклад, щоб переглянути логи з робочого Podʼа Cassandra, ви можете виконати
kubectl exec cassandra -- cat /var/log/cassandra/system.log
Ви можете запустити оболонку, яка підключена до вашого термінала, використовуючи аргументи -i
і -t
для kubectl exec
, наприклад:
kubectl exec -it cassandra -- sh
Для отримання додаткових відомостей дивіться Отримання оболонки до запущеного контейнера.
Налагодження за допомогою ефемерного контейнера
Kubernetes v1.25 [stable]
Ефемерні контейнери корисні для інтерактивного усунення несправностей, коли kubectl exec
недостатній через аварію контейнера або те, що образ контейнера не містить утиліт для налагодження, наприклад, в образах distroless.
Приклад налагодження за допомогою ефемерних контейнерів
Ви можете використовувати команду kubectl debug
, щоб додати ефемерні контейнери до запущеного Podʼа. Спочатку створіть Pod для прикладу:
kubectl run ephemeral-demo --image=registry.k8s.io/pause:3.1 --restart=Never
У цьому розділі приклади використовують образ контейнера pause
, оскільки він не містить утиліт для налагодження, але цей метод працює з будь-якими образом контейнера.
Якщо ви спробуєте використати kubectl exec
для створення оболонки, ви побачите помилку, оскільки в цьому образі контейнера немає оболонки.
kubectl exec -it ephemeral-demo -- sh
OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown
Замість цього ви можете додати контейнер для налагодження за допомогою kubectl debug
. Якщо ви вказуєте аргумент -i
/--interactive
, kubectl
автоматично приєднується до консолі ефемерного контейнера.
kubectl debug -it ephemeral-demo --image=busybox:1.28 --target=ephemeral-demo
Defaulting debug container name to debugger-8xzrl.
If you don't see a command prompt, try pressing enter.
/ #
Ця команда додає новий контейнер busybox і приєднується до нього. Параметр --target
спрямовує простір імен процесу до іншого контейнера. Це необхідно тут, оскільки kubectl run
не ввімкнув процес спільного використання простору імен у Pod, який він створює.
Примітка:
Параметр--target
повинен підтримуватись середовищем виконання контейнерів. Якщо не підтримується, то ефемерний контейнер не може бути запущений, або він може бути запущений з ізольованим простором імен процесу, так що команда ps
не відображатиме процеси в інших контейнерах.Ви можете переглянути стан нового ефемерного контейнера, використовуючи kubectl describe
:
kubectl describe pod ephemeral-demo
...
Ephemeral Containers:
debugger-8xzrl:
Container ID: docker://b888f9adfd15bd5739fefaa39e1df4dd3c617b9902082b1cfdc29c4028ffb2eb
Image: busybox
Image ID: docker-pullable://busybox@sha256:1828edd60c5efd34b2bf5dd3282ec0cc04d47b2ff9caa0b6d4f07a21d1c08084
Port: <none>
Host Port: <none>
State: Running
Started: Wed, 12 Feb 2020 14:25:42 +0100
Ready: False
Restart Count: 0
Environment: <none>
Mounts: <none>
...
Використовуйте kubectl delete
, щоб видалити Pod, коли ви закінчите:
kubectl delete pod ephemeral-demo
Налагодження за допомогою копії Podʼа
Іноді параметри конфігурації Podʼа ускладнюють усунення несправностей у певних ситуаціях. Наприклад, ви не можете виконувати kubectl exec
, щоб усунути несправності у вашому контейнері, якщо ваш образ контейнера не містить оболонки або якщо ваш застосунок аварійно завершується при запуску. У цих ситуаціях ви можете використовувати kubectl debug
, щоб створити копію Podʼа зі зміненими значеннями конфігурації для полегшення налагодження.
Копіювання Podʼа з додаванням нового контейнера
Додавання нового контейнера може бути корисним, коли ваш застосунок працює, але не так, як ви очікували, і ви хочете додати додаткові засоби усунення несправностей до Podʼа.
Наприклад, можливо, образ контейнера вашого застосунку збудований на основі busybox
, але вам потрібні засоби для налагодження, які не включені в busybox
. Ви можете симулювати цей сценарій за допомогою kubectl run
:
kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d
Виконайте цю команду, щоб створити копію myapp
з назвою myapp-debug
, яка додає новий контейнер Ubuntu для налагодження:
kubectl debug myapp -it --image=ubuntu --share-processes --copy-to=myapp-debug
Defaulting debug container name to debugger-w7xmf.
If you don't see a command prompt, try pressing enter.
root@myapp-debug:/#
Примітка:
kubectl debug
автоматично генерує назву контейнера, якщо ви не вибрали одну за допомогою прапорця--container
.- Прапорець
-i
стандартно призводить до приєднанняkubectl debug
до нового контейнера. Ви можете запобігти цьому, вказавши--attach=false
. Якщо ваша сесія розірвана, ви можете повторно приєднатися за допомогоюkubectl attach
. --share-processes
дозволяє контейнерам в цьому Podʼі бачити процеси з інших контейнерів у Podʼі. Для отримання додаткової інформації про те, як це працює, див. Спільне використання простору імен процесу між контейнерами в Podʼі.
Не забудьте прибрати Pod для налагодження, коли ви закінчите:
kubectl delete pod myapp myapp-debug
Копіювання Podʼа зі зміною його команди
Іноді корисно змінити команду для контейнера, наприклад, щоб додати прапорець для налагодження або через те, що застосунок аварійно завершується.
Щоб симулювати аварійне завершення застосунку, використайте kubectl run
, щоб створити контейнер, який негайно завершується:
kubectl run --image=busybox:1.28 myapp -- false
Ви можете побачити за допомогою kubectl describe pod myapp
, що цей контейнер аварійно завершується:
Containers:
myapp:
Image: busybox
...
Args:
false
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
Ви можете використовувати kubectl debug
, щоб створити копію цього Podʼа з командою зміненою на інтерактивну оболонку:
kubectl debug myapp -it --copy-to=myapp-debug --container=myapp -- sh
If you don't see a command prompt, try pressing enter.
/ #
Тепер у вас є інтерактивна оболонка, яку ви можете використовувати для виконання завдань, таких як перевірка шляхів файлової системи або виконання команди контейнера вручну.
Примітка:
- Щоб змінити команду для конкретного контейнера, вам потрібно вказати його назву за допомогою
--container
, інакшеkubectl debug
створить новий контейнер для виконання вказаної вами команди. - Прапорець
-i
призводить до того, щоkubectl debug
автоматично приєднується до контейнера. Ви можете це запобігти, вказавши--attach=false
. Якщо ваша сесія розірвана, ви можете повторно приєднатися за допомогоюkubectl attach
.
Не забудьте прибрати Pod для налагодження, коли ви закінчите:
kubectl delete pod myapp myapp-debug
Копіювання Podʼа з заміною образів контейнерів
Іноді вам може знадобитися змінити образ Podʼа, який поводитися неналежним чином, зі звичайного образу, що використовується в операційній діяльності, на образ, що містить збірку для налагодження або додаткові утиліти.
Наприклад, створіть Pod за допомогою kubectl run
:
kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d
Тепер використовуйте kubectl debug
, щоб створити копію та змінити його образ контейнера на ubuntu
:
kubectl debug myapp --copy-to=myapp-debug --set-image=*=ubuntu
Синтаксис --set-image
використовує ту ж синтаксис container_name=image
, що й kubectl set image
. *=ubuntu
означає зміну образу всіх контейнерів на ubuntu
.
Не забудьте прибрати Pod для налагодження, коли ви закінчите:
kubectl delete pod myapp myapp-debug
Налагодження через оболонку на вузлі
Якщо жоден з цих підходів не працює, ви можете знайти вузол, на якому працює Pod, і створити Pod, який буде виконуватися на цьому вузлі. Щоб створити інтерактивну оболонку на вузлі за допомогою kubectl debug
, виконайте:
kubectl debug node/mynode -it --image=ubuntu
Creating debugging pod node-debugger-mynode-pdx84 with container debugger on node mynode.
If you don't see a command prompt, try pressing enter.
root@ek8s:/#
При створенні сесії налагодження на вузлі майте на увазі, що:
kubectl debug
автоматично генерує назву нового Podʼа на основі назви вузла.- Коренева файлова система вузла буде змонтована в
/host
. - Контейнер працює у просторах імен IPC, мережі та PID вузла, хоча Pod не є привілейованим, тому читання деякої інформації про процеси може не вдатися, і
chroot /host
може не спрацювати. - Якщо вам потрібен привілейований Pod, створіть його вручну або використовуйте прапорець
--profile=sysadmin
Не забудьте прибрати Pod для налагодження, коли ви закінчите з ним:
kubectl delete pod node-debugger-mynode-pdx84
Профілі налагодження
Коли ви використовуєте kubectl debug
для налагодження вузла за допомогою Podʼа налагодження, Pod за ефемерним контейнером або скопійованого Pod, ви можете застосувати до них профіль налагодження за допомогою прапорця --profile
. Застосовуючи профіль, встановлюються конкретні властивості, такі як securityContext, що дозволяє адаптуватися до різних сценаріїв.
Доступні наступні профілі:
Профіль | Опис |
---|---|
legacy | Набір властивостей для зворотної сумісності з поведінкою 1.22 |
general | Розумний набір загальних властивостей для кожного завдання налагодження |
baseline | Набір властивостей, сумісних з Політикою базової безпеки PodSecurityStandard |
restricted | Набір властивостей, сумісних з Політикою обмеженої безпеки PodSecurityStandard |
netadmin | Набір властивостей, включаючи привілеї адміністратора мережі |
sysadmin | Набір властивостей, включаючи привілеї системного адміністратора (root) |
Примітка:
Якщо ви не вкажете--profile
, стандартно використовується профіль legacy
, але його планується найближчим часом визнати застарілим. Тому рекомендується використовувати інші профілі, такі як general
.Припустимо, що ви створюєте Pod і налагоджуєте його. Спочатку створіть Pod з назвою myapp
, наприклад:
kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d
Потім, перевірте Pod за допомогою ефемерного контейнера. Якщо ефемерному контейнеру потрібно мати привілеї, ви можете використовувати профіль sysadmin
:
kubectl debug -it myapp --image=busybox:1.28 --target=myapp --profile=sysadmin
Targeting container "myapp". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
Defaulting debug container name to debugger-6kg4x.
If you don't see a command prompt, try pressing enter.
/ #
Перевірте можливості процесу ефемерного контейнера, виконавши наступну команду всередині контейнера:
/ # grep Cap /proc/$$/status
...
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
...
Це означає, що процес контейнера наділений усіма можливостями як привілейований контейнер завдяки застосуванню профілю sysadmin
. Дивіться більше деталей про можливості.
Ви також можете перевірити, що ефемерний контейнер був створений як привілейований контейнер:
kubectl get pod myapp -o jsonpath='{.spec.ephemeralContainers[0].securityContext}'
{"privileged":true}
Очистіть Pod, коли ви закінчите з ним:
kubectl delete pod myapp
7 - Отримання доступу до оболонки запущеного контейнера
Ця сторінка показує, як використовувати kubectl exec
для отримання доступу до оболонки запущеного контейнера.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Отримання доступу до оболонки контейнера
У цьому завданні ви створите Pod, який має один контейнер. Контейнер виконує образ nginx. Ось файл конфігурації для Podʼа:
apiVersion: v1
kind: Pod
metadata:
name: shell-demo
spec:
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: nginx
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
hostNetwork: true
dnsPolicy: Default
Створіть Pod:
kubectl apply -f https://k8s.io/examples/application/shell-demo.yaml
Перевірте, що контейнер працює:
kubectl get pod shell-demo
Отримайте доступ до оболонки запущеного контейнера:
kubectl exec --stdin --tty shell-demo -- /bin/bash
Примітка:
Подвійне тире (--
) відокремлює аргументи, які ви хочете передати команді, від аргументів kubectl.У своїй оболонці виведіть список кореневої теки:
# Виконайте це всередині контейнера
ls /
У своїй оболонці експериментуйте з іншими командами. Ось деякі приклади:
# Ви можете виконати ці приклади команд всередині контейнера
ls /
cat /proc/mounts
cat /proc/1/maps
apt-get update
apt-get install -y tcpdump
tcpdump
apt-get install -y lsof
lsof
apt-get install -y procps
ps aux
ps aux | grep nginx
Редагування головної сторінки nginx
Знову перегляньте файл конфігурації вашого Podʼа. Pod має том emptyDir
, і контейнер монтує цей том в /usr/share/nginx/html
.
У своїй оболонці створіть файл index.html
у теці /usr/share/nginx/html
:
# Виконайте це всередині контейнера
echo 'Hello shell demo' > /usr/share/nginx/html/index.html
У своїй оболонці надішліть GET-запит до сервера nginx:
# Виконайте це в оболонці всередині вашого контейнера
apt-get update
apt-get install curl
curl http://localhost/
Результат покаже текст, який ви написали в файл index.html
:
Hello shell demo
Коли ви закінчите з вашою оболонкою, введіть exit
.
exit # Щоб вийти з оболонки в контейнері
Виконання окремих команд в контейнері
У звичайному вікні команд виведіть змінні оточення в запущеному контейнері:
kubectl exec shell-demo -- env
Експериментуйте з виконанням інших команд. Ось деякі приклади:
kubectl exec shell-demo -- ps aux
kubectl exec shell-demo -- ls /
kubectl exec shell-demo -- cat /proc/1/mounts
Відкриття оболонки, коли в Podʼі є більше одного контейнера
Якщо в Podʼі є більше одного контейнера, використовуйте --container
або -c
для зазначення контейнера в команді kubectl exec
. Наприклад, припустимо, у вас є Pod на ім’я my-pod, і в Podʼі є два контейнери з іменами main-app та helper-app. Наступна команда відкриє оболонку до контейнера main-app.
kubectl exec -i -t my-pod --container main-app -- /bin/bash
Примітка:
Короткі опції-i
і -t
такі ж, як довгі опції --stdin
і --tty
Що далі
- Прочитайте про kubectl exec