[TOC]

能干嘛?

  • 1、当做一个不用配置的沙盒,快速使用还是很香的。
  • 2、当做一个专一服务器,部署在自己电脑上,随取随用。
  • 3、自己构建的工程通过Docker封装后能够在其他地方使用。

重要概念

(GPT生成当中我选择的)

  1. 镜像(Image):镜像是一个只读的、包含文件系统和应用程序的轻量级模板。它是Docker容器的基础,也可以被看作是容器的“快照”。

  2. 容器(Container):容器是镜像的可运行实例。容器在隔离的环境中运行,它包含了应用程序及其所需的所有依赖项、库、配置文件等。容器可以被创建、启动、停止、删除等。

  3. Dockerfile:Dockerfile是一个包含创建Docker镜像的指令的文本文件。这些指令包括基本镜像、添加文件、设置环境变量、暴露端口等。

  4. 数据卷(Volume):数据卷是Docker容器的持久化存储机制,可以在容器之间共享和重新使用。使用数据卷可以将数据独立于容器的生命周期进行管理。

  5. 网络(Networking):Docker支持多种网络模式,例如桥接、主机和覆盖网络等,以满足不同场景下的容器通信需求。

  6. 多阶段构建(Multi-stage builds):多阶段构建是一种优化Docker镜像大小的方法,它允许在单个Dockerfile中使用多个基础镜像。这可以减少最终镜像的大小,从而提高部署和运行速度。

镜像(Image)

Docker镜像由多个层(Layers)组成,这些层是文件系统的叠加。每个层都是只读的,并表示Dockerfile中的一个指令。在构建过程中,Docker会为Dockerfile中的每个指令创建一个新的层,并将结果保存为一个中间镜像。这些层叠加在一起,形成最终的Docker镜像。

以下是Docker镜像组成的一些关键概念:

  • 层(Layer):每个层都是镜像构建过程中产生的一个中间结果。层是只读的,并可以被其他镜像复用。将镜像分解为多个层有助于节省存储空间加快镜像分发速度

  • 基础镜像(Base Image):基础镜像是构建新镜像的起点。它通常包括一个最小化的操作系统和一些基本工具。在Dockerfile中,基础镜像由FROM指令指定。例如,FROM ubuntu:20.04表示以Ubuntu 20.04版本为基础镜像。

  • 中间镜像(Intermediate Image):在构建过程中,Docker会为Dockerfile中的每个指令创建一个中间镜像。中间镜像可以用于调试、缓存和层复用。

  • 最终镜像(Final Image):最终镜像是构建过程的结果。它是一个包含所有层的完整镜像,可以用来创建和运行容器。

  • Dockerfile:Dockerfile是一个包含构建Docker镜像所需指令的文本文件。这些指令包括设置基础镜像、运行命令、添加文件、设置环境变量、暴露端口等。

  • 缓存(Cache):Docker在构建镜像时会缓存每个层。当重新构建镜像时,Docker会检查Dockerfile的指令是否已经在缓存中存在,如果存在,则直接使用缓存的层,而不是重新执行指令。这有助于加快构建速度。为了充分利用缓存,建议将不经常更改的指令放在Dockerfile的前面。

Docker镜像的分层结构使得构建、分发和存储镜像更加高效。理解Docker镜像的组成有助于更好地使用Docker进行应用程序的容器化和部署。

容器(Container)

Docker容器是从Docker镜像创建的运行时实例。一个容器包括镜像的全部内容以及一些运行时配置和元数据。以下是Docker容器的主要组成部分:

  • 镜像(Image):容器是基于镜像创建的。镜像包含了容器运行所需的文件系统、应用程序和依赖项。在运行容器时,Docker会将镜像的只读层加载到容器的文件系统中

  • 可写层(Writable Layer):当容器启动时,Docker会在镜像的只读层之上添加一个可写层。容器在运行过程中对文件系统的所有修改(如创建、修改和删除文件)都会发生在这个可写层。当容器停止时,可写层的更改会被丢弃,除非使用docker commit命令将其保存为新的镜像

  • 运行时配置:运行时配置包括用于创建和运行容器的一些参数和设置,如环境变量、端口映射、CPU和内存限制等。这些配置可以在运行docker run命令时通过命令行参数或Docker Compose文件指定。

  • 网络:每个容器都有一个或多个网络接口,用于与其他容器和主机进行通信。Docker提供了多种网络驱动和配置选项,以满足不同场景的需求。

  • 存储:容器可以使用数据卷(Volumes)或绑定挂载(Bind Mounts)将数据持久化。数据卷是Docker管理的特殊目录,而绑定挂载则是将主机上的目录或文件映射到容器中。这些存储选项可以在运行容器时进行配置。

  • 进程:容器中运行的进程是其主要功能的载体。通常,每个容器都会有一个主进程,负责执行容器的主要任务。当主进程退出时,容器会停止运行。

  • 日志:容器的输出(如stdout和stderr)会被Docker捕获并存储为日志。可以通过docker logs命令或其他日志管理工具查看和分析这些日志。

