0%

docker

1 什么是容器化技术

容器共享主机内核,轻量、隔离且高效,不像虚拟机需要完整的操作系统,下图展示了 Docker 容器的基本架构:

  • 上层: 是多个容器(App A~F),每个容器独立运行一个应用。
  • 中间层: 是 Docker,负责管理这些容器。
  • 底层: 是主机操作系统(Host OS)和基础设施,为容器提供硬件和系统支持。

通过容器化部署服务,可以解决之前传统应用部署的问题:

  • 环境标准化:将应用及其依赖打包在一起,确保在任何环境中都能一致运行
  • 轻量级:容器共享宿主机的操作系统内核,比虚拟机更轻量
  • 快速部署:容器可以在几秒内启动,大大提高了部署效率
  • 可移植性:一次构建,到处运行

容器化遵循"不可变基础设施"的理念:

  • 应用和环境被打包成不可变的镜像
  • 每次部署都使用相同的镜像
  • 配置通过环境变量或配置文件注入
  • 问题修复通过重新构建镜像而非修改运行中的容器

2 Docker 的核心概念

1. 镜像:镜像是一个只读的模板,包含了运行应用所需的所有内容:代码、运行时、库文件、环境变量和配置文件。

  • 分层存储:镜像由多个层组成,每一层代表一次修改
  • 只读性:镜像本身是只读的,不能直接修改
  • 可复用:同一个镜像可以实例化为多个容器
  • 版本管理:通过标签(tag)进行版本管理

2. 容器 (Container):容器是镜像的运行实例,是一个轻量级、可移植的执行环境。

  • 隔离性:每个容器都有自己的文件系统、网络和进程空间
  • 临时性:容器可以被创建、启动、停止、删除
  • 可写层:容器在镜像基础上添加了一个可写层
  • 进程级:容器内通常运行一个主进程

3. 仓库 (Repository):仓库是存储和分发镜像的地方,可以包含一个镜像的多个版本。有Docker Hub公共仓库、企业内部搭建私人仓库、软件官方维护的镜像仓库等

Docker 与虚拟机的区别

特性 虚拟机 Docker容器
隔离级别 硬件级别虚拟化 操作系统级别虚拟化
操作系统 每个VM需要完整OS 共享宿主机OS内核,调度决定权归根到底由主机OS决定
资源占用 重量级,占用较多资源 轻量级,资源占用少
启动时间 分钟级别 秒级别
性能开销 较大 接近原生性能
镜像大小 GB级别 MB级别

Docker 的优势和应用场景:

  • 微服务架构:每个微服务独立容器化;服务可以独立更新和扩展;不同服务可以使用不同技术
  • CI/CD流水线:标准化的构建环境;每个测试在独立容器中运行;相同镜像在不同环境部署
  • 开发环境标准化:新成员快速获得开发环境;团队使用相同的开发环境;避免本地环境冲突

3 Docker 架构

Docker 架构是基于客户端-服务器模式的,其中包括多个关键组件,确保容器化应用的高效构建、管理和运行。

Docker 的架构设计使得开发者能够轻松地将应用程序与其所有依赖封装在一个可移植的容器中,并在不同的机器环境中一致地运行。

Docker 容器通过 Docker 镜像来创建。

首先客户端即命令行界面输入docker指令后,本机的docker sever收到相关docker指令后执行,如dockfile构建镜像,运行镜像成容器,拉取镜像等等操作。

1. 工作流程

  • 构建镜像:使用 Dockerfile 创建镜像。
  • 推送镜像到注册表:将镜像上传到 Docker Hub 或私有注册表中。
  • 拉取镜像:通过 docker pull 从注册表中拉取镜像。
  • 运行容器:使用镜像创建并启动容器。
  • 管理容器:使用 Docker 客户端命令管理正在运行的容器(例如查看日志、停止容器、查看资源使用情况等)。
  • 网络与存储:容器之间通过 Docker 网络连接,数据通过 Docker 卷或绑定挂载进行持久化。

3.1 Docker 的核心组件

1. Docker 客户端(Docker Client):Docker 客户端是用户与 Docker 守护进程交互的命令行界面(CLI)。它是用户与 Docker 系统的主要交互方式,用户通过 Docker CLI 发出命令,这些命令被发送到 Docker 守护进程,由守护进程执行相应的操作。

  • 功能:允许用户使用命令与 Docker 守护进程通信,如创建容器、构建镜像、查看容器状态等。
  • 交互方式:Docker 客户端与 Docker 守护进程之间通过 REST API 或 Unix 套接字通信。常用的命令行工具是 docker,通过它,用户可以发出各种 Docker 操作命令。

2. Docker 守护进程(Docker Daemon):Docker 守护进程(通常是 dockerd)是 Docker 架构的核心,负责管理容器生命周期、构建镜像、分发镜像等任务。守护进程通常以后台进程的方式运行,等待来自 Docker 客户端的 API 请求。

  • 功能:启动和停止容器。构建、拉取和推送镜像。管理容器的网络和存储。启动、停止、查看容器日志等。与 Docker 注册表进行通信,管理镜像的存储与分发。 >
    1
    2
    >//启动 Docker 守护进程(通常是自动启动的):
    >sudo systemctl start docker
    >

3. Docker 引擎 API(Docker Engine API):Docker 引擎 API 是 Docker 提供的 RESTful 接口,允许外部客户端与 Docker 守护进程进行通信。通过这个 API,用户可以执行各种操作,如启动容器、构建镜像、查看容器状态等。API 提供了 HTTP 请求的接口,支持跨平台调用。

  • 向 Docker 守护进程发送 HTTP 请求,实现容器、镜像的管理。
  • 提供 RESTful 接口,允许通过编程与 Docker 进行交互。

4. Docker 容器(Docker Containers:容器是 Docker 的执行环境,它是轻量级、独立且可执行的软件包。容器是从 Docker 镜像启动的,包含了运行某个应用程序所需的一切——从操作系统库到应用程序代码。容器在运行时与其他容器和宿主机共享操作系统内核,但容器之间的文件系统和进程是隔离的。

  • 功能:提供独立的运行环境,确保应用程序在不同的环境中具有一致的行为。容器是临时的,通常在任务完成后被销毁。

5. Docker 镜像(Docker Images):Docker 镜像是容器的只读模板。每个镜像都包含了应用程序运行所需的操作系统、运行时、库、环境变量和应用代码等。镜像是静态的,用户可以根据镜像启动容器。

  • 功能:镜像是构建容器的基础,每个容器实例化时都会使用镜像。镜像是只读的,不同容器使用同一个镜像时,容器中的文件系统层是独立的。
    1
    2
    //拉取镜像
    docker pull ubuntu

6. Docker 仓库(Docker Registries):Docker 仓库是用来存储 Docker 镜像的地方,最常用的公共仓库是 Docker Hub。用户可以从 Docker Hub 下载镜像,也可以上传自己的镜像分享给其他人。除了公共仓库,用户也可以部署自己的私有 Docker 仓库来管理企业内部的镜像。

7. Docker Compose:Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过 Compose,用户可以使用一个 docker-compose.yml 配置文件定义多个容器(服务),并可以通过一个命令启动这些容器。Docker Compose 主要用于开发、测试和部署多容器的应用。

  • 功能:定义和运行多个容器组成的应用。通过 YAML 文件来配置应用的服务、网络和卷等。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //docker-compose.yml文件配置一个包含 Web 服务和数据库服务的应用
    version: '3'
    services:
    web:
    image: nginx
    ports:
    - "8080:80"
    db:
    image: mysql
    environment:
    MYSQL_ROOT_PASSWORD: example

8. Docker Swarm:Docker Swarm 是 Docker 提供的集群管理和调度工具。它允许将多个 Docker 主机(节点)组织成一个集群,并通过 Swarm 集群管理工具来调度和管理容器。Swarm 可以实现容器的负载均衡、高可用性和自动扩展等功能。

  • 功能:管理多节点 Docker 集群。通过调度器管理容器的部署和扩展。

9. Docker 网络(Docker Networks):Docker 网络允许容器之间相互通信,并与外部世界进行连接。Docker 提供了多种网络模式来满足不同的需求,如 bridge 网络(默认)、host 网络和 overlay 网络等。

  • 功能:管理容器间的网络通信。支持不同的网络模式,以适应不同场景下的需求。
    1
    2
    3
    创建一个自定义网络并将容器连接到该网络:
    docker network create my_network
    docker run -d --network my_network ubuntu

** 10. Docker 卷(Docker Volumes)**:Docker 卷是一种数据持久化机制,允许数据在容器之间共享,并且独立于容器的生命周期。与容器文件系统不同,卷的内容不会随着容器的销毁而丢失,适用于数据库等需要持久存储的应用。

  • 功能:允许容器间共享数据。保证数据持久化,独立于容器的生命周期。
    1
    2
    3
    //创建并挂载卷:
    docker volume create my_volume
    docker run -d -v my_volume:/data ubuntu

4 docker的安装

4.1 ubuntu安装

使用官方安装脚本自动安装

1
2
3
4
5
6
7
//下载并执行Docker官方安装脚本
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

//启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker

4.2 macos安装

1
brew install --cask --appdir=/Applications docker

5 docker的使用

5.1 客户端常用命令

命令 功能 效果
docker run 启动一个新的容器并运行命令 docker run -d ubuntu
docker ps 已发货当前正在运行的容器 docker ps
docker ps -a 已装运所有集装箱(包括已停止的集装箱) docker ps -a
docker build 使用 Dockerfile 构建镜像 docker build -t my-image .
docker images 仓库本地存储的所有镜像 docker images
docker pull 从 Docker 仓库拉取镜像 docker pull ubuntu
docker push 将镜像自动化到 Docker 仓库 docker push my-image
docker exec 在运行的容器中执行命令 docker exec -it container_name bash
docker stop 停止一个或多个容器 docker stop container_name
docker start 启动已停止的容器 docker start container_name
docker restart 重新启动一个容器 docker restart container_name
docker rm 删除一个或多个容器 docker rm container_name
docker rmi 删除一个或多个镜像 docker rmi my-image
docker logs 查看集装箱的日志 docker logs container_name
docker inspect 获取容器或镜像的详细信息 docker inspect container_name
docker exec -it 进入容器的接待终端 docker exec -it container_name /bin/bash
docker network ls 推出所有 Docker 网络 docker network ls
docker volume ls 已发布所有 Docker 卷 docker volume ls
docker-compose up 启动多容器应用(从docker-compose.yml文件) docker-compose up
docker-compose down 停止并删除由docker-compose启动的容器、网络等 docker-compose down
docker info 显示 Docker 系统的详细信息 docker info
docker version 显示 Docker 客户端和守护进程的版本信息 docker version
docker stats 显示容器的实时资源使用情况 docker stats
docker login 登录 Docker 仓库 docker login
docker logout 登出Docker仓库 docker logout
docker export 导出本地某个容器 docker export 1e560fca3906 > ubuntu.tar
docker import 快照文件中再导入为镜像 docker import mycontainer.tar myimage:latest

docker import有三种导入方式:

  • 从本地文件导:命令格式:docker import <容器快照文件>.tar <新镜像名>:<标签>

    1
    docker import mycontainer.tar myimage:latest

  • 从URL导:docker import <URL> <新镜像名>:<标签>

    1
    docker import http://example.com/container.tar myimage:latest

  • 从标准输入导:通过管道传递 .tar 文件,

    1
    cat container.tar | docker import - myimage:latest

常用选项说明:

  • -d:后台运行容器,例如docker run -d ubuntu
  • -it:以交互式运行容器,例如docker exec -it container_name bash
  • -t:为镜像指定标签,例如docker build -t my-image .

5.2 Dockerfile

Dockerfile 是一个文本文件,包含了构建 Docker 镜像的所有指令。Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。 通过定义一系列命令和参数,Dockerfile 指导 Docker 构建一个自定义的镜像。

5.2.1 dockerfile指令详解

指令 说明 典型使用场景 注意事项
FROM 指定基础镜像,用于后续的指令构建 FROM ubuntu:20.04 指定基于Ubuntu系统的构建环境 建议使用官方镜像并明确版本号,避免使用latest标签
MAINTAINER 指定Dockerfile的作者/维护者(已弃用) 旧版本兼容场景 推荐改用LABEL maintainer="name@example.com"格式
LABEL 添加镜像的元数据,使用键值对形式 LABEL version="1.0" description="Web application" 支持多标签声明,建议集中放置在FROM指令之后
RUN 在构建过程中执行命令 RUN apt-get update && apt-get install -y nginx 安装软件包 多条命令建议用&&连接,减少镜像层数
CMD 指定容器启动时的默认命令(可被覆盖) CMD ["nginx", "-g", "daemon off;"] 每个Dockerfile应只包含一个CMD指令,通常与ENTRYPOINT配合使用
ENTRYPOINT 设置容器启动时的主要命令(不可被覆盖) ENTRYPOINT ["java", "-jar", "app.jar"] 适合用作容器主进程,通常与CMD配合构成默认参数
EXPOSE 声明容器运行时监听的端口 EXPOSE 80 443 声明Web服务端口 仅具文档说明作用,实际端口映射需通过-p参数指定
ENV 设置容器内部环境变量 ENV NODE_ENV=production 配置运行环境 会持久化到镜像中,临时变量建议使用ARG
ADD 复制文件/目录/远程URL到镜像 ADD https://example.com/file.tar.gz /tmp 下载远程资源 自动解压压缩包,远程下载需谨慎使用
COPY 复制本地文件/目录到镜像 COPY ./dist /usr/share/nginx/html 部署前端静态资源 比ADD更透明,推荐常规文件复制场景使用
VOLUME 创建挂载点或声明卷 VOLUME /var/lib/mysql 数据库持久化存储 运行时可通过-v参数覆盖,建议重要数据都声明卷
WORKDIR 设置后续指令的工作目录 WORKDIR /app 切换操作目录 相对路径会基于前序WORKDIR解析,建议使用绝对路径
USER 指定运行用户 USER nobody 以非root用户运行 需确保目标用户已存在,否则会导致容器启动失败
ARG 定义构建时变量 ARG APP_VERSION=1.0 参数化构建过程 仅在构建阶段有效,不会保留到运行时环境
ONBUILD 当前镜像被用作基础镜像时触发的指令 ONBUILD COPY . /app 子镜像构建时自动操作 适合制作基础镜像模板

5.2.2 Dockerfile编写

1
2
3
4
FROM ubuntu:20.04
RUN apt-get install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz

上面的构建语句有三种命令,但通过 && 符号连接命令,这样执行后,只会创建 1 层镜像。

  • 在 Dockerfile 文件的存放目录下,执行构建动作。以下示例,通过目录下的 Dockerfile 构建一个 nginx:v3(镜像名称:镜像标签)。
    1
    $ docker build -t nginx:v3 .
    指令最后一个.是上下文路径。上下文路径,是指 docker在构建镜像,有时候想要使用到本机的文件,docker build命令得知这个路径后,会将路径下的所有内容打包到该镜像,实例为容器后可以使用。

5.3 Docker Compose

Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

Compose 使用的三个步骤:

  • 使用 Dockerfile 定义应用程序的环境。
  • 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  • 最后,执行docker-compose up 命令来启动并运行整个应用程序。

docker-compose.yml 的配置案例如下(配置参数参考下文):

<待完善>

6 docker容器化的底层原理

Docker 的核心原理是操作系统级别的虚拟化,它通过两种关键的技术来实现隔离,从而在一台机器上运行多个互不干扰的“环境”(容器):

  • Linux 命名空间 (Namespaces)
  • 控制组 (Control Groups, cgroups)

6.1 Linux 命名空间 (Namespaces) - 负责“隔离”

命名空间将全局的系统资源包装在一个抽象的隔离层中,让每个容器感觉自己拥有一个独立的系统资源实例。Docker 主要使用了以下几种命名空间:

  • PID 命名空间 (Process ID): 隔离进程 ID。容器内的进程 PID 从 1 开始,与宿主机和其他容器的 PID 独立。
  • Net 命名空间 (Network): 隔离网络设备、IP 地址、端口等。每个容器有自己的网络栈(如 eth0)。
  • IPC 命名空间 (Inter-Process Communication): 隔离进程间通信资源,如信号量、消息队列和共享内存。
  • Mount 命名空间: 隔离文件系统挂载点。每个容器看到的是自己的文件系统层次结构。
  • UTS 命名空间 (Unix Timesharing System): 隔离主机名和域名。每个容器可以有自己的 hostname。
  • User 命名空间: 隔离用户和用户组 ID。可以映射容器内的 root 用户到宿主机上的非特权用户,增强安全性。

6.2 b) 控制组 (cgroups) - 负责“资源限制”

