google chrome in docker: initial commit

master
mr c0b 8 years ago
commit 45eb5c28a7

@ -0,0 +1,35 @@
FROM ubuntu
ENV DEBIAN_FRONTEND=noninteractive
RUN set -xe \
&& apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl socat \
&& apt-get install -y --no-install-recommends xvfb x11vnc fluxbox xterm \
&& apt-get install -y --no-install-recommends sudo \
&& apt-get install -y --no-install-recommends supervisor \
&& rm -rf /var/lib/apt/lists/*
RUN set -xe \
&& curl -fsSL https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
&& apt-get update \
&& apt-get install -y google-chrome-stable \
&& rm -rf /var/lib/apt/lists/*
#========================================
# Add normal user with passwordless sudo
#========================================
RUN set -xe \
&& useradd -u 1000 -g 100 -G sudo --shell /bin/bash --no-create-home --home-dir /tmp user \
&& echo 'ALL ALL = (ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers
COPY supervisord.conf /etc/
COPY entry.sh /
User user
WORKDIR /tmp
VOLUME /tmp/chrome-data
CMD ["/entry.sh"]

@ -0,0 +1,232 @@
# google-chrome in docker
*Need to test some latest Chrome version's features?* but hestitant to
upgrade your main browser to unstable? this chrome-in-docker project can help you
## Features
- It downloads a google-chrome Linux version from chrome channels, either
stable, or beta, or developer version; install and pack into a docker
container, that can run on anywhere you have docker daemon;
https://www.chromium.org/getting-involved/dev-channel#TOC-Linux
- It turns google-chrome into a headless browser, can be used together
with Selenium with chrome webdriver, or with Chrome's native Remote
Debugging Protocol you can program with
https://developer.chrome.com/devtools/docs/debugger-protocol
https://github.com/cyrus-and/chrome-remote-interface
that makes it a better headless browser than PhantomJS or SlimerJS,
better programability in my opinion;
while if need debugging, you have a VNC session to see the actual browser,
and do whatever you want, or you can even use it as your everyday main browser.
# Usage
You may either just pull my prebuilt docker image at https://hub.docker.com/r/c0b0/chrome-stable/
$ docker pull c0b0/chrome-stable
$ docker run -it --rm c0b0/chrome-stable /opt/google/chrome/google-chrome --version
Google Chrome 52.0.2743.116
Or build it locally with Dockerfile here
$ docker build -t chrome-stable:20160813 .
Check what Chrome version is builtin, and tag a version:
$ docker run -it --rm chrome-stable:20160813 /opt/google/chrome/google-chrome --version
Google Chrome 52.0.2743.116
$ docker tag chrome-stable:20160813 chrome-stable:52.0.2743.116
The extra `get-latest-chrome.sh` script here is to get latest versions of
Chrome Stable, Beta, or Unstable version, for testing some latest features,
here you may modify the Dockerfile to build a different image with each one,
while, since the beta and unstable versions are changing fast, may be updating
every week or every day, you don't have to rebuild docker images everyday,
with this `get-latest-chrome.sh` and local volume bind, you can run a different
container with the same image; that way, within a relatively longer time range
you don't have to rebuild the base docker image; the reasons of a same base image
can be reused is dependencies of the different channels (stable, beta, or -dev)
are most probably the same, or changing much less often; anyway, if there is
any problem that stable can run but unstable cannot, you may always have a no-cache
rebuild: by `docker build --pull --no-cache ...` to force pull latest ubuntu base
and latest Chrome binary packages.
$ ./get-latest-chrome.sh
[... downloading latest Chrome and extracting to ./opt ...]
You may test run it one time first to check what's exact version of each Chrome channel:
$ docker run -it --rm -v $PWD/opt:/opt:ro chrome:20160813 \
/opt/google/chrome-unstable/google-chrome-unstable --version
Google Chrome 54.0.2824.0 dev
$ docker run -it --rm -v $PWD/opt:/opt:ro chrome:20160813 \
/opt/google/chrome-beta/google-chrome-beta --version
Google Chrome 53.0.2785.57 beta
$ docker run -it --rm -v $PWD/opt:/opt:ro chrome:20160813 \
/opt/google/chrome/google-chrome --version
Google Chrome 52.0.2743.116
Then run 3 different containers with the same base docker image:
```console
$ docker run -dt \
--name Chrome-dev-54.0.2824.0 \
-h chrome-dev-54.local \
-v $PWD/opt:/opt:ro \
-e CHROME=/opt/google/chrome-unstable/google-chrome-unstable \
chrome:20160813
56417156ffea4a55642cfa59cf5e9758a2be144144b2df39e91aa9265f098b75
$ docker run -dt \
--name Chrome-beta-53.0.2785.57 \
-h chrome-beta-53.local \
-v $PWD/opt:/opt:ro \
-e CHROME=/opt/google/chrome-beta/google-chrome-beta \
chrome:20160813
d5b784cbe9ac7d3a52b43c7fb6918b28366c8b939293b10fb9b1808de7b46e2e
$ docker run -dt \
--name Chrome-stable-52.0.2743.116 \
-h chrome-beta-52.local \
-v $PWD/opt:/opt:ro \
chrome:20160813
35974a5247cf8650da25d03d9f279749ae4cf1e5b0c57349af1d511b8ac99545
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
35974a5247cf chrome:20160813 "/entry.sh" ... Chrome-stable-52.0.2743.116
d5b784cbe9ac chrome:20160813 "/entry.sh" ... Chrome-beta-53.0.2785.57
56417156ffea chrome:20160813 "/entry.sh" ... Chrome-dev-54.0.2824.0
```
To connect the chrome in docker, you may either use port mappings, let it call proper
iptables to set up proper mappings; or use inspect to find out the ip addresses
of each container:
$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' Chrome-dev-54.0.2824.0
172.18.0.4
That means the chrome browser's Chrome Debugging Protocol can be accessed by `172.18.0.4:9222`
$ curl -s 172.18.0.4:9222/json/version
{
"Browser": "Chrome/54.0.2824.0",
"Protocol-Version": "1.1",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2824.0 Safari/537.36",
"WebKit-Version": "537.36 (@facabd3224aecbcab4bea9daadad31c67488d78c)"
}
Or, if you use docker port mapping, like:
```console
# this one is not using any local volume binding on /opt, so it's using the builtin Chrome at build time,
$ docker run -dt \
--name Chrome-stable-builtin-52.0.2743.116 \
-h chrome-stable-52.local \
-p 9222:9222 \
chrome:20160813
e9a3738f2d642e5d1a4dd895750d1a09ddece3dd187c82309ade99e1b4123027
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e9a3738f2d64 chrome:20160813 "/entry.sh" 3 seconds ago Up 3 seconds 0.0.0.0:9222->9222/tcp Chrome-stable-builtin-52.0.2743.116
# by inspect we know we can access this container by 172.18.0.2:9222
$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' Chrome-stable-builtin-52.0.2743.116
172.18.0.2
$ curl -s 172.18.0.2:9222/json/version
{
"Browser": "Chrome/52.0.2743.116",
"Protocol-Version": "1.1",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"WebKit-Version": "537.36 (@9115ecad1cae66fd5fe52bd9120af643384fd6f3)"
}
# by above port mapping, this container can also be accessed by 0.0.0.0:9222; if it's from localhost Linux,
$ curl -s localhost:9222/json/version
{
"Browser": "Chrome/52.0.2743.116",
"Protocol-Version": "1.1",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"WebKit-Version": "537.36 (@9115ecad1cae66fd5fe52bd9120af643384fd6f3)"
}
```
You may try https://github.com/cyrus-and/chrome-har-capturer with more har capturing commands
like `chrome-har-capturer -t 172.18.0.2 urls...`
## Debugging
VNC session listens default on the container's 5900 port, if you figured out the container's
IP address (by above inspect command), an VNC session can be opened by your favorite
VNC client connect to this ip address, or you may use another `-p localport:5900`
to set up another port forwarding to be able to use it from a 3rd computer.
## Env variables to customize
1. the default VNC password is `hola`; you may pass additional env var to docker run
by `-e VNC_PASSWORD=xxx` to change to use a different VNC password;
2. the default CHROME is `/opt/google/chrome/google-chrome`, if you use local
volume bind to have different chrome versions, you may pass additional env var
by `-e CHROME=/path/to/chrome or chromium`
# Design
## Docker Image Build Time
1. The Dockerfile defined process of where as start, it's starting from latest
2. Ubuntu as base image, then install VNC and some network utilties like curl and socat,
xvfb, x11vnc as Graphic layer for Chrome graphical output, xterm as debugging term window
supervisor as processes manager, sudo also for debugging, not technically required.
3. Then add Google-Chrome's apt source and install google-chrome-stable version,
and it will handle all runtime dependencies by Chrome;
This static version will be packed as part of the docker image, when you're not
using local volume bind, this version will be used. It depends how often do you
rebuild, but with above `./get-latest-chrome.sh` script, you don't have to rebuild
very often.
3. Then add a regular user at 1000:100 for improved security and run all services
under this regular user; sudo can be used for debugging.
Copying supervisord.conf as definition of process structure; and entry.sh as
container entrypoint.
## Container Spawn
At container spawn time (`docker run ...`), it starts from the entrypoint `entry.sh`
there it handles default VNC password `hola`, and check CHROME environment,
set it default to the stable version `/opt/google/chrome/google-chrome`;
Then it exec to supervisord to spawn more processes defined in `supervisord.conf`
## Process Management
Supervisord is the process manager, it spawns 4 processes:
1. Xvfb ... as X server
2. x11vnc ... as VNC on top of X Server
3. fluxbox as window manager, this is technically not required,
any X11 application can directly run on X server, but with a window
manager, it's easier for debugging, when need to move window, resize,
maximize, and minimize, etc.
4. xterm, same for debugging
5. start chrome from CHROME environment variable, with `--remote-debugging-port=19222`
to enable Remote Debugging Protocol
4. socat, as a forwarding channel, chrome can only listen on local loopback
interface (127.0.0.1); hence not accepting any request from outside
so a tcp forwarding tool like socat is necessary here.
Supervisord will respawn any managed processes if it crashed.
Ideally here should define dependencies between the processes, but due to
https://github.com/Supervisor/supervisor/issues/122 it lacks such feature.
# Some further improvements
- [ ] Chromium nightly https://download-chromium.appspot.com/
- [ ] VNC in browser, see https://github.com/fcwu/docker-ubuntu-vnc-desktop
have an openbox version, or lxde, an lightweight also full featured
Ubuntu desktop
- [ ] setup iptables instead of socat
- [ ] find replacement of supervisord, need a lightweight mananger also has
dependencies management. But sysvinit, upstart, or systemd is too heavy.

@ -0,0 +1,20 @@
#!/bin/bash
set -xe
VNC_STORE_PWD_FILE=~/.vnc/passwd
if [ ! -e "${VNC_STORE_PWD_FILE}" -o -n "${VNC_PASSWORD}" ]; then
mkdir -vp ~/.vnc
# the default VNC password is 'hola'
x11vnc -storepasswd ${VNC_PASSWORD:-hola} ${VNC_STORE_PWD_FILE}
fi
# default CHROME is the stable version
export CHROME=${CHROME:-/opt/google/chrome/google-chrome}
# make the new volume owned by regular user
sudo chown -Rv 1000:100 /tmp/chrome-data
# retain running as pid 1
exec supervisord

@ -0,0 +1,14 @@
#!/bin/bash
# delete previously versions
\rm -rf dl.google.com opt
# download latest unstable, beta, & stable chrome versions
wget -mS https://dl.google.com/linux/direct/google-chrome-{unstable,beta,stable}_current_amd64.deb
# on Debian/Ubuntu based systems, `dpkg --fsys-tarfile` can also be used to extract deb file contents,
# but ar is more generic, and availalbe on all Linux variants
ar p dl.google.com/linux/direct/google-chrome-unstable_current_amd64.deb data.tar.xz | tar --xz -xvv ./opt/google/chrome-unstable/
ar p dl.google.com/linux/direct/google-chrome-beta_current_amd64.deb data.tar.xz | tar --xz -xvv ./opt/google/chrome-beta/
ar p dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb data.tar.xz | tar --xz -xvv ./opt/google/chrome/

@ -0,0 +1,27 @@
[supervisord]
nodaemon=true
[program:xvfb]
command=Xvfb :10 -screen 0 1920x1480x24+32 -ac -r -cc 4 -accessx -xinerama +extension Composite -extension RANDR +extension GLX
[program:x11vnc]
command=x11vnc -rfbport 5900 -display :10 -rfbauth /tmp/.vnc/passwd -forever -shared
[program:fluxbox]
command=fluxbox -display :10
[program:xterm]
command=xterm -display :10
[program:chrome]
command=%(ENV_CHROME)s --no-first-run
--user-data-dir=./chrome-data
--force-device-scale-factor=2
--remote-debugging-port=19222
--enable-benchmarking
--enable-net-benchmarking
environment=DISPLAY=":10"
[program:socat]
command=/usr/bin/socat -v -d tcp-listen:9222,reuseaddr,fork tcp:localhost:19222
Loading…
Cancel
Save