什么是Docker容器?有什么的特点:轻量,在一台机器上运行的多个Docker容器可以共享这台机器的操作系统内核;它们能够迅速启动,只需占用很少的计算和内存资源。镜像是通过文件系统层进行构造的,并共享一些公共文件。这样就能尽量降低磁盘用量,并能更快地下载镜像。
我们先来看看几个概念。
- Docker在单个容器中运行MySQL之类的应用程序。
这是一个类似于虚拟机的轻量级软件包,包含操作系统,应用程序文件和所有依赖项。 - Web应用程序可能需要几个容器。代码(和runtime),数据库,Web服务器等。
- 从图像启动容器。
本质上,它是一个容器模板,用于在Dockerfile配置中定义操作系统,安装过程,设置等。可以从同一映像启动任意数量的容器。 - 容器以干净(映像)状态启动,因此不会永久存储数据。
可以挂载Docker卷或绑定主机文件夹以保留状态。 - 容器与主机和其他容器隔离。
可以定义网络并打开TCP / IP端口以允许通信。 - 每个容器都通过一个Docker命令启动。
Docker Compose
是一个实用程序,可以使用配置文件一步启动多个容器。docker-compose.yml
- 可选地,编排工具(例如
Docker Swarm
和Kubernetes
)可用于容器管理和生产系统上的复制。
容器
回忆一下如何使用虚拟机(VM)安装Web应用程序及其依赖项。诸如VMware、Parallels Desktop和VirtualBox之类的VM软件被称为管理程序。它们可以创建新的虚拟机,然后使用所需的应用程序堆栈(Web服务器,runtime,数据库等)安装适当的操作系统,如下图为单个虚拟机:
在某些情况下,可能无法在单个VM中安装所有应用程序,因此需要多个VM:
每个VM是在主机OS的仿真硬件上运行的完整OS,可以通过管理程序访问资源(例如网络)。这是相当大的开销,尤其是在依赖性很小的情况下。
Docker在一个单独的容器中启动每个依赖项。它有助于将容器视为具有自己的操作系统,库和应用程序文件的微型VM。
事实上:
- 虚拟机管理程序可仿真硬件,因此可以运行完整的操作系统
- Docker模拟了一个操作系统,因此可以在各自的文件系统中运行独立的应用程序。
因此,Docker使用的主机OS资源少于VM。
从技术上讲,可以在单个容器中运行应用程序的所有依赖项,但是这样做没有任何实际好处,并且管理变得更加困难。因此,应为应用程序,数据库和所需的任何其他依赖项使用单独的容器。
Docker 技术使用 Linux 内核和内核功能(例如 Cgroups 和 namespaces)来分隔进程,以便各进程相互独立运行。这种独立性正是采用容器的目的所在;它可以独立运行多种进程、多个应用,更加充分地发挥基础设施的作用,同时保持各个独立系统的安全性。
容器工具(包括 Docker)可提供基于镜像的部署模式。这使得它能够轻松跨多种环境,与其依赖程序共享应用或服务组。Docker 还可在这一容器环境中自动部署应用(或者合并多种流程,以构建单个应用)。
容器是隔离的
每个运行的容器都是可用的,但是必须公开一个TCP端口才能使用它,例如 localhost
127.0.0.1
Docker还允许访问容器外壳并公开其他端口,以便可以附加调试器查看问题。
容器是无状态且可丢弃的
一旦关闭,写入容器文件系统的数据就会丢失!
可以从同一基本映像启动任何数量的容器(请参见下文)。因为每个容器实例都是相同且可抛弃的,所以这使缩放变得容易。
这可能会改变应用程序开发的方式,特别是如果想在生产服务器上使用Docker。假定应用程序具有一个变量,该变量计算已登录用户的数量。如果它在两个容器中运行,则两个容器都可以处理登录,因此每个容器都有不同的用户数。
因此,Docker化的Web应用程序应避免将状态数据保留在变量和本地文件中。应用程序可以将数据存储在数据库中,例如redis,MySQL或MongoDB,这样状态在容器实例之间保持不变。
如果从一开始就以非无状态方式开发使用Docker容器的现有应用程序,则可能不切实际。但是,在开发期间,仍然可以在Docker容器中运行应用程序。
哪个提出了问题:如果数据库在容器中运行该怎么办?
重新启动时,它也会丢失数据,因此Docker提供了卷和主机文件夹绑定安装。
可能会想:“啊,我可以通过不停止容器来解决状态问题!” 确实如此。假定您的应用程序是100%无错误的。而且您的运行时是100%可靠的。而且操作系统永不崩溃。而且您永远不需要更新主机操作系统或容器本身。
在Linux上运行的容器
所使用的主机操作系统无关紧要:Docker容器在Linux上本地运行。因此,Windows和macOS在Linux VM内运行Docker容器!
Docker的macOS版本需要VirtualBox。
Windows版本的Docker要求:
- Hyper-V的。
Windows 10专业版和企业版免费提供的Microsoft虚拟机管理程序 - 在的Windows子系统为Linux(WSL)2。
Windows 2020年5月更新提供了此工具,它实际上是高度集成的无缝VM,可以安装在所有版本的Windows上。
Windows上的Docker Desktop可让您在两种类型之间切换。
因此,在Linux上运行Docker效率更高,但这在开发PC上几乎没有关系。使用您喜欢的任何操作系统和工具。
但是,如果您使用Docker部署应用程序,则Linux是实时服务器的最佳选择。
映像
Docker映像是具有库和应用程序可执行文件的文件和操作系统的快照。本质上,image是用于创建容器的控制器或模板。(以类似于某些计算机语言的方式,您可以定义可重复使用的 class 模板以实例化相同类型的对象。)
单个镜像可以启动任意数量的容器。尽管在开发过程中不太可能从同一映像启动多个容器,但这允许在生产服务器上进行扩展。
Docker Hubprovides 提供通用的流行的应用映像,如 NGINX、MySQL、MongoDB、Elasticsearch,Redis的等等。
还有针对Node.js,PHP,Python,Ruby,Rust以及您听说过的任何其他语言的运行时映像。
提醒:如果想发布自己的映像,请注册Docker Hub帐户。
Dockerfile
使用Dockerfile
配置映像。它定义:
- 起始基本映像,通常是操作系统
- 工作目录和用户权限
- 所有必要的安装步骤,例如定义环境变量,从主机复制文件,运行安装过程等。
- 容器是否应附加一个或多个卷以进行数据存储
- 容器是否应加入网络以与他人通信
- 主机上公开了哪些端口(如果有) localhost
- 应用程序启动命令。
在某些情况下,将按原样使用Docker Hub中的映像,例如 MySQL。但是,您的应用程序将需要它自己的自定义Dockerfile。
开发和生产Dockerfile
可以为应用程序创建两个Dockerfile配置:
- 一个开发环境
通常,它将激活日志记录,调试和远程访问。例如,在Node.js开发过程中,您可能希望使用Nodemon启动应用程序,以在更改文件时自动重新启动它。 - 一个生产环境
这将以更有效和更安全的模式运行。对于Node.js部署,可能会使用标准的运行时命令。
映像标签
Docker Hub管理Docker映像,而Github则用于Git存储库。
创建的任何映像都可以推送到Docker Hub。很少有开发人员执行此操作,但是对于部署目的或与其他人共享应用程序而言,这可能是实用的。
映像使用Docker Hub ID
进行名称分隔,以确保没有人可以使用相同的名称。他们也有一个标签,所以你可以创建相同的映像,例如多个版本 ,,,等。 1.0
1.1
2.0
latest
/:
例子:
yourname/yourapp:latest
, craigbuckler/myapp:1.0
.
Docker Hub
上的官方映像不需要Docker ID,例如 (假定),,。mysql:latest
mysql
mysql:latest
mysql:5``mysql:8.0.20
volumes
容器在重新启动之间不会保持状态。这通常是件好事; 可以从同一基本映像启动任意数量的容器,并且每个容器都可以处理传入的请求,而不管它们是如何启动或何时启动的(请参阅业务流程)。
但是,某些容器(例如数据库)绝对必须保留数据,因此Docker提供了两种存储机制类型:
- Volumes:由Docker管理的文件系统
- Bind mounts:主机上的文件或目录。
两者都可以在容器上安装目录,例如用于MongoDB存储的目录。 /data/db
建议使用Volumes来保留数据。在某些情况下,它是唯一的选择–例如,MongoDB当前不支持Windows或macOS文件系统上的绑定安装。
但是,绑定安装在开发过程中很实用。主机OS上的应用程序文件夹可以安装在容器中,因此任何文件更改都会触发应用程序重新启动,浏览器刷新等。
网络
任何TCP/IP
端口都可以暴露在容器中,例如MySQL
3306
。这允许主机上的应用程序与localhost:3306
上的数据库系统通信。
另一个容器无法与MySQL通信,因为localhost将解析为它自己。出于这个原因,Docker创建了一个虚拟网络,并为每个正在运行的容器分配一个唯一的IP地址。然后,一个容器就可以使用其地址与另一个容器通信。
不幸的是,Docker IP地址在每次启动一个容器时都可能改变。一个更简单的选择是创建您自己的Docker虚拟网络。任何添加到该网络的容器都可以使用其名称与另一个容器进行通信,例如mysql:3306解析到正确的地址。
容器TCP/IP端口可以暴露:
- 仅在虚拟网络内
- 在虚拟网络和主机之间。
假设你在同一个Docker网络上运行两个容器:
- 一个名为phpapp的容器,它在端口80上公开一个web应用程序
- 一个名为mysql的容器,它在端口3306上公开一个数据库。
在开发期间,您可能希望两个端口都公开给主机。应用程序可以在http://localhost/(端口80是默认)的web浏览器中启动,MySQL客户端可以连接到http://localhost:3306/。
在生产环境中,mysql端口不需要向主机公开。phpapp容器仍然可以与mysql:3306通信,但是肆无忌惮的黑客将不能探测主机上的端口3306。
通过仔细的规划,可以创建复杂的Docker网络来提高安全性,例如,mysql和redis容器可以被phpapp访问,但它们不能互相访问。
Docker Compose
单个Docker命令用于启动单个容器。一个需要Node.js,NGINX和MongoDB容器的应用程序以三个命令启动-可能在三个终端中以正确的顺序执行(可能是MongoDB,然后是Node.js应用程序,然后是NGINX)。
Docker Compose是一个用于管理具有关联volumes和网络的多个容器的工具。单个配置文件,通常命名为docker-compose.yml,定义容器,并可以在必要时覆盖Dockerfile设置。
为开发创建Docker组合配置是很实际的。也可以创建一个用于生产,但是还有更好的选择……
编排
容器是便携式且可复制的。这样,您可以通过在世界另一端的同一服务器,另一台服务器甚至不同的数据中心上启动相同的容器来扩展单个应用程序。
管理,扩展和维护容器的过程称为业务流程。Docker Compose可以用于基本的编排,但是最好使用专业工具,例如:
云主机还提供了自己的编排解决方案,例如AWS Fargate,Microsoft Azure和Google Cloud。这些通常基于Kubernetes,但可能具有自定义选项或工具。
Docker开发策略
您如何使用Docker容器化取决于您自己。
仅将Docker用于开发
Docker用于在开发PC上复制实时服务器的生产环境。可以在具有三个Docker容器的开发环境中模拟具有Node.js,MongoDB和NGINX的生产系统。
在可行的地方使用Docker
生产服务器将Docker用于某些应用程序。Node.js进程将是理想的选择,但是MongoDB数据库可以由云服务提供,而NGINX可以作为负载平衡器安装在主机OS上。
开发PC可以使用三个Docker容器模拟此环境。或者,也许在容器中运行Node.js和NGINX,但是访问同一MongoDB云服务上的测试数据库以消除兼容性问题。
并发处理
Node.js应用程序通常在单个处理线程上运行。运行有16个CPU内核(例如应用程序)的服务器将有15个处于闲置状态!对于其他运行时也是如此,尽管Apache和类似的Web服务器会随着请求的增加而启动其他线程(这有其自身的资源问题)。
Node.js应用程序可以实现群集或使用流程管理器(例如PM2)启动其他线程。但是,在资源允许的情况下,Docker启动和管理多个容器通常更为实用。
使用Docker进行开发和生产
可以在开发和生产中使用几乎相同的Docker容器。可能有必要为每个创建略有不同的启动配置。
更简单的开发和生产
- 应用程序Dockerfile仅配置生产环境。
- 出于开发目的,Docker Compose用于覆盖此基本配置。
因此,无论选择哪种编排或部署选项,都可以在生产服务器上按原样使用映像。
何时不使用Docker
在开发过程中使用Docker的缺点很少。它使您可以在任何PC上安装依赖项并模拟实时系统。您可以轻松地与其他人共享该隔离的环境,同时保留您喜欢的编辑器和工具。
但是,Docker并不是可以解决您所有生产难题的神奇解决方案!在某些情况下,Docker可能不合适。
- 应用程序不是无状态的
如果最初不是为基于容器的部署设计的,则对现有的整体应用程序进行Docker可能会很困难。将状态存储在变量或文件中的程序将需要进行修改以使用其他数据存储。
- 正在使用Windows Server
Docker在Linux上是本机,但是Windows在Hyper-V虚拟机或WSL2(实际上是另一个VM)中运行容器。这是额外的开销,尽管Docker可以让您运行Linux依赖项,但置备Linux服务器可能更有效。
- 性能至关重要
Docker容器已施加CPU和RAM限制。这些是可配置的,但是在主机OS上运行的应用程序始终会更快。
也就是说,如果您的应用程序通常在单个CPU内核上运行,则Docker可以通过水平扩展来实现并行处理。
- 稳定性很重要
Docker已经成熟,但它是安装,更新和管理的另一个依赖项。您是否拥有内部容器管理专业知识?
由于容器可以缩放并自动重新启动,因此您的应用程序似乎更健壮。这并不意味着它崩溃的频率不会比以前少!
- 存储关键任务数据
卷和绑定装载可以存储持久性数据,但是与标准文件系统选项相比,它们更难以管理和备份。
- 为了提高安全性
容器是隔离的,但是与真实的VM不同,容器没有从主机OS完全沙盒化。Docker提供了用于隐藏依赖项的选项,但它不能替代强大的安全性。
- 创建GUI应用程序
某个地方的人将使用容器创建一个跨平台的图形界面应用程序。但这并不是Docker理想的解决方案!