拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CentOS7 Docker daemon.json配置实战:从加速到日志轮转避坑指南

CentOS7 Docker daemon.json配置实战:从加速到日志轮转避坑指南

用 CentOS7 装机装了无数次 Docker 之后,我越来越确认一个观点:Docker 装好只是开始,真正决定你后面运维省不省心的,是你有没有把/etc/docker/daemon.json写对。很多人遇到拉镜像慢、容器日志把磁盘塞满、daemon 一重启业务就断、甚至 Docker 起不来,十有八九都是栽在这个文件上。这篇就把我这些年跟 daemon.json 打交道踩过的坑、总结出的写法、还有排查问题的思路一次性梳理清楚,照着抄基本不会出错。

1. 先搞清楚 daemon.json 是什么

1.1 它是 Docker 守护进程的“总配置入口”

Docker 在 CentOS7 上安装完以后,默认情况下你执行docker info,看到的是 Docker 自己的一套默认参数。但实际生产环境不可能全用默认值,你需要告诉 dockerd:镜像从哪里拉、容器日志怎么轮转、数据存哪个磁盘、daemon 重启时容器要不要跟着挂掉。

这些配置如果全部靠启动命令dockerd --xxx --yyy传参,那命令行会非常臃肿,而且不便于统一管理。daemon.json 就是把这些参数集中放到一个 JSON 文件里,dockerd 启动时会自动读取并应用。它的默认路径是/etc/docker/daemon.json,没有这个文件时 Docker 就走内置默认配置。

很多刚接触的人会疑惑:既然叫 daemon.json,那它管的是“daemon”,跟容器里的环境变量、命令参数有什么关系?关系不大。daemon.json 管的是 Docker 引擎本身的行为,不是某个具体容器的配置。容器级别的配置要么用docker run的参数,要么用 docker-compose.yml,而引擎级别的全局设置都在 daemon.json 里。这个认知如果没建立,后面配置容易张冠李戴。

1.2 什么场景下你非得动它

