news 2026/10/2 18:39:34

从Docker到Kubernetes的企业级容器化部署与迁移实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从Docker到Kubernetes的企业级容器化部署与迁移实战

最近有好几个读者问我同一个问题:项目要上 Kubernetes,但团队里只有几个会写 Dockerfile 的人,之前所有的服务都是用 docker run 或者 docker compose 在单机上面跑的,现在要往集群迁移,从哪儿起步?这就是我说的“阶段二”的典型场景。如果说阶段一是学会用 Docker 把应用容器化、理解镜像和容器的关系,那阶段二就是一场从“单机容器编排”到“多节点集群调度”的跨越,核心工作是把 Kubernetes 这套企业级调度系统从文档里搬到生产环境里,让它真正承载业务。

这篇文章整理的是我在多个项目里实践过的企业级容器化部署方案,重点放在 Kubernetes 集群的搭建、基础组件的落地、业务从 Docker 迁移到 K8s 的完整路径,以及过程中必须踩一遍才能总结出来的坑。适合已经有一定 Docker 基础、准备把业务迁到 K8s 上的运维和开发同学参考,我尽量把每一步背后的为什么也讲清楚,不只是给命令。

1. 阶段二的整体思路:从单机 Docker 到 K8s 集群的跨越

1.1 阶段一留下的痛点就是阶段二的起点

Docker 解决的是“应用运行环境一致性”的问题,一台服务器上能通过 docker run 快速拉起容器,通过 docker compose 编排几个关联服务,这在单机场景下完全够用。但当你手头的服务器从一台变成三台、五台,服务数量从几个变成几十个,单机 Docker 就会暴露出一连串问题:容器在哪个节点上启动靠人工决定,节点宕机了容器没人管,流量来了无法自动扩容,发布新版时无法做到平滑滚动。这些问题的本质是缺少一层“调度大脑”,而 Kubernetes 就是这层大脑。

阶段二的核心目标,是把 Docker 已经容器化好的业务负载,平滑地迁移到 Kubernetes 集群上,让集群接管容器的调度、生命周期管理、服务发现和弹性伸缩。所以这个阶段的第一步不是急着敲 kubeadm 命令,而是先想清楚你现有业务的容器化程度,哪些服务已经写好了 Dockerfile,哪些还依赖特定主机目录或 IP,这些存量问题会直接影响后续的迁移成本。

1.2 版本选型和发行版选择的实际考量

我在方案里选的是 Kubernetes v1.26.0,这个版本在热搜词里也出现过,确实是个很稳的版本,既有 CRI v1alpha2 到 v1 的平滑过渡,又有比较成熟的可控性。选择版本时有一条经验:别追求最新,生产环境选比自己熟悉的技术栈晚半年到一年的版本,生态兼容性最好。比如后面要用的 Ingress-Nginx、Prometheus、Calico,都跟 K8s 版本有对应关系,太新的 K8s 版本反而要等组件适配。

企业落地还有一个绕不开的选择:直接用 kubeadm 自建集群,还是用商业发行版。我的建议是阶段二用 kubeadm 自建,因为你需要通过手动搭建集群来理解各个组件之间的关系,这对后期排查问题是巨大帮助。商业发行版虽然省事,但会模糊掉很多底层细节,出了问题会比较被动。kubeadm 搭建的高可用集群在维护得当的前提下,稳定性不输商业版,性价比很高。

1.3 为什么容器运行时不再直接用 Docker

这里要特别提醒一点:阶段二里,Kubernetes 集群的容器运行时我强烈建议用 containerd,而不是 Docker。很多人不理解,说我们明明是用 Docker 构建的镜像,怎么到 K8s 里反而不用 Docker 了?因为 K8s 通过 CRI 接口跟容器运行时通信,Docker 在这个体系里相当于中间人,后面还要靠 dockershim 做适配,性能有损耗,维护链路也长。而 containerd 本身就是 Docker 底层的容器运行时组件,直接从 kubelet 接收指令,更轻更稳。

但这不代表 Docker 没用,镜像还是用 Docker 构建,Dockerfile 依然是我们定义应用运行环境的唯一标准。只是到了 K8s 集群里,真正负责跑容器的换成了 containerd,Docker 退回到“开发构建工具”的角色。这个观念转过来很关键,否则后面看到docker ps在集群节点上查不到容器会一脸懵。

2. 集群部署前的规划与准备工作

2.1 节点角色划分与硬件配置规划

阶段二最容易犯的错误是一上来就装集群,缺少数规划。一个企业级的 K8s 集群,至少要规划出控制平面节点和工作节点两类角色。控制平面节点跑 apiserver、controller-manager、scheduler、etcd,是整个集群的大脑;工作节点只负责跑业务容器。小规模环境可以单节点 all-in-one,但企业级应用至少是 3 个控制平面节点加若干工作节点,保证控制面高可用。

硬件配置方面,我的经验是控制平面节点 CPU 不低于 4 核、内存不低于 8G,etcd 所在节点磁盘尽量用 SSD,因为 etcd 是集群所有状态数据的存储,磁盘性能直接影响集群响应速度。工作节点按业务量估算,CPU、内存要求取决于你的业务负载,但建议最低 2 核 4G 起步。这里有一个容易被忽视的点:节点之间网络延迟越低越好,尽量在同一个机房或同一个内网网段,跨地域组集群会面临严重的 etcd 同步延迟问题。

2.2 操作系统与基础环境配置清单

操作系统我推荐 Ubuntu 22.04 或 CentOS 7.9,两者在 K8s 生态中的兼容性都验证得很充分。无论用哪个,都要做几项基础配置:关闭 swap,因为 kubelet 默认不支持带 swap 运行;加载 br_netfilter 内核模块并开启 iptables 桥接流量转发;同步节点时间,可以用 chrony 或 systemd-timesyncd;确保节点 hostname 唯一,且 /etc/hosts 里有所有节点的解析记录。

下面是基础环境配置的关键命令,Ubuntu 和 CentOS 差异不大,核心是内核参数:

# 关闭 swap(临时+永久) swapoff -a && sed -i '/ swap / s/^/#/' /etc/fstab # 加载内核模块 modprobe br_netfilter cat <<EOF > /etc/modules-load.d/k8s.conf br_netfilter EOF # 设置内核参数 cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF sysctl --system

这些配置看着基础,但少一条都会在后续出怪问题。比如没开 ip_forward,Pod 内访问外网就会失败;没关 swap,kubelet 可能直接报错无法启动。我在生产环境维护的集群里,这种问题出现的频率远高于你的想象。

2.3 容器运行时 containerd 的安装与验证

准备好系统环境后,接下来安装 containerd。大多数发行版的软件源里都能直接装,版本要选跟 K8s 兼容的,推荐 1.6 以上版本。安装完成后有一个必须检查的配置项:cgroup 驱动要和 kubelet 保持一致,现在主流都是 systemd 驱动,所以要把 containerd 默认的 cgroupfs 改成 systemd,否则 kubelet 和 containerd 的 cgroup 管理会冲突,节点会一直处于 NotReady 状态。

containerd 的配置修改集中在 /etc/containerd/config.toml,改完重启生效。配置里还建议顺手把镜像加速地址加上,国内环境拉取 gcr 镜像会快很多。下面是我常用的配置片段:

[plugins."io.containerd.grpc.v1.cri"] sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true

验证 containerd 是否正常的命令是crictl ps,能看到返回结果就说明没问题。注意 crictl 是专门跟 containerd 交互的命令行工具,不是 docker 命令,这也是阶段二要熟悉起来的新工具。集群搭好后,所有docker ps的习惯都要换成crictl或kubectl来查容器状态。

3. kubeadm 搭建企业级集群的完整实操

3.1 初始化控制平面节点的关键参数

所有前置工作准备完毕,就可以用 kubeadm init 初始化控制平面了。这一步的参数很讲究,我直接给一个适合企业内网环境的命令示例:

kubeadm init \ --apiserver-advertise-address=192.168.10.10 \ --control-plane-endpoint=lb.k8s.local:6443 \ --image-repository=registry.aliyuncs.com/google_containers \ --kubernetes-version=v1.26.0 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12 \ --cri-socket=/run/containerd/containerd.sock

参数含义要理解清楚,不能照抄:--apiserver-advertise-address是当前节点作为控制平面的通告 IP;--control-plane-endpoint是高可用集群的负载均衡入口,单控制平面时可以填本机 IP;--image-repository指定镜像仓库,国内必填;--pod-network-cidr是 Pod 网段,要跟你后面选的 CNI 插件保持一致,Calico 默认用 192.168.0.0/16,Flannel 常用 10.244.0.0/16;--service-cidr是 Service 虚拟 IP 网段,规划好后尽量别改。

初始化成功后会输出三段关键信息:kubeadm join 命令(工作节点加入集群用)、kubeconfig 配置文件路径、加入控制平面的 token。这些信息最好保存到本地文件,因为 token 有效期默认 24 小时,过期了要用kubeadm token create --print-join-command重新生成。

3.2 工作节点加入集群与 CNI 网络插件部署

控制平面初始化后,工作节点只需要执行 kubeadm join 命令即可加入。这里有个细节:join 命令里的--cri-socket参数要和初始化时保持一致,否则节点加入会报 CRI 连接错误。全部节点加入后,kubectl get nodes会看到所有节点处于 NotReady 状态,这是正常的,因为还没有部署 CNI 网络插件。

CNI 插件是集群通信的基石,负责给每个 Pod 分配 IP、打通节点间的容器网络。我推荐 Calico,功能比 Flannel 丰富,支持网络策略,企业级场景更合适。安装 Calico 最直接的方式是下载官方 manifest 文件,之前的--pod-network-cidr如果跟默认值不一样,要修改 manifest 里的 CALICO_IPV4POOL_CIDR 变量。执行完kubectl apply -f calico.yaml后等待片刻,再查看节点状态:

kubectl get nodes kubectl get pods -n kube-system | grep calico

等到全部节点 Ready、calico 相关 Pod 都 Running,集群的骨架才算真正完成。这里我踩过的一个坑是:忘记把 join 命令中的 token 带上--discovery-token-ca-cert-hash,导致节点加入时提示哈希校验失败。所以每次用 kubeadm init 输出的 join 命令时,最好在 24 小时内完整执行,别手动改造命令格式。

3.3 高可用控制面:负载均衡与 etcd 部署

企业级集群只部署一个控制平面节点,从严格意义上说不算高可用。如果条件允许,建议至少 3 个控制平面节点,前面用一个负载均衡器统一分发 apiserver 流量。负载均衡可以是云的 SLB,也可以是自建的 HAProxy + Keepalived,kubeadm 初始化和 join 时用同一个--control-plane-endpoint地址即可。

高可用架构下 etcd 的部署有两种方式:栈内部署和外部部署。阶段二建议先用栈内部署,即 etcd 以静态 Pod 形式跑在控制平面节点上,这是 kubeadm 的默认方案,运维成本低。对于规模更大的生产环境,可以考虑外部 etcd 集群,独立于 K8s 之外管理,但复杂度会上升。我个人的建议是:控制平面节点数不超过 5 个时,栈内 etcd 足够稳定,不需要过度设计。

高可用环境的初始化流程和单控制平面几乎一样,只是控制平面节点在第一个 init 完成后,还要再执行附加--control-plane的 join 命令加入其他控制面节点,工作节点则用普通 join 命令。这套流程多操作几次就能摸熟。

4. 集群基础组件落地:Ingress、监控、日志与存储

4.1 Ingress-Nginx 部署与外部流量接入

集群搭好后第一件事不是急着跑业务,而是把基础设施组件铺好。外部流量怎么进集群?有三种方式:NodePort、LoadBalancer、Ingress。NodePort 适合临时调试,LoadBalancer 依赖云厂商或自建 LB,企业级场景最常用的流量入口是 Ingress-Nginx,它相当于集群内部的七层反向代理,通过域名规则把请求转发到不同 Service。

