@@ -48,7 +48,6 @@ FROM node:20.9-bookworm-slim@sha256:c325fe5059c504933948ae6483f3402f136b96492dff
48
48
# https://cheatsheetseries.owasp.org/cheatsheets/NodeJS_Docker_Cheat_Sheet.html#5-properly-handle-events-to-safely-terminate-a-nodejs-docker-web-application
49
49
# https://github.com/Yelp/dumb-init
50
50
RUN apt update && apt install -y --no-install-recommends dumb-init
51
- ENTRYPOINT ["dumb-init" , "--" ]
52
51
53
52
FROM node:20.9-bookworm@sha256:3c48678afb1ae5ca5931bd154d8c1a92a4783555331b535bbd7e0822f9ca8603 AS install
54
53
# https://www.pathname.com/fhs/pub/fhs-2.3.html#USRSRCSOURCECODE
@@ -76,6 +75,8 @@ FROM configure AS run
76
75
ENV NODE_ENV production
77
76
# https://cheatsheetseries.owasp.org/cheatsheets/NodeJS_Docker_Cheat_Sheet.html#4-dont-run-containers-as-root
78
77
USER node
78
+ # https://docs.docker.com/build/building/best-practices/#entrypoint
79
+ ENTRYPOINT ["dumb-init" , "--" ]
79
80
CMD [ "node" , "index.js" ]
80
81
```
81
82
@@ -113,26 +114,22 @@ CMD [ "node", "index.js" ]
113
114
adds an additional layer which affects the final size. That being said, it is
114
115
recommended whenever is possible to chain RUN commands into single command.
115
116
116
- 5 . ` ENTRYPOINT ["dumb-init", "--"] `
117
-
118
- - As explained above, we are using dump-init as PID 1 process.
119
-
120
- 6 . ` FROM node:20.9-bookworm@sha256:3c...603 AS install `
117
+ 5 . ` FROM node:20.9-bookworm@sha256:3c...603 AS install `
121
118
122
119
- For dependency installation (and later for the build phase), we use the
123
120
standard ` bookworm ` image instead of the ` slim ` version because certain
124
121
dependencies require additional tools for the compilation step.
125
122
126
- 7 . ` WORKDIR /usr/src/app `
123
+ 6 . ` WORKDIR /usr/src/app `
127
124
128
125
- Application code should be placed inside ` /usr/src ` subdirectory.
129
126
130
- 8 . ` ENV NODE_ENV production `
127
+ 7 . ` ENV NODE_ENV production `
131
128
132
129
- If you are building your image for production this ensures that all frameworks
133
130
and libraries are using the optimal settings for performance and security.
134
131
135
- 9 . ` COPY package*.json . `
132
+ 8 . ` COPY package*.json . `
136
133
137
134
- It's important to notice here that we are copying ` package*.json ` files
138
135
separate from the rest of the codebase. By doing so, we are leveraging Docker
@@ -141,13 +138,13 @@ CMD [ "node", "index.js" ]
141
138
By copying source code files after dependency installation, we are only
142
139
re-executing those steps that come after that step, including that step.
143
140
144
- 10 . ` RUN npm ci --omit=dev `
141
+ 9 . ` RUN npm ci --omit=dev `
145
142
146
143
- devDependencies are not essential for the application to work. By installing
147
144
only production dependencies we are reducing security risks and image
148
145
footprint size and also improving build speed.
149
146
150
- 11 . ` COPY --chown=node:node --from=install /usr/src/app/node_modules ./node_modules `
147
+ 10 . ` COPY --chown=node:node --from=install /usr/src/app/node_modules ./node_modules `
151
148
152
149
- From the install phase we are copying only the node_modules folder in order
153
150
to keep the final Docker image minimal.
@@ -157,17 +154,23 @@ CMD [ "node", "index.js" ]
157
154
` node ` is the least privileged user and by selecting it, we are limiting the
158
155
number of actions an attacker can do in case our application gets compromised.
159
156
160
- 12 . ` COPY --chown=node:node ./index.js . `
157
+ 11 . ` COPY --chown=node:node ./index.js . `
161
158
162
159
- Copy the rest of the codebase as described in step 9. For this example, we
163
160
are copying only the ` index.js ` file because that is the only file we need in
164
161
order to run our application. Avoid adding unnecessary files to your builds by
165
162
explicitly stating the files or directories you intend to copy over.
166
163
167
- 13 . ` USER node `
164
+ 12 . ` USER node `
168
165
169
166
- The process should be owned by the ` node ` user instead of ` root ` .
170
167
168
+ 13 . ` ENTRYPOINT ["dumb-init", "--"] `
169
+
170
+ - Use the exec form to run as PID 1 process and provide default arguments with ` CMD ` .
171
+ - Define runtime configuration (` ENTRYPOINT ` and ` CMD ` ) in the final stage of
172
+ multi-stage build to enforce consistency, explicitness, and security.
173
+
171
174
14 . ` RUN --mount=type=secret,id=npmrc_secret,target=/usr/src/app/.npmrc,required npm ci --omit=dev `
172
175
173
176
- The files mounted as secrets will be available during build, but they will not
@@ -180,6 +183,7 @@ CMD [ "node", "index.js" ]
180
183
` docker build -t ntc-lms . --secret id=npmrc_secret,src=.npmrc `
181
184
182
185
- Docker compose.yaml example:
186
+
183
187
``` yaml
184
188
services :
185
189
app :
@@ -195,7 +199,6 @@ CMD [ "node", "index.js" ]
195
199
file : .npmrc
196
200
` ` `
197
201
198
-
199
202
## Typescript NodeJs application
200
203
201
204
### The application
@@ -218,7 +221,6 @@ CMD [ "node", "index.js" ]
218
221
``` dockerfile
219
222
FROM node:20.9-bookworm-slim@sha256:c325fe5059c504933948ae6483f3402f136b96492dff640ced5dfa1f72a51716 AS base
220
223
RUN apt update && apt install -y --no-install-recommends dumb-init
221
- ENTRYPOINT ["dumb-init" , "--" ]
222
224
223
225
FROM node:20.9-bookworm@sha256:3c48678afb1ae5ca5931bd154d8c1a92a4783555331b535bbd7e0822f9ca8603 AS build
224
226
WORKDIR /usr/src/app
@@ -241,6 +243,7 @@ COPY --chown=node:node --from=install /usr/src/app/node_modules ./node_modules
241
243
FROM configure AS run
242
244
ENV NODE_ENV production
243
245
USER node
246
+ ENTRYPOINT ["dumb-init" , "--" ]
244
247
CMD [ "node" , "dist/index.js" ]
245
248
```
246
249
0 commit comments