{T}

Docker安全性与命令实践指南

Docker安全性与命令实践指南

学习目标:掌握 Docker 镜像安全配置、Dockerfile 最佳实践、Docker 常用命令体系、容器权限管理。


一、Dockerfile 官方参考

1.1 Dockerfile 常用指令速查

官方文档位置Dockerfile Reference

code
Dockerfile 常用指令:
│
├── FROM 
│   ├── 作用:指定基础镜像
│   ├── 示例:FROM node:18-alpine
│   └── 说明:Dockerfile 第一条指令
│
├── RUN 
│   ├── 作用:执行命令(构建时运行)
│   ├── 示例:RUN npm install
│   └── 说明:每条 RUN 创建一个新层
│
├── CMD 
│   ├── 作用:容器启动时执行的默认命令
│   ├── 示例:CMD ["node", "app.js"]
│   └── 说明:只能有一个 CMD,可被覆盖
│
├── LABEL 
│   ├── 作用:添加镜像元数据(作者、版本等)
│   ├── 示例:LABEL maintainer="your@email.com"
│   └── 说明:替代已废弃的 MAINTAINER
│
├── EXPOSE 
│   ├── 作用:声明容器运行时监听的端口
│   ├── 示例:EXPOSE 3000
│   └── 说明:仅声明,实际映射需 docker run -p
│
├── ENV 
│   ├── 作用:设置环境变量
│   ├── 示例:ENV NODE_ENV=production
│   └── 说明:容器运行时可访问
│
├── ARG 
│   ├── 作用:构建时的变量(仅构建阶段有效)
│   ├── 示例:ARG NODE_VERSION=18
│   └── 说明:不保留在最终镜像中
│
├── COPY 
│   ├── 作用:复制文件到镜像
│   ├── 示例:COPY . /app
│   └── 说明:推荐用于简单复制
│
├── ADD 
│   ├── 作用:复制文件(支持 URL 和自动解压)
│   ├── 示例:ADD app.tar.gz /app
│   └── 说明:功能更多但推荐用 COPY
│
├── WORKDIR 
│   ├── 作用:设置工作目录
│   ├── 示例:WORKDIR /app
│   └── 说明:后续指令在此目录执行
│
└── USER (重点)
    ├── 作用:指定运行容器的用户
    ├── 示例:USER node
    └── 说明:提高安全性,避免使用 root

1.2 指令对比表格

指令执行时机作用域可缓存常用场景
RUN构建时构建阶段安装依赖、编译代码
CMD运行时运行阶段启动应用
ENTRYPOINT运行时运行阶段固定启动命令
ENV构建时+运行时全局环境变量配置
ARG构建时构建阶段参数化构建

二、Docker 安全性最佳实践

2.1 为什么需要设置 USER?

code
Docker 默认用户问题:
│
├── 默认行为
│   ├── RUN/COPY 命令默认使用 root 用户
│   └── 容器内进程以 root 权限运行
│
├── 安全风险 
│   ├── 可访问宿主机文件系统(通过 Volume)
│   ├── 可能破坏系统文件
│   ├── 权限过大,不符合最小权限原则
│   └── 容器逃逸风险增加
│
└── 解决方案 
    ├── 创建普通用户
    ├── 使用 USER 指定运行用户
    └── 限制文件操作权限

安全风险示例

bash
# 危险:容器以 root 运行,挂载宿主机目录
docker run -v /:/host alpine rm -rf /host/etc/passwd
#  可能破坏宿主机系统文件!

2.2 Linux 权限管理基础

核心命令

bash
# 创建用户组
groupadd mygroup

# 创建用户并指定组
useradd -g mygroup myuser

# 设置目录权限(读 r、写 w、执行 x)
chmod 755 /app          # 所有者:rwx,组:r-x,其他:r-x
chmod +x script.sh      # 添加执行权限

# 修改文件所有者
chown user:group file   # 修改文件所有者和组
chown -R user:group /app # 递归修改目录

权限数字说明

code
Linux 权限数字表示法:
│
├── 读(r)= 4
├── 写(w)= 2
└── 执行(x)= 1

权限组合示例:
├── 7 = 4 + 2 + 1 = rwx(读写执行)
├── 6 = 4 + 2 = rw-(读写)
├── 5 = 4 + 1 = r-x(读执行)
└── 755 = rwxr-xr-x(所有者:rwx,组:r-x,其他:r-x)

2.3 Node.js 基础镜像的安全用户

查看镜像内置用户

bash
# 查看 node:18-alpine 镜像的用户列表
docker run --rm node:18-alpine cat /etc/passwd

