Docker 概述

1. Docker 的出现背景

  • 环境一致性问题:在传统的软件开发流程中,开发人员在本地开发环境中编写代码,但当代码部署到生产环境时,常常会遇到“在我的电脑上可以运行”的问题。这是因为开发环境和生产环境在配置、依赖等方面存在差异。

  • 环境配置复杂:对于一些复杂的应用,如需要集群部署的 Redis、ES、Hadoop 等,环境配置非常繁琐且耗时。每次在新的机器上部署都需要重复配置,效率低下。

  • 跨平台问题:开发人员可能在 Windows 系统上开发,而生产环境可能是 Linux 系统,这导致了跨平台部署的困难。

2. Docker 的核心思想

  • 集装箱化:Docker 的设计灵感来源于集装箱。集装箱通过标准化的尺寸和结构,使得货物可以在不同的运输工具(如轮船、火车、卡车)之间高效地转运。同样,Docker 通过标准化的容器,将应用及其依赖打包在一起,确保应用在不同的环境中都能一致地运行。

  • 隔离性:Docker 容器提供了轻量级的隔离机制,每个容器都是一个独立的运行环境,互不影响。这类似于操作系统中的进程隔离,但 Docker 容器的隔离更为彻底,包括文件系统、网络、用户空间等方面的隔离。

3. Docker 的历史

  • 2010 年:dotCloud 公司成立,开始研发基于 LXC(Linux Container)的容器技术。

  • 2013 年:Docker 开源,迅速获得社区的关注和贡献。

  • 2014 年 4 月 9 日:Docker 1.0 版本发布,标志着 Docker 技术的成熟和稳定。

4. Docker 的优势

  • 轻量级:与传统的虚拟机相比,Docker 容器不需要虚拟整个操作系统,因此镜像体积小,启动速度快。Docker 镜像通常只有几十 MB,而虚拟机镜像可能需要几 GB。

  • 秒级启动:Docker 容器的启动时间通常在秒级,而虚拟机的启动需要几分钟。这是因为 Docker 容器直接利用宿主机的内核,无需等待操作系统启动。

  • 资源利用率高:Docker 容器共享宿主机的内核,因此可以更高效地利用宿主机的资源。在相同的硬件资源下,可以运行更多的 Docker 容器,提高了资源的利用率。

  • 环境一致性:Docker 容器确保应用在开发、测试和生产环境中具有一致的运行环境,减少了因环境差异导致的问题。

  • 易于部署和扩展:Docker 容器可以轻松地在不同的机器上部署和扩展。通过 Docker 仓库,可以方便地分享和获取镜像,实现应用的快速部署。

5. Docker 的应用场景

  • 开发环境标准化:开发人员可以在本地使用 Docker 容器来模拟生产环境,确保开发的代码在生产环境中能够正常运行。

  • 持续集成和持续部署(CI/CD):Docker 容器可以与 CI/CD 工具集成,实现自动化的构建、测试和部署流程。

  • 微服务架构:Docker 容器适合微服务架构,每个微服务可以运行在独立的容器中,实现服务的解耦和弹性扩展。

  • 多环境部署:Docker 容器可以轻松地在不同的环境中部署,包括开发、测试、预生产和生产环境,确保应用在不同环境中的行为一致。

  • 云原生应用:Docker 容器是云原生应用的基础,与 Kubernetes 等容器编排工具结合,可以实现大规模容器集群的管理。

6. Docker 的基本组成

  • 镜像(Image):镜像是用于创建容器的模板,包含了应用及其依赖的文件系统。镜像是只读的,可以被多个容器共享。

  • 容器(Container):容器是镜像的运行实例,是实际运行应用的环境。容器是隔离的、独立的运行环境,可以启动、停止、删除等操作。

  • 仓库(Repository):仓库是存储和分发镜像的地方。Docker Hub 是最常用的公有仓库,用户可以从中获取公共镜像,也可以将自己的镜像推送到仓库中。私有仓库则用于企业内部镜像的存储和管理。

