
When scaling down a ReplicaSet, delete doubled up replicas first, where a "doubled up replica" is defined as one that is on the same node as an active replica belonging to a related ReplicaSet. ReplicaSets are considered "related" if they have a common controller (typically a Deployment). The intention of this change is to make a rolling update of a Deployment scale down the old ReplicaSet as it scales up the new ReplicaSet by deleting pods from the old ReplicaSet that are colocated with ready pods of the new ReplicaSet. This change in the behavior of rolling updates can be combined with pod affinity rules to preserve the locality of a Deployment's pods over rollout. A specific scenario that benefits from this change is when a Deployment's pods are exposed by a Service that has type "LoadBalancer" and external traffic policy "Local". In this scenario, the load balancer uses health checks to determine whether it should forward traffic for the Service to a particular node. If the node has no local endpoints for the Service, the health check will fail for that node. Eventually, the load balancer will stop forwarding traffic to that node. In the meantime, the service proxy drops traffic for that Service. Thus, in order to reduce risk of dropping traffic during a rolling update, it is desirable preserve node locality of endpoints. * pkg/controller/controller_utils.go (ActivePodsWithRanks): New type to sort pods using a given ranking. * pkg/controller/controller_utils_test.go (TestSortingActivePodsWithRanks): New test for ActivePodsWithRanks. * pkg/controller/replicaset/replica_set.go (getReplicaSetsWithSameController): New method. Given a ReplicaSet, return all ReplicaSets that have the same owner. (manageReplicas): Call getIndirectlyRelatedPods, and pass its result to getPodsToDelete. (getIndirectlyRelatedPods): New method. Given a ReplicaSet, return all pods that are owned by any ReplicaSet with the same owner. (getPodsToDelete): Add an argument for related pods. Use related pods and the new getPodsRankedByRelatedPodsOnSameNode function to take into account whether a pod is doubled up when sorting pods for deletion. (getPodsRankedByRelatedPodsOnSameNode): New function. Return an ActivePodsWithRanks value that wraps the given slice of pods and computes ranks where each pod's rank is equal to the number of active related pods that are colocated on the same node. * pkg/controller/replicaset/replica_set_test.go (newReplicaSet): Set OwnerReferences on the ReplicaSet. (newPod): Set a unique UID on the pod. (byName): New type to sort pods by name. (TestGetReplicaSetsWithSameController): New test for getReplicaSetsWithSameController. (TestRelatedPodsLookup): New test for getIndirectlyRelatedPods. (TestGetPodsToDelete): Augment the "various pod phases and conditions, diff = len(pods)" test case to ensure that scale-down still selects doubled-up pods if there are not enough other pods to scale down. Add a "various pod phases and conditions, diff = len(pods), relatedPods empty" test case to verify that getPodsToDelete works even if related pods could not be determined. Add a "ready and colocated with another ready pod vs not colocated, diff < len(pods)" test case to verify that a doubled-up pod gets preferred for deletion. Augment the "various pod phases and conditions, diff < len(pods)" test case to ensure that not-ready pods are preferred over ready but doubled-up pods. * pkg/controller/replicaset/BUILD: Regenerate. * test/e2e/apps/deployment.go (testRollingUpdateDeploymentWithLocalTrafficLoadBalancer): New end-to-end test. Create a deployment with a rolling update strategy and affinity rules and a load balancer with "Local" external traffic policy, and verify that set of nodes with local endponts for the service remains unchanged during rollouts. (setAffinity): New helper, used by testRollingUpdateDeploymentWithLocalTrafficLoadBalancer. * test/e2e/framework/service/jig.go (GetEndpointNodes): Factor building the set of node names out... (GetEndpointNodeNames): ...into this new method.
93 lines
4.1 KiB
Python
93 lines
4.1 KiB
Python
package(default_visibility = ["//visibility:public"])
|
|
|
|
load(
|
|
"@io_bazel_rules_go//go:def.bzl",
|
|
"go_library",
|
|
"go_test",
|
|
)
|
|
|
|
go_library(
|
|
name = "go_default_library",
|
|
srcs = [
|
|
"doc.go",
|
|
"replica_set.go",
|
|
"replica_set_utils.go",
|
|
],
|
|
importpath = "k8s.io/kubernetes/pkg/controller/replicaset",
|
|
deps = [
|
|
"//pkg/api/v1/pod:go_default_library",
|
|
"//pkg/controller:go_default_library",
|
|
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
|
"//staging/src/k8s.io/client-go/informers/apps/v1:go_default_library",
|
|
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
|
|
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
|
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
|
"//staging/src/k8s.io/client-go/kubernetes/typed/apps/v1:go_default_library",
|
|
"//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
|
"//staging/src/k8s.io/client-go/listers/apps/v1:go_default_library",
|
|
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
|
|
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
|
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
|
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
|
|
"//staging/src/k8s.io/component-base/metrics/prometheus/ratelimiter:go_default_library",
|
|
"//vendor/k8s.io/klog:go_default_library",
|
|
"//vendor/k8s.io/utils/integer:go_default_library",
|
|
],
|
|
)
|
|
|
|
go_test(
|
|
name = "go_default_test",
|
|
srcs = [
|
|
"replica_set_test.go",
|
|
"replica_set_utils_test.go",
|
|
],
|
|
embed = [":go_default_library"],
|
|
deps = [
|
|
"//pkg/controller:go_default_library",
|
|
"//pkg/controller/testutil:go_default_library",
|
|
"//pkg/securitycontext:go_default_library",
|
|
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
|
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
|
|
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
|
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
|
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
|
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
|
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
|
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
|
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
|
|
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
|
|
],
|
|
)
|
|
|
|
filegroup(
|
|
name = "package-srcs",
|
|
srcs = glob(["**"]),
|
|
tags = ["automanaged"],
|
|
visibility = ["//visibility:private"],
|
|
)
|
|
|
|
filegroup(
|
|
name = "all-srcs",
|
|
srcs = [
|
|
":package-srcs",
|
|
"//pkg/controller/replicaset/config:all-srcs",
|
|
],
|
|
tags = ["automanaged"],
|
|
)
|