部署 Ingress-Nginx 非常简单,下载官方 manifest 文件后 apply 即可。关键是你想清楚它以什么方式暴露给外部访问:一般是用 LoadBalancer 类型的 Service,或者在裸金属环境用宿主机网络模式,直接把 80/443 端口监听在节点上。不管哪种,都要保证 Ingress 控制器所在的节点有稳定的网络出口。

下面是 Ingress 资源的一个典型示例,把业务域名 example.com 的请求路由到 myapp 服务的 8080 端口:

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress spec: rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: myapp port: number: 8080

4.2 监控体系:Prometheus 与 Grafana 的组合拳

企业环境没有监控等于裸奔。Prometheus 已经成为 K8s 监控的事实标准,配合 Grafana 做可视化、Alertmanager 做告警。部署方式有两条路:用 kube-prometheus-stack Helm chart 一把梭,或者手动部署各组件。阶段二推荐用 Helm chart,你只需要熟悉 values 文件的配置,就能把整套监控体系拉起来。

部署完成后,重点是在 Prometheus 的配置里增加对集群资源的抓取目标,kube-prometheus-stack 默认会抓取 kubelet、kube-apiserver 等核心组件指标,业务自定义指标的采集需要为业务 Pod 配置 annotations。我踩过的坑是:业务 Pod 的 metrics 端口没有加 annotations,Prometheus 完全发现不了它,在 Grafana 里看数据一片空白。

监控指标里最需要重点关注的是:节点 CPU/内存使用率、Pod 重启次数、etcd 的磁盘操作延迟、apiserver 的请求延迟。我把这些告警规则写在 Alertmanager 里,通过钉钉或邮件推送,实测效果比事后看监控面板强得多。

4.3 日志收集:从标准输出到集中式日志平台

日志这块企业里最常见的方案是 EFK/ELK 三件套:Elasticsearch 存储、Filebeat/Fluentd 采集、Kibana 展示。在 K8s 环境里,Filebeat 以 DaemonSet 方式跑在每个节点上,采集容器写往标准输出的日志,再发给 Elasticsearch。这种架构的好处是:应用只需要把日志打到 stdout,就能被自动采集,完全不用侵入业务代码。

版本上建议大家用 Elasticsearch 7.x 或 8.x,Kibana 版本要和 Elasticsearch 严格一致。从我和同事使用的体验看,每天日志量几个 GB 的中等规模集群,用三个 Elasticsearch 节点部署一个生产可用的集群完全够用。需要注意文件描述符和线程池参数,这是 Elasticsearch 性能的关键。

对于已经有日志文件的业务,可以在 Pod 里挂一个 shared volume 让 Filebeat 采集,或者干脆让业务通过 JSON 格式输出到 stdout,这样 K8s 采集最顺畅。阶段二里我建议给出一个日志接入规范,而不是为每个业务单独定制采集方案。

4.4 存储方案选型:本地卷、NFS 还是对象存储

很多业务是有状态服务,数据库、文件存储都需要持久化。K8s 里的持久化核心是 PV/PVC 和 StorageClass。存储选型要分场景:临时数据用 emptyDir,初始化数据用 ConfigMap/Secret,真正持久化的数据必须用 PV。

本地环境最常用的方案是 NFS 作为 StorageClass 底层,部署简单,支持 ReadWriteMany。生产上更可靠的方案是各云厂商的云盘或者自建分布式存储如 Ceph,但运维成本高。如果你是中小团队,我建议先从 NFS 起步,把业务跑起来,再逐步评估是否需要升级存储底座。

我自己在实际项目里踩过一个比较深的坑是:给 MySQL Pod 绑定的 PV 容量设置太小,业务运行几个月后磁盘占满,整个集群的数据库实例全部堵塞。容量规划时不要只算当前数据量,要给将来至少留 50% 的余量,有条件就配置存储卷自动扩容策略。

5. 业务容器化迁移与发布流程落地

5.1 从 Docker Compose 到 K8s 工作负载的迁移路径

阶段二最核心的业务动作,是把之前用 docker compose 跑的服务迁移到 K8s。迁移不是简单把 compose 文件翻译成 Deployment,而是要按照 K8s 的资源模型重新梳理:无状态服务用 Deployment,有状态服务用 StatefulSet,只在调度节点执行的任务用 Job/CronJob,需要持久化数据的服务要设计好 PVC。