7. Docker 的工作原理

  • Client-Server 架构:Docker 采用 Client-Server 架构,Docker 客户端通过 Socket 与 Docker 守护进程(Docker Daemon)通信,发送指令并获取结果。

  • 守护进程:Docker 守护进程运行在宿主机上,负责管理容器的生命周期,包括创建、启动、停止、删除等操作。

  • 容器运行时:Docker 容器运行时环境包括容器的文件系统、进程空间、网络接口等。容器直接利用宿主机的内核,通过命名空间(Namespaces)和控制组(Cgroups)实现隔离和资源限制。

8. Docker 与虚拟机的对比

  • 虚拟机

    • 虚拟化层次:虚拟机通过 Hypervisor 层虚拟化硬件资源,每个虚拟机都包含一个完整的操作系统。

    • 启动时间:虚拟机启动需要几分钟,因为需要加载操作系统。

    • 资源占用:虚拟机占用资源较多,每个虚拟机都需要分配一定的 CPU、内存和存储资源。

    • 隔离性:虚拟机的隔离性较强,但资源利用效率较低。

  • Docker 容器

    • 虚拟化层次:Docker 容器通过内核虚拟化技术实现轻量级的隔离,共享宿主机的内核,不需要虚拟整个操作系统。

    • 启动时间:Docker 容器启动只需几秒钟,因为直接利用宿主机的内核,无需加载操作系统。

    • 资源占用:Docker 容器占用资源较少,镜像体积小,运行效率高。

    • 隔离性:Docker 容器的隔离性足以满足大多数应用的需求,同时资源利用效率高。

9. Docker 的生态系统

  • Docker Hub:Docker Hub 是 Docker 的官方镜像仓库,提供了大量的公共镜像,用户可以从中获取所需的镜像,也可以将自己的镜像推送到 Docker Hub。

  • 私有仓库:企业可以搭建自己的私有仓库,用于存储和管理内部的镜像,确保镜像的安全性和私密性。

  • Dockerfile:Dockerfile 是构建 Docker 镜像的配置文件,通过编写 Dockerfile,可以自动化地构建镜像,确保镜像的一致性和可复现性。

  • Docker Compose:Docker Compose 是一个工具,用于定义和管理多容器 Docker 应用。通过编写 docker-compose.yml 文件,可以轻松地创建和管理多个容器的组合。

  • Docker Swarm:Docker Swarm 是 Docker 的原生容器编排工具,用于管理 Docker 容器集群。通过 Docker Swarm,可以实现容器的自动扩展、负载均衡和高可用性。

  • Kubernetes:Kubernetes 是目前最流行的容器编排工具,与 Docker 容器技术结合,可以实现大规模容器集群的管理。Kubernetes 提供了丰富的功能,如自动扩展、负载均衡、自我修复等。

Docker基本组成

镜像(images)

定义:用于创建容器的模板,包含了运行应用所需的所有内容,代码,运行时库,环境变量,配置文件等,镜像是只读的,可以被多个容器共存

特性:

分层结构:镜像是由多层文件系统组成的,每一层带爱哦一个特定的变更,可以使得镜像共享基础层,节省存储空间。

不可变:镜像一旦创建,其内容不可更改,如果需要修改镜像,通常需要创建一个新的镜像。

版本控制:镜像支持版本控制,可以通过标签(Tag)来区分不同的版本

容器(Container)

定义:容器是镜像的运行实例,是实际运行应用的环境,容器是隔离的、独立的运行环境,可以启动、停止、删除等操作

特性:

隔离性:容器之间是隔离的,每个容器都有自己的文件系统、网络结构和进程空间,互不影响

轻量级:容器共享宿主机的内核,不需要虚拟整个操作系统,一次启动速度快,资源占用少。

生命周期管理:容器的生命周期可以被精细管理,包括创建、启动、停止、删除、更新等操作。

仓库(Repository)

定义:仓库是存储和分发镜像的地方,分为共有仓库和私有仓库,Docker Hub是最常用的共有仓库,私有仓库用于企业内部镜像的存储和管理

其他重要概念

