如果你正在使用 Docker,你就会知道它就像一个魔盒,对于你的应用程序,它可以在任何地方运行,从你的笔记本电脑到一个大的服务器。但是制作这个盒子的火种(Dockerfile) 需要小心谨慎。如果做得不对,你的应用可能会变得缓慢、笨重,甚至不安全。
1. 选择轻量基础镜像
Dockerfile 从一个基本镜像开始,就像房子的地基一样。 Ubuntu 这样的大镜像有太多我们不需要的东西,使用像 Alpine Linux 这样的小镜像。
General Uses:
FROM ubuntu:latest
Better Option:
FROM alpine:latest
Alpine 只有 5 MB,而 ubuntu 超过 100 MB!更小意味着更快和更安全。
2. 使用多阶段构建来减少垃圾
当你构建一个应用程序时,你需要工具,就像木匠需要锤子一样。应用程序构建完成后,你就不需要这些工具来运行它了。多阶段构建允许您在一步中使用工具,然后将其丢弃。对于最终的容器,这使它保持轻量化。
例如,对于 Node.js 应用程序,您首先构建它,然后仅将最终文件复制到一个小镜像中。
3. 不要以 Root 用户运行
默认情况下,Docker 以“root”身份运行,如果一个黑客侵入,他们就能控制一切。最好使用普通用户, 就像为了安全多锁了一扇门。
Create a User
在你的 Dockerfile 中添加一个新用户,使用类似“RUN adduser -D myuser”这样的命令。“-D”表示没有密码,所以很简单。
Switch to That User
在应用程序运行之前使用 “USER myuser”,告诉 Docker 停止使用 root,切换到新用户。
Fix File Permissions
如果你的应用需要读取或写入文件,确保用户拥有相关权限。在复制文件后添加“RUN chown -R myuser /app”。
Test It
构建并运行容器,然后检查“docker exec -it [container_name] whoami”应该显示“myuser”,而不是“root”。
4. 调整顺序加速构建
Docker 是分层构建的。如果你把变化很大的东西(比如你的代码)放在最后,它重用了之前的步骤并节省了时间。因此,首先安装依赖项,然后复制你的应用代码。
5. 固定版本
如果你使用“FROM node:latest”, 镜像可能会更新,之后可能会破坏你的应用程序。使用固定版本,如 “node:18-alpine”,这就像坚持一个配方,不会突然发生变化!
示例:优化 Node.js 应用程序
让我们以一个 Node.js 应用为例,它包含两个文件:package.json (用于依赖关系) 和 index.js (应用)
以下是一个基本的 Dockerfile:
FROM node:latest
COPY . /app
WORKDIR /app
RUN npm install
CMD ["node", "index.js"]
Problems?
它很大,保留额外的工具,以 root 身份运行,并复制所有内容,甚至是无用的文件。
下面是优化的版本:
# Step 1: Build the app
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json .
RUN npm install
COPY index.js .
# Step 2: Create the production image
FROM node:18-alpine
WORKDIR /app
# Create a non-root user
RUN adduser -D myuser
# Copy files from builder stage
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/index.js .
# Fix permissions for the new user
RUN chown -R myuser /app
# Switch to the non-root user
USER myuser
# Run the app
CMD ["node", "index.js"]
其它注意事项
Check Health
添加以下内容,查看你的应用是否还活着
HEALTHCHECK CMD curl --fail http://localhost:3000 || exit 1
Scan It
使用“docker scan”查找安全漏洞。
Hide Secrets
不要在这里写入密码等配置,使用环境变量。