Docker详细介绍

2025-07-29 00:05
355
0

一、容器技术的简单介绍

容器技术是一种轻量级的虚拟化技术,它能够在操作系统层面实现资源的隔离和分配,让应用程序及其依赖可以在独立的环境中运行,且不会受到其他应用的干扰。这种技术的核心依赖于 Linux 内核的两大关键特性:NameSpace 和 CGroups。

1.1、NameSpace

NameSpace 是 Linux 内核提供的一种隔离机制,它能将进程运行时所需要的各种资源(如进程 ID、网络、文件系统等)进行隔离,使得每个容器内的进程只能看到自己 NameSpace 中的资源,仿佛处于一个独立的系统环境中。

常见的 NameSpace 类型及作用如下:

  • PID NameSpace:实现进程 ID 的隔离。在容器内,进程会有独立的 PID 编号,容器外的进程无法看到容器内的进程 PID,反之亦然。
  • NET NameSpace:实现网络资源的隔离。每个容器都有自己独立的网络设备、IP 地址、端口等网络配置,就像一个独立的网络环境,容器内的网络通信不会影响到容器外。
  • MNT NameSpace:实现文件系统挂载点的隔离。容器有自己独立的文件系统视图,可以挂载不同的文件系统,且不会影响到宿主机器和其他容器的文件系统。
  • UTS NameSpace:实现主机名和域名的隔离。每个容器可以有自己独立的主机名和域名,方便应用程序识别和通信。
  • USER NameSpace:实现用户和用户组 ID 的隔离。容器内的用户 ID 和用户组 ID 可以与宿主机器不同,提高了安全性。
  • IPC NameSpace:实现进程间通信的隔离。容器内的进程间通信(如信号量、消息队列等)只能在容器内部进行,不会干扰其他容器。

1.2、CGroups

CGroups(Control Groups)是 Linux 内核提供的一种资源限制机制,它可以对进程组的资源使用进行限制、统计和控制。通过 CGroups,能够为每个容器分配特定的 CPU、内存、磁盘 I/O、网络带宽等资源,防止某个容器过度占用资源而影响其他容器或宿主机器的正常运行。

其主要作用包括:

  • 资源限制:可以限制某个进程组对 CPU、内存等资源的最大使用量。例如,限制某个容器最多使用 1 个 CPU 核心和 2GB 内存。
  • 资源统计:能够统计进程组对各种资源的使用情况,如 CPU 使用率、内存占用量等,方便进行资源监控和计费。
  • 优先级控制:可以为不同的进程组设置资源使用的优先级,当资源紧张时,优先级高的进程组能获得更多的资源。
  • 进程控制:可以冻结或恢复进程组,方便进行进程的暂停和继续操作。

正是基于 NameSpace 的隔离能力和 CGroups 的资源控制能力,容器技术才能实现轻量级、高效的虚拟化,相比传统的虚拟机技术,具有启动速度快、资源占用少、移植性好等优势。

二、Docker介绍

Docker 是基于容器技术的开源应用容器引擎,它让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。Docker 简化了应用的部署、运行和管理流程,极大地提高了开发、测试和部署的效率。

2.1、Docker的核心概念

Docker 的核心概念围绕其运行和管理机制展开,这些概念相互关联,共同支撑起 Docker 的完整功能体系,以下是主要核心概念:​

2.1.1、镜像(Image)​

镜像是 Docker 中最基础的核心概念之一,它是一个只读的模板,包含了运行应用程序所需的所有内容,像代码、运行时环境、库、环境变量以及配置文件等。可以将其理解为容器的 “源代码”,是容器运行的基础。​

镜像采用分层存储结构每一层都对应着 Dockerfile 中的一条指令(如 RUN、COPY 等),并且每一层都是独立且只读的。这种分层结构带来了诸多优势,比如不同镜像可以共享相同的层,大大减少了存储空间的占用;同时,当需要修改镜像时,只需在原有层的基础上添加新的层,无需重新构建整个镜像,提高了构建效率。​

例如从 DockerHub 下载的 ubuntu 镜像,就包含了 ubuntu 操作系统运行所需的基础文件和配置,基于该镜像可以创建多个不同的容器。​

2.1.2、容器(Container)​

容器是镜像的运行实例,是一个动态的对象。它在镜像的基础上添加了一个可写层,当容器运行时,所有对容器内文件系统的修改(如创建文件、修改配置等)都会被记录在这个可写层中,而原始镜像不会受到任何影响。​

容器具有独立、隔离的特性,这得益于 Linux 内核的 NameSpace 和 CGroups 技术。每个容器都有自己独立的进程空间、网络环境、文件系统视图等,就像一个独立的 “小虚拟机”,但相比传统虚拟机更加轻量,启动速度更快,资源占用更少。​

