This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/README.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/README.md)
Kubernetes is a system for managing containerized applications across multiple
hosts, providing basic mechanisms for deployment, maintenance, and scaling of
applications.
Kubernetes establishes robust declarative primitives for maintaining the desired
state requested by the user. We see these primitives as the main value added by
Kubernetes. Self-healing mechanisms, such as auto-restarting, re-scheduling, and
replicating containers require active controllers, not just imperative
orchestration.
Kubernetes is primarily targeted at applications composed of multiple
containers, such as elastic, distributed micro-services. It is also designed to
facilitate migration of non-containerized application stacks to Kubernetes. It
therefore includes abstractions for grouping containers in both loosely coupled
and tightly coupled formations, and provides ways for containers to find and
communicate with each other in relatively familiar ways.
Kubernetes enables users to ask a cluster to run a set of containers. The system
automatically chooses hosts to run those containers on. While Kubernetes's
scheduler is currently very simple, we expect it to grow in sophistication over
time. Scheduling is a policy-rich, topology-aware, workload-specific function
that significantly impacts availability, performance, and capacity. The
scheduler needs to take into account individual and collective resource
requirements, quality of service requirements, hardware/software/policy
constraints, affinity and anti-affinity specifications, data locality,
inter-workload interference, deadlines, and so on. Workload-specific
requirements will be exposed through the API as necessary.
Kubernetes is intended to run on a number of cloud providers, as well as on
physical hosts.
A single Kubernetes cluster is not intended to span multiple availability zones.
Instead, we recommend building a higher-level layer to replicate complete
deployments of highly available applications across multiple zones (see
[the multi-cluster doc](../admin/multi-cluster.md) and [cluster federation proposal](../proposals/federation.md)
for more details).
Finally, Kubernetes aspires to be an extensible, pluggable, building-block OSS
platform and toolkit. Therefore, architecturally, we want Kubernetes to be built
as a collection of pluggable components and layers, with the ability to use
alternative schedulers, controllers, storage systems, and distribution
mechanisms, and we're evolving its current code in that direction. Furthermore,
we want others to be able to extend Kubernetes functionality, such as with
higher-level PaaS functionality or multi-cluster layers, without modification of
core Kubernetes source. Therefore, its API isn't just (or even necessarily
mainly) targeted at end users, but at tool and extension developers. Its APIs
are intended to serve as the foundation for an open ecosystem of tools,
automation systems, and higher-level API layers. Consequently, there are no
"internal" inter-component APIs. All APIs are visible and available, including
the APIs used by the scheduler, the node controller, the replication-controller
manager, Kubelet's API, etc. There's no glass to break -- in order to handle
more complex use cases, one can just access the lower-level APIs in a fully
transparent, composable manner.
For more about the Kubernetes architecture, see [architecture](architecture.md).
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/access.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/access.md)
This document suggests a direction for identity and access management in the
Kubernetes system.
## Background
High level goals are:
- Have a plan for how identity, authentication, and authorization will fit in
to the API.
- Have a plan for partitioning resources within a cluster between independent
organizational units.
- Ease integration with existing enterprise and hosted scenarios.
### Actors
Each of these can act as normal users or attackers.
- External Users: People who are accessing applications running on K8s (e.g.
a web site served by webserver running in a container on K8s), but who do not
have K8s API access.
- K8s Users: People who access the K8s API (e.g. create K8s API objects like
Pods)
- K8s Project Admins: People who manage access for some K8s Users
- K8s Cluster Admins: People who control the machines, networks, or binaries
that make up a K8s cluster.
- K8s Admin means K8s Cluster Admins and K8s Project Admins taken together.
### Threats
Both intentional attacks and accidental use of privilege are concerns.
For both cases it may be useful to think about these categories differently:
- Application Path - attack by sending network messages from the internet to
the IP/port of any application running on K8s. May exploit weakness in
application or misconfiguration of K8s.
- K8s API Path - attack by sending network messages to any K8s API endpoint.
- Insider Path - attack on K8s system components. Attacker may have
privileged access to networks, machines or K8s software and data. Software
errors in K8s system components and administrator error are some types of threat
in this category.
This document is primarily concerned with K8s API paths, and secondarily with
Internal paths. The Application path also needs to be secure, but is not the
focus of this document.
### Assets to protect
External User assets:
- Personal information like private messages, or images uploaded by External
Users.
- web server logs.
K8s User assets:
- External User assets of each K8s User.
- things private to the K8s app, like:
- credentials for accessing other services (docker private repos, storage
services, facebook, etc)
- SSL certificates for web servers
- proprietary data and code
K8s Cluster assets:
- Assets of each K8s User.
- Machine Certificates or secrets.
- The value of K8s cluster computing resources (cpu, memory, etc).
This document is primarily about protecting K8s User assets and K8s cluster
assets from other K8s Users and K8s Project and Cluster Admins.
### Usage environments
Cluster in Small organization:
- K8s Admins may be the same people as K8s Users.
- Few K8s Admins.
- Prefer ease of use to fine-grained access control/precise accounting, etc.
- Product requirement that it be easy for potential K8s Cluster Admin to try
out setting up a simple cluster.
Cluster in Large organization:
- K8s Admins typically distinct people from K8s Users. May need to divide
K8s Cluster Admin access by roles.
- K8s Users need to be protected from each other.
- Auditing of K8s User and K8s Admin actions important.
- Flexible accurate usage accounting and resource controls important.
- Lots of automated access to APIs.
- Need to integrate with existing enterprise directory, authentication,
accounting, auditing, and security policy infrastructure.
Org-run cluster:
- Organization that runs K8s master components is same as the org that runs
apps on K8s.
- Nodes may be on-premises VMs or physical machines; Cloud VMs; or a mix.
Hosted cluster:
- Offering K8s API as a service, or offering a Paas or Saas built on K8s.
- May already offer web services, and need to integrate with existing customer
account concept, and existing authentication, accounting, auditing, and security
policy infrastructure.
- May want to leverage K8s User accounts and accounting to manage their User
accounts (not a priority to support this use case.)
- Precise and accurate accounting of resources needed. Resource controls
needed for hard limits (Users given limited slice of data) and soft limits
(Users can grow up to some limit and then be expanded).
K8s ecosystem services:
- There may be companies that want to offer their existing services (Build, CI,
A/B-test, release automation, etc) for use with K8s. There should be some story
for this case.
Pods configs should be largely portable between Org-run and hosted
configurations.
# Design
Related discussion:
- http://issue.k8s.io/442
- http://issue.k8s.io/443
This doc describes two security profiles:
- Simple profile: like single-user mode. Make it easy to evaluate K8s
without lots of configuring accounts and policies. Protects from unauthorized
users, but does not partition authorized users.
- Enterprise profile: Provide mechanisms needed for large numbers of users.
Defense in depth. Should integrate with existing enterprise security
infrastructure.
K8s distribution should include templates of config, and documentation, for
simple and enterprise profiles. System should be flexible enough for
knowledgeable users to create intermediate profiles, but K8s developers should
only reason about those two Profiles, not a matrix.
Features in this doc are divided into "Initial Feature", and "Improvements".
Initial features would be candidates for version 1.00.
## Identity
### userAccount
K8s will have a `userAccount` API object.
-`userAccount` has a UID which is immutable. This is used to associate users
with objects and to record actions in audit logs.
-`userAccount` has a name which is a string and human readable and unique among
userAccounts. It is used to refer to users in Policies, to ensure that the
Policies are human readable. It can be changed only when there are no Policy
objects or other objects which refer to that name. An email address is a
suggested format for this field.
-`userAccount` is not related to the unix username of processes in Pods created
by that userAccount.
-`userAccount` API objects can have labels.
The system may associate one or more Authentication Methods with a
`userAccount` (but they are not formally part of the userAccount object.)
In a simple deployment, the authentication method for a user might be an
authentication token which is verified by a K8s server. In a more complex
deployment, the authentication might be delegated to another system which is
trusted by the K8s API to authenticate users, but where the authentication
details are unknown to K8s.
Initial Features:
- There is no superuser `userAccount`
-`userAccount` objects are statically populated in the K8s API store by reading
a config file. Only a K8s Cluster Admin can do this.
-`userAccount` can have a default `namespace`. If API call does not specify a
`namespace`, the default `namespace` for that caller is assumed.
-`userAccount` is global. A single human with access to multiple namespaces is
recommended to only have one userAccount.
Improvements:
- Make `userAccount` part of a separate API group from core K8s objects like
`pod.` Facilitates plugging in alternate Access Management.
Simple Profile:
- Single `userAccount`, used by all K8s Users and Project Admins. One access
token shared by all.
Enterprise Profile:
- Every human user has own `userAccount`.
-`userAccount`s have labels that indicate both membership in groups, and
ability to act in certain roles.
- Each service using the API has own `userAccount` too. (e.g. `scheduler`,
`repcontroller`)
- Automated jobs to denormalize the ldap group info into the local system
list of users into the K8s userAccount file.
### Unix accounts
A `userAccount` is not a Unix user account. The fact that a pod is started by a
`userAccount` does not mean that the processes in that pod's containers run as a
Unix user with a corresponding name or identity.
Initially:
- The unix accounts available in a container, and used by the processes running
in a container are those that are provided by the combination of the base
operating system and the Docker manifest.
- Kubernetes doesn't enforce any relation between `userAccount` and unix
accounts.
Improvements:
- Kubelet allocates disjoint blocks of root-namespace uids for each container.
This may provide some defense-in-depth against container escapes. (https://github.com/docker/docker/pull/4572)
- requires docker to integrate user namespace support, and deciding what
getpwnam() does for these uids.
- any features that help users avoid use of privileged containers
(http://issue.k8s.io/391)
### Namespaces
K8s will have a `namespace` API object. It is similar to a Google Compute
Engine `project`. It provides a namespace for objects created by a group of
people co-operating together, preventing name collisions with non-cooperating
groups. It also serves as a reference point for authorization policies.
Namespaces are described in [namespaces.md](namespaces.md).
In the Enterprise Profile:
- a `userAccount` may have permission to access several `namespace`s.
In the Simple Profile:
- There is a single `namespace` used by the single user.
Namespaces versus userAccount vs. Labels:
-`userAccount`s are intended for audit logging (both name and UID should be
logged), and to define who has access to `namespace`s.
-`labels` (see [docs/user-guide/labels.md](../../docs/user-guide/labels.md))
should be used to distinguish pods, users, and other objects that cooperate
towards a common goal but are different in some way, such as version, or
responsibilities.
-`namespace`s prevent name collisions between uncoordinated groups of people,
and provide a place to attach common policies for co-operating groups of people.
## Authentication
Goals for K8s authentication:
- Include a built-in authentication system with no configuration required to use
in single-user mode, and little configuration required to add several user
accounts, and no https proxy required.
- Allow for authentication to be handled by a system external to Kubernetes, to
allow integration with existing to enterprise authorization systems. The
Kubernetes namespace itself should avoid taking contributions of multiple
authorization schemes. Instead, a trusted proxy in front of the apiserver can be
used to authenticate users.
- For organizations whose security requirements only allow FIPS compliant
implementations (e.g. apache) for authentication.
- So the proxy can terminate SSL, and isolate the CA-signed certificate from
less trusted, higher-touch APIserver.
- For organizations that already have existing SaaS web services (e.g.
storage, VMs) and want a common authentication portal.
- Avoid mixing authentication and authorization, so that authorization policies
be centrally managed, and to allow changes in authentication methods without
affecting authorization code.
Initially:
- Tokens used to authenticate a user.
- Long lived tokens identify a particular `userAccount`.
- Administrator utility generates tokens at cluster setup.
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/admission_control.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/admission_control.md)
**Related PR:**
| Topic | Link |
| ----- | ---- |
| Separate validation from RESTStorage | http://issue.k8s.io/2977 |
## Background
High level goals:
* Enable an easy-to-use mechanism to provide admission control to cluster.
* Enable a provider to support multiple admission control strategies or author
their own.
* Ensure any rejected request can propagate errors back to the caller with why
the request failed.
Authorization via policy is focused on answering if a user is authorized to
perform an action.
Admission Control is focused on if the system will accept an authorized action.
Kubernetes may choose to dismiss an authorized action based on any number of
admission control strategies.
This proposal documents the basic design, and describes how any number of
admission control plug-ins could be injected.
Implementation of specific admission control strategies are handled in separate
documents.
## kube-apiserver
The kube-apiserver takes the following OPTIONAL arguments to enable admission
control:
| Option | Behavior |
| ------ | -------- |
| admission-control | Comma-delimited, ordered list of admission control choices to invoke prior to modifying or deleting an object. |
| admission-control-config-file | File with admission control configuration parameters to boot-strap plug-in. |
An **AdmissionControl** plug-in is an implementation of the following interface:
```go
packageadmission
// Attributes is an interface used by a plug-in to make an admission decision
// on a individual request.
typeAttributesinterface{
GetNamespace()string
GetKind()string
GetOperation()string
GetObject()runtime.Object
}
// Interface is an abstract, pluggable interface for Admission Control decisions.
typeInterfaceinterface{
// Admit makes an admission decision based on the request attributes
// An error is returned if it denies the request.
Admit(aAttributes)(errerror)
}
```
A **plug-in** must be compiled with the binary, and is registered as an
available option by providing a name, and implementation of admission.Interface.
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/admission_control_limit_range.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/admission_control_limit_range.md)
## Background
This document proposes a system for enforcing resource requirements constraints
as part of admission control.
## Use cases
1. Ability to enumerate resource requirement constraints per namespace
2. Ability to enumerate min/max resource constraints for a pod
3. Ability to enumerate min/max resource constraints for a container
4. Ability to specify default resource limits for a container
5. Ability to specify default resource requests for a container
6. Ability to enforce a ratio between request and limit for a resource.
7. Ability to enforce min/max storage requests for persistent volume claims
## Data Model
The **LimitRange** resource is scoped to a **Namespace**.
### Type
```go
// LimitType is a type of object that is limited
typeLimitTypestring
const(
// Limit that applies to all pods in a namespace
LimitTypePodLimitType="Pod"
// Limit that applies to all containers in a namespace
LimitTypeContainerLimitType="Container"
)
// LimitRangeItem defines a min/max usage limit for any resource that matches
// on kind.
typeLimitRangeItemstruct{
// Type of resource that this limit applies to.
TypeLimitType`json:"type,omitempty"`
// Max usage constraints on this kind by resource name.
MaxResourceList`json:"max,omitempty"`
// Min usage constraints on this kind by resource name.
MinResourceList`json:"min,omitempty"`
// Default resource requirement limit value by resource name if resource limit
// is omitted.
DefaultResourceList`json:"default,omitempty"`
// DefaultRequest is the default resource requirement request value by
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/admission_control_resource_quota.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/admission_control_resource_quota.md)
## Background
This document describes a system for enforcing hard resource usage limits per
namespace as part of admission control.
## Use cases
1. Ability to enumerate resource usage limits per namespace.
2. Ability to monitor resource usage for tracked resources.
3. Ability to reject resource usage exceeding hard quotas.
## Data Model
The **ResourceQuota** object is scoped to a **Namespace**.
```go
// The following identify resource constants for Kubernetes object types
// ResourceQuotaSpec defines the desired hard limits to enforce for Quota
typeResourceQuotaSpecstruct{
// Hard is the set of desired hard limits for each named resource
HardResourceList`json:"hard,omitempty" description:"hard is the set of desired hard limits for each named resource; see http://releases.k8s.io/HEAD/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota"`
}
// ResourceQuotaStatus defines the enforced hard limits and observed use
typeResourceQuotaStatusstruct{
// Hard is the set of enforced hard limits for each named resource
HardResourceList`json:"hard,omitempty" description:"hard is the set of enforced hard limits for each named resource; see http://releases.k8s.io/HEAD/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota"`
// Used is the current observed total usage of the resource in the namespace
UsedResourceList`json:"used,omitempty" description:"used is the current observed total usage of the resource in the namespace"`
}
// ResourceQuota sets aggregate quota restrictions enforced per namespace
typeResourceQuotastruct{
TypeMeta`json:",inline"`
ObjectMeta`json:"metadata,omitempty" description:"standard object metadata; see http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata"`
// Spec defines the desired quota
SpecResourceQuotaSpec`json:"spec,omitempty" description:"spec defines the desired quota; http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status"`
// Status defines the actual enforced quota and its current usage
StatusResourceQuotaStatus`json:"status,omitempty" description:"status defines the actual enforced quota and current usage; http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status"`
}
// ResourceQuotaList is a list of ResourceQuota items
typeResourceQuotaListstruct{
TypeMeta`json:",inline"`
ListMeta`json:"metadata,omitempty" description:"standard list metadata; see http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata"`
// Items is a list of ResourceQuota objects
Items[]ResourceQuota`json:"items" description:"items is a list of ResourceQuota objects; see http://releases.k8s.io/HEAD/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota"`
}
```
## Quota Tracked Resources
The following resources are supported by the quota system:
| Resource | Description |
| ------------ | ----------- |
| cpu | Total requested cpu usage |
| memory | Total requested memory usage |
| pods | Total number of active pods where phase is pending or active. |
| services | Total number of services |
| replicationcontrollers | Total number of replication controllers |
| resourcequotas | Total number of resource quotas |
| secrets | Total number of secrets |
| persistentvolumeclaims | Total number of persistent volume claims |
If a third-party wants to track additional resources, it must follow the
resource naming conventions prescribed by Kubernetes. This means the resource
must have a fully-qualified name (i.e. mycompany.org/shinynewresource)
## Resource Requirements: Requests vs. Limits
If a resource supports the ability to distinguish between a request and a limit
for a resource, the quota tracking system will only cost the request value
against the quota usage. If a resource is tracked by quota, and no request value
is provided, the associated entity is rejected as part of admission.
For an example, consider the following scenarios relative to tracking quota on
CPU:
| Pod | Container | Request CPU | Limit CPU | Result |
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture.md)
A running Kubernetes cluster contains node agents (`kubelet`) and master
components (APIs, scheduler, etc), on top of a distributed storage solution.
This diagram shows our desired eventual state, though we're still working on a
few things, like making `kubelet` itself (all our components, really) run within
containers, and making the scheduler 100% pluggable.
d="M 949.242 -47.953 C 939.87,-48.2618 921.694,-41.7773 924.25,-27.8819 C 926.806,-13.9865 939.018,-10.8988 944.13,-14.9129 C 949.242,-18.9271 936.178,4.54051 961.17,10.7162 C 986.161,16.8919 998.941,7.01079 995.249,-0.0912821 C 991.557,-7.19336 1017.12,16.5832 1029.04,2.99658 C 1040.97,-10.59 1016.83,-23.5589 1021.94,-21.7062 C 1027.06,-19.8535 1042.68,-22.3237 1037.56,-45.4827 C 1032.45,-68.6416 986.445,-50.7321 991.557,-54.1287 C 996.669,-57.5253 983.889,-74.5086 967.986,-71.112 C 952.082,-67.7153 950.954,-61.5516 949.25,-47.965 L 949.242,-47.953z"
d="M 949.242 -47.953 C 939.87,-48.2618 921.694,-41.7773 924.25,-27.8819 C 926.806,-13.9865 939.018,-10.8988 944.13,-14.9129 C 949.242,-18.9271 936.178,4.54051 961.17,10.7162 C 986.161,16.8919 998.941,7.01079 995.249,-0.0912821 C 991.557,-7.19336 1017.12,16.5832 1029.04,2.99658 C 1040.97,-10.59 1016.83,-23.5589 1021.94,-21.7062 C 1027.06,-19.8535 1042.68,-22.3237 1037.56,-45.4827 C 1032.45,-68.6416 986.445,-50.7321 991.557,-54.1287 C 996.669,-57.5253 983.889,-74.5086 967.986,-71.112 C 952.082,-67.7153 950.954,-61.5516 949.25,-47.965 L 949.242,-47.953"
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/aws_under_the_hood.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/aws_under_the_hood.md)
This document provides high-level insight into how Kubernetes works on AWS and
maps to AWS objects. We assume that you are familiar with AWS.
We encourage you to use [kube-up](../getting-started-guides/aws.md) to create
clusters on AWS. We recommend that you avoid manual configuration but are aware
that sometimes it's the only option.
Tip: You should open an issue and let us know what enhancements can be made to
the scripts to better suit your needs.
That said, it's also useful to know what's happening under the hood when
Kubernetes clusters are created on AWS. This can be particularly useful if
problems arise or in circumstances where the provided scripts are lacking and
you manually created or configured your cluster.
**Table of contents:**
*[Architecture overview](#architecture-overview)
*[Storage](#storage)
*[Auto Scaling group](#auto-scaling-group)
*[Networking](#networking)
*[NodePort and LoadBalancer services](#nodeport-and-loadbalancer-services)
*[Identity and access management (IAM)](#identity-and-access-management-iam)
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/clustering.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/clustering.md)
## Overview
The term "clustering" refers to the process of having all members of the
Kubernetes cluster find and trust each other. There are multiple different ways
to achieve clustering with different security and usability profiles. This
document attempts to lay out the user experiences for clustering that Kubernetes
aims to address.
Once a cluster is established, the following is true:
1.**Master -> Node** The master needs to know which nodes can take work and
what their current status is wrt capacity.
1.**Location** The master knows the name and location of all of the nodes in
the cluster.
* For the purposes of this doc, location and name should be enough
information so that the master can open a TCP connection to the Node. Most
probably we will make this either an IP address or a DNS name. It is going to be
important to be consistent here (master must be able to reach kubelet on that
DNS name) so that we can verify certificates appropriately.
2.**Target AuthN** A way to securely talk to the kubelet on that node.
Currently we call out to the kubelet over HTTP. This should be over HTTPS and
the master should know what CA to trust for that node.
3.**Caller AuthN/Z** This would be the master verifying itself (and
permissions) when calling the node. Currently, this is only used to collect
statistics as authorization isn't critical. This may change in the future
though.
2.**Node -> Master** The nodes currently talk to the master to know which pods
have been assigned to them and to publish events.
1.**Location** The nodes must know where the master is at.
2.**Target AuthN** Since the master is assigning work to the nodes, it is
critical that they verify whom they are talking to.
3.**Caller AuthN/Z** The nodes publish events and so must be authenticated to
the master. Ideally this authentication is specific to each node so that
authorization can be narrowly scoped. The details of the work to run (including
things like environment variables) might be considered sensitive and should be
locked down also.
**Note:** While the description here refers to a singular Master, in the future
we should enable multiple Masters operating in an HA mode. While the "Master" is
currently the combination of the API Server, Scheduler and Controller Manager,
we will restrict ourselves to thinking about the main API and policy engine --
the API Server.
## Current Implementation
A central authority (generally the master) is responsible for determining the
set of machines which are members of the cluster. Calls to create and remove
worker nodes in the cluster are restricted to this single authority, and any
other requests to add or remove worker nodes are rejected. (1.i.)
Communication from the master to nodes is currently over HTTP and is not secured
or authenticated in any way. (1.ii, 1.iii.)
The location of the master is communicated out of band to the nodes. For GCE,
this is done via Salt. Other cluster instructions/scripts use other methods.
(2.i.)
Currently most communication from the node to the master is over HTTP. When it
is done over HTTPS there is currently no verification of the cert of the master
(2.ii.)
Currently, the node/kubelet is authenticated to the master via a token shared
across all nodes. This token is distributed out of band (using Salt for GCE) and
is optional. If it is not present then the kubelet is unable to publish events
to the master. (2.iii.)
Our current mix of out of band communication doesn't meet all of our needs from
a security point of view and is difficult to set up and configure.
## Proposed Solution
The proposed solution will provide a range of options for setting up and
maintaining a secure Kubernetes cluster. We want to both allow for centrally
controlled systems (leveraging pre-existing trust and configuration systems) or
more ad-hoc automagic systems that are incredibly easy to set up.
The building blocks of an easier solution:
***Move to TLS** We will move to using TLS for all intra-cluster communication.
We will explicitly identify the trust chain (the set of trusted CAs) as opposed
to trusting the system CAs. We will also use client certificates for all AuthN.
*[optional]**API driven CA** Optionally, we will run a CA in the master that
will mint certificates for the nodes/kubelets. There will be pluggable policies
that will automatically approve certificate requests here as appropriate.
***CA approval policy** This is a pluggable policy object that can
automatically approve CA signing requests. Stock policies will include
`always-reject`, `queue` and `insecure-always-approve`. With `queue` there would
be an API for evaluating and accepting/rejecting requests. Cloud providers could
implement a policy here that verifies other out of band information and
automatically approves/rejects based on other external factors.
***Scoped Kubelet Accounts** These accounts are per-node and (optionally) give
a node permission to register itself.
* To start with, we'd have the kubelets generate a cert/account in the form of
`kubelet:<host>`. To start we would then hard code policy such that we give that
particular account appropriate permissions. Over time, we can make the policy
engine more generic.
*[optional]**Bootstrap API endpoint** This is a helper service hosted outside
of the Kubernetes cluster that helps with initial discovery of the master.
### Static Clustering
In this sequence diagram there is out of band admin entity that is creating all
certificates and distributing them. It is also making sure that the kubelets
know where to find the master. This provides for a lot of control but is more
difficult to set up as lots of information must be communicated outside of
Kubernetes.

### Dynamic Clustering
This diagram shows dynamic clustering using the bootstrap API endpoint. This
endpoint is used to both find the location of the master and communicate the
root CA for the master.
This flow has the admin manually approving the kubelet signing requests. This is
the `queue` policy defined above. This manual intervention could be replaced by
code that can verify the signing requests via other means.
This directory contains diagrams for the clustering design doc.
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/clustering/README.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/clustering/README.md)
This depends on the `seqdiag`[utility](http://blockdiag.com/en/seqdiag/index.html).
Assuming you have a non-borked python install, this should be installable with:
```sh
pip install seqdiag
```
Just call `make` to regenerate the diagrams.
## Building with Docker
If you are on a Mac or your pip install is messed up, you can easily build with
docker:
```sh
make docker
```
The first run will be slow but things should be fast after that.
To clean up the docker containers that are created (and other cruft that is left
around) you can run `make docker-clean`.
## Automatically rebuild on file changes
If you have the fswatch utility installed, you can have it monitor the file
system and automatically rebuild when files have changed. Just do a
# Container Command Execution & Port Forwarding in Kubernetes
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/command_execution_port_forwarding.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/command_execution_port_forwarding.md)
## Abstract
This document describes how to use Kubernetes to execute commands in containers,
with stdin/stdout/stderr streams attached and how to implement port forwarding
to the containers.
## Background
See the following related issues/PRs:
-[Support attach](http://issue.k8s.io/1521)
-[Real container ssh](http://issue.k8s.io/1513)
-[Provide easy debug network access to services](http://issue.k8s.io/1863)
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/configmap.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/configmap.md)
## Abstract
The `ConfigMap` API resource stores data used for the configuration of
applications deployed on Kubernetes.
The main focus of this resource is to:
* Provide dynamic distribution of configuration data to deployed applications.
* Encapsulate configuration information and simplify `Kubernetes` deployments.
* Create a flexible configuration model for `Kubernetes`.
## Motivation
A `Secret`-like API resource is needed to store configuration data that pods can
consume.
Goals of this design:
1. Describe a `ConfigMap` API resource.
2. Describe the semantics of consuming `ConfigMap` as environment variables.
3. Describe the semantics of consuming `ConfigMap` as files in a volume.
## Use Cases
1. As a user, I want to be able to consume configuration data as environment
variables.
2. As a user, I want to be able to consume configuration data as files in a
volume.
3. As a user, I want my view of configuration data in files to be eventually
consistent with changes to the data.
### Consuming `ConfigMap` as Environment Variables
A series of events for consuming `ConfigMap` as environment variables:
1. Create a `ConfigMap` object.
2. Create a pod to consume the configuration data via environment variables.
3. The pod is scheduled onto a node.
4. The Kubelet retrieves the `ConfigMap` resource(s) referenced by the pod and
starts the container processes with the appropriate configuration data from
environment variables.
### Consuming `ConfigMap` in Volumes
A series of events for consuming `ConfigMap` as configuration files in a volume:
1. Create a `ConfigMap` object.
2. Create a new pod using the `ConfigMap` via a volume plugin.
3. The pod is scheduled onto a node.
4. The Kubelet creates an instance of the volume plugin and calls its `Setup()`
method.
5. The volume plugin retrieves the `ConfigMap` resource(s) referenced by the pod
and projects the appropriate configuration data into the volume.
### Consuming `ConfigMap` Updates
Any long-running system has configuration that is mutated over time. Changes
made to configuration data must be made visible to pods consuming data in
volumes so that they can respond to those changes.
The `resourceVersion` of the `ConfigMap` object will be updated by the API
server every time the object is modified. After an update, modifications will be
made visible to the consumer container:
1. Create a `ConfigMap` object.
2. Create a new pod using the `ConfigMap` via the volume plugin.
3. The pod is scheduled onto a node.
4. During the sync loop, the Kubelet creates an instance of the volume plugin
and calls its `Setup()` method.
5. The volume plugin retrieves the `ConfigMap` resource(s) referenced by the pod
and projects the appropriate data into the volume.
6. The `ConfigMap` referenced by the pod is updated.
7. During the next iteration of the `syncLoop`, the Kubelet creates an instance
of the volume plugin and calls its `Setup()` method.
8. The volume plugin projects the updated data into the volume atomically.
It is the consuming pod's responsibility to make use of the updated data once it
is made visible.
Because environment variables cannot be updated without restarting a container,
configuration data consumed in environment variables will not be updated.
### Advantages
* Easy to consume in pods; consumer-agnostic
* Configuration data is persistent and versioned
* Consumers of configuration data in volumes can respond to changes in the data
## Proposed Design
### API Resource
The `ConfigMap` resource will be added to the main API:
```go
packageapi
// ConfigMap holds configuration data for pods to consume.
typeConfigMapstruct{
TypeMeta`json:",inline"`
ObjectMeta`json:"metadata,omitempty"`
// Data contains the configuration data. Each key must be a valid
// DNS_SUBDOMAIN or leading dot followed by valid DNS_SUBDOMAIN.
Datamap[string]string`json:"data,omitempty"`
}
typeConfigMapListstruct{
TypeMeta`json:",inline"`
ListMeta`json:"metadata,omitempty"`
Items[]ConfigMap`json:"items"`
}
```
A `Registry` implementation for `ConfigMap` will be added to
`pkg/registry/configmap`.
### Environment Variables
The `EnvVarSource` will be extended with a new selector for `ConfigMap`:
```go
packageapi
// EnvVarSource represents a source for the value of an EnvVar.
# Kubernetes and Cluster Federation Control Plane Resilience
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/control-plane-resilience.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/control-plane-resilience.md)
## Long Term Design and Current Status
### by Quinton Hoole, Mike Danese and Justin Santa-Barbara
### December 14, 2015
## Summary
Some amount of confusion exists around how we currently, and in future
want to ensure resilience of the Kubernetes (and by implication
Kubernetes Cluster Federation) control plane. This document is an attempt to capture that
definitively. It covers areas including self-healing, high
availability, bootstrapping and recovery. Most of the information in
this document already exists in the form of github comments,
PR's/proposals, scattered documents, and corridor conversations, so
document is primarily a consolidation and clarification of existing
ideas.
## Terms
***Self-healing:** automatically restarting or replacing failed
processes and machines without human intervention
***High availability:** continuing to be available and work correctly
even if some components are down or uncontactable. This typically
involves multiple replicas of critical services, and a reliable way
to find available replicas. Note that it's possible (but not
desirable) to have high
availability properties (e.g. multiple replicas) in the absence of
self-healing properties (e.g. if a replica fails, nothing replaces
it). Fairly obviously, given enough time, such systems typically
become unavailable (after enough replicas have failed).
***Bootstrapping**: creating an empty cluster from nothing
***Recovery**: recreating a non-empty cluster after perhaps
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/daemon.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/daemon.md)
**Author**: Ananya Kumar (@AnanyaKumar)
**Status**: Implemented.
This document presents the design of the Kubernetes DaemonSet, describes use
cases, and gives an overview of the code.
## Motivation
Many users have requested for a way to run a daemon on every node in a
Kubernetes cluster, or on a certain set of nodes in a cluster. This is essential
for use cases such as building a sharded datastore, or running a logger on every
node. In comes the DaemonSet, a way to conveniently create and manage
daemon-like workloads in Kubernetes.
## Use Cases
The DaemonSet can be used for user-specified system services, cluster-level
applications with strong node ties, and Kubernetes node services. Below are
example use cases in each category.
### User-Specified System Services:
Logging: Some users want a way to collect statistics about nodes in a cluster
and send those logs to an external database. For example, system administrators
might want to know if their machines are performing as expected, if they need to
add more machines to the cluster, or if they should switch cloud providers. The
DaemonSet can be used to run a data collection service (for example fluentd) on
every node and send the data to a service like ElasticSearch for analysis.
### Cluster-Level Applications
Datastore: Users might want to implement a sharded datastore in their cluster. A
few nodes in the cluster, labeled ‘app=datastore’, might be responsible for
storing data shards, and pods running on these nodes might serve data. This
architecture requires a way to bind pods to specific nodes, so it cannot be
achieved using a Replication Controller. A DaemonSet is a convenient way to
implement such a datastore.
For other uses, see the related [feature request](https://issues.k8s.io/1518)
## Functionality
The DaemonSet supports standard API features:
- create
- The spec for DaemonSets has a pod template field.
- Using the pod’s nodeSelector field, DaemonSets can be restricted to operate
over nodes that have a certain label. For example, suppose that in a cluster
some nodes are labeled ‘app=database’. You can use a DaemonSet to launch a
datastore pod on exactly those nodes labeled ‘app=database’.
- Using the pod's nodeName field, DaemonSets can be restricted to operate on a
specified node.
- The PodTemplateSpec used by the DaemonSet is the same as the PodTemplateSpec
used by the Replication Controller.
- The initial implementation will not guarantee that DaemonSet pods are
created on nodes before other pods.
- The initial implementation of DaemonSet does not guarantee that DaemonSet
pods show up on nodes (for example because of resource limitations of the node),
but makes a best effort to launch DaemonSet pods (like Replication Controllers
do with pods). Subsequent revisions might ensure that DaemonSet pods show up on
nodes, preempting other pods if necessary.
- The DaemonSet controller adds an annotation:
```"kubernetes.io/created-by: \<json API object reference\>"```
- YAML example:
```YAML
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
labels:
app: datastore
name: datastore
spec:
template:
metadata:
labels:
app: datastore-shard
spec:
nodeSelector:
app: datastore-node
containers:
name: datastore-shard
image: kubernetes/sharded
ports:
- containerPort: 9042
name: main
```
- commands that get info:
- get (e.g. kubectl get daemonsets)
- describe
- Modifiers:
- delete (if --cascade=true, then first the client turns down all the pods
controlled by the DaemonSet (by setting the nodeSelector to a uuid pair that is
unlikely to be set on any node); then it deletes the DaemonSet; then it deletes
the pods)
- label
- annotate
- update operations like patch and replace (only allowed to selector and to
nodeSelector and nodeName of pod template)
- DaemonSets have labels, so you could, for example, list all DaemonSets
with certain labels (the same way you would for a Replication Controller).
In general, for all the supported features like get, describe, update, etc,
the DaemonSet works in a similar way to the Replication Controller. However,
note that the DaemonSet and the Replication Controller are different constructs.
### Persisting Pods
- Ordinary liveness probes specified in the pod template work to keep pods
created by a DaemonSet running.
- If a daemon pod is killed or stopped, the DaemonSet will create a new
replica of the daemon pod on the node.
### Cluster Mutations
- When a new node is added to the cluster, the DaemonSet controller starts
daemon pods on the node for DaemonSets whose pod template nodeSelectors match
the node’s labels.
- Suppose the user launches a DaemonSet that runs a logging daemon on all
nodes labeled “logger=fluentd”. If the user then adds the “logger=fluentd” label
to a node (that did not initially have the label), the logging daemon will
launch on the node. Additionally, if a user removes the label from a node, the
logging daemon on that node will be killed.
## Alternatives Considered
We considered several alternatives, that were deemed inferior to the approach of
creating a new DaemonSet abstraction.
One alternative is to include the daemon in the machine image. In this case it
would run outside of Kubernetes proper, and thus not be monitored, health
checked, usable as a service endpoint, easily upgradable, etc.
A related alternative is to package daemons as static pods. This would address
most of the problems described above, but they would still not be easily
upgradable, and more generally could not be managed through the API server
interface.
A third alternative is to generalize the Replication Controller. We would do
something like: if you set the `replicas` field of the ReplicationControllerSpec
to -1, then it means "run exactly one replica on every node matching the
nodeSelector in the pod template." The ReplicationController would pretend
`replicas` had been set to some large number -- larger than the largest number
of nodes ever expected in the cluster -- and would use some anti-affinity
mechanism to ensure that no more than one Pod from the ReplicationController
runs on any given node. There are two downsides to this approach. First,
there would always be a large number of Pending pods in the scheduler (these
will be scheduled onto new machines when they are added to the cluster). The
second downside is more philosophical: DaemonSet and the Replication Controller
are very different concepts. We believe that having small, targeted controllers
for distinct purposes makes Kubernetes easier to understand and use, compared to
having larger multi-functional controllers (see
["Convert ReplicationController to a plugin"](http://issues.k8s.io/3058) for
some discussion of this topic).
## Design
#### Client
- Add support for DaemonSet commands to kubectl and the client. Client code was
added to pkg/client/unversioned. The main files in Kubectl that were modified are
pkg/kubectl/describe.go and pkg/kubectl/stop.go, since for other calls like Get, Create,
and Update, the client simply forwards the request to the backend via the REST
API.
#### Apiserver
- Accept, parse, validate client commands
- REST API calls are handled in pkg/registry/daemonset
- In particular, the api server will add the object to etcd
- DaemonManager listens for updates to etcd (using Framework.informer)
- API objects for DaemonSet were created in expapi/v1/types.go and
expapi/v1/register.go
- Validation code is in expapi/validation
#### Daemon Manager
- Creates new DaemonSets when requested. Launches the corresponding daemon pod
on all nodes with labels matching the new DaemonSet’s selector.
- Listens for addition of new nodes to the cluster, by setting up a
framework.NewInformer that watches for the creation of Node API objects. When a
new node is added, the daemon manager will loop through each DaemonSet. If the
label of the node matches the selector of the DaemonSet, then the daemon manager
will create the corresponding daemon pod in the new node.
- The daemon manager creates a pod on a node by sending a command to the API
server, requesting for a pod to be bound to the node (the node will be specified
via its hostname.)
#### Kubelet
- Does not need to be modified, but health checking will occur for the daemon
pods and revive the pods if they are killed (we set the pod restartPolicy to
Always). We reject DaemonSet objects with pod templates that don’t have
restartPolicy set to Always.
## Open Issues
- Should work similarly to [Deployment](http://issues.k8s.io/1743).
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/downward_api_resources_limits_requests.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/downward_api_resources_limits_requests.md)
## Background
Currently the downward API (via environment variables and volume plugin) only
supports exposing a Pod's name, namespace, annotations, labels and its IP
([see details](http://kubernetes.io/docs/user-guide/downward-api/)). This
document explains the need and design to extend them to expose resources
(e.g. cpu, memory) limits and requests.
## Motivation
Software applications require configuration to work optimally with the resources they're allowed to use.
Exposing the requested and limited amounts of available resources inside containers will allow
these applications to be configured more easily. Although docker already
exposes some of this information inside containers, the downward API helps
exposing this information in a runtime-agnostic manner in Kubernetes.
## Use cases
As an application author, I want to be able to use cpu or memory requests and
limits to configure the operational requirements of my applications inside containers.
For example, Java applications expect to be made aware of the available heap size via
a command line argument to the JVM, for example: java -Xmx:`<heap-size>`. Similarly, an
application may want to configure its thread pool based on available cpu resources and
the exported value of GOMAXPROCS.
## Design
This is mostly driven by the discussion in [this issue](https://github.com/kubernetes/kubernetes/issues/9473).
There are three approaches discussed in this document to obtain resources limits
and requests to be exposed as environment variables and volumes inside
containers:
1. The first approach requires users to specify full json path selectors
in which selectors are relative to the pod spec. The benefit of this
approach is to specify pod-level resources, and since containers are
also part of a pod spec, it can be used to specify container-level
resources too.
2. The second approach requires specifying partial json path selectors
which are relative to the container spec. This approach helps
in retrieving a container specific resource limits and requests, and at
the same time, it is simpler to specify than full json path selectors.
3. In the third approach, users specify fixed strings (magic keys) to retrieve
resources limits and requests and do not specify any json path
selectors. This approach is similar to the existing downward API
implementation approach. The advantages of this approach are that it is
simpler to specify that the first two, and does not require any type of
conversion between internal and versioned objects or json selectors as
discussed below.
Before discussing a bit more about merits of each approach, here is a
brief discussion about json path selectors and some implications related
to their use.
#### JSONpath selectors
Versioned objects in kubernetes have json tags as part of their golang fields.
Currently, objects in the internal API have json tags, but it is planned that
these will eventually be removed (see [3933](https://github.com/kubernetes/kubernetes/issues/3933)
for discussion). So for discussion in this proposal, we assume that
internal objects do not have json tags. In the first two approaches
(full and partial json selectors), when a user creates a pod and its
containers, the user specifies a json path selector in the pod's
spec to retrieve values of its limits and requests. The selector
is composed of json tags similar to json paths used with kubectl
([json](http://kubernetes.io/docs/user-guide/jsonpath/)). This proposal
uses kubernetes' json path library to process the selectors to retrieve
the values. As kubelet operates on internal objects (without json tags),
and the selectors are part of versioned objects, retrieving values of
the limits and requests can be handled using these two solutions:
1. By converting an internal object to versioned object, and then using
the json path library to retrieve the values from the versioned object
by processing the selector.
2. By converting a json selector of the versioned objects to internal
object's golang expression and then using the json path library to
retrieve the values from the internal object by processing the golang
expression. However, converting a json selector of the versioned objects
to internal object's golang expression will still require an instance
of the versioned object, so it seems more work from the first solution
unless there is another way without requiring the versioned object.
So there is a one time conversion cost associated with the first (full
path) and second (partial path) approaches, whereas the third approach
(magic keys) does not require any such conversion and can directly
work on internal objects. If we want to avoid conversion cost and to
have implementation simplicity, my opinion is that magic keys approach
is relatively easiest to implement to expose limits and requests with
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/enhance-pluggable-policy.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/enhance-pluggable-policy.md)
While trying to develop an authorization plugin for Kubernetes, we found a few
places where API extensions would ease development and add power. There are a
few goals:
1. Provide an authorization plugin that can evaluate a .Authorize() call based
on the full content of the request to RESTStorage. This includes information
like the full verb, the content of creates and updates, and the names of
resources being acted upon.
1. Provide a way to ask whether a user is permitted to take an action without
running in process with the API Authorizer. For instance, a proxy for exec
calls could ask whether a user can run the exec they are requesting.
1. Provide a way to ask who can perform a given action on a given resource.
This is useful for answering questions like, "who can create replication
controllers in my namespace".
This proposal adds to and extends the existing API to so that authorizers may
provide the functionality described above. It does not attempt to describe how
the policies themselves can be expressed, that is up the authorization plugins
themselves.
## Enhancements to existing Authorization interfaces
The existing Authorization interfaces are described
[here](../admin/authorization.md). A couple additions will allow the development
of an Authorizer that matches based on different rules than the existing
implementation.
### Request Attributes
The existing authorizer.Attributes only has 5 attributes (user, groups,
isReadOnly, kind, and namespace). If we add more detailed verbs, content, and
resource names, then Authorizer plugins will have the same level of information
available to RESTStorage components in order to express more detailed policy.
The replacement excerpt is below.
An API request has the following attributes that can be considered for
authorization:
- user - the user-string which a user was authenticated as. This is included
in the Context.
- groups - the groups to which the user belongs. This is included in the
Context.
- verb - string describing the requesting action. Today we have: get, list,
watch, create, update, and delete. The old `readOnly` behavior is equivalent to
allowing get, list, watch.
- namespace - the namespace of the object being access, or the empty string if
the endpoint does not support namespaced objects. This is included in the
Context.
- resourceGroup - the API group of the resource being accessed
- resourceVersion - the API version of the resource being accessed
- resource - which resource is being accessed
- applies only to the API endpoints, such as `/api/v1beta1/pods`. For
miscellaneous endpoints, like `/version`, the kind is the empty string.
- resourceName - the name of the resource during a get, update, or delete
action.
- subresource - which subresource is being accessed
A non-API request has 2 attributes:
- verb - the HTTP verb of the request
- path - the path of the URL being requested
### Authorizer Interface
The existing Authorizer interface is very simple, but there isn't a way to
provide details about allows, denies, or failures. The extended detail is useful
for UIs that want to describe why certain actions are allowed or disallowed. Not
all Authorizers will want to provide that information, but for those that do,
having that capability is useful. In addition, adding a `GetAllowedSubjects`
method that returns back the users and groups that can perform a particular
action makes it possible to answer questions like, "who can see resources in my
namespace" (see [ResourceAccessReview](#ResourceAccessReview) further down).
```go
// OLD
typeAuthorizerinterface{
Authorize(aAttributes)error
}
```
```go
// NEW
// Authorizer provides the ability to determine if a particular user can perform
// a particular action
typeAuthorizerinterface{
// Authorize takes a Context (for namespace, user, and traceability) and
// Attributes to make a policy determination.
// reason is an optional return value that can describe why a policy decision
// was made. Reasons are useful during debugging when trying to figure out
// why a user or group has access to perform a particular action.
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/event_compression.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/event_compression.md)
This document captures the design of event compression.
## Background
Kubernetes components can get into a state where they generate tons of events.
The events can be categorized in one of two ways:
1. same - The event is identical to previous events except it varies only on
timestamp.
2. similar - The event is identical to previous events except it varies on
timestamp and message.
For example, when pulling a non-existing image, Kubelet will repeatedly generate
`image_not_existing` and `container_is_waiting` events until upstream components
correct the image. When this happens, the spam from the repeated events makes
the entire event mechanism useless. It also appears to cause memory pressure in
etcd (see [#3853](http://issue.k8s.io/3853)).
The goal is introduce event counting to increment same events, and event
aggregation to collapse similar events.
## Proposal
Each binary that generates events (for example, `kubelet`) should keep track of
previously generated events so that it can collapse recurring events into a
single event instead of creating a new instance for each new event. In addition,
if many similar events are created, events should be aggregated into a single
event to reduce spam.
Event compression should be best effort (not guaranteed). Meaning, in the worst
case, `n` identical (minus timestamp) events may still result in `n` event
entries.
## Design
Instead of a single Timestamp, each event object
[contains](http://releases.k8s.io/HEAD/pkg/api/types.go#L1111) the following
fields:
*`FirstTimestamp unversioned.Time`
* The date/time of the first occurrence of the event.
*`LastTimestamp unversioned.Time`
* The date/time of the most recent occurrence of the event.
* On first occurrence, this is equal to the FirstTimestamp.
*`Count int`
* The number of occurrences of this event between FirstTimestamp and
LastTimestamp.
* On first occurrence, this is 1.
Each binary that generates events:
* Maintains a historical record of previously generated events:
* Implemented with
["Least Recently Used Cache"](https://github.com/golang/groupcache/blob/master/lru/lru.go)
in [`pkg/client/record/events_cache.go`](../../pkg/client/record/events_cache.go).
* Implemented behind an `EventCorrelator` that manages two subcomponents:
`EventAggregator` and `EventLogger`.
* The `EventCorrelator` observes all incoming events and lets each
subcomponent visit and modify the event in turn.
* The `EventAggregator` runs an aggregation function over each event. This
function buckets each event based on an `aggregateKey` and identifies the event
uniquely with a `localKey` in that bucket.
* The default aggregation function groups similar events that differ only by
`event.Message`. Its `localKey` is `event.Message` and its aggregate key is
produced by joining:
*`event.Source.Component`
*`event.Source.Host`
*`event.InvolvedObject.Kind`
*`event.InvolvedObject.Namespace`
*`event.InvolvedObject.Name`
*`event.InvolvedObject.UID`
*`event.InvolvedObject.APIVersion`
*`event.Reason`
* If the `EventAggregator` observes a similar event produced 10 times in a 10
minute window, it drops the event that was provided as input and creates a new
event that differs only on the message. The message denotes that this event is
used to group similar events that matched on reason. This aggregated `Event` is
then used in the event processing sequence.
* The `EventLogger` observes the event out of `EventAggregation` and tracks
the number of times it has observed that event previously by incrementing a key
in a cache associated with that matching event.
* The key in the cache is generated from the event object minus
timestamps/count/transient fields, specifically the following events fields are
used to construct a unique key for an event:
*`event.Source.Component`
*`event.Source.Host`
*`event.InvolvedObject.Kind`
*`event.InvolvedObject.Namespace`
*`event.InvolvedObject.Name`
*`event.InvolvedObject.UID`
*`event.InvolvedObject.APIVersion`
*`event.Reason`
*`event.Message`
* The LRU cache is capped at 4096 events for both `EventAggregator` and
`EventLogger`. That means if a component (e.g. kubelet) runs for a long period
of time and generates tons of unique events, the previously generated events
cache will not grow unchecked in memory. Instead, after 4096 unique events are
generated, the oldest events are evicted from the cache.
* When an event is generated, the previously generated events cache is checked
(see [`pkg/client/unversioned/record/event.go`](http://releases.k8s.io/HEAD/pkg/client/record/event.go)).
* If the key for the new event matches the key for a previously generated
event (meaning all of the above fields match between the new event and some
previously generated event), then the event is considered to be a duplicate and
the existing event entry is updated in etcd:
* The new PUT (update) event API is called to update the existing event
entry in etcd with the new last seen timestamp and count.
* The event is also updated in the previously generated events cache with
an incremented count, updated last seen timestamp, name, and new resource
version (all required to issue a future event update).
* If the key for the new event does not match the key for any previously
generated event (meaning none of the above fields match between the new event
and any previously generated events), then the event is considered to be
new/unique and a new event entry is created in etcd:
* The usual POST/create event API is called to create a new event entry in
etcd.
* An entry for the event is also added to the previously generated events
cache.
## Issues/Risks
* Compression is not guaranteed, because each component keeps track of event
history in memory
* An application restart causes event history to be cleared, meaning event
history is not preserved across application restarts and compression will not
occur across component restarts.
* Because an LRU cache is used to keep track of previously generated events,
if too many unique events are generated, old events will be evicted from the
cache, so events will only be compressed until they age out of the events cache,
at which point any new instance of the event will cause a new entry to be
created in etcd.
## Example
Sample kubectl output:
```console
FIRSTSEEN LASTSEEN COUNT NAME KIND SUBOBJECT REASON SOURCE MESSAGE
Thu, 12 Feb 2015 01:13:02 +0000 Thu, 12 Feb 2015 01:13:02 +0000 1 kubernetes-node-4.c.saad-dev-vms.internal Node starting {kubelet kubernetes-node-4.c.saad-dev-vms.internal} Starting kubelet.
Thu, 12 Feb 2015 01:13:09 +0000 Thu, 12 Feb 2015 01:13:09 +0000 1 kubernetes-node-1.c.saad-dev-vms.internal Node starting {kubelet kubernetes-node-1.c.saad-dev-vms.internal} Starting kubelet.
Thu, 12 Feb 2015 01:13:09 +0000 Thu, 12 Feb 2015 01:13:09 +0000 1 kubernetes-node-3.c.saad-dev-vms.internal Node starting {kubelet kubernetes-node-3.c.saad-dev-vms.internal} Starting kubelet.
Thu, 12 Feb 2015 01:13:09 +0000 Thu, 12 Feb 2015 01:13:09 +0000 1 kubernetes-node-2.c.saad-dev-vms.internal Node starting {kubelet kubernetes-node-2.c.saad-dev-vms.internal} Starting kubelet.
Thu, 12 Feb 2015 01:13:05 +0000 Thu, 12 Feb 2015 01:13:12 +0000 4 monitoring-influx-grafana-controller-0133o Pod failedScheduling {scheduler } Error scheduling: no nodes available to schedule pods
Thu, 12 Feb 2015 01:13:05 +0000 Thu, 12 Feb 2015 01:13:12 +0000 4 elasticsearch-logging-controller-fplln Pod failedScheduling {scheduler } Error scheduling: no nodes available to schedule pods
Thu, 12 Feb 2015 01:13:05 +0000 Thu, 12 Feb 2015 01:13:12 +0000 4 kibana-logging-controller-gziey Pod failedScheduling {scheduler } Error scheduling: no nodes available to schedule pods
Thu, 12 Feb 2015 01:13:05 +0000 Thu, 12 Feb 2015 01:13:12 +0000 4 skydns-ls6k1 Pod failedScheduling {scheduler } Error scheduling: no nodes available to schedule pods
Thu, 12 Feb 2015 01:13:05 +0000 Thu, 12 Feb 2015 01:13:12 +0000 4 monitoring-heapster-controller-oh43e Pod failedScheduling {scheduler } Error scheduling: no nodes available to schedule pods
Thu, 12 Feb 2015 01:13:20 +0000 Thu, 12 Feb 2015 01:13:20 +0000 1 kibana-logging-controller-gziey BoundPod implicitly required container POD pulled {kubelet kubernetes-node-4.c.saad-dev-vms.internal} Successfully pulled image "kubernetes/pause:latest"
Thu, 12 Feb 2015 01:13:20 +0000 Thu, 12 Feb 2015 01:13:20 +0000 1 kibana-logging-controller-gziey Pod scheduled {scheduler } Successfully assigned kibana-logging-controller-gziey to kubernetes-node-4.c.saad-dev-vms.internal
```
This demonstrates what would have been 20 separate entries (indicating
scheduling failure) collapsed/compressed down to 5 entries.
# Variable expansion in pod command, args, and env
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/expansion.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/expansion.md)
## Abstract
A proposal for the expansion of environment variables using a simple `$(var)`
syntax.
## Motivation
It is extremely common for users to need to compose environment variables or
pass arguments to their commands using the values of environment variables.
Kubernetes should provide a facility for the 80% cases in order to decrease
coupling and the use of workarounds.
## Goals
1. Define the syntax format
2. Define the scoping and ordering of substitutions
3. Define the behavior for unmatched variables
4. Define the behavior for unexpected/malformed input
## Constraints and Assumptions
* This design should describe the simplest possible syntax to accomplish the
use-cases.
* Expansion syntax will not support more complicated shell-like behaviors such
as default values (viz: `$(VARIABLE_NAME:"default")`), inline substitution, etc.
## Use Cases
1. As a user, I want to compose new environment variables for a container using
a substitution syntax to reference other variables in the container's
environment and service environment variables.
1. As a user, I want to substitute environment variables into a container's
command.
1. As a user, I want to do the above without requiring the container's image to
have a shell.
1. As a user, I want to be able to specify a default value for a service
variable which may not exist.
1. As a user, I want to see an event associated with the pod if an expansion
fails (ie, references variable names that cannot be expanded).
### Use Case: Composition of environment variables
Currently, containers are injected with docker-style environment variables for
the services in their pod's namespace. There are several variables for each
service, but users routinely need to compose URLs based on these variables
because there is not a variable for the exact format they need. Users should be
able to build new environment variables with the exact format they need.
Eventually, it should also be possible to turn off the automatic injection of
the docker-style variables into pods and let the users consume the exact
information they need via the downward API and composition.
#### Expanding expanded variables
It should be possible to reference an variable which is itself the result of an
expansion, if the referenced variable is declared in the container's environment
prior to the one referencing it. Put another way -- a container's environment is
expanded in order, and expanded variables are available to subsequent
expansions.
### Use Case: Variable expansion in command
Users frequently need to pass the values of environment variables to a
container's command. Currently, Kubernetes does not perform any expansion of
variables. The workaround is to invoke a shell in the container's command and
have the shell perform the substitution, or to write a wrapper script that sets
up the environment and runs the command. This has a number of drawbacks:
1. Solutions that require a shell are unfriendly to images that do not contain
a shell.
2. Wrapper scripts make it harder to use images as base images.
3. Wrapper scripts increase coupling to Kubernetes.
Users should be able to do the 80% case of variable expansion in command without
writing a wrapper script or adding a shell invocation to their containers'
commands.
### Use Case: Images without shells
The current workaround for variable expansion in a container's command requires
the container's image to have a shell. This is unfriendly to images that do not
contain a shell (`scratch` images, for example). Users should be able to perform
the other use-cases in this design without regard to the content of their
images.
### Use Case: See an event for incomplete expansions
It is possible that a container with incorrect variable values or command line
may continue to run for a long period of time, and that the end-user would have
no visual or obvious warning of the incorrect configuration. If the kubelet
creates an event when an expansion references a variable that cannot be
expanded, it will help users quickly detect problems with expansions.
## Design Considerations
### What features should be supported?
In order to limit complexity, we want to provide the right amount of
functionality so that the 80% cases can be realized and nothing more. We felt
that the essentials boiled down to:
1. Ability to perform direct expansion of variables in a string.
2. Ability to specify default values via a prioritized mapping function but
without support for defaults as a syntax-level feature.
### What should the syntax be?
The exact syntax for variable expansion has a large impact on how users perceive
and relate to the feature. We considered implementing a very restrictive subset
of the shell `${var}` syntax. This syntax is an attractive option on some level,
because many people are familiar with it. However, this syntax also has a large
number of lesser known features such as the ability to provide default values
for unset variables, perform inline substitution, etc.
In the interest of preventing conflation of the expansion feature in Kubernetes
with the shell feature, we chose a different syntax similar to the one in
Makefiles, `$(var)`. We also chose not to support the bar `$var` format, since
it is not required to implement the required use-cases.
Nested references, ie, variable expansion within variable names, are not
supported.
#### How should unmatched references be treated?
Ideally, it should be extremely clear when a variable reference couldn't be
expanded. We decided the best experience for unmatched variable references would
be to have the entire reference, syntax included, show up in the output. As an
example, if the reference `$(VARIABLE_NAME)` cannot be expanded, then
`$(VARIABLE_NAME)` should be present in the output.
#### Escaping the operator
Although the `$(var)` syntax does overlap with the `$(command)` form of command
substitution supported by many shells, because unexpanded variables are present
verbatim in the output, we expect this will not present a problem to many users.
If there is a collision between a variable name and command substitution syntax,
the syntax can be escaped with the form `$$(VARIABLE_NAME)`, which will evaluate
to `$(VARIABLE_NAME)` whether `VARIABLE_NAME` can be expanded or not.
## Design
This design encompasses the variable expansion syntax and specification and the
changes needed to incorporate the expansion feature into the container's
environment and command.
### Syntax and expansion mechanics
This section describes the expansion syntax, evaluation of variable values, and
how unexpected or malformed inputs are handled.
#### Syntax
The inputs to the expansion feature are:
1. A utf-8 string (the input string) which may contain variable references.
2. A function (the mapping function) that maps the name of a variable to the
variable's value, of type `func(string) string`.
Variable references in the input string are indicated exclusively with the syntax
`$(<variable-name>)`. The syntax tokens are:
-`$`: the operator,
-`(`: the reference opener, and
-`)`: the reference closer.
The operator has no meaning unless accompanied by the reference opener and
closer tokens. The operator can be escaped using `$$`. One literal `$` will be
emitted for each `$$` in the input.
The reference opener and closer characters have no meaning when not part of a
variable reference. If a variable reference is malformed, viz: `$(VARIABLE_NAME`
without a closing expression, the operator and expression opening characters are
treated as ordinary characters without special meanings.
#### Scope and ordering of substitutions
The scope in which variable references are expanded is defined by the mapping
function. Within the mapping function, any arbitrary strategy may be used to
determine the value of a variable name. The most basic implementation of a
mapping function is to use a `map[string]string` to lookup the value of a
variable.
In order to support default values for variables like service variables
presented by the kubelet, which may not be bound because the service that
provides them does not yet exist, there should be a mapping function that uses a
# Adding custom resources to the Kubernetes API server
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/extending-api.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/extending-api.md)
This document describes the design for implementing the storage of custom API
types in the Kubernetes API Server.
## Resource Model
### The ThirdPartyResource
The `ThirdPartyResource` resource describes the multiple versions of a custom
resource that the user wants to add to the Kubernetes API. `ThirdPartyResource`
is a non-namespaced resource; attempting to place it in a namespace will return
an error.
Each `ThirdPartyResource` resource has the following:
* Standard Kubernetes object metadata.
* ResourceKind - The kind of the resources described by this third party
resource.
* Description - A free text description of the resource.
* APIGroup - An API group that this resource should be placed into.
* Versions - One or more `Version` objects.
### The `Version` Object
The `Version` object describes a single concrete version of a custom resource.
The `Version` object currently only specifies:
* The `Name` of the version.
* The `APIGroup` this version should belong to.
## Expectations about third party objects
Every object that is added to a third-party Kubernetes object store is expected
to contain Kubernetes compatible [object metadata](../devel/api-conventions.md#metadata).
This requirement enables the Kubernetes API server to provide the following
features:
* Filtering lists of objects via label queries.
*`resourceVersion`-based optimistic concurrency via compare-and-swap.
* Versioned storage.
* Event recording.
* Integration with basic `kubectl` command line tooling.
* Watch for resource changes.
The `Kind` for an instance of a third-party object (e.g. CronTab) below is
expected to be programmatically convertible to the name of the resource using
the following conversion. Kinds are expected to be of the form
`<CamelCaseKind>`, and the `APIVersion` for the object is expected to be
`<api-group>/<api-version>`. To prevent collisions, it's expected that you'll
use a DNS name of at least three segments for the API group, e.g. `mygroup.example.com`.
For example `mygroup.example.com/v1`
'CamelCaseKind' is the specific type name.
To convert this into the `metadata.name` for the `ThirdPartyResource` resource
instance, the `<domain-name>` is copied verbatim, the `CamelCaseKind` is then
converted using '-' instead of capitalization ('camel-case'), with the first
character being assumed to be capitalized. In pseudo code:
```go
varresultstring
forix:=rangekindName{
ifisCapital(kindName[ix]){
result=append(result,'-')
}
result=append(result,toLowerCase(kindName[ix])
}
```
As a concrete example, the resource named `camel-case-kind.mygroup.example.com` defines
resources of Kind `CamelCaseKind`, in the APIGroup with the prefix
`mygroup.example.com/...`.
The reason for this is to enable rapid lookup of a `ThirdPartyResource` object
given the kind information. This is also the reason why `ThirdPartyResource` is
not namespaced.
## Usage
When a user creates a new `ThirdPartyResource`, the Kubernetes API Server reacts
by creating a new, namespaced RESTful resource path. For now, non-namespaced
objects are not supported. As with existing built-in objects, deleting a
namespace deletes all third party resources in that namespace.
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/federated-replicasets.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/federated-replicasets.md)
# Requirements & Design Document
This document is a markdown version converted from a working [Google Doc](https://docs.google.com/a/google.com/document/d/1C1HEHQ1fwWtEhyl9JYu6wOiIUJffSmFmZgkGta4720I/edit?usp=sharing). Please refer to the original for extended commentary and discussion.
Author: Marcin Wielgus [mwielgus@google.com](mailto:mwielgus@google.com)
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/federated-services.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/federated-services.md)
## Cross-cluster Load Balancing and Service Discovery
### Requirements and System Design
### by Quinton Hoole, Dec 3 2015
## Requirements
### Discovery, Load-balancing and Failover
1.**Internal discovery and connection**: Pods/containers (running in
a Kubernetes cluster) must be able to easily discover and connect
to endpoints for Kubernetes services on which they depend in a
consistent way, irrespective of whether those services exist in a
different kubernetes cluster within the same cluster federation.
Hence-forth referred to as "cluster-internal clients", or simply
"internal clients".
1.**External discovery and connection**: External clients (running
outside a Kubernetes cluster) must be able to discover and connect
to endpoints for Kubernetes services on which they depend.
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/federation-phase-1.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/federation-phase-1.md)
**Huawei PaaS Team**
## INTRODUCTION
In this document we propose a design for the “Control Plane” of
Kubernetes (K8S) federation (a.k.a. “Ubernetes”). For background of
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/ha_master.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/ha_master.md)
**Author:** filipg@, jsz@
# Introduction
We want to allow users to easily replicate kubernetes masters to have highly available cluster,
initially using `kube-up.sh` and `kube-down.sh`.
This document describes technical design of this feature. It assumes that we are using aforementioned
scripts for cluster deployment. All of the ideas described in the following sections should be easy
to implement on GCE, AWS and other cloud providers.
It is a non-goal to design a specific setup for bare-metal environment, which
might be very different.
# Overview
In a cluster with replicated master, we will have N VMs, each running regular master components
such as apiserver, etcd, scheduler or controller manager. These components will interact in the
following way:
* All etcd replicas will be clustered together and will be using master election
and quorum mechanism to agree on the state. All of these mechanisms are integral
parts of etcd and we will only have to configure them properly.
* All apiserver replicas will be working independently talking to an etcd on
127.0.0.1 (i.e. local etcd replica), which if needed will forward requests to the current etcd master
<h2>Warning! This document might be outdated.</h2>
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/horizontal-pod-autoscaler.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/horizontal-pod-autoscaler.md)
# Horizontal Pod Autoscaling
## Preface
This document briefly describes the design of the horizontal autoscaler for
pods. The autoscaler (implemented as a Kubernetes API resource and controller)
is responsible for dynamically controlling the number of replicas of some
collection (e.g. the pods of a ReplicationController) to meet some objective(s),
for example a target per-pod CPU utilization.
This design supersedes [autoscaling.md](http://releases.k8s.io/release-1.0/docs/proposals/autoscaling.md).
## Overview
The resource usage of a serving application usually varies over time: sometimes
the demand for the application rises, and sometimes it drops. In Kubernetes
version 1.0, a user can only manually set the number of serving pods. Our aim is
to provide a mechanism for the automatic adjustment of the number of pods based
on CPU utilization statistics (a future version will allow autoscaling based on
other resources/metrics).
## Scale Subresource
In Kubernetes version 1.1, we are introducing Scale subresource and implementing
horizontal autoscaling of pods based on it. Scale subresource is supported for
replication controllers and deployments. Scale subresource is a Virtual Resource
(does not correspond to an object stored in etcd). It is only present in the API
as an interface that a controller (in this case the HorizontalPodAutoscaler) can
use to dynamically scale the number of replicas controlled by some other API
object (currently ReplicationController and Deployment) and to learn the current
number of replicas. Scale is a subresource of the API object that it serves as
the interface for. The Scale subresource is useful because whenever we introduce
another type we want to autoscale, we just need to implement the Scale
subresource for it. The wider discussion regarding Scale took place in issue
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/identifiers.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/identifiers.md)
A summarization of the goals and recommendations for identifiers in Kubernetes.
Described in GitHub issue [#199](http://issue.k8s.io/199).
## Definitions
`UID`: A non-empty, opaque, system-generated value guaranteed to be unique in time
and space; intended to distinguish between historical occurrences of similar
entities.
`Name`: A non-empty string guaranteed to be unique within a given scope at a
particular time; used in resource URLs; provided by clients at creation time and
encouraged to be human friendly; intended to facilitate creation idempotence and
space-uniqueness of singleton objects, distinguish distinct entities, and
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/indexed-job.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/indexed-job.md)
## Summary
This design extends kubernetes with user-friendly support for
running embarrassingly parallel jobs.
Here, *parallel* means on multiple nodes, which means multiple pods.
By *embarrassingly parallel*, it is meant that the pods
have no dependencies between each other. In particular, neither
ordering between pods nor gang scheduling are supported.
Users already have two other options for running embarrassingly parallel
Jobs (described in the next section), but both have ease-of-use issues.
Therefore, this document proposes extending the Job resource type to support
a third way to run embarrassingly parallel programs, with a focus on
ease of use.
This new style of Job is called an *indexed job*, because each Pod of the Job
is specialized to work on a particular *index* from a fixed length array of work
items.
## Background
The Kubernetes [Job](../../docs/user-guide/jobs.md) already supports
the embarrassingly parallel use case through *workqueue jobs*.
While [workqueue jobs](../../docs/user-guide/jobs.md#job-patterns) are very
flexible, they can be difficult to use. They: (1) typically require running a
message queue or other database service, (2) typically require modifications
to existing binaries and images and (3) subtle race conditions are easy to
overlook.
Users also have another option for parallel jobs: creating [multiple Job objects
from a template](hdocs/design/indexed-job.md#job-patterns). For small numbers of
Jobs, this is a fine choice. Labels make it easy to view and delete multiple Job
objects at once. But, that approach also has its drawbacks: (1) for large levels
of parallelism (hundreds or thousands of pods) this approach means that listing
all jobs presents too much information, (2) users want a single source of
information about the success or failure of what the user views as a single
logical process.
Indexed job fills provides a third option with better ease-of-use for common
use cases.
## Requirements
### User Requirements
- Users want an easy way to run a Pod to completion *for each* item within a
[work list](#example-use-cases).
- Users want to run these pods in parallel for speed, but to vary the level of
parallelism as needed, independent of the number of work items.
- Users want to do this without requiring changes to existing images,
or source-to-image pipelines.
- Users want a single object that encompasses the lifetime of the parallel
program. Deleting it should delete all dependent objects. It should report the
status of the overall process. Users should be able to wait for it to complete,
and can refer to it from other resource types, such as
The JobSpec can be extended to hold a list of parameter tuples (which are more
easily expressed as a list of lists of individual parameters). For example:
```
apiVersion: extensions/v1beta1
kind: Job
...
spec:
completions: 3
...
template:
...
perCompletionArgs:
container: 0
-
- "-f apple.txt"
- "-f banana.txt"
- "-f cherry.txt"
-
- "--remove-seeds"
- ""
- "--remove-pit"
perCompletionEnvVars:
- name: "FRUIT_COLOR"
- "green"
- "yellow"
- "red"
```
However, just providing custom env vars, and not arguments, is sufficient for
many use cases: parameter can be put into env vars, and then substituted on the
command line.
#### Comparison
The multiple substitution approach:
- keeps the *per completion parameters* in the JobSpec.
- Drawback: makes the job spec large for job with thousands of completions. (But
for very large jobs, the work-queue style or another type of controller, such as
map-reduce or spark, may be a better fit.)
- Drawback: is a form of server-side templating, which we want in Kubernetes but
have not fully designed (see the [StatefulSets proposal](https://github.com/kubernetes/kubernetes/pull/18016/files?short_path=61f4179#diff-61f41798f4bced6e42e45731c1494cee)).
The index-only approach:
- Requires that the user keep the *per completion parameters* in a separate
storage, such as a configData or networked storage.
- Makes no changes to the JobSpec.
- Drawback: while in separate storage, they could be mutated, which would have
unexpected effects.
- Drawback: Logic for using index to lookup parameters needs to be in the Pod.
- Drawback: CLIs and UIs are limited to using the "index" as the identity of a
pod from a job. They cannot easily say, for example `repeated failures on the
pod processing banana.txt`.
Index-only approach relies on at least one of the following being true:
1. Image containing a shell and certain shell commands (not all images have
this).
1. Use directly consumes the index from annotations (file or env var) and
expands to specific behavior in the main program.
Also Using the index-only approach from non-kubectl clients requires that they
mimic the script-generation step, or only use the second style.
#### Decision
It is decided to implement the Index-only approach now. Once the server-side
templating design is complete for Kubernetes, and we have feedback from users,
we can consider if Multiple Substitution.
## Detailed Design
#### Job Resource Schema Changes
No changes are made to the JobSpec.
The JobStatus is also not changed. The user can gauge the progress of the job by
the `.status.succeeded` count.
#### Job Spec Compatilibity
A job spec written before this change will work exactly the same as before with
the new controller. The Pods it creates will have the same environment as
before. They will have a new annotation, but pod are expected to tolerate
unfamiliar annotations.
However, if the job controller version is reverted, to a version before this
change, the jobs whose pod specs depend on the new annotation will fail.
This is okay for a Beta resource.
#### Job Controller Changes
The Job controller will maintain for each Job a data structed which
indicates the status of each completion index. We call this the
*scoreboard* for short. It is an array of length `.spec.completions`.
Elements of the array are `enum` type with possible values including
`complete`, `running`, and `notStarted`.
The scoreboard is stored in Job Controller memory for efficiency. In either
case, the Status can be reconstructed from watching pods of the job (such as on
a controller manager restart). The index of the pods can be extracted from the
pod annotation.
When Job controller sees that the number of running pods is less than the
desired parallelism of the job, it finds the first index in the scoreboard with
value `notRunning`. It creates a pod with this creation index.
When it creates a pod with creation index `i`, it makes a copy of the
`.spec.template`, and sets
`.spec.template.metadata.annotations.[kubernetes.io/job/completion-index]` to
`i`. It does this in both the index-only and multiple-substitutions options.
Then it creates the pod.
When the controller notices that a pod has completed or is running or failed,
it updates the scoreboard.
When all entries in the scoreboard are `complete`, then the job is complete.
#### Downward API Changes
The downward API is changed to support extracting specific key names into a
single environment variable. So, the following would be supported:
# MetadataPolicy and its use in choosing the scheduler in a multi-scheduler system
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/metadata-policy.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/metadata-policy.md)
## Introduction
This document describes a new API resource, `MetadataPolicy`, that configures an
admission controller to take one or more actions based on an object's metadata.
Initially the metadata fields that the predicates can examine are labels and
annotations, and the actions are to add one or more labels and/or annotations,
or to reject creation/update of the object. In the future other actions might be
supported, such as applying an initializer.
The first use of `MetadataPolicy` will be to decide which scheduler should
schedule a pod in a [multi-scheduler](../proposals/multiple-schedulers.md)
Kubernetes system. In particular, the policy will add the scheduler name
annotation to a pod based on an annotation that is already on the pod that
indicates the QoS of the pod. (That annotation was presumably set by a simpler
admission controller that uses code, rather than configuration, to map the
resource requests and limits of a pod to QoS, and attaches the corresponding
annotation.)
We anticipate a number of other uses for `MetadataPolicy`, such as defaulting
for labels and annotations, prohibiting/requiring particular labels or
annotations, or choosing a scheduling policy within a scheduler. We do not
discuss them in this doc.
## API
```go
// MetadataPolicySpec defines the configuration of the MetadataPolicy API resource.
// Every rule is applied, in an unspecified order, but if the action for any rule
// that matches is to reject the object, then the object is rejected without being mutated.
typeMetadataPolicySpecstruct{
Rules[]MetadataPolicyRule`json:"rules,omitempty"`
}
// If the PolicyPredicate is met, then the PolicyAction is applied.
// Example rules:
// reject object if label with key X is present (i.e. require X)
// reject object if label with key X is not present (i.e. forbid X)
// add label X=Y if label with key X is not present (i.e. default X)
// add annotation A=B if object has annotation C=D or E=F
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/monitoring_architecture.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/monitoring_architecture.md)
## Executive Summary
Monitoring is split into two pipelines:
* A **core metrics pipeline** consisting of Kubelet, a resource estimator, a slimmed-down
Heapster called metrics-server, and the API server serving the master metrics API. These
metrics are used by core system components, such as scheduling logic (e.g. scheduler and
horizontal pod autoscaling based on system metrics) and simple out-of-the-box UI components
(e.g. `kubectl top`). This pipeline is not intended for integration with third-party
monitoring systems.
* A **monitoring pipeline** used for collecting various metrics from the system and exposing
them to end-users, as well as to the Horizontal Pod Autoscaler (for custom metrics) and Infrastore
via adapters. Users can choose from many monitoring system vendors, or run none at all. In
open-source, Kubernetes will not ship with a monitoring pipeline, but third-party options
will be easy to install. We expect that such pipelines will typically consist of a per-node
agent and a cluster-level aggregator.
The architecture is illustrated in the diagram in the Appendix of this doc.
## Introduction and Objectives
This document proposes a high-level monitoring architecture for Kubernetes. It covers
a subset of the issues mentioned in the “Kubernetes Monitoring Architecture” doc,
specifically focusing on an architecture (components and their interactions) that
hopefully meets the numerous requirements. We do not specify any particular timeframe
for implementing this architecture, nor any particular roadmap for getting there.
### Terminology
There are two types of metrics, system metrics and service metrics. System metrics are
generic metrics that are generally available from every entity that is monitored (e.g.
usage of CPU and memory by container and node). Service metrics are explicitly defined
in application code and exported (e.g. number of 500s served by the API server). Both
system metrics and service metrics can originate from users’ containers or from system
infrastructure components (master components like the API server, addon pods running on
the master, and addon pods running on user nodes).
We divide system metrics into
**core metrics*, which are metrics that Kubernetes understands and uses for operation
of its internal components and core utilities -- for example, metrics used for scheduling
(including the inputs to the algorithms for resource estimation, initial resources/vertical
autoscaling, cluster autoscaling, and horizontal pod autoscaling excluding custom metrics),
the kube dashboard, and “kubectl top.” As of now this would consist of cpu cumulative usage,
memory instantaneous usage, disk usage of pods, disk usage of containers
**non-core metrics*, which are not interpreted by Kubernetes; we generally assume they
include the core metrics (though not necessarily in a format Kubernetes understands) plus
additional metrics.
Service metrics can be divided into those produced by Kubernetes infrastructure components
(and thus useful for operation of the Kubernetes cluster) and those produced by user applications.
Service metrics used as input to horizontal pod autoscaling are sometimes called custom metrics.
Of course horizontal pod autoscaling also uses core metrics.
We consider logging to be separate from monitoring, so logging is outside the scope of
this doc.
### Requirements
The monitoring architecture should
* include a solution that is part of core Kubernetes and
* makes core system metrics about nodes, pods, and containers available via a standard
master API (today the master metrics API), such that core Kubernetes features do not
depend on non-core components
* requires Kubelet to only export a limited set of metrics, namely those required for
core Kubernetes components to correctly operate (this is related to #18770)
* can scale up to at least 5000 nodes
* is small enough that we can require that all of its components be running in all deployment
configurations
* include an out-of-the-box solution that can serve historical data, e.g. to support Initial
Resources and vertical pod autoscaling as well as cluster analytics queries, that depends
only on core Kubernetes
* allow for third-party monitoring solutions that are not part of core Kubernetes and can
be integrated with components like Horizontal Pod Autoscaler that require service metrics
## Architecture
We divide our description of the long-term architecture plan into the core metrics pipeline
and the monitoring pipeline. For each, it is necessary to think about how to deal with each
type of metric (core metrics, non-core metrics, and service metrics) from both the master
and minions.
### Core metrics pipeline
The core metrics pipeline collects a set of core system metrics. There are two sources for
these metrics
* Kubelet, providing per-node/pod/container usage information (the current cAdvisor that
is part of Kubelet will be slimmed down to provide only core system metrics)
* a resource estimator that runs as a DaemonSet and turns raw usage values scraped from
Kubelet into resource estimates (values used by scheduler for a more advanced usage-based
scheduler)
These sources are scraped by a component we call *metrics-server* which is like a slimmed-down
version of today's Heapster. metrics-server stores locally only latest values and has no sinks.
metrics-server exposes the master metrics API. (The configuration described here is similar
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/namespaces.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/namespaces.md)
## Abstract
A Namespace is a mechanism to partition resources created by users into
a logically named group.
## Motivation
A single cluster should be able to satisfy the needs of multiple user
communities.
Each user community wants to be able to work in isolation from other
| WATCH | GET | /api/{version}/watch/namespaces | Watch all namespaces |
This specification reserves the name *finalize* as a sub-resource to namespace.
As a consequence, it is invalid to have a *resourceType* managed by a namespace whose kind is *finalize*.
To interact with content associated with a Namespace:
| Action | HTTP Verb | Path | Description |
| ---- | ---- | ---- | ---- |
| CREATE | POST | /api/{version}/namespaces/{namespace}/{resourceType}/ | Create instance of {resourceType} in namespace {namespace} |
| GET | GET | /api/{version}/namespaces/{namespace}/{resourceType}/{name} | Get instance of {resourceType} in namespace {namespace} with {name} |
| UPDATE | PUT | /api/{version}/namespaces/{namespace}/{resourceType}/{name} | Update instance of {resourceType} in namespace {namespace} with {name} |
| DELETE | DELETE | /api/{version}/namespaces/{namespace}/{resourceType}/{name} | Delete instance of {resourceType} in namespace {namespace} with {name} |
| LIST | GET | /api/{version}/namespaces/{namespace}/{resourceType} | List instances of {resourceType} in namespace {namespace} |
| WATCH | GET | /api/{version}/watch/namespaces/{namespace}/{resourceType} | Watch for changes to a {resourceType} in namespace {namespace} |
| WATCH | GET | /api/{version}/watch/{resourceType} | Watch for changes to a {resourceType} across all namespaces |
| LIST | GET | /api/{version}/list/{resourceType} | List instances of {resourceType} across all namespaces |
The API server verifies the *Namespace* on resource creation matches the
*{namespace}* on the path.
The API server will associate a resource with a *Namespace* if not populated by
the end-user based on the *Namespace* context of the incoming request. If the
*Namespace* of the resource being created, or updated does not match the
*Namespace* on the request, then the API server will reject the request.
### Storage
A namespace provides a unique identifier space and therefore must be in the
storage path of a resource.
In etcd, we want to continue to still support efficient WATCH across namespaces.
Resources that persist content in etcd will have storage paths as follows:
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/networking.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/networking.md)
There are 4 distinct networking problems to solve:
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/nodeaffinity.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/nodeaffinity.md)
## Introduction
This document proposes a new label selector representation, called
`NodeSelector`, that is similar in many ways to `LabelSelector`, but is a bit
more flexible and is intended to be used only for selecting nodes.
In addition, we propose to replace the `map[string]string` in `PodSpec` that the
scheduler currently uses as part of restricting the set of nodes onto which a
pod is eligible to schedule, with a field of type `Affinity` that contains one
or more affinity specifications. In this document we discuss `NodeAffinity`,
which contains one or more of the following:
* a field called `RequiredDuringSchedulingRequiredDuringExecution` that will be
represented by a `NodeSelector`, and thus generalizes the scheduling behavior of
the current `map[string]string` but still serves the purpose of restricting
the set of nodes onto which the pod can schedule. In addition, unlike the
behavior of the current `map[string]string`, when it becomes violated the system
will try to eventually evict the pod from its node.
* a field called `RequiredDuringSchedulingIgnoredDuringExecution` which is
identical to `RequiredDuringSchedulingRequiredDuringExecution` except that the
system may or may not try to eventually evict the pod from its node.
* a field called `PreferredDuringSchedulingIgnoredDuringExecution` that
specifies which nodes are preferred for scheduling among those that meet all
scheduling requirements.
(In practice, as discussed later, we will actually *add* the `Affinity` field
rather than replacing `map[string]string`, due to backward compatibility
requirements.)
The affinity specifications described above allow a pod to request various
properties that are inherent to nodes, for example "run this pod on a node with
an Intel CPU" or, in a multi-zone cluster, "run this pod on a node in zone Z."
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/persistent-storage.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/persistent-storage.md)
This document proposes a model for managing persistent, cluster-scoped storage
for applications requiring long lived data.
### Abstract
Two new API kinds:
A `PersistentVolume` (PV) is a storage resource provisioned by an administrator.
It is analogous to a node. See [Persistent Volume Guide](../user-guide/persistent-volumes/)
for how to use it.
A `PersistentVolumeClaim` (PVC) is a user's request for a persistent volume to
use in a pod. It is analogous to a pod.
One new system component:
`PersistentVolumeClaimBinder` is a singleton running in master that watches all
PersistentVolumeClaims in the system and binds them to the closest matching
available PersistentVolume. The volume manager watches the API for newly created
volumes to manage.
One new volume:
`PersistentVolumeClaimVolumeSource` references the user's PVC in the same
namespace. This volume finds the bound PV and mounts that volume for the pod. A
`PersistentVolumeClaimVolumeSource` is, essentially, a wrapper around another
type of volume that is owned by someone else (the system).
Kubernetes makes no guarantees at runtime that the underlying storage exists or
is available. High availability is left to the storage provider.
### Goals
* Allow administrators to describe available storage.
* Allow pod authors to discover and request persistent volumes to use with pods.
* Enforce security through access control lists and securing storage to the same
namespace as the pod volume.
* Enforce quotas through admission control.
* Enforce scheduler rules by resource counting.
* Ensure developers can rely on storage being available without being closely
bound to a particular disk, server, network, or storage device.
#### Describe available storage
Cluster administrators use the API to manage *PersistentVolumes*. A custom store
`NewPersistentVolumeOrderedIndex` will index volumes by access modes and sort by
storage capacity. The `PersistentVolumeClaimBinder` watches for new claims for
storage and binds them to an available volume by matching the volume's
characteristics (AccessModes and storage size) to the user's request.
PVs are system objects and, thus, have no namespace.
Many means of dynamic provisioning will be eventually be implemented for various
storage types.
##### PersistentVolume API
| Action | HTTP Verb | Path | Description |
| ---- | ---- | ---- | ---- |
| CREATE | POST | /api/{version}/persistentvolumes/ | Create instance of PersistentVolume |
| GET | GET | /api/{version}persistentvolumes/{name} | Get instance of PersistentVolume with {name} |
| UPDATE | PUT | /api/{version}/persistentvolumes/{name} | Update instance of PersistentVolume with {name} |
| DELETE | DELETE | /api/{version}/persistentvolumes/{name} | Delete instance of PersistentVolume with {name} |
| LIST | GET | /api/{version}/persistentvolumes | List instances of PersistentVolume |
| WATCH | GET | /api/{version}/watch/persistentvolumes | Watch for changes to a PersistentVolume |
#### Request Storage
Kubernetes users request persistent storage for their pod by creating a
```PersistentVolumeClaim```. Their request for storage is described by their
requirements for resources and mount capabilities.
Requests for volumes are bound to available volumes by the volume manager, if a
suitable match is found. Requests for resources can go unfulfilled.
| CREATE | POST | /api/{version}/namespaces/{ns}/persistentvolumeclaims/ | Create instance of PersistentVolumeClaim in namespace {ns} |
| GET | GET | /api/{version}/namespaces/{ns}/persistentvolumeclaims/{name} | Get instance of PersistentVolumeClaim in namespace {ns} with {name} |
| UPDATE | PUT | /api/{version}/namespaces/{ns}/persistentvolumeclaims/{name} | Update instance of PersistentVolumeClaim in namespace {ns} with {name} |
| DELETE | DELETE | /api/{version}/namespaces/{ns}/persistentvolumeclaims/{name} | Delete instance of PersistentVolumeClaim in namespace {ns} with {name} |
| LIST | GET | /api/{version}/namespaces/{ns}/persistentvolumeclaims | List instances of PersistentVolumeClaim in namespace {ns} |
| WATCH | GET | /api/{version}/watch/namespaces/{ns}/persistentvolumeclaims | Watch for changes to PersistentVolumeClaim in namespace {ns} |
#### Scheduling constraints
Scheduling constraints are to be handled similar to pod resource constraints.
Pods will need to be annotated or decorated with the number of resources it
requires on a node. Similarly, a node will need to list how many it has used or
available.
TBD
#### Events
The implementation of persistent storage will not require events to communicate
to the user the state of their claim. The CLI for bound claims contains a
reference to the backing persistent volume. This is always present in the API
and CLI, making an event to communicate the same unnecessary.
Events that communicate the state of a mounted volume are left to the volume
plugins.
### Example
#### Admin provisions storage
An administrator provisions storage by posting PVs to the API. Various ways to
automate this task can be scripted. Dynamic provisioning is a future feature
that can maintain levels of PVs.
```yaml
POST:
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv0001
spec:
capacity:
storage: 10
persistentDisk:
pdName: "abc123"
fsType: "ext4"
```
```console
$ kubectl get pv
NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM REASON
pv0001 map[] 10737418240 RWO Pending
```
#### Users request storage
A user requests storage by posting a PVC to the API. Their request contains the
AccessModes they wish their volume to have and the minimum size needed.
The user must be within a namespace to create PVCs.
```yaml
POST:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim-1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3
```
```console
$ kubectl get pvc
NAME LABELS STATUS VOLUME
myclaim-1 map[] pending
```
#### Matching and binding
The ```PersistentVolumeClaimBinder``` attempts to find an available volume that
most closely matches the user's request. If one exists, they are bound by
putting a reference on the PV to the PVC. Requests can go unfulfilled if a
suitable match is not found.
```console
$ kubectl get pv
NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM REASON
# Inter-pod topological affinity and anti-affinity
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/podaffinity.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/podaffinity.md)
## Introduction
NOTE: It is useful to read about [node affinity](nodeaffinity.md) first.
This document describes a proposal for specifying and implementing inter-pod
topological affinity and anti-affinity. By that we mean: rules that specify that
certain pods should be placed in the same topological domain (e.g. same node,
same rack, same zone, same power domain, etc.) as some other pods, or,
conversely, should *not* be placed in the same topological domain as some other
pods.
Here are a few example rules; we explain how to express them using the API
described in this doc later, in the section "Examples."
* Affinity
* Co-locate the pods from a particular service or Job in the same availability
zone, without specifying which zone that should be.
* Co-locate the pods from service S1 with pods from service S2 because S1 uses
S2 and thus it is useful to minimize the network latency between them.
Co-location might mean same nodes and/or same availability zone.
* Anti-affinity
* Spread the pods of a service across nodes and/or availability zones, e.g. to
reduce correlated failures.
* Give a pod "exclusive" access to a node to guarantee resource isolation --
it must never share the node with other pods.
* Don't schedule the pods of a particular service on the same nodes as pods of
another service that are known to interfere with the performance of the pods of
the first service.
For both affinity and anti-affinity, there are three variants. Two variants have
the property of requiring the affinity/anti-affinity to be satisfied for the pod
to be allowed to schedule onto a node; the difference between them is that if
the condition ceases to be met later on at runtime, for one of them the system
will try to eventually evict the pod, while for the other the system may not try
to do so. The third variant simply provides scheduling-time *hints* that the
scheduler will try to satisfy but may not be able to. These three variants are
directly analogous to the three variants of [node affinity](nodeaffinity.md).
Note that this proposal is only about *inter-pod* topological affinity and
anti-affinity. There are other forms of topological affinity and anti-affinity.
For example, you can use [node affinity](nodeaffinity.md) to require (prefer)
that a set of pods all be scheduled in some specific zone Z. Node affinity is
not capable of expressing inter-pod dependencies, and conversely the API we
describe in this document is not capable of expressing node affinity rules. For
simplicity, we will use the terms "affinity" and "anti-affinity" to mean
"inter-pod topological affinity" and "inter-pod topological anti-affinity,"
Note that this works because `"service" NotIn "S"` matches pods with no key
"service" as well as pods with key "service" and a corresponding value that is
not "S."
## Algorithm
An example algorithm a scheduler might use to implement affinity and
anti-affinity rules is as follows. There are certainly more efficient ways to
do it; this is just intended to demonstrate that the API's semantics are
implementable.
Terminology definition: We say a pod P is "feasible" on a node N if P meets all
of the scheduler predicates for scheduling P onto N. Note that this algorithm is
only concerned about scheduling time, thus it makes no distinction between
RequiredDuringExecution and IgnoredDuringExecution.
To make the algorithm slightly more readable, we use the term "HardPodAffinity"
as shorthand for "RequiredDuringSchedulingScheduling pod affinity" and
"SoftPodAffinity" as shorthand for "PreferredDuringScheduling pod affinity."
Analogously for "HardPodAntiAffinity" and "SoftPodAntiAffinity."
** TODO: Update this algorithm to take weight for SoftPod{Affinity,AntiAffinity}
into account; currently it assumes all terms have weight 1. **
```
Z = the pod you are scheduling
{N} = the set of all nodes in the system // this algorithm will reduce it to the set of all nodes feasible for Z
// Step 1a: Reduce {N} to the set of nodes satisfying Z's HardPodAffinity in the "forward" direction
X = {Z's PodSpec's HardPodAffinity}
foreach element H of {X}
P = {all pods in the system that match H.LabelSelector}
M map[string]int // topology value -> number of pods running on nodes with that topology value
foreach pod Q of {P}
L = {labels of the node on which Q is running, represented as a map from label key to label value}
M[L[H.TopologyKey]]++
{N} = {N} intersect {all nodes of N with label [key=H.TopologyKey, value=any K such that M[K]>0]}
// Step 1b: Further reduce {N} to the set of nodes also satisfying Z's HardPodAntiAffinity
// This step is identical to Step 1a except the M[K] > 0 comparison becomes M[K] == 0
X = {Z's PodSpec's HardPodAntiAffinity}
foreach element H of {X}
P = {all pods in the system that match H.LabelSelector}
M map[string]int // topology value -> number of pods running on nodes with that topology value
foreach pod Q of {P}
L = {labels of the node on which Q is running, represented as a map from label key to label value}
M[L[H.TopologyKey]]++
{N} = {N} intersect {all nodes of N with label [key=H.TopologyKey, value=any K such that M[K]==0]}
// Step 2: Further reduce {N} by enforcing symmetry requirement for other pods' HardPodAntiAffinity
foreach node A of {N}
foreach pod B that is bound to A
if any of B's HardPodAntiAffinity are currently satisfied but would be violated if Z runs on A, then remove A from {N}
// At this point, all node in {N} are feasible for Z.
// Step 3a: Soft version of Step 1a
Y map[string]int // node -> number of Z's soft affinity/anti-affinity preferences satisfied by that node
Initialize the keys of Y to all of the nodes in {N}, and the values to 0
X = {Z's PodSpec's SoftPodAffinity}
Repeat Step 1a except replace the last line with "foreach node W of {N} having label [key=H.TopologyKey, value=any K such that M[K]>0], Y[W]++"
// Step 3b: Soft version of Step 1b
X = {Z's PodSpec's SoftPodAntiAffinity}
Repeat Step 1b except replace the last line with "foreach node W of {N} not having label [key=H.TopologyKey, value=any K such that M[K]>0], Y[W]++"
// Step 4: Symmetric soft, plus treat forward direction of hard affinity as a soft
foreach node A of {N}
foreach pod B that is bound to A
increment Y[A] by the number of B's SoftPodAffinity, SoftPodAntiAffinity, and HardPodAffinity that are satisfied if Z runs on A but are not satisfied if Z does not run on A
// We're done. {N} contains all of the nodes that satisfy the affinity/anti-affinity rules, and Y is
// a map whose keys are the elements of {N} and whose values are how "good" of a choice N is for Z with
// respect to the explicit and implicit affinity/anti-affinity rules (larger number is better).
```
## Special considerations for RequiredDuringScheduling anti-affinity
In this section we discuss three issues with RequiredDuringScheduling
anti-affinity: Denial of Service (DoS), co-existing with daemons, and
determining which pod(s) to kill. See issue [#18265](https://github.com/kubernetes/kubernetes/issues/18265)
for additional discussion of these topics.
### Denial of Service
Without proper safeguards, a pod using RequiredDuringScheduling anti-affinity
can intentionally or unintentionally cause various problems for other pods, due
to the symmetry property of anti-affinity.
The most notable danger is the ability for a pod that arrives first to some
topology domain, to block all other pods from scheduling there by stating a
conflict with all other pods. The standard approach to preventing resource
hogging is quota, but simple resource quota cannot prevent this scenario because
the pod may request very little resources. Addressing this using quota requires
a quota scheme that charges based on "opportunity cost" rather than based simply
on requested resources. For example, when handling a pod that expresses
RequiredDuringScheduling anti-affinity for all pods using a "node" `TopologyKey`
(i.e. exclusive access to a node), it could charge for the resources of the
average or largest node in the cluster. Likewise if a pod expresses
RequiredDuringScheduling anti-affinity for all pods using a "cluster"
`TopologyKey`, it could charge for the resources of the entire cluster. If node
affinity is used to constrain the pod to a particular topology domain, then the
admission-time quota charging should take that into account (e.g. not charge for
the average/largest machine if the PodSpec constrains the pod to a specific
machine with a known size; instead charge for the size of the actual machine
that the pod was constrained to). In all cases once the pod is scheduled, the
quota charge should be adjusted down to the actual amount of resources allocated
(e.g. the size of the actual machine that was assigned, not the
average/largest). If a cluster administrator wants to overcommit quota, for
example to allow more than N pods across all users to request exclusive node
access in a cluster with N nodes, then a priority/preemption scheme should be
added so that the most important pods run when resource demand exceeds supply.
An alternative approach, which is a bit of a blunt hammer, is to use a
capability mechanism to restrict use of RequiredDuringScheduling anti-affinity
to trusted users. A more complex capability mechanism might only restrict it
when using a non-"node" TopologyKey.
Our initial implementation will use a variant of the capability approach, which
requires no configuration: we will simply reject ALL requests, regardless of
user, that specify "all namespaces" with non-"node" TopologyKey for
RequiredDuringScheduling anti-affinity. This allows the "exclusive node" use
case while prohibiting the more dangerous ones.
A weaker variant of the problem described in the previous paragraph is a pod's
ability to use anti-affinity to degrade the scheduling quality of another pod,
but not completely block it from scheduling. For example, a set of pods S1 could
use node affinity to request to schedule onto a set of nodes that some other set
of pods S2 prefers to schedule onto. If the pods in S1 have
RequiredDuringScheduling or even PreferredDuringScheduling pod anti-affinity for
S2, then due to the symmetry property of anti-affinity, they can prevent the
pods in S2 from scheduling onto their preferred nodes if they arrive first (for
sure in the RequiredDuringScheduling case, and with some probability that
depends on the weighting scheme for the PreferredDuringScheduling case). A very
sophisticated priority and/or quota scheme could mitigate this, or alternatively
we could eliminate the symmetry property of the implementation of
PreferredDuringScheduling anti-affinity. Then only RequiredDuringScheduling
anti-affinity could affect scheduling quality of another pod, and as we
described in the previous paragraph, such pods could be charged quota for the
full topology domain, thereby reducing the potential for abuse.
We won't try to address this issue in our initial implementation; we can
consider one of the approaches mentioned above if it turns out to be a problem
in practice.
### Co-existing with daemons
A cluster administrator may wish to allow pods that express anti-affinity
against all pods, to nonetheless co-exist with system daemon pods, such as those
run by DaemonSet. In principle, we would like the specification for
RequiredDuringScheduling inter-pod anti-affinity to allow "toleration" of one or
more other pods (see [#18263](https://github.com/kubernetes/kubernetes/issues/18263)
for a more detailed explanation of the toleration concept).
There are at least two ways to accomplish this:
* Scheduler special-cases the namespace(s) where daemons live, in the
sense that it ignores pods in those namespaces when it is
determining feasibility for pods with anti-affinity. The name(s) of
the special namespace(s) could be a scheduler configuration
parameter, and default to `kube-system`. We could allow
multiple namespaces to be specified if we want cluster admins to be
able to give their own daemons this special power (they would add
their namespace to the list in the scheduler configuration). And of
course this would be symmetric, so daemons could schedule onto a node
that is already running a pod with anti-affinity.
* We could add an explicit "toleration" concept/field to allow the
user to specify namespaces that are excluded when they use
RequiredDuringScheduling anti-affinity, and use an admission
controller/defaulter to ensure these namespaces are always listed.
Our initial implementation will use the first approach.
### Determining which pod(s) to kill (for RequiredDuringSchedulingRequiredDuringExecution)
Because anti-affinity is symmetric, in the case of
RequiredDuringSchedulingRequiredDuringExecution anti-affinity, the system must
determine which pod(s) to kill when a pod's labels are updated in such as way as
to cause them to conflict with one or more other pods'
RequiredDuringSchedulingRequiredDuringExecution anti-affinity rules. In the
absence of a priority/preemption scheme, our rule will be that the pod with the
anti-affinity rule that becomes violated should be the one killed. A pod should
only specify constraints that apply to namespaces it trusts to not do malicious
things. Once we have priority/preemption, we can change the rule to say that the
lowest-priority pod(s) are killed until all
RequiredDuringSchedulingRequiredDuringExecution anti-affinity is satisfied.
## Special considerations for RequiredDuringScheduling affinity
The DoS potential of RequiredDuringScheduling *anti-affinity* stemmed from its
symmetry: if a pod P requests anti-affinity, P cannot schedule onto a node with
conflicting pods, and pods that conflict with P cannot schedule onto the node
one P has been scheduled there. The design we have described says that the
symmetry property for RequiredDuringScheduling *affinity* is weaker: if a pod P
says it can only schedule onto nodes running pod Q, this does not mean Q can
only run on a node that is running P, but the scheduler will try to schedule Q
onto a node that is running P (i.e. treats the reverse direction as preferred).
This raises the same scheduling quality concern as we mentioned at the end of
the Denial of Service section above, and can be addressed in similar ways.
The nature of affinity (as opposed to anti-affinity) means that there is no
issue of determining which pod(s) to kill when a pod's labels change: it is
obviously the pod with the affinity rule that becomes violated that must be
killed. (Killing a pod never "fixes" violation of an affinity rule; it can only
"fix" violation an anti-affinity rule.) However, affinity does have a different
question related to killing: how long should the system wait before declaring
that RequiredDuringSchedulingRequiredDuringExecution affinity is no longer met
at runtime? For example, if a pod P has such an affinity for a pod Q and pod Q
is temporarily killed so that it can be updated to a new binary version, should
that trigger killing of P? More generally, how long should the system wait
before declaring that P's affinity is violated? (Of course affinity is expressed
in terms of label selectors, not for a specific pod, but the scenario is easier
to describe using a concrete pod.) This is closely related to the concept of
forgiveness (see issue [#1574](https://github.com/kubernetes/kubernetes/issues/1574)).
In theory we could make this time duration be configurable by the user on a per-pod
basis, but for the first version of this feature we will make it a configurable
property of whichever component does the killing and that applies across all pods
using the feature. Making it configurable by the user would require a nontrivial
change to the API syntax (since the field would only apply to
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/principles.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/principles.md)
Principles to follow when extending Kubernetes.
## API
See also the [API conventions](../devel/api-conventions.md).
* All APIs should be declarative.
* API objects should be complementary and composable, not opaque wrappers.
* The control plane should be transparent -- there are no hidden internal APIs.
* The cost of API operations should be proportional to the number of objects
intentionally operated upon. Therefore, common filtered lookups must be indexed.
Beware of patterns of multiple API calls that would incur quadratic behavior.
* Object status must be 100% reconstructable by observation. Any history kept
must be just an optimization and not required for correct operation.
* Cluster-wide invariants are difficult to enforce correctly. Try not to add
them. If you must have them, don't enforce them atomically in master components,
that is contention-prone and doesn't provide a recovery path in the case of a
bug allowing the invariant to be violated. Instead, provide a series of checks
to reduce the probability of a violation, and make every component involved able
to recover from an invariant violation.
* Low-level APIs should be designed for control by higher-level systems.
Higher-level APIs should be intent-oriented (think SLOs) rather than
implementation-oriented (think control knobs).
## Control logic
* Functionality must be *level-based*, meaning the system must operate correctly
given the desired state and the current/observed state, regardless of how many
intermediate state updates may have been missed. Edge-triggered behavior must be
just an optimization.
* Assume an open world: continually verify assumptions and gracefully adapt to
external events and/or actors. Example: we allow users to kill pods under
control of a replication controller; it just replaces them.
* Do not define comprehensive state machines for objects with behaviors
associated with state transitions and/or "assumed" states that cannot be
ascertained by observation.
* Don't assume a component's decisions will not be overridden or rejected, nor
for the component to always understand why. For example, etcd may reject writes.
Kubelet may reject pods. The scheduler may not be able to schedule pods. Retry,
but back off and/or make alternative decisions.
* Components should be self-healing. For example, if you must keep some state
(e.g., cache) the content needs to be periodically refreshed, so that if an item
does get erroneously stored or a deletion event is missed etc, it will be soon
fixed, ideally on timescales that are shorter than what will attract attention
from humans.
* Component behavior should degrade gracefully. Prioritize actions so that the
most important activities can continue to function even when overloaded and/or
in states of partial failure.
## Architecture
* Only the apiserver should communicate with etcd/store, and not other
components (scheduler, kubelet, etc.).
* Compromising a single node shouldn't compromise the cluster.
* Components should continue to do what they were last told in the absence of
new instructions (e.g., due to network partition or component outage).
* All components should keep all relevant state in memory all the time. The
apiserver should write through to etcd/store, other components should write
through to the apiserver, and they should watch for updates made by other
clients.
* Watch is preferred over polling.
## Extensibility
TODO: pluggability
## Bootstrapping
*[Self-hosting](http://issue.k8s.io/246) of all components is a goal.
* Minimize the number of dependencies, particularly those required for
steady-state operation.
* Stratify the dependencies that remain via principled layering.
* Break any circular dependencies by converting hard dependencies to soft
dependencies.
* Also accept that data from other components from another source, such as
local files, which can then be manually populated at bootstrap time and then
continuously updated once those other components are available.
* State should be rediscoverable and/or reconstructable.
* Make it easy to run temporary, bootstrap instances of all components in
order to create the runtime state needed to run the components in the steady
state; use a lock (master election for distributed components, file lock for
local components like Kubelet) to coordinate handoff. We call this technique
"pivoting".
* Have a solution to restart dead components. For distributed components,
replication works well. For local components such as Kubelet, a process manager
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-qos.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-qos.md)
*This document presents the design of resource quality of service for containers in Kubernetes, and describes use cases and implementation details.*
## Introduction
This document describes the way Kubernetes provides different levels of Quality of Service to pods depending on what they *request*.
Pods that need to stay up reliably can request guaranteed resources, while pods with less stringent requirements can use resources with weaker or no guarantee.
Specifically, for each resource, containers specify a request, which is the amount of that resource that the system will guarantee to the container, and a limit which is the maximum amount that the system will allow the container to use.
The system computes pod level requests and limits by summing up per-resource requests and limits across all containers.
When request == limit, the resources are guaranteed, and when request < limit, the pod is guaranteed the request but can opportunistically scavenge the difference between request and limit if they are not being used by other containers.
This allows Kubernetes to oversubscribe nodes, which increases utilization, while at the same time maintaining resource guarantees for the containers that need guarantees.
Borg increased utilization by about 20% when it started allowing use of such non-guaranteed resources, and we hope to see similar improvements in Kubernetes.
## Requests and Limits
For each resource, containers can specify a resource request and limit, `0 <= request <= `[`Node Allocatable`](../proposals/node-allocatable.md) & `request <= limit <= Infinity`.
If a pod is successfully scheduled, the container is guaranteed the amount of resources requested.
Scheduling is based on `requests` and not `limits`.
The pods and its containers will not be allowed to exceed the specified limit.
How the request and limit are enforced depends on whether the resource is [compressible or incompressible](resources.md).
### Compressible Resource Guarantees
- For now, we are only supporting CPU.
- Pods are guaranteed to get the amount of CPU they request, they may or may not get additional CPU time (depending on the other jobs running). This isn't fully guaranteed today because cpu isolation is at the container level. Pod level cgroups will be introduced soon to achieve this goal.
- Excess CPU resources will be distributed based on the amount of CPU requested. For example, suppose container A requests for 600 milli CPUs, and container B requests for 300 milli CPUs. Suppose that both containers are trying to use as much CPU as they can. Then the extra 10 milli CPUs will be distributed to A and B in a 2:1 ratio (implementation discussed in later sections).
- Pods will be throttled if they exceed their limit. If limit is unspecified, then the pods can use excess CPU when available.
### Incompressible Resource Guarantees
- For now, we are only supporting memory.
- Pods will get the amount of memory they request, if they exceed their memory request, they could be killed (if some other pod needs memory), but if pods consume less memory than requested, they will not be killed (except in cases where system tasks or daemons need more memory).
- When Pods use more memory than their limit, a process that is using the most amount of memory, inside one of the pod's containers, will be killed by the kernel.
### Admission/Scheduling Policy
- Pods will be admitted by Kubelet & scheduled by the scheduler based on the sum of requests of its containers. The scheduler & kubelet will ensure that sum of requests of all containers is within the node's [allocatable](../proposals/node-allocatable.md) capacity (for both memory and CPU).
## QoS Classes
In an overcommitted system (where sum of limits > machine capacity) containers might eventually have to be killed, for example if the system runs out of CPU or memory resources. Ideally, we should kill containers that are less important. For each resource, we divide containers into 3 QoS classes: *Guaranteed*, *Burstable*, and *Best-Effort*, in decreasing order of priority.
The relationship between "Requests and Limits" and "QoS Classes" is subtle. Theoretically, the policy of classifying pods into QoS classes is orthogonal to the requests and limits specified for the container. Hypothetically, users could use an (currently unplanned) API to specify whether a pod is guaranteed or best-effort. However, in the current design, the policy of classifying pods into QoS classes is intimately tied to "Requests and Limits" - in fact, QoS classes are used to implement some of the memory guarantees described in the previous section.
Pods can be of one of 3 different classes:
- If `limits` and optionally `requests` (not equal to `0`) are set for all resources across all containers and they are *equal*, then the pod is classified as **Guaranteed**.
Examples:
```yaml
containers:
name:foo
resources:
limits:
cpu:10m
memory:1Gi
name:bar
resources:
limits:
cpu:100m
memory:100Mi
```
```yaml
containers:
name:foo
resources:
limits:
cpu:10m
memory:1Gi
requests:
cpu:10m
memory:1Gi
name:bar
resources:
limits:
cpu:100m
memory:100Mi
requests:
cpu:100m
memory:100Mi
```
- If `requests` and optionally `limits` are set (not equal to `0`) for one or more resources across one or more containers, and they are *not equal*, then the pod is classified as **Burstable**.
When `limits` are not specified, they default to the node capacity.
Examples:
Container `bar` has not resources specified.
```yaml
containers:
name:foo
resources:
limits:
cpu:10m
memory:1Gi
requests:
cpu:10m
memory:1Gi
name:bar
```
Container `foo` and `bar` have limits set for different resources.
```yaml
containers:
name:foo
resources:
limits:
memory:1Gi
name:bar
resources:
limits:
cpu:100m
```
Container `foo` has no limits set, and `bar` has neither requests nor limits specified.
```yaml
containers:
name:foo
resources:
requests:
cpu:10m
memory:1Gi
name:bar
```
- If `requests` and `limits` are not set for all of the resources, across all containers, then the pod is classified as **Best-Effort**.
Examples:
```yaml
containers:
name:foo
resources:
name:bar
resources:
```
Pods will not be killed if CPU guarantees cannot be met (for example if system tasks or daemons take up lots of CPU), they will be temporarily throttled.
Memory is an incompressible resource and so let's discuss the semantics of memory management a bit.
-*Best-Effort* pods will be treated as lowest priority. Processes in these pods are the first to get killed if the system runs out of memory.
These containers can use any amount of free memory in the node though.
-*Guaranteed* pods are considered top-priority and are guaranteed to not be killed until they exceed their limits, or if the system is under memory pressure and there are no lower priority containers that can be evicted.
-*Burstable* pods have some form of minimal resource guarantee, but can use more resources when available.
Under system memory pressure, these containers are more likely to be killed once they exceed their requests and no *Best-Effort* pods exist.
### OOM Score configuration at the Nodes
Pod OOM score configuration
- Note that the OOM score of a process is 10 times the % of memory the process consumes, adjusted by OOM_SCORE_ADJ, barring exceptions (e.g. process is launched by root). Processes with higher OOM scores are killed.
- The base OOM score is between 0 and 1000, so if process A’s OOM_SCORE_ADJ - process B’s OOM_SCORE_ADJ is over a 1000, then process A will always be OOM killed before B.
- The final OOM score of a process is also between 0 and 1000
*Best-effort*
- Set OOM_SCORE_ADJ: 1000
- So processes in best-effort containers will have an OOM_SCORE of 1000
*Guaranteed*
- Set OOM_SCORE_ADJ: -998
- So processes in guaranteed containers will have an OOM_SCORE of 0 or 1
*Burstable*
- If total memory request > 99.8% of available memory, OOM_SCORE_ADJ: 2
- Otherwise, set OOM_SCORE_ADJ to 1000 - 10 * (% of memory requested)
- This ensures that the OOM_SCORE of burstable pod is > 1
- If memory request is `0`, OOM_SCORE_ADJ is set to `999`.
- So burstable pods will be killed if they conflict with guaranteed pods
- If a burstable pod uses less memory than requested, its OOM_SCORE < 1000
- So best-effort pods will be killed if they conflict with burstable pods using less than requested memory
- If a process in burstable pod's container uses more memory than what the container had requested, its OOM_SCORE will be 1000, if not its OOM_SCORE will be < 1000
- Assuming that a container typically has a single big process, if a burstable pod's container that uses more memory than requested conflicts with another burstable pod's container using less memory than requested, the former will be killed
- If burstable pod's containers with multiple processes conflict, then the formula for OOM scores is a heuristic, it will not ensure "Request and Limit" guarantees.
*Pod infra containers* or *Special Pod init process*
- OOM_SCORE_ADJ: -998
*Kubelet, Docker*
- OOM_SCORE_ADJ: -999 (won’t be OOM killed)
- Hack, because these critical tasks might die if they conflict with guaranteed containers. In the future, we should place all user-pods into a separate cgroup, and set a limit on the memory they can consume.
## Known issues and possible improvements
The above implementation provides for basic oversubscription with protection, but there are a few known limitations.
#### Support for Swap
- The current QoS policy assumes that swap is disabled. If swap is enabled, then resource guarantees (for pods that specify resource requirements) will not hold. For example, suppose 2 guaranteed pods have reached their memory limit. They can continue allocating memory by utilizing disk space. Eventually, if there isn’t enough swap space, processes in the pods might get killed. The node must take into account swap space explicitly for providing deterministic isolation behavior.
## Alternative QoS Class Policy
An alternative is to have user-specified numerical priorities that guide Kubelet on which tasks to kill (if the node runs out of memory, lower priority tasks will be killed).
A strict hierarchy of user-specified numerical priorities is not desirable because:
1. Achieved behavior would be emergent based on how users assigned priorities to their pods. No particular SLO could be delivered by the system, and usage would be subject to gaming if not restricted administratively
2. Changes to desired priority bands would require changes to all user pod configurations.
**Note: this is a design doc, which describes features that have not been
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resources.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resources.md)
completely implemented. User documentation of the current state is
[here](../user-guide/compute-resources.md). The tracking issue for
implementation of this model is [#168](http://issue.k8s.io/168). Currently, both
limits and requests of memory and cpu on containers (not pods) are supported.
"memory" is in bytes and "cpu" is in milli-cores.**
# The Kubernetes resource model
To do good pod placement, Kubernetes needs to know how big pods are, as well as
the sizes of the nodes onto which they are being placed. The definition of "how
big" is given by the Kubernetes resource model — the subject of this
document.
The resource model aims to be:
* simple, for common cases;
* extensible, to accommodate future growth;
* regular, with few special cases; and
* precise, to avoid misunderstandings and promote pod portability.
## The resource model
A Kubernetes _resource_ is something that can be requested by, allocated to, or
consumed by a pod or container. Examples include memory (RAM), CPU, disk-time,
and network bandwidth.
Once resources on a node have been allocated to one pod, they should not be
allocated to another until that pod is removed or exits. This means that
Kubernetes schedulers should ensure that the sum of the resources allocated
(requested and granted) to its pods never exceeds the usable capacity of the
node. Testing whether a pod will fit on a node is called _feasibility checking_.
Note that the resource model currently prohibits over-committing resources; we
will want to relax that restriction later.
### Resource types
All resources have a _type_ that is identified by their _typename_ (a string,
e.g., "memory"). Several resource types are predefined by Kubernetes (a full
list is below), although only two will be supported at first: CPU and memory.
Users and system administrators can define their own resource types if they wish
(e.g., Hadoop slots).
A fully-qualified resource typename is constructed from a DNS-style _subdomain_,
followed by a slash `/`, followed by a name.
* The subdomain must conform to [RFC 1123](http://www.ietf.org/rfc/rfc1123.txt)
(e.g., `kubernetes.io`, `example.com`).
* The name must be not more than 63 characters, consisting of upper- or
lower-case alphanumeric characters, with the `-`, `_`, and `.` characters
allowed anywhere except the first or last character.
* As a shorthand, any resource typename that does not start with a subdomain and
a slash will automatically be prefixed with the built-in Kubernetes _namespace_,
`kubernetes.io/` in order to fully-qualify it. This namespace is reserved for
code in the open source Kubernetes repository; as a result, all user typenames
MUST be fully qualified, and cannot be created in this namespace.
Some example typenames include `memory` (which will be fully-qualified as
`kubernetes.io/memory`), and `example.com/Shiny_New-Resource.Type`.
For future reference, note that some resources, such as CPU and network
bandwidth, are _compressible_, which means that their usage can potentially be
throttled in a relatively benign manner. All other resources are
_incompressible_, which means that any attempt to throttle them is likely to
cause grief. This distinction will be important if a Kubernetes implementation
supports over-committing of resources.
### Resource quantities
Initially, all Kubernetes resource types are _quantitative_, and have an
associated _unit_ for quantities of the associated resource (e.g., bytes for
memory, bytes per seconds for bandwidth, instances for software licences). The
units will always be a resource type's natural base units (e.g., bytes, not MB),
to avoid confusion between binary and decimal multipliers and the underlying
unit multiplier (e.g., is memory measured in MiB, MB, or GB?).
Resource quantities can be added and subtracted: for example, a node has a fixed
quantity of each resource type that can be allocated to pods/containers; once
such an allocation has been made, the allocated resources cannot be made
available to other pods/containers without over-committing the resources.
To make life easier for people, quantities can be represented externally as
unadorned integers, or as fixed-point integers with one of these SI suffices
(E, P, T, G, M, K, m) or their power-of-two equivalents (Ei, Pi, Ti, Gi, Mi,
Ki). For example, the following represent roughly the same value: 128974848,
"129e6", "129M" , "123Mi". Small quantities can be represented directly as
decimals (e.g., 0.3), or using milli-units (e.g., "300m").
* "Externally" means in user interfaces, reports, graphs, and in JSON or YAML
resource specifications that might be generated or read by people.
* Case is significant: "m" and "M" are not the same, so "k" is not a valid SI
suffix. There are no power-of-two equivalents for SI suffixes that represent
multipliers less than 1.
* These conventions only apply to resource quantities, not arbitrary values.
Internally (i.e., everywhere else), Kubernetes will represent resource
quantities as integers so it can avoid problems with rounding errors, and will
not use strings to represent numeric values. To achieve this, quantities that
naturally have fractional parts (e.g., CPU seconds/second) will be scaled to
integral numbers of milli-units (e.g., milli-CPUs) as soon as they are read in.
Internal APIs, data structures, and protobufs will use these scaled integer
units. Raw measurement data such as usage may still need to be tracked and
calculated using floating point values, but internally they should be rescaled
to avoid some values being in milli-units and some not.
* Note that reading in a resource quantity and writing it out again may change
the way its values are represented, and truncate precision (e.g., 1.0001 may
become 1.000), so comparison and difference operations (e.g., by an updater)
must be done on the internal representations.
* Avoiding milli-units in external representations has advantages for people
who will use Kubernetes, but runs the risk of developers forgetting to rescale
or accidentally using floating-point representations. That seems like the right
choice. We will try to reduce the risk by providing libraries that automatically
do the quantization for JSON/YAML inputs.
### Resource specifications
Both users and a number of system components, such as schedulers, (horizontal)
auto-scalers, (vertical) auto-sizers, load balancers, and worker-pool managers
need to reason about resource requirements of workloads, resource capacities of
nodes, and resource usage. Kubernetes divides specifications of *desired state*,
aka the Spec, and representations of *current state*, aka the Status. Resource
requirements and total node capacity fall into the specification category, while
resource usage, characterizations derived from usage (e.g., maximum usage,
histograms), and other resource demand signals (e.g., CPU load) clearly fall
into the status category and are discussed in the Appendix for now.
Resource requirements for a container or pod should have the following form:
```yaml
resourceRequirementSpec:[
request:[cpu:2.5,memory:"40Mi"],
limit:[cpu:4.0,memory:"99Mi"],
]
```
Where:
* _request_ [optional]: the amount of resources being requested, or that were
requested and have been allocated. Scheduler algorithms will use these
quantities to test feasibility (whether a pod will fit onto a node).
If a container (or pod) tries to use more resources than its _request_, any
associated SLOs are voided — e.g., the program it is running may be
throttled (compressible resource types), or the attempt may be denied. If
_request_ is omitted for a container, it defaults to _limit_ if that is
explicitly specified, otherwise to an implementation-defined value; this will
always be 0 for a user-defined resource type. If _request_ is omitted for a pod,
it defaults to the sum of the (explicit or implicit) _request_ values for the
containers it encloses.
* _limit_ [optional]: an upper bound or cap on the maximum amount of resources
that will be made available to a container or pod; if a container or pod uses
more resources than its _limit_, it may be terminated. The _limit_ defaults to
"unbounded"; in practice, this probably means the capacity of an enclosing
container, pod, or node, but may result in non-deterministic behavior,
especially for memory.
Total capacity for a node should have a similar structure:
```yaml
resourceCapacitySpec:[
total:[cpu:12,memory:"128Gi"]
]
```
Where:
* _total_: the total allocatable resources of a node. Initially, the resources
at a given scope will bound the resources of the sum of inner scopes.
#### Notes
* It is an error to specify the same resource type more than once in each
list.
* It is an error for the _request_ or _limit_ values for a pod to be less than
the sum of the (explicit or defaulted) values for the containers it encloses.
(We may relax this later.)
* If multiple pods are running on the same node and attempting to use more
resources than they have requested, the result is implementation-defined. For
example: unallocated or unused resources might be spread equally across
claimants, or the assignment might be weighted by the size of the original
request, or as a function of limits, or priority, or the phase of the moon,
perhaps modulated by the direction of the tide. Thus, although it's not
mandatory to provide a _request_, it's probably a good idea. (Note that the
_request_ could be filled in by an automated system that is observing actual
usage and/or historical data.)
* Internally, the Kubernetes master can decide the defaulting behavior and the
kubelet implementation may expected an absolute specification. For example, if
the master decided that "the default is unbounded" it would pass 2^64 to the
kubelet.
## Kubernetes-defined resource types
The following resource types are predefined ("reserved") by Kubernetes in the
`kubernetes.io` namespace, and so cannot be used for user-defined resources.
Note that the syntax of all resource types in the resource spec is deliberately
similar, but some resource types (e.g., CPU) may receive significantly more
support than simply tracking quantities in the schedulers and/or the Kubelet.
### Processor cycles
* Name: `cpu` (or `kubernetes.io/cpu`)
* Units: Kubernetes Compute Unit seconds/second (i.e., CPU cores normalized to
a canonical "Kubernetes CPU")
* Internal representation: milli-KCUs
* Compressible? yes
* Qualities: this is a placeholder for the kind of thing that may be supported
in the future — see [#147](http://issue.k8s.io/147)
*[future]`schedulingLatency`: as per lmctfy
*[future]`cpuConversionFactor`: property of a node: the speed of a CPU
core on the node's processor divided by the speed of the canonical Kubernetes
CPU (a floating point value; default = 1.0).
To reduce performance portability problems for pods, and to avoid worse-case
provisioning behavior, the units of CPU will be normalized to a canonical
"Kubernetes Compute Unit" (KCU, pronounced ˈko͝oko͞o), which will roughly be
equivalent to a single CPU hyperthreaded core for some recent x86 processor. The
normalization may be implementation-defined, although some reasonable defaults
will be provided in the open-source Kubernetes code.
Note that requesting 2 KCU won't guarantee that precisely 2 physical cores will
be allocated — control of aspects like this will be handled by resource
_qualities_ (a future feature).
### Memory
* Name: `memory` (or `kubernetes.io/memory`)
* Units: bytes
* Compressible? no (at least initially)
The precise meaning of what "memory" means is implementation dependent, but the
basic idea is to rely on the underlying `memcg` mechanisms, support, and
definitions.
Note that most people will want to use power-of-two suffixes (Mi, Gi) for memory
quantities rather than decimal ones: "64MiB" rather than "64MB".
## Resource metadata
A resource type may have an associated read-only ResourceType structure, that
contains metadata about the type. For example:
```yaml
resourceTypes:[
"kubernetes.io/memory":[
isCompressible:false,...
]
"kubernetes.io/cpu":[
isCompressible:true,
internalScaleExponent:3,...
]
"kubernetes.io/disk-space":[...]
]
```
Kubernetes will provide ResourceType metadata for its predefined types. If no
resource metadata can be found for a resource type, Kubernetes will assume that
it is a quantified, incompressible resource that is not specified in
milli-units, and has no default value.
The defined properties are as follows:
| field name | type | contents |
| ---------- | ---- | -------- |
| name | string, required | the typename, as a fully-qualified string (e.g., `kubernetes.io/cpu`) |
| internalScaleExponent | int, default=0 | external values are multiplied by 10 to this power for internal storage (e.g., 3 for milli-units) |
| units | string, required | format: `unit* [per unit+]` (e.g., `second`, `byte per second`). An empty unit field means "dimensionless". |
| isCompressible | bool, default=false | true if the resource type is compressible |
| defaultRequest | string, default=none | in the same format as a user-supplied value |
| _[future]_ quantization | number, default=1 | smallest granularity of allocation: requests may be rounded up to a multiple of this unit; implementation-defined unit (e.g., the page size for RAM). |
# Appendix: future extensions
The following are planned future extensions to the resource model, included here
to encourage comments.
## Usage data
Because resource usage and related metrics change continuously, need to be
tracked over time (i.e., historically), can be characterized in a variety of
ways, and are fairly voluminous, we will not include usage in core API objects,
such as [Pods](../user-guide/pods.md) and Nodes, but will provide separate APIs
for accessing and managing that data. See the Appendix for possible
representations of usage data, but the representation we'll use is TBD.
Singleton values for observed and predicted future usage will rapidly prove
inadequate, so we will support the following structure for extended usage
information:
```yaml
resourceStatus:[
usage:[cpu:<CPU-info>,memory:<memory-info>],
maxusage:[cpu:<CPU-info>,memory:<memory-info>],
predicted:[cpu:<CPU-info>,memory:<memory-info>],
]
```
where a `<CPU-info>` or `<memory-info>` structure looks like this:
```yaml
{
mean:<value># arithmetic mean
max:<value># minimum value
min:<value># maximum value
count:<value># number of data points
percentiles:[# map from %iles to values
"10":<10th-percentile-value>,
"50":<median-value>,
"99":<99th-percentile-value>,
"99.9":<99.9th-percentile-value>,
...
]
}
```
All parts of this structure are optional, although we strongly encourage
including quantities for 50, 90, 95, 99, 99.5, and 99.9 percentiles.
_[In practice, it will be important to include additional info such as the
length of the time window over which the averages are calculated, the
confidence level, and information-quality metrics such as the number of dropped
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduler_extender.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduler_extender.md)
There are three ways to add new scheduling rules (predicates and priority
functions) to Kubernetes: (1) by adding these rules to the scheduler and
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/seccomp.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/seccomp.md)
A proposal for adding **alpha** support for
[seccomp](https://github.com/seccomp/libseccomp) to Kubernetes. Seccomp is a
system call filtering facility in the Linux kernel which lets applications
define limits on system calls they may make, and what should happen when
system calls are made. Seccomp is used to reduce the attack surface available
to applications.
## Motivation
Applications use seccomp to restrict the set of system calls they can make.
Recently, container runtimes have begun adding features to allow the runtime
to interact with seccomp on behalf of the application, which eliminates the
need for applications to link against libseccomp directly. Adding support in
the Kubernetes API for describing seccomp profiles will allow administrators
greater control over the security of workloads running in Kubernetes.
Goals of this design:
1. Describe how to reference seccomp profiles in containers that use them
## Constraints and Assumptions
This design should:
* build upon previous security context work
* be container-runtime agnostic
* allow use of custom profiles
* facilitate containerized applications that link directly to libseccomp
## Use Cases
1. As an administrator, I want to be able to grant access to a seccomp profile
to a class of users
2. As a user, I want to run an application with a seccomp profile similar to
the default one provided by my container runtime
3. As a user, I want to run an application which is already libseccomp-aware
in a container, and for my application to manage interacting with seccomp
unmediated by Kubernetes
4. As a user, I want to be able to use a custom seccomp profile and use
it with my containers
### Use Case: Administrator access control
Controlling access to seccomp profiles is a cluster administrator
concern. It should be possible for an administrator to control which users
have access to which profiles.
The [pod security policy](https://github.com/kubernetes/kubernetes/pull/7893)
API extension governs the ability of users to make requests that affect pod
and container security contexts. The proposed design should deal with
required changes to control access to new functionality.
### Use Case: Seccomp profiles similar to container runtime defaults
Many users will want to use images that make assumptions about running in the
context of their chosen container runtime. Such images are likely to
frequently assume that they are running in the context of the container
runtime's default seccomp settings. Therefore, it should be possible to
express a seccomp profile similar to a container runtime's defaults.
As an example, all dockerhub 'official' images are compatible with the Docker
default seccomp profile. So, any user who wanted to run one of these images
with seccomp would want the default profile to be accessible.
### Use Case: Applications that link to libseccomp
Some applications already link to libseccomp and control seccomp directly. It
should be possible to run these applications unmodified in Kubernetes; this
implies there should be a way to disable seccomp control in Kubernetes for
certain containers, or to run with a "no-op" or "unconfined" profile.
Sometimes, applications that link to seccomp can use the default profile for a
container runtime, and restrict further on top of that. It is important to
note here that in this case, applications can only place _further_
restrictions on themselves. It is not possible to re-grant the ability of a
process to make a system call once it has been removed with seccomp.
As an example, elasticsearch manages its own seccomp filters in its code.
Currently, elasticsearch is capable of running in the context of the default
Docker profile, but if in the future, elasticsearch needed to be able to call
`ioperm` or `iopr` (both of which are disallowed in the default profile), it
should be possible to run elasticsearch by delegating the seccomp controls to
the pod.
### Use Case: Custom profiles
Different applications have different requirements for seccomp profiles; it
should be possible to specify an arbitrary seccomp profile and use it in a
container. This is more of a concern for applications which need a higher
level of privilege than what is granted by the default profile for a cluster,
since applications that want to restrict privileges further can always make
additional calls in their own code.
An example of an application that requires the use of a syscall disallowed in
the Docker default profile is Chrome, which needs `clone` to create a new user
namespace. Another example would be a program which uses `ptrace` to
implement a sandbox for user-provided code, such as
[eval.in](https://eval.in/).
## Community Work
### Container runtime support for seccomp
#### Docker / opencontainers
Docker supports the open container initiative's API for
seccomp, which is very close to the libseccomp API. It allows full
specification of seccomp filters, with arguments, operators, and actions.
Docker allows the specification of a single seccomp filter. There are
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/secrets.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/secrets.md)
A proposal for the distribution of [secrets](../user-guide/secrets.md)
(passwords, keys, etc) to the Kubelet and to containers inside Kubernetes using
a custom [volume](../user-guide/volumes.md#secrets) type. See the
[secrets example](../user-guide/secrets/) for more information.
## Motivation
Secrets are needed in containers to access internal resources like the
Kubernetes master or external resources such as git repositories, databases,
etc. Users may also want behaviors in the kubelet that depend on secret data
(credentials for image pull from a docker registry) associated with pods.
Goals of this design:
1. Describe a secret resource
2. Define the various challenges attendant to managing secrets on the node
3. Define a mechanism for consuming secrets in containers without modification
## Constraints and Assumptions
* This design does not prescribe a method for storing secrets; storage of
secrets should be pluggable to accommodate different use-cases
* Encryption of secret data and node security are orthogonal concerns
* It is assumed that node and master are secure and that compromising their
security could also compromise secrets:
* If a node is compromised, the only secrets that could potentially be
exposed should be the secrets belonging to containers scheduled onto it
* If the master is compromised, all secrets in the cluster may be exposed
* Secret rotation is an orthogonal concern, but it should be facilitated by
this proposal
* A user who can consume a secret in a container can know the value of the
secret; secrets must be provisioned judiciously
## Use Cases
1. As a user, I want to store secret artifacts for my applications and consume
them securely in containers, so that I can keep the configuration for my
applications separate from the images that use them:
1. As a cluster operator, I want to allow a pod to access the Kubernetes
master using a custom `.kubeconfig` file, so that I can securely reach the
master
2. As a cluster operator, I want to allow a pod to access a Docker registry
using credentials from a `.dockercfg` file, so that containers can push images
3. As a cluster operator, I want to allow a pod to access a git repository
using SSH keys, so that I can push to and fetch from the repository
2. As a user, I want to allow containers to consume supplemental information
about services such as username and password which should be kept secret, so
that I can share secrets about a service amongst the containers in my
application securely
3. As a user, I want to associate a pod with a `ServiceAccount` that consumes a
secret and have the kubelet implement some reserved behaviors based on the types
of secrets the service account consumes:
1. Use credentials for a docker registry to pull the pod's docker image
2. Present Kubernetes auth token to the pod or transparently decorate
traffic between the pod and master service
4. As a user, I want to be able to indicate that a secret expires and for that
secret's value to be rotated once it expires, so that the system can help me
follow good practices
### Use-Case: Configuration artifacts
Many configuration files contain secrets intermixed with other configuration
information. For example, a user's application may contain a properties file
than contains database credentials, SaaS API tokens, etc. Users should be able
to consume configuration artifacts in their containers and be able to control
the path on the container's filesystems where the artifact will be presented.
### Use-Case: Metadata about services
Most pieces of information about how to use a service are secrets. For example,
a service that provides a MySQL database needs to provide the username,
password, and database name to consumers so that they can authenticate and use
the correct database. Containers in pods consuming the MySQL service would also
consume the secrets associated with the MySQL service.
### Use-Case: Secrets associated with service accounts
[Service Accounts](service_accounts.md) are proposed as a mechanism to decouple
capabilities and security contexts from individual human users. A
`ServiceAccount` contains references to some number of secrets. A `Pod` can
specify that it is associated with a `ServiceAccount`. Secrets should have a
`Type` field to allow the Kubelet and other system components to take action
based on the secret's type.
#### Example: service account consumes auth token secret
As an example, the service account proposal discusses service accounts consuming
secrets which contain Kubernetes auth tokens. When a Kubelet starts a pod
associated with a service account which consumes this type of secret, the
Kubelet may take a number of actions:
1. Expose the secret in a `.kubernetes_auth` file in a well-known location in
the container's file system
2. Configure that node's `kube-proxy` to decorate HTTP requests from that pod
to the `kubernetes-master` service with the auth token, e. g. by adding a header
to the request (see the [LOAS Daemon](http://issue.k8s.io/2209) proposal)
#### Example: service account consumes docker registry credentials
Another example use case is where a pod is associated with a secret containing
docker registry credentials. The Kubelet could use these credentials for the
docker pull to retrieve the image.
### Use-Case: Secret expiry and rotation
Rotation is considered a good practice for many types of secret data. It should
be possible to express that a secret has an expiry date; this would make it
possible to implement a system component that could regenerate expired secrets.
As an example, consider a component that rotates expired secrets. The rotator
could periodically regenerate the values for expired secrets of common types and
update their expiry dates.
## Deferral: Consuming secrets as environment variables
Some images will expect to receive configuration items as environment variables
instead of files. We should consider what the best way to allow this is; there
are a few different options:
1. Force the user to adapt files into environment variables. Users can store
secrets that need to be presented as environment variables in a format that is
easy to consume from a shell:
$ cat /etc/secrets/my-secret.txt
export MY_SECRET_ENV=MY_SECRET_VALUE
The user could `source` the file at `/etc/secrets/my-secret` prior to
executing the command for the image either inline in the command or in an init
script.
2. Give secrets an attribute that allows users to express the intent that the
platform should generate the above syntax in the file used to present a secret.
The user could consume these files in the same manner as the above option.
3. Give secrets attributes that allow the user to express that the secret
should be presented to the container as an environment variable. The container's
environment would contain the desired values and the software in the container
could use them without accommodation the command or setup script.
For our initial work, we will treat all secrets as files to narrow the problem
space. There will be a future proposal that handles exposing secrets as
environment variables.
## Flow analysis of secret data with respect to the API server
There are two fundamentally different use-cases for access to secrets:
1. CRUD operations on secrets by their owners
2. Read-only access to the secrets needed for a particular node by the kubelet
### Use-Case: CRUD operations by owners
In use cases for CRUD operations, the user experience for secrets should be no
different than for other API resources.
#### Data store backing the REST API
The data store backing the REST API should be pluggable because different
cluster operators will have different preferences for the central store of
secret data. Some possibilities for storage:
1. An etcd collection alongside the storage for other API resources
2. A collocated [HSM](http://en.wikipedia.org/wiki/Hardware_security_module)
3. A secrets server like [Vault](https://www.vaultproject.io/) or
[Keywhiz](https://square.github.io/keywhiz/)
4. An external datastore such as an external etcd, RDBMS, etc.
#### Size limit for secrets
There should be a size limit for secrets in order to:
1. Prevent DOS attacks against the API server
2. Allow kubelet implementations that prevent secret data from touching the
node's filesystem
The size limit should satisfy the following conditions:
1. Large enough to store common artifact types (encryption keypairs,
certificates, small configuration files)
2. Small enough to avoid large impact on node resource consumption (storage,
RAM for tmpfs, etc)
To begin discussion, we propose an initial value for this size limit of **1MB**.
#### Other limitations on secrets
Defining a policy for limitations on how a secret may be referenced by another
API resource and how constraints should be applied throughout the cluster is
tricky due to the number of variables involved:
1. Should there be a maximum number of secrets a pod can reference via a
volume?
2. Should there be a maximum number of secrets a service account can reference?
3. Should there be a total maximum number of secrets a pod can reference via
its own spec and its associated service account?
4. Should there be a total size limit on the amount of secret data consumed by
a pod?
5. How will cluster operators want to be able to configure these limits?
6. How will these limits impact API server validations?
7. How will these limits affect scheduling?
For now, we will not implement validations around these limits. Cluster
operators will decide how much node storage is allocated to secrets. It will be
the operator's responsibility to ensure that the allocated storage is sufficient
for the workload scheduled onto a node.
For now, kubelets will only attach secrets to api-sourced pods, and not file-
or http-sourced ones. Doing so would:
- confuse the secrets admission controller in the case of mirror pods.
- create an apiserver-liveness dependency -- avoiding this dependency is a
main reason to use non-api-source pods.
### Use-Case: Kubelet read of secrets for node
The use-case where the kubelet reads secrets has several additional requirements:
1. Kubelets should only be able to receive secret data which is required by
pods scheduled onto the kubelet's node
2. Kubelets should have read-only access to secret data
3. Secret data should not be transmitted over the wire insecurely
4. Kubelets must ensure pods do not have access to each other's secrets
#### Read of secret data by the Kubelet
The Kubelet should only be allowed to read secrets which are consumed by pods
scheduled onto that Kubelet's node and their associated service accounts.
Authorization of the Kubelet to read this data would be delegated to an
authorization plugin and associated policy rule.
#### Secret data on the node: data at rest
Consideration must be given to whether secret data should be allowed to be at
rest on the node:
1. If secret data is not allowed to be at rest, the size of secret data becomes
another draw on the node's RAM - should it affect scheduling?
2. If secret data is allowed to be at rest, should it be encrypted?
1. If so, how should be this be done?
2. If not, what threats exist? What types of secret are appropriate to
store this way?
For the sake of limiting complexity, we propose that initially secret data
should not be allowed to be at rest on a node; secret data should be stored on a
node-level tmpfs filesystem. This filesystem can be subdivided into directories
for use by the kubelet and by the volume plugin.
#### Secret data on the node: resource consumption
The Kubelet will be responsible for creating the per-node tmpfs file system for
secret storage. It is hard to make a prescriptive declaration about how much
storage is appropriate to reserve for secrets because different installations
will vary widely in available resources, desired pod to node density, overcommit
policy, and other operation dimensions. That being the case, we propose for
simplicity that the amount of secret storage be controlled by a new parameter to
the kubelet with a default value of **64MB**. It is the cluster operator's
responsibility to handle choosing the right storage size for their installation
and configuring their Kubelets correctly.
Configuring each Kubelet is not the ideal story for operator experience; it is
more intuitive that the cluster-wide storage size be readable from a central
configuration store like the one proposed in [#1553](http://issue.k8s.io/1553).
When such a store exists, the Kubelet could be modified to read this
configuration item from the store.
When the Kubelet is modified to advertise node resources (as proposed in
[#4441](http://issue.k8s.io/4441)), the capacity calculation
for available memory should factor in the potential size of the node-level tmpfs
in order to avoid memory overcommit on the node.
#### Secret data on the node: isolation
Every pod will have a [security context](security_context.md).
Secret data on the node should be isolated according to the security context of
the container. The Kubelet volume plugin API will be changed so that a volume
plugin receives the security context of a volume along with the volume spec.
This will allow volume plugins to implement setting the security context of
volumes they manage.
## Community work
Several proposals / upstream patches are notable as background for this
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/security.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/security.md)
Kubernetes should define a reasonable set of security best practices that allows
processes to be isolated from each other, from the cluster infrastructure, and
which preserves important boundaries between those who manage the cluster, and
those who use the cluster.
While Kubernetes today is not primarily a multi-tenant system, the long term
evolution of Kubernetes will increasingly rely on proper boundaries between
users and administrators. The code running on the cluster must be appropriately
isolated and secured to prevent malicious parties from affecting the entire
cluster.
## High Level Goals
1. Ensure a clear isolation between the container and the underlying host it
runs on
2. Limit the ability of the container to negatively impact the infrastructure
or other containers
3.[Principle of Least Privilege](http://en.wikipedia.org/wiki/Principle_of_least_privilege) -
ensure components are only authorized to perform the actions they need, and
limit the scope of a compromise by limiting the capabilities of individual
components
4. Reduce the number of systems that have to be hardened and secured by
defining clear boundaries between components
5. Allow users of the system to be cleanly separated from administrators
6. Allow administrative functions to be delegated to users where necessary
7. Allow applications to be run on the cluster that have "secret" data (keys,
certs, passwords) which is properly abstracted from "public" data.
## Use cases
### Roles
We define "user" as a unique identity accessing the Kubernetes API server, which
may be a human or an automated process. Human users fall into the following
categories:
1. k8s admin - administers a Kubernetes cluster and has access to the underlying
components of the system
2. k8s project administrator - administrates the security of a small subset of
the cluster
3. k8s developer - launches pods on a Kubernetes cluster and consumes cluster
resources
Automated process users fall into the following categories:
1. k8s container user - a user that processes running inside a container (on the
cluster) can use to access other cluster resources independent of the human
users attached to a project
2. k8s infrastructure user - the user that Kubernetes infrastructure components
use to perform cluster functions with clearly defined roles
### Description of roles
* Developers:
* write pod specs.
* making some of their own images, and using some "community" docker images
* know which pods need to talk to which other pods
* decide which pods should share files with other pods, and which should not.
* reason about application level security, such as containing the effects of a
local-file-read exploit in a webserver pod.
* do not often reason about operating system or organizational security.
* are not necessarily comfortable reasoning about the security properties of a
system at the level of detail of Linux Capabilities, SELinux, AppArmor, etc.
* Project Admins:
* allocate identity and roles within a namespace
* reason about organizational security within a namespace
* don't give a developer permissions that are not needed for role.
* protect files on shared storage from unnecessary cross-team access
* are less focused about application security
* Administrators:
* are less focused on application security. Focused on operating system
security.
* protect the node from bad actors in containers, and properly-configured
innocent containers from bad actors in other containers.
* comfortable reasoning about the security properties of a system at the level
of detail of Linux Capabilities, SELinux, AppArmor, etc.
* decides who can use which Linux Capabilities, run privileged containers, use
hostPath, etc.
* e.g. a team that manages Ceph or a mysql server might be trusted to have
raw access to storage devices in some organizations, but teams that develop the
applications at higher layers would not.
## Proposed Design
A pod runs in a *security context* under a *service account* that is defined by
an administrator or project administrator, and the *secrets* a pod has access to
is limited by that *service account*.
1. The API should authenticate and authorize user actions [authn and authz](access.md)
2. All infrastructure components (kubelets, kube-proxies, controllers,
scheduler) should have an infrastructure user that they can authenticate with
and be authorized to perform only the functions they require against the API.
3. Most infrastructure components should use the API as a way of exchanging data
and changing the system, and only the API should have access to the underlying
data store (etcd)
4. When containers run on the cluster and need to talk to other containers or
the API server, they should be identified and authorized clearly as an
autonomous process via a [service account](service_accounts.md)
1. If the user who started a long-lived process is removed from access to
the cluster, the process should be able to continue without interruption
2. If the user who started processes are removed from the cluster,
administrators may wish to terminate their processes in bulk
3. When containers run with a service account, the user that created /
triggered the service account behavior must be associated with the container's
action
5. When container processes run on the cluster, they should run in a
[security context](security_context.md) that isolates those processes via Linux
user security, user namespaces, and permissions.
1. Administrators should be able to configure the cluster to automatically
confine all container processes as a non-root, randomly assigned UID
2. Administrators should be able to ensure that container processes within
the same namespace are all assigned the same unix user UID
3. Administrators should be able to limit which developers and project
administrators have access to higher privilege actions
4. Project administrators should be able to run pods within a namespace
under different security contexts, and developers must be able to specify which
of the available security contexts they may use
5. Developers should be able to run their own images or images from the
community and expect those images to run correctly
6. Developers may need to ensure their images work within higher security
requirements specified by administrators
7. When available, Linux kernel user namespaces can be used to ensure 5.2
and 5.4 are met.
8. When application developers want to share filesystem data via distributed
filesystems, the Unix user ids on those filesystems must be consistent across
different container processes
6. Developers should be able to define [secrets](secrets.md) that are
automatically added to the containers when pods are run
1. Secrets are files injected into the container whose values should not be
displayed within a pod. Examples:
1. An SSH private key for git cloning remote data
2. A client certificate for accessing a remote system
3. A private key and certificate for a web server
4. A .kubeconfig file with embedded cert / token data for accessing the
Kubernetes master
5. A .dockercfg file for pulling images from a protected registry
2. Developers should be able to define the pod spec so that a secret lands
in a specific location
3. Project administrators should be able to limit developers within a
namespace from viewing or modifying secrets (anyone who can launch an arbitrary
pod can view secrets)
4. Secrets are generally not copied from one namespace to another when a
developer's application definitions are copied
### Related design discussion
*[Authorization and authentication](access.md)
*[Secret distribution via files](http://pr.k8s.io/2030)
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/security_context.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/security_context.md)
## Abstract
A security context is a set of constraints that are applied to a container in
order to achieve the following goals (from [security design](security.md)):
1. Ensure a clear isolation between container and the underlying host it runs
on
2. Limit the ability of the container to negatively impact the infrastructure
or other containers
## Background
The problem of securing containers in Kubernetes has come up
[before](http://issue.k8s.io/398) and the potential problems with container
security are [well known](http://opensource.com/business/14/7/docker-security-selinux).
Although it is not possible to completely isolate Docker containers from their
hosts, new features like [user namespaces](https://github.com/docker/libcontainer/pull/304)
make it possible to greatly reduce the attack surface.
## Motivation
### Container isolation
In order to improve container isolation from host and other containers running
on the host, containers should only be granted the access they need to perform
their work. To this end it should be possible to take advantage of Docker
features such as the ability to
[add or remove capabilities](https://docs.docker.com/reference/run/#runtime-privilege-linux-capabilities-and-lxc-configuration)
and [assign MCS labels](https://docs.docker.com/reference/run/#security-configuration)
to the container process.
Support for user namespaces has recently been
[merged](https://github.com/docker/libcontainer/pull/304) into Docker's
libcontainer project and should soon surface in Docker itself. It will make it
possible to assign a range of unprivileged uids and gids from the host to each
container, improving the isolation between host and container and between
containers.
### External integration with shared storage
In order to support external integration with shared storage, processes running
in a Kubernetes cluster should be able to be uniquely identified by their Unix
UID, such that a chain of ownership can be established. Processes in pods will
need to have consistent UID/GID/SELinux category labels in order to access
shared disks.
## Constraints and Assumptions
* It is out of the scope of this document to prescribe a specific set of
constraints to isolate containers from their host. Different use cases need
different settings.
* The concept of a security context should not be tied to a particular security
mechanism or platform (i.e. SELinux, AppArmor)
* Applying a different security context to a scope (namespace or pod) requires
a solution such as the one proposed for [service accounts](service_accounts.md).
## Use Cases
In order of increasing complexity, following are example use cases that would
be addressed with security contexts:
1. Kubernetes is used to run a single cloud application. In order to protect
nodes from containers:
* All containers run as a single non-root user
* Privileged containers are disabled
* All containers run with a particular MCS label
* Kernel capabilities like CHOWN and MKNOD are removed from containers
2. Just like case #1, except that I have more than one application running on
the Kubernetes cluster.
* Each application is run in its own namespace to avoid name collisions
* For each application a different uid and MCS label is used
3. Kubernetes is used as the base for a PAAS with multiple projects, each
project represented by a namespace.
* Each namespace is associated with a range of uids/gids on the node that
are mapped to uids/gids on containers using linux user namespaces.
* Certain pods in each namespace have special privileges to perform system
actions such as talking back to the server for deployment, run docker builds,
etc.
* External NFS storage is assigned to each namespace and permissions set
using the range of uids/gids assigned to that namespace.
## Proposed Design
### Overview
A *security context* consists of a set of constraints that determine how a
container is secured before getting created and run. A security context resides
on the container and represents the runtime parameters that will be used to
create and run the container via container APIs. A *security context provider*
is passed to the Kubelet so it can have a chance to mutate Docker API calls in
order to apply the security context.
It is recommended that this design be implemented in two phases:
1. Implement the security context provider extension point in the Kubelet
so that a default security context can be applied on container run and creation.
2. Implement a security context structure that is part of a service account. The
default context provider can then be used to apply a security context based on
the service account associated with the pod.
### Security Context Provider
The Kubelet will have an interface that points to a `SecurityContextProvider`.
The `SecurityContextProvider` is invoked before creating and running a given
container:
```go
typeSecurityContextProviderinterface{
// ModifyContainerConfig is called before the Docker createContainer call.
// The security context provider can make changes to the Config with which
// the container is created.
// An error is returned if it's not possible to secure the container as
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/selector-generation.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/selector-generation.md)
=============
# Goals
Make it really hard to accidentally create a job which has an overlapping
selector, while still making it possible to chose an arbitrary selector, and
without adding complex constraint solving to the APIserver.
# Use Cases
1. user can leave all label and selector fields blank and system will fill in
reasonable ones: non-overlappingness guaranteed.
2. user can put on the pod template some labels that are useful to the user,
without reasoning about non-overlappingness. System adds additional label to
assure not overlapping.
3. If user wants to reparent pods to new job (very rare case) and knows what
they are doing, they can completely disable this behavior and specify explicit
selector.
4. If a controller that makes jobs, like scheduled job, wants to use different
labels, such as the time and date of the run, it can do that.
5. If User reads v1beta1 documentation or reuses v1beta1 Job definitions and
just changes the API group, the user should not automatically be allowed to
specify a selector, since this is very rarely what people want to do and is
error prone.
6. If User downloads an existing job definition, e.g. with
`kubectl get jobs/old -o yaml` and tries to modify and post it, he should not
create an overlapping job.
7. If User downloads an existing job definition, e.g. with
`kubectl get jobs/old -o yaml` and tries to modify and post it, and he
accidentally copies the uniquifying label from the old one, then he should not
get an error from a label-key conflict, nor get erratic behavior.
8. If user reads swagger docs and sees the selector field, he should not be able
to set it without realizing the risks.
8. (Deferred requirement:) If user wants to specify a preferred name for the
non-overlappingness key, they can pick a name.
# Proposed changes
## API
`extensions/v1beta1 Job` remains the same. `batch/v1 Job` changes change as
follows.
Field `job.spec.manualSelector` is added. It controls whether selectors are
automatically generated. In automatic mode, user cannot make the mistake of
creating non-unique selectors. In manual mode, certain rare use cases are
supported.
Validation is not changed. A selector must be provided, and it must select the
pod template.
Defaulting changes. Defaulting happens in one of two modes:
### Automatic Mode
- User does not specify `job.spec.selector`.
- User is probably unaware of the `job.spec.manualSelector` field and does not
think about it.
- User optionally puts labels on pod template (optional). User does not think
about uniqueness, just labeling for user's own reasons.
- Defaulting logic sets `job.spec.selector` to
`matchLabels["controller-uid"]="$UIDOFJOB"`
- Defaulting logic appends 2 labels to the `.spec.template.metadata.labels`.
- The first label is controller-uid=$UIDOFJOB.
- The second label is "job-name=$NAMEOFJOB".
### Manual Mode
- User means User or Controller for the rest of this list.
- User does specify `job.spec.selector`.
- User does specify `job.spec.manualSelector=true`
- User puts a unique label or label(s) on pod template (required). User does
think carefully about uniqueness.
- No defaulting of pod labels or the selector happen.
### Rationale
UID is better than Name in that:
- it allows cross-namespace control someday if we need it.
- it is unique across all kinds. `controller-name=foo` does not ensure
uniqueness across Kinds `job` vs `replicaSet`. Even `job-name=foo` has a
problem: you might have a `batch.Job` and a `snazzyjob.io/types.Job` -- the
latter cannot use label `job-name=foo`, though there is a temptation to do so.
- it uniquely identifies the controller across time. This prevents the case
where, for example, someone deletes a job via the REST api or client
(where cascade=false), leaving pods around. We don't want those to be picked up
unintentionally. It also prevents the case where a user looks at an old job that
finished but is not deleted, and tries to select its pods, and gets the wrong
impression that it is still running.
Job name is more user friendly. It is self documenting
Commands like `kubectl get pods -l job-name=myjob` should do exactly what is
wanted 99.9% of the time. Automated control loops should still use the
controller-uid=label.
Using both gets the benefits of both, at the cost of some label verbosity.
The field is a `*bool`. Since false is expected to be much more common,
and since the feature is complex, it is better to leave it unspecified so that
users looking at a stored pod spec do not need to be aware of this field.
### Overriding Unique Labels
If user does specify `job.spec.selector` then the user must also specify
`job.spec.manualSelector`. This ensures the user knows that what he is doing is
not the normal thing to do.
To prevent users from copying the `job.spec.manualSelector` flag from existing
jobs, it will be optional and default to false, which means when you ask GET and
existing job back that didn't use this feature, you don't even see the
`job.spec.manualSelector` flag, so you are not tempted to wonder if you should
fiddle with it.
## Job Controller
No changes
## Kubectl
No required changes. Suggest moving SELECTOR to wide output of `kubectl get
jobs` since users do not write the selector.
## Docs
Remove examples that use selector and remove labels from pod templates.
Recommend `kubectl get jobs -l job-name=name` as the way to find pods of a job.
# Conversion
The following applies to Job, as well as to other types that adopt this pattern:
- Type `extensions/v1beta1` gets a field called `job.spec.autoSelector`.
- Both the internal type and the `batch/v1` type will get
`job.spec.manualSelector`.
- The fields `manualSelector` and `autoSelector` have opposite meanings.
- Each field defaults to false when unset, and so v1beta1 has a different
default than v1 and internal. This is intentional: we want new uses to default
to the less error-prone behavior, and we do not want to change the behavior of
v1beta1.
*Note*: since the internal default is changing, client library consumers that
create Jobs may need to add "job.spec.manualSelector=true" to keep working, or
switch to auto selectors.
Conversion is as follows:
-`extensions/__internal` to `extensions/v1beta1`: the value of
`__internal.Spec.ManualSelector` is defaulted to false if nil, negated,
defaulted to nil if false, and written `v1beta1.Spec.AutoSelector`.
-`extensions/v1beta1` to `extensions/__internal`: the value of
`v1beta1.SpecAutoSelector` is defaulted to false if nil, negated, defaulted to
nil if false, and written to `__internal.Spec.ManualSelector`.
This conversion gives the following properties.
1. Users that previously used v1beta1 do not start seeing a new field when they
get back objects.
2. Distinction between originally unset versus explicitly set to false is not
preserved (would have been nice to do so, but requires more complicated
solution).
3. Users who only created v1beta1 examples or v1 examples, will not ever see the
existence of either field.
4. Since v1beta1 are convertable to/from v1, the storage location (path in etcd)
does not need to change, allowing scriptable rollforward/rollback.
# Future Work
Follow this pattern for Deployments, ReplicaSet, DaemonSet when going to v1, if
it works well for job.
Docs will be edited to show examples without a `job.spec.selector`.
We probably want as much as possible the same behavior for Job and
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/selinux.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/selinux.md)
A proposal for enabling containers in a pod to share volumes using a pod level SELinux context.
## Motivation
Many users have a requirement to run pods on systems that have SELinux enabled. Volume plugin
authors should not have to explicitly account for SELinux except for volume types that require
special handling of the SELinux context during setup.
Currently, each container in a pod has an SELinux context. This is not an ideal factoring for
sharing resources using SELinux.
We propose a pod-level SELinux context and a mechanism to support SELinux labeling of volumes in a
generic way.
Goals of this design:
1. Describe the problems with a container SELinux context
2. Articulate a design for generic SELinux support for volumes using a pod level SELinux context
which is backward compatible with the v1.0.0 API
## Constraints and Assumptions
1. We will not support securing containers within a pod from one another
2. Volume plugins should not have to handle setting SELinux context on volumes
3. We will not deal with shared storage
## Current State Overview
### Docker
Docker uses a base SELinux context and calculates a unique MCS label per container. The SELinux
context of a container can be overridden with the `SecurityOpt` api that allows setting the different
parts of the SELinux context individually.
Docker has functionality to relabel bind-mounts with a usable SElinux and supports two different
use-cases:
1. The `:Z` bind-mount flag, which tells Docker to relabel a bind-mount with the container's
SELinux context
2. The `:z` bind-mount flag, which tells Docker to relabel a bind-mount with the container's
SElinux context, but remove the MCS labels, making the volume shareable between containers
We should avoid using the `:z` flag, because it relaxes the SELinux context so that any container
(from an SELinux standpoint) can use the volume.
### rkt
rkt currently reads the base SELinux context to use from `/etc/selinux/*/contexts/lxc_contexts`
and allocates a unique MCS label per pod.
### Kubernetes
There is a [proposed change](https://github.com/kubernetes/kubernetes/pull/9844) to the
EmptyDir plugin that adds SELinux relabeling capabilities to that plugin, which is also carried as a
patch in [OpenShift](https://github.com/openshift/origin). It is preferable to solve the problem
in general of handling SELinux in kubernetes to merging this PR.
A new `PodSecurityContext` type has been added that carries information about security attributes
that apply to the entire pod and that apply to all containers in a pod. See:
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/service_accounts.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/service_accounts.md)
## Motivation
Processes in Pods may need to call the Kubernetes API. For example:
- scheduler
- replication controller
- node controller
- a map-reduce type framework which has a controller that then tries to make a
dynamically determined number of workers and watch them
- continuous build and push system
- monitoring system
They also may interact with services other than the Kubernetes API, such as:
- an image repository, such as docker -- both when the images are pulled to
start the containers, and for writing images in the case of pods that generate
images.
- accessing other cloud services, such as blob storage, in the context of a
large, integrated, cloud offering (hosted or private).
- accessing files in an NFS volume attached to the pod
## Design Overview
A service account binds together several things:
- a *name*, understood by users, and perhaps by peripheral systems, for an
identity
- a *principal* that can be authenticated and [authorized](../admin/authorization.md)
- a [security context](security_context.md), which defines the Linux
Capabilities, User IDs, Groups IDs, and other capabilities and controls on
interaction with the file system and OS.
- a set of [secrets](secrets.md), which a container may use to access various
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/simple-rolling-update.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/simple-rolling-update.md)
This is a lightweight design document for simple
[rolling update](../user-guide/kubectl/kubectl_rolling-update.md) in `kubectl`.
Complete execution flow can be found [here](#execution-details). See the
[example of rolling update](../user-guide/update-demo/) for more information.
### Lightweight rollout
Assume that we have a current replication controller named `foo` and it is
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/taint-toleration-dedicated.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/taint-toleration-dedicated.md)
## Introduction
This document describes *taints* and *tolerations*, which constitute a generic
mechanism for restricting the set of pods that can use a node. We also describe
one concrete use case for the mechanism, namely to limit the set of users (or
more generally, authorization domains) who can access a set of nodes (a feature
we call *dedicated nodes*). There are many other uses--for example, a set of
nodes with a particular piece of hardware could be reserved for pods that
require that hardware, or a node could be marked as unschedulable when it is
being drained before shutdown, or a node could trigger evictions when it
experiences hardware or software problems or abnormal node configurations; see
issues [#17190](https://github.com/kubernetes/kubernetes/issues/17190) and
[#3885](https://github.com/kubernetes/kubernetes/issues/3885) for more discussion.
## Taints, tolerations, and dedicated nodes
A *taint* is a new type that is part of the `NodeSpec`; when present, it
prevents pods from scheduling onto the node unless the pod *tolerates* the taint
(tolerations are listed in the `PodSpec`). Note that there are actually multiple
flavors of taints: taints that prevent scheduling on a node, taints that cause
the scheduler to try to avoid scheduling on a node but do not prevent it, taints
that prevent a pod from starting on Kubelet even if the pod's `NodeName` was
written directly (i.e. pod did not go through the scheduler), and taints that
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/versioning.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/versioning.md)
This file has moved to [https://github.com/kubernetes/community/blob/master/contributors/design-proposals/volume-snapshotting.md](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/volume-snapshotting.md)
Many storage systems (GCE PD, Amazon EBS, etc.) provide the ability to create "snapshots" of a persistent volumes to protect against data loss. Snapshots can be used in place of a traditional backup system to back up and restore primary and critical data. Snapshots allow for quick data backup (for example, it takes a fraction of a second to create a GCE PD snapshot) and offer fast recovery time objectives (RTOs) and recovery point objectives (RPOs).
Typical existing backup solutions offer on demand or scheduled snapshots.
An application developer using a storage may want to create a snapshot before an update or other major event. Kubernetes does not currently offer a standardized snapshot API for creating, listing, deleting, and restoring snapshots on an arbitrary volume.
Existing solutions for scheduled snapshotting include [cron jobs](https://forums.aws.amazon.com/message.jspa?messageID=570265) and [external storage drivers](http://rancher.com/introducing-convoy-a-docker-volume-driver-for-backup-and-recovery-of-persistent-data/). Some cloud storage volumes can be configured to take automatic snapshots, but this is specified on the volumes themselves.
## Objectives
For the first version of snapshotting support in Kubernetes, only on-demand snapshots will be supported. Features listed in the roadmap for future versions are also nongoals.
* Goal 1: Enable *on-demand* snapshots of Kubernetes persistent volumes by application developers.
* Nongoal: Enable *automatic* periodic snapshotting for direct volumes in pods.
* Goal 2: Expose standardized snapshotting operations Create and List in Kubernetes REST API.
* Nongoal: Support Delete and Restore snapshot operations in API.
* Goal 3: Implement snapshotting interface for GCE PDs.
* Nongoal: Implement snapshotting interface for non GCE PD volumes.
### Feature Roadmap
Major features, in order of priority (bold features are priorities for v1):
***On demand snapshots**
* **API to create new snapshots and list existing snapshots**
* API to restore a disk from a snapshot and delete old snapshots
* Scheduled snapshots
* Support snapshots for non-cloud storage volumes (i.e. plugins that require actions to be triggered from the node)
## Requirements
### Performance
* Time SLA from issuing a snapshot to completion:
* The period we are interested is the time between the scheduled snapshot time and the time the snapshot is finishes uploading to its storage location.
* This should be on the order of a few minutes.
### Reliability
* Data corruption
* Though it is generally recommended to stop application writes before executing the snapshot command, we will not do this for several reasons:
* GCE and Amazon can create snapshots while the application is running.
* Stopping application writes cannot be done from the master and varies by application, so doing so will introduce unnecessary complexity and permission issues in the code.
* Most file systems and server applications are (and should be) able to restore inconsistent snapshots the same way as a disk that underwent an unclean shutdown.
* Snapshot failure
* Case: Failure during external process, such as during API call or upload
* Log error, retry until success (indefinitely)
* Case: Failure within Kubernetes, such as controller restarts
* If the master restarts in the middle of a snapshot operation, then the controller does not know whether or not the operation succeeded. However, since the annotation has not been deleted, the controller will retry, which may result in a crash loop if the first operation has not yet completed. This issue will not be addressed in the alpha version, but future versions will need to address it by persisting state.
## Solution Overview
Snapshot operations will be triggered by [annotations](http://kubernetes.io/docs/user-guide/annotations/) on PVC API objects.
A new controller responsible solely for snapshot operations will be added to the controllermanager on the master. This controller will watch the API server for new annotations on PVCs. When a create snapshot annotation is added, it will trigger the appropriate snapshot creation logic for the underlying persistent volume type. The list annotation will be populated by the controller and only identify all snapshots created for that PVC by Kubernetes.
The snapshot operation is a no-op for volume plugins that do not support snapshots via an API call (i.e. non-cloud storage).
## Detailed Design
### API
* Create snapshot
* Usage:
* Users create annotation with key "create.snapshot.volume.alpha.kubernetes.io", value does not matter
* When the annotation is deleted, the operation has succeeded. The snapshot will be listed in the value of snapshot-list.
* API is declarative and guarantees only that it will begin attempting to create the snapshot once the annotation is created and will complete eventually.
* PVC control loop in master
* If annotation on new PVC, search for PV of volume type that implements SnapshottableVolumePlugin. If one is available, use it. Otherwise, reject the claim and post an event to the PV.
* If annotation on existing PVC, if PV type implements SnapshottableVolumePlugin, continue to SnapshotController logic. Otherwise, delete the annotation and post an event to the PV.
* List existing snapshots
* Only displayed as annotations on PVC object.
* Only lists unique names and timestamps of snapshots taken using the Kubernetes API.
* Usage:
* Get the PVC object
* Snapshots are listed as key-value pairs within the PVC annotations
**PVC Informer:** A shared informer that stores (references to) PVC objects, populated by the API server. The annotations on the PVC objects are used to add items to SnapshotRequests.
**SnapshotRequests:** An in-memory cache of incomplete snapshot requests that is populated by the PVC informer. This maps unique volume IDs to PVC objects. Volumes are added when the create snapshot annotation is added, and deleted when snapshot requests are completed successfully.
**Reconciler:** Simple loop that triggers asynchronous snapshots via the OperationExecutor. Deletes create snapshot annotation if successful.
The controller will have a loop that does the following:
* Fetch State
* Fetch all PVC objects from the API server.
* Act
* Trigger snapshot:
* Loop through SnapshotRequests and trigger create snapshot logic (see below) for any PVCs that have the create snapshot annotation.
* Persist State
* Once a snapshot operation completes, write the snapshot ID/timestamp to the PVC Annotations and delete the create snapshot annotation in the PVC object via the API server.
Snapshot operations can take a long time to complete, so the primary controller loop should not block on these operations. Instead the reconciler should spawn separate threads for these operations via the operation executor.
The controller will reject snapshot requests if the unique volume ID already exists in the SnapshotRequests. Concurrent operations on the same volume will be prevented by the operation executor.
### Create Snapshot Logic
To create a snapshot:
* Acquire operation lock for volume so that no other attach or detach operations can be started for volume.
* Abort if there is already a pending operation for the specified volume (main loop will retry, if needed).
* Spawn a new thread:
* Execute the volume-specific logic to create a snapshot of the persistent volume reference by the PVC.
* For any errors, log the error, and terminate the thread (the main controller will retry as needed).
* Once a snapshot is created successfully:
* Make a call to the API server to delete the create snapshot annotation in the PVC object.
* Make a call to the API server to add the new snapshot ID/timestamp to the PVC Annotations.
*Brainstorming notes below, read at your own risk!*
* * *
Open questions:
* What has more value: scheduled snapshotting or exposing snapshotting/backups as a standardized API?
* It seems that the API route is a bit more feasible in implementation and can also be fully utilized.
* Can the API call methods on VolumePlugins? Yeah via controller
* The scheduler gives users functionality that doesn’t already exist, but required adding an entirely new controller
* Should the list and restore operations be part of v1?
* Do we call them snapshots or backups?
* From the SIG email: "The snapshot should not be suggested to be a backup in any documentation, because in practice is is necessary, but not sufficient, when conducting a backup of a stateful application."
* At what minimum granularity should snapshots be allowed?
* How do we store information about the most recent snapshot in case the controller restarts?
* In case of error, do we err on the side of fewer or more snapshots?
Snapshot Scheduler
1. PVC API Object
A new field, backupSchedule, will be added to the PVC API Object. The value of this field must be a cron expression.
* CRUD operations on snapshot schedules
* Create: Specify a snapshot within a PVC spec as a [cron expression](http://crontab-generator.org/)
* The cron expression provides flexibility to decrease the interval between snapshots in future versions
* Read: Display snapshot schedule to user via kubectl get pvc
* Update: Do not support changing the snapshot schedule for an existing PVC
* Delete: Do not support deleting the snapshot schedule for an existing PVC
* In v1, the snapshot schedule is tied to the lifecycle of the PVC. Update and delete operations are therefore not supported. In future versions, this may be done using kubectl edit pvc/name
* Validation
* Cron expressions must have a 0 in the minutes place and use exact, not interval syntax
* [EBS](http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/TakeScheduledSnapshot.html) appears to be able to take snapshots at the granularity of minutes, GCE PD takes at most minutes. Therefore for v1, we ensure that snapshots are taken at most hourly and at exact times (rather than at time intervals).
* If Kubernetes cannot find a PV that supports snapshotting via its API, reject the PVC and display an error message to the user
Objective
Goal: Enable automatic periodic snapshotting (NOTE: A snapshot is a read-only copy of a disk.) for all kubernetes volume plugins.
Goal: Implement snapshotting interface for GCE PDs.
Goal: Protect against data loss by allowing users to restore snapshots of their disks.
Nongoal: Implement snapshotting support on Kubernetes for non GCE PD volumes.
Nongoal: Use snapshotting to provide additional features such as migration.
Background
Many storage systems (GCE PD, Amazon EBS, NFS, etc.) provide the ability to create "snapshots" of a persistent volumes to protect against data loss. Snapshots can be used in place of a traditional backup system to back up and restore primary and critical data. Snapshots allow for quick data backup (for example, it takes a fraction of a second to create a GCE PD snapshot) and offer fast recovery time objectives (RTOs) and recovery point objectives (RPOs).
Currently, no container orchestration software (i.e. Kubernetes and its competitors) provide snapshot scheduling for application storage.
Existing solutions for automatic snapshotting include [cron jobs](https://forums.aws.amazon.com/message.jspa?messageID=570265)/shell scripts. Some volumes can be configured to take automatic snapshots, but this is specified on the volumes themselves, not via their associated applications. Snapshotting support gives Kubernetes clear competitive advantage for users who want automatic snapshotting on their volumes, and particularly those who want to configure application-specific schedules.
what is the value case? Who wants this? What do we enable by implementing this?
I think it introduces a lot of complexity, so what is the pay off? That should be clear in the document. Do mesos, or swarm or our competition implement this? AWS? Just curious.
Requirements
Functionality
Should this support PVs, direct volumes, or both?
Should we support deletion?
Should we support restores?
Automated schedule -- times or intervals? Before major event?
Performance
Snapshots are supposed to provide timely state freezing. What is the SLA from issuing one to it completing?
* GCE: The snapshot operation takes [a fraction of a second](https://cloudplatform.googleblog.com/2013/10/persistent-disk-backups-using-snapshots.html). If file writes can be paused, they should be paused until the snapshot is created (but can be restarted while it is pending). If file writes cannot be paused, the volume should be unmounted before snapshotting then remounted afterwards.
* Pending = uploading to GCE
* EBS is the same, but if the volume is the root device the instance should be stopped before snapshotting
Reliability
How do we ascertain that deletions happen when we want them to?
For the same reasons that Kubernetes should not expose a direct create-snapshot command, it should also not allow users to delete snapshots for arbitrary volumes from Kubernetes.
We may, however, want to allow users to set a snapshotExpiryPeriod and delete snapshots once they have reached certain age. At this point we do not see an immediate need to implement automatic deletion (re:Saad) but may want to revisit this.
What happens when the snapshot fails as these are async operations?
Retry (for some time period? indefinitely?) and log the error
Other
What is the UI for seeing the list of snapshots?
In the case of GCE PD, the snapshots are uploaded to cloud storage. They are visible and manageable from the GCE console. The same applies for other cloud storage providers (i.e. Amazon). Otherwise, users may need to ssh into the device and access a ./snapshot or similar directory. In other words, users will continue to access snapshots in the same way as they have been while creating manual snapshots.
Overview
There are several design options for the design of each layer of implementation as follows.
1.**Public API:**
Users will specify a snapshotting schedule for particular volumes, which Kubernetes will then execute automatically. There are several options for where this specification can happen. In order from most to least invasive:
1. New Volume API object
1. Currently, pods, PVs, and PVCs are API objects, but Volume is not. A volume is represented as a field within pod/PV objects and its details are lost upon destruction of its enclosing object.
2. We define Volume to be a brand new API object, with a snapshot schedule attribute that specifies the time at which Kubernetes should call out to the volume plugin to create a snapshot.
3. The Volume API object will be referenced by the pod/PV API objects. The new Volume object exists entirely independently of the Pod object.
4. Pros
1. Snapshot schedule conflicts: Since a single Volume API object ideally refers to a single volume, each volume has a single unique snapshot schedule. In the case where the same underlying PD is used by different pods which specify different snapshot schedules, we have a straightforward way of identifying and resolving the conflicts. Instead of using extra space to create duplicate snapshots, we can decide to, for example, use the most frequent snapshot schedule.
5. Cons
2. Heavyweight codewise; involves changing and touching a lot of existing code.
3. Potentially bad UX: How is the Volume API object created?
1. By the user independently of the pod (i.e. with something like my-volume.yaml). In order to create 1 pod with a volume, the user needs to create 2 yaml files and run 2 commands.
2. When a unique volume is specified in a pod or PV spec.
2. Directly in volume definition in the pod/PV object
6. When specifying a volume as part of the pod or PV spec, users have the option to include an extra attribute, e.g. ssTimes, to denote the snapshot schedule.
7. Pros
4. Easy for users to implement and understand
8. Cons
5. The same underlying PD may be used by different pods. In this case, we need to resolve when and how often to take snapshots. If two pods specify the same snapshot time for the same PD, we should not perform two snapshots at that time. However, there is no unique global identifier for a volume defined in a pod definition--its identifying details are particular to the volume plugin used.
6. Replica sets have the same pod spec and support needs to be added so that underlying volume used does not create new snapshots for each member of the set.
3. Only in PV object
9. When specifying a volume as part of the PV spec, users have the option to include an extra attribute, e.g. ssTimes, to denote the snapshot schedule.
10. Pros
7. Slightly cleaner than (b). It logically makes more sense to specify snapshotting at the time of the persistent volume definition (as opposed to in the pod definition) since the snapshot schedule is a volume property.
11. Cons
8. No support for direct volumes
9. Only useful for PVs that do not already have automatic snapshotting tools (e.g. Schedule Snapshot Wizard for iSCSI) -- many do and the same can be achieved with a simple cron job
10. Same problems as (b) with respect to non-unique resources. We may have 2 PV API objects for the same underlying disk and need to resolve conflicting/duplicated schedules.
4. Annotations: key value pairs on API object
12. User experience is the same as (b)
13. Instead of storing the snapshot attribute on the pod/PV API object, save this information in an annotation. For instance, if we define a pod with two volumes we might have {"ssTimes-vol1": [1,5], “ssTimes-vol2”: [2,17]} where the values are slices of integer values representing UTC hours.
14. Pros
11. Less invasive to the codebase than (a-c)
15. Cons
12. Same problems as (b-c) with non-unique resources. The only difference here is the API object representation.
2.**Business logic:**
5. Does this go on the master, node, or both?
16. Where the snapshot is stored
13. GCE, Amazon: cloud storage
14. Others stored on volume itself (gluster) or external drive (iSCSI)
17. Requirements for snapshot operation
15. Application flush, sync, and fsfreeze before creating snapshot
6. Suggestion:
18. New SnapshotController on master
16. Controller keeps a list of active pods/volumes, schedule for each, last snapshot
17. If controller restarts and we miss a snapshot in the process, just skip it
3. Alternatively, try creating the snapshot up to the time + retryPeriod (see 5)
18. If snapshotting call fails, retry for an amount of time specified in retryPeriod
19. Timekeeping mechanism: something similar to [cron](http://stackoverflow.com/questions/3982957/how-does-cron-internally-schedule-jobs); keep list of snapshot times, calculate time until next snapshot, and sleep for that period
19. Logic to prepare the disk for snapshotting on node
20. Application I/Os need to be flushed and the filesystem should be frozen before snapshotting (on GCE PD)
7. Alternatives: login entirely on node
20. Problems:
21. If pod moves from one node to another
4. A different node is in now in charge of snapshotting
5. If the volume plugin requires external memory for snapshots, we need to move the existing data
22. If the same pod exists on two different nodes, which node is in charge
3.**Volume plugin interface/internal API:**
8. Allow VolumePlugins to implement the SnapshottableVolumePlugin interface (structure similar to AttachableVolumePlugin)
9. When logic is triggered for a snapshot by the SnapshotController, the SnapshottableVolumePlugin calls out to volume plugin API to create snapshot
10. Similar to volume.attach call
4.**Other questions:**
11. Snapshot period
12. Time or period
13. What is our SLO around time accuracy?
21. Best effort, but no guarantees (depends on time or period) -- if going with time.
14. What if we miss a snapshot?
22. We will retry (assuming this means that we failed) -- take at the nearest next opportunity
15. Will we know when an operation has failed? How do we report that?
23. Get response from volume plugin API, log in kubelet log, generate Kube event in success and failure cases
16. Will we be responsible for GCing old snapshots?
24. Maybe this can be explicit non-goal, in the future can automate garbage collection
17. If the pod dies do we continue creating snapshots?
18. How to communicate errors (PD doesn’t support snapshotting, time period unsupported)
19. Off schedule snapshotting like before an application upgrade
20. We may want to take snapshots of encrypted disks. For instance, for GCE PDs, the encryption key must be passed to gcloud to snapshot an encrypted disk. Should Kubernetes handle this?
Options, pros, cons, suggestion/recommendation
Example 1b
During pod creation, a user can specify a pod definition in a yaml file. As part of this specification, users should be able to denote a [list of] times at which an existing snapshot command can be executed on the pod’s associated volume.
For a simple example, take the definition of a [pod using a GCE PD](http://kubernetes.io/docs/user-guide/volumes/#example-pod-2):
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
# This GCE PD must already exist.
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
Introduce a new field into the volume spec:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
# This GCE PD must already exist.
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
** ssTimes: ****[1, 5]**
Caveats
* Snapshotting should not be exposed to the user through the Kubernetes API (via an operation such as create-snapshot) because
* this does not provide value to the user and only adds an extra layer of indirection/complexity.
* ?
Dependencies
* Kubernetes
* Persistent volume snapshot support through API
* POST https://www.googleapis.com/compute/v1/projects/example-project/zones/us-central1-f/disks/example-disk/createSnapshot