Skip to content

Commit 11cdc04

Browse files
committed
K9db builds and runs on Apple sillicon and Arm64
* Add Dockerfile for dev on arm64 * Make release Dockerfile work on both architecture * Bug fixes with rust ffi, libsodium, and jvm/bazel to make things work on arm64
1 parent 4611b9d commit 11cdc04

19 files changed

Lines changed: 1579 additions & 50 deletions
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: "Dev tests (arm64)"
2+
on:
3+
push:
4+
branches:
5+
- 'main'
6+
pull_request:
7+
branches:
8+
- 'main'
9+
10+
jobs:
11+
test:
12+
runs-on: ubuntu-24.04-arm
13+
steps:
14+
- uses: actions/checkout@v4
15+
with:
16+
submodules: recursive
17+
18+
# Docker setup.
19+
- name: Build docker container
20+
run: |
21+
docker build --no-cache -f Dockerfile.dev.arm64 -t k9db/dev-arm64 .
22+
23+
# Run docker (rust dependencies are vendored, no setup needed).
24+
- name: Run docker container
25+
run: |
26+
docker run --mount type=bind,source=$(pwd),target=/home/k9db --name k9db -d -t k9db/dev-arm64
27+
sleep 10
28+
docker logs k9db
29+
30+
# bazel build ...
31+
- name: Build all
32+
run: |
33+
docker exec k9db sh -c "cd /home/k9db && bazel build ..."
34+
35+
# bazel test all (with encryption; on by default)
36+
- name: Test all
37+
run: docker exec k9db sh -c "cd /home/k9db && bazel test ... --test_output=all"
38+
39+
# bazel test all without encryption
40+
- name: Test all no encryption
41+
run: docker exec k9db sh -c "cd /home/k9db && bazel test ... --encryption=off --test_output=all"
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: "Test release Docker image (arm64)"
2+
on:
3+
push:
4+
branches:
5+
- 'main'
6+
pull_request:
7+
branches:
8+
- 'main'
9+
10+
jobs:
11+
release-test:
12+
runs-on: ubuntu-24.04-arm
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
# The arm64 runner image may not ship a mysql client.
17+
- name: Install mysql client
18+
run: sudo apt-get update && sudo apt-get install -y mysql-client
19+
20+
# (1) Build the release image.
21+
- name: Build release docker image
22+
run: docker build -f Dockerfile.release -t k9db:test .
23+
24+
# (2) Run it with a named volume for the database files.
25+
- name: Run k9db container
26+
run: |
27+
docker volume create k9db-data
28+
docker run -d --name k9db -p 10001:10001 -v k9db-data:/var/lib/k9db k9db:test
29+
./tests/release/wait-for-k9db.sh k9db
30+
31+
# (3) + (4) Feed sql into k9db and check the output of each statement.
32+
- name: Create schema and insert data
33+
run: |
34+
mysql --host=127.0.0.1 --port=10001 < tests/release/01-schema.sql | tee out.txt
35+
test ! -s out.txt # DDL and inserts produce no output.
36+
37+
- name: Check point lookups
38+
run: |
39+
mysql --host=127.0.0.1 --port=10001 < tests/release/02-selects.sql | tee out.txt
40+
diff tests/release/02-selects.expected out.txt
41+
42+
- name: Check view (calcite planner / dataflow)
43+
run: |
44+
mysql --host=127.0.0.1 --port=10001 < tests/release/03-view.sql | tail -n +2 | tee out.txt
45+
diff tests/release/03-view.expected out.txt
46+
47+
# (5) Stop and remove the container; (6) run a fresh one on the same volume.
48+
- name: Replace container (data must persist)
49+
run: |
50+
docker stop k9db
51+
docker rm k9db
52+
docker run -d --name k9db -p 10001:10001 -v k9db-data:/var/lib/k9db k9db:test
53+
./tests/release/wait-for-k9db.sh k9db
54+
55+
# (7) The old data (incl. the view) must have survived, and writes work.
56+
- name: Check persisted point lookups
57+
run: |
58+
mysql --host=127.0.0.1 --port=10001 < tests/release/02-selects.sql | tee out.txt
59+
diff tests/release/02-selects.expected out.txt
60+
61+
- name: Check persisted view
62+
run: |
63+
mysql --host=127.0.0.1 --port=10001 < tests/release/03-view.sql | tail -n +2 | tee out.txt
64+
diff tests/release/03-view.expected out.txt
65+
66+
- name: Check write after restart
67+
run: |
68+
mysql --host=127.0.0.1 --port=10001 < tests/release/04-write-after-restart.sql | tee out.txt
69+
diff tests/release/04-write-after-restart.expected out.txt
70+
71+
- name: Dump k9db logs on failure
72+
if: failure()
73+
run: docker logs k9db || true