Dockerfile:Dockerfile是构建Docker镜像的配置文件,包含了一系列指令,用于定义如何构建镜像,通过编写,可以自动化地构建镜像,确保镜像的一致性和可复现性

数据卷(Volume):数据卷是用于将容器内的数据持久化到宿主机,防止容器删除导致数据丢失,数据卷可以实现容器间的数据共享,也可以用于备份和恢复数据。

网络(Network):Docker提供了多种网络模式,包括桥接,主机模式,无网络模式和容器网络模式,通过自定义网络,可以实现容器之间的通信

Docker的常用命令

# 容器相关命令

## 运行容器
docker run [选项] 镜像名 [命令] # 从指定镜像创建并启动一个新容器
- `-d`:后台运行容器,并返回容器ID,例如`docker run -d nginx`,在后台运行nginx容器。
- `-it`:以交互模式运行容器,通常与`/bin/bash`等命令配合使用,例如`docker run -it ubuntu /bin/bash`,进入ubuntu容器的bash shell。
- `--name`:为容器指定一个名称,例如`docker run --name mycontainer -d nginx`,创建并启动一个名为mycontainer的nginx容器。
- `-p`:端口映射,格式为`宿主机端口:容器端口`,例如`docker run -p 8080:80 nginx`,将容器的80端口映射到宿主机的8080端口。

## 查看容器
docker ps # 列出当前正在运行的容器,显示容器ID、镜像名、创建时间、状态、端口映射等信息
docker ps -a # 列出所有容器,包括正在运行的和已经停止的,加上`-a`参数可以查看到所有容器的状态。

## 进入容器
docker exec -it 容器id /bin/bash # 进入指定容器的bash shell
- `-it`:使`docker exec`命令以交互模式执行,允许用户与容器内的shell进行交互。

## 停止/启动/重启容器
docker stop 容器id # 停止指定的正在运行的容器,容器会接收到SIGTERM信号,然后停止运行。
docker start 容器id # 启动一个已经停止的容器,使其重新运行。
docker restart 容器id # 重启指定的容器,先停止再启动。
docker kill 容器id #强制定制当前容器
## 删除容器
docker rm 容器id # 删除一个已经停止的容器,如果容器正在运行,需要先停止它。
docker rm -f 容器id # 强制删除一个正在运行的容器,`-f`参数表示强制删除。

# 镜像相关命令

## 拉取镜像
docker pull 镜像名 # 从Docker Hub拉取指定镜像,例如`docker pull ubuntu`拉取最新的ubuntu镜像。
docker pull 镜像名:标签 # 拉取指定标签的镜像,例如`docker pull ubuntu:20.04`拉取标签为20.04的ubuntu镜像。

## 查看镜像
docker images # 列出本地所有镜像,显示镜像名、标签、镜像ID、创建时间、大小等信息。

## 构建镜像
docker build -t 镜像名:标签 . # 使用当前目录下的Dockerfile构建镜像
- `-t`:指定构建的镜像名和标签,格式为`镜像名:标签`,例如`docker build -t myapp:v1 .`,表示使用当前目录下的Dockerfile构建一个名为myapp,标签为v1的镜像。

## 删除镜像
docker rmi 镜像id # 删除指定的本地镜像,如果该镜像有容器正在使用,则无法删除。
docker rmi -f 镜像id # 强制删除镜像,即使有容器正在使用该镜像也会删除,`-f`参数表示强制删除。

# 其他常用命令

## 查看日志
docker logs 容器id # 查看指定容器的日志输出,可以查看容器运行时产生的日志信息。

## 查看容器详情
docker inspect 容器id # 查看指定容器的详细信息,包括配置、网络、存储等详细信息,以JSON格式输出。

## 查看镜像详情
docker inspect 镜像id # 查看指定镜像的详细信息,包括镜像的配置、层信息等详细内容,同样以JSON格式输出。

## 查看Docker版本信息
docker version # 显示Docker客户端和服务器端的版本信息,包括版本号、API版本、Go版本等。

Dockerfile

Dockerfile 是用于构建 Docker 镜像的配置文件,它包含了一系列指令,这些指令定义了如何构建镜像。通过编写 Dockerfile,可以自动化地构建镜像,确保镜像的一致性和可复现性。以下是 Dockerfile 的详细介绍和常用指令。

1. Dockerfile 的基本结构

Dockerfile 通常包含以下几部分:

  • 基础镜像(Base Image):指定构建镜像的起始点。

  • 维护者信息(Maintainer):记录镜像的作者信息。

  • 镜像操作指令(Image Operations):定义如何修改镜像,如安装软件、设置环境变量等。

  • 容器启动指令(Container Startup):定义容器启动时运行的命令。

2. 常用指令

以下是一些常用的 Dockerfile 指令及其详细说明:

2.1 FROM
  • 作用:指定基础镜像,这是 Dockerfile 的起始指令。

  • 语法FROM <镜像名>:<标签>

  • 示例

    dockerfile
    FROM ubuntu:18.04
2.2 MAINTAINER
  • 作用:记录镜像的维护者信息。

  • 语法MAINTAINER <姓名> <邮箱>

  • 示例

    dockerfile
    MAINTAINER John Doe <john.doe@example.com>
2.3 RUN
  • 作用:在镜像构建过程中运行命令,用于安装软件、配置环境等。

  • 语法RUN <命令>

  • 示例

    dockerfile
    RUN apt-get update && apt-get install -y nginx
2.4 ADD
  • 作用:将文件、目录或远程文件添加到镜像中。

  • 语法ADD <源路径> <目标路径>

  • 示例

    dockerfile
    ADD ./app.jar /app.jar
2.5 COPY
  • 作用:与 ADD 类似,但更推荐使用 COPY,因为它更明确,不支持远程文件下载。

  • 语法COPY <源路径> <目标路径>

  • 示例

    dockerfile
    COPY ./app.jar /app.jar
2.6 WORKDIR
  • 作用:设置工作目录,后续的命令将在该目录下执行。

  • 语法WORKDIR <路径>

  • 示例

    dockerfile
    WORKDIR /app
2.7 ENV
  • 作用:设置环境变量。

  • 语法ENV <变量名> <值>

  • 示例

    ENV JAVA_HOME /usr/local/java
2.8 EXPOSE
  • 作用:声明容器运行时监听的端口,但不会实际发布端口。

  • 语法EXPOSE <端口>

  • 示例

    dockerfile
    EXPOSE 8080
2.9 CMD
  • 作用:指定容器启动时运行的命令,只能有一个 CMD 指令,最后一个生效。

  • 语法CMD ["命令", "参数"]

  • 示例

    CMD ["java", "-jar", "/app.jar"]
2.10 ENTRYPOINT
  • 作用:指定容器启动时运行的命令,可以追加参数。

  • 语法ENTRYPOINT ["命令", "参数"]

  • 示例

    ENTRYPOINT ["java", "-jar", "/app.jar"]
2.11 VOLUME
  • 作用:创建一个数据卷,用于数据持久化。

  • 语法VOLUME ["路径"]

  • 示例

    VOLUME ["/data"]
2.12 ONBUILD
  • 作用:当构建一个被继承的 Dockerfile 时,会自动执行 ONBUILD 指令。

  • 语法ONBUILD <指令>

  • 示例

    ONBUILD COPY . /app/src

3. 实战示例

以下是一个完整的 Dockerfile 示例,用于构建一个包含 Nginx 和自定义配置的镜像:

# 基础镜像
FROM nginx:1.18

# 维护者信息
MAINTAINER John Doe <john.doe@example.com>

# 设置工作目录
WORKDIR /usr/share/nginx/html

# 复制静态文件到工作目录
COPY ./static /usr/share/nginx/html

# 复制自定义配置文件
COPY ./nginx.conf /etc/nginx/nginx.conf

# 暴露端口
EXPOSE 80

# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]

4. 构建和运行镜像

  • 构建镜像

    docker build -t my-nginx:1.0 .
  • 运行容器

    docker run -d -p 8080:80 --name my-nginx-container my-nginx:1.0

