alixaxel / chrome-aws-lambda

Chromium Binary for AWS Lambda and Google Cloud Functions
MIT License
3.2k stars 292 forks source link

[REQUEST] Include ARM_64 binaries #241

Open villetuomaala opened 3 years ago

villetuomaala commented 3 years ago

What would you like to have implemented?

Include ARM_64 architecture supported binaries

Why would it be useful?

AWS Lambda now supports ARM_64 architecture but chrome-aws-lambda only ships with x86_64 binaries and is incompatible with this new Lambda feature.

Or am I misunderstanding something?

ghost commented 2 years ago

I compiled Chromium 97.0.4666.0 for ARM64 together with some minor patches to get it working on AWS Lambda (NodeJS 14).

Steps to get it working:

const browser = await chromium.launch({
     executablePath: "/opt/chromium",
     args: ["--no-zygote", "--in-process-gpu", "--single-process"]
   });

Let me know if you have troubles.

villetuomaala commented 2 years ago

Thank you @lifesaverluke for your help but unfortunately I wasn't able to to get this working. I used the the binaries as Lambda layer but on every invoke I receive an error:

{
    "errorType": "Error",
    "errorMessage": "Failed to launch the browser process! spawn /opt/chromium EACCES\n\n\nTROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md\n",
    "stack": [
        "Error: Failed to launch the browser process! spawn /opt/chromium EACCES",
        "",
        "",
        "TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md",
        "",
        "    at onClose (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:197:20)",
        "    at ChildProcess.<anonymous> (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:189:85)",
        "    at ChildProcess.emit (events.js:400:28)",
        "    at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)",
        "    at onErrorNT (internal/child_process.js:467:16)",
        "    at processTicksAndRejections (internal/process/task_queues.js:82:21)"
    ]
}

EACCES refers to permission issue on OS so I made a new Lambda layer archive where with -rwxrwxrwx permissons on all files, and still the same error exists.

The browser init I use is:

const initBrowser = async () => {
  return await chromium.puppeteer.launch({
    defaultViewport: chromium.defaultViewport,
    //executablePath: await chromium.executablePath,
    executablePath: "/opt/chromium",
    headless: chromium.headless,
    ignoreHTTPSErrors: true,
    acceptInsecureCerts: true,
    dumpio: true,
    args: [...chromium.args,  
      '--ignore-certificate-errors', 
      '--ignore-certificate-errors-spki-list', 
      '--enable-features=NetworkService']
  });
};

And I also tried with those "--no-zygote", "--in-process-gpu", "--single-process" appended. Maybe there are some lib files missing from the package?

ghost commented 2 years ago

Thank you @lifesaverluke for your help but unfortunately I wasn't able to to get this working. I used the the binaries as Lambda layer but on every invoke I receive an error: { "errorType": "Error", "errorMessage": "Failed to launch the browser process! spawn /opt/chromium EACCES\n\n\nTROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md\n", "stack": [ "Error: Failed to launch the browser process! spawn /opt/chromium EACCES", "", "", "TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md", "", " at onClose (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:197:20)", " at ChildProcess.<anonymous> (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:189:85)", " at ChildProcess.emit (events.js:400:28)", " at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)", " at onErrorNT (internal/child_process.js:467:16)", " at processTicksAndRejections (internal/process/task_queues.js:82:21)" ] }

EACCES refers to permission issue on OS so I made a new Lambda layer archive where with -rwxrwxrwx permissons on all files, and still the same error exists.

The browser init I use is: const initBrowser = async () => { return await chromium.puppeteer.launch({ defaultViewport: chromium.defaultViewport, //executablePath: await chromium.executablePath, executablePath: "/opt/chromium", headless: chromium.headless, ignoreHTTPSErrors: true, acceptInsecureCerts: true, dumpio: true, args: [...chromium.args, '--ignore-certificate-errors', '--ignore-certificate-errors-spki-list', '--enable-features=NetworkService'] }); }; And I also tried with those "--no-zygote", "--in-process-gpu", "--single-process" appended. Maybe there are some lib files missing from the package?

Weird! I'll investigate and send an update here as soon as I've found the problem.

ghost commented 2 years ago

@villetuomaala Fixed!

For some reason there was an extra /opt/chromium/chromium dir in the zipfile when used as layer, resulting in the error that you mentioned.

I uploaded a new version with a fix :-) Let me know if this works!

AliasIO commented 2 years ago

I'm trying this with puppeteer-core@10.4.0 on Lambda and I'm seeing this error when attempting to launch the browser:

Error: Protocol error (Target.setDiscoverTargets): Target closed.
    at /opt/nodejs/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:71:63
    at new Promise (<anonymous>)
    at Connection.send (/opt/nodejs/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:70:16)
    at Function.create (/opt/nodejs/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Browser.js:118:26)
    at ChromeLauncher.launch (/opt/nodejs/node_modules/puppeteer-core/lib/cjs/puppeteer/node/Launcher.js:109:56)

I'm also seeing this when re-attempting the launch:

ErrorEvent {
  target: WebSocket {
    _events: [Object: null prototype] { open: [Function], error: [Function] },
    _eventsCount: 2,
    _maxListeners: undefined,
    _binaryType: 'nodebuffer',
    _closeCode: 1006,
    _closeFrameReceived: false,
    _closeFrameSent: false,
    _closeMessage: '',
    _closeTimer: null,
    _extensions: {},
    _protocol: '',
    _readyState: 3,
    _receiver: null,
    _sender: null,
    _socket: null,
    _bufferedAmount: 0,
    _isServer: false,
    _redirects: 0,
    _url: 'ws://127.0.0.1:36089/devtools/browser/0fd89080-24a1-439e-955a-84de431d7f9e',
    _req: null,
    [Symbol(kCapture)]: false
  },
  type: 'error',
  message: 'socket hang up',
  error: Error: socket hang up
      at connResetException (internal/errors.js:628:14)
      at Socket.socketOnEnd (_http_client.js:499:23)
      at Socket.emit (events.js:412:35)
      at Socket.emit (domain.js:470:12)
      at endReadableNT (internal/streams/readable.js:1317:12)
      at processTicksAndRejections (internal/process/task_queues.js:82:21) {
    code: 'ECONNRESET'
  }
}

These are the arguments I'm using:

[
  '--no-sandbox',
  '--no-zygote',
  '--disable-gpu',
  '--ignore-certificate-errors',
  '--allow-running-insecure-content',
  '--disable-web-security',
  '--disable-setuid-sandbox',
  '--disable-dev-shm-usage',
  '--single-process',
  '--user-data-dir="/tmp/chromium"'
]

Puppeteer is expecting Chromium version 901912, which seems to be version 93.0.4577.0. Might that be why it's not working?

ghost commented 2 years ago

I'm trying this with puppeteer-core@10.4.0 on Lambda and I'm seeing this error when attempting to launch the browser:

Error: Protocol error (Target.setDiscoverTargets): Target closed.
    at /opt/nodejs/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:71:63
    at new Promise (<anonymous>)
    at Connection.send (/opt/nodejs/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:70:16)
    at Function.create (/opt/nodejs/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Browser.js:118:26)
    at ChromeLauncher.launch (/opt/nodejs/node_modules/puppeteer-core/lib/cjs/puppeteer/node/Launcher.js:109:56)

I'm also seeing this when re-attempting the launch:

ErrorEvent {
  target: WebSocket {
    _events: [Object: null prototype] { open: [Function], error: [Function] },
    _eventsCount: 2,
    _maxListeners: undefined,
    _binaryType: 'nodebuffer',
    _closeCode: 1006,
    _closeFrameReceived: false,
    _closeFrameSent: false,
    _closeMessage: '',
    _closeTimer: null,
    _extensions: {},
    _protocol: '',
    _readyState: 3,
    _receiver: null,
    _sender: null,
    _socket: null,
    _bufferedAmount: 0,
    _isServer: false,
    _redirects: 0,
    _url: 'ws://127.0.0.1:36089/devtools/browser/0fd89080-24a1-439e-955a-84de431d7f9e',
    _req: null,
    [Symbol(kCapture)]: false
  },
  type: 'error',
  message: 'socket hang up',
  error: Error: socket hang up
      at connResetException (internal/errors.js:628:14)
      at Socket.socketOnEnd (_http_client.js:499:23)
      at Socket.emit (events.js:412:35)
      at Socket.emit (domain.js:470:12)
      at endReadableNT (internal/streams/readable.js:1317:12)
      at processTicksAndRejections (internal/process/task_queues.js:82:21) {
    code: 'ECONNRESET'
  }
}

These are the arguments I'm using:

[
  '--no-sandbox',
  '--no-zygote',
  '--disable-gpu',
  '--ignore-certificate-errors',
  '--allow-running-insecure-content',
  '--disable-web-security',
  '--disable-setuid-sandbox',
  '--disable-dev-shm-usage',
  '--single-process',
  '--user-data-dir="/tmp/chromium"'
]

Puppeteer is expecting Chromium version 901912, which seems to be version 93.0.4577.0. Might that be why it's not working?

I'll try building Chromium 901912. Please hang tight!

ghost commented 2 years ago

@AliasIO

I just compiled Chromium 93.0.4577.0 for ARM for you. It seems to work fine with Playwright, but I have no puppeteer instance to test with. Can you please check if it works?

The file can be downloaded here.

Let me know!

AliasIO commented 2 years ago

@lifesaverluke Thank you for that. Unfortunately I'm still getting the same 'socket hang up' error.

The closest I could find is these posts, although it's about AMD64:

https://github.com/puppeteer/puppeteer/issues/2430 https://stackoverflow.com/questions/59885937/chrome-aws-lambda-amazon-linux-2-getting-error-socket-hang-up

ghost commented 2 years ago

@AliasIO Are you sure you have the environment variable set?

envvars

Otherwise, can you please share your code, and Puppeteer version so that I can try to reproduce it?

AliasIO commented 2 years ago

@lifesaverluke I missed that! With the environment variable it's working. Thank you. 👍

mohamedattahri commented 2 years ago

@lifesaverluke – The link to the zip file you posted seems to have expired. Mind posting again? Exactly what I need. Thanks.

anking commented 2 years ago

@lifesaverluke You are asking to pay $99/month to access your precompiled chromium binaries, am I reading you correctly?

I believe this is a feature request to add ARM64 binaries to chrome-aws-lambda, not a topic for promoting your stuff.

morgothulhu commented 2 years ago

any updates?

e-moshaya commented 2 years ago

any update on this?

jpike88 commented 2 years ago

Are there are noticeable performance improvements using ARM for this?

otterley commented 2 years ago

Hi everyone,

Currently there is no official port of Chromium to Amazon Linux 2 for the arm64 architecture used by AWS Lambda.

However, all is not lost! Since we can run container images on Lambda, we can build a lightweight container image based on Fedora 35 that includes a recent Chromium package and run it there. Here's an example Dockerfile you can use:

# Our code will live in the /function directory.
ARG FUNCTION_DIR="/function"

# Phase 1: Install Node, the Lambda runtime interface client (ric) bindings for
# Node, and the function code into a build container. This involves installing
# some build tools that we don't need in the final deployed image.

FROM public.ecr.aws/docker/library/fedora:35 AS build

ARG FUNCTION_DIR
RUN dnf install -y --setopt=install_weak_deps=False nodejs npm cmake autoconf automake libtool g++
RUN mkdir -p ${FUNCTION_DIR}

WORKDIR ${FUNCTION_DIR}

# Install node packages.
COPY package.json package-lock.json ${FUNCTION_DIR}/
RUN npm install 
# If you prefer, you can comment out the below line, and place aws-lambda-ric
# into your package.json file instead.
RUN npm install aws-lambda-ric

# Install our function code.
COPY index.js ${FUNCTION_DIR}/

# Step 2: Build the deployment container image. We install only Node and
# Chromium, then copy in our function and its dependencies from the build image.
FROM public.ecr.aws/docker/library/fedora:35

ARG FUNCTION_DIR

RUN dnf -y --setopt=install_weak_deps=False install npm https://kojipkgs.fedoraproject.org//packages/chromium/93.0.4577.63/1.fc35/$(uname -m)/chromium-headless-93.0.4577.63-1.fc35.$(uname -m).rpm && \
    dnf clean all && \
    rm -rf /var/cache/yum
COPY --from=build ${FUNCTION_DIR} ${FUNCTION_DIR}

USER nobody
WORKDIR ${FUNCTION_DIR}

ENTRYPOINT ["/usr/bin/npx", "aws-lambda-ric"]
CMD ["index.handler"]

You'll only need to make one minor change in the chrome.puppeteer.launch() invocation - specifically executablePath:

browser = await chromium.puppeteer.launch({
    args: chromium.args,
    defaultViewport: chromium.defaultViewport,
    headless: true,
    ignoreHTTPSErrors: true,
    executablePath: '/usr/lib64/chromium-browser/headless_shell',
}); 

📣 📈 I'm looking for data from customers as to whether there are any observable performance improvements or degradations when migrating from x86 to arm64 for their Lambda functions using Chromium headless. If you have useful data to report, please add it here!

stephankaag commented 3 months ago

I was able to compile Chromium for AWS Lambda on the ARM64 architecture (only Amazon Linux 2 for now, will build for Amazon Linux 2023 asap).

Amazon Linux 2 (NodeJS 16 & NodeJS 18): Download Chromium 120 (For Playwright v1.40.1 , v1.40.0 & Puppeteer v21.8.0) Download Chromium 121 (For Playwright v1.41.2 , v1.41.1 , v1.41.0 & Puppeteer v22.1.0 , v22.0.0 , v21.11.0 , v21.10.0 , v21.9.0)

Amazon Linux 2023 (NodeJS 20): Download Chromium 120 (For Playwright v1.40.1 , v1.40.0 & Puppeteer v21.8.0) Download Chromium 121 (For Playwright v1.41.2 , v1.41.1 , v1.41.0 & Puppeteer v22.1.0 , v22.0.0 , v21.11.0 , v21.10.0 , v21.9.0)