Single-source/multi-version docs structure
parent
db3acc9464
commit
eaaaa781a7
18
_config.yml
18
_config.yml
|
@ -12,6 +12,15 @@ safe: false
|
|||
lsi: false
|
||||
|
||||
defaults:
|
||||
-
|
||||
scope:
|
||||
path: "v1.0"
|
||||
values:
|
||||
version: "v1.0"
|
||||
versionfilesafe: "v1_0"
|
||||
layout: docwithnav
|
||||
showedit: true
|
||||
githubbranch: "release-1.0"
|
||||
-
|
||||
scope:
|
||||
path: "v1.1"
|
||||
|
@ -21,4 +30,13 @@ defaults:
|
|||
layout: docwithnav
|
||||
showedit: true
|
||||
githubbranch: "release-1.1"
|
||||
-
|
||||
scope:
|
||||
path: "v1.2"
|
||||
values:
|
||||
version: "v1.2"
|
||||
versionfilesafe: "v1_2"
|
||||
layout: docwithnav
|
||||
showedit: true
|
||||
githubbranch: "release-1.2"
|
||||
permalink: pretty
|
|
@ -0,0 +1,5 @@
|
|||
tocs:
|
||||
- guides
|
||||
- reference
|
||||
- samples
|
||||
- support
|
|
@ -0,0 +1,179 @@
|
|||
bigheader: "Guides"
|
||||
abstract: "How to get started, and acheive tasks, using Kubernetes"
|
||||
toc:
|
||||
- title: Guides
|
||||
path: /v1.0/
|
||||
|
||||
- title: Quickstarts
|
||||
section:
|
||||
- title: What is Kubernetes?
|
||||
path: /v1.0/docs/whatisk8s/
|
||||
- title: TODO - 5-minute Quickstart
|
||||
path: /v1.0/docs/hellonode/
|
||||
- title: Kubernetes 101
|
||||
path: /v1.0/docs/user-guide/walkthrough/
|
||||
- title: Kubernetes 201
|
||||
path: /v1.0/docs/user-guide/walkthrough/k8s201/
|
||||
|
||||
- title: Running Kubernetes
|
||||
section:
|
||||
- title: Picking the Right Solution
|
||||
path: /v1.0/docs/getting-started-guides/
|
||||
- title: Running Kubernetes on Your Local Machine
|
||||
section:
|
||||
- title: Running Kubernetes Locally via Docker
|
||||
path: /v1.0/docs/getting-started-guides/docker/
|
||||
- title: Running Kubernetes Locally via Vagrant
|
||||
path: /v1.0/docs/getting-started-guides/vagrant/
|
||||
- title: Running Kubernetes Locally with No VM
|
||||
path: /v1.0/docs/getting-started-guides/locally/
|
||||
- title: Running Kubernetes on Turn-key Cloud Solutions
|
||||
section:
|
||||
- title: Running Kubernetes on Google Container Engine
|
||||
path: https://cloud.google.com/container-engine/docs/before-you-begin/
|
||||
- title: Running Kubernetes on Google Compute Engine
|
||||
path: /v1.0/docs/getting-started-guides/gce/
|
||||
- title: Running Kubernetes on AWS EC2
|
||||
path: /v1.0/docs/getting-started-guides/aws/
|
||||
- title: Running Kubernetes on Azure
|
||||
path: /v1.0/docs/getting-started-guides/coreos/azure/
|
||||
- title: Running Kubernetes on Custom Solutions
|
||||
section:
|
||||
- title: Getting Started From Scratch
|
||||
path: /v1.0/docs/getting-started-guides/scratch/
|
||||
- title: Custom Cloud Solutions
|
||||
section:
|
||||
- title: AWS or GCE on CoreOS
|
||||
path: /v1.0/docs/getting-started-guides/coreos/
|
||||
- title: AWS or Joyent on Ubuntu
|
||||
path: /v1.0/docs/getting-started-guides/juju/
|
||||
- title: Rackspace on CoreOS
|
||||
path: /v1.0/docs/getting-started-guides/rackspace/
|
||||
- title: On-Premise VMs
|
||||
section:
|
||||
- title: Vagrant or VMware
|
||||
path: /v1.0/docs/getting-started-guides/coreos/
|
||||
- title: Cloudstack
|
||||
path: /v1.0/docs/getting-started-guides/cloudstack/
|
||||
- title: VMWare
|
||||
path: /v1.0/docs/getting-started-guides/vsphere/
|
||||
- title: Juju
|
||||
path: /v1.0/docs/getting-started-guides/juju/
|
||||
- title: libvirt on CoreOS
|
||||
path: /v1.0/docs/getting-started-guides/libvirt-coreos/
|
||||
- title: oVirt
|
||||
path: /v1.0/docs/getting-started-guides/ovirt/
|
||||
- title: libvirt or KVM
|
||||
path: /v1.0/docs/getting-started-guides/fedora/flannel_multi_node_cluster/
|
||||
- title: Bare Metal
|
||||
section:
|
||||
- title: Offline
|
||||
path: /v1.0/docs/getting-started-guides/coreos/bare_metal_offline/
|
||||
- title: Fedora via Ansible
|
||||
path: /v1.0/docs/getting-started-guides/fedora/fedora_ansible_config/
|
||||
- title: Fedora (Single Node)
|
||||
path: /v1.0/docs/getting-started-guides/fedora/fedora_manual_config/
|
||||
- title: Fedora (Multi Node)
|
||||
path: /v1.0/docs/getting-started-guides/fedora/flannel_multi_node_cluster/
|
||||
- title: Centos
|
||||
path: /v1.0/docs/getting-started-guides/centos/centos_manual_config/
|
||||
- title: Ubuntu
|
||||
path: /v1.0/docs/getting-started-guides/ubuntu/
|
||||
- title: Docker (Multi Node)
|
||||
path: /v1.0/docs/getting-started-guides/docker-multinode/
|
||||
|
||||
- title: Administering Clusters
|
||||
section:
|
||||
- title: Kubernetes Cluster Admin Guide
|
||||
path: /v1.0/docs/admin/
|
||||
- title: Using Multiple Clusters
|
||||
path: /v1.0/docs/admin/multi-cluster/
|
||||
- title: Using Large Clusters
|
||||
path: /v1.0/docs/admin/cluster-large/
|
||||
- title: Building High-Availability Clusters
|
||||
path: /v1.0/docs/admin/high-availability/
|
||||
- title: Accessing Clusters
|
||||
path: /v1.0/docs/user-guide/accessing-the-cluster/
|
||||
- title: Sharing a Cluster
|
||||
path: /v1.0/docs/admin/namespaces/
|
||||
- title: Changing Cluster Size
|
||||
path: https://github.com/kubernetes/kubernetes/wiki/User-FAQ#how-do-i-change-the-size-of-my-cluster/
|
||||
- title: Creating a Custom Cluster from Scratch
|
||||
path: /v1.0/docs/getting-started-guides/scratch/
|
||||
- title: Authenticating Across Clusters with kubeconfig
|
||||
path: /v1.0/docs/user-guide/kubeconfig-file/
|
||||
|
||||
- title: Using Nodes, Pods, and Containers
|
||||
section:
|
||||
- title: Assigning Pods to Nodes
|
||||
path: /v1.0/docs/user-guide/node-selection/
|
||||
- title: Working with Containers
|
||||
path: /v1.0/docs/user-guide/production-pods/
|
||||
- title: Creating Pods with the Downward API
|
||||
path: /v1.0/docs/user-guide/downward-api/
|
||||
- title: Updating Live Pods
|
||||
path: /v1.0/docs/user-guide/update-demo/
|
||||
- title: Running Commands in a Container with kubectl exec
|
||||
path: /v1.0/docs/user-guide/getting-into-containers/
|
||||
|
||||
- title: Networking
|
||||
section:
|
||||
- title: Networking in Kubernetes
|
||||
path: /v1.0/docs/admin/networking/
|
||||
- title: Setting Up and Configuring DNS
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/cluster-dns
|
||||
- title: Connecting Applications
|
||||
path: /v1.0/docs/user-guide/connecting-applications/
|
||||
- title: Creating Servers with External IPs
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/examples/simple-nginx.md
|
||||
- title: Using DNS Pods and Services
|
||||
path: /v1.0/docs/admin/dns/
|
||||
- title: Connect with Proxies
|
||||
path: /v1.0/docs/user-guide/connecting-to-applications-proxy/
|
||||
- title: Connect with Port Forwarding
|
||||
path: /v1.0/docs/user-guide/connecting-to-applications-port-forward/
|
||||
|
||||
- title: Configuring Kubernetes
|
||||
section:
|
||||
- title: Using Configuration Files
|
||||
path: /v1.0/docs/user-guide/simple-yaml/
|
||||
- title: Configuring Containers
|
||||
path: /v1.0/docs/user-guide/configuring-containers/
|
||||
- title: Using Environment Variables
|
||||
path: /v1.0/docs/user-guide/environment-guide/
|
||||
- title: Managing Compute Resources
|
||||
path: /v1.0/docs/user-guide/compute-resources/
|
||||
- title: Applying Resource Quotas and Limits
|
||||
path: /v1.0/docs/admin/resourcequota/
|
||||
- title: Setting Pod CPU and Memory Limits
|
||||
path: /v1.0/docs/admin/limitrange/
|
||||
- title: Configuring Garbage Collection
|
||||
path: /v1.0/docs/admin/garbage-collection/
|
||||
- title: Configuring Kubernetes with Salt
|
||||
path: /v1.0/docs/admin/salt/
|
||||
- title: Best Practices for Configuration
|
||||
path: /v1.0/docs/user-guide/config-best-practices/
|
||||
|
||||
- title: Application Management and Deployment
|
||||
section:
|
||||
- title: "Managing Applications: Prerequisites"
|
||||
path: /v1.0/docs/user-guide/prereqs/
|
||||
- title: Managing Deployments
|
||||
path: /v1.0/docs/user-guide/managing-deployments/
|
||||
- title: Deploying Applications
|
||||
path: /v1.0/docs/user-guide/deploying-applications/
|
||||
- title: Launching, Exposing, and Killing Applications
|
||||
path: /v1.0/docs/user-guide/quick-start/
|
||||
|
||||
- title: Testing and Monitoring
|
||||
section:
|
||||
- title: Simulating Large Test Loads
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/k8petstore
|
||||
- title: Checking Pod Health
|
||||
path: /v1.0/docs/user-guide/liveness/
|
||||
- title: Using Explorer to Examine the Runtime Environment
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/explorer
|
||||
- title: Resource Usage Monitoring
|
||||
path: /v1.0/docs/user-guide/monitoring/
|
||||
- title: Logging
|
||||
path: /v1.0/docs/user-guide/logging/
|
|
@ -0,0 +1,16 @@
|
|||
overrides:
|
||||
- path: v1.0/docs/man
|
||||
- path: v1.0/docs/proposals
|
||||
- path: v1.0/docs/api-reference
|
||||
- path: v1.0/docs/user-guide/kubectl
|
||||
- path: v1.0/docs/admin/kube-apiserver.md
|
||||
- path: v1.0/docs/admin/kube-controller-manager.md
|
||||
- path: v1.0/docs/admin/kube-proxy.md
|
||||
- path: v1.0/docs/admin/kube-scheduler.md
|
||||
- path: v1.0/docs/admin/kubelet.md
|
||||
- path: v1.0/docs/user-guide/kubectl
|
||||
- path: v1.0/docs/admin/kube-apiserver.md
|
||||
- path: v1.0/docs/admin/kube-controller-manager.md
|
||||
- path: v1.0/docs/admin/kube-proxy.md
|
||||
- path: v1.0/docs/admin/kube-scheduler.md
|
||||
- path: v1.0/docs/admin/kubelet.md
|
|
@ -0,0 +1,184 @@
|
|||
bigheader: "Reference Documentation"
|
||||
abstract: "Design docs, concept definitions, and references for APIs and CLIs."
|
||||
toc:
|
||||
- title: Reference Documentation
|
||||
path: /v1.0/reference/
|
||||
|
||||
- title: Kubernetes API
|
||||
section:
|
||||
- title: Kubernetes API Overview
|
||||
path: /v1.0/docs/api/
|
||||
- title: Kubernetes API Operations
|
||||
path: http://kubernetes.io/v1.0/docs/api-reference/v1/operations.html
|
||||
- title: Kubernetes API Definitions
|
||||
path: http://kubernetes.io/v1.0/docs/api-reference/v1/definitions.html
|
||||
|
||||
- title: Extensions API
|
||||
section:
|
||||
- title: Extensions API Operations
|
||||
path: http://kubernetes.io/v1.0/docs/api-reference/extensions/v1beta1/operations.html
|
||||
- title: Extensions API Definitions
|
||||
path: http://kubernetes.io/v1.0/docs/api-reference/extensions/v1beta1/definitions.html
|
||||
|
||||
- title: kubectl
|
||||
section:
|
||||
- title: kubectl Overview
|
||||
path: /v1.0/docs/user-guide/kubectl-overview/
|
||||
- title: kubectl for Docker Users
|
||||
path: /v1.0/docs/user-guide/docker-cli-to-kubectl/
|
||||
- title: kubectl Commands
|
||||
section:
|
||||
- title: kubectl
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl.md
|
||||
- title: kubectl annotate
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_annotate.md
|
||||
- title: kubectl api-versions
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_api-versions.md
|
||||
- title: kubectl apply
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_apply.md
|
||||
- title: kubectl attach
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_attach.md
|
||||
- title: kubectl autoscale
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_autoscale.md
|
||||
- title: kubectl cluster-info
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_cluster-info.md
|
||||
- title: kubectl config
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config.md
|
||||
- title: kubectl config set-cluster
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_set-cluster.md
|
||||
- title: kubectl config set-context
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_set-context.md
|
||||
- title: kubectl set-credentials
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_set-credentials.md
|
||||
- title: kubectl config set
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_set.md
|
||||
- title: kubectl config unset
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_unset.md
|
||||
- title: kubectl config use-context
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_use-context.md
|
||||
- title: kubectl config view
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_view.md
|
||||
- title: kubectl create
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_create.md
|
||||
- title: kubectl delete
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_delete.md
|
||||
- title: kubectl describe
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_describe.md
|
||||
- title: kubectl edit
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_edit.md
|
||||
- title: kubectl exec
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_exec.md
|
||||
- title: kubectl expose
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_expose.md
|
||||
- title: kubectl get
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_get.md
|
||||
- title: kubectl label
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_label.md
|
||||
- title: kubectl logs
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_logs.md
|
||||
- title: kubectl patch
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_patch.md
|
||||
- title: kubectl port-forward
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_port-forward.md
|
||||
- title: kubectl proxy
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_proxy.md
|
||||
- title: kubectl replace
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_replace.md
|
||||
- title: kubectl rolling-update
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_rolling-update.md
|
||||
- title: kubectl run
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_run.md
|
||||
- title: kubectl scale
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_scale.md
|
||||
- title: kubectl stop
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_stop.md
|
||||
- title: kubectl version
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_version.md
|
||||
|
||||
- title: kube-apiserver
|
||||
section:
|
||||
- title: Overview
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/admin/kube-apiserver.md
|
||||
- title: Authorization Plugins
|
||||
path: /v1.0/docs/admin/authorization/
|
||||
- title: Authentication
|
||||
path: /v1.0/docs/admin/authentication/
|
||||
- title: Accessing the API
|
||||
path: /v1.0/docs/admin/accessing-the-api/
|
||||
- title: Admission Controllers
|
||||
path: /v1.0/docs/admin/admission-controllers/
|
||||
- title: Managing Service Accounts
|
||||
path: /v1.0/docs/admin/service-accounts-admin/
|
||||
|
||||
- title: kub-scheduler
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/admin/kube-scheduler.md
|
||||
|
||||
- title: kubelet
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/admin/kubelet.md
|
||||
|
||||
- title: kube-proxy
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/admin/kube-proxy.md
|
||||
|
||||
- title: JSONpath
|
||||
path: /v1.0/docs/user-guide/jsonpath/
|
||||
|
||||
- title: etcd
|
||||
path: /v1.0/docs/admin/etcd/
|
||||
|
||||
- title: Concept Definitions
|
||||
section:
|
||||
- title: Container Environment
|
||||
path: /v1.0/docs/user-guide/container-environment/
|
||||
- title: Images
|
||||
path: /v1.0/docs/user-guide/images/
|
||||
- title: Pods
|
||||
path: /v1.0/docs/user-guide/pods/
|
||||
- title: Labels and Selectors
|
||||
path: /v1.0/docs/user-guide/labels/
|
||||
- title: Replication Controller
|
||||
path: /v1.0/docs/user-guide/replication-controller/
|
||||
- title: Services
|
||||
path: /v1.0/docs/user-guide/services/
|
||||
- title: Volumes
|
||||
path: /v1.0/docs/user-guide/volumes/
|
||||
- title: Persistent Volumes
|
||||
path: /v1.0/docs/user-guide/persistent-volumes/
|
||||
- title: Secrets
|
||||
path: /v1.0/docs/user-guide/secrets/
|
||||
- title: Names
|
||||
path: /v1.0/docs/user-guide/identifiers/
|
||||
- title: Namespaces
|
||||
path: /v1.0/docs/user-guide/namespaces/
|
||||
- title: Nodes
|
||||
path: /v1.0/docs/admin/node/
|
||||
- title: Service Accounts
|
||||
path: /v1.0/docs/user-guide/service-accounts/
|
||||
- title: Annotations
|
||||
path: /v1.0/docs/user-guide/annotations/
|
||||
- title: Daemon Sets
|
||||
path: /v1.0/docs/admin/daemons/
|
||||
- title: Deployments
|
||||
path: /v1.0/docs/user-guide/deployments/
|
||||
- title: Ingress Resources
|
||||
path: /v1.0/docs/user-guide/ingress/
|
||||
- title: Horizontal Pod Autoscaling
|
||||
path: /v1.0/docs/user-guide/horizontal-pod-autoscaler/
|
||||
- title: Jobs
|
||||
path: /v1.0/docs/user-guide/jobs/
|
||||
- title: Resource Quotas
|
||||
path: /v1.0/docs/admin/resource-quota/
|
||||
|
||||
- title: Kubernetes Design Docs
|
||||
section:
|
||||
- title: Kubernetes Architecture
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/architecture.md
|
||||
- title: Kubernetes Design Overview
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/
|
||||
- title: Security in Kubernetes
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/security.md
|
||||
- title: Kubernetes Identity and Access Management
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/access.md
|
||||
- title: Security Contexts
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/security_context.md
|
||||
- title: Kubernetes OpenVSwitch GRE/VxLAN networking
|
||||
path: /v1.0/docs/admin/ovs-networking/
|
|
@ -0,0 +1,54 @@
|
|||
bigheader: "Samples"
|
||||
abstract: "A collection of example applications that show how to use Kubernetes."
|
||||
toc:
|
||||
- title: Samples
|
||||
path: /v1.0/samples/
|
||||
|
||||
- title: Clustered Application Samples
|
||||
section:
|
||||
- title: Apache Cassandra Database
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/cassandra
|
||||
- title: Apache Spark
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/spark
|
||||
- title: Apache Storm
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/storm
|
||||
- title: Distributed Task Queue
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/celery-rabbitmq
|
||||
- title: Hazelcast
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/hazelcast
|
||||
- title: Meteor Applications
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/meteor/
|
||||
- title: Redis
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/redis/
|
||||
- title: RethinkDB
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/rethinkdb/
|
||||
- title: Elasticsearch/Kibana Logging Demonstration
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/logging-demo/
|
||||
- title: Elasticsearch
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/elasticsearch/
|
||||
- title: OpenShift Origin
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/openshift-origin/
|
||||
- title: Ceph
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/rbd/
|
||||
- title: MEAN stack on Google Cloud Platform
|
||||
path: /v1.0/docs/getting-started-guides/meanstack/
|
||||
|
||||
- title: Persistent Volume Samples
|
||||
section:
|
||||
- title: WordPress on a Kubernetes Persistent Volume
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/mysql-wordpress-pd/
|
||||
- title: GlusterFS
|
||||
path: /https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/glusterfs/
|
||||
- title: iSCSI
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/iscsi/
|
||||
- title: NFS
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/nfs/
|
||||
|
||||
- title: Multi-tier Application Samples
|
||||
section:
|
||||
- title: Guestbook - Go Server
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/guestbook-go/
|
||||
- title: GuestBook - PHP Server
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/guestbook/
|
||||
- title: MySQL - Phabricator Server
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/phabricator/
|
|
@ -0,0 +1,40 @@
|
|||
bigheader: "Support"
|
||||
abstract: "Troubleshooting resources, frequently asked questions, and community support channels."
|
||||
toc:
|
||||
- title: Support
|
||||
path: /v1.0/docs/troubleshooting/
|
||||
|
||||
- title: Troubleshooting
|
||||
section:
|
||||
- title: Web Interface
|
||||
path: /v1.0/docs/user-guide/ui/
|
||||
- title: Troubleshooting Applications
|
||||
path: /v1.0/docs/user-guide/application-troubleshooting/
|
||||
- title: Troubleshooting Clusters
|
||||
path: /v1.0/docs/admin/cluster-troubleshooting/
|
||||
|
||||
- title: Frequently Asked Questions
|
||||
section:
|
||||
- title: User FAQ
|
||||
path: https://github.com/kubernetes/kubernetes/wiki/User-FAQ/
|
||||
- title: Debugging FAQ
|
||||
path: https://github.com/kubernetes/kubernetes/wiki/Debugging-FAQ/
|
||||
- title: Services FAQ
|
||||
path: https://github.com/kubernetes/kubernetes/wiki/Services-FAQ/
|
||||
|
||||
- title: Other Resources
|
||||
section:
|
||||
- title: Known Issues
|
||||
path: /v1.0/docs/user-guide/known-issues/
|
||||
- title: Kubernetes Issue Tracker on GitHub
|
||||
path: https://github.com/kubernetes/kubernetes/issues/
|
||||
- title: Report a Security Vulnerability
|
||||
path: /v1.0/docs/reporting-security-issues/
|
||||
- title: Release Notes
|
||||
path: https://github.com/kubernetes/kubernetes/releases/
|
||||
- title: Release Roadmap
|
||||
path: /v1.0/docs/roadmap/
|
||||
- title: Contributing to Kubernetes Documentation
|
||||
path: /v1.0/editdocs/
|
||||
- title: Sitemap for v1.0
|
||||
path: /v1.0/pagelist/
|
|
@ -0,0 +1,5 @@
|
|||
tocs:
|
||||
- guides
|
||||
- reference
|
||||
- samples
|
||||
- support
|
|
@ -0,0 +1,179 @@
|
|||
bigheader: "Guides"
|
||||
abstract: "How to get started, and acheive tasks, using Kubernetes"
|
||||
toc:
|
||||
- title: Guides
|
||||
path: /v1.2/
|
||||
|
||||
- title: Quickstarts
|
||||
section:
|
||||
- title: What is Kubernetes?
|
||||
path: /v1.2/docs/whatisk8s/
|
||||
- title: TODO - 5-minute Quickstart
|
||||
path: /v1.2/docs/hellonode/
|
||||
- title: Kubernetes 101
|
||||
path: /v1.2/docs/user-guide/walkthrough/
|
||||
- title: Kubernetes 201
|
||||
path: /v1.2/docs/user-guide/walkthrough/k8s201/
|
||||
|
||||
- title: Running Kubernetes
|
||||
section:
|
||||
- title: Picking the Right Solution
|
||||
path: /v1.2/docs/getting-started-guides/
|
||||
- title: Running Kubernetes on Your Local Machine
|
||||
section:
|
||||
- title: Running Kubernetes Locally via Docker
|
||||
path: /v1.2/docs/getting-started-guides/docker/
|
||||
- title: Running Kubernetes Locally via Vagrant
|
||||
path: /v1.2/docs/getting-started-guides/vagrant/
|
||||
- title: Running Kubernetes Locally with No VM
|
||||
path: /v1.2/docs/getting-started-guides/locally/
|
||||
- title: Running Kubernetes on Turn-key Cloud Solutions
|
||||
section:
|
||||
- title: Running Kubernetes on Google Container Engine
|
||||
path: https://cloud.google.com/container-engine/docs/before-you-begin/
|
||||
- title: Running Kubernetes on Google Compute Engine
|
||||
path: /v1.2/docs/getting-started-guides/gce/
|
||||
- title: Running Kubernetes on AWS EC2
|
||||
path: /v1.2/docs/getting-started-guides/aws/
|
||||
- title: Running Kubernetes on Azure
|
||||
path: /v1.2/docs/getting-started-guides/coreos/azure/
|
||||
- title: Running Kubernetes on Custom Solutions
|
||||
section:
|
||||
- title: Getting Started From Scratch
|
||||
path: /v1.2/docs/getting-started-guides/scratch/
|
||||
- title: Custom Cloud Solutions
|
||||
section:
|
||||
- title: AWS or GCE on CoreOS
|
||||
path: /v1.2/docs/getting-started-guides/coreos/
|
||||
- title: AWS or Joyent on Ubuntu
|
||||
path: /v1.2/docs/getting-started-guides/juju/
|
||||
- title: Rackspace on CoreOS
|
||||
path: /v1.2/docs/getting-started-guides/rackspace/
|
||||
- title: On-Premise VMs
|
||||
section:
|
||||
- title: Vagrant or VMware
|
||||
path: /v1.2/docs/getting-started-guides/coreos/
|
||||
- title: Cloudstack
|
||||
path: /v1.2/docs/getting-started-guides/cloudstack/
|
||||
- title: VMWare
|
||||
path: /v1.2/docs/getting-started-guides/vsphere/
|
||||
- title: Juju
|
||||
path: /v1.2/docs/getting-started-guides/juju/
|
||||
- title: libvirt on CoreOS
|
||||
path: /v1.2/docs/getting-started-guides/libvirt-coreos/
|
||||
- title: oVirt
|
||||
path: /v1.2/docs/getting-started-guides/ovirt/
|
||||
- title: libvirt or KVM
|
||||
path: /v1.2/docs/getting-started-guides/fedora/flannel_multi_node_cluster/
|
||||
- title: Bare Metal
|
||||
section:
|
||||
- title: Offline
|
||||
path: /v1.2/docs/getting-started-guides/coreos/bare_metal_offline/
|
||||
- title: Fedora via Ansible
|
||||
path: /v1.2/docs/getting-started-guides/fedora/fedora_ansible_config/
|
||||
- title: Fedora (Single Node)
|
||||
path: /v1.2/docs/getting-started-guides/fedora/fedora_manual_config/
|
||||
- title: Fedora (Multi Node)
|
||||
path: /v1.2/docs/getting-started-guides/fedora/flannel_multi_node_cluster/
|
||||
- title: Centos
|
||||
path: /v1.2/docs/getting-started-guides/centos/centos_manual_config/
|
||||
- title: Ubuntu
|
||||
path: /v1.2/docs/getting-started-guides/ubuntu/
|
||||
- title: Docker (Multi Node)
|
||||
path: /v1.2/docs/getting-started-guides/docker-multinode/
|
||||
|
||||
- title: Administering Clusters
|
||||
section:
|
||||
- title: Kubernetes Cluster Admin Guide
|
||||
path: /v1.2/docs/admin/
|
||||
- title: Using Multiple Clusters
|
||||
path: /v1.2/docs/admin/multi-cluster/
|
||||
- title: Using Large Clusters
|
||||
path: /v1.2/docs/admin/cluster-large/
|
||||
- title: Building High-Availability Clusters
|
||||
path: /v1.2/docs/admin/high-availability/
|
||||
- title: Accessing Clusters
|
||||
path: /v1.2/docs/user-guide/accessing-the-cluster/
|
||||
- title: Sharing a Cluster
|
||||
path: /v1.2/docs/admin/namespaces/
|
||||
- title: Changing Cluster Size
|
||||
path: https://github.com/kubernetes/kubernetes/wiki/User-FAQ#how-do-i-change-the-size-of-my-cluster/
|
||||
- title: Creating a Custom Cluster from Scratch
|
||||
path: /v1.2/docs/getting-started-guides/scratch/
|
||||
- title: Authenticating Across Clusters with kubeconfig
|
||||
path: /v1.2/docs/user-guide/kubeconfig-file/
|
||||
|
||||
- title: Using Nodes, Pods, and Containers
|
||||
section:
|
||||
- title: Assigning Pods to Nodes
|
||||
path: /v1.2/docs/user-guide/node-selection/
|
||||
- title: Working with Containers
|
||||
path: /v1.2/docs/user-guide/production-pods/
|
||||
- title: Creating Pods with the Downward API
|
||||
path: /v1.2/docs/user-guide/downward-api/
|
||||
- title: Updating Live Pods
|
||||
path: /v1.2/docs/user-guide/update-demo/
|
||||
- title: Running Commands in a Container with kubectl exec
|
||||
path: /v1.2/docs/user-guide/getting-into-containers/
|
||||
|
||||
- title: Networking
|
||||
section:
|
||||
- title: Networking in Kubernetes
|
||||
path: /v1.2/docs/admin/networking/
|
||||
- title: Setting Up and Configuring DNS
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/cluster-dns
|
||||
- title: Connecting Applications
|
||||
path: /v1.2/docs/user-guide/connecting-applications/
|
||||
- title: Creating Servers with External IPs
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/examples/simple-nginx.md
|
||||
- title: Using DNS Pods and Services
|
||||
path: /v1.2/docs/admin/dns/
|
||||
- title: Connect with Proxies
|
||||
path: /v1.2/docs/user-guide/connecting-to-applications-proxy/
|
||||
- title: Connect with Port Forwarding
|
||||
path: /v1.2/docs/user-guide/connecting-to-applications-port-forward/
|
||||
|
||||
- title: Configuring Kubernetes
|
||||
section:
|
||||
- title: Using Configuration Files
|
||||
path: /v1.2/docs/user-guide/simple-yaml/
|
||||
- title: Configuring Containers
|
||||
path: /v1.2/docs/user-guide/configuring-containers/
|
||||
- title: Using Environment Variables
|
||||
path: /v1.2/docs/user-guide/environment-guide/
|
||||
- title: Managing Compute Resources
|
||||
path: /v1.2/docs/user-guide/compute-resources/
|
||||
- title: Applying Resource Quotas and Limits
|
||||
path: /v1.2/docs/admin/resourcequota/
|
||||
- title: Setting Pod CPU and Memory Limits
|
||||
path: /v1.2/docs/admin/limitrange/
|
||||
- title: Configuring Garbage Collection
|
||||
path: /v1.2/docs/admin/garbage-collection/
|
||||
- title: Configuring Kubernetes with Salt
|
||||
path: /v1.2/docs/admin/salt/
|
||||
- title: Best Practices for Configuration
|
||||
path: /v1.2/docs/user-guide/config-best-practices/
|
||||
|
||||
- title: Application Management and Deployment
|
||||
section:
|
||||
- title: "Managing Applications: Prerequisites"
|
||||
path: /v1.2/docs/user-guide/prereqs/
|
||||
- title: Managing Deployments
|
||||
path: /v1.2/docs/user-guide/managing-deployments/
|
||||
- title: Deploying Applications
|
||||
path: /v1.2/docs/user-guide/deploying-applications/
|
||||
- title: Launching, Exposing, and Killing Applications
|
||||
path: /v1.2/docs/user-guide/quick-start/
|
||||
|
||||
- title: Testing and Monitoring
|
||||
section:
|
||||
- title: Simulating Large Test Loads
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/k8petstore
|
||||
- title: Checking Pod Health
|
||||
path: /v1.2/docs/user-guide/liveness/
|
||||
- title: Using Explorer to Examine the Runtime Environment
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/explorer
|
||||
- title: Resource Usage Monitoring
|
||||
path: /v1.2/docs/user-guide/monitoring/
|
||||
- title: Logging
|
||||
path: /v1.2/docs/user-guide/logging/
|
|
@ -0,0 +1,16 @@
|
|||
overrides:
|
||||
- path: v1.2/docs/man
|
||||
- path: v1.2/docs/proposals
|
||||
- path: v1.2/docs/api-reference
|
||||
- path: v1.2/docs/user-guide/kubectl
|
||||
- path: v1.2/docs/admin/kube-apiserver.md
|
||||
- path: v1.2/docs/admin/kube-controller-manager.md
|
||||
- path: v1.2/docs/admin/kube-proxy.md
|
||||
- path: v1.2/docs/admin/kube-scheduler.md
|
||||
- path: v1.2/docs/admin/kubelet.md
|
||||
- path: v1.0/docs/user-guide/kubectl
|
||||
- path: v1.0/docs/admin/kube-apiserver.md
|
||||
- path: v1.0/docs/admin/kube-controller-manager.md
|
||||
- path: v1.0/docs/admin/kube-proxy.md
|
||||
- path: v1.0/docs/admin/kube-scheduler.md
|
||||
- path: v1.0/docs/admin/kubelet.md
|
|
@ -0,0 +1,184 @@
|
|||
bigheader: "Reference Documentation"
|
||||
abstract: "Design docs, concept definitions, and references for APIs and CLIs."
|
||||
toc:
|
||||
- title: Reference Documentation
|
||||
path: /v1.2/reference/
|
||||
|
||||
- title: Kubernetes API
|
||||
section:
|
||||
- title: Kubernetes API Overview
|
||||
path: /v1.2/docs/api/
|
||||
- title: Kubernetes API Operations
|
||||
path: http://kubernetes.io/v1.2/docs/api-reference/v1/operations.html
|
||||
- title: Kubernetes API Definitions
|
||||
path: http://kubernetes.io/v1.2/docs/api-reference/v1/definitions.html
|
||||
|
||||
- title: Extensions API
|
||||
section:
|
||||
- title: Extensions API Operations
|
||||
path: http://kubernetes.io/v1.2/docs/api-reference/extensions/v1beta1/operations.html
|
||||
- title: Extensions API Definitions
|
||||
path: http://kubernetes.io/v1.2/docs/api-reference/extensions/v1beta1/definitions.html
|
||||
|
||||
- title: kubectl
|
||||
section:
|
||||
- title: kubectl Overview
|
||||
path: /v1.2/docs/user-guide/kubectl-overview/
|
||||
- title: kubectl for Docker Users
|
||||
path: /v1.2/docs/user-guide/docker-cli-to-kubectl/
|
||||
- title: kubectl Commands
|
||||
section:
|
||||
- title: kubectl
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl.md
|
||||
- title: kubectl annotate
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_annotate.md
|
||||
- title: kubectl api-versions
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_api-versions.md
|
||||
- title: kubectl apply
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_apply.md
|
||||
- title: kubectl attach
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_attach.md
|
||||
- title: kubectl autoscale
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_autoscale.md
|
||||
- title: kubectl cluster-info
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_cluster-info.md
|
||||
- title: kubectl config
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config.md
|
||||
- title: kubectl config set-cluster
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_set-cluster.md
|
||||
- title: kubectl config set-context
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_set-context.md
|
||||
- title: kubectl set-credentials
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_set-credentials.md
|
||||
- title: kubectl config set
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_set.md
|
||||
- title: kubectl config unset
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_unset.md
|
||||
- title: kubectl config use-context
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_use-context.md
|
||||
- title: kubectl config view
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_config_view.md
|
||||
- title: kubectl create
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_create.md
|
||||
- title: kubectl delete
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_delete.md
|
||||
- title: kubectl describe
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_describe.md
|
||||
- title: kubectl edit
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_edit.md
|
||||
- title: kubectl exec
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_exec.md
|
||||
- title: kubectl expose
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_expose.md
|
||||
- title: kubectl get
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_get.md
|
||||
- title: kubectl label
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_label.md
|
||||
- title: kubectl logs
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_logs.md
|
||||
- title: kubectl patch
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_patch.md
|
||||
- title: kubectl port-forward
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_port-forward.md
|
||||
- title: kubectl proxy
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_proxy.md
|
||||
- title: kubectl replace
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_replace.md
|
||||
- title: kubectl rolling-update
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_rolling-update.md
|
||||
- title: kubectl run
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_run.md
|
||||
- title: kubectl scale
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_scale.md
|
||||
- title: kubectl stop
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_stop.md
|
||||
- title: kubectl version
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/user-guide/kubectl/kubectl_version.md
|
||||
|
||||
- title: kube-apiserver
|
||||
section:
|
||||
- title: Overview
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/admin/kube-apiserver.md
|
||||
- title: Authorization Plugins
|
||||
path: /v1.2/docs/admin/authorization/
|
||||
- title: Authentication
|
||||
path: /v1.2/docs/admin/authentication/
|
||||
- title: Accessing the API
|
||||
path: /v1.2/docs/admin/accessing-the-api/
|
||||
- title: Admission Controllers
|
||||
path: /v1.2/docs/admin/admission-controllers/
|
||||
- title: Managing Service Accounts
|
||||
path: /v1.2/docs/admin/service-accounts-admin/
|
||||
|
||||
- title: kub-scheduler
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/admin/kube-scheduler.md
|
||||
|
||||
- title: kubelet
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/admin/kubelet.md
|
||||
|
||||
- title: kube-proxy
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/admin/kube-proxy.md
|
||||
|
||||
- title: JSONpath
|
||||
path: /v1.2/docs/user-guide/jsonpath/
|
||||
|
||||
- title: etcd
|
||||
path: /v1.2/docs/admin/etcd/
|
||||
|
||||
- title: Concept Definitions
|
||||
section:
|
||||
- title: Container Environment
|
||||
path: /v1.2/docs/user-guide/container-environment/
|
||||
- title: Images
|
||||
path: /v1.2/docs/user-guide/images/
|
||||
- title: Pods
|
||||
path: /v1.2/docs/user-guide/pods/
|
||||
- title: Labels and Selectors
|
||||
path: /v1.2/docs/user-guide/labels/
|
||||
- title: Replication Controller
|
||||
path: /v1.2/docs/user-guide/replication-controller/
|
||||
- title: Services
|
||||
path: /v1.2/docs/user-guide/services/
|
||||
- title: Volumes
|
||||
path: /v1.2/docs/user-guide/volumes/
|
||||
- title: Persistent Volumes
|
||||
path: /v1.2/docs/user-guide/persistent-volumes/
|
||||
- title: Secrets
|
||||
path: /v1.2/docs/user-guide/secrets/
|
||||
- title: Names
|
||||
path: /v1.2/docs/user-guide/identifiers/
|
||||
- title: Namespaces
|
||||
path: /v1.2/docs/user-guide/namespaces/
|
||||
- title: Nodes
|
||||
path: /v1.2/docs/admin/node/
|
||||
- title: Service Accounts
|
||||
path: /v1.2/docs/user-guide/service-accounts/
|
||||
- title: Annotations
|
||||
path: /v1.2/docs/user-guide/annotations/
|
||||
- title: Daemon Sets
|
||||
path: /v1.2/docs/admin/daemons/
|
||||
- title: Deployments
|
||||
path: /v1.2/docs/user-guide/deployments/
|
||||
- title: Ingress Resources
|
||||
path: /v1.2/docs/user-guide/ingress/
|
||||
- title: Horizontal Pod Autoscaling
|
||||
path: /v1.2/docs/user-guide/horizontal-pod-autoscaler/
|
||||
- title: Jobs
|
||||
path: /v1.2/docs/user-guide/jobs/
|
||||
- title: Resource Quotas
|
||||
path: /v1.2/docs/admin/resource-quota/
|
||||
|
||||
- title: Kubernetes Design Docs
|
||||
section:
|
||||
- title: Kubernetes Architecture
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/architecture.md
|
||||
- title: Kubernetes Design Overview
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/
|
||||
- title: Security in Kubernetes
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/security.md
|
||||
- title: Kubernetes Identity and Access Management
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/access.md
|
||||
- title: Security Contexts
|
||||
path: https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/security_context.md
|
||||
- title: Kubernetes OpenVSwitch GRE/VxLAN networking
|
||||
path: /v1.2/docs/admin/ovs-networking/
|
|
@ -0,0 +1,54 @@
|
|||
bigheader: "Samples"
|
||||
abstract: "A collection of example applications that show how to use Kubernetes."
|
||||
toc:
|
||||
- title: Samples
|
||||
path: /v1.2/samples/
|
||||
|
||||
- title: Clustered Application Samples
|
||||
section:
|
||||
- title: Apache Cassandra Database
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/cassandra
|
||||
- title: Apache Spark
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/spark
|
||||
- title: Apache Storm
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/storm
|
||||
- title: Distributed Task Queue
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/celery-rabbitmq
|
||||
- title: Hazelcast
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/hazelcast
|
||||
- title: Meteor Applications
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/meteor/
|
||||
- title: Redis
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/redis/
|
||||
- title: RethinkDB
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/rethinkdb/
|
||||
- title: Elasticsearch/Kibana Logging Demonstration
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/logging-demo/
|
||||
- title: Elasticsearch
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/elasticsearch/
|
||||
- title: OpenShift Origin
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/openshift-origin/
|
||||
- title: Ceph
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/rbd/
|
||||
- title: MEAN stack on Google Cloud Platform
|
||||
path: /v1.2/docs/getting-started-guides/meanstack/
|
||||
|
||||
- title: Persistent Volume Samples
|
||||
section:
|
||||
- title: WordPress on a Kubernetes Persistent Volume
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/mysql-wordpress-pd/
|
||||
- title: GlusterFS
|
||||
path: /https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/glusterfs/
|
||||
- title: iSCSI
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/iscsi/
|
||||
- title: NFS
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/nfs/
|
||||
|
||||
- title: Multi-tier Application Samples
|
||||
section:
|
||||
- title: Guestbook - Go Server
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/guestbook-go/
|
||||
- title: GuestBook - PHP Server
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/guestbook/
|
||||
- title: MySQL - Phabricator Server
|
||||
path: https://github.com/kubernetes/kubernetes/tree/release-1.1/examples/phabricator/
|
|
@ -0,0 +1,40 @@
|
|||
bigheader: "Support"
|
||||
abstract: "Troubleshooting resources, frequently asked questions, and community support channels."
|
||||
toc:
|
||||
- title: Support
|
||||
path: /v1.2/docs/troubleshooting/
|
||||
|
||||
- title: Troubleshooting
|
||||
section:
|
||||
- title: Web Interface
|
||||
path: /v1.2/docs/user-guide/ui/
|
||||
- title: Troubleshooting Applications
|
||||
path: /v1.2/docs/user-guide/application-troubleshooting/
|
||||
- title: Troubleshooting Clusters
|
||||
path: /v1.2/docs/admin/cluster-troubleshooting/
|
||||
|
||||
- title: Frequently Asked Questions
|
||||
section:
|
||||
- title: User FAQ
|
||||
path: https://github.com/kubernetes/kubernetes/wiki/User-FAQ/
|
||||
- title: Debugging FAQ
|
||||
path: https://github.com/kubernetes/kubernetes/wiki/Debugging-FAQ/
|
||||
- title: Services FAQ
|
||||
path: https://github.com/kubernetes/kubernetes/wiki/Services-FAQ/
|
||||
|
||||
- title: Other Resources
|
||||
section:
|
||||
- title: Known Issues
|
||||
path: /v1.2/docs/user-guide/known-issues/
|
||||
- title: Kubernetes Issue Tracker on GitHub
|
||||
path: https://github.com/kubernetes/kubernetes/issues/
|
||||
- title: Report a Security Vulnerability
|
||||
path: /v1.2/docs/reporting-security-issues/
|
||||
- title: Release Notes
|
||||
path: https://github.com/kubernetes/kubernetes/releases/
|
||||
- title: Release Roadmap
|
||||
path: /v1.2/docs/roadmap/
|
||||
- title: Contributing to Kubernetes Documentation
|
||||
path: /v1.2/editdocs/
|
||||
- title: Sitemap for v1.2
|
||||
path: /v1.2/pagelist/
|
|
@ -0,0 +1,73 @@
|
|||
|
||||
This document describes what ports the Kubernetes apiserver
|
||||
may serve on and how to reach them. The audience is
|
||||
cluster administrators who want to customize their cluster
|
||||
or understand the details.
|
||||
|
||||
Most questions about accessing the cluster are covered
|
||||
in [Accessing the cluster](/{{page.version}}/docs/user-guide/accessing-the-cluster).
|
||||
|
||||
|
||||
## Ports and IPs Served On
|
||||
|
||||
The Kubernetes API is served by the Kubernetes apiserver process. Typically,
|
||||
there is one of these running on a single kubernetes-master node.
|
||||
|
||||
By default the Kubernetes APIserver serves HTTP on 2 ports:
|
||||
|
||||
1. Localhost Port
|
||||
- serves HTTP
|
||||
- default is port 8080, change with `--insecure-port` flag.
|
||||
- defaults IP is localhost, change with `--insecure-bind-address` flag.
|
||||
- no authentication or authorization checks in HTTP
|
||||
- protected by need to have host access
|
||||
2. Secure Port
|
||||
- default is port 6443, change with `--secure-port` flag.
|
||||
- default IP is first non-localhost network interface, change with `--bind-address` flag.
|
||||
- serves HTTPS. Set cert with `--tls-cert-file` and key with `--tls-private-key-file` flag.
|
||||
- uses token-file or client-certificate based [authentication](/{{page.version}}/docs/admin/authentication).
|
||||
- uses policy-based [authorization](/{{page.version}}/docs/admin/authorization).
|
||||
3. Removed: ReadOnly Port
|
||||
- For security reasons, this had to be removed. Use the [service account](/{{page.version}}/docs/user-guide/service-accounts) feature instead.
|
||||
|
||||
## Proxies and Firewall rules
|
||||
|
||||
Additionally, in some configurations there is a proxy (nginx) running
|
||||
on the same machine as the apiserver process. The proxy serves HTTPS protected
|
||||
by Basic Auth on port 443, and proxies to the apiserver on localhost:8080. In
|
||||
these configurations the secure port is typically set to 6443.
|
||||
|
||||
A firewall rule is typically configured to allow external HTTPS access to port 443.
|
||||
|
||||
The above are defaults and reflect how Kubernetes is deployed to Google Compute Engine using
|
||||
kube-up.sh. Other cloud providers may vary.
|
||||
|
||||
## Use Cases vs IP:Ports
|
||||
|
||||
There are three differently configured serving ports because there are a
|
||||
variety of uses cases:
|
||||
|
||||
1. Clients outside of a Kubernetes cluster, such as human running `kubectl`
|
||||
on desktop machine. Currently, accesses the Localhost Port via a proxy (nginx)
|
||||
running on the `kubernetes-master` machine. The proxy can use cert-based authentication
|
||||
or token-based authentication.
|
||||
2. Processes running in Containers on Kubernetes that need to read from
|
||||
the apiserver. Currently, these can use a [service account](/{{page.version}}/docs/user-guide/service-accounts).
|
||||
3. Scheduler and Controller-manager processes, which need to do read-write
|
||||
API operations. Currently, these have to run on the same host as the
|
||||
apiserver and use the Localhost Port. In the future, these will be
|
||||
switched to using service accounts to avoid the need to be co-located.
|
||||
4. Kubelets, which need to do read-write API operations and are necessarily
|
||||
on different machines than the apiserver. Kubelet uses the Secure Port
|
||||
to get their pods, to find the services that a pod can see, and to
|
||||
write events. Credentials are distributed to kubelets at cluster
|
||||
setup time. Kubelet and kube-proxy can use cert-based authentication or token-based
|
||||
authentication.
|
||||
|
||||
## Expected changes
|
||||
|
||||
- Policy will limit the actions kubelets can do via the authed port.
|
||||
- Scheduler and Controller-manager will use the Secure Port too. They
|
||||
will then be able to run on different machines than the apiserver.
|
||||
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## What are they?
|
||||
|
||||
An admission control plug-in is a piece of code that intercepts requests to the Kubernetes
|
||||
API server prior to persistence of the object, but after the request is authenticated
|
||||
and authorized. The plug-in code is in the API server process
|
||||
and must be compiled into the binary in order to be used at this time.
|
||||
|
||||
Each admission control plug-in is run in sequence before a request is accepted into the cluster. If
|
||||
any of the plug-ins in the sequence reject the request, the entire request is rejected immediately
|
||||
and an error is returned to the end-user.
|
||||
|
||||
Admission control plug-ins may mutate the incoming object in some cases to apply system configured
|
||||
defaults. In addition, admission control plug-ins may mutate related resources as part of request
|
||||
processing to do things like increment quota usage.
|
||||
|
||||
## Why do I need them?
|
||||
|
||||
Many advanced features in Kubernetes require an admission control plug-in to be enabled in order
|
||||
to properly support the feature. As a result, a Kubernetes API server that is not properly
|
||||
configured with the right set of admission control plug-ins is an incomplete server and will not
|
||||
support all the features you expect.
|
||||
|
||||
## How do I turn on an admission control plug-in?
|
||||
|
||||
The Kubernetes API server supports a flag, `admission-control` that takes a comma-delimited,
|
||||
ordered list of admission control choices to invoke prior to modifying objects in the cluster.
|
||||
|
||||
## What does each plug-in do?
|
||||
|
||||
### AlwaysAdmit
|
||||
|
||||
Use this plugin by itself to pass-through all requests.
|
||||
|
||||
### AlwaysDeny
|
||||
|
||||
Rejects all requests. Used for testing.
|
||||
|
||||
### DenyExecOnPrivileged (deprecated)
|
||||
|
||||
This plug-in will intercept all requests to exec a command in a pod if that pod has a privileged container.
|
||||
|
||||
If your cluster supports privileged containers, and you want to restrict the ability of end-users to exec
|
||||
commands in those containers, we strongly encourage enabling this plug-in.
|
||||
|
||||
This functionality has been merged into [DenyEscalatingExec](#denyescalatingexec).
|
||||
|
||||
### DenyEscalatingExec
|
||||
|
||||
This plug-in will deny exec and attach commands to pods that run with escalated privileges that
|
||||
allow host access. This includes pods that run as privileged, have access to the host IPC namespace, and
|
||||
have access to the host PID namespace.
|
||||
|
||||
If your cluster supports containers that run with escalated privileges, and you want to
|
||||
restrict the ability of end-users to exec commands in those containers, we strongly encourage
|
||||
enabling this plug-in.
|
||||
|
||||
### ServiceAccount
|
||||
|
||||
This plug-in implements automation for [serviceAccounts](/{{page.version}}/docs/user-guide/service-accounts).
|
||||
We strongly recommend using this plug-in if you intend to make use of Kubernetes `ServiceAccount` objects.
|
||||
|
||||
### SecurityContextDeny
|
||||
|
||||
This plug-in will deny any pod with a [SecurityContext](/{{page.version}}/docs/user-guide/security-context) that defines options that were not available on the `Container`.
|
||||
|
||||
### ResourceQuota
|
||||
|
||||
This plug-in will observe the incoming request and ensure that it does not violate any of the constraints
|
||||
enumerated in the `ResourceQuota` object in a `Namespace`. If you are using `ResourceQuota`
|
||||
objects in your Kubernetes deployment, you MUST use this plug-in to enforce quota constraints.
|
||||
|
||||
See the [resourceQuota design doc](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/admission_control_resource_quota.md) and the [example of Resource Quota](/{{page.version}}/docs/admin/resourcequota/) for more details.
|
||||
|
||||
It is strongly encouraged that this plug-in is configured last in the sequence of admission control plug-ins. This is
|
||||
so that quota is not prematurely incremented only for the request to be rejected later in admission control.
|
||||
|
||||
### LimitRanger
|
||||
|
||||
This plug-in will observe the incoming request and ensure that it does not violate any of the constraints
|
||||
enumerated in the `LimitRange` object in a `Namespace`. If you are using `LimitRange` objects in
|
||||
your Kubernetes deployment, you MUST use this plug-in to enforce those constraints. LimitRanger can also
|
||||
be used to apply default resource requests to Pods that don't specify any; currently, the default LimitRanger
|
||||
applies a 0.1 CPU requirement to all Pods in the `default` namespace.
|
||||
|
||||
See the [limitRange design doc](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/admission_control_limit_range.md) and the [example of Limit Range](/{{page.version}}/docs/admin/limitrange/) for more details.
|
||||
|
||||
### InitialResources (experimental)
|
||||
|
||||
This plug-in observes pod creation requests. If a container omits compute resource requests and limits,
|
||||
then the plug-in auto-populates a compute resource request based on historical usage of containers running the same image.
|
||||
If there is not enough data to make a decision the Request is left unchanged.
|
||||
When the plug-in sets a compute resource request, it annotates the pod with information on what compute resources it auto-populated.
|
||||
|
||||
See the [InitialResouces proposal](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/proposals/initial-resources.md) for more details.
|
||||
|
||||
### NamespaceExists (deprecated)
|
||||
|
||||
This plug-in will observe all incoming requests that attempt to create a resource in a Kubernetes `Namespace`
|
||||
and reject the request if the `Namespace` was not previously created. We strongly recommend running
|
||||
this plug-in to ensure integrity of your data.
|
||||
|
||||
The functionality of this admission controller has been merged into `NamespaceLifecycle`
|
||||
|
||||
### NamespaceAutoProvision (deprecated)
|
||||
|
||||
This plug-in will observe all incoming requests that attempt to create a resource in a Kubernetes `Namespace`
|
||||
and create a new `Namespace` if one did not already exist previously.
|
||||
|
||||
We strongly recommend `NamespaceLifecycle` over `NamespaceAutoProvision`.
|
||||
|
||||
### NamespaceLifecycle
|
||||
|
||||
This plug-in enforces that a `Namespace` that is undergoing termination cannot have new objects created in it,
|
||||
and ensures that requests in a non-existant `Namespace` are rejected.
|
||||
|
||||
A `Namespace` deletion kicks off a sequence of operations that remove all objects (pods, services, etc.) in that
|
||||
namespace. In order to enforce integrity of that process, we strongly recommend running this plug-in.
|
||||
|
||||
## Is there a recommended set of plug-ins to use?
|
||||
|
||||
Yes.
|
||||
|
||||
For Kubernetes 1.0, we strongly recommend running the following set of admission control plug-ins (order matters):
|
||||
|
||||
```shell
|
||||
--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
||||
```
|
|
@ -0,0 +1,126 @@
|
|||
|
||||
Kubernetes uses client certificates, tokens, or http basic auth to authenticate users for API calls.
|
||||
|
||||
**Client certificate authentication** is enabled by passing the `--client-ca-file=SOMEFILE`
|
||||
option to apiserver. The referenced file must contain one or more certificates authorities
|
||||
to use to validate client certificates presented to the apiserver. If a client certificate
|
||||
is presented and verified, the common name of the subject is used as the user name for the
|
||||
request.
|
||||
|
||||
**Token File** is enabled by passing the `--token-auth-file=SOMEFILE` option
|
||||
to apiserver. Currently, tokens last indefinitely, and the token list cannot
|
||||
be changed without restarting apiserver.
|
||||
|
||||
The token file format is implemented in `plugin/pkg/auth/authenticator/token/tokenfile/...`
|
||||
and is a csv file with 3 columns: token, user name, user uid.
|
||||
|
||||
When using token authentication from an http client the apiserver expects an `Authorization`
|
||||
header with a value of `Bearer SOMETOKEN`.
|
||||
|
||||
**OpenID Connect ID Token** is enabled by passing the following options to the apiserver:
|
||||
- `--oidc-issuer-url` (required) tells the apiserver where to connect to the OpenID provider. Only HTTPS scheme will be accepted.
|
||||
- `--oidc-client-id` (required) is used by apiserver to verify the audience of the token.
|
||||
A valid [ID token](http://openid.net/specs/openid-connect-core-1_0/#IDToken) MUST have this
|
||||
client-id in its `aud` claims.
|
||||
- `--oidc-ca-file` (optional) is used by apiserver to establish and verify the secure connection
|
||||
to the OpenID provider.
|
||||
- `--oidc-username-claim` (optional, experimental) specifies which OpenID claim to use as the user name. By default, `sub`
|
||||
will be used, which should be unique and immutable under the issuer's domain. Cluster administrator can
|
||||
choose other claims such as `email` to use as the user name, but the uniqueness and immutability is not guaranteed.
|
||||
|
||||
Please note that this flag is still experimental until we settle more on how to handle the mapping of the OpenID user to the Kubernetes user. Thus further changes are possible.
|
||||
|
||||
Currently, the ID token will be obtained by some third-party app. This means the app and apiserver
|
||||
MUST share the `--oidc-client-id`.
|
||||
|
||||
Like **Token File**, when using token authentication from an http client the apiserver expects
|
||||
an `Authorization` header with a value of `Bearer SOMETOKEN`.
|
||||
|
||||
**Basic authentication** is enabled by passing the `--basic-auth-file=SOMEFILE`
|
||||
option to apiserver. Currently, the basic auth credentials last indefinitely,
|
||||
and the password cannot be changed without restarting apiserver. Note that basic
|
||||
authentication is currently supported for convenience while we finish making the
|
||||
more secure modes described above easier to use.
|
||||
|
||||
The basic auth file format is implemented in `plugin/pkg/auth/authenticator/password/passwordfile/...`
|
||||
and is a csv file with 3 columns: password, user name, user id.
|
||||
|
||||
When using basic authentication from an http client, the apiserver expects an `Authorization` header
|
||||
with a value of `Basic BASE64ENCODED(USER:PASSWORD)`.
|
||||
|
||||
**Keystone authentication** is enabled by passing the `--experimental-keystone-url=<AuthURL>`
|
||||
option to the apiserver during startup. The plugin is implemented in
|
||||
`plugin/pkg/auth/authenticator/request/keystone/keystone.go`.
|
||||
For details on how to use keystone to manage projects and users, refer to the
|
||||
[Keystone documentation](http://docs.openstack.org/developer/keystone/). Please note that
|
||||
this plugin is still experimental which means it is subject to changes.
|
||||
Please refer to the [discussion](https://github.com/kubernetes/kubernetes/pull/11798#issuecomment-129655212)
|
||||
and the [blueprint](https://github.com/kubernetes/kubernetes/issues/11626) for more details
|
||||
|
||||
## Plugin Development
|
||||
|
||||
We plan for the Kubernetes API server to issue tokens
|
||||
after the user has been (re)authenticated by a *bedrock* authentication
|
||||
provider external to Kubernetes. We plan to make it easy to develop modules
|
||||
that interface between Kubernetes and a bedrock authentication provider (e.g.
|
||||
github.com, google.com, enterprise directory, kerberos, etc.)
|
||||
|
||||
## APPENDIX
|
||||
|
||||
### Creating Certificates
|
||||
|
||||
When using client certificate authentication, you can generate certificates manually or
|
||||
using an existing deployment script.
|
||||
|
||||
**Deployment script** is implemented at
|
||||
`cluster/saltbase/salt/generate-cert/make-ca-cert.sh`.
|
||||
Execute this script with two parameters. First is the IP address of apiserver, the second is
|
||||
a list of subject alternate names in the form `IP:<ip-address> or DNS:<dns-name>`.
|
||||
The script will generate three files:ca.crt, server.crt and server.key.
|
||||
Finally, add these parameters
|
||||
`--client-ca-file=/srv/kubernetes/ca.crt`
|
||||
`--tls-cert-file=/srv/kubernetes/server.cert`
|
||||
`--tls-private-key-file=/srv/kubernetes/server.key`
|
||||
into apiserver start parameters.
|
||||
|
||||
**easyrsa** can be used to manually generate certificates for your cluster.
|
||||
|
||||
1. Download, unpack, and initialize the patched version of easyrsa3.
|
||||
|
||||
curl -L -O https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
|
||||
tar xzf easy-rsa.tar.gz
|
||||
cd easy-rsa-master/easyrsa3
|
||||
./easyrsa init-pki
|
||||
1. Generate a CA. (`--batch` set automatic mode. `--req-cn` default CN to use.)
|
||||
|
||||
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
|
||||
1. Generate server certificate and key.
|
||||
(build-server-full [filename]: Generate a keypair and sign locally for a client or server)
|
||||
|
||||
./easyrsa --subject-alt-name="IP:${MASTER_IP}" build-server-full kubernetes-master nopass
|
||||
1. Copy `pki/ca.crt` `pki/issued/kubernetes-master.crt`
|
||||
`pki/private/kubernetes-master.key` to your directory.
|
||||
1. Remember fill the parameters
|
||||
`--client-ca-file=/yourdirectory/ca.crt`
|
||||
`--tls-cert-file=/yourdirectory/server.cert`
|
||||
`--tls-private-key-file=/yourdirectory/server.key`
|
||||
and add these into apiserver start parameters.
|
||||
|
||||
**openssl** can also be use to manually generate certificates for your cluster.
|
||||
|
||||
1. Generate a ca.key with 2048bit
|
||||
`openssl genrsa -out ca.key 2048`
|
||||
1. According to the ca.key generate a ca.crt. (-days set the certificate effective time).
|
||||
`openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt`
|
||||
1. Generate a server.key with 2048bit
|
||||
`openssl genrsa -out server.key 2048`
|
||||
1. According to the server.key generate a server.csr.
|
||||
`openssl req -new -key server.key -subj "/CN=${MASTER_IP}" -out server.csr`
|
||||
1. According to the ca.key, ca.crt and server.csr generate the server.crt.
|
||||
`openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
|
||||
-days 10000`
|
||||
1. View the certificate.
|
||||
`openssl x509 -noout -text -in ./server.crt`
|
||||
Finally, do not forget fill the same parameters and add parameters into apiserver start parameters.
|
||||
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
|
||||
In Kubernetes, authorization happens as a separate step from authentication.
|
||||
See the [authentication documentation](/{{page.version}}/docs/admin/authentication) for an
|
||||
overview of authentication.
|
||||
|
||||
Authorization applies to all HTTP accesses on the main (secure) apiserver port.
|
||||
|
||||
The authorization check for any request compares attributes of the context of
|
||||
the request, (such as user, resource, and namespace) with access
|
||||
policies. An API call must be allowed by some policy in order to proceed.
|
||||
|
||||
The following implementations are available, and are selected by flag:
|
||||
|
||||
- `--authorization-mode=AlwaysDeny`
|
||||
- `--authorization-mode=AlwaysAllow`
|
||||
- `--authorization-mode=ABAC`
|
||||
|
||||
`AlwaysDeny` blocks all requests (used in tests).
|
||||
`AlwaysAllow` allows all requests; use if you don't need authorization.
|
||||
`ABAC` allows for user-configured authorization policy. ABAC stands for Attribute-Based Access Control.
|
||||
|
||||
## ABAC Mode
|
||||
|
||||
### Request Attributes
|
||||
|
||||
A request has 5 attributes that can be considered for authorization:
|
||||
|
||||
- user (the user-string which a user was authenticated as).
|
||||
- group (the list of group names the authenticated user is a member of).
|
||||
- whether the request is readonly (GETs are readonly).
|
||||
- what resource is being accessed.
|
||||
- applies only to the API endpoints, such as
|
||||
`/api/v1/namespaces/default/pods`. For miscellaneous endpoints, like `/version`, the
|
||||
resource is the empty string.
|
||||
- the namespace of the object being access, or the empty string if the
|
||||
endpoint does not support namespaced objects.
|
||||
|
||||
We anticipate adding more attributes to allow finer grained access control and
|
||||
to assist in policy management.
|
||||
|
||||
### Policy File Format
|
||||
|
||||
For mode `ABAC`, also specify `--authorization-policy-file=SOME_FILENAME`.
|
||||
|
||||
The file format is [one JSON object per line](http://jsonlines.org/). There should be no enclosing list or map, just
|
||||
one map per line.
|
||||
|
||||
Each line is a "policy object". A policy object is a map with the following properties:
|
||||
|
||||
- `user`, type string; the user-string from `--token-auth-file`. If you specify `user`, it must match the username of the authenticated user.
|
||||
- `group`, type string; if you specify `group`, it must match one of the groups of the authenticated user.
|
||||
- `readonly`, type boolean, when true, means that the policy only applies to GET
|
||||
operations.
|
||||
- `resource`, type string; a resource from an URL, such as `pods`.
|
||||
- `namespace`, type string; a namespace string.
|
||||
|
||||
An unset property is the same as a property set to the zero value for its type (e.g. empty string, 0, false).
|
||||
However, unset should be preferred for readability.
|
||||
|
||||
In the future, policies may be expressed in a JSON format, and managed via a REST
|
||||
interface.
|
||||
|
||||
### Authorization Algorithm
|
||||
|
||||
A request has attributes which correspond to the properties of a policy object.
|
||||
|
||||
When a request is received, the attributes are determined. Unknown attributes
|
||||
are set to the zero value of its type (e.g. empty string, 0, false).
|
||||
|
||||
An unset property will match any value of the corresponding
|
||||
attribute. An unset attribute will match any value of the corresponding property.
|
||||
|
||||
The tuple of attributes is checked for a match against every policy in the policy file.
|
||||
If at least one line matches the request attributes, then the request is authorized (but may fail later validation).
|
||||
|
||||
To permit any user to do something, write a policy with the user property unset.
|
||||
To permit an action Policy with an unset namespace applies regardless of namespace.
|
||||
|
||||
### Examples
|
||||
|
||||
1. Alice can do anything: `{"user":"alice"}`
|
||||
2. Kubelet can read any pods: `{"user":"kubelet", "resource": "pods", "readonly": true}`
|
||||
3. Kubelet can read and write events: `{"user":"kubelet", "resource": "events"}`
|
||||
4. Bob can just read pods in namespace "projectCaribou": `{"user":"bob", "resource": "pods", "readonly": true, "namespace": "projectCaribou"}`
|
||||
|
||||
[Complete file example](http://releases.k8s.io/{{page.githubbranch}}/pkg/auth/authorizer/abac/example_policy_file.jsonl)
|
||||
|
||||
### A quick note on service accounts
|
||||
|
||||
A service account automatically generates a user. The user's name is generated according to the naming convention:
|
||||
|
||||
```shell
|
||||
system:serviceaccount:<namespace>:<serviceaccountname>
|
||||
```
|
||||
Creating a new namespace also causes a new service account to be created, of this form:*
|
||||
|
||||
```shell
|
||||
system:serviceaccount:<namespace>:default
|
||||
```
|
||||
|
||||
For example, if you wanted to grant the default service account in the kube-system full privilege to the API, you would add this line to your policy file:
|
||||
|
||||
```json
|
||||
{"user":"system:serviceaccount:kube-system:default"}
|
||||
```
|
||||
|
||||
The apiserver will need to be restarted to pickup the new policy lines.
|
||||
|
||||
## Plugin Development
|
||||
|
||||
Other implementations can be developed fairly easily.
|
||||
The APIserver calls the Authorizer interface:
|
||||
|
||||
```go
|
||||
type Authorizer interface {
|
||||
Authorize(a Attributes) error
|
||||
}
|
||||
```
|
||||
|
||||
to determine whether or not to allow each API action.
|
||||
|
||||
An authorization plugin is a module that implements this interface.
|
||||
Authorization plugin code goes in `pkg/auth/authorizer/$MODULENAME`.
|
||||
|
||||
An authorization module can be completely implemented in go, or can call out
|
||||
to a remote authorization service. Authorization modules can implement
|
||||
their own caching to reduce the cost of repeated authorization calls with the
|
||||
same or similar arguments. Developers should then consider the interaction between
|
||||
caching and revocation of permissions.
|
|
@ -0,0 +1,116 @@
|
|||
|
||||
This document outlines the various binary components that need to run to
|
||||
deliver a functioning Kubernetes cluster.
|
||||
|
||||
## Master Components
|
||||
|
||||
Master components are those that provide the cluster's control plane. For
|
||||
example, master components are responsible for making global decisions about the
|
||||
cluster (e.g., scheduling), and detecting and responding to cluster events
|
||||
(e.g., starting up a new pod when a replication controller's 'replicas' field is
|
||||
unsatisfied).
|
||||
|
||||
Master components could in theory be run on any node in the cluster. However,
|
||||
for simplicity, current set up scripts typically start all master components on
|
||||
the same VM, and does not run user containers on this VM. See
|
||||
[high-availability.md](/{{page.version}}/docs/admin/high-availability) for an example multi-master-VM setup.
|
||||
|
||||
Even in the future, when Kubernetes is fully self-hosting, it will probably be
|
||||
wise to only allow master components to schedule on a subset of nodes, to limit
|
||||
co-running with user-run pods, reducing the possible scope of a
|
||||
node-compromising security exploit.
|
||||
|
||||
### kube-apiserver
|
||||
|
||||
[kube-apiserver](/{{page.version}}/docs/admin/kube-apiserver) exposes the Kubernetes API; it is the front-end for the
|
||||
Kubernetes control plane. It is designed to scale horizontally (i.e., one scales
|
||||
it by running more of them-- [high-availability.md](/{{page.version}}/docs/admin/high-availability)).
|
||||
|
||||
### etcd
|
||||
|
||||
[etcd](/{{page.version}}/docs/admin/etcd) is used as Kubernetes' backing store. All cluster data is stored here.
|
||||
Proper administration of a Kubernetes cluster includes a backup plan for etcd's
|
||||
data.
|
||||
|
||||
### kube-controller-manager
|
||||
|
||||
[kube-controller-manager](/{{page.version}}/docs/admin/kube-controller-manager) is a binary that runs controllers, which are the
|
||||
background threads that handle routine tasks in the cluster. Logically, each
|
||||
controller is a separate process, but to reduce the number of moving pieces in
|
||||
the system, they are all compiled into a single binary and run in a single
|
||||
process.
|
||||
|
||||
These controllers include:
|
||||
|
||||
* Node Controller
|
||||
* Responsible for noticing & responding when nodes go down.
|
||||
* Replication Controller
|
||||
* Responsible for maintaining the correct number of pods for every replication
|
||||
controller object in the system.
|
||||
* Endpoints Controller
|
||||
* Populates the Endpoints object (i.e., join Services & Pods).
|
||||
* Service Account & Token Controllers
|
||||
* Create default accounts and API access tokens for new namespaces.
|
||||
* ... and others.
|
||||
|
||||
### kube-scheduler
|
||||
|
||||
[kube-scheduler](/{{page.version}}/docs/admin/kube-scheduler) watches newly created pods that have no node assigned, and
|
||||
selects a node for them to run on.
|
||||
|
||||
### addons
|
||||
|
||||
Addons are pods and services that implement cluster features. They don't run on
|
||||
the master VM, but currently the default setup scripts that make the API calls
|
||||
to create these pods and services does run on the master VM. See:
|
||||
[kube-master-addons](http://releases.k8s.io/{{page.githubbranch}}/cluster/saltbase/salt/kube-master-addons/kube-master-addons.sh)
|
||||
|
||||
Addon objects are created in the "kube-system" namespace.
|
||||
|
||||
Example addons are:
|
||||
* [DNS](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/dns/) provides cluster local DNS.
|
||||
* [kube-ui](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/kube-ui/) provides a graphical UI for the
|
||||
cluster.
|
||||
* [fluentd-elasticsearch](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/fluentd-elasticsearch/) provides
|
||||
log storage. Also see the [gcp version](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/fluentd-gcp/).
|
||||
* [cluster-monitoring](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/cluster-monitoring/) provides
|
||||
monitoring for the cluster.
|
||||
|
||||
## Node components
|
||||
|
||||
Node components run on every node, maintaining running pods and providing them
|
||||
the Kubernetes runtime environment.
|
||||
|
||||
### kubelet
|
||||
|
||||
[kubelet](/{{page.version}}/docs/admin/kubelet) is the primary node agent. It:
|
||||
* Watches for pods that have been assigned to its node (either by apiserver
|
||||
or via local configuration file) and:
|
||||
* Mounts the pod's required volumes
|
||||
* Downloads the pod's secrets
|
||||
* Run the pod's containers via docker (or, experimentally, rkt).
|
||||
* Periodically executes any requested container liveness probes.
|
||||
* Reports the status of the pod back to the rest of the system, by creating a
|
||||
"mirror pod" if necessary.
|
||||
* Reports the status of the node back to the rest of the system.
|
||||
|
||||
### kube-proxy
|
||||
|
||||
[kube-proxy](/{{page.version}}/docs/admin/kube-proxy) enables the Kubernetes service abstraction by maintaining
|
||||
network rules on the host and performing connection forwarding.
|
||||
|
||||
### docker
|
||||
|
||||
`docker` is of course used for actually running containers.
|
||||
|
||||
### rkt
|
||||
|
||||
`rkt` is supported experimentally as an alternative to docker.
|
||||
|
||||
### supervisord
|
||||
|
||||
`supervisord` is a lightweight process babysitting system for keeping kubelet and docker
|
||||
running.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
|
||||
## Support
|
||||
|
||||
At v1.0, Kubernetes supports clusters up to 100 nodes with 30 pods per node and 1-2 containers per pod.
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## Setup
|
||||
|
||||
A cluster is a set of nodes (physical or virtual machines) running Kubernetes agents, managed by a "master" (the cluster-level control plane).
|
||||
|
||||
Normally the number of nodes in a cluster is controlled by the the value `NUM_MINIONS` in the platform-specific `config-default.sh` file (for example, see [GCE's `config-default.sh`](http://releases.k8s.io/{{page.githubbranch}}/cluster/gce/config-default.sh)).
|
||||
|
||||
Simply changing that value to something very large, however, may cause the setup script to fail for many cloud providers. A GCE deployment, for example, will run in to quota issues and fail to bring the cluster up.
|
||||
|
||||
When setting up a large Kubernetes cluster, the following issues must be considered.
|
||||
|
||||
### Quota Issues
|
||||
|
||||
To avoid running into cloud provider quota issues, when creating a cluster with many nodes, consider:
|
||||
|
||||
* Increase the quota for things like CPU, IPs, etc.
|
||||
* In [GCE, for example,](https://cloud.google.com/compute/docs/resource-quotas) you'll want to increase the quota for:
|
||||
* CPUs
|
||||
* VM instances
|
||||
* Total persistent disk reserved
|
||||
* In-use IP addresses
|
||||
* Firewall Rules
|
||||
* Forwarding rules
|
||||
* Routes
|
||||
* Target pools
|
||||
* Gating the setup script so that it brings up new node VMs in smaller batches with waits in between, because some cloud providers rate limit the creation of VMs.
|
||||
|
||||
### Addon Resources
|
||||
|
||||
To prevent memory leaks or other resource issues in [cluster addons](https://releases.k8s.io/{{page.githubbranch}}/cluster/addons) from consuming all the resources available on a node, Kubernetes sets resource limits on addon containers to limit the CPU and Memory resources they can consume (See PR [#10653](http://pr.k8s.io/10653/files) and [#10778](http://pr.k8s.io/10778/files)).
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
containers:
|
||||
- image: gcr.io/google_containers/heapster:v0.15.0
|
||||
name: heapster
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 200Mi
|
||||
```
|
||||
|
||||
These limits, however, are based on data collected from addons running on 4-node clusters (see [#10335](http://issue.k8s.io/10335#issuecomment-117861225)). The addons consume a lot more resources when running on large deployment clusters (see [#5880](http://issue.k8s.io/5880#issuecomment-113984085)). So, if a large cluster is deployed without adjusting these values, the addons may continuously get killed because they keep hitting the limits.
|
||||
|
||||
To avoid running into cluster addon resource issues, when creating a cluster with many nodes, consider the following:
|
||||
|
||||
- Scale memory and CPU limits for each of the following addons, if used, along with the size of cluster (there is one replica of each handling the entire cluster so memory and CPU usage tends to grow proportionally with size/load on cluster):
|
||||
- Heapster ([GCM/GCL backed](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/cluster-monitoring/google/heapster-controller.yaml), [InfluxDB backed](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/cluster-monitoring/influxdb/heapster-controller.yaml), [InfluxDB/GCL backed](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/cluster-monitoring/googleinfluxdb/heapster-controller-combined.yaml), [standalone](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/cluster-monitoring/standalone/heapster-controller.yaml))
|
||||
* [InfluxDB and Grafana](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/cluster-monitoring/influxdb/influxdb-grafana-controller.yaml)
|
||||
* [skydns, kube2sky, and dns etcd](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/dns/skydns-rc.yaml.in)
|
||||
* [Kibana](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/fluentd-elasticsearch/kibana-controller.yaml)
|
||||
* Scale number of replicas for the following addons, if used, along with the size of cluster (there are multiple replicas of each so increasing replicas should help handle increased load, but, since load per replica also increases slightly, also consider increasing CPU/memory limits):
|
||||
* [elasticsearch](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/fluentd-elasticsearch/es-controller.yaml)
|
||||
* Increase memory and CPU limits slightly for each of the following addons, if used, along with the size of cluster (there is one replica per node but CPU/memory usage increases slightly along with cluster load/size as well):
|
||||
* [FluentD with ElasticSearch Plugin](http://releases.k8s.io/{{page.githubbranch}}/cluster/saltbase/salt/fluentd-es/fluentd-es.yaml)
|
||||
* [FluentD with GCP Plugin](http://releases.k8s.io/{{page.githubbranch}}/cluster/saltbase/salt/fluentd-gcp/fluentd-gcp.yaml)
|
||||
|
||||
For directions on how to detect if addon containers are hitting resource limits, see the [Troubleshooting section of Compute Resources](/{{page.version}}/docs/user-guide/compute-resources/#troubleshooting).
|
|
@ -0,0 +1,185 @@
|
|||
|
||||
This document describes several topics related to the lifecycle of a cluster: creating a new cluster,
|
||||
upgrading your cluster's
|
||||
master and worker nodes, performing node maintenance (e.g. kernel upgrades), and upgrading the Kubernetes API version of a
|
||||
running cluster.
|
||||
|
||||
## Creating and configuring a Cluster
|
||||
|
||||
To install Kubernetes on a set of machines, consult one of the existing [Getting Started guides](/{{page.version}}/docs/getting-started-guides/) depending on your environment.
|
||||
|
||||
## Upgrading a cluster
|
||||
|
||||
The current state of cluster upgrades is provider dependent.
|
||||
|
||||
### Master Upgrades
|
||||
|
||||
Both Google Container Engine (GKE) and
|
||||
Compute Engine Open Source (GCE-OSS) support node upgrades via a [Managed Instance Group](https://cloud.google.com/compute/docs/instance-groups/).
|
||||
Managed Instance Group upgrades sequentially delete and recreate each virtual machine, while maintaining the same
|
||||
Persistent Disk (PD) to ensure that data is retained across the upgrade.
|
||||
|
||||
In contrast, the `kube-push.sh` process used on [other platforms](#other-platforms) attempts to upgrade the binaries in
|
||||
places, without recreating the virtual machines.
|
||||
|
||||
### Node Upgrades
|
||||
|
||||
Node upgrades for GKE and GCE-OSS again use a Managed Instance Group, each node is sequentially destroyed and then recreated with new software. Any Pods that are running
|
||||
on that node need to be controlled by a Replication Controller, or manually re-created after the roll out.
|
||||
|
||||
For other platforms, `kube-push.sh` is again used, performing an in-place binary upgrade on existing machines.
|
||||
|
||||
### Upgrading Google Container Engine (GKE)
|
||||
|
||||
Google Container Engine automatically updates master components (e.g. `kube-apiserver`, `kube-scheduler`) to the latest
|
||||
version. It also handles upgrading the operating system and other components that the master runs on.
|
||||
|
||||
The node upgrade process is user-initiated and is described in the [GKE documentation.](https://cloud.google.com/container-engine/docs/clusters/upgrade)
|
||||
|
||||
### Upgrading open source Google Compute Engine clusters
|
||||
|
||||
Upgrades on open source Google Compute Engine (GCE) clusters are controlled by the `cluster/gce/upgrade.sh` script.
|
||||
|
||||
Get its usage by running `cluster/gce/upgrade.sh -h`.
|
||||
|
||||
For example, to upgrade just your master to a specific version (v1.0.2):
|
||||
|
||||
```shell
|
||||
cluster/gce/upgrade.sh -M v1.0.2
|
||||
```
|
||||
|
||||
Alternatively, to upgrade your entire cluster to the latest stable release:
|
||||
|
||||
```shell
|
||||
cluster/gce/upgrade.sh release/stable
|
||||
```
|
||||
|
||||
### Other platforms
|
||||
|
||||
The `cluster/kube-push.sh` script will do a rudimentary update. This process is still quite experimental, we
|
||||
recommend testing the upgrade on an experimental cluster before performing the update on a production cluster.
|
||||
|
||||
## Resizing a cluster
|
||||
|
||||
If your cluster runs short on resources you can easily add more machines to it if your cluster is running in [Node self-registration mode](/{{page.version}}/docs/admin/node/#self-registration-of-nodes).
|
||||
If you're using GCE or GKE it's done by resizing Instance Group managing your Nodes. It can be accomplished by modifying number of instances on `Compute > Compute Engine > Instance groups > your group > Edit group` [Google Cloud Console page](https://console.developers.google.com) or using gcloud CLI:
|
||||
|
||||
```shell
|
||||
gcloud compute instance-groups managed --zone compute-zone resize my-cluster-minon-group --new-size 42
|
||||
```
|
||||
|
||||
Instance Group will take care of putting appropriate image on new machines and start them, while Kubelet will register its Node with API server to make it available for scheduling. If you scale the instance group down, system will randomly choose Nodes to kill.
|
||||
|
||||
In other environments you may need to configure the machine yourself and tell the Kubelet on which machine API server is running.
|
||||
|
||||
|
||||
### Horizontal auto-scaling of nodes (GCE)
|
||||
|
||||
If you are using GCE, you can configure your cluster so that the number of nodes will be automatically scaled based on their CPU and memory utilization.
|
||||
Before setting up the cluster by `kube-up.sh`, you can set `KUBE_ENABLE_NODE_AUTOSCALE`
|
||||
environment variable to `true`
|
||||
and export it.
|
||||
The script will create an autoscaler for the instance group managing your nodes.
|
||||
|
||||
The autoscaler will try to maintain the average CPU and memory utilization of nodes within the cluster close to the target value.
|
||||
The target value can be configured by `KUBE_TARGET_NODE_UTILIZATION`
|
||||
environment variable (default: 0.7) for `kube-up.sh` when creating the cluster.
|
||||
The node utilization is the total node's CPU/memory usage (OS + k8s + user load) divided by the node's capacity.
|
||||
If the desired numbers of nodes in the cluster resulting from CPU utilization and memory utilization are different,
|
||||
the autoscaler will choose the bigger number.
|
||||
The number of nodes in the cluster set by the autoscaler will be limited from `KUBE_AUTOSCALER_MIN_NODES`
|
||||
(default: 1)
|
||||
to `KUBE_AUTOSCALER_MAX_NODES`
|
||||
(default: the initial number of nodes in the cluster).
|
||||
|
||||
The autoscaler is implemented as a Compute Engine Autoscaler.
|
||||
The initial values of the autoscaler parameters set by `kube-up.sh` and some more advanced options can be tweaked on
|
||||
`Compute > Compute Engine > Instance groups > your group > Edit group`[Google Cloud Console page](https://console.developers.google.com)
|
||||
or using gcloud CLI:
|
||||
|
||||
```shell
|
||||
gcloud preview autoscaler --zone compute-zone <command>
|
||||
```
|
||||
|
||||
Note that autoscaling will work properly only if node metrics are accessible in Google Cloud Monitoring. To make the metrics accessible, you need to create your cluster with `KUBE_ENABLE_CLUSTER_MONITORING` equal to `google` or `googleinfluxdb` (`googleinfluxdb` is the default value).
|
||||
|
||||
## Maintenance on a Node
|
||||
|
||||
If you need to reboot a node (such as for a kernel upgrade, libc upgrade, hardware repair, etc.), and the downtime is
|
||||
brief, then when the Kubelet restarts, it will attempt to restart the pods scheduled to it. If the reboot takes longer,
|
||||
then the node controller will terminate the pods that are bound to the unavailable node. If there is a corresponding
|
||||
replication controller, then a new copy of the pod will be started on a different node. So, in the case where all
|
||||
pods are replicated, upgrades can be done without special coordination, assuming that not all nodes will go down at the same time.
|
||||
|
||||
If you want more control over the upgrading process, you may use the following workflow:
|
||||
|
||||
Mark the node to be rebooted as unschedulable:
|
||||
|
||||
```shell
|
||||
kubectl replace nodes $NODENAME --patch='{"apiVersion": "v1", "spec": {"unschedulable": true}}'
|
||||
```
|
||||
|
||||
This keeps new pods from landing on the node while you are trying to get them off.
|
||||
|
||||
Get the pods off the machine, via any of the following strategies:
|
||||
* Wait for finite-duration pods to complete.
|
||||
* Delete pods with:
|
||||
|
||||
```shell
|
||||
kubectl delete pods $PODNAME
|
||||
```
|
||||
|
||||
For pods with a replication controller, the pod will eventually be replaced by a new pod which will be scheduled to a new node. Additionally, if the pod is part of a service, then clients will automatically be redirected to the new pod.
|
||||
|
||||
For pods with no replication controller, you need to bring up a new copy of the pod, and assuming it is not part of a service, redirect clients to it.
|
||||
|
||||
Perform maintenance work on the node.
|
||||
|
||||
Make the node schedulable again:
|
||||
|
||||
```shell
|
||||
kubectl replace nodes $NODENAME --patch='{"apiVersion": "v1", "spec": {"unschedulable": false}}'
|
||||
```
|
||||
|
||||
If you deleted the node's VM instance and created a new one, then a new schedulable node resource will
|
||||
be created automatically when you create a new VM instance (if you're using a cloud provider that supports
|
||||
node discovery; currently this is only Google Compute Engine, not including CoreOS on Google Compute Engine using kube-register). See [Node](/{{page.version}}/docs/admin/node) for more details.
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
### Upgrading to a different API version
|
||||
|
||||
When a new API version is released, you may need to upgrade a cluster to support the new API version (e.g. switching from 'v1' to 'v2' when 'v2' is launched)
|
||||
|
||||
This is an infrequent event, but it requires careful management. There is a sequence of steps to upgrade to a new API version.
|
||||
|
||||
1. Turn on the new api version.
|
||||
1. Upgrade the cluster's storage to use the new version.
|
||||
1. Upgrade all config files. Identify users of the old API version endpoints.
|
||||
1. Update existing objects in the storage to new version by running `cluster/update-storage-objects.sh`.
|
||||
1. Turn off the old API version.
|
||||
|
||||
### Turn on or off an API version for your cluster
|
||||
|
||||
Specific API versions can be turned on or off by passing --runtime-config=api/<version> flag while bringing up the API server. For example: to turn off v1 API, pass `--runtime-config=api/v1=false`.
|
||||
runtime-config also supports 2 special keys: api/all and api/legacy to control all and legacy APIs respectively.
|
||||
For example, for turning off all api versions except v1, pass `--runtime-config=api/all=false,api/v1=true`.
|
||||
For the purposes of these flags, _legacy_ APIs are those APIs which have been explicitly deprecated (e.g. `v1beta3`).
|
||||
|
||||
### Switching your cluster's storage API version
|
||||
|
||||
The objects that are stored to disk for a cluster's internal representation of the Kubernetes resources active in the cluster are written using a particular version of the API.
|
||||
When the supported API changes, these objects may need to be rewritten in the newer API. Failure to do this will eventually result in resources that are no longer decodable or usable
|
||||
by the kubernetes API server.
|
||||
|
||||
`KUBE_API_VERSIONS` environment variable for the `kube-apiserver` binary which controls the API versions that are supported in the cluster. The first version in the list is used as the cluster's storage version. Hence, to set a specific version as the storage version, bring it to the front of list of versions in the value of `KUBE_API_VERSIONS`. You need to restart the `kube-apiserver` binary
|
||||
for changes to this variable to take effect.
|
||||
|
||||
### Switching your config files to a new API version
|
||||
|
||||
You can use the `kube-version-change` utility to convert config files between different API versions.
|
||||
|
||||
```shell
|
||||
$ hack/build-go.sh cmd/kube-version-change
|
||||
$ _output/local/go/bin/kube-version-change -i myPod.v1beta3.yaml -o myPod.v1.yaml
|
||||
```
|
|
@ -0,0 +1,110 @@
|
|||
|
||||
This doc is about cluster troubleshooting; we assume you have already ruled out your application as the root cause of the
|
||||
problem you are experiencing. See
|
||||
the [application troubleshooting guide](/{{page.version}}/docs/user-guide/application-troubleshooting) for tips on application debugging.
|
||||
You may also visit [troubleshooting document](/{{page.version}}/docs/troubleshooting/) for more information.
|
||||
|
||||
## Listing your cluster
|
||||
|
||||
The first thing to debug in your cluster is if your nodes are all registered correctly.
|
||||
|
||||
Run
|
||||
|
||||
```shell
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
And verify that all of the nodes you expect to see are present and that they are all in the `Ready` state.
|
||||
|
||||
## Looking at logs
|
||||
|
||||
For now, digging deeper into the cluster requires logging into the relevant machines. Here are the locations
|
||||
of the relevant log files. (note that on systemd-based systems, you may need to use `journalctl` instead)
|
||||
|
||||
### Master
|
||||
|
||||
* /var/log/kube-apiserver.log - API Server, responsible for serving the API
|
||||
* /var/log/kube-scheduler.log - Scheduler, responsible for making scheduling decisions
|
||||
* /var/log/kube-controller-manager.log - Controller that manages replication controllers
|
||||
|
||||
### Worker Nodes
|
||||
|
||||
* /var/log/kubelet.log - Kubelet, responsible for running containers on the node
|
||||
* /var/log/kube-proxy.log - Kube Proxy, responsible for service load balancing
|
||||
|
||||
## A general overview of cluster failure modes
|
||||
|
||||
This is an incomplete list of things that could go wrong, and how to adjust your cluster setup to mitigate the problems.
|
||||
|
||||
Root causes:
|
||||
|
||||
- VM(s) shutdown
|
||||
- Network partition within cluster, or between cluster and users
|
||||
- Crashes in Kubernetes software
|
||||
- Data loss or unavailability of persistent storage (e.g. GCE PD or AWS EBS volume)
|
||||
- Operator error, e.g. misconfigured Kubernetes software or application software
|
||||
|
||||
Specific scenarios:
|
||||
|
||||
- Apiserver VM shutdown or apiserver crashing
|
||||
- Results
|
||||
- unable to stop, update, or start new pods, services, replication controller
|
||||
- existing pods and services should continue to work normally, unless they depend on the Kubernetes API
|
||||
- Apiserver backing storage lost
|
||||
- Results
|
||||
- apiserver should fail to come up
|
||||
- kubelets will not be able to reach it but will continue to run the same pods and provide the same service proxying
|
||||
- manual recovery or recreation of apiserver state necessary before apiserver is restarted
|
||||
- Supporting services (node controller, replication controller manager, scheduler, etc) VM shutdown or crashes
|
||||
- currently those are colocated with the apiserver, and their unavailability has similar consequences as apiserver
|
||||
- in future, these will be replicated as well and may not be co-located
|
||||
- they do not have their own persistent state
|
||||
- Individual node (VM or physical machine) shuts down
|
||||
- Results
|
||||
- pods on that Node stop running
|
||||
- Network partition
|
||||
- Results
|
||||
- partition A thinks the nodes in partition B are down; partition B thinks the apiserver is down. (Assuming the master VM ends up in partition A.)
|
||||
- Kubelet software fault
|
||||
- Results
|
||||
- crashing kubelet cannot start new pods on the node
|
||||
- kubelet might delete the pods or not
|
||||
- node marked unhealthy
|
||||
- replication controllers start new pods elsewhere
|
||||
- Cluster operator error
|
||||
- Results
|
||||
- loss of pods, services, etc
|
||||
- lost of apiserver backing store
|
||||
- users unable to read API
|
||||
- etc.
|
||||
|
||||
Mitigations:
|
||||
|
||||
- Action: Use IaaS provider's automatic VM restarting feature for IaaS VMs
|
||||
- Mitigates: Apiserver VM shutdown or apiserver crashing
|
||||
- Mitigates: Supporting services VM shutdown or crashes
|
||||
|
||||
- Action use IaaS providers reliable storage (e.g GCE PD or AWS EBS volume) for VMs with apiserver+etcd
|
||||
- Mitigates: Apiserver backing storage lost
|
||||
|
||||
- Action: Use (experimental) [high-availability](/{{page.version}}/docs/admin/high-availability) configuration
|
||||
- Mitigates: Master VM shutdown or master components (scheduler, API server, controller-managing) crashing
|
||||
- Will tolerate one or more simultaneous node or component failures
|
||||
- Mitigates: Apiserver backing storage (i.e., etcd's data directory) lost
|
||||
- Assuming you used clustered etcd.
|
||||
|
||||
- Action: Snapshot apiserver PDs/EBS-volumes periodically
|
||||
- Mitigates: Apiserver backing storage lost
|
||||
- Mitigates: Some cases of operator error
|
||||
- Mitigates: Some cases of Kubernetes software fault
|
||||
|
||||
- Action: use replication controller and services in front of pods
|
||||
- Mitigates: Node shutdown
|
||||
- Mitigates: Kubelet software fault
|
||||
|
||||
- Action: applications (containers) designed to tolerate unexpected restarts
|
||||
- Mitigates: Node shutdown
|
||||
- Mitigates: Kubelet software fault
|
||||
|
||||
- Action: [Multiple independent clusters](/{{page.version}}/docs/admin/multi-cluster) (and avoid making risky changes to all clusters at once)
|
||||
- Mitigates: Everything listed above.
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: extensions/v1beta1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: prometheus-node-exporter
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
name: prometheus-node-exporter
|
||||
labels:
|
||||
daemon: prom-node-exp
|
||||
spec:
|
||||
containers:
|
||||
- name: c
|
||||
image: prom/prometheus
|
||||
ports:
|
||||
- containerPort: 9090
|
||||
hostPort: 9090
|
||||
name: serverport
|
|
@ -0,0 +1,167 @@
|
|||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## What is a _Daemon Set_?
|
||||
|
||||
A _Daemon Set_ ensures that all (or some) nodes run a copy of a pod. As nodes are added to the
|
||||
cluster, pods are added to them. As nodes are removed from the cluster, those pods are garbage
|
||||
collected. Deleting a Daemon Set will clean up the pods it created.
|
||||
|
||||
Some typical uses of a Daemon Set are:
|
||||
|
||||
- running a cluster storage daemon, such as `glusterd`, `ceph`, on each node.
|
||||
- running a logs collection daemon on every node, such as `fluentd` or `logstash`.
|
||||
- running a node monitoring daemon on every node, such as [Prometheus Node Exporter](
|
||||
https://github.com/prometheus/node_exporter), `collectd`, New Relic agent, or Ganglia `gmond`.
|
||||
|
||||
In a simple case, one Daemon Set, covering all nodes, would be used for each type of daemon.
|
||||
A more complex setup might use multiple DaemonSets would be used for a single type of daemon,
|
||||
but with different flags and/or different memory and cpu requests for different hardware types.
|
||||
|
||||
## Writing a DaemonSet Spec
|
||||
|
||||
### Required Fields
|
||||
|
||||
As with all other Kubernetes config, a DaemonSet needs `apiVersion`, `kind`, and `metadata` fields. For
|
||||
general information about working with config files, see [here](/{{page.version}}/docs/user-guide/simple-yaml),
|
||||
[here](/{{page.version}}/docs/user-guide/configuring-containers), and [here](/{{page.version}}/docs/user-guide/working-with-resources).
|
||||
|
||||
A DaemonSet also needs a [`.spec`](/{{page.version}}/docs/devel/api-conventions/#spec-and-status) section.
|
||||
|
||||
### Pod Template
|
||||
|
||||
The `.spec.template` is the only required field of the `.spec`.
|
||||
|
||||
The `.spec.template` is a [pod template](/{{page.version}}/docs/user-guide/replication-controller/#pod-template).
|
||||
It has exactly the same schema as a [pod](/{{page.version}}/docs/user-guide/pods), except
|
||||
it is nested and does not have an `apiVersion` or `kind`.
|
||||
|
||||
In addition to required fields for a pod, a pod template in a DaemonSet has to specify appropriate
|
||||
labels (see [pod selector](#pod-selector)).
|
||||
|
||||
A pod template in a DaemonSet must have a [`RestartPolicy`](/{{page.version}}/docs/user-guide/pod-states)
|
||||
equal to `Always`, or be unspecified, which defaults to `Always`.
|
||||
|
||||
### Pod Selector
|
||||
|
||||
The `.spec.selector` field is a pod selector. It works the same as the `.spec.selector` of
|
||||
a [ReplicationController](/{{page.version}}/docs/user-guide/replication-controller) or
|
||||
[Job](/{{page.version}}/docs/user-guide/jobs).
|
||||
|
||||
If the `.spec.selector` is specified, it must equal the `.spec.template.metadata.labels`. If not
|
||||
specified, the are default to be equal. Config with these unequal will be rejected by the API.
|
||||
|
||||
Also you should not normally create any pods whose labels match this selector, either directly, via
|
||||
another DaemonSet, or via other controller such as ReplicationController. Otherwise, the DaemonSet
|
||||
controller will think that those pods were created by it. Kubernetes will not stop you from doing
|
||||
this. Once case where you might want to do this is manually create a pod with a different value on
|
||||
a node for testing.
|
||||
|
||||
### Running Pods on Only Some Nodes
|
||||
|
||||
If you specify a `.spec.template.spec.nodeSelector`, then the DaemonSet controller will
|
||||
create pods on nodes which match that [node
|
||||
selector](/{{page.version}}/docs/user-guide/node-selection/).
|
||||
|
||||
If you do not specify a `.spec.template.spec.nodeSelector`, then the DaemonSet controller will
|
||||
create pods on all nodes.
|
||||
|
||||
## How Daemon Pods are Scheduled
|
||||
|
||||
Normally, the machine that a pod runs on is selected by the Kubernetes scheduler. However, pods
|
||||
created by the Daemon controller have the machine already selected (`.spec.nodeName` is specified
|
||||
when the pod is created, so it is ignored by the scheduler). Therefore:
|
||||
|
||||
- the [`unschedulable`](/{{page.version}}/docs/admin/node/#manual-node-administration) field of a node is not respected
|
||||
by the daemon set controller.
|
||||
- daemon set controller can make pods even when the scheduler has not been started, which can help cluster
|
||||
bootstrap.
|
||||
|
||||
## Communicating with DaemonSet Pods
|
||||
|
||||
Some possible patterns for communicating with pods in a DaemonSet are:
|
||||
|
||||
- **Push**: Pods in the Daemon Set are configured to send updates to another service, such
|
||||
as a stats database. They do not have clients.
|
||||
- **NodeIP and Known Port**: Pods in the Daemon Set use a `hostPort`, so that the pods are reachable
|
||||
via the node IPs. Clients knows the the list of nodes ips somehow, and know the port by convention.
|
||||
- **DNS**: Create a [headless service](/{{page.version}}/docs/user-guide/services/#headless-services) with the same pod selector,
|
||||
and then discover DaemonSets using the `endpoints` resource or retrieve multiple A records from
|
||||
DNS.
|
||||
- **Service**: Create a service with the same pod selector, and use the service to reach a
|
||||
daemon on a random node. (No way to reach specific node.)
|
||||
|
||||
## Updating a DaemonSet
|
||||
|
||||
If node labels are changed, the DaemonSet will promptly add pods to newly matching nodes and delete
|
||||
pods from newly not-matching nodes.
|
||||
|
||||
You can modify the pods that a DaemonSet creates. However, pods do not allow all
|
||||
fields to be updated. Also, the DeamonSet controller will use the original template the next
|
||||
time a node (even with the same name) is created.
|
||||
|
||||
|
||||
You can delete a DeamonSet. If you specify `--cascade=false` with `kubectl`, then the pods
|
||||
will be left on the nodes. You can then create a new DaemonSet with a different template.
|
||||
the new DaemonSet with the different template will recognize all the existing pods as having
|
||||
matching labels. It will not modify or delete them despite a mismatch in the pod template.
|
||||
You will need to force new pod creation by deleting the pod or deleting the node.
|
||||
|
||||
You cannot update a DaemonSet.
|
||||
|
||||
Support for updating DaemonSets and controlled updating of nodes is planned.
|
||||
|
||||
## Alternatives to Daemon Set
|
||||
|
||||
### Init Scripts
|
||||
|
||||
It is certainly possible to run daemon processes by directly starting them on a node (e.g using
|
||||
`init`, `upstartd`, or `systemd`). This is perfectly fine. However, there are several advantages to
|
||||
running such processes via a DaemonSet:
|
||||
|
||||
- Ability to monitor and manage logs for daemons in the same way as applications.
|
||||
- Same config language and tools (e.g. pod templates, `kubectl`) for daemons and applications.
|
||||
- Future versions of Kubernetes will likely support integration between DaemonSet-created
|
||||
pods and node upgrade workflows.
|
||||
- Running daemons in containers with resource limits increases isolation between daemons from app
|
||||
containers. However, this can also be accomplished by running the daemons in a container but not in a pod
|
||||
(e.g. start directly via Docker).
|
||||
|
||||
### Bare Pods
|
||||
|
||||
It is possible to create pods directly which specify a particular node to run on. However,
|
||||
a Daemon Set replaces pods that are deleted or terminated for any reason, such as in the case of
|
||||
node failure or disruptive node maintenance, such as a kernel upgrade. For this reason, you should
|
||||
use a Daemon Set rather than creating individual pods.
|
||||
|
||||
### Static Pods
|
||||
|
||||
It is possible to create pods by writing a file to a certain directory watched by Kubelet. These
|
||||
are called [static pods](/{{page.version}}/docs/admin/static-pods).
|
||||
Unlike DaemonSet, static pods cannot be managed with kubectl
|
||||
or other Kubernetes API clients. Static pods do not depend on the apiserver, making them useful
|
||||
in cluster bootstrapping cases. Also, static pods may be deprecated in the future.
|
||||
|
||||
### Replication Controller
|
||||
|
||||
Daemon Set are similar to [Replication Controllers](/{{page.version}}/docs/user-guide/replication-controller) in that
|
||||
they both create pods, and those pods have processes which are not expected to terminate (e.g. web servers,
|
||||
storage servers).
|
||||
|
||||
Use a replication controller for stateless services, like frontends, where scaling up and down the
|
||||
number of replicas and rolling out updates are more important than controlling exactly which host
|
||||
the pod runs on. Use a Daemon Controller when it is important that a copy of a pod always run on
|
||||
all or certain hosts, and when it needs to start before other pods.
|
||||
|
||||
## Caveats
|
||||
|
||||
DaemonSet objects are in the [`extensions` API Group](/{{page.version}}/docs/api/#api-groups).
|
||||
DaemonSet is not enabled by default. Enable it by setting
|
||||
`--runtime-config=extensions/v1beta1/daemonsets=true` on the api server. This can be
|
||||
achieved by exporting ENABLE_DAEMONSETS=true before running kube-up.sh script
|
||||
on GCE.
|
||||
|
||||
DaemonSet objects effectively have [API version `v1alpha1`](/{{page.version}}/docs/api/)#api-versioning).
|
||||
Alpha objects may change or even be discontinued in future software releases.
|
||||
However, due to to a known issue, they will appear as API version `v1beta1` if enabled.
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
As of Kubernetes 0.8, DNS is offered as a [cluster add-on](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/README.md).
|
||||
If enabled, a DNS Pod and Service will be scheduled on the cluster, and the kubelets will be
|
||||
configured to tell individual containers to use the DNS Service's IP to resolve DNS names.
|
||||
|
||||
Every Service defined in the cluster (including the DNS server itself) will be
|
||||
assigned a DNS name. By default, a client Pod's DNS search list will
|
||||
include the Pod's own namespace and the cluster's default domain. This is best
|
||||
illustrated by example:
|
||||
|
||||
Assume a Service named `foo` in the Kubernetes namespace `bar`. A Pod running
|
||||
in namespace `bar` can look up this service by simply doing a DNS query for
|
||||
`foo`. A Pod running in namespace `quux` can look up this service by doing a
|
||||
DNS query for `foo.bar`.
|
||||
|
||||
The cluster DNS server ([SkyDNS](https://github.com/skynetservices/skydns))
|
||||
supports forward lookups (A records) and service lookups (SRV records).
|
||||
|
||||
## How it Works
|
||||
|
||||
The running DNS pod holds 3 containers - skydns, etcd (a private instance which skydns uses),
|
||||
and a Kubernetes-to-skydns bridge called kube2sky. The kube2sky process
|
||||
watches the Kubernetes master for changes in Services, and then writes the
|
||||
information to etcd, which skydns reads. This etcd instance is not linked to
|
||||
any other etcd clusters that might exist, including the Kubernetes master.
|
||||
|
||||
## Issues
|
||||
|
||||
The skydns service is reachable directly from Kubernetes nodes (outside
|
||||
of any container) and DNS resolution works if the skydns service is targeted
|
||||
explicitly. However, nodes are not configured to use the cluster DNS service or
|
||||
to search the cluster's DNS domain by default. This may be resolved at a later
|
||||
time.
|
||||
|
||||
## For more information
|
||||
|
||||
See [the docs for the DNS cluster addon](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/dns/README.md).
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
[etcd](https://coreos.com/etcd/docs/2.0.12/) is a highly-available key value
|
||||
store which Kubernetes uses for persistent storage of all of its REST API
|
||||
objects.
|
||||
|
||||
## Configuration: high-level goals
|
||||
|
||||
Access Control: give *only* kube-apiserver read/write access to etcd. You do not
|
||||
want apiserver's etcd exposed to every node in your cluster (or worse, to the
|
||||
internet at large), because access to etcd is equivalent to root in your
|
||||
cluster.
|
||||
|
||||
Data Reliability: for reasonable safety, either etcd needs to be run as a
|
||||
[cluster](/{{page.version}}/docs/admin/high-availability/#clustering-etcd) (multiple machines each running
|
||||
etcd) or etcd's data directory should be located on durable storage (e.g., GCE's
|
||||
persistent disk). In either case, if high availability is required--as it might
|
||||
be in a production cluster--the data directory ought to be [backed up
|
||||
periodically](https://coreos.com/etcd/docs/2.0.12/admin_guide/#disaster-recovery),
|
||||
to reduce downtime in case of corruption.
|
||||
|
||||
## Default configuration
|
||||
|
||||
The default setup scripts use kubelet's file-based static pods feature to run etcd in a
|
||||
[pod](http://releases.k8s.io/{{page.githubbranch}}/cluster/saltbase/salt/etcd/etcd.manifest). This manifest should only
|
||||
be run on master VMs. The default location that kubelet scans for manifests is
|
||||
`/etc/kubernetes/manifests/`.
|
||||
|
||||
## Kubernetes's usage of etcd
|
||||
|
||||
By default, Kubernetes objects are stored under the `/registry` key in etcd.
|
||||
This path can be prefixed by using the [kube-apiserver](/{{page.version}}/docs/admin/kube-apiserver) flag
|
||||
`--etcd-prefix="/foo"`.
|
||||
|
||||
`etcd` is the only place that Kubernetes keeps state.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
To test whether `etcd` is running correctly, you can try writing a value to a
|
||||
test key. On your master VM (or somewhere with firewalls configured such that
|
||||
you can talk to your cluster's etcd), try:
|
||||
|
||||
```shell
|
||||
curl -fs -X PUT "http://${host}:${port}/v2/keys/_test"
|
||||
```
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
Garbage collection is managed by kubelet automatically, mainly including unreferenced
|
||||
images and dead containers. kubelet applies container garbage collection every minute
|
||||
and image garbage collection every 5 minutes.
|
||||
Note that we don't recommend external garbage collection tool generally, since it could
|
||||
break the behavior of kubelet potentially if it attempts to remove all of the containers
|
||||
which acts as the tombstone kubelet relies on. Yet those garbage collector aims to deal
|
||||
with the docker leaking issues would be appreciated.
|
||||
|
||||
### Image Collection
|
||||
|
||||
kubernetes manages lifecycle of all images through imageManager, with the cooperation
|
||||
of cadvisor.
|
||||
The policy for garbage collecting images we apply takes two factors into consideration,
|
||||
`HighThresholdPercent` and `LowThresholdPercent`. Disk usage above the the high threshold
|
||||
will trigger garbage collection, which attempts to delete unused images until the low
|
||||
threshold is met. Least recently used images are deleted first.
|
||||
|
||||
### Container Collection
|
||||
|
||||
The policy for garbage collecting containers we apply takes on three variables, which can
|
||||
be user-defined. `MinAge` is the minimum age at which a container can be garbage collected,
|
||||
zero for no limit. `MaxPerPodContainer` is the max number of dead containers any single
|
||||
pod (UID, container name) pair is allowed to have, less than zero for no limit.
|
||||
`MaxContainers` is the max number of total dead containers, less than zero for no limit as well.
|
||||
|
||||
kubelet sorts out containers which are unidentified or stay out of bounds set by previous
|
||||
mentioned three flags. Gernerally the oldest containers are removed first. Since we take both
|
||||
`MaxPerPodContainer` and `MaxContainers` into consideration, it could happen when they
|
||||
have conflict -- retaining the max number of containers per pod goes out of range set by max
|
||||
number of global dead containers. In this case, we would sacrifice the `MaxPerPodContainer`
|
||||
a little bit. For the worst case, we first downgrade it to 1 container per pod, and then
|
||||
evict the oldest containers for the greater good.
|
||||
|
||||
When kubelet removes the dead containers, all the files inside the container will be cleaned up as well.
|
||||
Note that we will skip the containers that are not managed by kubelet.
|
||||
|
||||
### User Configuration
|
||||
|
||||
Users are free to set their own value to address image garbage collection.
|
||||
|
||||
1. `image-gc-high-threshold`, the percent of disk usage which triggers image garbage collection.
|
||||
Default is 90%.
|
||||
2. `image-gc-low-threshold`, the percent of disk usage to which image garbage collection attempts
|
||||
to free. Default is 80%.
|
||||
|
||||
We also allow users to customize garbage collection policy, basically via following three flags.
|
||||
|
||||
1. `minimum-container-ttl-duration`, minimum age for a finished container before it is
|
||||
garbage collected. Default is 1 minute.
|
||||
2. `maximum-dead-containers-per-container`, maximum number of old instances to retain
|
||||
per container. Default is 2.
|
||||
3. `maximum-dead-containers`, maximum number of old instances of containers to retain globally.
|
||||
Default is 100.
|
||||
|
||||
Note that we highly recommend a large enough value for `maximum-dead-containers-per-container`
|
||||
to allow at least 2 dead containers retaining per expected container when you customize the flag
|
||||
configuration. A loose value for `maximum-dead-containers` also assumes importance for a similar reason.
|
||||
See [this issue](https://github.com/kubernetes/kubernetes/issues/13287) for more details.
|
|
@ -0,0 +1,225 @@
|
|||
|
||||
This document describes how to build a high-availability (HA) Kubernetes cluster. This is a fairly advanced topic.
|
||||
Users who merely want to experiment with Kubernetes are encouraged to use configurations that are simpler to set up such as
|
||||
the simple [Docker based single node cluster instructions](/{{page.version}}/docs/getting-started-guides/docker),
|
||||
or try [Google Container Engine](https://cloud.google.com/container-engine/) for hosted Kubernetes.
|
||||
|
||||
Also, at this time high availability support for Kubernetes is not continuously tested in our end-to-end (e2e) testing. We will
|
||||
be working to add this continuous testing, but for now the single-node master installations are more heavily tested.
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## Overview
|
||||
|
||||
Setting up a truly reliable, highly available distributed system requires a number of steps, it is akin to
|
||||
wearing underwear, pants, a belt, suspenders, another pair of underwear, and another pair of pants. We go into each
|
||||
of these steps in detail, but a summary is given here to help guide and orient the user.
|
||||
|
||||
The steps involved are as follows:
|
||||
|
||||
* [Creating the reliable constituent nodes that collectively form our HA master implementation.](#reliable-nodes)
|
||||
* [Setting up a redundant, reliable storage layer with clustered etcd.](#establishing-a-redundant-reliable-data-storage-layer)
|
||||
* [Starting replicated, load balanced Kubernetes API servers](#replicated-api-servers)
|
||||
* [Setting up master-elected Kubernetes scheduler and controller-manager daemons](#master-elected-components)
|
||||
|
||||
Here's what the system should look like when it's finished:
|
||||

|
||||
|
||||
Ready? Let's get started.
|
||||
|
||||
## Initial set-up
|
||||
|
||||
The remainder of this guide assumes that you are setting up a 3-node clustered master, where each machine is running some flavor of Linux.
|
||||
Examples in the guide are given for Debian distributions, but they should be easily adaptable to other distributions.
|
||||
Likewise, this set up should work whether you are running in a public or private cloud provider, or if you are running
|
||||
on bare metal.
|
||||
|
||||
The easiest way to implement an HA Kubernetes cluster is to start with an existing single-master cluster. The
|
||||
instructions at [https://get.k8s.io](https://get.k8s.io)
|
||||
describe easy installation for single-master clusters on a variety of platforms.
|
||||
|
||||
## Reliable nodes
|
||||
|
||||
On each master node, we are going to run a number of processes that implement the Kubernetes API. The first step in making these reliable is
|
||||
to make sure that each automatically restarts when it fails. To achieve this, we need to install a process watcher. We choose to use
|
||||
the `kubelet` that we run on each of the worker nodes. This is convenient, since we can use containers to distribute our binaries, we can
|
||||
establish resource limits, and introspect the resource usage of each daemon. Of course, we also need something to monitor the kubelet
|
||||
itself (insert who watches the watcher jokes here). For Debian systems, we choose monit, but there are a number of alternate
|
||||
choices. For example, on systemd-based systems (e.g. RHEL, CentOS), you can run 'systemctl enable kubelet'.
|
||||
|
||||
If you are extending from a standard Kubernetes installation, the `kubelet` binary should already be present on your system. You can run
|
||||
`which kubelet` to determine if the binary is in fact installed. If it is not installed,
|
||||
you should install the [kubelet binary](https://storage.googleapis.com/kubernetes-release/release/v0.19.3/bin/linux/amd64/kubelet), the
|
||||
[kubelet init file](http://releases.k8s.io/{{page.githubbranch}}/cluster/saltbase/salt/kubelet/initd) and [high-availability/default-kubelet](/{{page.version}}/docs/admin/high-availability/default-kubelet)
|
||||
scripts.
|
||||
|
||||
If you are using monit, you should also install the monit daemon (`apt-get install monit`) and the [high-availability/monit-kubelet](/{{page.version}}/docs/admin/high-availability/monit-kubelet) and
|
||||
[high-availability/monit-docker](/{{page.version}}/docs/admin/high-availability/monit-docker) configs.
|
||||
|
||||
On systemd systems you `systemctl enable kubelet` and `systemctl enable docker`.
|
||||
|
||||
|
||||
## Establishing a redundant, reliable data storage layer
|
||||
|
||||
The central foundation of a highly available solution is a redundant, reliable storage layer. The number one rule of high-availability is
|
||||
to protect the data. Whatever else happens, whatever catches on fire, if you have the data, you can rebuild. If you lose the data, you're
|
||||
done.
|
||||
|
||||
Clustered etcd already replicates your storage to all master instances in your cluster. This means that to lose data, all three nodes would need
|
||||
to have their physical (or virtual) disks fail at the same time. The probability that this occurs is relatively low, so for many people
|
||||
running a replicated etcd cluster is likely reliable enough. You can add additional reliability by increasing the
|
||||
size of the cluster from three to five nodes. If that is still insufficient, you can add
|
||||
[even more redundancy to your storage layer](#even-more-reliable-storage).
|
||||
|
||||
### Clustering etcd
|
||||
|
||||
The full details of clustering etcd are beyond the scope of this document, lots of details are given on the
|
||||
[etcd clustering page](https://github.com/coreos/etcd/blob/master/Documentation/clustering.md). This example walks through
|
||||
a simple cluster set up, using etcd's built in discovery to build our cluster.
|
||||
|
||||
First, hit the etcd discovery service to create a new token:
|
||||
|
||||
```shell
|
||||
curl https://discovery.etcd.io/new?size=3
|
||||
```
|
||||
|
||||
On each node, copy the [etcd.yaml](/{{page.version}}/docs/admin/high-availability/etcd.yaml) file into `/etc/kubernetes/manifests/etcd.yaml`
|
||||
|
||||
The kubelet on each node actively monitors the contents of that directory, and it will create an instance of the `etcd`
|
||||
server from the definition of the pod specified in `etcd.yaml`.
|
||||
|
||||
Note that in `etcd.yaml` you should substitute the token URL you got above for `${DISCOVERY_TOKEN}` on all three machines,
|
||||
and you should substitute a different name (e.g. `node-1`) for ${NODE_NAME} and the correct IP address
|
||||
for `${NODE_IP}` on each machine.
|
||||
|
||||
|
||||
#### Validating your cluster
|
||||
|
||||
Once you copy this into all three nodes, you should have a clustered etcd set up. You can validate with
|
||||
|
||||
```shell
|
||||
etcdctl member list
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```shell
|
||||
etcdctl cluster-health
|
||||
```
|
||||
|
||||
You can also validate that this is working with `etcdctl set foo bar` on one node, and `etcd get foo`
|
||||
on a different node.
|
||||
|
||||
### Even more reliable storage
|
||||
|
||||
Of course, if you are interested in increased data reliability, there are further options which makes the place where etcd
|
||||
installs it's data even more reliable than regular disks (belts *and* suspenders, ftw!).
|
||||
|
||||
If you use a cloud provider, then they usually provide this
|
||||
for you, for example [Persistent Disk](https://cloud.google.com/compute/docs/disks/persistent-disks) on the Google Cloud Platform. These
|
||||
are block-device persistent storage that can be mounted onto your virtual machine. Other cloud providers provide similar solutions.
|
||||
|
||||
If you are running on physical machines, you can also use network attached redundant storage using an iSCSI or NFS interface.
|
||||
Alternatively, you can run a clustered file system like Gluster or Ceph. Finally, you can also run a RAID array on each physical machine.
|
||||
|
||||
Regardless of how you choose to implement it, if you chose to use one of these options, you should make sure that your storage is mounted
|
||||
to each machine. If your storage is shared between the three masters in your cluster, you should create a different directory on the storage
|
||||
for each node. Throughout these instructions, we assume that this storage is mounted to your machine in `/var/etcd/data`
|
||||
|
||||
|
||||
## Replicated API Servers
|
||||
|
||||
Once you have replicated etcd set up correctly, we will also install the apiserver using the kubelet.
|
||||
|
||||
### Installing configuration files
|
||||
|
||||
First you need to create the initial log file, so that Docker mounts a file instead of a directory:
|
||||
|
||||
```shell
|
||||
touch /var/log/kube-apiserver.log
|
||||
```
|
||||
|
||||
Next, you need to create a `/srv/kubernetes/` directory on each node. This directory includes:
|
||||
|
||||
* basic_auth.csv - basic auth user and password
|
||||
* ca.crt - Certificate Authority cert
|
||||
* known_tokens.csv - tokens that entities (e.g. the kubelet) can use to talk to the apiserver
|
||||
* kubecfg.crt - Client certificate, public key
|
||||
* kubecfg.key - Client certificate, private key
|
||||
* server.cert - Server certificate, public key
|
||||
* server.key - Server certificate, private key
|
||||
|
||||
The easiest way to create this directory, may be to copy it from the master node of a working cluster, or you can manually generate these files yourself.
|
||||
|
||||
### Starting the API Server
|
||||
|
||||
Once these files exist, copy the [kube-apiserver.yaml](/{{page.version}}/docs/admin/high-availability/kube-apiserver.yaml) into `/etc/kubernetes/manifests/` on each master node.
|
||||
|
||||
The kubelet monitors this directory, and will automatically create an instance of the `kube-apiserver` container using the pod definition specified
|
||||
in the file.
|
||||
|
||||
### Load balancing
|
||||
|
||||
At this point, you should have 3 apiservers all working correctly. If you set up a network load balancer, you should
|
||||
be able to access your cluster via that load balancer, and see traffic balancing between the apiserver instances. Setting
|
||||
up a load balancer will depend on the specifics of your platform, for example instructions for the Google Cloud
|
||||
Platform can be found [here](https://cloud.google.com/compute/docs/load-balancing/)
|
||||
|
||||
Note, if you are using authentication, you may need to regenerate your certificate to include the IP address of the balancer,
|
||||
in addition to the IP addresses of the individual nodes.
|
||||
|
||||
For pods that you deploy into the cluster, the `kubernetes` service/dns name should provide a load balanced endpoint for the master automatically.
|
||||
|
||||
For external users of the API (e.g. the `kubectl` command line interface, continuous build pipelines, or other clients) you will want to configure
|
||||
them to talk to the external load balancer's IP address.
|
||||
|
||||
## Master elected components
|
||||
|
||||
So far we have set up state storage, and we have set up the API server, but we haven't run anything that actually modifies
|
||||
cluster state, such as the controller manager and scheduler. To achieve this reliably, we only want to have one actor modifying state at a time, but we want replicated
|
||||
instances of these actors, in case a machine dies. To achieve this, we are going to use a lease-lock in etcd to perform
|
||||
master election. On each of the three apiserver nodes, we run a small utility application named `podmaster`. It's job is to implement a master
|
||||
election protocol using etcd "compare and swap". If the apiserver node wins the election, it starts the master component it is managing (e.g. the scheduler), if it
|
||||
loses the election, it ensures that any master components running on the node (e.g. the scheduler) are stopped.
|
||||
|
||||
In the future, we expect to more tightly integrate this lease-locking into the scheduler and controller-manager binaries directly, as described in the [high availability design proposal](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/proposals/high-availability.md)
|
||||
|
||||
### Installing configuration files
|
||||
|
||||
First, create empty log files on each node, so that Docker will mount the files not make new directories:
|
||||
|
||||
```shell
|
||||
touch /var/log/kube-scheduler.log
|
||||
touch /var/log/kube-controller-manager.log
|
||||
```
|
||||
|
||||
Next, set up the descriptions of the scheduler and controller manager pods on each node.
|
||||
by copying [kube-scheduler.yaml](/{{page.version}}/docs/admin/high-availability/kube-scheduler.yaml) and [kube-controller-manager.yaml](high-availability//{{page.version}}/docs/admin/kube-controller-manager.yaml) into the `/srv/kubernetes/` directory.
|
||||
|
||||
### Running the podmaster
|
||||
|
||||
Now that the configuration files are in place, copy the [podmaster.yaml](/{{page.version}}/docs/admin/high-availability/podmaster.yaml) config file into `/etc/kubernetes/manifests/`
|
||||
|
||||
As before, the kubelet on the node monitors this directory, and will start an instance of the podmaster using the pod specification provided in `podmaster.yaml`.
|
||||
|
||||
Now you will have one instance of the scheduler process running on a single master node, and likewise one
|
||||
controller-manager process running on a single (possibly different) master node. If either of these processes fail,
|
||||
the kubelet will restart them. If any of these nodes fail, the process will move to a different instance of a master
|
||||
node.
|
||||
|
||||
## Conclusion
|
||||
|
||||
At this point, you are done (yeah!) with the master components, but you still need to add worker nodes (boo!).
|
||||
|
||||
If you have an existing cluster, this is as simple as reconfiguring your kubelets to talk to the load-balanced endpoint, and
|
||||
restarting the kubelets on each node.
|
||||
|
||||
If you are turning up a fresh cluster, you will need to install the kubelet and kube-proxy on each worker node, and
|
||||
set the `--apiserver` flag to your replicated endpoint.
|
||||
|
||||
## Vagrant up!
|
||||
|
||||
We indeed have an initial proof of concept tester for this, which is available [here](https://releases.k8s.io/{{page.githubbranch}}/examples/high-availability).
|
||||
|
||||
It implements the major concepts (with a few minor reductions for simplicity), of the podmaster HA implementation alongside a quick smoke test using k8petstore.
|
|
@ -0,0 +1,8 @@
|
|||
# This should be the IP address of the load balancer for all masters
|
||||
MASTER_IP=<insert-ip-here>
|
||||
# This should be the internal service IP address reserved for DNS
|
||||
DNS_IP=<insert-dns-ip-here>
|
||||
|
||||
DAEMON_ARGS="$DAEMON_ARGS --api-servers=https://${MASTER_IP} --enable-debugging-handlers=true --cloud-provider=
|
||||
gce --config=/etc/kubernetes/manifests --allow-privileged=False --v=2 --cluster-dns=${DNS_IP} --cluster-domain=c
|
||||
luster.local --configure-cbr0=true --cgroup-root=/ --system-container=/system "
|
|
@ -0,0 +1,87 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: etcd-server
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- image: gcr.io/google_containers/etcd:2.0.9
|
||||
name: etcd-container
|
||||
command:
|
||||
- /usr/local/bin/etcd
|
||||
- --name
|
||||
- ${NODE_NAME}
|
||||
- --initial-advertise-peer-urls
|
||||
- http://${NODE_IP}:2380
|
||||
- --listen-peer-urls
|
||||
- http://${NODE_IP}:2380
|
||||
- --advertise-client-urls
|
||||
- http://${NODE_IP}:4001
|
||||
- --listen-client-urls
|
||||
- http://127.0.0.1:4001
|
||||
- --data-dir
|
||||
- /var/etcd/data
|
||||
- --discovery
|
||||
- ${DISCOVERY_TOKEN}
|
||||
ports:
|
||||
- containerPort: 2380
|
||||
hostPort: 2380
|
||||
name: serverport
|
||||
- containerPort: 4001
|
||||
hostPort: 4001
|
||||
name: clientport
|
||||
volumeMounts:
|
||||
- mountPath: /var/etcd
|
||||
name: varetcd
|
||||
- mountPath: /etc/ssl
|
||||
name: etcssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
readOnly: true
|
||||
- mountPath: /var/ssl
|
||||
name: varssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/ssl
|
||||
name: usrssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/openssl
|
||||
name: etcopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
readOnly: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /var/etcd/data
|
||||
name: varetcd
|
||||
- hostPath:
|
||||
path: /etc/ssl
|
||||
name: etcssl
|
||||
- hostPath:
|
||||
path: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
- hostPath:
|
||||
path: /var/ssl
|
||||
name: varssl
|
||||
- hostPath:
|
||||
path: /usr/ssl
|
||||
name: usrssl
|
||||
- hostPath:
|
||||
path: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
- hostPath:
|
||||
path: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
- hostPath:
|
||||
path: /etc/openssl
|
||||
name: etcopenssl
|
||||
- hostPath:
|
||||
path: /etc/pki/tls
|
||||
name: etcpkitls
|
|
@ -0,0 +1,90 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: kube-apiserver
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: kube-apiserver
|
||||
image: gcr.io/google_containers/kube-apiserver:9680e782e08a1a1c94c656190011bd02
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- /usr/local/bin/kube-apiserver --address=127.0.0.1 --etcd-servers=http://127.0.0.1:4001
|
||||
--cloud-provider=gce --admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
||||
--service-cluster-ip-range=10.0.0.0/16 --client-ca-file=/srv/kubernetes/ca.crt
|
||||
--basic-auth-file=/srv/kubernetes/basic_auth.csv --cluster-name=e2e-test-bburns
|
||||
--tls-cert-file=/srv/kubernetes/server.cert --tls-private-key-file=/srv/kubernetes/server.key
|
||||
--secure-port=443 --token-auth-file=/srv/kubernetes/known_tokens.csv --v=2
|
||||
--allow-privileged=False 1>>/var/log/kube-apiserver.log 2>&1
|
||||
ports:
|
||||
- containerPort: 443
|
||||
hostPort: 443
|
||||
name: https
|
||||
- containerPort: 7080
|
||||
hostPort: 7080
|
||||
name: http
|
||||
- containerPort: 8080
|
||||
hostPort: 8080
|
||||
name: local
|
||||
volumeMounts:
|
||||
- mountPath: /srv/kubernetes
|
||||
name: srvkube
|
||||
readOnly: true
|
||||
- mountPath: /var/log/kube-apiserver.log
|
||||
name: logfile
|
||||
- mountPath: /etc/ssl
|
||||
name: etcssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
readOnly: true
|
||||
- mountPath: /var/ssl
|
||||
name: varssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/ssl
|
||||
name: usrssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/openssl
|
||||
name: etcopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
readOnly: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /srv/kubernetes
|
||||
name: srvkube
|
||||
- hostPath:
|
||||
path: /var/log/kube-apiserver.log
|
||||
name: logfile
|
||||
- hostPath:
|
||||
path: /etc/ssl
|
||||
name: etcssl
|
||||
- hostPath:
|
||||
path: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
- hostPath:
|
||||
path: /var/ssl
|
||||
name: varssl
|
||||
- hostPath:
|
||||
path: /usr/ssl
|
||||
name: usrssl
|
||||
- hostPath:
|
||||
path: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
- hostPath:
|
||||
path: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
- hostPath:
|
||||
path: /etc/openssl
|
||||
name: etcopenssl
|
||||
- hostPath:
|
||||
path: /etc/pki/tls
|
||||
name: etcpkitls
|
|
@ -0,0 +1,82 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: kube-controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- /usr/local/bin/kube-controller-manager --master=127.0.0.1:8080 --cluster-name=e2e-test-bburns
|
||||
--cluster-cidr=10.245.0.0/16 --allocate-node-cidrs=true --cloud-provider=gce --service-account-private-key-file=/srv/kubernetes/server.key
|
||||
--v=2 1>>/var/log/kube-controller-manager.log 2>&1
|
||||
image: gcr.io/google_containers/kube-controller-manager:fda24638d51a48baa13c35337fcd4793
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10252
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 1
|
||||
name: kube-controller-manager
|
||||
volumeMounts:
|
||||
- mountPath: /srv/kubernetes
|
||||
name: srvkube
|
||||
readOnly: true
|
||||
- mountPath: /var/log/kube-controller-manager.log
|
||||
name: logfile
|
||||
- mountPath: /etc/ssl
|
||||
name: etcssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
readOnly: true
|
||||
- mountPath: /var/ssl
|
||||
name: varssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/ssl
|
||||
name: usrssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/openssl
|
||||
name: etcopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
readOnly: true
|
||||
hostNetwork: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /srv/kubernetes
|
||||
name: srvkube
|
||||
- hostPath:
|
||||
path: /var/log/kube-controller-manager.log
|
||||
name: logfile
|
||||
- hostPath:
|
||||
path: /etc/ssl
|
||||
name: etcssl
|
||||
- hostPath:
|
||||
path: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
- hostPath:
|
||||
path: /var/ssl
|
||||
name: varssl
|
||||
- hostPath:
|
||||
path: /usr/ssl
|
||||
name: usrssl
|
||||
- hostPath:
|
||||
path: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
- hostPath:
|
||||
path: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
- hostPath:
|
||||
path: /etc/openssl
|
||||
name: etcopenssl
|
||||
- hostPath:
|
||||
path: /etc/pki/tls
|
||||
name: etcpkitls
|
|
@ -0,0 +1,30 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: kube-scheduler
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: kube-scheduler
|
||||
image: gcr.io/google_containers/kube-scheduler:34d0b8f8b31e27937327961528739bc9
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- /usr/local/bin/kube-scheduler --master=127.0.0.1:8080 --v=2 1>>/var/log/kube-scheduler.log
|
||||
2>&1
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10251
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 1
|
||||
volumeMounts:
|
||||
- mountPath: /var/log/kube-scheduler.log
|
||||
name: logfile
|
||||
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
name: default-token-s8ejd
|
||||
readOnly: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /var/log/kube-scheduler.log
|
||||
name: logfile
|
|
@ -0,0 +1,9 @@
|
|||
check process docker with pidfile /var/run/docker.pid
|
||||
group docker
|
||||
start program = "/etc/init.d/docker start"
|
||||
stop program = "/etc/init.d/docker stop"
|
||||
if does not exist then restart
|
||||
if failed
|
||||
unixsocket /var/run/docker.sock
|
||||
protocol HTTP request "/version"
|
||||
then restart
|
|
@ -0,0 +1,11 @@
|
|||
check process kubelet with pidfile /var/run/kubelet.pid
|
||||
group kubelet
|
||||
start program = "/etc/init.d/kubelet start"
|
||||
stop program = "/etc/init.d/kubelet stop"
|
||||
if does not exist then restart
|
||||
if failed
|
||||
host 127.0.0.1
|
||||
port 10255
|
||||
protocol HTTP
|
||||
request "/healthz"
|
||||
then restart
|
|
@ -0,0 +1,43 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: scheduler-master
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: scheduler-elector
|
||||
image: gcr.io/google_containers/podmaster:1.1
|
||||
command:
|
||||
- /podmaster
|
||||
- --etcd-servers=http://127.0.0.1:4001
|
||||
- --key=scheduler
|
||||
- --source-file=/kubernetes/kube-scheduler.manifest
|
||||
- --dest-file=/manifests/kube-scheduler.manifest
|
||||
volumeMounts:
|
||||
- mountPath: /kubernetes
|
||||
name: k8s
|
||||
readOnly: true
|
||||
- mountPath: /manifests
|
||||
name: manifests
|
||||
- name: controller-manager-elector
|
||||
image: gcr.io/google_containers/podmaster:1.1
|
||||
command:
|
||||
- /podmaster
|
||||
- --etcd-servers=http://127.0.0.1:4001
|
||||
- --key=controller
|
||||
- --source-file=/kubernetes/kube-controller-manager.manifest
|
||||
- --dest-file=/manifests/kube-controller-manager.manifest
|
||||
terminationMessagePath: /dev/termination-log
|
||||
volumeMounts:
|
||||
- mountPath: /kubernetes
|
||||
name: k8s
|
||||
readOnly: true
|
||||
- mountPath: /manifests
|
||||
name: manifests
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /srv/kubernetes
|
||||
name: k8s
|
||||
- hostPath:
|
||||
path: /etc/kubernetes/manifests
|
||||
name: manifests
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
The cluster admin guide is for anyone creating or administering a Kubernetes cluster.
|
||||
It assumes some familiarity with concepts in the [User Guide](/{{page.version}}/docs/user-guide/).
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## Planning a cluster
|
||||
|
||||
There are many different examples of how to setup a kubernetes cluster. Many of them are listed in this
|
||||
[matrix](/{{page.version}}/docs/getting-started-guides/). We call each of the combinations in this matrix a *distro*.
|
||||
|
||||
Before choosing a particular guide, here are some things to consider:
|
||||
|
||||
- Are you just looking to try out Kubernetes on your laptop, or build a high-availability many-node cluster? Both
|
||||
models are supported, but some distros are better for one case or the other.
|
||||
- Will you be using a hosted Kubernetes cluster, such as [GKE](https://cloud.google.com/container-engine), or setting
|
||||
one up yourself?
|
||||
- Will your cluster be on-premises, or in the cloud (IaaS)? Kubernetes does not directly support hybrid clusters. We
|
||||
recommend setting up multiple clusters rather than spanning distant locations.
|
||||
- Will you be running Kubernetes on "bare metal" or virtual machines? Kubernetes supports both, via different distros.
|
||||
- Do you just want to run a cluster, or do you expect to do active development of kubernetes project code? If the
|
||||
latter, it is better to pick a distro actively used by other developers. Some distros only use binary releases, but
|
||||
offer is a greater variety of choices.
|
||||
- Not all distros are maintained as actively. Prefer ones which are listed as tested on a more recent version of
|
||||
Kubernetes.
|
||||
- If you are configuring kubernetes on-premises, you will need to consider what [networking
|
||||
model](/{{page.version}}/docs/admin/networking) fits best.
|
||||
- If you are designing for very high-availability, you may want [clusters in multiple zones](/{{page.version}}/docs/admin/multi-cluster).
|
||||
- You may want to familiarize yourself with the various
|
||||
[components](/{{page.version}}/docs/admin/cluster-components) needed to run a cluster.
|
||||
|
||||
## Setting up a cluster
|
||||
|
||||
Pick one of the Getting Started Guides from the [matrix](/{{page.version}}/docs/getting-started-guides/) and follow it.
|
||||
If none of the Getting Started Guides fits, you may want to pull ideas from several of the guides.
|
||||
|
||||
One option for custom networking is *OpenVSwitch GRE/VxLAN networking* ([ovs-networking.md](/{{page.version}}/docs/admin/ovs-networking)), which
|
||||
uses OpenVSwitch to set up networking between pods across
|
||||
Kubernetes nodes.
|
||||
|
||||
If you are modifying an existing guide which uses Salt, this document explains [how Salt is used in the Kubernetes
|
||||
project](/{{page.version}}/docs/admin/salt).
|
||||
|
||||
## Managing a cluster, including upgrades
|
||||
|
||||
[Managing a cluster](/{{page.version}}/docs/admin/cluster-management).
|
||||
|
||||
## Managing nodes
|
||||
|
||||
[Managing nodes](/{{page.version}}/docs/admin/node).
|
||||
|
||||
## Optional Cluster Services
|
||||
|
||||
* **DNS Integration with SkyDNS** ([dns.md](/{{page.version}}/docs/admin/dns)):
|
||||
Resolving a DNS name directly to a Kubernetes service.
|
||||
|
||||
* **Logging** with [Kibana](/{{page.version}}/docs/user-guide/logging)
|
||||
|
||||
## Multi-tenant support
|
||||
|
||||
* **Resource Quota** ([resource-quota.md](/{{page.version}}/docs/admin/resource-quota))
|
||||
|
||||
## Security
|
||||
|
||||
* **Kubernetes Container Environment** ([docs/user-guide/container-environment.md](/{{page.version}}/docs/user-guide/container-environment)):
|
||||
Describes the environment for Kubelet managed containers on a Kubernetes
|
||||
node.
|
||||
|
||||
* **Securing access to the API Server** [accessing the api](/{{page.version}}/docs/admin/accessing-the-api)
|
||||
|
||||
* **Authentication** [authentication](/{{page.version}}/docs/admin/authentication)
|
||||
|
||||
* **Authorization** [authorization](/{{page.version}}/docs/admin/authorization)
|
||||
|
||||
* **Admission Controllers** [admission_controllers](/{{page.version}}/docs/admin/admission-controllers)
|
|
@ -0,0 +1,192 @@
|
|||
|
||||
By default, pods run with unbounded CPU and memory limits. This means that any pod in the
|
||||
system will be able to consume as much CPU and memory on the node that executes the pod.
|
||||
|
||||
Users may want to impose restrictions on the amount of resource a single pod in the system may consume
|
||||
for a variety of reasons.
|
||||
|
||||
For example:
|
||||
|
||||
1. Each node in the cluster has 2GB of memory. The cluster operator does not want to accept pods
|
||||
that require more than 2GB of memory since no node in the cluster can support the requirement. To prevent a
|
||||
pod from being permanently unscheduled to a node, the operator instead chooses to reject pods that exceed 2GB
|
||||
of memory as part of admission control.
|
||||
2. A cluster is shared by two communities in an organization that runs production and development workloads
|
||||
respectively. Production workloads may consume up to 8GB of memory, but development workloads may consume up
|
||||
to 512MB of memory. The cluster operator creates a separate namespace for each workload, and applies limits to
|
||||
each namespace.
|
||||
3. Users may create a pod which consumes resources just below the capacity of a machine. The left over space
|
||||
may be too small to be useful, but big enough for the waste to be costly over the entire cluster. As a result,
|
||||
the cluster operator may want to set limits that a pod must consume at least 20% of the memory and cpu of their
|
||||
average node size in order to provide for more uniform scheduling and to limit waste.
|
||||
|
||||
This example demonstrates how limits can be applied to a Kubernetes namespace to control
|
||||
min/max resource limits per pod. In addition, this example demonstrates how you can
|
||||
apply default resource limits to pods in the absence of an end-user specified value.
|
||||
|
||||
See [LimitRange design doc](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/admission_control_limit_range.md) for more information. For a detailed description of the Kubernetes resource model, see [Resources](/{{page.version}}/docs/user-guide/compute-resources)
|
||||
|
||||
## Step 0: Prerequisites
|
||||
|
||||
This example requires a running Kubernetes cluster. See the [Getting Started guides](/{{page.version}}/docs/getting-started-guides/) for how to get started.
|
||||
|
||||
Change to the `<kubernetes>` directory if you're not already there.
|
||||
|
||||
## Step 1: Create a namespace
|
||||
|
||||
This example will work in a custom namespace to demonstrate the concepts involved.
|
||||
|
||||
Let's create a new namespace called limit-example:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/namespace.yaml
|
||||
namespace "limit-example" created
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 5m
|
||||
limit-example <none> Active 53s
|
||||
```
|
||||
|
||||
## Step 2: Apply a limit to the namespace
|
||||
|
||||
Let's create a simple limit in our namespace.
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/limits.yaml --namespace=limit-example
|
||||
limitrange "mylimits" created
|
||||
```
|
||||
|
||||
Let's describe the limits that we have imposed in our namespace.
|
||||
|
||||
```shell
|
||||
$ kubectl describe limits mylimits --namespace=limit-example
|
||||
Name: mylimits
|
||||
Namespace: limit-example
|
||||
Type Resource Min Max Request Limit Limit/Request
|
||||
---- -------- --- --- ------- ----- -------------
|
||||
Pod cpu 200m 2 - - -
|
||||
Pod memory 6Mi 1Gi - - -
|
||||
Container cpu 100m 2 200m 300m -
|
||||
Container memory 3Mi 1Gi 100Mi 200Mi -
|
||||
```
|
||||
|
||||
In this scenario, we have said the following:
|
||||
|
||||
1. If a max constraint is specified for a resource (2 CPU and 1Gi memory in this case), then a limit
|
||||
must be specified for that resource across all containers. Failure to specify a limit will result in
|
||||
a validation error when attempting to create the pod. Note that a default value of limit is set by
|
||||
*default* in file `limits.yaml` (300m CPU and 200Mi memory).
|
||||
2. If a min constraint is specified for a resource (100m CPU and 3Mi memory in this case), then a
|
||||
request must be specified for that resource across all containers. Failure to specify a request will
|
||||
result in a validation error when attempting to create the pod. Note that a default value of request is
|
||||
set by *defaultRequest* in file `limits.yaml` (200m CPU and 100Mi memory).
|
||||
3. For any pod, the sum of all containers memory requests must be >= 6Mi and the sum of all containers
|
||||
memory limits must be <= 1Gi; the sum of all containers CPU requests must be >= 200m and the sum of all
|
||||
containers CPU limits must be <= 2.
|
||||
|
||||
## Step 3: Enforcing limits at point of creation
|
||||
|
||||
The limits enumerated in a namespace are only enforced when a pod is created or updated in
|
||||
the cluster. If you change the limits to a different value range, it does not affect pods that
|
||||
were previously created in a namespace.
|
||||
|
||||
If a resource (cpu or memory) is being restricted by a limit, the user will get an error at time
|
||||
of creation explaining why.
|
||||
|
||||
Let's first spin up a replication controller that creates a single container pod to demonstrate
|
||||
how default values are applied to each pod.
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image=nginx --replicas=1 --namespace=limit-example
|
||||
replicationcontroller "nginx" created
|
||||
$ kubectl get pods --namespace=limit-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-aq0mf 1/1 Running 0 35s
|
||||
$ kubectl get pods nginx-aq0mf --namespace=limit-example -o yaml | grep resources -C 8
|
||||
```
|
||||
|
||||
```yaml
|
||||
resourceVersion: "127"
|
||||
selfLink: /api/v1/namespaces/limit-example/pods/nginx-aq0mf
|
||||
uid: 51be42a7-7156-11e5-9921-286ed488f785
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources:
|
||||
limits:
|
||||
cpu: 300m
|
||||
memory: 200Mi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 100Mi
|
||||
terminationMessagePath: /dev/termination-log
|
||||
volumeMounts:
|
||||
```
|
||||
|
||||
Note that our nginx container has picked up the namespace default cpu and memory resource *limits* and *requests*.
|
||||
|
||||
Let's create a pod that exceeds our allowed limits by having it have a container that requests 3 cpu cores.
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/invalid-pod.yaml --namespace=limit-example
|
||||
Error from server: error when creating "docs/admin/limitrange/invalid-pod.yaml": Pod "invalid-pod" is forbidden: [Maximum cpu usage per Pod is 2, but limit is 3., Maximum cpu usage per Container is 2, but limit is 3.]
|
||||
```
|
||||
|
||||
Let's create a pod that falls within the allowed limit boundaries.
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/limitrange/valid-pod.yaml --namespace=limit-example
|
||||
pod "valid-pod" created
|
||||
$ kubectl get pods valid-pod --namespace=limit-example -o yaml | grep -C 6 resources
|
||||
```
|
||||
|
||||
```yaml
|
||||
uid: 162a12aa-7157-11e5-9921-286ed488f785
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/google_containers/serve_hostname
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: kubernetes-serve-hostname
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
```
|
||||
|
||||
Note that this pod specifies explicit resource *limits* and *requests* so it did not pick up the namespace
|
||||
default values.
|
||||
|
||||
Note: The *limits* for CPU resource are not enforced in the default Kubernetes setup on the physical node
|
||||
that runs the container unless the administrator deploys the kubelet with the folllowing flag:
|
||||
|
||||
```shell
|
||||
$ kubelet --help
|
||||
Usage of kubelet
|
||||
....
|
||||
--cpu-cfs-quota[=false]: Enable CPU CFS quota enforcement for containers that specify CPU limits
|
||||
$ kubelet --cpu-cfs-quota=true ...
|
||||
```
|
||||
|
||||
## Step 4: Cleanup
|
||||
|
||||
To remove the resources used by this example, you can just delete the limit-example namespace.
|
||||
|
||||
```shell
|
||||
$ kubectl delete namespace limit-example
|
||||
namespace "limit-example" deleted
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 20m
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Cluster operators that want to restrict the amount of resources a single container or pod may consume
|
||||
are able to define allowable ranges per Kubernetes namespace. In the absence of any explicit assignments,
|
||||
the Kubernetes system is able to apply default resource *limits* and *requests* if desired in order to
|
||||
constrain the amount of resource a pod consumes on a node.
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: invalid-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: kubernetes-serve-hostname
|
||||
image: gcr.io/google_containers/serve_hostname
|
||||
resources:
|
||||
limits:
|
||||
cpu: "3"
|
||||
memory: 100Mi
|
|
@ -0,0 +1,26 @@
|
|||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: mylimits
|
||||
spec:
|
||||
limits:
|
||||
- max:
|
||||
cpu: "2"
|
||||
memory: 1Gi
|
||||
min:
|
||||
cpu: 200m
|
||||
memory: 6Mi
|
||||
type: Pod
|
||||
- default:
|
||||
cpu: 300m
|
||||
memory: 200Mi
|
||||
defaultRequest:
|
||||
cpu: 200m
|
||||
memory: 100Mi
|
||||
max:
|
||||
cpu: "2"
|
||||
memory: 1Gi
|
||||
min:
|
||||
cpu: 100m
|
||||
memory: 3Mi
|
||||
type: Container
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: limit-example
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: valid-pod
|
||||
labels:
|
||||
name: valid-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: kubernetes-serve-hostname
|
||||
image: gcr.io/google_containers/serve_hostname
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
You may want to set up multiple Kubernetes clusters, both to
|
||||
have clusters in different regions to be nearer to your users, and to tolerate failures and/or invasive maintenance.
|
||||
This document describes some of the issues to consider when making a decision about doing so.
|
||||
|
||||
Note that at present,
|
||||
Kubernetes does not offer a mechanism to aggregate multiple clusters into a single virtual cluster. However,
|
||||
we [plan to do this in the future](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/proposals/federation.md).
|
||||
|
||||
## Scope of a single cluster
|
||||
|
||||
On IaaS providers such as Google Compute Engine or Amazon Web Services, a VM exists in a
|
||||
[zone](https://cloud.google.com/compute/docs/zones) or [availability
|
||||
zone](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones).
|
||||
|
||||
We suggest that all the VMs in a Kubernetes cluster should be in the same availability zone, because:
|
||||
|
||||
- compared to having a single global Kubernetes cluster, there are fewer single-points of failure
|
||||
- compared to a cluster that spans availability zones, it is easier to reason about the availability properties of a
|
||||
single-zone cluster.
|
||||
- when the Kubernetes developers are designing the system (e.g. making assumptions about latency, bandwidth, or
|
||||
correlated failures) they are assuming all the machines are in a single data center, or otherwise closely connected.
|
||||
|
||||
It is okay to have multiple clusters per availability zone, though on balance we think fewer is better.
|
||||
Reasons to prefer fewer clusters are:
|
||||
|
||||
- improved bin packing of Pods in some cases with more nodes in one cluster (less resource fragmentation)
|
||||
- reduced operational overhead (though the advantage is diminished as ops tooling and processes matures)
|
||||
- reduced costs for per-cluster fixed resource costs, e.g. apiserver VMs (but small as a percentage
|
||||
of overall cluster cost for medium to large clusters).
|
||||
|
||||
Reasons to have multiple clusters include:
|
||||
|
||||
- strict security policies requiring isolation of one class of work from another (but, see Partitioning Clusters
|
||||
below).
|
||||
- test clusters to canary new Kubernetes releases or other cluster software.
|
||||
|
||||
## Selecting the right number of clusters
|
||||
|
||||
The selection of the number of Kubernetes clusters may be a relatively static choice, only revisited occasionally.
|
||||
By contrast, the number of nodes in a cluster and the number of pods in a service may be change frequently according to
|
||||
load and growth.
|
||||
|
||||
To pick the number of clusters, first, decide which regions you need to be in to have adequate latency to all your end users, for services that will run
|
||||
on Kubernetes (if you use a Content Distribution Network, the latency requirements for the CDN-hosted content need not
|
||||
be considered). Legal issues might influence this as well. For example, a company with a global customer base might decide to have clusters in US, EU, AP, and SA regions.
|
||||
Call the number of regions to be in `R`.
|
||||
|
||||
Second, decide how many clusters should be able to be unavailable at the same time, while still being available. Call
|
||||
the number that can be unavailable `U`. If you are not sure, then 1 is a fine choice.
|
||||
|
||||
If it is allowable for load-balancing to direct traffic to any region in the event of a cluster failure, then
|
||||
you need `R + U` clusters. If it is not (e.g you want to ensure low latency for all users in the event of a
|
||||
cluster failure), then you need to have `R * U` clusters (`U` in each of `R` regions). In any case, try to put each cluster in a different zone.
|
||||
|
||||
Finally, if any of your clusters would need more than the maximum recommended number of nodes for a Kubernetes cluster, then
|
||||
you may need even more clusters. Kubernetes v1.0 currently supports clusters up to 100 nodes in size, but we are targeting
|
||||
1000-node clusters by early 2016.
|
||||
|
||||
## Working with multiple clusters
|
||||
|
||||
When you have multiple clusters, you would typically create services with the same config in each cluster and put each of those
|
||||
service instances behind a load balancer (AWS Elastic Load Balancer, GCE Forwarding Rule or HTTP Load Balancer) spanning all of them, so that
|
||||
failures of a single cluster are not visible to end users.
|
|
@ -0,0 +1,143 @@
|
|||
|
||||
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 users or groups of users (henceforth a 'user community').
|
||||
|
||||
Each user community wants to be able to work in isolation from other communities.
|
||||
|
||||
Each user community has its own:
|
||||
|
||||
1. resources (pods, services, replication controllers, etc.)
|
||||
2. policies (who can or cannot perform actions in their community)
|
||||
3. constraints (this community is allowed this much quota, etc.)
|
||||
|
||||
A cluster operator may create a Namespace for each unique user community.
|
||||
|
||||
The Namespace provides a unique scope for:
|
||||
|
||||
1. named resources (to avoid basic naming collisions)
|
||||
2. delegated management authority to trusted users
|
||||
3. ability to limit community resource consumption
|
||||
|
||||
## Use cases
|
||||
|
||||
1. As a cluster operator, I want to support multiple user communities on a single cluster.
|
||||
2. As a cluster operator, I want to delegate authority to partitions of the cluster to trusted users
|
||||
in those communities.
|
||||
3. As a cluster operator, I want to limit the amount of resources each community can consume in order
|
||||
to limit the impact to other communities using the cluster.
|
||||
4. As a cluster user, I want to interact with resources that are pertinent to my user community in
|
||||
isolation of what other user communities are doing on the cluster.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Look [here](/{{page.version}}/docs/admin/namespaces/) for an in depth example of namespaces.
|
||||
|
||||
### Viewing namespaces
|
||||
|
||||
You can list the current namespaces in a cluster using:
|
||||
|
||||
```shell
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS
|
||||
default <none> Active
|
||||
kube-system <none> Active
|
||||
```
|
||||
|
||||
Kubernetes starts with two initial namespaces:
|
||||
* `default` The default namespace for objects with no other namespace
|
||||
* `kube-system` The namespace for objects created by the Kubernetes system
|
||||
|
||||
You can also get the summary of a specific namespace using:
|
||||
|
||||
```shell
|
||||
$ kubectl get namespaces <name>
|
||||
```
|
||||
|
||||
Or you can get detailed information with:
|
||||
|
||||
```shell
|
||||
$ kubectl describe namespaces <name>
|
||||
Name: default
|
||||
Labels: <none>
|
||||
Status: Active
|
||||
|
||||
No resource quota.
|
||||
|
||||
Resource Limits
|
||||
Type Resource Min Max Default
|
||||
---- -------- --- --- ---
|
||||
Container cpu - - 100m
|
||||
```
|
||||
|
||||
Note that these details show both resource quota (if present) as well as resource limit ranges.
|
||||
|
||||
Resource quota tracks aggregate usage of resources in the *Namespace* and allows cluster operators
|
||||
to define *Hard* resource usage limits that a *Namespace* may consume.
|
||||
|
||||
A limit range defines min/max constraints on the amount of resources a single entity can consume in
|
||||
a *Namespace*.
|
||||
|
||||
See [Admission control: Limit Range](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/admission_control_limit_range.md)
|
||||
|
||||
A namespace can be in one of two phases:
|
||||
* `Active` the namespace is in use
|
||||
* `Terminating` the namespace is being deleted, and can not be used for new objects
|
||||
|
||||
See the [design doc](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/namespaces.md#phases) for more details.
|
||||
|
||||
### Creating a new namespace
|
||||
|
||||
To create a new namespace, first create a new YAML file called `my-namespace.yaml` with the contents:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: <insert-namespace-name-here>
|
||||
```
|
||||
|
||||
Note that the name of your namespace must be a DNS compatible label.
|
||||
|
||||
More information on the `finalizers` field can be found in the namespace [design doc](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/namespaces.md#finalizers).
|
||||
|
||||
Then run:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./my-namespace.yaml
|
||||
```
|
||||
|
||||
### Working in namespaces
|
||||
|
||||
See [Setting the namespace for a request](/{{page.version}}/docs/user-guide/namespaces/#setting-the-namespace-for-a-request)
|
||||
and [Setting the namespace preference](/{{page.version}}/docs/user-guide/namespaces/#setting-the-namespace-preference).
|
||||
|
||||
### Deleting a namespace
|
||||
|
||||
You can delete a namespace with
|
||||
|
||||
```shell
|
||||
$ kubectl delete namespaces <insert-some-namespace-name>
|
||||
```
|
||||
|
||||
**WARNING, this deletes _everything_ under the namespace!**
|
||||
|
||||
This delete is asynchronous, so for a time you will see the namespace in the `Terminating` state.
|
||||
|
||||
## Namespaces and DNS
|
||||
|
||||
When you create a [Service](/{{page.version}}/docs/user-guide/services), it creates a corresponding [DNS entry](/{{page.version}}/docs/admin/dns).
|
||||
This entry is of the form `<service-name>.<namespace-name>.svc.cluster.local`, which means
|
||||
that if a container just uses `<service-name>` it will resolve to the service which
|
||||
is local to a namespace. This is useful for using the same configuration across
|
||||
multiple namespaces such as Development, Staging and Production. If you want to reach
|
||||
across namespaces, you need to use the fully qualified domain name (FQDN).
|
||||
|
||||
## Design
|
||||
|
||||
Details of the design of namespaces in Kubernetes, including a [detailed example](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/namespaces.md#example-openshift-origin-managing-a-kubernetes-namespace)
|
||||
can be found in the [namespaces design doc](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/namespaces.md)
|
|
@ -0,0 +1,248 @@
|
|||
|
||||
Kubernetes _namespaces_ help different projects, teams, or customers to share a Kubernetes cluster.
|
||||
|
||||
It does this by providing the following:
|
||||
|
||||
1. A scope for [Names](/{{page.version}}/docs/user-guide/identifiers).
|
||||
2. A mechanism to attach authorization and policy to a subsection of the cluster.
|
||||
|
||||
Use of multiple namespaces is optional.
|
||||
|
||||
This example demonstrates how to use Kubernetes namespaces to subdivide your cluster.
|
||||
|
||||
### Step Zero: Prerequisites
|
||||
|
||||
This example assumes the following:
|
||||
|
||||
1. You have an [existing Kubernetes cluster](/{{page.version}}/docs/getting-started-guides/).
|
||||
2. You have a basic understanding of Kubernetes _[pods](/{{page.version}}/docs/user-guide/pods)_, _[services](/{{page.version}}/docs/user-guide/services)_, and _[replication controllers](/{{page.version}}/docs/user-guide/replication-controller)_.
|
||||
|
||||
### Step One: Understand the default namespace
|
||||
|
||||
By default, a Kubernetes cluster will instantiate a default namespace when provisioning the cluster to hold the default set of pods,
|
||||
services, and replication controllers used by the cluster.
|
||||
|
||||
Assuming you have a fresh cluster, you can introspect the available namespace's by doing the following:
|
||||
|
||||
```shell
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS
|
||||
default <none>
|
||||
```
|
||||
|
||||
### Step Two: Create new namespaces
|
||||
|
||||
For this exercise, we will create two additional Kubernetes namespaces to hold our content.
|
||||
|
||||
Let's imagine a scenario where an organization is using a shared Kubernetes cluster for development and production use cases.
|
||||
|
||||
The development team would like to maintain a space in the cluster where they can get a view on the list of pods, services, and replication controllers
|
||||
they use to build and run their application. In this space, Kubernetes resources come and go, and the restrictions on who can or cannot modify resources
|
||||
are relaxed to enable agile development.
|
||||
|
||||
The operations team would like to maintain a space in the cluster where they can enforce strict procedures on who can or cannot manipulate the set of
|
||||
pods, services, and replication controllers that run the production site.
|
||||
|
||||
One pattern this organization could follow is to partition the Kubernetes cluster into two namespaces: development and production.
|
||||
|
||||
Let's create two new namespaces to hold our work.
|
||||
|
||||
Use the file [`namespace-dev.json`](/{{page.version}}/docs/admin/namespacesnamespace-dev.json) which describes a development namespace:
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE namespace-dev.json -->
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Namespace",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "development",
|
||||
"labels": {
|
||||
"name": "development"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[Download example](/{{page.version}}/docs/admin/namespacesnamespace-dev.json)
|
||||
<!-- END MUNGE: EXAMPLE namespace-dev.json -->
|
||||
|
||||
Create the development namespace using kubectl.
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/namespaces/namespace-dev.json
|
||||
```
|
||||
|
||||
And then lets create the production namespace using kubectl.
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/namespaces/namespace-prod.json
|
||||
```
|
||||
|
||||
To be sure things are right, let's list all of the namespaces in our cluster.
|
||||
|
||||
```shell
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS
|
||||
default <none> Active
|
||||
development name=development Active
|
||||
production name=production Active
|
||||
```
|
||||
|
||||
### Step Three: Create pods in each namespace
|
||||
|
||||
A Kubernetes namespace provides the scope for pods, services, and replication controllers in the cluster.
|
||||
|
||||
Users interacting with one namespace do not see the content in another namespace.
|
||||
|
||||
To demonstrate this, let's spin up a simple replication controller and pod in the development namespace.
|
||||
|
||||
We first check what is the current context:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: REDACTED
|
||||
server: https://130.211.122.180
|
||||
name: lithe-cocoa-92103_kubernetes
|
||||
contexts:
|
||||
- context:
|
||||
cluster: lithe-cocoa-92103_kubernetes
|
||||
user: lithe-cocoa-92103_kubernetes
|
||||
name: lithe-cocoa-92103_kubernetes
|
||||
current-context: lithe-cocoa-92103_kubernetes
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: lithe-cocoa-92103_kubernetes
|
||||
user:
|
||||
client-certificate-data: REDACTED
|
||||
client-key-data: REDACTED
|
||||
token: 65rZW78y8HbwXXtSXuUw9DbP4FLjHi4b
|
||||
- name: lithe-cocoa-92103_kubernetes-basic-auth
|
||||
user:
|
||||
password: h5M0FtUUIflBSdI7
|
||||
username: admin
|
||||
```
|
||||
|
||||
The next step is to define a context for the kubectl client to work in each namespace. The value of "cluster" and "user" fields are copied from the current context.
|
||||
|
||||
```shell
|
||||
$ kubectl config set-context dev --namespace=development --cluster=lithe-cocoa-92103_kubernetes --user=lithe-cocoa-92103_kubernetes
|
||||
$ kubectl config set-context prod --namespace=production --cluster=lithe-cocoa-92103_kubernetes --user=lithe-cocoa-92103_kubernetes
|
||||
```
|
||||
|
||||
The above commands provided two request contexts you can alternate against depending on what namespace you
|
||||
wish to work against.
|
||||
|
||||
Let's switch to operate in the development namespace.
|
||||
|
||||
```shell
|
||||
$ kubectl config use-context dev
|
||||
```
|
||||
|
||||
You can verify your current context by doing the following:
|
||||
|
||||
```shell
|
||||
$ kubectl config view
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: REDACTED
|
||||
server: https://130.211.122.180
|
||||
name: lithe-cocoa-92103_kubernetes
|
||||
contexts:
|
||||
- context:
|
||||
cluster: lithe-cocoa-92103_kubernetes
|
||||
namespace: development
|
||||
user: lithe-cocoa-92103_kubernetes
|
||||
name: dev
|
||||
- context:
|
||||
cluster: lithe-cocoa-92103_kubernetes
|
||||
user: lithe-cocoa-92103_kubernetes
|
||||
name: lithe-cocoa-92103_kubernetes
|
||||
- context:
|
||||
cluster: lithe-cocoa-92103_kubernetes
|
||||
namespace: production
|
||||
user: lithe-cocoa-92103_kubernetes
|
||||
name: prod
|
||||
current-context: dev
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: lithe-cocoa-92103_kubernetes
|
||||
user:
|
||||
client-certificate-data: REDACTED
|
||||
client-key-data: REDACTED
|
||||
token: 65rZW78y8HbwXXtSXuUw9DbP4FLjHi4b
|
||||
- name: lithe-cocoa-92103_kubernetes-basic-auth
|
||||
user:
|
||||
password: h5M0FtUUIflBSdI7
|
||||
username: admin
|
||||
```
|
||||
|
||||
At this point, all requests we make to the Kubernetes cluster from the command line are scoped to the development namespace.
|
||||
|
||||
Let's create some content.
|
||||
|
||||
```shell
|
||||
$ kubectl run snowflake --image=kubernetes/serve_hostname --replicas=2
|
||||
```
|
||||
|
||||
We have just created a replication controller whose replica size is 2 that is running the pod called snowflake with a basic container that just serves the hostname.
|
||||
|
||||
```shell
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
snowflake snowflake kubernetes/serve_hostname run=snowflake 2
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
snowflake-8w0qn 1/1 Running 0 22s
|
||||
snowflake-jrpzb 1/1 Running 0 22s
|
||||
```
|
||||
|
||||
And this is great, developers are able to do what they want, and they do not have to worry about affecting content in the production namespace.
|
||||
|
||||
Let's switch to the production namespace and show how resources in one namespace are hidden from the other.
|
||||
|
||||
```shell
|
||||
$ kubectl config use-context prod
|
||||
```
|
||||
|
||||
The production namespace should be empty.
|
||||
|
||||
```shell
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
```
|
||||
|
||||
Production likes to run cattle, so let's create some cattle pods.
|
||||
|
||||
```shell
|
||||
$ kubectl run cattle --image=kubernetes/serve_hostname --replicas=5
|
||||
|
||||
$ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
cattle cattle kubernetes/serve_hostname run=cattle 5
|
||||
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
cattle-97rva 1/1 Running 0 12s
|
||||
cattle-i9ojn 1/1 Running 0 12s
|
||||
cattle-qj3yv 1/1 Running 0 12s
|
||||
cattle-yc7vn 1/1 Running 0 12s
|
||||
cattle-zz7ea 1/1 Running 0 12s
|
||||
```
|
||||
|
||||
At this point, it should be clear that the resources users create in one namespace are hidden from the other namespace.
|
||||
|
||||
As the policy support in Kubernetes evolves, we will extend this scenario to show how you can provide different
|
||||
authorization rules for each namespace.
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"kind": "Namespace",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "development",
|
||||
"labels": {
|
||||
"name": "development"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"kind": "Namespace",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "production",
|
||||
"labels": {
|
||||
"name": "production"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
|
||||
Kubernetes approaches networking somewhat differently than Docker does by
|
||||
default. There are 4 distinct networking problems to solve:
|
||||
|
||||
1. Highly-coupled container-to-container communications: this is solved by
|
||||
[pods](/{{page.version}}/docs/user-guide/pods) and `localhost` communications.
|
||||
2. Pod-to-Pod communications: this is the primary focus of this document.
|
||||
3. Pod-to-Service communications: this is covered by [services](/{{page.version}}/docs/user-guide/services).
|
||||
4. External-to-Service communications: this is covered by [services](/{{page.version}}/docs/user-guide/services).
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
Kubernetes assumes that pods can communicate with other pods, regardless of
|
||||
which host they land on. We give every pod its own IP address so you do not
|
||||
need to explicitly create links between pods and you almost never need to deal
|
||||
with mapping container ports to host ports. This creates a clean,
|
||||
backwards-compatible model where pods can be treated much like VMs or physical
|
||||
hosts from the perspectives of port allocation, naming, service discovery, load
|
||||
balancing, application configuration, and migration.
|
||||
|
||||
To achieve this we must impose some requirements on how you set up your cluster
|
||||
networking.
|
||||
|
||||
## Docker model
|
||||
|
||||
Before discussing the Kubernetes approach to networking, it is worthwhile to
|
||||
review the "normal" way that networking works with Docker. By default, Docker
|
||||
uses host-private networking. It creates a virtual bridge, called `docker0` by
|
||||
default, and allocates a subnet from one of the private address blocks defined
|
||||
in [RFC1918](https://tools.ietf.org/html/rfc1918) for that bridge. For each
|
||||
container that Docker creates, it allocates a virtual ethernet device (called
|
||||
`veth`) which is attached to the bridge. The veth is mapped to appear as `eth0`
|
||||
in the container, using Linux namespaces. The in-container `eth0` interface is
|
||||
given an IP address from the bridge's address range.
|
||||
|
||||
The result is that Docker containers can talk to other containers only if they
|
||||
are on the same machine (and thus the same virtual bridge). Containers on
|
||||
different machines can not reach each other - in fact they may end up with the
|
||||
exact same network ranges and IP addresses.
|
||||
|
||||
In order for Docker containers to communicate across nodes, they must be
|
||||
allocated ports on the machine's own IP address, which are then forwarded or
|
||||
proxied to the containers. This obviously means that containers must either
|
||||
coordinate which ports they use very carefully or else be allocated ports
|
||||
dynamically.
|
||||
|
||||
## Kubernetes model
|
||||
|
||||
Coordinating ports across multiple developers is very difficult to do at
|
||||
scale and exposes users to cluster-level issues outside of their control.
|
||||
Dynamic port allocation brings a lot of complications to the system - every
|
||||
application has to take ports as flags, the API servers have to know how to
|
||||
insert dynamic port numbers into configuration blocks, services have to know
|
||||
how to find each other, etc. Rather than deal with this, Kubernetes takes a
|
||||
different approach.
|
||||
|
||||
Kubernetes imposes the following fundamental requirements on any networking
|
||||
implementation (barring any intentional network segmentation policies):
|
||||
|
||||
* all containers can communicate with all other containers without NAT
|
||||
* all nodes can communicate with all containers (and vice-versa) without NAT
|
||||
* the IP that a container sees itself as is the same IP that others see it as
|
||||
|
||||
What this means in practice is that you can not just take two computers
|
||||
running Docker and expect Kubernetes to work. You must ensure that the
|
||||
fundamental requirements are met.
|
||||
|
||||
This model is not only less complex overall, but it is principally compatible
|
||||
with the desire for Kubernetes to enable low-friction porting of apps from VMs
|
||||
to containers. If your job previously ran in a VM, your VM had an IP and could
|
||||
talk to other VMs in your project. This is the same basic model.
|
||||
|
||||
Until now this document has talked about containers. In reality, Kubernetes
|
||||
applies IP addresses at the `Pod` scope - containers within a `Pod` share their
|
||||
network namespaces - including their IP address. This means that containers
|
||||
within a `Pod` can all reach each other's ports on `localhost`. This does imply
|
||||
that containers within a `Pod` must coordinate port usage, but this is no
|
||||
different than processes in a VM. We call this the "IP-per-pod" model. This
|
||||
is implemented in Docker as a "pod container" which holds the network namespace
|
||||
open while "app containers" (the things the user specified) join that namespace
|
||||
with Docker's `--net=container:<id>` function.
|
||||
|
||||
As with Docker, it is possible to request host ports, but this is reduced to a
|
||||
very niche operation. In this case a port will be allocated on the host `Node`
|
||||
and traffic will be forwarded to the `Pod`. The `Pod` itself is blind to the
|
||||
existence or non-existence of host ports.
|
||||
|
||||
## How to achieve this
|
||||
|
||||
There are a number of ways that this network model can be implemented. This
|
||||
document is not an exhaustive study of the various methods, but hopefully serves
|
||||
as an introduction to various technologies and serves as a jumping-off point.
|
||||
If some techniques become vastly preferable to others, we might detail them more
|
||||
here.
|
||||
|
||||
### Google Compute Engine (GCE)
|
||||
|
||||
For the Google Compute Engine cluster configuration scripts, we use [advanced
|
||||
routing](https://developers.google.com/compute/docs/networking#routing) to
|
||||
assign each VM a subnet (default is `/24` - 254 IPs). Any traffic bound for that
|
||||
subnet will be routed directly to the VM by the GCE network fabric. This is in
|
||||
addition to the "main" IP address assigned to the VM, which is NAT'ed for
|
||||
outbound internet access. A linux bridge (called `cbr0`) is configured to exist
|
||||
on that subnet, and is passed to docker's `--bridge` flag.
|
||||
|
||||
We start Docker with:
|
||||
|
||||
```shell
|
||||
DOCKER_OPTS="--bridge=cbr0 --iptables=false --ip-masq=false"
|
||||
```
|
||||
|
||||
This bridge is created by Kubelet (controlled by the `--configure-cbr0=true`
|
||||
flag) according to the `Node`'s `spec.podCIDR`.
|
||||
|
||||
Docker will now allocate IPs from the `cbr-cidr` block. Containers can reach
|
||||
each other and `Nodes` over the `cbr0` bridge. Those IPs are all routable
|
||||
within the GCE project network.
|
||||
|
||||
GCE itself does not know anything about these IPs, though, so it will not NAT
|
||||
them for outbound internet traffic. To achieve that we use an iptables rule to
|
||||
masquerade (aka SNAT - to make it seem as if packets came from the `Node`
|
||||
itself) traffic that is bound for IPs outside the GCE project network
|
||||
(10.0.0.0/8).
|
||||
|
||||
```shell
|
||||
iptables -t nat -A POSTROUTING ! -d 10.0.0.0/8 -o eth0 -j MASQUERADE
|
||||
```
|
||||
|
||||
Lastly we enable IP forwarding in the kernel (so the kernel will process
|
||||
packets for bridged containers):
|
||||
|
||||
```shell
|
||||
sysctl net.ipv4.ip_forward=1
|
||||
```
|
||||
|
||||
The result of all this is that all `Pods` can reach each other and can egress
|
||||
traffic to the internet.
|
||||
|
||||
### L2 networks and linux bridging
|
||||
|
||||
If you have a "dumb" L2 network, such as a simple switch in a "bare-metal"
|
||||
environment, you should be able to do something similar to the above GCE setup.
|
||||
Note that these instructions have only been tried very casually - it seems to
|
||||
work, but has not been thoroughly tested. If you use this technique and
|
||||
perfect the process, please let us know.
|
||||
|
||||
Follow the "With Linux Bridge devices" section of [this very nice
|
||||
tutorial](http://blog.oddbit.com/2014/08/11/four-ways-to-connect-a-docker/) from
|
||||
Lars Kellogg-Stedman.
|
||||
|
||||
### Flannel
|
||||
|
||||
[Flannel](https://github.com/coreos/flannel#flannel) is a very simple overlay
|
||||
network that satisfies the Kubernetes requirements. It installs in minutes and
|
||||
should get you up and running if the above techniques are not working. Many
|
||||
people have reported success with Flannel and Kubernetes.
|
||||
|
||||
### OpenVSwitch
|
||||
|
||||
[OpenVSwitch](/{{page.version}}/docs/admin/ovs-networking) is a somewhat more mature but also
|
||||
complicated way to build an overlay network. This is endorsed by several of the
|
||||
"Big Shops" for networking.
|
||||
|
||||
### Weave
|
||||
|
||||
[Weave](https://github.com/zettio/weave) is yet another way to build an overlay
|
||||
network, primarily aiming at Docker integration.
|
||||
|
||||
### Calico
|
||||
|
||||
[Calico](https://github.com/Metaswitch/calico) uses BGP to enable real container
|
||||
IPs.
|
||||
|
||||
## Other reading
|
||||
|
||||
The early design of the networking model and its rationale, and some future
|
||||
plans are described in more detail in the [networking design
|
||||
document](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/networking.md).
|
|
@ -0,0 +1,210 @@
|
|||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## What is a node?
|
||||
|
||||
`Node` is a worker machine in Kubernetes, previously known as `Minion`. Node
|
||||
may be a VM or physical machine, depending on the cluster. Each node has
|
||||
the services necessary to run [Pods](/{{page.version}}/docs/user-guide/pods) and is managed by the master
|
||||
components. The services on a node include docker, kubelet and network proxy. See
|
||||
[The Kubernetes Node](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/architecture.md#the-kubernetes-node) section in the
|
||||
architecture design doc for more details.
|
||||
|
||||
## Node Status
|
||||
|
||||
Node status describes current status of a node. For now, there are the following
|
||||
pieces of information:
|
||||
|
||||
### Node Addresses
|
||||
|
||||
The usage of these fields varies depending on your cloud provider or bare metal configuration.
|
||||
|
||||
* HostName: Generally not used
|
||||
|
||||
* ExternalIP: Generally the IP address of the node that is externally routable (available from outside the cluster)
|
||||
|
||||
* InternalIP: Generally the IP address of the node that is routable only within the cluster
|
||||
|
||||
|
||||
### Node Phase
|
||||
|
||||
Node Phase is the current lifecycle phase of node, one of `Pending`,
|
||||
`Running` and `Terminated`.
|
||||
|
||||
* Pending: New nodes are created in this state. A node stays in this state until it is configured.
|
||||
|
||||
* Running: Node has been configured and the Kubernetes components are running
|
||||
|
||||
* Terminated: Node has been removed from the cluster. It will not receive any scheduling requests,
|
||||
and any running pods will be removed from the node.
|
||||
|
||||
Node with `Running` phase is necessary but not sufficient requirement for
|
||||
scheduling Pods. For a node to be considered a scheduling candidate, it
|
||||
must have appropriate conditions, see below.
|
||||
|
||||
### Node Condition
|
||||
|
||||
Node Condition describes the conditions of `Running` nodes. Currently the only
|
||||
node condition is Ready. The Status of this condition can be True, False, or
|
||||
Unknown. True means the Kubelet is healthy and ready to accept pods.
|
||||
False means the Kubelet is not healthy and is not accepting pods. Unknown
|
||||
means the Node Controller, which manages node lifecycle and is responsible for
|
||||
setting the Status of the condition, has not heard from the
|
||||
node recently (currently 40 seconds).
|
||||
Node condition is represented as a json object. For example,
|
||||
the following conditions mean the node is in sane state:
|
||||
|
||||
```json
|
||||
"conditions": [
|
||||
{
|
||||
"kind": "Ready",
|
||||
"status": "True",
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
If the Status of the Ready condition
|
||||
is Unknown or False for more than five minutes, then all of the Pods on the node are terminated by the Node Controller.
|
||||
|
||||
### Node Capacity
|
||||
|
||||
Describes the resources available on the node: CPUs, memory and the maximum
|
||||
number of pods that can be scheduled onto the node.
|
||||
|
||||
### Node Info
|
||||
|
||||
General information about the node, for instance kernel version, Kubernetes version
|
||||
(kubelet version, kube-proxy version), docker version (if used), OS name.
|
||||
The information is gathered by Kubelet from the node.
|
||||
|
||||
## Node Management
|
||||
|
||||
Unlike [Pods](/{{page.version}}/docs/user-guide/pods) and [Services](/{{page.version}}/docs/user-guide/services), a Node is not inherently
|
||||
created by Kubernetes: it is either taken from cloud providers like Google Compute Engine,
|
||||
or from your pool of physical or virtual machines. What this means is that when
|
||||
Kubernetes creates a node, it is really just creating an object that represents the node in its internal state.
|
||||
After creation, Kubernetes will check whether the node is valid or not.
|
||||
For example, if you try to create a node from the following content:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Node",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "10.240.79.157",
|
||||
"labels": {
|
||||
"name": "my-first-k8s-node"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Kubernetes will create a Node object internally (the representation), and
|
||||
validate the node by health checking based on the `metadata.name` field: we
|
||||
assume `metadata.name` can be resolved. If the node is valid, i.e. all necessary
|
||||
services are running, it is eligible to run a Pod; otherwise, it will be
|
||||
ignored for any cluster activity, until it becomes valid. Note that Kubernetes
|
||||
will keep the object for the invalid node unless it is explicitly deleted by the client, and it will keep
|
||||
checking to see if it becomes valid.
|
||||
|
||||
Currently, there are three components that interact with the Kubernetes node interface: Node Controller, Kubelet, and kubectl.
|
||||
|
||||
### Node Controller
|
||||
|
||||
Node controller is a component in Kubernetes master which manages Node
|
||||
objects. It performs two major functions: cluster-wide node synchronization
|
||||
and single node life-cycle management.
|
||||
|
||||
Node controller has a sync loop that creates/deletes Nodes from Kubernetes
|
||||
based on all matching VM instances listed from the cloud provider. The sync period
|
||||
can be controlled via flag `--node-sync-period`. If a new VM instance
|
||||
gets created, Node Controller creates a representation for it. If an existing
|
||||
instance gets deleted, Node Controller deletes the representation. Note however,
|
||||
that Node Controller is unable to provision the node for you, i.e. it won't install
|
||||
any binary; therefore, to
|
||||
join a node to a Kubernetes cluster, you as an admin need to make sure proper services are
|
||||
running in the node. In the future, we plan to automatically provision some node
|
||||
services.
|
||||
|
||||
### Self-Registration of Nodes
|
||||
|
||||
When kubelet flag `--register-node` is true (the default), the kubelet will attempt to
|
||||
register itself with the API server. This is the preferred pattern, used by most distros.
|
||||
|
||||
For self-registration, the kubelet is started with the following options:
|
||||
|
||||
- `--api-servers=` tells the kubelet the location of the apiserver.
|
||||
- `--kubeconfig` tells kubelet where to find credentials to authenticate itself to the apiserver.
|
||||
- `--cloud-provider=` tells the kubelet how to talk to a cloud provider to read metadata about itself.
|
||||
- `--register-node` tells the kubelet to create its own node resource.
|
||||
|
||||
Currently, any kubelet is authorized to create/modify any node resource, but in practice it only creates/modifies
|
||||
its own. (In the future, we plan to limit authorization to only allow a kubelet to modify its own Node resource.)
|
||||
|
||||
#### Manual Node Administration
|
||||
|
||||
A cluster administrator can create and modify Node objects.
|
||||
|
||||
If the administrator wishes to create node objects manually, set kubelet flag
|
||||
`--register-node=false`.
|
||||
|
||||
The administrator can modify Node resources (regardless of the setting of `--register-node`).
|
||||
Modifications include setting labels on the Node, and marking it unschedulable.
|
||||
|
||||
Labels on nodes can be used in conjunction with node selectors on pods to control scheduling,
|
||||
e.g. to constrain a Pod to only be eligible to run on a subset of the nodes.
|
||||
|
||||
Making a node unscheduleable will prevent new pods from being scheduled to that
|
||||
node, but will not affect any existing pods on the node. This is useful as a
|
||||
preparatory step before a node reboot, etc. For example, to mark a node
|
||||
unschedulable, run this command:
|
||||
|
||||
```shell
|
||||
kubectl replace nodes 10.1.2.3 --patch='{"apiVersion": "v1", "unschedulable": true}'
|
||||
```
|
||||
|
||||
Note that pods which are created by a daemonSet controller bypass the Kubernetes scheduler,
|
||||
and do not respect the unschedulable attribute on a node. The assumption is that daemons belong on
|
||||
the machine even if it is being drained of applications in preparation for a reboot.
|
||||
|
||||
### Node capacity
|
||||
|
||||
The capacity of the node (number of cpus and amount of memory) is part of the node resource.
|
||||
Normally, nodes register themselves and report their capacity when creating the node resource. If
|
||||
you are doing [manual node administration](#manual-node-administration), then you need to set node
|
||||
capacity when adding a node.
|
||||
|
||||
The Kubernetes scheduler ensures that there are enough resources for all the pods on a node. It
|
||||
checks that the sum of the limits of containers on the node is no greater than the node capacity. It
|
||||
includes all containers started by kubelet, but not containers started directly by docker, nor
|
||||
processes not in containers.
|
||||
|
||||
If you want to explicitly reserve resources for non-Pod processes, you can create a placeholder
|
||||
pod. Use the following template:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: resource-reserver
|
||||
spec:
|
||||
containers:
|
||||
- name: sleep-forever
|
||||
image: gcr.io/google_containers/pause:0.8.0
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 100Mi
|
||||
```
|
||||
|
||||
Set the `cpu` and `memory` values to the amount of resources you want to reserve.
|
||||
Place the file in the manifest directory (`--config=DIR` flag of kubelet). Do this
|
||||
on each kubelet where you want to reserve resources.
|
||||
|
||||
|
||||
## API Object
|
||||
|
||||
Node is a top-level resource in the kubernetes REST API. More details about the
|
||||
API object can be found at: [Node API
|
||||
object](http://kubernetes.io/v1.1/docs/api-reference/v1/definitions/#_v1_node).
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
This document describes how OpenVSwitch is used to setup networking between pods across nodes.
|
||||
The tunnel type could be GRE or VxLAN. VxLAN is preferable when large scale isolation needs to be performed within the network.
|
||||
|
||||

|
||||
|
||||
The vagrant setup in Kubernetes does the following:
|
||||
|
||||
The docker bridge is replaced with a brctl generated linux bridge (kbr0) with a 256 address space subnet. Basically, a node gets 10.244.x.0/24 subnet and docker is configured to use that bridge instead of the default docker0 bridge.
|
||||
|
||||
Also, an OVS bridge is created(obr0) and added as a port to the kbr0 bridge. All OVS bridges across all nodes are linked with GRE tunnels. So, each node has an outgoing GRE tunnel to all other nodes. It does not need to be a complete mesh really, just meshier the better. STP (spanning tree) mode is enabled in the bridges to prevent loops.
|
||||
|
||||
Routing rules enable any 10.244.0.0/16 target to become reachable via the OVS bridge connected with the tunnels.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
|
||||
When several users or teams share a cluster with a fixed number of nodes,
|
||||
there is a concern that one team could use more than its fair share of resources.
|
||||
|
||||
Resource quotas are a tool for administrators to address this concern. Resource quotas
|
||||
work like this:
|
||||
|
||||
- Different teams work in different namespaces. Currently this is voluntary, but
|
||||
support for making this mandatory via ACLs is planned.
|
||||
- The administrator creates a Resource Quota for each namespace.
|
||||
- Users put compute resource requests on their pods. The sum of all resource requests across
|
||||
all pods in the same namespace must not exceed any hard resource limit in any Resource Quota
|
||||
document for the namespace. Note that we used to verify Resource Quota by taking the sum of
|
||||
resource limits of the pods, but this was altered to use resource requests. Backwards compatibility
|
||||
for those pods previously created is preserved because pods that only specify a resource limit have
|
||||
their resource requests defaulted to match their defined limits. The user is only charged for the
|
||||
resources they request in the Resource Quota versus their limits because the request is the minimum
|
||||
amount of resource guaranteed by the cluster during scheduling. For more information on over commit,
|
||||
see [compute-resources](/{{page.version}}/docs/user-guide/compute-resources).
|
||||
- If creating a pod would cause the namespace to exceed any of the limits specified in the
|
||||
the Resource Quota for that namespace, then the request will fail with HTTP status
|
||||
code `403 FORBIDDEN`.
|
||||
- If quota is enabled in a namespace and the user does not specify *requests* on the pod for each
|
||||
of the resources for which quota is enabled, then the POST of the pod will fail with HTTP
|
||||
status code `403 FORBIDDEN`. Hint: Use the LimitRange admission controller to force default
|
||||
values of *limits* (then resource *requests* would be equal to *limits* by default, see
|
||||
[admission controller](/{{page.version}}/docs/admin/admission-controllers)) before the quota is checked to avoid this problem.
|
||||
|
||||
Examples of policies that could be created using namespaces and quotas are:
|
||||
|
||||
- In a cluster with a capacity of 32 GiB RAM, and 16 cores, let team A use 20 Gib and 10 cores,
|
||||
let B use 10GiB and 4 cores, and hold 2GiB and 2 cores in reserve for future allocation.
|
||||
- Limit the "testing" namespace to using 1 core and 1GiB RAM. Let the "production" namespace
|
||||
use any amount.
|
||||
|
||||
In the case where the total capacity of the cluster is less than the sum of the quotas of the namespaces,
|
||||
there may be contention for resources. This is handled on a first-come-first-served basis.
|
||||
|
||||
Neither contention nor changes to quota will affect already-running pods.
|
||||
|
||||
## Enabling Resource Quota
|
||||
|
||||
Resource Quota support is enabled by default for many Kubernetes distributions. It is
|
||||
enabled when the apiserver `--admission-control=` flag has `ResourceQuota` as
|
||||
one of its arguments.
|
||||
|
||||
Resource Quota is enforced in a particular namespace when there is a
|
||||
`ResourceQuota` object in that namespace. There should be at most one
|
||||
`ResourceQuota` object in a namespace.
|
||||
|
||||
## Compute Resource Quota
|
||||
|
||||
The total sum of [compute resources](/{{page.version}}/docs/user-guide/compute-resources) requested by pods
|
||||
in a namespace can be limited. The following compute resource types are supported:
|
||||
|
||||
| ResourceName | Description |
|
||||
| ------------ | ----------- |
|
||||
| cpu | Total cpu requests of containers |
|
||||
| memory | Total memory requests of containers
|
||||
|
||||
For example, `cpu` quota sums up the `resources.requests.cpu` fields of every
|
||||
container of every pod in the namespace, and enforces a maximum on that sum.
|
||||
|
||||
## Object Count Quota
|
||||
|
||||
The number of objects of a given type can be restricted. The following types
|
||||
are supported:
|
||||
|
||||
| ResourceName | Description |
|
||||
| ------------ | ----------- |
|
||||
| pods | Total number of pods |
|
||||
| services | Total number of services |
|
||||
| replicationcontrollers | Total number of replication controllers |
|
||||
| resourcequotas | Total number of [resource quotas](/{{page.version}}/docs/admin/admission-controllers/#resourcequota) |
|
||||
| secrets | Total number of secrets |
|
||||
| persistentvolumeclaims | Total number of [persistent volume claims](/{{page.version}}/docs/user-guide/persistent-volumes/#persistentvolumeclaims) |
|
||||
|
||||
For example, `pods` quota counts and enforces a maximum on the number of `pods`
|
||||
created in a single namespace.
|
||||
|
||||
You might want to set a pods quota on a namespace
|
||||
to avoid the case where a user creates many small pods and exhausts the cluster's
|
||||
supply of Pod IPs.
|
||||
|
||||
## Viewing and Setting Quotas
|
||||
|
||||
Kubectl supports creating, updating, and viewing quotas:
|
||||
|
||||
```shell
|
||||
$ kubectl namespace myspace
|
||||
$ cat <<EOF > quota.json
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ResourceQuota",
|
||||
"metadata": {
|
||||
"name": "quota",
|
||||
},
|
||||
"spec": {
|
||||
"hard": {
|
||||
"memory": "1Gi",
|
||||
"cpu": "20",
|
||||
"pods": "10",
|
||||
"services": "5",
|
||||
"replicationcontrollers":"20",
|
||||
"resourcequotas":"1",
|
||||
},
|
||||
}
|
||||
}
|
||||
EOF
|
||||
$ kubectl create -f ./quota.json
|
||||
$ kubectl get quota
|
||||
NAME
|
||||
quota
|
||||
$ kubectl describe quota quota
|
||||
Name: quota
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
cpu 0m 20
|
||||
memory 0 1Gi
|
||||
pods 5 10
|
||||
replicationcontrollers 5 20
|
||||
resourcequotas 1 1
|
||||
services 3 5
|
||||
```
|
||||
|
||||
## Quota and Cluster Capacity
|
||||
|
||||
Resource Quota objects are independent of the Cluster Capacity. They are
|
||||
expressed in absolute units. So, if you add nodes to your cluster, this does *not*
|
||||
automatically give each namespace the ability to consume more resources.
|
||||
|
||||
Sometimes more complex policies may be desired, such as:
|
||||
|
||||
- proportionally divide total cluster resources among several teams.
|
||||
- allow each tenant to grow resource usage as needed, but have a generous
|
||||
limit to prevent accidental resource exhaustion.
|
||||
- detect demand from one namespace, add nodes, and increase quota.
|
||||
|
||||
Such policies could be implemented using ResourceQuota as a building-block, by
|
||||
writing a 'controller' which watches the quota usage and adjusts the quota
|
||||
hard limits of each namespace according to other signals.
|
||||
|
||||
Note that resource quota divides up aggregate cluster resources, but it creates no
|
||||
restrictions around nodes: pods from several namespaces may run on the same node.
|
||||
|
||||
## Example
|
||||
|
||||
See a [detailed example for how to use resource quota](/{{page.version}}/docs/admin/resourcequota/).
|
||||
|
||||
## Read More
|
||||
|
||||
See [ResourceQuota design doc](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/admission_control_resource_quota.md) for more information.
|
|
@ -0,0 +1,154 @@
|
|||
|
||||
This example demonstrates how [resource quota](/{{page.version}}/docs/admin/admission-controllers/#resourcequota) and
|
||||
[limitsranger](/{{page.version}}/docs/admin/admission-controllers/#limitranger) can be applied to a Kubernetes namespace.
|
||||
See [ResourceQuota design doc](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/admission_control_resource_quota.md) for more information.
|
||||
|
||||
This example assumes you have a functional Kubernetes setup.
|
||||
|
||||
## Step 1: Create a namespace
|
||||
|
||||
This example will work in a custom namespace to demonstrate the concepts involved.
|
||||
|
||||
Let's create a new namespace called quota-example:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/namespace.yaml
|
||||
namespace "quota-example" created
|
||||
$ kubectl get namespaces
|
||||
NAME LABELS STATUS AGE
|
||||
default <none> Active 2m
|
||||
quota-example <none> Active 39s
|
||||
```
|
||||
|
||||
## Step 2: Apply a quota to the namespace
|
||||
|
||||
By default, a pod will run with unbounded CPU and memory requests/limits. This means that any pod in the
|
||||
system will be able to consume as much CPU and memory on the node that executes the pod.
|
||||
|
||||
Users may want to restrict how much of the cluster resources a given namespace may consume
|
||||
across all of its pods in order to manage cluster usage. To do this, a user applies a quota to
|
||||
a namespace. A quota lets the user set hard limits on the total amount of node resources (cpu, memory)
|
||||
and API resources (pods, services, etc.) that a namespace may consume. In term of resources, Kubernetes
|
||||
checks the total resource *requests*, not resource *limits* of all containers/pods in the namespace.
|
||||
|
||||
Let's create a simple quota in our namespace:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/quota.yaml --namespace=quota-example
|
||||
resourcequota "quota" created
|
||||
```
|
||||
|
||||
Once your quota is applied to a namespace, the system will restrict any creation of content
|
||||
in the namespace until the quota usage has been calculated. This should happen quickly.
|
||||
|
||||
You can describe your current quota usage to see what resources are being consumed in your
|
||||
namespace.
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota quota --namespace=quota-example
|
||||
Name: quota
|
||||
Namespace: quota-example
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
cpu 0 20
|
||||
memory 0 1Gi
|
||||
persistentvolumeclaims 0 10
|
||||
pods 0 10
|
||||
replicationcontrollers 0 20
|
||||
resourcequotas 1 1
|
||||
secrets 1 10
|
||||
services 0 5
|
||||
```
|
||||
|
||||
## Step 3: Applying default resource requests and limits
|
||||
|
||||
Pod authors rarely specify resource requests and limits for their pods.
|
||||
|
||||
Since we applied a quota to our project, let's see what happens when an end-user creates a pod that has unbounded
|
||||
cpu and memory by creating an nginx container.
|
||||
|
||||
To demonstrate, lets create a replication controller that runs nginx:
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image=nginx --replicas=1 --namespace=quota-example
|
||||
replicationcontroller "nginx" created
|
||||
```
|
||||
|
||||
Now let's look at the pods that were created.
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
```
|
||||
|
||||
What happened? I have no pods! Let's describe the replication controller to get a view of what is happening.
|
||||
|
||||
```shell
|
||||
kubectl describe rc nginx --namespace=quota-example
|
||||
Name: nginx
|
||||
Namespace: quota-example
|
||||
Image(s): nginx
|
||||
Selector: run=nginx
|
||||
Labels: run=nginx
|
||||
Replicas: 0 current / 1 desired
|
||||
Pods Status: 0 Running / 0 Waiting / 0 Succeeded / 0 Failed
|
||||
No volumes.
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Reason Message
|
||||
42s 11s 3 {replication-controller } FailedCreate Error creating: Pod "nginx-" is forbidden: Must make a non-zero request for memory since it is tracked by quota.
|
||||
```
|
||||
|
||||
The Kubernetes API server is rejecting the replication controllers requests to create a pod because our pods
|
||||
do not specify any memory usage *request*.
|
||||
|
||||
So let's set some default values for the amount of cpu and memory a pod can consume:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/admin/resourcequota/limits.yaml --namespace=quota-example
|
||||
limitrange "limits" created
|
||||
$ kubectl describe limits limits --namespace=quota-example
|
||||
Name: limits
|
||||
Namespace: quota-example
|
||||
Type Resource Min Max Request Limit Limit/Request
|
||||
---- -------- --- --- ------- ----- -------------
|
||||
Container memory - - 256Mi 512Mi -
|
||||
Container cpu - - 100m 200m -
|
||||
```
|
||||
|
||||
Now any time a pod is created in this namespace, if it has not specified any resource request/limit, the default
|
||||
amount of cpu and memory per container will be applied, and the request will be used as part of admission control.
|
||||
|
||||
Now that we have applied default resource *request* for our namespace, our replication controller should be able to
|
||||
create its pods.
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-fca65 1/1 Running 0 1m
|
||||
```
|
||||
|
||||
And if we print out our quota usage in the namespace:
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota quota --namespace=quota-example
|
||||
Name: quota
|
||||
Namespace: quota-example
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
cpu 100m 20
|
||||
memory 256Mi 1Gi
|
||||
persistentvolumeclaims 0 10
|
||||
pods 1 10
|
||||
replicationcontrollers 1 20
|
||||
resourcequotas 1 1
|
||||
secrets 1 10
|
||||
services 0 5
|
||||
```
|
||||
|
||||
You can now see the pod that was created is consuming explicit amounts of resources (specified by resource *request*), and the usage is being tracked by the Kubernetes system properly.
|
||||
|
||||
## Summary
|
||||
|
||||
Actions that consume node resources for cpu and memory can be subject to hard quota limits defined by the namespace quota. The resource consumption is measured by resource *request* in pod specification.
|
||||
|
||||
Any action that consumes those resources can be tweaked, or can pick up namespace level defaults to meet your end goal.
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: limits
|
||||
spec:
|
||||
limits:
|
||||
- default:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
defaultRequest:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
type: Container
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: quota-example
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: quota
|
||||
spec:
|
||||
hard:
|
||||
cpu: "20"
|
||||
memory: 1Gi
|
||||
persistentvolumeclaims: "10"
|
||||
pods: "10"
|
||||
replicationcontrollers: "20"
|
||||
resourcequotas: "1"
|
||||
secrets: "10"
|
||||
services: "5"
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
The Kubernetes cluster can be configured using Salt.
|
||||
|
||||
The Salt scripts are shared across multiple hosting providers, so it's important to understand some background information prior to making a modification to ensure your changes do not break hosting Kubernetes across multiple environments. Depending on where you host your Kubernetes cluster, you may be using different operating systems and different networking configurations. As a result, it's important to understand some background information before making Salt changes in order to minimize introducing failures for other hosting providers.
|
||||
|
||||
## Salt cluster setup
|
||||
|
||||
The **salt-master** service runs on the kubernetes-master [(except on the default GCE setup)](#standalone-salt-configuration-on-gce).
|
||||
|
||||
The **salt-minion** service runs on the kubernetes-master and each kubernetes-node in the cluster.
|
||||
|
||||
Each salt-minion service is configured to interact with the **salt-master** service hosted on the kubernetes-master via the **master.conf** file [(except on GCE)](#standalone-salt-configuration-on-gce).
|
||||
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/minion.d/master.conf
|
||||
master: kubernetes-master
|
||||
```
|
||||
|
||||
The salt-master is contacted by each salt-minion and depending upon the machine information presented, the salt-master will provision the machine as either a kubernetes-master or kubernetes-node with all the required capabilities needed to run Kubernetes.
|
||||
|
||||
If you are running the Vagrant based environment, the **salt-api** service is running on the kubernetes-master. It is configured to enable the vagrant user to introspect the salt cluster in order to find out about machines in the Vagrant environment via a REST API.
|
||||
|
||||
## Standalone Salt Configuration on GCE
|
||||
|
||||
On GCE, the master and nodes are all configured as [standalone minions](http://docs.saltstack.com/en/latest/topics/tutorials/standalone_minion). The configuration for each VM is derived from the VM's [instance metadata](https://cloud.google.com/compute/docs/metadata) and then stored in Salt grains (`/etc/salt/minion.d/grains.conf`) and pillars (`/srv/salt-overlay/pillar/cluster-params.sls`) that local Salt uses to enforce state.
|
||||
|
||||
All remaining sections that refer to master/minion setups should be ignored for GCE. One fallout of the GCE setup is that the Salt mine doesn't exist - there is no sharing of configuration amongst nodes.
|
||||
|
||||
## Salt security
|
||||
|
||||
*(Not applicable on default GCE setup.)*
|
||||
|
||||
Security is not enabled on the salt-master, and the salt-master is configured to auto-accept incoming requests from minions. It is not recommended to use this security configuration in production environments without deeper study. (In some environments this isn't as bad as it might sound if the salt master port isn't externally accessible and you trust everyone on your network.)
|
||||
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/master.d/auto-accept.conf
|
||||
open_mode: True
|
||||
auto_accept: True
|
||||
```
|
||||
|
||||
## Salt minion configuration
|
||||
|
||||
Each minion in the salt cluster has an associated configuration that instructs the salt-master how to provision the required resources on the machine.
|
||||
|
||||
An example file is presented below using the Vagrant based environment.
|
||||
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/minion.d/grains.conf
|
||||
grains:
|
||||
etcd_servers: $MASTER_IP
|
||||
cloud_provider: vagrant
|
||||
roles:
|
||||
- kubernetes-master
|
||||
```
|
||||
|
||||
Each hosting environment has a slightly different grains.conf file that is used to build conditional logic where required in the Salt files.
|
||||
|
||||
The following enumerates the set of defined key/value pairs that are supported today. If you add new ones, please make sure to update this list.
|
||||
|
||||
Key | Value
|
||||
------------- | -------------
|
||||
`api_servers` | (Optional) The IP address / host name where a kubelet can get read-only access to kube-apiserver
|
||||
`cbr-cidr` | (Optional) The minion IP address range used for the docker container bridge.
|
||||
`cloud` | (Optional) Which IaaS platform is used to host Kubernetes, *gce*, *azure*, *aws*, *vagrant*
|
||||
`etcd_servers` | (Optional) Comma-delimited list of IP addresses the kube-apiserver and kubelet use to reach etcd. Uses the IP of the first machine in the kubernetes_master role, or 127.0.0.1 on GCE.
|
||||
`hostnamef` | (Optional) The full host name of the machine, i.e. uname -n
|
||||
`node_ip` | (Optional) The IP address to use to address this node
|
||||
`hostname_override` | (Optional) Mapped to the kubelet hostname-override
|
||||
`network_mode` | (Optional) Networking model to use among nodes: *openvswitch*
|
||||
`networkInterfaceName` | (Optional) Networking interface to use to bind addresses, default value *eth0*
|
||||
`publicAddressOverride` | (Optional) The IP address the kube-apiserver should use to bind against for external read-only access
|
||||
`roles` | (Required) 1. `kubernetes-master` means this machine is the master in the Kubernetes cluster. 2. `kubernetes-pool` means this machine is a kubernetes-node. Depending on the role, the Salt scripts will provision different resources on the machine.
|
||||
|
||||
These keys may be leveraged by the Salt sls files to branch behavior.
|
||||
|
||||
In addition, a cluster may be running a Debian based operating system or Red Hat based operating system (Centos, Fedora, RHEL, etc.). As a result, it's important to sometimes distinguish behavior based on operating system using if branches like the following.
|
||||
|
||||
```liquid
|
||||
{% raw %}
|
||||
{% if grains['os_family'] == 'RedHat' %}
|
||||
// something specific to a RedHat environment (Centos, Fedora, RHEL) where you may use yum, systemd, etc.
|
||||
{% else %}
|
||||
// something specific to Debian environment (apt-get, initd)
|
||||
{% endif %}
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. When configuring default arguments for processes, it's best to avoid the use of EnvironmentFiles (Systemd in Red Hat environments) or init.d files (Debian distributions) to hold default values that should be common across operating system environments. This helps keep our Salt template files easy to understand for editors who may not be familiar with the particulars of each distribution.
|
||||
|
||||
## Future enhancements (Networking)
|
||||
|
||||
Per pod IP configuration is provider-specific, so when making networking changes, it's important to sandbox these as all providers may not use the same mechanisms (iptables, openvswitch, etc.)
|
||||
|
||||
We should define a grains.conf key that captures more specifically what network configuration environment is being used to avoid future confusion across providers.
|
||||
|
||||
## Further reading
|
||||
|
||||
The [cluster/saltbase](http://releases.k8s.io/{{page.githubbranch}}/cluster/saltbase/) tree has more details on the current SaltStack configuration.
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
*This is a Cluster Administrator guide to service accounts. It assumes knowledge of
|
||||
the [User Guide to Service Accounts](/{{page.version}}/docs/user-guide/service-accounts).*
|
||||
|
||||
*Support for authorization and user accounts is planned but incomplete. Sometimes
|
||||
incomplete features are referred to in order to better describe service accounts.*
|
||||
|
||||
## User accounts vs service accounts
|
||||
|
||||
Kubernetes distinguished between the concept of a user account and a service accounts
|
||||
for a number of reasons:
|
||||
|
||||
- User accounts are for humans. Service accounts are for processes, which
|
||||
run in pods.
|
||||
- User accounts are intended to be global. Names must be unique across all
|
||||
namespaces of a cluster, future user resource will not be namespaced).
|
||||
Service accounts are namespaced.
|
||||
- Typically, a cluster's User accounts might be synced from a corporate
|
||||
database, where new user account creation requires special privileges and
|
||||
is tied to complex business processes. Service account creation is intended
|
||||
to be more lightweight, allowing cluster users to create service accounts for
|
||||
specific tasks (i.e. principle of least privilege).
|
||||
- Auditing considerations for humans and service accounts may differ.
|
||||
- A config bundle for a complex system may include definition of various service
|
||||
accounts for components of that system. Because service accounts can be created
|
||||
ad-hoc and have namespaced names, such config is portable.
|
||||
|
||||
## Service account automation
|
||||
|
||||
Three separate components cooperate to implement the automation around service accounts:
|
||||
|
||||
- A Service account admission controller
|
||||
- A Token controller
|
||||
- A Service account controller
|
||||
|
||||
### Service Account Admission Controller
|
||||
|
||||
The modification of pods is implemented via a plugin
|
||||
called an [Admission Controller](/{{page.version}}/docs/admin/admission-controllers). It is part of the apiserver.
|
||||
It acts synchronously to modify pods as they are created or updated. When this plugin is active
|
||||
(and it is by default on most distributions), then it does the following when a pod is created or modified:
|
||||
|
||||
1. If the pod does not have a `ServiceAccount` set, it sets the `ServiceAccount` to `default`.
|
||||
2. It ensures that the `ServiceAccount` referenced by the pod exists, and otherwise rejects it.
|
||||
4. If the pod does not contain any `ImagePullSecrets`, then `ImagePullSecrets` of the
|
||||
`ServiceAccount` are added to the pod.
|
||||
5. It adds a `volume` to the pod which contains a token for API access.
|
||||
6. It adds a `volumeSource` to each container of the pod mounted at `/var/run/secrets/kubernetes.io/serviceaccount`.
|
||||
|
||||
### Token Controller
|
||||
|
||||
TokenController runs as part of controller-manager. It acts asynchronously. It:
|
||||
|
||||
- observes serviceAccount creation and creates a corresponding Secret to allow API access.
|
||||
- observes serviceAccount deletion and deletes all corresponding ServiceAccountToken Secrets
|
||||
- observes secret addition, and ensures the referenced ServiceAccount exists, and adds a token to the secret if needed
|
||||
- observes secret deletion and removes a reference from the corresponding ServiceAccount if needed
|
||||
|
||||
#### To create additional API tokens
|
||||
|
||||
A controller loop ensures a secret with an API token exists for each service
|
||||
account. To create additional API tokens for a service account, create a secret
|
||||
of type `ServiceAccountToken` with an annotation referencing the service
|
||||
account, and the controller will update it with a generated token:
|
||||
|
||||
```json
|
||||
secret.json:
|
||||
{
|
||||
"kind": "Secret",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "mysecretname",
|
||||
"annotations": {
|
||||
"kubernetes.io/service-account.name": "myserviceaccount"
|
||||
}
|
||||
},
|
||||
"type": "kubernetes.io/service-account-token"
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl create -f ./secret.json
|
||||
kubectl describe secret mysecretname
|
||||
```
|
||||
|
||||
#### To delete/invalidate a service account token
|
||||
|
||||
```shell
|
||||
kubectl delete secret mysecretname
|
||||
```
|
||||
|
||||
### Service Account Controller
|
||||
|
||||
Service Account Controller manages ServiceAccount inside namespaces, and ensures
|
||||
a ServiceAccount named "default" exists in every active namespace.
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
|
||||
**Static pods are to be deprecated and can be removed in any future Kubernetes release!**
|
||||
|
||||
*Static pod* are managed directly by kubelet daemon on a specific node, without API server observing it. It does not have associated any replication controller, kubelet daemon itself watches it and restarts it when it crashes. There is no health check though. Static pods are always bound to one kubelet daemon and always run on the same node with it.
|
||||
|
||||
Kubelet automatically creates so-called *mirror pod* on Kubernetes API server for each static pod, so the pods are visible there, but they cannot be controlled from the API server.
|
||||
|
||||
## Static pod creation
|
||||
|
||||
Static pod can be created in two ways: either by using configuration file(s) or by HTTP.
|
||||
|
||||
### Configuration files
|
||||
|
||||
The configuration files are just standard pod definition in json or yaml format in specific directory. Use `kubelet --config=<the directory>` to start kubelet daemon, which periodically scans the directory and creates/deletes static pods as yaml/json files appear/disappear there.
|
||||
|
||||
For example, this is how to start a simple web server as a static pod:
|
||||
|
||||
1. Choose a node where we want to run the static pod. In this example, it's `my-minion1`.
|
||||
|
||||
```shell
|
||||
[joe@host ~] $ ssh my-minion1
|
||||
```
|
||||
|
||||
2. Choose a directory, say `/etc/kubelet.d` and place a web server pod definition there, e.g. `/etc/kubernetes.d/static-web.yaml`:
|
||||
|
||||
```shell
|
||||
[root@my-minion1 ~] $ mkdir /etc/kubernetes.d/
|
||||
[root@my-minion1 ~] $ cat <<EOF >/etc/kubernetes.d/static-web.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: static-web
|
||||
labels:
|
||||
role: myrole
|
||||
spec:
|
||||
containers:
|
||||
- name: web
|
||||
image: nginx
|
||||
ports:
|
||||
- name: web
|
||||
containerPort: 80
|
||||
protocol: tcp
|
||||
EOF
|
||||
```
|
||||
|
||||
2. Configure your kubelet daemon on the node to use this directory by running it with `--config=/etc/kubelet.d/` argument. On Fedora Fedora 21 with Kubernetes 0.17 edit `/etc/kubernetes/kubelet` to include this line:
|
||||
|
||||
```
|
||||
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --config=/etc/kubelet.d/"
|
||||
```
|
||||
Instructions for other distributions or Kubernetes installations may vary.
|
||||
|
||||
3. Restart kubelet. On Fedora 21, this is:
|
||||
|
||||
```shell
|
||||
[root@my-minion1 ~] $ systemctl restart kubelet
|
||||
```
|
||||
|
||||
## Pods created via HTTP
|
||||
|
||||
Kubelet periodically downloads a file specified by `--manifest-url=<URL>` argument and interprets it as a json/yaml file with a pod definition. It works the same as `--config=<directory>`, i.e. it's reloaded every now and then and changes are applied to running static pods (see below).
|
||||
|
||||
## Behavior of static pods
|
||||
|
||||
When kubelet starts, it automatically starts all pods defined in directory specified in `--config=` or `--manifest-url=` arguments, i.e. our static-web. (It may take some time to pull nginx image, be patient'|):
|
||||
|
||||
```shell
|
||||
[joe@my-minion1 ~] $ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
|
||||
f6d05272b57e nginx:latest "nginx" 8 minutes ago Up 8 minutes k8s_web.6f802af4_static-web-fk-minion1_default_67e24ed9466ba55986d120c867395f3c_378e5f3c
|
||||
```
|
||||
|
||||
If we look at our Kubernetes API server (running on host `my-master`), we see that a new mirror-pod was created there too:
|
||||
|
||||
```shell
|
||||
[joe@host ~] $ ssh my-master
|
||||
[joe@my-master ~] $ kubectl get pods
|
||||
POD IP CONTAINER(S) IMAGE(S) HOST LABELS STATUS CREATED MESSAGE
|
||||
static-web-my-minion1 172.17.0.3 my-minion1/192.168.100.71 role=myrole Running 11 minutes
|
||||
web nginx Running 11 minutes
|
||||
```
|
||||
|
||||
Labels from the static pod are propagated into the mirror-pod and can be used as usual for filtering.
|
||||
|
||||
Notice we cannot delete the pod with the API server (e.g. via [`kubectl`](/{{page.version}}/docs/user-guide/kubectl/kubectl) command), kubelet simply won't remove it.
|
||||
|
||||
```shell
|
||||
[joe@my-master ~] $ kubectl delete pod static-web-my-minion1
|
||||
pods/static-web-my-minion1
|
||||
[joe@my-master ~] $ kubectl get pods
|
||||
POD IP CONTAINER(S) IMAGE(S) HOST ...
|
||||
static-web-my-minion1 172.17.0.3 my-minion1/192.168.100.71 ...
|
||||
```
|
||||
|
||||
Back to our `my-minion1` host, we can try to stop the container manually and see, that kubelet automatically restarts it in a while:
|
||||
|
||||
```shell
|
||||
[joe@host ~] $ ssh my-minion1
|
||||
[joe@my-minion1 ~] $ docker stop f6d05272b57e
|
||||
[joe@my-minion1 ~] $ sleep 20
|
||||
[joe@my-minion1 ~] $ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED ...
|
||||
5b920cbaf8b1 nginx:latest "nginx -g 'daemon of 2 seconds ago ...
|
||||
```
|
||||
|
||||
## Dynamic addition and removal of static pods
|
||||
|
||||
Running kubelet periodically scans the configured directory (`/etc/kubelet.d` in our example) for changes and adds/removes pods as files appear/disappear in this directory.
|
||||
|
||||
```shell
|
||||
[joe@my-minion1 ~] $ mv /etc/kubernetes.d/static-web.yaml /tmp
|
||||
[joe@my-minion1 ~] $ sleep 20
|
||||
[joe@my-minion1 ~] $ docker ps
|
||||
// no nginx container is running
|
||||
[joe@my-minion1 ~] $ mv /tmp/static-web.yaml /etc/kubernetes.d/
|
||||
[joe@my-minion1 ~] $ sleep 20
|
||||
[joe@my-minion1 ~] $ docker ps
|
||||
CONTAINER ID IMAGE COMMAND CREATED ...
|
||||
e7a62e3427f1 nginx:latest "nginx -g 'daemon of 27 seconds ago
|
||||
```
|
|
@ -0,0 +1,127 @@
|
|||
|
||||
Primary system and API concepts are documented in the [User guide](/{{page.version}}/docs/user-guide/).
|
||||
|
||||
Overall API conventions are described in the [API conventions doc](/{{page.version}}/docs/devel/api-conventions).
|
||||
|
||||
Complete API details are documented via [Swagger](http://swagger.io/). The Kubernetes apiserver (aka "master") exports an API that can be used to retrieve the [Swagger spec](https://github.com/swagger-api/swagger-spec/tree/master/schemas/v1.2) for the Kubernetes API, by default at `/swaggerapi`, and a UI you can use to browse the API documentation at `/swagger-ui`. We also periodically update a [statically generated UI](http://kubernetes.io/third_party/swagger-ui/).
|
||||
|
||||
Remote access to the API is discussed in the [access doc](/{{page.version}}/docs/admin/accessing-the-api).
|
||||
|
||||
The Kubernetes API also serves as the foundation for the declarative configuration schema for the system. The [Kubectl](/{{page.version}}/docs/user-guide/kubectl/kubectl) command-line tool can be used to create, update, delete, and get API objects.
|
||||
|
||||
Kubernetes also stores its serialized state (currently in [etcd](https://coreos.com/docs/distributed-configuration/getting-started-with-etcd/)) in terms of the API resources.
|
||||
|
||||
Kubernetes itself is decomposed into multiple components, which interact through its API.
|
||||
|
||||
## API changes
|
||||
|
||||
In our experience, any system that is successful needs to grow and change as new use cases emerge or existing ones change. Therefore, we expect the Kubernetes API to continuously change and grow. However, we intend to not break compatibility with existing clients, for an extended period of time. In general, new API resources and new resource fields can be expected to be added frequently. Elimination of resources or fields will require following a deprecation process. The precise deprecation policy for eliminating features is TBD, but once we reach our 1.0 milestone, there will be a specific policy.
|
||||
|
||||
What constitutes a compatible change and how to change the API are detailed by the [API change document](/{{page.version}}/docs/devel/api_changes).
|
||||
|
||||
## API versioning
|
||||
|
||||
To make it easier to eliminate fields or restructure resource representations, Kubernetes supports
|
||||
multiple API versions, each at a different API path, such as `/api/v1` or
|
||||
`/apis/extensions/v1beta1`.
|
||||
|
||||
We chose to version at the API level rather than at the resource or field level to ensure that the API presents a clear, consistent view of system resources and behavior, and to enable controlling access to end-of-lifed and/or experimental APIs.
|
||||
|
||||
Note that API versioning and Software versioning are only indirectly related. The [API and release
|
||||
versioning proposal](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/versioning.md) describes the relationship between API versioning and
|
||||
software versioning.
|
||||
|
||||
|
||||
Different API versions imply different levels of stability and support. The criteria for each level are described
|
||||
in more detail in the [API Changes documentation](/{{page.version}}/docs/devel/api_changes/#alpha-beta-and-stable-versions). They are summarized here:
|
||||
|
||||
- Alpha level:
|
||||
- The version names contain `alpha` (e.g. `v1alpha1`).
|
||||
- May be buggy. Enabling the feature may expose bugs. Disabled by default.
|
||||
- Support for feature may be dropped at any time without notice.
|
||||
- The API may change in incompatible ways in a later software release without notice.
|
||||
- Recommended for use only in short-lived testing clusters, due to increased risk of bugs and lack of long-term support.
|
||||
- Beta level:
|
||||
- The version names contain `beta` (e.g. `v2beta3`).
|
||||
- Code is well tested. Enabling the feature is considered safe. Enabled by default.
|
||||
- Support for the overall feature will not be dropped, though details may change.
|
||||
- The schema and/or semantics of objects may change in incompatible ways in a subsequent beta or stable release. When this happens,
|
||||
we will provide instructions for migrating to the next version. This may require deleting, editing, and re-creating
|
||||
API objects. The editing process may require some thought. This may require downtime for appplications that rely on the feature.
|
||||
- Recommended for only non-business-critical uses because of potential for incompatible changes in subsequent releases. If you have
|
||||
multiple clusters which can be upgraded independently, you may be able to relax this restriction.
|
||||
- **Please do try our beta features and give feedback on them! Once they exit beta, it may not be practical for us to make more changes.**
|
||||
- Stable level:
|
||||
- The version name is `vX` where `X` is an integer.
|
||||
- Stable versions of features will appear in released software for many subsequent versions.
|
||||
|
||||
## API groups
|
||||
|
||||
To make it easier to extend the Kubernetes API, we are in the process of implementing [*API
|
||||
groups*](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/proposals/api-group.md). These are simply different interfaces to read and/or modify the
|
||||
same underlying resources. The API group is specified in a REST path and in the `apiVersion` field
|
||||
of a serialized object.
|
||||
|
||||
Currently there are two API groups in use:
|
||||
|
||||
1. the "core" group, which is at REST path `/api/v1` and is not specified as part of the `apiVersion` field, e.g.
|
||||
`apiVersion: v1`.
|
||||
1. the "extensions" group, which is at REST path `/apis/extensions/$VERSION`, and which uses
|
||||
`apiVersion: extensions/$VERSION` (e.g. currently `apiVersion: extensions/v1beta1`).
|
||||
|
||||
In the future we expect that there will be more API groups, all at REST path `/apis/$API_GROUP` and
|
||||
using `apiVersion: $API_GROUP/$VERSION`. We expect that there will be a way for (third parties to
|
||||
create their own API groups](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/extending-api.md), and to avoid naming collisions.
|
||||
|
||||
## Enabling resources in the extensions group
|
||||
|
||||
Jobs, Ingress and HorizontalPodAutoscalers are enabled by default.
|
||||
Other extensions resources can be enabled by setting runtime-config on
|
||||
apiserver. runtime-config accepts comma separated values. For ex: to enable deployments and disable jobs, set
|
||||
`--runtime-config=extensions/v1beta1/deployments=true,extensions/v1beta1/jobs=false`
|
||||
|
||||
## v1beta1, v1beta2, and v1beta3 are deprecated; please move to v1 ASAP
|
||||
|
||||
As of June 4, 2015, the Kubernetes v1 API has been enabled by default. The v1beta1 and v1beta2 APIs were deleted on June 1, 2015. v1beta3 is planned to be deleted on July 6, 2015.
|
||||
|
||||
### v1 conversion tips (from v1beta3)
|
||||
|
||||
We're working to convert all documentation and examples to v1. A simple [API conversion tool](/{{page.version}}/docs/admin/cluster-management/#switching-your-config-files-to-a-new-api-version) has been written to simplify the translation process. Use `kubectl create --validate` in order to validate your json or yaml against our Swagger spec.
|
||||
|
||||
Changes to services are the most significant difference between v1beta3 and v1.
|
||||
|
||||
* The `service.spec.portalIP` property is renamed to `service.spec.clusterIP`.
|
||||
* The `service.spec.createExternalLoadBalancer` property is removed. Specify `service.spec.type: "LoadBalancer"` to create an external load balancer instead.
|
||||
* The `service.spec.publicIPs` property is deprecated and now called `service.spec.deprecatedPublicIPs`. This property will be removed entirely when v1beta3 is removed. The vast majority of users of this field were using it to expose services on ports on the node. Those users should specify `service.spec.type: "NodePort"` instead. Read [External Services](/{{page.version}}/docs/user-guide/services/#external-services) for more info. If this is not sufficient for your use case, please file an issue or contact @thockin.
|
||||
|
||||
Some other difference between v1beta3 and v1:
|
||||
|
||||
* The `pod.spec.containers[*].privileged` and `pod.spec.containers[*].capabilities` properties are now nested under the `pod.spec.containers[*].securityContext` property. See [Security Contexts](/{{page.version}}/docs/user-guide/security-context).
|
||||
* The `pod.spec.host` property is renamed to `pod.spec.nodeName`.
|
||||
* The `endpoints.subsets[*].addresses.IP` property is renamed to `endpoints.subsets[*].addresses.ip`.
|
||||
* The `pod.status.containerStatuses[*].state.termination` and `pod.status.containerStatuses[*].lastState.termination` properties are renamed to `pod.status.containerStatuses[*].state.terminated` and `pod.status.containerStatuses[*].lastState.terminated` respectively.
|
||||
* The `pod.status.Condition` property is renamed to `pod.status.conditions`.
|
||||
* The `status.details.id` property is renamed to `status.details.name`.
|
||||
|
||||
### v1beta3 conversion tips (from v1beta1/2)
|
||||
|
||||
Some important differences between v1beta1/2 and v1beta3:
|
||||
|
||||
* The resource `id` is now called `name`.
|
||||
* `name`, `labels`, `annotations`, and other metadata are now nested in a map called `metadata`
|
||||
* `desiredState` is now called `spec`, and `currentState` is now called `status`
|
||||
* `/minions` has been moved to `/nodes`, and the resource has kind `Node`
|
||||
* The namespace is required (for all namespaced resources) and has moved from a URL parameter to the path: `/api/v1beta3/namespaces/{namespace}/{resource_collection}/{resource_name}`. If you were not using a namespace before, use `default` here.
|
||||
* The names of all resource collections are now lower cased - instead of `replicationControllers`, use `replicationcontrollers`.
|
||||
* To watch for changes to a resource, open an HTTP or Websocket connection to the collection query and provide the `?watch=true` query parameter along with the desired `resourceVersion` parameter to watch from.
|
||||
* The `labels` query parameter has been renamed to `labelSelector`.
|
||||
* The `fields` query parameter has been renamed to `fieldSelector`.
|
||||
* The container `entrypoint` has been renamed to `command`, and `command` has been renamed to `args`.
|
||||
* Container, volume, and node resources are expressed as nested maps (e.g., `resources{cpu:1}`) rather than as individual fields, and resource values support [scaling suffixes](/{{page.version}}/docs/user-guide/compute-resources/#specifying-resource-quantities) rather than fixed scales (e.g., milli-cores).
|
||||
* Restart policy is represented simply as a string (e.g., `"Always"`) rather than as a nested map (`always{}`).
|
||||
* Pull policies changed from `PullAlways`, `PullNever`, and `PullIfNotPresent` to `Always`, `Never`, and `IfNotPresent`.
|
||||
* The volume `source` is inlined into `volume` rather than nested.
|
||||
* Host volumes have been changed from `hostDir` to `hostPath` to better reflect that they can be files or directories.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,657 @@
|
|||
|
||||
Updated: 9/20/2015
|
||||
|
||||
*This document is oriented at users who want a deeper understanding of the Kubernetes
|
||||
API structure, and developers wanting to extend the Kubernetes API. An introduction to
|
||||
using resources with kubectl can be found in [Working with resources](/{{page.version}}/docs/user-guide/working-with-resources).*
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
The conventions of the [Kubernetes API](/{{page.version}}/docs/api/) (and related APIs in the ecosystem) are intended to ease client development and ensure that configuration mechanisms can be implemented that work across a diverse set of use cases consistently.
|
||||
|
||||
The general style of the Kubernetes API is RESTful - clients create, update, delete, or retrieve a description of an object via the standard HTTP verbs (POST, PUT, DELETE, and GET) - and those APIs preferentially accept and return JSON. Kubernetes also exposes additional endpoints for non-standard verbs and allows alternative content types. All of the JSON accepted and returned by the server has a schema, identified by the "kind" and "apiVersion" fields. Where relevant HTTP header fields exist, they should mirror the content of JSON fields, but the information should not be represented only in the HTTP header.
|
||||
|
||||
The following terms are defined:
|
||||
|
||||
* **Kind** the name of a particular object schema (e.g. the "Cat" and "Dog" kinds would have different attributes and properties)
|
||||
* **Resource** a representation of a system entity, sent or retrieved as JSON via HTTP to the server. Resources are exposed via:
|
||||
* Collections - a list of resources of the same type, which may be queryable
|
||||
* Elements - an individual resource, addressable via a URL
|
||||
|
||||
Each resource typically accepts and returns data of a single kind. A kind may be accepted or returned by multiple resources that reflect specific use cases. For instance, the kind "Pod" is exposed as a "pods" resource that allows end users to create, update, and delete pods, while a separate "pod status" resource (that acts on "Pod" kind) allows automated processes to update a subset of the fields in that resource.
|
||||
|
||||
Resource collections should be all lowercase and plural, whereas kinds are CamelCase and singular.
|
||||
|
||||
|
||||
## Types (Kinds)
|
||||
|
||||
Kinds are grouped into three categories:
|
||||
|
||||
1. **Objects** represent a persistent entity in the system.
|
||||
|
||||
Creating an API object is a record of intent - once created, the system will work to ensure that resource exists. All API objects have common metadata.
|
||||
|
||||
An object may have multiple resources that clients can use to perform specific actions that create, update, delete, or get.
|
||||
|
||||
Examples: `Pod`, `ReplicationController`, `Service`, `Namespace`, `Node`.
|
||||
|
||||
2. **Lists** are collections of **resources** of one (usually) or more (occasionally) kinds.
|
||||
|
||||
Lists have a limited set of common metadata. All lists use the "items" field to contain the array of objects they return.
|
||||
|
||||
Most objects defined in the system should have an endpoint that returns the full set of resources, as well as zero or more endpoints that return subsets of the full list. Some objects may be singletons (the current user, the system defaults) and may not have lists.
|
||||
|
||||
In addition, all lists that return objects with labels should support label filtering (see [docs/user-guide/labels.md](/{{page.version}}/docs/user-guide/labels), and most lists should support filtering by fields.
|
||||
|
||||
Examples: PodLists, ServiceLists, NodeLists
|
||||
|
||||
TODO: Describe field filtering below or in a separate doc.
|
||||
|
||||
3. **Simple** kinds are used for specific actions on objects and for non-persistent entities.
|
||||
|
||||
Given their limited scope, they have the same set of limited common metadata as lists.
|
||||
|
||||
For instance, the "Status" kind is returned when errors occur and is not persisted in the system.
|
||||
|
||||
Many simple resources are "subresources", which are rooted at API paths of specific resources. When resources wish to expose alternative actions or views that are closely coupled to a single resource, they should do so using new sub-resources. Common subresources include:
|
||||
|
||||
* `/binding`: Used to bind a resource representing a user request (e.g., Pod, PersistentVolumeClaim) to a cluster infrastructure resource (e.g., Node, PersistentVolume).
|
||||
* `/status`: Used to write just the status portion of a resource. For example, the `/pods` endpoint only allows updates to `metadata` and `spec`, since those reflect end-user intent. An automated process should be able to modify status for users to see by sending an updated Pod kind to the server to the "/pods/<name>/status" endpoint - the alternate endpoint allows different rules to be applied to the update, and access to be appropriately restricted.
|
||||
* `/scale`: Used to read and write the count of a resource in a manner that is independent of the specific resource schema.
|
||||
|
||||
Two additional subresources, `proxy` and `portforward`, provide access to cluster resources as described in [docs/user-guide/accessing-the-cluster.md](/{{page.version}}/docs/user-guide/accessing-the-cluster).
|
||||
|
||||
The standard REST verbs (defined below) MUST return singular JSON objects. Some API endpoints may deviate from the strict REST pattern and return resources that are not singular JSON objects, such as streams of JSON objects or unstructured text log data.
|
||||
|
||||
The term "kind" is reserved for these "top-level" API types. The term "type" should be used for distinguishing sub-categories within objects or subobjects.
|
||||
|
||||
### Resources
|
||||
|
||||
All JSON objects returned by an API MUST have the following fields:
|
||||
|
||||
* kind: a string that identifies the schema this object should have
|
||||
* apiVersion: a string that identifies the version of the schema the object should have
|
||||
|
||||
These fields are required for proper decoding of the object. They may be populated by the server by default from the specified URL path, but the client likely needs to know the values in order to construct the URL path.
|
||||
|
||||
### Objects
|
||||
|
||||
#### Metadata
|
||||
|
||||
Every object kind MUST have the following metadata in a nested object field called "metadata":
|
||||
|
||||
* namespace: a namespace is a DNS compatible subdomain that objects are subdivided into. The default namespace is 'default'. See [docs/user-guide/namespaces.md](/{{page.version}}/docs/user-guide/namespaces) for more.
|
||||
* name: a string that uniquely identifies this object within the current namespace (see [docs/user-guide/identifiers.md](/{{page.version}}/docs/user-guide/identifiers)). This value is used in the path when retrieving an individual object.
|
||||
* uid: a unique in time and space value (typically an RFC 4122 generated identifier, see [docs/user-guide/identifiers.md](/{{page.version}}/docs/user-guide/identifiers)) used to distinguish between objects with the same name that have been deleted and recreated
|
||||
|
||||
Every object SHOULD have the following metadata in a nested object field called "metadata":
|
||||
|
||||
* resourceVersion: a string that identifies the internal version of this object that can be used by clients to determine when objects have changed. This value MUST be treated as opaque by clients and passed unmodified back to the server. Clients should not assume that the resource version has meaning across namespaces, different kinds of resources, or different servers. (see [concurrency control](#concurrency-control-and-consistency), below, for more details)
|
||||
* generation: a sequence number representing a specific generation of the desired state. Set by the system and monotonically increasing, per-resource. May be compared, such as for RAW and WAW consistency.
|
||||
* creationTimestamp: a string representing an RFC 3339 date of the date and time an object was created
|
||||
* deletionTimestamp: a string representing an RFC 3339 date of the date and time after which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource will be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field. Once set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time.
|
||||
* labels: a map of string keys and values that can be used to organize and categorize objects (see [docs/user-guide/labels.md](/{{page.version}}/docs/user-guide/labels))
|
||||
* annotations: a map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about this object (see [docs/user-guide/annotations.md](/{{page.version}}/docs/user-guide/annotations))
|
||||
|
||||
Labels are intended for organizational purposes by end users (select the pods that match this label query). Annotations enable third-party automation and tooling to decorate objects with additional metadata for their own use.
|
||||
|
||||
#### Spec and Status
|
||||
|
||||
By convention, the Kubernetes API makes a distinction between the specification of the desired state of an object (a nested object field called "spec") and the status of the object at the current time (a nested object field called "status"). The specification is a complete description of the desired state, including configuration settings provided by the user, [default values](#defaulting) expanded by the system, and properties initialized or otherwise changed after creation by other ecosystem components (e.g., schedulers, auto-scalers), and is persisted in stable storage with the API object. If the specification is deleted, the object will be purged from the system. The status summarizes the current state of the object in the system, and is usually persisted with the object by an automated processes but may be generated on the fly. At some cost and perhaps some temporary degradation in behavior, the status could be reconstructed by observation if it were lost.
|
||||
|
||||
When a new version of an object is POSTed or PUT, the "spec" is updated and available immediately. Over time the system will work to bring the "status" into line with the "spec". The system will drive toward the most recent "spec" regardless of previous versions of that stanza. In other words, if a value is changed from 2 to 5 in one PUT and then back down to 3 in another PUT the system is not required to 'touch base' at 5 before changing the "status" to 3. In other words, the system's behavior is *level-based* rather than *edge-based*. This enables robust behavior in the presence of missed intermediate state changes.
|
||||
|
||||
The Kubernetes API also serves as the foundation for the declarative configuration schema for the system. In order to facilitate level-based operation and expression of declarative configuration, fields in the specification should have declarative rather than imperative names and semantics -- they represent the desired state, not actions intended to yield the desired state.
|
||||
|
||||
The PUT and POST verbs on objects will ignore the "status" values. A `/status` subresource is provided to enable system components to update statuses of resources they manage.
|
||||
|
||||
Otherwise, PUT expects the whole object to be specified. Therefore, if a field is omitted it is assumed that the client wants to clear that field's value. The PUT verb does not accept partial updates. Modification of just part of an object may be achieved by GETting the resource, modifying part of the spec, labels, or annotations, and then PUTting it back. See [concurrency control](#concurrency-control-and-consistency), below, regarding read-modify-write consistency when using this pattern. Some objects may expose alternative resource representations that allow mutation of the status, or performing custom actions on the object.
|
||||
|
||||
All objects that represent a physical resource whose state may vary from the user's desired intent SHOULD have a "spec" and a "status". Objects whose state cannot vary from the user's desired intent MAY have only "spec", and MAY rename "spec" to a more appropriate name.
|
||||
|
||||
Objects that contain both spec and status should not contain additional top-level fields other than the standard metadata fields.
|
||||
|
||||
##### Typical status properties
|
||||
|
||||
**Conditions** represent the latest available observations of an object's current state. Objects may report multiple conditions, and new types of conditions may be added in the future. Therefore, conditions are represented using a list/slice, where all have similar structure.
|
||||
|
||||
The `FooCondition` type for some resource type `Foo` may include a subset of the following fields, but must contain at least `type` and `status` fields:
|
||||
|
||||
```go
|
||||
Type FooConditionType `json:"type" description:"type of Foo condition"`
|
||||
Status ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"`
|
||||
LastHeartbeatTime unversioned.Time `json:"lastHeartbeatTime,omitempty" description:"last time we got an update on a given condition"`
|
||||
LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty" description:"last time the condition transit from one status to another"`
|
||||
Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"`
|
||||
Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"`
|
||||
```
|
||||
|
||||
Additional fields may be added in the future.
|
||||
|
||||
Conditions should be added to explicitly convey properties that users and components care about rather than requiring those properties to be inferred from other observations.
|
||||
|
||||
Condition status values may be `True`, `False`, or `Unknown`. The absence of a condition should be interpreted the same as `Unknown`.
|
||||
|
||||
In general, condition values may change back and forth, but some condition transitions may be monotonic, depending on the resource and condition type. However, conditions are observations and not, themselves, state machines, nor do we define comprehensive state machines for objects, nor behaviors associated with state transitions. The system is level-based rather than edge-triggered, and should assume an Open World.
|
||||
|
||||
A typical oscillating condition type is `Ready`, which indicates the object was believed to be fully operational at the time it was last probed. A possible monotonic condition could be `Succeeded`. A `False` status for `Succeeded` would imply failure. An object that was still active would not have a `Succeeded` condition, or its status would be `Unknown`.
|
||||
|
||||
Some resources in the v1 API contain fields called **`phase`**, and associated `message`, `reason`, and other status fields. The pattern of using `phase` is deprecated. Newer API types should use conditions instead. Phase was essentially a state-machine enumeration field, that contradicted [system-design principles](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/principles.md#control-logic) and hampered evolution, since [adding new enum values breaks backward compatibility](/{{page.version}}/docs/devel/api_changes). Rather than encouraging clients to infer implicit properties from phases, we intend to explicitly expose the conditions that clients need to monitor. Conditions also have the benefit that it is possible to create some conditions with uniform meaning across all resource types, while still exposing others that are unique to specific resource types. See [#7856](http://issues.k8s.io/7856) for more details and discussion.
|
||||
|
||||
In condition types, and everywhere else they appear in the API, **`Reason`** is intended to be a one-word, CamelCase representation of the category of cause of the current status, and **`Message`** is intended to be a human-readable phrase or sentence, which may contain specific details of the individual occurrence. `Reason` is intended to be used in concise output, such as one-line `kubectl get` output, and in summarizing occurrences of causes, whereas `Message` is intended to be presented to users in detailed status explanations, such as `kubectl describe` output.
|
||||
|
||||
Historical information status (e.g., last transition time, failure counts) is only provided with reasonable effort, and is not guaranteed to not be lost.
|
||||
|
||||
Status information that may be large (especially proportional in size to collections of other resources, such as lists of references to other objects -- see below) and/or rapidly changing, such as [resource usage](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/resources.md#usage-data), should be put into separate objects, with possibly a reference from the original object. This helps to ensure that GETs and watch remain reasonably efficient for the majority of clients, which may not need that data.
|
||||
|
||||
Some resources report the `observedGeneration`, which is the `generation` most recently observed by the component responsible for acting upon changes to the desired state of the resource. This can be used, for instance, to ensure that the reported status reflects the most recent desired status.
|
||||
|
||||
#### References to related objects
|
||||
|
||||
References to loosely coupled sets of objects, such as [pods](/{{page.version}}/docs/user-guide/pods) overseen by a [replication controller](/{{page.version}}/docs/user-guide/replication-controller), are usually best referred to using a [label selector](/{{page.version}}/docs/user-guide/labels). In order to ensure that GETs of individual objects remain bounded in time and space, these sets may be queried via separate API queries, but will not be expanded in the referring object's status.
|
||||
|
||||
References to specific objects, especially specific resource versions and/or specific fields of those objects, are specified using the `ObjectReference` type (or other types representing strict subsets of it). Unlike partial URLs, the ObjectReference type facilitates flexible defaulting of fields from the referring object or other contextual information.
|
||||
|
||||
References in the status of the referee to the referrer may be permitted, when the references are one-to-one and do not need to be frequently updated, particularly in an edge-based manner.
|
||||
|
||||
#### Lists of named subobjects preferred over maps
|
||||
|
||||
Discussed in [#2004](http://issue.k8s.io/2004) and elsewhere. There are no maps of subobjects in any API objects. Instead, the convention is to use a list of subobjects containing name fields.
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- name: www
|
||||
containerPort: 80
|
||||
```
|
||||
|
||||
vs.
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
www:
|
||||
containerPort: 80
|
||||
```
|
||||
|
||||
This rule maintains the invariant that all JSON/YAML keys are fields in API objects. The only exceptions are pure maps in the API (currently, labels, selectors, annotations, data), as opposed to sets of subobjects.
|
||||
|
||||
#### Constants
|
||||
|
||||
Some fields will have a list of allowed values (enumerations). These values will be strings, and they will be in CamelCase, with an initial uppercase letter. Examples: "ClusterFirst", "Pending", "ClientIP".
|
||||
|
||||
### Lists and Simple kinds
|
||||
|
||||
Every list or simple kind SHOULD have the following metadata in a nested object field called "metadata":
|
||||
|
||||
* resourceVersion: a string that identifies the common version of the objects returned by in a list. This value MUST be treated as opaque by clients and passed unmodified back to the server. A resource version is only valid within a single namespace on a single kind of resource.
|
||||
|
||||
Every simple kind returned by the server, and any simple kind sent to the server that must support idempotency or optimistic concurrency should return this value.Since simple resources are often used as input alternate actions that modify objects, the resource version of the simple resource should correspond to the resource version of the object.
|
||||
|
||||
|
||||
## Differing Representations
|
||||
|
||||
An API may represent a single entity in different ways for different clients, or transform an object after certain transitions in the system occur. In these cases, one request object may have two representations available as different resources, or different kinds.
|
||||
|
||||
An example is a Service, which represents the intent of the user to group a set of pods with common behavior on common ports. When Kubernetes detects a pod matches the service selector, the IP address and port of the pod are added to an Endpoints resource for that Service. The Endpoints resource exists only if the Service exists, but exposes only the IPs and ports of the selected pods. The full service is represented by two distinct resources - under the original Service resource the user created, as well as in the Endpoints resource.
|
||||
|
||||
As another example, a "pod status" resource may accept a PUT with the "pod" kind, with different rules about what fields may be changed.
|
||||
|
||||
Future versions of Kubernetes may allow alternative encodings of objects beyond JSON.
|
||||
|
||||
|
||||
## Verbs on Resources
|
||||
|
||||
API resources should use the traditional REST pattern:
|
||||
|
||||
* GET /<resourceNamePlural> - Retrieve a list of type <resourceName>, e.g. GET /pods returns a list of Pods.
|
||||
* POST /<resourceNamePlural> - Create a new resource from the JSON object provided by the client.
|
||||
* GET /<resourceNamePlural>/<name> - Retrieves a single resource with the given name, e.g. GET /pods/first returns a Pod named 'first'. Should be constant time, and the resource should be bounded in size.
|
||||
* DELETE /<resourceNamePlural>/<name> - Delete the single resource with the given name. DeleteOptions may specify gracePeriodSeconds, the optional duration in seconds before the object should be deleted. Individual kinds may declare fields which provide a default grace period, and different kinds may have differing kind-wide default grace periods. A user provided grace period overrides a default grace period, including the zero grace period ("now").
|
||||
* PUT /<resourceNamePlural>/<name> - Update or create the resource with the given name with the JSON object provided by the client.
|
||||
* PATCH /<resourceNamePlural>/<name> - Selectively modify the specified fields of the resource. See more information [below](#patch).
|
||||
* GET /<resourceNamePlural>&watch=true - Receive a stream of JSON objects corresponding to changes made to any resource of the given kind over time.
|
||||
|
||||
### PATCH operations
|
||||
|
||||
The API supports three different PATCH operations, determined by their corresponding Content-Type header:
|
||||
|
||||
* JSON Patch, `Content-Type: application/json-patch+json`
|
||||
* As defined in [RFC6902](https://tools.ietf.org/html/rfc6902), a JSON Patch is a sequence of operations that are executed on the resource, e.g. `{"op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ]}`. For more details on how to use JSON Patch, see the RFC.
|
||||
* Merge Patch, `Content-Type: application/merge-patch+json`
|
||||
* As defined in [RFC7386](https://tools.ietf.org/html/rfc7386), a Merge Patch is essentially a partial representation of the resource. The submitted JSON is "merged" with the current resource to create a new one, then the new one is saved. For more details on how to use Merge Patch, see the RFC.
|
||||
* Strategic Merge Patch, `Content-Type: application/strategic-merge-patch+json`
|
||||
* Strategic Merge Patch is a custom implementation of Merge Patch. For a detailed explanation of how it works and why it needed to be introduced, see below.
|
||||
|
||||
#### Strategic Merge Patch
|
||||
|
||||
In the standard JSON merge patch, JSON objects are always merged but lists are always replaced. Often that isn't what we want. Let's say we start with the following Pod:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx-1.0
|
||||
```
|
||||
|
||||
...and we POST that to the server (as JSON). Then let's say we want to *add* a container to this Pod.
|
||||
|
||||
```yaml
|
||||
PATCH /api/v1/namespaces/default/pods/pod-name
|
||||
spec:
|
||||
containers:
|
||||
- name: log-tailer
|
||||
image: log-tailer-1.0
|
||||
```
|
||||
|
||||
If we were to use standard Merge Patch, the entire container list would be replaced with the single log-tailer container. However, our intent is for the container lists to merge together based on the `name` field.
|
||||
|
||||
To solve this problem, Strategic Merge Patch uses metadata attached to the API objects to determine what lists should be merged and which ones should not. Currently the metadata is available as struct tags on the API objects themselves, but will become available to clients as Swagger annotations in the future. In the above example, the `patchStrategy` metadata for the `containers` field would be `merge` and the `patchMergeKey` would be `name`.
|
||||
|
||||
Note: If the patch results in merging two lists of scalars, the scalars are first deduplicated and then merged.
|
||||
|
||||
Strategic Merge Patch also supports special operations as listed below.
|
||||
|
||||
### List Operations
|
||||
|
||||
To override the container list to be strictly replaced, regardless of the default:
|
||||
|
||||
```yaml
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx-1.0
|
||||
- $patch: replace # any further $patch operations nested in this list will be ignored
|
||||
```
|
||||
|
||||
To delete an element of a list that should be merged:
|
||||
|
||||
```yaml
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx-1.0
|
||||
- $patch: delete
|
||||
name: log-tailer # merge key and value goes here
|
||||
```
|
||||
|
||||
### Map Operations
|
||||
|
||||
To indicate that a map should not be merged and instead should be taken literally:
|
||||
|
||||
```yaml
|
||||
$patch: replace # recursive and applies to all fields of the map it's in
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx-1.0
|
||||
```
|
||||
|
||||
To delete a field of a map:
|
||||
|
||||
```yaml
|
||||
name: nginx
|
||||
image: nginx-1.0
|
||||
labels:
|
||||
live: null # set the value of the map key to null
|
||||
```
|
||||
|
||||
## Idempotency
|
||||
|
||||
All compatible Kubernetes APIs MUST support "name idempotency" and respond with an HTTP status code 409 when a request is made to POST an object that has the same name as an existing object in the system. See [docs/user-guide/identifiers.md](/{{page.version}}/docs/user-guide/identifiers) for details.
|
||||
|
||||
Names generated by the system may be requested using `metadata.generateName`. GenerateName indicates that the name should be made unique by the server prior to persisting it. A non-empty value for the field indicates the name will be made unique (and the name returned to the client will be different than the name passed). The value of this field will be combined with a unique suffix on the server if the Name field has not been provided. The provided value must be valid within the rules for Name, and may be truncated by the length of the suffix required to make the value unique on the server. If this field is specified, and Name is not present, the server will NOT return a 409 if the generated name exists - instead, it will either return 201 Created or 504 with Reason `ServerTimeout` indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).
|
||||
|
||||
## Defaulting
|
||||
|
||||
Default resource values are API version-specific, and they are applied during
|
||||
the conversion from API-versioned declarative configuration to internal objects
|
||||
representing the desired state (`Spec`) of the resource. Subsequent GETs of the
|
||||
resource will include the default values explicitly.
|
||||
|
||||
Incorporating the default values into the `Spec` ensures that `Spec` depicts the
|
||||
full desired state so that it is easier for the system to determine how to
|
||||
achieve the state, and for the user to know what to anticipate.
|
||||
|
||||
API version-specific default values are set by the API server.
|
||||
|
||||
## Late Initialization
|
||||
|
||||
Late initialization is when resource fields are set by a system controller
|
||||
after an object is created/updated.
|
||||
|
||||
For example, the scheduler sets the `pod.spec.nodeName` field after the pod is created.
|
||||
|
||||
Late-initializers should only make the following types of modifications:
|
||||
|
||||
- Setting previously unset fields
|
||||
- Adding keys to maps
|
||||
- Adding values to arrays which have mergeable semantics (`patchStrategy:"merge"` attribute in
|
||||
the type definition).
|
||||
|
||||
These conventions:
|
||||
|
||||
1. allow a user (with sufficient privilege) to override any system-default behaviors by setting
|
||||
the fields that would otherwise have been defaulted.
|
||||
1. enables updates from users to be merged with changes made during late initialization, using
|
||||
strategic merge patch, as opposed to clobbering the change.
|
||||
1. allow the component which does the late-initialization to use strategic merge patch, which
|
||||
facilitates composition and concurrency of such components.
|
||||
|
||||
Although the apiserver Admission Control stage acts prior to object creation,
|
||||
Admission Control plugins should follow the Late Initialization conventions
|
||||
too, to allow their implementation to be later moved to a 'controller', or to client libraries.
|
||||
|
||||
## Concurrency Control and Consistency
|
||||
|
||||
Kubernetes leverages the concept of *resource versions* to achieve optimistic concurrency. All Kubernetes resources have a "resourceVersion" field as part of their metadata. This resourceVersion is a string that identifies the internal version of an object that can be used by clients to determine when objects have changed. When a record is about to be updated, it's version is checked against a pre-saved value, and if it doesn't match, the update fails with a StatusConflict (HTTP status code 409).
|
||||
|
||||
The resourceVersion is changed by the server every time an object is modified. If resourceVersion is included with the PUT operation the system will verify that there have not been other successful mutations to the resource during a read/modify/write cycle, by verifying that the current value of resourceVersion matches the specified value.
|
||||
|
||||
The resourceVersion is currently backed by [etcd's modifiedIndex](https://coreos.com/docs/distributed-configuration/etcd-api/). However, it's important to note that the application should *not* rely on the implementation details of the versioning system maintained by Kubernetes. We may change the implementation of resourceVersion in the future, such as to change it to a timestamp or per-object counter.
|
||||
|
||||
The only way for a client to know the expected value of resourceVersion is to have received it from the server in response to a prior operation, typically a GET. This value MUST be treated as opaque by clients and passed unmodified back to the server. Clients should not assume that the resource version has meaning across namespaces, different kinds of resources, or different servers. Currently, the value of resourceVersion is set to match etcd's sequencer. You could think of it as a logical clock the API server can use to order requests. However, we expect the implementation of resourceVersion to change in the future, such as in the case we shard the state by kind and/or namespace, or port to another storage system.
|
||||
|
||||
In the case of a conflict, the correct client action at this point is to GET the resource again, apply the changes afresh, and try submitting again. This mechanism can be used to prevent races like the following:
|
||||
|
||||
```shell
|
||||
Client #1 Client #2
|
||||
GET Foo GET Foo
|
||||
Set Foo.Bar = "one" Set Foo.Baz = "two"
|
||||
PUT Foo PUT Foo
|
||||
```
|
||||
|
||||
When these sequences occur in parallel, either the change to Foo.Bar or the change to Foo.Baz can be lost.
|
||||
|
||||
On the other hand, when specifying the resourceVersion, one of the PUTs will fail, since whichever write succeeds changes the resourceVersion for Foo.
|
||||
|
||||
resourceVersion may be used as a precondition for other operations (e.g., GET, DELETE) in the future, such as for read-after-write consistency in the presence of caching.
|
||||
|
||||
"Watch" operations specify resourceVersion using a query parameter. It is used to specify the point at which to begin watching the specified resources. This may be used to ensure that no mutations are missed between a GET of a resource (or list of resources) and a subsequent Watch, even if the current version of the resource is more recent. This is currently the main reason that list operations (GET on a collection) return resourceVersion.
|
||||
|
||||
|
||||
## Serialization Format
|
||||
|
||||
APIs may return alternative representations of any resource in response to an Accept header or under alternative endpoints, but the default serialization for input and output of API responses MUST be JSON.
|
||||
|
||||
All dates should be serialized as RFC3339 strings.
|
||||
|
||||
## Units
|
||||
|
||||
Units must either be explicit in the field name (e.g., `timeoutSeconds`), or must be specified as part of the value (e.g., `resource.Quantity`). Which approach is preferred is TBD, though currently we use the `fooSeconds` convention for durations.
|
||||
|
||||
|
||||
## Selecting Fields
|
||||
|
||||
Some APIs may need to identify which field in a JSON object is invalid, or to reference a value to extract from a separate resource. The current recommendation is to use standard JavaScript syntax for accessing that field, assuming the JSON object was transformed into a JavaScript object, without the leading dot, such as `metadata.name`.
|
||||
|
||||
Examples:
|
||||
|
||||
* Find the field "current" in the object "state" in the second item in the array "fields": `fields[1].state.current`
|
||||
|
||||
## Object references
|
||||
|
||||
Object references should either be called `fooName` if referring to an object of kind `Foo` by just the name (within the current namespace, if a namespaced resource), or should be called `fooRef`, and should contain a subset of the fields of the `ObjectReference` type.
|
||||
|
||||
|
||||
TODO: Plugins, extensions, nested kinds, headers
|
||||
|
||||
|
||||
## HTTP Status codes
|
||||
|
||||
The server will respond with HTTP status codes that match the HTTP spec. See the section below for a breakdown of the types of status codes the server will send.
|
||||
|
||||
The following HTTP status codes may be returned by the API.
|
||||
|
||||
#### Success codes
|
||||
|
||||
* `200 StatusOK`
|
||||
* Indicates that the request completed successfully.
|
||||
* `201 StatusCreated`
|
||||
* Indicates that the request to create kind completed successfully.
|
||||
* `204 StatusNoContent`
|
||||
* Indicates that the request completed successfully, and the response contains no body.
|
||||
* Returned in response to HTTP OPTIONS requests.
|
||||
|
||||
#### Error codes
|
||||
|
||||
* `307 StatusTemporaryRedirect`
|
||||
* Indicates that the address for the requested resource has changed.
|
||||
* Suggested client recovery behavior
|
||||
* Follow the redirect.
|
||||
* `400 StatusBadRequest`
|
||||
* Indicates the requested is invalid.
|
||||
* Suggested client recovery behavior:
|
||||
* Do not retry. Fix the request.
|
||||
* `401 StatusUnauthorized`
|
||||
* Indicates that the server can be reached and understood the request, but refuses to take any further action, because the client must provide authorization. If the client has provided authorization, the server is indicating the provided authorization is unsuitable or invalid.
|
||||
* Suggested client recovery behavior
|
||||
* If the user has not supplied authorization information, prompt them for the appropriate credentials
|
||||
* If the user has supplied authorization information, inform them their credentials were rejected and optionally prompt them again.
|
||||
* `403 StatusForbidden`
|
||||
* Indicates that the server can be reached and understood the request, but refuses to take any further action, because it is configured to deny access for some reason to the requested resource by the client.
|
||||
* Suggested client recovery behavior
|
||||
* Do not retry. Fix the request.
|
||||
* `404 StatusNotFound`
|
||||
* Indicates that the requested resource does not exist.
|
||||
* Suggested client recovery behavior
|
||||
* Do not retry. Fix the request.
|
||||
* `405 StatusMethodNotAllowed`
|
||||
* Indicates that the action the client attempted to perform on the resource was not supported by the code.
|
||||
* Suggested client recovery behavior
|
||||
* Do not retry. Fix the request.
|
||||
* `409 StatusConflict`
|
||||
* Indicates that either the resource the client attempted to create already exists or the requested update operation cannot be completed due to a conflict.
|
||||
* Suggested client recovery behavior
|
||||
* * If creating a new resource
|
||||
* * Either change the identifier and try again, or GET and compare the fields in the pre-existing object and issue a PUT/update to modify the existing object.
|
||||
* * If updating an existing resource:
|
||||
* See `Conflict` from the `status` response section below on how to retrieve more information about the nature of the conflict.
|
||||
* GET and compare the fields in the pre-existing object, merge changes (if still valid according to preconditions), and retry with the updated request (including `ResourceVersion`).
|
||||
* `422 StatusUnprocessableEntity`
|
||||
* Indicates that the requested create or update operation cannot be completed due to invalid data provided as part of the request.
|
||||
* Suggested client recovery behavior
|
||||
* Do not retry. Fix the request.
|
||||
* `429 StatusTooManyRequests`
|
||||
* Indicates that the either the client rate limit has been exceeded or the server has received more requests then it can process.
|
||||
* Suggested client recovery behavior:
|
||||
* Read the `Retry-After` HTTP header from the response, and wait at least that long before retrying.
|
||||
* `500 StatusInternalServerError`
|
||||
* Indicates that the server can be reached and understood the request, but either an unexpected internal error occurred and the outcome of the call is unknown, or the server cannot complete the action in a reasonable time (this maybe due to temporary server load or a transient communication issue with another server).
|
||||
* Suggested client recovery behavior:
|
||||
* Retry with exponential backoff.
|
||||
* `503 StatusServiceUnavailable`
|
||||
* Indicates that required service is unavailable.
|
||||
* Suggested client recovery behavior:
|
||||
* Retry with exponential backoff.
|
||||
* `504 StatusServerTimeout`
|
||||
* Indicates that the request could not be completed within the given time. Clients can get this response ONLY when they specified a timeout param in the request.
|
||||
* Suggested client recovery behavior:
|
||||
* Increase the value of the timeout param and retry with exponential backoff
|
||||
|
||||
## Response Status Kind
|
||||
|
||||
Kubernetes will always return the `Status` kind from any API endpoint when an error occurs.
|
||||
Clients SHOULD handle these types of objects when appropriate.
|
||||
|
||||
A `Status` kind will be returned by the API in two cases:
|
||||
|
||||
1. When an operation is not successful (i.e. when the server would return a non 2xx HTTP status code).
|
||||
2. When a HTTP `DELETE` call is successful.
|
||||
|
||||
The status object is encoded as JSON and provided as the body of the response. The status object contains fields for humans and machine consumers of the API to get more detailed information for the cause of the failure. The information in the status object supplements, but does not override, the HTTP status code's meaning. When fields in the status object have the same meaning as generally defined HTTP headers and that header is returned with the response, the header should be considered as having higher priority.
|
||||
|
||||
**Example:**
|
||||
|
||||
```shell
|
||||
$ curl -v -k -H "Authorization: Bearer WhCDvq4VPpYhrcfmF6ei7V9qlbqTubUc" https://10.240.122.184:443/api/v1/namespaces/default/pods/grafana
|
||||
|
||||
> GET /api/v1/namespaces/default/pods/grafana HTTP/1.1
|
||||
> User-Agent: curl/7.26.0
|
||||
> Host: 10.240.122.184
|
||||
> Accept: */*
|
||||
> Authorization: Bearer WhCDvq4VPpYhrcfmF6ei7V9qlbqTubUc
|
||||
>
|
||||
|
||||
< HTTP/1.1 404 Not Found
|
||||
< Content-Type: application/json
|
||||
< Date: Wed, 20 May 2015 18:10:42 GMT
|
||||
< Content-Length: 232
|
||||
<
|
||||
{
|
||||
"kind": "Status",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"status": "Failure",
|
||||
"message": "pods \"grafana\" not found",
|
||||
"reason": "NotFound",
|
||||
"details": {
|
||||
"name": "grafana",
|
||||
"kind": "pods"
|
||||
},
|
||||
"code": 404
|
||||
}
|
||||
```
|
||||
|
||||
`status` field contains one of two possible values:
|
||||
* `Success`
|
||||
* `Failure`
|
||||
|
||||
`message` may contain human-readable description of the error
|
||||
|
||||
`reason` may contain a machine-readable, one-word, CamelCase description of why this operation is in the `Failure` status. If this value is empty there is no information available. The `reason` clarifies an HTTP status code but does not override it.
|
||||
|
||||
`details` may contain extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type.
|
||||
|
||||
Possible values for the `reason` and `details` fields:
|
||||
|
||||
* `BadRequest`
|
||||
* Indicates that the request itself was invalid, because the request doesn't make any sense, for example deleting a read-only object.
|
||||
* This is different than `status reason` `Invalid` above which indicates that the API call could possibly succeed, but the data was invalid.
|
||||
* API calls that return BadRequest can never succeed.
|
||||
* Http status code: `400 StatusBadRequest`
|
||||
* `Unauthorized`
|
||||
* Indicates that the server can be reached and understood the request, but refuses to take any further action without the client providing appropriate authorization. If the client has provided authorization, this error indicates the provided credentials are insufficient or invalid.
|
||||
* Details (optional):
|
||||
* `kind string`
|
||||
* The kind attribute of the unauthorized resource (on some operations may differ from the requested resource).
|
||||
* `name string`
|
||||
* The identifier of the unauthorized resource.
|
||||
* HTTP status code: `401 StatusUnauthorized`
|
||||
* `Forbidden`
|
||||
* Indicates that the server can be reached and understood the request, but refuses to take any further action, because it is configured to deny access for some reason to the requested resource by the client.
|
||||
* Details (optional):
|
||||
* `kind string`
|
||||
* The kind attribute of the forbidden resource (on some operations may differ from the requested resource).
|
||||
* `name string`
|
||||
* The identifier of the forbidden resource.
|
||||
* HTTP status code: `403 StatusForbidden`
|
||||
* `NotFound`
|
||||
* Indicates that one or more resources required for this operation could not be found.
|
||||
* Details (optional):
|
||||
* `kind string`
|
||||
* The kind attribute of the missing resource (on some operations may differ from the requested resource).
|
||||
* `name string`
|
||||
* The identifier of the missing resource.
|
||||
* HTTP status code: `404 StatusNotFound`
|
||||
* `AlreadyExists`
|
||||
* Indicates that the resource you are creating already exists.
|
||||
* Details (optional):
|
||||
* `kind string`
|
||||
* The kind attribute of the conflicting resource.
|
||||
* `name string`
|
||||
* The identifier of the conflicting resource.
|
||||
* HTTP status code: `409 StatusConflict`
|
||||
* `Conflict`
|
||||
* Indicates that the requested update operation cannot be completed due to a conflict. The client may need to alter the request. Each resource may define custom details that indicate the nature of the conflict.
|
||||
* HTTP status code: `409 StatusConflict`
|
||||
* `Invalid`
|
||||
* Indicates that the requested create or update operation cannot be completed due to invalid data provided as part of the request.
|
||||
* Details (optional):
|
||||
* `kind string`
|
||||
* the kind attribute of the invalid resource
|
||||
* `name string`
|
||||
* the identifier of the invalid resource
|
||||
* `causes`
|
||||
* One or more `StatusCause` entries indicating the data in the provided resource that was invalid. The `reason`, `message`, and `field` attributes will be set.
|
||||
* HTTP status code: `422 StatusUnprocessableEntity`
|
||||
* `Timeout`
|
||||
* Indicates that the request could not be completed within the given time. Clients may receive this response if the server has decided to rate limit the client, or if the server is overloaded and cannot process the request at this time.
|
||||
* Http status code: `429 TooManyRequests`
|
||||
* The server should set the `Retry-After` HTTP header and return `retryAfterSeconds` in the details field of the object. A value of `0` is the default.
|
||||
* `ServerTimeout`
|
||||
* Indicates that the server can be reached and understood the request, but cannot complete the action in a reasonable time. This maybe due to temporary server load or a transient communication issue with another server.
|
||||
* Details (optional):
|
||||
* `kind string`
|
||||
* The kind attribute of the resource being acted on.
|
||||
* `name string`
|
||||
* The operation that is being attempted.
|
||||
* The server should set the `Retry-After` HTTP header and return `retryAfterSeconds` in the details field of the object. A value of `0` is the default.
|
||||
* Http status code: `504 StatusServerTimeout`
|
||||
* `MethodNotAllowed`
|
||||
* Indicates that the action the client attempted to perform on the resource was not supported by the code.
|
||||
* For instance, attempting to delete a resource that can only be created.
|
||||
* API calls that return MethodNotAllowed can never succeed.
|
||||
* Http status code: `405 StatusMethodNotAllowed`
|
||||
* `InternalError`
|
||||
* Indicates that an internal error occurred, it is unexpected and the outcome of the call is unknown.
|
||||
* Details (optional):
|
||||
* `causes`
|
||||
* The original error.
|
||||
* Http status code: `500 StatusInternalServerError`
|
||||
|
||||
`code` may contain the suggested HTTP return code for this status.
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
Events are complementary to status information, since they can provide some historical information about status and occurrences in addition to current or previous status. Generate events for situations users or administrators should be alerted about.
|
||||
|
||||
Choose a unique, specific, short, CamelCase reason for each event category. For example, `FreeDiskSpaceInvalid` is a good event reason because it is likely to refer to just one situation, but `Started` is not a good reason because it doesn't sufficiently indicate what started, even when combined with other event fields.
|
||||
|
||||
`Error creating foo` or `Error creating foo %s` would be appropriate for an event message, with the latter being preferable, since it is more informational.
|
||||
|
||||
Accumulate repeated events in the client, especially for frequent events, to reduce data volume, load on the system, and noise exposed to users.
|
||||
|
||||
## Naming conventions
|
||||
|
||||
* Go field names must be CamelCase. JSON field names must be camelCase. Other than capitalization of the initial letter, the two should almost always match. No underscores nor dashes in either.
|
||||
* Field and resource names should be declarative, not imperative (DoSomething, SomethingDoer, DoneBy, DoneAt).
|
||||
* `Minion` has been deprecated in favor of `Node`. Use `Node` where referring to the node resource in the context of the cluster. Use `Host` where referring to properties of the individual physical/virtual system, such as `hostname`, `hostPath`, `hostNetwork`, etc.
|
||||
* `FooController` is a deprecated kind naming convention. Name the kind after the thing being controlled instead (e.g., `Job` rather than `JobController`).
|
||||
* The name of a field that specifies the time at which `something` occurs should be called `somethingTime`. Do not use `stamp` (e.g., `creationTimestamp`).
|
||||
* We use the `fooSeconds` convention for durations, as discussed in the [units subsection](#units).
|
||||
* `fooPeriodSeconds` is preferred for periodic intervals and other waiting periods (e.g., over `fooIntervalSeconds`).
|
||||
* `fooTimeoutSeconds` is preferred for inactivity/unresponsiveness deadlines.
|
||||
* `fooDeadlineSeconds` is preferred for activity completion deadlines.
|
||||
* Do not use abbreviations in the API, except where they are extremely commonly used, such as "id", "args", or "stdin".
|
||||
* Acronyms should similarly only be used when extremely commonly known. All letters in the acronym should have the same case, using the appropriate case for the situation. For example, at the beginning of a field name, the acronym should be all lowercase, such as "httpGet". Where used as a constant, all letters should be uppercase, such as "TCP" or "UDP".
|
||||
* The name of a field referring to another resource of kind `Foo` by name should be called `fooName`. The name of a field referring to another resource of kind `Foo` by ObjectReference (or subset thereof) should be called `fooRef`.
|
||||
* More generally, include the units and/or type in the field name if they could be ambiguous and they are not specified by the value or value type.
|
||||
|
||||
## Label, selector, and annotation conventions
|
||||
|
||||
Labels are the domain of users. They are intended to facilitate organization and management of API resources using attributes that are meaningful to users, as opposed to meaningful to the system. Think of them as user-created mp3 or email inbox labels, as opposed to the directory structure used by a program to store its data. The former is enables the user to apply an arbitrary ontology, whereas the latter is implementation-centric and inflexible. Users will use labels to select resources to operate on, display label values in CLI/UI columns, etc. Users should always retain full power and flexibility over the label schemas they apply to labels in their namespaces.
|
||||
|
||||
However, we should support conveniences for common cases by default. For example, what we now do in ReplicationController is automatically set the RC's selector and labels to the labels in the pod template by default, if they are not already set. That ensures that the selector will match the template, and that the RC can be managed using the same labels as the pods it creates. Note that once we generalize selectors, it won't necessarily be possible to unambiguously generate labels that match an arbitrary selector.
|
||||
|
||||
If the user wants to apply additional labels to the pods that it doesn't select upon, such as to facilitate adoption of pods or in the expectation that some label values will change, they can set the selector to a subset of the pod labels. Similarly, the RC's labels could be initialized to a subset of the pod template's labels, or could include additional/different labels.
|
||||
|
||||
For disciplined users managing resources within their own namespaces, it's not that hard to consistently apply schemas that ensure uniqueness. One just needs to ensure that at least one value of some label key in common differs compared to all other comparable resources. We could/should provide a verification tool to check that. However, development of conventions similar to the examples in [Labels](/{{page.version}}/docs/user-guide/labels) make uniqueness straightforward. Furthermore, relatively narrowly used namespaces (e.g., per environment, per application) can be used to reduce the set of resources that could potentially cause overlap.
|
||||
|
||||
In cases where users could be running misc. examples with inconsistent schemas, or where tooling or components need to programmatically generate new objects to be selected, there needs to be a straightforward way to generate unique label sets. A simple way to ensure uniqueness of the set is to ensure uniqueness of a single label value, such as by using a resource name, uid, resource hash, or generation number.
|
||||
|
||||
Problems with uids and hashes, however, include that they have no semantic meaning to the user, are not memorable nor readily recognizable, and are not predictable. Lack of predictability obstructs use cases such as creation of a replication controller from a pod, such as people want to do when exploring the system, bootstrapping a self-hosted cluster, or deletion and re-creation of a new RC that adopts the pods of the previous one, such as to rename it. Generation numbers are more predictable and much clearer, assuming there is a logical sequence. Fortunately, for deployments that's the case. For jobs, use of creation timestamps is common internally. Users should always be able to turn off auto-generation, in order to permit some of the scenarios described above. Note that auto-generated labels will also become one more field that needs to be stripped out when cloning a resource, within a namespace, in a new namespace, in a new cluster, etc., and will need to be ignored around when updating a resource via patch or read-modify-write sequence.
|
||||
|
||||
Inclusion of a system prefix in a label key is fairly hostile to UX. A prefix is only necessary in the case that the user cannot choose the label key, in order to avoid collisions with user-defined labels. However, I firmly believe that the user should always be allowed to select the label keys to use on their resources, so it should always be possible to override default label keys.
|
||||
|
||||
Therefore, resources supporting auto-generation of unique labels should have a `uniqueLabelKey` field, so that the user could specify the key if they wanted to, but if unspecified, it could be set by default, such as to the resource type, like job, deployment, or replicationController. The value would need to be at least spatially unique, and perhaps temporally unique in the case of job.
|
||||
|
||||
Annotations have very different intended usage from labels. We expect them to be primarily generated and consumed by tooling and system extensions. I'm inclined to generalize annotations to permit them to directly store arbitrary json. Rigid names and name prefixes make sense, since they are analogous to API fields.
|
||||
|
||||
In fact, in-development API fields, including those used to represent fields of newer alpha/beta API versions in the older stable storage version, may be represented as annotations with the form `something.alpha.kubernetes.io/name` or `something.beta.kubernetes.io/name` (depending on our confidence in it). For example `net.alpha.kubernetes.io/policy` might represent an experimental network policy field.
|
||||
|
||||
Other advice regarding use of labels, annotations, and other generic map keys by Kubernetes components and tools:
|
||||
|
||||
- Key names should be all lowercase, with words separated by dashes, such as `desired-replicas`
|
||||
- Prefix the key with `kubernetes.io/` or `foo.kubernetes.io/`, preferably the latter if the label/annotation is specific to `foo`
|
||||
- For instance, prefer `service-account.kubernetes.io/name` over `kubernetes.io/service-account.name`
|
||||
- Use annotations to store API extensions that the controller responsible for the resource doesn't need to know about, experimental fields that aren't intended to be generally used API fields, etc. Beware that annotations aren't automatically handled by the API conversion machinery.
|
|
@ -0,0 +1,584 @@
|
|||
|
||||
Before attempting a change to the API, you should familiarize yourself
|
||||
with a number of existing API types and with the [API
|
||||
conventions](/{{page.version}}/docs/devel/api-conventions). If creating a new API
|
||||
type/resource, we also recommend that you first send a PR containing
|
||||
just a proposal for the new API types, and that you initially target
|
||||
the extensions API (pkg/apis/extensions).
|
||||
|
||||
The Kubernetes API has two major components - the internal structures and
|
||||
the versioned APIs. The versioned APIs are intended to be stable, while the
|
||||
internal structures are implemented to best reflect the needs of the Kubernetes
|
||||
code itself.
|
||||
|
||||
What this means for API changes is that you have to be somewhat thoughtful in
|
||||
how you approach changes, and that you have to touch a number of pieces to make
|
||||
a complete change. This document aims to guide you through the process, though
|
||||
not all API changes will need all of these steps.
|
||||
|
||||
## Operational overview
|
||||
|
||||
It is important to have a high level understanding of the API system used in
|
||||
Kubernetes in order to navigate the rest of this document.
|
||||
|
||||
As mentioned above, the internal representation of an API object is decoupled
|
||||
from any one API version. This provides a lot of freedom to evolve the code,
|
||||
but it requires robust infrastructure to convert between representations. There
|
||||
are multiple steps in processing an API operation - even something as simple as
|
||||
a GET involves a great deal of machinery.
|
||||
|
||||
The conversion process is logically a "star" with the internal form at the
|
||||
center. Every versioned API can be converted to the internal form (and
|
||||
vice-versa), but versioned APIs do not convert to other versioned APIs directly.
|
||||
This sounds like a heavy process, but in reality we do not intend to keep more
|
||||
than a small number of versions alive at once. While all of the Kubernetes code
|
||||
operates on the internal structures, they are always converted to a versioned
|
||||
form before being written to storage (disk or etcd) or being sent over a wire.
|
||||
Clients should consume and operate on the versioned APIs exclusively.
|
||||
|
||||
To demonstrate the general process, here is a (hypothetical) example:
|
||||
|
||||
1. A user POSTs a `Pod` object to `/api/v7beta1/...`
|
||||
2. The JSON is unmarshalled into a `v7beta1.Pod` structure
|
||||
3. Default values are applied to the `v7beta1.Pod`
|
||||
4. The `v7beta1.Pod` is converted to an `api.Pod` structure
|
||||
5. The `api.Pod` is validated, and any errors are returned to the user
|
||||
6. The `api.Pod` is converted to a `v6.Pod` (because v6 is the latest stable
|
||||
version)
|
||||
7. The `v6.Pod` is marshalled into JSON and written to etcd
|
||||
|
||||
Now that we have the `Pod` object stored, a user can GET that object in any
|
||||
supported api version. For example:
|
||||
|
||||
1. A user GETs the `Pod` from `/api/v5/...`
|
||||
2. The JSON is read from etcd and unmarshalled into a `v6.Pod` structure
|
||||
3. Default values are applied to the `v6.Pod`
|
||||
4. The `v6.Pod` is converted to an `api.Pod` structure
|
||||
5. The `api.Pod` is converted to a `v5.Pod` structure
|
||||
6. The `v5.Pod` is marshalled into JSON and sent to the user
|
||||
|
||||
The implication of this process is that API changes must be done carefully and
|
||||
backward-compatibly.
|
||||
|
||||
## On compatibility
|
||||
|
||||
Before talking about how to make API changes, it is worthwhile to clarify what
|
||||
we mean by API compatibility. An API change is considered backward-compatible
|
||||
if it:
|
||||
|
||||
* adds new functionality that is not required for correct behavior (e.g.,
|
||||
does not add a new required field)
|
||||
* does not change existing semantics, including:
|
||||
* default values and behavior
|
||||
* interpretation of existing API types, fields, and values
|
||||
* which fields are required and which are not
|
||||
|
||||
Put another way:
|
||||
|
||||
1. Any API call (e.g. a structure POSTed to a REST endpoint) that worked before
|
||||
your change must work the same after your change.
|
||||
2. Any API call that uses your change must not cause problems (e.g. crash or
|
||||
degrade behavior) when issued against servers that do not include your change.
|
||||
3. It must be possible to round-trip your change (convert to different API
|
||||
versions and back) with no loss of information.
|
||||
4. Existing clients need not be aware of your change in order for them to continue
|
||||
to function as they did previously, even when your change is utilized
|
||||
|
||||
If your change does not meet these criteria, it is not considered strictly
|
||||
compatible.
|
||||
|
||||
Let's consider some examples. In a hypothetical API (assume we're at version
|
||||
v6), the `Frobber` struct looks something like this:
|
||||
|
||||
```go
|
||||
// API v6.
|
||||
type Frobber struct {
|
||||
Height int `json:"height"`
|
||||
Param string `json:"param"`
|
||||
}
|
||||
```
|
||||
|
||||
You want to add a new `Width` field. It is generally safe to add new fields
|
||||
without changing the API version, so you can simply change it to:
|
||||
|
||||
```go
|
||||
// Still API v6.
|
||||
type Frobber struct {
|
||||
Height int `json:"height"`
|
||||
Width int `json:"width"`
|
||||
Param string `json:"param"`
|
||||
}
|
||||
```
|
||||
|
||||
The onus is on you to define a sane default value for `Width` such that rule #1
|
||||
above is true - API calls and stored objects that used to work must continue to
|
||||
work.
|
||||
|
||||
For your next change you want to allow multiple `Param` values. You can not
|
||||
simply change `Param string` to `Params []string` (without creating a whole new
|
||||
API version) - that fails rules #1 and #2. You can instead do something like:
|
||||
|
||||
```go
|
||||
// Still API v6, but kind of clumsy.
|
||||
type Frobber struct {
|
||||
Height int `json:"height"`
|
||||
Width int `json:"width"`
|
||||
Param string `json:"param"` // the first param
|
||||
ExtraParams []string `json:"params"` // additional params
|
||||
}
|
||||
```
|
||||
|
||||
Now you can satisfy the rules: API calls that provide the old style `Param`
|
||||
will still work, while servers that don't understand `ExtraParams` can ignore
|
||||
it. This is somewhat unsatisfying as an API, but it is strictly compatible.
|
||||
|
||||
Part of the reason for versioning APIs and for using internal structs that are
|
||||
distinct from any one version is to handle growth like this. The internal
|
||||
representation can be implemented as:
|
||||
|
||||
```go
|
||||
// Internal, soon to be v7beta1.
|
||||
type Frobber struct {
|
||||
Height int
|
||||
Width int
|
||||
Params []string
|
||||
}
|
||||
```
|
||||
|
||||
The code that converts to/from versioned APIs can decode this into the somewhat
|
||||
uglier (but compatible!) structures. Eventually, a new API version, let's call
|
||||
it v7beta1, will be forked and it can use the clean internal structure.
|
||||
|
||||
We've seen how to satisfy rules #1 and #2. Rule #3 means that you can not
|
||||
extend one versioned API without also extending the others. For example, an
|
||||
API call might POST an object in API v7beta1 format, which uses the cleaner
|
||||
`Params` field, but the API server might store that object in trusty old v6
|
||||
form (since v7beta1 is "beta"). When the user reads the object back in the
|
||||
v7beta1 API it would be unacceptable to have lost all but `Params[0]`. This
|
||||
means that, even though it is ugly, a compatible change must be made to the v6
|
||||
API.
|
||||
|
||||
However, this is very challenging to do correctly. It often requires
|
||||
multiple representations of the same information in the same API resource, which
|
||||
need to be kept in sync in the event that either is changed. For example,
|
||||
let's say you decide to rename a field within the same API version. In this case,
|
||||
you add units to `height` and `width`. You implement this by adding duplicate
|
||||
fields:
|
||||
|
||||
```go
|
||||
type Frobber struct {
|
||||
Height *int `json:"height"`
|
||||
Width *int `json:"width"`
|
||||
HeightInInches *int `json:"heightInInches"`
|
||||
WidthInInches *int `json:"widthInInches"`
|
||||
}
|
||||
```
|
||||
|
||||
You convert all of the fields to pointers in order to distinguish between unset and
|
||||
set to 0, and then set each corresponding field from the other in the defaulting
|
||||
pass (e.g., `heightInInches` from `height`, and vice versa), which runs just prior
|
||||
to conversion. That works fine when the user creates a resource from a hand-written
|
||||
configuration -- clients can write either field and read either field, but what about
|
||||
creation or update from the output of GET, or update via PATCH (see
|
||||
[In-place updates](/{{page.version}}/docs/user-guide/managing-deployments/#in-place-updates-of-resources))?
|
||||
In this case, the two fields will conflict, because only one field would be updated
|
||||
in the case of an old client that was only aware of the old field (e.g., `height`).
|
||||
|
||||
Say the client creates:
|
||||
|
||||
```json
|
||||
{
|
||||
"height": 10,
|
||||
"width": 5
|
||||
}
|
||||
```
|
||||
|
||||
and GETs:
|
||||
|
||||
```json
|
||||
{
|
||||
"height": 10,
|
||||
"heightInInches": 10,
|
||||
"width": 5,
|
||||
"widthInInches": 5
|
||||
}
|
||||
```
|
||||
|
||||
then PUTs back:
|
||||
|
||||
```json
|
||||
{
|
||||
"height": 13,
|
||||
"heightInInches": 10,
|
||||
"width": 5,
|
||||
"widthInInches": 5
|
||||
}
|
||||
```
|
||||
|
||||
The update should not fail, because it would have worked before `heightInInches` was added.
|
||||
|
||||
Therefore, when there are duplicate fields, the old field MUST take precedence
|
||||
over the new, and the new field should be set to match by the server upon write.
|
||||
A new client would be aware of the old field as well as the new, and so can ensure
|
||||
that the old field is either unset or is set consistently with the new field. However,
|
||||
older clients would be unaware of the new field. Please avoid introducing duplicate
|
||||
fields due to the complexity they incur in the API.
|
||||
|
||||
A new representation, even in a new API version, that is more expressive than an old one
|
||||
breaks backward compatibility, since clients that only understood the old representation
|
||||
would not be aware of the new representation nor its semantics. Examples of
|
||||
proposals that have run into this challenge include [generalized label
|
||||
selectors](http://issues.k8s.io/341) and [pod-level security
|
||||
context](http://prs.k8s.io/12823).
|
||||
|
||||
As another interesting example, enumerated values cause similar challenges.
|
||||
Adding a new value to an enumerated set is *not* a compatible change. Clients
|
||||
which assume they know how to handle all possible values of a given field will
|
||||
not be able to handle the new values. However, removing value from an
|
||||
enumerated set *can* be a compatible change, if handled properly (treat the
|
||||
removed value as deprecated but allowed). This is actually a special case of
|
||||
a new representation, discussed above.
|
||||
|
||||
## Incompatible API changes
|
||||
|
||||
There are times when this might be OK, but mostly we want changes that
|
||||
meet this definition. If you think you need to break compatibility,
|
||||
you should talk to the Kubernetes team first.
|
||||
|
||||
Breaking compatibility of a beta or stable API version, such as v1, is unacceptable.
|
||||
Compatibility for experimental or alpha APIs is not strictly required, but
|
||||
breaking compatibility should not be done lightly, as it disrupts all users of the
|
||||
feature. Experimental APIs may be removed. Alpha and beta API versions may be deprecated
|
||||
and eventually removed wholesale, as described in the [versioning document](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/versioning.md).
|
||||
Document incompatible changes across API versions under the [conversion tips](/{{page.version}}/docs/api/).
|
||||
|
||||
If your change is going to be backward incompatible or might be a breaking change for API
|
||||
consumers, please send an announcement to `kubernetes-dev@googlegroups.com` before
|
||||
the change gets in. If you are unsure, ask. Also make sure that the change gets documented in
|
||||
the release notes for the next release by labeling the PR with the "release-note" github label.
|
||||
|
||||
If you found that your change accidentally broke clients, it should be reverted.
|
||||
|
||||
In short, the expected API evolution is as follows:
|
||||
|
||||
* `extensions/v1alpha1` ->
|
||||
* `newapigroup/v1alpha1` -> ... -> `newapigroup/v1alphaN` ->
|
||||
* `newapigroup/v1beta1` -> ... -> `newapigroup/v1betaN` ->
|
||||
* `newapigroup/v1` ->
|
||||
* `newapigroup/v2alpha1` -> ...
|
||||
|
||||
While in extensions we have no obligation to move forward with the API at all and may delete or break it at any time.
|
||||
|
||||
While in alpha we expect to move forward with it, but may break it.
|
||||
|
||||
Once in beta we will preserve forward compatibility, but may introduce new versions and delete old ones.
|
||||
|
||||
v1 must be backward-compatible for an extended length of time.
|
||||
|
||||
## Changing versioned APIs
|
||||
|
||||
For most changes, you will probably find it easiest to change the versioned
|
||||
APIs first. This forces you to think about how to make your change in a
|
||||
compatible way. Rather than doing each step in every version, it's usually
|
||||
easier to do each versioned API one at a time, or to do all of one version
|
||||
before starting "all the rest".
|
||||
|
||||
### Edit types.go
|
||||
|
||||
The struct definitions for each API are in `pkg/api/<version>/types.go`. Edit
|
||||
those files to reflect the change you want to make. Note that all types and non-inline
|
||||
fields in versioned APIs must be preceded by descriptive comments - these are used to generate
|
||||
documentation.
|
||||
|
||||
Optional fields should have the `,omitempty` json tag; fields are interpreted as being
|
||||
required otherwise.
|
||||
|
||||
### Edit defaults.go
|
||||
|
||||
If your change includes new fields for which you will need default values, you
|
||||
need to add cases to `pkg/api/<version>/defaults.go`. Of course, since you
|
||||
have added code, you have to add a test: `pkg/api/<version>/defaults_test.go`.
|
||||
|
||||
Do use pointers to scalars when you need to distinguish between an unset value
|
||||
and an automatic zero value. For example,
|
||||
`PodSpec.TerminationGracePeriodSeconds` is defined as `*int64` the go type
|
||||
definition. A zero value means 0 seconds, and a nil value asks the system to
|
||||
pick a default.
|
||||
|
||||
Don't forget to run the tests!
|
||||
|
||||
### Edit conversion.go
|
||||
|
||||
Given that you have not yet changed the internal structs, this might feel
|
||||
premature, and that's because it is. You don't yet have anything to convert to
|
||||
or from. We will revisit this in the "internal" section. If you're doing this
|
||||
all in a different order (i.e. you started with the internal structs), then you
|
||||
should jump to that topic below. In the very rare case that you are making an
|
||||
incompatible change you might or might not want to do this now, but you will
|
||||
have to do more later. The files you want are
|
||||
`pkg/api/<version>/conversion.go` and `pkg/api/<version>/conversion_test.go`.
|
||||
|
||||
Note that the conversion machinery doesn't generically handle conversion of values,
|
||||
such as various kinds of field references and API constants. [The client
|
||||
library](https://releases.k8s.io/{{page.githubbranch}}/pkg/client/unversioned/request.go) has custom conversion code for
|
||||
field references. You also need to add a call to api.Scheme.AddFieldLabelConversionFunc
|
||||
with a mapping function that understands supported translations.
|
||||
|
||||
## Changing the internal structures
|
||||
|
||||
Now it is time to change the internal structs so your versioned changes can be
|
||||
used.
|
||||
|
||||
### Edit types.go
|
||||
|
||||
Similar to the versioned APIs, the definitions for the internal structs are in
|
||||
`pkg/api/types.go`. Edit those files to reflect the change you want to make.
|
||||
Keep in mind that the internal structs must be able to express *all* of the
|
||||
versioned APIs.
|
||||
|
||||
## Edit validation.go
|
||||
|
||||
Most changes made to the internal structs need some form of input validation.
|
||||
Validation is currently done on internal objects in
|
||||
`pkg/api/validation/validation.go`. This validation is the one of the first
|
||||
opportunities we have to make a great user experience - good error messages and
|
||||
thorough validation help ensure that users are giving you what you expect and,
|
||||
when they don't, that they know why and how to fix it. Think hard about the
|
||||
contents of `string` fields, the bounds of `int` fields and the
|
||||
requiredness/optionalness of fields.
|
||||
|
||||
Of course, code needs tests - `pkg/api/validation/validation_test.go`.
|
||||
|
||||
## Edit version conversions
|
||||
|
||||
At this point you have both the versioned API changes and the internal
|
||||
structure changes done. If there are any notable differences - field names,
|
||||
types, structural change in particular - you must add some logic to convert
|
||||
versioned APIs to and from the internal representation. If you see errors from
|
||||
the `serialization_test`, it may indicate the need for explicit conversions.
|
||||
|
||||
Performance of conversions very heavily influence performance of apiserver.
|
||||
Thus, we are auto-generating conversion functions that are much more efficient
|
||||
than the generic ones (which are based on reflections and thus are highly
|
||||
inefficient).
|
||||
|
||||
The conversion code resides with each versioned API. There are two files:
|
||||
|
||||
- `pkg/api/<version>/conversion.go` containing manually written conversion
|
||||
functions
|
||||
- `pkg/api/<version>/conversion_generated.go` containing auto-generated
|
||||
conversion functions
|
||||
- `pkg/apis/extensions/<version>/conversion.go` containing manually written
|
||||
conversion functions
|
||||
- `pkg/apis/extensions/<version>/conversion_generated.go` containing
|
||||
auto-generated conversion functions
|
||||
|
||||
Since auto-generated conversion functions are using manually written ones,
|
||||
those manually written should be named with a defined convention, i.e. a function
|
||||
converting type X in pkg a to type Y in pkg b, should be named:
|
||||
`convert_a_X_To_b_Y`.
|
||||
|
||||
Also note that you can (and for efficiency reasons should) use auto-generated
|
||||
conversion functions when writing your conversion functions.
|
||||
|
||||
Once all the necessary manually written conversions are added, you need to
|
||||
regenerate auto-generated ones. To regenerate them, run:
|
||||
|
||||
```shell
|
||||
hack/update-generated-conversions.sh
|
||||
|
||||
```
|
||||
If running the above script is impossible due to compile errors, the easiest
|
||||
workaround is to comment out the code causing errors and let the script to
|
||||
regenerate it. If the auto-generated conversion methods are not used by the
|
||||
manually-written ones, it's fine to just remove the whole file and let the
|
||||
generator to create it from scratch.
|
||||
|
||||
Unsurprisingly, adding manually written conversion also requires you to add tests to
|
||||
`pkg/api/<version>/conversion_test.go`.
|
||||
|
||||
## Edit deep copy files
|
||||
|
||||
At this point you have both the versioned API changes and the internal
|
||||
structure changes done. You now need to generate code to handle deep copy
|
||||
of your versioned api objects.
|
||||
|
||||
The deep copy code resides with each versioned API:
|
||||
|
||||
- `pkg/api/<version>/deep_copy_generated.go` containing auto-generated copy functions
|
||||
- `pkg/apis/extensions/<version>/deep_copy_generated.go` containing auto-generated copy functions
|
||||
|
||||
To regenerate them, run:
|
||||
|
||||
```shell
|
||||
hack/update-generated-deep-copies.sh
|
||||
```
|
||||
|
||||
## Edit json (un)marshaling code
|
||||
|
||||
We are auto-generating code for marshaling and unmarshaling json representation
|
||||
of api objects - this is to improve the overall system performance.
|
||||
|
||||
The auto-generated code resides with each versioned API:
|
||||
|
||||
- `pkg/api/<version>/types.generated.go`
|
||||
- `pkg/apis/extensions/<version>/types.generated.go`
|
||||
|
||||
To regenerate them, run:
|
||||
|
||||
```shell
|
||||
hack/update-codecgen.sh
|
||||
```
|
||||
|
||||
## Making a new API Group
|
||||
|
||||
This section is under construction, as we make the tooling completely generic.
|
||||
|
||||
At the moment, you'll have to make a new directory under pkg/apis/; copy the
|
||||
directory structure from pkg/apis/extensions. Add the new group/version to all
|
||||
of the hack/{verify,update}-generated-{deep-copy,conversions,swagger}.sh files
|
||||
in the appropriate places--it should just require adding your new group/version
|
||||
to a bash array. You will also need to make sure your new types are imported by
|
||||
the generation commands (cmd/gendeepcopy/ & cmd/genconversion). These
|
||||
instructions may not be complete and will be updated as we gain experience.
|
||||
|
||||
Adding API groups outside of the pkg/apis/ directory is not currently supported,
|
||||
but is clearly desirable. The deep copy & conversion generators need to work by
|
||||
parsing go files instead of by reflection; then they will be easy to point at
|
||||
arbitrary directories: see issue [#13775](http://issue.k8s.io/13775).
|
||||
|
||||
## Update the fuzzer
|
||||
|
||||
Part of our testing regimen for APIs is to "fuzz" (fill with random values) API
|
||||
objects and then convert them to and from the different API versions. This is
|
||||
a great way of exposing places where you lost information or made bad
|
||||
assumptions. If you have added any fields which need very careful formatting
|
||||
(the test does not run validation) or if you have made assumptions such as
|
||||
"this slice will always have at least 1 element", you may get an error or even
|
||||
a panic from the `serialization_test`. If so, look at the diff it produces (or
|
||||
the backtrace in case of a panic) and figure out what you forgot. Encode that
|
||||
into the fuzzer's custom fuzz functions. Hint: if you added defaults for a field,
|
||||
that field will need to have a custom fuzz function that ensures that the field is
|
||||
fuzzed to a non-empty value.
|
||||
|
||||
The fuzzer can be found in `pkg/api/testing/fuzzer.go`.
|
||||
|
||||
## Update the semantic comparisons
|
||||
|
||||
VERY VERY rarely is this needed, but when it hits, it hurts. In some rare
|
||||
cases we end up with objects (e.g. resource quantities) that have morally
|
||||
equivalent values with different bitwise representations (e.g. value 10 with a
|
||||
base-2 formatter is the same as value 0 with a base-10 formatter). The only way
|
||||
Go knows how to do deep-equality is through field-by-field bitwise comparisons.
|
||||
This is a problem for us.
|
||||
|
||||
The first thing you should do is try not to do that. If you really can't avoid
|
||||
this, I'd like to introduce you to our semantic DeepEqual routine. It supports
|
||||
custom overrides for specific types - you can find that in `pkg/api/helpers.go`.
|
||||
|
||||
There's one other time when you might have to touch this: unexported fields.
|
||||
You see, while Go's `reflect` package is allowed to touch unexported fields, us
|
||||
mere mortals are not - this includes semantic DeepEqual. Fortunately, most of
|
||||
our API objects are "dumb structs" all the way down - all fields are exported
|
||||
(start with a capital letter) and there are no unexported fields. But sometimes
|
||||
you want to include an object in our API that does have unexported fields
|
||||
somewhere in it (for example, `time.Time` has unexported fields). If this hits
|
||||
you, you may have to touch the semantic DeepEqual customization functions.
|
||||
|
||||
## Implement your change
|
||||
|
||||
Now you have the API all changed - go implement whatever it is that you're
|
||||
doing!
|
||||
|
||||
## Write end-to-end tests
|
||||
|
||||
Check out the [E2E docs](/{{page.version}}/docs/devel/e2e-tests) for detailed information about how to write end-to-end
|
||||
tests for your feature.
|
||||
|
||||
## Examples and docs
|
||||
|
||||
At last, your change is done, all unit tests pass, e2e passes, you're done,
|
||||
right? Actually, no. You just changed the API. If you are touching an
|
||||
existing facet of the API, you have to try *really* hard to make sure that
|
||||
*all* the examples and docs are updated. There's no easy way to do this, due
|
||||
in part to JSON and YAML silently dropping unknown fields. You're clever -
|
||||
you'll figure it out. Put `grep` or `ack` to good use.
|
||||
|
||||
If you added functionality, you should consider documenting it and/or writing
|
||||
an example to illustrate your change.
|
||||
|
||||
Make sure you update the swagger API spec by running:
|
||||
|
||||
```shell
|
||||
hack/update-swagger-spec.sh
|
||||
```
|
||||
|
||||
The API spec changes should be in a commit separate from your other changes.
|
||||
|
||||
## Adding new REST objects
|
||||
|
||||
TODO(smarterclayton): write this.
|
||||
|
||||
## Alpha, Beta, and Stable Versions
|
||||
|
||||
New feature development proceeds through a series of stages of increasing maturity:
|
||||
|
||||
- Development level
|
||||
- Object Versioning: no convention
|
||||
- Availability: not commited to main kubernetes repo, and thus not available in offical releases
|
||||
- Audience: other developers closely collaborating on a feature or proof-of-concept
|
||||
- Upgradeability, Reliability, Completeness, and Support: no requirements or guarantees
|
||||
- Alpha level
|
||||
- Object Versioning: API version name contains `alpha` (e.g. `v1alpha1`)
|
||||
- Availability: committed to main kubernetes repo; appears in an official release; feature is
|
||||
disabled by default, but may be enabled by flag
|
||||
- Audience: developers and expert users interested in giving early feedback on features
|
||||
- Completeness: some API operations, CLI commands, or UI support may not be implemented; the API
|
||||
need not have had an *API review* (an intensive and targeted review of the API, on top of a normal
|
||||
code review)
|
||||
- Upgradeability: the object schema and semantics may change in a later software release, without
|
||||
any provision for preserving objects in an existing cluster;
|
||||
removing the upgradability concern allows developers to make rapid progress; in particular,
|
||||
API versions can increment faster than the minor release cadence and the developer need not
|
||||
maintain multiple versions; developers should still increment the API version when object schema
|
||||
or semantics change in an [incompatible way](#on-compatibility)
|
||||
- Cluster Reliability: because the feature is relatively new, and may lack complete end-to-end
|
||||
tests, enabling the feature via a flag might expose bugs with destabilize the cluster (e.g. a
|
||||
bug in a control loop might rapidly create excessive numbers of object, exhausting API storage).
|
||||
- Support: there is *no commitment* from the project to complete the feature; the feature may be
|
||||
dropped entirely in a later software release
|
||||
- Recommended Use Cases: only in short-lived testing clusters, due to complexity of upgradeability
|
||||
and lack of long-term support and lack of upgradability.
|
||||
- Beta level:
|
||||
- Object Versioning: API version name contains `beta` (e.g. `v2beta3`)
|
||||
- Availability: in official Kubernetes releases, and enabled by default
|
||||
- Audience: users interested in providing feedback on features
|
||||
- Completeness: all API operations, CLI commands, and UI support should be implemented; end-to-end
|
||||
tests complete; the API has had a thorough API review and is thought to be complete, though use
|
||||
during beta may frequently turn up API issues not thought of during review
|
||||
- Upgradeability: the object schema and semantics may change in a later software release; when
|
||||
this happens, an upgrade path will be documentedr; in some cases, objects will be automatically
|
||||
converted to the new version; in other cases, a manual upgrade may be necessary; a manual
|
||||
upgrade may require downtime for anything relying on the new feature, and may require
|
||||
manual conversion of objects to the new version; when manual conversion is necessary, the
|
||||
project will provide documentation on the process (for an example, see [v1 conversion
|
||||
tips](/{{page.version}}/docs/api/))
|
||||
- Cluster Reliability: since the feature has e2e tests, enabling the feature via a flag should not
|
||||
create new bugs in unrelated features; because the feature is new, it may have minor bugs
|
||||
- Support: the project commits to complete the feature, in some form, in a subsequent Stable
|
||||
version; typically this will happen within 3 months, but sometimes longer; releases should
|
||||
simultaneously support two consecutive versions (e.g. `v1beta1` and `v1beta2`; or `v1beta2` and
|
||||
`v1`) for at least one minor release cycle (typically 3 months) so that users have enough time
|
||||
to upgrade and migrate objects
|
||||
- Recommended Use Cases: in short-lived testing clusters; in production clusters as part of a
|
||||
short-lived evaluation of the feature in order to provide feedback
|
||||
- Stable level:
|
||||
- Object Versioning: API version `vX` where `X` is an integer (e.g. `v1`)
|
||||
- Availability: in official Kubernetes releases, and enabled by default
|
||||
- Audience: all users
|
||||
- Completeness: same as beta
|
||||
- Upgradeability: only [strictly compatible](#on-compatibility) changes allowed in subsequent
|
||||
software releases
|
||||
- Cluster Reliability: high
|
||||
- Support: API version will continue to be present for many subsequent software releases;
|
||||
- Recommended Use Cases: any
|
|
@ -0,0 +1,101 @@
|
|||
|
||||
Kubernetes uses a variety of automated tools in an attempt to relieve developers of repeptitive, low
|
||||
brain power work. This document attempts to describe these processes.
|
||||
|
||||
|
||||
## Submit Queue
|
||||
|
||||
In an effort to:
|
||||
|
||||
* reduce load on core developers
|
||||
* maintain e2e stability
|
||||
* load test githubs label feature
|
||||
|
||||
We have added an automated [submit-queue](https://github.com/kubernetes/contrib/tree/master/submit-queue)
|
||||
for kubernetes.
|
||||
|
||||
The submit-queue does the following:
|
||||
|
||||
```go
|
||||
for _, pr := range readyToMergePRs() {
|
||||
if testsAreStable() {
|
||||
mergePR(pr)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The status of the submit-queue is [online.](http://submit-queue.k8s.io/)
|
||||
|
||||
### Ready to merge status
|
||||
|
||||
A PR is considered "ready for merging" if it matches the following:
|
||||
|
||||
* it has the `lgtm` label, and that `lgtm` is newer than the latest commit
|
||||
* it has passed the cla pre-submit and has the `cla:yes` label
|
||||
* it has passed the travis and shippable pre-submit tests
|
||||
* one (or all) of
|
||||
* its author is in kubernetes/contrib/submit-queue/whitelist.txt
|
||||
* its author is in contributors.txt via the github API.
|
||||
* the PR has the `ok-to-merge` label
|
||||
* One (or both of)
|
||||
* it has passed the Jenkins e2e test
|
||||
* it has the `e2e-not-required` label
|
||||
|
||||
Note that the combined whitelist/committer list is available at [submit-queue.k8s.io](http://submit-queue.k8s.io)
|
||||
|
||||
### Merge process
|
||||
|
||||
Merges _only_ occur when the `critical builds` (Jenkins e2e for gce, gke, scalability, upgrade) are passing.
|
||||
We're open to including more builds here, let us know...
|
||||
|
||||
Merges are serialized, so only a single PR is merged at a time, to ensure against races.
|
||||
|
||||
If the PR has the `e2e-not-required` label, it is simply merged.
|
||||
If the PR does not have this label, e2e tests are re-run, if these new tests pass, the PR is merged.
|
||||
|
||||
If e2e flakes or is currently buggy, the PR will not be merged, but it will be re-run on the following
|
||||
pass.
|
||||
|
||||
## Github Munger
|
||||
|
||||
We also run a [github "munger"](https://github.com/kubernetes/contrib/tree/master/mungegithub)
|
||||
|
||||
This runs repeatedly over github pulls and issues and runs modular "mungers" similar to "mungedocs"
|
||||
|
||||
Currently this runs:
|
||||
|
||||
* blunderbuss - Tries to automatically find an owner for a PR without an owner, uses mapping file here:
|
||||
https://github.com/kubernetes/contrib/blob/master/mungegithub/blunderbuss.yml
|
||||
* needs-rebase - Adds `needs-rebase` to PRs that aren't currently mergeable, and removes it from those that are.
|
||||
* size - Adds `size/xs` - `size/xxl` labels to PRs
|
||||
* ok-to-test - Adds the `ok-to-test` message to PRs that have an `lgtm` but the e2e-builder would otherwise not test due to whitelist
|
||||
* ping-ci - Attempts to ping the ci systems (Travis/Shippable) if they are missing from a PR.
|
||||
* lgtm-after-commit - Removes the `lgtm` label from PRs where there are commits that are newer than the `lgtm` label
|
||||
|
||||
In the works:
|
||||
* issue-detector - machine learning for determining if an issue that has been filed is a `support` issue, `bug` or `feature`
|
||||
|
||||
Please feel free to unleash your creativity on this tool, send us new mungers that you think will help support the Kubernetes development process.
|
||||
|
||||
## PR builder
|
||||
|
||||
We also run a robotic PR builder that attempts to run e2e tests for each PR.
|
||||
|
||||
Before a PR from an unknown user is run, the PR builder bot (`k8s-bot`) asks to a message from a
|
||||
contributor that a PR is "ok to test", the contributor replies with that message. Contributors can also
|
||||
add users to the whitelist by replying with the message "add to whitelist" ("please" is optional, but
|
||||
remember to treat your robots with kindness...)
|
||||
|
||||
If a PR is approved for testing, and tests either haven't run, or need to be re-run, you can ask the
|
||||
PR builder to re-run the tests. To do this, reply to the PR with a message that begins with `@k8s-bot test this`, this should trigger a re-build/re-test.
|
||||
|
||||
|
||||
## FAQ:
|
||||
|
||||
#### How can I ask my PR to be tested again for Jenkins failures?
|
||||
|
||||
Right now you have to ask a contributor (this may be you!) to re-run the test with "@k8s-bot test this"
|
||||
|
||||
### How can I kick Shippable to re-test on a failure?
|
||||
|
||||
Right now the easiest way is to close and then immediately re-open the PR.
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
This document explains cherry picks are managed on release branches within the
|
||||
Kubernetes projects.
|
||||
|
||||
## Propose a Cherry Pick
|
||||
|
||||
Any contributor can propose a cherry pick of any pull request, like so:
|
||||
|
||||
```shell
|
||||
hack/cherry_pick_pull.sh upstream/release-3.14 98765
|
||||
```
|
||||
|
||||
This will walk you through the steps to propose an automated cherry pick of pull
|
||||
#98765 for remote branch `upstream/release-3.14`.
|
||||
|
||||
## Cherry Pick Review
|
||||
|
||||
Cherry pick pull requests are reviewed differently than normal pull requests. In
|
||||
particular, they may be self-merged by the release branch owner without fanfare,
|
||||
in the case the release branch owner knows the cherry pick was already
|
||||
requested - this should not be the norm, but it may happen.
|
||||
|
||||
[Contributor License Agreements](http://releases.k8s.io/{{page.githubbranch}}/CONTRIBUTING.md) is considered implicit
|
||||
for all code within cherry-pick pull requests, ***unless there is a large
|
||||
conflict***.
|
||||
|
||||
## Searching for Cherry Picks
|
||||
|
||||
Now that we've structured cherry picks as PRs, searching for all cherry-picks
|
||||
against a release is a GitHub query: For example,
|
||||
[this query is all of the v0.21.x cherry-picks](https://github.com/kubernetes/kubernetes/pulls?utf8=%E2%9C%93&q=is%3Apr+%22automated+cherry+pick%22+base%3Arelease-0.21)
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
See github issues with the following labels:
|
||||
* [area/app-config-deployment](https://github.com/kubernetes/kubernetes/labels/area/app-config-deployment)
|
||||
* [component/kubectl](https://github.com/kubernetes/kubernetes/labels/component/kubectl)
|
||||
* [component/clientlib](https://github.com/kubernetes/kubernetes/labels/component/clientlib)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
### Supported
|
||||
|
||||
* [Go](http://releases.k8s.io/{{page.githubbranch}}/pkg/client/)
|
||||
|
||||
### User Contributed
|
||||
|
||||
*Note: Libraries provided by outside parties are supported by their authors, not the core Kubernetes team*
|
||||
|
||||
* [Java (OSGi)](https://bitbucket.org/amdatulabs/amdatu-kubernetes)
|
||||
* [Java (Fabric8, OSGi)](https://github.com/fabric8io/kubernetes-client)
|
||||
* [Ruby](https://github.com/Ch00k/kuber)
|
||||
* [Ruby](https://github.com/abonas/kubeclient)
|
||||
* [PHP](https://github.com/devstub/kubernetes-api-php-client)
|
||||
* [PHP](https://github.com/maclof/kubernetes-client)
|
||||
* [Node.js](https://github.com/tenxcloud/node-kubernetes-client)
|
||||
* [Perl](https://metacpan.org/pod/Net::Kubernetes)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
|
||||
- Bash
|
||||
- https://google-styleguide.googlecode.com/svn/trunk/shell.xml
|
||||
- Ensure that build, release, test, and cluster-management scripts run on OS X
|
||||
- Go
|
||||
- Ensure your code passes the [presubmit checks](/{{page.version}}/docs/devel/development/#hooks)
|
||||
- [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)
|
||||
- [Effective Go](https://golang.org/doc/effective_go)
|
||||
- Comment your code.
|
||||
- [Go's commenting conventions](http://blog.golang.org/godoc-documenting-go-code)
|
||||
- If reviewers ask questions about why the code is the way it is, that's a sign that comments might be helpful.
|
||||
- Command-line flags should use dashes, not underscores
|
||||
- Naming
|
||||
- Please consider package name when selecting an interface name, and avoid redundancy.
|
||||
- e.g.: `storage.Interface` is better than `storage.StorageInterface`.
|
||||
- Do not use uppercase characters, underscores, or dashes in package names.
|
||||
- Please consider parent directory name when choosing a package name.
|
||||
- so pkg/controllers/autoscaler/foo.go should say `package autoscaler` not `package autoscalercontroller`.
|
||||
- Unless there's a good reason, the `package foo` line should match the name of the directory in which the .go file exists.
|
||||
- Importers can use a different name if they need to disambiguate.
|
||||
- Locks should be called `lock` and should never be embedded (always `lock sync.Mutex`). When multiple locks are present, give each lock a distinct name following Go conventions - `stateLock`, `mapLock` etc.
|
||||
- API conventions
|
||||
- [API changes](/{{page.version}}/docs/devel/api_changes)
|
||||
- [API conventions](/{{page.version}}/docs/devel/api-conventions)
|
||||
- [Kubectl conventions](/{{page.version}}/docs/devel/kubectl-conventions)
|
||||
- [Logging conventions](/{{page.version}}/docs/devel/logging)
|
||||
|
||||
Testing conventions
|
||||
|
||||
- All new packages and most new significant functionality must come with unit tests
|
||||
- Table-driven tests are preferred for testing multiple scenarios/inputs; for example, see [TestNamespaceAuthorization](https://releases.k8s.io/{{page.githubbranch}}/test/integration/auth_test.go)
|
||||
- Significant features should come with integration (test/integration) and/or end-to-end (test/e2e) tests
|
||||
- Including new kubectl commands and major features of existing commands
|
||||
- Unit tests must pass on OS X and Windows platforms - if you use Linux specific features, your test case must either be skipped on windows or compiled out (skipped is better when running Linux specific commands, compiled out is required when your code does not compile on Windows).
|
||||
|
||||
Directory and file conventions
|
||||
|
||||
- Avoid package sprawl. Find an appropriate subdirectory for new packages. (See [#4851](http://issues.k8s.io/4851) for discussion.)
|
||||
- Libraries with no more appropriate home belong in new package subdirectories of pkg/util
|
||||
- Avoid general utility packages. Packages called "util" are suspect. Instead, derive a name that describes your desired function. For example, the utility functions dealing with waiting for operations are in the "wait" package and include functionality like Poll. So the full name is wait.Poll
|
||||
- Go source files and directories use underscores, not dashes
|
||||
- Package directories should generally avoid using separators as much as possible (when packages are multiple words, they usually should be in nested subdirectories).
|
||||
- Document directories and filenames should use dashes rather than underscores
|
||||
- Contrived examples that illustrate system features belong in /docs/user-guide or /docs/admin, depending on whether it is a feature primarily intended for users that deploy applications or cluster administrators, respectively. Actual application examples belong in /examples.
|
||||
- Examples should also illustrate [best practices for using the system](/{{page.version}}/docs/user-guide/config-best-practices)
|
||||
- Third-party code
|
||||
- Third-party Go code is managed using Godeps
|
||||
- Other third-party code belongs in /third_party
|
||||
- Third-party code must include licenses
|
||||
- This includes modified third-party code and excerpts, as well
|
||||
|
||||
Coding advice
|
||||
|
||||
- Go
|
||||
- [Go landmines](https://gist.github.com/lavalamp/4bd23295a9f32706a48f)
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
Kubernetes is open source, but many of the people working on it do so as their day job. In order to avoid forcing people to be "at work" effectively 24/7, we want to establish some semi-formal protocols around development. Hopefully these rules make things go more smoothly. If you find that this is not the case, please complain loudly.
|
||||
|
||||
## Patches welcome
|
||||
|
||||
First and foremost: as a potential contributor, your changes and ideas are welcome at any hour of the day or night, weekdays, weekends, and holidays. Please do not ever hesitate to ask a question or send a PR.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All changes must be code reviewed. For non-maintainers this is obvious, since you can't commit anyway. But even for maintainers, we want all changes to get at least one review, preferably (for non-trivial changes obligatorily) from someone who knows the areas the change touches. For non-trivial changes we may want two reviewers. The primary reviewer will make this decision and nominate a second reviewer, if needed. Except for trivial changes, PRs should not be committed until relevant parties (e.g. owners of the subsystem affected by the PR) have had a reasonable chance to look at PR in their local business hours.
|
||||
|
||||
Most PRs will find reviewers organically. If a maintainer intends to be the primary reviewer of a PR they should set themselves as the assignee on GitHub and say so in a reply to the PR. Only the primary reviewer of a change should actually do the merge, except in rare cases (e.g. they are unavailable in a reasonable timeframe).
|
||||
|
||||
If a PR has gone 2 work days without an owner emerging, please poke the PR thread and ask for a reviewer to be assigned.
|
||||
|
||||
Except for rare cases, such as trivial changes (e.g. typos, comments) or emergencies (e.g. broken builds), maintainers should not merge their own changes.
|
||||
|
||||
Expect reviewers to request that you avoid [common go style mistakes](https://github.com/golang/go/wiki/CodeReviewComments) in your PRs.
|
||||
|
||||
## Assigned reviews
|
||||
|
||||
Maintainers can assign reviews to other maintainers, when appropriate. The assignee becomes the shepherd for that PR and is responsible for merging the PR once they are satisfied with it or else closing it. The assignee might request reviews from non-maintainers.
|
||||
|
||||
## Merge hours
|
||||
|
||||
Maintainers will do merges of appropriately reviewed-and-approved changes during their local "business hours" (typically 7:00 am Monday to 5:00 pm (17:00h) Friday). PRs that arrive over the weekend or on holidays will only be merged if there is a very good reason for it and if the code review requirements have been met. Concretely this means that nobody should merge changes immediately before going to bed for the night.
|
||||
|
||||
There may be discussion an even approvals granted outside of the above hours, but merges will generally be deferred.
|
||||
|
||||
If a PR is considered complex or controversial, the merge of that PR should be delayed to give all interested parties in all timezones the opportunity to provide feedback. Concretely, this means that such PRs should be held for 24
|
||||
hours before merging. Of course "complex" and "controversial" are left to the judgment of the people involved, but we trust that part of being a committer is the judgment required to evaluate such things honestly, and not be
|
||||
motivated by your desire (or your cube-mate's desire) to get their code merged. Also see "Holds" below, any reviewer can issue a "hold" to indicate that the PR is in fact complicated or complex and deserves further review.
|
||||
|
||||
PRs that are incorrectly judged to be merge-able, may be reverted and subject to re-review, if subsequent reviewers believe that they in fact are controversial or complex.
|
||||
|
||||
|
||||
## Holds
|
||||
|
||||
Any maintainer or core contributor who wants to review a PR but does not have time immediately may put a hold on a PR simply by saying so on the PR discussion and offering an ETA measured in single-digit days at most. Any PR that has a hold shall not be merged until the person who requested the hold acks the review, withdraws their hold, or is overruled by a preponderance of maintainers.
|
|
@ -0,0 +1,343 @@
|
|||
|
||||
Running kubernetes with Vagrant (and VirtualBox) is an easy way to run/test/develop on your local machine (Linux, Mac OS X).
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install latest version >= 1.6.2 of vagrant from http://www.vagrantup.com/downloads.html
|
||||
2. Install one of:
|
||||
1. The latest version of Virtual Box from https://www.virtualbox.org/wiki/Downloads
|
||||
2. [VMWare Fusion](https://www.vmware.com/products/fusion/) version 5 or greater as well as the appropriate [Vagrant VMWare Fusion provider](https://www.vagrantup.com/vmware)
|
||||
3. [VMWare Workstation](https://www.vmware.com/products/workstation/) version 9 or greater as well as the [Vagrant VMWare Workstation provider](https://www.vagrantup.com/vmware)
|
||||
4. [Parallels Desktop](https://www.parallels.com/products/desktop/) version 9 or greater as well as the [Vagrant Parallels provider](https://parallels.github.io/vagrant-parallels/)
|
||||
3. Get or build a [binary release](/{{page.version}}/docs/getting-started-guides/binary_release)
|
||||
|
||||
### Setup
|
||||
|
||||
By default, the Vagrant setup will create a single master VM (called kubernetes-master) and one node (called kubernetes-minion-1). Each VM will take 1 GB, so make sure you have at least 2GB to 4GB of free memory (plus appropriate free disk space). To start your local cluster, open a shell and run:
|
||||
|
||||
```shell
|
||||
cd kubernetes
|
||||
|
||||
export KUBERNETES_PROVIDER=vagrant
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
The `KUBERNETES_PROVIDER` environment variable tells all of the various cluster management scripts which variant to use. If you forget to set this, the assumption is you are running on Google Compute Engine.
|
||||
|
||||
If you installed more than one Vagrant provider, Kubernetes will usually pick the appropriate one. However, you can override which one Kubernetes will use by setting the [`VAGRANT_DEFAULT_PROVIDER`](https://docs.vagrantup.com/v2/providers/default) environment variable:
|
||||
|
||||
```shell
|
||||
export VAGRANT_DEFAULT_PROVIDER=parallels
|
||||
export KUBERNETES_PROVIDER=vagrant
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
Vagrant will provision each machine in the cluster with all the necessary components to run Kubernetes. The initial setup can take a few minutes to complete on each machine.
|
||||
|
||||
By default, each VM in the cluster is running Fedora, and all of the Kubernetes services are installed into systemd.
|
||||
|
||||
To access the master or any node:
|
||||
|
||||
```shell
|
||||
vagrant ssh master
|
||||
vagrant ssh minion-1
|
||||
```
|
||||
|
||||
If you are running more than one nodes, you can access the others by:
|
||||
|
||||
```shell
|
||||
vagrant ssh minion-2
|
||||
vagrant ssh minion-3
|
||||
```
|
||||
|
||||
To view the service status and/or logs on the kubernetes-master:
|
||||
|
||||
```shell
|
||||
$ vagrant ssh master
|
||||
[vagrant@kubernetes-master ~] $ sudo systemctl status kube-apiserver
|
||||
[vagrant@kubernetes-master ~] $ sudo journalctl -r -u kube-apiserver
|
||||
|
||||
[vagrant@kubernetes-master ~] $ sudo systemctl status kube-controller-manager
|
||||
[vagrant@kubernetes-master ~] $ sudo journalctl -r -u kube-controller-manager
|
||||
|
||||
[vagrant@kubernetes-master ~] $ sudo systemctl status etcd
|
||||
[vagrant@kubernetes-master ~] $ sudo systemctl status nginx
|
||||
```
|
||||
|
||||
To view the services on any of the nodes:
|
||||
|
||||
```shell
|
||||
$ vagrant ssh minion-1
|
||||
[vagrant@kubernetes-minion-1] $ sudo systemctl status docker
|
||||
[vagrant@kubernetes-minion-1] $ sudo journalctl -r -u docker
|
||||
[vagrant@kubernetes-minion-1] $ sudo systemctl status kubelet
|
||||
[vagrant@kubernetes-minion-1] $ sudo journalctl -r -u kubelet
|
||||
```
|
||||
|
||||
### Interacting with your Kubernetes cluster with Vagrant.
|
||||
|
||||
With your Kubernetes cluster up, you can manage the nodes in your cluster with the regular Vagrant commands.
|
||||
|
||||
To push updates to new Kubernetes code after making source changes:
|
||||
|
||||
```shell
|
||||
./cluster/kube-push.sh
|
||||
```
|
||||
|
||||
To stop and then restart the cluster:
|
||||
|
||||
```shell
|
||||
vagrant halt
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
To destroy the cluster:
|
||||
|
||||
```shell
|
||||
vagrant destroy
|
||||
```
|
||||
|
||||
Once your Vagrant machines are up and provisioned, the first thing to do is to check that you can use the `kubectl.sh` script.
|
||||
|
||||
You may need to build the binaries first, you can do this with `make`
|
||||
|
||||
```shell
|
||||
$ ./cluster/kubectl.sh get nodes
|
||||
|
||||
NAME LABELS STATUS
|
||||
kubernetes-minion-0whl kubernetes.io/hostname=kubernetes-minion-0whl Ready
|
||||
kubernetes-minion-4jdf kubernetes.io/hostname=kubernetes-minion-4jdf Ready
|
||||
kubernetes-minion-epbe kubernetes.io/hostname=kubernetes-minion-epbe Ready
|
||||
```
|
||||
|
||||
### Interacting with your Kubernetes cluster with the `kube-*` scripts.
|
||||
|
||||
Alternatively to using the vagrant commands, you can also use the `cluster/kube-*.sh` scripts to interact with the vagrant based provider just like any other hosting platform for kubernetes.
|
||||
|
||||
All of these commands assume you have set `KUBERNETES_PROVIDER` appropriately:
|
||||
|
||||
```shell
|
||||
export KUBERNETES_PROVIDER=vagrant
|
||||
```
|
||||
|
||||
Bring up a vagrant cluster
|
||||
|
||||
```shell
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
Destroy the vagrant cluster
|
||||
|
||||
```shell
|
||||
./cluster/kube-down.sh
|
||||
```
|
||||
|
||||
Update the vagrant cluster after you make changes (only works when building your own releases locally):
|
||||
|
||||
```shell
|
||||
./cluster/kube-push.sh
|
||||
```
|
||||
|
||||
Interact with the cluster
|
||||
|
||||
```shell
|
||||
./cluster/kubectl.sh
|
||||
```
|
||||
|
||||
### Authenticating with your master
|
||||
|
||||
When using the vagrant provider in Kubernetes, the `cluster/kubectl.sh` script will cache your credentials in a `~/.kubernetes_vagrant_auth` file so you will not be prompted for them in the future.
|
||||
|
||||
```shell
|
||||
$ cat ~/.kubernetes_vagrant_auth
|
||||
{ "User": "vagrant",
|
||||
"Password": "vagrant"
|
||||
"CAFile": "/home/k8s_user/.kubernetes.vagrant.ca.crt",
|
||||
"CertFile": "/home/k8s_user/.kubecfg.vagrant.crt",
|
||||
"KeyFile": "/home/k8s_user/.kubecfg.vagrant.key"
|
||||
}
|
||||
```
|
||||
|
||||
You should now be set to use the `cluster/kubectl.sh` script. For example try to list the nodes that you have started with:
|
||||
|
||||
```shell
|
||||
./cluster/kubectl.sh get nodes
|
||||
```
|
||||
|
||||
### Running containers
|
||||
|
||||
Your cluster is running, you can list the nodes in your cluster:
|
||||
|
||||
```shell
|
||||
$ ./cluster/kubectl.sh get nodes
|
||||
|
||||
NAME LABELS STATUS
|
||||
kubernetes-minion-0whl kubernetes.io/hostname=kubernetes-minion-0whl Ready
|
||||
kubernetes-minion-4jdf kubernetes.io/hostname=kubernetes-minion-4jdf Ready
|
||||
kubernetes-minion-epbe kubernetes.io/hostname=kubernetes-minion-epbe Ready
|
||||
```
|
||||
|
||||
Now start running some containers!
|
||||
|
||||
You can now use any of the cluster/kube-*.sh commands to interact with your VM machines.
|
||||
Before starting a container there will be no pods, services and replication controllers.
|
||||
|
||||
```shell
|
||||
$ cluster/kubectl.sh get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
|
||||
$ cluster/kubectl.sh get services
|
||||
NAME LABELS SELECTOR IP(S) PORT(S)
|
||||
|
||||
$ cluster/kubectl.sh get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
```
|
||||
|
||||
Start a container running nginx with a replication controller and three replicas
|
||||
|
||||
```shell
|
||||
$ cluster/kubectl.sh run my-nginx --image=nginx --replicas=3 --port=80
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
my-nginx my-nginx nginx run=my-nginx 3
|
||||
```
|
||||
|
||||
When listing the pods, you will see that three containers have been started and are in Waiting state:
|
||||
|
||||
```shell
|
||||
$ cluster/kubectl.sh get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
my-nginx-389da 1/1 Waiting 0 33s
|
||||
my-nginx-kqdjk 1/1 Waiting 0 33s
|
||||
my-nginx-nyj3x 1/1 Waiting 0 33s
|
||||
```
|
||||
|
||||
You need to wait for the provisioning to complete, you can monitor the minions by doing:
|
||||
|
||||
```shell
|
||||
$ sudo salt '*minion-1' cmd.run 'docker images'
|
||||
kubernetes-minion-1:
|
||||
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
|
||||
<none> <none> 96864a7d2df3 26 hours ago 204.4 MB
|
||||
kubernetes/pause latest 6c4579af347b 8 weeks ago 239.8 kB
|
||||
```
|
||||
|
||||
Once the docker image for nginx has been downloaded, the container will start and you can list it:
|
||||
|
||||
```shell
|
||||
$ sudo salt '*minion-1' cmd.run 'docker ps'
|
||||
kubernetes-minion-1:
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
dbe79bf6e25b nginx:latest "nginx" 21 seconds ago Up 19 seconds k8s--mynginx.8c5b8a3a--7813c8bd_-_3ffe_-_11e4_-_9036_-_0800279696e1.etcd--7813c8bd_-_3ffe_-_11e4_-_9036_-_0800279696e1--fcfa837f
|
||||
fa0e29c94501 kubernetes/pause:latest "/pause" 8 minutes ago Up 8 minutes 0.0.0.0:8080->80/tcp k8s--net.a90e7ce4--7813c8bd_-_3ffe_-_11e4_-_9036_-_0800279696e1.etcd--7813c8bd_-_3ffe_-_11e4_-_9036_-_0800279696e1--baf5b21b
|
||||
```
|
||||
|
||||
Going back to listing the pods, services and replicationcontrollers, you now have:
|
||||
|
||||
```shell
|
||||
$ cluster/kubectl.sh get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
my-nginx-389da 1/1 Running 0 33s
|
||||
my-nginx-kqdjk 1/1 Running 0 33s
|
||||
my-nginx-nyj3x 1/1 Running 0 33s
|
||||
|
||||
$ cluster/kubectl.sh get services
|
||||
NAME LABELS SELECTOR IP(S) PORT(S)
|
||||
|
||||
$ cluster/kubectl.sh get rc
|
||||
NAME IMAGE(S) SELECTOR REPLICAS
|
||||
my-nginx nginx run=my-nginx 3
|
||||
```
|
||||
|
||||
We did not start any services, hence there are none listed. But we see three replicas displayed properly.
|
||||
Check the [guestbook](https://github.com/kubernetes/kubernetes/tree/{{page.githubbranch}}/examples/guestbook/) application to learn how to create a service.
|
||||
You can already play with scaling the replicas with:
|
||||
|
||||
```shell
|
||||
$ ./cluster/kubectl.sh scale rc my-nginx --replicas=2
|
||||
$ ./cluster/kubectl.sh get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
my-nginx-kqdjk 1/1 Running 0 13m
|
||||
my-nginx-nyj3x 1/1 Running 0 13m
|
||||
```
|
||||
|
||||
Congratulations!
|
||||
|
||||
### Testing
|
||||
|
||||
The following will run all of the end-to-end testing scenarios assuming you set your environment in `cluster/kube-env.sh`:
|
||||
|
||||
```shell
|
||||
NUM_MINIONS=3 hack/e2e-test.sh
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
#### I keep downloading the same (large) box all the time!
|
||||
|
||||
By default the Vagrantfile will download the box from S3. You can change this (and cache the box locally) by providing a name and an alternate URL when calling `kube-up.sh`
|
||||
|
||||
```shell
|
||||
export KUBERNETES_BOX_NAME=choose_your_own_name_for_your_kuber_box
|
||||
export KUBERNETES_BOX_URL=path_of_your_kuber_box
|
||||
export KUBERNETES_PROVIDER=vagrant
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
#### I just created the cluster, but I am getting authorization errors!
|
||||
|
||||
You probably have an incorrect ~/.kubernetes_vagrant_auth file for the cluster you are attempting to contact.
|
||||
|
||||
```shell
|
||||
rm ~/.kubernetes_vagrant_auth
|
||||
```
|
||||
|
||||
After using kubectl.sh make sure that the correct credentials are set:
|
||||
|
||||
```shell
|
||||
$ cat ~/.kubernetes_vagrant_auth
|
||||
{
|
||||
"User": "vagrant",
|
||||
"Password": "vagrant"
|
||||
}
|
||||
```
|
||||
|
||||
#### I just created the cluster, but I do not see my container running!
|
||||
|
||||
If this is your first time creating the cluster, the kubelet on each node schedules a number of docker pull requests to fetch prerequisite images. This can take some time and as a result may delay your initial pod getting provisioned.
|
||||
|
||||
#### I changed Kubernetes code, but it's not running!
|
||||
|
||||
Are you sure there was no build error? After running `$ vagrant provision`, scroll up and ensure that each Salt state was completed successfully on each box in the cluster.
|
||||
It's very likely you see a build error due to an error in your source files!
|
||||
|
||||
#### I have brought Vagrant up but the nodes won't validate!
|
||||
|
||||
Are you sure you built a release first? Did you install `net-tools`? For more clues, login to one of the nodes (`vagrant ssh minion-1`) and inspect the salt minion log (`sudo cat /var/log/salt/minion`).
|
||||
|
||||
#### I want to change the number of nodes!
|
||||
|
||||
You can control the number of nodes that are instantiated via the environment variable `NUM_MINIONS` on your host machine. If you plan to work with replicas, we strongly encourage you to work with enough nodes to satisfy your largest intended replica size. If you do not plan to work with replicas, you can save some system resources by running with a single node. You do this, by setting `NUM_MINIONS` to 1 like so:
|
||||
|
||||
```shell
|
||||
export NUM_MINIONS=1
|
||||
```
|
||||
|
||||
#### I want my VMs to have more memory!
|
||||
|
||||
You can control the memory allotted to virtual machines with the `KUBERNETES_MEMORY` environment variable.
|
||||
Just set it to the number of megabytes you would like the machines to have. For example:
|
||||
|
||||
```shell
|
||||
export KUBERNETES_MEMORY=2048
|
||||
```
|
||||
|
||||
If you need more granular control, you can set the amount of memory for the master and nodes independently. For example:
|
||||
|
||||
```shell
|
||||
export KUBERNETES_MASTER_MEMORY=1536
|
||||
export KUBERNETES_MINION_MEMORY=2048
|
||||
|
||||
```
|
||||
#### I ran vagrant suspend and nothing works!
|
||||
|
||||
`vagrant suspend` seems to mess up the network. It's not supported at this time.
|
|
@ -0,0 +1,315 @@
|
|||
|
||||
# Releases and Official Builds
|
||||
|
||||
Official releases are built in Docker containers. Details are [here](http://releases.k8s.io/{{page.githubbranch}}/build/README.md). You can do simple builds and development with just a local Docker installation. If want to build go locally outside of docker, please continue below.
|
||||
|
||||
## Go development environment
|
||||
|
||||
Kubernetes is written in [Go](http://golang.org) programming language. If you haven't set up Go development environment, please follow [this instruction](http://golang.org/doc/code) to install go tool and set up GOPATH. Ensure your version of Go is at least 1.3.
|
||||
|
||||
## Git Setup
|
||||
|
||||
Below, we outline one of the more common git workflows that core developers use. Other git workflows are also valid.
|
||||
|
||||
### Visual overview
|
||||
|
||||

|
||||
|
||||
### Fork the main repository
|
||||
|
||||
1. Go to https://github.com/kubernetes/kubernetes
|
||||
2. Click the "Fork" button (at the top right)
|
||||
|
||||
### Clone your fork
|
||||
|
||||
The commands below require that you have $GOPATH set ([$GOPATH docs](https://golang.org/doc/code/#GOPATH)). We highly recommend you put Kubernetes' code into your GOPATH. Note: the commands below will not work if there is more than one directory in your `$GOPATH`.
|
||||
|
||||
```shell
|
||||
mkdir -p $GOPATH/src/k8s.io
|
||||
cd $GOPATH/src/k8s.io
|
||||
# Replace "$YOUR_GITHUB_USERNAME" below with your github username
|
||||
git clone https://github.com/$YOUR_GITHUB_USERNAME/kubernetes.git
|
||||
cd kubernetes
|
||||
git remote add upstream 'https://github.com/kubernetes/kubernetes.git'
|
||||
```
|
||||
|
||||
### Create a branch and make changes
|
||||
|
||||
```shell
|
||||
git checkout -b myfeature
|
||||
# Make your code changes
|
||||
```
|
||||
|
||||
### Keeping your development fork in sync
|
||||
|
||||
```shell
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
```
|
||||
|
||||
Note: If you have write access to the main repository at github.com/kubernetes/kubernetes, you should modify your git configuration so that you can't accidentally push to upstream:
|
||||
|
||||
```shell
|
||||
git remote set-url --push upstream no_push
|
||||
```
|
||||
|
||||
### Committing changes to your fork
|
||||
|
||||
```shell
|
||||
git commit
|
||||
git push -f origin myfeature
|
||||
```
|
||||
|
||||
### Creating a pull request
|
||||
|
||||
1. Visit https://github.com/$YOUR_GITHUB_USERNAME/kubernetes
|
||||
2. Click the "Compare and pull request" button next to your "myfeature" branch.
|
||||
3. Check out the pull request [process](/{{page.version}}/docs/devel/pull-requests) for more details
|
||||
|
||||
### When to retain commits and when to squash
|
||||
|
||||
Upon merge, all git commits should represent meaningful milestones or units of
|
||||
work. Use commits to add clarity to the development and review process.
|
||||
|
||||
Before merging a PR, squash any "fix review feedback", "typo", and "rebased"
|
||||
sorts of commits. It is not imperative that every commit in a PR compile and
|
||||
pass tests independently, but it is worth striving for. For mass automated
|
||||
fixups (e.g. automated doc formatting), use one or more commits for the
|
||||
changes to tooling and a final commit to apply the fixup en masse. This makes
|
||||
reviews much easier.
|
||||
|
||||
See [Faster Reviews](/{{page.version}}/docs/devel/faster_reviews) for more details.
|
||||
|
||||
## godep and dependency management
|
||||
|
||||
Kubernetes uses [godep](https://github.com/tools/godep) to manage dependencies. It is not strictly required for building Kubernetes but it is required when managing dependencies under the Godeps/ tree, and is required by a number of the build and test scripts. Please make sure that ``godep`` is installed and in your ``$PATH``.
|
||||
|
||||
### Installing godep
|
||||
|
||||
There are many ways to build and host go binaries. Here is an easy way to get utilities like `godep` installed:
|
||||
|
||||
1) Ensure that [mercurial](http://mercurial.selenic.com/wiki/Download) is installed on your system. (some of godep's dependencies use the mercurial
|
||||
source control system). Use `apt-get install mercurial` or `yum install mercurial` on Linux, or [brew.sh](http://brew.sh) on OS X, or download
|
||||
directly from mercurial.
|
||||
|
||||
2) Create a new GOPATH for your tools and install godep:
|
||||
|
||||
```shell
|
||||
export GOPATH=$HOME/go-tools
|
||||
mkdir -p $GOPATH
|
||||
go get github.com/tools/godep
|
||||
```
|
||||
|
||||
3) Add $GOPATH/bin to your path. Typically you'd add this to your ~/.profile:
|
||||
|
||||
```shell
|
||||
export GOPATH=$HOME/go-tools
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
```
|
||||
|
||||
### Using godep
|
||||
|
||||
Here's a quick walkthrough of one way to use godeps to add or update a Kubernetes dependency into Godeps/_workspace. For more details, please see the instructions in [godep's documentation](https://github.com/tools/godep).
|
||||
|
||||
1) Devote a directory to this endeavor:
|
||||
|
||||
_Devoting a separate directory is not required, but it is helpful to separate dependency updates from other changes._
|
||||
|
||||
```shell
|
||||
export KPATH=$HOME/code/kubernetes
|
||||
mkdir -p $KPATH/src/k8s.io/kubernetes
|
||||
cd $KPATH/src/k8s.io/kubernetes
|
||||
git clone https://path/to/your/fork .
|
||||
# Or copy your existing local repo here. IMPORTANT: making a symlink doesn't work.
|
||||
```
|
||||
|
||||
2) Set up your GOPATH.
|
||||
|
||||
```shell
|
||||
# Option A: this will let your builds see packages that exist elsewhere on your system.
|
||||
export GOPATH=$KPATH:$GOPATH
|
||||
# Option B: This will *not* let your local builds see packages that exist elsewhere on your system.
|
||||
export GOPATH=$KPATH
|
||||
# Option B is recommended if you're going to mess with the dependencies.
|
||||
```
|
||||
|
||||
3) Populate your new GOPATH.
|
||||
|
||||
```shell
|
||||
cd $KPATH/src/k8s.io/kubernetes
|
||||
godep restore
|
||||
```
|
||||
|
||||
4) Next, you can either add a new dependency or update an existing one.
|
||||
|
||||
```shell
|
||||
# To add a new dependency, do:
|
||||
cd $KPATH/src/k8s.io/kubernetes
|
||||
go get path/to/dependency
|
||||
# Change code in Kubernetes to use the dependency.
|
||||
godep save ./...
|
||||
# To update an existing dependency, do:
|
||||
cd $KPATH/src/k8s.io/kubernetes
|
||||
go get -u path/to/dependency
|
||||
# Change code in Kubernetes accordingly if necessary.
|
||||
godep update path/to/dependency/...
|
||||
```
|
||||
|
||||
_If `go get -u path/to/dependency` fails with compilation errors, instead try `go get -d -u path/to/dependency`
|
||||
to fetch the dependencies without compiling them. This can happen when updating the cadvisor dependency._
|
||||
|
||||
|
||||
5) Before sending your PR, it's a good idea to sanity check that your Godeps.json file is ok by running hack/verify-godeps.sh
|
||||
|
||||
_If hack/verify-godeps.sh fails after a `godep update`, it is possible that a transitive dependency was added or removed but not
|
||||
updated by godeps. It then may be necessary to perform a `godep save ./...` to pick up the transitive dependency changes._
|
||||
|
||||
It is sometimes expedient to manually fix the /Godeps/godeps.json file to minimize the changes.
|
||||
|
||||
Please send dependency updates in separate commits within your PR, for easier reviewing.
|
||||
|
||||
## Hooks
|
||||
|
||||
Before committing any changes, please link/copy these hooks into your .git
|
||||
directory. This will keep you from accidentally committing non-gofmt'd go code.
|
||||
|
||||
```shell
|
||||
cd kubernetes/.git/hooks/
|
||||
ln -s ../../hooks/pre-commit .
|
||||
```
|
||||
|
||||
## Unit tests
|
||||
|
||||
```shell
|
||||
cd kubernetes
|
||||
hack/test-go.sh
|
||||
```
|
||||
|
||||
Alternatively, you could also run:
|
||||
|
||||
```shell
|
||||
cd kubernetes
|
||||
godep go test ./...
|
||||
```
|
||||
|
||||
If you only want to run unit tests in one package, you could run ``godep go test`` under the package directory. For example, the following commands will run all unit tests in package kubelet:
|
||||
|
||||
```shell
|
||||
$ cd kubernetes # step into the kubernetes directory.
|
||||
$ cd pkg/kubelet
|
||||
$ godep go test
|
||||
# some output from unit tests
|
||||
PASS
|
||||
ok k8s.io/kubernetes/pkg/kubelet 0.317s
|
||||
```
|
||||
|
||||
## Coverage
|
||||
|
||||
Currently, collecting coverage is only supported for the Go unit tests.
|
||||
|
||||
To run all unit tests and generate an HTML coverage report, run the following:
|
||||
|
||||
```shell
|
||||
cd kubernetes
|
||||
KUBE_COVER=y hack/test-go.sh
|
||||
```
|
||||
|
||||
At the end of the run, an the HTML report will be generated with the path printed to stdout.
|
||||
|
||||
To run tests and collect coverage in only one package, pass its relative path under the `kubernetes` directory as an argument, for example:
|
||||
|
||||
```shell
|
||||
cd kubernetes
|
||||
KUBE_COVER=y hack/test-go.sh pkg/kubectl
|
||||
```
|
||||
|
||||
Multiple arguments can be passed, in which case the coverage results will be combined for all tests run.
|
||||
|
||||
Coverage results for the project can also be viewed on [Coveralls](https://coveralls.io/r/kubernetes/kubernetes), and are continuously updated as commits are merged. Additionally, all pull requests which spawn a Travis build will report unit test coverage results to Coveralls. Coverage reports from before the Kubernetes Github organization was created can be found [here](https://coveralls.io/r/GoogleCloudPlatform/kubernetes).
|
||||
|
||||
## Integration tests
|
||||
|
||||
You need an [etcd](https://github.com/coreos/etcd/releases/tag/v2.0.0) in your path, please make sure it is installed and in your ``$PATH``.
|
||||
|
||||
```shell
|
||||
cd kubernetes
|
||||
hack/test-integration.sh
|
||||
```
|
||||
|
||||
## End-to-End tests
|
||||
|
||||
You can run an end-to-end test which will bring up a master and two nodes, perform some tests, and then tear everything down. Make sure you have followed the getting started steps for your chosen cloud platform (which might involve changing the `KUBERNETES_PROVIDER` environment variable to something other than "gce".
|
||||
|
||||
```shell
|
||||
cd kubernetes
|
||||
hack/e2e-test.sh
|
||||
```
|
||||
|
||||
Pressing control-C should result in an orderly shutdown but if something goes wrong and you still have some VMs running you can force a cleanup with this command:
|
||||
|
||||
```shell
|
||||
go run hack/e2e.go --down
|
||||
```
|
||||
|
||||
### Flag options
|
||||
|
||||
See the flag definitions in `hack/e2e.go` for more options, such as reusing an existing cluster, here is an overview:
|
||||
|
||||
```shell
|
||||
# Build binaries for testing
|
||||
go run hack/e2e.go --build
|
||||
# Create a fresh cluster. Deletes a cluster first, if it exists
|
||||
go run hack/e2e.go --up
|
||||
# Create a fresh cluster at a specific release version.
|
||||
go run hack/e2e.go --up --version=0.7.0
|
||||
# Test if a cluster is up.
|
||||
go run hack/e2e.go --isup
|
||||
# Push code to an existing cluster
|
||||
go run hack/e2e.go --push
|
||||
# Push to an existing cluster, or bring up a cluster if it's down.
|
||||
go run hack/e2e.go --pushup
|
||||
# Run all tests
|
||||
go run hack/e2e.go --test
|
||||
# Run tests matching the regex "Pods.*env"
|
||||
go run hack/e2e.go -v -test --test_args="--ginkgo.focus=Pods.*env"
|
||||
# Alternately, if you have the e2e cluster up and no desire to see the event stream, you can run ginkgo-e2e.sh directly:
|
||||
hack/ginkgo-e2e.sh --ginkgo.focus=Pods.*env
|
||||
```
|
||||
|
||||
### Combining flags
|
||||
|
||||
```shell
|
||||
# Flags can be combined, and their actions will take place in this order:
|
||||
# -build, -push|-up|-pushup, -test|-tests=..., -down
|
||||
# e.g.:
|
||||
go run hack/e2e.go -build -pushup -test -down
|
||||
# -v (verbose) can be added if you want streaming output instead of only
|
||||
# seeing the output of failed commands.
|
||||
# -ctl can be used to quickly call kubectl against your e2e cluster. Useful for
|
||||
# cleaning up after a failed test or viewing logs. Use -v to avoid suppressing
|
||||
# kubectl output.
|
||||
go run hack/e2e.go -v -ctl='get events'
|
||||
go run hack/e2e.go -v -ctl='delete pod foobar'
|
||||
```
|
||||
|
||||
## Conformance testing
|
||||
|
||||
End-to-end testing, as described above, is for [development
|
||||
distributions](/{{page.version}}/docs/devel/writing-a-getting-started-guide). A conformance test is used on
|
||||
a [versioned distro](/{{page.version}}/docs/devel/writing-a-getting-started-guide).
|
||||
|
||||
The conformance test runs a subset of the e2e-tests against a manually-created cluster. It does not
|
||||
require support for up/push/down and other operations. To run a conformance test, you need to know the
|
||||
IP of the master for your cluster and the authorization arguments to use. The conformance test is
|
||||
intended to run against a cluster at a specific binary release of Kubernetes.
|
||||
See [conformance-test.sh](http://releases.k8s.io/{{page.githubbranch}}/hack/conformance-test.sh).
|
||||
|
||||
## Testing out flaky tests
|
||||
|
||||
[Instructions here](/{{page.version}}/docs/devel/flaky-tests)
|
||||
|
||||
## Regenerating the CLI documentation
|
||||
|
||||
```shell
|
||||
hack/update-generated-docs.sh
|
||||
```
|
|
@ -0,0 +1,110 @@
|
|||
|
||||
The end-2-end tests for kubernetes provide a mechanism to test behavior of the system, and to ensure end user operations match developer specifications. In distributed systems it is not uncommon that a minor change may pass all unit tests, but cause unforseen changes at the system level. Thus, the primary objectives of the end-2-end tests are to ensure a consistent and reliable behavior of the kubernetes code base, and to catch bugs early.
|
||||
|
||||
The end-2-end tests in kubernetes are built atop of [ginkgo] (http://onsi.github.io/ginkgo/) and [gomega] (http://onsi.github.io/gomega/). There are a host of features that this BDD testing framework provides, and it is recommended that the developer read the documentation prior to diving into the tests.
|
||||
|
||||
The purpose of *this* document is to serve as a primer for developers who are looking to execute, or add tests, using a local development environment.
|
||||
|
||||
## Building and Running the Tests
|
||||
|
||||
**NOTE:** The tests have an array of options. For simplicity, the examples will focus on leveraging the tests on a local cluster using `sudo ./hack/local-up-cluster.sh`
|
||||
|
||||
### Building the Tests
|
||||
|
||||
The tests are built into a single binary which can be run against any deployed kubernetes system. To build the tests, navigate to your source directory and execute:
|
||||
|
||||
`$ make all`
|
||||
|
||||
The output for the end-2-end tests will be a single binary called `e2e.test` under the default output directory, which is typically `_output/local/bin/linux/amd64/`. Within the repository there are scripts that are provided under the `./hack` directory that are helpful for automation, but may not apply for a local development purposes. Instead, we recommend familiarizing yourself with the executable options. To obtain the full list of options, run the following:
|
||||
|
||||
`$ ./e2e.test --help`
|
||||
|
||||
### Running the Tests
|
||||
|
||||
For the purposes of brevity, we will look at a subset of the options, which are listed below:
|
||||
|
||||
```shell
|
||||
-ginkgo.dryRun=false: If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v.
|
||||
-ginkgo.failFast=false: If set, ginkgo will stop running a test suite after a failure occurs.
|
||||
-ginkgo.failOnPending=false: If set, ginkgo will mark the test suite as failed if any specs are pending.
|
||||
-ginkgo.focus="": If set, ginkgo will only run specs that match this regular expression.
|
||||
-ginkgo.skip="": If set, ginkgo will only run specs that do not match this regular expression.
|
||||
-ginkgo.trace=false: If set, default reporter prints out the full stack trace when a failure occurs
|
||||
-ginkgo.v=false: If set, default reporter print out all specs as they begin.
|
||||
-host="": The host, or api-server, to connect to
|
||||
-kubeconfig="": Path to kubeconfig containing embedded authinfo.
|
||||
-prom-push-gateway="": The URL to prometheus gateway, so that metrics can be pushed during e2es and scraped by prometheus. Typically something like 127.0.0.1:9091.
|
||||
-provider="": The name of the Kubernetes provider (gce, gke, local, vagrant, etc.)
|
||||
-repo-root="../../": Root directory of kubernetes repository, for finding test files.
|
||||
```
|
||||
|
||||
Prior to running the tests, it is recommended that you first create a simple auth file in your home directory, e.g. `$HOME/.kubernetes_auth` , with the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"User": "root",
|
||||
"Password": ""
|
||||
}
|
||||
```
|
||||
|
||||
Next, you will need a cluster that you can test against. As mentioned earlier, you will want to execute `sudo ./hack/local-up-cluster.sh`. To get a sense of what tests exist, you may want to run:
|
||||
|
||||
```shell
|
||||
e2e.test --host="127.0.0.1:8080" --provider="local" --ginkgo.v=true -ginkgo.dryRun=true --kubeconfig="$HOME/.kubernetes_auth" --repo-root="$KUBERNETES_SRC_PATH"
|
||||
```
|
||||
|
||||
If you wish to execute a specific set of tests you can use the `-ginkgo.focus=` regex, e.g.:
|
||||
|
||||
```shell
|
||||
e2e.test ... --ginkgo.focus="DNS|(?i)nodeport(?-i)|kubectl guestbook"
|
||||
```
|
||||
|
||||
Conversely, if you wish to exclude a set of tests, you can run:
|
||||
|
||||
```shell
|
||||
e2e.test ... --ginkgo.skip="Density|Scale"
|
||||
```
|
||||
|
||||
As mentioned earlier there are a host of other options that are available, but are left to the developer
|
||||
|
||||
**NOTE:** If you are running tests on a local cluster repeatedly, you may need to periodically perform some manual cleanup.
|
||||
- `rm -rf /var/run/kubernetes`, clear kube generated credentials, sometimes stale permissions can cause problems.
|
||||
- `sudo iptables -F`, clear ip tables rules left by the kube-proxy.
|
||||
|
||||
## Adding a New Test
|
||||
|
||||
As mentioned above, prior to adding a new test, it is a good idea to perform a `-ginkgo.dryRun=true` on the system, in order to see if a behavior is already being tested, or to determine if it may be possible to augment an existing set of tests for a specific use case.
|
||||
|
||||
If a behavior does not currently have coverage and a developer wishes to add a new e2e test, navigate to the ./test/e2e directory and create a new test using the existing suite as a guide.
|
||||
|
||||
**TODO:** Create a self-documented example which has been disabled, but can be copied to create new tests and outlines the capabilities and libraries used.
|
||||
|
||||
## Performance Evaluation
|
||||
|
||||
Another benefit of the end-2-end tests is the ability to create reproducible loads on the system, which can then be used to determine the responsiveness, or analyze other characteristics of the system. For example, the density tests load the system to 30,50,100 pods per/node and measures the different characteristics of the system, such as throughput, api-latency, etc.
|
||||
|
||||
For a good overview of how we analyze performance data, please read the following [post](http://blog.kubernetes.io/2015/09/kubernetes-performance-measurements-and)
|
||||
|
||||
For developers who are interested in doing their own performance analysis, we recommend setting up [prometheus](http://prometheus.io/) for data collection, and using [promdash](http://prometheus.io/docs/visualization/promdash/) to visualize the data. There also exists the option of pushing your own metrics in from the tests using a [prom-push-gateway](http://prometheus.io/docs/instrumenting/pushing/). Containers for all of these components can be found [here](https://hub.docker.com/u/prom/).
|
||||
|
||||
For more accurate measurements, you may wish to set up prometheus external to kubernetes in an environment where it can access the major system components (api-server, controller-manager, scheduler). This is especially useful when attempting to gather metrics in a load-balanced api-server environment, because all api-servers can be analyzed independently as well as collectively. On startup, configuration file is passed to prometheus that specifies the endpoints that prometheus will scrape, as well as the sampling interval.
|
||||
|
||||
**prometheus.conf**
|
||||
|
||||
```conf
|
||||
job: {
|
||||
name: "kubernetes"
|
||||
scrape_interval: "1s"
|
||||
target_group: {
|
||||
# apiserver(s)
|
||||
target: "http://localhost:8080/metrics"
|
||||
# scheduler
|
||||
target: "http://localhost:10251/metrics"
|
||||
# controller-manager
|
||||
target: "http://localhost:10252/metrics"
|
||||
}
|
||||
```
|
||||
|
||||
Once prometheus is scraping the kubernetes endpoints, that data can then be plotted using promdash, and alerts can be created against the assortment of metrics that kubernetes provides.
|
||||
|
||||
**HAPPY TESTING!**
|
|
@ -0,0 +1,200 @@
|
|||
|
||||
Most of what is written here is not at all specific to Kubernetes, but it bears
|
||||
being written down in the hope that it will occasionally remind people of "best
|
||||
practices" around code reviews.
|
||||
|
||||
You've just had a brilliant idea on how to make Kubernetes better. Let's call
|
||||
that idea "FeatureX". Feature X is not even that complicated. You have a
|
||||
pretty good idea of how to implement it. You jump in and implement it, fixing a
|
||||
bunch of stuff along the way. You send your PR - this is awesome! And it sits.
|
||||
And sits. A week goes by and nobody reviews it. Finally someone offers a few
|
||||
comments, which you fix up and wait for more review. And you wait. Another
|
||||
week or two goes by. This is horrible.
|
||||
|
||||
What went wrong? One particular problem that comes up frequently is this - your
|
||||
PR is too big to review. You've touched 39 files and have 8657 insertions.
|
||||
When your would-be reviewers pull up the diffs they run away - this PR is going
|
||||
to take 4 hours to review and they don't have 4 hours right now. They'll get to it
|
||||
later, just as soon as they have more free time (ha!).
|
||||
|
||||
Let's talk about how to avoid this.
|
||||
|
||||
## 0. Familiarize yourself with project conventions
|
||||
|
||||
* [Development guide](/{{page.version}}/docs/devel/development)
|
||||
* [Coding conventions](/{{page.version}}/docs/devel/coding-conventions)
|
||||
* [API conventions](/{{page.version}}/docs/devel/api-conventions)
|
||||
* [Kubectl conventions](/{{page.version}}/docs/devel/kubectl-conventions)
|
||||
|
||||
## 1. Don't build a cathedral in one PR
|
||||
|
||||
Are you sure FeatureX is something the Kubernetes team wants or will accept, or
|
||||
that it is implemented to fit with other changes in flight? Are you willing to
|
||||
bet a few days or weeks of work on it? If you have any doubt at all about the
|
||||
usefulness of your feature or the design - make a proposal doc (in docs/proposals;
|
||||
for example [the QoS proposal](http://prs.k8s.io/11713)) or a sketch PR (e.g., just
|
||||
the API or Go interface) or both. Write or code up just enough to express the idea
|
||||
and the design and why you made those choices, then get feedback on this. Be clear
|
||||
about what type of feedback you are asking for. Now, if we ask you to change a
|
||||
bunch of facets of the design, you won't have to re-write it all.
|
||||
|
||||
## 2. Smaller diffs are exponentially better
|
||||
|
||||
Small PRs get reviewed faster and are more likely to be correct than big ones.
|
||||
Let's face it - attention wanes over time. If your PR takes 60 minutes to
|
||||
review, I almost guarantee that the reviewer's eye for details is not as keen in
|
||||
the last 30 minutes as it was in the first. This leads to multiple rounds of
|
||||
review when one might have sufficed. In some cases the review is delayed in its
|
||||
entirety by the need for a large contiguous block of time to sit and read your
|
||||
code.
|
||||
|
||||
Whenever possible, break up your PRs into multiple commits. Making a series of
|
||||
discrete commits is a powerful way to express the evolution of an idea or the
|
||||
different ideas that make up a single feature. There's a balance to be struck,
|
||||
obviously. If your commits are too small they become more cumbersome to deal
|
||||
with. Strive to group logically distinct ideas into commits.
|
||||
|
||||
For example, if you found that FeatureX needed some "prefactoring" to fit in,
|
||||
make a commit that JUST does that prefactoring. Then make a new commit for
|
||||
FeatureX. Don't lump unrelated things together just because you didn't think
|
||||
about prefactoring. If you need to, fork a new branch, do the prefactoring
|
||||
there and send a PR for that. If you can explain why you are doing seemingly
|
||||
no-op work ("it makes the FeatureX change easier, I promise") we'll probably be
|
||||
OK with it.
|
||||
|
||||
Obviously, a PR with 25 commits is still very cumbersome to review, so use
|
||||
common sense.
|
||||
|
||||
## 3. Multiple small PRs are often better than multiple commits
|
||||
|
||||
If you can extract whole ideas from your PR and send those as PRs of their own,
|
||||
you can avoid the painful problem of continually rebasing. Kubernetes is a
|
||||
fast-moving codebase - lock in your changes ASAP, and make merges be someone
|
||||
else's problem.
|
||||
|
||||
Obviously, we want every PR to be useful on its own, so you'll have to use
|
||||
common sense in deciding what can be a PR vs what should be a commit in a larger
|
||||
PR. Rule of thumb - if this commit or set of commits is directly related to
|
||||
FeatureX and nothing else, it should probably be part of the FeatureX PR. If
|
||||
you can plausibly imagine someone finding value in this commit outside of
|
||||
FeatureX, try it as a PR.
|
||||
|
||||
Don't worry about flooding us with PRs. We'd rather have 100 small, obvious PRs
|
||||
than 10 unreviewable monoliths.
|
||||
|
||||
## 4. Don't rename, reformat, comment, etc in the same PR
|
||||
|
||||
Often, as you are implementing FeatureX, you find things that are just wrong.
|
||||
Bad comments, poorly named functions, bad structure, weak type-safety. You
|
||||
should absolutely fix those things (or at least file issues, please) - but not
|
||||
in this PR. See the above points - break unrelated changes out into different
|
||||
PRs or commits. Otherwise your diff will have WAY too many changes, and your
|
||||
reviewer won't see the forest because of all the trees.
|
||||
|
||||
## 5. Comments matter
|
||||
|
||||
Read up on GoDoc - follow those general rules. If you're writing code and you
|
||||
think there is any possible chance that someone might not understand why you did
|
||||
something (or that you won't remember what you yourself did), comment it. If
|
||||
you think there's something pretty obvious that we could follow up on, add a
|
||||
TODO. Many code-review comments are about this exact issue.
|
||||
|
||||
## 5. Tests are almost always required
|
||||
|
||||
Nothing is more frustrating than doing a review, only to find that the tests are
|
||||
inadequate or even entirely absent. Very few PRs can touch code and NOT touch
|
||||
tests. If you don't know how to test FeatureX - ask! We'll be happy to help
|
||||
you design things for easy testing or to suggest appropriate test cases.
|
||||
|
||||
## 6. Look for opportunities to generify
|
||||
|
||||
If you find yourself writing something that touches a lot of modules, think hard
|
||||
about the dependencies you are introducing between packages. Can some of what
|
||||
you're doing be made more generic and moved up and out of the FeatureX package?
|
||||
Do you need to use a function or type from an otherwise unrelated package? If
|
||||
so, promote! We have places specifically for hosting more generic code.
|
||||
|
||||
Likewise if FeatureX is similar in form to FeatureW which was checked in last
|
||||
month and it happens to exactly duplicate some tricky stuff from FeatureW,
|
||||
consider prefactoring core logic out and using it in both FeatureW and FeatureX.
|
||||
But do that in a different commit or PR, please.
|
||||
|
||||
## 7. Fix feedback in a new commit
|
||||
|
||||
Your reviewer has finally sent you some feedback on FeatureX. You make a bunch
|
||||
of changes and ... what? You could patch those into your commits with git
|
||||
"squash" or "fixup" logic. But that makes your changes hard to verify. Unless
|
||||
your whole PR is pretty trivial, you should instead put your fixups into a new
|
||||
commit and re-push. Your reviewer can then look at that commit on its own - so
|
||||
much faster to review than starting over.
|
||||
|
||||
We might still ask you to clean up your commits at the very end, for the sake
|
||||
of a more readable history, but don't do this until asked, typically at the point
|
||||
where the PR would otherwise be tagged LGTM.
|
||||
|
||||
General squashing guidelines:
|
||||
|
||||
* Sausage => squash
|
||||
|
||||
When there are several commits to fix bugs in the original commit(s), address reviewer feedback, etc. Really we only want to see the end state and commit message for the whole PR.
|
||||
|
||||
* Layers => don't squash
|
||||
|
||||
When there are independent changes layered upon each other to achieve a single goal. For instance, writing a code munger could be one commit, applying it could be another, and adding a precommit check could be a third. One could argue they should be separate PRs, but there's really no way to test/review the munger without seeing it applied, and there needs to be a precommit check to ensure the munged output doesn't immediately get out of date.
|
||||
|
||||
A commit, as much as possible, should be a single logical change. Each commit should always have a good title line (<70 characters) and include an additional description paragraph describing in more detail the change intended. Do not link pull requests by `#` in a commit description, because GitHub creates lots of spam. Instead, reference other PRs via the PR your commit is in.
|
||||
|
||||
## 8. KISS, YAGNI, MVP, etc
|
||||
|
||||
Sometimes we need to remind each other of core tenets of software design - Keep
|
||||
It Simple, You Aren't Gonna Need It, Minimum Viable Product, and so on. Adding
|
||||
features "because we might need it later" is antithetical to software that
|
||||
ships. Add the things you need NOW and (ideally) leave room for things you
|
||||
might need later - but don't implement them now.
|
||||
|
||||
## 9. Push back
|
||||
|
||||
We understand that it is hard to imagine, but sometimes we make mistakes. It's
|
||||
OK to push back on changes requested during a review. If you have a good reason
|
||||
for doing something a certain way, you are absolutely allowed to debate the
|
||||
merits of a requested change. You might be overruled, but you might also
|
||||
prevail. We're mostly pretty reasonable people. Mostly.
|
||||
|
||||
## 10. I'm still getting stalled - help?!
|
||||
|
||||
So, you've done all that and you still aren't getting any PR love? Here's some
|
||||
things you can do that might help kick a stalled process along:
|
||||
|
||||
* Make sure that your PR has an assigned reviewer (assignee in GitHub). If
|
||||
this is not the case, reply to the PR comment stream asking for one to be
|
||||
assigned.
|
||||
|
||||
* Ping the assignee (@username) on the PR comment stream asking for an
|
||||
estimate of when they can get to it.
|
||||
|
||||
* Ping the assignee by email (many of us have email addresses that are well
|
||||
published or are the same as our GitHub handle @google.com or @redhat.com).
|
||||
|
||||
* Ping the [team](https://github.com/orgs/kubernetes/teams) (via @team-name)
|
||||
that works in the area you're submitting code.
|
||||
|
||||
If you think you have fixed all the issues in a round of review, and you haven't
|
||||
heard back, you should ping the reviewer (assignee) on the comment stream with a
|
||||
"please take another look" (PTAL) or similar comment indicating you are done and
|
||||
you think it is ready for re-review. In fact, this is probably a good habit for
|
||||
all PRs.
|
||||
|
||||
One phenomenon of open-source projects (where anyone can comment on any issue)
|
||||
is the dog-pile - your PR gets so many comments from so many people it becomes
|
||||
hard to follow. In this situation you can ask the primary reviewer
|
||||
(assignee) whether they want you to fork a new PR to clear out all the comments.
|
||||
Remember: you don't HAVE to fix every issue raised by every person who feels
|
||||
like commenting, but you should at least answer reasonable comments with an
|
||||
explanation.
|
||||
|
||||
## Final: Use common sense
|
||||
|
||||
Obviously, none of these points are hard rules. There is no document that can
|
||||
take the place of common sense and good taste. Use your best judgment, but put
|
||||
a bit of thought into how your work can be made easier to review. If you do
|
||||
these things your PRs will flow much more easily.
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
Sometimes unit tests are flaky. This means that due to (usually) race conditions, they will occasionally fail, even though most of the time they pass.
|
||||
|
||||
We have a goal of 99.9% flake free tests. This means that there is only one flake in one thousand runs of a test.
|
||||
|
||||
Running a test 1000 times on your own machine can be tedious and time consuming. Fortunately, there is a better way to achieve this using Kubernetes.
|
||||
|
||||
_Note: these instructions are mildly hacky for now, as we get run once semantics and logging they will get better_
|
||||
|
||||
There is a testing image `brendanburns/flake` up on the docker hub. We will use this image to test our fix.
|
||||
|
||||
Create a replication controller with the following config:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
name: flakecontroller
|
||||
spec:
|
||||
replicas: 24
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: flake
|
||||
spec:
|
||||
containers:
|
||||
- name: flake
|
||||
image: brendanburns/flake
|
||||
env:
|
||||
- name: TEST_PACKAGE
|
||||
value: pkg/tools
|
||||
- name: REPO_SPEC
|
||||
value: https://github.com/kubernetes/kubernetes
|
||||
```
|
||||
|
||||
Note that we omit the labels and the selector fields of the replication controller, because they will be populated from the labels field of the pod template by default.
|
||||
|
||||
```shell
|
||||
kubectl create -f ./controller.yaml
|
||||
```
|
||||
|
||||
This will spin up 24 instances of the test. They will run to completion, then exit, and the kubelet will restart them, accumulating more and more runs of the test.
|
||||
You can examine the recent runs of the test by calling `docker ps -a` and looking for tasks that exited with non-zero exit codes. Unfortunately, docker ps -a only keeps around the exit status of the last 15-20 containers with the same image, so you have to check them frequently.
|
||||
You can use this script to automate checking for failures, assuming your cluster is running on GCE and has four nodes:
|
||||
|
||||
```shell
|
||||
echo "" > output.txt
|
||||
for i in {1..4}; do
|
||||
echo "Checking kubernetes-minion-${i}"
|
||||
echo "kubernetes-minion-${i}:" >> output.txt
|
||||
gcloud compute ssh "kubernetes-minion-${i}" --command="sudo docker ps -a" >> output.txt
|
||||
done
|
||||
grep "Exited ([^0])" output.txt
|
||||
```
|
||||
|
||||
Eventually you will have sufficient runs for your purposes. At that point you can stop and delete the replication controller by running:
|
||||
|
||||
```shell
|
||||
kubectl stop replicationcontroller flakecontroller
|
||||
```
|
||||
|
||||
If you do a final check for flakes with `docker ps -a`, ignore tasks that exited -1, since that's what happens when you stop the replication controller.
|
||||
|
||||
Happy flake hunting!
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
You can use [hack/get-build.sh](http://releases.k8s.io/{{page.githubbranch}}/hack/get-build.sh) to or use as a reference on how to get the most recent builds with curl. With `get-build.sh` you can grab the most recent stable build, the most recent release candidate, or the most recent build to pass our ci and gce e2e tests (essentially a nightly build).
|
||||
|
||||
Run `./hack/get-build.sh -h` for its usage.
|
||||
|
||||
For example, to get a build at a specific version (v1.0.2):
|
||||
|
||||
```shell
|
||||
./hack/get-build.sh v1.0.2
|
||||
```
|
||||
|
||||
Alternatively, to get the latest stable release:
|
||||
|
||||
```shell
|
||||
./hack/get-build.sh release/stable
|
||||
```
|
||||
|
||||
Finally, you can just print the latest or stable version:
|
||||
|
||||
```shell
|
||||
./hack/get-build.sh -v ci/latest
|
||||
```
|
||||
|
||||
You can also use the gsutil tool to explore the Google Cloud Storage release buckets. Here are some examples:
|
||||
|
||||
```shell
|
||||
gsutil cat gs://kubernetes-release/ci/latest.txt # output the latest ci version number
|
||||
gsutil cat gs://kubernetes-release/ci/latest-green.txt # output the latest ci version number that passed gce e2e
|
||||
gsutil ls gs://kubernetes-release/ci/v0.20.0-29-g29a55cc/ # list the contents of a ci release
|
||||
gsutil ls gs://kubernetes-release/release # list all official releases and rcs
|
||||
```
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
The developer guide is for anyone wanting to either write code which directly accesses the
|
||||
Kubernetes API, or to contribute directly to the Kubernetes project.
|
||||
It assumes some familiarity with concepts in the [User Guide](/{{page.version}}/docs/user-guide/) and the [Cluster Admin
|
||||
Guide](/{{page.version}}/docs/admin/).
|
||||
|
||||
|
||||
## The process of developing and contributing code to the Kubernetes project
|
||||
|
||||
* **On Collaborative Development** ([collab.md](/{{page.version}}/docs/devel/collab)): Info on pull requests and code reviews.
|
||||
|
||||
* **GitHub Issues** ([issues.md](/{{page.version}}/docs/devel/issues)): How incoming issues are reviewed and prioritized.
|
||||
|
||||
* **Pull Request Process** ([pull-requests.md](/{{page.version}}/docs/devel/pull-requests)): When and why pull requests are closed.
|
||||
|
||||
* **Faster PR reviews** ([faster_reviews.md](/{{page.version}}/docs/devel/faster_reviews)): How to get faster PR reviews.
|
||||
|
||||
* **Getting Recent Builds** ([getting-builds.md](/{{page.version}}/docs/devel/getting-builds)): How to get recent builds including the latest builds that pass CI.
|
||||
|
||||
* **Automated Tools** ([automation.md](/{{page.version}}/docs/devel/automation)): Descriptions of the automation that is running on our github repository.
|
||||
|
||||
|
||||
## Setting up your dev environment, coding, and debugging
|
||||
|
||||
* **Development Guide** ([development.md](/{{page.version}}/docs/devel/development)): Setting up your development environment.
|
||||
|
||||
* **Hunting flaky tests** ([flaky-tests.md](/{{page.version}}/docs/devel/flaky-tests)): We have a goal of 99.9% flake free tests.
|
||||
Here's how to run your tests many times.
|
||||
|
||||
* **Logging Conventions** ([logging.md](/{{page.version}}/docs/devel/logging)]: Glog levels.
|
||||
|
||||
* **Profiling Kubernetes** ([profiling.md](/{{page.version}}/docs/devel/profiling)): How to plug in go pprof profiler to Kubernetes.
|
||||
|
||||
* **Instrumenting Kubernetes with a new metric**
|
||||
([instrumentation.md](/{{page.version}}/docs/devel/instrumentation)): How to add a new metrics to the
|
||||
Kubernetes code base.
|
||||
|
||||
* **Coding Conventions** ([coding-conventions.md](/{{page.version}}/docs/devel/coding-conventions)):
|
||||
Coding style advice for contributors.
|
||||
|
||||
|
||||
## Developing against the Kubernetes API
|
||||
|
||||
* API objects are explained at [http://kubernetes.io/third_party/swagger-ui/](http://kubernetes.io/third_party/swagger-ui/).
|
||||
|
||||
* **Annotations** ([docs/user-guide/annotations.md](/{{page.version}}/docs/user-guide/annotations)): are for attaching arbitrary non-identifying metadata to objects.
|
||||
Programs that automate Kubernetes objects may use annotations to store small amounts of their state.
|
||||
|
||||
* **API Conventions** ([api-conventions.md](/{{page.version}}/docs/devel/api-conventions)):
|
||||
Defining the verbs and resources used in the Kubernetes API.
|
||||
|
||||
* **API Client Libraries** ([client-libraries.md](/{{page.version}}/docs/devel/client-libraries)):
|
||||
A list of existing client libraries, both supported and user-contributed.
|
||||
|
||||
|
||||
## Writing plugins
|
||||
|
||||
* **Authentication Plugins** ([docs/admin/authentication.md](/{{page.version}}/docs/admin/authentication)):
|
||||
The current and planned states of authentication tokens.
|
||||
|
||||
* **Authorization Plugins** ([docs/admin/authorization.md](/{{page.version}}/docs/admin/authorization)):
|
||||
Authorization applies to all HTTP requests on the main apiserver port.
|
||||
This doc explains the available authorization implementations.
|
||||
|
||||
* **Admission Control Plugins** ([admission_control](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/design/admission_control.md))
|
||||
|
||||
|
||||
## Building releases
|
||||
|
||||
* **Making release notes** ([making-release-notes.md](/{{page.version}}/docs/devel/making-release-notes)): Generating release nodes for a new release.
|
||||
|
||||
* **Releasing Kubernetes** ([releasing.md](/{{page.version}}/docs/devel/releasing)): How to create a Kubernetes release (as in version)
|
||||
and how the version information gets embedded into the built binaries.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
The following is a step-by-step guide for adding a new metric to the Kubernetes code base.
|
||||
|
||||
We use the Prometheus monitoring system's golang client library for instrumenting our code. Once you've picked out a file that you want to add a metric to, you should:
|
||||
|
||||
1. Import "github.com/prometheus/client_golang/prometheus".
|
||||
|
||||
2. Create a top-level var to define the metric. For this, you have to:
|
||||
1. Pick the type of metric. Use a Gauge for things you want to set to a particular value, a Counter for things you want to increment, or a Histogram or Summary for histograms/distributions of values (typically for latency). Histograms are better if you're going to aggregate the values across jobs, while summaries are better if you just want the job to give you a useful summary of the values.
|
||||
2. Give the metric a name and description.
|
||||
3. Pick whether you want to distinguish different categories of things using labels on the metric. If so, add "Vec" to the name of the type of metric you want and add a slice of the label names to the definition.
|
||||
|
||||
https://github.com/kubernetes/kubernetes/blob/cd3299307d44665564e1a5c77d0daa0286603ff5/pkg/apiserver/apiserver.go#L53
|
||||
https://github.com/kubernetes/kubernetes/blob/cd3299307d44665564e1a5c77d0daa0286603ff5/pkg/kubelet/metrics/metrics.go#L31
|
||||
|
||||
3. Register the metric so that prometheus will know to export it.
|
||||
|
||||
https://github.com/kubernetes/kubernetes/blob/cd3299307d44665564e1a5c77d0daa0286603ff5/pkg/kubelet/metrics/metrics.go#L74
|
||||
https://github.com/kubernetes/kubernetes/blob/cd3299307d44665564e1a5c77d0daa0286603ff5/pkg/apiserver/apiserver.go#L78
|
||||
|
||||
4. Use the metric by calling the appropriate method for your metric type (Set, Inc/Add, or Observe, respectively for Gauge, Counter, or Histogram/Summary), first calling WithLabelValues if your metric has any labels
|
||||
|
||||
https://github.com/kubernetes/kubernetes/blob/3ce7fe8310ff081dbbd3d95490193e1d5250d2c9/pkg/kubelet/kubelet.go#L1384
|
||||
https://github.com/kubernetes/kubernetes/blob/cd3299307d44665564e1a5c77d0daa0286603ff5/pkg/apiserver/apiserver.go#L87
|
||||
|
||||
|
||||
These are the metric type definitions if you're curious to learn about them or need more information:
|
||||
https://github.com/prometheus/client_golang/blob/master/prometheus/gauge.go
|
||||
https://github.com/prometheus/client_golang/blob/master/prometheus/counter.go
|
||||
https://github.com/prometheus/client_golang/blob/master/prometheus/histogram.go
|
||||
https://github.com/prometheus/client_golang/blob/master/prometheus/summary.go
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
A list quick overview of how we will review and prioritize incoming issues at https://github.com/kubernetes/kubernetes/issues
|
||||
|
||||
## Priorities
|
||||
|
||||
We will use GitHub issue labels for prioritization. The absence of a priority label means the bug has not been reviewed and prioritized yet.
|
||||
|
||||
## Definitions
|
||||
|
||||
* P0 - something broken for users, build broken, or critical security issue. Someone must drop everything and work on it.
|
||||
* P1 - must fix for earliest possible binary release (every two weeks)
|
||||
* P2 - should be fixed in next major release version
|
||||
* P3 - default priority for lower importance bugs that we still want to track and plan to fix at some point
|
||||
* design - priority/design is for issues that are used to track design discussions
|
||||
* support - priority/support is used for issues tracking user support requests
|
||||
* untriaged - anything without a priority/X label will be considered untriaged
|
|
@ -0,0 +1,96 @@
|
|||
|
||||
Updated: 8/27/2015
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
|
||||
## Principles
|
||||
|
||||
* Strive for consistency across commands
|
||||
* Explicit should always override implicit
|
||||
* Environment variables should override default values
|
||||
* Command-line flags should override default values and environment variables
|
||||
* --namespace should also override the value specified in a specified resource
|
||||
|
||||
## Command conventions
|
||||
|
||||
* Command names are all lowercase, and hyphenated if multiple words.
|
||||
* kubectl VERB NOUNs for commands that apply to multiple resource types
|
||||
* NOUNs may be specified as TYPE name1 name2 ... or TYPE/name1 TYPE/name2; TYPE is omitted when only a single type is expected
|
||||
* Resource types are all lowercase, with no hyphens; both singular and plural forms are accepted
|
||||
* NOUNs may also be specified by one or more file arguments: -f file1 -f file2 ...
|
||||
* Resource types may have 2- or 3-letter aliases.
|
||||
* Business logic should be decoupled from the command framework, so that it can be reused independently of kubectl, cobra, etc.
|
||||
* Ideally, commonly needed functionality would be implemented server-side in order to avoid problems typical of "fat" clients and to make it readily available to non-Go clients
|
||||
* Commands that generate resources, such as `run` or `expose`, should obey the following conventions:
|
||||
* Flags should be converted to a parameter Go map or json map prior to invoking the generator
|
||||
* The generator must be versioned so that users depending on a specific behavior may pin to that version, via `--generator=`
|
||||
* Generation should be decoupled from creation
|
||||
* `--dry-run` should output the resource that would be created, without creating it
|
||||
* A command group (e.g., `kubectl config`) may be used to group related non-standard commands, such as custom generators, mutations, and computations
|
||||
|
||||
## Flag conventions
|
||||
|
||||
* Flags are all lowercase, with words separated by hyphens
|
||||
* Flag names and single-character aliases should have the same meaning across all commands
|
||||
* Command-line flags corresponding to API fields should accept API enums exactly (e.g., --restart=Always)
|
||||
* Do not reuse flags for different semantic purposes, and do not use different flag names for the same semantic purpose -- grep for `"Flags()"` before adding a new flag
|
||||
* Use short flags sparingly, only for the most frequently used options, prefer lowercase over uppercase for the most common cases, try to stick to well known conventions for UNIX commands and/or Docker, where they exist, and update this list when adding new short flags
|
||||
* `-f`: Resource file
|
||||
* also used for `--follow` in `logs`, but should be deprecated in favor of `-F`
|
||||
* `-l`: Label selector
|
||||
* also used for `--labels` in `expose`, but should be deprecated
|
||||
* `-L`: Label columns
|
||||
* `-c`: Container
|
||||
* also used for `--client` in `version`, but should be deprecated
|
||||
* `-i`: Attach stdin
|
||||
* `-t`: Allocate TTY
|
||||
* also used for `--template`, but deprecated
|
||||
* `-w`: Watch (currently also used for `--www` in `proxy`, but should be deprecated)
|
||||
* `-p`: Previous
|
||||
* also used for `--pod` in `exec`, but deprecated
|
||||
* also used for `--patch` in `patch`, but should be deprecated
|
||||
* also used for `--port` in `proxy`, but should be deprecated
|
||||
* `-P`: Static file prefix in `proxy`, but should be deprecated
|
||||
* `-r`: Replicas
|
||||
* `-u`: Unix socket
|
||||
* `-v`: Verbose logging level
|
||||
* `--dry-run`: Don't modify the live state; simulate the mutation and display the output
|
||||
* `--local`: Don't contact the server; just do local read, transformation, generation, etc. and display the output
|
||||
* `--output-version=...`: Convert the output to a different API group/version
|
||||
* `--validate`: Validate the resource schema
|
||||
|
||||
## Output conventions
|
||||
|
||||
* By default, output is intended for humans rather than programs
|
||||
* However, affordances are made for simple parsing of `get` output
|
||||
* Only errors should be directed to stderr
|
||||
* `get` commands should output one row per resource, and one resource per row
|
||||
* Column titles and values should not contain spaces in order to facilitate commands that break lines into fields: cut, awk, etc.
|
||||
* By default, `get` output should fit within about 80 columns
|
||||
* Eventually we could perhaps auto-detect width
|
||||
* `-o wide` may be used to display additional columns
|
||||
* The first column should be the resource name, titled `NAME` (may change this to an abbreviation of resource type)
|
||||
* NAMESPACE should be displayed as the first column when --all-namespaces is specified
|
||||
* The last default column should be time since creation, titled `AGE`
|
||||
* `-Lkey` should append a column containing the value of label with key `key`, with `<none>` if not present
|
||||
* json, yaml, Go template, and jsonpath template formats should be supported and encouraged for subsequent processing
|
||||
* Users should use --api-version or --output-version to ensure the output uses the version they expect
|
||||
* `describe` commands may output on multiple lines and may include information from related resources, such as events. Describe should add additional information from related resources that a normal user may need to know - if a user would always run "describe resource1" and the immediately want to run a "get type2" or "describe resource2", consider including that info. Examples, persistent volume claims for pods that reference claims, events for most resources, nodes and the pods scheduled on them. When fetching related resources, a targeted field selector should be used in favor of client side filtering of related resources.
|
||||
* Mutations should output TYPE/name verbed by default, where TYPE is singular; `-o name` may be used to just display TYPE/name, which may be used to specify resources in other commands
|
||||
|
||||
## Documentation conventions
|
||||
|
||||
* Commands are documented using Cobra; docs are then auto-generated by `hack/update-generated-docs.sh`.
|
||||
* Use should contain a short usage string for the most common use case(s), not an exhaustive specification
|
||||
* Short should contain a one-line explanation of what the command does
|
||||
* Long may contain multiple lines, including additional information about input, output, commonly used flags, etc.
|
||||
* Example should contain examples
|
||||
* Start commands with `$`
|
||||
* A comment should precede each example command, and should begin with `#`
|
||||
* Use "FILENAME" for filenames
|
||||
* Use "TYPE" for the particular flavor of resource type accepted by kubectl, rather than "RESOURCE" or "KIND"
|
||||
* Use "NAME" for resource names
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
The following conventions for the glog levels to use. [glog](http://godoc.org/github.com/golang/glog) is globally preferred to [log](http://golang.org/pkg/log/) for better runtime control.
|
||||
|
||||
* glog.Errorf() - Always an error
|
||||
* glog.Warningf() - Something unexpected, but probably not an error
|
||||
* glog.Infof() has multiple levels:
|
||||
* glog.V(0) - Generally useful for this to ALWAYS be visible to an operator
|
||||
* Programmer errors
|
||||
* Logging extra info about a panic
|
||||
* CLI argument handling
|
||||
* glog.V(1) - A reasonable default log level if you don't want verbosity.
|
||||
* Information about config (listening on X, watching Y)
|
||||
* Errors that repeat frequently that relate to conditions that can be corrected (pod detected as unhealthy)
|
||||
* glog.V(2) - Useful steady state information about the service and important log messages that may correlate to significant changes in the system. This is the recommended default log level for most systems.
|
||||
* Logging HTTP requests and their exit code
|
||||
* System state changing (killing pod)
|
||||
* Controller state change events (starting pods)
|
||||
* Scheduler log messages
|
||||
* glog.V(3) - Extended information about changes
|
||||
* More info about system state changes
|
||||
* glog.V(4) - Debug level verbosity (for now)
|
||||
* Logging in particularly thorny parts of code where you may want to come back later and check it
|
||||
|
||||
As per the comments, the practical default level is V(2). Developers and QE environments may wish to run at V(3) or V(4). If you wish to change the log level, you can pass in `-v=X` where X is the desired maximum level to log.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
This documents the process for making release notes for a release.
|
||||
|
||||
### 1) Note the PR number of the previous release
|
||||
|
||||
Find the most-recent PR that was merged with the previous .0 release. Remember this as $LASTPR.
|
||||
_TODO_: Figure out a way to record this somewhere to save the next release engineer time.
|
||||
|
||||
Find the most-recent PR that was merged with the current .0 release. Remember this as $CURRENTPR.
|
||||
|
||||
### 2) Run the release-notes tool
|
||||
|
||||
```shell
|
||||
${KUBERNETES_ROOT}/build/make-release-notes.sh $LASTPR $CURRENTPR
|
||||
```
|
||||
|
||||
### 3) Trim the release notes
|
||||
|
||||
This generates a list of the entire set of PRs merged since the last minor
|
||||
release. It is likely long and many PRs aren't worth mentioning. If any of the
|
||||
PRs were cherrypicked into patches on the last minor release, you should exclude
|
||||
them from the current release's notes.
|
||||
|
||||
Open up `candidate-notes.md` in your favorite editor.
|
||||
|
||||
Remove, regroup, organize to your hearts content.
|
||||
|
||||
|
||||
### 4) Update CHANGELOG.md
|
||||
|
||||
With the final markdown all set, cut and paste it to the top of `CHANGELOG.md`
|
||||
|
||||
### 5) Update the Release page
|
||||
|
||||
* Switch to the [releases](https://github.com/kubernetes/kubernetes/releases) page.
|
||||
* Open up the release you are working on.
|
||||
* Cut and paste the final markdown from above into the release notes
|
||||
* Press Save.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
This document explain how to plug in profiler and how to profile Kubernetes services.
|
||||
|
||||
## Profiling library
|
||||
|
||||
Go comes with inbuilt 'net/http/pprof' profiling library and profiling web service. The way service works is binding debug/pprof/ subtree on a running webserver to the profiler. Reading from subpages of debug/pprof returns pprof-formatted profiles of the running binary. The output can be processed offline by the tool of choice, or used as an input to handy 'go tool pprof', which can graphically represent the result.
|
||||
|
||||
## Adding profiling to services to APIserver.
|
||||
|
||||
TL;DR: Add lines:
|
||||
|
||||
```go
|
||||
m.mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
m.mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
m.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
```
|
||||
|
||||
to the init(c *Config) method in 'pkg/master/master.go' and import 'net/http/pprof' package.
|
||||
|
||||
In most use cases to use profiler service it's enough to do 'import _ net/http/pprof', which automatically registers a handler in the default http.Server. Slight inconvenience is that APIserver uses default server for intra-cluster communication, so plugging profiler to it is not really useful. In 'pkg/master/server/server.go' more servers are created and started as separate goroutines. The one that is usually serving external traffic is secureServer. The handler for this traffic is defined in 'pkg/master/master.go' and stored in Handler variable. It is created from HTTP multiplexer, so the only thing that needs to be done is adding profiler handler functions to this multiplexer. This is exactly what lines after TL;DR do.
|
||||
|
||||
## Connecting to the profiler
|
||||
|
||||
Even when running profiler I found not really straightforward to use 'go tool pprof' with it. The problem is that at least for dev purposes certificates generated for APIserver are not signed by anyone trusted and because secureServer serves only secure traffic it isn't straightforward to connect to the service. The best workaround I found is by creating an ssh tunnel from the kubernetes_master open unsecured port to some external server, and use this server as a proxy. To save everyone looking for correct ssh flags, it is done by running:
|
||||
|
||||
```shell
|
||||
ssh kubernetes_master -L<local_port>:localhost:8080
|
||||
```
|
||||
|
||||
or analogous one for you Cloud provider. Afterwards you can e.g. run
|
||||
|
||||
```shell
|
||||
go tool pprof http://localhost:<local_port>/debug/pprof/profile
|
||||
```
|
||||
|
||||
to get 30 sec. CPU profile.
|
||||
|
||||
## Contention profiling
|
||||
|
||||
To enable contention profiling you need to add line `rt.SetBlockProfileRate(1)` in addition to `m.mux.HandleFunc(...)` added before (`rt` stands for `runtime` in `master.go`). This enables 'debug/pprof/block' subpage, which can be used as an input to `go tool pprof`.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
An overview of how we will manage old or out-of-date pull requests.
|
||||
|
||||
## Process
|
||||
|
||||
We will close any pull requests older than two weeks.
|
||||
|
||||
Exceptions can be made for PRs that have active review comments, or that are awaiting other dependent PRs. Closed pull requests are easy to recreate, and little work is lost by closing a pull request that subsequently needs to be reopened.
|
||||
|
||||
We want to limit the total number of PRs in flight to:
|
||||
* Maintain a clean project
|
||||
* Remove old PRs that would be difficult to rebase as the underlying code has changed over time
|
||||
* Encourage code velocity
|
||||
|
||||
## Life of a Pull Request
|
||||
|
||||
Unless in the last few weeks of a milestone when we need to reduce churn and stabilize, we aim to be always accepting pull requests.
|
||||
|
||||
Either the [on call](https://github.com/kubernetes/kubernetes/wiki/Kubernetes-on-call-rotation) manually or the [submit queue](https://github.com/kubernetes/contrib/tree/master/submit-queue) automatically will manage merging PRs.
|
||||
|
||||
There are several requirements for the submit queue to work:
|
||||
* Author must have signed CLA ("cla: yes" label added to PR)
|
||||
* No changes can be made since last lgtm label was applied
|
||||
* k8s-bot must have reported the GCE E2E build and test steps passed (Travis, Shippable and Jenkins build)
|
||||
|
||||
Additionally, for infrequent or new contributors, we require the on call to apply the "ok-to-merge" label manually. This is gated by the [whitelist](https://github.com/kubernetes/contrib/tree/master/submit-queue/whitelist.txt).
|
||||
|
||||
## Automation
|
||||
|
||||
We use a variety of automation to manage pull requests. This automation is described in detail
|
||||
[elsewhere.](/{{page.version}}/docs/devel/automation)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
|
||||
This document explains how to cut a release, and the theory behind it. If you
|
||||
just want to cut a release and move on with your life, you can stop reading
|
||||
after the first section.
|
||||
|
||||
## How to cut a Kubernetes release
|
||||
|
||||
Regardless of whether you are cutting a major or minor version, cutting a
|
||||
release breaks down into four pieces:
|
||||
|
||||
1. Selecting release components.
|
||||
1. Tagging and merging the release in Git.
|
||||
1. Building and pushing the binaries.
|
||||
1. Writing release notes.
|
||||
|
||||
You should progress in this strict order.
|
||||
|
||||
### Building a New Major/Minor Version (`vX.Y.0`)
|
||||
|
||||
#### Selecting Release Components
|
||||
|
||||
When cutting a major/minor release, your first job is to find the branch
|
||||
point. We cut `vX.Y.0` releases directly from `master`, which is also the
|
||||
branch that we have most continuous validation on. Go first to [the main GCE
|
||||
Jenkins end-to-end job](http://go/k8s-test/job/kubernetes-e2e-gce) and next to [the
|
||||
Critical Builds page](http://go/k8s-test/view/Critical%20Builds) and hopefully find a
|
||||
recent Git hash that looks stable across at least `kubernetes-e2e-gce` and
|
||||
`kubernetes-e2e-gke-ci`. First glance through builds and look for nice solid
|
||||
rows of green builds, and then check temporally with the other Critical Builds
|
||||
to make sure they're solid around then as well. Once you find some greens, you
|
||||
can find the Git hash for a build by looking at the "Console Log", then look for
|
||||
`githash=`. You should see a line line:
|
||||
|
||||
```shell
|
||||
+ githash=v0.20.2-322-g974377b
|
||||
```
|
||||
|
||||
Because Jenkins builds frequently, if you're looking between jobs
|
||||
(e.g. `kubernetes-e2e-gke-ci` and `kubernetes-e2e-gce`), there may be no single
|
||||
`githash` that's been run on both jobs. In that case, take the a green
|
||||
`kubernetes-e2e-gce` build (but please check that it corresponds to a temporally
|
||||
similar build that's green on `kubernetes-e2e-gke-ci`). Lastly, if you're having
|
||||
trouble understanding why the GKE continuous integration clusters are failing
|
||||
and you're trying to cut a release, don't hesitate to contact the GKE
|
||||
oncall.
|
||||
|
||||
Before proceeding to the next step:
|
||||
|
||||
```shell
|
||||
export BRANCHPOINT=v0.20.2-322-g974377b
|
||||
```
|
||||
|
||||
Where `v0.20.2-322-g974377b` is the git hash you decided on. This will become
|
||||
our (retroactive) branch point.
|
||||
|
||||
#### Branching, Tagging and Merging
|
||||
|
||||
Do the following:
|
||||
|
||||
1. `export VER=x.y` (e.g. `0.20` for v0.20)
|
||||
1. cd to the base of the repo
|
||||
1. `git fetch upstream && git checkout -b release-${VER} ${BRANCHPOINT}` (you did set `${BRANCHPOINT}`, right?)
|
||||
1. Make sure you don't have any files you care about littering your repo (they
|
||||
better be checked in or outside the repo, or the next step will delete them).
|
||||
1. `make clean && git reset --hard HEAD && git clean -xdf`
|
||||
1. `make` (TBD: you really shouldn't have to do this, but the swagger output step requires it right now)
|
||||
1. `./build/mark-new-version.sh v${VER}.0` to mark the new release and get further
|
||||
instructions. This creates a series of commits on the branch you're working
|
||||
on (`release-${VER}`), including forking our documentation for the release,
|
||||
the release version commit (which is then tagged), and the post-release
|
||||
version commit.
|
||||
1. Follow the instructions given to you by that script. They are canon for the
|
||||
remainder of the Git process. If you don't understand something in that
|
||||
process, please ask!
|
||||
|
||||
**TODO**: how to fix tags, etc., if you have to shift the release branchpoint.
|
||||
|
||||
#### Building and Pushing Binaries
|
||||
|
||||
In your git repo (you still have `${VER}` set from above right?):
|
||||
|
||||
1. `git checkout upstream/master && build/build-official-release.sh v${VER}.0` (the `build-official-release.sh` script is version agnostic, so it's best to run it off `master` directly).
|
||||
1. Follow the instructions given to you by that script.
|
||||
1. At this point, you've done all the Git bits, you've got all the binary bits pushed, and you've got the template for the release started on GitHub.
|
||||
|
||||
#### Writing Release Notes
|
||||
|
||||
[This helpful guide](/{{page.version}}/docs/devel/making-release-notes) describes how to write release
|
||||
notes for a major/minor release. In the release template on GitHub, leave the
|
||||
last PR number that the tool finds for the `.0` release, so the next releaser
|
||||
doesn't have to hunt.
|
||||
|
||||
### Building a New Patch Release (`vX.Y.Z` for `Z > 0`)
|
||||
|
||||
#### Selecting Release Components
|
||||
|
||||
We cut `vX.Y.Z` releases from the `release-vX.Y` branch after all cherry picks
|
||||
to the branch have been resolved. You should ensure all outstanding cherry picks
|
||||
have been reviewed and merged and the branch validated on Jenkins (validation
|
||||
TBD). See the [Cherry Picks](/{{page.version}}/docs/devel/cherry-picks) for more information on how to
|
||||
manage cherry picks prior to cutting the release.
|
||||
|
||||
#### Tagging and Merging
|
||||
|
||||
1. `export VER=x.y` (e.g. `0.20` for v0.20)
|
||||
1. `export PATCH=Z` where `Z` is the patch level of `vX.Y.Z`
|
||||
1. cd to the base of the repo
|
||||
1. `git fetch upstream && git checkout -b upstream/release-${VER} release-${VER}`
|
||||
1. Make sure you don't have any files you care about littering your repo (they
|
||||
better be checked in or outside the repo, or the next step will delete them).
|
||||
1. `make clean && git reset --hard HEAD && git clean -xdf`
|
||||
1. `make` (TBD: you really shouldn't have to do this, but the swagger output step requires it right now)
|
||||
1. `./build/mark-new-version.sh v${VER}.${PATCH}` to mark the new release and get further
|
||||
instructions. This creates a series of commits on the branch you're working
|
||||
on (`release-${VER}`), including forking our documentation for the release,
|
||||
the release version commit (which is then tagged), and the post-release
|
||||
version commit.
|
||||
1. Follow the instructions given to you by that script. They are canon for the
|
||||
remainder of the Git process. If you don't understand something in that
|
||||
process, please ask! When proposing PRs, you can pre-fill the body with
|
||||
`hack/cherry_pick_list.sh upstream/release-${VER}` to inform people of what
|
||||
is already on the branch.
|
||||
|
||||
**TODO**: how to fix tags, etc., if the release is changed.
|
||||
|
||||
#### Building and Pushing Binaries
|
||||
|
||||
In your git repo (you still have `${VER}` and `${PATCH}` set from above right?):
|
||||
|
||||
1. `git checkout upstream/master && build/build-official-release.sh
|
||||
v${VER}.${PATCH}` (the `build-official-release.sh` script is version
|
||||
agnostic, so it's best to run it off `master` directly).
|
||||
1. Follow the instructions given to you by that script. At this point, you've
|
||||
done all the Git bits, you've got all the binary bits pushed, and you've got
|
||||
the template for the release started on GitHub.
|
||||
|
||||
#### Writing Release Notes
|
||||
|
||||
Run `hack/cherry_pick_list.sh ${VER}.${PATCH}~1` to get the release notes for
|
||||
the patch release you just created. Feel free to prune anything internal, like
|
||||
you would for a major release, but typically for patch releases we tend to
|
||||
include everything in the release notes.
|
||||
|
||||
## Origin of the Sources
|
||||
|
||||
Kubernetes may be built from either a git tree (using `hack/build-go.sh`) or
|
||||
from a tarball (using either `hack/build-go.sh` or `go install`) or directly by
|
||||
the Go native build system (using `go get`).
|
||||
|
||||
When building from git, we want to be able to insert specific information about
|
||||
the build tree at build time. In particular, we want to use the output of `git
|
||||
describe` to generate the version of Kubernetes and the status of the build
|
||||
tree (add a `-dirty` prefix if the tree was modified.)
|
||||
|
||||
When building from a tarball or using the Go build system, we will not have
|
||||
access to the information about the git tree, but we still want to be able to
|
||||
tell whether this build corresponds to an exact release (e.g. v0.3) or is
|
||||
between releases (e.g. at some point in development between v0.3 and v0.4).
|
||||
|
||||
## Version Number Format
|
||||
|
||||
In order to account for these use cases, there are some specific formats that
|
||||
may end up representing the Kubernetes version. Here are a few examples:
|
||||
|
||||
- **v0.5**: This is official version 0.5 and this version will only be used
|
||||
when building from a clean git tree at the v0.5 git tag, or from a tree
|
||||
extracted from the tarball corresponding to that specific release.
|
||||
- **v0.5-15-g0123abcd4567**: This is the `git describe` output and it indicates
|
||||
that we are 15 commits past the v0.5 release and that the SHA1 of the commit
|
||||
where the binaries were built was `0123abcd4567`. It is only possible to have
|
||||
this level of detail in the version information when building from git, not
|
||||
when building from a tarball.
|
||||
- **v0.5-15-g0123abcd4567-dirty** or **v0.5-dirty**: The extra `-dirty` prefix
|
||||
means that the tree had local modifications or untracked files at the time of
|
||||
the build, so there's no guarantee that the source code matches exactly the
|
||||
state of the tree at the `0123abcd4567` commit or at the `v0.5` git tag
|
||||
(resp.)
|
||||
- **v0.5-dev**: This means we are building from a tarball or using `go get` or,
|
||||
if we have a git tree, we are using `go install` directly, so it is not
|
||||
possible to inject the git version into the build information. Additionally,
|
||||
this is not an official release, so the `-dev` prefix indicates that the
|
||||
version we are building is after `v0.5` but before `v0.6`. (There is actually
|
||||
an exception where a commit with `v0.5-dev` is not present on `v0.6`, see
|
||||
later for details.)
|
||||
|
||||
## Injecting Version into Binaries
|
||||
|
||||
In order to cover the different build cases, we start by providing information
|
||||
that can be used when using only Go build tools or when we do not have the git
|
||||
version information available.
|
||||
|
||||
To be able to provide a meaningful version in those cases, we set the contents
|
||||
of variables in a Go source file that will be used when no overrides are
|
||||
present.
|
||||
|
||||
We are using `pkg/version/base.go` as the source of versioning in absence of
|
||||
information from git. Here is a sample of that file's contents:
|
||||
|
||||
```go
|
||||
var (
|
||||
gitVersion string = "v0.4-dev" // version from git, output of $(git describe)
|
||||
gitCommit string = "" // sha1 from git, output of $(git rev-parse HEAD)
|
||||
)
|
||||
```
|
||||
|
||||
This means a build with `go install` or `go get` or a build from a tarball will
|
||||
yield binaries that will identify themselves as `v0.4-dev` and will not be able
|
||||
to provide you with a SHA1.
|
||||
|
||||
To add the extra versioning information when building from git, the
|
||||
`hack/build-go.sh` script will gather that information (using `git describe` and
|
||||
`git rev-parse`) and then create a `-ldflags` string to pass to `go install` and
|
||||
tell the Go linker to override the contents of those variables at build time. It
|
||||
can, for instance, tell it to override `gitVersion` and set it to
|
||||
`v0.4-13-g4567bcdef6789-dirty` and set `gitCommit` to `4567bcdef6789...` which
|
||||
is the complete SHA1 of the (dirty) tree used at build time.
|
||||
|
||||
## Handling Official Versions
|
||||
|
||||
Handling official versions from git is easy, as long as there is an annotated
|
||||
git tag pointing to a specific version then `git describe` will return that tag
|
||||
exactly which will match the idea of an official version (e.g. `v0.5`).
|
||||
|
||||
Handling it on tarballs is a bit harder since the exact version string must be
|
||||
present in `pkg/version/base.go` for it to get embedded into the binaries. But
|
||||
simply creating a commit with `v0.5` on its own would mean that the commits
|
||||
coming after it would also get the `v0.5` version when built from tarball or `go
|
||||
get` while in fact they do not match `v0.5` (the one that was tagged) exactly.
|
||||
|
||||
To handle that case, creating a new release should involve creating two adjacent
|
||||
commits where the first of them will set the version to `v0.5` and the second
|
||||
will set it to `v0.5-dev`. In that case, even in the presence of merges, there
|
||||
will be a single commit where the exact `v0.5` version will be used and all
|
||||
others around it will either have `v0.4-dev` or `v0.5-dev`.
|
||||
|
||||
The diagram below illustrates it.
|
||||
|
||||

|
||||
|
||||
After working on `v0.4-dev` and merging PR 99 we decide it is time to release
|
||||
`v0.5`. So we start a new branch, create one commit to update
|
||||
`pkg/version/base.go` to include `gitVersion = "v0.5"` and `git commit` it.
|
||||
|
||||
We test it and make sure everything is working as expected.
|
||||
|
||||
Before sending a PR for it, we create a second commit on that same branch,
|
||||
updating `pkg/version/base.go` to include `gitVersion = "v0.5-dev"`. That will
|
||||
ensure that further builds (from tarball or `go install`) on that tree will
|
||||
always include the `-dev` prefix and will not have a `v0.5` version (since they
|
||||
do not match the official `v0.5` exactly.)
|
||||
|
||||
We then send PR 100 with both commits in it.
|
||||
|
||||
Once the PR is accepted, we can use `git tag -a` to create an annotated tag
|
||||
*pointing to the one commit* that has `v0.5` in `pkg/version/base.go` and push
|
||||
it to GitHub. (Unfortunately GitHub tags/releases are not annotated tags, so
|
||||
this needs to be done from a git client and pushed to GitHub using SSH or
|
||||
HTTPS.)
|
||||
|
||||
## Parallel Commits
|
||||
|
||||
While we are working on releasing `v0.5`, other development takes place and
|
||||
other PRs get merged. For instance, in the example above, PRs 101 and 102 get
|
||||
merged to the master branch before the versioning PR gets merged.
|
||||
|
||||
This is not a problem, it is only slightly inaccurate that checking out the tree
|
||||
at commit `012abc` or commit `345cde` or at the commit of the merges of PR 101
|
||||
or 102 will yield a version of `v0.4-dev` *but* those commits are not present in
|
||||
`v0.5`.
|
||||
|
||||
In that sense, there is a small window in which commits will get a
|
||||
`v0.4-dev` or `v0.4-N-gXXX` label and while they're indeed later than `v0.4`
|
||||
but they are not really before `v0.5` in that `v0.5` does not contain those
|
||||
commits.
|
||||
|
||||
Unfortunately, there is not much we can do about it. On the other hand, other
|
||||
projects seem to live with that and it does not really become a large problem.
|
||||
|
||||
As an example, Docker commit a327d9b91edf has a `v1.1.1-N-gXXX` label but it is
|
||||
not present in Docker `v1.2.0`:
|
||||
|
||||
```shell
|
||||
$ git describe a327d9b91edf
|
||||
v1.1.1-822-ga327d9b91edf
|
||||
|
||||
$ git log --oneline v1.2.0..a327d9b91edf
|
||||
a327d9b91edf Fix data space reporting from Kb/Mb to KB/MB
|
||||
|
||||
(Non-empty output here means the commit is not present on v1.2.0.)
|
||||
```
|
||||
|
||||
## Release Notes
|
||||
|
||||
No official release should be made final without properly matching release notes.
|
||||
|
||||
There should be made available, per release, a small summary, preamble, of the
|
||||
major changes, both in terms of feature improvements/bug fixes and notes about
|
||||
functional feature changes (if any) regarding the previous released version so
|
||||
that the BOM regarding updating to it gets as obvious and trouble free as possible.
|
||||
|
||||
After this summary, preamble, all the relevant PRs/issues that got in that
|
||||
version should be listed and linked together with a small summary understandable
|
||||
by plain mortals (in a perfect world PR/issue's title would be enough but often
|
||||
it is just too cryptic/geeky/domain-specific that it isn't).
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
The Kubernetes scheduler runs as a process alongside the other master
|
||||
components such as the API server. Its interface to the API server is to watch
|
||||
for Pods with an empty PodSpec.NodeName, and for each Pod, it posts a Binding
|
||||
indicating where the Pod should be scheduled.
|
||||
|
||||
## The scheduling process
|
||||
|
||||
The scheduler tries to find a node for each Pod, one at a time, as it notices
|
||||
these Pods via watch. There are three steps. First it applies a set of "predicates" that filter out
|
||||
inappropriate nodes. For example, if the PodSpec specifies resource requests, then the scheduler
|
||||
will filter out nodes that don't have at least that much resources available (computed
|
||||
as the capacity of the node minus the sum of the resource requests of the containers that
|
||||
are already running on the node). Second, it applies a set of "priority functions"
|
||||
that rank the nodes that weren't filtered out by the predicate check. For example,
|
||||
it tries to spread Pods across nodes while at the same time favoring the least-loaded
|
||||
nodes (where "load" here is sum of the resource requests of the containers running on the node,
|
||||
divided by the node's capacity).
|
||||
Finally, the node with the highest priority is chosen
|
||||
(or, if there are multiple such nodes, then one of them is chosen at random). The code
|
||||
for this main scheduling loop is in the function `Schedule()` in
|
||||
[plugin/pkg/scheduler/generic_scheduler.go](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/generic_scheduler.go)
|
||||
|
||||
## Scheduler extensibility
|
||||
|
||||
The scheduler is extensible: the cluster administrator can choose which of the pre-defined
|
||||
scheduling policies to apply, and can add new ones. The built-in predicates and priorities are
|
||||
defined in [plugin/pkg/scheduler/algorithm/predicates/predicates.go](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/algorithm/predicates/predicates.go) and
|
||||
[plugin/pkg/scheduler/algorithm/priorities/priorities.go](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/algorithm/priorities/priorities.go), respectively.
|
||||
The policies that are applied when scheduling can be chosen in one of two ways. Normally,
|
||||
the policies used are selected by the functions `defaultPredicates()` and `defaultPriorities()` in
|
||||
[plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go).
|
||||
However, the choice of policies
|
||||
can be overridden by passing the command-line flag `--policy-config-file` to the scheduler, pointing to a JSON
|
||||
file specifying which scheduling policies to use. See
|
||||
[examples/scheduler-policy-config.json](https://github.com/kubernetes/kubernetes/tree/{{page.githubbranch}}/examples/scheduler-policy-config.json) for an example
|
||||
config file. (Note that the config file format is versioned; the API is defined in
|
||||
[plugin/pkg/scheduler/api](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/api/)).
|
||||
Thus to add a new scheduling policy, you should modify predicates.go or priorities.go,
|
||||
and either register the policy in `defaultPredicates()` or `defaultPriorities()`, or use a policy config file.
|
||||
|
||||
## Exploring the code
|
||||
|
||||
If you want to get a global picture of how the scheduler works, you can start in
|
||||
[plugin/cmd/kube-scheduler/app/server.go](http://releases.k8s.io/{{page.githubbranch}}/plugin/cmd/kube-scheduler/app/server.go)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
For each unscheduled Pod, the Kubernetes scheduler tries to find a node across the cluster according to a set of rules. A general introduction to the Kubernetes scheduler can be found at [scheduler.md](/{{page.version}}/docs/devel/scheduler). In this document, the algorithm of how to select a node for the Pod is explained. There are two steps before a destination node of a Pod is chosen. The first step is filtering all the nodes and the second is ranking the remaining nodes to find a best fit for the Pod.
|
||||
|
||||
## Filtering the nodes
|
||||
|
||||
The purpose of filtering the nodes is to filter out the nodes that do not meet certain requirements of the Pod. For example, if the free resource on a node (measured by the capacity minus the sum of the resource requests of all the Pods that already run on the node) is less than the Pod's required resource, the node should not be considered in the ranking phase so it is filtered out. Currently, there are several "predicates" implementing different filtering policies, including:
|
||||
|
||||
- `NoDiskConflict`: Evaluate if a pod can fit due to the volumes it requests, and those that are already mounted.
|
||||
- `PodFitsResources`: Check if the free resource (CPU and Memory) meets the requirement of the Pod. The free resource is measured by the capacity minus the sum of requests of all Pods on the node. To learn more about the resource QoS in Kubernetes, please check [QoS proposal](https://github.com/kubernetes/kubernetes/blob/{{page.githubbranch}}/docs/proposals/resource-qos.md).
|
||||
- `PodFitsHostPorts`: Check if any HostPort required by the Pod is already occupied on the node.
|
||||
- `PodFitsHost`: Filter out all nodes except the one specified in the PodSpec's NodeName field.
|
||||
- `PodSelectorMatches`: Check if the labels of the node match the labels specified in the Pod's `nodeSelector` field ([Here](/{{page.version}}/docs/user-guide/node-selection/) is an example of how to use `nodeSelector` field).
|
||||
- `CheckNodeLabelPresence`: Check if all the specified labels exist on a node or not, regardless of the value.
|
||||
|
||||
The details of the above predicates can be found in [plugin/pkg/scheduler/algorithm/predicates/predicates.go](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/algorithm/predicates/predicates.go). All predicates mentioned above can be used in combination to perform a sophisticated filtering policy. Kubernetes uses some, but not all, of these predicates by default. You can see which ones are used by default in [plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go).
|
||||
|
||||
## Ranking the nodes
|
||||
|
||||
The filtered nodes are considered suitable to host the Pod, and it is often that there are more than one nodes remaining. Kubernetes prioritizes the remaining nodes to find the "best" one for the Pod. The prioritization is performed by a set of priority functions. For each remaining node, a priority function gives a score which scales from 0-10 with 10 representing for "most preferred" and 0 for "least preferred". Each priority function is weighted by a positive number and the final score of each node is calculated by adding up all the weighted scores. For example, suppose there are two priority functions, `priorityFunc1` and `priorityFunc2` with weighting factors `weight1` and `weight2` respectively, the final score of some NodeA is:
|
||||
|
||||
finalScoreNodeA = (weight1 * priorityFunc1) + (weight2 * priorityFunc2)
|
||||
|
||||
After the scores of all nodes are calculated, the node with highest score is chosen as the host of the Pod. If there are more than one nodes with equal highest scores, a random one among them is chosen.
|
||||
|
||||
Currently, Kubernetes scheduler provides some practical priority functions, including:
|
||||
|
||||
- `LeastRequestedPriority`: The node is prioritized based on the fraction of the node that would be free if the new Pod were scheduled onto the node. (In other words, (capacity - sum of requests of all Pods already on the node - request of Pod that is being scheduled) / capacity). CPU and memory are equally weighted. The node with the highest free fraction is the most preferred. Note that this priority function has the effect of spreading Pods across the nodes with respect to resource consumption.
|
||||
- `CalculateNodeLabelPriority`: Prefer nodes that have the specified label.
|
||||
- `BalancedResourceAllocation`: This priority function tries to put the Pod on a node such that the CPU and Memory utilization rate is balanced after the Pod is deployed.
|
||||
- `CalculateSpreadPriority`: Spread Pods by minimizing the number of Pods belonging to the same service on the same node.
|
||||
- `CalculateAntiAffinityPriority`: Spread Pods by minimizing the number of Pods belonging to the same service on nodes with the same value for a particular label.
|
||||
|
||||
The details of the above priority functions can be found in [plugin/pkg/scheduler/algorithm/priorities](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/algorithm/priorities/). Kubernetes uses some, but not all, of these priority functions by default. You can see which ones are used by default in [plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go](http://releases.k8s.io/{{page.githubbranch}}/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go). Similar as predicates, you can combine the above priority functions and assign weight factors (positive number) to them as you want (check [scheduler.md](/{{page.version}}/docs/devel/scheduler) for how to customize).
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
This page gives some advice for anyone planning to write or update a Getting Started Guide for Kubernetes.
|
||||
It also gives some guidelines which reviewers should follow when reviewing a pull request for a
|
||||
guide.
|
||||
|
||||
A Getting Started Guide is instructions on how to create a Kubernetes cluster on top of a particular
|
||||
type(s) of infrastructure. Infrastructure includes: the IaaS provider for VMs;
|
||||
the node OS; inter-node networking; and node Configuration Management system.
|
||||
A guide refers to scripts, Configuration Management files, and/or binary assets such as RPMs. We call
|
||||
the combination of all these things needed to run on a particular type of infrastructure a
|
||||
**distro**.
|
||||
|
||||
[The Matrix](/{{page.version}}/docs/getting-started-guides/) lists the distros. If there is already a guide
|
||||
which is similar to the one you have planned, consider improving that one.
|
||||
|
||||
|
||||
Distros fall into two categories:
|
||||
|
||||
- **versioned distros** are tested to work with a particular binary release of Kubernetes. These
|
||||
come in a wide variety, reflecting a wide range of ideas and preferences in how to run a cluster.
|
||||
- **development distros** are tested work with the latest Kubernetes source code. But, there are
|
||||
relatively few of these and the bar is much higher for creating one. They must support
|
||||
fully automated cluster creation, deletion, and upgrade.
|
||||
|
||||
There are different guidelines for each.
|
||||
|
||||
## Versioned Distro Guidelines
|
||||
|
||||
These guidelines say *what* to do. See the Rationale section for *why*.
|
||||
|
||||
- Send us a PR.
|
||||
- Put the instructions in `docs/getting-started-guides/...`. Scripts go there too. This helps devs easily
|
||||
search for uses of flags by guides.
|
||||
- We may ask that you host binary assets or large amounts of code in our `contrib` directory or on your
|
||||
own repo.
|
||||
- Add or update a row in [The Matrix](/{{page.version}}/docs/getting-started-guides/).
|
||||
- State the binary version of Kubernetes that you tested clearly in your Guide doc.
|
||||
- Setup a cluster and run the [conformance test](/{{page.version}}/docs/devel/development/#conformance-testing) against it, and report the
|
||||
results in your PR.
|
||||
- Versioned distros should typically not modify or add code in `cluster/`. That is just scripts for developer
|
||||
distros.
|
||||
- When a new major or minor release of Kubernetes comes out, we may also release a new
|
||||
conformance test, and require a new conformance test run to earn a conformance checkmark.
|
||||
|
||||
If you have a cluster partially working, but doing all the above steps seems like too much work,
|
||||
we still want to hear from you. We suggest you write a blog post or a Gist, and we will link to it on our wiki page.
|
||||
Just file an issue or chat us on [Slack](/{{page.version}}/docs/troubleshooting/#slack) and one of the committers will link to it from the wiki.
|
||||
|
||||
## Development Distro Guidelines
|
||||
|
||||
These guidelines say *what* to do. See the Rationale section for *why*.
|
||||
|
||||
- the main reason to add a new development distro is to support a new IaaS provider (VM and
|
||||
network management). This means implementing a new `pkg/cloudprovider/providers/$IAAS_NAME`.
|
||||
- Development distros should use Saltstack for Configuration Management.
|
||||
- development distros need to support automated cluster creation, deletion, upgrading, etc.
|
||||
This mean writing scripts in `cluster/$IAAS_NAME`.
|
||||
- all commits to the tip of this repo need to not break any of the development distros
|
||||
- the author of the change is responsible for making changes necessary on all the cloud-providers if the
|
||||
change affects any of them, and reverting the change if it breaks any of the CIs.
|
||||
- a development distro needs to have an organization which owns it. This organization needs to:
|
||||
- Setting up and maintaining Continuous Integration that runs e2e frequently (multiple times per day) against the
|
||||
Distro at head, and which notifies all devs of breakage.
|
||||
- being reasonably available for questions and assisting with
|
||||
refactoring and feature additions that affect code for their IaaS.
|
||||
|
||||
## Rationale
|
||||
|
||||
- We want people to create Kubernetes clusters with whatever IaaS, Node OS,
|
||||
configuration management tools, and so on, which they are familiar with. The
|
||||
guidelines for **versioned distros** are designed for flexibility.
|
||||
- We want developers to be able to work without understanding all the permutations of
|
||||
IaaS, NodeOS, and configuration management. The guidelines for **developer distros** are designed
|
||||
for consistency.
|
||||
- We want users to have a uniform experience with Kubernetes whenever they follow instructions anywhere
|
||||
in our Github repository. So, we ask that versioned distros pass a **conformance test** to make sure
|
||||
really work.
|
||||
- We want to **limit the number of development distros** for several reasons. Developers should
|
||||
only have to change a limited number of places to add a new feature. Also, since we will
|
||||
gate commits on passing CI for all distros, and since end-to-end tests are typically somewhat
|
||||
flaky, it would be highly likely for there to be false positives and CI backlogs with many CI pipelines.
|
||||
- We do not require versioned distros to do **CI** for several reasons. It is a steep
|
||||
learning curve to understand our automated testing scripts. And it is considerable effort
|
||||
to fully automate setup and teardown of a cluster, which is needed for CI. And, not everyone
|
||||
has the time and money to run CI. We do not want to
|
||||
discourage people from writing and sharing guides because of this.
|
||||
- Versioned distro authors are free to run their own CI and let us know if there is breakage, but we
|
||||
will not include them as commit hooks -- there cannot be so many commit checks that it is impossible
|
||||
to pass them all.
|
||||
- We prefer a single Configuration Management tool for development distros. If there were more
|
||||
than one, the core developers would have to learn multiple tools and update config in multiple
|
||||
places. **Saltstack** happens to be the one we picked when we started the project. We
|
||||
welcome versioned distros that use any tool; there are already examples of
|
||||
CoreOS Fleet, Ansible, and others.
|
||||
- You can still run code from head or your own branch
|
||||
if you use another Configuration Management tool -- you just have to do some manual steps
|
||||
during testing and deployment.
|
|
@ -0,0 +1,101 @@
|
|||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. You need an AWS account. Visit [http://aws.amazon.com](http://aws.amazon.com) to get started
|
||||
2. Install and configure [AWS Command Line Interface](http://aws.amazon.com/cli)
|
||||
3. You need an AWS [instance profile and role](http://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles) with EC2 full access.
|
||||
|
||||
NOTE: This script use the 'default' AWS profile by default.
|
||||
You may explicitly set AWS profile to use using the `AWS_DEFAULT_PROFILE` environment variable:
|
||||
|
||||
```shell
|
||||
export AWS_DEFAULT_PROFILE=myawsprofile
|
||||
```
|
||||
|
||||
## Cluster turnup
|
||||
|
||||
### Supported procedure: `get-kube`
|
||||
|
||||
```shell
|
||||
#Using wget
|
||||
export KUBERNETES_PROVIDER=aws; wget -q -O - https://get.k8s.io | bash
|
||||
#Using cURL
|
||||
export KUBERNETES_PROVIDER=aws; curl -sS https://get.k8s.io | bash
|
||||
```
|
||||
|
||||
NOTE: This script calls [cluster/kube-up.sh](http://releases.k8s.io/{{page.githubbranch}}/cluster/kube-up.sh)
|
||||
which in turn calls [cluster/aws/util.sh](http://releases.k8s.io/{{page.githubbranch}}/cluster/aws/util.sh)
|
||||
using [cluster/aws/config-default.sh](http://releases.k8s.io/{{page.githubbranch}}/cluster/aws/config-default.sh).
|
||||
|
||||
This process takes about 5 to 10 minutes. Once the cluster is up, the IP addresses of your master and node(s) will be printed,
|
||||
as well as information about the default services running in the cluster (monitoring, logging, dns). User credentials and security
|
||||
tokens are written in `~/.kube/config`, they will be necessary to use the CLI or the HTTP Basic Auth.
|
||||
|
||||
By default, the script will provision a new VPC and a 4 node k8s cluster in us-west-2a (Oregon) with `t2.micro` instances running on Ubuntu.
|
||||
You can override the variables defined in [config-default.sh](http://releases.k8s.io/{{page.githubbranch}}/cluster/aws/config-default.sh) to change this behavior as follows:
|
||||
|
||||
```shell
|
||||
export KUBE_AWS_ZONE=eu-west-1c
|
||||
export NUM_MINIONS=2
|
||||
export MINION_SIZE=m3.medium
|
||||
export AWS_S3_REGION=eu-west-1
|
||||
export AWS_S3_BUCKET=mycompany-kubernetes-artifacts
|
||||
export INSTANCE_PREFIX=k8s
|
||||
...
|
||||
```
|
||||
|
||||
It will also try to create or reuse a keypair called "kubernetes", and IAM profiles called "kubernetes-master" and "kubernetes-minion".
|
||||
If these already exist, make sure you want them to be used here.
|
||||
|
||||
NOTE: If using an existing keypair named "kubernetes" then you must set the `AWS_SSH_KEY` key to point to your private key.
|
||||
|
||||
### Alternatives
|
||||
|
||||
A contributed [example](/{{page.version}}/docs/getting-started-guides/coreos/coreos_multinode_cluster) allows you to setup a Kubernetes cluster based on [CoreOS](http://www.coreos.com), using
|
||||
EC2 with user data (cloud-config).
|
||||
|
||||
## Getting started with your cluster
|
||||
|
||||
### Command line administration tool: `kubectl`
|
||||
|
||||
The cluster startup script will leave you with a `kubernetes` directory on your workstation.
|
||||
Alternately, you can download the latest Kubernetes release from [this page](https://github.com/kubernetes/kubernetes/releases).
|
||||
|
||||
Next, add the appropriate binary folder to your `PATH` to access kubectl:
|
||||
|
||||
```shell
|
||||
# OS X
|
||||
export PATH=<path/to/kubernetes-directory>/platforms/darwin/amd64:$PATH
|
||||
# Linux
|
||||
export PATH=<path/to/kubernetes-directory>/platforms/linux/amd64:$PATH
|
||||
```
|
||||
|
||||
An up-to-date documentation page for this tool is available here: [kubectl manual](/{{page.version}}/docs/user-guide/kubectl/kubectl)
|
||||
|
||||
By default, `kubectl` will use the `kubeconfig` file generated during the cluster startup for authenticating against the API.
|
||||
For more information, please read [kubeconfig files](/{{page.version}}/docs/user-guide/kubeconfig-file)
|
||||
|
||||
### Examples
|
||||
|
||||
See [a simple nginx example](/{{page.version}}/docs/user-guide/simple-nginx) to try out your new cluster.
|
||||
|
||||
The "Guestbook" application is another popular example to get started with Kubernetes: [guestbook example](https://github.com/kubernetes/kubernetes/tree/{{page.githubbranch}}/examples/guestbook/)
|
||||
|
||||
For more complete applications, please look in the [examples directory](https://github.com/kubernetes/kubernetes/tree/{{page.githubbranch}}/examples/)
|
||||
|
||||
## Tearing down the cluster
|
||||
|
||||
Make sure the environment variables you used to provision your cluster are still exported, then call the following script inside the
|
||||
`kubernetes` directory:
|
||||
|
||||
```shell
|
||||
cluster/kube-down.sh
|
||||
```
|
||||
|
||||
## Further reading
|
||||
|
||||
Please see the [Kubernetes docs](/{{page.version}}/docs/) for more details on administering
|
||||
and using a Kubernetes cluster.
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
|
||||
## Getting started on Microsoft Azure
|
||||
|
||||
Checkout the [coreos azure getting started guide](/{{page.version}}/docs/getting-started-guides/coreos/azure/)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
You can either build a release from sources or download a pre-built release. If you do not plan on developing Kubernetes itself, we suggest a pre-built release.
|
||||
|
||||
### Prebuilt Binary Release
|
||||
|
||||
The list of binary releases is available for download from the [GitHub Kubernetes repo release page](https://github.com/kubernetes/kubernetes/releases).
|
||||
|
||||
Download the latest release and unpack this tar file on Linux or OS X, cd to the created `kubernetes/` directory, and then follow the getting started guide for your cloud.
|
||||
|
||||
### Building from source
|
||||
|
||||
Get the Kubernetes source. If you are simply building a release from source there is no need to set up a full golang environment as all building happens in a Docker container.
|
||||
|
||||
Building a release is simple.
|
||||
|
||||
```shell
|
||||
git clone https://github.com/kubernetes/kubernetes.git
|
||||
cd kubernetes
|
||||
make release
|
||||
```
|
||||
|
||||
For more details on the release process see the [`build/` directory](http://releases.k8s.io/{{page.githubbranch}}/build/)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You need two machines with CentOS installed on them.
|
||||
|
||||
## Starting a cluster
|
||||
|
||||
This is a getting started guide for CentOS. It is a manual configuration so you understand all the underlying packages / services / ports, etc...
|
||||
|
||||
This guide will only get ONE node working. Multiple nodes requires a functional [networking configuration](/{{page.version}}/docs/admin/networking) done outside of kubernetes. Although the additional Kubernetes configuration requirements should be obvious.
|
||||
|
||||
The Kubernetes package provides a few services: kube-apiserver, kube-scheduler, kube-controller-manager, kubelet, kube-proxy. These services are managed by systemd and the configuration resides in a central location: /etc/kubernetes. We will break the services up between the hosts. The first host, centos-master, will be the Kubernetes master. This host will run the kube-apiserver, kube-controller-manager, and kube-scheduler. In addition, the master will also run _etcd_. The remaining host, centos-minion will be the node and run kubelet, proxy, cadvisor and docker.
|
||||
|
||||
**System Information:**
|
||||
|
||||
Hosts:
|
||||
|
||||
```conf
|
||||
centos-master = 192.168.121.9
|
||||
centos-minion = 192.168.121.65
|
||||
```
|
||||
|
||||
**Prepare the hosts:**
|
||||
|
||||
* Create virt7-testing repo on all hosts - centos-{master,minion} with following information.
|
||||
|
||||
```conf
|
||||
[virt7-testing]
|
||||
name=virt7-testing
|
||||
baseurl=http://cbs.centos.org/repos/virt7-testing/x86_64/os/
|
||||
gpgcheck=0
|
||||
```
|
||||
|
||||
* Install Kubernetes on all hosts - centos-{master,minion}. This will also pull in etcd, docker, and cadvisor.
|
||||
|
||||
```shell
|
||||
yum -y install --enablerepo=virt7-testing kubernetes
|
||||
```
|
||||
|
||||
* Note * Using etcd-0.4.6-7 (This is temporary update in documentation)
|
||||
|
||||
If you do not get etcd-0.4.6-7 installed with virt7-testing repo,
|
||||
|
||||
In the current virt7-testing repo, the etcd package is updated which causes service failure. To avoid this,
|
||||
|
||||
```shell
|
||||
yum erase etcd
|
||||
```
|
||||
|
||||
It will uninstall the current available etcd package
|
||||
|
||||
```shell
|
||||
yum install http://cbs.centos.org/kojifiles/packages/etcd/0.4.6/7.el7.centos/x86_64/etcd-0.4.6-7.el7.centos.x86_64.rpm
|
||||
yum -y install --enablerepo=virt7-testing kubernetes
|
||||
```
|
||||
|
||||
* Add master and node to /etc/hosts on all machines (not needed if hostnames already in DNS)
|
||||
|
||||
```shell
|
||||
echo "192.168.121.9 centos-master
|
||||
192.168.121.65 centos-minion" >> /etc/hosts
|
||||
```
|
||||
|
||||
* Edit `/etc/kubernetes/config` which will be the same on all hosts to contain:
|
||||
|
||||
```shell
|
||||
# Comma separated list of nodes in the etcd cluster
|
||||
KUBE_ETCD_SERVERS="--etcd-servers=http://centos-master:4001"
|
||||
|
||||
# logging to stderr means we get it in the systemd journal
|
||||
KUBE_LOGTOSTDERR="--logtostderr=true"
|
||||
|
||||
# journal message level, 0 is debug
|
||||
KUBE_LOG_LEVEL="--v=0"
|
||||
|
||||
# Should this cluster be allowed to run privileged docker containers
|
||||
KUBE_ALLOW_PRIV="--allow-privileged=false"
|
||||
```
|
||||
|
||||
* Disable the firewall on both the master and node, as docker does not play well with other firewall rule managers
|
||||
|
||||
```shell
|
||||
systemctl disable iptables-services firewalld
|
||||
systemctl stop iptables-services firewalld
|
||||
```
|
||||
|
||||
**Configure the Kubernetes services on the master.**
|
||||
|
||||
* Edit /etc/kubernetes/apiserver to appear as such:
|
||||
|
||||
```shell
|
||||
# The address on the local server to listen to.
|
||||
KUBE_API_ADDRESS="--address=0.0.0.0"
|
||||
|
||||
# The port on the local server to listen on.
|
||||
KUBE_API_PORT="--port=8080"
|
||||
|
||||
# How the replication controller and scheduler find the kube-apiserver
|
||||
KUBE_MASTER="--master=http://centos-master:8080"
|
||||
|
||||
# Port kubelets listen on
|
||||
KUBELET_PORT="--kubelet-port=10250"
|
||||
|
||||
# Address range to use for services
|
||||
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"
|
||||
|
||||
# Add your own!
|
||||
KUBE_API_ARGS=""
|
||||
```
|
||||
|
||||
* Start the appropriate services on master:
|
||||
|
||||
```shell
|
||||
for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler; do
|
||||
systemctl restart $SERVICES
|
||||
systemctl enable $SERVICES
|
||||
systemctl status $SERVICES
|
||||
done
|
||||
```
|
||||
|
||||
**Configure the Kubernetes services on the node.**
|
||||
|
||||
***We need to configure the kubelet and start the kubelet and proxy***
|
||||
|
||||
* Edit `/etc/kubernetes/kubelet` to appear as such:
|
||||
|
||||
```shell
|
||||
# The address for the info server to serve on
|
||||
KUBELET_ADDRESS="--address=0.0.0.0"
|
||||
|
||||
# The port for the info server to serve on
|
||||
KUBELET_PORT="--port=10250"
|
||||
|
||||
# You may leave this blank to use the actual hostname
|
||||
KUBELET_HOSTNAME="--hostname-override=centos-minion"
|
||||
|
||||
# Location of the api-server
|
||||
KUBELET_API_SERVER="--api-servers=http://centos-master:8080"
|
||||
|
||||
# Add your own!
|
||||
KUBELET_ARGS=""
|
||||
```
|
||||
|
||||
* Start the appropriate services on node (centos-minion).
|
||||
|
||||
```shell
|
||||
for SERVICES in kube-proxy kubelet docker; do
|
||||
systemctl restart $SERVICES
|
||||
systemctl enable $SERVICES
|
||||
systemctl status $SERVICES
|
||||
done
|
||||
```
|
||||
|
||||
*You should be finished!*
|
||||
|
||||
* Check to make sure the cluster can see the node (on centos-master)
|
||||
|
||||
```shell
|
||||
$ kubectl get nodes
|
||||
NAME LABELS STATUS
|
||||
centos-minion <none> Ready
|
||||
```
|
||||
|
||||
**The cluster should be running! Launch a test pod.**
|
||||
|
||||
You should have a functional cluster, check out [101](/{{page.version}}/docs/user-guide/walkthrough/)!
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
CloudStack is a software to build public and private clouds based on hardware virtualization principles (traditional IaaS). To deploy Kubernetes on CloudStack there are several possibilities depending on the Cloud being used and what images are made available. [Exoscale](http://exoscale.ch) for instance makes a [CoreOS](http://coreos.com) template available, therefore instructions to deploy Kubernetes on coreOS can be used. CloudStack also has a vagrant plugin available, hence Vagrant could be used to deploy Kubernetes either using the existing shell provisioner or using new Salt based recipes.
|
||||
|
||||
[CoreOS](http://coreos.com) templates for CloudStack are built [nightly](http://stable.release.core-os.net/amd64-usr/current/). CloudStack operators need to [register](http://docs.cloudstack.apache.org/projects/cloudstack-administration/en/latest/templates) this template in their cloud before proceeding with these Kubernetes deployment instructions.
|
||||
|
||||
This guide uses an [Ansible playbook](https://github.com/runseb/ansible-kubernetes).
|
||||
This is a completely automated, a single playbook deploys Kubernetes based on the coreOS [instructions](/{{page.version}}/docs/getting-started-guides/coreos/coreos_multinode_cluster).
|
||||
|
||||
|
||||
This [Ansible](http://ansibleworks.com) playbook deploys Kubernetes on a CloudStack based Cloud using CoreOS images. The playbook, creates an ssh key pair, creates a security group and associated rules and finally starts coreOS instances configured via cloud-init.
|
||||
|
||||
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
$ sudo apt-get install -y python-pip
|
||||
$ sudo pip install ansible
|
||||
$ sudo pip install cs
|
||||
|
||||
[_cs_](https://github.com/exoscale/cs) is a python module for the CloudStack API.
|
||||
|
||||
Set your CloudStack endpoint, API keys and HTTP method used.
|
||||
|
||||
You can define them as environment variables: `CLOUDSTACK_ENDPOINT`, `CLOUDSTACK_KEY`, `CLOUDSTACK_SECRET` and `CLOUDSTACK_METHOD`.
|
||||
|
||||
Or create a `~/.cloudstack.ini` file:
|
||||
|
||||
[cloudstack]
|
||||
endpoint = <your cloudstack api endpoint>
|
||||
key = <your api access key>
|
||||
secret = <your api secret key>
|
||||
method = post
|
||||
|
||||
We need to use the http POST method to pass the _large_ userdata to the coreOS instances.
|
||||
|
||||
### Clone the playbook
|
||||
|
||||
$ git clone --recursive https://github.com/runseb/ansible-kubernetes.git
|
||||
$ cd ansible-kubernetes
|
||||
|
||||
The [ansible-cloudstack](https://github.com/resmo/ansible-cloudstack) module is setup in this repository as a submodule, hence the `--recursive`.
|
||||
|
||||
### Create a Kubernetes cluster
|
||||
|
||||
You simply need to run the playbook.
|
||||
|
||||
$ ansible-playbook k8s.yml
|
||||
|
||||
Some variables can be edited in the `k8s.yml` file.
|
||||
|
||||
vars:
|
||||
ssh_key: k8s
|
||||
k8s_num_nodes: 2
|
||||
k8s_security_group_name: k8s
|
||||
k8s_node_prefix: k8s2
|
||||
k8s_template: Linux CoreOS alpha 435 64-bit 10GB Disk
|
||||
k8s_instance_type: Tiny
|
||||
|
||||
This will start a Kubernetes master node and a number of compute nodes (by default 2).
|
||||
The `instance_type` and `template` by default are specific to [exoscale](http://exoscale.ch), edit them to specify your CloudStack cloud specific template and instance type (i.e service offering).
|
||||
|
||||
Check the tasks and templates in `roles/k8s` if you want to modify anything.
|
||||
|
||||
Once the playbook as finished, it will print out the IP of the Kubernetes master:
|
||||
|
||||
TASK: [k8s | debug msg='k8s master IP is {{ k8s_master.default_ip }}'] ********
|
||||
|
||||
SSH to it using the key that was created and using the _core_ user and you can list the machines in your cluster:
|
||||
|
||||
$ ssh -i ~/.ssh/id_rsa_k8s core@<master IP>
|
||||
$ fleetctl list-machines
|
||||
MACHINE IP METADATA
|
||||
a017c422... <node #1 IP> role=node
|
||||
ad13bf84... <master IP> role=master
|
||||
e9af8293... <node #2 IP> role=node
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
There are multiple guides on running Kubernetes with [CoreOS](https://coreos.com/kubernetes/docs/latest/):
|
||||
|
||||
### Official CoreOS Guides
|
||||
|
||||
These guides are maintained by CoreOS and deploy Kubernetes the "CoreOS Way" with full TLS, the DNS add-on, and more. These guides pass Kubernetes conformance testing and we encourage you to [test this yourself](https://coreos.com/kubernetes/docs/latest/conformance-tests).
|
||||
|
||||
[**Vagrant Multi-Node**](https://coreos.com/kubernetes/docs/latest/kubernetes-on-vagrant)
|
||||
|
||||
Guide to setting up a multi-node cluster on Vagrant. The deployer can independently configure the number of etcd nodes, master nodes, and worker nodes to bring up a fully HA control plane.
|
||||
|
||||
<hr/>
|
||||
|
||||
[**Vagrant Single-Node**](https://coreos.com/kubernetes/docs/latest/kubernetes-on-vagrant-single)
|
||||
|
||||
The quickest way to set up a Kubernetes development environment locally. As easy as `git clone`, `vagrant up` and configuring `kubectl`.
|
||||
|
||||
<hr/>
|
||||
|
||||
[**Full Step by Step Guide**](https://coreos.com/kubernetes/docs/latest/getting-started)
|
||||
|
||||
A generic guide to setting up an HA cluster on any cloud or bare metal, with full TLS. Repeat the master or worker steps to configure more machines of that role.
|
||||
|
||||
### Community Guides
|
||||
|
||||
These guides are maintained by community members, cover specific platforms and use cases, and experiment with different ways of configuring Kubernetes on CoreOS.
|
||||
|
||||
[**Multi-node Cluster**](/{{page.version}}/docs/getting-started-guides/coreos/coreos_multinode_cluster)
|
||||
|
||||
Set up a single master, multi-worker cluster on your choice of platform: AWS, GCE, or VMware Fusion.
|
||||
|
||||
<hr/>
|
||||
|
||||
[**Easy Multi-node Cluster on Google Compute Engine**](https://github.com/rimusz/coreos-multi-node-k8s-gce/blob/master/README.md)
|
||||
|
||||
Scripted installation of a single master, multi-worker cluster on GCE. Kubernetes components are managed by [fleet](https://github.com/coreos/fleet).
|
||||
|
||||
<hr/>
|
||||
|
||||
[**Multi-node cluster using cloud-config and Weave on Vagrant**](https://github.com/errordeveloper/weave-demos/blob/master/poseidon/README.md)
|
||||
|
||||
Configure a Vagrant-based cluster of 3 machines with networking provided by Weave.
|
||||
|
||||
<hr/>
|
||||
|
||||
[**Multi-node cluster using cloud-config and Vagrant**](https://github.com/pires/kubernetes-vagrant-coreos-cluster/blob/master/README.md)
|
||||
|
||||
Configure a single master, multi-worker cluster locally, running on your choice of hypervisor: VirtualBox, Parallels, or VMware
|
||||
|
||||
<hr/>
|
||||
|
||||
[**Multi-node cluster with Vagrant and fleet units using a small OS X App**](https://github.com/rimusz/coreos-osx-gui-kubernetes-cluster/blob/master/README.md)
|
||||
|
||||
Guide to running a single master, multi-worker cluster controlled by an OS X menubar application. Uses Vagrant under the hood.
|
||||
|
||||
<hr/>
|
||||
|
||||
[**Resizable multi-node cluster on Azure with Weave**](/{{page.version}}/docs/getting-started-guides/coreos/azure/)
|
||||
|
||||
Guide to running an HA etcd cluster with a single master on Azure. Uses the Azure node.js CLI to resize the cluster.
|
||||
|
||||
<hr/>
|
||||
|
||||
[**Multi-node cluster using cloud-config, CoreOS and VMware ESXi**](https://github.com/xavierbaude/VMware-coreos-multi-nodes-Kubernetes)
|
||||
|
||||
Configure a single master, single worker cluster on VMware ESXi.
|
|
@ -0,0 +1 @@
|
|||
node_modules/
|
|
@ -0,0 +1,92 @@
|
|||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
name: kube-dns-v8
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
version: v8
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
k8s-app: kube-dns
|
||||
version: v8
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
version: v8
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
containers:
|
||||
- name: etcd
|
||||
image: gcr.io/google_containers/etcd:2.0.9
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
command:
|
||||
- /usr/local/bin/etcd
|
||||
- -data-dir
|
||||
- /var/etcd/data
|
||||
- -listen-client-urls
|
||||
- http://127.0.0.1:2379,http://127.0.0.1:4001
|
||||
- -advertise-client-urls
|
||||
- http://127.0.0.1:2379,http://127.0.0.1:4001
|
||||
- -initial-cluster-token
|
||||
- skydns-etcd
|
||||
volumeMounts:
|
||||
- name: etcd-storage
|
||||
mountPath: /var/etcd/data
|
||||
- name: kube2sky
|
||||
image: gcr.io/google_containers/kube2sky:1.11
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
args:
|
||||
# command = "/kube2sky"
|
||||
- -domain=kube.local
|
||||
- -kube_master_url=http://kube-00:8080
|
||||
- name: skydns
|
||||
image: gcr.io/google_containers/skydns:2015-03-11-001
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
args:
|
||||
# command = "/skydns"
|
||||
- -machines=http://localhost:4001
|
||||
- -addr=0.0.0.0:53
|
||||
- -domain=kube.local
|
||||
ports:
|
||||
- containerPort: 53
|
||||
name: dns
|
||||
protocol: UDP
|
||||
- containerPort: 53
|
||||
name: dns-tcp
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 30
|
||||
timeoutSeconds: 5
|
||||
- name: healthz
|
||||
image: gcr.io/google_containers/exechealthz:1.0
|
||||
resources:
|
||||
limits:
|
||||
cpu: 10m
|
||||
memory: 20Mi
|
||||
args:
|
||||
- -cmd=nslookup kubernetes.default.svc.kube.local localhost >/dev/null
|
||||
- -port=8080
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
volumes:
|
||||
- name: etcd-storage
|
||||
emptyDir: {}
|
||||
dnsPolicy: Default # Don't use cluster DNS.
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kube-dns
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
kubernetes.io/cluster-service: "true"
|
||||
kubernetes.io/name: "KubeDNS"
|
||||
spec:
|
||||
selector:
|
||||
k8s-app: kube-dns
|
||||
clusterIP: 10.1.0.3
|
||||
ports:
|
||||
- name: dns
|
||||
port: 53
|
||||
protocol: UDP
|
||||
- name: dns-tcp
|
||||
port: 53
|
||||
protocol: TCP
|
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
require('child_process').fork('node_modules/azure-cli/bin/azure', ['login'].concat(process.argv));
|
|
@ -0,0 +1,19 @@
|
|||
## This file is used as input to deployment script, which amends it as needed.
|
||||
## More specifically, we need to add peer hosts for each but the elected peer.
|
||||
|
||||
coreos:
|
||||
units:
|
||||
- name: etcd2.service
|
||||
enable: true
|
||||
command: start
|
||||
etcd2:
|
||||
name: '%H'
|
||||
initial-cluster-token: 'etcd-cluster'
|
||||
initial-advertise-peer-urls: 'http://%H:2380'
|
||||
listen-peer-urls: 'http://%H:2380'
|
||||
listen-client-urls: 'http://0.0.0.0:2379,http://0.0.0.0:4001'
|
||||
advertise-client-urls: 'http://%H:2379,http://%H:4001'
|
||||
initial-cluster-state: 'new'
|
||||
update:
|
||||
group: stable
|
||||
reboot-strategy: off
|
|
@ -0,0 +1,339 @@
|
|||
## This file is used as input to deployment script, which amends it as needed.
|
||||
## More specifically, we need to add environment files for as many nodes as we
|
||||
## are going to deploy.
|
||||
|
||||
write_files:
|
||||
- path: /opt/bin/curl-retry.sh
|
||||
permissions: '0755'
|
||||
owner: root
|
||||
content: |
|
||||
#!/bin/sh -x
|
||||
until curl $@
|
||||
do sleep 1
|
||||
done
|
||||
|
||||
coreos:
|
||||
update:
|
||||
group: stable
|
||||
reboot-strategy: off
|
||||
units:
|
||||
- name: systemd-networkd-wait-online.service
|
||||
drop-ins:
|
||||
- name: 50-check-github-is-reachable.conf
|
||||
content: |
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c \
|
||||
'until curl --silent --fail https://status.github.com/api/status.json | grep -q \"good\"; do sleep 2; done'
|
||||
|
||||
- name: docker.service
|
||||
drop-ins:
|
||||
- name: 50-weave-kubernetes.conf
|
||||
content: |
|
||||
[Service]
|
||||
Environment=DOCKER_OPTS='--bridge="weave" -r="false"'
|
||||
|
||||
- name: weave-network.target
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Weave Network Setup Complete
|
||||
Documentation=man:systemd.special(7)
|
||||
RefuseManualStart=no
|
||||
After=network-online.target
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=kubernetes-master.target
|
||||
WantedBy=kubernetes-node.target
|
||||
|
||||
- name: kubernetes-master.target
|
||||
enable: true
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Cluster Master
|
||||
Documentation=http://kubernetes.io/
|
||||
RefuseManualStart=no
|
||||
After=weave-network.target
|
||||
Requires=weave-network.target
|
||||
ConditionHost=kube-00
|
||||
Wants=kube-apiserver.service
|
||||
Wants=kube-scheduler.service
|
||||
Wants=kube-controller-manager.service
|
||||
Wants=kube-proxy.service
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
- name: kubernetes-node.target
|
||||
enable: true
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Cluster Node
|
||||
Documentation=http://kubernetes.io/
|
||||
RefuseManualStart=no
|
||||
After=weave-network.target
|
||||
Requires=weave-network.target
|
||||
ConditionHost=!kube-00
|
||||
Wants=kube-proxy.service
|
||||
Wants=kubelet.service
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
- name: 10-weave.network
|
||||
runtime: false
|
||||
content: |
|
||||
[Match]
|
||||
Type=bridge
|
||||
Name=weave*
|
||||
[Network]
|
||||
|
||||
- name: install-weave.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=network-online.target
|
||||
Before=weave.service
|
||||
Before=weave-helper.service
|
||||
Before=docker.service
|
||||
Description=Install Weave
|
||||
Documentation=http://docs.weave.works/
|
||||
Requires=network-online.target
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStartPre=/bin/mkdir -p /opt/bin/
|
||||
ExecStartPre=/opt/bin/curl-retry.sh \
|
||||
--silent \
|
||||
--location \
|
||||
https://github.com/weaveworks/weave/releases/download/latest_release/weave \
|
||||
--output /opt/bin/weave
|
||||
ExecStartPre=/opt/bin/curl-retry.sh \
|
||||
--silent \
|
||||
--location \
|
||||
https://raw.github.com/errordeveloper/weave-demos/master/poseidon/weave-helper \
|
||||
--output /opt/bin/weave-helper
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/weave
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/weave-helper
|
||||
ExecStart=/bin/echo Weave Installed
|
||||
[Install]
|
||||
WantedBy=weave-network.target
|
||||
WantedBy=weave.service
|
||||
|
||||
- name: weave-helper.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-weave.service
|
||||
After=docker.service
|
||||
Description=Weave Network Router
|
||||
Documentation=http://docs.weave.works/
|
||||
Requires=docker.service
|
||||
Requires=install-weave.service
|
||||
[Service]
|
||||
ExecStart=/opt/bin/weave-helper
|
||||
Restart=always
|
||||
[Install]
|
||||
WantedBy=weave-network.target
|
||||
|
||||
- name: weave.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-weave.service
|
||||
After=docker.service
|
||||
Description=Weave Network Router
|
||||
Documentation=http://docs.weave.works/
|
||||
Requires=docker.service
|
||||
Requires=install-weave.service
|
||||
[Service]
|
||||
TimeoutStartSec=0
|
||||
EnvironmentFile=/etc/weave.%H.env
|
||||
ExecStartPre=/opt/bin/weave setup
|
||||
ExecStartPre=/opt/bin/weave launch $WEAVE_PEERS
|
||||
ExecStart=/usr/bin/docker attach weave
|
||||
Restart=on-failure
|
||||
Restart=always
|
||||
ExecStop=/opt/bin/weave stop
|
||||
[Install]
|
||||
WantedBy=weave-network.target
|
||||
|
||||
- name: weave-create-bridge.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=network.target
|
||||
After=install-weave.service
|
||||
Before=weave.service
|
||||
Before=docker.service
|
||||
Requires=network.target
|
||||
Requires=install-weave.service
|
||||
[Service]
|
||||
Type=oneshot
|
||||
EnvironmentFile=/etc/weave.%H.env
|
||||
ExecStart=/opt/bin/weave --local create-bridge
|
||||
ExecStart=/usr/bin/ip addr add dev weave $BRIDGE_ADDRESS_CIDR
|
||||
ExecStart=/usr/bin/ip route add $BREAKOUT_ROUTE dev weave scope link
|
||||
ExecStart=/usr/bin/ip route add 224.0.0.0/4 dev weave
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=weave-network.target
|
||||
|
||||
- name: install-kubernetes.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=network-online.target
|
||||
Before=kube-apiserver.service
|
||||
Before=kube-controller-manager.service
|
||||
Before=kubelet.service
|
||||
Before=kube-proxy.service
|
||||
Description=Download Kubernetes Binaries
|
||||
Documentation=http://kubernetes.io/
|
||||
Requires=network-online.target
|
||||
[Service]
|
||||
Environment=KUBE_RELEASE_TARBALL=https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v1.0.1/kubernetes.tar.gz
|
||||
ExecStartPre=/bin/mkdir -p /opt/
|
||||
ExecStart=/opt/bin/curl-retry.sh --silent --location $KUBE_RELEASE_TARBALL --output /tmp/kubernetes.tgz
|
||||
ExecStart=/bin/tar xzvf /tmp/kubernetes.tgz -C /tmp/
|
||||
ExecStart=/bin/tar xzvf /tmp/kubernetes/server/kubernetes-server-linux-amd64.tar.gz -C /opt
|
||||
ExecStartPost=/bin/chmod o+rx -R /opt/kubernetes
|
||||
ExecStartPost=/bin/ln -s /opt/kubernetes/server/bin/kubectl /opt/bin/
|
||||
ExecStartPost=/bin/mv /tmp/kubernetes/examples/guestbook /home/core/guestbook-example
|
||||
ExecStartPost=/bin/chown core. -R /home/core/guestbook-example
|
||||
ExecStartPost=/bin/rm -rf /tmp/kubernetes
|
||||
ExecStartPost=/bin/sed 's/# type: LoadBalancer/type: NodePort/' -i /home/core/guestbook-example/frontend-service.yaml
|
||||
RemainAfterExit=yes
|
||||
Type=oneshot
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
WantedBy=kubernetes-node.target
|
||||
|
||||
- name: kube-apiserver.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
Before=kube-controller-manager.service
|
||||
Before=kube-scheduler.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kube-apiserver
|
||||
Description=Kubernetes API Server
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=install-kubernetes.service
|
||||
ConditionHost=kube-00
|
||||
[Service]
|
||||
ExecStart=/opt/kubernetes/server/bin/kube-apiserver \
|
||||
--address=0.0.0.0 \
|
||||
--port=8080 \
|
||||
$ETCD_SERVERS \
|
||||
--service-cluster-ip-range=10.1.0.0/16 \
|
||||
--logtostderr=true --v=3
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
|
||||
- name: kube-scheduler.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=kube-apiserver.service
|
||||
After=install-kubernetes.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kube-scheduler
|
||||
Description=Kubernetes Scheduler
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=kube-apiserver.service
|
||||
ConditionHost=kube-00
|
||||
[Service]
|
||||
ExecStart=/opt/kubernetes/server/bin/kube-scheduler \
|
||||
--logtostderr=true \
|
||||
--master=127.0.0.1:8080
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
|
||||
- name: kube-controller-manager.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
After=kube-apiserver.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kube-controller-manager
|
||||
Description=Kubernetes Controller Manager
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=kube-apiserver.service
|
||||
Wants=install-kubernetes.service
|
||||
ConditionHost=kube-00
|
||||
[Service]
|
||||
ExecStart=/opt/kubernetes/server/bin/kube-controller-manager \
|
||||
--master=127.0.0.1:8080 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
|
||||
- name: kubelet.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kubelet
|
||||
Description=Kubernetes Kubelet
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=install-kubernetes.service
|
||||
ConditionHost=!kube-00
|
||||
[Service]
|
||||
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests/
|
||||
ExecStart=/opt/kubernetes/server/bin/kubelet \
|
||||
--address=0.0.0.0 \
|
||||
--port=10250 \
|
||||
--hostname-override=%H \
|
||||
--api-servers=http://kube-00:8080 \
|
||||
--logtostderr=true \
|
||||
--cluster-dns=10.1.0.3 \
|
||||
--cluster-domain=kube.local \
|
||||
--config=/etc/kubernetes/manifests/
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-node.target
|
||||
|
||||
- name: kube-proxy.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kube-proxy
|
||||
Description=Kubernetes Proxy
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=install-kubernetes.service
|
||||
[Service]
|
||||
ExecStart=/opt/kubernetes/server/bin/kube-proxy \
|
||||
--master=http://kube-00:8080 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
WantedBy=kubernetes-node.target
|
||||
|
||||
- name: kube-create-addons.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kubectl
|
||||
ConditionPathIsDirectory=/etc/kubernetes/addons/
|
||||
ConditionHost=kube-00
|
||||
Description=Kubernetes Addons
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=install-kubernetes.service
|
||||
Wants=kube-apiserver.service
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=no
|
||||
ExecStart=/opt/kubernetes/server/bin/kubectl create -f /etc/kubernetes/addons/
|
||||
SuccessExitStatus=1
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var azure = require('./lib/azure_wrapper.js');
|
||||
var kube = require('./lib/deployment_logic/kubernetes.js');
|
||||
|
||||
azure.create_config('kube', { 'etcd': 3, 'kube': 3 });
|
||||
|
||||
azure.run_task_queue([
|
||||
azure.queue_default_network(),
|
||||
azure.queue_storage_if_needed(),
|
||||
azure.queue_machines('etcd', 'stable',
|
||||
kube.create_etcd_cloud_config),
|
||||
azure.queue_machines('kube', 'stable',
|
||||
kube.create_node_cloud_config),
|
||||
]);
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var azure = require('./lib/azure_wrapper.js');
|
||||
|
||||
azure.destroy_cluster(process.argv[2]);
|
||||
|
||||
console.log('The cluster had been destroyed, you can delete the state file now.');
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -e
|
||||
|
||||
[ ! -z $1 ] || (echo Usage: $0 ssh_conf; exit 1)
|
||||
|
||||
fe_port=$(ssh -F $1 kube-00 \
|
||||
"/opt/bin/kubectl get -o template --template='{{(index .spec.ports 0).nodePort}}' services frontend -L name=frontend" \
|
||||
)
|
||||
|
||||
echo "Guestbook app is on port $fe_port, will map it to port 80 on kube-00"
|
||||
|
||||
./node_modules/.bin/azure vm endpoint create kube-00 80 $fe_port
|
||||
|
||||
./node_modules/.bin/azure vm endpoint show kube-00 tcp-80-${fe_port}
|
|
@ -0,0 +1,225 @@
|
|||
|
||||
In this guide I will demonstrate how to deploy a Kubernetes cluster to Azure cloud. You will be using CoreOS with [Weave](http://weave.works),
|
||||
which implements simple and secure networking, in a transparent, yet robust way. The purpose of this guide is to provide an out-of-the-box
|
||||
implementation that can ultimately be taken into production with little change. It will demonstrate how to provision a dedicated Kubernetes
|
||||
master and etcd nodes, and show how to scale the cluster with ease.
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. You need an Azure account.
|
||||
|
||||
## Let's go!
|
||||
|
||||
To get started, you need to checkout the code:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/kubernetes/kubernetes
|
||||
cd kubernetes/docs/getting-started-guides/coreos/azure/
|
||||
```
|
||||
|
||||
You will need to have [Node.js installed](http://nodejs.org/download/) on you machine. If you have previously used Azure CLI, you should have it already.
|
||||
|
||||
First, you need to install some of the dependencies with
|
||||
|
||||
```shell
|
||||
npm install
|
||||
```
|
||||
|
||||
Now, all you need to do is:
|
||||
|
||||
```shell
|
||||
./azure-login.js -u <your_username>
|
||||
./create-kubernetes-cluster.js
|
||||
```
|
||||
|
||||
This script will provision a cluster suitable for production use, where there is a ring of 3 dedicated etcd nodes: 1 kubernetes master and 2 kubernetes nodes.
|
||||
The `kube-00` VM will be the master, your work loads are only to be deployed on the nodes, `kube-01` and `kube-02`. Initially, all VMs are single-core, to
|
||||
ensure a user of the free tier can reproduce it without paying extra. I will show how to add more bigger VMs later.
|
||||
|
||||

|
||||
|
||||
Once the creation of Azure VMs has finished, you should see the following:
|
||||
|
||||
```shell
|
||||
...
|
||||
azure_wrapper/info: Saved SSH config, you can use it like so: `ssh -F ./output/kube_1c1496016083b4_ssh_conf <hostname>`
|
||||
azure_wrapper/info: The hosts in this deployment are:
|
||||
[ 'etcd-00', 'etcd-01', 'etcd-02', 'kube-00', 'kube-01', 'kube-02' ]
|
||||
azure_wrapper/info: Saved state into `./output/kube_1c1496016083b4_deployment.yml`
|
||||
```
|
||||
|
||||
Let's login to the master node like so:
|
||||
|
||||
```shell
|
||||
ssh -F ./output/kube_1c1496016083b4_ssh_conf kube-00
|
||||
```
|
||||
|
||||
> Note: config file name will be different, make sure to use the one you see.
|
||||
|
||||
Check there are 2 nodes in the cluster:
|
||||
|
||||
```shell
|
||||
core@kube-00 ~ $ kubectl get nodes
|
||||
NAME LABELS STATUS
|
||||
kube-01 kubernetes.io/hostname=kube-01 Ready
|
||||
kube-02 kubernetes.io/hostname=kube-02 Ready
|
||||
```
|
||||
|
||||
## Deploying the workload
|
||||
|
||||
Let's follow the Guestbook example now:
|
||||
|
||||
```shell
|
||||
kubectl create -f ~/guestbook-example
|
||||
```
|
||||
|
||||
You need to wait for the pods to get deployed, run the following and wait for `STATUS` to change from `Pending` to `Running`.
|
||||
|
||||
```shell
|
||||
kubectl get pods --watch
|
||||
```
|
||||
|
||||
> Note: the most time it will spend downloading Docker container images on each of the nodes.
|
||||
|
||||
Eventually you should see:
|
||||
|
||||
```shell
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
frontend-0a9xi 1/1 Running 0 4m
|
||||
frontend-4wahe 1/1 Running 0 4m
|
||||
frontend-6l36j 1/1 Running 0 4m
|
||||
redis-master-talmr 1/1 Running 0 4m
|
||||
redis-slave-12zfd 1/1 Running 0 4m
|
||||
redis-slave-3nbce 1/1 Running 0 4m
|
||||
```
|
||||
|
||||
## Scaling
|
||||
|
||||
Two single-core nodes are certainly not enough for a production system of today. Let's scale the cluster by adding a couple of bigger nodes.
|
||||
|
||||
You will need to open another terminal window on your machine and go to the same working directory (e.g. `~/Workspace/kubernetes/docs/getting-started-guides/coreos/azure/`).
|
||||
|
||||
First, lets set the size of new VMs:
|
||||
|
||||
```shell
|
||||
export AZ_VM_SIZE=Large
|
||||
```
|
||||
|
||||
Now, run scale script with state file of the previous deployment and number of nodes to add:
|
||||
|
||||
```shell
|
||||
core@kube-00 ~ $ ./scale-kubernetes-cluster.js ./output/kube_1c1496016083b4_deployment.yml 2
|
||||
...
|
||||
azure_wrapper/info: Saved SSH config, you can use it like so: `ssh -F ./output/kube_8f984af944f572_ssh_conf <hostname>`
|
||||
azure_wrapper/info: The hosts in this deployment are:
|
||||
[ 'etcd-00',
|
||||
'etcd-01',
|
||||
'etcd-02',
|
||||
'kube-00',
|
||||
'kube-01',
|
||||
'kube-02',
|
||||
'kube-03',
|
||||
'kube-04' ]
|
||||
azure_wrapper/info: Saved state into `./output/kube_8f984af944f572_deployment.yml`
|
||||
```
|
||||
|
||||
> Note: this step has created new files in `./output`.
|
||||
|
||||
Back on `kube-00`:
|
||||
|
||||
```shell
|
||||
core@kube-00 ~ $ kubectl get nodes
|
||||
NAME LABELS STATUS
|
||||
kube-01 kubernetes.io/hostname=kube-01 Ready
|
||||
kube-02 kubernetes.io/hostname=kube-02 Ready
|
||||
kube-03 kubernetes.io/hostname=kube-03 Ready
|
||||
kube-04 kubernetes.io/hostname=kube-04 Ready
|
||||
```
|
||||
|
||||
You can see that two more nodes joined happily. Let's scale the number of Guestbook instances now.
|
||||
|
||||
First, double-check how many replication controllers there are:
|
||||
|
||||
```shell
|
||||
core@kube-00 ~ $ kubectl get rc
|
||||
ONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
frontend php-redis kubernetes/example-guestbook-php-redis:v2 name=frontend 3
|
||||
redis-master master redis name=redis-master 1
|
||||
redis-slave worker kubernetes/redis-slave:v2 name=redis-slave 2
|
||||
```
|
||||
|
||||
As there are 4 nodes, let's scale proportionally:
|
||||
|
||||
```shell
|
||||
core@kube-00 ~ $ kubectl scale --replicas=4 rc redis-slave
|
||||
>>>>>>> coreos/azure: Updates for 1.0
|
||||
scaled
|
||||
core@kube-00 ~ $ kubectl scale --replicas=4 rc frontend
|
||||
scaled
|
||||
```
|
||||
|
||||
Check what you have now:
|
||||
|
||||
```shell
|
||||
core@kube-00 ~ $ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
frontend php-redis kubernetes/example-guestbook-php-redis:v2 name=frontend 4
|
||||
redis-master master redis name=redis-master 1
|
||||
redis-slave worker kubernetes/redis-slave:v2 name=redis-slave 4
|
||||
```
|
||||
|
||||
You now will have more instances of front-end Guestbook apps and Redis slaves; and, if you look up all pods labeled `name=frontend`, you should see one running on each node.
|
||||
|
||||
```shell
|
||||
core@kube-00 ~/guestbook-example $ kubectl get pods -l name=frontend
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
frontend-0a9xi 1/1 Running 0 22m
|
||||
frontend-4wahe 1/1 Running 0 22m
|
||||
frontend-6l36j 1/1 Running 0 22m
|
||||
frontend-z9oxo 1/1 Running 0 41s
|
||||
```
|
||||
|
||||
## Exposing the app to the outside world
|
||||
|
||||
There is no native Azure load-balancer support in Kubernetes 1.0, however here is how you can expose the Guestbook app to the Internet.
|
||||
|
||||
```shell
|
||||
./expose_guestbook_app_port.sh ./output/kube_1c1496016083b4_ssh_conf
|
||||
Guestbook app is on port 31605, will map it to port 80 on kube-00
|
||||
info: Executing command vm endpoint create
|
||||
+ Getting virtual machines
|
||||
+ Reading network configuration
|
||||
+ Updating network configuration
|
||||
info: vm endpoint create command OK
|
||||
info: Executing command vm endpoint show
|
||||
+ Getting virtual machines
|
||||
data: Name : tcp-80-31605
|
||||
data: Local port : 31605
|
||||
data: Protcol : tcp
|
||||
data: Virtual IP Address : 137.117.156.164
|
||||
data: Direct server return : Disabled
|
||||
info: vm endpoint show command OK
|
||||
```
|
||||
|
||||
You then should be able to access it from anywhere via the Azure virtual IP for `kube-00` displayed above, i.e. `http://137.117.156.164/` in my case.
|
||||
|
||||
## Next steps
|
||||
|
||||
You now have a full-blow cluster running in Azure, congrats!
|
||||
|
||||
You should probably try deploy other [example apps](https://github.com/kubernetes/kubernetes/tree/{{page.githubbranch}}/examples/) or write your own ;)
|
||||
|
||||
## Tear down...
|
||||
|
||||
If you don't wish care about the Azure bill, you can tear down the cluster. It's easy to redeploy it, as you can see.
|
||||
|
||||
```shell
|
||||
./destroy-cluster.js ./output/kube_8f984af944f572_deployment.yml
|
||||
```
|
||||
|
||||
> Note: make sure to use the _latest state file_, as after scaling there is a new one.
|
||||
|
||||
By the way, with the scripts shown, you can deploy multiple clusters, if you like :)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue