跳过正文
  1. 博客文章/

用 Docker Compose 部署 Draw.io 并接入 GitLab 存储

·1060 字·5 分钟·
DevOps SRE Draw.io Diagrams.net GitLab Docker Docker-Compose Nginx DevOps
Zayn
作者
Zayn
专注 Kubernetes、CI/CD、可观测性等云原生技术栈,记录生产环境中的实战经验与踩坑复盘。
目录
生产变更复盘 - 这篇文章属于一个选集。
7: 本文
Draw.io 自托管后,可以把架构图和流程图留在自己的入口、GitLab 和网络边界内。这份记录把 Docker Compose、Nginx 代理、GitLab OAuth、PlantUML、图片导出和脱敏检查串成一条可复现路径。
文中使用 draw.example.comgitlab.example.com192.0.2.16 作为示例值。落地时替换为自己的域名、GitLab 地址和服务器 IP;OAuth 应用 ID 与 Secret 只放在部署机 .env 或密钥管理系统里。

这套部署把 diagrams.net / Draw.io 跑成内网可控的 Web 服务,再通过 GitLab OAuth 接入仓库存储。入口由 Nginx 做 HTTPS 代理,容器侧同时启用 PlantUML 和图片导出服务,适合在 GitLab Wiki、技术文档和架构图维护场景里使用。

0. 部署边界
#

服务diagrams.net / Draw.io
部署方式Docker Compose
主服务镜像jgraph/drawio
容器名drawio
容器内端口8080
宿主机端口8016
对外入口Nginx HTTPS 反向代理
GitLab 回调路径https://draw.example.com/gitlab
可选能力PlantUML、图片导出、中文默认语言、自托管静态资源

整体链路如下:

flowchart LR
    browser["Browser"]
    nginx["Nginx HTTPS
draw.example.com:8716"] drawio["drawio
jgraph/drawio:8080"] plantuml["plantuml-server
:8080"] export["image-export
:8000"] gitlab["GitLab
OAuth + Repository API"] browser -->|HTTPS| nginx nginx -->|HTTP proxy_pass| drawio drawio -->|PLANTUML_URL| plantuml drawio -->|EXPORT_URL| export drawio -->|OAuth / Save / Open| gitlab

这里没有把 Draw.io 直接暴露到公网。公网入口只交给 Nginx,后端端口按实际拓扑限制来源。

1. 目录准备
#

创建部署目录:

mkdir -p /data/docker-compose/drawio/data/fonts
cd /data/docker-compose/drawio

建议目录结构:

/data/docker-compose/drawio/
├── compose.yaml
├── .env
├── PreConfig.js
└── data/
    └── fonts/

data/fonts 用于挂载自定义字体。PreConfig.js 用于观察和补丁 Draw.io 前端初始化配置,比如默认中文和 GitLab 开关。

2. GitLab OAuth 应用
#

Draw.io 保存到 GitLab 时需要 OAuth 应用。用管理员账号进入 GitLab 后台:

Admin Area -> Applications -> New application

按下面方式创建:

配置项
Namedrawio
Redirect URIhttps://draw.example.com/gitlab
Confidential按 GitLab 后台默认策略启用
Scopesapiread_repositorywrite_repository

创建后会拿到两项信息:

  • Application ID:写入 .envDRAWIO_GITLAB_ID
  • Secret:写入 .envDRAWIO_GITLAB_SECRET

这两个值只在部署机 .env 和密钥管理系统里保存。截图发布前至少确认没有 Secret;如果截图里出现 Secret,先在 GitLab 后台轮换后再发布。

GitLab OAuth 应用创建完成后,页面上能看到 Application ID、更新 Secret 按钮、回调 URL 和授权范围。生产环境里只需要把 ID 和 Secret 写入 .env

GitLab OAuth 应用配置示例

3. 环境变量
#

在部署目录创建 .env

DRAWIO_BASE_URL=https://draw.example.com
DRAWIO_VIEWER_URL=https://draw.example.com/js/viewer.min.js
DRAWIO_LIGHTBOX_URL=https://draw.example.com

DRAWIO_GITLAB_ID=CHANGE_ME_GITLAB_APPLICATION_ID
DRAWIO_GITLAB_SECRET=CHANGE_ME_GITLAB_APPLICATION_SECRET
DRAWIO_GITLAB_URL=https://gitlab.example.com
DRAWIO_CSP_HEADER="default-src 'self'; script-src 'self' https://storage.googleapis.com https://apis.google.com https://docs.google.com https://code.jquery.com 'unsafe-inline'; connect-src 'self' https://gitlab.example.com https://gitlab.com https://*.dropboxapi.com https://api.trello.com https://api.github.com https://raw.githubusercontent.com https://*.googleapis.com https://*.googleusercontent.com https://graph.microsoft.com https://*.1drv.com https://*.sharepoint.com https://*.google.com https://fonts.gstatic.com https://fonts.googleapis.com; img-src * data:; media-src * data:; font-src * about:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; frame-src 'self' https://*.google.com;"

EXPORT_URL=http://image-export:8000/
PLANTUML_URL=http://plantuml-server:8080/
DRAWIO_SELF_CONTAINED=1
DRAWIO_PUSHER_MODE=2
TZ=Asia/Shanghai

限制权限:

chmod 600 /data/docker-compose/drawio/.env

DRAWIO_GITLAB_URL 填 GitLab 站点根地址,例如 https://gitlab.example.comjgraph/drawio 容器启动脚本会基于这个值生成服务端 OAuth token 地址,即 ${DRAWIO_GITLAB_URL}/oauth/token。不要在这里再手动拼 /oauth/token,否则容易生成重复路径。

如果接入的是自建 GitLab,DRAWIO_CSP_HEADERconnect-src 里也要放行 GitLab 域名。否则页面能打开,但保存到 GitLab 时浏览器控制台可能出现 CSP 拦截。

4. Compose 配置
#

compose.yaml

services:
  drawio:
    image: jgraph/drawio
    container_name: drawio
    restart: always
    env_file:
      - .env
    ports:
      - "8016:8080"
    volumes:
      - ./data/fonts:/usr/share/fonts/drawio
      - ./PreConfig.js:/usr/local/tomcat/webapps/draw/js/PreConfig.js
    networks:
      - drawionet
    depends_on:
      - plantuml-server
      - image-export
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "2"

  plantuml-server:
    image: linkease/drawio-plantuml-server:2022121901
    container_name: plantuml-server
    restart: always
    environment:
      - TZ=Asia/Shanghai
    networks:
      - drawionet
    expose:
      - "8080"

  image-export:
    image: linkease/drawio-image-export:2022121901
    container_name: image-export
    restart: always
    environment:
      - TZ=Asia/Shanghai
    networks:
      - drawionet
    expose:
      - "8000"

networks:
  drawionet:
    driver: bridge

如果 Nginx 和 Draw.io 在同一台机器上,可以把端口收得更紧:

ports:
  - "127.0.0.1:8016:8080"

如果 Nginx 是独立入口机,后端 Draw.io 需要被入口机访问,就保留 8016:8080,同时用防火墙或安全组只允许 Nginx 入口机访问 8016

这里继续使用现场已有的 linkease/drawio-plantuml-server:2022121901linkease/drawio-image-export:2022121901。如果环境允许统一使用官方镜像,也可以把两个辅助服务替换成 jgraph/plantuml-serverjgraph/export-server,但替换前要重新验证 PlantUML 渲染和图片导出。

5. PreConfig.js
#

jgraph/drawio 每次启动都会生成 /usr/local/tomcat/webapps/draw/js/PreConfig.js。当 Compose 把 ./PreConfig.js 挂载到这个路径时,容器生成的内容会写回宿主机文件。

先创建空文件,避免 Docker 把同名路径创建成目录:

cd /data/docker-compose/drawio
touch PreConfig.js
docker compose up -d drawio
test -s PreConfig.js && echo "PreConfig generated"

如果需要默认中文,在容器启动后追加:

urlParams['lang'] = 'zh';

可以用命令补丁,刷新浏览器即可,不要为了这一步立即重启容器:

grep -q "urlParams\\['lang'\\] = 'zh'" PreConfig.js || \
  printf "\\nurlParams['lang'] = 'zh';\\n" >> PreConfig.js

这个补丁在下一次容器启动时会被入口脚本重新生成的内容覆盖。升级、重启或重建后,再执行一次上面的补丁命令即可。需要长期固化时,把补丁命令放到部署脚本里,或者维护一个派生镜像。

如果 GitLab 入口没有出现在 Draw.io 的保存菜单里,检查 PreConfig.js 里是否存在 GitLab 配置。环境变量方式会在启动阶段写入:

window.DRAWIO_GITLAB_URL = 'https://gitlab.example.com';
window.DRAWIO_GITLAB_ID = 'CHANGE_ME_GITLAB_APPLICATION_ID';

不要手工删除这些 GitLab 相关配置。PreConfig.js 里只会出现 GitLab URL 和应用 ID,Secret 会写入容器内 WEB-INF/gitlab_client_secret,不要把容器文件和日志原样贴到公开渠道。

6. 启动和基础验证
#

启动服务:

cd /data/docker-compose/drawio
docker compose up -d

查看状态:

docker compose ps

期望三个容器都是 Up

NAME              STATUS
drawio            Up
plantuml-server   Up
image-export      Up

检查 Draw.io HTTP:

curl -I http://127.0.0.1:8016

检查日志:

docker logs --tail 120 drawio

日志中应能看到 PreConfig.js 初始化输出,并且 GitLab 环境变量不为空。如果日志里没有 GitLab 相关配置,优先检查 .env 是否被容器读取。检查时不要把 Secret 打到终端:

docker exec drawio sh -lc '[ -n "$DRAWIO_GITLAB_ID" ] && [ -n "$DRAWIO_GITLAB_SECRET" ] && [ -n "$DRAWIO_GITLAB_URL" ] && echo "GitLab env OK"'

验证辅助服务的网络连通:

docker exec drawio sh -lc 'getent hosts plantuml-server && getent hosts image-export'

7. Nginx 反向代理
#

下面示例保留根路径代理,不做 /drawio/ 之类的子路径改写。Draw.io 的静态资源、OAuth 回调和前端路由都从根路径进入,最少踩坑。

如果 Nginx 和容器在同一台机器:

server {
    listen 8716 ssl http2;
    listen [::]:8716 ssl http2;
    server_name draw.example.com;

    ssl_certificate     /etc/nginx/certs/example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass http://127.0.0.1:8016;
    }
}

