summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanet Kuo <chiachenk@google.com>2017-07-21 14:55:22 -0700
committerGitHub <noreply@github.com>2017-07-21 14:55:22 -0700
commit951fd045cac5c6c601e76268ce27be71c7007fda (patch)
tree0636f796a7fe91c4a6d794fd9056e49b114d52ac
parent732cecfc69523145ca46f88eb56c06cd1211caa8 (diff)
parentedf520a3bb25281238845557d2621362c76fcbae (diff)
Merge pull request #527 from janetkuo/ds-update-history
Proposal for DaemonSet history and rollback
-rw-r--r--contributors/design-proposals/daemonset-update.md141
1 files changed, 77 insertions, 64 deletions
diff --git a/contributors/design-proposals/daemonset-update.md b/contributors/design-proposals/daemonset-update.md
index b3cd7384..b50beb86 100644
--- a/contributors/design-proposals/daemonset-update.md
+++ b/contributors/design-proposals/daemonset-update.md
@@ -67,7 +67,7 @@ type DaemonSetUpdateStrategy struct {
// RollingUpdate.
//---
// TODO: Update this to follow our convention for oneOf, whatever we decide it
- // to be. Same as DeploymentStrategy.RollingUpdate.
+ // to be. Same as Deployment `strategy.rollingUpdate`.
// See https://github.com/kubernetes/kubernetes/issues/35345
// +optional
RollingUpdate *RollingUpdateDaemonSet
@@ -118,10 +118,16 @@ type DaemonSetSpec struct {
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
+ // DEPRECATED.
// A sequence number representing a specific generation of the template.
// Populated by the system. Can be set at creation time. Read-only otherwise.
// +optional
TemplateGeneration int64 `json:"templateGeneration,omitempty"`
+
+ // The number of old history to retain to allow rollback.
+ // This is a pointer to distinguish between explicit zero and not specified.
+ // Defaults to 10.
+ RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty"`
}
// DaemonSetStatus represents the current status of a daemon set.
@@ -146,13 +152,25 @@ type DaemonSetStatus struct {
// (ready for at least minReadySeconds)
// +optional
NumberUnavailable int32 `json:"numberUnavailable"`
+
+ // Count of hash collisions for the DaemonSet. The DaemonSet controller
+ // uses this field as a collision avoidance mechanism when it needs to
+ // create the name for the newest ControllerRevision.
+ // +optional
+ CollisionCount *int64 `json:"collisionCount,omitempty"`
}
const (
+ // DEPRECATED: DefaultDeploymentUniqueLabelKey is used instead.
// DaemonSetTemplateGenerationKey is the key of the labels that is added
- // to daemon set pods to distinguish between old and new pod templates
+ // to daemon set pods to distinguish between old and new pod
// during DaemonSet template update.
DaemonSetTemplateGenerationKey string = "pod-template-generation"
+
+ // DefaultDaemonSetUniqueLabelKey is the default label key that is added
+ // to existing DaemonSet pods to distinguish between old and new
+ // DaemonSet pods during DaemonSet template updates.
+ DefaultDaemonSetUniqueLabelKey string = "daemonset-controller-hash"
)
```
@@ -163,27 +181,61 @@ const (
The DaemonSet Controller will make DaemonSet updates happen. It will watch
DaemonSets on the apiserver.
+DaemonSet controller manages [`ControllerRevisions`](controller_history.md) for
+DaemonSet revision introspection and rollback. It's referred to as "history"
+throughout the rest of this proposal.
+
For each pending DaemonSet updates, it will:
-1. Find all pods whose labels are matched by DaemonSet `.spec.selector`.
- - If `OwnerReference` is implemented for DaemonSets, filter out pods that
- aren't controlled by this DaemonSet too.
+1. Reconstruct DaemonSet history:
+ - List existing DaemonSet history controlled by this DaemonSet
+ - Find the history of DaemonSet's current target state, and create one if
+ not found:
+ - The `.name` of this history will be unique, generated from pod template
+ hash with hash collision resolution. If history creation failed:
+ - If it's because of name collision:
+ - Compare history with DaemonSet current target state:
+ - If they're the same, we've already created the history
+ - Otherwise, bump DaemonSet `.status.collisionCount` by 1, exit and
+ retry in the next sync loop
+ - Otherwise, exit and retry again in the next sync loop.
+ - The history will be labeled with `DefaultDaemonSetUniqueLabelKey`.
+ - DaemonSet controller will add a ControllerRef in the history
+ `.ownerReferences`.
+ - Current history should have the largest `.revision` number amonst all
+ existing history. Update `.revision` if it's not (e.g. after a rollback.)
+ - If more than one current history is found, remove duplicates and relabel
+ their pods' `DefaultDaemonSetUniqueLabelKey`.
+1. Sync nodes:
+ - Find all nodes that should run these pods created by this DaemonSet.
+ - Create daemon pods on nodes when they should have those pods running but not
+ yet. Otherwise, delete running daemon pods that shouldn't be running on nodes.
+ - Label new pods with current `.spec.templateGeneration` and
+ `DefaultDaemonSetUniqueLabelKey` value of current history when creating them.
1. Check `DaemonSetUpdateStrategy`:
- If `OnDelete`: do nothing
- If `RollingUpdate`:
- - Find all daemon pods that belong to this DaemonSet using label selectors.
- - Pods with "pod-template-generation" value equal to the DaemonSet's
- `.spec.templateGeneration` are new pods, otherwise they're old pods.
- - Note that pods without "pod-template-generation" labels (e.g. DaemonSet
- pods created before RollingUpdate strategy is implemented) will be
- seen as old pods.
+ - For all pods owned by this DaemonSet:
+ - If its `pod-template-generation` label value equals to DaemonSet's
+ `.spec.templateGeneration`, it's a new pod (don't compare
+ `DefaultDaemonSetUniqueLabelKey`, for backward compatibility).
+ - Add `DefaultDaemonSetUniqueLabelKey` label to the new pod based on current
+ history, if the pod doesn't have this label set yet.
+ - Otherwise, if the value doesn't match, or the pod doesn't have a
+ `pod-template-generation` label, check its `DefaultDaemonSetUniqueLabelKey` label:
+ - If the value matches any of the history's `DefaultDaemonSetUniqueLabelKey` label,
+ it's a pod generated from that history.
+ - If that history matches the current target state of the DaemonSet,
+ it's a new pod.
+ - Otherwise, it's an old pod.
+ - Otherwise, if the pod doesn't have a `DefaultDaemonSetUniqueLabelKey` label, or no
+ matching history is found, it's an old pod.
- If there are old pods found, compare `MaxUnavailable` with DaemonSet
`.status.numberUnavailable` to see how many old daemon pods can be
killed. Then, kill those pods in the order that unhealthy pods (failed,
pending, not ready) are killed first.
-1. Find all nodes that should run these pods created by this DaemonSet.
-1. Create daemon pods on nodes when they should have those pods running but not
- yet. Otherwise, delete running daemon pods that shouldn't be running on nodes.
+1. Clean up old history based on `.spec.revisionHistoryLimit`
+ - Always keep live history and current history
1. Cleanup, update DaemonSet status
- `.status.numberAvailable` = the total number of DaemonSet pods that have
become `Ready` for `MinReadySeconds`
@@ -198,6 +250,8 @@ In DaemonSet strategy (pkg/registry/extensions/daemonset/strategy.go#PrepareForU
increase DaemonSet's `.spec.templateGeneration` by 1 if any changes is made to
DaemonSet's `.spec.template`.
+This was originally implmeneted in 1.6, and kept in 1.7 for backward compatibility.
+
### kubectl
#### kubectl rollout
@@ -206,6 +260,9 @@ Users can use `kubectl rollout` to monitor DaemonSet updates:
- `kubectl rollout status daemonset/<DaemonSet-Name>`: to see the DaemonSet
upgrade status
+- `kubectl rollout history daemonset/<DaemonSet-Name>`: to view the history of
+ DaemonSet updates.
+- `kubectl rollout undo daemonset/<DaemonSet-Name>`: to rollback a DaemonSet
## Updating DaemonSets mid-way
@@ -216,7 +273,7 @@ one will begin rolling out.
## Deleting DaemonSets
-Deleting a DaemonSet (with cascading) will delete all its pods.
+Deleting a DaemonSet (with cascading) will delete all its pods and history.
## DaemonSet Strategies
@@ -281,57 +338,13 @@ In the future, we may:
- Support pausing DaemonSet rolling update
- Support auto-rollback DaemonSets
-### DaemonSet History
-
-In the future, we will support DaemonSet history, so that users can view
-previous revisions and roll back when necessary.
-
-One possible approach is to create a new resource called `DaemonSetRevision` to
-store DaemonSet history.
-
-Another way to implement DaemonSet history is through creating `PodTemplates` as
-snapshots of DaemonSet templates, and then create them in DaemonSet controller:
-
-- Find existing PodTemplates whose labels are matched by DaemonSet
- `.spec.selector`.
- - Sort those PodTemplates by creation timestamp and only retain at most
- `.spec.revisionHistoryLimit` latest PodTemplates (remove the rest).
- - Find the PodTemplate whose `.template` is the same as the DaemonSet's
- `.spec.template`.
- - If not found, create a new PodTemplate from DaemonSet's
- `.spec.template`:
- - The name will be `<DaemonSet-Name>-<template-generation>`
- - PodTemplate `.metadata.labels` will have a "pod-template-generation"
- label, value be the same as DaemonSet's `.spec.templateGeneration`.
- - PodTemplate will have revision information to avoid triggering
- unnecessary restarts on rollback, since we only roll forward and only
- increase templateGeneration.
- - PodTemplate `.metadata.annotations` will be copied from DaemonSet
- `.metadata.annotations`.
- - If the PodTemplate is found, sync its "pod-template-generation" and
- revision information with current DaemonSet.
- - DaemonSet creates pods with "pod-template-generation" label.
-
-PodTemplate may need to be made an admin-only or read only resource if it's used
-to store DaemonSet history.
-
-#### History Clean Up Policy
-
-We also need to specify a clean up policy for the number of history to keep in
-the system, and keep only limited number of history by default (for example, 3).
-
-#### kubectl
-
-`kubectl` should also support DaemonSet history:
-
-- `kubectl rollout undo daemonset/<DaemonSet-Name>` to roll back
-- `kubectl rollout history daemonset/<DaemonSet-Name>`: to view the history of
- DaemonSet updates
+### API
-#### API
+Implement a subresource for DaemonSet history (`daemonsets/foo/history`) that
+summarizes the information in the history.
-Implement a subresource for DaemonSet history (e.g. `daemonsets/foo/history`)
-that summarizes the information in the history.
+Implement a subresource for DaemonSet rollback (`daemonsets/foo/rollback`) that
+triggers a DaemonSet rollback.
### Tests