从我实际接触的 CentOS7 运维环境看,下面这几个场景基本是绕不开 daemon.json 的:

  • 镜像拉取慢,或者默认官方源访问不稳定,需要配置国内可用的镜像加速地址。
  • 容器日志无限增长,/var/lib/docker/containers/目录把根分区撑爆,需要配置日志轮转策略。
  • Docker 默认数据目录在系统盘,根分区空间紧张,需要把>ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

    注意这行里没有带--config-file参数,所以 dockerd 默认去找/etc/docker/daemon.json。如果你因为某种原因把配置文件放到了别的路径,就必须在启动命令里显式指定。可以创建一个 drop-in 文件:

    mkdir -p /etc/systemd/system/docker.service.d cat > /etc/systemd/system/docker.service.d/override.conf <<'EOF' [Service] ExecStart= ExecStart=/usr/bin/dockerd --config-file=/opt/docker/conf/daemon.json EOF

    这里有一个非常容易踩的坑:drop-in 文件里如果写了 ExecStart,必须先把原来的 ExecStart 清空,也就是先写一行ExecStart=再写新的。否则 systemd 会因为没有清空而追加多个 ExecStart,最终导致 dockerd 启动报错。我早期就因为这个原因折腾了大半天,后来形成习惯:凡是覆盖 ExecStart,必定先写一行空的。

    另外要注意,daemon.json 的优先级高于命令行参数。如果你既在 daemon.json 里写了"hosts": ["tcp://0.0.0.0:2375"],又在命令行里传了-H fd://,有可能引发冲突导致 dockerd 无法启动。所以不要两条路同时走,选一种方式并保持一致。

    2. 核心配置项逐一拆解:字段含义与参数计算

    2.1 registry-mirrors:镜像加速的配置逻辑

    先说明一点,这里讨论的是纯技术层面的配置方法。国内网络环境下直接访问官方镜像仓库往往很慢,为了提升拉取镜像的效率,Docker 原生提供了registry-mirrors这个数组配置项,让你把镜像源指向国内公共的镜像加速服务。这是 Docker 官方支持的合法功能,配置格式如下:

    { "registry-mirrors": ["https://docker.m.daocloud.io"] }

    配置完成后,docker pull命令会优先从加速地址拉取,如果加速地址没有缓存或不可用,会自动回源到官方镜像仓库。这里注意几个细节:

    • 有些加速服务只对 Docker Hub 官方镜像生效,如果你拉取的是第三方仓库的镜像(比如quay.io/xxx/yyy或某个私有仓库),registry-mirrors不会拦截,它会直接访问原始仓库地址。
    • 加速器地址必须是 HTTPS 或者 HTTP,如果地址写错了,拉镜像时会报certificate signed by unknown authority或者直接超时。配置后一定要用docker info看Registry Mirrors一栏确认是否生效。
    • 多个加速器可以同时配置,Docker 会按顺序尝试,我一般习惯配 1~2 个,配太多意义不大,因为一个挂了会自动尝试下一个,但每个加速服务响应速度差异很大,多了反而拖慢首次拉取的失败耗时。

    预期收益:配置前拉一个几百 MB 的镜像可能要 10 分钟,配置后通常 1~2 分钟就能完成,命令层面和操作习惯完全不用变。这也是 daemon.json 里性价比最高的一个配置项。

    2.2 日志轮转:max-size 和 max-file 的参数计算

    容器日志是磁盘空间杀手。Docker 默认的日志驱动是json-file,并且默认不给日志做轮转。这意味着一个容器如果持续输出日志,它的日志文件会无限增长。之前我遇到过一晚上一个日志量大的服务把 40G 根分区打满,蚕食鲸吞的速度相当惊人。

    daemon.json 里通过log-driver和log-opts控制:

    { "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }

    这里解释一下两个参数的配合逻辑:max-size=100m表示单个日志文件超过 100MB 就进行轮转;max-file=3表示只保留最近 3 个轮转文件。算下来单个容器最多占用100 * 3 = 300MB日志空间。

    怎么给这个值?我自己有个经验公式:先估一下业务高峰期十分钟能产生多少日志,再决定max-size。比如某个服务每十分钟产生约 50MB 日志,你希望至少保留最近半小时的日志用于排查,那max-file至少得是 3 份。如果希望保留 1 小时,就得 6 份。但文件数不宜设置过大,因为 Docker 在轮转日志时会有短暂 IO 压力,文件数太多还会占用过多 inode。

    还有一点需要提醒,log-driver也可以在运行容器时单独指定,但 daemon.json 里配置的是默认值。如果你有一个特殊容器需要保留更久日志,可以在docker run时覆盖:

    docker run --log-driver json-file --log-opt max-size=500m --log-opt max-file=5 nginx

    但不要养成习惯,统一写在 daemon.json 里才便于管理,特殊需求再单独覆盖。生产环境我建议至少保证所有容器都有轮转策略,这是磁盘安全的底线。

    2.3 storage-driver 与>{ "data-root": "/data/docker" }

    改完重启 Docker 后,旧数据不会自动迁移。你需要在重启前手动迁移,步骤大致是:

    1. 停掉 docker 以及所有容器:systemctl stop docker
    2. 把旧目录移动到新位置:mv /var/lib/docker /data/docker
    3. 设置好目录权限:chown -R root:root /data/docker(Docker 目录属主一般是 root)
    4. 修改 daemon.json 里的>tar czvf /backup/docker_backup.tar.gz /var/lib/docker

      打包耗时取决于数据量,几百 GB 可能要跑一阵子。建议选业务低峰期操作。

      2.4 网络相关:bip、iptables 与 hosts

      daemon.json 里还有一组网络相关参数,平时不一定用得上,但一旦公司内部网络规划严格时,它们就是救命的。

      先看bip,它控制 Docker 默认 bridge 网络的网段。Docker 默认会用172.17.0.0/16这个段。如果公司内网恰好用了172.17.x.x做机房网段,就会冲突。这时得改:

      { "bip": "10.88.0.1/24" }

      这里bip只能是 IP 加掩码的写法,指定的是 bridge 接口的地址,后续容器自动从这个网段分配 IP。注意它不会限制自定义 bridge 网络的地址池,那是另一个参数default-address-pools管的:

      { "default-address-pools": [ {"base": "172.80.0.0/16", "size": 24} ] }

      它规定了当你用docker network create创建自定义网络时,可以从哪些大网段里自动切分/24子网。如果你的容器数量特别多,默认的地址池不够用,可以适当扩大。

      再看iptables。Docker 默认会自动修改宿主机的 iptables 规则,实现容器网络隔离、端口映射和 NAT。如果没有特殊的安全合规要求,保持默认的"iptables": true即可。但有些安全要求严格的机房不允许 Docker 自动动 iptables,会设置"iptables": false。改了这个以后,容器对外通信和端口映射都会失效,你需要手工维护防火墙规则。实际操作中不建议关闭,除非你有充分的理由和配套的网络方案。

      hosts字段则用来指定 dockerd 监听的地址。默认只监听本地 unix socket。如果需要对外提供 API,比如后期接一套可视化管理平台,就需要暴露 TCP 端口:

      { "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"] }

      这里一定把unix:///var/run/docker.sock也写上,否则本地docker命令就无法访问 daemon。而且这个字段和 systemd 启动命令里的-H fd://会冲突,如果你在 daemon.json 里配置了 hosts,就用 drop-in 文件覆盖掉原来的 ExecStart,去掉-H fd://。这是一个比较隐蔽的坑,后面排查部分我会再提。

      2.5 其他容易被忽略但很实用的参数

      除了上面几组,下面这些字段我建议也认真了解一下,因为它们解决的都是 CentOS7 环境下的高频问题。

      exec-opts 与 cgroupdriver

      Kubernetes 1.24 之后默认使用 containerd 运行时,但如果你还在用 Docker 作为 k8s 容器运行时(dockershim 时代遗留),或者用 kubeadm 初始化时还在走 docker runtime,那么 cgroupdriver 的一致性就是绕不过去的 KPI。CentOS7 上 systemd 作为 init 进程,推荐把 Docker 的 cgroupdriver 也设为 systemd:

      { "exec-opts": ["native.cgroupdriver=systemd"] }

      不设的话,Docker 默认用 cgroupfs,而 kubelet 如果指定了 systemd,两者会双份管理 cgroup,导致资源隔离混乱,甚至节点状态异常。这也是为什么官方一直强调二者要保持一致。

      max-concurrent-downloads / max-concurrent-uploads

      这两个参数控制镜像拉取和推送的并发层数。默认分别是 3 和 5。内网带宽有限时,把下载并发调低到 1 或 2,避免多镜像同时拉取把带宽打满;带宽充裕时调高到 8 或 10 能明显提高大批量镜像拉取速度。

      live-restore

      这个参数建议无条件开启:

      { "live-restore": true }

      默认情况下 dockerd 重启,所有容器都会跟着挂掉。如果配置了live-restore: true,daemon 重启时容器不会停止,只是短暂失去监控和网络管理能力,恢复后自动重连。这个特性可以让你在做系统升级时尽量降低对业务的影响。

      userland-proxy

      默认 true。它用于在宿主机上启动一个用户态进程处理端口映射。某些环境下开启会带来多余的性能损耗和连接问题,比如容器内看到来源 IP 变成网关地址。如果对纯 DNAT 方案有信心,可以设"userland-proxy": false。不过不建议在没有充分测试的机器上贸然开启,默认行为更稳妥。

      insecure-registries

      如果公司内部搭建了 HTTP 协议的私有镜像仓库(没有 TLS 证书),直接 pull 是会报证书错误或提示不安全的。需要把这个仓库地址加到这个数组里:

      { "insecure-registries": ["registry.internal:5000"] }

      注意,配置了这个之后等于放弃了该仓库的证书校验,只适合在内网可信环境使用,不建议在公网场景这么干。

      3. CentOS7 上 daemon.json 实操全流程

      3.1 环境准备与 Docker 安装升级

      既然讲 daemon.json,默认你已经装好了 Docker。但如果你是从零开始,在 CentOS7 上装 Docker 也有几个版本坑要避。

      CentOS7 默认源里的 docker 是老版本,通常是 1.13 或更旧。这个版本首先不支持后面很多新的配置项,比如live-restore、max-concurrent-downloads在它看来可能就是无效字段。所以正规做法是从 Docker 官方仓库装 docker-ce 新版。

      先配置 Docker 的 yum 源。因为默认源访问慢,很多教程会让你把 yum 源换成国内镜像源,这是环境搭建的一部分,和 daemon.json 没有直接关系,但环境好才能让后续操作顺畅:

      yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

      然后查看可用版本:

      yum list docker-ce --showduplicates | sort -r

      选择某个版本安装,比如:

      yum install -y docker-ce-20.10.24

      装完先查看当前版本和一些关键默认信息:

      docker version docker info

      这里你会发现docker info输出的内容非常详细,包括 Storage Driver、Cgroup Driver、Registry Mirrors、Docker Root Dir 等,这些就是后面对照验证 daemon.json 是否生效的核心依据。

      如果你是老版本想升级,同样用上面的步骤,把 docker-ce 重新装到目标版本即可。升级前先备份/etc/docker/daemon.json,因为不同版本对某些字段的兼容性略有差异,备份能让你在任何时候回滚配置而不是从头写。

      3.2 编写一份可直接落地的完整 daemon.json

      结合前面讲的字段,我这里给出一份生产环境常用配置模板。这份配置兼顾了镜像加速、日志轮转、数据目录、cgroup 一致性、网络地址池、并发控制等常见需求:

      { "data-root": "/data/docker", "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" }, "registry-mirrors": [ "https://docker.m.daocloud.io" ], "max-concurrent-downloads": 5, "max-concurrent-uploads": 5, "live-restore": true, "storage-driver": "overlay2", "default-address-pools": [ { "base": "172.80.0.0/16", "size": 24 } ], "insecure-registries": [] }

      几个说明:

      • >python -c "import json;print(json.load(open('/etc/docker/daemon.json')))"

        如果输出了一堆字典内容,说明格式没问题;如果报错,它会提示你第几行出错了。CentOS7 默认带 python2,但上面的语句在 python2 下也能运行。如果你装了 python3,用下面这个更直观:

        python3 -m json.tool /etc/docker/daemon.json

        校验通过后再重启 Docker。

        3.3 重启 Docker 与验证配置是否生效

        在重启之前,我习惯先执行一遍:

        systemctl daemon-reload

        如果你创建过 systemd drop-in 文件,这一步尤其重要,它让 systemd 重新读取新增或修改的 unit 文件。然后重启 docker:

        systemctl restart docker systemctl status docker

        状态显示active (running)说明基本正常。接下来一定要验证配置是否真正生效。保险起见,我一般执行:

        docker info

        重点看这几行:

        • Docker Root Dir是否变成了你设置的>journalctl -u docker | grep -i "daemon.json"

          日志里如果出现unable to configure the Docker daemon with file /etc/docker/daemon.json: ...这类信息,后面跟着的就是具体错误原因。

          3.4 数据目录迁移的完整说明

          前面提到把>df -h /data

          1. 停掉 docker:
          systemctl stop docker
          1. 确认没有残留容器进程,然后迁移:
          mv /var/lib/docker /data/docker

          如果你的服务器上已经跑了很多容器,mv跨文件系统时速度会慢且占用 IO,建议先用 rsync 同步再切换:

          rsync -avxP /var/lib/docker/ /data/docker/

          rsync 可以断点续传,-P显示进度,-x不跨文件系统边界,-a归档模式保留权限和链接。同步完成后停 docker,再执行一次 rsync 把增量数据也同步过去,然后mv掉旧目录或者先改 daemon.json 里的>

        • 修改 daemon.json 里的>{ "data-root": "/data/docker" }
          1. 启动 docker:
          systemctl start docker
          1. 再次docker info确认Docker Root Dir已经是/data/docker,然后随意拉一个镜像或启动一个测试容器确认镜像层能正常读取。

          这个操作最核心的注意事项是:迁移过程中不要把新旧目录搞混。我见过有人 rsync 还没跑完就改了 daemon.json,导致 Docker 启动时从头开始初始化新目录,等于旧数据全部丢了。顺序一定是先确保新目录数据完整,再切 daemon.json。

          4. 配置后常见问题与排查记录

          4.1 dockerd 起不来,日志各种报错

          这是改 daemon.json 后概率最高的问题,几乎每个人都遇到过。常见情形有两种。

          第一种是 JSON 格式错误。这种最直观,journalctl -u docker会直接告诉你第几行有问题:

          unable to configure the Docker daemon with file /etc/docker/daemon.json: json: cannot unmarshal string into Go struct field ...

          解决方法很简单:用python3 -m json.tool校验。写的时候千万注意 JSON 里字符串必须用双引号,键也必须用双引号,不能有注释。很多人把 YAML 的#注释习惯带进 JSON,这几乎是必炸的错误。

          第二种是字段冲突。典型的就是hosts字段和 systemd 启动参数里的-H fd://冲突。日志报错类似:

          unable to configure the Docker daemon with file /etc/docker/daemon.json: the following directives are specified both as a flag and in the configuration file: hosts

          这种需要创建一个 drop-in 文件覆盖 ExecStart,把-H fd://去掉,只保留纯 dockerd 启动。或者反过来,把 daemon.json 里的hosts字段删掉,用系统参数控制监听地址。两选一,不要同时用。

          还有一类问题比较隐蔽:你配置的>docker run -d --name log-test nginx

          然后往它的日志里灌点数据,观察/var/lib/docker/containers/<id>/下的 json 日志文件的轮转情况:

          ls -lh /var/lib/docker/containers/$(docker inspect -f '{{.Id}}' log-test)/*.json

          如果生成了多个文件或者单文件体积不超过设置的max-size,说明轮转生效了。

          另外补充一个容易被忽略的点:json-file驱动在写日志时,Docker 会维护一个带.log后缀的文件,还有一个以-json.log结尾的文件。轮转后可能出现类似xxx-json.log.1这样的历史文件。你看到的max-file=3对应的就是最多保留 3 个这样的轮转文件。

          4.3 镜像加速不生效,或者拉取仍然超时

          配置了registry-mirrors之后,如果执行docker info能看到加速地址,但拉镜像还是慢,甚至超时,一般有下面几种情况:

          • 拉取的是非 Docker Hub 官方镜像。registry-mirrors只对 Docker Hub 生效,比如你拉quay.io/bitnami/nginx,那它不会走加速,这很正常,不是配置问题。
          • 加速服务本身在你的网络环境下不稳定。不同地区访问不同加速服务的速度差异很大,换一个再试试。
          • 容器没有重启。注意是重启 daemon,不是单纯重启容器。docker pull是 daemon 干的活,所以必须systemctl restart docker。有些教程只让你service docker restart,道理一样,但确认一下 daemon 确实重启过。

          我在排查这类问题时有个节奏:先docker info看加速地址在不在列表;在的话直接docker pull一个小镜像测试速度;如果还是慢,就手动 curl 一下加速地址看看连通性和响应时间,快速定位问题在网络还是配置。

          4.4 修改 daemon.json 后容器网络异常

          之前改过bip后遇到一次诡异问题:容器能启动,但容器里访问外部服务时有时通有时不通。后来排查发现是宿主机上有多个网卡,路由表里出现了冲突。

          因为bip改成了10.88.0.1/24,而服务器上某条内网路由恰好也是走10.88.0.0/24段的,结果容器出网的数据包被路由到了错误网关。这个问题纯靠 daemon.json 配置很难规避,只能提前和网络同事确认网段分配,避开公司内部真实使用的网段。

          另一个常见情况是设置了"iptables": false之后,容器无法访问外网。这是预期行为,因为你手动关掉了 Docker 的 NAT 规则。需要自己在宿主机上配置相应的 iptables 转发规则,或者改用 macvlan 等网络方案。我建议非必要不关闭,这字段的真正用途是在某些和外部网络强管控场景下配合定制防火墙策略,普通环境用默认就行。

          4.5 宿主机无法 ping 通外网,排查链路里别忘了 Docker

          热搜里有“centos7 无法ping通百度”这样一个词条,我看过大量新手提问。其实这问题跟 Docker 的关系不一定很大,但如果你恰好是在装了 Docker 之后出现的,排查链路里要加入网络相关配置。

          Docker 启动后默认会修改 iptables 的 FORWARD 链,并且开启内核转发参数/proc/sys/net/ipv4/ip_forward。如果系统安装时没有开启转发,Docker 会尝试自动设置,但某些系统模板可能限制了内核对网络命名空间的权限,导致容器网络初始化失败。

          遇到宿主机本身 ping 不通外网,先按这个顺序排查:

          ip route cat /etc/resolv.conf ping 114.114.114.114 ping www.baidu.com

          先测 IP 通不通,再测 DNS 解析。如果 IP 通但域名不通,基本是 DNS 问题,检查/etc/resolv.conf里有没有有效的 nameserver。如果 IP 不通,查看默认路由:

          ip route | grep default

          如果默认路由缺失,手动加一条:

          ip route add default via <网关IP> dev <网卡名>

          这里要注意,如果你改过 daemon.json 里的bip,而且宿主机网卡 IP 恰好和新的 bridge 网段重合,也会出现路由混乱。我处理过一次 CentOS7 虚拟机改完静态 IP 后重启失联的情况,最后发现是/etc/sysconfig/network-scripts/ifcfg-eth0里网段和 Docker 的 bridge 网段冲突,把 daemon.json 里的bip改了才恢复。

          4.6 常见问题速查表

          现象原因解决方案
          dockerd 启动失败daemon.json JSON 格式错误python3 -m json.tool校验修复
          daemon 启动报 hosts 冲突daemon.jsonhosts与 systemd 参数重复用 drop-in 覆盖 ExecStart,去掉-H fd://
          日志目录撑爆磁盘老容器未应用新日志轮转策略重建容器或单独配置容器日志参数
          镜像拉取仍慢非 Docker Hub 镜像 / 加速服务不稳定换加速地址,确认拉取镜像来源
          容器访问外网失败关闭了 iptables 或 bip 网段冲突恢复 iptables 默认,检查路由表
          docker info 配置不生效daemon.json 字段名拼错或未重启拼写检查,systemctl restart docker
          数据目录还是 /var/lib/docker只改配置没有迁移数据按 3.4 节步骤执行完整迁移
          升级 Docker 后配置异常老版本字段兼容性差异逐项核对 daemon.json 里字段,删除新版不识别项

          5. 一份安全可控的改动流程建议

          写到这里,想再分享一个我实践下来很顺手的改动流程。每次要动 daemon.json 时,先备份旧文件:

          cp /etc/docker/daemon.json /etc/docker/daemon.json.bak.$(date +%F)

          然后开始编辑。改完之后先校验格式,再重启。但很多人看完配置直接systemctl restart docker,如果这台机器上有正在运行的业务,这个重启动作本身就是有损的。虽然live-restore能减少影响,但重启 daemon 期间容器网络会短暂断开,对于长连接服务,终端用户还是能感知到闪断。

          更平滑的方式是分步操作:

          • 如果只是需要让新容器生效,但暂时不想影响存量容器,可以不重启 daemon,等维护窗口再统一重启。
          • 如果必须立即生效,可以考虑先挑一台测试机验证配置,再批量应用到生产机器。
          • 如果服务器上容器重要性较高,先在业务低峰期做一次演练,确定live-restore开启后的实际影响再纳入变更方案。

          另外,习惯在改动后执行docker info做一个“快照保存”,把关键字段记录下来。下次再改时,对比一下就知道哪些配置丢了或失效了,比凭记忆强太多。

          6. 最后分享一点个人体会

          我跟 daemon.json 打交道这几年,最深的一个体会是:配置文件看似只是改几个字段,但它映射的是你对 Docker 工作原理的理解程度。比如你不搞懂 cgroupdriver 的作用,就不知道为什么 k8s 环境下必须把它和 systemd 对齐;你不亲历一次日志撑爆磁盘,就体会不到日志轮转的价值。很多坑不是配置复杂,而是原理没理顺。

          建议大家拿到一台新 CentOS7,装完 Docker 先别急着拉镜像跑容器,花十分钟把 daemon.json 写好,把数据目录、日志轮转、加速地址这些基础项一次性配置到位。后面你省下的时间,会是这十分钟的几十倍。如果真遇到问题,也别慌,按日志一级一级往上查,daemon.json 的错误在日志里都会留下痕迹,它远没有你想象的那么难缠。

返回列表