5. 小结

Dockerfile 是构建 Docker 镜像的关键配置文件,通过编写 Dockerfile,可以自动化地构建镜像,确保镜像的一致性和可复现性。常用指令如 FROMRUNCOPYEXPOSECMDENTRYPOINT 等,可以满足大多数镜像构建的需求。掌握这些指令和它们的使用方法,可以高效地构建和管理 Docker 镜像。

以下是一个更复杂的 Dockerfile 示例,用于构建一个包含 Spring Boot 应用、配置文件、日志目录和环境变量设置的镜像。这个示例展示了如何从基础镜像开始,逐步构建一个完整的应用镜像。

1. 项目结构

假设你的项目结构如下:

my-spring-boot-app/
├── src/
│   └── main/
│       └── java/
│           └── com/
│               └── example/
│                   └── DemoApplication.java
├── target/
│   └── my-spring-boot-app-1.0.0.jar
├── config/
│   └── application.properties
├── logs/
└── Dockerfile

2. Dockerfile

# 基础镜像
FROM openjdk:11-jdk-slim

# 维护者信息
MAINTAINER John Doe <john.doe@example.com>

# 设置工作目录
WORKDIR /app

# 复制应用 JAR 文件到工作目录
COPY target/my-spring-boot-app-1.0.0.jar /app/my-spring-boot-app.jar

# 复制配置文件到工作目录
COPY config/application.properties /app/config/application.properties

# 创建日志目录
RUN mkdir -p /app/logs

# 设置环境变量
ENV SPRING_PROFILES_ACTIVE=prod
ENV JAVA_OPTS="-Xms512m -Xmx1024m"

# 暴露应用端口
EXPOSE 8080

# 设置容器启动时运行的命令
ENTRYPOINT ["java", "-jar", "/app/my-spring-boot-app.jar", "--spring.config.location=file:/app/config/application.properties"]

# 启动应用
CMD ["--spring.profiles.active=${SPRING_PROFILES_ACTIVE}"]

3. 构建和运行镜像

3.1 构建镜像

在项目根目录下运行以下命令构建镜像:

docker build -t my-spring-boot-app:1.0.0 .

3.2 运行容器

运行容器时,可以指定端口映射和环境变量:

docker run -d -p 8080:8080 --name my-spring-boot-container -e SPRING_PROFILES_ACTIVE=dev my-spring-boot-app:1.0.0

4. 详细说明

  • 基础镜像:使用 openjdk:11-jdk-slim 作为基础镜像,这是一个轻量级的 OpenJDK 11 镜像。

  • 维护者信息:记录镜像的维护者信息。

  • 工作目录:设置工作目录为 /app,后续的命令将在该目录下执行。

  • 复制 JAR 文件:将构建好的 Spring Boot 应用 JAR 文件复制到工作目录。

  • 复制配置文件:将配置文件 application.properties 复制到工作目录下的 config 目录。

  • 创建日志目录:创建日志目录 /app/logs,用于存储应用日志。

  • 设置环境变量:设置环境变量 SPRING_PROFILES_ACTIVEJAVA_OPTS,分别用于指定激活的 Spring 配置文件和 Java 运行参数。

  • 暴露端口:声明容器运行时监听的端口 8080

  • ENTRYPOINT:设置容器启动时运行的命令,使用 java -jar 启动 JAR 文件,并指定配置文件的位置。

  • CMD:设置默认的命令参数,可以通过运行容器时的环境变量覆盖。

5. 进一步扩展

  • 数据卷:如果需要持久化日志文件,可以使用数据卷:

    docker run -d -p 8080:8080 --name my-spring-boot-container -e SPRING_PROFILES_ACTIVE=dev -v /host/logs:/app/logs my-spring-boot-app:1.0.0
  • 自定义网络:如果需要多个容器之间通信,可以创建自定义网络:

    docker network create my-network
    docker run -d -p 8080:8080 --name my-spring-boot-container --network my-network -e SPRING_PROFILES_ACTIVE=dev my-spring-boot-app:1.0.0

