jgraph / drawio-desktop

Official electron build of draw.io
https://www.diagrams.net
Apache License 2.0
50.65k stars 5.02k forks source link

Support command line (headless) mode inside docker container #127

Closed cgraupner-bm closed 2 years ago

cgraupner-bm commented 5 years ago

Request

It would be great if the draw.io app would run headless inside a docker container in command line mode for export to pdf or any other export format.

What I did so far

I create a docker contrainer with the following Dockerfile:

FROM node:10-jessie-slim
RUN apt-get update \
  && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
   libx11-xcb1 libatk-bridge2.0 libgtk-3-0 libnss3 libxss1 libasound2\
   graphviz \
   build-essential \
   python-pip \
   gconf2 gconf-service libnotify4 libappindicator1 xvfb xauth \
  && apt-get purge -y --auto-remove apt-transport-https \
  && apt-get clean \
  && rm -rf /tmp/* /var/lib/apt/lists/* /var/cache/apt/archives/*
RUN wget -q -O /tmp/draw-io.deb https://github.com/jgraph/drawio-desktop/releases/download/v10.8.0/draw.io-amd64-10.8.0.deb \
  && dpkg -i /tmp/draw-io.deb \
  && rm -rf /tmp/*
RUN pip install -U mkdocs pymdown-extensions
RUN npm install -g xvfb-maybe

Build with:

docker build -t draw-io-test .

and run with

docker run --rm  -v $(pwd):$(pwd) -w "$(pwd)" "/usr/local/bin/draw.io" -a -x -e -t -o "output.pdf" "input.drawio"

Unfortunately the draw.io app seem to require dbus running, so I get the following error preventing a successful run of draw.io in headless mode:

/usr/local/bin/draw.io: /lib/x86_64-linux-gnu/libdbus-1.so.3: no version information available (required by /usr/local/bin/draw.io)

I tried to run it with xvfb-run as some docs for electron suggest to use it to run electron in headless mode, but the error message is still there.

kanaka commented 5 years ago

I just built my own docker image with drawio only to discover several issues that prevent clean dockerization. I would like to dockerize drawio because it is part of my latex pipeline and I already have all my latex and image conversion tools in the container. I would like to have a portable pipeline that isn't sensitive to which particular system I happen to be on, is easy to get running on new systems, is versioned so I know what versions of the tools I am using, etc.

The first problem is that drawio wants the chrome-sandbox command to be setuid. This is easy to fix but this probably shouldn't be required for command line usage. I suspect this was introduced with recent security improvement to the desktop mode of draw.io.

RUN chmod +4755 /opt/draw.io/chrome-sandbox

The next problem is that drawio wants to put itself in a network namespace. Which is great for normal usage, but when running inside an existing docker container this extra namespacing is probably not desirable. This can be worked around by add SYS_ADMIN capability when the container is running but SYS_ADMIN is a pretty wide capability which means in some ways I am now less secure because I'm being forced to run a docker container with wide-open security posture (i.e. I have to trust draw.io and the other stuff in the container). I would prefer that draw.io have the option to not require this:

docker run --cap-add SYS_ADMIN ...

As noted by @cgraupner-bm, the next problem is that even in command line mode, draw.io still wants to connect to X. This can be worked around with xvfb-run.

The next issue is that having HOME set to / causes drawio to hang on start even for pure command line usage:

$ xvfb-run drawio --help
A JavaScript error occurred in the main process
Uncaught Exception:
Error: Failed to get 'appData' path
    at App.app._setDefaultAppPaths (/opt/draw.io/resources/electron.asar/browser/api/app.js:54:43)
    at Object.<anonymous> (/opt/draw.io/resources/electron.asar/browser/init.js:133:5)
    at Module._compile (internal/modules/cjs/loader.js:786:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:798:10)
    at Module.load (internal/modules/cjs/loader.js:645:32)
    at Function.Module._load (internal/modules/cjs/loader.js:560:12)
    at Function.Module.runMain (internal/modules/cjs/loader.js:850:10)
    at internal/main/run_main_module.js:17:11
Home directory not accessible: Permission denied
[[[[ HANGS HERE ]]]]

Settting HOME to /tmp will still complain about "Home directory not accessible: Permission denied " but at least it now runs.

Here is what the relevant snippet of my Dockerfile looks like:

FROM ubuntu:19.04
...
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install curl libnotify4 libnss3 libappindicator3-1 libsecret-1-0
RUN curl -LO https://github.com/jgraph/drawio-desktop/releases/download/v11.1.4/draw.io-amd64-11.1.4.deb && \
    dpkg -i draw.io-amd64-11.1.4.deb && \
    rm draw.io-amd64-11.1.4.deb
RUN chmod +4755 /opt/draw.io/chrome-sandbox

RUN apt-get install -y xvfb

RUN echo "#!/bin/sh\nxvfb-run /usr/bin/drawio \"\${@}\"" > /usr/local/bin/drawio && \
    chmod +x /usr/local/bin/drawio

ENV HOME /tmp

Most of the issues I would consider hacks, but the necessity of using --cap-add SYS_ADMIN is the biggest issue that is most pressing at least IMO.

davidjgraph commented 5 years ago

Please one issue per issue, otherwise it gets messy when x out of y parts of an issue are completed and we start needing sub tick lists to track what is and isn't done.

This issue is a request for headless support of this app.

kanaka commented 5 years ago

@davidjgraph I've filed separate tickets as requested.

You might want to add a contribution guideline or issue template to set expectations about issue filing. I searched for them but didn't find any so I went with my own preference as maintainer of several projects. For my own projects I usually create tick-lists myself when people file higher-level feature/bugs because I usually have a better idea of what the actual sub-tasks are that are needed and tick-lists show up on the main issues page which helps knowing progress and I find having lots of outstanding issues to be hard to manage and keep track of. I typically prefer fewer issues with sub-tasks as tick lists rather than lots of related issues as github doesn't yet provide a good way for linking issues as sub-tasks to keep them organized like some other ticketing system do. E.g. https://github.com/kanaka/mal/issues/166.

My intention in listing all the problems I ran into along with workarounds is so that anybody else looking to do the same thing (command-line usage from docker image) would have everything they need in one place. I apologize if that came across as noise.

davidjgraph commented 5 years ago

@kanaka Thanks for doing that. Yeah, we are missing a lot of guideline docs in the project, we need an issue to track those ;)

The problem I have with Github is it lacks the tooling to properly sub-task. Much as I hate Jira, it does things like sub-tasks better. I'm not sure if the original poster meant for it to be a generic docker thread or was really just asking for headless mode.

Just for info, we do have a puppetter based image export, https://github.com/jgraph/draw-image-export2, that the web version uses when the operation isn't possible client-side. I wonder if that might be better suited in this case. It lacks a command line interface, but we can add that.

tomkludy commented 4 years ago

Following the comments above I was able to build a docker container that exposes drawio Desktop as a RESTful API:

https://hub.docker.com/r/tomkludy/drawio-renderer

Hopefully this can be of help to others; it is already functioning in my own build pipeline.

davidjgraph commented 2 years ago

@tomkludy 's repo looks like the best solution, we'll close this issue.

ebousse commented 2 years ago

For those interested, I also made a (very) simple docker image here, Fedora based, to be used in CLI only, with good handling of fonts: https://gitlab.univ-nantes.fr/bousse-e/docker-drawio

Published in a registry and thus usable in docker as docker-registry.univ-nantes.fr/bousse-e/docker-drawio

I make this image mostly to use it in a CI pipeline, where I automatically convert a whole batch of drawio files into PNGs.