Skip to content

Commit 2edaefd

Browse files
[feat] update angular sample guide to use dhi example (#23820)
## Description This PR adds a DHI-based Dockerfile example demonstrating how to build an Angular application using the dhi-node image and serve it through the dhi-nginx image. ## Reviews - [x] Technical review
1 parent 6c68968 commit 2edaefd

File tree

2 files changed

+91
-18
lines changed

2 files changed

+91
-18
lines changed

content/guides/angular/containerize.md

Lines changed: 89 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ By the end of this guide, you will:
2828
- Containerize an Angular application using Docker.
2929
- Create and optimize a Dockerfile for production builds.
3030
- Use multi-stage builds to minimize image size.
31-
- Serve the application efficiently with a custom NGINX configuration.
31+
- Serve the application efficiently with a custom Nginx configuration.
3232
- Build secure and maintainable Docker images by following best practices.
3333

3434
---
@@ -77,7 +77,7 @@ For consistency, please use the same responses shown in the example below when p
7777
| Question | Answer |
7878
|------------------------------------------------------------|-----------------|
7979
| What application platform does your project use? | Node |
80-
| What version of Node do you want to use? | 23.11.0-alpine |
80+
| What version of Node do you want to use? | 24.12.0-alpine |
8181
| Which package manager do you want to use? | npm |
8282
| Do you want to run "npm run build" before starting server? | yes |
8383
| What directory is your build output to? | dist |
@@ -105,7 +105,7 @@ The default Dockerfile generated by `docker init` serves as a solid starting poi
105105
In this step, you’ll improve the Dockerfile and configuration files by following best practices:
106106

107107
- Use multi-stage builds to keep the final image clean and small
108-
- Serve the app using NGINX, a fast and secure web server
108+
- Serve the app using Nginx, a fast and secure web server
109109
- Improve performance and security by only including what’s needed
110110

111111
These updates help ensure your app is easy to deploy, fast to load, and production-ready.
@@ -114,19 +114,90 @@ These updates help ensure your app is easy to deploy, fast to load, and producti
114114
> A `Dockerfile` is a plain text file that contains step-by-step instructions to build a Docker image. It automates packaging your application along with its dependencies and runtime environment.
115115
> For full details, see the [Dockerfile reference](/reference/dockerfile/).
116116
117-
118117
### Step 2: Configure the Dockerfile
119118

120-
Copy and replace the contents of your existing `Dockerfile` with the configuration below:
119+
Before creating a Dockerfile, you need to choose a base image. You can either use the [Node.js Official Image](https://hub.docker.com/_/node) or a Docker Hardened Image (DHI) from the [Hardened Image catalog](https://hub.docker.com/hardened-images/catalog).
120+
121+
Choosing DHI offers the advantage of a production-ready image that is lightweight and secure. For more information, see [Docker Hardened Images](https://docs.docker.com/dhi/).
122+
123+
> [!IMPORTANT]
124+
> This guide uses a stable Node.js LTS image tag that is considered secure when the guide is written. Because new releases and security patches are published regularly, the tag shown here may no longer be the safest option when you follow the guide. Always review the latest available image tags and select a secure, up-to-date version before building or deploying your application.
125+
>
126+
> Official Node.js Docker Images: https://hub.docker.com/_/node
127+
128+
{{< tabs >}}
129+
{{< tab name="Using Docker Hardened Images" >}}
130+
Docker Hardened Images (DHIs) are available for Node.js in the [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog/dhi/node). Docker Hardened Images are freely available to everyone with no subscription required. You can pull and use them like any other Docker image after signing in to the DHI registry. For more information, see the [DHI quickstart](/dhi/get-started/) guide.
131+
132+
1. Sign in to the DHI registry:
133+
```console
134+
$ docker login dhi.io
135+
```
136+
137+
2. Pull the Node.js DHI (check the catalog for available versions):
138+
```console
139+
$ docker pull dhi.io/node:24-alpine3.22-dev
140+
```
141+
142+
In the following Dockerfile, the `FROM` instruction uses `dhi.io/node:24-alpine3.22-dev` as the base image.
121143

122144
```dockerfile
123145
# =========================================
124146
# Stage 1: Build the Angular Application
125147
# =========================================
148+
149+
# Use a lightweight DHI Node.js image for building
150+
FROM dhi.io/node:24-alpine3.22-dev AS builder
151+
152+
# Set the working directory inside the container
153+
WORKDIR /app
154+
155+
# Copy package-related files first to leverage Docker's caching mechanism
156+
COPY package.json package-lock.json* ./
157+
158+
# Install project dependencies using npm ci (ensures a clean, reproducible install)
159+
RUN --mount=type=cache,target=/root/.npm npm ci
160+
161+
# Copy the rest of the application source code into the container
162+
COPY . .
163+
164+
# Build the Angular application
165+
RUN npm run build
166+
167+
# =========================================
168+
# Stage 2: Prepare Nginx to Serve Static Files
169+
# =========================================
170+
171+
FROM dhi.io/nginx:1.28.0-alpine3.21-dev AS runner
172+
173+
# Copy custom Nginx config
174+
COPY nginx.conf /etc/nginx/nginx.conf
175+
176+
# Copy the static build output from the build stage to Nginx's default HTML serving directory
177+
COPY --chown=nginx:nginx --from=builder /app/dist/*/browser /usr/share/nginx/html
178+
179+
# Use a non-root user for security best practices
180+
USER nginx
181+
182+
# Expose port 8080 to allow HTTP traffic
183+
# Note: The default Nginx container now listens on port 8080 instead of 80
184+
EXPOSE 8080
185+
186+
# Start Nginx directly with custom config
187+
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
188+
CMD ["-g", "daemon off;"]
189+
```
190+
191+
{{< /tab >}}
192+
{{< tab name="Using the Docker Official Image" >}}
193+
194+
Now you need to create a production-ready multi-stage Dockerfile. Replace the generated Dockerfile with the following optimized configuration:
195+
196+
```dockerfile
126197
# =========================================
127198
# Stage 1: Build the Angular Application
128199
# =========================================
129-
ARG NODE_VERSION=24.7.0-alpine
200+
ARG NODE_VERSION=24.12.0-alpine
130201
ARG NGINX_VERSION=alpine3.22
131202

132203
# Use a lightweight Node.js image for building (customizable via ARG)
@@ -136,7 +207,7 @@ FROM node:${NODE_VERSION} AS builder
136207
WORKDIR /app
137208

138209
# Copy package-related files first to leverage Docker's caching mechanism
139-
COPY package.json package-lock.json ./
210+
COPY package.json *package-lock.json* ./
140211

141212
# Install project dependencies using npm ci (ensures a clean, reproducible install)
142213
RUN --mount=type=cache,target=/root/.npm npm ci
@@ -153,32 +224,34 @@ RUN npm run build
153224

154225
FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} AS runner
155226

156-
# Use a built-in non-root user for security best practices
157-
USER nginx
158-
159227
# Copy custom Nginx config
160228
COPY nginx.conf /etc/nginx/nginx.conf
161229

162230
# Copy the static build output from the build stage to Nginx's default HTML serving directory
163231
COPY --chown=nginx:nginx --from=builder /app/dist/*/browser /usr/share/nginx/html
164232

233+
# Use a built-in non-root user for security best practices
234+
USER nginx
235+
165236
# Expose port 8080 to allow HTTP traffic
166-
# Note: The default NGINX container now listens on port 8080 instead of 80
237+
# Note: The default Nginx container now listens on port 8080 instead of 80
167238
EXPOSE 8080
168239

169240
# Start Nginx directly with custom config
170241
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
171242
CMD ["-g", "daemon off;"]
172-
173243
```
174244

175245
> [!NOTE]
176-
> We are using nginx-unprivileged instead of the standard NGINX image to follow security best practices.
246+
> We are using nginx-unprivileged instead of the standard Nginx image to follow security best practices.
177247
> Running as a non-root user in the final image:
178248
>- Reduces the attack surface
179249
>- Aligns with Docker’s recommendations for container hardening
180250
>- Helps comply with stricter security policies in production environments
181251
252+
{{< /tab >}}
253+
{{< /tabs >}}
254+
182255
### Step 3: Configure the .dockerignore file
183256

184257
The `.dockerignore` file tells Docker which files and folders to exclude when building the image.
@@ -259,12 +332,12 @@ docker-compose*.yml
259332

260333
### Step 4: Create the `nginx.conf` file
261334

262-
To serve your Angular application efficiently inside the container, you’ll configure NGINX with a custom setup. This configuration is optimized for performance, browser caching, gzip compression, and support for client-side routing.
335+
To serve your Angular application efficiently inside the container, you’ll configure Nginx with a custom setup. This configuration is optimized for performance, browser caching, gzip compression, and support for client-side routing.
263336

264337
Create a file named `nginx.conf` in the root of your project directory, and add the following content:
265338

266339
> [!NOTE]
267-
> To learn more about configuring NGINX, see the [official NGINX documentation](https://nginx.org/en/docs/).
340+
> To learn more about configuring Nginx, see the [official Nginx documentation](https://nginx.org/en/docs/).
268341
269342

270343
```nginx
@@ -351,7 +424,7 @@ With your custom configuration in place, you're now ready to build the Docker im
351424

352425
The updated setup includes:
353426

354-
- The updated setup includes a clean, production-ready NGINX configuration tailored specifically for Angular.
427+
- The updated setup includes a clean, production-ready Nginx configuration tailored specifically for Angular.
355428
- Efficient multi-stage Docker build, ensuring a small and secure final image.
356429

357430
After completing the previous steps, your project directory should now contain the following files:

content/guides/angular/develop.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Create a file named `Dockerfile.dev` in your project root with the following con
3838
# =========================================
3939

4040
# Define the Node.js version to use (Alpine for a small footprint)
41-
ARG NODE_VERSION=24.7.0-alpine
41+
ARG NODE_VERSION=24.12.0-alpine
4242

4343
# Set the base image for development
4444
FROM node:${NODE_VERSION} AS dev
@@ -50,7 +50,7 @@ ENV NODE_ENV=development
5050
WORKDIR /app
5151

5252
# Copy only the dependency files first to optimize Docker caching
53-
COPY package.json package-lock.json ./
53+
COPY package.json package-lock.json* ./
5454

5555
# Install dependencies using npm with caching to speed up subsequent builds
5656
RUN --mount=type=cache,target=/root/.npm npm install

0 commit comments

Comments
 (0)