Skip to content
This repository was archived by the owner on Dec 17, 2024. It is now read-only.

Commit fd7df2e

Browse files
committed
Initial implementation of a Chromium image for arm64 which is required to run Selenoid on M1. See build-chromium.sh for details or just pull sskorol/selenoid_chromium_vnc:100.0 for testing.
Note that your `browsers.json` should label this image as chrome. Your Selenium tests should also pass a `browserName = chrome` capability as `chromium` isn't explicitly supported for filtering. Base image should be built with UBUNTU_VERSION=18.04 arg for M1 as Focal doesn't have fresh updates for Chromium. Also note that `libgtk-3-0` package is required for Chromium image. Otherwise, a browser just crashes in runtime with 500 error from Selenoid. DevTools support was temporary removed due to an issue accessing Chrome sub-folder from Chromium docker context for further reusing during the build.
1 parent 5568265 commit fd7df2e

File tree

9 files changed

+325
-4
lines changed

9 files changed

+325
-4
lines changed

build-chromium.sh

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
3+
VERSION=${1:-101.0.4951.64-0ubuntu0.18.04.1}
4+
TAG=${2:-chromium_101.0}
5+
BASE_TAG=${3:-7.3.6}
6+
7+
# Cleanup stuff
8+
export BUILDKIT_PROGRESS=plain
9+
docker rmi -f selenoid/vnc:$TAG browsers/base:$BASE_TAG $(docker images -q selenoid/dev_chromium:*)
10+
rm -rf ../selenoid-container-tests
11+
12+
# Prepare for building images
13+
go get github.com/markbates/pkger/cmd/pkger
14+
go generate github.com/aerokube/images
15+
go build
16+
17+
# Forked tests with a bugfix
18+
git clone -b add-missing-dependency https://github.com/sskorol/selenoid-container-tests.git ../selenoid-container-tests
19+
20+
# Force build browsers/base image as it has arm64-specific updates
21+
cd ./selenium/base && docker build --no-cache --build-arg UBUNTU_VERSION=18.04 -t browsers/base:$BASE_TAG . && docker system prune -f
22+
23+
# Build chromium image
24+
cd ../../ && ./images chromium -b $VERSION -t selenoid/vnc:$TAG --test && docker system prune -f

build/chromium.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package build
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
)
8+
9+
type Chromium struct {
10+
Requirements
11+
}
12+
13+
func (c *Chromium) Build() error {
14+
15+
pkgSrcPath, pkgVersion, err := c.BrowserSource.Prepare()
16+
if err != nil {
17+
return fmt.Errorf("invalid browser source: %v", err)
18+
}
19+
20+
pkgTagVersion := extractVersion(pkgVersion)
21+
22+
if err != nil {
23+
return fmt.Errorf("parse chromiumdriver version: %v", err)
24+
}
25+
26+
// Build dev image
27+
devDestDir, err := tmpDir()
28+
if err != nil {
29+
return fmt.Errorf("create dev temporary dir: %v", err)
30+
}
31+
32+
srcDir := "chromium/apt"
33+
34+
if pkgSrcPath != "" {
35+
srcDir = "chromium/local"
36+
pkgDestDir := filepath.Join(devDestDir, srcDir)
37+
err := os.MkdirAll(pkgDestDir, 0755)
38+
if err != nil {
39+
return fmt.Errorf("create %v temporary dir: %v", pkgDestDir, err)
40+
}
41+
pkgDestPath := filepath.Join(pkgDestDir, "chromium.deb")
42+
err = os.Rename(pkgSrcPath, pkgDestPath)
43+
if err != nil {
44+
return fmt.Errorf("move package: %v", err)
45+
}
46+
}
47+
48+
devImageTag := fmt.Sprintf("selenoid/dev_chromium:%s", pkgTagVersion)
49+
devImageRequirements := Requirements{NoCache: c.NoCache, Tags: []string{devImageTag}}
50+
devImage, err := NewImage(srcDir, devDestDir, devImageRequirements)
51+
if err != nil {
52+
return fmt.Errorf("init dev image: %v", err)
53+
}
54+
devBuildArgs := []string{fmt.Sprintf("VERSION=%s", pkgVersion)}
55+
devImage.BuildArgs = devBuildArgs
56+
if pkgSrcPath != "" {
57+
devImage.FileServer = true
58+
}
59+
60+
err = devImage.Build()
61+
if err != nil {
62+
return fmt.Errorf("build dev image: %v", err)
63+
}
64+
65+
// Build main image
66+
destDir, err := tmpDir()
67+
if err != nil {
68+
return fmt.Errorf("create temporary dir: %v", err)
69+
}
70+
71+
image, err := NewImage("chromium", destDir, c.Requirements)
72+
if err != nil {
73+
return fmt.Errorf("init image: %v", err)
74+
}
75+
image.BuildArgs = append(image.BuildArgs, fmt.Sprintf("VERSION=%s", pkgTagVersion))
76+
77+
err = image.Build()
78+
if err != nil {
79+
return fmt.Errorf("build image: %v", err)
80+
}
81+
82+
// Must be Chrome even it's Chromium-based container
83+
err = image.Test(c.TestsDir, "chrome", pkgTagVersion)
84+
if err != nil {
85+
return fmt.Errorf("test image: %v", err)
86+
}
87+
88+
err = image.Push()
89+
if err != nil {
90+
return fmt.Errorf("push image: %v", err)
91+
}
92+
93+
return nil
94+
}

