From cb222b46a634aeb3c61949c45d78e6b5874ca4d4 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Fri, 8 Jul 2022 16:04:40 +0200 Subject: [PATCH 1/5] build image from scratch --- Dockerfile | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1102fb2970..a8026909c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,13 @@ #### Builder #### FROM node:18-alpine3.16 as builder +# get the latest security upgrades and install tini +RUN apk -U upgrade && apk add --no-cache tini + +# create node user and group +RUN echo 'node:x:1000:1000:node,,,:/home/node:/sbin/nologin' > /tmp/passwd \ + && echo 'node:x:1000:node' > /tmp/group + WORKDIR /usr/src/app COPY . . @@ -47,10 +54,7 @@ RUN cp -r frontend/dist /usr/src/build/public \ && find /usr/src/build/.yarn -mindepth 1 -name cache -prune -o -exec rm -rf {} + #### Release #### -FROM alpine:3.16 as release - -RUN addgroup -g 1000 node && adduser -u 1000 -G node -s /bin/sh -D node -RUN apk add --no-cache tini libstdc++ +FROM scratch as release WORKDIR /usr/src/app @@ -59,8 +63,16 @@ ENV NODE_ENV "production" ARG PORT=8080 ENV PORT $PORT -# copy node binary +# copy users and groups +COPY --from=builder /tmp/passwd /tmp/group /etc/ + +# copy binaries COPY --from=builder /usr/local/bin/node /usr/local/bin/ +COPY --from=builder /sbin/tini /sbin/ + +# copy libraries +COPY --from=builder /lib/ld-musl-x86_64.so* /lib/libcrypto.so* /lib/libssl.so* /lib/libz.so* /lib/ +COPY --from=builder /usr/lib/libstdc++.so* /usr/lib/libgcc_s.so* /usr/lib/engines-1.1 /usr/lib/ # copy production directory COPY --chown=node:node --from=builder /usr/src/build . From 9693c655f7d0f88ac277b3ae4f4f415bda49fc4c Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Fri, 8 Jul 2022 16:21:48 +0200 Subject: [PATCH 2/5] fix docker test --- backend/test/docker.spec.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/backend/test/docker.spec.js b/backend/test/docker.spec.js index 4c4eb56bfa..a677efb341 100644 --- a/backend/test/docker.spec.js +++ b/backend/test/docker.spec.js @@ -33,11 +33,6 @@ const activeNodeReleases = { } } -async function getNodeDockerfile (nodeVersion, alpineVersion) { - const body = await client.request(`${nodeVersion}/alpine${alpineVersion}/Dockerfile`) - return DockerfileParser.parse(body) -} - async function getDashboardDockerfile () { const filename = path.join(__dirname, '..', '..', 'Dockerfile') const data = await readFile(filename, 'utf8') @@ -66,12 +61,6 @@ describe('dockerfile', function () { const endOfLife = activeNodeReleases[nodeRelease].endOfLife // Node release ${nodeRelease} reached end of life. Update node base image in Dockerfile. expect(endOfLife.getTime()).toBeGreaterThan(Date.now()) - const dashboardReleaseBaseImage = buildStages.release.getImage() - const [, alpineVersion] = /alpine:(\d+\.\d+)/.exec(dashboardReleaseBaseImage) - const nodeDockerfile = await getNodeDockerfile(nodeRelease, alpineVersion) - expect(nodeDockerfile.getFROMs()).toHaveLength(1) - const nodeBaseImage = _.first(nodeDockerfile.getFROMs()).getImage() - // Alpine base images of "dashboard-release" image and "node" image do not match! - expect(dashboardReleaseBaseImage.endsWith(nodeBaseImage)).toBe(true) + expect(buildStages.release.getImage()).toBe('scratch') }, timeout) }) From b9da9a67f735012e2760629c2bceeca201547258 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Fri, 8 Jul 2022 16:24:54 +0200 Subject: [PATCH 3/5] fix lint error --- backend/test/docker.spec.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/backend/test/docker.spec.js b/backend/test/docker.spec.js index a677efb341..ecd05ecdec 100644 --- a/backend/test/docker.spec.js +++ b/backend/test/docker.spec.js @@ -12,10 +12,6 @@ const _ = require('lodash') const { promisify } = require('util') const readFile = promisify(fs.readFile) const { DockerfileParser } = require('dockerfile-ast') -const { extend, globalAgent } = jest.requireActual('@gardener-dashboard/request') -const client = extend({ - prefixUrl: 'https://raw.githubusercontent.com/nodejs/docker-node/main/' -}) /* Nodejs release schedule (see https://nodejs.org/en/about/releases/) */ const activeNodeReleases = { @@ -40,12 +36,6 @@ async function getDashboardDockerfile () { } describe('dockerfile', function () { - const timeout = 15 * 1000 - - afterAll(() => { - globalAgent.destroy() - }) - it('should have the same alpine base image as the corresponding node image', async function () { const dashboardDockerfile = await getDashboardDockerfile() @@ -62,5 +52,5 @@ describe('dockerfile', function () { // Node release ${nodeRelease} reached end of life. Update node base image in Dockerfile. expect(endOfLife.getTime()).toBeGreaterThan(Date.now()) expect(buildStages.release.getImage()).toBe('scratch') - }, timeout) + }) }) From 9b507fc6af2c444af32c63ac0c5de872f6296323 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Fri, 8 Jul 2022 17:06:26 +0200 Subject: [PATCH 4/5] remove even more libs --- Dockerfile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index a8026909c7..3fb685592c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -67,12 +67,10 @@ ENV PORT $PORT COPY --from=builder /tmp/passwd /tmp/group /etc/ # copy binaries -COPY --from=builder /usr/local/bin/node /usr/local/bin/ -COPY --from=builder /sbin/tini /sbin/ +COPY --from=builder /usr/local/bin/node /sbin/tini /bin/ # copy libraries -COPY --from=builder /lib/ld-musl-x86_64.so* /lib/libcrypto.so* /lib/libssl.so* /lib/libz.so* /lib/ -COPY --from=builder /usr/lib/libstdc++.so* /usr/lib/libgcc_s.so* /usr/lib/engines-1.1 /usr/lib/ +COPY --from=builder /lib/ld-musl-x86_64.so* /usr/lib/libstdc++.so* /usr/lib/libgcc_s.so* /lib/ # copy production directory COPY --chown=node:node --from=builder /usr/src/build . @@ -83,5 +81,5 @@ EXPOSE $PORT VOLUME ["/home/node"] -ENTRYPOINT [ "/sbin/tini", "--", "node", "--require=/usr/src/app/.pnp.cjs", "--experimental-loader=/usr/src/app/.pnp.loader.mjs"] +ENTRYPOINT [ "tini", "--", "node", "--require=/usr/src/app/.pnp.cjs", "--experimental-loader=/usr/src/app/.pnp.loader.mjs"] CMD ["server.js"] \ No newline at end of file From 08582e64770edd118a3d37e35bca18faae54ccf2 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Mon, 11 Jul 2022 15:49:26 +0200 Subject: [PATCH 5/5] final optimizations --- Dockerfile | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3fb685592c..75b794dc93 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,14 +5,7 @@ #### Builder #### FROM node:18-alpine3.16 as builder -# get the latest security upgrades and install tini -RUN apk -U upgrade && apk add --no-cache tini - -# create node user and group -RUN echo 'node:x:1000:1000:node,,,:/home/node:/sbin/nologin' > /tmp/passwd \ - && echo 'node:x:1000:node' > /tmp/group - -WORKDIR /usr/src/app +WORKDIR /app COPY . . @@ -49,31 +42,44 @@ RUN yarn workspace @gardener-dashboard/backend prod-install --pack /usr/src/ # run frontend build RUN yarn workspace @gardener-dashboard/frontend run build -# copy files to production directory -RUN cp -r frontend/dist /usr/src/build/public \ - && find /usr/src/build/.yarn -mindepth 1 -name cache -prune -o -exec rm -rf {} + +WORKDIR /volume + +RUN apk add --no-cache tini \ + # tini and node binaries + && mkdir -p ./sbin ./usr/local/bin \ + && cp /sbin/tini ./sbin/ \ + && cp /usr/local/bin/node ./usr/local/bin/ \ + # root ca certificates + && mkdir -p ./etc/ssl \ + && cp -r /etc/ssl/certs ./etc/ssl \ + # node user + && echo 'node:x:1000:1000:node,,,:/home/node:/sbin/nologin' > ./etc/passwd \ + && echo 'node:x:1000:node' > ./etc/group \ + && mkdir -p ./home/node \ + && chown 1000:1000 ./home/node \ + # libc, libgcc and libstdc++ libraries + && mkdir -p ./lib ./usr/lib \ + && cp -d /lib/ld-musl-x86_64.so.* ./lib \ + && cp -d /lib/libc.musl-x86_64.so.* ./lib \ + && cp -d /usr/lib/libgcc_s.so.* ./usr/lib \ + && cp -d /usr/lib/libstdc++.so.* ./usr/lib \ + # application + && mv /usr/src/build ./app \ + && find ./app/.yarn -mindepth 1 -name cache -prune -o -exec rm -rf {} + \ + && mv /app/frontend/dist ./app/public \ + && chown -R 1000:1000 ./app #### Release #### FROM scratch as release -WORKDIR /usr/src/app +WORKDIR /app ENV NODE_ENV "production" ARG PORT=8080 ENV PORT $PORT -# copy users and groups -COPY --from=builder /tmp/passwd /tmp/group /etc/ - -# copy binaries -COPY --from=builder /usr/local/bin/node /sbin/tini /bin/ - -# copy libraries -COPY --from=builder /lib/ld-musl-x86_64.so* /usr/lib/libstdc++.so* /usr/lib/libgcc_s.so* /lib/ - -# copy production directory -COPY --chown=node:node --from=builder /usr/src/build . +COPY --from=builder /volume / USER node @@ -81,5 +87,5 @@ EXPOSE $PORT VOLUME ["/home/node"] -ENTRYPOINT [ "tini", "--", "node", "--require=/usr/src/app/.pnp.cjs", "--experimental-loader=/usr/src/app/.pnp.loader.mjs"] +ENTRYPOINT [ "tini", "--", "node", "--require=/app/.pnp.cjs", "--experimental-loader=/app/.pnp.loader.mjs"] CMD ["server.js"] \ No newline at end of file