如果 Nginx 在入口机,Draw.io 在后端机器,把 proxy_pass 指向后端内网地址:

proxy_pass http://192.0.2.16:8016;

加载前检查语法:

nginx -t

重载:

systemctl reload nginx

外部验证:

curl -I https://draw.example.com:8716/

如果使用标准 443 端口,把 Nginx listen 和访问地址改成自己的 HTTPS 入口即可。

8. GitLab Diagrams.net 集成
#

如果要在 GitLab Wiki 或 Markdown 编辑器里直接打开自建 Draw.io,需要在 GitLab 管理后台启用 Diagrams.net:

Admin Area -> Settings -> General -> Diagrams.net

配置:

  • 勾选 Enable Diagrams.net
  • Diagrams.net URLhttps://draw.example.com,如果使用自定义端口则填 https://draw.example.com:8716
  • 保存配置。

GitLab 官方文档说明,自托管 GitLab 可以接入公共 diagrams.net,也可以接入本地部署的 diagrams.net。离线或内网环境通常选择后者。

GitLab 后台保存后,Diagrams.net 区块会保留当前配置的 Draw.io URL。这个 URL 必须和 Nginx 对外入口一致,否则 Wiki 里打开的仍然不是自建实例。

GitLab Diagrams.net URL 设置示例

验证方式:

  1. 进入一个测试项目的 Wiki。
  2. 新建或编辑页面。
  3. 插入 diagrams.net 图。
  4. 确认打开的是自建 Draw.io 地址。
  5. 保存后重新打开,确认 SVG 图能正常加载。

9. Review Gate
#

部署前先过这些检查:

检查项命令继续条件停止条件
Dockerdocker --version && docker compose version命令正常返回Docker/Compose 不可用
目录test -d /data/docker-compose/drawio目录存在且可写部署目录不可写
.envtest -f .env && grep '^DRAWIO_GITLAB_ID=' .env已配置 OAuth 应用仍是空值或占位值
权限stat -c '%a %n' .env.env 权限为 600普通用户可读
端口`ss -lntupgrep ‘:8016’
Nginxnginx -t配置语法通过语法失败
OAuth 回调GitLab 应用后台检查Redirect URI 是 /gitlab回调地址和入口不一致
敏感信息`find . -type f ! -name .env -print0 | xargs -0 grep -IlE ‘gloas-|glpat-|BEGIN PRIVATE’true`

只要 OAuth Secret 曾经出现在截图、聊天或仓库里,就先在 GitLab 后台重置,再更新 .env 并重启容器。

10. 功能验收
#

最小验收不要只看首页能打开,要覆盖存储、回调和辅助服务:

场景操作通过标准
首页打开 https://draw.example.com:8716/页面正常加载,无静态资源 404
GitLab 登录选择保存到 GitLab跳转 GitLab OAuth,授权后回到 /gitlab
仓库保存选择测试项目保存 .drawio.svgGitLab 仓库中出现文件
重新打开从 GitLab 打开刚才保存的图图形内容完整
PlantUML插入一段 PlantUML 图能渲染图形
图片导出导出 PNG/SVG/PDF文件可以下载,内容不为空
GitLab Wiki在 Wiki 插入 diagrams.net 图编辑器打开自建 Draw.io

排查时先看 Draw.io 日志,再看 Nginx access/error log,最后看 GitLab OAuth 应用配置。OAuth 回调不一致是最常见的问题。

11. 备份和回滚
#

Draw.io 本身接近无状态,关键配置在部署目录:

  • compose.yaml
  • .env
  • PreConfig.js
  • data/fonts

备份:

cd /data/docker-compose
tar czf drawio-backup-$(date +%F-%H%M%S).tar.gz drawio/compose.yaml drawio/.env drawio/PreConfig.js drawio/data/fonts

修改镜像、Nginx 或 OAuth 配置前先备份。回滚时恢复文件后重启:

cd /data/docker-compose/drawio
docker compose down
docker compose up -d

如果问题发生在 GitLab OAuth 应用配置,优先恢复 Redirect URI、Scopes 和 Secret,而不是回滚容器。

12. 常见问题
#

GitLab 保存菜单没有出现
#

先检查 DRAWIO_GITLAB_IDDRAWIO_GITLAB_SECRETDRAWIO_GITLAB_URL 是否进入容器。不要用 docker compose config 直接 grep Secret:

docker exec drawio sh -lc '[ -n "$DRAWIO_GITLAB_ID" ] && [ -n "$DRAWIO_GITLAB_SECRET" ] && [ -n "$DRAWIO_GITLAB_URL" ] && echo "GitLab env OK"'
docker exec drawio sh -lc 'grep -q "DRAWIO_GITLAB" /usr/local/tomcat/webapps/draw/js/PreConfig.js && echo "PreConfig GitLab OK"'

如果 PreConfig.js 被宿主机旧文件覆盖,需要重新从容器生成文件,或者把 GitLab 配置补回去。

OAuth 提示 redirect_uri 不匹配
#

GitLab 应用里的 Redirect URI 必须和入口完全一致:

https://draw.example.com/gitlab

如果入口使用 8716 端口,则应配置:

https://draw.example.com:8716/gitlab

协议、域名、端口和路径都要一致。

invalid_client 或 401
#

通常是 DRAWIO_GITLAB_IDDRAWIO_GITLAB_SECRETDRAWIO_GITLAB_URL 错误。DRAWIO_GITLAB_URL 填 GitLab 根地址,不要额外拼 /oauth/token

浏览器控制台出现 CSP 拦截
#

自建 GitLab 域名需要进入 DRAWIO_CSP_HEADERconnect-src。改完 .env 后重建容器:

docker compose up -d --force-recreate drawio

再刷新页面重试 GitLab 保存流程。

PlantUML 或导出失败
#

先检查容器互通:

docker exec drawio sh -lc 'getent hosts plantuml-server image-export'
docker logs --tail 100 plantuml-server
docker logs --tail 100 image-export

PLANTUML_URLEXPORT_URL 必须使用 Compose 网络里的服务名,不要写宿主机外部域名。

反向代理后静态资源 404
#

确认 Nginx 使用根路径代理:

location / {
    proxy_pass http://127.0.0.1:8016;
}

不要把 Draw.io 强行挂到子路径,除非已经验证过所有静态资源、OAuth 回调和前端路由。

13. 发布前清理
#

这类文档最容易泄露三样东西:OAuth Secret、GitLab 内部域名和后台截图里的凭据。发布前至少扫一遍 Markdown:

grep -nEi 'gloas-|glpat-|oauth2:|BEGIN (RSA|OPENSSH|PRIVATE)|Authorization:[[:space:]]*Bearer|client_secret|private_key|10\\.|172\\.(1[6-9]|2[0-9]|3[0-1])\\.|192\\.168\\.' drawio-docker-compose-deployment-blog.md || true

命中占位变量名是正常的,命中真实 token、真实内网地址或真实域名就停止发布。截图如果包含 Secret、私钥或不可公开的后台地址,先打码或轮换后再发布。

14. 参考链接
#

生产变更复盘 - 这篇文章属于一个选集。
7: 本文

相关文章

用 Docker Compose 部署 ALLinSSL 并接入 Nginx 反向代理
·564 字·3 分钟
SRE SSL TLS Nginx DevOps +4
生产 DNS 集群平滑升级复盘:dnsdist 与 Technitium 的滚动变更
·989 字·5 分钟
SRE DNS SRE DevOps Dnsdist +3
用 Docker Compose 部署 Scrutiny:NVMe 健康监控的最小可用方案
·772 字·4 分钟
SRE NVMe SMART SRE DevOps +3