I would allow me to start the node server. But --cap-add=SYS_ADMIN adds linux admin permissions required in my application (puppeteer). MAybe there is a way to add these permissions in the Dockerfile?
You should have full root access to your VMs by default. The arguments came to tweak Docker don’t apply to your app on Fly. Are you getting permission errors?
I get an Unable to open X display error without adding SYS_ADMIN. When google-chrome-stable is run it barfs about some permissions issue that ends up leading to this inability to locate it display. Under the hood I think puppeteer is trying to use xvfb.
I get an Unable to open X display error without adding SYS_ADMIN. When google-chrome-stable is run it barfs about some permissions issue that ends up leading to this inability to locate it display. Under the hood I think puppeteer is trying to use xvfb.
I think what is going on here is my setup starts puppeteer with Chrome using CMD ["google-chrome-stable"]. PUPPETEER_SKIP_CHROMIUM_DOWNLOAD is false. This enables full media support (at least that’s what I assume is happening). However your example app uses:
Does fly.io provide a Chrome bin? If so I can modify my setup for fly. However, it would be cool to be able to use the best practice container provided by Google.
I just got around to revisiting this. In looking at fly’s sample it looks like PUPPETEER_EXECUTABLE_PATH must be supplied by the platform. I’ve tried to implement puppeteer-core to avoid the need to pass system capabilities in docker run. I am getting the following error:
// puppeteer-core doesn't take into account PUPPETEER_* env variables.
if (!launcher._isPuppeteerCore) {
const executablePath = process.env.PUPPETEER_EXECUTABLE_PATH ||
process.env.npm_config_puppeteer_executable_path ||
process.env.npm_package_config_puppeteer_executable_path;
if (executablePath) {
const missingText = !fs.existsSync(executablePath)
? 'Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: ' +
executablePath
: null;
return { executablePath, missingText };
}
}
Puppeteer resolves the executable path as follows:
// puppeteer-core doesn't take into account PUPPETEER_* env variables.
if (!launcher._isPuppeteerCore) {
const executablePath = process.env.PUPPETEER_EXECUTABLE_PATH ||
process.env.npm_config_puppeteer_executable_path ||
process.env.npm_package_config_puppeteer_executable_path;
if (executablePath) {
const missingText = !fs.existsSync(executablePath)
? 'Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: ' +
executablePath
: null;
return { executablePath, missingText };
}
}
Do you have undocumented support for a browser executable by setting PUPPETEER_EXECUTABLE_PATH in your environments? If not you really need to add support for container capabilities like AWS did.
Kurt, thanks for responding. Full docker file is below:
FROM node:16-slim
MAINTAINER Dorian Smiley, dsmiley@codestrap.me
WORKDIR /usr/app
# Install latest chrome dev package and fonts to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others)
# Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer
# installs, work.
RUN apt-get update \
&& apt-get install -y wget gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y xvfb \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# If running Docker >= 1.13.0 use docker run's --init arg to reap zombie processes, otherwise
# uncomment the following lines to have `dumb-init` as PID 1
# ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_x86_64 /usr/local/bin/dumb-init
# RUN chmod +x /usr/local/bin/dumb-init
# ENTRYPOINT ["dumb-init", "--"]
# Uncomment to skip the chromium download when installing puppeteer. If you do,
# you'll need to launch puppeteer with:
# browser.launch({executablePath: 'google-chrome-stable'})
# ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
COPY package.json .
# COPY package-lock.json .
COPY index.html .
COPY favicon.ico .
COPY index.js .
COPY ./css ./css
COPY ./img ./img
COPY ./program ./program
COPY server.js .
COPY ./ssr ./ssr
# Install puppeteer so it's available in the container.
RUN npm install \
# Add user so we don't need --no-sandbox.
# same layer as npm install to keep re-chowned files from using up several hundred MBs more space
&& groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /usr/app/node_modules
# allow the pptruser write permissions to the container
RUN chown -R pptruser:pptruser /usr/app
RUN chmod 755 /usr/app
# Run everything after as non-privileged user.
USER pptruser
ENV PORT=80
ENV DISPLAY=1.0
ENV DEBUG='codestrap-website:*'
EXPOSE 3000
EXPOSE 80
EXPOSE 443
CMD ["google-chrome-stable"]
This is mostly taken from Google’s official docker guide for Puppeteer. The error is Unable to open X display which is described in this stack overflow issue. However xvfb requires --cap-add=SYS_ADMIN.
Also, the error I get when running the fly example app for puppeteer is:
Error: Could not find browser revision 756035. Run "npm install" or "yarn install" to download a browser binary.
at ChromeLauncher.launch (/Users/doriansmiley/workspace/puppeteer-js-renderer/node_modules/puppeteer-core/lib/Launcher.js:59:23)
at async /Users/doriansmiley/workspace/puppeteer-js-renderer/server.js:40:25
Hey Michael, thanks for responding. " If you absolutely trust the content you open in Chrome, you can launch Chrome with the --no-sandbox argument". This is a website publishing service for a framework I created. I don’t trust the content passing through the service. That said I’ll add the no-sandbox option and see if it resolves the issue.
Disabling the sandbox is the recommended way to run on Heroku and Lambda sadly. But since you have root access to the machine on Fly you should be able to configure it using one of the other methods. We also have an upcoming api that lets you launch and destroy VMs very quickly which you could use to run untrusted code safely.
hey Michael, I am having numerous issues migrating this project so it will run on Fly. I tried implementing an entry point script but I could not get it to work. Could you checkout the repo and see if you can get this setup to work on flow. codestrap/infra/fly/website at master · doriansmiley/codestrap · GitHub
I may have made a breakthrough. I just changed the command to CMD ["npm", "start"]. This removes the need for me to pass node -e \"cat server.js\" in docker run. I’m deploying now. Is there a way to specify port mappings in fly? I default to port 3000 and want to map 443:3000