Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ashnur/ccbfd6a4899cf27d5bfa53704d800891 to your computer and use it in GitHub Desktop.
Save ashnur/ccbfd6a4899cf27d5bfa53704d800891 to your computer and use it in GitHub Desktop.

Revisions

  1. @x-yuri x-yuri revised this gist Dec 29, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,7 @@ applications, and from the user's mouse and keyboard input. Therefore, applicati

    So, to run a GUI application in a `docker` container, you've got to provide a way for it
    to communicate to the X server running on the host. One way to go about it is to use `host`
    networking (`--network host`). In this case the container shares the `host`'s networking namespace.
    networking (`--network host`). In this case the container shares the host's networking namespace.
    I.e. container’s network stack is *not* isolated from the Docker host. Particularly, the container
    can connect to any servers running on the host.

  2. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@ docker run --rm \
    "${chrome_cmd[@]}"
    ```

    If you decide to use `cypress/included` image, you've got to override the default entrypoint (`entrypoint ''`):
    If you decide to use `cypress/included` image, you've got to override the default entrypoint (`--entrypoint ''`):

    ```sh
    chrome_cmd=(
  3. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    Let's with the basics of how X Window System works. X uses client-server model.
    Let's start with the basics of how X Window System works. X uses client-server model.
    An X server program runs on a computer with a graphical display and communicates
    with various client programs (X clients). The X server acts as a go-between for the user and
    the client programs, accepting requests for graphical output
    @@ -18,7 +18,7 @@ applications, and from the user's mouse and keyboard input. Therefore, applicati
    So, to run a GUI application in a `docker` container, you've got to provide a way for it
    to communicate to the X server running on the host. One way to go about it is to use `host`
    networking (`--network host`). In this case the container shares the `host`'s networking namespace.
    I.e. container’s network stack is not isolated from the Docker host. Particularly, the container
    I.e. container’s network stack is *not* isolated from the Docker host. Particularly, the container
    can connect to any servers running on the host.

    Also, you've got to let the container authenticate to the X server. Again, one way to achieve this is to use
  4. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 14 additions and 0 deletions.
    14 changes: 14 additions & 0 deletions Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -129,6 +129,20 @@ xvfb-run sh -c '
    [`import`][3] is an ImageMagick utility that captures some or all of an X server screen,
    [`eog`][4] is an image viewer.

    And how to run `cypress` tests in a `docker` container:

    ```sh
    docker run -it --rm \
    --network host \
    -v ~/.Xauthority:/root/.Xauthority:ro \
    -e DISPLAY \
    -v $PWD:/e2e \
    -w /e2e \
    --entrypoint '' \
    cypress/included:3.6.1 \
    npx cypress open
    ```

    [3]: https://imagemagick.org/script/import.php
    [4]: https://wiki.gnome.org/Apps/EyeOfGnome

  5. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -94,7 +94,7 @@ As a bonus, here's how to take a screenshot of a browser running under `xvfb-run
    `./1.sh`:

    ```sh
    #!/bin/bash
    #!/usr/bin/env bash
    set -eu
    chrome_cmd=(
    google-chrome
  6. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -89,7 +89,7 @@ docker container run --rm \
    chromium-browser --no-sandbox
    ```

    As a bonus, here's how to make a screenshot of a browser running under `xvfb-run`:
    As a bonus, here's how to take a screenshot of a browser running under `xvfb-run`:

    `./1.sh`:

  7. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -126,7 +126,7 @@ xvfb-run sh -c '
    ./1.sh && eog 1.png
    ```

    [`import`][3] is one of the ImageMagick utilities that captures some or all of an X server screen,
    [`import`][3] is an ImageMagick utility that captures some or all of an X server screen,
    [`eog`][4] is an image viewer.

    [3]: https://imagemagick.org/script/import.php
  8. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 43 additions and 0 deletions.
    43 changes: 43 additions & 0 deletions Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -89,6 +89,49 @@ docker container run --rm \
    chromium-browser --no-sandbox
    ```

    As a bonus, here's how to make a screenshot of a browser running under `xvfb-run`:

    `./1.sh`:

    ```sh
    #!/bin/bash
    set -eu
    chrome_cmd=(
    google-chrome
    --disable-gpu
    --no-sandbox
    --no-first-run
    https://google.com
    )
    docker run --rm \
    -v $PWD:/d \
    -w /d \
    --entrypoint ./2.sh \
    cypress/browsers:node12.6.0-chrome77 \
    "${chrome_cmd[@]}"
    ```

    `./2.sh`:

    ```sh
    #!/bin/sh
    xvfb-run sh -c '
    "$@" \
    & sleep 2 \
    && import -window root 1.png
    ' -- "$@"
    ```

    ```sh
    ./1.sh && eog 1.png
    ```

    [`import`][3] is one of the ImageMagick utilities that captures some or all of an X server screen,
    [`eog`][4] is an image viewer.

    [3]: https://imagemagick.org/script/import.php
    [4]: https://wiki.gnome.org/Apps/EyeOfGnome

    P.S. If you do anything memory instensive with Chrome it might crash. That's because by default
    `/dev/shm` size in a `docker` container is 64MB. You can remedy it either by adding
    `--disable-dev-shm-usage` to Chrome, or `--ipc=host` to `docker run`.
  9. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -38,7 +38,7 @@ that it's okay to run under `root` account:
    [6:6:1214/141504.683039:ERROR:zygote_host_impl_linux.cc(89)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.
    ```

    And `--no-first-run` makes it not show the popup where you can make `Chrome` the default browser, and all.
    And `--no-first-run` makes it not show the Fisrt Launch popup.

    ```sh
    chrome_cmd=(
  10. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -43,6 +43,7 @@ And `--no-first-run` makes it not show the popup where you can make `Chrome` the
    ```sh
    chrome_cmd=(
    google-chrome
    --disable-gpu
    --no-sandbox
    --no-first-run
    https://google.com
    @@ -55,8 +56,7 @@ docker run --rm \
    "${chrome_cmd[@]}"
    ```

    If you decide to use `cypress/included` image, you've got to add `--disable-gpu` flag for Chrome,
    or else it won't start for some reason. And override the default entrypoint (`entrypoint ''`):
    If you decide to use `cypress/included` image, you've got to override the default entrypoint (`entrypoint ''`):

    ```sh
    chrome_cmd=(
  11. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 33 additions and 15 deletions.
    48 changes: 33 additions & 15 deletions Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -31,7 +31,7 @@ the `DISPLAY` variable from the host into the container (`--env DISPLAY`).

    [1]: https://www.x.org/archive/X11R6.8.1/doc/X.7.html#sect4

    As for the Chrome we need `--disable-gpu` flag. Otherwise it won't start. `--no-sandbox` tells it
    As for Chrome we need `--disable-gpu` flag. Otherwise it won't start. `--no-sandbox` tells it
    that it's okay to run under `root` account:

    ```
    @@ -43,7 +43,6 @@ And `--no-first-run` makes it not show the popup where you can make `Chrome` the
    ```sh
    chrome_cmd=(
    google-chrome
    --disable-gpu
    --no-sandbox
    --no-first-run
    https://google.com
    @@ -52,30 +51,49 @@ docker run --rm \
    --network host \
    --volume ~/.Xauthority:/root/.Xauthority:ro \
    --env DISPLAY \
    --entrypoint sh \
    cypress/included:3.6.1 \
    -c "${chrome_cmd[*]@Q}"
    cypress/browsers:node12.6.0-chrome77 \
    "${chrome_cmd[@]}"
    ```

    If you do anything memory instensive with Chrome it might crash. That's because by default
    `/dev/shm` size in a `docker` container is 64MB. You can remedy it either by adding
    `--disable-dev-shm-usage` to `google-chrome`, or `--ipc=host` to `docker run`.
    More on it here:
    If you decide to use `cypress/included` image, you've got to add `--disable-gpu` flag for Chrome,
    or else it won't start for some reason. And override the default entrypoint (`entrypoint ''`):

    https://sondnm.github.io/blog/2018/09/08/i-just-learnt-about-/dev/shm/
    https://peter.sh/experiments/chromium-command-line-switches/
    https://docs.docker.com/engine/reference/run/#ipc-settings---ipc
    ```sh
    chrome_cmd=(
    google-chrome
    --disable-gpu
    --no-sandbox
    --no-first-run
    https://google.com
    )
    docker run --rm \
    --network host \
    --volume ~/.Xauthority:/root/.Xauthority:ro \
    --env DISPLAY \
    --entrypoint '' \
    cypress/included:3.8.0 \
    "${chrome_cmd[@]}"
    ```

    Or using [`zenika/alpine-chrome`][2] image:
    Or using the [`zenika/alpine-chrome`][2] image:

    [2]: https://hub.docker.com/r/zenika/alpine-chrome/

    ```
    ```sh
    docker container run --rm \
    --network=host \
    --volume ~/.Xauthority:/home/chrome/.Xauthority:ro \
    --env DISPLAY \
    --entrypoint '' \
    zenika/alpine-chrome \
    chromium-browser --no-sandbox
    ```
    ```

    P.S. If you do anything memory instensive with Chrome it might crash. That's because by default
    `/dev/shm` size in a `docker` container is 64MB. You can remedy it either by adding
    `--disable-dev-shm-usage` to Chrome, or `--ipc=host` to `docker run`.
    More on it here:

    https://sondnm.github.io/blog/2018/09/08/i-just-learnt-about-/dev/shm/
    https://peter.sh/experiments/chromium-command-line-switches/
    https://docs.docker.com/engine/reference/run/#ipc-settings---ipc
  12. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -21,7 +21,7 @@ networking (`--network host`). In this case the container shares the `host`'s ne
    I.e. container’s network stack is not isolated from the Docker host. Particularly, the container
    can connect to any servers running on the host.

    Also, you've got to let the container authenticate to the X server. Again, one way is to use
    Also, you've got to let the container authenticate to the X server. Again, one way to achieve this is to use
    cookie-based authentication. For that you've got to share the `~/.Xauthority` file with the container
    (`--volume ~/.Xauthority:/root/.Xauthority:ro`).

  13. @x-yuri x-yuri revised this gist Dec 14, 2019. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -16,7 +16,7 @@ applications, and from the user's mouse and keyboard input. Therefore, applicati
    ![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/03/X_client_server_example.svg/250px-X_client_server_example.svg.png)

    So, to run a GUI application in a `docker` container, you've got to provide a way for it
    to communicate to the X server running on the host. One way to go about it is to `host`
    to communicate to the X server running on the host. One way to go about it is to use `host`
    networking (`--network host`). In this case the container shares the `host`'s networking namespace.
    I.e. container’s network stack is not isolated from the Docker host. Particularly, the container
    can connect to any servers running on the host.
    @@ -66,7 +66,9 @@ https://sondnm.github.io/blog/2018/09/08/i-just-learnt-about-/dev/shm/
    https://peter.sh/experiments/chromium-command-line-switches/
    https://docs.docker.com/engine/reference/run/#ipc-settings---ipc

    Or using `zenika/alpine-chrome` image:
    Or using [`zenika/alpine-chrome`][2] image:

    [2]: https://hub.docker.com/r/zenika/alpine-chrome/

    ```
    docker container run --rm \
  14. @x-yuri x-yuri created this gist Dec 14, 2019.
    79 changes: 79 additions & 0 deletions Running GUI applications inside Docker containers.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,79 @@
    Let's with the basics of how X Window System works. X uses client-server model.
    An X server program runs on a computer with a graphical display and communicates
    with various client programs (X clients). The X server acts as a go-between for the user and
    the client programs, accepting requests for graphical output
    from the client programs and displaying them to the user (display),
    and receiving user input (keyboard, mouse) and transmitting it to the client programs.

    In X, the server runs on the user's computer, while the clients may run on remote machines.
    This terminology reverses the common notion of client–server systems, where the client
    normally runs on the user's local computer and the server runs on the remote computer.
    The X Window terminology takes the perspective that the X Window program is at the
    centre of all activity, i.e. the X Window program accepts and responds to requests from
    applications, and from the user's mouse and keyboard input. Therefore, applications
    (on remote computers) are viewed as clients of the X Window server program.

    ![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/03/X_client_server_example.svg/250px-X_client_server_example.svg.png)

    So, to run a GUI application in a `docker` container, you've got to provide a way for it
    to communicate to the X server running on the host. One way to go about it is to `host`
    networking (`--network host`). In this case the container shares the `host`'s networking namespace.
    I.e. container’s network stack is not isolated from the Docker host. Particularly, the container
    can connect to any servers running on the host.

    Also, you've got to let the container authenticate to the X server. Again, one way is to use
    cookie-based authentication. For that you've got to share the `~/.Xauthority` file with the container
    (`--volume ~/.Xauthority:/root/.Xauthority:ro`).

    And you've got to tell the container where the X server is running. For that the [`DISPLAY` variable][1] is used.
    Since the container is going to have access to the host's network namespace, you can simply pass
    the `DISPLAY` variable from the host into the container (`--env DISPLAY`).

    [1]: https://www.x.org/archive/X11R6.8.1/doc/X.7.html#sect4

    As for the Chrome we need `--disable-gpu` flag. Otherwise it won't start. `--no-sandbox` tells it
    that it's okay to run under `root` account:

    ```
    [6:6:1214/141504.683039:ERROR:zygote_host_impl_linux.cc(89)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.
    ```

    And `--no-first-run` makes it not show the popup where you can make `Chrome` the default browser, and all.

    ```sh
    chrome_cmd=(
    google-chrome
    --disable-gpu
    --no-sandbox
    --no-first-run
    https://google.com
    )
    docker run --rm \
    --network host \
    --volume ~/.Xauthority:/root/.Xauthority:ro \
    --env DISPLAY \
    --entrypoint sh \
    cypress/included:3.6.1 \
    -c "${chrome_cmd[*]@Q}"
    ```

    If you do anything memory instensive with Chrome it might crash. That's because by default
    `/dev/shm` size in a `docker` container is 64MB. You can remedy it either by adding
    `--disable-dev-shm-usage` to `google-chrome`, or `--ipc=host` to `docker run`.
    More on it here:

    https://sondnm.github.io/blog/2018/09/08/i-just-learnt-about-/dev/shm/
    https://peter.sh/experiments/chromium-command-line-switches/
    https://docs.docker.com/engine/reference/run/#ipc-settings---ipc

    Or using `zenika/alpine-chrome` image:

    ```
    docker container run --rm \
    --network=host \
    --volume ~/.Xauthority:/home/chrome/.Xauthority:ro \
    --env DISPLAY \
    --entrypoint '' \
    zenika/alpine-chrome \
    chromium-browser --no-sandbox
    ```