diff --git a/.woodpecker/.workflow.yml b/.woodpecker/.workflow.yml index 978a940..f979367 100644 --- a/.woodpecker/.workflow.yml +++ b/.woodpecker/.workflow.yml @@ -3,10 +3,6 @@ when: branch: main steps: - - name: npm install - image: node:18 - commands: - - npm install - name: docker build and publish when: - event: [tag, manual, push, pull_request] @@ -21,5 +17,5 @@ steps: - /var/run/docker.sock:/var/run/docker.sock commands: - docker login forgejo.transprot.eu -u $DOCKER_USERNAME -p $DOCKER_PASSWORD - - docker build -t 'forgejo.transprot.eu/public/react-bun-rspack:latest' . - - docker push forgejo.transprot.eu/public/react-bun-rspack:latest \ No newline at end of file + - docker build -t 'forgejo.transprot.eu/public/react-nginx-distroless:latest' . + - docker push forgejo.transprot.eu/public/react-nginx-distroless:latest \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index fb3d1aa..e86a478 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ COPY . . RUN bun i && bun run build # Production stage to run the application -FROM nginx:stable-alpine AS production +FROM cgr.dev/chainguard/nginx AS production COPY --from=build /app/dist /usr/share/nginx/html -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file +EXPOSE 8080 +ENTRYPOINT ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/README.md b/README.md index 9ad2a91..4dfb550 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,44 @@ We even have a slight improvement in the final size, a whopping 1.2 MB less than But again, this optimization is mainly to speed up the package installation time and build time of the react application, which in turns speeds up the docker build. +### Sixth optimization: Probably the last one, using distroless images + +The very sixth (and probably the last optimization I can think of): distroless images. + +[Distroless](https://github.com/GoogleContainerTools/distroless) images are more secure by diminishing the attack surface for potential vulnerabilities and lighter, containing only the necessary dependencies to run your application. This means no shells, no package managers or any other program usually found in a Linux distro. + +There's many people trying to make distroless images of popular tools, and you can find some starters and even build some yourselves by looking at the necessary dependencies of the images you use. + +I have been using [Chainguard](https://www.chainguard.dev/) which has a great [image repository](https://images.chainguard.dev/) where you can find many popular images in distroless. + +This is what the Dockerfile now looks like: +```Dockerfile +# Build stage of the application +FROM oven/bun AS build +WORKDIR /app +COPY . . +RUN bun i && bun run build + +# Production stage to run the application +FROM cgr.dev/chainguard/nginx AS production +COPY --from=build /app/dist /usr/share/nginx/html +EXPOSE 8080 +ENTRYPOINT ["nginx", "-g", "daemon off;"] +``` + +You can build the image running the following command: +```shell +docker build -t 'react-nginx-distroless' . +``` + +And here's the image size now: +![Distroless size](./assets/react-nginx-distroless-size.png) + +This is the biggest optimization in image size to date! A 1 998,2 MB less than the original image, which is a crazy small image, 63,83 times smaller than the original!!! It's a ridiculous 98,43% reduction in size! And our application is much more secure !!!!! + +I personally love distroless images. I've seen people say that you can debug them less, and not having basic tools like a shell is contraining, but I personally think it's not needed. +You can simply build both a distroless and alpine image of your same code, then when there's a need to debug, scitch the container image for the alpine version. Or even better, use distroless images in production environments and alpines in development environments. + # Français @@ -503,3 +541,41 @@ Voici une image de la taille de nos images docker jusqu'à présent: On a même une taille plus réduite de l'image avec une amélioration drastique de l'image final qui pèse maintenant 1.2 MB de moins que l'image précédente, avec une différence de 1 955,7 MB par rapport à la première image, ce qui est 27.32 fois plus petit et une réduction de 96,33% de la taille !!!!! Mais pour réitérer, le but de ces optimisations est d'installer les dépendances et de construire l'application React plus rapidement, ce qui réduit le temps de construction de l'image docker par conséquence. + +### Sixième optimisation: Probablement la dernière, utilisation des images distroless + +La sixième (et probablement la dernière optimization à laquelle que je peux penser): les images distroless. + +Les images [distroless](https://github.com/GoogleContainerTools/distroless) sont plus sécurisé en diminuant la surface d'attaque de vos applications car elles ne contiennent que le strict minimum de dépendances pour éxecuter votre application. Ce qui veut généralement dire pas d'invite de commande, de package managers et d'autres programmes généralement disponible dans les distros Linux. + +Beaucoup de gens s'essayent à construire des images distroless d'outils bien connus, et vous pouvez vous-même en construire en regardant le strict nécessaire pour faire tourner vos images applicatives. + +J'ai commencé à utiliser [Chainguard](https://www.chainguard.dev/) qui a une grande selection d'image dans leur [repository](https://images.chainguard.dev/) où vous pourrez trouver des images populaires en distroless. + +Voici le Dockerfile à présent: +```Dockerfile +# Build stage of the application +FROM oven/bun AS build +WORKDIR /app +COPY . . +RUN bun i && bun run build + +# Production stage to run the application +FROM cgr.dev/chainguard/nginx AS production +COPY --from=build /app/dist /usr/share/nginx/html +EXPOSE 8080 +ENTRYPOINT ["nginx", "-g", "daemon off;"] +``` + +Vous pouvez construire l'image avec la commande suivante : +```shell +docker build -t 'react-nginx-distroless' . +``` + +Et voici la taille des images juste ici : +![Distroless size](./assets/react-nginx-distroless-size.png) + +C'est la plus grosse optimisation de taille jusqu'à présent ! Une différence de 1 998,2 MB de moins que l'image original, c'est 63,83 fois plus petit!!! C'est une réduction folle de 98,43% ! Et le meilleur dans tout ça? L'application est beaucoup plus sécurisé !!!!! + +Personnellement j'adore les images distroless. J'ai vu certaines personnes dire qu'elles sont moins débuggable en n'ayant aucun outil basique comme un bash mais je pense que ce n'est pas nécessaire. +Vous pouvez tout simplement construire une image alpine et distroless de votre application, puis remplacer votre image distroless par l'alpine pour débugger en cas de bug. Ou encore mieux et ce que je fais personnelelement, utiliser une image alpine en environnement de développement et distroless en production. \ No newline at end of file diff --git a/assets/react-nginx-distroless-size.png b/assets/react-nginx-distroless-size.png new file mode 100644 index 0000000..139865c Binary files /dev/null and b/assets/react-nginx-distroless-size.png differ