Docker
Docker
简介
Docker 是一种轻量级的容器化平台,用于将应用程序和它们的依赖项打包到可移植的容器中,以便在任何地方都可以轻松部署和运行。Docker 技术提供了一种在容器中封装应用程序的方法,使得应用程序可以在任何环境中以相同的方式运行,而无需担心环境差异和依赖项的问题。
Docker架构
概念 | 说明 |
---|---|
Docker镜像(Images) | Docker 镜像是一个只读的模板,用于创建 Docker 容器。它包含了运行应用程序所需的所有代码、运行时库、依赖项和配置文件。可以将 Docker 镜像看作是容器的静态快照。 |
Docker容器(Container) | Docker 容器是 Docker 镜像的运行实例,它包含了运行应用程序所需的所有内容,包括代码、运行时库、环境变量和文件系统。Docker 容器可以被启动、停止、删除、暂停和恢复等操作。 |
Docker客户端 (Client) | Docker 客户端是与 Docker 引擎交互的命令行工具或图形界面。它允许用户通过命令或界面与 Docker 守护进程进行通信,例如构建镜像、创建容器、管理容器等。 |
Docker主机(Host) | Docker 主机是安装了 Docker 引擎(Docker Engine)的物理计算机或虚拟机。它负责运行 Docker 容器,并提供了容器运行时环境。 |
Docker Registry | Docker Registry 是存储 Docker 镜像的仓库服务,用户可以从 Docker Registry 中获取镜像,并将自己的镜像推送到 Registry 中。Docker Hub 是一个公共的 Docker Registry,用户也可以搭建私有的 Docker Registry。 |
Namespaces
命名空间 (namespaces) 是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。在日常使用 Linux 或者 macOS 时,我们并没有运行多个完全分离的服务器的需要,但是如果我们在服务器上启动了多个服务,这些服务其实会相互影响的,每一个服务都能看到其他服务的进程,也可以访问宿主机器上的任意文件,这是很多时候我们都不愿意看到的,我们更希望运行在同一台机器上的不同服务能做到完全隔离,就像运行在多台不同的机器上一样。
在这种情况下,一旦服务器上的某一个服务被入侵,那么入侵者就能够访问当前机器上的所有服务和文件,这也是我们不想看到的,而 Docker 其实就通过 Linux 的 Namespaces 对不同的容器实现了隔离。
进程
进程是 Linux 以及现在操作系统中非常重要的概念,它表示一个正在执行的程序,也是在现代分时系统中的一个任务单元。在每一个 *nix 的操作系统上,我们都能够通过 ps 命令打印出当前操作系统中正在执行的进程,比如在 Ubuntu 上,使用该命令就能得到以下的结果。
如果我们在当前的 Linux 操作系统下运行一个新的 Docker 容器,并通过 exec 进入其内部的 bash 并打印其中的全部进程,我们会得到以下的结果
在新的容器内部执行 ps 命令打印出了非常干净的进程列表,只有包含当前 ps -ef 在内的三个进程,在宿主机器上的几十个进程都已经消失不见。
在容器内,pid=1 的进程通常是容器的主进程,也称为 init 进程。这个进程负责启动容器内的其他所有进程,并且在容器退出时负责清理和回收资源。在 Docker 容器中,通常情况下,pid=1 的进程就是应用程序的启动命令,比如一个 Web 服务器或者一个后台服务的启动命令。
网络
如果 Docker 的容器通过 Linux 的命名空间完成了与宿主机进程的网络隔离,但是却又没有办法通过宿主机的网络与整个互联网相连,就会产生很多限制,所以 Docker 虽然可以通过命名空间创建一个隔离的网络环境,但是 Docker 中的服务仍然需要与外界相连才能发挥作用。
每一个使用 docker run 启动的容器其实都具有单独的网络命名空间,Docker 为我们提供了四种不同的网络模式,Host、Container、None 和 Bridge 模式
默认网桥模式(Bridge),在这种模式下,除了分配隔离的网络命名空间之外,Docker 还会为所有的容器设置 IP 地址。当 Docker 服务器在主机上启动之后会创建新的虚拟网桥 docker0,随后在该主机上启动的全部服务在默认情况下都与该网桥相连
CGroups
我们通过 Linux 的命名空间为新创建的进程隔离了文件系统、网络并与宿主机器之间的进程相互隔离,但是命名空间并不能够为我们提供物理资源上的隔离,比如 CPU 或者内存,如果在同一台机器上运行了多个对彼此以及宿主机器一无所知的『容器』,这些容器却共同占用了宿主机器的物理资源。
如果其中的某一个容器正在执行 CPU 密集型的任务,那么就会影响其他容器中任务的性能与执行效率,导致多个容器相互影响并且抢占资源。如何对多个容器的资源使用进行限制就成了解决进程虚拟资源隔离之后的主要问题,而 Control Groups(简称 CGroups)就是能够隔离宿主机器上的物理资源,例如 CPU、内存、磁盘 I/O 和网络带宽。
Linux 使用文件系统来实现 CGroup,我们可以直接使用下面的命令查看当前的 CGroup 中有哪些子系统
如果我们想要创建一个新的 cgroup 只需要在想要分配或者限制资源的子系统下面创建一个新的文件夹,然后这个文件夹下就会自动出现很多的内容,如果你在 Linux 上安装了 Docker,你就会发现所有子系统的目录下都有一个名为 docker 的文件夹
9c3057xxx 其实就是我们运行的一个 Docker 容器,启动这个容器时,Docker 会为这个容器创建一个与容器标识符相同的 CGroup,在当前的主机上 CGroup 就会有以下的层级关系
每一个 CGroup 下面都有一个 tasks 文件,其中存储着属于当前控制组的所有进程的 pid。
存储卷
Docker的存储卷称之为volume,本质上容器上的一个或者多个目录,而这些目录绕过了联合文件系统,与宿主机中的目录或者其他容器目录进行了绑定关系,这种绑定关系可以看作Linux的mount操作,当容器中的程序对这些目录写入数据时,其实写入到的是与之绑定的宿主机目录上,这样就实现了数据的存储功能。
默认情况下,容器不使用任何 volume时,容器的数据被保存在容器之内,它只在容器的生命周期内存在,会随着容器的删除而被删除,而想要持久化的存储这些数据,就得使用存储卷。
保存容器中的数据也可以使用 docker commit 命令将容器提交为一个新的镜像,这个镜像中会保存容器运行时的所有数据。但此种方法非常不推荐,因为这样的镜像通常会很大,镜像拉取以及运行容器都会变慢。当容器使用了存储卷,即使容器被删除了,但是与绑定的存储卷还在,对应目录的数据都会保存,如果想要恢复该容器,只要新建的容器绑定该存储卷,对应目录的数据也会随之恢复。
volume存储卷由 Docker 创建和管理,我们可以使用该docker volume create命令显式的创建卷,或者在容器创建时创建卷。
# 创建一个名为 myvolume 的存储卷
docker volume create myvolume
# 将存储卷 myvolume 挂载到容器的 /data 目录(挂载卷不存在会自动创建)
docker run -v myvolume:/data mycontainer
可以看到挂载点处于docker的根目录/var/lib/docker/volumes下
镜像
Docker 中的每一个镜像都是由一系列只读的层组成的,Dockerfile 中的每一个命令都会在已有的只读层上创建一个新的层。
容器中的每一层都只对当前容器进行了非常小的修改,上述的 Dockerfile 文件会构建一个拥有四层 layer 的镜像。
当镜像被 docker run 命令创建时就会在镜像的最上层添加一个可写的层,也就是容器层,所有对于运行时容器的修改其实都是对这个容器读写层的修改。
容器和镜像的区别就在于,所有的镜像都是只读的,而每一个容器其实等于镜像加上一个可读写的层,也就是同一个镜像可以对应多个容器。
Docker-compose
Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。
Docker-Compose将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)。Docker-Compose运行目录下的所有文件(docker-compose.yml,extends文件或环境变量文件等)组成一个工程,若无特殊指定工程名即为当前目录名。一个工程当中可包含多个服务,每个服务中定义了容器运行的镜像,参数,依赖。
一个服务当中可包括多个容器实例,Docker-Compose并没有解决负载均衡的问题,因此需要借助其它工具实现服务发现及负载均衡。 Docker-Compose的工程配置文件默认为docker-compose.yml,可通过环境变量COMPOSE_FILE或-f参数自定义配置文件,其定义了多个有依赖关系的服务及每个服务运行的容器。
使用一个Dockerfile模板文件,可以让用户很方便的定义一个单独的应用容器。在工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个Web项目,除了Web服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。 Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
Docker-Compose项目由Python编写,调用Docker服务提供的API来对容器进行管理。因此,只要所操作的平台支持Docker API,就可以在其上利用Compose来进行编排管理。
下面为nginx和mysql服务的docker-compose.yml配置文件示例;
version: '3.8'
services:
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
networks:
my_network:
ipv4_address: 172.18.0.10
mysql:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: example
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
networks:
my_network:
ipv4_address: 172.18.0.11
networks:
my_network:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
Docker常用命令
以下是一些常用的 Docker 命令:
- 镜像管理:
docker images
: 列出本地所有的镜像。docker pull <image_name>
: 拉取指定镜像。docker rmi <image_name>
: 删除指定镜像。
- 容器管理:
docker ps
: 列出正在运行的容器。docker ps -a
: 列出所有容器,包括停止的。docker run <image_name>
: 运行指定镜像创建容器。docker start <container_id>
: 启动指定的容器。docker stop <container_id>
: 停止指定的容器。docker rm <container_id>
: 删除指定的容器。
- 日志和状态:
docker logs <container_id>
: 查看容器的日志。docker stats <container_id>
: 查看容器的资源使用情况。
- 网络:
docker network ls
: 列出所有的 Docker 网络。docker network inspect <network_id>
: 查看指定网络的详细信息。
- 数据管理:
docker volume ls
: 列出所有 Docker 数据卷。docker volume create <volume_name>
: 创建一个新的数据卷。docker volume rm <volume_name>
: 删除指定的数据卷。
- 其他常用命令:
docker version
: 显示 Docker 版本信息。docker info
: 显示 Docker 系统信息。docker exec -it <container_id> <command>
: 在运行中的容器内执行命令。
Docker-compose常用命令
以下是一些常用的 Docker Compose 命令:
- 启动和停止服务:
docker-compose up
: 启动 Docker Compose 文件定义的所有服务。docker-compose up -d
: 后台启动 Docker Compose 文件定义的所有服务。docker-compose down
: 停止 Docker Compose 文件定义的所有服务并删除相关的容器。
- 管理服务:
docker-compose start <service_name>
: 启动指定的服务。docker-compose stop <service_name>
: 停止指定的服务。docker-compose restart <service_name>
: 重启指定的服务。
- 查看服务状态:
docker-compose ps
: 显示 Docker Compose 文件定义的所有服务的状态。
- 日志和状态:
docker-compose logs <service_name>
: 查看指定服务的日志。docker-compose logs -f <service_name>
: 实时跟踪指定服务的日志输出。
- 构建服务:
docker-compose build <service_name>
: 构建指定的服务。
- 其他常用命令:
docker-compose config
: 检查 Docker Compose 文件的配置是否正确。docker-compose exec <service_name> <command>
: 在运行中的容器内执行命令。docker-compose pull
: 拉取 Docker Compose 文件定义的所有服务的镜像。