通过这个复杂的示例,你可以看到如何使用 Dockerfile 构建一个包含应用、配置文件、日志目录和环境变量的完整镜像,并通过命令行参数和环境变量进行灵活配置。


Docker 网络是 Docker 容器之间通信的基础。Docker 提供了多种网络模式,每种模式适用于不同的场景。以下是对 Docker 网络的详细介绍,包括网络模式、常用命令和实战示例。

DOCKER 网络

1. 网络模式

Docker 支持以下几种网络模式:

1.1 bridge(桥接模式)

  • 默认模式:这是 Docker 的默认网络模式。每个容器都会被分配一个独立的 IP 地址,并通过一个虚拟的以太网桥(通常是 docker0)与宿主机网络连接。

  • 特点

    • 容器之间可以相互通信,但需要通过 IP 地址。

    • 容器与宿主机之间可以相互通信。

    • 容器对外部网络是隔离的,但可以通过端口映射访问。

1.2 host(主机模式)
  • 特点:容器将直接使用宿主机的网络栈,不进行网络隔离。容器内的应用可以直接绑定宿主机的端口,没有网络性能损耗。

  • 适用场景:适用于对网络性能要求极高的应用,如高性能的网络服务。

1.3 none(无网络模式)
  • 特点:容器不配置任何网络,完全隔离。适用于不需要网络通信的容器。

1.4 container(容器模式)
  • 特点:容器共享另一个容器的网络命名空间。适用于需要多个进程运行在同一个网络命名空间中的场景。

1.5 overlay(覆盖网络)
  • 特点:用于多主机网络,允许多个 Docker 守护进程之间的容器相互通信。通常与 Docker Swarm 一起使用。

2. 常用命令

2.1 查看网络
  • 命令docker network ls

  • 示例

    sh
    docker network ls
2.2 查看网络详情
  • 命令docker network inspect <网络名>

  • 示例

    sh
    docker network inspect bridge
2.3 创建网络
  • 命令docker network create --driver <驱动> <网络名>

  • 示例

    sh
    docker network create --driver bridge my-bridge-network
2.4 删除网络
  • 命令docker network rm <网络名>

  • 示例

    sh
    docker network rm my-bridge-network
2.5 连接容器到网络

命令docker network connect <网络名> <容器名>

  • 示例

    sh
    docker network connect my-bridge-network my-container
2.6 断开容器与网络的连接
  • 命令docker network disconnect <网络名> <容器名>

  • 示例

    shdocker network disconnect my-bridge-network my-container

3. 实战示例

3.1 创建自定义桥接网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 my-bridge-network
3.2 启动容器并连接到自定义网络
docker run -d --name my-container --network my-bridge-network nginx
3.3 查看网络配置
docker network inspect my-bridge-network
3.4 连接另一个容器到同一网络
docker run -d --name my-another-container --network my-bridge-network redis
3.5 验证容器之间的通信
docker exec -it my-container ping my-another-container

4. 网络连通性测试

4.1 创建两个容器并测试通信
# 创建两个容器,连接到默认的 bridge 网络
docker run -d --name container1 nginx
docker run -d --name container2 nginx

# 测试 container1 和 container2 之间的通信
docker exec -it container1 ping container2
4.2 使用自定义网络
# 创建自定义网络
docker network create --driver bridge my-custom-network

# 启动两个容器,连接到自定义网络
docker run -d --name container3 --network my-custom-network nginx
docker run -d --name container4 --network my-custom-network nginx

# 测试 container3 和 container4 之间的通信
docker exec -it container3 ping container4

5. 小结

Docker 网络提供了多种模式,每种模式适用于不同的场景。通过创建自定义网络,可以更好地管理容器之间的通信,确保网络的隔离和安全性。常用命令如 docker network lsdocker network inspectdocker network createdocker network rm 等,可以帮助你管理和维护 Docker 网络。通过实战示例,你可以看到如何创建自定义网络、连接容器到网络并测试容器之间的通信。