资讯动态

Docker部署GitLab完整指南:从核心参数到备份恢复

发布时间:2026/10/22 8:25:53 来源:尧图企业网站定制
1. 整体设计思路为什么选 Docker 部署 GitLab先说结论用 Docker 跑 GitLab 是我试过的最省心的自托管代码托管方案没有之一。但前提是你得先理解几个核心概念否则后面踩坑会踩到怀疑人生。GitLab 本身是个重量级应用官方推荐的部署方式有两种一种是直接装在裸机上另一种就是用 Docker。我在某公司维护过一套裸机部署的 GitLab升级一次要折腾半天依赖冲突、Ruby 版本不兼容、PostgreSQL 数据迁移失败这些问题轮着来。后来换了 Docker 部署整个体验完全不一样——升级就是拉新镜像重启容器回滚就是换回旧镜像数据都挂在宿主机目录里稳得很。不过 Docker 化部署也有它自己的坑。最大的坑在于 GitLab 官方镜像是一个“全家桶”容器里面不只是 GitLab 本身还集成了 PostgreSQL、Redis、Nginx 这些组件。这意味着如果你之前对单体应用的理解是“一个容器只跑一个进程”那用 GitLab 镜像时会有点不习惯。选择 Docker 部署的核心理由有三个我实际操作下来体会很深第一隔离性。GitLab 依赖的 Ruby、PostgreSQL、Redis 版本都是写死在镜像里的不会污染宿主机的系统环境。我见过有人在宿主机上装了别的软件结果把系统自带的 PostgreSQL 给顶掉了GitLab 直接罢工。Docker 部署完全不存在这种问题。第二可移植性。整个 GitLab 环境被我打包成了一个镜像想迁移到新服务器只要把数据目录拷过去在新机器上跑同样一条命令就行数据一致性有保障。第三版本切换方便。我升级 GitLab 时如果发现新版本有问题一条命令就能回滚到旧版本整个过程不会超过五分钟。这在裸机部署时代想都不敢想。当然Docker 部署也不是没有代价。最明显的就是数据卷管理你得搞清楚容器里的路径和宿主机路径的对应关系否则容器一删代码库全没了那时候真是欲哭无泪。后面我会详细讲这块的配置。我在架构设计时采用的是最标准的方案宿主机上建一个专门的目录作为 GitLab 的数据根目录里面分三个子目录分别存代码仓库、数据库文件和备份文件。这样规划的目的很明确——升级容器时数据不丢备份时只需要打包一个目录恢复时也只需要把目录放回去。这个设计思路是所有 GitLab Docker 部署方案的基础你可以把它想象成把 GitLab 的家搬到了宿主机上容器只是临时过来住的。现在很多团队在考虑代码托管方案时第一反应是直接用现成的托管平台。但如果你有私有化部署的需求——比如代码不能出内网、或者想要完全掌控数据——那么自建 GitLab 几乎是绕不开的选择。Docker 化的 GitLab 正好把这个过程变得足够简单让中小团队也能轻松搞定。2. 部署前的关键参数拆解2.1 核心参数external_url 的设计逻辑部署 GitLab 之前第一个要决定的事情就是 external_url。这个参数很多人不理解以为只是随便填个地址实际上它决定了 GitLab 生成的克隆地址、CI/CD 回调地址、Web IDE 跳转地址等一系列行为。external_url 的值要和你最终访问 GitLab 的地址保持一致。举个例子如果我用http://gitlab.example.com访问 GitLab那 external_url 就要填这个地址。如果只是在内网测试用 IP 访问那就填http://192.168.1.100。这里有个常见失误我见过不止一次有人 external_url 填的是http://localhost结果其他同事访问服务器 IP 时页面上生成的克隆地址全是 localhost根本没法用。这个坑务必记住——external_url 必须是所有用户都能访问到的地址不是你自己机器上的地址。还要注意 http 和 https 的区别。如果你打算用 HTTPS 访问external_url 一开始就要填 https 的地址不然后面改起来会有点麻烦GitLab 内部很多配置是跟着这个地址走的改了之后有些地方会有一段时间不生效。如果以后要绑域名可以先把 DNS 解析做好再部署 GitLab。因为 GitLab 在初始化时会根据 external_url 生成 SSL 证书相关配置如果这个地址后面变了虽然可以改但会多出不少操作。我的建议是域名提前规划好解析先做好external_url 一步到位。2.2 端口映射规划22 和 443 的冲突问题端口映射也是容易出问题的地方。GitLab 容器内部默认监听的端口是 80HTTP和 443HTTPSSSH 走的是 22。我第一次部署时天真地以为直接映射就行结果发现宿主机上的 22 端口已经被系统 SSH 服务占用了。这里有几种解法我推荐优先级从高到低排列方案一把宿主机的 SSH 端口改成其他端口比如 2222把 22 端口留给 GitLab 的 SSH 功能。这个方案最优雅但前提是你有宿主机 root 权限而且改完之后要测试 SSH 还能登录。方案二GitLab 的 SSH 映射到宿主机的非 22 端口比如 2222。但这样有个小麻烦——用户克隆代码时默认生成的地址是ssh://githost:2222/group/project.git每次都要带端口号有点繁琐。方案三只开放 HTTP/HTTPS 访问不用 SSH 协议。用户在克隆代码时全部走 HTTP同时开启 GitLab 的 HTTP 推送功能。对于很多团队来说这个方案足够用了而且省心不少。我最终选择了方案一把宿主机 SSH 端口改掉腾出 22 给 GitLab。因为 GitLab 的 SSH 模式对开发者最友好git clone时地址最简洁而且支持 SSH Key 认证方式体验和 GitHub 一致。另外容器里的 80 端口通常映射到宿主机的 8080 或 80。如果宿主机 80 端口已经被占用映射到 8080 也没问题但访问时就得带端口号。这个要提前规划好最好用 Nginx 反向代理统一处理域名和端口的关系。2.3 数据卷挂载三个目录都必须配置GitLab 官方推荐的挂载目录有三个缺一个都会出问题。我在/srv/gitlab目录下建立三个子目录/srv/gitlab/data存 Git 仓库、文件上传、SQL 数据库文件。这个目录是重中之重删了就完蛋。/srv/gitlab/logs日志文件。排查问题时用的最多。/srv/gitlab/config配置文件包括gitlab.rb和gitlab-secrets.json。这个目录也很关键因为部署时的初始密码、RSA 密钥都存放在这里。这三个目录都要挂载不能偷懒。我见过有人只挂载了 data 目录结果容器重建后 GitLab 信息全丢了——因为gitlab-secrets.json文件在 config 目录里没挂载的话每次容器创建都会重新生成令牌、密钥全部对不上用户需要重新登录。数据卷挂载的本质是持久化这个概念对于理解 Docker 部署 GitLab 非常重要。容器就像一次性的临时工干完活就没了只有宿主机上的目录才是你的固定资产。所以数据卷必须设计好后面升级、迁移、备份都依赖这个基础。2.4 时区和 root 密码设置GitLab 默认时区是 UTC如果不改你在页面上看到的时间会差 8 个小时日志时间也对不上。我的建议是在环境变量里加上TZAsia/Shanghai这个配置这是一个很小但非常实用的设置。root 密码方面GitLab 第一次启动时会生成一个随机密码在页面上首次登录时系统会强制你修改。有一个更省事的办法在一开始设置环境变量GITLAB_ROOT_PASSWORD指定初始密码。但要注意这个设置在首次初始化时才生效后面改密码得去页面或命令行。我建议首次部署时不要设置 GITLAB_ROOT_PASSWORD而是用随机密码登录然后手动修改。原因很简单——随机密码绝对安全不会因为你设置了一个弱密码导致安全隐患。你要是图省事设了个admin123那基本等于把代码仓库的大门敞开了。3. 完整部署实操记录3.1 环境准备和目录初始化我在一台干净的 Ubuntu 服务器上操作的系统版本和 Docker 版本其实不太重要只要是主流版本都行。第一步是创建数据目录给 GitLab 专门建一个家。mkdir -p /srv/gitlab/config mkdir -p /srv/gitlab/data mkdir -p /srv/gitlab/logs这三行命令的顺序和含义先建配置目录再建数据目录最后建日志目录。目录权限方面Docker 容器默认以 root 用户运行所以目录权限暂时不需要特殊调整。如果你有特殊的权限要求可以运行容器后再改目录属主和权限但初期不需要纠结这个。3.2 docker-compose 配置详解用docker run命令直接跑也行但作为长期维护的项目我推荐用 docker-compose 管理可读性强后续也方便扩展。以下是我项目里的 docker-compose.yml 配置version: 3.8 services: gitlab: image: gitlab/gitlab-ce:latest container_name: gitlab restart: always hostname: gitlab.example.com environment: TZ: Asia/Shanghai GITLAB_OMNIBUS_CONFIG: | external_url http://gitlab.example.com gitlab_rails[gitlab_shell_ssh_port] 22 gitlab_rails[time_zone] Asia/Shanghai nginx[enable] true nginx[listen_port] 80 ports: - 80:80 - 443:443 - 22:22 volumes: - /srv/gitlab/config:/etc/gitlab - /srv/gitlab/logs:/var/log/gitlab - /srv/gitlab/data:/var/opt/gitlab shm_size: 256m逐个解释几个关键配置项的含义。restart: always容器挂了自动重启这是生产环境必备的配置。服务器重启后 Docker 会自动拉起容器不用人工干预。hostname容器的主机名建议和 external_url 保持一致。如果 hostname 和 external_url 不一致GitLab 内部生成的链接有时会有点奇怪。GITLAB_OMNIBUS_CONFIG这个环境变量很强大它允许你把原本写在gitlab.rb里的配置直接通过环境变量传进去。这样容器第一次初始化时就会自动应用这些配置不用再手动改文件。注意|符号表示多行字符串后面每一行缩进要对齐。ports映射的优先级22 端口是 SSH 用的80 端口是 HTTP 用的443 端口是 HTTPS 用的。如果你的宿主机 80 和 443 被占用可以映射到别的端口但这样访问时就要手动加端口号体验会打折。shm_size: 256m这个参数容易被忽略但它确实有影响。GitLab 内部用到了 PostgreSQL而 PostgreSQL 对共享内存有要求。设置 256MB 可以避免一些奇怪的并发连接错误我是踩过这个坑才加上这个参数的。3.3 启动和初始化过程配置文件写好后开始启动docker-compose up -d第一次启动会拉取镜像GitLab 镜像比较大几个 GB所以要有耐心。启动完成后查看容器状态docker ps | grep gitlab这个命令能确认容器有没有成功运行。如果状态正常就可以开始等待 GitLab 初始化了。GitLab 第一次初始化很慢通常要 3 到 5 分钟期间容器会反复重启这是正常现象不用慌。怎么判断初始化完成了呢我习惯用这个命令docker exec -it gitlab grep GitLab is fully ready /var/log/gitlab/unicorn/current如果能看到这行日志说明可以访问了。还有人会直接访问页面试如果能看到登录界面基本就差不多了。初始化期间尽量不要去操作容器不要重启它不要改配置给它一点时间自己完成。我试过一次初始化到一半强制重启容器结果配置文件写坏了一半最后把整个目录清空重新来了一遍。初始化完成后第一次访问http://gitlab.example.com会跳转到修改密码页面让你设置 root 用户的密码。设置完就能用 root 账号登录了。3.4 首次登录和基本配置检查登录之后别急着建项目先做几个基本检查在左下角的菜单里找到“关于”确认版本号是否正确。在管理区域中检查“系统信息”看是否有异常警告。创建一个测试项目试试能不能正常推送代码。创建一个空的测试仓库然后在本机试一下git clone http://gitlab.example.com/root/test-project.git cd test-project touch README.md git add README.md git commit -m init git push origin main如果推送成功说明整个链路是通的。这一步很重要因为有些问题在网页上完全看不出来只有实际推拉代码才能暴露。我还习惯顺便检查一下 SSH 协议是否正常。在你自己的机器上生成一对密钥把公钥添加到 GitLab 的 SSH Keys 里然后试一下git clone gitgitlab.example.com:root/test-project.git能克隆成功说明 SSH 配置没问题开发者的体验会比较顺畅。4. 运维和常见问题排查实录4.1 配置修改单文件搞定GitLab 的所有配置都在一个文件里/srv/gitlab/config/gitlab.rb。这个文件是挂在宿主机上的所以直接编辑宿主机里的这个文件即可。配置修改后的生效过程很简单核心是这两步docker exec -it gitlab gitlab-ctl reconfigure docker exec -it gitlab gitlab-ctl restartreconfigure会把 gitlab.rb 里的配置重新生成到各个子服务里这一步会更新 Nginx 配置、数据库配置等。restart是重启全部服务。注意顺序不能乱先 reconfigure 再 restart。我在实际操作中发现改配置有小概率会失败多数情况是语法错误。所以我的建议是每次执行完 reconfigure 后先看一下有没有报错再考虑要不要 restart。如果 reconfigure 报错了改回来再执行一次就行。顺便说一句改配置前最好先备份一下 gitlab.rb 文件一条命令的事cp /srv/gitlab/config/gitlab.rb /srv/gitlab/config/gitlab.rb.bak这个习惯看似多余但能救命。有一次我把配置文件改坏了GitLab 完全起不来最后就是从备份文件恢复的。4.2 常见错误排查速查表我把自己实际遇到过的几个典型问题整理成一个表格方便排查时快速定位。现象可能原因排查方法解决办法页面出现 502 错误GitLab 还在初始化或某个服务挂了查看容器日志和服务状态等待几分钟用 gitlab-ctl status 检查服务推送代码时提示没有权限SSH Key 没配置好在页面检查 SSH Keys 是否添加正确重新添加公钥确认公钥对应正确的用户页面能登录但克隆地址是错的external_url 没设置对查看页面左下角的克隆地址修改 gitlab.rb 里的 external_url重新 reconfigure容器反复重启初始化过程中断或数据目录权限问题查看 docker logs 的输出确认数据目录属主必要时重新初始化磁盘空间不足镜像和仓库数据占满磁盘使用 df -h 查看磁盘使用率清理旧的 Docker 镜像扩展磁盘空间配置仓库清理策略邮件发不出去SMTP 没配置检查 gitlab.rb 里的 SMTP 设置配置正确的 SMTP 参数或使用 sendmail测试邮件发送访问慢得像蜗牛服务器配置低或内存不足查看服务器 CPU 和内存使用率增加内存或等 GitLab 初始化完成后自然变快首次运行时后台任务多这些问题的排查思路大同小异先看日志确认原因再对症解决。不要盲目重启容器很多时候重启解决不了问题反而会把现场搞丢。4.3 备份恢复的完整操作这部分是最重要的操作没有之一。代码仓库如果丢了那真是叫天天不应。备份命令很简单docker exec -it gitlab gitlab-backup create这个命令会把备份文件生成在/srv/gitlab/data/backups目录下文件名类似1702936800_2023_12_19_16.0.5_gitlab_backup.tar前面的数字是时间戳后面是 GitLab 版本号。备份文件只会备份 Git 仓库、数据库、文件上传这些数据不含配置文件。所以真正的完整备份还要把/srv/gitlab/config目录一起拷贝走。我通常会打包整个 /srv/gitlab 目录tar -czf gitlab_backup_$(date %Y%m%d).tar.gz /srv/gitlab这样一份备份就包含了配置和数据恢复时直接解压覆盖到原路径然后启动容器就能恢复。恢复操作要特别注意版本一致性。如果备份是 16.0.5 的恢复到的 GitLab 版本也应该是 16.0.5。版本不一致时恢复容易出问题因为数据库结构可能对不上。这是我实际踩过的大坑升级之前一定要先做一次完整备份升级后发现不对劲马上回滚。一个更稳妥的做法在升级之前先把当前版本的数据目录整体打包一份放到安全的地方。这样如果升级后出问题可以安全地回到旧版本。升级没问题后再把这份备份清理掉。4.4 升级GitLab版本的正确方式Docker 部署 GitLab 的升级非常直接docker-compose pull docker-compose up -d第一条命令会拉取最新的 GitLab 镜像第二条命令会用新镜像重建容器。数据都在宿主机卷里所以容器重建不会丢数据。但升级前一定要做备份这个不能省。我给自己定的规矩是升级前必须完成一次完整备份升级后确认所有功能正常才敢放心用。还有一个值得注意的点GitLab 不支持跨大版本直接升级。比如从 15.x 直接升到 17.x 是不行的必须 15 → 16 → 17 这样逐级升级。因为 GitLab 的数据库迁移是按版本顺序设计的跳级会导致迁移失败。实际操作中建议先看一下当前版本和目标版本之间的差距docker exec -it gitlab cat /opt/gitlab/version-manifest.txt这个文件里记录了当前版本的详细信息。如果差距太大老老实实先升中间版本别嫌麻烦。4.5 容器日志的查看技巧排障时用得最多的命令就是查看容器日志docker logs -f gitlab这个命令可以看到容器的标准输出GitLab 的启动日志都打到这里。但只用这个还不够因为 GitLab 内部多个服务的日志分散在不同的文件里。常用的日志路径我整理了一下/var/log/gitlab/gitlab-rails/production.log应用日志访问出错时先看这个。/var/log/gitlab/nginx/error.logNginx 错误日志502 之类的问题主要看这里。/var/log/gitlab/postgresql/数据库日志。/var/log/gitlab/gitlab-workhorse/currentGitLab Workhorse 日志。查看应用日志docker exec -it gitlab tail -f /var/log/gitlab/gitlab-rails/production.log如果某个请求报错日志里会打出详细的堆栈信息排查效率高很多。我经常遇到用户在网页上操作报了个莫名的错误页面只显示“500”一看日志才发现是数据库连接断了或者某个迁移没有执行。4.6 容器权限和安全性细节GitLab 容器默认以 root 用户运行这在隔离环境下问题不大但如果你对安全要求高可以做进一步加固。第一个建议是限制容器的资源使用。在 docker-compose.yml 里加上resources: limits: memory: 4g cpus: 2.0内存限制很关键GitLab 是个内存大户如果不设限制它可能会吃掉服务器大部分内存。我自己的服务器是 8GB 内存给 GitLab 限了 4GB其他服务也不会被拖垮。第二个建议是限制容器访问网络。如果 GitLab 只在内网使用可以用ports: - 127.0.0.1:80:80这样 80 端口只监听本机只有通过 Nginx 反向代理才能访问到 GitLab避免暴露在公网环境。第三个是关于 SSH 端口如果 GitLab 和宿主机共用 22 端口存在风险顾虑可以用非标准端口。但我前面提到过改了端口后克隆地址会带端口号开发体验略受影响。怎么取舍要看你自己团队的情况。4.7 GitLab Runner 的临时配置很多团队部署 GitLab 之后接下来就要用 CI/CD所以 GitLab Runner 也是绕不开的环节。这里简单提一下怎么临时配置一个 Runner。GitLab Runner 更适合单独部署而不是跑在 GitLab 容器里。我用 docker 跑了一个独立的 Runner 容器runner: image: gitlab/gitlab-runner:latest container_name: gitlab-runner restart: always volumes: - /srv/gitlab-runner/config:/etc/gitlab-runner - /var/run/docker.sock:/var/run/docker.sock挂载 Docker socket 的意思是让 Runner 能动态创建新的容器来执行 CI 任务这是最常用的执行器方式。注册 Runner 的命令我放在下面具体需要填的 token 在 GitLab 管理区域的 CI/CD 页面可以看到docker exec -it gitlab-runner gitlab-runner register \ --url http://gitlab.example.com \ --registration-token YOUR_TOKEN \ --executor docker \ --docker-image docker:latest \ --description my-runner注册完成后Runner 会立即出现在 GitLab 的 Runner 列表里。跑一次流水线测试一下确认没问题就大功告成了。这里有个小坑如果你的 GitLab 是用自签名证书HTTPSRunner 注册时可能会因为证书不被信任而失败。解决办法是在 Runner 配置里加上tls_verify false或者把证书挂载进去。这个细节我踩过提一下免得大家再绕路。5. 数据备份与恢复的深度实践前面提到了基本的备份命令这一节我把它展开到“出事之后怎么恢复”的完整流程。因为备份做得再勤不会恢复等于没做。5.1 完整备份命令的最佳实践我推荐的备份流程是三段式每一步都不能省略第一步停止某个服务以保障数据一致性新版本 GitLab 会在备份时自动处理可以不停止服务但保险起见还是要停止docker exec -it gitlab gitlab-ctl stop puma docker exec -it gitlab gitlab-ctl stop sidekiq这两个服务是 GitLab 的应用服务器和后台任务处理器。停止它们可以防止备份过程中有新的数据写入造成备份文件不一致。注意这两个操作之后要记得启动服务。第二步执行备份docker exec -it gitlab gitlab-backup create第三步恢复服务并复制配置和杂物目录docker exec -it gitlab gitlab-ctl start tar -czf /srv/gitlab/backup/config_backup_$(date %Y%m%d).tar.gz /srv/gitlab/config我实际操作时发现先停服务再备份备份文件的可靠性确实更高不会出现备份到一半数据还在写入的情况。虽然 GitLab 官方说在线备份也可以但能稳妥一点就不要冒险对吧。5.2 灾难恢复的完整流程假设最坏的情况发生了服务器上的 GitLab 数据全部丢失你的备份在另一台机器上。恢复流程如下。第一步在新机器上搭好相同的 Docker 环境建立相同的目录结构mkdir -p /srv/gitlab/config mkdir -p /srv/gitlab/data mkdir -p /srv/gitlab/logs第二步把备份文件解压到对应目录。配置文件放回/srv/gitlab/config备份 tar 包放回/srv/gitlab/data/backups前提是你把整个 /srv/gitlab 打包了如果只打包了 data 的备份文件则把备份 tar 文件放到 data/backups 就可以了。第三步用相同的 docker-compose.yml 启动容器。GitLab 启动时会自动使用挂载的配置和数据。第四步对 GitLab 备份文件执行恢复命令docker exec -it gitlab gitlab-backup restore BACKUP1702936800_2023_12_19_16.0.5这一步会弹出多次确认提示都需要输入yes。恢复过程中会重建数据库所以之前不要启动 puma 或 sidekiq否则会连接冲突。第五步恢复完成后重启服务docker exec -it gitlab gitlab-ctl reconfigure docker exec -it gitlab gitlab-ctl restart docker restart gitlab我在一次演练中测试过完整流程从零开始到数据恢复完成大概需要 20 分钟。这 20 分钟在关键时刻就是救命时间值得花半天提前演练一遍。5.3 备份策略建议实际操作中我建议至少做到三条每天凌晨自动备份备份文件保留 7 天。每周把备份文件拷贝到另一台机器或对象存储上。每季度做一次恢复演练确认备份文件可用。自动备份用 cron 就能实现Linux 下写个脚本#!/bin/bash docker exec -it gitlab gitlab-ctl stop puma docker exec -it gitlab gitlab-ctl stop sidekiq docker exec -it gitlab gitlab-backup create docker exec -it gitlab gitlab-ctl start find /srv/gitlab/data/backups -type f -mtime 7 -delete这个脚本放在/etc/cron.d/gitlab-backup里每天凌晨 2 点执行。别小看这几行代码真的能保命。我之所以把停止服务的步骤放进自动备份脚本是因为半夜停了服务影响最小同时也最稳妥。6. 我踩过的坑和最终的几点体会Docker 部署 GitLab 这件事说难也难说简单也简单。难的是你第一次接触时概念不熟悉参数拿不准容易出各种奇怪的问题。简单的是只要照着正确的方法走一遍后续所有操作都有规律可循基本不会出大问题。我在某公司的环境里维护这套方案已经运行了几个月中间经历过升级、迁移、磁盘告警、Runner 故障等各种情况目前的感受是这套架构的稳定性完全在掌控之内。个人觉得最有价值的时间投入就是前期目录规划、备份流程和升级路径。最后再分享两个亲测有效的小技巧。第一个是关于日志清理的。GitLab 运行时间久了日志文件会变得很大占用不少磁盘空间。可以设置日志轮转在gitlab.rb里加上logging[logrotate_frequency] daily logging[logrotate_rotate] 7 logging[logrotate_size] 100M然后执行gitlab-ctl reconfigure日志就不会无限膨胀了。第二个是关于初始密码的如果你不小心忘了 root 密码可以用命令重新设置docker exec -it gitlab gitlab-rails runner user User.where(username: root).first; user.password 新密码; user.password_confirmation 新密码; user.save!这个命令本质上是打开 GitLab 的 Rails 控制台直接修改用户模型属于最底层的操作一定会生效。这段命令本身也是绕开网页登录验证的一个简单办法遇到忘记密码时不用重装整个系统。Docker 部署 GitLab 这套流程越往后越会体会到它的便利。尤其是备份恢复和版本切换的灵活性对比传统部署方式优势非常明显。建议你动手搭一个哪怕只是在自己电脑上跑个测试环境跑通一遍之后对这套方案的理解就完全不一样了。

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

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

免费获取报价 →
↑