Docker 入门指南:如何将镜像作为容器运行

本教程专为 Docker 初学者设计,将指导你如何使用 docker run 命令来运行 Docker 镜像。内容涵盖镜像与容器的基础知识、常用命令与选项、数据持久化、问题排查等,助你自信地启动和管理容器。

阅读时长: 8 分钟
共 3978字
作者: eimoon.com

如果你正在探索如何运行一个 Docker 镜像 (Image),那么你并不孤单。无论是从 Docker Hub 拉取的镜像,还是自己构建的镜像,运行它都是将应用程序变为现实的关键一步。

本教程是一篇面向初学者的指南,将带你深入了解 docker run 命令及其相关操作。你将学到:

  • Docker 镜像 (Image) 与容器 (Container) 的真正含义。
  • 如何使用不同的选项来运行镜像。
  • 如何像专业人士一样停止、移除和排查容器问题。

读完本文,你将能够自信地启动自己的容器,并清楚地了解其背后的工作原理。

理解 Docker 镜像与容器

在深入研究命令示例之前,让我们先用简单的语言来理解 Docker 镜像和容器。如果你已经对这些概念非常熟悉,可以直接跳到下一节。

什么是 Docker 镜像 (Image)?

Docker 镜像 (Image) 是你应用程序的一个不可变的蓝图。它包含了运行容器所需的一切:代码、库、环境变量和配置文件。一旦拥有了一个镜像,你就可以用它来启动一个或上百个容器,并且每次都能保持一致。

那么,镜像是从哪里来的呢?答案是 DockerfileDockerfile 是一个文本文件,你可以在其中定义使用哪个基础镜像、需要安装哪些依赖以及应用程序应该如何运行。

Dockerfile 准备就绪后,你只需运行 docker build 命令,它就会按照文件中的步骤,将所有内容打包成一个可复用的镜像。

什么是 Docker 容器 (Container)?

Docker 容器 (Container) 是 Docker 镜像的一个正在运行的实例。它允许你的应用程序在自己的隔离环境中运行,确保无论宿主系统如何,其行为都保持一致。这遵循了“一次构建,随处运行”的理念,让你不必每次都手动配置环境。

镜像 vs. 容器

下表直观地对比了镜像和容器的区别:

特性 镜像 (Image) 容器 (Container)
本质 一个标准化的软件包,包含运行容器所需的所有文件、二进制文件、库和配置。 镜像的一个运行时实例。
可变性 镜像是不可变的。这意味着除非重新构建,否则它不会改变。 容器是可变的。你可以在它运行时修改它,比如安装新软件包或更改配置文件。
来源 镜像是通过 Dockerfile(一组构建镜像的指令)创建的。 容器是通过镜像创建的。
存储 镜像文件存储在你的计算机上(如硬盘)。 容器在内存中运行。

docker run 命令详解

当你执行 docker run 命令时,你实际上是在告诉 Docker 基于某个镜像启动一个新容器。简单来说,你正在一个隔离的环境中启动一个程序。这个程序可以是一个简单的 Web 应用,也可以是一个包含多个进程的复杂服务。

基本语法

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  • [OPTIONS]: 额外的标志,用于自定义容器的运行方式。
  • IMAGE: Docker 镜像的名称。
  • [COMMAND] (可选): 覆盖镜像中设置的默认命令。
  • [ARG...] (可选): 传递给命令的参数。

常用标志与选项

  • -d (detached): 分离模式,在后台运行容器。
  • -p (port): 端口映射。要从浏览器访问服务(如 API 或 Web 应用),你需要暴露一个端口。例如:-p 3000:3000 将你的宿主机 3000 端口映射到容器的 3000 端口。
  • --name: 为容器指定一个自定义名称,而不是使用 Docker 生成的默认名称。
  • -v (volume): 挂载卷。用于将数据与容器本身分离,确保即使容器被停止或删除,数据也能持久化。
  • --rm: 当容器停止时,自动删除它。
  • -e (environment): 传递环境变量,用于传入数据库密码或 API 密钥等敏感信息,避免硬编码在代码中。

交互式容器 vs. 分离式容器

Docker 以两种模式运行容器:交互模式 (-it) 和分离模式 (-d)。

  • 交互模式 (-it): 如果你想直接在容器内部通过终端工作,可以使用 -it 标志。它会让你进入容器的交互模式,可以输入命令、查看输出,并进行实时操作。
    • -i: 保持输入流打开,以便你可以向容器输入命令。
    • -t: 为容器分配一个伪终端(pseudo-TTY),提供一个类似终端的界面。
  • 分离模式 (-d): 它会在后台运行容器,这样你的终端就可以继续用于其他任务。

拉取并运行 Docker 镜像

了解了 docker run 的语法后,本节将向你展示如何创建和运行自定义镜像。

使用 Docker Hub 的镜像

Docker Hub 就像一个容器镜像的在线图书馆。你可以获取预构建的镜像,也可以上传自己的镜像与他人共享。它同时支持公共和私有仓库,方便你与社区共享或在团队内部进行访问控制。

运行自定义镜像

要运行一个 Docker 镜像,你首先需要使用 Dockerfile 来构建它。然后,你可以在本地运行它,或者将其推送到 Docker Hub 进行分享。

首先,让我们创建一个 Dockerfile。这是一个示例:

# 使用官方的 Python slim 基础镜像
FROM python:3.11-slim

# 在容器内设置工作目录
WORKDIR /app

# 复制依赖文件并安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码的其余部分
COPY . .

# 暴露 5000 端口
EXPOSE 5000

# 设置默认命令
CMD ["python", "app.py"]

这个 Dockerfile 的含义是:

  • FROM python:3.11-slim: 使用 Python 3.11 的轻量级版本作为基础镜像。
  • WORKDIR /app: 在容器内将 /app 设置为工作目录。
  • COPY requirements.txt .: 将本地的 requirements.txt 文件复制到容器的 /app 目录。
  • RUN pip install ...: 安装 requirements.txt 中列出的所有依赖。
  • COPY . .: 将当前目录下的所有代码复制到容器的 /app 目录。
  • EXPOSE 5000: 声明容器在运行时将监听 5000 端口。
  • CMD ["python", "app.py"]: 设置容器启动时执行的默认命令为 python app.py

第 1 步:构建 Dockerfile

让我们构建这个 Dockerfile

docker build -t my-python-app .

注意: 要使此命令正常工作,你的系统需要先安装好 Docker。

执行构建命令后,Docker 会:

  1. 读取 Dockerfile
  2. 从 Docker Hub 拉取 python:3.11-slim 基础镜像。
  3. 设置工作目录为 /app
  4. 复制并安装所有依赖。
  5. 将你的代码复制到 /app 目录。
  6. 最终将生成的镜像标记为 my-python-app

第 2 步:运行 Docker 镜像

镜像构建完成后,使用以下命令运行它:

docker run -p 5000:5000 my-python-app

运行后:

  • 一个基于 my-python-app 镜像的新容器被创建。
  • 通过 -p 5000:5000,宿主机的 5000 端口被映射到容器的 5000 端口。
  • CMD ["python", "app.py"] 命令被执行,启动应用。
  • 如果你使用了 -d 标志,容器将在后台运行。

此时,访问 http://localhost:5000,你应该能看到应用正在运行的欢迎页面。

带配置运行镜像

有时,你需要为应用程序提供特定的配置来运行镜像。

数据持久化

容器默认是无状态的,删除容器会导致数据丢失。卷 (Volume) 是一种将数据存储在容器之外的方式,即使容器被移除或重启,数据也能保持持久化。

要挂载一个卷,可以运行如下命令:

docker run -v my-volume:/app/data my-image

这样,写入到容器内 /app/data 目录的数据将被保存在名为 my-volume 的卷中。

传递环境变量

环境变量用于在运行时向 Docker 容器传递配置。这使你无需修改镜像即可自定义容器。

有两种传递环境变量的方式:

  1. 使用 -e 参数:

    docker run -e ENV=production -e DEBUG=False my-image
    
  2. 使用 --env-file 指定一个 .env 文件:

    docker run --env-file .env my-image
    

    一个示例 .env 文件内容如下:

    ENV=staging
    DEBUG=True
    SECRET_KEY=mysecret
    

管理运行中的容器

容器运行后,你可以查看、停止和访问它。

查看活跃容器

要列出系统上所有正在运行的 Docker 容器,执行 docker psdocker container ls

docker ps
# 或者
docker container ls

要查看所有容器(包括已停止的),使用 -a 标志:

docker ps -a

停止与移除容器

要停止一个特定的容器,使用 docker stop 命令,后跟容器的 ID 或名称:

docker stop <container_id_or_name>

要一次性停止所有正在运行的容器:

docker stop $(docker ps -q)

$(docker ps -q) 会返回所有运行中容器的 ID 列表。

容器停止后,你可以使用 docker rm 将其移除:

docker rm <container_id_or_name>

要移除所有已停止的容器,运行:

docker container prune

访问容器日志与 Shell

  • docker logs: 批量检索容器在执行时产生的日志。
  • docker exec: 在一个正在运行的容器内执行新命令,而无需停止或重启它。这就像在容器内打开一个新的终端,方便你进行调试、运行脚本或检查日志。
  • docker attach: 将你的终端直接连接到正在运行的容器的主进程。你可以看到容器的实时输出(日志、提示等),并与之交互。

常见问题排查

这里是一些运行 Docker 镜像时常见问题的解决方法。

错误 1: pull access denied for [image], repository does not exist or may require 'docker login'

  • 含义: Docker 尝试拉取一个镜像,但该镜像不存在或是私有镜像,而你没有进行身份验证。
  • 解决方法:
    • 仔细检查 Docker Hub 上的镜像名称和标签是否正确。
    • 如果镜像是私有的,运行 docker login 进行身份验证。
    • 如果从自定义仓库拉取,请确保镜像存在。

错误 2: No such image found: <image-name>:<tag>

  • 含义: 你尝试运行或标记一个本地镜像,但该镜像(或指定的标签)在你的系统上不存在。
  • 解决方法:
    • 使用 docker images 检查可用的本地镜像。
    • 明确地拉取镜像:docker pull <image-name>:<tag>

错误 3: manifest for <image>:<tag> not found

  • 含义: 这通常意味着指定的镜像或标签在仓库中不存在。
  • 解决方法:
    • 确认镜像和标签名称的拼写是否正确。
    • 在 Docker Hub 或你的私有仓库中查找可用的标签。
    • 如果是在本地构建,请确保 Dockerfile 正确,并使用 docker build -t <image>:<tag> . 命令构建镜像。

端口冲突与绑定失败

当多个容器或一个容器与其他应用程序尝试使用相同的宿主机端口时,会发生端口冲突。

  • 解决方法:
    • 在运行容器时使用一个不同的宿主机端口:
      docker run -p 8081:80 <image>
      
    • 停止当前占用该端口的服务。
    • 使用 lsof -i :<port>(例如 lsof -i :8080)来识别哪个进程正在使用该端口。

总结

运行 Docker 镜像是在使用容器技术中至关重要的一步,无论你是启动一个简单的 Web 服务器还是部署一个复杂的应用程序。通过 docker rundocker psdocker stop 等几个核心命令,你现在已经具备了自信地启动、管理和排查容器问题的能力。

如果你准备更进一步,可以尝试使用 Dockerfile 构建自己的镜像,探索更多高级的 docker run 标志,或者学习如何使用 Docker Compose 管理多个容器。

FAQs

问:我可以从同一个 Docker 镜像运行多个容器吗? 答:是的,你可以从同一个镜像运行多个容器。每个容器都是相互隔离的,可以拥有各自的设置、端口和环境变量。

问:如何安全地将密钥或 API 密钥传递给 Docker 容器? 答:使用 -e 标志设置环境变量,或使用一个 .env 文件和 --env-file 选项在运行时传递密钥,避免硬编码。

问:如何让 Docker 镜像在后台运行? 答:在 docker run 命令中使用 -d 标志,以分离模式(detached mode)启动容器,这样终端可以继续用于其他命令。

问:docker execdocker attach 有什么区别? 答:docker exec 在容器内打开一个新的 shell 会话,而 docker attach 连接到容器的主进程及其实时输出。

问:为什么运行镜像时会出现“pull access denied”错误? 答:这通常意味着镜像名称或标签拼写错误,或者是私有镜像。请检查名称,并使用 docker login 登录到 Docker Hub。

问:容器停止后,如何持久化数据? 答:使用 -v 标志挂载一个卷 (volume),确保数据存储在容器之外,即使容器被删除也能保持完好。

问:用于开发目的的最佳容器运行方式是什么? 答:使用 -it 标志进入交互模式,并结合卷挂载和环境变量来模拟本地开发环境。

问:如何查看是哪个进程占用了我的端口? 答:使用 lsof -i :<port> 命令来识别哪个进程正在使用特定端口,然后停止它或为你的容器选择另一个主机端口。

问:如何查看正在运行的 Docker 容器的日志? 答:使用 docker logs <container_id> 命令来检索和查看容器的标准输出和错误流中的日志。

关于

关注我获取更多资讯

公众号
📢 公众号
个人号
💬 个人号
使用 Hugo 构建
主题 StackJimmy 设计