Merge pull request #2781 from pikasTech/fix/2779-temporal-reaper
Pipelines as Code CI / hwlab-web-probe-sentinel-nc01- Success
Pipelines as Code CI / platform-infra-gitea-nc01- Success
Pipelines as Code CI / unidesk-host- Success

修复 Temporal server PID 1 子进程回收泄露
This commit is contained in:
Lyon
2026-07-21 20:30:21 +08:00
committed by GitHub
2 changed files with 17 additions and 3 deletions
+1
View File
@@ -47,6 +47,7 @@ runtime:
frontendPort: 7233
dynamicConfigFilePath: /etc/temporal/config/dynamicconfig/docker.yaml
enableServiceLinks: false
shareProcessNamespace: true
ui:
deploymentName: temporal-ui
serviceName: temporal-ui
+16 -3
View File
@@ -80,6 +80,7 @@ export interface TemporalConfig {
frontendPort: number;
dynamicConfigFilePath: string;
enableServiceLinks: boolean;
shareProcessNamespace: boolean;
};
ui: {
deploymentName: string;
@@ -290,6 +291,7 @@ spec:
app.kubernetes.io/part-of: temporal
spec:
enableServiceLinks: ${server.enableServiceLinks}
shareProcessNamespace: ${server.shareProcessNamespace}
containers:
- name: temporal
image: ${temporal.images.server}
@@ -498,19 +500,26 @@ ui_ready="$(kubectl -n ${target.namespace} get deploy ${ui.deploymentName} -o js
endpoint="$(kubectl -n ${target.namespace} get endpoints ${server.serviceName} -o jsonpath='{.subsets[0].addresses[0].ip}' 2>/dev/null || true)"
ui_endpoint="$(kubectl -n ${target.namespace} get endpoints ${ui.serviceName} -o jsonpath='{.subsets[0].addresses[0].ip}' 2>/dev/null || true)"
secret="$(kubectl -n ${target.namespace} get secret ${temporal.database.secretName} -o name 2>/dev/null || true)"
process_table="$(kubectl -n ${target.namespace} exec deploy/${server.deploymentName} -- ps -eo pid,ppid,stat,comm,args 2>/dev/null || true)"
pid1_command="$(printf '%s\n' "$process_table" | awk 'NR > 1 && $1 == 1 { print $4; exit }')"
temporal_pid="$(printf '%s\n' "$process_table" | awk 'NR > 1 && $4 == "temporal-server" { print $1; exit }')"
zombie_count="$(printf '%s\n' "$process_table" | awk 'NR > 1 && $3 ~ /^Z/ { count += 1 } END { print count + 0 }')"
logical_present=0
for logical in ${logicalArgs}; do
if kubectl -n ${target.namespace} exec deploy/${server.deploymentName} -- temporal operator namespace describe --address ${server.serviceName}:${server.frontendPort} --namespace "$logical" >/dev/null 2>&1; then
logical_present=$((logical_present + 1))
fi
done
python3 - "$server_ready" "$ui_ready" "$endpoint" "$ui_endpoint" "$secret" "$logical_present" "${logicalNames.length}" "${validate}" <<'PY'
python3 - "$server_ready" "$ui_ready" "$endpoint" "$ui_endpoint" "$secret" "$logical_present" "${logicalNames.length}" "$pid1_command" "$temporal_pid" "$zombie_count" "${validate}" <<'PY'
import json, sys
server_ready, ui_ready, endpoint, ui_endpoint, secret = sys.argv[1:6]
logical_present, logical_expected = int(sys.argv[6]), int(sys.argv[7])
validate = sys.argv[8] == "true"
pid1_command, temporal_pid = sys.argv[8], sys.argv[9]
zombie_count = int(sys.argv[10])
validate = sys.argv[11] == "true"
ready = int(server_ready or 0) >= ${server.replicas} and int(ui_ready or 0) >= ${ui.replicas}
ok = ready and bool(endpoint) and bool(ui_endpoint) and bool(secret) and logical_present == logical_expected
process_reaping = bool(pid1_command) and pid1_command != "temporal-server" and int(temporal_pid or 0) > 1 and zombie_count == 0
ok = ready and bool(endpoint) and bool(ui_endpoint) and bool(secret) and logical_present == logical_expected and process_reaping
print(json.dumps({
"ok": ok,
"mode": "validate" if validate else "status",
@@ -519,6 +528,7 @@ print(json.dumps({
"ui": {"readyReplicas": int(ui_ready or 0), "endpointPresent": bool(ui_endpoint), "publicUrl": "${temporal.publicExposure.publicBaseUrl}"},
"database": {"mode": "nc01-host-native-postgresql", "host": "${temporal.database.host}", "secretPresent": bool(secret), "valuesPrinted": False},
"logicalNamespaces": {"expected": logical_expected, "present": logical_present, "names": ${JSON.stringify(logicalNames)}},
"processReaping": {"ok": process_reaping, "pid1Command": pid1_command, "temporalPid": int(temporal_pid or 0), "zombieCount": zombie_count},
}, ensure_ascii=False))
sys.exit(0 if ok else 1)
PY
@@ -623,6 +633,7 @@ export function readTemporalConfig(): TemporalConfig {
...deploymentConfig(server, `${configLabel}.runtime.server`, "frontendPort"),
dynamicConfigFilePath: stringField(server, "dynamicConfigFilePath", `${configLabel}.runtime.server`),
enableServiceLinks: booleanField(server, "enableServiceLinks", `${configLabel}.runtime.server`),
shareProcessNamespace: booleanField(server, "shareProcessNamespace", `${configLabel}.runtime.server`),
},
ui: {
...deploymentConfig(ui, `${configLabel}.runtime.ui`, "port"),
@@ -696,6 +707,7 @@ function policyChecks(temporal: TemporalConfig, target: TemporalTarget, manifest
{ name: "native-postgres", ok: temporal.database.configRef === "config/platform-db/postgres-nc01.yaml", detail: temporal.database.configRef },
{ name: "no-in-cluster-postgres", ok: !/kind: StatefulSet|PersistentVolumeClaim|image: .*postgres/iu.test(manifest), detail: "Temporal manifest contains no PostgreSQL workload or PVC." },
{ name: "cluster-internal-grpc", ok: !/type: (?:NodePort|LoadBalancer)/u.test(manifest), detail: `${temporal.runtime.server.serviceName}.${target.namespace}.svc.cluster.local` },
{ name: "pid1-reaper", ok: temporal.runtime.server.shareProcessNamespace && /shareProcessNamespace: true/u.test(manifest), detail: `${configLabel}.runtime.server.shareProcessNamespace` },
{ name: "public-ui-only", ok: temporal.publicExposure.publicBaseUrl === "https://temporal.hwpod.com", detail: temporal.publicExposure.publicBaseUrl },
{ name: "unified-web-admin", ok: temporal.runtime.ui.auth.secretName === "temporal-web-admin", detail: "Web password is distributed from unified-admin-password.txt through the secrets CLI." },
];
@@ -711,6 +723,7 @@ function summary(temporal: TemporalConfig, target: TemporalTarget): Record<strin
images: temporal.images,
database: { mode: "host-native", configRef: temporal.database.configRef, sourceRef: temporal.database.sourceRef, host: temporal.database.host, sslMode: temporal.database.sslMode },
frontend: `${temporal.runtime.server.serviceName}.${target.namespace}.svc.cluster.local:${temporal.runtime.server.frontendPort}`,
processReaping: { shareProcessNamespace: temporal.runtime.server.shareProcessNamespace },
logicalNamespaces: temporal.runtime.logicalNamespaces,
publicExposure: temporal.publicExposure,
};