-
-
Couldn't load subscription status.
- Fork 1.4k
Docker: creating an effective image #1802
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
Open
riiji
wants to merge
2
commits into
fireship-io:master
Choose a base branch
from
riiji:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- | ||
| title: Egor Chebkasov | ||
| date: 2025-03-01 0:00:00 | ||
|
|
||
| featured_img: /img/contributors/egor-chebkasov.jpeg | ||
|
|
||
| links: | ||
| github: https://github.com/riiji | ||
| linkedin: https://www.linkedin.com/in/egor-chebkasov/ | ||
| --- | ||
|
|
||
| Egor is a software dev. Loves to cook |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Docker logo is outdated. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| --- | ||
| title: Build an effective image with Node.js | ||
| lastmod: 2025-03-01T00:00:00-00:00 | ||
| publishdate: 2025-03-01T02:00:00-00:00 | ||
| author: Egor Chebkasov | ||
| draft: false | ||
| description: Learn techniques for creating efficient, secure, and more production-ready Docker images with Node.js | ||
| tags: | ||
| - docker | ||
| - node | ||
| - security | ||
| - devops | ||
|
|
||
| youtube: | ||
| github: https://github.com/fireship-io/docker-nodejs-advanced-demo | ||
| # disable_toc: true | ||
| # disable_qna: true | ||
|
|
||
| # courses | ||
| # step: 0 | ||
|
|
||
| # versions: | ||
| # rxdart: 0.20 | ||
| --- | ||
|
|
||
| Building on our [Docker Basics Tutorial](/lessons/docker-basics-tutorial-nodejs/), this guide shows you how to create better Docker images for Node.js apps. | ||
|
|
||
| ## The Problem with Basic Docker Images | ||
|
|
||
| Let's look at a simple Dockerfile that many developers start with. It works fine for learning, but has some problems we should fix: | ||
|
|
||
| {{< file "docker" "Dockerfile" >}} | ||
| ```docker | ||
| FROM node:22 | ||
| WORKDIR /app | ||
| COPY package.json package-lock.json ./ | ||
| RUN npm install | ||
| COPY . . | ||
| CMD ["node", "server.js"] | ||
| ``` | ||
|
|
||
| This works for development, but has several issues for production: | ||
|
|
||
| 1. **Security vulnerabilities** - `npm install` includes dev dependencies that might have security problems | ||
| 2. **Unreliable dependencies' code** - `npm install` might update packages beyond what's in package-lock.json, which can break your app | ||
| 3. **Large image size** - Dev dependencies make the image much bigger than needed | ||
| 4. **Huge base image** - node:22 is very large, making deployments slow and expensive | ||
|
|
||
| ### Base image improvements | ||
|
|
||
| First, the base image is too big: | ||
|
|
||
| ```docker | ||
| FROM node:22 | ||
| ``` | ||
|
|
||
| We can use Alpine Linux instead, which is much smaller: | ||
|
|
||
| ```docker | ||
| FROM node:22-alpine | ||
| ``` | ||
|
|
||
| Google offers "distroless" images that contain only what you need to run your app - nothing else. This gives you better security. The size difference between Alpine and distroless is small so you shouldn't think about it too much. | ||
|
|
||
| Please, don't overengineer. Distroless is what big companies like Google use, but for most projects, Alpine works great. Distroless images make debugging harder since they have no tools inside them. | ||
|
|
||
| ```docker | ||
| FROM gcr.io/distroless/nodejs22-debian12 | ||
| ``` | ||
|
|
||
| ### npm install issues | ||
|
|
||
| This line causes many problems: | ||
|
|
||
| ```docker | ||
| npm install | ||
| ``` | ||
|
|
||
| A better approach is using `npm ci`, which uses exactly what's in package-lock.json. It won't try to update packages. | ||
| Adding `--omit=dev` removes development tools like eslint and testing libraries. We only keep what the app needs to run: | ||
|
|
||
| ```docker | ||
| npm ci --omit=dev | ||
| ``` | ||
|
|
||
| Here's our improved image: | ||
|
|
||
| {{< file "docker" "Dockerfile" >}} | ||
| ```docker | ||
| FROM node:22-alpine | ||
| WORKDIR /app | ||
| COPY package.json package-lock.json ./ | ||
| RUN npm ci --omit=dev | ||
| COPY . . | ||
| CMD ["node", "server.js"] | ||
| ``` | ||
|
|
||
| Now let's try the best practice approach with distroless images. | ||
| We need a multi-stage build because distroless images don't have tools like npm: | ||
|
|
||
| {{< file "docker" "Dockerfile" >}} | ||
| ```docker | ||
| FROM node:22-alpine AS dependencies | ||
| WORKDIR /app | ||
| COPY package.json package-lock.json ./ | ||
| RUN npm ci --omit=dev | ||
| COPY . . | ||
|
|
||
| FROM gcr.io/distroless/nodejs22-debian12 | ||
| WORKDIR /app | ||
| COPY --from=dependencies --chown=nonroot:nonroot /app . | ||
| USER nonroot | ||
| CMD ["server.js"] | ||
| ``` | ||
|
|
||
| ### Non-root user for better security | ||
|
|
||
| Notice the USER nonroot line. This is an important security practice - by default, Docker runs as root, which creates a security risk. Distroless images come with a nonroot user built-in, making it easy to follow this best practice with just one line of code. | ||
|
|
||
|
|
||
| ## Let's look at the results | ||
|
|
||
| I tested these approaches with a real Node.js app: | ||
|
|
||
| | Image Type | Size | | ||
| |------------|------| | ||
| | Basic | 1.18GB | | ||
| | Alpine | 170MB | | ||
| | Distroless | 162MB | | ||
|
|
||
| The difference is huge! Image size matters because your servers need to download these images. Smaller images mean faster deployments and less storage costs. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Docker logo is outdated.
https://www.docker.com/company/newsroom/media-resources/