dockerdocker_0">什么是docker,docker解决了什么问题
docker_2">用docker可以解决什么问题
在日常开发中,我们可能经常面临这样的问题
- 环境一致性问题,同一个程序,可能在开发环境能运行,但是到测试、生产环境就会遇到各种各样的问题,这是因为程序的正常运行需要正确的库和配置,不一定每个服务器都能统一配置。
- 可移植性差,比如我们在A服务器(Ubuntu系统)上部署了一个应用程序,如果要迁移到B服务器(Centos系统),因为操作系统的不同,则部署程序的脚本要重新适配。比如Ubuntu系统安装jdk的命令是
sudo apt install openjdk-11-jdk
,centos就是sudo yum install java-11-openjdk-devel
。 - 库和依赖的冲突,同一个服务器上,部署多个程序,可能程序A依赖python2.x版本的库,而程序B依赖python3.x的库,导致两个程序依赖发生冲突,产生一些不可预估的错误。
- 程序之间相互影响,同一个服务器上,部署多个程序,如果程序A发生故障,耗尽了服务器资源,则程序B也会受到影响。
针对以上问题,我们的解决方案可能有:
-
一个服务器部署一个程序,可以解决上述3、4的问题,但是缺点是成本太。
-
通过虚拟化技术在宿主机上虚拟多个vm,每个vm部署一个程序,也可以解决一定的问题,但是缺点是虚拟机技术需要通过 虚拟化管理程序(Hypervisor) 对计算机底层硬件做虚拟化,并且每个vm都有单独的操作系统,内核,硬件驱动程序,仅为了隔离单个应用程序而启动 VM 会带来很大的开销。
针对以上的问题,docker应用而生,docker也是一种虚拟化技术,但是不对底层硬件做虚拟化,也不用虚拟化整个操作系统,而是只虚拟一个容器,这个容器只包括应用程序所需要库和配置。它运行在宿主机操作系统的用户空间中,作为一个独立的进程存在,然后通过命名空间(Namespace) 技术隔离各个容器的进程,确保它们互不干扰,同时利用控制组(cgroups) 来限制和监控容器的资源使用情况,包括 CPU、内存、块 I/O 等,确保每个容器在资源使用上的隔离与管理。
我们在来总结一些docker的优势吧:
- 轻量级:docker 容器与传统虚拟机相比,启动速度更快,资源占用更少,因为容器共享宿主操作系统的内核,而不需要运行完整的操作系统。
- 快速部署与弹性扩展:docker容器可移植性好,提供了快速构建、部署和扩展应用的能力,使得在需要时可以快速启动新的容器实例。
- 简化的持续集成和持续交付(CI/CD):docker 可以很容易地与 CI/CD 工具集成,简化应用的构建和部署流程。比如我们有一个开发中的应用程序,当我们在本地测试完毕后,可以推送代码到Git仓库,然后触发CI工具(Jenkins等),CI工具就可pull到最新的代码,使用 Dockerfile 文件构建应用程序的 docker 镜像,并触发单元测试和集成测试。如果测试通过,CI 工具就会将构建好的 docker 镜像推送到 docker 镜像仓库,接下来,可以使用 CD 工具(如 Kubernetes、docker Swarm 或其他容器编排工具)自动部署新镜像到生产环境。在生产环境中,CD 工具会拉取最新的 docker 镜像并替换掉现有的应用实例,确保新版本的应用顺利上线。这是虚拟机做不到的。
docker_31">理解docker的几个概念
容器(container)
什么是容器,就是用来存储物品的储存器,那么docker容器也是一样的,只不过docker容器存储的是应用程序运行所需要的所有库、依赖、配置。体现在我们的操作系统里,是一个独立的的进程。容器有以下特点:
- 自包含,容器包含运行需要的一切环境和配置,不依赖宿主机。
- 隔离的,容器独立运行,多个容器是相互隔离的,对其他容器和宿主机没有影响,安全性有保障。
- 独立,删除一个容器不影响其他容器。
- 可移植,由于容器内包含了运行应用所需的所有依赖,可以在任何支持 docker 的平台上运行同一个容器。
容器镜像(image)
我们说容器是一个隔离的进程,那么在这个进程内如何获取文件和配置,我们又如何将这个体现为进程的容器移植或者分享呢。镜像的概念就有了,我们可以将容器打包成一个镜像,这个镜像是一个静态的快照,其中包含容器运行需要的所有文件、库、配置。然后将镜像分发给需要的开发人员,其他开发人员在获得镜像后,就可以通过docker run
在他们得机器上启动一个新的docker容器实例。镜像有以下特点:
- docker 镜像由多个层组成,每一层都是只读的,这些层在镜像创建时就已经固定,无法在运行时进行修改。
- 通过镜像启动一个容器时,docker 会在镜像的最上面创建一个新的可写层。所有对容器的修改(如创建文件、修改文件、安装软件等)都会在这个可写层中进行,而原始的镜像层保持不变。
注册表(registry)
注册表类似于Github,Github用来存储代码,开发者A写完代码可以通过git push
推动到代码仓库,开发者B可以通过git pull
来获取到A提交得最新代码。注册表也是一样的,它可以集中存储和管理容器镜像,开发人员可以通过docker pull <image_name>
从注册表下载镜像,可以通过docker push image_name
将本地的镜像上传到注册表。docker官方提供了一个公共的注册表,我们也可以搭建私有化的注册表。
docker_compose_56">docker compose
通过docker run
可以运行单个容器,但是我们建设一个网站可能需要启动MySql、Redis、Nginx、App等多个服务,如果我们将这些所有的内容都放在一个容器内,耦合性太强,并不是一个最佳实践,最好的方案是每个服务都是一个单独的容器,那现在我们就有4个容器,并且这4个容器的启动需要按照一定的顺序(MySql->Rddis->Nginx->App)进行。当然我们可以使用docker run
一次启动这多个容器,但是docker compose为我们提供了一种更优雅方便的方案,我们可以将所有的容器和配置定义在一个yaml文件中,然后通过docker compose up
来一键启动所有的容器,并且其他开发者也可以根据这个yaml来启动和运行。这是一个docker官网给出的示例yaml:
services:app:image: node:18-alpinecommand: sh -c "yarn install && yarn run dev"ports:- 127.0.0.1:3000:3000working_dir: /appvolumes:- ./:/appenvironment:MYSQL_HOST: mysqlMYSQL_USER: rootMYSQL_PASSWORD: secretMYSQL_DB: todosmysql:image: mysql:8.0volumes:- todo-mysql-data:/var/lib/mysqlenvironment:MYSQL_ROOT_PASSWORD: secretMYSQL_DATABASE: todosvolumes:todo-mysql-data:
docker_88">docker基本架构
docker 使用客户端-服务端架构。主要有客户端(docker clinet)、守护进程(docker daemon)、镜像、容器、注册表等组件。docker 客户端和守护进程可以在同一系统上运行,连接到远程 docker 守护进程,docker 客户端和守护程序使用 REST API、UNIX 套接字或网络接口进行通信。