Skip to content

Docker

基本概念

概念说明
镜像(Image)只读模板,用于创建容器
容器(Container)镜像运行的实例
仓库(Registry)存储和分发镜像的服务(如 Docker Hub)
数据卷(Volume)容器外的持久化存储,容器删除后数据依然保留
网络(Network)容器间通信的虚拟网络,默认提供 bridge 模式

安装(Linux / CentOS)

bash
# 安装依赖工具
yum install -y yum-utils device-mapper-persistent-data lvm2

# 添加阿里源(国内推荐)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 安装 Docker(含 buildx 和 compose 插件)
yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

# 启动并设置开机自启
systemctl start docker
systemctl enable docker

# 验证安装
docker version

配置镜像加速

bash
mkdir -p /etc/docker
vim /etc/docker/daemon.json

写入以下内容:

json
{
  "registry-mirrors": ["https://hub.rat.dev"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "storage-driver": "overlay2"
}
bash
# 重启生效
systemctl daemon-reload && systemctl restart docker

# 验证镜像加速是否生效
docker info | grep -A 5 "Registry Mirrors"

国内大部分公共镜像源已停服,可使用阿里云个人镜像加速地址

镜像操作

bash
docker search <镜像>                        # 搜索镜像
docker pull <镜像>:<tag>                    # 拉取指定版本镜像
docker images                                 # 列出本地镜像
docker image history <镜像名|ID>              # 查看镜像分层历史
docker image inspect <镜像名|ID>              # 查看镜像元数据
docker rmi <镜像名|ID>                        # 删除镜像
docker image prune                            # 清理无用(dangling)镜像
docker image push <用户>/<>:<tag>       # 推送镜像到仓库

docker images 中出现 REPOSITORY 为 <none> 的镜像,运行 docker image prune 清理


镜像拉取失败排查

  1. 确认加速器是否生效

    bash
    docker info | grep -A 5 "Registry Mirrors"

    输出包含配置的地址即表示生效。拉取成功后输出的 docker.io/library/node:latest 是镜像的规范名称,不代表走的是原始地址,这是正常现象。

  2. 特定 tag 拉不下来(如 node:22-alpine

    国内镜像站对 alpine 变体同步范围有限,可改用华为云 SWR:

    bash
    # 通过华为云 SWR 拉取(同步较全)
    docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/node:22-alpine
    
    # 拉取成功后重新打 tag
    docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/node:22-alpine node:22-alpine
    
    # 删除临时 tag
    docker rmi swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/node:22-alpine

    alpine 同步差时也可改用 node:22-slim(基于 Debian,镜像站同步更稳定)

  3. docker rmi <ID> 提示被多个 tag 引用

    同一 Image ID 有多个 tag 时,需按完整名称逐个删除:

    bash
    docker rmi swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/node:22-alpine
    docker rmi node:22-alpine

    所有 tag 删除后镜像层才真正释放。不确定有哪些 tag 时,用 docker images 查看 IMAGE ID 相同的行,逐一删除。

容器操作

启动容器

bash
# 常用参数说明
# -d              后台运行
# --name          指定容器名
# -p              端口映射(宿主机端口:容器端口)
# -v              目录挂载(宿主机目录:容器目录)
# -e              设置环境变量
# --network       指定网络
# --restart       自动重启策略
docker run -d \
  --name <容器> \
  -p <宿主机端>:<容器端> \
  -v <宿主机目>:<容器目> \
  -e KEY=VALUE \
  --network <网络> \
  --restart always \
  <镜像>

# --restart 可选值
# always        — 总是重启
# no            — 不重启(默认)
# on-failure    — 退出码非 0 时重启
# unless-stopped — 手动停止前总是重启

# 挂载权限
docker run -v /data:/data:ro ...             # 只读挂载
docker run -v /data:/data:rw ...             # 读写挂载(默认)

# 交互式运行(临时测试用)
docker run -it --rm <镜像> /bin/sh

# --link 已废弃,推荐使用自定义网络代替
# docker run -d --link <容器名>:<别名> <镜像名>
# 推荐:将容器加入同一自定义网络,直接通过容器名访问
docker run -d --network <网络> --name <容器> <镜像>

管理容器

bash
docker ps                                             # 查看运行中的容器
docker ps -a                                          # 查看所有容器
docker logs <容器名|ID>                               # 查看容器日志
docker logs -f <容器名|ID>                            # 实时跟踪日志
docker exec -it <容器名|ID> /bin/bash                 # 进入容器(简单环境用 /bin/sh)
docker top <容器名|ID>                                # 查看容器内正在运行的进程
docker stats <容器名|ID>                              # 查看容器资源使用(CPU、内存等)
docker inspect <容器名|ID>                            # 查看容器详情
docker port <容器名|ID>                               # 查看端口映射
docker stop <容器名|ID>                               # 停止容器
docker start <容器名|ID>                              # 启动容器
docker restart <容器名|ID>                            # 重启容器
docker kill <容器名|ID>                               # 强制停止容器
docker rm <容器名|ID>                                 # 删除已停止的容器
docker rm -f <容器名|ID>                              # 强制删除运行中的容器
docker container prune                                # 交互式清理所有已停止的容器(更安全)
docker system prune                                   # 清理所有无用资源

# 资源限制(推荐在 run 时指定,不依赖 docker update)
docker run --memory=512m --cpus=1.5 --name <容器> <镜像>

# 运行后动态调整(临时方案)
docker update --memory 512m <容器名|ID>
docker update --cpu-shares 1024 <容器名|ID>

数据卷操作

bash
docker volume ls                            # 列出数据卷
docker volume create <>                 # 创建数据卷
docker volume inspect <>                # 查看数据卷详情
docker volume rm <>                     # 删除数据卷
docker volume prune                         # 清理未使用的数据卷

# 使用具名数据卷挂载
docker run -v <>:/data <镜像>

网络操作

Docker 安装后默认创建三种网络:

模式说明
bridge默认模式,容器通过虚拟网桥互通,通过端口映射与宿主机通信
host容器与宿主机共享网络命名空间,直接使用宿主机 IP 和端口
none容器无任何网络接口,完全隔离
bash
docker network ls                                         # 列出所有网络
docker network create <网络> --driver bridge            # 创建自定义网络
docker network connect <网络> <容器>                  # 将容器加入网络
docker network inspect <网络>                           # 查看网络详情
docker network rm <网络>                                # 删除网络
docker network prune                                      # 清理未使用的网络

# 启动容器时指定网络
docker run -d --network <网络> --name <容器> <镜像>

同一自定义网络内的容器可直接通过容器名互相访问,无需 --link

容器间通信(关键)

同一自定义网络内,容器之间以容器名--name 指定的值)作为主机名直接访问,端口填容器内监听端口(不是宿主机映射端口)。

bash
# 创建自定义网络
docker network create myweb

# 启动 Node 应用,加入 myweb 网络
docker run -d --name server --network myweb my-node-app

# 启动 Nginx,加入同一网络,对外暴露 80/443
docker run -d --name nginx --network myweb -p 80:80 -p 443:443 nginx:stable

Nginx 配置反向代理到 Node 服务,直接用容器名:

nginx
location / {
    proxy_pass http://server:3000;         # server 是容器名,3000 是容器内端口
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

应用通过容器名连接数据库(以 MySQL 为例):

bash
# 启动 MySQL,加入同一网络
docker run -d --name mysql --network myweb \
  -e MYSQL_ROOT_PASSWORD=123456 \
  mysql:8.4

# 应用启动时通过环境变量传入数据库地址
# MYSQL_HOST 填容器名(即主机名),MYSQL_PORT 填容器内端口(非宿主机映射端口)
docker run -d --name server --network myweb \
  -e MYSQL_HOST=mysql \
  -e MYSQL_PORT=3306 \
  my-node-app

容器名即主机名;建议始终显式指定 --name,避免 Docker 随机命名导致引用失效

常用服务快速启动

Redis

bash
docker run -d \
  --name redis \
  -p 6379:6379 \
  -v ~/redis/data:/data \
  -v ~/redis/conf/redis.conf:/etc/redis/redis.conf \
  redis redis-server /etc/redis/redis.conf

redis.conf 关键配置:

ini
bind 0.0.0.0         # 允许外部访问
daemonize no         # 不使用守护进程(Docker 托管)
requirepass 你的密码
appendonly yes       # 开启持久化

MySQL

bash
docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -v ~/mysql/data:/var/lib/mysql \
  -v ~/mysql/log:/var/log/mysql \
  -v ~/mysql/conf:/etc/mysql/conf.d \
  -v ~/mysql/init:/docker-entrypoint-initdb.d \
  mysql:8.4

/docker-entrypoint-initdb.d 目录下的 .sql 文件会在容器首次启动时自动执行,可用于数据库初始化

MongoDB

bash
docker run -d \
  --name mongo \
  -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=root \
  -e MONGO_INITDB_ROOT_PASSWORD=123456 \
  -v ~/mongo/data:/data/db \
  mongo:7

Dockerfile

常用指令

指令说明
FROM基础镜像,必须为第一条指令
WORKDIR设置工作目录
COPY将文件复制进镜像
ADD同 COPY,额外支持自动解压 tar 和下载 URL
RUN构建时执行命令,每条都会新建一层
ENV设置环境变量,可用 ${KEY} 引用
EXPOSE声明容器监听的端口(仅文档作用)
VOLUME声明数据卷挂载点
CMD容器启动时的默认命令,可被 docker run 覆盖
ENTRYPOINT容器启动入口,不会被覆盖,与 CMD 配合使用
USER指定 RUN/CMD/ENTRYPOINT 使用的用户,生产环境应避免用 root
LABEL为镜像添加元数据标签,替代已废弃的 MAINTAINER
HEALTHCHECK健康检查,定期检测容器是否正常运行

优先使用 COPY 而非 ADD;多条 RUN 命令用 && 合并以减少镜像层数

基础示例

dockerfile
FROM node:22-alpine

WORKDIR /app

# 先复制依赖文件,利用层缓存:仅 package.json 变动时才重新安装
COPY package.json yarn.lock ./
RUN yarn config set registry 'https://registry.npmmirror.com' && yarn --frozen-lockfile --production

COPY . .

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD wget -qO- http://localhost:3000/health || exit 1

CMD ["node", "index.js"]

pnpm 单阶段构建

适合输出文件已包含所有依赖、无需分离构建与运行环境的项目(如 tsup 打包后的服务):

dockerfile
FROM node:22-alpine

WORKDIR /app

# 通过 corepack 激活 pnpm,无需全局安装
RUN corepack enable && corepack prepare pnpm@latest --activate

# 先复制依赖文件,利用层缓存
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

COPY . .
RUN pnpm build

# 创建专用非 root 用户,避免以 root 身份运行服务
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 3000
CMD ["node", "dist/index.js"]

多阶段构建(推荐)

适用于需要分离构建环境与运行环境的场景(如 TypeScript 编译),可大幅减小最终镜像体积:

dockerfile
# ── 构建阶段 ──────────────────────────────────────────────
FROM node:22-alpine AS builder

WORKDIR /app

# 通过 corepack 激活 pnpm,无需全局安装
RUN corepack enable && corepack prepare pnpm@latest --activate

COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

COPY . .
RUN pnpm build

# ── 运行阶段 ──────────────────────────────────────────────
# 若使用 tsup 等打包工具,dist/index.js 已包含所有依赖,无需复制 node_modules
FROM node:22-alpine

WORKDIR /app

COPY --from=builder /app/dist ./dist

# 创建专用非 root 用户,避免以 root 身份运行服务
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 3000
CMD ["node", "dist/index.js"]

.dockerignore

避免将无关文件打入镜像,加快构建速度:

text
.git
node_modules
dist
*.log

构建镜像

bash
# 基本构建
docker build -t <镜像>:<版本> .

# 指定 Dockerfile 文件
docker build -f Dockerfile.prod -t my-app:1.0 .

# 查看镜像分层
docker image history <镜像名|ID>

待补充

  • [ ] Docker 健康检查(HEALTHCHECK)
  • [ ] 镜像推送到私有仓库
  • [ ] 资源限制(--memory、--cpus)最佳实践

持续学习,持续成长