cmd/chromium.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package cmd
2+
3+
import (
4+
"github.com/aerokube/images/build"
5+
"github.com/spf13/cobra"
6+
)
7+
8+
var (
9+
chromiumCmd = &cobra.Command{
10+
Use: "chromium",
11+
Short: "build Chromium image",
12+
RunE: func(cmd *cobra.Command, args []string) error {
13+
req := build.Requirements{
14+
BrowserSource: build.BrowserSource(browserSource),
15+
NoCache: noCache,
16+
TestsDir: testsDir,
17+
RunTests: test,
18+
IgnoreTests: ignoreTests,
19+
Tags: tags,
20+
PushImage: push,
21+
}
22+
chromium := &build.Chromium{req}
23+
return chromium.Build()
24+
},
25+
}
26+
)

cmd/root.go

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func initFlags() {
5151
func init() {
5252
initFlags()
5353
rootCmd.AddCommand(chromeCmd)
54+
rootCmd.AddCommand(chromiumCmd)
5455
rootCmd.AddCommand(edgeCmd)
5556
rootCmd.AddCommand(firefoxCmd)
5657
rootCmd.AddCommand(operaCmd)

selenium/base/Dockerfile

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
1+
ARG UBUNTU_VERSION=20.04
2+
13
FROM golang:1.17 as go
24

35
COPY xseld /xseld
46

57
COPY fileserver /fileserver
68

79
RUN \
10+
if [ `uname -m` = "aarch64" ]; then ARCH="arm64"; else ARCH="amd64"; fi && \
811
apt-get update && \
912
apt-get install -y upx-ucl libx11-dev && \
1013
cd /xseld && \
11-
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
14+
GOOS=linux GOARCH=$ARCH go build -ldflags="-s -w" && \
1215
upx /xseld/xseld && \
1316
cd /fileserver && \
1417
go test -race && \
15-
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
18+
GOOS=linux GOARCH=$ARCH go build -ldflags="-s -w" && \
1619
upx /fileserver/fileserver
1720

18-
FROM ubuntu:20.04
21+
# For M1 Chromium images it's required to override a version to 18.04 as latest Ubuntu distributions don't ship updates
22+
FROM ubuntu:$UBUNTU_VERSION
1923

2024
RUN \
2125
apt update && \
@@ -49,7 +53,6 @@ RUN \
4953
xfonts-base \
5054
xfonts-encodings \
5155
xfonts-utils \
52-
flashplugin-installer \
5356
xvfb \
5457
pulseaudio \
5558
fluxbox \
@@ -58,6 +61,7 @@ RUN \
5861
wmctrl \
5962
libnss-wrapper \
6063
xsel && \
64+
if [ `uname -m` = "amd64" ]; then apt install -y flashplugin-installer; fi && \
6165
mkdir -p /var/lib/locales/supported.d/ && grep UTF-8 /usr/share/i18n/SUPPORTED > /var/lib/locales/supported.d/all && \
6266
locale-gen && update-locale && \
6367
fc-cache -f -v && \

static/chromium/Dockerfile

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
ARG VERSION
2+
FROM selenoid/dev_chromium:$VERSION
3+
4+
ENV DBUS_SESSION_BUS_ADDRESS=/dev/null
5+
COPY entrypoint.sh /
6+
7+
RUN chmod +x /usr/bin/chromedriver
8+
USER selenium
9+
10+
EXPOSE 4444
11+
ENTRYPOINT ["/entrypoint.sh"]

static/chromium/apt/Dockerfile

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM browsers/base:7.3.6
2+
3+
ARG VERSION
4+
ARG PACKAGE=chromium-browser
5+
6+
LABEL browser=$PACKAGE:$VERSION
7+
8+
RUN \
9+
apt-get update && \
10+
apt-get -y --no-install-recommends install \
11+
iproute2 \
12+
libgtk-3-0 \
13+
${PACKAGE}=${VERSION} \
14+
chromium-chromedriver=${VERSION} && \
15+
chromium-browser --version && \
16+
rm -Rf /tmp/* && rm -Rf /var/lib/apt/lists/*

static/chromium/entrypoint.sh

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/bin/bash
2+
SCREEN_RESOLUTION=${SCREEN_RESOLUTION:-"1920x1080x24"}
3+
DISPLAY_NUM=99
4+
export DISPLAY=":$DISPLAY_NUM"
5+
6+
VERBOSE=${VERBOSE:-""}
7+
DRIVER_ARGS=${DRIVER_ARGS:-""}
8+
if [ -n "$VERBOSE" ]; then
9+
DRIVER_ARGS="$DRIVER_ARGS --verbose"
10+
fi
11+
12+
clean() {
13+
if [ -n "$FILESERVER_PID" ]; then
14+
kill -TERM "$FILESERVER_PID"
15+
fi
16+
if [ -n "$XSELD_PID" ]; then
17+
kill -TERM "$XSELD_PID"
18+
fi
19+
if [ -n "$XVFB_PID" ]; then
20+
kill -TERM "$XVFB_PID"
21+
fi
22+
if [ -n "$DRIVER_PID" ]; then
23+
kill -TERM "$DRIVER_PID"
24+
fi
25+
if [ -n "$X11VNC_PID" ]; then
26+
kill -TERM "$X11VNC_PID"
27+
fi
28+
if [ -n "$PULSE_PID" ]; then
29+
kill -TERM "$PULSE_PID"
30+
fi
31+
}
32+
33+
trap clean SIGINT SIGTERM
34+
35+
if env | grep -q ROOT_CA_; then
36+
mkdir -p $HOME/.pki/nssdb
37+
certutil -N --empty-password -d sql:$HOME/.pki/nssdb
38+
for e in $(env | grep ROOT_CA_ | sed -e 's/=.*$//'); do
39+
certname=$(echo -n $e | sed -e 's/ROOT_CA_//')
40+
echo ${!e} | base64 -d >/tmp/cert.pem
41+
certutil -A -n ${certname} -t "TC,C,T" -i /tmp/cert.pem -d sql:$HOME/.pki/nssdb
42+
if cat tmp/cert.pem | grep -q "PRIVATE KEY"; then
43+
PRIVATE_KEY_PASS=${PRIVATE_KEY_PASS:-\'\'}
44+
openssl pkcs12 -export -in /tmp/cert.pem -clcerts -nodes -out /tmp/key.p12 -passout pass:${PRIVATE_KEY_PASS} -passin pass:${PRIVATE_KEY_PASS}
45+
pk12util -d sql:$HOME/.pki/nssdb -i /tmp/key.p12 -W ${PRIVATE_KEY_PASS}
46+
rm /tmp/key.p12
47+
fi
48+
rm /tmp/cert.pem
49+
done
50+
fi
51+
52+
/usr/bin/fileserver &
53+
FILESERVER_PID=$!
54+
55+
DISPLAY="$DISPLAY" /usr/bin/xseld &
56+
XSELD_PID=$!
57+
58+
while ip addr | grep inet | grep -q tentative > /dev/null; do sleep 0.1; done
59+
60+
mkdir -p ~/pulse/.config/pulse
61+
echo -n 'gIvST5iz2S0J1+JlXC1lD3HWvg61vDTV1xbmiGxZnjB6E3psXsjWUVQS4SRrch6rygQgtpw7qmghDFTaekt8qWiCjGvB0LNzQbvhfs1SFYDMakmIXuoqYoWFqTJ+GOXYByxpgCMylMKwpOoANEDePUCj36nwGaJNTNSjL8WBv+Bf3rJXqWnJ/43a0hUhmBBt28Dhiz6Yqowa83Y4iDRNJbxih6rB1vRNDKqRr/J9XJV+dOlM0dI+K6Vf5Ag+2LGZ3rc5sPVqgHgKK0mcNcsn+yCmO+XLQHD1K+QgL8RITs7nNeF1ikYPVgEYnc0CGzHTMvFR7JLgwL2gTXulCdwPbg=='| base64 -d>~/pulse/.config/pulse/cookie
62+
HOME=$HOME/pulse pulseaudio --start --exit-idle-time=-1
63+
HOME=$HOME/pulse pactl load-module module-native-protocol-tcp
64+
PULSE_PID=$(ps --no-headers -C pulseaudio -o pid | sed -r 's/( )+//g')
65+
66+
/usr/bin/xvfb-run -l -n "$DISPLAY_NUM" -s "-ac -screen 0 $SCREEN_RESOLUTION -noreset -listen tcp" /usr/bin/fluxbox -display "$DISPLAY" -log /dev/null 2>/dev/null &
67+
XVFB_PID=$!
68+
69+
retcode=1
70+
until [ $retcode -eq 0 ]; do
71+
DISPLAY="$DISPLAY" wmctrl -m >/dev/null 2>&1
72+
retcode=$?
73+
if [ $retcode -ne 0 ]; then
74+
echo Waiting X server...
75+
sleep 0.1
76+
fi
77+
done
78+
79+
if [ "$ENABLE_VNC" == "true" ]; then
80+
x11vnc -display "$DISPLAY" -passwd selenoid -shared -forever -loop500 -rfbport 5900 -rfbportv6 5900 -logfile /dev/null &
81+
X11VNC_PID=$!
82+
fi
83+
84+
DISPLAY="$DISPLAY" /usr/bin/chromedriver --port=4444 --allowed-ips='' --allowed-origins='*' ${DRIVER_ARGS} &
85+
DRIVER_PID=$!
86+
87+
wait

static/chromium/local/Dockerfile

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
FROM browsers/base:7.3.6
2+
3+
ARG VERSION=noop
4+
ARG PACKAGE=chromium-browser
5+
6+
LABEL browser=$PACKAGE:$VERSION
7+
8+
RUN \
9+
apt-get update && \
10+
apt-get -y --no-install-recommends install gconf-service \
11+
libasound2 \
12+
libatk1.0-0 \
13+
libc6 \
14+
libcairo2 \
15+
libcups2 \
16+
libdbus-1-3 \
17+
libexpat1 \
18+
libfontconfig1 \
19+
libfreetype6 \
20+
libgcc1 \
21+
libgconf-2-4 \
22+
libgdk-pixbuf2.0-0 \
23+
libglib2.0-0 \
24+
libgtk2.0-0 \
25+
libgtk-3-0 \
26+
libnspr4 \
27+
libnss3 \
28+
libpango1.0-0 \
29+
libstdc++6 \
30+
libx11-6 \
31+
libx11-xcb1 \
32+
libxcb1 \
33+
libxcomposite1 \
34+
libxcursor1 \
35+
libxdamage1 \
36+
libxext6 \
37+
libxfixes3 \
38+
libxi6 \
39+
libxrandr2 \
40+
libxrender1 \
41+
libxss1 \
42+
libxtst6 \
43+
ca-certificates \
44+
fonts-liberation \
45+
libappindicator3-1 \
46+
libnss3 \
47+
lsb-base \
48+
xdg-utils \
49+
libcurl4 \
50+
iproute2 \
51+
curl \
52+
chromium-chromedriver && \
53+
curl -O http://host.docker.internal:8080/chromium-browser.deb && \
54+
apt-get -y purge curl && \
55+
dpkg -i chromium-browser.deb && \
56+
chromium-browser --version && \
57+
rm -Rf /tmp/* && \
58+
rm -Rf /var/lib/apt/lists/*

0 commit comments

Comments
 (0)