Skip to content

Commit 264da9e

Browse files
committed
fix(docker): build the image from an allowlisted context in a builder stage
- Send only the build inputs to the Docker build context: .dockerignore is an allowlist, which keeps VCS metadata and CI-written files out of it. - Bind-mount the build context into a separate builder stage instead of COPYing it. The final stage gets only the playwright-java artifacts of the local Maven repository and runs the CLI from a bind mount of the builder's classes and runtime dependencies.
1 parent bc1337e commit 264da9e

5 files changed

Lines changed: 96 additions & 61 deletions

File tree

‎.dockerignore‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
# The repository root is the Docker build context (see utils/docker/build.sh),
2-
# and the image build copies all of it. Keep VCS metadata, registry credentials
3-
# and local environment files out of the build context.
1+
# The repository root is the Docker build context (see utils/docker/build.sh).
2+
# Send only what the image build reads, which keeps VCS metadata, registry
3+
# credentials and local environment files out of the build context.
4+
*
5+
!pom.xml
6+
!driver
7+
!driver-bundle
8+
!playwright
9+
!utils/docker/maven
10+
**/target
411
**/.git
512
**/.npmrc
613
**/.env*
7-
# Downloaded by publish_docker.sh after the first push.
8-
utils/docker/oras

‎utils/docker/Dockerfile.jammy‎

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
ARG ACR_CACHE_PREFIX
2-
FROM ${ACR_CACHE_PREFIX}ubuntu:jammy
2+
FROM ${ACR_CACHE_PREFIX}ubuntu:jammy AS base
33

44
ARG DEBIAN_FRONTEND=noninteractive
55
ARG TZ=America/Los_Angeles
@@ -38,8 +38,26 @@ RUN --mount=type=bind,source=utils/docker/maven,target=/tmp/maven \
3838
ARG PW_TARGET_ARCH
3939
ENV JAVA_HOME=/usr/lib/jvm/java-25-openjdk-${PW_TARGET_ARCH}
4040

41+
# === BUILD PLAYWRIGHT JAVA ===
42+
43+
# The image gets only what the final stage explicitly copies or mounts from this stage.
44+
FROM base AS builder
45+
46+
# The optional Maven settings secret routes dependency resolution through a mirror
47+
# (see .azure-pipelines/publish-docker.yml). The CLI runs from /build: the classes of
48+
# the playwright module and its runtime dependencies.
49+
RUN --mount=type=bind,source=.,target=/tmp/pw-java,rw \
50+
--mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
51+
cd /tmp/pw-java && \
52+
mvn install -D skipTests --no-transfer-progress && \
53+
mvn dependency:copy-dependencies -D includeScope=runtime -D outputDirectory=/build/lib \
54+
-f playwright/pom.xml --no-transfer-progress && \
55+
cp -r playwright/target/classes /build/classes
56+
4157
# === BAKE BROWSERS INTO IMAGE ===
4258

59+
FROM base
60+
4361
# Browsers will remain downloaded in `/ms-playwright`.
4462
# Note: make sure to set 777 to the registry so that any user can access
4563
# registry.
@@ -50,25 +68,17 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
5068
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
5169
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
5270

53-
RUN mkdir /ms-playwright && \
54-
mkdir /tmp/pw-java
71+
# Keep the playwright-java artifacts in the local Maven repository so that Maven projects
72+
# built in the image resolve them without downloading.
73+
COPY --from=builder /root/.m2/repository/com/microsoft/playwright /root/.m2/repository/com/microsoft/playwright
5574

56-
COPY . /tmp/pw-java
75+
RUN mkdir /ms-playwright
5776