通过docker run命令可以基于镜像创建并启动容器,容器可以被启动、停止、重启、删除等。例如基于 ubuntu 镜像创建的容器,在其中安装软件后,停止容器再重新启动,之前安装的软件仍然存在(存储在可写层)。​

2.1.3、Docker 引擎(Docker Engine)​

Docker 引擎是 Docker 的核心运行环境,它由Docker daemon(守护进程)、Docker client(客户端) 以及相关工具和库组成。​

  • Docker daemon:运行在 Docker Host(宿主机器)上的后台进程,负责管理 Docker 的所有资源,包括镜像的下载与构建、容器的创建与运行、网络和存储的配置等。它能够接收并处理来自 Docker client 的命令请求,并执行相应的操作。​
  • Docker client:是用户与 Docker 引擎交互的接口,用户通过 Docker client(如命令行工具docker)输入命令,这些命令会被发送给 Docker daemon 进行处理。例如执行docker pull命令时,客户端会将请求发送给 daemon,由 daemon 完成镜像的下载。​

2.1.4、仓库(Registry)​

仓库是用于存储和分发 Docker 镜像的场所,相当于镜像的 “仓库”。它分为公有仓库和私有仓库:​

  • 公有仓库:最具代表性的是 Docker Hub,里面存放了大量官方和第三方提供的镜像,用户可以免费下载使用,如常见的 ubuntu、nginx 等镜像都可以从 Docker Hub 获取。​
  • 私有仓库:由企业或个人搭建,用于存储私有镜像,适用于企业内部的镜像管理,保证镜像的安全性和私密性,避免敏感镜像泄露。​

通过docker push命令可以将本地构建的镜像上传到仓库,使用docker pull命令可以从仓库下载镜像到本地。​

2.1.5、数据卷(Volume)​

数据卷是用于在容器和宿主机器之间或容器之间共享和持久化数据的一种机制。它是独立于容器文件系统的特殊目录,其生命周期不受容器的影响,即使容器被删除,数据卷中的数据仍然保留。​

数据卷可以绕过容器的可写层,直接与宿主机器的文件系统进行交互,不仅提高了数据读写性能,还解决了容器内数据持久化的问题。例如在运行数据库容器时,将数据库的数据目录挂载到数据卷,这样即使容器被删除,数据库数据也不会丢失。​

通过docker volume create命令可以创建数据卷,在启动容器时通过-v选项将数据卷挂载到容器内的指定目录。

2.2、Docker生态

Docker 生态由多个组件构成,它们相互协作,共同完成 Docker 的各项功能:

  • Docker Host:指运行 Docker 引擎的主机,可以是物理机也可以是虚拟机。Docker Host 为容器提供运行环境,包括硬件资源和操作系统支持。
  • Docker deamon:运行在 Docker Host 上的后台进程,负责管理 Docker 的各种资源,如镜像、容器、网络和存储等。它接收并处理来自 Docker client 的命令请求,完成相应的操作。
  • Registry:用于存储和分发 Docker 镜像的仓库。Registry 分为公有和私有两种,公有 Registry 以 Docker Hub 为代表,里面存放了大量的官方和第三方镜像;私有 Registry 则用于企业内部存储和管理私有镜像。
  • Docker client:是用户与 Docker 进行交互的命令行工具或图形界面工具。用户通过 Docker client 向 Docker deamon 发送命令,如构建镜像、运行容器等。
  • Container:是镜像的运行实例,它是一个动态的对象。容器在镜像的基础上添加了一个可写层,当容器运行时,所有的修改操作都会在这个可写层进行,不会影响到原始镜像。
  • Docker desktop:是适用于 Windows 和 Mac 操作系统的 Docker 桌面应用,它集成了 Docker 引擎、Docker client、Docker Compose 等工具,为开发者提供了便捷的图形化操作界面,使得在非 Linux 系统上使用 Docker 变得简单。

三、Docker常用命令介绍

  • docker run:该命令用于创建并启动一个容器。
    • 基本语法:docker run [选项] 镜像名称 [命令] [参数]
    • 示例:docker run -it --name mycontainer ubuntu /bin/bash,此命令以交互模式启动一个名为 mycontainer 的容器,使用 ubuntu 镜像,并在容器内执行 /bin/bash 命令。其中,-i表示保持标准输入打开,-t表示分配一个伪终端。
  • docker ps:用于查看正在运行的容器。
    • 基本语法:docker ps [选项]
    • 常用选项:-a查看所有容器(包括已停止的);-l查看最近创建的容器。
    • 示例:docker ps -a,显示所有容器的信息,包括容器 ID、镜像名称、创建时间、状态等。
  • docker inspect:用于查看容器或镜像的详细信息,包括配置、网络、存储等。
    • 基本语法:docker inspect [容器ID/容器名称/镜像ID/镜像名称]
    • 示例:docker inspect mycontainer,查看名为 mycontainer 的容器的详细信息。
  • docker exec:用于在运行的容器中执行命令。
    • 基本语法:docker exec [选项] 容器ID/容器名称 命令 [参数]
    • 示例:docker exec -it mycontainer /bin/bash,在 mycontainer 容器中以交互模式执行 /bin/bash 命令,进入容器内部。
  • docker attach:用于连接到正在运行的容器,进入容器的终端。
    • 基本语法:docker attach [容器ID/容器名称]
    • 示例:docker attach mycontainer,连接到 mycontainer 容器,此时在终端输入的命令会在容器内执行。需要注意的是,如果从该终端退出,可能会导致容器停止。
  • docker stop:用于停止运行中的容器。
    • 基本语法:docker stop [容器ID/容器名称]
    • 示例:docker stop mycontainer,停止 mycontainer 容器的运行。
  • docker start:用于启动已停止的容器。
    • 基本语法:docker start [容器ID/容器名称]
    • 示例:docker start mycontainer,启动已停止的 mycontainer 容器。
  • docker top:用于查看容器内运行的进程信息。
    • 基本语法:docker top [容器ID/容器名称]
    • 示例:docker top mycontainer,显示 mycontainer 容器内运行的进程,包括进程 ID、用户、命令等信息。
  • docker rm:用于删除容器。
    • 基本语法:docker rm [选项] [容器ID/容器名称]
    • 常用选项:-f强制删除正在运行的容器。
    • 示例:docker rm mycontainer,删除已停止的 mycontainer 容器;docker rm -f mycontainer,强制删除正在运行的 mycontainer 容器。

四、获得容器的四种方式

  1. 在 DockerHub 直接下载
    • DockerHub 是最大的公有 Docker 镜像仓库,里面存放了大量的官方和社区镜像,用户可以直接从上面下载所需的镜像。
    • 操作方法:使用docker pull命令,语法为docker pull 镜像名称[:标签]。如果不指定标签,默认下载 latest 标签的镜像。
    • 示例:docker pull ubuntu:20.04,从 DockerHub 下载 ubuntu 20.04 版本的镜像。这种方式简单便捷,适用于获取常见的、公开的镜像。
  2. 把操作系统中文件系统打包为容器镜像
    • 这种方式是将操作系统中的某个目录下的文件系统打包成镜像,适用于将现有的应用及其依赖文件直接打包成镜像。
    • 操作步骤相对复杂,一般需要先创建一个基础的文件系统目录,然后将应用相关文件复制到该目录,再通过docker import命令将该目录打包为镜像。
    • 示例:先创建一个目录myfs,并在其中放入应用文件,然后执行tar -cC myfs . | docker import - myimage:v1,将 myfs 目录下的文件系统打包为名为 myimage、标签为 v1 的镜像。
  3. 把正在运行的容器打包为容器镜像,即 docker commit
    • 当对运行中的容器进行了一些修改(如安装软件、配置环境等),可以使用docker commit命令将其打包为新的镜像,以便后续复用。
    • 基本语法:docker commit [选项] 容器ID/容器名称 新镜像名称[:标签]
    • 示例:对名为 mycontainer 的运行中容器进行修改后,执行docker commit mycontainer mynewimage:v1,将该容器打包为 mynewimage:v1 镜像。这种方式适合临时保存容器状态,但不推荐用于生产环境,因为它无法追踪镜像的构建过程,可维护性差。
  4. 通过 Dockerfile 实现容器镜像的自定义及生成
    • Dockerfile 是一个文本文件,里面包含了一系列构建镜像的指令。通过编写 Dockerfile,可以精确地定义镜像的构建过程,实现镜像的自定义生成。这种方式具有可重复性、可维护性和可扩展性,是生产环境中推荐使用的镜像构建方式。(具体实现过程将在后面的 Dockerfile 相关部分详细介绍。)

五、Dockerfile 自定义实现容器镜像

Dockerfile 是一个由一系列指令组成的文本文件,这些指令按顺序执行,用于构建 Docker 镜像。它采用了一种声明式的语法,每一条指令都对应着镜像构建过程中的一个操作,如指定基础镜像、安装软件、设置环境变量等。通过 Dockerfile,开发者可以清晰地记录镜像的构建步骤,使得镜像构建过程可重复、可追溯,方便团队协作和版本控制。

5.1、Dockerfile 基本构成

