jlandure / alpine-chrome

Chrome Headless docker images built upon alpine official image
https://hub.docker.com/r/zenika/alpine-chrome
Apache License 2.0
1.89k stars 245 forks source link

Help adding custom fonts #155

Open Joebayld opened 3 years ago

Joebayld commented 3 years ago

I'm trying to add a Google font to zenika/alpine-chrome:with-puppeteer but am not having much luck. Has anyone successfully done this?

For example, I'm trying to install: https://fonts.google.com/specimen/Montserrat

The main issue seems to be that I can't perform wget. I tried to install it with apk or even apt-get, but those give me errors as well.

FROM zenika/alpine-chrome:with-puppeteer

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD 1
ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/chromium-browser

# this fails
RUN apk --no-cache add \
    fontconfig \
    wget \

ENV NODE_ENV=production
WORKDIR /usr/src/app
COPY package*.json ./
COPY tsconfig*.json ./
COPY ./src ./src

RUN npm install
RUN npm run build 
EXPOSE 8080
CMD [ "node", "dist/index.js"]

This script throws the error `#5 1.040 ERROR: Unable to lock database: Permission denied

5 1.041 ERROR: Failed to open apk database: Permission denied`..

Thanks.

jlandure commented 3 years ago

Hi @Joebayld 👋

Thanks for this issue. 👍

I think you can achieve easily the installation of your font. I don't see the code where you are downloading the font but the Unable to lock database: Permission denied is quite easy to resolve.

First you need to change the user before installing new alpine packages.

FROM zenika/alpine-chrome:with-puppeteer

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD 1
ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/chromium-browser

USER root
RUN apk --no-cache add \
    fontconfig \
    wget \

USER chrome
...

It should work! Please keep me updated! 👍 You can find an example with the with-node Dockerfile

And don't forget to use the good user to install your files.

COPY --chown=chrome package.json package-lock.json ./
RUN npm install
COPY --chown=chrome . ./
Joebayld commented 3 years ago

Hey @jlandure

Thanks for your help!! It took a few tries but looks like I got it. I also found that wget was already installed so I just skipped that! Here's my final script - how's this look?

FROM zenika/alpine-chrome:with-puppeteer

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD 1
ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/chromium-browser
ENV NODE_ENV=production

# install google fonts
USER root
RUN wget 'https://fonts.google.com/download?family=Roboto|Montserrat' -O googlefonts.zip
RUN unzip googlefonts.zip -d /usr/share/fonts/googlefonts/
RUN rm -f googlefonts.zip
USER chrome

# refresh the font cache
RUN fc-cache -fv

# copy npm / src files
WORKDIR /usr/src/app
COPY --chown=chrome package*.json ./
COPY --chown=chrome tsconfig*.json ./
COPY --chown=chrome ./src ./src

RUN npm install
RUN npm run build 
EXPOSE 8080
CMD [ "node", "dist/index.js"]

One thing I also learned is that I can install them to the user fonts instead of the root via the following. I'm not sure if there is any benefit though.

# install google fonts to user directory
RUN wget 'https://fonts.google.com/download?family=Roboto|Montserrat' -O googlefonts.zip
RUN unzip googlefonts.zip -d ~/.fonts
RUN rm -f googlefonts.zip

I'm also curious the need for --chown=chrome? Isn't the current user already set to chome? It did work fine before but I'm rather new to this and am learning!

Thanks again, Joe

jlandure commented 3 years ago

Hey @Joebayld

Glad you succeed! 🎉

For the chown flag, please use this ref https://github.com/moby/moby/issues/34819 or this page. To sum up, it is a way to ensure the copied files are used with the good user (not the one you have on your laptop/outside the container). To check that, please do a ls -l in your folder

-rw-r--r--    1 chrome   chrome         452 Feb  2 08:26 package.json

FYI, a good practice is to do the npm install before copying your src to maximize the Docker layer cache. Another good practice is to sum up operations in one RUN sentence to create only one layer. And you don't need the with-puppeteer version, just the with-node.

So a good way to proceed will be:

FROM zenika/alpine-chrome:with-node

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD 1
ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/chromium-browser
ENV NODE_ENV=production
WORKDIR /usr/src/app

# install and refresh the font cache
RUN wget 'https://fonts.google.com/download?family=Roboto|Montserrat' -O googlefonts.zip \
  && unzip googlefonts.zip -d ~/.fonts \
  && rm -f googlefonts.zip \
  && fc-cache -fv

# copy npm / src files
COPY --chown=chrome package*.json tsconfig*.json ./
RUN npm install

COPY --chown=chrome ./src ./src
RUN npm run build 
EXPOSE 8080
CMD [ "node", "dist/index.js"]

Please tell me if it works! And I invite you to create a fully working example in the dedicated folder to help the community. 😊

Have a good day! 👍

Joebayld commented 3 years ago

Thanks again for the tips @jlandure.

I was using the with-puppeteer versions and using it as a devDependency so it didn't get installed with docker (and thus used the global version) - but I'll switch it over to the with-node version now and use a dependency instead.

Also, in doing this switch I realized that 20min ago was a major puppeteer release! 😅 So I'm sure you're going to want to update the included chrome version as they updated it. https://github.com/puppeteer/puppeteer/releases/tag/v6.0.0

I will absolutely make a PR for a fully working example. I just need to fine tune it a little more.

Joe

jlandure commented 3 years ago

Hello @Joebayld 👋

This project is using Alpine and the release of Chromium is described here FYI, Alpine supports only Chrome 86 at the moment.

We are very welcome to make a PR with your fully working example! 🎉 Thanks a lot!

jlandure commented 3 years ago

Hi @Joebayld 👋

How are you? Did you find the time to contribute with your working example? 👍 It could be very useful for the community. 😊

Have a good day. ☀️

jlandure commented 3 years ago

Hi @Joebayld

No news for your contribution? 😊