58-
# The optional Maven settings secret routes dependency resolution through a mirror
59-
# (see .azure-pipelines/publish-docker.yml).
60-
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
61-
cd /tmp/pw-java && \
62-
mvn install -D skipTests --no-transfer-progress && \
63-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
64-
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
65-
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
66-
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
67-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
68-
-D exec.args="install" -f playwright/pom.xml --no-transfer-progress && \
69-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
70-
-D exec.args="mark-docker-image '${DOCKER_IMAGE_NAME_TEMPLATE}'" -f playwright/pom.xml --no-transfer-progress && \
71-
rm -rf /tmp/pw-java && \
77+
RUN --mount=type=bind,from=builder,source=/build,target=/tmp/pw-java \
78+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install-driver && \
79+
DEBIAN_FRONTEND=noninteractive java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install-deps && \
80+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install && \
81+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
7282
# Workaround for https://github.com/microsoft/playwright/issues/27313
7383
# While the gstreamer plugin load process can be in-process, it ended up throwing
7484
# an error that it can't have libsoup2 and libsoup3 in the same process because

‎utils/docker/Dockerfile.noble‎

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
ARG ACR_CACHE_PREFIX
2-
FROM ${ACR_CACHE_PREFIX}ubuntu:noble
2+
FROM ${ACR_CACHE_PREFIX}ubuntu:noble AS base
33

44
ARG DEBIAN_FRONTEND=noninteractive
55
ARG TZ=America/Los_Angeles
@@ -38,8 +38,26 @@ RUN --mount=type=bind,source=utils/docker/maven,target=/tmp/maven \
3838
ARG PW_TARGET_ARCH
3939
ENV JAVA_HOME=/usr/lib/jvm/java-25-openjdk-${PW_TARGET_ARCH}
4040

41+
# === BUILD PLAYWRIGHT JAVA ===
42+
43+
# The image gets only what the final stage explicitly copies or mounts from this stage.
44+
FROM base AS builder
45+
46+
# The optional Maven settings secret routes dependency resolution through a mirror
47+
# (see .azure-pipelines/publish-docker.yml). The CLI runs from /build: the classes of
48+
# the playwright module and its runtime dependencies.
49+
RUN --mount=type=bind,source=.,target=/tmp/pw-java,rw \
50+
--mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
51+
cd /tmp/pw-java && \
52+
mvn install -D skipTests --no-transfer-progress && \
53+
mvn dependency:copy-dependencies -D includeScope=runtime -D outputDirectory=/build/lib \
54+
-f playwright/pom.xml --no-transfer-progress && \
55+
cp -r playwright/target/classes /build/classes
56+
4157
# === BAKE BROWSERS INTO IMAGE ===
4258

59+
FROM base
60+
4361
# Browsers will remain downloaded in `/ms-playwright`.
4462
# Note: make sure to set 777 to the registry so that any user can access
4563
# registry.
@@ -50,24 +68,16 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
5068
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
5169
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
5270

53-
RUN mkdir /ms-playwright && \
54-
mkdir /tmp/pw-java
71+
# Keep the playwright-java artifacts in the local Maven repository so that Maven projects
72+
# built in the image resolve them without downloading.
73+
COPY --from=builder /root/.m2/repository/com/microsoft/playwright /root/.m2/repository/com/microsoft/playwright
5574

56-
COPY . /tmp/pw-java
75+
RUN mkdir /ms-playwright
5776

58-
# The optional Maven settings secret routes dependency resolution through a mirror
59-
# (see .azure-pipelines/publish-docker.yml).
60-
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
61-
cd /tmp/pw-java && \
62-
mvn install -D skipTests --no-transfer-progress && \
63-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
64-
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
65-
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
66-
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
67-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
68-
-D exec.args="install" -f playwright/pom.xml --no-transfer-progress && \
69-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
70-
-D exec.args="mark-docker-image '${DOCKER_IMAGE_NAME_TEMPLATE}'" -f playwright/pom.xml --no-transfer-progress && \
71-
rm -rf /tmp/pw-java && \
77+
RUN --mount=type=bind,from=builder,source=/build,target=/tmp/pw-java \
78+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install-driver && \
79+
DEBIAN_FRONTEND=noninteractive java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install-deps && \
80+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install && \
81+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
7282
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
7383
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR

‎utils/docker/Dockerfile.resolute‎

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
ARG ACR_CACHE_PREFIX
2-
FROM ${ACR_CACHE_PREFIX}ubuntu:resolute
2+
FROM ${ACR_CACHE_PREFIX}ubuntu:resolute AS base
33

44
ARG DEBIAN_FRONTEND=noninteractive
55
ARG TZ=America/Los_Angeles
@@ -32,8 +32,26 @@ RUN find /etc/apt -type f \( -name '*.list' -o -name '*.sources' \) \
3232
ARG PW_TARGET_ARCH
3333
ENV JAVA_HOME=/usr/lib/jvm/java-25-openjdk-${PW_TARGET_ARCH}
3434

35+
# === BUILD PLAYWRIGHT JAVA ===
36+
37+
# The image gets only what the final stage explicitly copies or mounts from this stage.
38+
FROM base AS builder
39+
40+
# The optional Maven settings secret routes dependency resolution through a mirror
41+
# (see .azure-pipelines/publish-docker.yml). The CLI runs from /build: the classes of
42+
# the playwright module and its runtime dependencies.
43+
RUN --mount=type=bind,source=.,target=/tmp/pw-java,rw \
44+
--mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
45+
cd /tmp/pw-java && \
46+
mvn install -D skipTests --no-transfer-progress && \
47+
mvn dependency:copy-dependencies -D includeScope=runtime -D outputDirectory=/build/lib \
48+
-f playwright/pom.xml --no-transfer-progress && \
49+
cp -r playwright/target/classes /build/classes
50+
3551
# === BAKE BROWSERS INTO IMAGE ===
3652

53+
FROM base
54+
3755
# Browsers will remain downloaded in `/ms-playwright`.
3856
# Note: make sure to set 777 to the registry so that any user can access
3957
# registry.
@@ -44,24 +62,16 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
4462
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
4563
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
4664

47-
RUN mkdir /ms-playwright && \
48-
mkdir /tmp/pw-java
65+
# Keep the playwright-java artifacts in the local Maven repository so that Maven projects
66+
# built in the image resolve them without downloading.
67+
COPY --from=builder /root/.m2/repository/com/microsoft/playwright /root/.m2/repository/com/microsoft/playwright
4968

50-
COPY . /tmp/pw-java
69+
RUN mkdir /ms-playwright
5170

52-
# The optional Maven settings secret routes dependency resolution through a mirror
53-
# (see .azure-pipelines/publish-docker.yml).
54-
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
55-
cd /tmp/pw-java && \
56-
mvn install -D skipTests --no-transfer-progress && \
57-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
58-
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
59-
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
60-
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
61-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
62-
-D exec.args="install" -f playwright/pom.xml --no-transfer-progress && \
63-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
64-
-D exec.args="mark-docker-image '${DOCKER_IMAGE_NAME_TEMPLATE}'" -f playwright/pom.xml --no-transfer-progress && \
65-
rm -rf /tmp/pw-java && \
71+
RUN --mount=type=bind,from=builder,source=/build,target=/tmp/pw-java \
72+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install-driver && \
73+
DEBIAN_FRONTEND=noninteractive java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install-deps && \
74+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI install && \
75+
java -cp '/tmp/pw-java/classes:/tmp/pw-java/lib/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
6676
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
6777
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR

‎utils/docker/build.sh‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ fi
3434

3535
PW_TARGET_ARCH=$(echo $1 | cut -c3-)
3636

37-
# Assemble the driver on the host where npm is available; the Dockerfile picks
38-
# it up via `COPY . /tmp/pw-java`.
37+
# Assemble the driver on the host where npm is available; the builder stage of the
38+
# Dockerfile picks it up from the build context.
3939
../../scripts/download_driver.sh
4040

4141
# The jammy and noble images install this Maven (see the Dockerfiles). Fetch it with the

0 commit comments

Comments
 (0)