- A+
1.docker发展历史
1979年:Unix V7
这个年代,计算资源匮乏,想要通过快速销毁和重建基础设施来解决测试环境污染问题变得几乎不可能。为隔离出可供软件进行构建和测试的环境,chroot(change root)系统调用程序横空出现。
在1979年Unix V7的开发过程中,正式引入chroot系统调用,为每个进程提供一个独立的磁盘空间,将一个进程及其子进程的根目录改变到文件系统中的新位置,让这些进程只能访问到该目录。这个被隔离出来的新环境被叫做 Chroot Jail。这标志着进程隔离的开始,隔离每个进程的文件访问权限。
2000年:FreeBSD Jails
2000年,FreeBSD操作系统正式发布FreeBSD jails隔离环境,真正意义上实现进程的沙箱化。这为文件系统、用户、网络等隔离增加了进程沙盒功能,实现了客户服务之间的隔离和管理。
据悉,这种沙箱的实现,依靠操作系统级别的隔离与限制能力而非硬件虚拟化技术。FreeBSD Jails允许管理员将FreeBSD计算机系统划分为几个独立的、较小的系统,称为“ jails”,并能为每个系统和配置分配IP地址,可以对软件的安装和配置进行定制。
2001年:LinuxVServer
与FreeBSD Jails一样,Linux VServer也是采取一种类似的上述Jails机制,它可以对计算机系统上的资源(文件系统、网络地址、内存)进行分区。每个所划分的区域叫做一个安全上下文(security context),其中的虚拟系统叫做虚拟私有服务器(virtual private server,VPS)。该操作系统虚拟化于2001年推出,通过修补Linux内核来实现,测试性补丁目前仍然可用,但最后一个稳定的修补程序是2006年发布。
2004年:Solaris容器
2004年2月,Oracle发布Oracle Solaris Containers,这是一个用于X86和SPARC处理器的Linux-Vserver版本。Solaris Container 是由系统资源控制和通过 zones 提供的边界分离(boundary separation)所组合而成的。zones 是一个单一操作系统实例中的完全隔离的虚拟服务器。
2005年:Open VZ(Open Virtuzzo)
这是Linux操作系统级虚拟化技术,它通过Linux内核补丁形式进行虚拟化、隔离、资源管理和状态检查。
操作系统级虚拟化有一些限制,因为容器共享相同的体系结构和内核版本,当客户需要不同于主机的内核版本情况下,这种缺点就会显现出来。该代码未作为正式Linux内核的一部分发布。每个 OpenVZ 容器都有一套隔离的文件系统、用户、用户组、进程树、网络、设备和 IPC 对象。
2006年:Process Containers
Process Containers(由Google在2006年推出)旨在用于限制、计算和隔离一系列流程的资源使用(CPU、内存、磁盘I / O、网络)。
一年后,为了避免和 Linux 内核上下文中的“容器”一词混淆而改名为 ControlGroups简称Cgroups,并最终合并到Linux内核2.6.24中。
这也可以说明 Google 很早就参与了容器技术的开发。
2008年:LXC
Linux容器(LXC)是第一个、最完整的Linux容器管理器的实现方案。2008年,通过将 Cgroups 的资源管理能力和 Linux Namespace 的视图隔离能力组合在一起,LXC完整的容器技术出现在Linux 内核中,并且可以在单个Linux内核上运行而无需任何补丁。
LXC 存在于 liblxc 库中,提供各种编程语言的 API 实现,包括 Python3、Python2、Lua、Go、Ruby 和 Haskell。现在 LXC project 由 Canonical 公司赞助并托管的。
2011年:Warden
Warden由CloudFoundry在2011年成立,这是一个管理隔离、短暂存在和被资源控制的环境的API。在其第一个版本中,Warden使用LXC,之后替换为他们自己的实现方案。
不像 LXC,Warden 并不紧密耦合到 Linux 上,可以为任何系统提供隔离运行环境。Warden以后台保护程序运行,而且能提供用于容器管理的API。它开发了一个CS(客户端-服务端)模型来管理跨多个主机的容器集群,并且Warden提供用于管理cgroup、名称空间和进程生命周期的相关服务。
2013年:LMCTFY
LMCTFY 是2013年Google容器技术的开源版本,它提供Linux应用程序容器,旨在提供性能可保证的、高资源利用率的、资源共享的、可超售的、接近零消耗的容器。
2015年,Google开始向由Docker发起的Libcontainer贡献LMCTFY核心概念后,LMCTFY在2015年主动停止部署,Libcontainer现在是Open Container Foundation(开放容器基金会)的一部分。
2013年:Docker
2013年,随着Docker的出现,容器开始迅速普及。
它最初是一个叫做 dotCloud 的 PaaS 服务公司的内部项目,后来该公司改名为 Docker。Docker的迅速普及并非偶然,它引入了一整套管理容器的生态系统,包括高效、分层的容器镜像模型、全局和本地的容器注册库、清晰的REST API、命令行等。 与Warden一样,Docker最初阶段使用的也是LXC,后来用自己的库libcontainer进行替换。Docker 推动实现了一个叫做 Docker Swarm 的容器集群管理方案
2014年:Rocket
Rocket 是由 CoreOS 所启动的项目,类似于 Docker,但是其修复了一些 Docker 中发现的问题。
CoreOS的初衷是旨在提供一个比 Docker 更严格的安全性和产品需求。更重要的是,它是在一个更加开放的标准 AppContainer 规范上实现的。在 Rocket 之外,CoreOS也开发了其它几个可用于 Docker 和 Kubernetes容器相关的产品,例如,CoreOS 操作系统、etcd 和flannel。
2016年:Windows Containers
2015 年,微软在 Windows Server 上为基于 Windows 的应用添加了容器支持,称之为 Windows Containers。它与 Windows Server 2016 一同发布,Docker 可以原生地在 Windows 上运行 Docker 容器,而不需要启动一个虚拟机来运行 Docker( Windows 上早期运行 Docker 需要使用 Linux 虚拟机)。
2017年:容器工具日趋成熟
在2017年以前,市场上已经有上百种工具用来管理容器,这些类型的工具已存在多年。
但是,2017年许多工具脱颖而出,最知名的是Kubernetes。自从2016年被纳入CNCF以来,VMWare、Azure、AWS甚至Docker都宣布在其基础架构上提供相关支持。
随着容器市场的发展,一些工具已经开始定义容器的某些功能。Ceph和REX-Ray为容器存储设定了标准,在CI / CD中,Jenkins完全改变了构建和部署应用程序的方式。
2017年,CoreOS和Docker联合提议将rkt和containerd作为新项目纳入CNCF,这标志着容器生态系统初步形成,容器项目之间协作更加丰富。
从 Docker 最初宣布将剥离其核心运行时到2017年捐赠给CNCF 协会,“containerd”项目在过去两年经历显著增长。Docker捐赠的主要目的是通过提供一个核心容器运行时来促进容器生态系统的进一步创新,容器系统供应商和编排项目(如 Kubernetes、Swarm 等)可以利用这个核心容器运行时。
“containerd”的一个重要设计原则是可以对 Kubernetes 提供一流支持,但又不完全依赖于 Kubernetes,这也为许多容器的用例打开新大门,如 developer desktop、CI/CD、单节点部署、edge 和物联网等。
2018年:规范化向前发展
容器化成为现代软件基础架构的基础。众所周知,Kubernetes也被用于大多数企业容器项目。
2018年,GitHub上的Kubernetes项目有27000多个Star,1500多个贡献者,成为最重要的开源社区之一。
Kubernetes的广泛采用推动了诸如AWS云供应商提供托管的Kubernetes服务。
此外,VMWare、RedHat和Rancher等领先的软件供应商也开始提供基于Kubernetes的管理平台。
2019年:历史变革
2019年是容器发生历史性变革的一年。
这一年发生许多历史性变革事件,包括容器生态变化、产业资本并购和出现新技术解决方案等。
在2019年,新的运行时引擎开始替代docker运行引擎,其最具代表性的新引擎就是CNCF的Containerd和CRI-O(一个用于Kubernetes的轻量级运行时)。CRI-O能让用户直接从 Kubernetes 运行容器,而无需任何不必要的代码或工具。只要容器符合 OCI 标准,CRI-O 就可以运行它。
在2019年,产业方面也发送巨大变化,DockerEnterprise卖给Mirantis(一家专注于OpenStack、Kubernetes的云计算公司),可以预见的是Docker Swarm将逐步被淘汰。
同时,虽然rkt已经正式成为CNCF一部分,但是其普及率正在、逐步下降。此外,VMware先后收购Heptio和Pivotal Software(包括PAS和PKS),此举可以帮助企业客户更好建立并运行基于Kubernetes的容器化架构。其中,Heptio公司是由两位曾在2014年帮助谷歌联合建立Kubernetes项目的主力(当时的项目负责人共有三名)共同建立,创始人及其团队都将一同加盟VMware公司。如此清晰的创始人背景,可能意味着VMware有意在Kubernetes领域发动全面冲击,甚至预示VMware已经把Kubernetes视为企业业务运营的根本性基石之一。
2019年,容器技术领域也出现新变革,函数即服务(‘函数’或者‘无服务器’)已经成为一种新的抽象趋势。其允许开发人员更轻松地运行并部署代码片段,且这些代码片段将能快速实现规模伸缩以响应事件需求。
例如,企业只要使用由Google与Pivotal、IBM、红帽和SAP等企业共同开发的跨云Serverless管理平台Knative,就能在支持Kubernetes的云平台上自由的迁移工作负载,无论是跨私有云或是公有云及各种混合云架构都没问题。
2019年也出现了基于Kubernetes -混合云解决方案,如IBM CloudPaks、谷歌Anthos,AWS Outposts、和Azure Arc。这些云平台模糊了云环境与本地环境之间的传统界限,可以更方便管理本地和供应商云服务。
Kubernetes已经成为构建容器化平台体系的默认抽象方案,上诉这些新功能的出现也代表着Kubernetes的下一步演进方向,诸如Anthos、Arc和Outposts之类超抽象。在超抽象中,计算资源从管理层解耦,类似于Kubernetes的工作方式,它将工作负载从管理层解耦。
2020:容器安全成为新挑战
作为一种轻量级的虚拟化技术,容器使用方便、操作便捷,大大提高开发人员的工作效率,并得到业内的广泛使用。但与此同时,容器安全事故频发,包括不安全的镜像源、容器入侵事件、运行环境的安全问题等等。
1.不安全的镜像源
开发者通常会在Docker 官方的Docker Hub仓库下载镜像,这些镜像一部分来源于开发镜像内相应软件的官方组织,还有大量镜像来自第三方组织甚至个人。从这些镜像仓库中获取镜像的同时,也带来潜在的安全风险。例如,下载镜像内软件本身是否就包含漏洞,下载的镜像是否被恶意植入后门,镜像在传输过程中是否被篡改。
2.容器入侵事件
由docker本身的架构与机制可能产生的问题,这一攻击场景主要产生在黑客已经控制了宿主机上的一些容器(或者通过在公有云上建立容器的方式获得这个条件),然后对宿主机或其他容器发起攻击来产生影响。
3.运行环境的安全
除docker 本身存在的问题外,docker运行环境存在的问题同样给docker的使用带来风险。
由于容器是介于基础设施和平台之间的虚拟化技术,因此面向基础设施虚拟化的传统云安全解决方案无法完全解决前述安全问题。如以容器为支撑技术构建DevOps环境,就需要设计涵盖从容器镜像的创建到投产上线的整个生命周期的容器安全方案。
2.docker基础用法
什么是docker
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。 Docker 和传统虚拟化方式的不同之处,可见容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。
docker中的容器:
- lxc --> libcontainer --> runC
OCI&OCF
OCI
Open Container-initiative(一个容器的开放协议)
- 由Linux基金会主导于2015年6月创立
- 旨在围绕容器格式和运行时制定一个开放的工业化标准
- contains two specifications(包含两个规格)
- the Runtime Specification(runtime-spec) 运行时的规范
- the Image Specification(image-spec) 镜像的规范
OCF
Open Container Format(一个开放的容器格式)
runC is a CLI tool for spawning and running containers according to the OCI specification(runC是一个CLI工具,用于根据OCI规范生成和运行容器)
- Containers are started as a child process of runC and can be embedded into various other systems without having to run a daemon(容器作为runC的子进程启动,可以嵌入到其他各种系统中,而不需要运行守护进程)
- runC is built on libcontainer, the same container technology powering millions of Docker Engine installations(runC构建在libcontainer之上,同样的容器技术支撑着数以百万计的Docker引擎安装)
docker提供了一个专门容纳容器镜像的站点:https://hub.docker.com
docker架构
docker镜像与镜像仓库
-
registry:镜像的仓库
-
Repository:本身是一个仓库,这个仓库里面可以放具体的镜像,是指具体的某个镜像的仓库
-
按照Docker的logo来看,Repository是集装箱,Registry是鲸鱼。
镜像是静态的,而容器是动态的,容器有其生命周期,镜像与容器的关系类似于程序与进程的关系。镜像类似于文件系统中的程序文件,而容器则类似于将一个程序运行起来的状态,也即进程。所以容器是可以删除的,容器被删除后其镜像是不会被删除的。
docker对象
When you use docker, you are creating and using images, containers, networks, volumes, pluginns, and other objects.(当你使用docker时,你是在创建和使用图像、容器、网络、卷、插件和其他对象。)
- IMAGES(镜像)
- An image is a read-only template with instructions for creating a docker container.(镜像是一个只读的模板用于创建dorker容器)
- Often, an image is based on another image, with some additional customization.(通常,一个镜像基于另一个镜像,并带有一些额外的定制。)
- You might create your own images or you might only use those created by others and published in a registry.(你可以创建自己的镜像,也可以只使用其他人创建并在镜像仓库中发布的图像。)
- CONTAINERS(容器)
- A conntainer is a runnable instance of an image.(容器是镜像的可运行实例。)
- You can create, run, stop, move, or delete a container using the docker API or CLI.(你可以使用docker API或CLI创建、运行、停止、移动或删除容器。)
- You can connect a container to one or more networks, attach storage to it, or even create a new image based on its current state.(你可以将一个容器连接到一个或多个网络,将存储附加到它,甚至根据它的当前状态创建一个新镜像)
安装docker
[root@localhost ~]# cd /etc/yum.repos.d/ [root@localhost yum.repos.d]# wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo [root@localhost yum.repos.d]# sed -i 's@https://download.docker.com@https://mirrors.tuna.tsinghua.edu.cn/docker-ce@g' docker-ce.repo [root@localhost yum.repos.d]# dnf -y install docker-ce
配置镜像加速
docker-ce的配置文件是/etc/docker/daemon.json,此文件默认不存在,需要我们手动创建并进行配置,而docker的加速就是通过配置此文件来实现的。
docker的加速有多种方式:
- docker cn
- 中国科技大学加速器
- 阿里云加速器(需要通过阿里云开发者平台注册帐号,免费使用个人私有的加速器)
[root@localhost ~]# sudo mkdir -p /etc/docker [root@localhost ~]# sudo tee /etc/docker/daemon.json <<-'EOF' > { > "registry-mirrors": ["https://w673ojdv.mirror.aliyuncs.com"] > } > EOF { "registry-mirrors": ["https://w673ojdv.mirror.aliyuncs.com"] } [root@localhost ~]# sudo systemctl daemon-reload [root@localhost ~]# sudo systemctl restart docker [root@localhost ~]# systemctl enable docker Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service. [root@localhost ~]# docker version //显示Docker版本信息 Client: Docker Engine - Community Version: 20.10.17 API version: 1.41 Go version: go1.17.11 Git commit: 100c701 Built: Mon Jun 6 23:03:11 2022 OS/Arch: linux/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.17 API version: 1.41 (minimum version 1.12) Go version: go1.17.11 Git commit: a89b842 Built: Mon Jun 6 23:01:29 2022 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.6 GitCommit: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1 runc: Version: 1.1.2 GitCommit: v1.1.2-0-ga916309 docker-init: Version: 0.19.0 GitCommit: de40ad0 [root@localhost ~]# docker info //显示整个系统的信息 Client: Context: default Debug Mode: false Plugins: app: Docker App (Docker Inc., v0.9.1-beta3) buildx: Docker Buildx (Docker Inc., v0.8.2-docker) scan: Docker Scan (Docker Inc., v0.17.0) Server: Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 20.10.17 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true userxattr: false Logging Driver: json-file Cgroup Driver: cgroupfs Cgroup Version: 1 Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc Default Runtime: runc Init Binary: docker-init containerd version: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1 runc version: v1.1.2-0-ga916309 init version: de40ad0 Security Options: seccomp Profile: default Kernel Version: 4.18.0-365.el8.x86_64 Operating System: CentOS Stream 8 OSType: linux Architecture: x86_64 CPUs: 4 Total Memory: 3.618GiB Name: localhost.localdomain ID: ZHWC:G7Y5:BYBD:PHYP:6Z4P:RCXN:NMVB:N3OJ:KLGH:JRRP:7FM3:5MUI Docker Root Dir: /var/lib/docker Debug Mode: false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Registry Mirrors: https://w673ojdv.mirror.aliyuncs.com/ Live Restore Enabled: false
docker常用操作
命令 | 功能 |
---|---|
docker search | 在Docker Hub上查找镜像 |
docker pull | 从镜像仓库中拉取或者更新指定镜像 |
docker images | 列出本地镜像 |
docker create | 创建一个新的容器但不启动它 |
docker start | 启动容器 |
docker run | 创建一个新的容器并运行一个命令 |
docker attach | 连接到运行的容器 |
docker ps | 列出容器 |
docker logs | 查看容器日志 |
docker restart | 重启容器 |
docker stop | 停止容器 |
docker kill | 干掉一个或多个运行中的容器 |
docker rm | 删除一个或多个容器 |
docker exec | 在运行的容器中运行命令 |
docker info | 显示整个系统的信息 |
docker inspect | 返回Docker对象的低级信息 |
//在Docker Hub上查找镜像 [root@localhost ~]# docker search httpd NAME DESCRIPTION STARS OFFICIAL AUTOMATED httpd The Apache HTTP Server Project 4108 [OK] centos/httpd-24-centos7 Platform for running Apache httpd 2.4 or bui… 44 centos/httpd 35 [OK] clearlinux/httpd httpd HyperText Transfer Protocol (HTTP) ser… 2 //从镜像仓库中拉取或者更新指定镜像 [root@localhost ~]# docker pull httpd //拉取httpd镜像 可指定版本号,未指定为最新版 Using default tag: latest latest: Pulling from library/httpd a2abf6c4d29d: Pull complete dcc4698797c8: Pull complete 41c22baa66ec: Pull complete 67283bbdd4a0: Pull complete d982c879c57e: Pull complete Digest: sha256:0954cc1af252d824860b2c5dc0a10720af2b7a3d3435581ca788dff8480c7b32 Status: Downloaded newer image for httpd:latest docker.io/library/httpd:latest //列出本地镜像 [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE httpd latest dabbfbe0c57b 7 months ago 144MB //创建一个新的容器但不启动它 [root@localhost ~]# docker create --name web -p 80:80 httpd 9fdaf3c409dac424fababe2f40d16f3ffd4059dc61a0e2a2b92262e947876a9b //列出容器 [root@localhost ~]# docker ps //列出容器不包括未启动的 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@localhost ~]# docker ps -a //列出所有容器包括未启动的 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9fdaf3c409da httpd "httpd-foreground" 21 seconds ago Created web //启动容器 [root@localhost ~]# docker start web //可以用ID或者名字 web [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9fdaf3c409da httpd "httpd-foreground" 2 minutes ago Up 9 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp web //查看是否启动 //关闭容器 [root@localhost ~]# docker stop web //可以用ID或者名字 web [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9fdaf3c409da httpd "httpd-foreground" 3 minutes ago Exited (0) 3 seconds ago web //重启容器 [root@localhost ~]# docker restart web //可以用ID或者名字 web [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9fdaf3c409da httpd "httpd-foreground" 4 minutes ago Up 5 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp web //干掉运行中的容器 //stop正常退出 kill强制关闭 [root@localhost ~]# docker kill web web [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9fdaf3c409da httpd "httpd-foreground" 6 minutes ago Exited (137) 4 seconds ago web //查看容器日志 [root@localhost ~]# docker logs web AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message [Fri Aug 05 15:17:38.444681 2022] [mpm_event:notice] [pid 1:tid 139833106722112] AH00489: Apache/2.4.52 (Unix) configured -- resuming normal operations //删除一个或多个容器 运行时不可以删除 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9fdaf3c409da httpd "httpd-foreground" 13 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp web [root@localhost ~]# docker stop web //先停止 web [root@localhost ~]# docker rm web //在进出删除 web [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES //-f 在运行时可以强制删除 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 662e0fdfb4ca httpd "/bin/sh" 25 seconds ago Exited (0) 3 seconds ago test [root@localhost ~]# docker rm -f test test [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES //创建一个新的容器并运行一个命令 [root@localhost ~]# docker run -it --name test httpd /bin/sh # [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8592a0cf0a8a httpd "/bin/sh" 8 seconds ago Up 8 seconds 80/tcp test [root@localhost ~]# docker run -it --name test httpd /bin/sh # exit //交互模式内 如果退出 就会停止容器 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8592a0cf0a8a httpd "/bin/sh" 37 seconds ago Exited (0) 4 seconds ago test //连接到正在运行中的容器 [root@localhost ~]# docker start test test [root@localhost ~]# docker start test test # exit //此方式 进入退出后也会自动关闭容器 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8592a0cf0a8a httpd "/bin/sh" 3 minutes ago Exited (130) 4 seconds ago test //在运行的容器中执行命令 [root@localhost ~]# docker start test test [root@localhost ~]# docker exec -it test /bin/sh # exit //使用exec进入后退出后容器不会停止运行 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8592a0cf0a8a httpd "/bin/sh" 5 minutes ago Up 55 seconds 80/tcp test //返回Docker对象的低级信息 [root@localhost ~]# docker inspect "docker inspect" requires at least 1 argument. See 'docker inspect --help'. Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...] Return low-level information on Docker objects [root@localhost ~]# docker inspect test [ { "Id": "8592a0cf0a8a981579b57a156c4807a706be1279bf1336c20208679aa7c81472", "Created": "2022-08-05T15:34:30.163877907Z", "Path": "/bin/sh", "Args": [], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 176575, "ExitCode": 0, "Error": "", "StartedAt": "2022-08-05T15:39:10.071223772Z", "FinishedAt": "2022-08-05T15:38:06.009220384Z" ......省略 "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "93f3fbf6b5b9952e23ebd8e3799b996cc8bd4161977b51038af852c505c9a4dc", "EndpointID": "3f49e68f641af9bc93eff3aa01d065f6650db6543e2ecd453ab5d8cd15cb3518", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } } } ]
3.docker存储驱动
docker提供了多种存储驱动来实现不同的方式存储镜像,下面是常用的几种存储驱动:
- AUFS
- OverlayFS
- Devicemapper
- Btrfs
- VFS
- zfs
AUFS
AUFS(AnotherUnionFS)是一种Union FS,是文件级的存储驱动。AUFS是一个能透明覆盖一个或多个现有文件系统的层状文件系统,把多层合并成文件系统的单层表示。简单来说就是支持将不同目录挂载到同一个虚拟文件系统下的文件系统。这种文件系统可以一层一层地叠加修改文件。无论底下有多少层都是只读的,只有最上层的文件系统是可写的。当需要修改一个文件时,AUFS创建该文件的一个副本,使用CoW将文件从只读层复制到可写层进行修改,结果也保存在可写层。在Docker中,底下的只读层就是image,可写层就是Container。
AUFS文件系统据说有3W行代码,而ext4文件系统却只有4000-5000行左右代码,这些代码是要被整合进内核的,后来AUFS申请要被合并进内核代码的时候,linuz觉得它这代码太过臃肿,于是拒绝了。因此AUFS这个文件系统一直以来就不是linux内核中自有的文件系统,想用AUFS这个文件系统的话,必须自己向内核打补丁并去编译使用它,但redhat系列的操作系统一向以稳定著称,不会干这种出格的事,所以在redhat系列操作系统中使用AUFS并无可能。而ubuntu上的docker默认使用的就是AUFS。
OverlayFS
Overlay是Linux内核3.18后支持的,也是一种Union FS,和AUFS的多层不同的是Overlay只有两层:一个upper文件系统和一个lower文件系统,分别代表Docker的镜像层和容器层。当需要修改一个文件时,使用CoW将文件从只读的lower复制到可写的upper进行修改,结果也保存在upper层。在Docker中,底下的只读层就是image,可写层就是Container。目前最新的OverlayFS为Overlay2。
AUFS和Overlay都是联合文件系统,但AUFS有多层,而Overlay只有两层,所以在做写时复制操作时,如果文件比较大且存在比较低的层,则AUSF会慢一些。而且Overlay并入了linux kernel mainline,AUFS没有。目前AUFS已基本被淘汰。
DeviceMapper
Device mapper是Linux内核2.6.9后支持的,提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的管理策略。AUFS和OverlayFS都是文件级存储,而Device mapper是块级存储,所有的操作都是直接对块进行操作,而不是文件。Device mapper驱动会先在块设备上创建一个资源池,然后在资源池上创建一个带有文件系统的基本设备,所有镜像都是这个基本设备的快照,而容器则是镜像的快照。所以在容器里看到文件系统是资源池上基本设备的文件系统的快照,并没有为容器分配空间。当要写入一个新文件时,在容器的镜像内为其分配新的块并写入数据,这个叫用时分配。当要修改已有文件时,再使用CoW为容器快照分配块空间,将要修改的数据复制到在容器快照中新的块里再进行修改。
OverlayFS是文件级存储,Device mapper是块级存储,当文件特别大而修改的内容很小,Overlay不管修改的内容大小都会复制整个文件,对大文件进行修改显然要比小文件要消耗更多的时间,而块级无论是大文件还是小文件都只复制需要修改的块,并不是整个文件,在这种场景下,显然device mapper要快一些。因为块级的是直接访问逻辑盘,适合IO密集的场景。而对于程序内部复杂,大并发但少IO的场景,Overlay的性能相对要强一些。
Btrfs
Btrfs被称为下一代写时复制文件系统,并入Linux内核,也是文件级级存储,但可以像Device mapper一直接操作底层设备。Btrfs把文件系统的一部分配置为一个完整的子文件系统,称之为subvolume 。那么采用 subvolume,一个大的文件系统可以被划分为多个子文件系统,这些子文件系统共享底层的设备空间,在需要磁盘空间时便从底层设备中分配,类似应用程序调用 malloc()分配内存一样。为了灵活利用设备空间,Btrfs 将磁盘空间划分为多个chunk 。每个chunk可以使用不同的磁盘空间分配策略。比如某些chunk只存放metadata,某些chunk只存放数据。这种模型有很多优点,比如Btrfs支持动态添加设备。用户在系统中增加新的磁盘之后,可以使用Btrfs的命令将该设备添加到文件系统中。Btrfs把一个大的文件系统当成一个资源池,配置成多个完整的子文件系统,还可以往资源池里加新的子文件系统,而基础镜像则是子文件系统的快照,每个子镜像和容器都有自己的快照,这些快照则都是subvolume的快照
当写入一个新文件时,为在容器的快照里为其分配一个新的数据块,文件写在这个空间里,这个叫用时分配。而当要修改已有文件时,使用CoW复制分配一个新的原始数据和快照,在这个新分配的空间变更数据,变结束再更新相关的数据结构指向新子文件系统和快照,原来的原始数据和快照没有指针指向,被覆盖
ZFS
ZFS 文件系统是一个革命性的全新的文件系统,它从根本上改变了文件系统的管理方式,ZFS 完全抛弃了“卷管理”,不再创建虚拟的卷,而是把所有设备集中到一个存储池中来进行管理,用“存储池”的概念来管理物理存储空间。过去,文件系统都是构建在物理设备之上的。为了管理这些物理设备,并为数据提供冗余,“卷管理”的概念提供了一个单设备的映像。而ZFS创建在虚拟的,被称为“zpools”的存储池之上。每个存储池由若干虚拟设备(virtual devices,vdevs)组成。这些虚拟设备可以是原始磁盘,也可能是一个RAID1镜像设备,或是非标准RAID等级的多磁盘组。于是zpool上的文件系统可以使用这些虚拟设备的总存储容量
在Docker里ZFS的使用。首先从zpool里分配一个ZFS文件系统给镜像的基础层,而其他镜像层则是这个ZFS文件系统快照的克隆,快照是只读的,而克隆是可写的,当容器启动时则在镜像的最顶层生成一个可写层。
当要写一个新文件时,使用按需分配,一个新的数据快从zpool里生成,新的数据写入这个块,而这个新空间存于容器(ZFS的克隆)里
当要修改一个已存在的文件时,使用写时复制,分配一个新空间并把原始数据复制到新空间完成修改
存储驱动 | 特点 | 优点 | 缺点 | 使用场景 |
---|---|---|---|---|
AUFS | 联合文件系统、未并入内核主线、文件级存储 | 作为docker的第一个存储驱动,已经有很长的历史,比较稳定,且在大量的生产中实践过,有较强的社区支持 | 有多层,在做写时复制操作时,如果文件比较大且存在比较低的层,可能会慢一些 | 大并发但少IO的场景 |
overlayFS | 联合文件系统、并入内核主线、文件级存储 | 只有两层 | 不管修改的内容大小都会复制整个文件,对大文件进行修改显示要比小文件消耗更多的时间 | 大并发但少IO的场景 |
Devicemapper | 并入内核主线、块级存储 | 块级无论是大文件还是小文件都只复制需要修改的块,并不是整个文件 | 不支持共享存储,当有多个容器读同一个文件时,需要生成多个复本,在很多容器启停的情况下可能会导致磁盘溢出 | 适合io密集的场景 |
Btrfs | 并入linux内核、文件级存储 | 可以像devicemapper一样直接操作底层设备,支持动态添加设备 | 不支持共享存储,当有多个容器读同一个文件时,需要生成多个复本 | 不适合在高密度容器的paas平台上使用 |
ZFS | 把所有设备集中到一个存储池中来进行管理 | 支持多个容器共享一个缓存块,适合内存大的环境 | COW使用碎片化问题更加严重,文件在硬盘上的物理地址会变的不再连续,顺序读会变的性能比较差 | 适合paas和高密度的场景 |
**1、AUFS VS Overlay** AUFS和Overlay都是联合文件系统,但AUFS有多层,而Overlay只有两层,所以在做写时复制操作时,如果文件比较大且存在比较低的层,则AUSF可能会慢一些。而且Overlay并入了linux kernel mainline,AUFS没有,所以可能会比AUFS快。但Overlay还太年轻,要谨慎在生产使用。而AUFS做为docker的第一个存储驱动,已经有很长的历史,比较的稳定,且在大量的生产中实践过,有较强的社区支持。目前开源的DC/OS指定使用Overlay
2、Overlay VS Device mapper
Overlay是文件级存储,Device mapper是块级存储,当文件特别大而修改的内容很小,Overlay不管修改的内容大小都会复制整个文件,对大文件进行修改显示要比小文件要消耗更多的时间,而块级无论是大文件还是小文件都只复制需要修改的块,并不是整个文件,在这种场景下,显然device mapper要快一些。因为块级的是直接访问逻辑盘,适合IO密集的场景。而对于程序内部复杂,大并发但少IO的场景,Overlay的性能相对要强一些。
3、Device mapper VS Btrfs Driver VS ZFS
Device mapper和Btrfs都是直接对块操作,都不支持共享存储,表示当有多个容器读同一个文件时,需要生活多个复本,所以这种存储驱动不适合在高密度容器的PaaS平台上使用。而且在很多容器启停的情况下可能会导致磁盘溢出,造成主机不能工作。Device mapper不建议在生产使用。Btrfs在docker build可以很高效。
ZFS最初是为拥有大量内存的Salaris服务器设计的,所在在使用时对内存会有影响,适合内存大的环境。ZFS的COW使碎片化问题更加严重,对于顺序写生成的大文件,如果以后随机的对其中的一部分进行了更改,那么这个文件在硬盘上的物理地址就变得不再连续,未来的顺序读会变得性能比较差。ZFS支持多个容器共享一个缓存块,适合PaaS和高密度的用户场景
4、在IO性能上
AUFS在读的方面性能相比Overlay要差一些,但在写的方面性能比Overlay要好
device mapper在512M以上文件的读写性能都非常的差,但在512M以下的文件读写性能都比较好
btrfs在512M以上的文件读写性能都非常好,但在512M以下的文件读写性能相比其他的存储驱动都比较差
ZFS整体的读写性能相比其他的存储驱动都要差一些