In a recent project I’ve had some challenges trying to run Puppeteer on AWS CodeBuild Windows containers. Since the complete solution was nowhere to be found, I’ve though to share my findings in this post 😉
The code running on the container was already battle tested on Linux and similar to the one below:
const puppeteer = require('puppeteer');
function run () {
return new Promise(async (resolve, reject) => {
try {
console.log('launch');
// launches the browser
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
// opens a page
console.log('page');
const page = await browser.newPage();
// navigates to the url
console.log('goto');
await page.goto('https://www.google.com');
// closes the browser
console.log('close');
browser.close();
return resolve('done');
} catch (e) {
return reject(e);
}
})
}
run().then(console.log).catch(console.error);
When executed, puppeteer.launch
throws the following exception:
ErrorEvent {
[Symbol(kTarget)]: WebSocket {
_events: [Object: null prototype] { open: [Function], error: [Function] },
_eventsCount: 2,
_maxListeners: undefined,
_binaryType: 'nodebuffer',
_closeCode: 1006,
_closeFrameReceived: false,
_closeFrameSent: false,
_closeMessage: <Buffer >,
_closeTimer: null,
_extensions: {},
_protocol: '',
_readyState: 3,
_receiver: null,
_sender: null,
_socket: null,
_bufferedAmount: 0,
_isServer: false,
_redirects: 0,
_url: 'ws://127.0.0.1:49157/devtools/browser/caa58731-4163-4482-a3fa-7690b728ba5b',
_req: null,
[Symbol(kCapture)]: false
},
[Symbol(kType)]: 'error',
[Symbol(kError)]: Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:209:20) {
errno: -4077,
code: 'ECONNRESET',
syscall: 'read'
},
[Symbol(kMessage)]: 'read ECONNRESET'
}
The error message is quite cryptic and doesn’t give us any useful hints. Actually, it sends us to the wrong direction, as from a first look it seems a web socket connectivity issue. To make things worse, AWS CodeBuild doesn’t allow to open a shell or run the container outside of the AWS infrastructure. After a few back and forth messages with the AWS support, they suggested that it was likely a Puppeteer problem and that we should try to reproduce it locally using the official Windows Server 2019 Core image that can found here .
Fortunately, the issue was easy to reproduce locally, using Docker Desktop and a Docker file similar to the one below. Note, remember to switch to Windows containers in Docker desktop before building and running the container.
FROM mcr.microsoft.com/windows/servercore:1909
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV NODE_VERSION 14.15.1
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; \
Expand-Archive node.zip -DestinationPath C:\ ; \
Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\NodeJs' ; \
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\NodeJs', 'Machine')
COPY ./package.json .
RUN npm install
COPY ./main.js .
CMD [ "node.exe", "main.js" ]
Digging a bit deeper into the web, I found a similar case here
. The solution looked straightforward, just a bunch of fonts missing from the Windows image 😌 Unfortunately, it did not work for me, as the Add-Font.ps1
script just hanged there forever 😠Last thing I tried, was to register the fonts into Windows using the FontReg.exe x64 utility found here
.
COPY ./fonts/ /Windows/Fonts
COPY /FontReg.exe /
RUN ./FontReg.exe
That was it, the script worked like a charm with no code changes 😅! Once applied to the buildspec, the same fix worked on AWS CodeBuild too 😌
See the complete Docker file below:
FROM mcr.microsoft.com/windows/servercore:1909
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV NODE_VERSION 14.15.1
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; \
Expand-Archive node.zip -DestinationPath C:\ ; \
Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\NodeJs' ; \
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\NodeJs', 'Machine')
COPY ./fonts/ /Windows/Fonts
COPY /FontReg.exe /
RUN ./FontReg.exe
COPY ./package.json .
RUN npm install
COPY ./main.js .
CMD [ "node.exe", "main.js" ]