Skip to content

Commit 2ff7e5e

Browse files
authored
deploy: restart now force-recreates compose containers (#752)
Operator-reported: editing source files mounted into a service via bind volumes (alert rules, dashboards, scripts, templates, telegraf config) and running 'laconic-so deployment ... restart' did not take effect. Operator had to fall back to 'stop && start' to pick up changes. Root cause: 'restart' calls up_operation, which translates to 'docker compose up -d'. Compose's up only recreates a container when the *service definition* itself (image, env, ports, volume declarations) changes. Bind-mount target file content is not part of that hash, so the running container kept its old in-memory state (e.g. Grafana's pre-edit provisioning). Add force_recreate kwarg through the deployer interface and have restart pass force_recreate=True. compose path threads through to python_on_whales' compose.up(force_recreate=...). k8s path accepts the kwarg but is a no-op for now (rolling update on unchanged-spec needs a separate fix that stamps the kubectl.kubernetes.io/restartedAt annotation on managed Deployments; tracked in a follow-up).
1 parent cf0e230 commit 2ff7e5e

5 files changed

Lines changed: 45 additions & 4 deletions

File tree

stack_orchestrator/deploy/compose/deploy_docker.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,21 @@ def __init__(
4848
self.compose_project_name = compose_project_name
4949
self.compose_env_file = compose_env_file
5050

51-
def up(self, detach, skip_cluster_management, services, image_overrides=None):
51+
def up(
52+
self,
53+
detach,
54+
skip_cluster_management,
55+
services,
56+
image_overrides=None,
57+
force_recreate=False,
58+
):
5259
if not opts.o.dry_run:
5360
try:
54-
return self.docker.compose.up(detach=detach, services=services)
61+
return self.docker.compose.up(
62+
detach=detach,
63+
services=services,
64+
force_recreate=force_recreate,
65+
)
5566
except DockerException as e:
5667
raise DeployerException(e)
5768

stack_orchestrator/deploy/deploy.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ def up_operation(
142142
stay_attached=False,
143143
skip_cluster_management=False,
144144
image_overrides=None,
145+
force_recreate=False,
145146
):
146147
global_context = ctx.parent.parent.obj
147148
deploy_context = ctx.obj
@@ -161,6 +162,7 @@ def up_operation(
161162
skip_cluster_management=skip_cluster_management,
162163
services=services_list,
163164
image_overrides=image_overrides,
165+
force_recreate=force_recreate,
164166
)
165167
for post_start_command in cluster_context.post_start_commands:
166168
_run_command(global_context, cluster_context.cluster, post_start_command)

stack_orchestrator/deploy/deployer.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@
2020

2121
class Deployer(ABC):
2222
@abstractmethod
23-
def up(self, detach, skip_cluster_management, services, image_overrides=None):
23+
def up(
24+
self,
25+
detach,
26+
skip_cluster_management,
27+
services,
28+
image_overrides=None,
29+
force_recreate=False,
30+
):
2431
pass
2532

2633
@abstractmethod

stack_orchestrator/deploy/deployment.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,12 +471,18 @@ def restart(ctx, stack_path, spec_file, config_file, force, expected_ip, image):
471471
ctx, deployment_context, maintenance_svc, image_overrides
472472
)
473473
else:
474+
# force_recreate=True so source-file edits (alert rules, dashboards,
475+
# entrypoint scripts, etc. mounted via bind volumes) are picked up.
476+
# docker compose up -d alone is a no-op when the service definition
477+
# itself is unchanged, leaving the running container with stale
478+
# in-memory state.
474479
up_operation(
475480
ctx,
476481
services_list=None,
477482
stay_attached=False,
478483
skip_cluster_management=True,
479484
image_overrides=image_overrides or None,
485+
force_recreate=True,
480486
)
481487

482488
# Restore cwd after both create_operation and up_operation have run.
@@ -514,12 +520,15 @@ def _restart_with_maintenance(
514520

515521
# Step 1: Apply the full deployment (creates/updates all pods + services)
516522
# This ensures maintenance pod exists before we swap Ingress to it.
523+
# force_recreate intent matches the non-maintenance restart path; the
524+
# k8s deployer currently ignores the flag (TODO in deploy_k8s.up).
517525
up_operation(
518526
ctx,
519527
services_list=None,
520528
stay_attached=False,
521529
skip_cluster_management=True,
522530
image_overrides=image_overrides or None,
531+
force_recreate=True,
523532
)
524533

525534
# Parse maintenance service spec: "container-name:port"

stack_orchestrator/deploy/k8s/deploy_k8s.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,19 @@ def _create_nodeports(self):
987987
else:
988988
raise
989989

990-
def up(self, detach, skip_cluster_management, services, image_overrides=None):
990+
def up(
991+
self,
992+
detach,
993+
skip_cluster_management,
994+
services,
995+
image_overrides=None,
996+
force_recreate=False,
997+
):
998+
# TODO: honor force_recreate by stamping the
999+
# kubectl.kubernetes.io/restartedAt annotation on managed
1000+
# Deployments so a rollout occurs even when the manifest is
1001+
# unchanged. Today this method is a no-op for that flag.
1002+
# Tracked separately from the compose-side fix.
9911003
# Merge spec-level image overrides with CLI overrides
9921004
spec_overrides = self.cluster_info.spec.get("image-overrides", {})
9931005
if spec_overrides:

0 commit comments

Comments
 (0)