Docker容器将镜像、运行时配置、网络、存储、进程和日志等组件整合在一起,形成一个独立、隔离的运行环境。理解Docker容器的组成有助于更好地使用和管理容器,以及优化应用程序的容器化和部署。

数据卷(Volume)

Docker提供了多种数据存储选项,包括未命名卷(Unnamed Volumes)、命名卷(Named Volumes)和绑定挂载(Bind Mounts)。这些选项有不同的特点和用途,以下是它们的区别:

  • 未命名卷(Unnamed Volumes)生命周期跟着容器

    未命名卷是在创建容器时自动创建的数据卷,没有指定名称。当容器被删除时,未命名卷会被标记为“孤立”,但不会自动删除。你可以通过docker volume prune命令删除未使用的未命名卷。未命名卷的使用场景相对有限,因为它们难以识别和管理。
    例如,在运行docker run命令时,通过-v参数指定一个容器内的挂载点(不指定宿主机的路径和名称):

    1
    docker run -d -v /data my-image
  • 命名卷(Named Volumes)生命周期与容器无关
    命名卷是具有指定名称的数据卷,可以在多个容器之间共享和重用。命名卷由Docker守护程序管理,可以使用docker volume命令或Docker Compose文件创建、列出和删除。与未命名卷相比,命名卷更易于识别和管理。
    例如,在运行docker run命令时,通过-v参数指定一个数据卷名称和容器内的挂载点:

    1
    docker run -d -v my-volume:/data my-image
  • 绑定挂载(Bind Mounts):
    绑定挂载是将宿主机上的目录或文件映射到容器的文件系统中。与数据卷不同,绑定挂载不受Docker守护程序的管理,而是直接由宿主机的文件系统管理。绑定挂载允许容器直接访问宿主机的文件和目录,适用于需要与宿主机共享数据或配置文件的场景。
    例如,在运行docker run命令时,通过-v参数指定宿主机的路径和容器内的挂载点:

    1
    docker run -d -v /host/path:/data my-image

    总结一下:

  • 未命名卷:自动创建,无指定名称,难以识别和管理,适用于临时存储或不关心卷名称的场景。

  • 命名卷:具有指定名称,由Docker守护程序管理,易于识别和管理,适用于持久化存储和在多个容器之间共享数据的场景。

  • 绑定挂载:将宿主机的目录或文件映射到容器,不受Docker管理,适用于与宿主机共享数据或配置文件的场景。

  • zhongqian:未命名卷可以在绑定挂载目录下子目录存在,用于保存一些不重要的临时文件。

卷与BindMounts之间冲突了怎么办?

  • Docker有一个简单的规则:就是谁长先听谁的。
    • 比如匿名卷/app/xyz,BindMounts绑定/app,由于BindMounts没有xyz文件夹,所以这两个能够正常运行

build images时 Copy进去与Volume之间的差别?

