[TOC]
能干嘛?
- 1、当做一个不用配置的沙盒,快速使用还是很香的。
- 2、当做一个专一服务器,部署在自己电脑上,随取随用。
- 3、自己构建的工程通过Docker封装后能够在其他地方使用。
重要概念
(GPT生成当中我选择的)
镜像(Image):镜像是一个只读的、包含文件系统和应用程序的轻量级模板。它是Docker容器的基础,也可以被看作是容器的“快照”。
容器(Container):容器是镜像的可运行实例。容器在隔离的环境中运行,它包含了应用程序及其所需的所有依赖项、库、配置文件等。容器可以被创建、启动、停止、删除等。
Dockerfile:Dockerfile是一个包含创建Docker镜像的指令的文本文件。这些指令包括基本镜像、添加文件、设置环境变量、暴露端口等。
数据卷(Volume):数据卷是Docker容器的持久化存储机制,可以在容器之间共享和重新使用。使用数据卷可以将数据独立于容器的生命周期进行管理。
网络(Networking):Docker支持多种网络模式,例如桥接、主机和覆盖网络等,以满足不同场景下的容器通信需求。
多阶段构建(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
2ENTRYPOINT ["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 | version: "3.8" # 版本号 |
使用流程
常规使用流程
一个Docker从头到尾的常规的使用顺序是
创建Dockerfile,通过Dockerfile构建image
docker build -t 名字:版本号 目录
构建完成后运行镜像,如果需要集成volumes,ports,network,env,cmd还需要一一加载命令。
docker run --name 容器名称
1
2
3
4
5
6docker run -v 执行bind mount
docker run -p ports映射
docker run -e 环境变量设置
docker run --network 绑定网络,注意这个是需要创建一个网络,才能使用
# 创建网络
docker network create 名字
一般到这一个步骤之后就算是完成了。
docker-compose的使用流程
Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。通过使用Docker Compose,您可以使用YAML文件定义应用程序的各个服务、网络和数据卷,然后使用单个命令来创建、启动、停止和重启整个应用程序栈。Docker Compose是一个非常适合在开发、测试和生产环境中部署和管理多容器应用程序的工具。
创建docker-compose.yaml的内容,运行以下命令进行构建并运行
- 构建并运行
docker-compose up -d --build
- 只构建
docker-compose build # 只build,不run
- 构建并运行
关闭命令
docker-compose down# 关闭,但不会删除卷,如果需要删除卷 + '-v'
docker在生产环境使用流程
其实生产环境使用Docker一般情况下就是在常规使用流程的基础上,结合了bind mounts,代码修改后可以直接在Docker上运行。
而部署环境下则尽量不用bind mount这类操作,而是转换为volume或者是database下使用。
docker在部署环境使用流程
- 上面其实讲到的“常规流程”与docker-compose使用流程,其实都是部署流程,但是还有比如说
- CI / CD:依靠自动集成自动部署的方式,使用上会更加方便
- k8s:其实k8s集成了很多能够多机部署以及自动重启等等的内容
docker非常规流程
- 这个是我以前的一个非常不好但很实用的使用流程:
- 直接
docker pull 一个原始镜像
- 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 执行的命令 - 把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生成并挑选过
- 直接
保持Docker镜像简洁:使用精简的基础镜像,如Alpine Linux,并使用多阶段构建来减小镜像大小。这有助于降低部署时间、节省存储空间和提高运行效率。
使用版本控制:为Docker镜像和容器使用版本控制,确保您的环境可以重现。为镜像添加标签,以便于版本追踪和回滚。
利用Dockerfile的缓存机制:Docker在构建镜像时会缓存中间层。将不经常更改的指令放在Dockerfile的前面,以充分利用缓存加快构建速度。
单一职责原则:让每个容器只执行一个任务或服务。这有助于容器的可维护性、可扩展性和可替换性。
使用数据卷管理数据:使用数据卷(Volumes)而不是绑定挂载(Bind mounts)来存储持久化数据。数据卷可以更好地管理数据,同时保持容器的独立性。
通过环境变量进行配置:使用环境变量为容器提供配置信息,而不是在镜像中硬编码配置。这使得容器在不同环境中更易于重用。
使用Docker Compose简化部署:使用Docker Compose编排多容器应用,以便在开发、测试和生产环境中一致地部署和管理应用。
利用Docker的安全特性:限制容器的资源使用、网络访问,并使用Docker Secrets等机制管理敏感数据。
监控和日志:确保收集并监控容器的运行时指标和日志。可以使用像Prometheus、Grafana和ELK Stack这样的工具来分析和可视化这些数据。
学习和使用Docker的最佳实践:关注Docker官方文档、博客和社区,以获取最新的技巧和最佳实践。
保持Docker环境的更新:定期更新Docker引擎、镜像和依赖库,以修复安全漏洞和获取新功能。使用CI/CD:将Docker集成到持续集成/持续部署(CI/CD)流程中,以自动化构建、测试和部署应用。