Skip to content

Commit d8c3b85

Browse files
authored
Merge pull request #260 from fiaas/pdb-unhealthy-pod-eviction-policy
Add support in PDBs to be able to set unhealthyPodEvictionPolicy.
2 parents d3c8d3c + 137748b commit d8c3b85

File tree

5 files changed

+49
-4
lines changed

5 files changed

+49
-4
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ limitations under the License.
2121

2222
[![Build status](https://fiaas-svc.semaphoreci.com/badges/fiaas-deploy-daemon.svg?style=shields)](https://fiaas-svc.semaphoreci.com/projects/fiaas-deploy-daemon)
2323

24-
You need Python 3.9+ and `pip`(7.x.x or higher) on your `PATH` to work with fiaas-deploy-daemon.
24+
You need Python 3.12 and `pip`(7.x.x or higher) on your `PATH` to work with fiaas-deploy-daemon.
2525

2626
Supported use-cases
2727
-------------------

docs/operator_guide.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,13 @@ This feature is disabled by default.
211211

212212
By default, PDB will be set with maxUnavailable = 1 in case the deployment has more than 1 replica. This parameter allows to change that value either with another int value or with a string percentage (i.e. "20%"). Recommendation is some low value like 10% to avoid issues. Also in case of a number, something below min_replicas should be used to allow evictions.
213213

214+
### pdb-unhealthy-pod-eviction-policy
215+
This option is useful for avoiding operational problems, with node rotations, when there exists deployments with only unhealthy pods. This can be useful in dev clusters which have deployment with only unhealthy pods or in production clusters where the applications tolerate unhealthy pods being disrupted, while new pods are being started.
216+
217+
This option Controls when unhealthy running pods can be evicted. The default 'IfHealthyBudget' allows eviction only if enough healthy pods are available to maintain the desired count of healthy pods. 'AlwaysAllow' permits eviction of unhealthy running pods even if doing so would leave fewer pods than desired temporarily.
218+
219+
[Kubernetes documentation is available here.](https://kubernetes.io/docs/tasks/run-application/configure-pdb/#unhealthy-pod-eviction-policy)
220+
214221
### disable-service-links
215222

216223
By default, [enableServiceLinks](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#podspec-v1-core) is set to true, which means that environment variables are automatically created for each service in the same namespace. This parameter allows you to disable this feature by setting disable-service-links to true. This can be useful in scenarios where you have a large number of services and you want to reduce the number of environment variables that are automatically created. For new installations, it's recommended to disable this feature to streamline the environment setup. However, for existing installations, proceed with caution when disabling this feature. This is due to potential compatibility issues, as some services might rely on these automatically created environment variables for communication.

fiaas_deploy_daemon/config.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,16 @@ def _parse_args(self, args):
328328
default="1",
329329
type=_int_or_unicode
330330
)
331+
parser.add_argument(
332+
"--pdb-unhealthy-pod-eviction-policy",
333+
help=(
334+
"The policy for unhealthy pods. IfHealthyBudget will only evict pods if the there "
335+
"are enough healthy pods to maintain the budget. AlwaysAllow will allow "
336+
"disruptions of unhealthy pods, even when the budget is not met."
337+
),
338+
default="IfHealthyBudget",
339+
choices=("IfHealthyBudget", "AlwaysAllow"),
340+
)
331341
# Logic is inverted due to ConfigArgParse not supporting boolean flags with negation
332342
parser.add_argument(
333343
"--disable-service-links",

fiaas_deploy_daemon/deployer/kubernetes/pod_disruption_budget.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(self, owner_references, extension_hook, config):
3434
self._owner_references = owner_references
3535
self._extension_hook = extension_hook
3636
self.max_unavailable = config.pdb_max_unavailable
37+
self.unhealthy_pod_eviction_policy = config.pdb_unhealthy_pod_eviction_policy
3738

3839
@retry_on_upsert_conflict
3940
def deploy(self, app_spec: AppSpec, selector: dict[str, any], labels: dict[str, any]):
@@ -58,7 +59,8 @@ def deploy(self, app_spec: AppSpec, selector: dict[str, any], labels: dict[str,
5859

5960
spec = PodDisruptionBudgetSpec(
6061
selector=LabelSelector(matchLabels=selector),
61-
maxUnavailable=max_unavailable
62+
maxUnavailable=max_unavailable,
63+
unhealthyPodEvictionPolicy=self.unhealthy_pod_eviction_policy
6264
)
6365

6466
pdb = PodDisruptionBudget.get_or_create(metadata=metadata, spec=spec)

tests/fiaas_deploy_daemon/deployer/kubernetes/test_pod_disruption_budget_deploy.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ def deployer(self, owner_references, extension_hook, config):
4343

4444
@pytest.fixture
4545
def config(self):
46-
config = create_autospec(Configuration([]), spec_set=True)
47-
config.pdb_max_unavailable = 1
46+
config = Configuration([])
4847
return config
4948

5049
@pytest.mark.usefixtures("get")
@@ -54,6 +53,7 @@ def test_new_pdb(self, deployer, post, app_spec, owner_references, extension_hoo
5453
"spec": {
5554
"maxUnavailable": 1,
5655
"selector": {"matchExpressions": [], "matchLabels": {"app": "testapp"}},
56+
"unhealthyPodEvictionPolicy": "IfHealthyBudget",
5757
},
5858
}
5959
mock_response = create_autospec(Response)
@@ -101,6 +101,7 @@ def test_setting_max_int(self, deployer, post, app_spec, owner_references, exten
101101
"spec": {
102102
"maxUnavailable": 2,
103103
"selector": {"matchExpressions": [], "matchLabels": {"app": "testapp"}},
104+
"unhealthyPodEvictionPolicy": "IfHealthyBudget",
104105
},
105106
}
106107
mock_response = create_autospec(Response)
@@ -132,6 +133,31 @@ def test_setting_max_str(self, deployer, post, app_spec, owner_references, exten
132133
"spec": {
133134
"maxUnavailable": "20%",
134135
"selector": {"matchExpressions": [], "matchLabels": {"app": "testapp"}},
136+
"unhealthyPodEvictionPolicy": "IfHealthyBudget",
137+
},
138+
}
139+
mock_response = create_autospec(Response)
140+
mock_response.json.return_value = expected_pdb
141+
post.return_value = mock_response
142+
143+
deployer.deploy(app_spec, SELECTOR, LABELS)
144+
145+
pytest.helpers.assert_any_call(post, PDB_API, expected_pdb)
146+
owner_references.apply.assert_called_once_with(TypeMatcher(PodDisruptionBudget), app_spec)
147+
extension_hook.apply.assert_called_once_with(TypeMatcher(PodDisruptionBudget), app_spec)
148+
149+
@pytest.mark.usefixtures("get")
150+
def test_setting_unhealthy_policy(self, deployer, post, app_spec, owner_references, extension_hook):
151+
app_spec = app_spec._replace(
152+
autoscaler=AutoscalerSpec(enabled=True, min_replicas=4, max_replicas=6, cpu_threshold_percentage=50)
153+
)
154+
deployer.unhealthy_pod_eviction_policy = "AlwaysAllow"
155+
expected_pdb = {
156+
"metadata": pytest.helpers.create_metadata("testapp", labels=LABELS),
157+
"spec": {
158+
"maxUnavailable": 1,
159+
"selector": {"matchExpressions": [], "matchLabels": {"app": "testapp"}},
160+
"unhealthyPodEvictionPolicy": "AlwaysAllow",
135161
},
136162
}
137163
mock_response = create_autospec(Response)

0 commit comments

Comments
 (0)