Move Support topics. (#3108)
* Move Support topics. * Update stage-documentation-changes.md * Update stage-documentation-changes.mdreviewable/pr3018/r2
parent
0e8f7ded2d
commit
c57fad453f
|
@ -1,4 +1,25 @@
|
|||
bigheader: "Kubernetes Documentation"
|
||||
abstract: "Documentation for using and learning about Kubernetes."
|
||||
toc:
|
||||
- docs/index.md
|
||||
- docs/home/index.md
|
||||
|
||||
- docs/home/index.md
|
||||
|
||||
- title: Contributing to the Kubernetes Docs
|
||||
section:
|
||||
- editdocs.md
|
||||
- docs/home/contribute/create-pull-request.md
|
||||
- docs/home/contribute/write-new-topic.md
|
||||
- docs/home/contribute/stage-documentation-changes.md
|
||||
- docs/home/contribute/page-templates.md
|
||||
- docs/home/contribute/review-issues.md
|
||||
- docs/home/contribute/style-guide.md
|
||||
|
||||
- title: Release Notes
|
||||
path: https://github.com/kubernetes/kubernetes/releases/
|
||||
- title: Release Roadmap
|
||||
path: https://github.com/kubernetes/kubernetes/milestones/
|
||||
- docs/home/deprecation-policy.md
|
||||
- docs/home/security.md
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
tocs:
|
||||
- docs-home
|
||||
- guides
|
||||
- tutorials
|
||||
- tasks
|
||||
- tutorials
|
||||
- concepts
|
||||
- reference
|
||||
- tools
|
||||
|
|
|
@ -42,3 +42,4 @@ toc:
|
|||
|
||||
- title: Deprecation Policy
|
||||
path: /docs/deprecation-policy.md
|
||||
|
||||
|
|
|
@ -53,6 +53,11 @@ toc:
|
|||
- docs/tasks/debug-application-cluster/logging-stackdriver.md
|
||||
- docs/tasks/debug-application-cluster/monitor-node-health.md
|
||||
- docs/tasks/debug-application-cluster/logging-elasticsearch-kibana.md
|
||||
- docs/tasks/debug-application-cluster/debug-application.md
|
||||
- docs/tasks/debug-application-cluster/debug-application-introspection.md
|
||||
- docs/tasks/debug-application-cluster/debug-cluster.md
|
||||
- docs/tasks/debug-application-cluster/debug-pod-replication-controller.md
|
||||
- docs/tasks/debug-application-cluster/debug-service.md
|
||||
|
||||
- title: Accessing the Kubernetes API
|
||||
section:
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
<div class="nav-buttons" data-auto-burger="primary">
|
||||
<ul class="global-nav">
|
||||
<li><a href="/docs/">Documentation</a></li>
|
||||
<li><a href="/docs/home">Documentation</a></li>
|
||||
<li><a href="http://blog.kubernetes.io/">Blog</a></li>
|
||||
<li><a href="/partners/">Partners</a></li>
|
||||
<li><a href="/community/">Community</a></li>
|
||||
<li><a href="/case-studies/">Case Studies</a></li>
|
||||
</ul>
|
||||
<!-- <a href="/docs/" class="button" id="viewDocs" data-auto-burger-exclude>View Documentation</a> -->
|
||||
<!-- <a href="/docs/home" class="button" id="viewDocs" data-auto-burger-exclude>View Documentation</a> -->
|
||||
<a href="/docs/tutorials/kubernetes-basics/" class="button" id="tryKubernetes" data-auto-burger-exclude>Try Kubernetes</a>
|
||||
<button id="hamburger" onclick="kub.toggleMenu()" data-auto-burger-exclude><div></div></button>
|
||||
</div>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<p>Ready to get your hands dirty? Build a simple Kubernetes cluster that runs "Hello World" for Node.js.</p>
|
||||
</div>
|
||||
<div class="nav-box">
|
||||
<h3><a href="/docs/">Documentation</a></h3>
|
||||
<h3><a href="/docs/home">Documentation</a></h3>
|
||||
<p>Learn how to use Kubernetes with the use of walkthroughs, samples, and reference documentation. You can even <a href="/editdocs/" data-auto-burger-exclude>help contribute to the docs</a>!</p>
|
||||
</div>
|
||||
<div class="nav-box">
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
The topics in the [Support](/docs/troubleshooting/) section of the Kubernetes docs
|
||||
are being moved to the [Home](/docs/home/) section. The content in this topic has moved to:
|
|
@ -22,7 +22,7 @@
|
|||
<h5>{{ toc.abstract }}</h5>
|
||||
<div id="vendorStrip" class="light-text">
|
||||
<ul>
|
||||
<li><a href="/docs/" {% if toc.bigheader == "Kubernetes Documentation" %}class="YAH"{% endif %}>DOCS HOME</a></li>
|
||||
<li><a href="/docs/home/" {% if toc.bigheader == "Kubernetes Documentation" %}class="YAH"{% endif %}>HOME</a></li>
|
||||
<li><a href="/docs/user-guide/" {% if toc.bigheader == "Guides" %}class="YAH"{% endif %}>GUIDES</a></li>
|
||||
<li><a href="/docs/tutorials/" {% if toc.bigheader == "Tutorials" %}class="YAH"{% endif %}>TUTORIALS</a></li>
|
||||
<li><a href="/docs/tasks/" {% if toc.bigheader == "Tasks" %}class="YAH"{% endif %}>TASKS</a></li>
|
||||
|
@ -40,9 +40,7 @@
|
|||
<section id="encyclopedia">
|
||||
<div id="docsToc">
|
||||
<div class="pi-accordion">
|
||||
{% if toc.bigheader != "Kubernetes Documentation" %}
|
||||
{% include_cached tree.html tree=toc.toc %}
|
||||
{% endif %}
|
||||
</div> <!-- /pi-accordion -->
|
||||
<button class="push-menu-close-button" onclick="kub.toggleToc()"></button>
|
||||
</div> <!-- /docsToc -->
|
||||
|
|
|
@ -4,112 +4,6 @@ assignees:
|
|||
title: Troubleshooting 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/user-guide/application-troubleshooting) for tips on application debugging.
|
||||
You may also visit [troubleshooting document](/docs/troubleshooting/) for more information.
|
||||
{% include user-guide-content-moved.md %}
|
||||
|
||||
## 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/admin/multi-cluster) (and avoid making risky changes to all clusters at once)
|
||||
- Mitigates: Everything listed above.
|
||||
[Debugging Clusters](/docs/tasks/debug-application-cluster/debug-cluster/)
|
||||
|
|
|
@ -2,97 +2,6 @@
|
|||
title: Creating a Documentation Pull Request
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
{% include support-content-moved.md %}
|
||||
|
||||
To contribute to the Kubernetes documentation, create a pull request against the
|
||||
[kubernetes/kubernetes.github.io](https://github.com/kubernetes/kubernetes.github.io){: target="_blank"}
|
||||
repository. This page shows how to create a pull request.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
|
||||
1. Create a [GitHub account](https://github.com){: target="_blank"}.
|
||||
|
||||
1. Sign the
|
||||
[Linux Foundation Contributor License Agreement](https://identity.linuxfoundation.org/projects/cncf){: target="_blank"}.
|
||||
|
||||
Documentation will be published under the [CC BY SA 4.0](https://github.com/kubernetes/kubernetes.github.io/blob/master/LICENSE) license.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
## Creating a fork of the Kubernetes documentation repository
|
||||
|
||||
1. Go to the
|
||||
[kubernetes/kubernetes.github.io](https://github.com/kubernetes/kubernetes.github.io){: target="_blank"}
|
||||
repository.
|
||||
|
||||
1. In the upper-right corner, click **Fork**. This creates a copy of the
|
||||
Kubernetes documentation repository in your GitHub account. The copy
|
||||
is called a *fork*.
|
||||
|
||||
## Making your changes
|
||||
|
||||
1. In your GitHub account, in your fork of the Kubernetes docs, create
|
||||
a new branch to use for your contribution.
|
||||
|
||||
1. In your new branch, make your changes and commit them. If you want to
|
||||
[write a new topic](/docs/contribute/write-new-topic/),
|
||||
choose the
|
||||
[page type](/docs/contribute/page-templates/)
|
||||
that is the best fit for your content.
|
||||
|
||||
## Submitting a pull request to the master branch (Current Release)
|
||||
|
||||
If you want your change to be published in the released version Kubernetes docs,
|
||||
create a pull request against the master branch of the Kubernetes
|
||||
documentation repository.
|
||||
|
||||
1. In your GitHub account, in your new branch, create a pull request
|
||||
against the master branch of the kubernetes/kubernetes.github.io
|
||||
repository. This opens a page that shows the status of your pull request.
|
||||
|
||||
1. Click **Show all checks**. Wait for the **deploy/netlify** check to complete.
|
||||
To the right of **deploy/netlify**, click **Details**. This opens a staging
|
||||
site where you can verify that your changes have rendered correctly.
|
||||
|
||||
1. During the next few days, check your pull request for reviewer comments.
|
||||
If needed, revise your pull request by committing changes to your
|
||||
new branch in your fork.
|
||||
|
||||
## Submitting a pull request to the <vnext> branch (Upcoming Release)
|
||||
|
||||
If your documentation change should not be released until the next release of
|
||||
the Kubernetes product, create a pull request against the <vnext> branch
|
||||
of the Kubernetes documentation repository. The <vnext> branch has the
|
||||
form `release-<version-number>`, for example release-1.5.
|
||||
|
||||
1. In your GitHub account, in your new branch, create a pull request
|
||||
against the <vnext> branch of the kubernetes/kubernetes.github.io
|
||||
repository. This opens a page that shows the status of your pull request.
|
||||
|
||||
1. Click **Show all checks**. Wait for the **deploy/netlify** check to complete.
|
||||
To the right of **deploy/netlify**, click **Details**. This opens a staging
|
||||
site where you can verify that your changes have rendered correctly.
|
||||
|
||||
1. During the next few days, check your pull request for reviewer comments.
|
||||
If needed, revise your pull request by committing changes to your
|
||||
new branch in your fork.
|
||||
|
||||
The staging site for the upcoming Kubernetes release is here:
|
||||
[http://kubernetes-io-vnext-staging.netlify.com/](http://kubernetes-io-vnext-staging.netlify.com/).
|
||||
The staging site reflects the current state of what's been merged in the
|
||||
release branch, or in other words, what the docs will look like for the
|
||||
next upcoming release. It's automatically updated as new PRs get merged.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [writing a new topic](/docs/contribute/write-new-topic).
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [staging your changes](/docs/contribute/stage-documentation-changes).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
||||
[Creating a Documentation Pull Request](/docs/home/contribute/create-pull-request/)
|
||||
|
|
|
@ -5,218 +5,6 @@ redirect_from:
|
|||
title: Using Page Templates
|
||||
---
|
||||
|
||||
<!--<html>
|
||||
<body>-->
|
||||
|
||||
<p>These page templates are available for writers who would like to contribute new topics to the Kubernetes docs:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="#task_template">Task</a></li>
|
||||
<li><a href="#tutorial_template">Tutorial</a></li>
|
||||
<li><a href="#concept_template">Concept</a></li>
|
||||
</ul>
|
||||
|
||||
<p>The page templates are in the <a href="https://github.com/kubernetes/kubernetes.github.io/tree/master/_includes/templates" target="_blank">_includes/templates</a> directory of the <a href="https://github.com/kubernetes/kubernetes.github.io">kubernetes.github.io</a> repository.
|
||||
|
||||
<h2 id="task_template">Task template</h2>
|
||||
|
||||
<p>A task page shows how to do a single thing, typically by giving a short
|
||||
sequence of steps. Task pages have minimal explanation, but often provide links
|
||||
to conceptual topics that provide related background and knowledge.</p>
|
||||
|
||||
<p>To write a new task page, create a Markdown file in a subdirectory of the
|
||||
/docs/tasks directory. In your Markdown file, provide values for these
|
||||
variables, and then include templates/task.md:</p>
|
||||
|
||||
<ul>
|
||||
<li>overview - required</li>
|
||||
<li>prerequisites - required</li>
|
||||
<li>steps - required</li>
|
||||
<li>discussion - optional</li>
|
||||
<li>whatsnext - optional</li>
|
||||
</ul>
|
||||
|
||||
<p>In the <code>steps</code> section, use <code>##</code> to start with a level-two heading. For subheadings,
|
||||
use <code>###</code> and <code>####</code> as needed. Similarly, if you choose to have a <code>discussion</code> section,
|
||||
start the section with a level-two heading.</p>
|
||||
|
||||
<p>Here's an example of a Markdown file that uses the task template:</p>
|
||||
|
||||
{% raw %}
|
||||
<pre>---
|
||||
title: Configuring This Thing
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page shows how to ...
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
* Do this.
|
||||
* Do this too.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
## Doing ...
|
||||
|
||||
1. Do this.
|
||||
1. Do this next. Possibly read this [related explanation](...).
|
||||
{% endcapture %}
|
||||
|
||||
{% capture discussion %}
|
||||
## Understanding ...
|
||||
|
||||
Here's an interesting thing to know about the steps you just did.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn more about [this](...).
|
||||
* See this [related task](...).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
||||
</pre>
|
||||
{% endraw %}
|
||||
|
||||
<p>Here's an example of a published topic that uses the task template:</p>
|
||||
|
||||
<p><a href="/docs/tasks/access-kubernetes-api/http-proxy-access-api">Using an HTTP Proxy to Access the Kubernetes API</a></p>
|
||||
|
||||
<h2 id="tutorial_template">Tutorial template</h2>
|
||||
|
||||
<p>A tutorial page shows how to accomplish a goal that is larger than a single
|
||||
task. Typically a tutorial page has several sections, each of which has a
|
||||
sequence of steps. For example, a tutorial might provide a walkthrough of a
|
||||
code sample that illustrates a certain feature of Kubernetes. Tutorials can
|
||||
include surface-level explanations, but should link to related concept topics
|
||||
for deep explanations.
|
||||
|
||||
<p>To write a new tutorial page, create a Markdown file in a subdirectory of the
|
||||
/docs/tutorials directory. In your Markdown file, provide values for these
|
||||
variables, and then include templates/tutorial.md:</p>
|
||||
|
||||
<ul>
|
||||
<li>overview - required</li>
|
||||
<li>prerequisites - required</li>
|
||||
<li>objectives - required</li>
|
||||
<li>lessoncontent - required</li>
|
||||
<li>cleanup - optional</li>
|
||||
<li>whatsnext - optional</li>
|
||||
</ul>
|
||||
|
||||
<p>In the <code>lessoncontent</code> section, use <code>##</code> to start with a level-two heading. For subheadings,
|
||||
use <code>###</code> and <code>####</code> as needed.
|
||||
|
||||
<p>Here's an example of a Markdown file that uses the tutorial template:</p>
|
||||
|
||||
{% raw %}
|
||||
<pre>---
|
||||
title: Running a Thing
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page shows how to ...
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
* Do this.
|
||||
* Do this too.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture objectives %}
|
||||
* Learn this.
|
||||
* Build this.
|
||||
* Run this.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture lessoncontent %}
|
||||
## Building ...
|
||||
|
||||
1. Do this.
|
||||
1. Do this next. Possibly read this [related explanation](...).
|
||||
|
||||
## Running ...
|
||||
|
||||
1. Do this.
|
||||
1. Do this next.
|
||||
|
||||
## Understanding the code
|
||||
Here's something interesting about the code you ran in the preceding steps.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture cleanup %}
|
||||
* Delete this.
|
||||
* Stop this.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn more about [this](...).
|
||||
* See this [related tutorial](...).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/tutorial.md %}
|
||||
</pre>
|
||||
{% endraw %}
|
||||
|
||||
<p>Here's an example of a published topic that uses the tutorial template:</p>
|
||||
|
||||
<p><a href="/docs/tutorials/stateless-application/run-stateless-application-deployment/">Running a Stateless Application Using a Deployment</a></p>
|
||||
|
||||
<h2 id="concept_template">Concept template</h2>
|
||||
|
||||
<p>A concept page explains some aspect of Kubernetes. For example, a concept
|
||||
page might describe the Kubernetes Deployment object and explain the role it
|
||||
plays as an application is deployed, scaled, and updated. Typically, concept
|
||||
pages don't include sequences of steps, but instead provide links to tasks or
|
||||
tutorials.
|
||||
|
||||
<p>To write a new concept page, create a Markdown file in a subdirectory of the
|
||||
/docs/concepts directory. In your Markdown file, provide values for these
|
||||
variables, and then include templates/concept.md:</p>
|
||||
|
||||
<ul>
|
||||
<li>overview - required</li>
|
||||
<li>body - required</li>
|
||||
<li>whatsnext - optional</li>
|
||||
</ul>
|
||||
|
||||
<p>In the <code>body</code> section, use <code>##</code> to start with a level-two heading. For subheadings,
|
||||
use <code>###</code> and <code>####</code> as needed.
|
||||
|
||||
<p>Here's an example of a page that uses the concept template:</p>
|
||||
|
||||
{% raw %}
|
||||
<pre>---
|
||||
title: Understanding this Thing
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page explains ...
|
||||
{% endcapture %}
|
||||
|
||||
{% capture body %}
|
||||
## Understanding ...
|
||||
|
||||
Kubernetes provides ...
|
||||
|
||||
## Using ...
|
||||
|
||||
To use ...
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn more about [this](...).
|
||||
* See this [related task](...).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/concept.md %}
|
||||
</pre>
|
||||
{% endraw %}
|
||||
|
||||
<p>Here's an example of a published topic that uses the concept template:</p>
|
||||
|
||||
<p><a href="/docs/concepts/object-metadata/annotations">Annotations</a></p>
|
||||
|
||||
<!--</body>
|
||||
</html>-->
|
||||
{% include support-content-moved.md %}
|
||||
|
||||
[Using Page Templates](/docs/home/contribute/page-template/)
|
||||
|
|
|
@ -2,72 +2,6 @@
|
|||
title: Reviewing Documentation Issues
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
{% include support-content-moved.md %}
|
||||
|
||||
This page explains how documentation issues are reviewed and prioritized for the [kubernetes/kubernetes.github.io](https://github.com/kubernetes/kubernetes.github.io){: target="_blank"} repository. The purpose is to provide a way to organize issues and make it easier to contribute to Kubernetes documentation. The following should be used as the standard way of prioritizing, labeling, and interacting with issues.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture body %}
|
||||
|
||||
## Categorizing issues
|
||||
Issues should be sorted into different buckets of work using the following labels and definitions. If an issue doesn't have enough information to identify a problem that can be researched, reviewed, or worked on (i.e. the issue doesn't fit into any of the categories below) you should close the issue with a comment explaining why it is being closed.
|
||||
|
||||
### Needs Clarification
|
||||
* Issues that need more information from the original submitter to make them actionable. Issues with this label that aren't followed up within a week may be closed.
|
||||
|
||||
### Actionable
|
||||
* Issues that can be worked on with current information (or may need a comment to explain what needs to be done to make it more clear)
|
||||
* Allows contributors to have easy to find issues to work on
|
||||
|
||||
|
||||
### Needs Tech Review
|
||||
* Issues that need more information in order to be worked on (the proposed solution needs to be proven, a subject matter expert needs to be involved, work needs to be done to understand the problem/resolution and if the issue is still relevant)
|
||||
* Promotes transparency about level of work needed for the issue and that issue is in progress
|
||||
|
||||
### Needs Docs Review
|
||||
* Issues that are suggestions for better processes or site improvements that require community agreement to be implemented
|
||||
* Topics can be brought to SIG meetings as agenda items
|
||||
|
||||
### Needs UX Review
|
||||
* Issues that are suggestions for improving the user interface of the site.
|
||||
* Fixing broken site elements.
|
||||
|
||||
|
||||
## Prioritizing Issues
|
||||
The following labels and definitions should be used to prioritize issues. If you change the priority of an issues, please comment on the issue with your reasoning for the change.
|
||||
|
||||
### P1
|
||||
* Major content errors affecting more than 1 page
|
||||
* Broken code sample on a heavily trafficked page
|
||||
* Errors on a “getting started” page
|
||||
* Well known or highly publicized customer pain points
|
||||
* Automation issues
|
||||
|
||||
### P2
|
||||
* Default for all new issues
|
||||
* Broken code for sample that is not heavily used
|
||||
* Minor content issues in a heavily trafficked page
|
||||
* Major content issues on a lower-trafficked page
|
||||
|
||||
### P3
|
||||
* Typos and broken anchor links
|
||||
|
||||
## Handling special issue types
|
||||
|
||||
### Duplicate issues
|
||||
If a single problem has one or more issues open for it, the problem should be consolodated into a single issue. You should decide which issue to keep open (or open a new issue), port over all relevant information, link related issues, and close all the other issues that describe the same problem. Only having a single issue to work on will help reduce confusion and avoid duplicating work on the same problem.
|
||||
|
||||
### Dead link issues
|
||||
Depending on where the dead link is reported, different actions are required to resolve the issue. Dead links in the API and Kubectl docs are automation issues and should be assigned a P1 until the problem can be fully understood. All other dead links are issues that need to be manually fixed and can be assigned a P3.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [writing a new topic](/docs/contribute/write-new-topic).
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [staging your changes](/docs/contribute/stage-documentation-changes).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/concept.md %}
|
||||
[Reviewing Documentation Issues](/docs/home/contribute/review-issues/)
|
||||
|
|
|
@ -2,108 +2,6 @@
|
|||
title: Staging Your Documentation Changes
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page shows how to stage content that you want to contribute
|
||||
to the Kubernetes documentation.
|
||||
{% endcapture %}
|
||||
{% include support-content-moved.md %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
Create a fork of the Kubernetes documentation repository as described in
|
||||
[Creating a Documentation Pull Request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
## Staging from your GitHub account
|
||||
|
||||
GitHub provides staging of content in your master branch. Note that you
|
||||
might not want to merge your changes into your master branch. If that is
|
||||
the case, choose another option for staging your content.
|
||||
|
||||
1. In your GitHub account, in your fork, merge your changes into
|
||||
the master branch.
|
||||
|
||||
1. Change the name of your repository to `<your-username>.github.io`, where
|
||||
`<your-username>` is the username of your GitHub account.
|
||||
|
||||
1. Delete the `CNAME` file.
|
||||
|
||||
1. View your staged content at this URL:
|
||||
|
||||
https://<your-username>.github.io
|
||||
|
||||
## Staging a pull request
|
||||
|
||||
When you create a pull request, either against the master or <vnext>
|
||||
branch, your changes are staged in a custom subdomain on Netlify so that
|
||||
you can see your changes in rendered form before the pull request is merged.
|
||||
|
||||
1. In your GitHub account, in your new branch, submit a pull request to the
|
||||
kubernetes/kubernetes.github.io repository. This opens a page that shows the
|
||||
status of your pull request.
|
||||
|
||||
1. Scroll down to the list of automated checks. Click **Show all checks**.
|
||||
Wait for the **deploy/netlify** check to complete. To the right of
|
||||
**deploy/netlify**, click **Details**. This opens a staging site where you
|
||||
can see your changes.
|
||||
|
||||
## Staging locally using Docker
|
||||
|
||||
You can use the k8sdocs Docker image to run a local staging server. If you're
|
||||
interested, you can view the
|
||||
[Dockerfile](https://github.com/kubernetes/kubernetes.github.io/blob/master/staging-container/Dockerfile){: target="_blank"}
|
||||
for this image.
|
||||
|
||||
1. Install Docker if you don't already have it.
|
||||
|
||||
1. Clone your fork to your local development machine.
|
||||
|
||||
1. In the root of your cloned repository, enter this command to start a local
|
||||
web server:
|
||||
|
||||
docker run -ti --rm -v "$PWD":/k8sdocs -p 4000:4000 gcr.io/google-samples/k8sdocs:1.1
|
||||
|
||||
1. View your staged content at
|
||||
[http://localhost:4000](http://localhost:4000){: target="_blank"}.
|
||||
|
||||
## Staging locally without Docker
|
||||
|
||||
1. [Install Ruby 2.2 or later](https://www.ruby-lang.org){: target="_blank"}.
|
||||
|
||||
1. [Install RubyGems](https://rubygems.org){: target="_blank"}.
|
||||
|
||||
1. Verify that Ruby and RubyGems are installed:
|
||||
|
||||
gem --version
|
||||
|
||||
1. Install the GitHub Pages package, which includes Jekyll:
|
||||
|
||||
gem install github-pages
|
||||
|
||||
1. Clone your fork to your local development machine.
|
||||
|
||||
1. In the root of your cloned repository, enter this command to start a local
|
||||
web server:
|
||||
|
||||
jekyll serve
|
||||
|
||||
1. View your staged content at
|
||||
[http://localhost:4000](http://localhost:4000){: target="_blank"}.
|
||||
|
||||
<i>NOTE: If you do not want Jekyll to interfere with your other globally installed gems, you can use `bundler`:</i>
|
||||
|
||||
gem install bundler
|
||||
bundle install
|
||||
bundler exec jekyll serve
|
||||
|
||||
<i> Regardless of whether you use `bundler` or not, your copy of the site will then be viewable at: [http://localhost:4000](http://localhost:4000)</i>
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [writing a new topic](/docs/contribute/write-new-topic/).
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [creating a pull request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
||||
[Staging Your Documentation Changes](/docs/home/contribute/stage-documentation-changes/)
|
||||
|
|
|
@ -2,235 +2,6 @@
|
|||
title: Documentation Style Guide
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page gives writing style guidelines for the Kubernetes documentation.
|
||||
These are guidelines, not rules. Use your best judgment, and feel free to
|
||||
propose changes to this document in a pull request.
|
||||
{% include support-content-moved.md %}
|
||||
|
||||
For additional information on creating new content for the Kubernetes
|
||||
docs, follow the instructions on
|
||||
[using page templates](/docs/contribute/page-templates/) and
|
||||
[creating a documentation pull request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% capture body %}
|
||||
|
||||
## Documentation formatting standards
|
||||
|
||||
### Use camel case for API objects
|
||||
|
||||
When you refer to an API object, use the same uppercase and lowercase letters
|
||||
that are used in the actual object name. Typically, the names of API
|
||||
objects use
|
||||
[camel case](https://en.wikipedia.org/wiki/Camel_case).
|
||||
|
||||
Don't split the API object name into separate words. For example, use
|
||||
PodTemplateList, not Pod Template List.
|
||||
|
||||
Refer to API objects without saying "object," unless omitting "object"
|
||||
leads to an awkward construction.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>The Pod has two Containers.</td><td>The pod has two containers.</td></tr>
|
||||
<tr><td>The Deployment is responsible for ...</td><td>The Deployment object is responsible for ...</td></tr>
|
||||
<tr><td>A PodList is a list of Pods.</td><td>A Pod List is a list of pods.</td></tr>
|
||||
<tr><td>The two ContainerPorts ...</td><td>The two ContainerPort objects ...</td></tr>
|
||||
<tr><td>The two ContainerStateTerminated objects ...</td><td>The two ContainerStateTerminateds ...</td></tr>
|
||||
</table>
|
||||
|
||||
### Use angle brackets for placeholders
|
||||
|
||||
Use angle brackets for placeholders. Tell the reader what a placeholder
|
||||
represents.
|
||||
|
||||
1. Display information about a pod:
|
||||
|
||||
kubectl describe pod <pod-name>
|
||||
|
||||
where `<pod-name>` is the name of one of your pods.
|
||||
|
||||
### Use bold for user interface elements
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Click <b>Fork</b>.</td><td>Click "Fork".</td></tr>
|
||||
<tr><td>Select <b>Other</b>.</td><td>Select 'Other'.</td></tr>
|
||||
</table>
|
||||
|
||||
### Use italics to define or introduce new terms
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>A <i>cluster</i> is a set of nodes ...</td><td>A "cluster" is a set of nodes ...</td></tr>
|
||||
<tr><td>These components form the <i>control plane.</i></td><td>These components form the <b>control plane.</b></td></tr>
|
||||
</table>
|
||||
|
||||
### Use code style for filenames, directories, and paths
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Open the <code>envars.yaml</code> file.</td><td>Open the envars.yaml file.</td></tr>
|
||||
<tr><td>Go to the <code>/docs/tutorials</code> directory.</td><td>Go to the /docs/tutorials directory.</td></tr>
|
||||
<tr><td>Open the <code>/_data/concepts.yaml</code> file.</td><td>Open the /_data/concepts.yaml file.</td></tr>
|
||||
</table>
|
||||
|
||||
## Inline code formatting
|
||||
|
||||
### Use code style for inline code and commands
|
||||
|
||||
For inline code in an HTML document, use the `<code>` tag. In a Markdown
|
||||
document, use the backtick (`).
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>The <code>kubectl run</code> command creates a Deployment.</td><td>The "kubectl run" command creates a Deployment.</td></tr>
|
||||
<tr><td>For declarative management, use <code>kubectl apply</code>.</td><td>For declarative management, use "kubectl apply".</td></tr>
|
||||
</table>
|
||||
|
||||
### Use code style for object field names
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Set the value of the <code>replicas</code> field in the configuration file.</td><td>Set the value of the "replicas" field in the configuration file.</td></tr>
|
||||
<tr><td>The value of the <code>exec</code> field is an ExecAction object.</td><td>The value of the "exec" field is an ExecAction object.</td></tr>
|
||||
</table>
|
||||
|
||||
### Use normal style for string and integer field values
|
||||
|
||||
For field values of type string or integer, use normal style without quotation marks.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Set the value of <code>imagePullPolicy</code> to Always.</td><td>Set the value of <code>imagePullPolicy</code> to "Always".</td></tr>
|
||||
<tr><td>Set the value of <code>image</code> to nginx:1.8.</td><td>Set the value of <code>image</code> to <code>nginx:1.8</code>.</td></tr>
|
||||
<tr><td>Set the value of the <code>replicas</code> field to 2.</td><td>Set the value of the <code>replicas</code> field to <code>2</code>.</td></tr>
|
||||
</table>
|
||||
|
||||
## Code snippet formatting
|
||||
|
||||
### Don't include the command prompt
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>kubectl get pods</td><td>$ kubectl get pods</td></tr>
|
||||
</table>
|
||||
|
||||
### Separate commands from output
|
||||
|
||||
Verify that the pod is running on your chosen node:
|
||||
|
||||
kubectl get pods --output=wide
|
||||
|
||||
The output is similar to this:
|
||||
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
nginx 1/1 Running 0 13s 10.200.0.4 worker0
|
||||
|
||||
|
||||
{% comment %}## Kubernetes.io word list
|
||||
|
||||
A list of Kubernetes-specific terms and words to be used consistently across the site.
|
||||
|
||||
<table>
|
||||
<tr><th>Term</th><th>Useage</th></tr>
|
||||
<tr><td>TBD</td><td>TBD</td></tr>
|
||||
</table>{% endcomment %}
|
||||
|
||||
|
||||
## Content best practices
|
||||
|
||||
This section contains suggested best practices for clear, concise, and consistent content.
|
||||
|
||||
### Use present tense
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>This command starts a proxy.</td><td>This command will start a proxy.</td></tr>
|
||||
</table>
|
||||
|
||||
Exception: Use future or past tense if it is required to convey the correct
|
||||
meaning.
|
||||
|
||||
### Use active voice
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>You can explore the API using a browser.</td><td>The API can be explored using a browser.</td></tr>
|
||||
<tr><td>The YAML file specifies the replica count.</td><td>The replica count is specified in the YAML file.</td></tr>
|
||||
</table>
|
||||
|
||||
Exception: Use passive voice if active voice leads to an awkward construction.
|
||||
|
||||
### Use simple and direct language
|
||||
|
||||
Use simple and direct language. Avoid using unnecessary phrases, such as saying "please."
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>To create a ReplicaSet, ...</td><td>In order to create a ReplicaSet, ...</td></tr>
|
||||
<tr><td>See the configuration file.</td><td>Please see the configuration file.</td></tr>
|
||||
<tr><td>View the Pods.</td><td>With this next command, we'll view the Pods.</td></tr>
|
||||
|
||||
</table>
|
||||
|
||||
### Address the reader as "you"
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>You can create a Deployment by ...</td><td>We'll create a Deployment by ...</td></tr>
|
||||
<tr><td>In the preceding output, you can see...</td><td>In the preceding output, we can see ...</td></tr>
|
||||
</table>
|
||||
|
||||
## Patterns to avoid
|
||||
|
||||
### Avoid using "we"
|
||||
|
||||
Using "we" in a sentence can be confusing, because the reader might not know
|
||||
whether they're part of the "we" you're describing.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Version 1.4 includes ...</td><td>In version 1.4, we have added ...</td></tr>
|
||||
<tr><td>Kubernetes provides a new feature for ...</td><td>We provide a new feature ...</td></tr>
|
||||
<tr><td>This page teaches you how to use pods.</td><td>In this page, we are going to learn about pods.</td></tr>
|
||||
</table>
|
||||
|
||||
### Avoid jargon and idioms
|
||||
|
||||
Some readers speak English as a second language. Avoid jargon and idioms to help make their understanding easier.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Internally, ...</td><td>Under the hood, ...</td></tr>
|
||||
<tr><td>Create a new cluster.</td><td>Turn up a new cluster.</td></tr>
|
||||
</table>
|
||||
|
||||
### Avoid statements about the future
|
||||
|
||||
Avoid making promises or giving hints about the future. If you need to talk about
|
||||
an alpha feature, put the text under a heading that identifies it as alpha
|
||||
information.
|
||||
|
||||
### Avoid statements that will soon be out of date
|
||||
|
||||
Avoid words like "currently" and "new." A feature that is new today might not be
|
||||
considered new in a few months.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>In version 1.4, ...</td><td>In the current version, ...</td></tr>
|
||||
<tr><td>The Federation feature provides ...</td><td>The new Federation feature provides ...</td></tr>
|
||||
</table>
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [writing a new topic](/docs/contribute/write-new-topic/).
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [staging your changes](/docs/contribute/stage-documentation-changes/)
|
||||
* Learn about [creating a pull request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/concept.md %}
|
||||
[Documentation Style Guide](/docs/home/contribute/style-guide/)
|
||||
|
|
|
@ -2,142 +2,6 @@
|
|||
title: Writing a New Topic
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page shows how to create a new topic for the Kubernetes docs.
|
||||
{% endcapture %}
|
||||
{% include support-content-moved.md %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
Create a fork of the Kubernetes documentation repository as described in
|
||||
[Creating a Documentation Pull Request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
## Choosing a page type
|
||||
|
||||
As you prepare to write a new topic, think about which of these page types
|
||||
is the best fit for your content:
|
||||
|
||||
<table>
|
||||
|
||||
<tr>
|
||||
<td>Task</td>
|
||||
<td>A task page shows how to do a single thing, typically by giving a short sequence of steps. Task pages have minimal explanation, but often provide links to conceptual topics that provide related background and knowledge.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Tutorial</td>
|
||||
<td>A tutorial page shows how to accomplish a goal that is larger than a single task. Typically a tutorial page has several sections, each of which has a sequence of steps. For example, a tutorial might provide a walkthrough of a code sample that illustrates a certain feature of Kubernetes. Tutorials can include surface-level explanations, but should link to related concept topics for deep explanations.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Concept</td>
|
||||
<td>A concept page explains some aspect of Kubernetes. For example, a concept page might describe the Kubernetes Deployment object and explain the role it plays as an application is deployed, scaled, and updated. Typically, concept pages don't include sequences of steps, but instead provide links to tasks or tutorials.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
Each page type has a
|
||||
[template](/docs/contribute/page-templates/)
|
||||
that you can use as you write your topic.
|
||||
Using templates helps ensure consistency among topics of a given type.
|
||||
|
||||
## Choosing a title and filename
|
||||
|
||||
Choose a title that has the keywords you want search engines to find.
|
||||
Create a filename that uses the words in your title separated by hyphens.
|
||||
For example, the topic with title
|
||||
[Using an HTTP Proxy to Access the Kubernetes API](/docs/tasks/access-kubernetes-api/http-proxy-access-api/)
|
||||
has filename `http-proxy-access-api.md`. You don't need to put
|
||||
"kubernetes" in the filename, because "kubernetes" is already in the
|
||||
URL for the topic, for example:
|
||||
|
||||
http://kubernetes.io/docs/tasks/access-kubernetes-api/http-proxy-access-api/
|
||||
|
||||
## Adding the topic title to the front matter
|
||||
|
||||
In your topic, put a `title` field in the
|
||||
[front matter](https://jekyllrb.com/docs/frontmatter/).
|
||||
The front matter is the YAML block that is between the
|
||||
triple-dashed lines at the top of the page. Here's an example:
|
||||
|
||||
---
|
||||
title: Using an HTTP Proxy to Access the Kubernetes API
|
||||
---
|
||||
|
||||
## Choosing a directory
|
||||
|
||||
Depending on your page type, put your new file in a subdirectory of one of these:
|
||||
|
||||
* /docs/tasks/
|
||||
* /docs/tutorials/
|
||||
* /docs/concepts/
|
||||
|
||||
You can put your file in an existing subdirectory, or you can create a new
|
||||
subdirectory.
|
||||
|
||||
## Creating an entry in the table of contents
|
||||
|
||||
Depending page type, create an entry in one of these files:
|
||||
|
||||
* /_data/tasks.yaml
|
||||
* /_data/tutorials.yaml
|
||||
* /_data/concepts.yaml
|
||||
|
||||
Here's an example of an entry in /_data/tasks.yaml:
|
||||
|
||||
- docs/tasks/configure-pod-container/configure-volume-storage.md
|
||||
|
||||
## Including code from another file
|
||||
|
||||
To include a code file in your topic, place the code file in the Kubernetes
|
||||
documentation repository, preferably in the same directory as your topic
|
||||
file. In your topic file, use the `include` tag:
|
||||
|
||||
<pre>{% include code.html language="<LEXERVALUE>" file="<RELATIVEPATH>" ghlink="/<PATHFROMROOT>" %}</pre>
|
||||
|
||||
where:
|
||||
|
||||
* `<LEXERVALUE>` is the language in which the file was written. This must be
|
||||
[a value supported by Rouge](https://github.com/jneen/rouge/wiki/list-of-supported-languages-and-lexers).
|
||||
* `<RELATIVEPATH>` is the path to the file you're including, relative to the current file, for example, `gce-volume.yaml`.
|
||||
* `<PATHFROMROOT>` is the path to the file relative to root, for example, `docs/tutorials/stateful-application/gce-volume.yaml`.
|
||||
|
||||
Here's an example of using the `include` tag:
|
||||
|
||||
<pre>{% include code.html language="yaml" file="gce-volume.yaml" ghlink="/docs/tutorials/stateful-application/gce-volume.yaml" %}</pre>
|
||||
|
||||
## Showing how to create an API object from a configuration file
|
||||
|
||||
If you need to show the reader how to create an API object based on a
|
||||
configuration file, place the configuration file in the Kubernetes documentation
|
||||
repository, preferably in the same directory as your topic file.
|
||||
|
||||
In your topic, show this command:
|
||||
|
||||
kubectl create -f http://k8s.io/<PATHFROMROOT>
|
||||
|
||||
where `<PATHFROMROOT>` is the path to the configuration file relative to root,
|
||||
for example, `docs/tutorials/stateful-application/gce-volume.yaml`.
|
||||
|
||||
Here's an example of a command that creates an API object from a configuration file:
|
||||
|
||||
kubectl create -f http://k8s.io/docs/tutorials/stateful-application/gce-volume.yaml
|
||||
|
||||
For an example of a topic that uses this technique, see
|
||||
[Running a Single-Instance Stateful Application](/docs/tutorials/stateful-application/run-stateful-application/).
|
||||
|
||||
## Adding images to a topic
|
||||
|
||||
Put image files in the `/images` directory. The preferred
|
||||
image format is SVG.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [staging your changes](/docs/contribute/stage-documentation-changes).
|
||||
* Learn about [creating a pull request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
||||
[Writing a New Topic](/docs/home/contribute/write-new-topic/)
|
||||
|
|
|
@ -6,257 +6,7 @@ assignees:
|
|||
title: Kubernetes Deprecation Policy
|
||||
---
|
||||
|
||||
Kubernetes is a large system with many components and many contributors. As
|
||||
with any such software, the feature set naturally evolves over time, and
|
||||
sometimes a feature may need to be removed. This could include an API, a flag,
|
||||
or even an entire feature. To avoid breaking existing users, Kubernetes follows
|
||||
a deprecation policy for aspects of the system that are slated to be removed.
|
||||
{% include support-content-moved.md %}
|
||||
|
||||
This document details the deprecation policy for various facets of the system.
|
||||
[Kubernetes Deprecation Policy](/docs/home/deprecation-policy/)
|
||||
|
||||
## Deprecating parts of the API
|
||||
|
||||
Since Kubernetes is an API-driven system, the API has evolved over time to
|
||||
reflect the evolving understanding of the problem space. The Kubernetes API is
|
||||
actually a set of APIs, called "API groups", and each API group is
|
||||
independently versioned. [API versions](http://kubernetes.io/docs/api/) fall
|
||||
into 3 main tracks, each of which has different policies for deprecation:
|
||||
|
||||
| Example | Track |
|
||||
|----------|----------------------------------|
|
||||
| v1 | GA (generally available, stable) |
|
||||
| v1beta1 | Beta (pre-release) |
|
||||
| v1alpha1 | Alpha (experimental) |
|
||||
|
||||
A given release of Kubernetes can support any number of API groups and any
|
||||
number of versions of each.
|
||||
|
||||
The following rules govern the deprecation of elements of the API. This
|
||||
includes:
|
||||
|
||||
* REST resources (aka API objects)
|
||||
* Fields of REST resources
|
||||
* Enumerated or constant values
|
||||
* Component config structures
|
||||
|
||||
These rules are enforced between official releases, not between
|
||||
arbitrary commits to master or release branches.
|
||||
|
||||
**Rule #1: API elements may only be removed by incrementing the version of the
|
||||
API group.**
|
||||
|
||||
Once an API element has been added to an API group at a particular version, it
|
||||
can not be removed from that version or have its behavior significantly
|
||||
changed, regardless of track.
|
||||
|
||||
Note: For historical reasons, there are 2 "monolithic" API groups - "core" (no
|
||||
group name) and "extensions". Resources will incrementally be moved from these
|
||||
legacy API groups into more domain-specific API groups.
|
||||
|
||||
**Rule #2: API objects must be able to round-trip between API versions in a given
|
||||
release without information loss, with the exception of whole REST resources
|
||||
that do not exist in some versions.**
|
||||
|
||||
For example, an object can be written as v1 and then read back as v2 and
|
||||
converted to v1, and the resulting v1 resource will be identical to the
|
||||
original. The representation in v2 might be different from v1, but the system
|
||||
knows how to convert between them in both directions. Additionally, any new
|
||||
field added in v2 must be able to round-trip to v1 and back, which means v1
|
||||
might have to add an equivalent field or represent it as an annotation.
|
||||
|
||||
**Rule #3: An API version in a given track may not be deprecated until a new
|
||||
API version at least as stable is released.**
|
||||
|
||||
GA API versions can replace GA API versions as well as beta and alpha API
|
||||
version. Beta API versions *may not* replace GA API versions.
|
||||
|
||||
**Rule #4: Other than the most recent API version in each track, older API
|
||||
versions must be supported after their announced deprecation for a duration of
|
||||
no less than:**
|
||||
|
||||
* **GA: 1 year or 2 releases (whichever is longer)**
|
||||
* **Beta: 3 months or 1 release (whichever is longer)**
|
||||
* **Alpha: 0 releases**
|
||||
|
||||
This is best illustrated by example. Imagine a Kubernetes release, version X,
|
||||
which supports a particular API group. A new Kubernetes release is made every
|
||||
approximately 3 months (4 per year). The following table describes which API
|
||||
versions are supported in a series of subsequent releases.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Release</th>
|
||||
<th>API Versions</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>X</td>
|
||||
<td>v1</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+1</td>
|
||||
<td>v1, v2alpha1</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+2</td>
|
||||
<td>v1, v2alpha2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2alpha1 is removed, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+3</td>
|
||||
<td>v1, v2beta1</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2alpha2 is removed, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+4</td>
|
||||
<td>v1, v2beta1, v2beta2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2beta1 is deprecated, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+5</td>
|
||||
<td>v1, v2, v2beta2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2beta1 is removed, "action required" relnote</li>
|
||||
<li>v2beta2 is deprecated, "action required" relnote</li>
|
||||
<li>v1 is deprecated, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+6</td>
|
||||
<td>v1, v2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2beta2 is removed, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+7</td>
|
||||
<td>v1, v2</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+8</td>
|
||||
<td>v1, v2</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+9</td>
|
||||
<td>v2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v1 is removed, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### REST resources (aka API objects)
|
||||
|
||||
Consider a hypothetical REST resource named Widget, which was present in API v1
|
||||
in the above timeline, and which needs to be deprecated. We
|
||||
[document](http://kubernetes.io/docs/deprecated/) and
|
||||
[announce](https://groups.google.com/forum/#!forum/kubernetes-announce) the
|
||||
deprecation in sync with release X+1. The Widget resource still exists in API
|
||||
version v1 (deprecated) but not in v2alpha1. The Widget resource continues to
|
||||
exist and function in releases up to and including X+8. Only in release X+9,
|
||||
when API v1 has aged out, does the Widget resource cease to exist, and the
|
||||
behavior get removed.
|
||||
|
||||
### Fields of REST resources
|
||||
|
||||
As with whole REST resources, an individual field which was present in API v1
|
||||
must exist and function until API v1 is removed. Unlike whole resources, the
|
||||
v2 APIs may choose a different representation for the field, as long as it can
|
||||
be round-tripped. For example a v1 field named "magnitude" which was
|
||||
deprecated might be named "deprecatedMagnitude" in API v2. When v1 is
|
||||
eventually removed, the deprecated field can be removed from v2.
|
||||
|
||||
### Enumerated or constant values
|
||||
|
||||
As with whole REST resources and fields thereof, a constant value which was
|
||||
supported in API v1 must exist and function until API v1 is removed.
|
||||
|
||||
### Component config structures
|
||||
|
||||
Component configs are versioned and managed just like REST resources.
|
||||
|
||||
### Future work
|
||||
|
||||
Over time, Kubernetes will introduce more fine-grained API versions, at which
|
||||
point these rules will be adjusted as needed.
|
||||
|
||||
## Deprecating a flag or CLI
|
||||
|
||||
The Kubernetes system is comprised of several different programs cooperating.
|
||||
Sometimes, a Kubernetes release might remove flags or CLI commands
|
||||
(collectively "CLI elements") in these programs. The individual programs
|
||||
naturally sort into two main groups - user-facing and admin-facing programs,
|
||||
which vary slightly in their deprecation policies. Unless a flag is explicitly
|
||||
prefixed or documented as "alpha" or "beta", it is considered GA.
|
||||
|
||||
CLI elements are effectively part of the API to the system, but since they are
|
||||
not versioned in the same way as the REST API, the rules for deprecation are as
|
||||
follows:
|
||||
|
||||
**Rule #5a: CLI elements of user-facing components (e.g. kubectl) must function
|
||||
after their announced deprecation for no less than:**
|
||||
|
||||
* **GA: 1 year or 2 releases (whichever is longer)**
|
||||
* **Beta: 3 months or 1 release (whichever is longer)**
|
||||
* **Alpha: 0 releases**
|
||||
|
||||
**Rule #5b: CLI elements of admin-facing components (e.g. kubelet) must function
|
||||
after their announced deprecation for no less than:**
|
||||
|
||||
* **GA: 6 months or 1 release (whichever is longer)**
|
||||
* **Beta: 3 months or 1 release (whichever is longer)**
|
||||
* **Alpha: 0 releases**
|
||||
|
||||
**Rule #6: Deprecated CLI elements must emit warnings (optionally disable)
|
||||
when used.**
|
||||
|
||||
## Deprecating a feature or behavior
|
||||
|
||||
Occasionally a Kubernetes release needs to deprecate some feature or behavior
|
||||
of the system that is not controlled by the API or CLI. In this case, the
|
||||
rules for deprecation are as follows:
|
||||
|
||||
**Rule #7: Deprecated behaviors must function for no less than 1 year after their
|
||||
announced deprecation.**
|
||||
|
||||
This does not imply that all changes to the system are governed by this policy.
|
||||
This applies only to significant, user-visible behaviors which impact the
|
||||
correctness of applications running on Kubernetes or that impact the
|
||||
administration of Kubernetes clusters, and which are being removed entirely.
|
||||
|
||||
## Exceptions
|
||||
|
||||
No policy can cover every possible situation. This policy is a living
|
||||
document, and will evolve over time. In practice, there will be situations
|
||||
that do not fit neatly into this policy, or for which this policy becomes a
|
||||
serious impediment. Such situations should be discussed with SIGs and project
|
||||
leaders to find the best solutions for those specific cases, always bearing in
|
||||
mind that Kubernetes is committed to being a stable system that, as much as
|
||||
possible, never breaks users. Exceptions will always be announced in all
|
||||
relevant release notes.
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
title: Creating a Documentation Pull Request
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
To contribute to the Kubernetes documentation, create a pull request against the
|
||||
[kubernetes/kubernetes.github.io](https://github.com/kubernetes/kubernetes.github.io){: target="_blank"}
|
||||
repository. This page shows how to create a pull request.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
|
||||
1. Create a [GitHub account](https://github.com){: target="_blank"}.
|
||||
|
||||
1. Sign the
|
||||
[Linux Foundation Contributor License Agreement](https://identity.linuxfoundation.org/projects/cncf){: target="_blank"}.
|
||||
|
||||
Documentation will be published under the [CC BY SA 4.0](https://github.com/kubernetes/kubernetes.github.io/blob/master/LICENSE) license.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
## Creating a fork of the Kubernetes documentation repository
|
||||
|
||||
1. Go to the
|
||||
[kubernetes/kubernetes.github.io](https://github.com/kubernetes/kubernetes.github.io){: target="_blank"}
|
||||
repository.
|
||||
|
||||
1. In the upper-right corner, click **Fork**. This creates a copy of the
|
||||
Kubernetes documentation repository in your GitHub account. The copy
|
||||
is called a *fork*.
|
||||
|
||||
## Making your changes
|
||||
|
||||
1. In your GitHub account, in your fork of the Kubernetes docs, create
|
||||
a new branch to use for your contribution.
|
||||
|
||||
1. In your new branch, make your changes and commit them. If you want to
|
||||
[write a new topic](/docs/contribute/write-new-topic/),
|
||||
choose the
|
||||
[page type](/docs/contribute/page-templates/)
|
||||
that is the best fit for your content.
|
||||
|
||||
## Submitting a pull request to the master branch (Current Release)
|
||||
|
||||
If you want your change to be published in the released version Kubernetes docs,
|
||||
create a pull request against the master branch of the Kubernetes
|
||||
documentation repository.
|
||||
|
||||
1. In your GitHub account, in your new branch, create a pull request
|
||||
against the master branch of the kubernetes/kubernetes.github.io
|
||||
repository. This opens a page that shows the status of your pull request.
|
||||
|
||||
1. Click **Show all checks**. Wait for the **deploy/netlify** check to complete.
|
||||
To the right of **deploy/netlify**, click **Details**. This opens a staging
|
||||
site where you can verify that your changes have rendered correctly.
|
||||
|
||||
1. During the next few days, check your pull request for reviewer comments.
|
||||
If needed, revise your pull request by committing changes to your
|
||||
new branch in your fork.
|
||||
|
||||
## Submitting a pull request to the <vnext> branch (Upcoming Release)
|
||||
|
||||
If your documentation change should not be released until the next release of
|
||||
the Kubernetes product, create a pull request against the <vnext> branch
|
||||
of the Kubernetes documentation repository. The <vnext> branch has the
|
||||
form `release-<version-number>`, for example release-1.5.
|
||||
|
||||
1. In your GitHub account, in your new branch, create a pull request
|
||||
against the <vnext> branch of the kubernetes/kubernetes.github.io
|
||||
repository. This opens a page that shows the status of your pull request.
|
||||
|
||||
1. Click **Show all checks**. Wait for the **deploy/netlify** check to complete.
|
||||
To the right of **deploy/netlify**, click **Details**. This opens a staging
|
||||
site where you can verify that your changes have rendered correctly.
|
||||
|
||||
1. During the next few days, check your pull request for reviewer comments.
|
||||
If needed, revise your pull request by committing changes to your
|
||||
new branch in your fork.
|
||||
|
||||
The staging site for the upcoming Kubernetes release is here:
|
||||
[http://kubernetes-io-vnext-staging.netlify.com/](http://kubernetes-io-vnext-staging.netlify.com/).
|
||||
The staging site reflects the current state of what's been merged in the
|
||||
release branch, or in other words, what the docs will look like for the
|
||||
next upcoming release. It's automatically updated as new PRs get merged.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [writing a new topic](/docs/contribute/write-new-topic).
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [staging your changes](/docs/contribute/stage-documentation-changes).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
|
@ -0,0 +1,222 @@
|
|||
---
|
||||
redirect_from:
|
||||
- "/docs/templatedemos/"
|
||||
- "/docs/templatedemos.html"
|
||||
title: Using Page Templates
|
||||
---
|
||||
|
||||
<!--<html>
|
||||
<body>-->
|
||||
|
||||
<p>These page templates are available for writers who would like to contribute new topics to the Kubernetes docs:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="#task_template">Task</a></li>
|
||||
<li><a href="#tutorial_template">Tutorial</a></li>
|
||||
<li><a href="#concept_template">Concept</a></li>
|
||||
</ul>
|
||||
|
||||
<p>The page templates are in the <a href="https://github.com/kubernetes/kubernetes.github.io/tree/master/_includes/templates" target="_blank">_includes/templates</a> directory of the <a href="https://github.com/kubernetes/kubernetes.github.io">kubernetes.github.io</a> repository.
|
||||
|
||||
<h2 id="task_template">Task template</h2>
|
||||
|
||||
<p>A task page shows how to do a single thing, typically by giving a short
|
||||
sequence of steps. Task pages have minimal explanation, but often provide links
|
||||
to conceptual topics that provide related background and knowledge.</p>
|
||||
|
||||
<p>To write a new task page, create a Markdown file in a subdirectory of the
|
||||
/docs/tasks directory. In your Markdown file, provide values for these
|
||||
variables, and then include templates/task.md:</p>
|
||||
|
||||
<ul>
|
||||
<li>overview - required</li>
|
||||
<li>prerequisites - required</li>
|
||||
<li>steps - required</li>
|
||||
<li>discussion - optional</li>
|
||||
<li>whatsnext - optional</li>
|
||||
</ul>
|
||||
|
||||
<p>In the <code>steps</code> section, use <code>##</code> to start with a level-two heading. For subheadings,
|
||||
use <code>###</code> and <code>####</code> as needed. Similarly, if you choose to have a <code>discussion</code> section,
|
||||
start the section with a level-two heading.</p>
|
||||
|
||||
<p>Here's an example of a Markdown file that uses the task template:</p>
|
||||
|
||||
{% raw %}
|
||||
<pre>---
|
||||
title: Configuring This Thing
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page shows how to ...
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
* Do this.
|
||||
* Do this too.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
## Doing ...
|
||||
|
||||
1. Do this.
|
||||
1. Do this next. Possibly read this [related explanation](...).
|
||||
{% endcapture %}
|
||||
|
||||
{% capture discussion %}
|
||||
## Understanding ...
|
||||
|
||||
Here's an interesting thing to know about the steps you just did.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn more about [this](...).
|
||||
* See this [related task](...).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
||||
</pre>
|
||||
{% endraw %}
|
||||
|
||||
<p>Here's an example of a published topic that uses the task template:</p>
|
||||
|
||||
<p><a href="/docs/tasks/access-kubernetes-api/http-proxy-access-api">Using an HTTP Proxy to Access the Kubernetes API</a></p>
|
||||
|
||||
<h2 id="tutorial_template">Tutorial template</h2>
|
||||
|
||||
<p>A tutorial page shows how to accomplish a goal that is larger than a single
|
||||
task. Typically a tutorial page has several sections, each of which has a
|
||||
sequence of steps. For example, a tutorial might provide a walkthrough of a
|
||||
code sample that illustrates a certain feature of Kubernetes. Tutorials can
|
||||
include surface-level explanations, but should link to related concept topics
|
||||
for deep explanations.
|
||||
|
||||
<p>To write a new tutorial page, create a Markdown file in a subdirectory of the
|
||||
/docs/tutorials directory. In your Markdown file, provide values for these
|
||||
variables, and then include templates/tutorial.md:</p>
|
||||
|
||||
<ul>
|
||||
<li>overview - required</li>
|
||||
<li>prerequisites - required</li>
|
||||
<li>objectives - required</li>
|
||||
<li>lessoncontent - required</li>
|
||||
<li>cleanup - optional</li>
|
||||
<li>whatsnext - optional</li>
|
||||
</ul>
|
||||
|
||||
<p>In the <code>lessoncontent</code> section, use <code>##</code> to start with a level-two heading. For subheadings,
|
||||
use <code>###</code> and <code>####</code> as needed.
|
||||
|
||||
<p>Here's an example of a Markdown file that uses the tutorial template:</p>
|
||||
|
||||
{% raw %}
|
||||
<pre>---
|
||||
title: Running a Thing
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page shows how to ...
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
* Do this.
|
||||
* Do this too.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture objectives %}
|
||||
* Learn this.
|
||||
* Build this.
|
||||
* Run this.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture lessoncontent %}
|
||||
## Building ...
|
||||
|
||||
1. Do this.
|
||||
1. Do this next. Possibly read this [related explanation](...).
|
||||
|
||||
## Running ...
|
||||
|
||||
1. Do this.
|
||||
1. Do this next.
|
||||
|
||||
## Understanding the code
|
||||
Here's something interesting about the code you ran in the preceding steps.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture cleanup %}
|
||||
* Delete this.
|
||||
* Stop this.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn more about [this](...).
|
||||
* See this [related tutorial](...).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/tutorial.md %}
|
||||
</pre>
|
||||
{% endraw %}
|
||||
|
||||
<p>Here's an example of a published topic that uses the tutorial template:</p>
|
||||
|
||||
<p><a href="/docs/tutorials/stateless-application/run-stateless-application-deployment/">Running a Stateless Application Using a Deployment</a></p>
|
||||
|
||||
<h2 id="concept_template">Concept template</h2>
|
||||
|
||||
<p>A concept page explains some aspect of Kubernetes. For example, a concept
|
||||
page might describe the Kubernetes Deployment object and explain the role it
|
||||
plays as an application is deployed, scaled, and updated. Typically, concept
|
||||
pages don't include sequences of steps, but instead provide links to tasks or
|
||||
tutorials.
|
||||
|
||||
<p>To write a new concept page, create a Markdown file in a subdirectory of the
|
||||
/docs/concepts directory. In your Markdown file, provide values for these
|
||||
variables, and then include templates/concept.md:</p>
|
||||
|
||||
<ul>
|
||||
<li>overview - required</li>
|
||||
<li>body - required</li>
|
||||
<li>whatsnext - optional</li>
|
||||
</ul>
|
||||
|
||||
<p>In the <code>body</code> section, use <code>##</code> to start with a level-two heading. For subheadings,
|
||||
use <code>###</code> and <code>####</code> as needed.
|
||||
|
||||
<p>Here's an example of a page that uses the concept template:</p>
|
||||
|
||||
{% raw %}
|
||||
<pre>---
|
||||
title: Understanding this Thing
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page explains ...
|
||||
{% endcapture %}
|
||||
|
||||
{% capture body %}
|
||||
## Understanding ...
|
||||
|
||||
Kubernetes provides ...
|
||||
|
||||
## Using ...
|
||||
|
||||
To use ...
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn more about [this](...).
|
||||
* See this [related task](...).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/concept.md %}
|
||||
</pre>
|
||||
{% endraw %}
|
||||
|
||||
<p>Here's an example of a published topic that uses the concept template:</p>
|
||||
|
||||
<p><a href="/docs/concepts/object-metadata/annotations">Annotations</a></p>
|
||||
|
||||
<!--</body>
|
||||
</html>-->
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
title: Reviewing Documentation Issues
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
This page explains how documentation issues are reviewed and prioritized for the [kubernetes/kubernetes.github.io](https://github.com/kubernetes/kubernetes.github.io){: target="_blank"} repository. The purpose is to provide a way to organize issues and make it easier to contribute to Kubernetes documentation. The following should be used as the standard way of prioritizing, labeling, and interacting with issues.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture body %}
|
||||
|
||||
## Categorizing issues
|
||||
Issues should be sorted into different buckets of work using the following labels and definitions. If an issue doesn't have enough information to identify a problem that can be researched, reviewed, or worked on (i.e. the issue doesn't fit into any of the categories below) you should close the issue with a comment explaining why it is being closed.
|
||||
|
||||
### Needs Clarification
|
||||
* Issues that need more information from the original submitter to make them actionable. Issues with this label that aren't followed up within a week may be closed.
|
||||
|
||||
### Actionable
|
||||
* Issues that can be worked on with current information (or may need a comment to explain what needs to be done to make it more clear)
|
||||
* Allows contributors to have easy to find issues to work on
|
||||
|
||||
|
||||
### Needs Tech Review
|
||||
* Issues that need more information in order to be worked on (the proposed solution needs to be proven, a subject matter expert needs to be involved, work needs to be done to understand the problem/resolution and if the issue is still relevant)
|
||||
* Promotes transparency about level of work needed for the issue and that issue is in progress
|
||||
|
||||
### Needs Docs Review
|
||||
* Issues that are suggestions for better processes or site improvements that require community agreement to be implemented
|
||||
* Topics can be brought to SIG meetings as agenda items
|
||||
|
||||
### Needs UX Review
|
||||
* Issues that are suggestions for improving the user interface of the site.
|
||||
* Fixing broken site elements.
|
||||
|
||||
|
||||
## Prioritizing Issues
|
||||
The following labels and definitions should be used to prioritize issues. If you change the priority of an issues, please comment on the issue with your reasoning for the change.
|
||||
|
||||
### P1
|
||||
* Major content errors affecting more than 1 page
|
||||
* Broken code sample on a heavily trafficked page
|
||||
* Errors on a “getting started” page
|
||||
* Well known or highly publicized customer pain points
|
||||
* Automation issues
|
||||
|
||||
### P2
|
||||
* Default for all new issues
|
||||
* Broken code for sample that is not heavily used
|
||||
* Minor content issues in a heavily trafficked page
|
||||
* Major content issues on a lower-trafficked page
|
||||
|
||||
### P3
|
||||
* Typos and broken anchor links
|
||||
|
||||
## Handling special issue types
|
||||
|
||||
### Duplicate issues
|
||||
If a single problem has one or more issues open for it, the problem should be consolodated into a single issue. You should decide which issue to keep open (or open a new issue), port over all relevant information, link related issues, and close all the other issues that describe the same problem. Only having a single issue to work on will help reduce confusion and avoid duplicating work on the same problem.
|
||||
|
||||
### Dead link issues
|
||||
Depending on where the dead link is reported, different actions are required to resolve the issue. Dead links in the API and Kubectl docs are automation issues and should be assigned a P1 until the problem can be fully understood. All other dead links are issues that need to be manually fixed and can be assigned a P3.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [writing a new topic](/docs/contribute/write-new-topic).
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [staging your changes](/docs/contribute/stage-documentation-changes).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/concept.md %}
|
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
title: Staging Your Documentation Changes
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page shows how to stage content that you want to contribute
|
||||
to the Kubernetes documentation.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
Create a fork of the Kubernetes documentation repository as described in
|
||||
[Creating a Documentation Pull Request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
## Staging from your GitHub account
|
||||
|
||||
GitHub provides staging of content in your master branch. Note that you
|
||||
might not want to merge your changes into your master branch. If that is
|
||||
the case, choose another option for staging your content.
|
||||
|
||||
1. In your GitHub account, in your fork, merge your changes into
|
||||
the master branch.
|
||||
|
||||
1. Change the name of your repository to `<your-username>.github.io`, where
|
||||
`<your-username>` is the username of your GitHub account.
|
||||
|
||||
1. Delete the `CNAME` file.
|
||||
|
||||
1. View your staged content at this URL:
|
||||
|
||||
https://<your-username>.github.io
|
||||
|
||||
## Staging a pull request
|
||||
|
||||
When you create a pull request, either against the master or <vnext>
|
||||
branch, your changes are staged in a custom subdomain on Netlify so that
|
||||
you can see your changes in rendered form before the pull request is merged.
|
||||
|
||||
1. In your GitHub account, in your new branch, submit a pull request to the
|
||||
kubernetes/kubernetes.github.io repository. This opens a page that shows the
|
||||
status of your pull request.
|
||||
|
||||
1. Scroll down to the list of automated checks. Click **Show all checks**.
|
||||
Wait for the **deploy/netlify** check to complete. To the right of
|
||||
**deploy/netlify**, click **Details**. This opens a staging site where you
|
||||
can see your changes.
|
||||
|
||||
## Staging locally using Docker
|
||||
|
||||
You can use the k8sdocs Docker image to run a local staging server. If you're
|
||||
interested, you can view the
|
||||
[Dockerfile](https://github.com/kubernetes/kubernetes.github.io/blob/master/staging-container/Dockerfile){: target="_blank"}
|
||||
for this image.
|
||||
|
||||
1. Install Docker if you don't already have it.
|
||||
|
||||
1. Clone your fork to your local development machine.
|
||||
|
||||
1. In the root of your cloned repository, enter this command to start a local
|
||||
web server:
|
||||
|
||||
docker run -ti --rm -v "$PWD":/k8sdocs -p 4000:4000 gcr.io/google-samples/k8sdocs:1.0
|
||||
|
||||
1. View your staged content at
|
||||
[http://localhost:4000](http://localhost:4000){: target="_blank"}.
|
||||
|
||||
## Staging locally without Docker
|
||||
|
||||
1. [Install Ruby 2.2 or later](https://www.ruby-lang.org){: target="_blank"}.
|
||||
|
||||
1. [Install RubyGems](https://rubygems.org){: target="_blank"}.
|
||||
|
||||
1. Verify that Ruby and RubyGems are installed:
|
||||
|
||||
gem --version
|
||||
|
||||
1. Install the GitHub Pages package, which includes Jekyll:
|
||||
|
||||
gem install github-pages
|
||||
|
||||
1. Clone your fork to your local development machine.
|
||||
|
||||
1. In the root of your cloned repository, enter this command to start a local
|
||||
web server:
|
||||
|
||||
jekyll serve
|
||||
|
||||
1. View your staged content at
|
||||
[http://localhost:4000](http://localhost:4000){: target="_blank"}.
|
||||
|
||||
<i>NOTE: If you do not want Jekyll to interfere with your other globally installed gems, you can use `bundler`:</i>
|
||||
|
||||
gem install bundler
|
||||
bundle install
|
||||
bundler exec jekyll serve
|
||||
|
||||
<i> Regardless of whether you use `bundler` or not, your copy of the site will then be viewable at: [http://localhost:4000](http://localhost:4000)</i>
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [writing a new topic](/docs/contribute/write-new-topic/).
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [creating a pull request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
|
@ -0,0 +1,236 @@
|
|||
---
|
||||
title: Documentation Style Guide
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page gives writing style guidelines for the Kubernetes documentation.
|
||||
These are guidelines, not rules. Use your best judgment, and feel free to
|
||||
propose changes to this document in a pull request.
|
||||
|
||||
For additional information on creating new content for the Kubernetes
|
||||
docs, follow the instructions on
|
||||
[using page templates](/docs/contribute/page-templates/) and
|
||||
[creating a documentation pull request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% capture body %}
|
||||
|
||||
## Documentation formatting standards
|
||||
|
||||
### Use camel case for API objects
|
||||
|
||||
When you refer to an API object, use the same uppercase and lowercase letters
|
||||
that are used in the actual object name. Typically, the names of API
|
||||
objects use
|
||||
[camel case](https://en.wikipedia.org/wiki/Camel_case).
|
||||
|
||||
Don't split the API object name into separate words. For example, use
|
||||
PodTemplateList, not Pod Template List.
|
||||
|
||||
Refer to API objects without saying "object," unless omitting "object"
|
||||
leads to an awkward construction.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>The Pod has two Containers.</td><td>The pod has two containers.</td></tr>
|
||||
<tr><td>The Deployment is responsible for ...</td><td>The Deployment object is responsible for ...</td></tr>
|
||||
<tr><td>A PodList is a list of Pods.</td><td>A Pod List is a list of pods.</td></tr>
|
||||
<tr><td>The two ContainerPorts ...</td><td>The two ContainerPort objects ...</td></tr>
|
||||
<tr><td>The two ContainerStateTerminated objects ...</td><td>The two ContainerStateTerminateds ...</td></tr>
|
||||
</table>
|
||||
|
||||
### Use angle brackets for placeholders
|
||||
|
||||
Use angle brackets for placeholders. Tell the reader what a placeholder
|
||||
represents.
|
||||
|
||||
1. Display information about a pod:
|
||||
|
||||
kubectl describe pod <pod-name>
|
||||
|
||||
where `<pod-name>` is the name of one of your pods.
|
||||
|
||||
### Use bold for user interface elements
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Click <b>Fork</b>.</td><td>Click "Fork".</td></tr>
|
||||
<tr><td>Select <b>Other</b>.</td><td>Select 'Other'.</td></tr>
|
||||
</table>
|
||||
|
||||
### Use italics to define or introduce new terms
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>A <i>cluster</i> is a set of nodes ...</td><td>A "cluster" is a set of nodes ...</td></tr>
|
||||
<tr><td>These components form the <i>control plane.</i></td><td>These components form the <b>control plane.</b></td></tr>
|
||||
</table>
|
||||
|
||||
### Use code style for filenames, directories, and paths
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Open the <code>envars.yaml</code> file.</td><td>Open the envars.yaml file.</td></tr>
|
||||
<tr><td>Go to the <code>/docs/tutorials</code> directory.</td><td>Go to the /docs/tutorials directory.</td></tr>
|
||||
<tr><td>Open the <code>/_data/concepts.yaml</code> file.</td><td>Open the /_data/concepts.yaml file.</td></tr>
|
||||
</table>
|
||||
|
||||
## Inline code formatting
|
||||
|
||||
### Use code style for inline code and commands
|
||||
|
||||
For inline code in an HTML document, use the `<code>` tag. In a Markdown
|
||||
document, use the backtick (`).
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>The <code>kubectl run</code> command creates a Deployment.</td><td>The "kubectl run" command creates a Deployment.</td></tr>
|
||||
<tr><td>For declarative management, use <code>kubectl apply</code>.</td><td>For declarative management, use "kubectl apply".</td></tr>
|
||||
</table>
|
||||
|
||||
### Use code style for object field names
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Set the value of the <code>replicas</code> field in the configuration file.</td><td>Set the value of the "replicas" field in the configuration file.</td></tr>
|
||||
<tr><td>The value of the <code>exec</code> field is an ExecAction object.</td><td>The value of the "exec" field is an ExecAction object.</td></tr>
|
||||
</table>
|
||||
|
||||
### Use normal style for string and integer field values
|
||||
|
||||
For field values of type string or integer, use normal style without quotation marks.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Set the value of <code>imagePullPolicy</code> to Always.</td><td>Set the value of <code>imagePullPolicy</code> to "Always".</td></tr>
|
||||
<tr><td>Set the value of <code>image</code> to nginx:1.8.</td><td>Set the value of <code>image</code> to <code>nginx:1.8</code>.</td></tr>
|
||||
<tr><td>Set the value of the <code>replicas</code> field to 2.</td><td>Set the value of the <code>replicas</code> field to <code>2</code>.</td></tr>
|
||||
</table>
|
||||
|
||||
## Code snippet formatting
|
||||
|
||||
### Don't include the command prompt
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>kubectl get pods</td><td>$ kubectl get pods</td></tr>
|
||||
</table>
|
||||
|
||||
### Separate commands from output
|
||||
|
||||
Verify that the pod is running on your chosen node:
|
||||
|
||||
kubectl get pods --output=wide
|
||||
|
||||
The output is similar to this:
|
||||
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
nginx 1/1 Running 0 13s 10.200.0.4 worker0
|
||||
|
||||
|
||||
{% comment %}## Kubernetes.io word list
|
||||
|
||||
A list of Kubernetes-specific terms and words to be used consistently across the site.
|
||||
|
||||
<table>
|
||||
<tr><th>Term</th><th>Useage</th></tr>
|
||||
<tr><td>TBD</td><td>TBD</td></tr>
|
||||
</table>{% endcomment %}
|
||||
|
||||
|
||||
## Content best practices
|
||||
|
||||
This section contains suggested best practices for clear, concise, and consistent content.
|
||||
|
||||
### Use present tense
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>This command starts a proxy.</td><td>This command will start a proxy.</td></tr>
|
||||
</table>
|
||||
|
||||
Exception: Use future or past tense if it is required to convey the correct
|
||||
meaning.
|
||||
|
||||
### Use active voice
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>You can explore the API using a browser.</td><td>The API can be explored using a browser.</td></tr>
|
||||
<tr><td>The YAML file specifies the replica count.</td><td>The replica count is specified in the YAML file.</td></tr>
|
||||
</table>
|
||||
|
||||
Exception: Use passive voice if active voice leads to an awkward construction.
|
||||
|
||||
### Use simple and direct language
|
||||
|
||||
Use simple and direct language. Avoid using unnecessary phrases, such as saying "please."
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>To create a ReplicaSet, ...</td><td>In order to create a ReplicaSet, ...</td></tr>
|
||||
<tr><td>See the configuration file.</td><td>Please see the configuration file.</td></tr>
|
||||
<tr><td>View the Pods.</td><td>With this next command, we'll view the Pods.</td></tr>
|
||||
|
||||
</table>
|
||||
|
||||
### Address the reader as "you"
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>You can create a Deployment by ...</td><td>We'll create a Deployment by ...</td></tr>
|
||||
<tr><td>In the preceding output, you can see...</td><td>In the preceding output, we can see ...</td></tr>
|
||||
</table>
|
||||
|
||||
## Patterns to avoid
|
||||
|
||||
### Avoid using "we"
|
||||
|
||||
Using "we" in a sentence can be confusing, because the reader might not know
|
||||
whether they're part of the "we" you're describing.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Version 1.4 includes ...</td><td>In version 1.4, we have added ...</td></tr>
|
||||
<tr><td>Kubernetes provides a new feature for ...</td><td>We provide a new feature ...</td></tr>
|
||||
<tr><td>This page teaches you how to use pods.</td><td>In this page, we are going to learn about pods.</td></tr>
|
||||
</table>
|
||||
|
||||
### Avoid jargon and idioms
|
||||
|
||||
Some readers speak English as a second language. Avoid jargon and idioms to help make their understanding easier.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>Internally, ...</td><td>Under the hood, ...</td></tr>
|
||||
<tr><td>Create a new cluster.</td><td>Turn up a new cluster.</td></tr>
|
||||
</table>
|
||||
|
||||
### Avoid statements about the future
|
||||
|
||||
Avoid making promises or giving hints about the future. If you need to talk about
|
||||
an alpha feature, put the text under a heading that identifies it as alpha
|
||||
information.
|
||||
|
||||
### Avoid statements that will soon be out of date
|
||||
|
||||
Avoid words like "currently" and "new." A feature that is new today might not be
|
||||
considered new in a few months.
|
||||
|
||||
<table>
|
||||
<tr><th>Do</th><th>Don't</th></tr>
|
||||
<tr><td>In version 1.4, ...</td><td>In the current version, ...</td></tr>
|
||||
<tr><td>The Federation feature provides ...</td><td>The new Federation feature provides ...</td></tr>
|
||||
</table>
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [writing a new topic](/docs/contribute/write-new-topic/).
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [staging your changes](/docs/contribute/stage-documentation-changes/)
|
||||
* Learn about [creating a pull request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/concept.md %}
|
|
@ -0,0 +1,143 @@
|
|||
---
|
||||
title: Writing a New Topic
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
This page shows how to create a new topic for the Kubernetes docs.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
Create a fork of the Kubernetes documentation repository as described in
|
||||
[Creating a Documentation Pull Request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
## Choosing a page type
|
||||
|
||||
As you prepare to write a new topic, think about which of these page types
|
||||
is the best fit for your content:
|
||||
|
||||
<table>
|
||||
|
||||
<tr>
|
||||
<td>Task</td>
|
||||
<td>A task page shows how to do a single thing, typically by giving a short sequence of steps. Task pages have minimal explanation, but often provide links to conceptual topics that provide related background and knowledge.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Tutorial</td>
|
||||
<td>A tutorial page shows how to accomplish a goal that is larger than a single task. Typically a tutorial page has several sections, each of which has a sequence of steps. For example, a tutorial might provide a walkthrough of a code sample that illustrates a certain feature of Kubernetes. Tutorials can include surface-level explanations, but should link to related concept topics for deep explanations.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Concept</td>
|
||||
<td>A concept page explains some aspect of Kubernetes. For example, a concept page might describe the Kubernetes Deployment object and explain the role it plays as an application is deployed, scaled, and updated. Typically, concept pages don't include sequences of steps, but instead provide links to tasks or tutorials.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
Each page type has a
|
||||
[template](/docs/contribute/page-templates/)
|
||||
that you can use as you write your topic.
|
||||
Using templates helps ensure consistency among topics of a given type.
|
||||
|
||||
## Choosing a title and filename
|
||||
|
||||
Choose a title that has the keywords you want search engines to find.
|
||||
Create a filename that uses the words in your title separated by hyphens.
|
||||
For example, the topic with title
|
||||
[Using an HTTP Proxy to Access the Kubernetes API](/docs/tasks/access-kubernetes-api/http-proxy-access-api/)
|
||||
has filename `http-proxy-access-api.md`. You don't need to put
|
||||
"kubernetes" in the filename, because "kubernetes" is already in the
|
||||
URL for the topic, for example:
|
||||
|
||||
http://kubernetes.io/docs/tasks/access-kubernetes-api/http-proxy-access-api/
|
||||
|
||||
## Adding the topic title to the front matter
|
||||
|
||||
In your topic, put a `title` field in the
|
||||
[front matter](https://jekyllrb.com/docs/frontmatter/).
|
||||
The front matter is the YAML block that is between the
|
||||
triple-dashed lines at the top of the page. Here's an example:
|
||||
|
||||
---
|
||||
title: Using an HTTP Proxy to Access the Kubernetes API
|
||||
---
|
||||
|
||||
## Choosing a directory
|
||||
|
||||
Depending on your page type, put your new file in a subdirectory of one of these:
|
||||
|
||||
* /docs/tasks/
|
||||
* /docs/tutorials/
|
||||
* /docs/concepts/
|
||||
|
||||
You can put your file in an existing subdirectory, or you can create a new
|
||||
subdirectory.
|
||||
|
||||
## Creating an entry in the table of contents
|
||||
|
||||
Depending page type, create an entry in one of these files:
|
||||
|
||||
* /_data/tasks.yaml
|
||||
* /_data/tutorials.yaml
|
||||
* /_data/concepts.yaml
|
||||
|
||||
Here's an example of an entry in /_data/tasks.yaml:
|
||||
|
||||
- docs/tasks/configure-pod-container/configure-volume-storage.md
|
||||
|
||||
## Including code from another file
|
||||
|
||||
To include a code file in your topic, place the code file in the Kubernetes
|
||||
documentation repository, preferably in the same directory as your topic
|
||||
file. In your topic file, use the `include` tag:
|
||||
|
||||
<pre>{% include code.html language="<LEXERVALUE>" file="<RELATIVEPATH>" ghlink="/<PATHFROMROOT>" %}</pre>
|
||||
|
||||
where:
|
||||
|
||||
* `<LEXERVALUE>` is the language in which the file was written. This must be
|
||||
[a value supported by Rouge](https://github.com/jneen/rouge/wiki/list-of-supported-languages-and-lexers).
|
||||
* `<RELATIVEPATH>` is the path to the file you're including, relative to the current file, for example, `gce-volume.yaml`.
|
||||
* `<PATHFROMROOT>` is the path to the file relative to root, for example, `docs/tutorials/stateful-application/gce-volume.yaml`.
|
||||
|
||||
Here's an example of using the `include` tag:
|
||||
|
||||
<pre>{% include code.html language="yaml" file="gce-volume.yaml" ghlink="/docs/tutorials/stateful-application/gce-volume.yaml" %}</pre>
|
||||
|
||||
## Showing how to create an API object from a configuration file
|
||||
|
||||
If you need to show the reader how to create an API object based on a
|
||||
configuration file, place the configuration file in the Kubernetes documentation
|
||||
repository, preferably in the same directory as your topic file.
|
||||
|
||||
In your topic, show this command:
|
||||
|
||||
kubectl create -f http://k8s.io/<PATHFROMROOT>
|
||||
|
||||
where `<PATHFROMROOT>` is the path to the configuration file relative to root,
|
||||
for example, `docs/tutorials/stateful-application/gce-volume.yaml`.
|
||||
|
||||
Here's an example of a command that creates an API object from a configuration file:
|
||||
|
||||
kubectl create -f http://k8s.io/docs/tutorials/stateful-application/gce-volume.yaml
|
||||
|
||||
For an example of a topic that uses this technique, see
|
||||
[Running a Single-Instance Stateful Application](/docs/tutorials/stateful-application/run-stateful-application/).
|
||||
|
||||
## Adding images to a topic
|
||||
|
||||
Put image files in the `/images` directory. The preferred
|
||||
image format is SVG.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
* Learn about [using page templates](/docs/contribute/page-templates/).
|
||||
* Learn about [staging your changes](/docs/contribute/stage-documentation-changes).
|
||||
* Learn about [creating a pull request](/docs/contribute/create-pull-request/).
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
|
@ -0,0 +1,262 @@
|
|||
---
|
||||
assignees:
|
||||
- bgrant0607
|
||||
- lavalamp
|
||||
- thockin
|
||||
title: Kubernetes Deprecation Policy
|
||||
---
|
||||
|
||||
Kubernetes is a large system with many components and many contributors. As
|
||||
with any such software, the feature set naturally evolves over time, and
|
||||
sometimes a feature may need to be removed. This could include an API, a flag,
|
||||
or even an entire feature. To avoid breaking existing users, Kubernetes follows
|
||||
a deprecation policy for aspects of the system that are slated to be removed.
|
||||
|
||||
This document details the deprecation policy for various facets of the system.
|
||||
|
||||
## Deprecating parts of the API
|
||||
|
||||
Since Kubernetes is an API-driven system, the API has evolved over time to
|
||||
reflect the evolving understanding of the problem space. The Kubernetes API is
|
||||
actually a set of APIs, called "API groups", and each API group is
|
||||
independently versioned. [API versions](http://kubernetes.io/docs/api/) fall
|
||||
into 3 main tracks, each of which has different policies for deprecation:
|
||||
|
||||
| Example | Track |
|
||||
|----------|----------------------------------|
|
||||
| v1 | GA (generally available, stable) |
|
||||
| v1beta1 | Beta (pre-release) |
|
||||
| v1alpha1 | Alpha (experimental) |
|
||||
|
||||
A given release of Kubernetes can support any number of API groups and any
|
||||
number of versions of each.
|
||||
|
||||
The following rules govern the deprecation of elements of the API. This
|
||||
includes:
|
||||
|
||||
* REST resources (aka API objects)
|
||||
* Fields of REST resources
|
||||
* Enumerated or constant values
|
||||
* Component config structures
|
||||
|
||||
These rules are enforced between official releases, not between
|
||||
arbitrary commits to master or release branches.
|
||||
|
||||
**Rule #1: API elements may only be removed by incrementing the version of the
|
||||
API group.**
|
||||
|
||||
Once an API element has been added to an API group at a particular version, it
|
||||
can not be removed from that version or have its behavior significantly
|
||||
changed, regardless of track.
|
||||
|
||||
Note: For historical reasons, there are 2 "monolithic" API groups - "core" (no
|
||||
group name) and "extensions". Resources will incrementally be moved from these
|
||||
legacy API groups into more domain-specific API groups.
|
||||
|
||||
**Rule #2: API objects must be able to round-trip between API versions in a given
|
||||
release without information loss, with the exception of whole REST resources
|
||||
that do not exist in some versions.**
|
||||
|
||||
For example, an object can be written as v1 and then read back as v2 and
|
||||
converted to v1, and the resulting v1 resource will be identical to the
|
||||
original. The representation in v2 might be different from v1, but the system
|
||||
knows how to convert between them in both directions. Additionally, any new
|
||||
field added in v2 must be able to round-trip to v1 and back, which means v1
|
||||
might have to add an equivalent field or represent it as an annotation.
|
||||
|
||||
**Rule #3: An API version in a given track may not be deprecated until a new
|
||||
API version at least as stable is released.**
|
||||
|
||||
GA API versions can replace GA API versions as well as beta and alpha API
|
||||
version. Beta API versions *may not* replace GA API versions.
|
||||
|
||||
**Rule #4: Other than the most recent API version in each track, older API
|
||||
versions must be supported after their announced deprecation for a duration of
|
||||
no less than:**
|
||||
|
||||
* **GA: 1 year or 2 releases (whichever is longer)**
|
||||
* **Beta: 3 months or 1 release (whichever is longer)**
|
||||
* **Alpha: 0 releases**
|
||||
|
||||
This is best illustrated by example. Imagine a Kubernetes release, version X,
|
||||
which supports a particular API group. A new Kubernetes release is made every
|
||||
approximately 3 months (4 per year). The following table describes which API
|
||||
versions are supported in a series of subsequent releases.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Release</th>
|
||||
<th>API Versions</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>X</td>
|
||||
<td>v1</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+1</td>
|
||||
<td>v1, v2alpha1</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+2</td>
|
||||
<td>v1, v2alpha2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2alpha1 is removed, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+3</td>
|
||||
<td>v1, v2beta1</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2alpha2 is removed, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+4</td>
|
||||
<td>v1, v2beta1, v2beta2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2beta1 is deprecated, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+5</td>
|
||||
<td>v1, v2, v2beta2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2beta1 is removed, "action required" relnote</li>
|
||||
<li>v2beta2 is deprecated, "action required" relnote</li>
|
||||
<li>v1 is deprecated, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+6</td>
|
||||
<td>v1, v2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v2beta2 is removed, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+7</td>
|
||||
<td>v1, v2</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+8</td>
|
||||
<td>v1, v2</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X+9</td>
|
||||
<td>v2</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>v1 is removed, "action required" relnote</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### REST resources (aka API objects)
|
||||
|
||||
Consider a hypothetical REST resource named Widget, which was present in API v1
|
||||
in the above timeline, and which needs to be deprecated. We
|
||||
[document](http://kubernetes.io/docs/deprecated/) and
|
||||
[announce](https://groups.google.com/forum/#!forum/kubernetes-announce) the
|
||||
deprecation in sync with release X+1. The Widget resource still exists in API
|
||||
version v1 (deprecated) but not in v2alpha1. The Widget resource continues to
|
||||
exist and function in releases up to and including X+8. Only in release X+9,
|
||||
when API v1 has aged out, does the Widget resource cease to exist, and the
|
||||
behavior get removed.
|
||||
|
||||
### Fields of REST resources
|
||||
|
||||
As with whole REST resources, an individual field which was present in API v1
|
||||
must exist and function until API v1 is removed. Unlike whole resources, the
|
||||
v2 APIs may choose a different representation for the field, as long as it can
|
||||
be round-tripped. For example a v1 field named "magnitude" which was
|
||||
deprecated might be named "deprecatedMagnitude" in API v2. When v1 is
|
||||
eventually removed, the deprecated field can be removed from v2.
|
||||
|
||||
### Enumerated or constant values
|
||||
|
||||
As with whole REST resources and fields thereof, a constant value which was
|
||||
supported in API v1 must exist and function until API v1 is removed.
|
||||
|
||||
### Component config structures
|
||||
|
||||
Component configs are versioned and managed just like REST resources.
|
||||
|
||||
### Future work
|
||||
|
||||
Over time, Kubernetes will introduce more fine-grained API versions, at which
|
||||
point these rules will be adjusted as needed.
|
||||
|
||||
## Deprecating a flag or CLI
|
||||
|
||||
The Kubernetes system is comprised of several different programs cooperating.
|
||||
Sometimes, a Kubernetes release might remove flags or CLI commands
|
||||
(collectively "CLI elements") in these programs. The individual programs
|
||||
naturally sort into two main groups - user-facing and admin-facing programs,
|
||||
which vary slightly in their deprecation policies. Unless a flag is explicitly
|
||||
prefixed or documented as "alpha" or "beta", it is considered GA.
|
||||
|
||||
CLI elements are effectively part of the API to the system, but since they are
|
||||
not versioned in the same way as the REST API, the rules for deprecation are as
|
||||
follows:
|
||||
|
||||
**Rule #5a: CLI elements of user-facing components (e.g. kubectl) must function
|
||||
after their announced deprecation for no less than:**
|
||||
|
||||
* **GA: 1 year or 2 releases (whichever is longer)**
|
||||
* **Beta: 3 months or 1 release (whichever is longer)**
|
||||
* **Alpha: 0 releases**
|
||||
|
||||
**Rule #5b: CLI elements of admin-facing components (e.g. kubelet) must function
|
||||
after their announced deprecation for no less than:**
|
||||
|
||||
* **GA: 6 months or 1 release (whichever is longer)**
|
||||
* **Beta: 3 months or 1 release (whichever is longer)**
|
||||
* **Alpha: 0 releases**
|
||||
|
||||
**Rule #6: Deprecated CLI elements must emit warnings (optionally disable)
|
||||
when used.**
|
||||
|
||||
## Deprecating a feature or behavior
|
||||
|
||||
Occasionally a Kubernetes release needs to deprecate some feature or behavior
|
||||
of the system that is not controlled by the API or CLI. In this case, the
|
||||
rules for deprecation are as follows:
|
||||
|
||||
**Rule #7: Deprecated behaviors must function for no less than 1 year after their
|
||||
announced deprecation.**
|
||||
|
||||
This does not imply that all changes to the system are governed by this policy.
|
||||
This applies only to significant, user-visible behaviors which impact the
|
||||
correctness of applications running on Kubernetes or that impact the
|
||||
administration of Kubernetes clusters, and which are being removed entirely.
|
||||
|
||||
## Exceptions
|
||||
|
||||
No policy can cover every possible situation. This policy is a living
|
||||
document, and will evolve over time. In practice, there will be situations
|
||||
that do not fit neatly into this policy, or for which this policy becomes a
|
||||
serious impediment. Such situations should be discussed with SIGs and project
|
||||
leaders to find the best solutions for those specific cases, always bearing in
|
||||
mind that Kubernetes is committed to being a stable system that, as much as
|
||||
possible, never breaks users. Exceptions will always be announced in all
|
||||
relevant release notes.
|
|
@ -3,6 +3,9 @@ assignees:
|
|||
- bgrant0607
|
||||
- thockin
|
||||
title: Kubernetes Documentation
|
||||
redirect_from:
|
||||
- "/docs/"
|
||||
- "/docs/index.html"
|
||||
---
|
||||
|
||||
<p>Kubernetes documentation can help you set up Kubernetes, learn about the system, or get your applications and workloads running on Kubernetes. To learn the basics of what Kubernetes is and how it works, read "<a href="/docs/whatisk8s/">What is Kubernetes</a>". </p>
|
|
@ -5,4 +5,4 @@ assignees:
|
|||
title: Report a Security Vulnerability
|
||||
---
|
||||
|
||||
This document has moved to [http://kubernetes.io/security](http://kubernetes.io/security).
|
||||
This document has moved to [Report a Security Vulnerability](/security).
|
||||
|
|
|
@ -0,0 +1,362 @@
|
|||
---
|
||||
assignees:
|
||||
- janetkuo
|
||||
- thockin
|
||||
title: Application Introspection and Debugging
|
||||
---
|
||||
|
||||
---
|
||||
assignees:
|
||||
- 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
|
||||
{: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.
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
Copy this to a file *./my-nginx-dep.yaml*
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./my-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
|
||||
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 Variables:
|
||||
Conditions:
|
||||
Type Status
|
||||
Ready True
|
||||
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
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
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
|
||||
kubernetes-node-861h NotReady 1h
|
||||
kubernetes-node-bols Ready 1h
|
||||
kubernetes-node-st6x Ready 1h
|
||||
kubernetes-node-unaj Ready 1h
|
||||
|
||||
$ kubectl describe node kubernetes-node-861h
|
||||
Name: kubernetes-node-861h
|
||||
Labels: kubernetes.io/hostname=kubernetes-node-861h
|
||||
CreationTimestamp: Fri, 10 Jul 2015 14:32:29 -0700
|
||||
Conditions:
|
||||
Type Status LastHeartbeatTime LastTransitionTime Reason Message
|
||||
Ready Unknown Fri, 10 Jul 2015 14:34:32 -0700 Fri, 10 Jul 2015 14:35:15 -0700 Kubelet stopped posting node status.
|
||||
Addresses: 10.240.115.55,104.197.0.26
|
||||
Capacity:
|
||||
cpu: 1
|
||||
memory: 3800808Ki
|
||||
pods: 100
|
||||
Version:
|
||||
Kernel Version: 3.16.0-0.bpo.4-amd64
|
||||
OS Image: Debian GNU/Linux 7 (wheezy)
|
||||
Container Runtime Version: docker://Unknown
|
||||
Kubelet Version: v0.21.1-185-gffc5a86098dc01
|
||||
Kube-Proxy Version: v0.21.1-185-gffc5a86098dc01
|
||||
PodCIDR: 10.244.0.0/24
|
||||
ExternalID: 15233045891481496305
|
||||
Pods: (0 in total)
|
||||
Namespace Name
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Reason Message
|
||||
Fri, 10 Jul 2015 14:32:28 -0700 Fri, 10 Jul 2015 14:32:28 -0700 1 {kubelet kubernetes-node-861h} NodeNotReady Node kubernetes-node-861h status is now: NodeNotReady
|
||||
Fri, 10 Jul 2015 14:32:30 -0700 Fri, 10 Jul 2015 14:32:30 -0700 1 {kubelet kubernetes-node-861h} NodeNotReady Node kubernetes-node-861h status is now: NodeNotReady
|
||||
Fri, 10 Jul 2015 14:33:00 -0700 Fri, 10 Jul 2015 14:33:00 -0700 1 {kubelet kubernetes-node-861h} starting Starting kubelet.
|
||||
Fri, 10 Jul 2015 14:33:02 -0700 Fri, 10 Jul 2015 14:33:02 -0700 1 {kubelet kubernetes-node-861h} NodeReady Node kubernetes-node-861h status is now: NodeReady
|
||||
Fri, 10 Jul 2015 14:35:15 -0700 Fri, 10 Jul 2015 14:35:15 -0700 1 {controllermanager } NodeNotReady Node kubernetes-node-861h status is now: NodeNotReady
|
||||
|
||||
|
||||
$ 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/user-guide/logging/overview)
|
||||
* [Monitoring](/docs/user-guide/monitoring)
|
||||
* [Getting into containers via `exec`](/docs/user-guide/getting-into-containers)
|
||||
* [Connecting to containers via proxies](/docs/user-guide/connecting-to-applications-proxy)
|
||||
* [Connecting to containers via port forwarding](/docs/user-guide/connecting-to-applications-port-forward)
|
||||
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
---
|
||||
assignees:
|
||||
- mikedanese
|
||||
- thockin
|
||||
title: Troubleshooting 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
|
||||
{:toc}
|
||||
|
||||
## FAQ
|
||||
|
||||
Users are highly encouraged to check out our [FAQ](https://github.com/kubernetes/kubernetes/wiki/User-FAQ)
|
||||
|
||||
## 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 @@
|
|||
---
|
||||
assignees:
|
||||
- davidopp
|
||||
title: Troubleshooting 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/user-guide/application-troubleshooting) 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/admin/multi-cluster) (and avoid making risky changes to all clusters at once)
|
||||
- Mitigates: Everything listed above.
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
assignees:
|
||||
- bprashanth
|
||||
title: Debugging Pods and Replication Controllers
|
||||
---
|
||||
|
||||
* TOC
|
||||
{: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 limit 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/admin/resourcequota/)
|
||||
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,636 @@
|
|||
---
|
||||
assignees:
|
||||
- bprashanth
|
||||
- janetkuo
|
||||
- thockin
|
||||
title: Debugging Services
|
||||
---
|
||||
|
||||
An issue that comes up rather frequently for new installations of Kubernetes is
|
||||
that `Services` are not working properly. You've run all your `Pods` and
|
||||
`Deployments`, but you get no response when you try to access them.
|
||||
This document will hopefully help you to figure out what's going wrong.
|
||||
|
||||
* TOC
|
||||
{: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. You can start a busybox `Pod` and run commands in it:
|
||||
|
||||
```shell
|
||||
$ kubectl run -i --tty busybox --image=busybox --generator="run-pod/v1"
|
||||
Waiting for pod default/busybox to be running, status is Pending, pod ready: false
|
||||
|
||||
Hit enter for command prompt
|
||||
|
||||
/ #
|
||||
```
|
||||
|
||||
If you already have a running `Pod`, run a command in it using:
|
||||
|
||||
```shell
|
||||
$ kubectl exec <POD-NAME> -c <CONTAINER-NAME> -- <COMMAND>
|
||||
```
|
||||
|
||||
or run an interactive shell with:
|
||||
|
||||
```shell
|
||||
$ kubectl exec -ti <POD-NAME> -c <CONTAINER-NAME> sh
|
||||
/ #
|
||||
```
|
||||
|
||||
## 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=gcr.io/google_containers/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: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: hostnames
|
||||
spec:
|
||||
selector:
|
||||
app: hostnames
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: hostnames
|
||||
spec:
|
||||
containers:
|
||||
- name: hostnames
|
||||
image: gcr.io/google_containers/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'
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```shell
|
||||
u@pod$ echo $HOSTNAMES_SERVICE_HOST
|
||||
```
|
||||
|
||||
So the first thing to check is whether that `Service` actually exists:
|
||||
|
||||
```shell
|
||||
$ kubectl get svc hostnames
|
||||
Error from server: service "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.0.226 <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
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
|
||||
Name: hostnames
|
||||
Address: 10.0.1.175
|
||||
```
|
||||
|
||||
If this fails, perhaps your `Pod` and `Service` are in different
|
||||
`Namespaces`, try a namespace-qualified name:
|
||||
|
||||
```shell
|
||||
u@pod$ nslookup hostnames.default
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
|
||||
Name: hostnames.default
|
||||
Address: 10.0.1.175
|
||||
```
|
||||
|
||||
If this works, you'll need to ensure that `Pods` and `Services` run in the same
|
||||
`Namespace`. If this still fails, try a fully-qualified name:
|
||||
|
||||
```shell
|
||||
u@pod$ nslookup hostnames.default.svc.cluster.local
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
|
||||
Name: hostnames.default.svc.cluster.local
|
||||
Address: 10.0.1.175
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
You can also try this from a `Node` in the cluster (note: 10.0.0.10 is my DNS
|
||||
`Service`):
|
||||
|
||||
```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 `kubelet` is running with the right flags.
|
||||
The `--cluster-dns` flag needs to point to your DNS `Service`'s IP and the
|
||||
`--cluster-domain` flag needs to be your cluster's domain - we assumed
|
||||
"cluster.local" in this document, but yours might be different, in which case
|
||||
you should change that in all of the commands above.
|
||||
|
||||
### 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
|
||||
|
||||
Name: kubernetes
|
||||
Address 1: 10.0.0.1
|
||||
```
|
||||
|
||||
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?
|
||||
|
||||
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 `Pods`. 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`? 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 control loop 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`.
|
||||
|
||||
## 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`.
|
||||
|
||||
```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.
|
||||
|
||||
## 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.
|
||||
|
||||
### 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.
|
||||
|
||||
#### 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.
|
||||
|
||||
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:
|
||||
|
||||
$ 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:
|
||||
|
||||
...
|
||||
spec:
|
||||
- selector:
|
||||
name: nginx
|
||||
type: frontend
|
||||
|
||||
You can use:
|
||||
|
||||
$ 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? Container
|
||||
Engine doesn't do port remapping, so if your application serves on 8080,
|
||||
the `containerPort` field needs to be 8080.
|
||||
|
||||
### A Pod cannot reach itself via Service IP
|
||||
|
||||
This mostly happens when `kube-proxy` is running in `iptables` mode and Pods
|
||||
are connected with bridge network. The `Kubelet` exposes a `hairpin-mode`
|
||||
[flag](http://kubernetes.io/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/google-containers) or
|
||||
[GitHub](https://github.com/kubernetes/kubernetes).
|
||||
|
||||
## More information
|
||||
|
||||
Visit [troubleshooting document](/docs/troubleshooting/) for more information.
|
||||
|
|
@ -5,191 +5,6 @@ assignees:
|
|||
title: Troubleshooting 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)
|
||||
{% include user-guide-content-moved.md %}
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## FAQ
|
||||
|
||||
Users are highly encouraged to check out our [FAQ](https://github.com/kubernetes/kubernetes/wiki/User-FAQ)
|
||||
|
||||
## 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.
|
||||
[Debugging Applications](/docs/tasks/debug-application-cluster/debug-application/)
|
||||
|
|
|
@ -4,105 +4,6 @@ assignees:
|
|||
title: Debugging Pods and Replication Controllers
|
||||
---
|
||||
|
||||
* TOC
|
||||
{: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 limit 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/admin/resourcequota/)
|
||||
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.
|
||||
{% include user-guide-content-moved.md %}
|
||||
|
||||
[Debugging Pods and Replication Controllers](/docs/tasks/debug-application-cluster/debug-pod-replication-controller/)
|
||||
|
|
|
@ -6,630 +6,6 @@ assignees:
|
|||
title: Debugging Services
|
||||
---
|
||||
|
||||
An issue that comes up rather frequently for new installations of Kubernetes is
|
||||
that `Services` are not working properly. You've run all your `Pods` and
|
||||
`Deployments`, but you get no response when you try to access them.
|
||||
This document will hopefully help you to figure out what's going wrong.
|
||||
{% include user-guide-content-moved.md %}
|
||||
|
||||
* TOC
|
||||
{: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. You can start a busybox `Pod` and run commands in it:
|
||||
|
||||
```shell
|
||||
$ kubectl run -i --tty busybox --image=busybox --generator="run-pod/v1"
|
||||
Waiting for pod default/busybox to be running, status is Pending, pod ready: false
|
||||
|
||||
Hit enter for command prompt
|
||||
|
||||
/ #
|
||||
```
|
||||
|
||||
If you already have a running `Pod`, run a command in it using:
|
||||
|
||||
```shell
|
||||
$ kubectl exec <POD-NAME> -c <CONTAINER-NAME> -- <COMMAND>
|
||||
```
|
||||
|
||||
or run an interactive shell with:
|
||||
|
||||
```shell
|
||||
$ kubectl exec -ti <POD-NAME> -c <CONTAINER-NAME> sh
|
||||
/ #
|
||||
```
|
||||
|
||||
## 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=gcr.io/google_containers/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/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: hostnames
|
||||
spec:
|
||||
selector:
|
||||
app: hostnames
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: hostnames
|
||||
spec:
|
||||
containers:
|
||||
- name: hostnames
|
||||
image: gcr.io/google_containers/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'
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```shell
|
||||
u@pod$ echo $HOSTNAMES_SERVICE_HOST
|
||||
```
|
||||
|
||||
So the first thing to check is whether that `Service` actually exists:
|
||||
|
||||
```shell
|
||||
$ kubectl get svc hostnames
|
||||
Error from server: service "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.0.226 <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
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
|
||||
Name: hostnames
|
||||
Address: 10.0.1.175
|
||||
```
|
||||
|
||||
If this fails, perhaps your `Pod` and `Service` are in different
|
||||
`Namespaces`, try a namespace-qualified name:
|
||||
|
||||
```shell
|
||||
u@pod$ nslookup hostnames.default
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
|
||||
Name: hostnames.default
|
||||
Address: 10.0.1.175
|
||||
```
|
||||
|
||||
If this works, you'll need to ensure that `Pods` and `Services` run in the same
|
||||
`Namespace`. If this still fails, try a fully-qualified name:
|
||||
|
||||
```shell
|
||||
u@pod$ nslookup hostnames.default.svc.cluster.local
|
||||
Server: 10.0.0.10
|
||||
Address: 10.0.0.10#53
|
||||
|
||||
Name: hostnames.default.svc.cluster.local
|
||||
Address: 10.0.1.175
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
You can also try this from a `Node` in the cluster (note: 10.0.0.10 is my DNS
|
||||
`Service`):
|
||||
|
||||
```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 `kubelet` is running with the right flags.
|
||||
The `--cluster-dns` flag needs to point to your DNS `Service`'s IP and the
|
||||
`--cluster-domain` flag needs to be your cluster's domain - we assumed
|
||||
"cluster.local" in this document, but yours might be different, in which case
|
||||
you should change that in all of the commands above.
|
||||
|
||||
### 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
|
||||
|
||||
Name: kubernetes
|
||||
Address 1: 10.0.0.1
|
||||
```
|
||||
|
||||
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?
|
||||
|
||||
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 `Pods`. 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`? 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 control loop 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`.
|
||||
|
||||
## 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`.
|
||||
|
||||
```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.
|
||||
|
||||
## 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.
|
||||
|
||||
### 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.
|
||||
|
||||
#### 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.
|
||||
|
||||
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:
|
||||
|
||||
$ 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:
|
||||
|
||||
...
|
||||
spec:
|
||||
- selector:
|
||||
name: nginx
|
||||
type: frontend
|
||||
|
||||
You can use:
|
||||
|
||||
$ 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? Container
|
||||
Engine doesn't do port remapping, so if your application serves on 8080,
|
||||
the `containerPort` field needs to be 8080.
|
||||
|
||||
### A Pod cannot reach itself via Service IP
|
||||
|
||||
This mostly happens when `kube-proxy` is running in `iptables` mode and Pods
|
||||
are connected with bridge network. The `Kubelet` exposes a `hairpin-mode`
|
||||
[flag](http://kubernetes.io/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/google-containers) or
|
||||
[GitHub](https://github.com/kubernetes/kubernetes).
|
||||
|
||||
## More information
|
||||
|
||||
Visit [troubleshooting document](/docs/troubleshooting/) for more information.
|
||||
[Debugging Services](/docs/tasks/debug-application-cluster/debug-service/)
|
||||
|
|
|
@ -5,350 +5,6 @@ assignees:
|
|||
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
|
||||
{: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.
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
Copy this to a file *./my-nginx-dep.yaml*
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./my-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
|
||||
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 Variables:
|
||||
Conditions:
|
||||
Type Status
|
||||
Ready True
|
||||
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
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
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
|
||||
kubernetes-node-861h NotReady 1h
|
||||
kubernetes-node-bols Ready 1h
|
||||
kubernetes-node-st6x Ready 1h
|
||||
kubernetes-node-unaj Ready 1h
|
||||
|
||||
$ kubectl describe node kubernetes-node-861h
|
||||
Name: kubernetes-node-861h
|
||||
Labels: kubernetes.io/hostname=kubernetes-node-861h
|
||||
CreationTimestamp: Fri, 10 Jul 2015 14:32:29 -0700
|
||||
Conditions:
|
||||
Type Status LastHeartbeatTime LastTransitionTime Reason Message
|
||||
Ready Unknown Fri, 10 Jul 2015 14:34:32 -0700 Fri, 10 Jul 2015 14:35:15 -0700 Kubelet stopped posting node status.
|
||||
Addresses: 10.240.115.55,104.197.0.26
|
||||
Capacity:
|
||||
cpu: 1
|
||||
memory: 3800808Ki
|
||||
pods: 100
|
||||
Version:
|
||||
Kernel Version: 3.16.0-0.bpo.4-amd64
|
||||
OS Image: Debian GNU/Linux 7 (wheezy)
|
||||
Container Runtime Version: docker://Unknown
|
||||
Kubelet Version: v0.21.1-185-gffc5a86098dc01
|
||||
Kube-Proxy Version: v0.21.1-185-gffc5a86098dc01
|
||||
PodCIDR: 10.244.0.0/24
|
||||
ExternalID: 15233045891481496305
|
||||
Pods: (0 in total)
|
||||
Namespace Name
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Reason Message
|
||||
Fri, 10 Jul 2015 14:32:28 -0700 Fri, 10 Jul 2015 14:32:28 -0700 1 {kubelet kubernetes-node-861h} NodeNotReady Node kubernetes-node-861h status is now: NodeNotReady
|
||||
Fri, 10 Jul 2015 14:32:30 -0700 Fri, 10 Jul 2015 14:32:30 -0700 1 {kubelet kubernetes-node-861h} NodeNotReady Node kubernetes-node-861h status is now: NodeNotReady
|
||||
Fri, 10 Jul 2015 14:33:00 -0700 Fri, 10 Jul 2015 14:33:00 -0700 1 {kubelet kubernetes-node-861h} starting Starting kubelet.
|
||||
Fri, 10 Jul 2015 14:33:02 -0700 Fri, 10 Jul 2015 14:33:02 -0700 1 {kubelet kubernetes-node-861h} NodeReady Node kubernetes-node-861h status is now: NodeReady
|
||||
Fri, 10 Jul 2015 14:35:15 -0700 Fri, 10 Jul 2015 14:35:15 -0700 1 {controllermanager } NodeNotReady Node kubernetes-node-861h status is now: NodeNotReady
|
||||
|
||||
|
||||
$ 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/user-guide/logging/overview)
|
||||
* [Monitoring](/docs/user-guide/monitoring)
|
||||
* [Getting into containers via `exec`](/docs/user-guide/getting-into-containers)
|
||||
* [Connecting to containers via proxies](/docs/user-guide/connecting-to-applications-proxy)
|
||||
* [Connecting to containers via port forwarding](/docs/user-guide/connecting-to-applications-port-forward)
|
||||
{% include user-guide-content-moved.md %}
|
||||
|
||||
[Application Introspection and Debugging](/docs/tasks/debug-application-cluster/debug-application-introspection/)
|
||||
|
|
Loading…
Reference in New Issue