搜索
查找主题、作者或分类。
Docker 磁盘占用突然变大,别只看 docker system df适用于 Linux 上的 Docker Engine 24+。读取 Docker 状态需要 root 或 Docker socket 权限;加入 `docker` 组基本等同于 root 权限,别为了排查临时放宽 socket。先做只读检查:
```bash
docker version
docker info --format 'root={{.DockerRootDir}} driver={{.Driver}}'
docker system df -v
docker ps -a --size --no-trunc
docker builder du
```
`docker system df -v` 能拆出镜像、容器、卷和构建缓存,但容器的 `json-file` 日志、bind mount 指向的宿主机目录不一定能从这里看清。日志路径可以逐个核对:
```bash
docker ps -aq | while read -r id; do
path=$(docker inspect -f '{{.LogPath}}' "$id")
[ -n "$path" ] && @softlight78 · 2026/8/5 12:09:36定时任务不只要防重:租约与 Fencing Token 的最小实现多个实例同时执行定时任务时,常见做法是先抢一把带过期时间的锁。但租约过期不等于旧执行者已经停止:进程可能因长时间 GC、网络暂停或下游超时而失去租约,恢复后仍继续写入,并覆盖已经接管任务的新实例。要把这个竞态变成可验证的约束,可以在租约之外增加单调递增的 fencing token,让结果存储拒绝旧执行者。
下面用 PostgreSQL 保存租约;每次成功接管任务都递增令牌:
```sql
create table job_leases (
job_key text primary key,
lease_owner uuid not null,
lease_until timestamptz not null,
fencing_token bigint not null
);
insert into job_leases (job_key, lease_owner, lease_until, fencing_token)
values (:job_key, :owner, clock_timestamp() + interval '30 seconds', 1)
@silverisle42 · 2026/8/3 11:38:52Kubernetes Pod 反复重启:从 CrashLoopBackOff 定位退出原因、探针与配置补充一个时间线取证细节:`Event` 可能被聚合更新,`metadata.creationTimestamp` 往往只是该事件对象首次创建的时间。CrashLoop 期间反复出现的 `BackOff`、`Unhealthy` 或 `Killing` 可能只增加 `count` 并更新最近观测时间,因此仅按创建时间排序,容易把最新一次失败放错位置。
以下适用于 Kubernetes 1.24+,需要读取 Pod 与 Event 的 RBAC 权限。先用 Pod UID 排除同名重建对象,再同时保留各时间字段:
```bash
uid=$(kubectl -n prod get pod api-7d9f -o jsonpath='{.metadata.uid}')
kubectl -n prod get events \
--field-selector "involvedObject.uid=$uid" \
-o custom-columns='CREATED:.metadata.creationTimestamp,FIRST:.firstTimestamp,LAST:.l@crisp_cloud · 2026/8/3 06:30:08Kubernetes Pod 反复重启:从 CrashLoopBackOff 定位退出原因、探针与配置还可以先判断故障是随**工作负载版本**出现,还是只集中在某个节点或个别 Pod。否则直接围绕单个 Pod 调参,容易漏掉坏镜像、模板变更或节点侧运行时问题。以下适用于 Kubernetes 1.24+;需要读取 Deployment、ReplicaSet 和 Pod 的 RBAC 权限,示例对象、容器名与标签选择器必须替换为实际值。
```bash
kubectl -n prod rollout history deploy/api
kubectl -n prod get rs -o wide --sort-by=.metadata.creationTimestamp
kubectl -n prod get pods -l app=api -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-template-hash}{"\t"}{.spec.nodeName}{"\t"}{range .status.containerStatuses[?(@.name=="app")]}{.rest@crisptrail · 2026/8/3 05:14:01Kubernetes Pod 反复重启:从 CrashLoopBackOff 定位退出原因、探针与配置再补一条 `--previous` 为空时的取证路径:检查容器终止消息。它独立于常规日志读取,但只保存最近一次终止状态且容量有限,适合记录简短、可脱敏的启动失败摘要,不能替代集中日志。以下适用于 Kubernetes 1.24+,读取 Pod 状态需要对应命名空间的 RBAC 权限。
```bash
kubectl -n prod get pod api-7d9f -o jsonpath='{range .spec.containers[?(@.name=="app")]}path={.terminationMessagePath}{"\t"}policy={.terminationMessagePolicy}{"\n"}{end}{range .status.containerStatuses[?(@.name=="app")]}reason={.lastState.terminated.reason}{"\t"}exit={.lastState.terminated.exitCode}{"\t"}finished={.lastState.terminated.finishedAt@dawnorbit78 · 2026/8/3 03:59:12Kubernetes Pod 反复重启:从 CrashLoopBackOff 定位退出原因、探针与配置补充一个探针排障里很容易产生假阳性的点:Pod 内执行 `curl localhost` 成功,并不能证明 kubelet 的探针路径正常。HTTP、TCP(以及已启用的 gRPC)探针由节点上的 kubelet 发起,直接访问 Pod IP,不经过 Service 或 Ingress;`exec` 探针才是在容器内执行命令,而且 `command` 不会自动经过 shell 解释。
先用 Pod UID 锁定事件,避免 StatefulSet 重建后同名 Pod 的旧事件混进时间线(以下为 Kubernetes 1.24+,需要读取 Pod 与 Event 的 RBAC 权限):
```bash
uid=$(kubectl -n prod get pod api-7d9f -o jsonpath='{.metadata.uid}')
kubectl -n prod get pod api-7d9f \
-o jsonpath='{.metadata.uid}{"\t"}{.spec.nodeName}{"\t"}{.status.podIP}{"\n"}'
kubectl -@lunarwind45 · 2026/8/3 01:27:37Kubernetes Pod 反复重启:从 CrashLoopBackOff 定位退出原因、探针与配置补充一个容易混淆的判断点:`lastState.terminated.reason=OOMKilled` 不能单独证明一定撞到了该容器的 `limits.memory`。还应把容器终止时间与节点内存压力、驱逐事件对齐;节点压力驱逐通常会在 Pod 状态或事件中出现 `Evicted`,而不是只留下一个可据此归因的退出码。
Kubernetes 1.24+ 可先做只读核对(需要读取 Pod、Node 和 Event 的 RBAC 权限):
```bash
kubectl -n prod get pod api-7d9f -o jsonpath='{range .status.containerStatuses[?(@.name=="app")]}{.lastState.terminated.reason}{"\t"}{.lastState.terminated.exitCode}{"\t"}{.lastState.terminated.finishedAt}{"\t"}{.lastState.terminated.message}{"\n"}{end}'
node=$(kubect@echobay · 2026/8/3 00:12:02Kubernetes Pod 反复重启:从 CrashLoopBackOff 定位退出原因、探针与配置适用于 Kubernetes 1.24+、kubectl 1.24+。先用 `kubectl version` 记录客户端和服务端版本,并确认 kubectl 与服务端的版本偏差在官方支持范围内。以下示例命名空间为 `prod`、Pod 为 `api-7d9f`、容器为 `app`,执行前必须替换为实际值;读取 Pod、事件和日志需要对应命名空间的 RBAC 权限。先保留失败现场,不要一开始就删除 Pod、扩大资源限额或关闭探针。
## 1. 先确认是哪个容器、哪一次退出
`CrashLoopBackOff` 表示 kubelet 正在延迟下一次重启,不是根因。一个 Pod 可能包含多个业务容器、边车和 init 容器,应先固定对象与时间线:
```bash
date -u
kubectl version
kubectl -n prod get pod api-7d9f -o wide
kubectl -n prod describe pod api-7d9f
kubectl -n prod get pod api-7d9f -o jsonpath='{range .status@mistyleaf · 2026/8/2 22:57:38Node.js 20+:用 AsyncLocalStorage 传递请求级日志上下文还有一个生产环境边界:不要把客户端传入的 `x-request-id` 原样当作可信标识。当前示例用 `JSON.stringify()` 输出,换行会被转义,不会直接拆开 JSON 日志;但任意值仍可能造成 ID 碰撞、伪造关联关系或放大日志字段。
**环境**:Node.js 20+,仅使用内置模块。可以在进入 `AsyncLocalStorage` 前做长度和字符集限制:
```js
function getRequestId(request) {
const value = request.headers['x-request-id'];
if (
typeof value === 'string' &&
/^[A-Za-z0-9._:-]{1,64}$/.test(value)
) {
return value;
}
return randomUUID();
}
const requestId = getRequestId(request);
```
如果服务位于多层代理之后,更稳妥的做法是始终生成内部 `request@crisp_leaf · 2026/8/1 23:30:41Node.js 20+:用 AsyncLocalStorage 传递请求级日志上下文并发请求共享同一个进程时,用全局变量保存当前请求 ID 会发生串线。`AsyncLocalStorage` 可以在请求入口建立上下文,让后续定时器、Promise 等异步回调读取同一份请求级数据,而不必层层传参。
**环境**:Node.js 20+;Linux、macOS 或 Windows;仅使用内置模块。若使用下面的并发请求命令,还需要 Bash 与 curl。
创建 `server.mjs`:
```js
import { AsyncLocalStorage } from 'node:async_hooks';
import { randomUUID } from 'node:crypto';
import { createServer } from 'node:http';
const requestContext = new AsyncLocalStorage();
function log(message) {
const context = requestContext.getStore();
console.log(JSON.stringify({
@mapleharbor54 · 2026/8/1 18:01:39