Dockerfile.dev.arm64

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Docker image for lightweight k9db development on arm64 (e.g. Apple Silicon
2+
# Macs): building from source and running tests, plus re-vendoring the rust
3+
# dependencies. Unlike Dockerfile.dev, this image does NOT include the
4+
# experiment pipeline (mariadb baselines, memcached, latex/plotting).
5+
FROM ubuntu:24.04
6+
7+
ENV DEBIAN_FRONTEND=noninteractive
8+
ENV LANG=C.UTF-8
9+
# /root/.cargo/bin: rust/cargo (installed below) available in every shell.
10+
ENV PATH=/root/.cargo/bin:/usr/local/bin:$PATH
11+
12+
# Add apt-add-repository and the ppa for gcc-11.
13+
RUN apt-get update && apt-get install -y software-properties-common \
14+
&& add-apt-repository -y ppa:ubuntu-toolchain-r/test
15+
16+
# Build dependencies.
17+
RUN apt-get update && apt-get install -y \
18+
apt-utils libssl-dev lsb-release openssl git \
19+
build-essential zlib1g-dev libbz2-dev liblzma-dev libffi-dev \
20+
wget gcc-11 g++-11 unzip zip pkg-config \
21+
openjdk-11-jdk curl libclang-dev clang \
22+
libsnappy-dev python3 python3-dev mariadb-client \
23+
&& ln -sf /usr/bin/python3 /usr/bin/python
24+
25+
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 90 \
26+
--slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-11 \
27+
--slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-11 \
28+
--slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-11 \
29+
--slave /usr/bin/g++ g++ /usr/bin/g++-11 \
30+
&& update-alternatives --set gcc /usr/bin/gcc-11
31+
32+
# Install bazel 4.0. No installer script is published for linux-arm64, so
33+
# download the standalone binary directly.
34+
RUN wget -O /usr/local/bin/bazel \
35+
https://github.com/bazelbuild/bazel/releases/download/4.0.0/bazel-4.0.0-linux-arm64 \
36+
&& chmod +x /usr/local/bin/bazel
37+
38+
# Install rust and cargo-raze. The raze outputs (**/cargo/) are vendored in
39+
# the repo; cargo-raze is only needed to re-vendor them after changing rust
40+
# dependencies: run ./vendor-rust.sh from the repo root and commit the changes.
41+
RUN curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly-2023-12-06
42+
RUN git clone https://github.com/KinanBab/cargo-raze.git /home/cargo-raze \
43+
&& cargo install --locked --path /home/cargo-raze/impl
44+
45+
# The k9db repo is bind-mounted here during docker run (do not copy).
46+
RUN mkdir /home/k9db
47+
48+
# Generate docker.bazelrc (imported by the repo's .bazelrc).
49+
RUN printf '%s\n' \
50+
"test:asan --test_env LSAN_OPTIONS=suppressions=/home/k9db/.lsan_jvm_suppress.txt" \
51+
"test:tsan --test_env LSAN_OPTIONS=suppressions=/home/k9db/.lsan_jvm_suppress.txt" \
52+
"test:tsan --test_env TSAN_OPTIONS=suppressions=/home/k9db/.tsan_jvm_suppress.txt" \
53+
> /home/docker.bazelrc
54+
55+
EXPOSE 10001/tcp
56+
57+
ENTRYPOINT ["/bin/bash"]
58+
59+
# Run with docker run --mount type=bind,source=$(pwd),target=/home/k9db --name k9db-arm64 -it -p 10001:10001 k9db/dev-arm64

Dockerfile.release

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# Stage 1: build k9db from source.
1818
##############################################################################
1919
FROM ubuntu:24.04 AS build
20+
ARG TARGETARCH
2021

2122
ENV DEBIAN_FRONTEND=noninteractive
2223
ENV LANG=C.UTF-8
@@ -31,7 +32,7 @@ RUN apt-get update && apt-get install -y \
3132
apt-utils libssl-dev lsb-release openssl git \
3233
build-essential zlib1g-dev libbz2-dev liblzma-dev libffi-dev \
3334
wget gcc-11 g++-11 unzip zip pkg-config \
34-
openjdk-11-jdk curl libclang-dev libevent-dev \
35+
openjdk-11-jdk curl libclang-dev clang libevent-dev \
3536
libsnappy-dev python3 python3-dev
3637

3738
RUN ln -sf /usr/bin/python3 /usr/bin/python
@@ -43,12 +44,19 @@ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 90 \
4344
--slave /usr/bin/g++ g++ /usr/bin/g++-11 \
4445
&& update-alternatives --set gcc /usr/bin/gcc-11
4546

46-
# Install bazel 4.0.
47-
RUN cd /tmp \
48-
&& wget https://github.com/bazelbuild/bazel/releases/download/4.0.0/bazel-4.0.0-installer-linux-x86_64.sh \
49-
&& chmod +x bazel-4.0.0-installer-linux-x86_64.sh \
50-
&& ./bazel-4.0.0-installer-linux-x86_64.sh \
51-
&& rm bazel-4.0.0-installer-linux-x86_64.sh
47+
# Install bazel 4.0. No installer script is published for linux-arm64, so
48+
# download the standalone binary directly on arm64.
49+
RUN if [ "$TARGETARCH" = "arm64" ]; then \
50+
wget -O /usr/local/bin/bazel \
51+
https://github.com/bazelbuild/bazel/releases/download/4.0.0/bazel-4.0.0-linux-arm64 \
52+
&& chmod +x /usr/local/bin/bazel; \
53+
else \
54+
cd /tmp \
55+
&& wget https://github.com/bazelbuild/bazel/releases/download/4.0.0/bazel-4.0.0-installer-linux-x86_64.sh \
56+
&& chmod +x bazel-4.0.0-installer-linux-x86_64.sh \
57+
&& ./bazel-4.0.0-installer-linux-x86_64.sh \
58+
&& rm bazel-4.0.0-installer-linux-x86_64.sh; \
59+
fi
5260

5361
# Copy sources (see .dockerignore for exclusions). The bazel rules for the
5462
# proxy's rust dependencies (k9db/proxy/cargo/) are vendored in the repo, so
@@ -75,6 +83,7 @@ RUN BIN="$(bazel info bazel-bin --config opt)" \
7583
# Stage 2: minimal runtime image.
7684
##############################################################################
7785
FROM ubuntu:24.04 AS runtime
86+
ARG TARGETARCH
7887

7988
ENV DEBIAN_FRONTEND=noninteractive
8089
ENV LANG=C.UTF-8
@@ -91,7 +100,8 @@ COPY --from=build /opt/k9db /opt/k9db
91100
# the working directory, so this must be /opt/k9db.
92101
WORKDIR /opt/k9db
93102

94-
ENV LD_LIBRARY_PATH=/opt/k9db/lib:/usr/lib/jvm/java-11-openjdk-amd64/lib/server:/usr/lib/jvm/java-11-openjdk-amd64/lib
103+
# The jvm directory suffix matches docker's TARGETARCH (amd64/arm64).
104+
ENV LD_LIBRARY_PATH=/opt/k9db/lib:/usr/lib/jvm/java-11-openjdk-${TARGETARCH}/lib/server:/usr/lib/jvm/java-11-openjdk-${TARGETARCH}/lib
95105
# Send glog output to the container log instead of files in /tmp.
96106
ENV GLOG_logtostderr=1
97107

README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,22 @@ or use our [provided Docker container](https://github.com/brownsys/K9db/wiki/Req
4949

5050
You can then use bazel to [build and run K9db](https://github.com/brownsys/K9db/wiki/Building,-Testing,-and-Running).
5151

52-
K9db does not currently build on Mac machines with M1/M2 processors, even when using the Docker container.
52+
K9db also builds and runs on Apple Silicon Macs (M series) using Docker, as a
53+
native arm64 Linux container: the release image is multi-arch, and a
54+
lightweight arm64 development image is provided (see the section below).
55+
Native (non-Docker) macOS builds are not supported.
5356

5457
## Using Docker
5558

56-
The repository provides two Docker images.
59+
The repository provides Docker images for running K9db and for developing it.
5760

5861
### Running K9db (release image)
5962

6063
`Dockerfile.release` packages K9db into a small self-contained image: an
6164
intermediate stage builds K9db from source, and only the compiled server and
62-
its runtime dependencies are shipped in the final image.
65+
its runtime dependencies are shipped in the final image. The image is
66+
multi-arch: it builds natively on both x86_64 and arm64 (e.g. Apple Silicon
67+
Macs) hosts.
6368

6469
```bash
6570
docker build -f Dockerfile.release -t k9db .
@@ -92,6 +97,22 @@ docker exec -it k9db-dev /bin/bash
9297
cd /home/k9db && bazel build ... && bazel test ...
9398
```
9499

100+
`Dockerfile.dev` is x86_64-only.
101+
102+
On arm64 machines (e.g. Apple Silicon Macs), use `Dockerfile.dev.arm64` instead:
103+
a lightweight development image that can build K9db from source,
104+
run the tests, and re-vendor the rust dependencies,
105+
but does not include the experiments pipeline (mariadb baselines, memcached,
106+
and plotting):
107+
108+
```bash
109+
docker build -f Dockerfile.dev.arm64 -t k9db/dev-arm64 .
110+
docker run --mount type=bind,source=$(pwd),target=/home/k9db --name k9db-dev -d -it -p 10001:10001 k9db/dev-arm64
111+
docker exec -it k9db-dev /bin/bash
112+
# Inside the container:
113+
cd /home/k9db && bazel build ... && bazel test ...
114+
```
115+
95116
### Re-vendoring rust dependencies (devs)
96117

97118
The bazel BUILD files for the rust (cargo) dependencies of the proxy and of

WORKSPACE.bazel

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,23 @@ workspace(name = "k9db")
33
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
44
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository")
55

6+
# Override bazel's builtin remote_java_tools_linux (same archive bazel 4.0.0
7+
# ships with) to patch a missing '#include <limits>' in ijar's zlib_client.h.
8+
# On x86_64 this doesn't matter (bazel uses the prebuilt ijar binary), but on
9+
# arm64 there is no prebuilt ijar, so it is compiled from source and fails
10+
# against newer libstdc++ where <limits> is no longer transitively included.
11+
http_archive(
12+
name = "remote_java_tools_linux",
13+
patch_cmds = [
14+
"grep -rl numeric_limits java_tools --include=*.h --include=*.cc | xargs sed -i '1i #include <limits>'",
15+
],
16+
sha256 = "355c27c603e8fc64bb0e2d7f809741f42576d5f4540f9ce28fd55922085af639",
17+
urls = [
18+
"https://mirror.bazel.build/bazel_java_tools/releases/javac11/v10.5/java_tools_javac11_linux-v10.5.zip",
19+
"https://github.com/bazelbuild/java_tools/releases/download/javac11_v10.5/java_tools_javac11_linux-v10.5.zip",
20+
],
21+
)
22+
623

724
# Rules java
825
http_archive(
@@ -361,12 +378,24 @@ filegroup(
361378
362379
configure_make(
363380
name = "libsodium",
381+
# libsodium only enables its aarch64 AES256-GCM implementation when
382+
# compiled with clang (the code is gated on __clang__). Override CFLAGS
383+
# and LDFLAGS as they carry gcc-only flags from the bazel toolchain that
384+
# clang rejects; configure arguments take precedence over the environment.
385+
configure_options = select({
386+
"@platforms//cpu:aarch64": [
387+
"CC=clang",
388+
"CFLAGS='-O2 -fPIC'",
389+
"LDFLAGS=",
390+
],
391+
"//conditions:default": [],
392+
}),
364393
lib_source = ":all_srcs",
365394
out_lib_dir = "lib",
366395
visibility = ["//visibility:public"],
367396
)
368397
""",
369-
strip_prefix = "libsodium-1.0.18-RELEASE",
398+
strip_prefix = "libsodium-1.0.20-RELEASE",
370399
type = "zip",
371-
url = "https://github.com/jedisct1/libsodium/archive/1.0.18-RELEASE.zip",
400+
url = "https://github.com/jedisct1/libsodium/archive/1.0.20-RELEASE.zip",
372401
)

k9db/planner/calcite/src/com/brownsys/k9db/nativelib/BUILD.bazel

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,15 @@ genrule(
9191
com/brownsys/k9db/nativelib/DataFlowGraphLibrary.java
9292
9393
# Move outputs to proper directory and remove tmp directory.
94+
# javacpp writes the library to a platform-specific directory
95+
# (e.g. linux-x86_64/ or linux-arm64/), so glob instead of hardcoding.
9496
cd $${EXEC_PATH}
95-
if [ -f $${PCKG_DIR}linux-x86_64/libjniDataFlowGraphLibrary.so ]; then
96-
mv $${PCKG_DIR}linux-x86_64/libjniDataFlowGraphLibrary.so $@
97-
else
98-
touch $@
97+
JNILIB=$$(ls $${PCKG_DIR}linux-*/libjniDataFlowGraphLibrary.so 2>/dev/null | head -1)
98+
if [ -z "$${JNILIB}" ]; then
99+
echo "ERROR: javacpp did not produce libjniDataFlowGraphLibrary.so" >&2
100+
exit 1
99101
fi
102+
mv $${JNILIB} $@
100103
rm -rf $${TMP_DIR}
101104
""",
102105
tools = ["@maven//:org_bytedeco_javacpp"],

0 commit comments

Comments
 (0)