Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running on alpine #24

Closed
PJUllrich opened this issue Jul 3, 2019 · 8 comments
Closed

Running on alpine #24

PJUllrich opened this issue Jul 3, 2019 · 8 comments

Comments

@PJUllrich
Copy link
Contributor

PJUllrich commented Jul 3, 2019

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 [email protected] [email protected] -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();
...
@speeddragon
Copy link
Contributor

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 [email protected] [email protected] -g

Do we really need all this flags ?

["--no-sandbox", "--disable-software-rasterizer", "--headless", "--disable-gpu", "--disable-dev-shm-usage"] });

@PJUllrich
Copy link
Contributor Author

The [email protected] 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 [email protected] 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 if puppeteer-pdf is run as root. This flag can be omitted, if a dedicated user is added as explained in the toubleshooting section.
  • --headless is needed if puppeteer-pdf is run on a server without display/screen. Can be omitted, if puppeteer-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 the OpenGL ES and EGL libraries libGLESv2 and libEGL which are needed by chromium for rendering are only available on Debian, but not for alpine. The alpine versions of these libraries mesa-egl and mesa-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 :)

@speeddragon
Copy link
Contributor

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!

@PJUllrich
Copy link
Contributor Author

Please verify whether this works for you. I added a link to this issue to the Readme in #25

@speeddragon
Copy link
Contributor

speeddragon commented Jul 7, 2019

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 [email protected] [email protected] -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"]

@PJUllrich
Copy link
Contributor Author

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 [email protected] [email protected] -g

# After
RUN npm install [email protected] [email protected] -g

I already updated my Dockerfile in my first post.

@speeddragon
Copy link
Contributor

Is that a problem that happen right now ? When I tested I didn't have any issue generating the PDF.

@PJUllrich
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants