资讯动态

Docker与K8s全方位对比:云原生容器化落地指南

发布时间:2026/9/24 18:47:18 来源:尧图企业网站定制
1. 云原生到底在说什么我经常在面试和团队交流的时候被问到同一个问题“云原生是不是就是 Docker 加 K8s”每次听到这种问题我都能理解提问者的困惑因为这个概念被各种技术文章和厂商宣传包装得太玄了。但答案其实没那么复杂Docker 和 K8s 是云原生落地最核心的两个工具但它们不是云原生的全部。云原生是一种构建和运行应用程序的方法论它强调应用应该生于云、长于云充分利用云计算弹性和分布式的优势。这个概念里面包含四个关键要素容器化、微服务、DevOps、持续交付。容器化解决的是应用打包和运行环境一致性的问题微服务解决的是应用拆分和独立治理的问题DevOps 解决的是开发和运维协作的问题持续交付解决的是版本快速迭代的问题。你会发现这里面最基础、最先要落地的一步就是容器化。为啥容器化是第一步因为后面的微服务拆分、自动化运维、弹性伸缩全都建立在“应用能够被标准化打包、快速启动、随处运行”这个前提之上。没有容器化微服务跑在各自不同的环境里环境差异就能折腾死人有了容器化一个镜像包到处跑环境问题被彻底隔离在镜像构建阶段。这就是为什么几乎所有人学云原生都是从 Docker 入手然后进阶到 Kubernetes。回到最初的问题Docker 加 K8s 这套组合本质上解决了云原生架构里两个最核心的问题Docker 解决“怎么把应用和环境一起打包、分发、运行”K8s 解决“怎么让一堆容器自动部署、自动伸缩、自动恢复”。一个管单机上的容器一个管集群里的容器调度两者配合才构成了现代云原生基础设施的基石。这篇文章不打算讲太多虚的我想从实际操作的角度把 Docker 和 K8s 的优缺点、适用场景、常见坑一次说清楚。不管你是刚接触容器技术的新手还是准备在团队里推动容器化落地的技术负责人这篇文章应该能给你一个比较完整的视角。2. Docker和K8s的优缺点横向对比着看2.1 Docker的优点是真的让人回不去我最早接触 Docker 是 2016 年左右那会儿部署一个 Java 应用要先装 JDK、配环境变量、调 Tomcat遇到 CentOS 和 Ubuntu 的路径差异还得改配置。Docker 出现以后这些全都不需要关心了。把 JDK、Tomcat、应用 jar 包统统打进镜像一条 docker run 命令就能跑起来换台机器同样一条命令结果一模一样。Docker 最直观的优点就是环境一致性。开发环境、测试环境、生产环境不再有“在我电脑上是好的呀”这种问题因为镜像本身就是完整的运行环境。其次是启动速度快容器直接复用宿主机内核比虚拟机省去了一整层操作系统启动的时间秒级启动是常态。还有一个容易被忽略的优点镜像分层机制。多个镜像可以共享底层的基础镜像层比如都基于同一个基础镜像的 Nginx 容器和应用容器在磁盘上只存一份底层数据节省大量磁盘空间推送和拉取也快得多。资源利用率方面Docker 比虚拟机更轻。虚拟机需要给每个虚机装一个完整操作系统CPU、内存、磁盘都有不小的开销容器只包含应用及其依赖共享宿主机内核一台 16G 内存的机器跑十几个容器毫无压力换作虚拟机可能三四个就卡了。对于中小团队来说这意味着用同样的服务器成本可以跑更多的服务。从团队协作来看Docker 还改变了交付方式。以前开发给运维的是一个部署文档写着“先装 JDK 1.8再配 /etc/profile然后改 Tomcat 的 server.xml……”运维照着做还容易出错。现在开发直接给一个镜像或者给一个 Dockerfile运维只需要 docker build 和 docker run。交付物从“文档”变成了“镜像”这个转变的价值怎么强调都不过分。2.2 Docker的缺点用久了才会发现Docker 并非没有短板。最典型的一个它只是单机工具不具备跨主机的编排能力。你在单台机器上 docker run 管理几个容器没问题但生产环境一上规模几十上百个容器分布在多台服务器上怎么分配怎么保证某个容器挂了自动重启怎么平滑升级这些问题 Docker 原生机制根本管不了。另一个痛点是网络和存储。Docker 默认的 bridge 网络模式在单机环境下够用但跨主机通信就需要额外方案。存储方面容器本身是无状态的数据写在容器可写层里容器一删数据就没了必须挂载 volume 才能真正持久化。很多初学者在这个地方吃过亏——容器删了数据丢了来找我排查一看就是没用 volume 挂载。安全隔离也是 Docker 长期以来被诟病的问题。容器共享宿主内核不像虚拟机有硬件级别的虚拟化隔离一旦内核出现漏洞理论上可能影响所有容器。虽然现在有 gVisor、Kata Containers 这类安全容器方案但常规 Docker 运行方式下多租户隔离的强隔离需求并不适合直接用 Docker 实现。还有一个经常被忽略的问题缺乏自愈能力。Docker 可以配置 restart policy容器崩了能自动拉起但如果是宿主机宕机呢容器就再也没有人管了。对于核心业务来说这种单点风险是不可接受的。这也是 Docker 之后必须引入 K8s 的最直接理由。2.3 K8s的优点解决的是大规模生产问题Kubernetes 的价值不在于“同时能跑多少个容器”而在于它提供了一整套自动化运维框架。服务发现与负载均衡是默认能力每个 Pod 都有独立的 IP服务之间通过 Service 访问K8s 自动做流量转发和负载均衡。配置管理用 ConfigMap 和 Secret 集中管理环境变量和敏感信息不再散落在各个部署脚本里。自动伸缩是 K8s 最吸引人的特性之一。Pod 水平自动伸缩器可以根据 CPU、内存等指标自动增减副本数配合集群自动伸缩器可以在整个集群层面伸缩节点。我做过一个电商类的项目平时 20 个 Pod 足够大促期间流量涨十倍K8s 自动弹到 200 个 Pod活动结束自动缩回全程不需要人工干预。这种弹性能力在传统架构下根本无法想象。自愈能力也是 K8s 的核心卖点。它有一个控制回路永远在比较“期望状态”和“实际状态”。你声明需要 3 个副本实际只有 2 个K8s 会自动创建一个新的某个节点宕机了跑在上面的 Pod 会在其他健康节点上自动重建。这种声明式管理的思路让运维从“盯着监控做事后处理”变成了“提前声明好状态系统自动维持”。K8s 还有一个容易被低估的优点生态极其繁荣。Helm 做应用打包Prometheus 做监控Istio 做服务网格Argo CD 做 GitOps几乎你能想到的云原生基础设施能力都能在 Kubernetes 生态里找到成熟的方案。这意味着你不是在用一个孤立的编排工具而是加入了一整个技术生态体系。2.4 K8s的缺点也要如实说K8s 最大的缺点就是复杂这不是我一家之言而是社区公认的。一个生产可用的集群涉及 API Server、etcd、Controller Manager、Scheduler、kubelet、kube-proxy 等组件每一个都需要正确配置和监控。安装工具倒是越来越成熟从 kubeadm 到 kubekey都大幅降低了部署门槛但真正把集群运维得稳定可靠需要投入的学习成本仍然很高。etcd 是 K8s 的大脑所有集群状态都存在这里。它的性能直接影响集群的反应速度它挂了整个集群就瘫了。但很多初次搭建集群的团队对 etcd 的备份和恢复没有足够重视真出问题的时候才发现没有演练过恢复流程。这属于典型“用的时候才后悔”的场景。另一个痛点版本升级。K8s 的版本迭代速度非常快每年三四个大版本。版本升级不是简单的换二进制需要考虑 API 兼容性、kubelet 和 API Server 的版本偏差、第三方控制器和 CNI 插件的适配情况。很多团队升一次级前前后后要折腾几个晚上。我见过一些团队干脆停留在旧版本不升了结果遇到安全漏洞又不得不升反而更被动。资源占用也要说清楚。K8s 控制平面本身需要消耗资源etcd、API Server、控制器等组件大概需要 2-4G 内存。对于小规模集群来说这个开销占比不低。如果只是跑三五个应用上一套 K8s 有点杀鸡用牛刀的感觉复杂度带来的成本超过了收益。2.5 Docker和K8s怎么选看需求而不是看热度这可能是大家最关心的问题。我的建议就一句话看你的规模。单机环境的个人项目或者学习实践容器数量少、不需要弹性伸缩、挂了手动重启就行用 Docker Compose 就够了。Compose 把一个项目的多个容器编排在一起docker-compose.yml 里定义服务、网络、卷一条 docker compose up 就全部拉起来学习成本低维护成本也低。测试环境可以考虑从 Docker Compose 过渡到 K8s。这个阶段的价值在于让团队熟悉 K8s 的工作方式同时利用 K8s 的环境一致性来减少测试环境差异。不过说实话如果团队没有 K8s 基础一上来就铺开一套完整集群学习曲线会很陡容易挫伤积极性。生产环境超过三台服务器或者业务有明显波峰波谷或者对服务可用性有较高要求直接上 K8s。选择这个时机远比选择工具本身更重要。K8s 在你业务规模还没到的时候可能显得笨重等业务真的到了那个规模再来迁移反而更痛苦。我见过太多团队在业务快速扩张期才想起来容器化结果一边赶业务一边做迁移那叫一个狼狈。下面我用一个表格直观对比 Docker 和 K8s 的核心差异方便你做决策时参考对比维度DockerKubernetes定位容器引擎单机容器管理容器编排平台集群级调度管理学习曲线较低几天能上手较高需要数周甚至数月资源开销低直接运行在宿主机较高控制平面需额外资源跨主机调度不支持原生支持自愈能力仅支持简单重启策略自动恢复、自动伸缩、滚动更新服务发现与负载均衡手动实现或借助额外工具原生内置适用规模单机、少量容器规模化容器、微服务架构数据持久化Volume 机制PV/PVC 抽象支持对接多种存储生产级可靠性一般存在单点风险高本身就是为生产设计3. Docker的核心环节实操3.1 Docker安装中的高频坑Docker 的安装本身不难但我在帮别人排障的过程中遇到的安装类问题反而最多。最典型的就是 Windows 上装 Docker Desktop启动时报错“virtualization support not detected”或者“virtualization is disabled in firmware”。这个意思是 BIOS 里没开启虚拟化或者 Windows 功能里的虚拟机平台和 Hyper-V 没有打开。处理步骤重启电脑进 BIOS 开启 Intel VT-x 或 AMD SVM然后在 Windows“启用或关闭 Windows 功能”里勾选“虚拟机平台”和“适用于 Linux 的 Windows 子系统”重启后再启动 Docker Desktop。还有更高频的一个报错“failed to connect to the docker api at npipe:////./pipe/dockerdesktoplinuxen”这通常是 Docker Desktop 的 Linux 后端没起来解决办法是在任务栏托盘里右键 Docker 图标选 Restart或者彻底退出后用管理员身份重启 Docker Desktop。Linux 上装 Docker 相对顺利但国内用户会遇到镜像拉取慢的问题。解决办法是配置国内镜像源在 /etc/docker/daemon.json 里写入镜像加速地址注意这里不要使用那些已经失效的公共加速器最好在云厂商控制台获取你自己的专属加速地址。{ registry-mirrors: [你的专属加速地址] }改完记得执行 systemctl daemon-reload 和 systemctl restart docker 让配置生效。3.2 镜像优化与依赖管理的实用技巧镜像体积直接关系到推送、拉取和启动速度。我见过不少团队的镜像动辄 2-3G其实就是 Dockerfile 写得粗糙。核心优化思路有这么几条尽量用官方镜像或轻量基础镜像Java 应用可以用 eclipse-temurin 的 slim 版本前端构建产物可以用 nginx:alpine 来跑Node 应用看场景用 node:alpine。基础镜像小了整体镜像体积直接降一个量级。Dockerfile 的指令顺序也有讲究。每条 RUN、COPY 都会产生一个新的镜像层构建时会尽可能利用缓存。把不常变的依赖安装指令放在前面把经常变的代码复制指令放在后面这样每次改代码后构建前面的层都能命中缓存构建速度快很多。多阶段构建是处理编译型应用的最佳实践。以 Java 应用为例第一阶段用带 JDK 的镜像编译打包第二阶段用只带 JRE 的镜像运行中间产物不进入最终镜像。前端应用同理第一阶段 npm build第二阶段把 dist 目录复制到 nginx 镜像里镜像体积能从 1G 降到几十兆。对于那些容器化运行带依赖管理的工具比如一些自动化脚本框架建议在基础镜像中预装好依赖管理模块然后通过挂载配置目录和运行目录的方式来隔离不同项目的依赖避免所有项目挤在同一个容器里导致依赖版本冲突。3.3 Docker Compose编排与典型中间件部署有人问单机容器管理是不是直接 docker run 就行我的建议是即使是单机也尽量用 Compose。docker-compose.yml 把服务的镜像、端口映射、环境变量、卷挂载都声明在文件里随代码一起版本管理。换机器部署或者新同事接手一条 docker compose up -d 就能复现一套完整环境。以部署 MySQL 8.0 为例一个可用的 compose 配置大概是这样的services: mysql: image: mysql:8.0 container_name: mysql8 restart: always environment: MYSQL_ROOT_PASSWORD: your_password MYSQL_DATABASE: appdb TZ: Asia/Shanghai ports: - 3306:3306 volumes: - ./data:/var/lib/mysql - ./conf/my.cnf:/etc/mysql/conf.d/my.cnf - ./logs:/var/log/mysql command: --character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_ci这里面有三个要点数据目录要挂载到宿主机否则容器删了数据就没了字符集要在启动参数里显式指定 utf8mb4否则默认字符集在中文场景下会出问题配置文件最好也挂载出来方便后面调优不用重新构建镜像。Redis 主从部署也是常见的需求。主从复制的原理是主实例把写操作记录成 RDB 快照和 AOF 日志从实例连接主实例后同步这些数据。Compose 里先起一个主节点映射 6379 端口再起一个从节点通过 redis-server --slaveof 命令指定主节点地址。4. K8s从入门到能用的关键步骤4.1 集群规划与安装方式选择K8s 集群的安装方式我建议从学习到生产分阶段选择。学习阶段用 minikube 或者单节点 kubeadm 就足够了重点是理解工作逻辑而不是搭建过程的细节。到了准生产阶段用 kubeadm 逐台安装这个过程能让你对组件间的关系有深入理解。等团队有一定基础后可以考虑 kubekey 这类自动化工具它能简化多节点集群的搭建对高可用部署也有很好的支持。集群规划上最常见的生产配置是三节点 master 加若干 node。三台 master 保证控制平面的高可用即使一台挂了集群仍然可以正常调度。但要注意etcd 的写入需要多数派确认三节点最多允许挂一个所以三台 master 是最能平衡成本和可用性的方案。如果只有两台 master挂一台集群就失去法定人数了所以要么三台起要么就别做高可用。K8s 对机器配置的建议是master 节点 4C8G 起步etcd 对磁盘 IO 敏感务必用固态硬盘。节点能加就加但我见过不少测试环境 2C4G 也跑起来了只是不建议在生产环境这么干。4.2 控制器、Service和常用命令K8s 里的控制器Controller是保证声明状态的引擎。Deployment 用来管理无状态应用保证指定数量的副本始终运行支持滚动更新和回滚。StatefulSet 专门为有状态应用设计为每个副本提供稳定的网络标识和独立的存储卷适合数据库类应用。DaemonSet 保证每个节点上运行一个 Pod比如日志采集器、监控 Agent 这类组件就适合用 DaemonSet。Job 和 CronJob 分别处理一次性任务和定时任务。Service 是 K8s 服务发现的基石。因为 Pod 的 IP 是不固定的重启后就会变化所以需要通过 Service 提供稳定的访问入口。Service 有多种类型ClusterIP 在集群内部访问NodePort 在节点上暴露端口供外部访问LoadBalancer 对接云厂商负载均衡器。访问流程就是流量先到 ServiceService 按规则转发到后端的某个 Pod。命令方面日常用最多的就是这几个kubectl get pods -A kubectl logs -f pod-name kubectl describe pod pod-name kubectl exec -it pod-name -- bash kubectl apply -f yaml文件 kubectl rollout status deployment/名称kubectl describe 是我排障用得最多的命令Pod 卡在 Pending、CrashLoopBackOff、ImagePullBackOff 这些状态时describe 输出里会给出原因比如资源不足、镜像拉取失败或者健康检查不通过。记不住命令很正常遇到不确定的先 help 或 --help用多了自然就记住了。4.3 监控、GPU和证书管理集群跑起来以后监控是第一个要考虑的事情。Prometheus 加 Grafana 是事实标准部署方式推荐用 kube-prometheus-stack 这个 Helm Chart它把 Prometheus、Alertmanager、Grafana 以及 node-exporter、kube-state-metrics 等组件打包好了一次部署就能覆盖节点层面和容器层面的监控。告警规则也可以模板化比如节点 CPU 高、Pod 反复重启、磁盘空间不足等场景网上有大量成熟的规则可以直接参考。AI 相关的负载要调度 GPU 资源需要在节点上预先安装 NVIDIA 驱动和 nvidia-container-toolkit然后在 K8s 里部署 NVIDIA Device Plugin。部署成功后节点会上报 nvidia.com/gpu 这个资源Pod 就可以在资源声明里请求 GPU。我踩过的坑是驱动版本和 CUDA 版本不匹配容器起不来排查了大半天。建议先用 nvidia-smi 确认驱动正常再部署 Device Plugin最后用一个简单的 CUDA 镜像测试能不能正常申请到 GPU 资源。证书过期的坑相信每个 K8s 运维都经历过。默认证书有效期只有一年集群跑久了 kubelet 证书过期节点直接 NotReady。手动续期又麻烦又容易忘记。解决办法是配置自动续期kubeadm 支持把 kubelet 证书设置为自动续期控制平面的证书也可以用定时任务定期执行 kubeadm certs renew 来更新。5. 微服务上云时的要不要用Docker和K8s5.1 传统架构迁移到云原生的真实路径这几年我参与过不少从传统单体架构向云原生迁移的项目包括现在很多人都在做的若依微服务迁移踩过的坑也比较多。若依这个框架很典型它有网关、认证、系统管理、监控等多个微服务模块每个模块需要独立的部署和配置。传统方式下部署这些服务至少需要准备一台服务器手动装好 Redis、MySQL、Nacos、Nginx然后逐个配置 Java 环境、启动参数整个过程耗时两三个小时。容器化改造以后整个流程变成为每个微服务模块编写 Dockerfile制作镜像推到私有仓库用 docker-compose 在单机环境快速拉起一套完整环境验证没问题再迁移到 K8s为每个服务编写 Deployment 和 Service 的 YAML。在 K8s 上面每个服务都声明好需要的副本数量、资源限制、健康检查探针K8s 会保证服务始终处于健康状态。要做滚动发布时只需要更新镜像版本执行 kubectl rollout restartK8s 会自动创建新 Pod等新 Pod 就绪后再摘除旧 Pod整个过程中服务不中断。我们这个迁移过程花了两天时间核心工作集中在两个部分一是把每个服务的配置文件从原来的本地配置文件方式改成 ConfigMap 方式让配置和镜像解耦二是处理数据库连接、Redis 地址这类配置在容器环境的网络访问问题。如果新版本的若依本身已经有比较完善的容器化支持这个工作量会少很多。5.2 不停服、不丢数据的迁移策略说到迁移最怕的是什么服务中断和数据丢失。关于不停服这个话题我总结几个核心原则先静态后动态先无状态后有状态回滚预案永远提前准备。对于无状态服务比如 Web 应用、API 服务滚动迁移完全可行。在 K8s 里设置 maxSurge 和 maxUnavailable 参数控制滚动过程中新老 Pod 的比例保证始终有足够的实例对外服务。strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0这个配置的意思是滚动更新时先额外创建一个新 Pod等新 Pod 就绪后再停止一个旧 Pod。整个过程永远保持至少满额的服务能力不会出现服务完全不可用的情况。有状态服务类似数据库的迁移要复杂得多。以 MySQL 为例核心思路是建立主从复制关系。先在新的容器环境里起一个从库让它从旧库同步数据等同步进度追上主库后把写流量切换到新主库上。实际操作中我用的是 mysqldump 先做全量备份然后在容器环境恢复再通过 binlog 做增量同步。全量备份的导出和导入速度取决于数据量大小增量同步追平之后选择一个流量低谷期做切换整个过程对用户的影响可以压缩到分钟级以内。这里要特别提醒数据迁移前必须做完整的备份和校验不要在没有任何后备的情况下直接切主库。我见过有人图省事直接在生产库里执行了删表操作等发现误删再想办法恢复那叫一个痛苦。5.3 Service Mesh和服务网格的联系聊 K8s 不可避免会提到 Service Mesh。Dubbo Mesh 这类方案就是在 K8s 之上再加一层服务网格用边车代理接管服务间通信。Service Mesh 解决的是微服务通信治理问题比如超时、重试、熔断、灰度发布、流量监控等这些在传统微服务框架里是靠 SDK 实现的升级框架就要改代码重新发布。有了 Service Mesh这些能力下放到基础设施层业务代码基本不需要关心对业务侵入性更小。如果你的服务已经基于 Spring Cloud 或者 Dubbo 在运行迁移到 K8s 初期不一定要上 Service Mesh因为原来的服务注册发现、负载均衡机制在 K8s 网络里也能跑。等规模大了或者需要精细流量治理了再考虑引入 Istio 这类方案也不迟。核心原则还是那句话不要为了技术而技术架构演进要跟着实际问题走。6. 常见问题排查实录与避坑指南6.1 Docker常见问题速查下面按问题和解决方案的方式整理都是我实际排查过程中遇到过的。问题现象可能原因解决办法Docker Desktop 启动失败提示 virtualization not detectedBIOS 虚拟化未开启进 BIOS 开启 Intel VT-x/AMD SVM开启 Windows 虚拟机平台容器内网络不通端口映射配置错误确认 -p 参数格式是宿主端口:容器端口检查防火墙放行镜像拉取超时网络原因或镜像源不稳定配置国内镜像加速源确认网络可达容器删除后数据丢失未挂载数据卷使用 -v 挂载宿主机目录或命名卷docker compose 里服务间无法通信服务名或网络配置错误确认服务名、自定义网络配置检查 yaml 缩进格式容器时区不正确未配置时区设置环境变量 TZAsia/Shanghai或挂载 /etc/localtime6.2 K8s常见问题速查K8s 的排障思路和 Docker 完全不是一回事这里分享几个高频问题的定位方法。问题现象可能原因解决办法Pod 一直 Pending节点资源不足或调度约束不满足kubectl describe pod 查看事件检查节点资源、污点容忍、资源请求值Pod 反复 CrashLoopBackOff应用启动失败或健康检查失败查看日志 kubectl logs检查 liveness/readiness 探针配置镜像拉取失败 ImagePullBackOff镜像仓库认证失败或镜像不存在设置 imagePullSecret检查镜像名和标签是否正确节点状态 NotReadykubelet 异常或证书过期检查 kubelet 服务状态确认证书有效期并续期Service 无法访问选择器标签不匹配检查 Service 的 selector 是否匹配 Pod 的 labelsetcd 磁盘空间不足历史数据未压缩配置定期 defrag 和压缩开启自动压缩策略6.3 证书续期和备份恢复的实战心得最后单独说说证书和备份这两件事。K8s 的证书续期有几种自动化方案kubeadm 模式下可以直接修改 kubelet 配置让证书自动续期。控制平面组件证书我用 cronjob 每天早上 2 点执行一次 kubeadm certs renew all然后 reload 相关组件的配置。这个方案跑了一年多没有再遇到过证书过期引发的集群故障。备份方面K8s 集群要备份的核心是 etcd里面存着所有资源对象的声明状态。我用的是一个简单的备份脚本每天凌晨通过 etcdctl 快照备份到对象存储保留最近七天的备份。单节点集群的快照恢复流程我演练过先停 kube-apiserver然后从快照恢复 etcd 数据再启动服务恢复过程半个小时以内完成。对于生产环境不演练过恢复流程的备份等于没有备份。容器化改造不是一锤子买卖它是一条持续演进的技术路线。最初用 Docker 解决环境一致性问题后面用 Compose 管理多容器编排再到上 K8s 获得弹性伸缩和自愈能力每一步的驱动力都是实际的业务痛点。现在 Kubernetes 生态还在不断膨胀从服务网格到 GitOps 到 eBPF基础设施的能力边界一直在扩展。工具更新换代很快但背后的核心思路没变让应用的构建、部署、运维变得更标准化、更自动化。把握住这条主线技术选型就不会跑偏。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价