文章目录
- 一、Docker:容器化应用的基石
- 1.1 环境
- 1.2 Docker 是什么
- 1.3 Docker镜像
- 1.3.1 基础镜像(Base Image)
- 1.3.2 Dockerfile
- 1.3.3 容器镜像(Container Image)
- 1.4 Registry
- 1.5 容器
- 1.6 Docker VS 虚拟机
- 二、Docker 的架构原理
- 2.1 C/S软件架构
- 2.2 docker 命令
- 2.2.1 docker build
- 2.2.2 docker pull/push
- 2.2.3 docker run
- 三、Docker部署工具
- 3.1 Docker Compose :多容器部署
- 3.2 Docker Swarm :集群部署
- 3.3 Kubernetes :开源的容器编排平台
- 四、总结
- 全文参考《Docker 是什么?》
- golang全栈指南:
一、Docker:容器化应用的基石
1.1 环境
我们经常能听到程序员说"这个程序在我环境里明明是好的啊,怎么到你这就不行了呢"?注意这里的关键词,程序和环境。程序是跑在操作系统上的,而操作系统上又装了各种不同版本的依赖库和配置,这些被程序所依赖的信息,我们统称为"环境"。
作为一个程序员,如果你想安装一个 vim
文本编辑器,在不同环境里你得执行不同的命令。在 ubuntu,你需要执行 apt-get install vim
,在 centos 里,你需要执行 yum install vim
。装个小软件尚且如此,要是你想将自己写的代码部署到各个不同操作系统的服务器上,那依赖的软件和配置就更多了,需要针对每个环境单独写一套部署脚本,太麻烦了。
1.2 Docker 是什么
Docker 是一种开源的容器化平台,它允许开发者将应用程序及其依赖的环境打包到一个独立的容器中,作为代码和操作系统之间的中间层。
Docker 有三大核心组件,分别是镜像(Image)、容器(Container)和仓库(Repository):
- Docker 镜像:是一个只读的模板,用于创建 Docker 容器。它包含了容器运行所需的代码、运行时环境、库、环境变量和配置文件等。
- 容器:镜像的可写运行实例,它包含了运行应用程序所需要的一切,包括代码、运行时、系统工具、系统库等。容器通过镜像创建,可以被启动、停止、删除等。
- Docker 仓库:存储和分发镜像的场所,分为公共仓库(Docker Hub)和私有仓库。
1.3 Docker镜像
1.3.1 基础镜像(Base Image)
容器是一个轻量级、可移植的执行环境,它与宿主机共享内核,但拥有独立的用户空间。通过 Docker,开发者可以在不同的操作系统和环境中一致地部署和运行应用程序,从而解决了“在我的机器上可以运行”的问题。
既然上面提到环境不同,会导致程序运行结果不同,那么我们首先要做的最重要的事情,就是统一环境。而环境中,最最重要的就是操作系统。比如 centos 还是 ubuntu,我们得选一个,让所有程序都跑在同一个操作系统上。操作系统分为用户空间和内核空间,应用程序运行在用户空间。因此,我们可以阉割操作系统,只需要利用操作系统的用户空间部分,就能构建出应用所需的环境。
其次就是统一程序语言依赖,比如要跑 python 应用,你得装个 python 解释器,要跑个 java 应用,得装个 JVM,要跑 go 应用,那就。。什么都不需要装。选中一个基础操作系统和语言后,我们将它们对应的文件系统,依赖库,配置等放一起打包成一个类似压缩包的文件,这就是所谓的基础镜像(Base Image)。
1.3.2 Dockerfile
Dockerfile 是一个文本文件,它包含了一系列指令,定义了如何构建容器镜像。
有了基础镜像之后还不够,我们经常还需要安装一些依赖,比如yum install gcc
,甚至还要创建一些文件夹。最后才是运行我们的目标应用程序。
Linux 中,所有工作都可以通过命令行完成,所以我们可以将要做的事情以命令行的形式一行行列出来。就像一份 todo list。意思是要求在基础镜像的基础上按着 todo list 挨个执行命令。这份 todo list 长下面这样。
# 指定基础镜像
FROM python:3.9# 设置工作目录
WORKDIR /app# 复制依赖文件到容器中
COPY requirements.txt .RUN yum install gcc
# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt# 将当前目录下的所有文件复制到容器的 /app 目录下
COPY . /app# 设置容器启动时执行的命令
CMD ["python", "app.py"]
具体含义是,基于一个装了 python3.9 解释器的操作系统(基础镜像),再执行 pip install 等命令安装其他依赖,从而构建出一个适合程序运行的环境,最后用
python app.py
运行我们的目标应用程序。
像这样一份列清楚了,从操作系统到应用服务启动,需要做哪些事情的清单文件(todo list),就是所谓的 Dockerfile。通过 Dockerfile,开发者可以清晰地描述应用程序的构建过程,确保每次构建的镜像都是一致的。
1.3.3 容器镜像(Container Image)
Dockerfile 只是描述了要做哪些事情,并没有真正开始做。当我们用命令行执行 docker build 的时候,Docker 软件就会按着 Dockerfile 的说明,一行行构建环境+应用程序。最终将这个环境+程序,打包成一个类似"压缩包"的东西,我们叫它容器镜像(container image)。
只要将容器镜像传到任意一台服务器上,对这个"压缩包"执行"解压缩",我们就能同时运行环境和程序。太完美了!但是现在还有个问题,怎么将容器镜像传到那么多服务器上呢?
1.4 Registry
服务器那么多,挨个将容器镜像传过去也不是不行,就是将压力全给到发送方的网络带宽了。有没有更好的解决方案?有。可以参考 github
代码仓库 的做法,我们通常会使用 git push
将代码传到 github,有需要的人自己通过 git pull
的方式将代码从 github 拉到自己的机器上。
那 Docker 也一样,弄一个镜像仓库,通过 docker push 将镜像推到仓库,有需要的时候再通过 docker pull 将镜像拉到机器上。这个负责管理镜像仓库推拉能力的服务,就叫 Docker Registry。
基于 Docker Registry 的能力,我们可以搭建各种官方或私人镜像仓库,比如官方的叫 DockerHub,非官方的有清华大学的 Tuna 等等,一般公司内部也会有自己的镜像仓库。
1.5 容器
现在,我们解决了服务器间传输容器镜像的问题。我们可以跑到目的服务器上,执行 docker pull 拿到容器镜像。然后执行 docker run 命令,将这个类似"压缩包"的容器镜像给"解压缩",获得一个独立的环境和应用程序并运行起来。这样一个独立的环境和应用程序,就是所谓的容器(container)。我们可以在一个操作系统上同时跑多个容器。且这些容器之间都是互相独立,互相隔离的。
- 隔离性 :容器之间相互隔离,每个容器都有自己独立的文件系统、进程空间和网络空间,不会互相干扰。这保证了应用程序在容器中运行的稳定性和安全性。
- 轻量化 :容器共享宿主机的内核,不需要像虚拟机那样虚拟出一整个硬件环境,因此容器的启动速度非常快,通常只需要几秒钟,并且占用的资源也相对较少。
- 可移植性 :由于容器是基于镜像运行的,而镜像在不同的环境(如开发、测试、生产环境)中都可以保持一致,因此容器可以在任何安装了 Docker 的机器上运行,具有很强的可移植性。
1.6 Docker VS 虚拟机
容器看起来很像我们用 vmware 或 kvm 整出来的传统虚拟机,但不同的是,传统虚拟机自带一个完整操作系统,而容器本身不带完整操作系统。
容器的基础镜像实际上只包含了操作系统的核心依赖库和配置文件等必要组件,它利用一个叫 Namespace 的能力让它看起来就像是一个独立操作系统一样,再利用一个叫 Cgroup 的能力限制它能使用的计算资源。所以说,容器本质上只是个自带独立运行环境的特殊进程,底层用的其实是宿主机的操作系统内核。
二、Docker 的架构原理
2.1 C/S软件架构
现在,我们回到日常使用场景中,聊聊 Docker 的架构原理。它是经典的 Client/Server
架构。Client
对应 Docker-cli
, Server
对应 Docker daemon
。我们在命令行里敲 Docker 命令,使用的就是 Docker-cli.
Docker-cli
会解析我们输入的 cmd 命令,然后调用 Docker daemon
守护进程提供的 RESTful API,守护进程收到命令后,会根据指令创建和管理各个容器。再具体点,Docker Daemon
内部分为 Docker Server,Engine
两层。
Docker Server
:本质上就是个 HTTP 服务,负责对外提供操作容器和镜像的 api 接口,接收到 API 请求后,会分发任务给Engine
层Engine
层:负责创建Job
,由Job
实际执行各种工作。不同的 Docker 命令会执行不同类型的 Job 任务。
2.2 docker 命令
2.2.1 docker build
如果你执行的是 docker build
命令,Job 则会根据 Dockerfile 指令,像包洋葱皮似的一层层构建容器镜像文件。
2.2.2 docker pull/push
如果你执行的是 docker pull
或 push
之类的镜像推拉操作,Job 则会跟外部的 Docker Registry
交互,将镜像上传或下载。
2.2.3 docker run
如果你执行的是 docker run
命令,Job 就会基于镜像文件调用 containerd 组件,驱使 runC 组件创建和运行容器。
现在我们再回过头来看这句话,Docker 本质上就是一个将程序和环境打包并运行的工具软件。具体点来说就是,它通过 Dockerfile 描述环境和应用程序的依赖关系, docker build 构建镜像, docker pull/push 跟 Docker Registry 交互实现存储和分发镜像,docker run 命令基于镜像启动容器,基于容器技术运行程序和它对应的环境,从而解决环境依赖导致的各种问题。
好了,到这里,我们就了解了 Docker 的架构和基本运行原理了。接下来,我们再来聊聊跟 Docker 相关的几个周边。
三、Docker部署工具
3.1 Docker Compose :多容器部署
我们现在知道了 Docker 容器 本身只是一个特殊进程,但如果我想要部署多个容器,且对这些容器的顺序有一定要求呢?比如一个博客系统,当然是先启动数据库,再启动身份验证服务,最后才能启动博客 web 服务。
按理说挨个执行 docker run 命令当然是没问题的,但有没有更优雅的解决方案?有。我们可以通过一个 YAML 文件写清楚要部署的容器有哪些,部署顺序是怎么样的,以及这些容器占用的 cpu 和内存等信息。
version: "3.8"services:A:image: "some-image-for-a"deploy:resources:limits:cpus: "0.50" # 限制 CPU 使用率为 50%memory: 256M # 限制内存使用量为 256MBB:image: "some-image-for-b"depends_on:- AC:image: "some-image-for-c"depends_on:- B
然后,通过一行Docker-compose up
命令,开始解析 YAML 文件,将容器们一键按顺序部署,就完成一整套服务的部署。这其实就是 Docker Compose 干的事情。Docker Compose 使得多容器应用的部署变得简单高效,特别适合开发和测试环境。
3.2 Docker Swarm :集群部署
Docker
:解决的是一个容器的部署。Docker Compose
:解决的是多个容器组成的一整套服务的部署。Docker Swarm
:解决的是这一整套服务在多台服务器上的集群部署问题。
Docker Swarm 是 Docker 官方提供的容器编排工具,用于在多台主机上管理和部署容器集群。它允许开发者将多个 Docker 主机组成一个虚拟的 Docker 环境,从而实现容器的高可用性、弹性伸缩和负载均衡。
在 Docker Swarm 中,容器可以自动在不同的主机之间迁移,当某个主机出现故障时,其他主机可以接管其上的容器,确保应用程序的持续运行。此外,Swarm 还支持服务的扩缩容,可以根据业务需求动态调整容器的数量。
3.3 Kubernetes :开源的容器编排平台
Kubernetes(通常简称为 k8s)是一个开源的容器编排平台,它与 Docker Swarm 的目标类似,都是用于管理和部署容器集群。
-
Docker 是 Kubernetes 的运行时基础
在 Kubernetes 中,容器是应用程序的基本运行单元,而 Docker 容器是 Kubernetes 支持的主要容器运行时之一(除了支持 Docker 的容器外,还支持别人家的容器)。Docker 提供了容器的隔离、打包和分发机制,而 Kubernetes 则在此基础上提供了更高级的编排功能,如服务发现、负载均衡、自动扩缩容等。 -
Pod 与 Docker 容器
Kubernetes 的核心概念是 Pod,Pod 是 Kubernetes 中最小的部署单元,它封装了一个或多个紧密相关的容器。在 Kubernetes 中,一个 Pod 中的容器共享相同的网络命名空间、存储卷等资源,它们可以像一个整体一样被调度和管理。从某种意义上说,Pod 可以被视为一个“超级容器”,它将多个 Docker 容器组(本质上就是一个服务进程)合在一起,形成一个逻辑单元。Docker 容器是 Pod 的组成部分,而 Pod 是 Kubernetes 编排的基本对象。
k8s会在多台 Node 服务器上调度 Pod,进行部署和扩缩容。每个 Pod 内部可以含有多个 container -
Kubernetes 的编排功能
Kubernetes 提供了强大的容器编排功能,它通过一系列的控制器(如 Deployment、StatefulSet、DaemonSet 等)来管理 Pod 的生命周期。这些控制器可以根据预定义的策略自动创建、更新、删除 Pod,并确保应用程序的高可用性和一致性。此外,Kubernetes 还提供了服务发现和负载均衡机制,通过定义 Service 对象,可以将 Pod 暴露为一个网络服务,客户端可以通过 Service 的虚拟 IP 地址访问 Pod 提供的服务。Kubernetes 的自动扩缩容功能可以根据业务负载动态调整 Pod 的数量,从而实现资源的高效利用。 -
对比Docker Compose
Docker Compose 基于多个 container 创建的一整套服务,其实就是 k8s 里的 pod。而 Docker Swarm 做的事情和 k8s 一样,本质上就是在调度 pod。k8s 的官方定义,叫容器编排引擎,将它理解为,以 API 编程的方式管理安排各个容器的引擎。
现在,我们再>回过头来看下 Docker 的图标,是一个个集装箱,放在一艘船上,这一个个集装箱指的就是互相隔离的容器,而 k8s 的图标,则是一个轮船上的方向盘,意思是 k8s 控制着轮船的航向,其实指的就是调度容器。这波联想就非常形象了,现在大家通了吗?
四、总结
-
Docker 本质上就是一个将程序和环境打包并运行的工具软件,而 Docker 容器本质上只是个自带独立运行环境的特殊进程,底层用的其实是宿主机的操作系统内核。
-
Docker 软件 通过
Dockerfile
描述环境和应用程序的依赖关系,docker build
构建镜像,docker pull/push
跟Docker Registry
交互实现存储和分发镜像,docker run
命令基于镜像启动容器,基于容器技术运行程序和它对应的环境,从而解决环境依赖导致的各种问题。 -
Docker 解决的是一个容器的部署问题,
Docker Compose
解决的是多个容器组成的一套服务的部署问题,Docker Swarm
解决的是多个容器组成的一套服务在多台服务器上的部署问题,k8s
则是Docker Swarm
的竞品,在更高维度上兼容了 Docker 容器,实现了容器编排调度。
在现代的云原生架构中,Docker 和 Kubernetes 已成为不可或缺的技术,它们为开发和运维团队提供了强大的工具,使得应用程序的开发、部署和管理变得更加高效和可靠。