# 输出结果(最后一行)
# node:x:1000:1000:Linux User,,,:/home/node:/bin/bash

解析

code
/etc/passwd 文件格式:
node:x:1000:1000:Linux User,,,:/home/node:/bin/bash
│    │  │    │  │           │           └── 默认 shell
│    │  │    │  │           └── 用户主目录
│    │  │    │  └── 用户信息
│    │  │    └── 组 ID (GID)
│    │  └── 用户 ID (UID)
│    └── 密码占位符(x 表示密码在 /etc/shadow)
└── 用户名

关键信息

  • 用户名:node
  • 用户 ID:1000
  • 组 ID:1000
  • 主目录:/home/node

2.4 安全配置实战

完整 Dockerfile 安全配置示例

dockerfile
# ==================== 构建阶段 ====================
# 使用 ARG 定义变量(仅构建时有效)
ARG NODE_VERSION=18

FROM node:${NODE_VERSION}-alpine AS builder

# 切换到 node 用户(基础镜像已预创建)
USER node

# 设置工作目录(在 node 用户的主目录下)
WORKDIR /home/node/app

# 复制依赖配置文件并设置权限
# --chown=node:node 设置文件所有者为 node 用户和组
COPY --chown=node:node package*.json ./

# 安装依赖
RUN npm install

# 复制源码(设置权限)
COPY --chown=node:node . .

# 构建应用
RUN npm run build

# ==================== 生产阶段 ====================
FROM node:${NODE_VERSION}-alpine AS production

USER node
WORKDIR /home/node/app

# 从构建阶段复制产物(设置权限)
COPY --from=builder --chown=node:node /home/node/app/.output ./.output

EXPOSE 3000
ENV NODE_ENV=production

# 容器启动命令(以 node 用户运行)
CMD ["node", ".output/server/index.mjs"]

关键配置说明

配置项作用示例
USER node后续命令以 node 用户运行RUN、CMD 都会使用此用户
WORKDIR /home/node/app工作目录设在 node 用户主目录下node 用户有完整权限
COPY --chown=node:node复制文件并设置所有者node 用户可读写文件
ARG NODE_VERSION构建时变量便于版本管理

2.5 安全配置对比

不安全配置(默认 root)

dockerfile
#  不安全示例
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "app.js"]
# 默认以 root 用户运行!

安全配置(推荐)

dockerfile
#  安全示例
FROM node:18-alpine
USER node                    # 指定用户
WORKDIR /home/node/app       # 使用 node 用户目录
COPY --chown=node:node . .   # 设置文件权限
RUN npm install
CMD ["node", "app.js"]
# 以 node 用户(UID 1000)运行

安全优势

code
使用普通用户的优势:
│
├── 1. 最小权限原则 
│   ├── 只能访问用户目录
│   └── 无法修改系统文件
│
├── 2. 降低安全风险 
│   ├── 限制容器破坏范围
│   └── 减少容器逃逸风险
│
├── 3. 符合生产规范 
│   ├── 企业安全要求
│   └── 审计合规
│
└── 4. 文件隔离 
    ├── 不同用户文件独立
    └── 避免权限冲突

三、Docker 命令体系总结

3.1 镜像管理命令

bash
# ==================== 镜像构建 ====================
# 构建镜像
docker build -t <name>:<tag> .

# 示例
docker build -t nuxt-app:1.0 .

# 不使用缓存构建(排查问题用)
docker build --no-cache -t nuxt-app:1.0 .

# ==================== 镜像查看 ====================
# 查看本地镜像
docker images

# 输出示例:
# REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
# nuxt-app      1.0       abc123def456   2 hours ago    250MB
# node          18-alpine def789abc123   3 days ago     170MB

# ==================== 镜像删除 ====================
# 删除镜像(使用 IMAGE ID)
docker rmi <image_id>

# 删除镜像(使用名称:标签)
docker rmi nuxt-app:1.0

# 强制删除(即使有容器使用)
docker rmi -f <image_id>

# ==================== 镜像管理 ====================
# 镜像标签(重命名)
docker tag old-name:1.0 new-name:2.0

# 清理未使用的镜像
docker image prune

# 清理所有未使用的镜像
docker image prune -a

3.2 容器生命周期管理

bash
# ==================== 容器运行 ====================
# 基础运行
docker run <image_name>

# 常用参数完整示例
docker run \
  -d \                      # 后台运行(detached)
  -it \                     # 交互式终端(interactive + tty)
  --name myapp \            # 容器名称
  -p 8001:3000 \            # 端口映射(宿主机:容器)
  -e BASE_URL=http://api \  # 环境变量
  -v /host/path:/container/path \  # 卷挂载
  --rm \                    # 容器退出后自动删除
  --user node \             # 指定运行用户
  nuxt-app:1.0              # 镜像名称

# ==================== 容器启停 ====================
# 启动已停止的容器
docker start <container_name_or_id>

# 停止运行中的容器
docker stop <container_name_or_id>

# 重启容器
docker restart <container_name_or_id>

# ==================== 容器删除 ====================
# 删除已停止的容器
docker rm <container_name_or_id>

# 强制删除运行中的容器
docker rm -f <container_name_or_id>

# 删除所有已停止的容器
docker container prune

# ==================== 容器查看 ====================
# 查看运行中的容器
docker ps

# 查看所有容器(包括已停止)
docker ps -a

# 输出示例:
# CONTAINER ID   IMAGE          COMMAND        STATUS        PORTS                NAMES
# abc123def456   nuxt-app:1.0   "node app.js"  Up 2 hours    0.0.0.0:8001->3000   myapp

# ==================== 容器日志 ====================
# 查看容器日志
docker logs <container_name_or_id>

# 实时查看日志(follow)
docker logs -f <container_name_or_id>

# 查看最后 100 行日志
docker logs --tail 100 <container_name_or_id>

3.3 容器调试命令

bash
# 进入运行中的容器
docker exec -it <container_name> sh

# 以 root 用户进入容器
docker exec -it --user root <container_name> sh

# 在容器内执行命令(不进入容器)
docker exec <container_name> ls /app

# 查看容器详细信息
docker inspect <container_name>

# 查看容器资源使用情况
docker stats <container_name>

# 查看容器进程
docker top <container_name>

# 复制文件到容器
docker cp local_file.txt <container_name>:/app/

# 从容器复制文件到宿主机
docker cp <container_name>:/app/logs.txt ./logs.txt

3.4 实用参数详解

参数说明示例使用场景
-d后台运行(detached)docker run -d nginx生产环境部署
-it交互式终端docker run -it alpine sh进入容器调试
--name容器名称--name myapp便于管理识别
-p端口映射-p 8001:3000服务对外访问
-e环境变量-e NODE_ENV=prod配置传递
-v卷挂载-v /host:/container数据持久化、配置文件
--rm退出后删除docker run --rm alpine临时测试
--user指定用户--user node安全运行
--restart重启策略--restart always自动重启

重启策略详解

bash
# 容器退出时不重启(默认)
docker run --restart no nginx

# 容器退出时总是重启
docker run --restart always nginx

# 容器异常退出时重启(正常退出不重启)
docker run --restart on-failure nginx

# 限制重启次数(最多重启 5 次)
docker run --restart on-failure:5 nginx

3.5 Docker Compose 批量管理

Docker Compose vs Docker Run

yaml
# docker run 命令
docker run -d --name nuxt-app -p 8001:3000 -e BASE_URL=http://api nuxt-app:1.0

# 等价的 docker-compose.yml
version: '3.8'
services:
  nuxt-app:
    image: nuxt-app:1.0
    container_name: nuxt-app
    ports:
      - "8001:3000"
    environment:
      - BASE_URL=http://api
    restart: always

Docker Compose 命令

bash
# 启动所有服务(后台运行)
docker compose up -d

# 启动并重新构建
docker compose up -d --build

# 停止所有服务
docker compose down

# 停止并删除卷
docker compose down -v

# 查看服务状态
docker compose ps

# 查看服务日志
docker compose logs

# 实时查看特定服务日志
docker compose logs -f nuxt-app

# 重启所有服务
docker compose restart

# 重启特定服务
docker compose restart nuxt-app

# 启动特定服务
docker compose start nuxt-app

# 停止特定服务
docker compose stop nuxt-app

# 进入容器
docker compose exec nuxt-app sh

# 查看服务配置
docker compose config

Docker Compose 优势

code
Docker Compose 优势:
│
├── 1. 配置集中管理 
│   ├── 所有服务配置在一个文件
│   └── 环境变量统一管理
│
├── 2. 多服务编排 
│   ├── 服务依赖管理(depends_on)
│   ├── 网络自动配置
│   └── 启动顺序控制
│
├── 3. 一键部署 
│   ├── docker compose up -d
│   └── 快速搭建完整环境
│
└── 4. 环境变量文件支持 
    ├── env_file: .env.production
    └── 多环境配置切换

四、镜像构建流程总结

4.1 完整构建流程

code
Docker 镜像构建完整流程:
│
├── 第一步:创建配置文件
│   ├── .dockerignore(排除不必要文件)
│   ├── Dockerfile(镜像构建配置)
│   └── docker-compose.yml(可选,服务编排)
│
├── 第二步:编写 Dockerfile
│   ├── 确定基础镜像(FROM)
│   ├── 设置工作目录(WORKDIR)
│   ├── 安装依赖(RUN npm install)
│   ├── 复制源码(COPY)
│   ├── 构建应用(RUN npm run build)
│   ├── 配置环境变量(ENV)
│   ├── 暴露端口(EXPOSE)
│   ├── 设置用户(USER,安全)
│   └── 启动命令(CMD)
│
├── 第三步:构建镜像
│   ├── docker build -t app:1.0 .
│   ├── 查看日志排查问题
│   └── 调整配置重新构建
│
├── 第四步:运行容器
│   ├── docker run(测试)
│   ├── docker compose up -d(生产)
│   └── 验证服务是否正常
│
└── 第五步:问题排查
    ├── docker logs 查看日志
    ├── docker exec 进入容器调试
    └── 根据错误调整配置

4.2 配置文件固定后的优势

code
配置文件固定后的优势:
│
├── 1. 无需频繁修改 
│   ├── 依赖更新无需改 Dockerfile
│   └── 代码更新无需改配置
│
├── 2. 版本控制友好 
│   ├── Dockerfile 可纳入 Git
│   └── 团队协作一致性
│
├── 3. CI/CD 集成 
│   ├── 自动化构建流水线
│   └── 一键部署到生产环境
│
└── 4. 环境一致性 
    ├── 开发环境 = 生产环境
    └── 避免"在我机器上能运行"问题

五、问题排查最佳实践

5.1 排查流程

code
Docker 问题排查流程:
│
├── 1. 构建阶段问题
│   ├── 查看 docker build 输出日志
│   ├── 定位失败的步骤(STEP)
│   ├── 根据错误信息调整 Dockerfile
│   └── 重新构建(可能需 --no-cache)
│
├── 2. 运行阶段问题
│   ├── docker logs 查看容器日志
│   ├── docker ps -a 查看容器状态
│   ├── docker exec 进入容器调试
│   └── 检查环境变量、端口、文件
│
├── 3. 网络问题
│   ├── 检查端口映射(-p 参数)
│   ├── docker port 查看端口映射
│   └── curl 测试服务可访问性
│
└── 4. 权限问题
    ├── 检查 USER 配置
    ├── 检查文件权限(ls -l)
    └── 检查卷挂载权限

5.2 常见错误速查

错误信息可能原因解决方案
permission denied用户权限不足检查 USER 和文件权限
port is already allocated端口被占用更换端口或停止占用服务
no such file or directory文件路径错误检查 COPY 和 WORKDIR
network unreachable网络配置问题检查端口映射和网络模式
OOMKilled内存不足增加内存限制或优化代码
executable file not found命令不存在检查 CMD 或依赖安装

5.3 调试技巧

bash
# 1. 查看详细构建日志
docker build --progress=plain -t app:1.0 .

# 2. 进入失败容器的最后一层镜像调试
docker run -it <image_id> sh

# 3. 查看容器完整配置
docker inspect <container_name> | grep -A 10 "Env"

# 4. 查看容器文件系统
docker export <container_name> | tar -tvf - | grep <filename>

# 5. 测试网络连通性
docker exec <container_name> curl http://localhost:3000

六、实战案例:安全的生产级配置

6.1 需求描述

创建一个安全的、生产就绪的 Nuxt3 应用容器配置,要求:

  1. 非 root 用户运行
  2. 多阶段构建优化体积
  3. 支持环境变量配置
  4. 完整的权限管理

6.2 完整配置

.dockerignore

plaintext
node_modules
.nuxt
.output
dist
.git
.github
.env*
*.log
.DS_Store

Dockerfile

dockerfile
# ==================== 构建阶段 ====================
ARG NODE_VERSION=18

FROM node:${NODE_VERSION}-alpine AS builder

# 使用 node 用户(安全最佳实践)
USER node
WORKDIR /home/node/app

# 复制依赖配置(利用 Docker 缓存)
COPY --chown=node:node package*.json ./

# 设置淘宝源加速(国内环境)
RUN npm config set registry https://registry.npmmirror.com && \
    npm ci --only=production=false

# 复制源码并构建
COPY --chown=node:node . .
RUN npm run build

# ==================== 生产阶段 ====================
FROM node:${NODE_VERSION}-alpine AS production

# 安全配置:使用普通用户
USER node
WORKDIR /home/node/app

# 复制构建产物(设置权限)
COPY --from=builder --chown=node:node /home/node/app/.output ./.output

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"

# 环境变量
ENV NODE_ENV=production

# 暴露端口(容器内部)
EXPOSE 3000

# 启动应用(以 node 用户运行)
CMD ["node", ".output/server/index.mjs"]

docker-compose.yml

yaml
version: '3.8'

services:
  nuxt-app:
    build:
      context: .
      args:
        NODE_VERSION: 18
    image: nuxt-app:secure
    container_name: nuxt-app-prod
    restart: always
    user: node                    # 指定用户
    ports:
      - "8001:3000"
    env_file:
      - .env.production
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
      interval: 30s
      timeout: 3s
      retries: 3

networks:
  app-network:
    driver: bridge

.env.production

bash
BASE_URL=http://api.example.com
NODE_ENV=production

6.3 部署命令

bash
# 构建镜像
docker compose build

# 启动服务
docker compose up -d

# 查看运行状态
docker compose ps

# 查看日志
docker compose logs -f

# 验证用户(应该是 node,不是 root)
docker exec nuxt-app-prod whoami
# 输出: node

# 验证文件权限
docker exec nuxt-app-prod ls -la /home/node/app
# 输出: drwxr-xr-x node node ...

七、学习要点总结

核心要点

  1. USER 指令是生产必备的安全配置

    • 避免容器以 root 权限运行
    • 限制文件操作范围
    • 降低安全风险
  2. COPY --chown 是设置文件权限的关键

    • 普通用户需要有文件权限才能读写
    • 使用 --chown=node:node 设置所有者
    • 所有 COPY 都要设置权限
  3. Docker 命令体系清晰

    • 镜像命令:build、images、rmi、tag
    • 容器命令:run、start、stop、restart、rm、ps、logs
    • 调试命令:exec、inspect、stats、cp
  4. Docker Compose 简化多容器管理

    • 配置集中管理
    • 一键启停
    • 环境变量文件支持
  5. 问题排查能力比记忆命令更重要

    • docker logs 查看日志
    • 根据错误信息定位问题
    • 善用 AI 工具辅助

八、延伸学习资源

官方文档

进阶主题

code
推荐学习路径:
│
├── 1. Docker 网络安全
│   ├── 用户定义网络
│   ├── 网络隔离
│   └── 防火墙配置
│
├── 2. 容器资源限制
│   ├── CPU 限制
│   ├── 内存限制
│   └── 磁盘 IO 限制
│
├── 3. 镜像安全扫描
│   ├── Trivy
│   ├── Clair
│   └── Docker Scout
│
├── 4. Secrets 管理
│   ├── Docker Secrets
│   ├── 环境变量加密
│   └── Vault 集成
│
└── 5. 多阶段构建进阶
    ├── 缓存优化
    ├── 构建速度优化
    └── 镜像层合并

实践建议

  1. 对比测试:使用 root 用户 vs 普通用户运行容器,观察权限差异
  2. 安全扫描:使用 docker scout 扫描镜像漏洞
  3. 性能测试:对比不同基础镜像(alpine vs slim)的体积和性能
  4. CI/CD 集成:将安全配置集成到自动化流水线

附录:命令速查表

Docker 镜像命令

bash
docker build -t name:tag .        # 构建镜像
docker images                      # 查看镜像列表
docker rmi <image_id>             # 删除镜像
docker tag old:tag new:tag        # 重命名镜像
docker image prune                # 清理未使用镜像
docker image prune -a             # 清理所有未使用镜像

Docker 容器命令

bash
# 运行管理
docker run -d -p 8001:3000 --name app img  # 运行容器
docker start <container>                    # 启动容器
docker stop <container>                     # 停止容器
docker restart <container>                  # 重启容器
docker rm <container>                       # 删除容器

# 查看调试
docker ps                                   # 查看运行中容器
docker ps -a                                # 查看所有容器
docker logs -f <container>                  # 查看日志
docker exec -it <container> sh              # 进入容器
docker inspect <container>                  # 查看详细信息

# 清理命令
docker container prune                      # 清理已停止容器
docker system prune                         # 清理所有未使用资源

Docker Compose 命令

bash
docker compose up -d               # 启动服务
docker compose down                # 停止服务
docker compose ps                  # 查看状态
docker compose logs -f             # 查看日志
docker compose restart             # 重启服务
docker compose exec <service> sh   # 进入容器

下一步学习:Kubernetes 安全配置、容器资源限制、镜像漏洞扫描、Secrets 管理实战。