一个重要的认知更新是:在 K8s 里,Pod 是临时资源,重建后 IP 会变,所以服务之间的调用不能写死 IP,要通过 Service 名称做服务发现。比如之前 compose 里 MySQL 的连接地址是mysql:3306,迁移到 K8s 后还是mysql:3306,只是这个域名现在由 K8s 的 DNS 解析到对应的 Service 上,对应用代码来说是透明的。

下面是典型的迁移模板,把一个 Spring Boot 或 Node.js 服务从 compose 裸奔升级为 K8s 的 Deployment:

apiVersion: apps/v1 kind: Deployment metadata: name: myapp labels: app: myapp spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: registry.example.com/myapp:v1.0.0 ports: - containerPort: 8080 env: - name: DB_HOST value: "mysql" resources: requests: cpu: 250m memory: 512Mi limits: cpu: 1000m memory: 1Gi livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 30

5.2 配置管理:ConfigMap 与 Secret 的正确用法

迁移阶段另一个必要动作是:把配置文件从镜像里拆出来。Docker 时代常见的做法是把配置文件用 COPY 写进镜像,但到了 K8s 时代,这意味着每次改配置都要重新构建镜像,非常低效。正确做法是用 ConfigMap 保存非敏感配置,Secret 保存敏感信息,容器启动时挂载为文件或环境变量。

我有一个深刻体会:Secret 虽然叫 Secret,但默认只做 base64 编码,没有真正加密,安全性有限。在企业环境里,建议使用外部密钥管理系统,比如社区的 sealed-secrets 或云厂商的 KMS,把真正的密钥加密后存入 Secret,避免配置直接明文泄露在仓库里。

5.3 从手动发布走向 Pipeline 流水线

迁移到 K8s 之后的另一个重要变化是发布方式。阶段一可能是登录服务器执行docker compose pull && docker compose up -d,阶段二要逐渐向自动化流水线靠拢,至少做到“镜像构建、镜像推送、K8s 滚动更新”这三步可以一条命令完成,而不是每次手动 kubectl apply。

我之前一套比较成熟的做法是:代码推到 Git 仓库后,通过 Jenkins 或 GitLab CI 触发构建,成功后执行kubectl rollout restart deployment/myapp,让 K8s 自动进行滚动更新。注意滚动更新期间要保证 maxUnavailable 和 maxSurge 配置合理,避免变更过程中旧实例被全部杀掉,导致服务短暂不可用。这个过程中如果你比较熟练,还会发现 HPA 是让集群更聪明的关键一步,通过 metrics 自动扩容 Pod 副本数,是按真实业务压力驱动集群弹性的核心能力。

6. 企业级部署中的常见问题与避坑指南

6.1 节点异常与网络问题速查表

现象可能原因排查与解决
节点一直 NotReadykubelet 未启动、CRI 配置错误、CNI 异常先看 kubelet 日志journalctl -u kubelet,确认 containerd 正常且 cgroup 驱动一致
Pod 一直 Pending资源不足、没有匹配的节点、PVC 未绑定kubectl describe pod查看事件,补充资源或创建可用 StorageClass
Pod 启动后 CrashLoopBackOff启动命令失败、配置错误、依赖服务未就绪查看容器日志kubectl logs,优先排查 ConfigMap 和环境变量
Service 访问不通标签选择器不匹配、Pod 未就绪、Ingress 规则错误检查 Service 的 Endpoints 是否有数据,kubectl get endpoints
集群 DNS 解析失败CoreDNS 未运行或上游 DNS 配置异常确认 CoreDNS Pod 运行状态,检查 kubelet 的 resolvConf 配置

这张速查表是我使用过程中总结出来的,基本覆盖了新手阶段能遇到的 80% 问题类型。排查时要把握一个原则:先看事件、再看日志、最后看配置,不要一上来就重启节点或删 Pod,否则很容易把现场信息丢掉。

6.2 一次真实事故:业务扩容后节点内存耗尽

有一次在生产环境对某个业务做扩容,replicas 从 2 调到 10,结果不到半小时,整个节点开始卡顿,部分 Pod 被 OOM Killer 杀掉。原因是当时所有工作节点的内存规格一致,而我发布 Deployment 时没有设置 requests 和 limits,调度器把所有副本都堆到了一个节点上。这是比较典型的事故,本质上是因为没用 requests 限制调度决策。

正确做法是在 Deployment 里设置合理的 requests,让调度器知道每个 Pod 需要多少资源,同时设置 limits 防止单个 Pod 把节点资源挤爆。阶段初期的业务普遍不做资源声明,这在单机 Docker 时代问题不大,但到 K8s 里就成了隐患。给每个工作负载一张资源声明表,是我在项目初期就要求的规范。

6.3 镜像仓库与版本的规范化管理

最后提一个容易被忽略但非常重要的事:镜像仓库和版本管理。早期用 Docker 的人习惯打 latest 标签,一天 build 很多次都用同一个 tag,这在 K8s 集群里非常危险。因为 K8s 默认如果镜像 tag 不变,Pod 重建时会使用节点缓存的旧镜像,导致你明明构建了新镜像,线上跑的却是旧代码。

规范做法是:每个镜像都用带版本号的 tag,比如myapp-v1.2.3或干脆用 Git commit SHA,发布新版本时更新 Deployment 的镜像地址。同时在部署清单中把 imagePullPolicy 设置为 IfNotPresent 或 Always,按实际场景合理选择。镜像清理也要形成制度,避免测试镜像堆满仓库磁盘,尤其是使用镜像仓库存储的企业,这个坑对运维项目有着长期的影响。

阶段二之后的扩展方向

阶段二做完了,Kubernetes 集群能跑、业务能发布、监控日志都就位,这就完成了从单机 Docker 到容器编排平台的关键一步。之后的演进方向,我自己的体会按优先级排是:先把 GitOps 做起来,用声明式配置管理整个集群的期望状态;再评估是否需要引入服务网格,比如 Istio,解决灰度发布和服务观测的问题;如果业务有 GPU 需求,比如做 AI 推理,那要在集群里规划 GPU 节点和对应的调度插件,用容器化方式统一管理异构算力。这些方向都建立在阶段二打好的底子上。按我实际操作的经验,把集群的基础组件和运维规范固化下来,比追新功能重要得多,阶段三的收益来自稳定性和自动化,而不是堆更多组件。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 18:35:04

跨节点容器网络通信指南:从静态路由到VXLAN Overlay

跨节点的容器间网络通信&#xff0c;这标题光看可能觉得没什么&#xff0c;但真上手做容器集群的时候&#xff0c;它往往是第一个让你半夜爬起来抓包的东西。单机环境下跑几个 Docker 容器&#xff0c;网络折腾起来几乎是无感的——你只需要知道-p 8080:80这种端口映射就能干活…

作者头像 李华
网站建设 2026/10/2 18:34:07

Java课程设计图书管理系统:从源码识别到部署答辩全攻略

简介&#xff1a;这是一份面向Java学习者和高校学生的课程设计图书管理系统源码包&#xff0c;以JavaFX构建图形界面&#xff0c;整合Druid连接池与MySQL数据库&#xff0c;覆盖图书信息管理、借还流程、多角色登录等典型业务场景&#xff0c;适合完成课程设计、期末项目或练习…

作者头像 李华
网站建设 2026/10/2 18:31:42

微信小程序+Java后端:个性化推荐点餐平台设计与实现全解析

这套题目我一看就很有共鸣——每年毕业设计季&#xff0c;总有大量同学在“微信小程序 Java后端”这个组合上反复纠结&#xff1a;题目看着热闹&#xff0c;落地时却处处是坑。这个标题把三个关键词串起来了&#xff1a;个性化推荐、点餐平台、微信小程序&#xff0c;背后本质…

作者头像 李华
网站建设 2026/10/2 18:30:02

本地部署抠图工具BiRefNet:环境配置、参数调优与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华