Docker构建镜像时的COPY指令和运行容器时的Volume(数据卷)具有不同的用途和特点。以下是它们之间的差别:

  • COPY指令:
    COPY指令用于在Docker镜像构建过程中,将宿主机的文件或目录复制到镜像的文件系统中。这些文件或目录会成为镜像的一部分,当启动基于该镜像的容器时,这些文件或目录将存在于容器的文件系统中。
    优点:

    • 文件或目录成为镜像的一部分,容器启动时自动包含这些文件或目录。

    • 便于将应用程序代码、配置文件等打包到镜像中,实现应用程序的一致性和可移植性

      缺点:

    • 当文件或目录发生更改时,需要重新构建镜像以更新内容

    • 不适合在容器运行时共享或持久化数据,因为容器间的数据是隔离的,容器删除后数据会丢失。

  • Volume(数据卷):
    数据卷是一种用于持久化和共享容器数据的机制。数据卷是独立于容器的存储区域,可以在容器之间共享数据和保持数据持久性。当启动一个容器时,可以将一个或多个数据卷挂载到容器的文件系统上。
    优点:

    • 数据卷可以实现容器数据的持久化和共享,适用于数据库、日志文件等需要保留的数据。

    • 容器可以在运行时读写数据卷,无需重新构建镜像

      缺点:

    • 数据卷不是镜像的一部分,需要单独管理和配置。

    • 数据卷可能会引入额外的复杂性,如数据卷的生命周期、备份和恢复等。

总结一下,COPY指令用于将文件或目录复制到镜像中,适用于打包应用程序代码和配置文件;而Volume(数据卷)用于在容器之间共享和持久化数据,适用于数据库、日志文件等需要保留的数据。根据应用程序的需求和场景,可以选择合适的方法来管理容器的文件和数据。

网络(Networking)

Docker提供了多种网络模式,以支持不同的网络需求和场景。以下是Docker常见的网络模式及其区别:

Bridge(桥接)模式:

  • 桥接模式是Docker的默认网络模式。在这种模式下,Docker为每个容器分配一个私有、隔离的网络命名空间,并将容器连接到一个虚拟桥接器上。桥接器可以将容器的网络连接到宿主机的网络,容器之间也可以通过桥接器进行通信。每个容器在桥接网络上拥有一个内部IP地址,与宿主机和其他容器通信时可以使用端口映射

Host(主机)模式:

  • 在主机模式下,容器将直接共享宿主机的网络命名空间,而不是创建一个独立的网络命名空间。这意味着容器可以直接使用宿主机的IP地址和端口,而无需端口映射。与桥接模式相比,主机模式可以提供更好的网络性能,但牺牲了网络隔离性。

None(无网络)模式:

  • 在无网络模式下,容器将拥有一个独立的网络命名空间,但不会被连接到任何网络接口。这意味着容器无法访问外部网络,也无法与其他容器通信。这种模式适用于需要完全隔离网络环境的场景,例如安全性要求较高的应用程序。

Overlay(覆盖)模式:

  • 覆盖模式适用于跨多个主机的Docker容器网络,通常用于Docker Swarm集群。在这种模式下,Docker使用VXLAN技术在主机之间创建一个虚拟覆盖网络,允许容器跨主机进行通信。覆盖网络提供了跨主机的网络隔离和可扩展性,适用于分布式应用程序和微服务架构

Macvlan(MAC VLAN)模式:

  • 在MAC VLAN模式下,Docker为容器分配一个独立的MAC地址,并将容器连接到宿主机的物理网络。容器在网络上表现为一个独立的物理设备,可以直接使用宿主机所在子网的IP地址。这种模式适用于需要将容器与物理网络集成的场景,例如遗留应用程序或特殊网络需求。

windows与mac的宿主机通信地址

  • host.docker.internal

Docker间通信(两种方案)

  • 同一个network下可以通过容器名称
  • 不同网络下宿主机映射端口通信

