Running on alpine
PJUllrich opened this issue · comments
I encountered a range of dependency problems, when I tried to run this in an alpine
docker container. I wanted to share how to make this run with (elixir) puppeteer-pdf=1.0.3
and (node) puppeteer-pdf=1.2.0
. The main source of making this work was the documentation on the official Puppeteer GitHub page.
Prepare your alpine
Docker container
I used this Dockerfile
for building the container:
RUN apk add --update
RUN apk update && apk upgrade && \
echo @edge http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \
echo @edge http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \
apk add --no-cache \
nodejs \
nodejs-npm \
inotify-tools \
chromium@edge=~73.0.3683.103 \
nss@edge \
freetype@edge \
freetype-dev@edge \
harfbuzz@edge \
ttf-freefont@edge
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
RUN npm install puppeteer-pdf@1.2.0 puppeteer@1.12.2 -g
COPY assets/config/puppeteer-pdf.js /usr/lib/node_modules/puppeteer-pdf
Set launch
arguments in puppeteer-pdf.js
Change the following line in your /usr/lib/node_modules/puppeteer-pdf/puppeteer-pdf.js
file:
# Before
const browser = await puppeteer.launch({args: ["--no-sandbox"] });
# After
const browser = await puppeteer.launch({executablePath: '/usr/bin/chromium-browser', args: ["--no-sandbox", "--disable-software-rasterizer", "--headless", "--disable-gpu", "--disable-dev-shm-usage"] });
Now, you "should" be able to use the (elixir) puppeteer-pdf
library on alpine
as well!
Problems encountered
Just for documentation purposes, I'm adding some error logs that I've encountered until I found this solution.
Without settting the --disable-gpu
and --disable-software-rasterizer
flag
Failed to load /usr/lib/chromium/swiftshader/libGLESv2.so: Error loading shared library /usr/lib/chromium/swiftshader/libGLESv2.so: No such file or directory
Bonus: Insert your own .css
file.
In your puppeteer-pdf.js
file, add the following line:
...
# Add the following line:
await page.addStyleTag({path: '/src/priv/static/css/app.css'}); // <--- Add this line
await page.pdf(options);
await browser.close();
...
Hi @PJUllrich, thanks for sharing your configuration for the Docker Alpine version. I will try it to check if everything is working, but can you explain if the versions set on your example need to be fixed, or can be the last version ?
chromium@edge=~73.0.3683.103 \
...
RUN npm install puppeteer@1.12.2 puppeteer-pdf@1.2.0 -g
Do we really need all this flags ?
["--no-sandbox", "--disable-software-rasterizer", "--headless", "--disable-gpu", "--disable-dev-shm-usage"] });
The puppeteer@1.12.2
version needs to be fixed according to the troubleshooting section. I also fixed the puppeteer-pdf
version here so that this configuration won't break if for whatever reason puppeteer-pdf
doesn't support puppeteer@1.12.2
anymore.
Unfortunately, these flags are necessary in order to make this run on alpine
. I tested removing any of them and puppeteer-pdf
won't start if any is removed. In the following a short explanation why these flags are needed:
--no-sandbox
is needed ifpuppeteer-pdf
is run asroot
. This flag can be omitted, if a dedicated user is added as explained in the toubleshooting section.--headless
is needed ifpuppeteer-pdf
is run on a server without display/screen. Can be omitted, ifpuppeteer-pdf
is run on a local development machine with desktop (i.e. your laptop/computer)--disable-dev-shm-usage
is recommended by the troubleshooting section since:
Docker runs a container with a /dev/shm shared memory space 64MB. This is typically too small for Chrome and will cause Chrome to crash when rendering large pages
--disable-gpu
and--disable-software-rasterizer
are related to the issue that theOpenGL ES
andEGL
librarieslibGLESv2
andlibEGL
which are needed bychromium
for rendering are only available on Debian, but not foralpine
. Thealpine
versions of these librariesmesa-egl
andmesa-gles
apparently don't fix the issue. Therefore, the only option as of now is to disable the gpu rendering with these flags.
I hope this answers your questions :)
Yes, thanks for the detailed answer. I will check if everything is working, if you want you can open a PR to include this information you have written in the README.md, or I will add it later.
Thanks!
Please verify whether this works for you. I added a link to this issue to the Readme in #25
Thanks, I finally got time to test it. I notice that in your example you use COPY assets/config/puppeteer-pdf.js /usr/lib/node_modules/puppeteer-pdf
to do the change on puppeteer-pdf.js
. I think it is better to used sed
to automate that action:
RUN sed -i 's~const browser = await puppeteer.launch({ args: \["--no-sandbox"\] });~const browser = await puppeteer.launch({executablePath: "/usr/bin/chromium-browser", args: \["--no-sandbox", "--disable-software-rasterizer", "--headless", "--disable-gpu", "--disable-dev-shm-usage"\] });~g' /usr/lib/node_modules/puppeteer-pdf/puppeteer-pdf.js
Puppeteer-pdf executable will be on: /usr/bin/puppeteer-pdf
Here my Dockerbuild
sample.
#
# Stage 1
#
FROM bitwalker/alpine-elixir-phoenix:1.8.1 as builder
ENV MIX_ENV=prod
WORKDIR /myapp
# Umbrella
COPY mix.exs mix.lock ./
COPY config config
RUN mix local.hex --force && \
mix local.rebar --force
# Apps
COPY lib lib
COPY priv priv
RUN mix do deps.get, deps.compile
WORKDIR /myapp
COPY rel rel
RUN mix distillery.release --env=prod --verbose
#
# Stage 2
#
FROM bitwalker/alpine-elixir-phoenix:1.8.1
RUN apk add --update
RUN apk update && apk upgrade && \
echo @edge http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \
echo @edge http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \
apk add --no-cache \
nodejs \
nodejs-npm \
inotify-tools \
chromium@edge=~73.0.3683.103 \
nss@edge \
freetype@edge \
freetype-dev@edge \
harfbuzz@edge \
ttf-freefont@edge
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
RUN npm install puppeteer-pdf@1.2.0 puppeteer@1.12.2 -g
RUN sed -i 's~const browser = await puppeteer.launch({ args: \["--no-sandbox"\] });~const browser = await puppeteer.launch({executablePath: "/usr/bin/chromium-browser", args: \["--no-sandbox", "--disable-software-rasterizer", "--headless", "--disable-gpu", "--disable-dev-shm-usage"\] });~g' /usr/lib/node_modules/puppeteer-pdf/puppeteer-pdf.js
WORKDIR /myapp
COPY --from=builder /myapp/_build/prod/rel/myapp/releases/*/myapp.tar.gz .
RUN tar zxf myapp.tar.gz && rm myapp.tar.gz
CMD ["/myapp/bin/myapp", "foreground"]
Please be aware that you need to turn around the npm install
packages. Otherwise, the puppeteer-pdf
package will install a newer version of puppeteer
and this will break the puppeteer -> chrome
version dependency. So, I'd recommend to change your Dockerbuild like this:
# Before
RUN npm install puppeteer@1.12.2 puppeteer-pdf@1.2.0 -g
# After
RUN npm install puppeteer-pdf@1.2.0 puppeteer@1.12.2 -g
I already updated my Dockerfile in my first post.
Is that a problem that happen right now ? When I tested I didn't have any issue generating the PDF.
Yes, it occurred only now. I cannot pinpoint why this happened now other than observing that puppeteer-pdf
installed a higher version of puppeteer
. PDF generation simply timed out in this case. It's weird, but this "should" solve it.