Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up docker image building and switch base image to alpine #17731

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@
**/*.jar
**/*.class
dist
target

**/target

# To support building the docker image from the distribution file built on host machine,
# we need to keep binary files under the target directory of distribution module.
# This rule MUST be after above '**/target' rule
!distribution/target/*-bin.tar.gz

*.iml
*.ipr
*.iws
Expand All @@ -35,3 +42,4 @@ target
*.DS_Store
_site
dependency-reduced-pom.xml
**/node_modules
1 change: 1 addition & 0 deletions .github/workflows/distribution-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ on:
- '[0-9]+.[0-9]+.[0-9]+-[A-Za-z0-9]+' # release branches
paths:
- 'distribution/**'
- 'web-console/**'
- '**/pom.xml'
pull_request:
branches:
Expand Down
118 changes: 73 additions & 45 deletions distribution/docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,68 +19,96 @@

ARG JDK_VERSION=17

# By default we build the entire distribution from source in docker
# This can be unset if the tarball was already built outside of Docker
ARG BUILD_FROM_SOURCE="true"

#===============================================================
# web-console building stage
#===============================================================
# The platform is explicitly specified as x64 to build the Druid distribution.
# This is because it's not able to build the distribution on arm64 due to dependency problem of web-console. See: https://github.com/apache/druid/issues/13012
# Since only java jars are shipped in the final image, it's OK to build the distribution on x64.
# Once the web-console dependency problem is resolved, we can remove the --platform directive.
FROM --platform=linux/amd64 maven:3.9 as builder

# Rebuild from source in this stage
# This can be unset if the tarball was already built outside of Docker
ARG BUILD_FROM_SOURCE="true"

RUN export DEBIAN_FRONTEND=noninteractive \
&& apt-get -qq update \
FROM --platform=linux/amd64 node:20.9.0-slim AS web-console-builder

RUN npm install -g [email protected]

# Only copy necessary files to web-console to build to try the best to use docker cache
COPY ./web-console /src/web-console
COPY ./docs /src/docs
WORKDIR /src/web-console

# Re-declare the ARG to make it available in this stage
ARG BUILD_FROM_SOURCE

# Suppress a building error saying error:0308010C:digital envelope routines::unsupported
ENV NODE_OPTIONS=--openssl-legacy-provider

# The directory of output, during the package stage, files will be copied from this directory
RUN mkdir /output

# The ls command below is just for debug purpose helping us know which files are updated that docker cache are invalidated
RUN if [ "$BUILD_FROM_SOURCE" = "true" ]; then \
ls -l && \
npm ci \
; fi
RUN if [ "$BUILD_FROM_SOURCE" = "true" ]; then \
./script/build \
&& ./script/cp-to ./output \
; fi

#===============================================================
# Declare a builder stage to build the Druid distribution
#===============================================================
FROM maven:3.9.9-eclipse-temurin-${JDK_VERSION} AS builder
RUN apt-get -qq update \
&& apt-get -qq -y install --no-install-recommends python3 python3-yaml

COPY . /src
WORKDIR /src

# Copy the web-console resources from the web-console-builder to include it in this stage to package
COPY --from=web-console-builder /output /src/web-console/target/resources

# Re-declare the ARG to make it available in this stage
ARG BUILD_FROM_SOURCE

# Note: use web.console.skip to exclude building of web-console but include the package of web-console
RUN --mount=type=cache,target=/root/.m2 if [ "$BUILD_FROM_SOURCE" = "true" ]; then \
mvn -B -ff -q \
rm -fr distribution/target/ && \
mvn -B -ff -ntp \
install \
-Pdist,bundle-contrib-exts \
-Pskip-static-checks,skip-tests \
-Dmaven.javadoc.skip=true -T1C \
; fi

RUN --mount=type=cache,target=/root/.m2 VERSION=$(mvn -B -q org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.version -DforceStdout=true \
) \
&& tar -zxf ./distribution/target/apache-druid-${VERSION}-bin.tar.gz -C /opt \
&& mv /opt/apache-druid-${VERSION} /opt/druid

FROM alpine:3 as bash-static
ARG TARGETARCH
#
# Download bash-static binary to execute scripts that require bash.
# Although bash-static supports multiple platforms, but there's no need for us to support all those platform, amd64 and arm64 are enough.
#
ARG BASH_URL_BASE="https://github.com/robxu9/bash-static/releases/download/5.1.016-1.2.3"
RUN if [ "$TARGETARCH" = "arm64" ]; then \
BASH_URL="${BASH_URL_BASE}/bash-linux-aarch64" ; \
elif [ "$TARGETARCH" = "amd64" ]; then \
BASH_URL="${BASH_URL_BASE}/bash-linux-x86_64" ; \
else \
echo "Unsupported architecture ($TARGETARCH)" && exit 1; \
fi; \
echo "Downloading bash-static from ${BASH_URL}" \
&& wget ${BASH_URL} -O /bin/bash

FROM busybox:1.35.0-glibc as busybox

FROM gcr.io/distroless/java$JDK_VERSION-debian12
-Dweb.console.skip=true \
-pl '!org.apache.druid:druid-benchmarks, !org.apache.druid:druid-integration-tests, !org.apache.druid.integration-tests:druid-it-tools, !org.apache.druid.integration-tests:druid-it-image, !org.apache.druid.integration-tests:druid-it-cases' \
-T1C \
; fi


# RUN ls ./distribution/target
RUN DISTRIBUTION=$(ls ./distribution/target/apache-druid-*-bin.tar.gz) \
&& tar -zxf ${DISTRIBUTION} -C /opt \
&& mv /opt/apache-druid-* /opt/druid

#===============================================================
# Final stage
#===============================================================
# Above bulding staging uses images based on eclipse-temurin,
# however here we directly use alpine because eclipse-temurin-alpine for JRE17 does not ship a image with ARM64 architecture.
FROM alpine:latest
LABEL maintainer="Apache Druid Developers <[email protected]>"

COPY --from=busybox /bin/busybox /busybox/busybox
RUN ["/busybox/busybox", "--install", "/bin"]
# Re-daclare the ARG to make it available in this stage
ARG JDK_VERSION


RUN addgroup -S -g 1000 druid \
# Install necessary packages to easier debugging
RUN apk add --no-cache openjdk${JDK_VERSION}-jre bash curl net-tools strace lsof \
&& addgroup -S -g 1000 druid \
&& adduser -S -u 1000 -D -H -h /opt/druid -s /bin/sh -g '' -G druid druid


COPY --from=bash-static /bin/bash /bin/bash
RUN chmod 755 /bin/bash
ENV JAVA_HOME=/usr/lib/jvm/java-${JDK_VERSION}-openjdk

COPY distribution/docker/druid.sh /druid.sh
COPY distribution/docker/peon.sh /peon.sh
Expand Down
19 changes: 7 additions & 12 deletions distribution/docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,18 @@

## Build

From the root of the repo, run following command:
From the root of the repo, run the following command:

```bash
DOCKER_BUILDKIT=1 docker build -t apache/druid:tag -f distribution/docker/Dockerfile .
```

### Building images on Apple M1/M2
To build images on Apple M1/M2, you need to follow the instructions in this section.

1. build Druid distribution from the root of the repo
```bash
mvn clean package -DskipTests -Pdist
```
2. build target image
```
DOCKER_BUILDKIT=1 docker build -t apache/druid:tag -f distribution/docker/Dockerfile --build-arg BUILD_FROM_SOURCE=false .
```
There are two extra build arguments that can be passed to the build command by using `--build-arg` flag.

| Building argument | Description | Default value |
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
| JDK_VERSION | The version of JDK to use. By default JDK 17 is used. Use 17 and above. | 17 |
| BUILD_FROM_SOURCE | Whether to build Druid from source inside docker.<br/> If you already build the distribution outside the docker, you can manully set this argument to false to speed up building. | true |

## Run

Expand Down
8 changes: 7 additions & 1 deletion distribution/docker/druid.sh
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,13 @@ fi
DRUID_SET_HOST_IP=${DRUID_SET_HOST_IP:-0}
if [ "${DRUID_SET_HOST_IP}" = "1" ]
then
setKey $SERVICE druid.host $(ip r get 1 | awk '{print $7;exit}')
# Get local ip from the 'ip' tool
IP=$(ip r get 1 | awk '{print $7;exit}')
if [ -z "$IP" ]; then
echo "ERROR: IP address not found."
exit 1
fi
setKey $SERVICE druid.host $IP
fi

env | grep ^druid_ | while read evar;
Expand Down
2 changes: 1 addition & 1 deletion web-console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"sasslint-fix-changed-only": "npm run sasslint-changed-only -- --fix",
"prettify": "prettier --write '{src,e2e-tests}/**/*.{ts,tsx,scss}' './*.js'",
"prettify-check": "prettier --check '{src,e2e-tests}/**/*.{ts,tsx,scss}' './*.js'",
"generate-licenses-file": "license-checker --production --json --out licenses.json",
"generate-licenses-file": "license-checker --production --json --out target/licenses.json",
"check-licenses": "license-checker --production --onlyAllow 'Apache-1.1;Apache-2.0;BSD-2-Clause;BSD-3-Clause;0BSD;MIT;ISC;CC0-1.0;OFL-1.1' --summary",
"start": "webpack serve"
},
Expand Down
8 changes: 7 additions & 1 deletion web-console/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
<properties>
<resources.directory>${project.build.directory}/resources</resources.directory>
<web.console.skip>false</web.console.skip> <!-- this property is overidden in Travis CI to skip the javascript-related work -->

<!--
NOTE: When changing the following properties, the docker base image specified in distribution/docker/Dockerfile must be updated accordingly
-->
<node.version>v20.9.0</node.version>
<npm.version>10.9.0</npm.version>
</properties>
Expand Down Expand Up @@ -150,11 +154,13 @@
</executions>
</plugin>
<plugin>
<!--
The web.console.skip is NOT applied to this stage as this is required for web-console package when building docker image
-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<outputDirectory>${project.build.outputDirectory}/org/apache/druid/console</outputDirectory>
<skip>${web.console.skip}</skip>
</configuration>
</plugin>
</plugins>
Expand Down
Loading