Convert site to Hugo (#8316)
This commit converts content and layout to use Hugo.
This commit is contained in:
committed by
k8s-ci-robot
parent
7745f0e0c5
commit
7f3b633aa0
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Monitor, Log, and Debug"
|
||||
weight: 80
|
||||
---
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
apiVersion: audit.k8s.io/v1beta1 # This is required.
|
||||
kind: Policy
|
||||
# Don't generate audit events for all requests in RequestReceived stage.
|
||||
omitStages:
|
||||
- "RequestReceived"
|
||||
rules:
|
||||
# Log pod changes at RequestResponse level
|
||||
- level: RequestResponse
|
||||
resources:
|
||||
- group: ""
|
||||
# Resource "pods" doesn't match requests to any subresource of pods,
|
||||
# which is consistent with the RBAC policy.
|
||||
resources: ["pods"]
|
||||
# Log "pods/log", "pods/status" at Metadata level
|
||||
- level: Metadata
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["pods/log", "pods/status"]
|
||||
|
||||
# Don't log requests to a configmap called "controller-leader"
|
||||
- level: None
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["configmaps"]
|
||||
resourceNames: ["controller-leader"]
|
||||
|
||||
# Don't log watch requests by the "system:kube-proxy" on endpoints or services
|
||||
- level: None
|
||||
users: ["system:kube-proxy"]
|
||||
verbs: ["watch"]
|
||||
resources:
|
||||
- group: "" # core API group
|
||||
resources: ["endpoints", "services"]
|
||||
|
||||
# Don't log authenticated requests to certain non-resource URL paths.
|
||||
- level: None
|
||||
userGroups: ["system:authenticated"]
|
||||
nonResourceURLs:
|
||||
- "/api*" # Wildcard matching.
|
||||
- "/version"
|
||||
|
||||
# Log the request body of configmap changes in kube-system.
|
||||
- level: Request
|
||||
resources:
|
||||
- group: "" # core API group
|
||||
resources: ["configmaps"]
|
||||
# This rule only applies to resources in the "kube-system" namespace.
|
||||
# The empty string "" can be used to select non-namespaced resources.
|
||||
namespaces: ["kube-system"]
|
||||
|
||||
# Log configmap and secret changes in all other namespaces at the Metadata level.
|
||||
- level: Metadata
|
||||
resources:
|
||||
- group: "" # core API group
|
||||
resources: ["secrets", "configmaps"]
|
||||
|
||||
# Log all other resources in core and extensions at the Request level.
|
||||
- level: Request
|
||||
resources:
|
||||
- group: "" # core API group
|
||||
- group: "extensions" # Version of group should NOT be included.
|
||||
|
||||
# A catch-all rule to log all other requests at the Metadata level.
|
||||
- level: Metadata
|
||||
# Long-running requests like watches that fall under this rule will not
|
||||
# generate an audit event in RequestReceived.
|
||||
omitStages:
|
||||
- "RequestReceived"
|
||||
@@ -0,0 +1,394 @@
|
||||
---
|
||||
reviewers:
|
||||
- soltysh
|
||||
- sttts
|
||||
- ericchiang
|
||||
title: Auditing
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
{{< feature-state state="beta" >}}
|
||||
|
||||
Kubernetes auditing provides a security-relevant chronological set of records documenting
|
||||
the sequence of activities that have affected system by individual users, administrators
|
||||
or other components of the system. It allows cluster administrator to
|
||||
answer the following questions:
|
||||
|
||||
- what happened?
|
||||
- when did it happen?
|
||||
- who initiated it?
|
||||
- on what did it happen?
|
||||
- where was it observed?
|
||||
- from where was it initiated?
|
||||
- to where was it going?
|
||||
|
||||
[Kube-apiserver][kube-apiserver] performs auditing. Each request on each stage
|
||||
of its execution generates an event, which is then pre-processed according to
|
||||
a certain policy and written to a backend. The policy determines what's recorded
|
||||
and the backends persist the records. The current backend implementations
|
||||
include logs files and webhooks.
|
||||
|
||||
Each request can be recorded with an associated "stage". The known stages are:
|
||||
|
||||
- `RequestReceived` - The stage for events generated as soon as the audit
|
||||
handler receives the request, and before it is delegated down the handler
|
||||
chain.
|
||||
- `ResponseStarted` - Once the response headers are sent, but before the
|
||||
response body is sent. This stage is only generated for long-running requests
|
||||
(e.g. watch).
|
||||
- `ResponseComplete` - The response body has been completed and no more bytes
|
||||
will be sent.
|
||||
- `Panic` - Events generated when a panic occurred.
|
||||
|
||||
{{< note >}}
|
||||
**Note** The audit logging feature increases the memory consumption of the API
|
||||
server because some context required for auditing is stored for each request.
|
||||
Additionally, memory consumption depends on the audit logging configuration.
|
||||
{{< /note >}}
|
||||
|
||||
## Audit Policy
|
||||
|
||||
Audit policy defines rules about what events should be recorded and what data
|
||||
they should include. The audit policy object structure is defined in the
|
||||
[`audit.k8s.io` API group][auditing-api]. When an event is processed, it's
|
||||
compared against the list of rules in order. The first matching rule sets the
|
||||
"audit level" of the event. The known audit levels are:
|
||||
|
||||
- `None` - don't log events that match this rule.
|
||||
- `Metadata` - log request metadata (requesting user, timestamp, resource,
|
||||
verb, etc.) but not request or response body.
|
||||
- `Request` - log event metadata and request body but not response body.
|
||||
This does not apply for non-resource requests.
|
||||
- `RequestResponse` - log event metadata, request and response bodies.
|
||||
This does not apply for non-resource requests.
|
||||
|
||||
You can pass a file with the policy to [kube-apiserver][kube-apiserver]
|
||||
using the `--audit-policy-file` flag. If the flag is omitted, no events are logged.
|
||||
Note that the `rules` field __must__ be provided in the audit policy file.
|
||||
A policy with no (0) rules is treated as illegal.
|
||||
|
||||
Below is an example audit policy file:
|
||||
|
||||
{{< code file="audit-policy.yaml" >}}
|
||||
|
||||
You can use a minimal audit policy file to log all requests at the `Metadata` level:
|
||||
|
||||
```yaml
|
||||
# Log all requests at the Metadata level.
|
||||
apiVersion: audit.k8s.io/v1beta1
|
||||
kind: Policy
|
||||
rules:
|
||||
- level: Metadata
|
||||
```
|
||||
|
||||
The [audit profile used by GCE][gce-audit-profile] should be used as reference by
|
||||
admins constructing their own audit profiles.
|
||||
|
||||
## Audit backends
|
||||
|
||||
Audit backends persist audit events to an external storage.
|
||||
[Kube-apiserver][kube-apiserver] out of the box provides two backends:
|
||||
|
||||
- Log backend, which writes events to a disk
|
||||
- Webhook backend, which sends events to an external API
|
||||
|
||||
In both cases, audit events structure is defined by the API in the
|
||||
`audit.k8s.io` API group. The current version of the API is
|
||||
[`v1beta1`][auditing-api].
|
||||
|
||||
**Note:** In case of patches, request body is a JSON array with patch operations, not a JSON object
|
||||
with an appropriate Kubernetes API object. For example, the following request body is a valid patch
|
||||
request to `/apis/batch/v1/namespaces/some-namespace/jobs/some-job-name`.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/spec/parallelism",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"op": "remove",
|
||||
"path": "/spec/template/spec/containers/0/terminationMessagePolicy"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Log backend
|
||||
|
||||
Log backend writes audit events to a file in JSON format. You can configure
|
||||
log audit backend using the following [kube-apiserver][kube-apiserver] flags:
|
||||
|
||||
- `--audit-log-path` specifies the log file path that log backend uses to write
|
||||
audit events. Not specifying this flag disables log backend. `-` means standard out
|
||||
- `--audit-log-maxage` defined the maximum number of days to retain old audit log files
|
||||
- `--audit-log-maxbackup` defines the maximum number of audit log files to retain
|
||||
- `--audit-log-maxsize` defines the maximum size in megabytes of the audit log file before it gets rotated
|
||||
|
||||
### Webhook backend
|
||||
|
||||
Webhook backend sends audit events to a remote API, which is assumed to be the
|
||||
same API as [kube-apiserver][kube-apiserver] exposes. You can configure webhook
|
||||
audit backend using the following kube-apiserver flags:
|
||||
|
||||
- `--audit-webhook-config-file` specifies the path to a file with a webhook
|
||||
configuration. Webhook configuration is effectively a [kubeconfig][kubeconfig].
|
||||
- `--audit-webhook-initial-backoff` specifies the amount of time to wait after the first failed
|
||||
request before retrying. Subsequent requests are retried with exponential backoff.
|
||||
|
||||
The webhook config file uses the kubeconfig format to specify the remote address of
|
||||
the service and credentials used to connect to it.
|
||||
|
||||
### Batching
|
||||
|
||||
Both log and webhook backends support batching. Using webhook as an example, here's the list of
|
||||
available flags. To get the same flag for log backend, replace `webhook` with `log` in the flag
|
||||
name. By default, batching is enabled in `webhook` and disabled in `log`. Similarly, by default
|
||||
throttling is enabled in `webhook` and disabled in `log`.
|
||||
|
||||
- `--audit-webhook-mode` defines the buffering strategy. One of the following:
|
||||
- `batch` - buffer events and asynchronously process them in batches. This is the default.
|
||||
- `blocking` - block API server responses on processing each individual event.
|
||||
|
||||
The following flags are used only in the `batch` mode.
|
||||
|
||||
- `--audit-webhook-batch-buffer-size` defines the number of events to buffer before batching.
|
||||
If the rate of incoming events overflows the buffer, events are dropped.
|
||||
- `--audit-webhook-batch-max-size` defines the maximum number of events in one batch.
|
||||
- `--audit-webhook-batch-max-wait` defines the maximum amount of time to wait before unconditionally
|
||||
batching events in the queue.
|
||||
- `--audit-webhook-batch-throttle-qps` defines the maximum average number of batches generated
|
||||
per second.
|
||||
- `--audit-webhook-batch-throttle-burst` defines the maximum number of batches generated at the same
|
||||
moment if the allowed QPS was underutilized previously.
|
||||
|
||||
#### Parameter tuning
|
||||
|
||||
Parameters should be set to accommodate the load on the apiserver.
|
||||
|
||||
For example, if kube-apiserver receives 100 requests each second, and each request is audited only
|
||||
on `ResponseStarted` and `ResponseComplete` stages, you should account for ~200 audit
|
||||
events being generated each second. Assuming that there are up to 100 events in a batch,
|
||||
you should set throttling level at least 2 QPS. Assuming that the backend can take up to
|
||||
5 seconds to write events, you should set the buffer size to hold up to 5 seconds of events, i.e.
|
||||
10 batches, i.e. 1000 events.
|
||||
|
||||
In most cases however, the default parameters should be sufficient and you don't have to worry about
|
||||
setting them manually. You can look at the following Prometheus metrics exposed by kube-apiserver
|
||||
and in the logs to monitor the state of the auditing subsystem.
|
||||
|
||||
- `apiserver_audit_event_total` metric contains the total number of audit events exported.
|
||||
- `apiserver_audit_error_total` metric contains the total number of events dropped due to an error
|
||||
during exporting.
|
||||
|
||||
## Multi-cluster setup
|
||||
|
||||
If you're extending the Kubernetes API with the [aggregation layer][kube-aggregator], you can also
|
||||
set up audit logging for the aggregated apiserver. To do this, pass the configuration options in the
|
||||
same format as described above to the aggregated apiserver and set up the log ingesting pipeline
|
||||
to pick up audit logs. Different apiservers can have different audit configurations and different
|
||||
audit policies.
|
||||
|
||||
## Log Collector Examples
|
||||
|
||||
### Use fluentd to collect and distribute audit events from log file
|
||||
|
||||
[Fluentd][fluentd] is an open source data collector for unified logging layer.
|
||||
In this example, we will use fluentd to split audit events by different namespaces.
|
||||
|
||||
1. install [fluentd, fluent-plugin-forest and fluent-plugin-rewrite-tag-filter][fluentd_install_doc] in the kube-apiserver node
|
||||
1. create a config file for fluentd
|
||||
|
||||
```shell
|
||||
$ cat <<EOF > /etc/fluentd/config
|
||||
# fluentd conf runs in the same host with kube-apiserver
|
||||
<source>
|
||||
@type tail
|
||||
# audit log path of kube-apiserver
|
||||
path /var/log/audit
|
||||
pos_file /var/log/audit.pos
|
||||
format json
|
||||
time_key time
|
||||
time_format %Y-%m-%dT%H:%M:%S.%N%z
|
||||
tag audit
|
||||
</source>
|
||||
|
||||
<filter audit>
|
||||
#https://github.com/fluent/fluent-plugin-rewrite-tag-filter/issues/13
|
||||
type record_transformer
|
||||
enable_ruby
|
||||
<record>
|
||||
namespace ${record["objectRef"].nil? ? "none":(record["objectRef"]["namespace"].nil? ? "none":record["objectRef"]["namespace"])}
|
||||
</record>
|
||||
</filter>
|
||||
|
||||
<match audit>
|
||||
# route audit according to namespace element in context
|
||||
@type rewrite_tag_filter
|
||||
rewriterule1 namespace ^(.+) ${tag}.$1
|
||||
</match>
|
||||
|
||||
<filter audit.**>
|
||||
@type record_transformer
|
||||
remove_keys namespace
|
||||
</filter>
|
||||
|
||||
<match audit.**>
|
||||
@type forest
|
||||
subtype file
|
||||
remove_prefix audit
|
||||
<template>
|
||||
time_slice_format %Y%m%d%H
|
||||
compress gz
|
||||
path /var/log/audit-${tag}.*.log
|
||||
format json
|
||||
include_time_key true
|
||||
</template>
|
||||
</match>
|
||||
```
|
||||
|
||||
1. start fluentd
|
||||
|
||||
```shell
|
||||
$ fluentd -c /etc/fluentd/config -vv
|
||||
```
|
||||
|
||||
1. start kube-apiserver with the following options:
|
||||
|
||||
```shell
|
||||
--audit-policy-file=/etc/kubernetes/audit-policy.yaml --audit-log-path=/var/log/kube-audit --audit-log-format=json
|
||||
```
|
||||
|
||||
1. check audits for different namespaces in /var/log/audit-*.log
|
||||
|
||||
### Use logstash to collect and distribute audit events from webhook backend
|
||||
|
||||
[Logstash][logstash] is an open source, server-side data processing tool. In this example,
|
||||
we will use logstash to collect audit events from webhook backend, and save events of
|
||||
different users into different files.
|
||||
|
||||
1. install [logstash][logstash_install_doc]
|
||||
1. create config file for logstash
|
||||
|
||||
```shell
|
||||
$ cat <<EOF > /etc/logstash/config
|
||||
input{
|
||||
http{
|
||||
#TODO, figure out a way to use kubeconfig file to authenticate to logstash
|
||||
#https://www.elastic.co/guide/en/logstash/current/plugins-inputs-http.html#plugins-inputs-http-ssl
|
||||
port=>8888
|
||||
}
|
||||
}
|
||||
filter{
|
||||
split{
|
||||
# Webhook audit backend sends several events together with EventList
|
||||
# split each event here.
|
||||
field=>[items]
|
||||
# We only need event subelement, remove others.
|
||||
remove_field=>[headers, metadata, apiVersion, "@timestamp", kind, "@version", host]
|
||||
}
|
||||
mutate{
|
||||
rename => {items=>event}
|
||||
}
|
||||
}
|
||||
output{
|
||||
file{
|
||||
# Audit events from different users will be saved into different files.
|
||||
path=>"/var/log/kube-audit-%{[event][user][username]}/audit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. start logstash
|
||||
|
||||
```shell
|
||||
$ bin/logstash -f /etc/logstash/config --path.settings /etc/logstash/
|
||||
```
|
||||
|
||||
1. create a [kubeconfig file](/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/) for kube-apiserver webhook audit backend
|
||||
|
||||
```shell
|
||||
$ cat <<EOF > /etc/kubernetes/audit-webhook-kubeconfig
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: http://<ip_of_logstash>:8888
|
||||
name: logstash
|
||||
contexts:
|
||||
- context:
|
||||
cluster: logstash
|
||||
user: ""
|
||||
name: default-context
|
||||
current-context: default-context
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users: []
|
||||
EOF
|
||||
```
|
||||
|
||||
1. start kube-apiserver with the following options:
|
||||
|
||||
```shell
|
||||
--audit-policy-file=/etc/kubernetes/audit-policy.yaml --audit-webhook-config-file=/etc/kubernetes/audit-webhook-kubeconfig
|
||||
```
|
||||
|
||||
1. check audits in logstash node's directories /var/log/kube-audit-*/audit
|
||||
|
||||
Note that in addition to file output plugin, logstash has a variety of outputs that
|
||||
let users route data where they want. For example, users can emit audit events to elasticsearch
|
||||
plugin which supports full-text search and analytics.
|
||||
|
||||
## Legacy Audit
|
||||
|
||||
__Note:__ Legacy Audit is deprecated and is disabled by default since 1.8 and
|
||||
will be removed in 1.12. To fallback to this legacy audit, disable the advanced
|
||||
auditing feature using the `AdvancedAuditing` feature gate in [kube-apiserver][kube-apiserver]:
|
||||
|
||||
```
|
||||
--feature-gates=AdvancedAuditing=false
|
||||
```
|
||||
|
||||
In legacy format, each audit log entry contains two lines:
|
||||
|
||||
1. The request line containing a unique ID to match the response and request
|
||||
metadata, such as the source IP, requesting user, impersonation information,
|
||||
resource being requested, etc.
|
||||
2. The response line containing a unique ID matching the request line and the response code.
|
||||
|
||||
Example output for `admin` user listing pods in the `default` namespace:
|
||||
|
||||
```
|
||||
2017-03-21T03:57:09.106841886-04:00 AUDIT: id="c939d2a7-1c37-4ef1-b2f7-4ba9b1e43b53" ip="127.0.0.1" method="GET" user="admin" groups="\"system:masters\",\"system:authenticated\"" as="<self>" asgroups="<lookup>" namespace="default" uri="/api/v1/namespaces/default/pods"
|
||||
2017-03-21T03:57:09.108403639-04:00 AUDIT: id="c939d2a7-1c37-4ef1-b2f7-4ba9b1e43b53" response="200"
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
[Kube-apiserver][kube-apiserver] provides the following options which are responsible
|
||||
for configuring where and how audit logs are handled:
|
||||
|
||||
- `audit-log-path` - enables the audit log pointing to a file where the requests are being logged to, '-' means standard out.
|
||||
- `audit-log-maxage` - specifies maximum number of days to retain old audit log files based on the timestamp encoded in their filename.
|
||||
- `audit-log-maxbackup` - specifies maximum number of old audit log files to retain.
|
||||
- `audit-log-maxsize` - specifies maximum size in megabytes of the audit log file before it gets rotated. Defaults to 100MB.
|
||||
|
||||
If an audit log file already exists, Kubernetes appends new audit logs to that file.
|
||||
Otherwise, Kubernetes creates an audit log file at the location you specified in
|
||||
`audit-log-path`. If the audit log file exceeds the size you specify in `audit-log-maxsize`,
|
||||
Kubernetes will rename the current log file by appending the current timestamp on
|
||||
the file name (before the file extension) and create a new audit log file.
|
||||
Kubernetes may delete old log files when creating a new log file; you can configure
|
||||
how many files are retained and how old they can be by specifying the `audit-log-maxbackup`
|
||||
and `audit-log-maxage` options.
|
||||
|
||||
[kube-apiserver]: /docs/admin/kube-apiserver
|
||||
[auditing-proposal]: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/auditing.md
|
||||
[auditing-api]: https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go
|
||||
[gce-audit-profile]: https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/cluster/gce/gci/configure-helper.sh#L735
|
||||
[kubeconfig]: https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
|
||||
[fluentd]: http://www.fluentd.org/
|
||||
[fluentd_install_doc]: http://docs.fluentd.org/v0.12/articles/quickstart#step1-installing-fluentd
|
||||
[logstash]: https://www.elastic.co/products/logstash
|
||||
[logstash_install_doc]: https://www.elastic.co/guide/en/logstash/current/installing-logstash.html
|
||||
[kube-aggregator]: /docs/concepts/api-extension/apiserver-aggregation
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
reviewers:
|
||||
- fgrzadkowski
|
||||
- piosz
|
||||
title: Core metrics pipeline
|
||||
---
|
||||
|
||||
Starting from Kubernetes 1.8, resource usage metrics, such as container CPU and memory usage,
|
||||
are available in Kubernetes through the Metrics API. These metrics can be either accessed directly
|
||||
by user, for example by using `kubectl top` command, or used by a controller in the cluster, e.g.
|
||||
Horizontal Pod Autoscaler, to make decisions.
|
||||
|
||||
## The Metrics API
|
||||
|
||||
Through the Metrics API you can get the amount of resource currently used
|
||||
by a given node or a given pod. This API doesn't store the metric values,
|
||||
so it's not possible for example to get the amount of resources used by a
|
||||
given node 10 minutes ago.
|
||||
|
||||
The API is no different from any other API:
|
||||
|
||||
- it is discoverable through the same endpoint as the other Kubernetes APIs under `/apis/metrics.k8s.io/` path
|
||||
- it offers the same security, scalability and reliability guarantees
|
||||
|
||||
The API is defined in [k8s.io/metrics](https://github.com/kubernetes/metrics/blob/master/pkg/apis/metrics/v1beta1/types.go)
|
||||
repository. You can find more information about the API there.
|
||||
|
||||
**Note:** The API requires metrics server to be deployed in the cluster. Otherwise it will be not available.
|
||||
|
||||
## Metrics Server
|
||||
|
||||
[Metrics Server](https://github.com/kubernetes-incubator/metrics-server) is a cluster-wide aggregator of resource usage data.
|
||||
Starting from Kubernetes 1.8 it's deployed by default in clusters created by `kube-up.sh` script
|
||||
as a Deployment object. If you use a different Kubernetes setup mechanism you can deploy it using the provided
|
||||
[deployment yamls](https://github.com/kubernetes-incubator/metrics-server/tree/master/deploy).
|
||||
It's supported in Kubernetes 1.7+ (see details below).
|
||||
|
||||
Metric server collects metrics from the Summary API, exposed by [Kubelet](/docs/admin/kubelet/) on each node.
|
||||
|
||||
Metrics Server registered in the main API server through
|
||||
[Kubernetes aggregator](https://kubernetes.io/docs/concepts/api-extension/apiserver-aggregation/),
|
||||
which was introduced in Kubernetes 1.7.
|
||||
|
||||
Learn more about the metrics server in [the design doc](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/metrics-server.md).
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: counter
|
||||
spec:
|
||||
containers:
|
||||
- name: count
|
||||
image: busybox
|
||||
args: [/bin/sh, -c,
|
||||
'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
|
||||
@@ -0,0 +1,363 @@
|
||||
---
|
||||
reviewers:
|
||||
- janetkuo
|
||||
- thockin
|
||||
title: Application Introspection and Debugging
|
||||
---
|
||||
|
||||
Once your application is running, you'll inevitably need to debug problems with it.
|
||||
Earlier we described how you can use `kubectl get pods` to retrieve simple status information about
|
||||
your pods. But there are a number of ways to get even more information about your application.
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Using `kubectl describe pod` to fetch details about pods
|
||||
|
||||
For this example we'll use a Deployment to create two pods, similar to the earlier example.
|
||||
|
||||
{{< code file="nginx-dep.yaml" >}}
|
||||
|
||||
Create deployment by running following command:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/nginx-dep.yaml
|
||||
deployment "nginx-deployment" created
|
||||
```
|
||||
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-1006230814-6winp 1/1 Running 0 11s
|
||||
nginx-deployment-1006230814-fmgu3 1/1 Running 0 11s
|
||||
```
|
||||
|
||||
We can retrieve a lot more information about each of these pods using `kubectl describe pod`. For example:
|
||||
|
||||
```shell
|
||||
$ kubectl describe pod nginx-deployment-1006230814-6winp
|
||||
Name: nginx-deployment-1006230814-6winp
|
||||
Namespace: default
|
||||
Node: kubernetes-node-wul5/10.240.0.9
|
||||
Start Time: Thu, 24 Mar 2016 01:39:49 +0000
|
||||
Labels: app=nginx,pod-template-hash=1006230814
|
||||
Annotations: kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind" :"ReplicaSet","namespace":"default","name":"nginx-deployment-1956810328","uid":"14e607e7-8ba1-11e7-b5cb-fa16" ...
|
||||
Status: Running
|
||||
IP: 10.244.0.6
|
||||
Controllers: ReplicaSet/nginx-deployment-1006230814
|
||||
Containers:
|
||||
nginx:
|
||||
Container ID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
|
||||
Image: nginx
|
||||
Image ID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
|
||||
Port: 80/TCP
|
||||
QoS Tier:
|
||||
cpu: Guaranteed
|
||||
memory: Guaranteed
|
||||
Limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
Requests:
|
||||
memory: 128Mi
|
||||
cpu: 500m
|
||||
State: Running
|
||||
Started: Thu, 24 Mar 2016 01:39:51 +0000
|
||||
Ready: True
|
||||
Restart Count: 0
|
||||
Environment: <none>
|
||||
Mounts:
|
||||
/var/run/secrets/kubernetes.io/serviceaccount from default-token-5kdvl (ro)
|
||||
Conditions:
|
||||
Type Status
|
||||
Initialized True
|
||||
Ready True
|
||||
PodScheduled True
|
||||
Volumes:
|
||||
default-token-4bcbi:
|
||||
Type: Secret (a volume populated by a Secret)
|
||||
SecretName: default-token-4bcbi
|
||||
Optional: false
|
||||
QoS Class: Guaranteed
|
||||
Node-Selectors: <none>
|
||||
Tolerations: <none>
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
54s 54s 1 {default-scheduler } Normal Scheduled Successfully assigned nginx-deployment-1006230814-6winp to kubernetes-node-wul5
|
||||
54s 54s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Pulling pulling image "nginx"
|
||||
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Pulled Successfully pulled image "nginx"
|
||||
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Created Created container with docker id 90315cc9f513
|
||||
53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Started Started container with docker id 90315cc9f513
|
||||
```
|
||||
|
||||
Here you can see configuration information about the container(s) and Pod (labels, resource requirements, etc.), as well as status information about the container(s) and Pod (state, readiness, restart count, events, etc.).
|
||||
|
||||
The container state is one of Waiting, Running, or Terminated. Depending on the state, additional information will be provided -- here you can see that for a container in Running state, the system tells you when the container started.
|
||||
|
||||
Ready tells you whether the container passed its last readiness probe. (In this case, the container does not have a readiness probe configured; the container is assumed to be ready if no readiness probe is configured.)
|
||||
|
||||
Restart Count tells you how many times the container has been restarted; this information can be useful for detecting crash loops in containers that are configured with a restart policy of 'always.'
|
||||
|
||||
Currently the only Condition associated with a Pod is the binary Ready condition, which indicates that the pod is able to service requests and should be added to the load balancing pools of all matching services.
|
||||
|
||||
Lastly, you see a log of recent events related to your Pod. The system compresses multiple identical events by indicating the first and last time it was seen and the number of times it was seen. "From" indicates the component that is logging the event, "SubobjectPath" tells you which object (e.g. container within the pod) is being referred to, and "Reason" and "Message" tell you what happened.
|
||||
|
||||
## Example: debugging Pending Pods
|
||||
|
||||
A common scenario that you can detect using events is when you've created a Pod that won't fit on any node. For example, the Pod might request more resources than are free on any node, or it might specify a label selector that doesn't match any nodes. Let's say we created the previous Deployment with 5 replicas (instead of 2) and requesting 600 millicores instead of 500, on a four-node cluster where each (virtual) machine has 1 CPU. In that case one of the Pods will not be able to schedule. (Note that because of the cluster addon pods such as fluentd, skydns, etc., that run on each node, if we requested 1000 millicores then none of the Pods would be able to schedule.)
|
||||
|
||||
```shell
|
||||
$ 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
|
||||
```
|
||||
|
||||
To find out why the nginx-deployment-1370807587-fz9sd pod is not running, we can use `kubectl describe pod` on the pending Pod and look at its events:
|
||||
|
||||
```shell
|
||||
$ 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
|
||||
```
|
||||
|
||||
Here you can see the event generated by the scheduler saying that the Pod failed to schedule for reason `FailedScheduling` (and possibly others). The message tells us that there were not enough resources for the Pod on any of the nodes.
|
||||
|
||||
To correct this situation, you can use `kubectl scale` to update your Deployment to specify four or fewer replicas. (Or you could just leave the one Pod pending, which is harmless.)
|
||||
|
||||
Events such as the ones you saw at the end of `kubectl describe pod` are persisted in etcd and provide high-level information on what is happening in the cluster. To list all events you can use
|
||||
|
||||
```shell
|
||||
kubectl get events
|
||||
```
|
||||
|
||||
but you have to remember that events are namespaced. This means that if you're interested in events for some namespaced object (e.g. what happened with Pods in namespace `my-namespace`) you need to explicitly provide a namespace to the command:
|
||||
|
||||
```shell
|
||||
kubectl get events --namespace=my-namespace
|
||||
```
|
||||
|
||||
To see events from all namespaces, you can use the `--all-namespaces` argument.
|
||||
|
||||
In addition to `kubectl describe pod`, another way to get extra information about a pod (beyond what is provided by `kubectl get pod`) is to pass the `-o yaml` output format flag to `kubectl get pod`. This will give you, in YAML format, even more information than `kubectl describe pod`--essentially all of the information the system has about the Pod. Here you will see things like annotations (which are key-value metadata without the label restrictions, that is used internally by Kubernetes system components), restart policy, ports, and volumes.
|
||||
|
||||
```yaml
|
||||
$ kubectl get pod nginx-deployment-1006230814-6winp -o yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
annotations:
|
||||
kubernetes.io/created-by: |
|
||||
{"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1006230814","uid":"4c84c175-f161-11e5-9a78-42010af00005","apiVersion":"extensions","resourceVersion":"133434"}}
|
||||
creationTimestamp: 2016-03-24T01:39:50Z
|
||||
generateName: nginx-deployment-1006230814-
|
||||
labels:
|
||||
app: nginx
|
||||
pod-template-hash: "1006230814"
|
||||
name: nginx-deployment-1006230814-6winp
|
||||
namespace: default
|
||||
resourceVersion: "133447"
|
||||
selfLink: /api/v1/namespaces/default/pods/nginx-deployment-1006230814-6winp
|
||||
uid: 4c879808-f161-11e5-9a78-42010af00005
|
||||
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
|
||||
volumeMounts:
|
||||
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
name: default-token-4bcbi
|
||||
readOnly: true
|
||||
dnsPolicy: ClusterFirst
|
||||
nodeName: kubernetes-node-wul5
|
||||
restartPolicy: Always
|
||||
securityContext: {}
|
||||
serviceAccount: default
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 30
|
||||
volumes:
|
||||
- name: default-token-4bcbi
|
||||
secret:
|
||||
secretName: default-token-4bcbi
|
||||
status:
|
||||
conditions:
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: 2016-03-24T01:39:51Z
|
||||
status: "True"
|
||||
type: Ready
|
||||
containerStatuses:
|
||||
- containerID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
|
||||
image: nginx
|
||||
imageID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
|
||||
lastState: {}
|
||||
name: nginx
|
||||
ready: true
|
||||
restartCount: 0
|
||||
state:
|
||||
running:
|
||||
startedAt: 2016-03-24T01:39:51Z
|
||||
hostIP: 10.240.0.9
|
||||
phase: Running
|
||||
podIP: 10.244.0.6
|
||||
startTime: 2016-03-24T01:39:49Z
|
||||
```
|
||||
|
||||
## Example: debugging a down/unreachable node
|
||||
|
||||
Sometimes when debugging it can be useful to look at the status of a node -- for example, because you've noticed strange behavior of a Pod that's running on the node, or to find out why a Pod won't schedule onto the node. As with Pods, you can use `kubectl describe node` and `kubectl get node -o yaml` to retrieve detailed information about nodes. For example, here's what you'll see if a node is down (disconnected from the network, or kubelet dies and won't restart, etc.). Notice the events that show the node is NotReady, and also notice that the pods are no longer running (they are evicted after five minutes of NotReady status).
|
||||
|
||||
```shell
|
||||
$ kubectl get nodes
|
||||
NAME STATUS AGE VERSION
|
||||
kubernetes-node-861h NotReady 1h v1.6.0+fff5156
|
||||
kubernetes-node-bols Ready 1h v1.6.0+fff5156
|
||||
kubernetes-node-st6x Ready 1h v1.6.0+fff5156
|
||||
kubernetes-node-unaj Ready 1h v1.6.0+fff5156
|
||||
|
||||
$ kubectl describe node kubernetes-node-861h
|
||||
Name: kubernetes-node-861h
|
||||
Role
|
||||
Labels: beta.kubernetes.io/arch=amd64
|
||||
beta.kubernetes.io/os=linux
|
||||
kubernetes.io/hostname=kubernetes-node-861h
|
||||
Annotations: node.alpha.kubernetes.io/ttl=0
|
||||
volumes.kubernetes.io/controller-managed-attach-detach=true
|
||||
Taints: <none>
|
||||
CreationTimestamp: Mon, 04 Sep 2017 17:13:23 +0800
|
||||
Phase:
|
||||
Conditions:
|
||||
Type Status LastHeartbeatTime LastTransitionTime Reason Message
|
||||
---- ------ ----------------- ------------------ ------ -------
|
||||
OutOfDisk Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
MemoryPressure Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
DiskPressure Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
Ready Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
Addresses: 10.240.115.55,104.197.0.26
|
||||
Capacity:
|
||||
cpu: 2
|
||||
hugePages: 0
|
||||
memory: 4046788Ki
|
||||
pods: 110
|
||||
Allocatable:
|
||||
cpu: 1500m
|
||||
hugePages: 0
|
||||
memory: 1479263Ki
|
||||
pods: 110
|
||||
System Info:
|
||||
Machine ID: 8e025a21a4254e11b028584d9d8b12c4
|
||||
System UUID: 349075D1-D169-4F25-9F2A-E886850C47E3
|
||||
Boot ID: 5cd18b37-c5bd-4658-94e0-e436d3f110e0
|
||||
Kernel Version: 4.4.0-31-generic
|
||||
OS Image: Debian GNU/Linux 8 (jessie)
|
||||
Operating System: linux
|
||||
Architecture: amd64
|
||||
Container Runtime Version: docker://1.12.5
|
||||
Kubelet Version: v1.6.9+a3d1dfa6f4335
|
||||
Kube-Proxy Version: v1.6.9+a3d1dfa6f4335
|
||||
ExternalID: 15233045891481496305
|
||||
Non-terminated Pods: (9 in total)
|
||||
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
--------- ---- ------------ ---------- --------------- -------------
|
||||
......
|
||||
Allocated resources:
|
||||
(Total limits may be over 100 percent, i.e., overcommitted.)
|
||||
CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
------------ ---------- --------------- -------------
|
||||
900m (60%) 2200m (146%) 1009286400 (66%) 5681286400 (375%)
|
||||
Events: <none>
|
||||
|
||||
$ kubectl get node kubernetes-node-861h -o yaml
|
||||
apiVersion: v1
|
||||
kind: Node
|
||||
metadata:
|
||||
creationTimestamp: 2015-07-10T21:32:29Z
|
||||
labels:
|
||||
kubernetes.io/hostname: kubernetes-node-861h
|
||||
name: kubernetes-node-861h
|
||||
resourceVersion: "757"
|
||||
selfLink: /api/v1/nodes/kubernetes-node-861h
|
||||
uid: 2a69374e-274b-11e5-a234-42010af0d969
|
||||
spec:
|
||||
externalID: "15233045891481496305"
|
||||
podCIDR: 10.244.0.0/24
|
||||
providerID: gce://striped-torus-760/us-central1-b/kubernetes-node-861h
|
||||
status:
|
||||
addresses:
|
||||
- address: 10.240.115.55
|
||||
type: InternalIP
|
||||
- address: 104.197.0.26
|
||||
type: ExternalIP
|
||||
capacity:
|
||||
cpu: "1"
|
||||
memory: 3800808Ki
|
||||
pods: "100"
|
||||
conditions:
|
||||
- lastHeartbeatTime: 2015-07-10T21:34:32Z
|
||||
lastTransitionTime: 2015-07-10T21:35:15Z
|
||||
reason: Kubelet stopped posting node status.
|
||||
status: Unknown
|
||||
type: Ready
|
||||
nodeInfo:
|
||||
bootID: 4e316776-b40d-4f78-a4ea-ab0d73390897
|
||||
containerRuntimeVersion: docker://Unknown
|
||||
kernelVersion: 3.16.0-0.bpo.4-amd64
|
||||
kubeProxyVersion: v0.21.1-185-gffc5a86098dc01
|
||||
kubeletVersion: v0.21.1-185-gffc5a86098dc01
|
||||
machineID: ""
|
||||
osImage: Debian GNU/Linux 7 (wheezy)
|
||||
systemUUID: ABE5F6B4-D44B-108B-C46A-24CCE16C8B6E
|
||||
```
|
||||
|
||||
## What's next?
|
||||
|
||||
Learn about additional debugging tools, including:
|
||||
|
||||
* [Logging](/docs/concepts/cluster-administration/logging/)
|
||||
* [Monitoring](/docs/tasks/debug-application-cluster/resource-usage-monitoring/)
|
||||
* [Getting into containers via `exec`](/docs/tasks/debug-application-cluster/get-shell-running-container/)
|
||||
* [Connecting to containers via proxies](/docs/tasks/access-kubernetes-api/http-proxy-access-api/)
|
||||
* [Connecting to containers via port forwarding](/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
---
|
||||
reviewers:
|
||||
- mikedanese
|
||||
- thockin
|
||||
title: Troubleshoot Applications
|
||||
---
|
||||
|
||||
This guide is to help users debug applications that are deployed into Kubernetes and not behaving correctly.
|
||||
This is *not* a guide for people who want to debug their cluster. For that you should check out
|
||||
[this guide](/docs/admin/cluster-troubleshooting).
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Diagnosing the problem
|
||||
|
||||
The first step in troubleshooting is triage. What is the problem? Is it your Pods, your Replication Controller or
|
||||
your Service?
|
||||
|
||||
* [Debugging Pods](#debugging-pods)
|
||||
* [Debugging Replication Controllers](#debugging-replication-controllers)
|
||||
* [Debugging Services](#debugging-services)
|
||||
|
||||
### Debugging Pods
|
||||
|
||||
The first step in debugging a Pod is taking a look at it. Check the current state of the Pod and recent events with the following command:
|
||||
|
||||
```shell
|
||||
$ kubectl describe pods ${POD_NAME}
|
||||
```
|
||||
|
||||
Look at the state of the containers in the pod. Are they all `Running`? Have there been recent restarts?
|
||||
|
||||
Continue debugging depending on the state of the pods.
|
||||
|
||||
#### My pod stays pending
|
||||
|
||||
If a Pod is stuck in `Pending` it means that it can not be scheduled onto a node. Generally this is because
|
||||
there are insufficient resources of one type or another that prevent scheduling. Look at the output of the
|
||||
`kubectl describe ...` command above. There should be messages from the scheduler about why it can not schedule
|
||||
your pod. Reasons include:
|
||||
|
||||
* **You don't have enough resources**: You may have exhausted the supply of CPU or Memory in your cluster, in this case
|
||||
you need to delete Pods, adjust resource requests, or add new nodes to your cluster. See [Compute Resources document](/docs/user-guide/compute-resources/#my-pods-are-pending-with-event-message-failedscheduling) for more information.
|
||||
|
||||
* **You are using `hostPort`**: When you bind a Pod to a `hostPort` there are a limited number of places that pod can be
|
||||
scheduled. In most cases, `hostPort` is unnecessary, try using a Service object to expose your Pod. If you do require
|
||||
`hostPort` then you can only schedule as many Pods as there are nodes in your Kubernetes cluster.
|
||||
|
||||
|
||||
#### My pod stays waiting
|
||||
|
||||
If a Pod is stuck in the `Waiting` state, then it has been scheduled to a worker node, but it can't run on that machine.
|
||||
Again, the information from `kubectl describe ...` should be informative. The most common cause of `Waiting` pods is a failure to pull the image. There are three things to check:
|
||||
|
||||
* Make sure that you have the name of the image correct.
|
||||
* Have you pushed the image to the repository?
|
||||
* Run a manual `docker pull <image>` on your machine to see if the image can be pulled.
|
||||
|
||||
#### My pod is crashing or otherwise unhealthy
|
||||
|
||||
First, take a look at the logs of
|
||||
the current container:
|
||||
|
||||
```shell
|
||||
$ kubectl logs ${POD_NAME} ${CONTAINER_NAME}
|
||||
```
|
||||
|
||||
If your container has previously crashed, you can access the previous container's crash log with:
|
||||
|
||||
```shell
|
||||
$ kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}
|
||||
```
|
||||
|
||||
Alternately, you can run commands inside that container with `exec`:
|
||||
|
||||
```shell
|
||||
$ kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}
|
||||
```
|
||||
|
||||
Note that `-c ${CONTAINER_NAME}` is optional and can be omitted for Pods that only contain a single container.
|
||||
|
||||
As an example, to look at the logs from a running Cassandra pod, you might run
|
||||
|
||||
```shell
|
||||
$ kubectl exec cassandra -- cat /var/log/cassandra/system.log
|
||||
```
|
||||
|
||||
If none of these approaches work, you can find the host machine that the pod is running on and SSH into that host,
|
||||
but this should generally not be necessary given tools in the Kubernetes API. Therefore, if you find yourself needing to ssh into a machine, please file a
|
||||
feature request on GitHub describing your use case and why these tools are insufficient.
|
||||
|
||||
#### My pod is running but not doing what I told it to do
|
||||
|
||||
If your pod is not behaving as you expected, it may be that there was an error in your
|
||||
pod description (e.g. `mypod.yaml` file on your local machine), and that the error
|
||||
was silently ignored when you created the pod. Often a section of the pod description
|
||||
is nested incorrectly, or a key name is typed incorrectly, and so the key is ignored.
|
||||
For example, if you misspelled `command` as `commnd` then the pod will be created but
|
||||
will not use the command line you intended it to use.
|
||||
|
||||
The first thing to do is to delete your pod and try creating it again with the `--validate` option.
|
||||
For example, run `kubectl create --validate -f mypod.yaml`.
|
||||
If you misspelled `command` as `commnd` then will give an error like this:
|
||||
|
||||
```shell
|
||||
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
|
||||
```
|
||||
|
||||
<!-- TODO: Now that #11914 is merged, this advice may need to be updated -->
|
||||
|
||||
The next thing to check is whether the pod on the apiserver
|
||||
matches the pod you meant to create (e.g. in a yaml file on your local machine).
|
||||
For example, run `kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml` and then
|
||||
manually compare the original pod description, `mypod.yaml` with the one you got
|
||||
back from apiserver, `mypod-on-apiserver.yaml`. There will typically be some
|
||||
lines on the "apiserver" version that are not on the original version. This is
|
||||
expected. However, if there are lines on the original that are not on the apiserver
|
||||
version, then this may indicate a problem with your pod spec.
|
||||
|
||||
### Debugging Replication Controllers
|
||||
|
||||
Replication controllers are fairly straightforward. They can either create Pods or they can't. If they can't
|
||||
create pods, then please refer to the [instructions above](#debugging-pods) to debug your pods.
|
||||
|
||||
You can also use `kubectl describe rc ${CONTROLLER_NAME}` to introspect events related to the replication
|
||||
controller.
|
||||
|
||||
### Debugging Services
|
||||
|
||||
Services provide load balancing across a set of pods. There are several common problems that can make Services
|
||||
not work properly. The following instructions should help debug Service problems.
|
||||
|
||||
First, verify that there are endpoints for the service. For every Service object, the apiserver makes an `endpoints` resource available.
|
||||
|
||||
You can view this resource with:
|
||||
|
||||
```shell
|
||||
$ kubectl get endpoints ${SERVICE_NAME}
|
||||
```
|
||||
|
||||
Make sure that the endpoints match up with the number of containers that you expect to be a member of your service.
|
||||
For example, if your Service is for an nginx container with 3 replicas, you would expect to see three different
|
||||
IP addresses in the Service's endpoints.
|
||||
|
||||
#### My service is missing endpoints
|
||||
|
||||
If you are missing endpoints, try listing pods using the labels that Service uses. Imagine that you have
|
||||
a Service where the labels are:
|
||||
|
||||
```yaml
|
||||
...
|
||||
spec:
|
||||
- selector:
|
||||
name: nginx
|
||||
type: frontend
|
||||
```
|
||||
|
||||
You can use:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --selector=name=nginx,type=frontend
|
||||
```
|
||||
|
||||
to list pods that match this selector. Verify that the list matches the Pods that you expect to provide your Service.
|
||||
|
||||
If the list of pods matches expectations, but your endpoints are still empty, it's possible that you don't
|
||||
have the right ports exposed. If your service has a `containerPort` specified, but the Pods that are
|
||||
selected don't have that port listed, then they won't be added to the endpoints list.
|
||||
|
||||
Verify that the pod's `containerPort` matches up with the Service's `containerPort`
|
||||
|
||||
#### Network traffic is not forwarded
|
||||
|
||||
If you can connect to the service, but the connection is immediately dropped, and there are endpoints
|
||||
in the endpoints list, it's likely that the proxy can't contact your pods.
|
||||
|
||||
There are three things to
|
||||
check:
|
||||
|
||||
* Are your pods working correctly? Look for restart count, and [debug pods](#debugging-pods).
|
||||
* Can you connect to your pods directly? Get the IP address for the Pod, and try to connect directly to that IP.
|
||||
* Is your application serving on the port that you configured? Kubernetes doesn't do port remapping, so if your application serves on 8080, the `containerPort` field needs to be 8080.
|
||||
|
||||
#### More information
|
||||
|
||||
If none of the above solves your problem, follow the instructions in [Debugging Service document](/docs/user-guide/debugging-services) to make sure that your `Service` is running, has `Endpoints`, and your `Pods` are actually serving; you have DNS working, iptables rules installed, and kube-proxy does not seem to be misbehaving.
|
||||
|
||||
You may also visit [troubleshooting document](/docs/troubleshooting/) for more information.
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
reviewers:
|
||||
- davidopp
|
||||
title: Troubleshoot Clusters
|
||||
---
|
||||
|
||||
This doc is about cluster troubleshooting; we assume you have already ruled out your application as the root cause of the
|
||||
problem you are experiencing. See
|
||||
the [application troubleshooting guide](/docs/tasks/debug-application-cluster/debug-application) for tips on application debugging.
|
||||
You may also visit [troubleshooting document](/docs/troubleshooting/) for more information.
|
||||
|
||||
## Listing your cluster
|
||||
|
||||
The first thing to debug in your cluster is if your nodes are all registered correctly.
|
||||
|
||||
Run
|
||||
|
||||
```shell
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
And verify that all of the nodes you expect to see are present and that they are all in the `Ready` state.
|
||||
|
||||
## Looking at logs
|
||||
|
||||
For now, digging deeper into the cluster requires logging into the relevant machines. Here are the locations
|
||||
of the relevant log files. (note that on systemd-based systems, you may need to use `journalctl` instead)
|
||||
|
||||
### Master
|
||||
|
||||
* /var/log/kube-apiserver.log - API Server, responsible for serving the API
|
||||
* /var/log/kube-scheduler.log - Scheduler, responsible for making scheduling decisions
|
||||
* /var/log/kube-controller-manager.log - Controller that manages replication controllers
|
||||
|
||||
### Worker Nodes
|
||||
|
||||
* /var/log/kubelet.log - Kubelet, responsible for running containers on the node
|
||||
* /var/log/kube-proxy.log - Kube Proxy, responsible for service load balancing
|
||||
|
||||
## A general overview of cluster failure modes
|
||||
|
||||
This is an incomplete list of things that could go wrong, and how to adjust your cluster setup to mitigate the problems.
|
||||
|
||||
Root causes:
|
||||
|
||||
- VM(s) shutdown
|
||||
- Network partition within cluster, or between cluster and users
|
||||
- Crashes in Kubernetes software
|
||||
- Data loss or unavailability of persistent storage (e.g. GCE PD or AWS EBS volume)
|
||||
- Operator error, e.g. misconfigured Kubernetes software or application software
|
||||
|
||||
Specific scenarios:
|
||||
|
||||
- Apiserver VM shutdown or apiserver crashing
|
||||
- Results
|
||||
- unable to stop, update, or start new pods, services, replication controller
|
||||
- existing pods and services should continue to work normally, unless they depend on the Kubernetes API
|
||||
- Apiserver backing storage lost
|
||||
- Results
|
||||
- apiserver should fail to come up
|
||||
- kubelets will not be able to reach it but will continue to run the same pods and provide the same service proxying
|
||||
- manual recovery or recreation of apiserver state necessary before apiserver is restarted
|
||||
- Supporting services (node controller, replication controller manager, scheduler, etc) VM shutdown or crashes
|
||||
- currently those are colocated with the apiserver, and their unavailability has similar consequences as apiserver
|
||||
- in future, these will be replicated as well and may not be co-located
|
||||
- they do not have their own persistent state
|
||||
- Individual node (VM or physical machine) shuts down
|
||||
- Results
|
||||
- pods on that Node stop running
|
||||
- Network partition
|
||||
- Results
|
||||
- partition A thinks the nodes in partition B are down; partition B thinks the apiserver is down. (Assuming the master VM ends up in partition A.)
|
||||
- Kubelet software fault
|
||||
- Results
|
||||
- crashing kubelet cannot start new pods on the node
|
||||
- kubelet might delete the pods or not
|
||||
- node marked unhealthy
|
||||
- replication controllers start new pods elsewhere
|
||||
- Cluster operator error
|
||||
- Results
|
||||
- loss of pods, services, etc
|
||||
- lost of apiserver backing store
|
||||
- users unable to read API
|
||||
- etc.
|
||||
|
||||
Mitigations:
|
||||
|
||||
- Action: Use IaaS provider's automatic VM restarting feature for IaaS VMs
|
||||
- Mitigates: Apiserver VM shutdown or apiserver crashing
|
||||
- Mitigates: Supporting services VM shutdown or crashes
|
||||
|
||||
- Action: Use IaaS providers reliable storage (e.g. GCE PD or AWS EBS volume) for VMs with apiserver+etcd
|
||||
- Mitigates: Apiserver backing storage lost
|
||||
|
||||
- Action: Use (experimental) [high-availability](/docs/admin/high-availability) configuration
|
||||
- Mitigates: Master VM shutdown or master components (scheduler, API server, controller-managing) crashing
|
||||
- Will tolerate one or more simultaneous node or component failures
|
||||
- Mitigates: Apiserver backing storage (i.e., etcd's data directory) lost
|
||||
- Assuming you used clustered etcd.
|
||||
|
||||
- Action: Snapshot apiserver PDs/EBS-volumes periodically
|
||||
- Mitigates: Apiserver backing storage lost
|
||||
- Mitigates: Some cases of operator error
|
||||
- Mitigates: Some cases of Kubernetes software fault
|
||||
|
||||
- Action: use replication controller and services in front of pods
|
||||
- Mitigates: Node shutdown
|
||||
- Mitigates: Kubelet software fault
|
||||
|
||||
- Action: applications (containers) designed to tolerate unexpected restarts
|
||||
- Mitigates: Node shutdown
|
||||
- Mitigates: Kubelet software fault
|
||||
|
||||
- Action: [Multiple independent clusters](/docs/concepts/cluster-administration/federation/) (and avoid making risky changes to all clusters at once)
|
||||
- Mitigates: Everything listed above.
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
reviewers:
|
||||
- bprashanth
|
||||
- enisoc
|
||||
- erictune
|
||||
- foxish
|
||||
- janetkuo
|
||||
- kow3ns
|
||||
- smarterclayton
|
||||
title: Debug Init Containers
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
This page shows how to investigate problems related to the execution of
|
||||
Init Containers. The example command lines below refer to the Pod as
|
||||
`<pod-name>` and the Init Containers as `<init-container-1>` and
|
||||
`<init-container-2>`.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
* You should be familiar with the basics of
|
||||
[Init Containers](/docs/concepts/abstractions/init-containers/).
|
||||
* You should have [Configured an Init Container](/docs/tasks/configure-pod-container/configure-pod-initialization/#creating-a-pod-that-has-an-init-container/).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
## Checking the status of Init Containers
|
||||
|
||||
Display the status of your pod:
|
||||
|
||||
```shell
|
||||
kubectl get pod <pod-name>
|
||||
```
|
||||
|
||||
For example, a status of `Init:1/2` indicates that one of two Init Containers
|
||||
has completed successfully:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
<pod-name> 0/1 Init:1/2 0 7s
|
||||
```
|
||||
|
||||
See [Understanding Pod status](#understanding-pod-status) for more examples of
|
||||
status values and their meanings.
|
||||
|
||||
## Getting details about Init Containers
|
||||
|
||||
View more detailed information about Init Container execution:
|
||||
|
||||
```shell
|
||||
kubectl describe pod <pod-name>
|
||||
```
|
||||
|
||||
For example, a Pod with two Init Containers might show the following:
|
||||
|
||||
```
|
||||
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
|
||||
...
|
||||
```
|
||||
|
||||
You can also access the Init Container statuses programmatically by reading the
|
||||
`status.initContainerStatuses` field on the Pod Spec:
|
||||
|
||||
|
||||
```shell
|
||||
kubectl get pod nginx --template '{{.status.initContainerStatuses}}'
|
||||
```
|
||||
|
||||
|
||||
This command will return the same information as above in raw JSON.
|
||||
|
||||
## Accessing logs from Init Containers
|
||||
|
||||
Pass the Init Container name along with the Pod name
|
||||
to access its logs.
|
||||
|
||||
```shell
|
||||
kubectl logs <pod-name> -c <init-container-2>
|
||||
```
|
||||
|
||||
Init Containers that run a shell script print
|
||||
commands as they're executed. For example, you can do this in Bash by running
|
||||
`set -x` at the beginning of the script.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture discussion %}}
|
||||
|
||||
## Understanding Pod status
|
||||
|
||||
A Pod status beginning with `Init:` summarizes the status of Init Container
|
||||
execution. The table below describes some example status values that you might
|
||||
see while debugging Init Containers.
|
||||
|
||||
Status | Meaning
|
||||
------ | -------
|
||||
`Init:N/M` | The Pod has `M` Init Containers, and `N` have completed so far.
|
||||
`Init:Error` | An Init Container has failed to execute.
|
||||
`Init:CrashLoopBackOff` | An Init Container has failed repeatedly.
|
||||
`Pending` | The Pod has not yet begun executing Init Containers.
|
||||
`PodInitializing` or `Running` | The Pod has already finished executing Init Containers.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
reviewers:
|
||||
- bprashanth
|
||||
title: Debug Pods and Replication Controllers
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Debugging pods
|
||||
|
||||
The first step in debugging a pod is taking a look at it. Check the current
|
||||
state of the pod and recent events with the following command:
|
||||
|
||||
$ kubectl describe pods ${POD_NAME}
|
||||
|
||||
Look at the state of the containers in the pod. Are they all `Running`? Have
|
||||
there been recent restarts?
|
||||
|
||||
Continue debugging depending on the state of the pods.
|
||||
|
||||
### My pod stays pending
|
||||
|
||||
If a pod is stuck in `Pending` it means that it can not be scheduled onto a
|
||||
node. Generally this is because there are insufficient resources of one type or
|
||||
another that prevent scheduling. Look at the output of the `kubectl describe
|
||||
...` command above. There should be messages from the scheduler about why it
|
||||
can not schedule your pod. Reasons include:
|
||||
|
||||
#### Insufficient resources
|
||||
|
||||
You may have exhausted the supply of CPU or Memory in your cluster. In this
|
||||
case you can try several things:
|
||||
|
||||
* [Add more nodes](/docs/admin/cluster-management/#resizing-a-cluster) to the cluster.
|
||||
|
||||
* [Terminate unneeded pods](/docs/user-guide/pods/single-container/#deleting_a_pod)
|
||||
to make room for pending pods.
|
||||
|
||||
* Check that the pod is not larger than your nodes. For example, if all
|
||||
nodes have a capacity of `cpu:1`, then a pod with a request of `cpu: 1.1`
|
||||
will never be scheduled.
|
||||
|
||||
You can check node capacities with the `kubectl get nodes -o <format>`
|
||||
command. Here are some example command lines that extract just the necessary
|
||||
information:
|
||||
|
||||
kubectl get nodes -o yaml | grep '\sname\|cpu\|memory'
|
||||
kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, cap: .status.capacity}'
|
||||
|
||||
The [resource quota](/docs/concepts/policy/resource-quotas/)
|
||||
feature can be configured to limit the total amount of
|
||||
resources that can be consumed. If used in conjunction with namespaces, it can
|
||||
prevent one team from hogging all the resources.
|
||||
|
||||
#### Using hostPort
|
||||
|
||||
When you bind a pod to a `hostPort` there are a limited number of places that
|
||||
the pod can be scheduled. In most cases, `hostPort` is unnecessary; try using a
|
||||
service object to expose your pod. If you do require `hostPort` then you can
|
||||
only schedule as many pods as there are nodes in your container cluster.
|
||||
|
||||
### My pod stays waiting
|
||||
|
||||
If a pod is stuck in the `Waiting` state, then it has been scheduled to a
|
||||
worker node, but it can't run on that machine. Again, the information from
|
||||
`kubectl describe ...` should be informative. The most common cause of
|
||||
`Waiting` pods is a failure to pull the image. There are three things to check:
|
||||
|
||||
* Make sure that you have the name of the image correct.
|
||||
* Have you pushed the image to the repository?
|
||||
* Run a manual `docker pull <image>` on your machine to see if the image can be
|
||||
pulled.
|
||||
|
||||
### My pod is crashing or otherwise unhealthy
|
||||
|
||||
First, take a look at the logs of the current container:
|
||||
|
||||
$ kubectl logs ${POD_NAME} ${CONTAINER_NAME}
|
||||
|
||||
If your container has previously crashed, you can access the previous
|
||||
container's crash log with:
|
||||
|
||||
$ kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}
|
||||
|
||||
Alternately, you can run commands inside that container with `exec`:
|
||||
|
||||
$ kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}
|
||||
|
||||
Note that `-c ${CONTAINER_NAME}` is optional and can be omitted for pods that
|
||||
only contain a single container.
|
||||
|
||||
As an example, to look at the logs from a running Cassandra pod, you might run:
|
||||
|
||||
$ kubectl exec cassandra -- cat /var/log/cassandra/system.log
|
||||
|
||||
If none of these approaches work, you can find the host machine that the pod is
|
||||
running on and SSH into that host.
|
||||
|
||||
## Debugging Replication Controllers
|
||||
|
||||
Replication controllers are fairly straightforward. They can either create pods
|
||||
or they can't. If they can't create pods, then please refer to the
|
||||
[instructions above](#debugging_pods) to debug your pods.
|
||||
|
||||
You can also use `kubectl describe rc ${CONTROLLER_NAME}` to inspect events
|
||||
related to the replication controller.
|
||||
|
||||
@@ -0,0 +1,607 @@
|
||||
---
|
||||
reviewers:
|
||||
- thockin
|
||||
- bowei
|
||||
title: Debug Services
|
||||
---
|
||||
|
||||
An issue that comes up rather frequently for new installations of Kubernetes is
|
||||
that a `Service` is not working properly. You've run your `Deployment` and
|
||||
created a `Service`, but you get no response when you try to access it.
|
||||
This document will hopefully help you to figure out what's going wrong.
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Conventions
|
||||
|
||||
Throughout this doc you will see various commands that you can run. Some
|
||||
commands need to be run within a `Pod`, others on a Kubernetes `Node`, and others
|
||||
can run anywhere you have `kubectl` and credentials for the cluster. To make it
|
||||
clear what is expected, this document will use the following conventions.
|
||||
|
||||
If the command "COMMAND" is expected to run in a `Pod` and produce "OUTPUT":
|
||||
|
||||
```shell
|
||||
u@pod$ COMMAND
|
||||
OUTPUT
|
||||
```
|
||||
|
||||
If the command "COMMAND" is expected to run on a `Node` and produce "OUTPUT":
|
||||
|
||||
```shell
|
||||
u@node$ COMMAND
|
||||
OUTPUT
|
||||
```
|
||||
|
||||
If the command is "kubectl ARGS":
|
||||
|
||||
```shell
|
||||
$ kubectl ARGS
|
||||
OUTPUT
|
||||
```
|
||||
|
||||
## Running commands in a Pod
|
||||
|
||||
For many steps here you will want to see what a `Pod` running in the cluster
|
||||
sees. The simplest way to do this is to run an interactive busybox `Pod`:
|
||||
|
||||
```shell
|
||||
$ kubectl run -it --rm --restart=Never busybox --image=busybox sh
|
||||
If you don't see a command prompt, try pressing enter.
|
||||
/ #
|
||||
```
|
||||
|
||||
If you already have a running `Pod` that you prefer to use, you can run a
|
||||
command in it using:
|
||||
|
||||
```shell
|
||||
$ kubectl exec <POD-NAME> -c <CONTAINER-NAME> -- <COMMAND>
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
For the purposes of this walk-through, let's run some `Pods`. Since you're
|
||||
probably debugging your own `Service` you can substitute your own details, or you
|
||||
can follow along and get a second data point.
|
||||
|
||||
```shell
|
||||
$ kubectl run hostnames --image=k8s.gcr.io/serve_hostname \
|
||||
--labels=app=hostnames \
|
||||
--port=9376 \
|
||||
--replicas=3
|
||||
deployment "hostnames" created
|
||||
```
|
||||
|
||||
`kubectl` commands will print the type and name of the resource created or mutated, which can then be used in subsequent commands.
|
||||
Note that this is the same as if you had started the `Deployment` with
|
||||
the following YAML:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: hostnames
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: hostnames
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: hostnames
|
||||
spec:
|
||||
containers:
|
||||
- name: hostnames
|
||||
image: k8s.gcr.io/serve_hostname
|
||||
ports:
|
||||
- containerPort: 9376
|
||||
protocol: TCP
|
||||
```
|
||||
|
||||
Confirm your `Pods` are running:
|
||||
|
||||
```shell
|
||||
$ 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
|
||||
```
|
||||
|
||||
## Does the Service exist?
|
||||
|
||||
The astute reader will have noticed that we did not actually create a `Service`
|
||||
yet - that is intentional. This is a step that sometimes gets forgotten, and
|
||||
is the first thing to check.
|
||||
|
||||
So what would happen if I tried to access a non-existent `Service`? Assuming you
|
||||
have another `Pod` that consumes this `Service` by name you would get something
|
||||
like:
|
||||
|
||||
```shell
|
||||
u@pod$ wget -qO- hostnames
|
||||
wget: bad address 'hostname'
|
||||
```
|
||||
|
||||
So the first thing to check is whether that `Service` actually exists:
|
||||
|
||||
```shell
|
||||
$ kubectl get svc hostnames
|
||||
Error from server (NotFound): services "hostnames" not found
|
||||
```
|
||||
|
||||
So we have a culprit, let's create the `Service`. As before, this is for the
|
||||
walk-through - you can use your own `Service`'s details here.
|
||||
|
||||
```shell
|
||||
$ kubectl expose deployment hostnames --port=80 --target-port=9376
|
||||
service "hostnames" exposed
|
||||
```
|
||||
|
||||
And read it back, just to be sure:
|
||||
|
||||
```shell
|
||||
$ kubectl get svc hostnames
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
hostnames 10.0.1.175 <none> 80/TCP 5s
|
||||
```
|
||||
|
||||
As before, this is the same as if you had started the `Service` with YAML:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: hostnames
|
||||
spec:
|
||||
selector:
|
||||
app: hostnames
|
||||
ports:
|
||||
- name: default
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
```
|
||||
|
||||
Now you can confirm that the `Service` exists.
|
||||
|
||||
## Does the Service work by DNS?
|
||||
|
||||
From a `Pod` in the same `Namespace`:
|
||||
|
||||
```shell
|
||||
u@pod$ 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
|
||||
```
|
||||
|
||||
If this fails, perhaps your `Pod` and `Service` are in different
|
||||
`Namespaces`, try a namespace-qualified name:
|
||||
|
||||
```shell
|
||||
u@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
|
||||
```
|
||||
|
||||
If this works, you'll need to adjust your app to use a cross-namespace name, or
|
||||
run your app and `Service` in the same `Namespace`. If this still fails, try a
|
||||
fully-qualified name:
|
||||
|
||||
```shell
|
||||
u@pod$ 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
|
||||
```
|
||||
|
||||
Note the suffix here: "default.svc.cluster.local". The "default" is the
|
||||
`Namespace` we're operating in. The "svc" denotes that this is a `Service`.
|
||||
The "cluster.local" is your cluster domain, which COULD be different in your
|
||||
own cluster.
|
||||
|
||||
You can also try this from a `Node` in the cluster (note: 10.0.0.10 is my DNS
|
||||
`Service`, yours might be different):
|
||||
|
||||
```shell
|
||||
u@node$ 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
|
||||
```
|
||||
|
||||
If you are able to do a fully-qualified name lookup but not a relative one, you
|
||||
need to check that your `/etc/resolv.conf` file is correct.
|
||||
|
||||
```shell
|
||||
u@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
|
||||
```
|
||||
|
||||
The `nameserver` line must indicate your cluster's DNS `Service`. This is
|
||||
passed into `kubelet` with the `--cluster-dns` flag.
|
||||
|
||||
The `search` line must include an appropriate suffix for you to find the
|
||||
`Service` name. In this case it is looking for `Services` in the local
|
||||
`Namespace` (`default.svc.cluster.local`), `Services` in all `Namespaces`
|
||||
(`svc.cluster.local`), and the cluster (`cluster.local`). Depending on your own
|
||||
install you might have additional records after that (up to 6 total). The
|
||||
cluster suffix is passed into `kubelet` with the `--cluster-domain` flag. We
|
||||
assume that is "cluster.local" in this document, but yours might be different,
|
||||
in which case you should change that in all of the commands above.
|
||||
|
||||
The `options` line must set `ndots` high enough that your DNS client library
|
||||
considers search paths at all. Kubernetes sets this to 5 by default, which is
|
||||
high enough to cover all of the DNS names it generates.
|
||||
|
||||
### Does any Service exist in DNS?
|
||||
|
||||
If the above still fails - DNS lookups are not working for your `Service` - we
|
||||
can take a step back and see what else is not working. The Kubernetes master
|
||||
`Service` should always work:
|
||||
|
||||
```shell
|
||||
u@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
|
||||
```
|
||||
|
||||
If this fails, you might need to go to the kube-proxy section of this doc, or
|
||||
even go back to the top of this document and start over, but instead of
|
||||
debugging your own `Service`, debug DNS.
|
||||
|
||||
## Does the Service work by IP?
|
||||
|
||||
Assuming we can confirm that DNS works, the next thing to test is whether your
|
||||
`Service` works at all. From a node in your cluster, access the `Service`'s
|
||||
IP (from `kubectl get` above).
|
||||
|
||||
```shell
|
||||
u@node$ curl 10.0.1.175:80
|
||||
hostnames-0uton
|
||||
|
||||
u@node$ curl 10.0.1.175:80
|
||||
hostnames-yp2kp
|
||||
|
||||
u@node$ curl 10.0.1.175:80
|
||||
hostnames-bvc05
|
||||
```
|
||||
|
||||
If your `Service` is working, you should get correct responses. If not, there
|
||||
are a number of things that could be going wrong. Read on.
|
||||
|
||||
## Is the Service correct?
|
||||
|
||||
It might sound silly, but you should really double and triple check that your
|
||||
`Service` is correct and matches your `Pod`'s port. Read back your `Service`
|
||||
and verify it:
|
||||
|
||||
```shell
|
||||
$ kubectl get service hostnames -o json
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "hostnames",
|
||||
"namespace": "default",
|
||||
"selfLink": "/api/v1/namespaces/default/services/hostnames",
|
||||
"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": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Is the port you are trying to access in `spec.ports[]`? Is the `targetPort`
|
||||
correct for your `Pods` (many `Pods` choose to use a different port than the
|
||||
`Service`)? If you meant it to be a numeric port, is it a number (9376) or a
|
||||
string "9376"? If you meant it to be a named port, do your `Pods` expose a port
|
||||
with the same name? Is the port's `protocol` the same as the `Pod`'s?
|
||||
|
||||
## Does the Service have any Endpoints?
|
||||
|
||||
If you got this far, we assume that you have confirmed that your `Service`
|
||||
exists and is resolved by DNS. Now let's check that the `Pods` you ran are
|
||||
actually being selected by the `Service`.
|
||||
|
||||
Earlier we saw that the `Pods` were running. We can re-check that:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods -l app=hostnames
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
hostnames-0uton 1/1 Running 0 1h
|
||||
hostnames-bvc05 1/1 Running 0 1h
|
||||
hostnames-yp2kp 1/1 Running 0 1h
|
||||
```
|
||||
|
||||
The "AGE" column says that these `Pods` are about an hour old, which implies that
|
||||
they are running fine and not crashing.
|
||||
|
||||
The `-l app=hostnames` argument is a label selector - just like our `Service`
|
||||
has. Inside the Kubernetes system is a control loop which evaluates the
|
||||
selector of every `Service` and saves the results into an `Endpoints` object.
|
||||
|
||||
```shell
|
||||
$ kubectl get endpoints hostnames
|
||||
NAME ENDPOINTS
|
||||
hostnames 10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376
|
||||
```
|
||||
|
||||
This confirms that the endpoints controller has found the correct `Pods` for
|
||||
your `Service`. If the `hostnames` row is blank, you should check that the
|
||||
`spec.selector` field of your `Service` actually selects for `metadata.labels`
|
||||
values on your `Pods`. A common mistake is to have a typo or other error, such
|
||||
as the `Service` selecting for `run=hostnames`, but the `Deployment` specifying
|
||||
`app=hostnames`.
|
||||
|
||||
## Are the Pods working?
|
||||
|
||||
At this point, we know that your `Service` exists and has selected your `Pods`.
|
||||
Let's check that the `Pods` are actually working - we can bypass the `Service`
|
||||
mechanism and go straight to the `Pods`. Note that these commands use the `Pod`
|
||||
port (9376), rather than the `Service` port (80).
|
||||
|
||||
```shell
|
||||
u@pod$ wget -qO- 10.244.0.5:9376
|
||||
hostnames-0uton
|
||||
|
||||
pod $ wget -qO- 10.244.0.6:9376
|
||||
hostnames-bvc05
|
||||
|
||||
u@pod$ wget -qO- 10.244.0.7:9376
|
||||
hostnames-yp2kp
|
||||
```
|
||||
|
||||
We expect each `Pod` in the `Endpoints` list to return its own hostname. If
|
||||
this is not what happens (or whatever the correct behavior is for your own
|
||||
`Pods`), you should investigate what's happening there. You might find
|
||||
`kubectl logs` to be useful or `kubectl exec` directly to your `Pods` and check
|
||||
service from there.
|
||||
|
||||
Another thing to check is that your `Pods` are not crashing or being restarted.
|
||||
Frequent restarts could lead to intermittent connectivity issues.
|
||||
|
||||
```shell
|
||||
$ 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
|
||||
```
|
||||
|
||||
If the restart count is high, read more about how to [debug
|
||||
pods](/docs/tasks/debug-application-cluster/debug-pod-replication-controller/#debugging-pods).
|
||||
|
||||
## Is the kube-proxy working?
|
||||
|
||||
If you get here, your `Service` is running, has `Endpoints`, and your `Pods`
|
||||
are actually serving. At this point, the whole `Service` proxy mechanism is
|
||||
suspect. Let's confirm it, piece by piece.
|
||||
|
||||
### Is kube-proxy running?
|
||||
|
||||
Confirm that `kube-proxy` is running on your `Nodes`. You should get something
|
||||
like the below:
|
||||
|
||||
```shell
|
||||
u@node$ 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
|
||||
```
|
||||
|
||||
Next, confirm that it is not failing something obvious, like contacting the
|
||||
master. To do this, you'll have to look at the logs. Accessing the logs
|
||||
depends on your `Node` OS. On some OSes it is a file, such as
|
||||
/var/log/kube-proxy.log, while other OSes use `journalctl` to access logs. You
|
||||
should see something like:
|
||||
|
||||
```shell
|
||||
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:53.999055 5063 server.go:255] Tearing down userspace rules. Errors here are acceptable.
|
||||
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
|
||||
```
|
||||
|
||||
If you see error messages about not being able to contact the master, you
|
||||
should double-check your `Node` configuration and installation steps.
|
||||
|
||||
One of the possible reasons that `kube-proxy` cannot run correctly is that the
|
||||
required `conntrack` binary cannot be found. This may happen on some Linux
|
||||
systems, depending on how you are installing the cluster, for example, you are
|
||||
installing Kubernetes from scratch. If this is the case, you need to manually
|
||||
install the `conntrack` package (e.g. `sudo apt install conntrack` on Ubuntu)
|
||||
and then retry.
|
||||
|
||||
### Is kube-proxy writing iptables rules?
|
||||
|
||||
One of the main responsibilities of `kube-proxy` is to write the `iptables`
|
||||
rules which implement `Services`. Let's check that those rules are getting
|
||||
written.
|
||||
|
||||
The kube-proxy can run in either "userspace" mode or "iptables" mode.
|
||||
Hopefully you are using the newer, faster, more stable "iptables" mode. You
|
||||
should see one of the following cases.
|
||||
|
||||
#### Userspace
|
||||
|
||||
```shell
|
||||
u@node$ iptables-save | grep hostnames
|
||||
-A KUBE-PORTALS-CONTAINER -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j REDIRECT --to-ports 48577
|
||||
-A KUBE-PORTALS-HOST -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j DNAT --to-destination 10.240.115.247:48577
|
||||
```
|
||||
|
||||
There should be 2 rules for each port on your `Service` (just one in this
|
||||
example) - a "KUBE-PORTALS-CONTAINER" and a "KUBE-PORTALS-HOST". If you do
|
||||
not see these, try restarting `kube-proxy` with the `-V` flag set to 4, and
|
||||
then look at the logs again.
|
||||
|
||||
Almost nobody should be using the "userspace" mode any more, so we won't spend
|
||||
more time on it here.
|
||||
|
||||
#### Iptables
|
||||
|
||||
```shell
|
||||
u@node$ 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
|
||||
```
|
||||
|
||||
There should be 1 rule in `KUBE-SERVICES`, 1 or 2 rules per endpoint in
|
||||
`KUBE-SVC-(hash)` (depending on `SessionAffinity`), one `KUBE-SEP-(hash)` chain
|
||||
per endpoint, and a few rules in each `KUBE-SEP-(hash)` chain. The exact rules
|
||||
will vary based on your exact config (including node-ports and load-balancers).
|
||||
|
||||
### Is kube-proxy proxying?
|
||||
|
||||
Assuming you do see the above rules, try again to access your `Service` by IP:
|
||||
|
||||
```shell
|
||||
u@node$ curl 10.0.1.175:80
|
||||
hostnames-0uton
|
||||
```
|
||||
|
||||
If this fails and you are using the userspace proxy, you can try accessing the
|
||||
proxy directly. If you are using the iptables proxy, skip this section.
|
||||
|
||||
Look back at the `iptables-save` output above, and extract the
|
||||
port number that `kube-proxy` is using for your `Service`. In the above
|
||||
examples it is "48577". Now connect to that:
|
||||
|
||||
```shell
|
||||
u@node$ curl localhost:48577
|
||||
hostnames-yp2kp
|
||||
```
|
||||
|
||||
If this still fails, look at the `kube-proxy` logs for specific lines like:
|
||||
|
||||
```shell
|
||||
Setting endpoints for default/hostnames:default to [10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376]
|
||||
```
|
||||
|
||||
If you don't see those, try restarting `kube-proxy` with the `-V` flag set to 4, and
|
||||
then look at the logs again.
|
||||
|
||||
### A Pod cannot reach itself via Service IP
|
||||
|
||||
This can happen when the network is not properly configured for "hairpin"
|
||||
traffic, usually when `kube-proxy` is running in `iptables` mode and Pods
|
||||
are connected with bridge network. The `Kubelet` exposes a `hairpin-mode`
|
||||
[flag](/docs/admin/kubelet/) that allows endpoints of a Service to loadbalance back to themselves
|
||||
if they try to access their own Service VIP. The `hairpin-mode` flag must either be
|
||||
set to `hairpin-veth` or `promiscuous-bridge`.
|
||||
|
||||
The common steps to trouble shoot this are as follows:
|
||||
|
||||
* Confirm `hairpin-mode` is set to `hairpin-veth` or `promiscuous-bridge`.
|
||||
You should see something like the below. `hairpin-mode` is set to
|
||||
`promiscuous-bridge` in the following example.
|
||||
|
||||
```shell
|
||||
u@node$ 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
|
||||
|
||||
```
|
||||
|
||||
* Confirm the effective `hairpin-mode`. To do this, you'll have to look at
|
||||
kubelet log. Accessing the logs depends on your Node OS. On some OSes it
|
||||
is a file, such as /var/log/kubelet.log, while other OSes use `journalctl`
|
||||
to access logs. Please be noted that the effective hairpin mode may not
|
||||
match `--hairpin-mode` flag due to compatibility. Check if there is any log
|
||||
lines with key word `hairpin` in kubelet.log. There should be log lines
|
||||
indicating the effective hairpin mode, like something below.
|
||||
|
||||
```shell
|
||||
I0629 00:51:43.648698 3252 kubelet.go:380] Hairpin mode set to "promiscuous-bridge"
|
||||
```
|
||||
|
||||
* If the effective hairpin mode is `hairpin-veth`, ensure the `Kubelet` has
|
||||
the permission to operate in `/sys` on node. If everything works properly,
|
||||
you should see something like:
|
||||
|
||||
```shell
|
||||
u@node$ for intf in /sys/devices/virtual/net/cbr0/brif/*; do cat $intf/hairpin_mode; done
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
```
|
||||
|
||||
* If the effective hairpin mode is `promiscuous-bridge`, ensure `Kubelet`
|
||||
has the permission to manipulate linux bridge on node. If cbr0` bridge is
|
||||
used and configured properly, you should see:
|
||||
|
||||
```shell
|
||||
u@node$ ifconfig cbr0 |grep PROMISC
|
||||
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1460 Metric:1
|
||||
|
||||
```
|
||||
|
||||
* Seek help if none of above works out.
|
||||
|
||||
|
||||
## Seek help
|
||||
|
||||
If you get this far, something very strange is happening. Your `Service` is
|
||||
running, has `Endpoints`, and your `Pods` are actually serving. You have DNS
|
||||
working, `iptables` rules installed, and `kube-proxy` does not seem to be
|
||||
misbehaving. And yet your `Service` is not working. You should probably let
|
||||
us know, so we can help investigate!
|
||||
|
||||
Contact us on
|
||||
[Slack](/docs/troubleshooting/#slack) or
|
||||
[email](https://groups.google.com/forum/#!forum/kubernetes-users) or
|
||||
[GitHub](https://github.com/kubernetes/kubernetes).
|
||||
|
||||
## More information
|
||||
|
||||
Visit [troubleshooting document](/docs/troubleshooting/) for more information.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
reviewers:
|
||||
- bprashanth
|
||||
- enisoc
|
||||
- erictune
|
||||
- foxish
|
||||
- janetkuo
|
||||
- kow3ns
|
||||
- smarterclayton
|
||||
title: Debug a StatefulSet
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
This task shows you how to debug a StatefulSet.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
* You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster.
|
||||
* You should have a StatefulSet running that you want to investigate.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
## Debugging a StatefulSet
|
||||
|
||||
In order to list all the pods which belong to a StatefulSet, which have a label `app=myapp` set on them,
|
||||
you can use the following:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=myapp
|
||||
```
|
||||
|
||||
If you find that any Pods listed are in `Unknown` or `Terminating` state for an extended period of time,
|
||||
refer to the [Deleting StatefulSet Pods](/docs/tasks/manage-stateful-set/delete-pods/) task for
|
||||
instructions on how to deal with them.
|
||||
You can debug individual Pods in a StatefulSet using the
|
||||
[Debugging Pods](/docs/tasks/debug-application-cluster/debug-pod-replication-controller/) guide.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
Learn more about [debugging an init-container](/docs/tasks/debug-application-cluster/debug-init-containers/).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
title: Determine the Reason for Pod Failure
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
This page shows how to write and read a Container
|
||||
termination message.
|
||||
|
||||
Termination messages provide a way for containers to write
|
||||
information about fatal events to a location where it can
|
||||
be easily retrieved and surfaced by tools like dashboards
|
||||
and monitoring software. In most cases, information that you
|
||||
put in a termination message should also be written to
|
||||
the general
|
||||
[Kubernetes logs](/docs/concepts/cluster-administration/logging/).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
## Writing and reading a termination message
|
||||
|
||||
In this exercise, you create a Pod that runs one container.
|
||||
The configuration file specifies a command that runs when
|
||||
the container starts.
|
||||
|
||||
{{< code file="termination.yaml" >}}
|
||||
|
||||
1. Create a Pod based on the YAML configuration file:
|
||||
|
||||
kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/termination.yaml
|
||||
|
||||
In the YAML file, in the `cmd` and `args` fields, you can see that the
|
||||
container sleeps for 10 seconds and then writes "Sleep expired" to
|
||||
the `/dev/termination-log` file. After the container writes
|
||||
the "Sleep expired" message, it terminates.
|
||||
|
||||
1. Display information about the Pod:
|
||||
|
||||
kubectl get pod termination-demo
|
||||
|
||||
Repeat the preceding command until the Pod is no longer running.
|
||||
|
||||
1. Display detailed information about the Pod:
|
||||
|
||||
kubectl get pod --output=yaml
|
||||
|
||||
The output includes the "Sleep expired" message:
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
...
|
||||
lastState:
|
||||
terminated:
|
||||
containerID: ...
|
||||
exitCode: 0
|
||||
finishedAt: ...
|
||||
message: |
|
||||
Sleep expired
|
||||
...
|
||||
|
||||
1. Use a Go template to filter the output so that it includes
|
||||
only the termination message:
|
||||
|
||||
```
|
||||
kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"
|
||||
```
|
||||
|
||||
## Customizing the termination message
|
||||
|
||||
Kubernetes retrieves termination messages from the termination message file
|
||||
specified in the `terminationMessagePath` field of a Container, which as a default
|
||||
value of `/dev/termination-log`. By customizing this field, you can tell Kubernetes
|
||||
to use a different file. Kubernetes use the contents from the specified file to
|
||||
populate the Container's status message on both success and failure.
|
||||
|
||||
In the following example, the container writes termination messages to
|
||||
`/tmp/my-log` for Kubernetes to retrieve:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: msg-path-demo
|
||||
spec:
|
||||
containers:
|
||||
- name: msg-path-demo-container
|
||||
image: debian
|
||||
terminationMessagePath: "/tmp/my-log"
|
||||
```
|
||||
|
||||
Moreover, users can set the `terminationMessagePolicy` field of a Container for
|
||||
further customization. This field defaults to "`File`" which means the termination
|
||||
messages are retrieved only from the termination message file. By setting the
|
||||
`terminationMessagePolicy` to "`FallbackToLogsOnError`", you can tell Kubernetes
|
||||
to use the last chunk of container log output if the termination message file
|
||||
is empty and the container exited with an error. The log output is limited to
|
||||
2048 bytes or 80 lines, whichever is smaller.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* See the `terminationMessagePath` field in
|
||||
[Container](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core).
|
||||
* Learn about [retrieving logs](/docs/concepts/cluster-administration/logging/).
|
||||
* Learn about [Go templates](https://golang.org/pkg/text/template/).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: event-exporter-sa
|
||||
namespace: default
|
||||
labels:
|
||||
app: event-exporter
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: event-exporter-rb
|
||||
labels:
|
||||
app: event-exporter
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: view
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: event-exporter-sa
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: event-exporter-v0.1.0
|
||||
namespace: default
|
||||
labels:
|
||||
app: event-exporter
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: event-exporter
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: event-exporter
|
||||
spec:
|
||||
serviceAccountName: event-exporter-sa
|
||||
containers:
|
||||
- name: event-exporter
|
||||
image: k8s.gcr.io/event-exporter:v0.1.0
|
||||
command:
|
||||
- '/event-exporter'
|
||||
terminationGracePeriodSeconds: 30
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
reviewers:
|
||||
- piosz
|
||||
- x13n
|
||||
title: Events in Stackdriver
|
||||
---
|
||||
|
||||
|
||||
|
||||
Kubernetes events are objects that provide insight into what is happening
|
||||
inside a cluster, such as what decisions were made by scheduler or why some
|
||||
pods were evicted from the node. You can read more about using events
|
||||
for debugging your application in the [Application Introspection and Debugging
|
||||
](/docs/tasks/debug-application-cluster/debug-application-introspection/)
|
||||
section.
|
||||
|
||||
Since events are API objects, they are stored in the apiserver on master. To
|
||||
avoid filling up master's disk, a retention policy is enforced: events are
|
||||
removed one hour after the last occurrence. To provide longer history
|
||||
and aggregation capabilities, a third party solution should be installed
|
||||
to capture events.
|
||||
|
||||
This article describes a solution that exports Kubernetes events to
|
||||
Stackdriver Logging, where they can be processed and analyzed.
|
||||
|
||||
**Note:** it is not guaranteed that all events happening in a cluster will be
|
||||
exported to Stackdriver. One possible scenario when events will not be
|
||||
exported is when event exporter is not running (e.g. during restart or
|
||||
upgrade). In most cases it's fine to use events for purposes like setting up
|
||||
[metrics][sdLogMetrics] and [alerts][sdAlerts], but you should be aware
|
||||
of the potential inaccuracy.
|
||||
|
||||
[sdLogMetrics]: https://cloud.google.com/logging/docs/view/logs_based_metrics
|
||||
[sdAlerts]: https://cloud.google.com/logging/docs/view/logs_based_metrics#creating_an_alerting_policy
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Deployment
|
||||
|
||||
### Google Kubernetes Engine
|
||||
|
||||
In Google Kubernetes Engine, if cloud logging is enabled, event exporter
|
||||
is deployed by default to the clusters with master running version 1.7 and
|
||||
higher. To prevent disturbing your workloads, event exporter does not have
|
||||
resources set and is in the best effort QOS class, which means that it will
|
||||
be the first to be killed in the case of resource starvation. If you want
|
||||
your events to be exported, make sure you have enough resources to facilitate
|
||||
the event exporter pod. This may vary depending on the workload, but on
|
||||
average, approximately 100Mb RAM and 100m CPU is needed.
|
||||
|
||||
### Deploying to the Existing Cluster
|
||||
|
||||
Deploy event exporter to your cluster using the following command:
|
||||
|
||||
```shell
|
||||
kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/event-exporter-deploy.yaml
|
||||
```
|
||||
|
||||
Since event exporter accesses the Kubernetes API, it requires permissions to
|
||||
do so. The following deployment is configured to work with RBAC
|
||||
authorization. It sets up a service account and a cluster role binding
|
||||
to allow event exporter to read events. To make sure that event exporter
|
||||
pod will not be evicted from the node, you can additionally set up resource
|
||||
requests. As mentioned earlier, 100Mb RAM and 100m CPU should be enough.
|
||||
|
||||
{{< code file="event-exporter-deploy.yaml" >}}
|
||||
|
||||
## User Guide
|
||||
|
||||
Events are exported to the `GKE Cluster` resource in Stackdriver Logging.
|
||||
You can find them by selecting an appropriate option from a drop-down menu
|
||||
of available resources:
|
||||
|
||||
<img src="/images/docs/stackdriver-event-exporter-resource.png" alt="Events location in the Stackdriver Logging interface" width="500">
|
||||
|
||||
You can filter based on the event object fields using Stackdriver Logging
|
||||
[filtering mechanism](https://cloud.google.com/logging/docs/view/advanced_filters).
|
||||
For example, the following query will show events from the scheduler
|
||||
about pods from deployment `nginx-deployment`:
|
||||
|
||||
```
|
||||
resource.type="gke_cluster"
|
||||
jsonPayload.kind="Event"
|
||||
jsonPayload.source.component="default-scheduler"
|
||||
jsonPayload.involvedObject.name:"nginx-deployment"
|
||||
```
|
||||
|
||||
<img src="/images/docs/stackdriver-event-exporter-filter.png" alt="Filtered events in the Stackdriver Logging interface" width="500">
|
||||
@@ -0,0 +1,390 @@
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
data:
|
||||
containers.input.conf: |-
|
||||
# This configuration file for Fluentd is used
|
||||
# to watch changes to Docker log files that live in the
|
||||
# directory /var/lib/docker/containers/ and are symbolically
|
||||
# linked to from the /var/log/containers directory using names that capture the
|
||||
# pod name and container name. These logs are then submitted to
|
||||
# Google Cloud Logging which assumes the installation of the cloud-logging plug-in.
|
||||
#
|
||||
# Example
|
||||
# =======
|
||||
# A line in the Docker log file might look like this JSON:
|
||||
#
|
||||
# {"log":"2014/09/25 21:15:03 Got request with path wombat\\n",
|
||||
# "stream":"stderr",
|
||||
# "time":"2014-09-25T21:15:03.499185026Z"}
|
||||
#
|
||||
# The record reformer is used to write the tag to focus on the pod name
|
||||
# and the Kubernetes container name. For example a Docker container's logs
|
||||
# might be in the directory:
|
||||
# /var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b
|
||||
# and in the file:
|
||||
# 997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log
|
||||
# where 997599971ee6... is the Docker ID of the running container.
|
||||
# The Kubernetes kubelet makes a symbolic link to this file on the host machine
|
||||
# in the /var/log/containers directory which includes the pod name and the Kubernetes
|
||||
# container name:
|
||||
# synthetic-logger-0.25lps-pod_default-synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log
|
||||
# ->
|
||||
# /var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log
|
||||
# The /var/log directory on the host is mapped to the /var/log directory in the container
|
||||
# running this instance of Fluentd and we end up collecting the file:
|
||||
# /var/log/containers/synthetic-logger-0.25lps-pod_default-synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log
|
||||
# This results in the tag:
|
||||
# var.log.containers.synthetic-logger-0.25lps-pod_default-synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log
|
||||
# The record reformer is used is discard the var.log.containers prefix and
|
||||
# the Docker container ID suffix and "kubernetes." is pre-pended giving the tag:
|
||||
# kubernetes.synthetic-logger-0.25lps-pod_default-synth-lgr
|
||||
# Tag is then parsed by google_cloud plugin and translated to the metadata,
|
||||
# visible in the log viewer
|
||||
|
||||
# Example:
|
||||
# {"log":"[info:2016-02-16T16:04:05.930-08:00] Some log text here\n","stream":"stdout","time":"2016-02-17T00:04:05.931087621Z"}
|
||||
<source>
|
||||
type tail
|
||||
format json
|
||||
time_key time
|
||||
path /var/log/containers/*.log
|
||||
pos_file /var/log/gcp-containers.log.pos
|
||||
time_format %Y-%m-%dT%H:%M:%S.%N%Z
|
||||
tag reform.*
|
||||
read_from_head true
|
||||
</source>
|
||||
|
||||
<filter reform.**>
|
||||
type parser
|
||||
format /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<log>.*)/
|
||||
reserve_data true
|
||||
suppress_parse_error_log true
|
||||
key_name log
|
||||
</filter>
|
||||
|
||||
<match reform.**>
|
||||
type record_reformer
|
||||
enable_ruby true
|
||||
tag raw.kubernetes.${tag_suffix[4].split('-')[0..-2].join('-')}
|
||||
</match>
|
||||
|
||||
# Detect exceptions in the log output and forward them as one log entry.
|
||||
<match raw.kubernetes.**>
|
||||
@type copy
|
||||
|
||||
<store>
|
||||
@type prometheus
|
||||
|
||||
<metric>
|
||||
type counter
|
||||
name logging_line_count
|
||||
desc Total number of lines generated by application containers
|
||||
<labels>
|
||||
tag ${tag}
|
||||
</labels>
|
||||
</metric>
|
||||
</store>
|
||||
<store>
|
||||
@type detect_exceptions
|
||||
|
||||
remove_tag_prefix raw
|
||||
message log
|
||||
stream stream
|
||||
multiline_flush_interval 5
|
||||
max_bytes 500000
|
||||
max_lines 1000
|
||||
</store>
|
||||
</match>
|
||||
system.input.conf: |-
|
||||
# Example:
|
||||
# 2015-12-21 23:17:22,066 [salt.state ][INFO ] Completed state [net.ipv4.ip_forward] at time 23:17:22.066081
|
||||
<source>
|
||||
type tail
|
||||
format /^(?<time>[^ ]* [^ ,]*)[^\[]*\[[^\]]*\]\[(?<severity>[^ \]]*) *\] (?<message>.*)$/
|
||||
time_format %Y-%m-%d %H:%M:%S
|
||||
path /var/log/salt/minion
|
||||
pos_file /var/log/gcp-salt.pos
|
||||
tag salt
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# Dec 21 23:17:22 gke-foo-1-1-4b5cbd14-node-4eoj startupscript: Finished running startup script /var/run/google.startup.script
|
||||
<source>
|
||||
type tail
|
||||
format syslog
|
||||
path /var/log/startupscript.log
|
||||
pos_file /var/log/gcp-startupscript.log.pos
|
||||
tag startupscript
|
||||
</source>
|
||||
|
||||
# Examples:
|
||||
# time="2016-02-04T06:51:03.053580605Z" level=info msg="GET /containers/json"
|
||||
# time="2016-02-04T07:53:57.505612354Z" level=error msg="HTTP Error" err="No such image: -f" statusCode=404
|
||||
<source>
|
||||
type tail
|
||||
format /^time="(?<time>[^)]*)" level=(?<severity>[^ ]*) msg="(?<message>[^"]*)"( err="(?<error>[^"]*)")?( statusCode=($<status_code>\d+))?/
|
||||
path /var/log/docker.log
|
||||
pos_file /var/log/gcp-docker.log.pos
|
||||
tag docker
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# 2016/02/04 06:52:38 filePurge: successfully removed file /var/etcd/data/member/wal/00000000000006d0-00000000010a23d1.wal
|
||||
<source>
|
||||
type tail
|
||||
# Not parsing this, because it doesn't have anything particularly useful to
|
||||
# parse out of it (like severities).
|
||||
format none
|
||||
path /var/log/etcd.log
|
||||
pos_file /var/log/gcp-etcd.log.pos
|
||||
tag etcd
|
||||
</source>
|
||||
|
||||
# Multi-line parsing is required for all the kube logs because very large log
|
||||
# statements, such as those that include entire object bodies, get split into
|
||||
# multiple lines by glog.
|
||||
|
||||
# Example:
|
||||
# I0204 07:32:30.020537 3368 server.go:1048] POST /stats/container/: (13.972191ms) 200 [[Go-http-client/1.1] 10.244.1.3:40537]
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\w\d{4}/
|
||||
format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
|
||||
time_format %m%d %H:%M:%S.%N
|
||||
path /var/log/kubelet.log
|
||||
pos_file /var/log/gcp-kubelet.log.pos
|
||||
tag kubelet
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# I1118 21:26:53.975789 6 proxier.go:1096] Port "nodePort for kube-system/default-http-backend:http" (:31429/tcp) was open before and is still needed
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\w\d{4}/
|
||||
format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
|
||||
time_format %m%d %H:%M:%S.%N
|
||||
path /var/log/kube-proxy.log
|
||||
pos_file /var/log/gcp-kube-proxy.log.pos
|
||||
tag kube-proxy
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# I0204 07:00:19.604280 5 handlers.go:131] GET /api/v1/nodes: (1.624207ms) 200 [[kube-controller-manager/v1.1.3 (linux/amd64) kubernetes/6a81b50] 127.0.0.1:38266]
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\w\d{4}/
|
||||
format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
|
||||
time_format %m%d %H:%M:%S.%N
|
||||
path /var/log/kube-apiserver.log
|
||||
pos_file /var/log/gcp-kube-apiserver.log.pos
|
||||
tag kube-apiserver
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# 2017-02-09T00:15:57.992775796Z AUDIT: id="90c73c7c-97d6-4b65-9461-f94606ff825f" ip="104.132.1.72" method="GET" user="kubecfg" as="<self>" asgroups="<lookup>" namespace="default" uri="/api/v1/namespaces/default/pods"
|
||||
# 2017-02-09T00:15:57.993528822Z AUDIT: id="90c73c7c-97d6-4b65-9461-f94606ff825f" response="200"
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\S+\s+AUDIT:/
|
||||
# Fields must be explicitly captured by name to be parsed into the record.
|
||||
# Fields may not always be present, and order may change, so this just looks
|
||||
# for a list of key="\"quoted\" value" pairs separated by spaces.
|
||||
# Unknown fields are ignored.
|
||||
# Note: We can't separate query/response lines as format1/format2 because
|
||||
# they don't always come one after the other for a given query.
|
||||
# TODO: Maybe add a JSON output mode to audit log so we can get rid of this?
|
||||
format1 /^(?<time>\S+) AUDIT:(?: (?:id="(?<id>(?:[^"\\]|\\.)*)"|ip="(?<ip>(?:[^"\\]|\\.)*)"|method="(?<method>(?:[^"\\]|\\.)*)"|user="(?<user>(?:[^"\\]|\\.)*)"|groups="(?<groups>(?:[^"\\]|\\.)*)"|as="(?<as>(?:[^"\\]|\\.)*)"|asgroups="(?<asgroups>(?:[^"\\]|\\.)*)"|namespace="(?<namespace>(?:[^"\\]|\\.)*)"|uri="(?<uri>(?:[^"\\]|\\.)*)"|response="(?<response>(?:[^"\\]|\\.)*)"|\w+="(?:[^"\\]|\\.)*"))*/
|
||||
time_format %FT%T.%L%Z
|
||||
path /var/log/kube-apiserver-audit.log
|
||||
pos_file /var/log/gcp-kube-apiserver-audit.log.pos
|
||||
tag kube-apiserver-audit
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# I0204 06:55:31.872680 5 servicecontroller.go:277] LB already exists and doesn't need update for service kube-system/kubernetes-dashboard
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\w\d{4}/
|
||||
format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
|
||||
time_format %m%d %H:%M:%S.%N
|
||||
path /var/log/kube-controller-manager.log
|
||||
pos_file /var/log/gcp-kube-controller-manager.log.pos
|
||||
tag kube-controller-manager
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# W0204 06:49:18.239674 7 reflector.go:245] pkg/scheduler/factory/factory.go:193: watch of *api.Service ended with: 401: The event in requested index is outdated and cleared (the requested history has been cleared [2578313/2577886]) [2579312]
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\w\d{4}/
|
||||
format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
|
||||
time_format %m%d %H:%M:%S.%N
|
||||
path /var/log/kube-scheduler.log
|
||||
pos_file /var/log/gcp-kube-scheduler.log.pos
|
||||
tag kube-scheduler
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# I1104 10:36:20.242766 5 rescheduler.go:73] Running Rescheduler
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\w\d{4}/
|
||||
format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
|
||||
time_format %m%d %H:%M:%S.%N
|
||||
path /var/log/rescheduler.log
|
||||
pos_file /var/log/gcp-rescheduler.log.pos
|
||||
tag rescheduler
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# I0603 15:31:05.793605 6 cluster_manager.go:230] Reading config from path /etc/gce.conf
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\w\d{4}/
|
||||
format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
|
||||
time_format %m%d %H:%M:%S.%N
|
||||
path /var/log/glbc.log
|
||||
pos_file /var/log/gcp-glbc.log.pos
|
||||
tag glbc
|
||||
</source>
|
||||
|
||||
# Example:
|
||||
# I0603 15:31:05.793605 6 cluster_manager.go:230] Reading config from path /etc/gce.conf
|
||||
<source>
|
||||
type tail
|
||||
format multiline
|
||||
multiline_flush_interval 5s
|
||||
format_firstline /^\w\d{4}/
|
||||
format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
|
||||
time_format %m%d %H:%M:%S.%N
|
||||
path /var/log/cluster-autoscaler.log
|
||||
pos_file /var/log/gcp-cluster-autoscaler.log.pos
|
||||
tag cluster-autoscaler
|
||||
</source>
|
||||
|
||||
# Logs from systemd-journal for interesting services.
|
||||
<source>
|
||||
type systemd
|
||||
filters [{ "_SYSTEMD_UNIT": "docker.service" }]
|
||||
pos_file /var/log/gcp-journald-docker.pos
|
||||
read_from_head true
|
||||
tag docker
|
||||
</source>
|
||||
|
||||
<source>
|
||||
type systemd
|
||||
filters [{ "_SYSTEMD_UNIT": "kubelet.service" }]
|
||||
pos_file /var/log/gcp-journald-kubelet.pos
|
||||
read_from_head true
|
||||
tag kubelet
|
||||
</source>
|
||||
monitoring.conf: |-
|
||||
# Prometheus monitoring
|
||||
<source>
|
||||
@type prometheus
|
||||
port 80
|
||||
</source>
|
||||
|
||||
<source>
|
||||
@type prometheus_monitor
|
||||
</source>
|
||||
output.conf: |-
|
||||
# We use 2 output stanzas - one to handle the container logs and one to handle
|
||||
# the node daemon logs, the latter of which explicitly sends its logs to the
|
||||
# compute.googleapis.com service rather than container.googleapis.com to keep
|
||||
# them separate since most users don't care about the node logs.
|
||||
<match kubernetes.**>
|
||||
@type copy
|
||||
|
||||
<store>
|
||||
@type google_cloud
|
||||
|
||||
# Set the buffer type to file to improve the reliability and reduce the memory consumption
|
||||
buffer_type file
|
||||
buffer_path /var/log/fluentd-buffers/kubernetes.containers.buffer
|
||||
# Set queue_full action to block because we want to pause gracefully
|
||||
# in case of the off-the-limits load instead of throwing an exception
|
||||
buffer_queue_full_action block
|
||||
# Set the chunk limit conservatively to avoid exceeding the GCL limit
|
||||
# of 10MiB per write request.
|
||||
buffer_chunk_limit 2M
|
||||
# Cap the combined memory usage of this buffer and the one below to
|
||||
# 2MiB/chunk * (6 + 2) chunks = 16 MiB
|
||||
buffer_queue_limit 6
|
||||
# Never wait more than 5 seconds before flushing logs in the non-error case.
|
||||
flush_interval 5s
|
||||
# Never wait longer than 30 seconds between retries.
|
||||
max_retry_wait 30
|
||||
# Disable the limit on the number of retries (retry forever).
|
||||
disable_retry_limit
|
||||
# Use multiple threads for processing.
|
||||
num_threads 2
|
||||
</store>
|
||||
<store>
|
||||
@type prometheus
|
||||
|
||||
<metric>
|
||||
type counter
|
||||
name logging_entry_count
|
||||
desc Total number of log entries generated by either an application container or a system component
|
||||
<labels>
|
||||
tag ${tag}
|
||||
component container
|
||||
</labels>
|
||||
</metric>
|
||||
</store>
|
||||
</match>
|
||||
|
||||
# Keep a smaller buffer here since these logs are less important than the user's
|
||||
# container logs.
|
||||
<match **>
|
||||
@type copy
|
||||
|
||||
<store>
|
||||
@type google_cloud
|
||||
|
||||
detect_subservice false
|
||||
buffer_type file
|
||||
buffer_path /var/log/fluentd-buffers/kubernetes.system.buffer
|
||||
buffer_queue_full_action block
|
||||
buffer_chunk_limit 2M
|
||||
buffer_queue_limit 2
|
||||
flush_interval 5s
|
||||
max_retry_wait 30
|
||||
disable_retry_limit
|
||||
num_threads 2
|
||||
</store>
|
||||
<store>
|
||||
@type prometheus
|
||||
|
||||
<metric>
|
||||
type counter
|
||||
name logging_entry_count
|
||||
desc Total number of log entries generated by either an application container or a system component
|
||||
<labels>
|
||||
tag ${tag}
|
||||
component system
|
||||
</labels>
|
||||
</metric>
|
||||
</store>
|
||||
</match>
|
||||
metadata:
|
||||
name: fluentd-gcp-config
|
||||
labels:
|
||||
addonmanager.kubernetes.io/mode: Reconcile
|
||||
@@ -0,0 +1,113 @@
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: fluentd-gcp-v2.0
|
||||
labels:
|
||||
k8s-app: fluentd-gcp
|
||||
kubernetes.io/cluster-service: "true"
|
||||
addonmanager.kubernetes.io/mode: Reconcile
|
||||
version: v2.0
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s-app: fluentd-gcp
|
||||
kubernetes.io/cluster-service: "true"
|
||||
version: v2.0
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: fluentd-gcp
|
||||
kubernetes.io/cluster-service: "true"
|
||||
version: v2.0
|
||||
# This annotation ensures that fluentd does not get evicted if the node
|
||||
# supports critical pod annotation based priority scheme.
|
||||
# Note that this does not guarantee admission on the nodes (#40573).
|
||||
annotations:
|
||||
scheduler.alpha.kubernetes.io/critical-pod: ''
|
||||
spec:
|
||||
dnsPolicy: Default
|
||||
containers:
|
||||
- name: fluentd-gcp
|
||||
image: k8s.gcr.io/fluentd-gcp:2.0.2
|
||||
# If fluentd consumes its own logs, the following situation may happen:
|
||||
# fluentd fails to send a chunk to the server => writes it to the log =>
|
||||
# tries to send this message to the server => fails to send a chunk and so on.
|
||||
# Writing to a file, which is not exported to the back-end prevents it.
|
||||
# It also allows to increase the fluentd verbosity by default.
|
||||
command:
|
||||
- '/bin/sh'
|
||||
- '-c'
|
||||
- '/run.sh $FLUENTD_ARGS 2>&1 >>/var/log/fluentd.log'
|
||||
env:
|
||||
- name: FLUENTD_ARGS
|
||||
value: --no-supervisor
|
||||
resources:
|
||||
limits:
|
||||
memory: 300Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 200Mi
|
||||
volumeMounts:
|
||||
- name: varlog
|
||||
mountPath: /var/log
|
||||
- name: varlibdockercontainers
|
||||
mountPath: /var/lib/docker/containers
|
||||
readOnly: true
|
||||
- name: libsystemddir
|
||||
mountPath: /host/lib
|
||||
readOnly: true
|
||||
- name: config-volume
|
||||
mountPath: /etc/fluent/config.d
|
||||
# Liveness probe is aimed to help in situations where fluentd
|
||||
# silently hangs for no apparent reasons until manual restart.
|
||||
# The idea of this probe is that if fluentd is not queueing or
|
||||
# flushing chunks for 5 minutes, something is not right. If
|
||||
# you want to change the fluentd configuration, reducing amount of
|
||||
# logs fluentd collects, consider changing the threshold or turning
|
||||
# liveness probe off completely.
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 600
|
||||
periodSeconds: 60
|
||||
exec:
|
||||
command:
|
||||
- '/bin/sh'
|
||||
- '-c'
|
||||
- >
|
||||
LIVENESS_THRESHOLD_SECONDS=${LIVENESS_THRESHOLD_SECONDS:-300};
|
||||
STUCK_THRESHOLD_SECONDS=${LIVENESS_THRESHOLD_SECONDS:-900};
|
||||
if [ ! -e /var/log/fluentd-buffers ];
|
||||
then
|
||||
exit 1;
|
||||
fi;
|
||||
LAST_MODIFIED_DATE=`stat /var/log/fluentd-buffers | grep Modify | sed -r "s/Modify: (.*)/\1/"`;
|
||||
LAST_MODIFIED_TIMESTAMP=`date -d "$LAST_MODIFIED_DATE" +%s`;
|
||||
if [ `date +%s` -gt `expr $LAST_MODIFIED_TIMESTAMP + $STUCK_THRESHOLD_SECONDS` ];
|
||||
then
|
||||
rm -rf /var/log/fluentd-buffers;
|
||||
exit 1;
|
||||
fi;
|
||||
if [ `date +%s` -gt `expr $LAST_MODIFIED_TIMESTAMP + $LIVENESS_THRESHOLD_SECONDS` ];
|
||||
then
|
||||
exit 1;
|
||||
fi;
|
||||
nodeSelector:
|
||||
beta.kubernetes.io/fluentd-ds-ready: "true"
|
||||
tolerations:
|
||||
- key: "node.alpha.kubernetes.io/ismaster"
|
||||
effect: "NoSchedule"
|
||||
terminationGracePeriodSeconds: 30
|
||||
volumes:
|
||||
- name: varlog
|
||||
hostPath:
|
||||
path: /var/log
|
||||
- name: varlibdockercontainers
|
||||
hostPath:
|
||||
path: /var/lib/docker/containers
|
||||
- name: libsystemddir
|
||||
hostPath:
|
||||
path: /usr/lib64
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: fluentd-gcp-config
|
||||
@@ -0,0 +1,146 @@
|
||||
---
|
||||
reviewers:
|
||||
- caesarxuchao
|
||||
- mikedanese
|
||||
title: Get a Shell to a Running Container
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
This page shows how to use `kubectl exec` to get a shell to a
|
||||
running Container.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
## Getting a shell to a Container
|
||||
|
||||
In this exercise, you create a Pod that has one Container. The Container
|
||||
runs the nginx image. Here is the configuration file for the Pod:
|
||||
|
||||
{{< code file="shell-demo.yaml" >}}
|
||||
|
||||
Create the Pod:
|
||||
|
||||
```shell
|
||||
kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/shell-demo.yaml
|
||||
```
|
||||
|
||||
Verify that the Container is running:
|
||||
|
||||
```shell
|
||||
kubectl get pod shell-demo
|
||||
```
|
||||
|
||||
Get a shell to the running Container:
|
||||
|
||||
```shell
|
||||
kubectl exec -it shell-demo -- /bin/bash
|
||||
```
|
||||
|
||||
In your shell, list the root directory:
|
||||
|
||||
```shell
|
||||
root@shell-demo:/# ls /
|
||||
```
|
||||
|
||||
In your shell, experiment with other commands. Here are
|
||||
some examples:
|
||||
|
||||
```shell
|
||||
root@shell-demo:/# ls /
|
||||
root@shell-demo:/# cat /proc/mounts
|
||||
root@shell-demo:/# cat /proc/1/maps
|
||||
root@shell-demo:/# apt-get update
|
||||
root@shell-demo:/# apt-get install -y tcpdump
|
||||
root@shell-demo:/# tcpdump
|
||||
root@shell-demo:/# apt-get install -y lsof
|
||||
root@shell-demo:/# lsof
|
||||
root@shell-demo:/# apt-get install -y procps
|
||||
root@shell-demo:/# ps aux
|
||||
root@shell-demo:/# ps aux | grep nginx
|
||||
```
|
||||
|
||||
## Writing the root page for nginx
|
||||
|
||||
Look again at the configuration file for your Pod. The Pod
|
||||
has an `emptyDir` volume, and the Container mounts the volume
|
||||
at `/usr/share/nginx/html`.
|
||||
|
||||
In your shell, create an `index.html` file in the `/usr/share/nginx/html`
|
||||
directory:
|
||||
|
||||
```shell
|
||||
root@shell-demo:/# echo Hello shell demo > /usr/share/nginx/html/index.html
|
||||
```
|
||||
|
||||
In your shell, send a GET request to the nginx server:
|
||||
|
||||
```shell
|
||||
root@shell-demo:/# apt-get update
|
||||
root@shell-demo:/# apt-get install curl
|
||||
root@shell-demo:/# curl localhost
|
||||
```
|
||||
|
||||
The output shows the text that you wrote to the `index.html` file:
|
||||
|
||||
```shell
|
||||
Hello shell demo
|
||||
```
|
||||
|
||||
When you are finished with your shell, enter `exit`.
|
||||
|
||||
## Running individual commands in a Container
|
||||
|
||||
In an ordinary command window, not your shell, list the environment
|
||||
variables in the running Container:
|
||||
|
||||
```shell
|
||||
kubectl exec shell-demo env
|
||||
```
|
||||
|
||||
Experiment running other commands. Here are some examples:
|
||||
|
||||
```shell
|
||||
kubectl exec shell-demo ps aux
|
||||
kubectl exec shell-demo ls /
|
||||
kubectl exec shell-demo cat /proc/1/mounts
|
||||
```
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture discussion %}}
|
||||
|
||||
## Opening a shell when a Pod has more than one Container
|
||||
|
||||
If a Pod has more than one Container, use `--container` or `-c` to
|
||||
specify a Container in the `kubectl exec` command. For example,
|
||||
suppose you have a Pod named my-pod, and the Pod has two containers
|
||||
named main-app and helper-app. The following command would open a
|
||||
shell to the main-app Container.
|
||||
|
||||
```shell
|
||||
kubectl exec -it my-pod --container main-app -- /bin/bash
|
||||
```
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* [kubectl exec](/docs/reference/generated/kubectl/kubectl-commands/#exec)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: Developing and debugging services locally
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
Kubernetes applications usually consist of multiple, separate services, each running in its own container. Developing and debugging these services on a remote Kubernetes cluster can be cumbersome, requiring you to [get a shell on a running container](https://kubernetes.io/docs/tasks/debug-application-cluster/get-shell-running-container/) and running your tools inside the remote shell.
|
||||
|
||||
`telepresence` is a tool to ease the process of developing and debugging services locally, while proxying the service to a remote Kubernetes cluster. Using `telepresence` allows you to use custom tools, such as a debugger and IDE, for a local service and provides the service full access to ConfigMap, secrets, and the services running on the remote cluster.
|
||||
|
||||
This document describes using `telepresence` to develop and debug services running on a remote cluster locally.
|
||||
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
* Kubernetes cluster is installed
|
||||
* `kubectl` is configured to communicate with the cluster
|
||||
* [Telepresence](https://www.telepresence.io/reference/install) is installed
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
## Getting a shell on a remote cluster
|
||||
|
||||
Open a terminal and run `telepresence` with no arguments to get a `telepresence` shell. This shell runs locally, giving you full access to your local filesystem.
|
||||
|
||||
The `telepresence` shell can be used in a variety of ways. For example, write a shell script on your laptop, and run it directly from the shell in real time. You can do this on a remote shell as well, but you might not be able to use your preferred code editor, and the script is deleted when the container is terminated.
|
||||
|
||||
Enter `exit` to quit and close the shell.
|
||||
|
||||
## Developing or debugging an existing service
|
||||
|
||||
When developing an application on Kubernetes, you typically program or debug a single service. The service might require access to other services for testing and debugging. One option is to use the continuous deployment pipeline, but even the fastest deployment pipeline introduces a delay in the program or debug cycle.
|
||||
|
||||
Use the `--swap-deployment` option to swap an existing deployment with the Telepresence proxy. Swapping allows you to run a service locally and connect to the remote Kubernetes cluster. The services in the remote cluster can now access the locally running instance.
|
||||
|
||||
To run telepresence with `--swap-deployment`, enter:
|
||||
|
||||
`telepresence --swap-deployment $DEPLOYMENT_NAME`
|
||||
|
||||
where $DEPLOYMENT_NAME is the name of your existing deployment.
|
||||
|
||||
Running this command spawns a shell. In the shell, start your service. You can then make edits to the source code locally, save, and see the changes take effect immediately. You can also run your service in a debugger, or any other local development tool.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
If you're interested in a hands-on tutorial, check out [this tutorial](https://cloud.google.com/community/tutorials/developing-services-with-k8s) that walks through locally developing the Guestbook application on Google Kubernetes Engine.
|
||||
|
||||
Telepresence has [numerous proxying options](https://www.telepresence.io/reference/methods), depending on your situation.
|
||||
|
||||
For further reading, visit the [Telepresence website](https://www.telepresence.io).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
---
|
||||
reviewers:
|
||||
- piosz
|
||||
- x13n
|
||||
title: Logging Using Elasticsearch and Kibana
|
||||
---
|
||||
|
||||
On the Google Compute Engine (GCE) platform, the default logging support targets
|
||||
[Stackdriver Logging](https://cloud.google.com/logging/), which is described in detail
|
||||
in the [Logging With Stackdriver Logging](/docs/user-guide/logging/stackdriver).
|
||||
|
||||
This article describes how to set up a cluster to ingest logs into
|
||||
[Elasticsearch](https://www.elastic.co/products/elasticsearch) and view
|
||||
them using [Kibana](https://www.elastic.co/products/kibana), as an alternative to
|
||||
Stackdriver Logging when running on GCE. Note that Elasticsearch and Kibana
|
||||
cannot be setup automatically in the Kubernetes cluster hosted on
|
||||
Google Kubernetes Engine, you have to deploy it manually.
|
||||
|
||||
To use Elasticsearch and Kibana for cluster logging, you should set the
|
||||
following environment variable as shown below when creating your cluster with
|
||||
kube-up.sh:
|
||||
|
||||
```shell
|
||||
KUBE_LOGGING_DESTINATION=elasticsearch
|
||||
```
|
||||
|
||||
You should also ensure that `KUBE_ENABLE_NODE_LOGGING=true` (which is the default for the GCE platform).
|
||||
|
||||
Now, when you create a cluster, a message will indicate that the Fluentd log
|
||||
collection daemons that run on each node will target Elasticsearch:
|
||||
|
||||
```shell
|
||||
$ cluster/kube-up.sh
|
||||
...
|
||||
Project: kubernetes-satnam
|
||||
Zone: us-central1-b
|
||||
... calling kube-up
|
||||
Project: kubernetes-satnam
|
||||
Zone: us-central1-b
|
||||
+++ Staging server tars to Google Storage: gs://kubernetes-staging-e6d0e81793/devel
|
||||
+++ kubernetes-server-linux-amd64.tar.gz uploaded (sha1 = 6987c098277871b6d69623141276924ab687f89d)
|
||||
+++ kubernetes-salt.tar.gz uploaded (sha1 = bdfc83ed6b60fa9e3bff9004b542cfc643464cd0)
|
||||
Looking for already existing resources
|
||||
Starting master and configuring firewalls
|
||||
Created [https://www.googleapis.com/compute/v1/projects/kubernetes-satnam/zones/us-central1-b/disks/kubernetes-master-pd].
|
||||
NAME ZONE SIZE_GB TYPE STATUS
|
||||
kubernetes-master-pd us-central1-b 20 pd-ssd READY
|
||||
Created [https://www.googleapis.com/compute/v1/projects/kubernetes-satnam/regions/us-central1/addresses/kubernetes-master-ip].
|
||||
+++ Logging using Fluentd to elasticsearch
|
||||
```
|
||||
|
||||
The per-node Fluentd pods, the Elasticsearch pods, and the Kibana pods should
|
||||
all be running in the kube-system namespace soon after the cluster comes to
|
||||
life.
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=kube-system
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
elasticsearch-logging-v1-78nog 1/1 Running 0 2h
|
||||
elasticsearch-logging-v1-nj2nb 1/1 Running 0 2h
|
||||
fluentd-elasticsearch-kubernetes-node-5oq0 1/1 Running 0 2h
|
||||
fluentd-elasticsearch-kubernetes-node-6896 1/1 Running 0 2h
|
||||
fluentd-elasticsearch-kubernetes-node-l1ds 1/1 Running 0 2h
|
||||
fluentd-elasticsearch-kubernetes-node-lz9j 1/1 Running 0 2h
|
||||
kibana-logging-v1-bhpo8 1/1 Running 0 2h
|
||||
kube-dns-v3-7r1l9 3/3 Running 0 2h
|
||||
monitoring-heapster-v4-yl332 1/1 Running 1 2h
|
||||
monitoring-influx-grafana-v1-o79xf 2/2 Running 0 2h
|
||||
```
|
||||
|
||||
The `fluentd-elasticsearch` pods gather logs from each node and send them to
|
||||
the `elasticsearch-logging` pods, which are part of a
|
||||
[service](/docs/concepts/services-networking/service/) named `elasticsearch-logging`. These
|
||||
Elasticsearch pods store the logs and expose them via a REST API.
|
||||
The `kibana-logging` pod provides a web UI for reading the logs stored in
|
||||
Elasticsearch, and is part of a service named `kibana-logging`.
|
||||
|
||||
The Elasticsearch and Kibana services are both in the `kube-system` namespace
|
||||
and are not directly exposed via a publicly reachable IP address. To reach them,
|
||||
follow the instructions for [Accessing services running in a cluster](/docs/concepts/cluster-administration/access-cluster/#accessing-services-running-on-the-cluster).
|
||||
|
||||
If you try accessing the `elasticsearch-logging` service in your browser, you'll
|
||||
see a status page that looks something like this:
|
||||
|
||||

|
||||
|
||||
You can now type Elasticsearch queries directly into the browser, if you'd
|
||||
like. See [Elasticsearch's documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html)
|
||||
for more details on how to do so.
|
||||
|
||||
Alternatively, you can view your cluster's logs using Kibana (again using the
|
||||
[instructions for accessing a service running in the cluster](/docs/user-guide/accessing-the-cluster/#accessing-services-running-on-the-cluster)).
|
||||
The first time you visit the Kibana URL you will be presented with a page that
|
||||
asks you to configure your view of the ingested logs. Select the option for
|
||||
timeseries values and select `@timestamp`. On the following page select the
|
||||
`Discover` tab and then you should be able to see the ingested logs.
|
||||
You can set the refresh interval to 5 seconds to have the logs
|
||||
regularly refreshed.
|
||||
|
||||
Here is a typical view of ingested logs from the Kibana viewer:
|
||||
|
||||

|
||||
|
||||
Kibana opens up all sorts of powerful options for exploring your logs! For some
|
||||
ideas on how to dig into it, check out [Kibana's documentation](https://www.elastic.co/guide/en/kibana/current/discover.html).
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
---
|
||||
reviewers:
|
||||
- piosz
|
||||
- x13n
|
||||
title: Logging Using Stackdriver
|
||||
---
|
||||
|
||||
Before reading this page, it's highly recommended to familiarize yourself
|
||||
with the [overview of logging in Kubernetes](/docs/concepts/cluster-administration/logging).
|
||||
|
||||
**Note:** By default, Stackdriver logging collects only your container's standard output and
|
||||
standard error streams. To collect any logs your application writes to a file (for example),
|
||||
see the [sidecar approach](/docs/concepts/cluster-administration/logging#sidecar-container-with-a-logging-agent)
|
||||
in the Kubernetes logging overview.
|
||||
|
||||
## Deploying
|
||||
|
||||
To ingest logs, you must deploy the Stackdriver Logging agent to each node in your cluster.
|
||||
The agent is a configured `fluentd` instance, where the configuration is stored in a `ConfigMap`
|
||||
and the instances are managed using a Kubernetes `DaemonSet`. The actual deployment of the
|
||||
`ConfigMap` and `DaemonSet` for your cluster depends on your individual cluster setup.
|
||||
|
||||
### Deploying to a new cluster
|
||||
|
||||
#### Google Kubernetes Engine
|
||||
|
||||
Stackdriver is the default logging solution for clusters deployed on Google Kubernetes Engine.
|
||||
Stackdriver Logging is deployed to a new cluster by default unless you explicitly opt-out.
|
||||
|
||||
#### Other platforms
|
||||
|
||||
To deploy Stackdriver Logging on a *new* cluster that you're
|
||||
creating using `kube-up.sh`, do the following:
|
||||
|
||||
1. Set the `KUBE_LOGGING_DESTINATION` environment variable to `gcp`.
|
||||
1. **If not running on GCE**, include the `beta.kubernetes.io/fluentd-ds-ready=true`
|
||||
in the `KUBE_NODE_LABELS` variable.
|
||||
|
||||
Once your cluster has started, each node should be running the Stackdriver Logging agent.
|
||||
The `DaemonSet` and `ConfigMap` are configured as addons. If you're not using `kube-up.sh`,
|
||||
consider starting a cluster without a pre-configured logging solution and then deploying
|
||||
Stackdriver Logging agents to the running cluster.
|
||||
|
||||
{{< warning >}}
|
||||
**Warning:** The Stackdriver logging daemon has known issues on platforms other
|
||||
than Google Kubernetes Engine. Proceed at your own risk.
|
||||
{{< /warning >}}
|
||||
|
||||
### Deploying to an existing cluster
|
||||
|
||||
1. Apply a label on each node, if not already present.
|
||||
|
||||
The Stackdriver Logging agent deployment uses node labels to determine to which nodes
|
||||
it should be allocated. These labels were introduced to distinguish nodes with the
|
||||
Kubernetes version 1.6 or higher. If the cluster was created with Stackdriver Logging
|
||||
configured and node has version 1.5.X or lower, it will have fluentd as static pod. Node
|
||||
cannot have more than one instance of fluentd, therefore only apply labels to the nodes
|
||||
that don't have fluentd pod allocated already. You can ensure that your node is labelled
|
||||
properly by running `kubectl describe` as follows:
|
||||
|
||||
```
|
||||
kubectl describe node $NODE_NAME
|
||||
```
|
||||
|
||||
The output should be similar to this:
|
||||
|
||||
```
|
||||
Name: NODE_NAME
|
||||
Role:
|
||||
Labels: beta.kubernetes.io/fluentd-ds-ready=true
|
||||
...
|
||||
```
|
||||
|
||||
Ensure that the output contains the label `beta.kubernetes.io/fluentd-ds-ready=true`. If it
|
||||
is not present, you can add it using the `kubectl label` command as follows:
|
||||
|
||||
```
|
||||
kubectl label node $NODE_NAME beta.kubernetes.io/fluentd-ds-ready=true
|
||||
```
|
||||
|
||||
**Note:** If a node fails and has to be recreated, you must re-apply the label to
|
||||
the recreated node. To make this easier, you can use Kubelet's command-line parameter
|
||||
for applying node labels in your node startup script.
|
||||
|
||||
1. Deploy a `ConfigMap` with the logging agent configuration by running the following command:
|
||||
|
||||
```
|
||||
kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/fluentd-gcp-configmap.yaml
|
||||
```
|
||||
|
||||
The command creates the `ConfigMap` in the `default` namespace. You can download the file
|
||||
manually and change it before creating the `ConfigMap` object.
|
||||
|
||||
1. Deploy the logging agent `DaemonSet` by running the following command:
|
||||
|
||||
```
|
||||
kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/fluentd-gcp-ds.yaml
|
||||
```
|
||||
|
||||
You can download and edit this file before using it as well.
|
||||
|
||||
## Verifying your Logging Agent Deployment
|
||||
|
||||
After Stackdriver `DaemonSet` is deployed, you can discover logging agent deployment status
|
||||
by running the following command:
|
||||
|
||||
```shell
|
||||
kubectl get ds --all-namespaces
|
||||
```
|
||||
|
||||
If you have 3 nodes in the cluster, the output should looks similar to this:
|
||||
|
||||
```
|
||||
NAMESPACE NAME DESIRED CURRENT READY NODE-SELECTOR AGE
|
||||
...
|
||||
default fluentd-gcp-v2.0 3 3 3 beta.kubernetes.io/fluentd-ds-ready=true 5m
|
||||
...
|
||||
```
|
||||
|
||||
To understand how logging with Stackdriver works, consider the following
|
||||
synthetic log generator pod specification [counter-pod.yaml](/docs/tasks/debug-application-cluster/counter-pod.yaml):
|
||||
|
||||
{{< code file="counter-pod.yaml" >}}
|
||||
|
||||
This pod specification has one container that runs a bash script
|
||||
that writes out the value of a counter and the date once per
|
||||
second, and runs indefinitely. Let's create this pod in the default namespace.
|
||||
|
||||
```shell
|
||||
kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/counter-pod.yaml
|
||||
```
|
||||
|
||||
You can observe the running pod:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
counter 1/1 Running 0 5m
|
||||
```
|
||||
|
||||
For a short period of time you can observe the 'Pending' pod status, because the kubelet
|
||||
has to download the container image first. When the pod status changes to `Running`
|
||||
you can use the `kubectl logs` command to view the output of this counter pod.
|
||||
|
||||
```shell
|
||||
$ kubectl logs counter
|
||||
0: Mon Jan 1 00:00:00 UTC 2001
|
||||
1: Mon Jan 1 00:00:01 UTC 2001
|
||||
2: Mon Jan 1 00:00:02 UTC 2001
|
||||
...
|
||||
```
|
||||
|
||||
As described in the logging overview, this command fetches log entries
|
||||
from the container log file. If the container is killed and then restarted by
|
||||
Kubernetes, you can still access logs from the previous container. However,
|
||||
if the pod is evicted from the node, log files are lost. Let's demonstrate this
|
||||
by deleting the currently running counter container:
|
||||
|
||||
```shell
|
||||
$ kubectl delete pod counter
|
||||
pod "counter" deleted
|
||||
```
|
||||
|
||||
and then recreating it:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/counter-pod.yaml
|
||||
pod "counter" created
|
||||
```
|
||||
|
||||
After some time, you can access logs from the counter pod again:
|
||||
|
||||
```shell
|
||||
$ kubectl logs counter
|
||||
0: Mon Jan 1 00:01:00 UTC 2001
|
||||
1: Mon Jan 1 00:01:01 UTC 2001
|
||||
2: Mon Jan 1 00:01:02 UTC 2001
|
||||
...
|
||||
```
|
||||
|
||||
As expected, only recent log lines are present. However, for a real-world
|
||||
application you will likely want to be able to access logs from all containers,
|
||||
especially for the debug purposes. This is exactly when the previously enabled
|
||||
Stackdriver Logging can help.
|
||||
|
||||
## Viewing logs
|
||||
|
||||
Stackdriver Logging agent attaches metadata to each log entry, for you to use later
|
||||
in queries to select only the messages you're interested in: for example,
|
||||
the messages from a particular pod.
|
||||
|
||||
The most important pieces of metadata are the resource type and log name.
|
||||
The resource type of a container log is `container`, which is named
|
||||
`GKE Containers` in the UI (even if the Kubernetes cluster is not on Google Kubernetes Engine).
|
||||
The log name is the name of the container, so that if you have a pod with
|
||||
two containers, named `container_1` and `container_2` in the spec, their logs
|
||||
will have log names `container_1` and `container_2` respectively.
|
||||
|
||||
System components have resource type `compute`, which is named
|
||||
`GCE VM Instance` in the interface. Log names for system components are fixed.
|
||||
For a Google Kubernetes Engine node, every log entry from a system component has one of the following
|
||||
log names:
|
||||
|
||||
* docker
|
||||
* kubelet
|
||||
* kube-proxy
|
||||
|
||||
You can learn more about viewing logs on [the dedicated Stackdriver page](https://cloud.google.com/logging/docs/view/logs_viewer).
|
||||
|
||||
One of the possible ways to view logs is using the
|
||||
[`gcloud logging`](https://cloud.google.com/logging/docs/api/gcloud-logging)
|
||||
command line interface from the [Google Cloud SDK](https://cloud.google.com/sdk/).
|
||||
It uses Stackdriver Logging [filtering syntax](https://cloud.google.com/logging/docs/view/advanced_filters)
|
||||
to query specific logs. For example, you can run the following command:
|
||||
|
||||
```shell
|
||||
$ gcloud beta logging read 'logName="projects/$YOUR_PROJECT_ID/logs/count"' --format json | jq '.[].textPayload'
|
||||
...
|
||||
"2: Mon Jan 1 00:01:02 UTC 2001\n"
|
||||
"1: Mon Jan 1 00:01:01 UTC 2001\n"
|
||||
"0: Mon Jan 1 00:01:00 UTC 2001\n"
|
||||
...
|
||||
"2: Mon Jan 1 00:00:02 UTC 2001\n"
|
||||
"1: Mon Jan 1 00:00:01 UTC 2001\n"
|
||||
"0: Mon Jan 1 00:00:00 UTC 2001\n"
|
||||
```
|
||||
|
||||
As you can see, it outputs messages for the count container from both
|
||||
the first and second runs, despite the fact that the kubelet already deleted
|
||||
the logs for the first container.
|
||||
|
||||
### Exporting logs
|
||||
|
||||
You can export logs to [Google Cloud Storage](https://cloud.google.com/storage/)
|
||||
or to [BigQuery](https://cloud.google.com/bigquery/) to run further
|
||||
analysis. Stackdriver Logging offers the concept of sinks, where you can
|
||||
specify the destination of log entries. More information is available on
|
||||
the Stackdriver [Exporting Logs page](https://cloud.google.com/logging/docs/export/configure_export_v2).
|
||||
|
||||
## Configuring Stackdriver Logging Agents
|
||||
|
||||
Sometimes the default installation of Stackdriver Logging may not suit your needs, for example:
|
||||
|
||||
* You may want to add more resources because default performance doesn't suit your needs.
|
||||
* You may want to introduce additional parsing to extract more metadata from your log messages,
|
||||
like severity or source code reference.
|
||||
* You may want to send logs not only to Stackdriver or send it to Stackdriver only partially.
|
||||
|
||||
In this case you need to be able to change the parameters of `DaemonSet` and `ConfigMap`.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
If you're using GKE and Stackdriver Logging is enabled in your cluster, you
|
||||
cannot change its configuration, because it's managed and supported by GKE.
|
||||
However, you can disable the default integration and deploy your own. Note,
|
||||
that you will have to support and maintain a newly deployed configuration
|
||||
yourself: update the image and configuration, adjust the resources and so on.
|
||||
To disable the default logging integration, use the following command:
|
||||
|
||||
```
|
||||
gcloud beta container clusters update --logging-service=none CLUSTER
|
||||
```
|
||||
|
||||
You can find notes on how to then install Stackdriver Logging agents into
|
||||
a running cluster in the [Deploying section](#deploying).
|
||||
|
||||
### Changing `DaemonSet` parameters
|
||||
|
||||
When you have the Stackdriver Logging `DaemonSet` in your cluster, you can just modify the
|
||||
`template` field in its spec, daemonset controller will update the pods for you. For example,
|
||||
let's assume you've just installed the Stackdriver Logging as described above. Now you want to
|
||||
change the memory limit to give fluentd more memory to safely process more logs.
|
||||
|
||||
Get the spec of `DaemonSet` running in your cluster:
|
||||
|
||||
```shell
|
||||
kubectl get ds fluentd-gcp-v2.0 --namespace kube-system -o yaml > fluentd-gcp-ds.yaml
|
||||
```
|
||||
|
||||
Then edit resource requirements in the spec file and update the `DaemonSet` object
|
||||
in the apiserver using the following command:
|
||||
|
||||
```shell
|
||||
kubectl replace -f fluentd-gcp-ds.yaml
|
||||
```
|
||||
|
||||
After some time, Stackdriver Logging agent pods will be restarted with the new configuration.
|
||||
|
||||
### Changing fluentd parameters
|
||||
|
||||
Fluentd configuration is stored in the `ConfigMap` object. It is effectively a set of configuration
|
||||
files that are merged together. You can learn about fluentd configuration on the [official
|
||||
site](http://docs.fluentd.org).
|
||||
|
||||
Imagine you want to add a new parsing logic to the configuration, so that fluentd can understand
|
||||
default Python logging format. An appropriate fluentd filter looks similar to this:
|
||||
|
||||
```
|
||||
<filter reform.**>
|
||||
type parser
|
||||
format /^(?<severity>\w):(?<logger_name>\w):(?<log>.*)/
|
||||
reserve_data true
|
||||
suppress_parse_error_log true
|
||||
key_name log
|
||||
</filter>
|
||||
```
|
||||
|
||||
Now you have to put it in the configuration and make Stackdriver Logging agents pick it up.
|
||||
Get the current version of the Stackdriver Logging `ConfigMap` in your cluster
|
||||
by running the following command:
|
||||
|
||||
```shell
|
||||
kubectl get cm fluentd-gcp-config --namespace kube-system -o yaml > fluentd-gcp-configmap.yaml
|
||||
```
|
||||
|
||||
Then in the value for the key `containers.input.conf` insert a new filter right after
|
||||
the `source` section. **Note:** order is important.
|
||||
|
||||
Updating `ConfigMap` in the apiserver is more complicated than updating `DaemonSet`. It's better
|
||||
to consider `ConfigMap` to be immutable. Then, in order to update the configuration, you should
|
||||
create `ConfigMap` with a new name and then change `DaemonSet` to point to it
|
||||
using [guide above](#changing-daemonset-parameters).
|
||||
|
||||
### Adding fluentd plugins
|
||||
|
||||
Fluentd is written in Ruby and allows to extend its capabilities using
|
||||
[plugins](http://www.fluentd.org/plugins). If you want to use a plugin, which is not included
|
||||
in the default Stackdriver Logging container image, you have to build a custom image. Imagine
|
||||
you want to add Kafka sink for messages from a particular container for additional processing.
|
||||
You can re-use the default [container image sources](https://git.k8s.io/contrib/fluentd/fluentd-gcp-image)
|
||||
with minor changes:
|
||||
|
||||
* Change Makefile to point to your container repository, e.g. `PREFIX=gcr.io/<your-project-id>`.
|
||||
* Add your dependency to the Gemfile, for example `gem 'fluent-plugin-kafka'`.
|
||||
|
||||
Then run `make build push` from this directory. After updating `DaemonSet` to pick up the
|
||||
new image, you can use the plugin you installed in the fluentd configuration.
|
||||
@@ -0,0 +1,165 @@
|
||||
---
|
||||
reviewers:
|
||||
- Random-Liu
|
||||
- dchen1107
|
||||
title: Monitor Node Health
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Node Problem Detector
|
||||
|
||||
*Node problem detector* is a [DaemonSet](/docs/concepts/workloads/controllers/daemonset/) monitoring the
|
||||
node health. It collects node problems from various daemons and reports them
|
||||
to the apiserver as [NodeCondition](/docs/concepts/architecture/nodes/#condition)
|
||||
and [Event](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#event-v1-core).
|
||||
|
||||
It supports some known kernel issue detection now, and will detect more and
|
||||
more node problems over time.
|
||||
|
||||
Currently Kubernetes won't take any action on the node conditions and events
|
||||
generated by node problem detector. In the future, a remedy system could be
|
||||
introduced to deal with node problems.
|
||||
|
||||
See more information
|
||||
[here](https://github.com/kubernetes/node-problem-detector).
|
||||
|
||||
## Limitations
|
||||
|
||||
* The kernel issue detection of node problem detector only supports file based
|
||||
kernel log now. It doesn't support log tools like journald.
|
||||
|
||||
* The kernel issue detection of node problem detector has assumption on kernel
|
||||
log format, and now it only works on Ubuntu and Debian. However, it is easy to extend
|
||||
it to [support other log format](/docs/tasks/debug-application-cluster/monitor-node-health/#support-other-log-format).
|
||||
|
||||
## Enable/Disable in GCE cluster
|
||||
|
||||
Node problem detector is [running as a cluster addon](/docs/admin/cluster-large/#addon-resources) enabled by default in the
|
||||
gce cluster.
|
||||
|
||||
You can enable/disable it by setting the environment variable
|
||||
`KUBE_ENABLE_NODE_PROBLEM_DETECTOR` before `kube-up.sh`.
|
||||
|
||||
## Use in Other Environment
|
||||
|
||||
To enable node problem detector in other environment outside of GCE, you can use
|
||||
either `kubectl` or addon pod.
|
||||
|
||||
### Kubectl
|
||||
|
||||
This is the recommended way to start node problem detector outside of GCE. It
|
||||
provides more flexible management, such as overwriting the default
|
||||
configuration to fit it into your environment or detect
|
||||
customized node problems.
|
||||
|
||||
* **Step 1:** `node-problem-detector.yaml`:
|
||||
|
||||
{{< code file="node-problem-detector.yaml" >}}
|
||||
|
||||
|
||||
***Notice that you should make sure the system log directory is right for your
|
||||
OS distro.***
|
||||
|
||||
* **Step 2:** Start node problem detector with `kubectl`:
|
||||
|
||||
```shell
|
||||
kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/node-problem-detector.yaml
|
||||
```
|
||||
|
||||
### Addon Pod
|
||||
|
||||
This is for those who have their own cluster bootstrap solution, and don't need
|
||||
to overwrite the default configuration. They could leverage the addon pod to
|
||||
further automate the deployment.
|
||||
|
||||
Just create `node-problem-detector.yaml`, and put it under the addon pods directory
|
||||
`/etc/kubernetes/addons/node-problem-detector` on master node.
|
||||
|
||||
## Overwrite the Configuration
|
||||
|
||||
The [default configuration](https://github.com/kubernetes/node-problem-detector/tree/v0.1/config)
|
||||
is embedded when building the docker image of node problem detector.
|
||||
|
||||
However, you can use [ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap/) to overwrite it
|
||||
following the steps:
|
||||
|
||||
* **Step 1:** Change the config files in `config/`.
|
||||
* **Step 2:** Create the ConfigMap `node-problem-detector-config` with `kubectl create configmap
|
||||
node-problem-detector-config --from-file=config/`.
|
||||
* **Step 3:** Change the `node-problem-detector.yaml` to use the ConfigMap:
|
||||
|
||||
{{< code file="node-problem-detector-configmap.yaml" >}}
|
||||
|
||||
|
||||
* **Step 4:** Re-create the node problem detector with the new yaml file:
|
||||
|
||||
```shell
|
||||
kubectl delete -f https://k8s.io/docs/tasks/debug-application-cluster/node-problem-detector.yaml # If you have a node-problem-detector running
|
||||
kubectl create -f https://k8s.io/docs/tasks/debug-application-cluster/node-problem-detector-configmap.yaml
|
||||
```
|
||||
|
||||
***Notice that this approach only applies to node problem detector started with `kubectl`.***
|
||||
|
||||
For node problem detector running as cluster addon, because addon manager doesn't support
|
||||
ConfigMap, configuration overwriting is not supported now.
|
||||
|
||||
## Kernel Monitor
|
||||
|
||||
*Kernel Monitor* is a problem daemon in node problem detector. It monitors kernel log
|
||||
and detects known kernel issues following predefined rules.
|
||||
|
||||
The Kernel Monitor matches kernel issues according to a set of predefined rule list in
|
||||
[`config/kernel-monitor.json`](https://github.com/kubernetes/node-problem-detector/blob/v0.1/config/kernel-monitor.json).
|
||||
The rule list is extensible, and you can always extend it by overwriting the
|
||||
configuration.
|
||||
|
||||
### Add New NodeConditions
|
||||
|
||||
To support new node conditions, you can extend the `conditions` field in
|
||||
`config/kernel-monitor.json` with new condition definition:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "NodeConditionType",
|
||||
"reason": "CamelCaseDefaultNodeConditionReason",
|
||||
"message": "arbitrary default node condition message"
|
||||
}
|
||||
```
|
||||
|
||||
### Detect New Problems
|
||||
|
||||
To detect new problems, you can extend the `rules` field in `config/kernel-monitor.json`
|
||||
with new rule definition:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "temporary/permanent",
|
||||
"condition": "NodeConditionOfPermanentIssue",
|
||||
"reason": "CamelCaseShortReason",
|
||||
"message": "regexp matching the issue in the kernel log"
|
||||
}
|
||||
```
|
||||
|
||||
### Change Log Path
|
||||
|
||||
Kernel log in different OS distros may locate in different path. The `log`
|
||||
field in `config/kernel-monitor.json` is the log path inside the container.
|
||||
You can always configure it to match your OS distro.
|
||||
|
||||
### Support Other Log Format
|
||||
|
||||
Kernel monitor uses [`Translator`](https://github.com/kubernetes/node-problem-detector/blob/v0.1/pkg/kernelmonitor/translator/translator.go)
|
||||
plugin to translate kernel log the internal data structure. It is easy to
|
||||
implement a new translator for a new log format.
|
||||
|
||||
## Caveats
|
||||
|
||||
It is recommended to run the node problem detector in your cluster to monitor
|
||||
the node health. However, you should be aware that this will introduce extra
|
||||
resource overhead on each node. Usually this is fine, because:
|
||||
|
||||
* The kernel log is generated relatively slowly.
|
||||
* Resource limit is set for node problem detector.
|
||||
* Even under high load, the resource usage is acceptable.
|
||||
(see [benchmark result](https://github.com/kubernetes/node-problem-detector/issues/2#issuecomment-220255629))
|
||||
@@ -0,0 +1,23 @@
|
||||
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
|
||||
@@ -0,0 +1,49 @@
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: node-problem-detector-v0.1
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: node-problem-detector
|
||||
version: v0.1
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s-app: node-problem-detector
|
||||
version: v0.1
|
||||
kubernetes.io/cluster-service: "true"
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: node-problem-detector
|
||||
version: v0.1
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: node-problem-detector
|
||||
image: k8s.gcr.io/node-problem-detector:v0.1
|
||||
securityContext:
|
||||
privileged: true
|
||||
resources:
|
||||
limits:
|
||||
cpu: "200m"
|
||||
memory: "100Mi"
|
||||
requests:
|
||||
cpu: "20m"
|
||||
memory: "20Mi"
|
||||
volumeMounts:
|
||||
- name: log
|
||||
mountPath: /log
|
||||
readOnly: true
|
||||
- name: config # Overwrite the config/ directory with ConfigMap volume
|
||||
mountPath: /config
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: log
|
||||
hostPath:
|
||||
path: /var/log/
|
||||
- name: config # Define ConfigMap volume
|
||||
configMap:
|
||||
name: node-problem-detector-config
|
||||
@@ -0,0 +1,43 @@
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: node-problem-detector-v0.1
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: node-problem-detector
|
||||
version: v0.1
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s-app: node-problem-detector
|
||||
version: v0.1
|
||||
kubernetes.io/cluster-service: "true"
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: node-problem-detector
|
||||
version: v0.1
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: node-problem-detector
|
||||
image: k8s.gcr.io/node-problem-detector:v0.1
|
||||
securityContext:
|
||||
privileged: true
|
||||
resources:
|
||||
limits:
|
||||
cpu: "200m"
|
||||
memory: "100Mi"
|
||||
requests:
|
||||
cpu: "20m"
|
||||
memory: "20Mi"
|
||||
volumeMounts:
|
||||
- name: log
|
||||
mountPath: /log
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: log
|
||||
hostPath:
|
||||
path: /var/log/
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
reviewers:
|
||||
- mikedanese
|
||||
title: Tools for Monitoring Compute, Storage, and Network Resources
|
||||
---
|
||||
|
||||
Understanding how an application behaves when deployed is crucial to scaling the application and providing a reliable service. In a Kubernetes cluster, application performance can be examined at many different levels: containers, [pods](/docs/user-guide/pods), [services](/docs/user-guide/services), and whole clusters. As part of Kubernetes we want to provide users with detailed resource usage information about their running applications at all these levels. This will give users deep insights into how their applications are performing and where possible application bottlenecks may be found. In comes [Heapster](https://github.com/kubernetes/heapster), a project meant to provide a base monitoring platform on Kubernetes.
|
||||
|
||||
## Overview
|
||||
|
||||
Heapster is a cluster-wide aggregator of monitoring and event data. It currently supports Kubernetes natively and works on all Kubernetes setups. Heapster runs as a pod in the cluster, similar to how any Kubernetes application would run. The Heapster pod discovers all nodes in the cluster and queries usage information from the nodes' [Kubelet](/docs/admin/kubelet/)s, the on-machine Kubernetes agent. The Kubelet itself fetches the data from [cAdvisor](https://github.com/google/cadvisor). Heapster groups the information by pod along with the relevant labels. This data is then pushed to a configurable backend for storage and visualization. Currently supported backends include [InfluxDB](http://influxdb.com/) (with [Grafana](http://grafana.org/) for visualization), [Google Cloud Monitoring](https://cloud.google.com/monitoring/) and many others described in more details [here](https://git.k8s.io/heapster/docs/sink-configuration.md). The overall architecture of the service can be seen below:
|
||||
|
||||

|
||||
|
||||
Let's look at some of the other components in more detail.
|
||||
|
||||
### cAdvisor
|
||||
|
||||
cAdvisor is an open source container resource usage and performance analysis agent. It is purpose-built for containers and supports Docker containers natively. In Kubernetes, cAdvisor is integrated into the Kubelet binary. cAdvisor auto-discovers all containers in the machine and collects CPU, memory, filesystem, and network usage statistics. cAdvisor also provides the overall machine usage by analyzing the 'root' container on the machine.
|
||||
|
||||
On most Kubernetes clusters, cAdvisor exposes a simple UI for on-machine containers on port 4194. Here is a snapshot of part of cAdvisor's UI that shows the overall machine usage:
|
||||
|
||||

|
||||
|
||||
### Kubelet
|
||||
|
||||
The Kubelet acts as a bridge between the Kubernetes master and the nodes. It manages the pods and containers running on a machine. Kubelet translates each pod into its constituent containers and fetches individual container usage statistics from cAdvisor. It then exposes the aggregated pod resource usage statistics via a REST API.
|
||||
|
||||
## Storage Backends
|
||||
|
||||
### InfluxDB and Grafana
|
||||
|
||||
A Grafana setup with InfluxDB is a very popular combination for monitoring in the open source world. InfluxDB exposes an easy to use API to write and fetch time series data. Heapster is setup to use this storage backend by default on most Kubernetes clusters. A detailed setup guide can be found [here](https://github.com/GoogleCloudPlatform/heapster/blob/master/docs/influxdb.md). InfluxDB and Grafana run in Pods. The pod exposes itself as a Kubernetes service which is how Heapster discovers it.
|
||||
|
||||
The Grafana container serves Grafana's UI which provides an easy to configure dashboard interface. The default dashboard for Kubernetes contains an example dashboard that monitors resource usage of the cluster and the pods inside of it. This dashboard can easily be customized and expanded. Take a look at the storage schema for InfluxDB [here](https://github.com/GoogleCloudPlatform/heapster/blob/master/docs/storage-schema.md#metrics).
|
||||
|
||||
Here is a video showing how to monitor a Kubernetes cluster using heapster, InfluxDB and Grafana:
|
||||
|
||||
[](http://www.youtube.com/watch?v=SZgqjMrxo3g)
|
||||
|
||||
Here is a snapshot of the default Kubernetes Grafana dashboard that shows the CPU and Memory usage of the entire cluster, individual pods and containers:
|
||||
|
||||

|
||||
|
||||
### Google Cloud Monitoring
|
||||
|
||||
Google Cloud Monitoring is a hosted monitoring service that allows you to visualize and alert on important metrics in your application. Heapster can be setup to automatically push all collected metrics to Google Cloud Monitoring. These metrics are then available in the [Cloud Monitoring Console](https://app.google.stackdriver.com/). This storage backend is the easiest to setup and maintain. The monitoring console allows you to easily create and customize dashboards using the exported data.
|
||||
|
||||
Here is a video showing how to setup and run a Google Cloud Monitoring backed Heapster:
|
||||
|
||||
[](http://www.youtube.com/watch?v=xSMNR2fcoLs)
|
||||
|
||||
Here is a snapshot of the Google Cloud Monitoring dashboard showing cluster-wide resource usage.
|
||||
|
||||

|
||||
|
||||
## Try it out!
|
||||
|
||||
Now that you've learned a bit about Heapster, feel free to try it out on your own clusters! The [Heapster repository](https://github.com/kubernetes/heapster) is available on GitHub. It contains detailed instructions to setup Heapster and its storage backends. Heapster runs by default on most Kubernetes clusters, so you may already have it! Feedback is always welcome. Please let us know if you run into any issues via the troubleshooting [channels](/docs/troubleshooting/).
|
||||
|
||||
***
|
||||
*Authors: Vishnu Kannan and Victor Marmol, Google Software Engineers.*
|
||||
*This article was originally posted in [Kubernetes blog](http://blog.kubernetes.io/2015/05/resource-usage-monitoring-kubernetes.html).*
|
||||
@@ -0,0 +1,14 @@
|
||||
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
|
||||
@@ -0,0 +1,10 @@
|
||||
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"]
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
reviewers:
|
||||
- brendandburns
|
||||
- davidopp
|
||||
title: Troubleshooting
|
||||
---
|
||||
|
||||
Sometimes things go wrong. This guide is aimed at making them right. It has
|
||||
two sections:
|
||||
|
||||
* [Troubleshooting your application](/docs/tasks/debug-application-cluster/debug-application/) - Useful for users who are deploying code into Kubernetes and wondering why it is not working.
|
||||
* [Troubleshooting your cluster](/docs/tasks/debug-application-cluster/debug-cluster/) - Useful for cluster administrators and people whose Kubernetes cluster is unhappy.
|
||||
|
||||
You should also check the known issues for the [release](https://github.com/kubernetes/kubernetes/releases)
|
||||
you're using.
|
||||
|
||||
## Getting help
|
||||
|
||||
If your problem isn't answered by any of the guides above, there are variety of
|
||||
ways for you to get help from the Kubernetes team.
|
||||
|
||||
### Questions
|
||||
|
||||
The documentation on this site has been structured to provide answers to a wide
|
||||
range of questions. [Concepts](/docs/concepts/) explain the Kubernetes
|
||||
architecture and how each component works, while [Setup](/docs/setup/) provides
|
||||
practical instructions for getting started. [Tasks](/docs/tasks/) show how to
|
||||
accomplish commonly used tasks, and [Tutorials](/docs/tutorials/) are more
|
||||
comprehensive walkthroughs of real-world, industry-specific, or end-to-end
|
||||
development scenarios. The [Reference](/docs/reference/) section provides
|
||||
detailed documentation on the [Kubernetes API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/)
|
||||
and command-line interfaces (CLIs), such as [`kubectl`](/docs/user-guide/kubectl-overview/).
|
||||
|
||||
You may also find the Stack Overflow topics relevant:
|
||||
|
||||
* [Kubernetes](http://stackoverflow.com/questions/tagged/kubernetes)
|
||||
* [Google Kubernetes Engine](http://stackoverflow.com/questions/tagged/google-container-engine)
|
||||
|
||||
## Help! My question isn't covered! I need help now!
|
||||
|
||||
### Stack Overflow
|
||||
|
||||
Someone else from the community may have already asked a similar question or may
|
||||
be able to help with your problem. The Kubernetes team will also monitor
|
||||
[posts tagged Kubernetes](http://stackoverflow.com/questions/tagged/kubernetes).
|
||||
If there aren't any existing questions that help, please [ask a new one](http://stackoverflow.com/questions/ask?tags=kubernetes)!
|
||||
|
||||
### Slack
|
||||
|
||||
The Kubernetes team hangs out on Slack in the `#kubernetes-users` channel. You
|
||||
can participate in discussion with the Kubernetes team [here](https://kubernetes.slack.com).
|
||||
Slack requires registration, but the Kubernetes team is open invitation to
|
||||
anyone to register [here](http://slack.kubernetes.io). Feel free to come and ask
|
||||
any and all questions.
|
||||
|
||||
Once registered, browse the growing list of channels for various subjects of
|
||||
interest. For example, people new to Kubernetes may also want to join the
|
||||
`#kubernetes-novice` channel. As another example, developers should join the
|
||||
`#kubernetes-dev` channel.
|
||||
|
||||
There are also many country specific/local language channels. Feel free to join
|
||||
these channels for localized support and info:
|
||||
|
||||
- China: `#cn-users`, `#cn-events`
|
||||
- France: `#fr-users`, `#fr-events`
|
||||
- Germany: `#de-users`, `#de-events`
|
||||
- India: `#in-users`, `#in-events`
|
||||
- Italy: `#it-users`, `#it-events`
|
||||
- Japan: `#jp-users`, `#jp-events`
|
||||
- Korea: `#kr-users`
|
||||
- Netherlands: `#nl-users`
|
||||
- Norway: `#norw-users`
|
||||
- Poland: `#pl-users`
|
||||
- Russia: `#ru-users`
|
||||
- Spain: `#es-users`
|
||||
- Turkey: `#tr-users`, `#tr-events`
|
||||
|
||||
### Mailing List
|
||||
|
||||
The Kubernetes / Google Kubernetes Engine mailing list is [kubernetes-users@googlegroups.com](https://groups.google.com/forum/#!forum/kubernetes-users)
|
||||
|
||||
### Bugs and Feature requests
|
||||
|
||||
If you have what looks like a bug, or you would like to make a feature request,
|
||||
please use the [Github issue tracking system](https://github.com/kubernetes/kubernetes/issues).
|
||||
|
||||
Before you file an issue, please search existing issues to see if your issue is
|
||||
already covered.
|
||||
|
||||
If filing a bug, please include detailed information about how to reproduce the
|
||||
problem, such as:
|
||||
|
||||
* Kubernetes version: `kubectl version`
|
||||
* Cloud provider, OS distro, network configuration, and Docker version
|
||||
* Steps to reproduce the problem
|
||||
Reference in New Issue
Block a user