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:  # 声明命名卷
相关推荐
SelectDB15 小时前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
曲幽1 天前
别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了
python·docker·web·pot·translate·libretranslate·arogstranslate
XIAOHEZIcode2 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220703 天前
如何搭建本地yum源(上)
运维
武子康3 天前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
大树886 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠6 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质6 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工6 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
Alsn866 天前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker