Creating efficient and secure Docker images is critical to optimizing your containerized applications. In this guide we will walk through some of the best practices for creating Docker images using Dockerfiles and techniques for reducing image size while maintaining functionality and security.
Assumptions/Prerequisites
To make the most out of this guide, it is assumed that you have:
- Basic knowledge of Docker and Dockerfile syntax.
- Familiarity with Node.js applications, including
package.jsonand npm. - Docker installed and set up on your machine.
- A sample Node.js project to test the examples.
Best Practices
1. Start with a Minimal Base Image
- Use lightweight base images like
node:alpineto reduce image size. - For example:
FROM node:alpine2. Specify an Explicit Version
- Avoid using
latestas the tag for your base image since it can lead to inconsistencies. - Instead:
FROM node:18.16.0-alpine3. Minimize the Number of Layers
- Combine related commands to reduce the number of layers in the final image.
- Example of combining commands:
RUN apk add --no-cache curl \
&& npm install --production \
&& npm cache clean --force4. Use Multi-Stage Builds
- Multi-stage builds allow you to separate build-time and runtime dependencies, which reduces the final image size.
- Example:
# Build stage
FROM node:18.16.0 AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build
# Runtime stage
FROM node:alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package.json ./
RUN npm install --production
CMD ["node", "dist/index.js"]5. Avoid Adding Unnecessary Files
- Use
.dockerignoreto exclude files that are not needed in the build context. - Example
.dockerignore:
node_modules
*.log
*.tmp
dist6. Install Only Required Packages
- Be precise about the tools and libraries you install to avoid unnecessary bloat.
- Example:
RUN npm install express dotenv7. Clean Up Temporary Files
- Remove cache files and temporary artifacts created during the build.
- Example:
RUN npm cache clean --force8. Use COPY Instead of ADD
- Prefer
COPYoverADDunless you need to extract a tar file or download from a URL. - Example:
COPY src/ /app/src/9. Set Metadata Using Labels
- Add labels for documentation, versioning, and maintainership.
- Example:
LABEL maintainer="you@example.com" \
version="1.0" \
description="Node.js application"10. Leverage Caching
- Order commands in your Dockerfile to maximize caching benefits.
- Place frequently changing commands (e.g.,
COPY) towards the end. - Example:
RUN npm install
COPY . /app11. Set a Non-Root User
- Avoid running your application as
rootfor security reasons. - Example:
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser12. Use ENTRYPOINT Over CMD
- Use
ENTRYPOINTfor the main application command andCMDfor default arguments. - Example:
ENTRYPOINT ["node", "dist/index.js"]
CMD ["--help"]13. Optimize Image Layers
- Use
--squash(experimental feature) to merge layers and reduce image size. - Example:
docker build --squash -t myapp:optimized .14. Scan for Vulnerabilities
- Use tools like
Trivyor Docker’s built-indocker scanto identify security vulnerabilities in your image. - Example:
trivy image myapp:latestExample Dockerfile
Here’s a complete Dockerfile incorporating best practices for a Node.js application:
# Stage 1: Build stage
FROM node:18.16.0 AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build
# Stage 2: Runtime stage
FROM node:alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package.json ./
RUN npm install --production
USER node
CMD ["node", "dist/index.js"]Reducing Image Size Checklist
- Use lightweight base images.
- Remove unnecessary files and cache.
- Leverage multi-stage builds.
- Use
.dockerignoreeffectively. - Combine commands and minimize layers.
Conclusion
By following these best practices, you can create Docker images that are efficient, secure, and optimized for production environments. These principles not only improve performance but also enhance maintainability and security. Remember, building small and robust images is an essential step in ensuring your containerized applications run smoothly in any environment.
Comments
Post a Comment