Skip to content

Commit

Permalink
Improve Dockerfile with cache, Bazelisk, and cmake support (#2643)
Browse files Browse the repository at this point in the history
Allow `bazel` and `cmake` to be used with docker by simply adding them after `docker run ...`. Moreover it is designed to keep build and bazel cache between runs, which means no re-downloads between separate `docker run` commands.

Co-authored-by: Bart Louwers <[email protected]>
  • Loading branch information
nyurik and louwers authored Jul 24, 2024
1 parent 89a860d commit 1b014a1
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 60 deletions.
2 changes: 2 additions & 0 deletions docker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.cache/
!.cache/empty_file
53 changes: 53 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
FROM ubuntu:22.04

# Install build tools and dependencies
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
apt-transport-https \
curl \
gnupg \
sudo `# allows dev to install more packages without switching to root or rebuilding container` \
build-essential \
libsqlite3-dev \
libcurl4-openssl-dev \
libglfw3-dev \
libuv1-dev \
libpng-dev \
libicu-dev \
libjpeg-turbo8-dev \
libwebp-dev \
xvfb \
clang \
git \
cmake \
ccache \
ninja-build \
pkg-config \
&& : # end of the RUN cmd - easier to keep a colon at the end of the list, than to keep the backslashes in check

# This could also be `.../releases/latest/download/bazelisk-linux-amd64` for the latest version, but for predictability better hardcode it
RUN curl -fsSL https://github.com/bazelbuild/bazelisk/releases/download/v1.20.0/bazelisk-linux-amd64 -o /usr/local/bin/bazel \
&& chmod +x /usr/local/bin/bazel \
&& :

WORKDIR /app

ARG USERNAME=user
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Create docker user wuth sudo rights as passed in by the build command
# This was modeled on https://code.visualstudio.com/remote/advancedcontainers/add-nonroot-user
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME

COPY startup.sh /usr/local/bin/startup.sh
RUN chmod +x /usr/local/bin/startup.sh

# This allows users to `docker run` without specifying -u and -g
USER $USERNAME

ENTRYPOINT ["/usr/local/bin/startup.sh"]
CMD ["bash"]
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Exclude everything because we expect users to mount this dir as a volume,
# so none of this repos' content should be part of the docker build context.
*
!startup.sh
43 changes: 43 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Building with Docker

These steps will allow you to compile code as described [platform/linux/README.md](../platform/linux/README.md) using a Docker container. All the steps should be executed from the root of the repository.

> [!IMPORTANT]
> Not all platform builds are currently supported. Docker builds are a work in progress.
> [!IMPORTANT]
> You cannot build MapLibre native using both Docker and host methods at the same time. If you want to switch, you need to clean the repository first, e.g. by using this command:
>
> ```bash
> git clean -dxfi -e .idea -e .clwb -e .vscode
> ```
### Build Docker Image
You must build your own Docker image, specific with your user and group IDs to ensure file permissions stay correct.
```bash
# Build docker image from the repo __root__
# Specifying USER_UID and USER_GID allows container to create files with the same owner as the host user,
# and avoids having to pass -u $(id -u):$(id -g) to docker run.
docker build \
-t maplibre-native-image \
--build-arg USER_UID=$(id -u) \
--build-arg USER_GID=$(id -g) \
-f docker/Dockerfile \
docker
```
## Run Docker Container

```bash
# Run all build commands using the docker container.
# You can also execute build commands from inside the docker container by starting it without the build command.
docker run --rm -it -v "$PWD:/app/" -v "$PWD/docker/.cache:/home/user/.cache" maplibre-native-image
```

You can also use the container to run just one specific commands, e.g. `cmake` or `bazel`. Any downloaded dependencies will be cached in the `docker/.cache` directory.

```bash
docker run --rm -it -v "$PWD:/app/" -v "$PWD/docker/.cache:/home/user/.cache" maplibre-native-image cmake ...
```
13 changes: 13 additions & 0 deletions docker/startup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

if [ ! -d /app/.github ] || [ ! -d /home/user/.cache ]; then
echo " "
echo "ERROR: Docker container was not started properly."
echo " From the root of this repo, run the following command."
echo " You may add any command to perform in the container at the end of this command."
echo " "
echo ' docker run --rm -it -v "$PWD:/app/" -v "$PWD/docker/.cache:/home/user/.cache" maplibre-native-image'
exit 1
fi

exec "$@"
33 changes: 0 additions & 33 deletions platform/linux/Dockerfile

This file was deleted.

31 changes: 4 additions & 27 deletions platform/linux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ cd maplibre-native
```

## Requirements

### Building without Docker

```bash
# Install build tools
apt install clang cmake ccache ninja-build pkg-config
apt install build-essential clang cmake ccache ninja-build pkg-config

# Install system dependencies
apt install libcurl4-openssl-dev libglfw3-dev libuv1-dev libpng-dev libicu-dev libjpeg-turbo8-dev libwebp-dev xvfb
Expand All @@ -26,26 +27,7 @@ Optional: `libsqlite3-dev` (also available as vendored dependency).

### Building with Docker

You can use a Docker container to build MapLibre Native. A `Dockerfile` that installes the required dependencies when the image is built is provided in this directory.

```bash
# Build docker image from the repo root
docker build -t maplibre-native-image -f platform/linux/Dockerfile .

# Run docker image as the current user.
# This ensures that the files created in the container are owned by the current user.
docker run --rm -it -v "$PWD:/code/" -u $(id -u):$(id -g) maplibre-native-image ___any_build_command___

# You can also execute build commands from inside the docker container by starting it without parameters:
docker run --rm -it -v "$PWD:/code/" -u $(id -u):$(id -g) maplibre-native-image
```

You can safely ignore this type of message and a missing username. It happens if your linux user was not the first one created on the system.

```
groups: cannot find name for group ID ....
I have no name!@...:/root$ `
```
See instructions in [docker/README.md](../../docker/README.md) to build in a docker container.

## Build

Expand All @@ -57,22 +39,17 @@ cmake -B build -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DC
cmake --build build --target mbgl-render -j $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null)
```


## Running `mbgl-render`
Running `mbgl-render --style https://raw.githubusercontent.com/maplibre/demotiles/gh-pages/style.json` should produce a map tile image with the default MapLibre styling from [the MapLibre demo](https://maplibre.org/).

![Sample image of world from mbgl-render command](/misc/sample-maplibre-style-mbgl-render-out.png)

### Outside of Docker

Render output image using default MapLibre demo tiles server. You can run this binary on your host machine even if you built it inside a Docker container.

```bash
./build/bin/mbgl-render --style https://raw.githubusercontent.com/maplibre/demotiles/gh-pages/style.json --output out.png
xdg-open out.png
```

### Inside Docker
### Headless rendering

If you run `mbgl-render` inside a Docker or on a remote headless server, you will likely get this error because there is no X server running in the container.

Expand Down

0 comments on commit 1b014a1

Please sign in to comment.