Dockerfile文件解析

  • .dockerignore文件可以控制不被Copy到镜像的内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    # 使用哪个image作为底层;基础镜像
    FROM node

    # RUN的工作目录
    WORKDIR /app

    # 把外面当前目录(.)复制到容器里/app当中
    COPY . /app

    # 运行这个命令,“RUN”这个命令一般用于构建image的时候使用,运行image则不是这个命令
    RUN npm install

    # 将端口暴露到当前主机当中
    # 注意:当前这个阶段是构建过程中的,并非运行过程中,如需要运行,则需要 run -p 3000:80ß
    # EXPOSE 80

    # Argument硬编码在Dockerfile中
    ARG DEFAULT_PORT=80
    # 定义端口
    ENV PORT $DEFAULT_PORT
    # 使用这个上述定义
    EXPOSE $PORT

    # 运行image时使用,但是CMD传递的是一个数组
    CMD ["node", "server.js"]

    CMD 和ENTRYPOINT两个指令区别

    在Dockerfile中,CMD和ENTRYPOINT都是用于指定容器启动时要执行的命令。然而,它们之间存在一些区别:

  • CMD(命令):
    CMD指令用于指定容器启动时要执行的默认命令及其参数。如果在运行docker run命令时没有指定任何命令,Docker将执行CMD指令中定义的命令。
    Dockerfile中可以包含多个CMD指令,但仅最后一个CMD指令生效。
    例如,Dockerfile中指定一个CMD指令:

    1
    CMD ["python", "app.py"]

    在运行docker run命令时,如果没有指定任何命令,容器将执行python app.py

  • ENTRYPOINT(入口点):
    ENTRYPOINT指令用于指定容器启动时要执行的固定命令。与CMD指令不同,ENTRYPOINT指令定义的命令不能被docker run命令覆盖除非使用–entrypoint参数)。
    ENTRYPOINT指令通常与CMD指令结合使用。当这两个指令同时存在时,ENTRYPOINT指令定义的命令将作为主命令执行CMD指令定义的参数将作为ENTRYPOINT命令的参数
    例如,Dockerfile中指定一个ENTRYPOINT指令和一个CMD指令:

    1
    2
    ENTRYPOINT ["python"]
    CMD ["app.py"]

    在运行docker run命令时,容器将执行python app.py。如果在docker run命令中指定了其他参数,例如docker run my-image test.py,容器将执行python test.py

总结一下,CMD指令用于指定容器启动时要执行的默认命令,可以被docker run命令覆盖;而ENTRYPOINT指令用于指定容器启动时要执行的固定命令,不能轻易被覆盖ENTRYPOINT指令通常与CMD指令结合使用,以实现灵活的命令执行和参数传递

环境变量定义

  • dockerfile定义

    1
    2
    3
    4
    # Dockerfile硬编码定义端口
    ENV PORT 80
    # 使用这个上述定义
    EXPOSE $PORT
  • 可以使用命令的方式

    1
    2
    3
    4
    5
    6
    # 通过终端命令直接调用(这个是命令)
    --env PORT=8000
    -e PORT=8000

    # 通过终端命令调用文件(这个是命令)
    --env-file 文件名

    Docker-compose

    核心概念

  • Docker Compose does NOT replace Dockerfiles for custom Images

  • Docker Compose does NOT replace Images or Containers

  • Docker Compose is NOT suited for managing multiple containers on different hosts (machines)

  • zhongqian note: 需要明确一点,这个Docker Compose类似shell命令的打包软件

    • 将一个或多个Docker运行命令打包成一个yaml文件,进行执行。
  • zhongqian note: 还有就是默认container都是在同一个网络下的。

文件解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
version: "3.8" # 版本号
services: # 服务
mongodb: # 容器一名称
image: 'mongo'
volumes: # 绑定挂载 or 卷加载
- data:/data/db

#environment: # 单个环境变量加载
# MONGO_INITDB_ROOT_USERNAME: max
env_file: # 环境变量文件加载
- ./env/mongo.env

backend: # 容器二名称
build: ./backend # 这个是用来做Docker build backend 文件夹里Dockerfile
# build:
# context:

ports: # 端口映射
- '3000:80'

depands_on: # 这个是为了当前docker绑定前面docker时使用,因为当前Docker绑定了用名字命名的服务,但是名字会变化的,因此,这个时候需要这个。
- mongodb

frontend: # 容器三名称
build: ./frontend
ports:
- '3000:3000'
volumes:
- ./frontend/src:/app/src
stdin_open: true # 这个是docker run -ti 的交互模式
tty: true # 这个是docker run -ti 的交互模


volumes: # 只要绑定了命名卷,最后需要说明一下, 这个命令就是如果没有此卷,需要创建一下。
data:

使用流程

常规使用流程

一个Docker从头到尾的常规的使用顺序是

  1. 创建Dockerfile,通过Dockerfile构建image

    • docker build -t 名字:版本号 目录
  2. 构建完成后运行镜像,如果需要集成volumes,ports,network,env,cmd还需要一一加载命令。

    • docker run --name 容器名称
      1
      2
      3
      4
      5
      6
      docker run -v 执行bind mount
      docker run -p ports映射
      docker run -e 环境变量设置
      docker run --network 绑定网络,注意这个是需要创建一个网络,才能使用
      # 创建网络
      docker network create 名字
  3. 一般到这一个步骤之后就算是完成了。

