Docker常用命令

(一)镜像

【1】搜索镜像

  • 返回的信息的 OFFICIAL 标记为 [OK] 的镜像,安全性更有保障。

    powershell 复制代码
    docker search 镜像名称

【2】从仓库获取镜像

powershell 复制代码
docker pull [选项] [Registry地址/]仓库名[:标签]

如:

powershell 复制代码
docker.io / library / ubuntu : 24.04
────┬────   ───┬───   ──┬───   ──┬──
    │          │        │        │
Registry地址  用户名    仓库名    标签
 (可省略)    (可省略)
组成部分 说明 默认值
Registry 地址 镜像仓库地址 docker.io (Docker Hub)
用户名 镜像所属用户/组织 library (官方镜像)
仓库名 镜像名称 必须指定
标签 版本标识 latest

【3】运行镜像

docker run 在需要时会自动 pull 镜像,因此通常不需要单独执行 docker pull。

powershell 复制代码
# 拉取镜像
docker pull ubuntu:24.04
# 基于镜像启动一个容器
docker run -it --rm ubuntu:24.04 bash
参数 说明
-it 交互式终端模式
--rm 退出后自动删除容器
bash 启动命令

【4】查看所有镜像

powershell 复制代码
docker image ls
# 等同于
docker images 
  • 将会列出所有镜像,其中 EXTRA 如果为 U (In Use) 表示有容器在使用该镜像

    IMAGE ID DISK USAGE CONTENT SIZE EXTRA
    mysql:latest 24e450bbd24f 1.27GB 283MB U
    n8nio/n8n:latest ab216dc8d10d 2.01GB 283MB

【5】查看某个镜像

powershell 复制代码
docker iamges[仓库名][:标签]

【6】虚悬镜像

在镜像列表里,你可能会看到一些仓库名和标签都为 的镜像,这类镜像被称为虚悬镜像。

  • 虚悬镜像

    powershell 复制代码
    $ docker images
    REPOSITORY   TAG       IMAGE ID       SIZE
    <none>       <none>    00285df0df87   342MB
  • 列出虚悬镜像

    powershell 复制代码
    docker images -f dangling=true
  • 删除虚悬镜像

    powershell 复制代码
    docker image prune

【7】删除本地镜像

docker rmi 是 docker image rm 的简写,两者等效。

powershell 复制代码
docker image rm [选项] <镜像1> [<镜像2> ...]

(二)容器

  • 将镜像运行起来后就是容器

【1】新建并启动容器

powershell 复制代码
docker run [选项] 镜像 [命令] [参数...]
powershell 复制代码
$ docker run -it ubuntu:24.04 /bin/bash
root@af8bae53bdd3:/#
参数 作用 示例
-i 保持标准输入 (stdin) 打开,允许输入
-t 分配伪终端 (pseudo-TTY),提供终端界面
-it 两者组合使用,获得交互式终端 docker run -it ubuntu bash
-d 后台运行 (detach) docker run -d nginx
--name 指定容器名称 docker run --name myapp nginx
--rm 退出后自动删除容器 docker run --rm ubuntu echo hi

【2】端口映射

powershell 复制代码
## 将宿主机的 8080 端口映射到容器的 80 端口

$ docker run -d -p 8080:80 nginx

## 随机映射端口

$ docker run -d -P nginx

## 只绑定到 localhost

$ docker run -d -p 127.0.0.1:8080:80 nginx

【3】查看所有容器

powershell 复制代码
## 查看启动中的容器
docker ps
# 或者
docker container ls

### 查看所有容器(包括已停止的)
docker ps -a 
# 或者
docker container ls -a

【4】启动已终止的容器

powershell 复制代码
## 重新启动容器
docker start 容器名称

## 启动并附加终端
docker start -ai 容器名称
参数 全称 作用
-a --attach 将容器的标准输出(STDOUT)和标准错误(STDERR)附加到当前终端
-i --interactive 保持标准输入(STDIN)打开,允许你与容器进行交互

【5】容器启动后立即退出的原因

  • 原因:主进程执行完毕或无法保持运行
powershell 复制代码
## 这个容器会立即退出
## `-d` 参数 不是 让容器 "一直运行",是让容器 "在后台运行",能运行多久取决于主进程
$ docker run -d ubuntu:24.04
  • 上边命令的执行过程:
    • 1.容器启动
    • 2.没有指定命令,默认执行 /bin/bash
    • 3.但没有交互式终端 (没有 -it 参数),bash 发现没有输入源
    • 4.bash 立即退出
    • 5.主进程退出,容器停止

【6】运行一个不会立即终止的ubuntu

  1. 下面的命令创建的 ubuntu 容器会一直运行,并且给出终端与 ubuntu 进行交互,退出时需要在终端中输入exit

    • -it:交互模式(-i保持标准输入打开,-t分配伪终端),允许用户与容器内Shell交互。
    • --name myubuntu:为容器指定名称myubuntu(便于后续管理,如docker stop myubuntu)。
    • ubuntu:24.04:使用24.04版本的ubuntu镜像(Docker Hub已验证存在)。
    • bash:启动Bash Shell作为容器主进程。
    powershell 复制代码
    docker run -it --name myubuntu ubuntu:24.04  bash