cgroups 用于限制和记录一个进程组所使用的物理资源,防止某个容器耗尽整个系统的资源。

  • 资源限制: 可以限制容器使用的 CPU、内存、磁盘 I/O 和网络带宽。
  • 优先级分配: 可以设置容器使用 CPU 和磁盘 I/O 的优先级。
  • 资源核算: 测量组的资源使用情况,用于计费等。
  • 进程控制: 可以挂起、恢复或杀死一组进程。

6.3 为什么能在一台机器上运行多个Mysql容器?

当你运行多个 MySQL 容器时:

  • 每个容器通过 Mount 命名空间 拥有自己独立的文件系统,它们的数据库文件 (/var/lib/mysql) 是分开的,互不冲突。
  • 每个容器通过 Net 命名空间 拥有自己独立的网络栈。你可以将它们的 3306 端口分别映射到宿主机的不同端口(如 3306, 3307, 3308),从而都可以被外部访问。
  • 每个容器通过 PID 命名空间 运行着自己独立的 mysqld 进程。
  • cgroups 确保这些 MySQL 容器不会互相争抢资源,比如一个容器不会吃掉所有的内存导致其他容器崩溃。

“系统”这个词的辨析:容器内运行的并不是一个完整的操作系统内核。所有容器都共享宿主机的内核。容器里运行的是一个个被隔离的用户空间进程和它所需的文件(由容器镜像提供,如/bin, /lib 等)。所以它看起来像一个精简版的“系统”,但其核心(内核)是共用的。这正是它比虚拟机轻量、快速的根本原因。

因此假如在 Windows 运行 Linux 容器,CPU 的调度按照 Windows 宿主机的调度规则,但执行环境是 Linux,它的流程是:

Linux 容器进程 -> (被) Linux VM 内核调度 -> (作为) Windows 进程 -> (被) Windows 内核调度 -> (运行于) 物理 CPU