docker-compose的使用流程

Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。通过使用Docker Compose,您可以使用YAML文件定义应用程序的各个服务、网络和数据卷,然后使用单个命令来创建、启动、停止和重启整个应用程序栈。Docker Compose是一个非常适合在开发、测试和生产环境中部署和管理多容器应用程序的工具。

  1. 创建docker-compose.yaml的内容,运行以下命令进行构建并运行

    • 构建并运行docker-compose up -d --build
    • 只构建docker-compose build # 只build,不run
  2. 关闭命令

    • docker-compose down# 关闭,但不会删除卷,如果需要删除卷 + '-v'

docker在生产环境使用流程

其实生产环境使用Docker一般情况下就是在常规使用流程的基础上,结合了bind mounts,代码修改后可以直接在Docker上运行。
而部署环境下则尽量不用bind mount这类操作,而是转换为volume或者是database下使用。

docker在部署环境使用流程

  • 上面其实讲到的“常规流程”与docker-compose使用流程,其实都是部署流程,但是还有比如说
    • CI / CD:依靠自动集成自动部署的方式,使用上会更加方便
    • k8s:其实k8s集成了很多能够多机部署以及自动重启等等的内容

docker非常规流程

  • 这个是我以前的一个非常不好但很实用的使用流程:
    1. 直接docker pull 一个原始镜像
    2. docker进入交互模式
      1
      2
      3
      4
      5
      6
      7
      8
      # 这个是直接运行时进入交互模式 t = tty 终端,i = 交互模式
      docker run -ti

      # 这个是重启docker进入交互模式 a = attach
      docker start -a -i

      # 这个是在docker运行过程中进入交互模式
      docker exec -ti 容器名称/id 执行的命令
    3. 把docker里需要做的事情做完后,容器转换为镜像,然后压缩(上传)分发
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # 容器转为镜像
      docker commit 容器id 镜像名称:版本号

      # 将镜像压缩
      docker save -o 压缩文件名称 镜像名称:版本号

      # 上传
      docker push 镜像名称:版本号

      # 将压缩文件还原为镜像
      docker load -i 压缩文件名称

      Docker使用经验,GPT生成并挑选过

  1. 保持Docker镜像简洁:使用精简的基础镜像,如Alpine Linux,并使用多阶段构建来减小镜像大小。这有助于降低部署时间、节省存储空间和提高运行效率。

  2. 使用版本控制:为Docker镜像和容器使用版本控制,确保您的环境可以重现。为镜像添加标签,以便于版本追踪和回滚。

  3. 利用Dockerfile的缓存机制:Docker在构建镜像时会缓存中间层。将不经常更改的指令放在Dockerfile的前面,以充分利用缓存加快构建速度。

  4. 单一职责原则:让每个容器只执行一个任务或服务。这有助于容器的可维护性、可扩展性和可替换性。

  5. 使用数据卷管理数据:使用数据卷(Volumes)而不是绑定挂载(Bind mounts)来存储持久化数据。数据卷可以更好地管理数据,同时保持容器的独立性。

  6. 通过环境变量进行配置:使用环境变量为容器提供配置信息,而不是在镜像中硬编码配置。这使得容器在不同环境中更易于重用。

  7. 使用Docker Compose简化部署:使用Docker Compose编排多容器应用,以便在开发、测试和生产环境中一致地部署和管理应用。

  8. 利用Docker的安全特性:限制容器的资源使用、网络访问,并使用Docker Secrets等机制管理敏感数据。

  9. 监控和日志:确保收集并监控容器的运行时指标和日志。可以使用像Prometheus、Grafana和ELK Stack这样的工具来分析和可视化这些数据。

  10. 学习和使用Docker的最佳实践:关注Docker官方文档、博客和社区,以获取最新的技巧和最佳实践。
    保持Docker环境的更新:定期更新Docker引擎、镜像和依赖库,以修复安全漏洞和获取新功能。

  11. 使用CI/CD:将Docker集成到持续集成/持续部署(CI/CD)流程中,以自动化构建、测试和部署应用。