一个完整的 Dockerfile 通常由以下几个部分构成:

  • 基础镜像指定:通过 FROM 指令指定基础镜像,这是 Dockerfile 的起始点。
  • 环境配置:包括安装依赖软件(RUN 指令)、设置环境变量(ENV 指令)、设置工作目录(WORKDIR 指令)等。
  • 文件复制:通过 COPY 或 ADD 指令将宿主机的应用代码、配置文件等复制到镜像中。
  • 端口声明:使用 EXPOSE 指令声明容器运行时需要暴露的端口。
  • 启动命令设置:通过 CMD 或 ENTRYPOINT 指令设置容器启动时执行的命令。

5.2、Dockerfile 指令

常用的 Dockerfile 指令及其作用如下:

  • FROM:指定基础镜像,所有的构建都是在基础镜像之上进行的。语法为FROM 镜像名称[:标签],例如FROM ubuntu:20.04
  • RUN:在镜像构建过程中执行命令,用于安装软件、配置环境等。语法有两种,RUN 命令(shell 形式)RUN ["可执行文件", "参数1", "参数2"](exec 形式)。例如RUN apt-get update && apt-get install -y nginx
  • COPY:将宿主机中的文件或目录复制到镜像中。语法为COPY [--chown=用户:组] 源路径 目标路径,例如COPY app.py /app/
  • ADD:功能与 COPY 类似,但它还支持自动解压压缩文件以及从 URL 下载文件。语法与 COPY 相同,例如ADD test.tar.gz /tmp/
  • WORKDIR:设置后续指令的工作目录,相当于在镜像中切换目录。语法为WORKDIR 目录路径,例如WORKDIR /app
  • ENV:设置环境变量,这些环境变量在镜像构建过程和容器运行时都有效。语法为ENV 变量名 变量值或ENV 变量名=变量值,例如ENV JAVA_HOME /usr/local/jdk
  • EXPOSE:声明容器运行时监听的端口,但它只是一种声明,不会自动映射端口到宿主机。语法为EXPOSE 端口号,例如EXPOSE 80
  • CMD:指定容器启动时默认执行的命令。一个 Dockerfile 中只能有一个 CMD 指令,如果有多个,只有最后一个生效。语法有三种,CMD ["可执行文件", "参数1", "参数2"](exec 形式,推荐)、CMD 命令 参数1 参数2(shell 形式)、CMD ["参数1", "参数2"](作为 ENTRYPOINT 的参数)。例如CMD ["nginx", "-g", "daemon off;"]
  • ENTRYPOINT:与 CMD 类似,用于指定容器启动时执行的命令,但它不会被容器启动时的命令行参数覆盖,而是将命令行参数作为其参数。语法有两种,ENTRYPOINT ["可执行文件", "参数1", "参数2"](exec 形式)和ENTRYPOINT 命令 参数1 参数2(shell 形式)。

5.3、Dockerfile示例

以下是一个构建简单 Python 应用镜像的 Dockerfile 示例:

# 指定基础镜像
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 复制当前目录下的requirements.txt到镜像的/app目录
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制当前目录下的所有文件到镜像的/app目录
COPY . .

# 声明暴露的端口
EXPOSE 5000

# 设置启动命令
CMD \["python", "app.py"]

对应的构建命令:在 Dockerfile 所在目录执行docker build -t mypythonapp:v1 ,即可生成 mypythonapp:v1 镜像。该镜像基于 python:3.9-slim 基础镜像,安装了 requirements.txt 中指定的依赖,复制了应用代码,并设置启动时运行 app.py,暴露 5000 端口。

5.4、Dockerfile 容器镜像优化

优化 Docker 镜像可以减小镜像体积、提高构建速度、增强安全性等。常用的优化方法如下:

选择合适的基础镜像:尽量使用体积小的基础镜像,如 Alpine 版本的镜像,相比完整版镜像体积更小。例如使用python:3.9-alpine替代python:3.9。

减少镜像层数:Dockerfile 中每一条 RUN、COPY、ADD 等指令都会创建一个新的镜像层,层数过多会增加镜像体积。可以将多个 RUN 命令合并为一个,使用&&连接命令,并用\进行换行

清理无用文件:在每个 RUN 指令中,及时清理安装过程中产生的临时文件、缓存文件等,如apt-get clean、rm -rf等命令。

使用多阶段构建:多阶段构建可以将构建过程分为多个阶段,只将最终需要的文件复制到最终镜像中,减少镜像体积。例如,在构建 Go 应用时,第一阶段使用包含编译工具的镜像进行编译,第二阶段使用基础镜像,只复制编译好的可执行文件。

合理使用 COPY 和 ADD:优先使用 COPY 指令,因为它功能更单一、更安全;ADD 指令的自动解压和 URL 下载功能可能会引入不必要的文件,增加镜像体积。

避免使用RUN apt-get upgrade:升级系统包可能会导致镜像不稳定,且会增加镜像体积,如需特定版本的包,在安装时指定即可。

 

全部评论