2.运行一个在后台运行的 ubuntu 容器

  • -d:让容器在后台运行(不阻塞当前终端)。

  • --name myubuntu:为容器指定名称(可选,方便后续管理)。

  • ubuntu:24.04:使用24.04版本的ubuntu镜像(确保已拉取,或自动拉取)。

  • tail -f /dev/null:

    • Ubuntu 镜像默认没有长期运行的服务(如 systemd),直接运行 bash 会因终端退出而停止容器。
    • tail -f /dev/null 是一个无操作命令,会持续运行,保持容器存活。
    powershell 复制代码
    docker run -d --name myubuntu ubuntu:24.04 tail -f /dev/null

【7】查看容器退出状态码

powershell 复制代码
# 查看 STATUS 列,如 "Exited (1)" 表示异常退出
docker ps -a --filter "name=容器名称"

【8】查看容器日志

powershell 复制代码
docker logs 容器名称

【9】让已经在后台运行的容器回到前台

  • 退出终端使用 exit
powershell 复制代码
docker exec -it 容器名 /bin/bash
参数 作用
-i 保持标准输入打开 (interactive)
-t 分配伪终端 (TTY)
-it 两者组合,获得完整交互体验
-u 指定用户 (如 -u root)
-w 指定工作目录
-e 设置环境变量

【10】终止容器

  • 优雅停止:先发 SIGTERM,超时后发 SIGKILL

    powershell 复制代码
    docker stop 容器名或ID
  • 强制停止:直接发 SIGKILL

    powershell 复制代码
    docker kill 容器名或ID

【11】启动已停止的容器

powershell 复制代码
docker start 容器名或ID

## 启动并附加终端
docker start -ai 容器名

【12】重启运行中的容器

powershell 复制代码
## 先停止再启动
docker restart 容器名

【13】导出容器

如果不知道自己导出的文件在哪,可以看看自己导出命令时用的终端所在的目录位置

  • 输出的路径是指你自己的电脑的路径,不是docker

    powershell 复制代码
    docker export -o 输入的路径/输出的名字 <容器ID或名词>
  • 如下,将输出文件放在D盘 myContainer 文件夹下

    powershell 复制代码
    docker export -o d:/myContainer/myubuntu.tar myubuntu
  • 也可以在放置容器的目录下打开终端,然后输入如下命令即可

    • 导出的压缩包会报错,不建议使用
    powershell 复制代码
    docker export myubuntu > ubuntu.tar

【14】导入容器

注意:导入自己导出的容器后,docker export 命令会将容器转换为镜像

  • 语法:

    powershell 复制代码
    docker import [选项] <文件路径或URL> [镜像名称:标签]
  • 示例,路径就是你电脑的路径:

    powershell 复制代码
    docker import C:\path\to\my_container.tar my_image:latest

【15】删除已停止的容器

  • 容器删除后数据会丢失:因为所有的数据修改都保存在最上层的容器层中,容器销毁时,这个层也就随之销毁了。(除非使用了数据卷)

    powershell 复制代码
    docker rm 容器名或ID
    #等同于
    docker container rm 容器名或ID

(三)仓库

  • docker.io/ubuntudocker.io 是注册服务器地址,ubuntu 是仓库名。
  • 实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。
  • ubuntu 的所有版本都在ubuntu仓库中。

【1】创建一个私有仓库

  • 原理:Docker 的私有仓库可以通过使用官方的 registry 镜像创建一个本地的 registry 容器来实现,这是 Docker 官方提供的一种轻量级私有仓库解决方案。

    powershell 复制代码
    docker run -d -p 5000:5000 --name my-registry registry
    • -d:表示在后台运行容器。
    • -p 5000:5000:将主机的 5000 端口映射到容器的 5000 端口,这样可以通过主机的 5000 端口访问私有仓库。
    • --name my-registry:为容器指定一个名称,方便后续管理。
    • registry:指定要运行的镜像名称,不带 tag 默认就是 latest
  • 这时候容器中就会有一个名字为 "my-registry" 的容器,就是本地的私有仓库

【2】验证仓库是否运行/ 查看仓库中的镜像

  • http://localhost:5000/v2/_catalog 就是自己的仓库地址

  • 返回:{"repositories":[]} 代表运行成功

    powershell 复制代码
    curl http://localhost:5000/v2/_catalog

【3】在私有仓库上传

  1. 在将镜像推送到私有仓库之前,需要先为镜像打上私有仓库的标签。

    • 将本地的 nginx 镜像标记为私有仓库的镜像:

    docker tag <源镜像名称>:<标签> <私有仓库地址>:<端口>/<目标镜像名称>:<标签>

    powershell 复制代码
    docker tag nginx:latest localhost:5000/nginx:latest。
  2. 使用 docker push 上传标记的镜像 docker push <私有仓库地址>:<端口>/<目标镜像名称>:<标签>

    powershell 复制代码
    docker push localhost:5000/nginx:latest

【4】从私有仓库下载镜像

powershell 复制代码
docker pull localhost:5000/nginx:latest

【5】查看私有仓库中的镜像。

  • 浏览器直接输入 http://localhost:5000/v2/_catalog 也能看对应的信息

    powershell 复制代码
    curl localhost:5000/v2/_catalog
  • 将会输出 {"repositories":["nginx"]}

【6】配置非 https 仓库地址

  • 如果你不想使用 127.0.0.1:5000 作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如 192.168.199.100:5000 这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。

  • 这是因为 Docker 默认不允许非 HTTPS 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制,或者查看下一节配置能够通过 HTTPS 访问的私有仓库。

  • 对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容

    json 复制代码
    {
      "insecure-registries": [
        "192.168.199.100:5000"
      ]
    }
  • 对于 windows 系统可以在 docker.desktop 的"设置"》》"Docker Engine" 中进行配置

(四)DockerFile

  • Dockerfile 是一个文本文件,其内包含了一条条的 指令 (Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

【1】FROM 命令

  • FROM 命令用来指定基础镜像,之后所有的操作都是基于这个基础镜像进行的。

  • linux 一般推荐使用 Alpine 镜像(众多 Linux 发行版本中的一员,小巧、安全)。

  • 实际上,node:22.20.0-alpine 中的 alpine 指的是 Alpine Linux 发行版,这是一个轻量级的 Linux 发行版。在这种情况下,它既是 Node.js 的轻量级运行环境,也是基于轻量级 Linux 发行版的容器镜像。

    powershell 复制代码
    FROM <镜像> [AS <阶段名称>]
    powershell 复制代码
    # 基于 node 的 22.20.0 版本创建一个镜像
    FROM node:22.20.0
    powershell 复制代码
    # 用 node 的 22.20.0 的轻量版本。
    FROM node:22.20.0-alpine

【2】RUN 执行命令

  • RUN 指令在当前镜像层之上创建一个新层,执行指定的命令,并提交结果。

  • 为了保持Dockerfile配置文件的可读性及可维护性,建议将长的或复杂的RUN命令用反斜杠("\")连接起来。

  • 不要使用 RUN apt-get upgrade 命令 ,如果某个包确定要升级(如 foo 包),则使用 apt-get install -y foo 命令

  • 语法

    powershell 复制代码
    RUN <command>
    RUN ["executable", "param1", "param2"]
  • 最佳实践:组合命令,减少层数

    powershell 复制代码
    ## 更新包列表 并安装 nginx 然后删除缓存
    RUN apt-get update && \
        apt-get install -y nginx && \
        rm -rf /var/lib/apt/lists/*
  • 常见问题

    • 下边的命令中,hello.txt 将会出现在根目录 /,而不是 /app。原因:每个 RUN 都在一个新的 Shell/容器环境中执行。cd 只影响当前 RUN 的环境。解决:使用 WORKDIR 指令。

      powershell 复制代码
      RUN cd /app
      RUN touch hello.txt
    • 使用 WORKDIR

      powershell 复制代码
      WORKDIR /app
      RUN touch hello.txt

【3】COPY 命令和 dockerignore

  • COPY 指令将构建上下文中的文件或目录复制到镜像内。

    powershell 复制代码
    COPY [选项] <源路径>... <目标路径>
    COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
    powershell 复制代码
    ## 复制文件到指定目录
    COPY package.json /app/
    
    ## 复制文件并重命名
    COPY config.json /app/settings.json
    
    ## 复制整个目录的内容(不是目录本身)
    COPY src/ /app/src/
  • 从其他构建阶段复制

    为什么先复制 package.json 进去,安装依赖之后再复制其他文件,直接全部复制进去不就行了?

    不是的,这两种写法的效果不同。

    docker 是分层存储的,dockerfile 里的每一行指令是一层,会做缓存。

    每次 docker build 的时候,只会从变化的层开始重新构建,没变的层会直接复用。

    也就说现在这种写法,如果 package.json 没变,那么就不会执行 npm install,直接复用之前的。

    那如果一开始就把所有文件复制进去呢?

    那不管 package.json 变没变,任何一个文件变了,都会重新 npm install,这样没法充分利用缓存,性能不好。

    powershell 复制代码
    ## 构建阶段
    
    FROM node:20 AS builder
    WORKDIR /app
    COPY package*.json ./
    RUN npm install
    ## 注意:需要配合 .dockerignore 文件,不要将本地的 node_modules 文件夹也复制进容器了,
    ## 因为会覆盖掉容器的 node_modules 导致运行不起来
    COPY . .
    RUN npm run build
    
    ## 生产阶段
    
    FROM nginx:alpine
    COPY --from=builder /app/dist /usr/share/nginx/html
  • 使用 .dockerignore 排除不需要复制的文件:

    • 这可以:减小构建上下文大小;加速构建;避免复制敏感文件
    powershell 复制代码
    ## .dockerignore
    
    node_modules
    .git
    .env
    *.log
    Dockerfile
    .dockerignore

【4】ENV 设置环境变量

  • 基本语法

    powershell 复制代码
    ## 格式一:单个变量
    ENV <key> <value>
    
    ## 格式二:多个变量(推荐)
    ENV <key1>=<value1> <key2>=<value2> ...
    powershell 复制代码
    # 设置单个变量
    ENV NODE_VERSION 20.10.0
    ENV APP_ENV production
    
    # 设置多个变量,包含空格的值用双引号括起来。
    ENV NODE_VERSION=20.10.0 \
        APP_ENV=production \
        APP_NAME="My Application"
  • 使用环境变量:可以使用 $变量名${变量名} 格式:

    powershell 复制代码
    ENV NODE_VERSION=20.10.0
    
    ## 在 RUN 中使用
    
    RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz \
        | tar -xJ -C /usr/local --strip-components=1
    
    ## 在 WORKDIR 中使用
    
    ENV APP_HOME=/app
    WORKDIR $APP_HOME
    
    ## 在 COPY 中使用
    
    COPY . $APP_HOME
  • 运行时覆盖

    • 使用 -e--env 覆盖 Dockerfile 中定义的环境变量:
    powershell 复制代码
    ## 覆盖单个变量
    docker run -e APP_ENV=development myimage
    
    ## 覆盖多个变量
    docker run -e APP_ENV=development -e DEBUG=true myimage
    
    ## 从环境变量文件读取
    docker run --env-file .env myimage
  • 统一管理版本号

    powershell 复制代码
    ## ✅ 好:版本集中管理
    
    ENV NGINX_VERSION=1.25.0 \
        NODE_VERSION=20.10.0 \
        PYTHON_VERSION=3.12.0
    
    RUN apt-get install nginx=${NGINX_VERSION}
    
    ## ❌ 差:版本分散在各处
    
    RUN apt-get install nginx=1.25.0

【11】ARG 构建参数

  • ARG 指令定义构建时的变量,可以在 docker build 时通过 --build-arg 传入。

    powershell 复制代码
    ARG <参数名>[=<默认值>]
  • ARG vs ENV

    特性 ARG ENV
    生效时间 仅构建时 构建时 + 运行时
    持久性 构建后消失 写入镜像
    覆盖方式 docker build --build-arg docker run -e
    适用场景 构建参数 (版本号等) 应用配置
    可见性 docker history 可见 docker inspect 可见
    powershell 复制代码
    构建时                         运行时
    ├─ ARG VERSION=1.0             │ (ARG 已消失)
    ├─ ENV APP_ENV=prod            │ APP_ENV=prod(仍存在)
    └─ RUN echo $VERSION           │
  • 基本用法

    powershell 复制代码
    ## 定义有默认值的 ARG
    ARG NODE_VERSION=20
    
    ## 使用 ARG
    FROM node:${NODE_VERSION}-alpine
    RUN echo "Using Node.js $NODE_VERSION"
  • 构建时传入多个 ARG 参数

    powershell 复制代码
    ## 可以不设置默认值
    ARG aaa
    ARG bbb
    powershell 复制代码
    docker build --build-arg aaa=3 --build-arg bbb=4 -t arg-test -f Dockerfile .
  • 构建时覆盖

    powershell 复制代码
    ## 使用默认值
    $ docker build -t myapp .
    
    ## 覆盖默认值
    $ docker build --build-arg NODE_VERSION=18 -t myapp .
  • FROM 之前的 ARG 只能用于 FROM 指令,FROM 之后重新声明

    powershell 复制代码
    ARG NODE_VERSION=20
    
    FROM node:${NODE_VERSION}-alpine
    
    ## 需要再次声明才能使用
    
    ARG NODE_VERSION
    ## RUN echo "Node version: 20"        
    RUN echo "Node version: $NODE_VERSION"
  • 组合使用 ENV 和 ARG

    powershell 复制代码
    ## ARG 接收构建时参数
    ARG NODE_VERSION=20
    
    ## ENV 保存到运行时
    ENV NODE_VERSION=$NODE_VERSION
    
    ## 后续指令使用
    RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/...
    powershell 复制代码
    ## 构建时指定版本
    docker build --build-arg NODE_VERSION=18 -t myapp .

【5】WORKDIR 指定工作目录

  • WORKDIR 指定后续指令的工作目录。如果目录不存在,Docker 会自动创建。

    powershell 复制代码
    WORKDIR <工作目录路径>
    powershell 复制代码
    WORKDIR /app
    
    RUN pwd          # 输出 /app
    RUN echo "hello" > world.txt    # 创建 /app/world.txt
    COPY . .         # 复制上下文目录到 /app/
  • 常见错误

    powershell 复制代码
    ## ❌ 错误:cd 在下一个 RUN 中无效
    RUN cd /app #只是在自己这一次容器中cd 
    RUN echo "hello" > world.txt    # 文件在根目录!
  • 多阶段构建中的 WORKDIR

    • 尽早使用 WORKDIR,路径要使用绝对路径
    powershell 复制代码
    ## 构建阶段
    
    FROM node:20 AS builder
    WORKDIR /build  # 绝对路径
    COPY package*.json ./
    RUN npm install
    COPY . .
    RUN npm run build
    
    ## 生产阶段
    
    FROM nginx:alpine
    WORKDIR /usr/share/nginx/html
    COPY --from=builder /build/dist .

【6】EXPOSE 暴露端口

  • EXPOSE 声明容器运行时提供服务的端口。这是一个文档性质的声明,告诉使用者容器会监听哪些端口。

  • 告诉镜像使用者,容器将在哪些端口提供服务

    powershell 复制代码
    ## 声明单个端口,这个容器会在 80 端口提供服务
    ## docker run -p 8080:80 nginx  这个命令才会将宿主机 8080 端口映射到容器 80 端口
    EXPOSE 80
    
    ## 声明多个端口
    EXPOSE 80 443
    
    ## 声明 TCP 和 UDP 端口
    EXPOSE 80/tcp
    EXPOSE 53/udp

【7】CMD 容器启动命令

  • CMD 指令用于指定容器启动时默认执行的命令。它定义了容器的 "主进程"。

  • 核心概念:容器的生命周期 = 主进程的生命周期。CMD 指定的命令就是这个主进程。

  • 在Dockerfile配置文件中,CMD命令或ENTRYPOINT命令至少必有其一。

  • 注意点: CMD 使用双引号,(JSON 不支持单引号), 多个 CMD 只有最后一个生效

    powershell 复制代码
    CMD ["node", "server.js"]
  • docker run 后的命令会覆盖 Dockerfile 中的 CMD:

    • 当我们使用 docker run my-app-image,Dockerfile 中的的CMD命令将会执行node /app/main.js

      powershell 复制代码
      CMD ["node", "/app/main.js"]
    • 如果使用 docker run my-app-image node /app/test.js ,将执行 node /app/test.js 而不是原来的 /app/main.js

【8】ENTRYPOINT入口点

  • ENTRYPOINT 指定容器启动时运行的入口程序。与 CMD 不同,ENTRYPOINT 定义的命令不会被 docker run 的参数覆盖,而是 接收这些参数

  • 核心作用:让镜像像一个可执行程序一样使用,docker run 的参数作为这个程序的参数。

  • ENTRYPOINT 和 CMD 的区别

    特性 ENTRYPOINT CMD
    定位 固定的入口程序 默认参数
    docker run 参数 追加为参数 完全覆盖
    覆盖方式 --entrypoint 直接指定命令
    适用场景 把镜像当命令用 提供默认行为
  • 基本使用

    powershell 复制代码
    ## Dockerfile 中的 CMD
    CMD ["curl", "-s"]
    powershell 复制代码
    ## 运行镜像时
    docker run myimage                      # curl -s(缺参数)
    docker run myimage http://example.com   # curl -s http://example.com ✓
  • 和CMD组合使用

    powershell 复制代码
    ## Dockerfile 文件
    ## ENTRYPOINT + CMD 组合(推荐)
    ENTRYPOINT ["curl", "-s"]
    CMD ["http://example.com"]
    powershell 复制代码
    ## 运行时允许通过参数修改地址
    docker run myimage                      # curl -s http://example.com(默认)
    docker run myimage http://other.com     # curl -s http://other.com ✓
    docker run myimage -v http://other.com  # curl -s -v http://other.com ✓
  • 注意:当Dockerfile 如下面所示时,执行 docker run my-image http://different-url.com 命令时,命令的参数会被附加到已有的 ENTRYPOINT 命令之后,但实际上由于 curl 命令已经完整,新的参数不会被使用。

    powershell 复制代码
    ## Dockerfile 中如果时下面这样
    ENTRYPOINT ["curl", "-s", "http://example.com"]
  • 可以使用 --entrypoint 参数将 Dockerfile 中的ENTRYPOINT给覆盖掉

    powershell 复制代码
    ## Dockerfile 文件
    FROM alpine
    ENTRYPOINT ["echo", "Hello from Dockerfile"]
    powershell 复制代码
    ## 正常运行
    docker run my-image
    # 输出: Hello from Dockerfile
    
    ## 使用 --entrypoint 覆盖:
    ## 注意镜像的位置
    docker run --entrypoint echo my-image "Hello from runtime"
    # 输出: Hello from runtime

【9】VOLUME 定义匿名卷

定义的卷并不是在容器里。VOLUME /var/lib/mysql 指定的不是容器内部的一个普通目录,而是一个由 Docker 创建的挂载点。数据存在 Docker 管理的独立卷(volume)里,这个卷在容器外,只是在运行时被挂载到容器的 /var/lib/mysql,是一个匿名卷。

  • VOLUME 指令创建挂载点,并标记为外部挂载的卷。

  • 核心原则:容器存储层应该保持无状态,任何运行时数据都应该存储在卷中。

    powershell 复制代码
    ## 定义多个卷
    VOLUME ["/路径1", "/路径2"]
    ## 定义单个卷
    VOLUME /路径
    powershell 复制代码
    ## 定义单个卷
    FROM mysql:8.0
    VOLUME /var/lib/mysql
    ## 定义多个卷
    FROM myapp
    VOLUME ["/data", "/logs", "/config"]
  • 自动创建匿名卷:如果运行时未指定挂载,Docker 会自动创建匿名卷:

    powershell 复制代码
    docker run mysql:latest
    docker volume ls
    ## 输出
    DRIVER    VOLUME NAME
    local     a1b2c3d4e5f6...  # 自动创建的匿名卷
  • 使用命名卷替代匿名卷

    powershell 复制代码
    ## 这个命令会代替Dockerfile 文件中的 VOLUME 
    ## 虽然 VOLUME 可以被舍弃掉,但保留 VOLUME,方便他人理解并减少误用
    
    docker run -v mysql_data:/var/lib/mysql mysql:latest
    docker volume ls
    ## 输出
    DRIVER    VOLUME NAME
    local      mysql_data  # 自定的卷名称
  • 可被 Bind Mount 覆盖

    powershell 复制代码
    ## 使用宿主机目录替代
    ## 下面是将使用宿主机的d盘 mysql_data 文件夹
    docker run -v "D:\mysql_data:/var/lib/mysql" mysql:latest
  • VOLUME 在构建时的特殊行为

    • VOLUME 之后对该目录的修改会被丢弃!

    原因:在构建过程中,VOLUME 指令会为该目录创建一个临时的匿名卷。后续 RUN 指令对该目录的写入实际发生在这个临时卷中,而非镜像层。当该 RUN 指令结束后,临时卷被丢弃,因此写入的内容不会保存到最终镜像中。注意:这与容器运行时创建的匿名卷是不同的------运行时创建的卷会在容器生命周期内持续存在。

    powershell 复制代码
    FROM ubuntu
    VOLUME /data
    
    ## ❌ 这个文件不会出现在镜像中!
    RUN echo "hello" > /data/test.txt
    • 正确做法
    powershell 复制代码
    FROM ubuntu
    
    ## ✅ 先写入文件
    RUN mkdir -p /data && echo "hello" > /data/test.txt
    
    ## 再声明 VOLUME
    VOLUME /data
  • VOLUME 和 docker run -v

    特性 Dockerfile VOLUME docker run -v
    定义时机 镜像构建时 容器运行时
    默认行为 创建匿名卷 可指定命名卷或路径
    灵活性 低 (固定路径) 高 (可任意指定)
    适用场景 定义必须持久化的路径 灵活的数据管理

【10】BUILD 构建镜像

当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。
一般来说,应该将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。
那么为什么会有人误以为 . 是指定Dockerfile 所在目录呢?这是因为在默认情况下,如果不额外指定 Dockerfile 的话,会将上下文目录下的名为 Dockerfile 的文件作为 Dockerfile。

这只是默认行为,实际上 Dockerfile 的文件名并不要求必须为 Dockerfile,而且并不要求必须位于上下文目录中,比如可以用 -f ../Dockerfile.php 参数指定某个文件作为 Dockerfile

powershell 复制代码
docker build [选项] <上下文路径/URL/->
选项 说明
-t,--tag 为镜像指定一个名称和标签
-f,--file 指定Dockerfile文件的路径或URL地址;
-m,--memory 设置Docker build命令的内存限制;
powershell 复制代码
docker build -t myapp:1.0 -f myapp/Dockerfile .
  • 下面命令中有一个 . ,它实际上是在指定上下文的目录docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。

    powershell 复制代码
    docker build -t my-image:v1 .
    ## 命令执行后将会输出如下命令。就是将构建上线文内容交给 Docker 引擎
    # Sending build context to Docker daemon 2.048 kB

(五)数据卷

  • 容器的存储层有一个关键问题:容器删除后,数据就没了。

  • 数据卷 (Volume) 解决了这个问题,它的生命周期独立于容器。

  • 数据卷的特性

    特性 说明
    持久化 容器删除后数据仍然保留
    共享 多个容器可以挂载同一个数据卷
    即时生效 对数据卷的修改立即可见
    不影响镜像 数据卷中的数据不会打包进镜像
    性能更好 绕过 UnionFS,直接读写

【1】创建数据卷

powershell 复制代码
docker volume create my-vol

【2】列出所有数据卷

powershell 复制代码
docker volume ls

【3】查看数据卷详情

powershell 复制代码
docker volume inspect 数据卷名

【4】挂载数据卷

powershell 复制代码
# 推荐
docker run -d \
    --name web \
    --mount source=my-vol,target=/usr/share/nginx/html \
    nginx
    
# 简写(不推荐)挂载路径不存在会自动创建
docker run -d \
    --name web \
    -v my-vol:/usr/share/nginx/html \
    nginx
    
# 只读挂载
docker run -d \
    --mount source=my-vol,target=/data,readonly \
    nginx
  • 参数说明

    参数 说明
    source 数据卷名称 (不存在会自动创建)
    target 容器内挂载路径
    readonly 可选,只读挂载

(六)挂载主机目录

  • Bind Mount (绑定挂载) 将 宿主机的目录或文件 直接挂载到容器中。容器可以读写宿主机的文件系统。

  • Bind Mount vs Volume

    特性 Bind Mount Volume
    数据位置 宿主机任意路径 Docker 管理的目录
    路径指定 必须是绝对路径 卷名
    可移植性 依赖宿主机路径 更好 (Docker 管理)
    性能 依赖宿主机文件系统 优化的存储驱动
    适用场景 开发环境、配置文件 生产数据持久化
    备份 直接访问文件 需要通过 Docker
  • 选择建议

    需求 推荐方案
    开发时同步代码 Bind Mount
    持久化数据库数据 Volume
    共享配置文件 Bind Mount
    容器间共享数据 Volume
    备份方便 Bind Mount (直接访问)
    生产环境 Volume

【1】挂载

powershell 复制代码
## 推荐
docker run -d \
    --mount type=bind,source=/宿主机路径,target=/容器路径 \
    nginx

## 简写,宿主机路径会自动创建
docker run -d \
    -v /宿主机路径:/容器路径 \
    nginx

【2】开发环境代码同步

powershell 复制代码
## 将本地代码目录挂载到容器

$ docker run -d \
    -p 8080:80 \
    --mount type=bind,source=$(pwd)/src,target=/usr/share/nginx/html \
    nginx

## 修改本地文件,容器内立即生效(热更新)

【3】配置文件挂载

powershell 复制代码
## 挂载自定义 nginx 配置

docker run -d \
    --mount type=bind,source=/path/to/nginx.conf,target=/etc/nginx/nginx.conf,readonly \
    nginx

【4】MySQL 定义卷和挂载点完整流程

  1. 创建 Dockerfile

    powershell 复制代码
    # 使用官方 MySQL 镜像作为基础镜像
    FROM mysql:latest
    
    # 设置 MySQL root 用户的密码环境变量
    # 注意:这里设置的是默认值,运行时可以通过 -e 参数覆盖
    ENV MYSQL_ROOT_PASSWORD=rootpassword
    
    # 设置默认创建的数据库名称
    ENV MYSQL_DATABASE=myapp
    
    # 设置默认创建的数据库用户
    ENV MYSQL_USER=myuser
    
    # 设置默认创建的数据库用户的密码
    ENV MYSQL_PASSWORD=userpassword
    
    # 定义数据卷挂载点
    # /var/lib/mysql 是 MySQL 默认的数据存储目录
    # 这里声明为 VOLUME,Docker 会自动创建一个匿名卷来持久化数据
    # 注意:VOLUME 指令只能声明容器内的挂载点,无法指定宿主机路径
    VOLUME ["/var/lib/mysql"]
    
    # 可选:定义配置文件目录的挂载点
    # /etc/mysql/conf.d 是 MySQL 的自定义配置目录
    # 可以在这个目录下放置自定义的配置文件
    VOLUME ["/etc/mysql/conf.d"]
    
    # 设置工作目录
    WORKDIR /docker-entrypoint-initdb.d
    
    # 可选:复制初始化 SQL 脚本到容器中
    # 这些脚本会在容器首次启动时自动执行
    # COPY init.sql /docker-entrypoint-initdb.d/
    
    # 暴露 MySQL 默认端口 3306
    EXPOSE 3306
    
    # 使用 MySQL 官方镜像的启动脚本作为入口点
    # 这个脚本会处理初始化、配置加载等任务
    ENTRYPOINT ["docker-entrypoint.sh"]
    
    # 启动 MySQL 服务器
    # mysqld 是 MySQL 服务器的守护进程
    CMD ["mysqld"]
  2. 在dockerfile 所在的文件夹中执行构建命令,将根据 dockerfile 构建一个镜像

    powershell 复制代码
    docker build -t my-mysql .
  3. 运行自己构建的镜像,并设置了数据库和配置文件的本地目录

    powershell 复制代码
    docker run -d -v d:\data:/var/lib/mysql -v d:\config.d:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root123 mymysql

(七)Docker Compose

首先介绍几个术语。

  • 服务 (service):一个应用容器,实际上可以运行多个相同镜像的实例。
  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元。

可见,一个项目可以由多个服务 (容器) 关联而成,Compose 面向项目进行管理。
Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

  • 我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

  • Compose 恰好满足了这样的需求。它允许用户通过一个单独的 compose.yaml (历史默认名也常见为 docker-compose.yml) 模板文件 (YAML 格式) 来定义一组相关联的应用容器为一个项目 (project)。

【1】安装与卸载

  1. 如果是 windows 系统,并且安装了 Docker Desktop 那么已经默认安装过了Compose

  2. 如果是linux,你可以通过 Docker 官方发布页安装 Compose CLI 插件。把二进制文件保存到 $DOCKER_CONFIG/cli-plugins/docker-compose,并赋予执行权限即可。

    powershell 复制代码
    DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
    mkdir -p $DOCKER_CONFIG/cli-plugins
    curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
    chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
  3. 测试安装

    powershell 复制代码
    $ docker compose version
    Docker Compose version vX.Y.Z
  4. 卸载,linux 将二进制文件删除即可

    powershell 复制代码
    rm $DOCKER_CONFIG/cli-plugins/docker-compose

【2】简单使用

  1. 新建一个文件夹,在文件夹中创建 app.py 文件,作为一个项目,内容如下

    python 复制代码
    from flask import Flask
    from redis import Redis
    
    app = Flask(__name__)
    redis = Redis(host='redis', port=6379)
    
    @app.route('/')
    def hello():
        count = redis.incr('hits')
        return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", debug=True)
  2. 在同一个文件夹中新建 Dockerfile 文件,内容如下

    javascript 复制代码
    FROM python:3.12-alpine
    ADD . /code
    WORKDIR /code
    RUN pip install redis flask
    CMD ["python", "app.py"]
  3. 在同一个文件夹中新建 compose.yaml 文件,内容如下

    yaml 复制代码
    services:
      web:
        build: .
        ports:
          - "5000:5000"
    
      redis:
        image: "redis:alpine"
  4. 在项目的目录下,使用如下命令,启动项目(项目会下载需要的镜像设置对应的端口等)

    • 如果在命令的最后加上 -d 可以在后台运行
    powershell 复制代码
    docker compose up
  5. 等待项目启动完成后,可以在浏览器中输入localhost:5000 访问页面,每次刷新页面,计数就会加 1。

  6. 可以在命令行工具中使用 Ctrl + C 停止项目

    • 也可以使用如下命令进行停止
    powershell 复制代码
    docker compose stop
  7. 如果是在后台运行,可以使用如下命令进入服务:

    powershell 复制代码
    # 进入到 redis 容器,sh 指的是 shell 终端,让你能与 redis 容器进行交互操作
    $ docker compose exec redis sh
    /data # redis-cli
    127.0.0.1:6379> get hits
    "9"

【3】项目启动与停止

  • docker compose up:第一次启动项目,拉取镜像、创建容器
  • docker compose start:启动已停止的容器(项目已存在)
  • docker compose stop:优雅地停止容器(不删除容器)
  • docker compose down:完全清理,删除容器和网络(开发时常用)

【4】调试与查看

  • docker compose ps:查看项目中的容器状态
  • docker compose logs:查看容器日志(排查问题的第一步)
  • docker compose exec:进入正在运行的容器执行命令

【5】构建与更新

  • docker compose build:重新构建镜像(修改 Dockerfile 后)
  • docker compose pull:更新所有镜像到最新版本

【6】配置验证

  • docker compose config:验证 docker-compose.yml 格式是否正确

【7】命令对象与格式

  • 对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。

    powershell 复制代码
    docker compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
    • -f, --file FILE 指定使用的 Compose 模板文件。默认会自动识别 compose.yaml (也兼容 docker-compose.yml 等),并且可以多次指定。
    • -p, --project-name NAME 指定项目名称,默认将使用所在目录名称作为项目名。
    • --verbose 输出更多调试信息。
    • -v, --version 打印版本并退出。

【8】Compose 模板文件

  • 模板文件是使用 Compose 的核心,涉及到的指令关键字也比较多。但大部分指令跟 docker run 相关参数的含义都是类似的。

  • 默认的模板文件名称为 compose.yaml (也兼容 docker-compose.yml 等历史文件名),格式为 YAML。

    yaml 复制代码
    services:
      webapp:
        image: examples/web
        ports:
          - "80:80"
        volumes:
          - "/data"
  • 注意每个服务都必须通过 image 指令指定镜像或 build 指令 (需要 Dockerfile) 等来自动构建生成镜像。

  • 如果使用 build 指令,在 Dockerfile 中设置的选项 (例如:CMDEXPOSEVOLUMEENV 等) 将会自动被获取,无需在 Compose 文件中重复设置。

【9】挂载卷

powershell 复制代码
services:
  db:
    image: postgres:16
    volumes:
      # 命名卷(推荐)

      - postgres_data:/var/lib/postgresql/data
      # Bind Mount

      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

volumes:
  postgres_data:  # 声明命名卷
相关推荐
姜太小白2 小时前
【Ollama】Docker部署Ollama完整指南
运维·docker·容器
佩洛君2 小时前
Ubuntu22.04系统apt换国内源
linux·运维·ubuntu
七夜zippoe2 小时前
OpenClaw 浏览器自动化实战
运维·chrome·自动化·浏览器·playwright·openclaw
Giggle12182 小时前
从零解构一套校园外卖系统:架构设计、技术选型与核心难点剖析
java·运维·微服务
IT从业者张某某2 小时前
Docker部署伪分布Hadoop
hadoop·docker·容器
淮北4942 小时前
AppImage转变成APP-》ubuntu22.04
运维·服务器
笨手笨脚の2 小时前
云原生部署常见服务
redis·docker·云原生·kubernetes·redis-cluster
D4c-lovetrain2 小时前
Linux个人心得28(OSI 7 层模型全解析)
linux·运维·网络
CORNERSTONE3652 小时前
生产管理六要素(PQCDSM)
大数据·运维·人工智能·生产管理