Docker概述
Docker为什么会出现
来看以下场景:
- 如果在公司做过开发的童鞋就会知道,一个项目有开发/测试环境,和线上环境。而每套环境都需要部署应用环境,对应用进行配置。
- 程序在开发环境可以使用,在线上环境不可用。又或者线上环境由于服务器操作系统其他组件的更新,导致该项目的服务不可用。这对于运维来说,考验很大。
- 环境配置是十分麻烦的,每台机器都要部署环境(集群redis、ES、hadoop),费时费力。
之前在服务器上配置一个应用的环境(Redis MySQL ES JDK Hadoop),非常麻烦,而且环境是不跨平台的。比方说下面的场景:
传统:开发人员将项目打包成jar,然后将其交给运维来部署;
如今:开发+打包+部署,一套流程做完。
所以,能否发布一个项目(比如springboot fat jar + (Redis MySQL JDK ES Hadoop)),连同环境一起打包? Docker就是做这个事情的。
java --> jar --> 打包项目且带上环境(docker镜像)–> Docker仓库 --> 下载我们发布的镜像 --> 直接运行即可!
技术的本质:所有的技术的出现都是因为有新问题需要解决。也因此我们才需要去学习。
Docker的历史
2010年,几个搞IT的年轻人,在美国成立了一家公司dotCloud。
做一些PaaS的云计算服务,LXC的容器技术。
他们将自己的技术(容器化技术)命名就是Docker。
Docker刚刚诞生的时候并没有引起行业的注意。所以为了让公司存活下去,于是把Docker开源了。
后来,越来越多的人发现了docker的优点,开始火了起来。Docker每个月都会更新一个版本。2014年4月9日,Docker 1.0发布。
Docker为什么这么火(有什么优势)
- 很轻巧
容器出现前,普遍用的是虚拟机,比如常见的VMware。虚拟机很笨重。
- 应用可以更快的交付和部署
传统方式:一堆帮助文档,安装程序;
docker:打包镜像,发布测试,一键运行。
- 扩容和缩容更便捷
使用了docker之后,我们部署应用就像搭积木一样简单。
- 更简单的系统运维
在容器化之后,我们的开发、测试环境都是高度一致的。
- 更高效的计算资源利用
一个物理机上可以运行很多个容器实例。
Docker是什么
引用维基百科对Docker的介绍:
Docker是Go语言开发的开源项目。
官方文档:https://docs.docker.com 。文档很详细!
官方镜像仓库:https://hub.docker.com
Docker能做什么
- 容器化技术与虚拟机技术的区别
容器化技术不是模拟一个完整的操作系统;
容器内的应用直接运行在宿主机上,容器是没有自己的内核的,也没有虚拟出硬件;
每个容器间相互隔离,每个容器内都有属于自己的一个文件系统。
Docker的基本组成
Docker是一个C/S架构的系统,Docker的守护进程运行在主机上。客户端通过socket去访问服务端。
Docker为什么比虚拟机快
1、Docker有着比虚拟机更少的抽象层;
2、Docker使用的是宿主机的内核,而VM使用的是虚拟出来的Guest OS。
因此,新建一个容器时,docker不需要像虚拟机一样重新加载一个操作系统内核,能够做到秒级的加载速度;而虚拟机是加载Guest OS,分钟级别的加载速度。
- 镜像(image)
docker镜像就好比是一个模板,可以通过这个模板来创建容器服务。一个镜像可以创建多个容器(container)。
- 容器(container)
Docker利用容器技术,独立运行一个或者一个组应用。
目前可以把这个容器理解为一个简易的Linux系统。
- 仓库(repository)
用来存放镜像的地方。
仓库分为公有仓库和私有仓库。
Docker安装、卸载
从官方文档获取安装方法。
1、Centos7
1、先卸载旧版本的docker
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
2、设置镜像的仓库
$ sudo yum install -y yum-utils
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
// 将上面官方的仓库改为国内的镜像仓库地址:
$ sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
// 更新yum源或者出现配置yum源之后,通常都会使用yum makecache 生成缓存,
// 这个命令是将软件包信息提前在本地缓存一份,用来提高搜索安装软件的速度。
$ sudo yum makecache fast
// 如果觉得占用磁盘空间,可以使用yum clean指令清除缓存。
$ sudo yum clean all
3、安装docker引擎
// 直接安装最新版本
$ sudo yum install docker-ce docker-ce-cli containerd.io
//查看可安装的docker版本
$ yum list docker-ce --showduplicates | sort -r
//安装指定版本的docker
$ sudo yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
4、启动docker服务
$ sudo systemctl start docker
使用docker version
来判断是否安装成功:
或运行官方的hello-world
镜像来验证。
$ sudo docker run hello-world
5、Docker的卸载
- Step1:Uninstall the Docker Engine, CLI, and Containerd packages:
$ sudo yum remove docker-ce docker-ce-cli containerd.io
- Step2:Images, containers, volumes, or customized configuration files on your host are not automatically removed. To delete all images, containers, and volumes:
$ sudo rm -rf /var/lib/docker
$ sudo rm -rf /var/lib/containerd
6、其实可以指定镜像、容器存放的位置。
编辑/etc/docker/daemon.json
文件即可(如果不存在该文件,则新建)。
配置阿里云的容器镜像加速器
同样是编辑 /etc/docker/daemon.json
文件即可。
PS:每个阿里云用户的加速地址都不同的。上面这个我记得当时我是在网络上找的别人的加速地址。
另外,其实腾讯云也有这种加速服务的。
回顾启动hello-world镜像的流程
docker run
命令的执行流程如下图:
Docker常用命令
官方参考文档:https://docs.docker.com/reference/
帮助命令
docker version //显示版本信息
docker info //显示docker的系统信息,包括镜像和容器
docker <COMMAND> --help //万能命令
镜像命令
docker images
查看所有本机的镜像
[root@VM-8-8-centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 6 months ago 13.3kB
//解释
REPOSITORY 镜像在仓库中的名称
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
//可选项
Options:
-a, --all Show all images (default hides intermediate images)
-q, --quiet Only show image IDs
docker search
搜索镜像
[root@VM-8-8-centos ~]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 11433 [OK]
mariadb MariaDB Server is a high performing open sou… 4341 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 848 [OK]
percona Percona Server is a fork of the MySQL relati… 554 [OK]
phpmyadmin phpMyAdmin - A web interface for MySQL and M… 324 [OK]
centos/mysql-57-centos7 MySQL 5.7 SQL database server 91
mysql/mysql-cluster Experimental MySQL Cluster Docker images. Cr… 88
centurylink/mysql Image containing mysql. Optimized to be link… 59 [OK]
//可选项
Options:
-f, --filter filter //过滤出符合指定条件的结果
//过滤出STARS>=3000的mysql镜像
[root@VM-8-8-centos ~]# docker search mysql --filter=STARS=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 11433 [OK]
mariadb MariaDB Server is a high performing open sou… 4341 [OK]
docker pull
拉取镜像
docker pull 镜像名[:tag]
[root@VM-8-8-centos ~]# docker pull mysql
Using default tag: latest //如果不指定tag,默认就是lastest
latest: Pulling from library/mysql
a330b6cecb98: Pull complete //分层下载, docker images 的核心
9c8f656c32b8: Pull complete
88e473c3f553: Pull complete
062463ea5d2f: Pull complete
daf7e3bdf4b6: Pull complete
1839c0b7aac9: Pull complete
cf0a0cfee6d0: Pull complete
1b42041bb11e: Pull complete
10459d86c7e6: Pull complete
b7199599d5f9: Pull complete
1d6f51e17d45: Pull complete
50e0789bacad: Pull complete
Digest: sha256:99e0989e7e3797cfbdb8d51a19d32c8d286dd8862794d01a547651a896bcf00c //签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest //真实地址,换言之:docker pull mysql 等价于 docker pull docker.io/library/mysql:latest
docker rmi
删除镜像
//删除单个容器
[root@VM-8-8-centos ~]# docker rmi -f <images id>
//删除多个容器
[root@VM-8-8-centos ~]# docker rmi -f <images id1> <images id2> <images id3> ...
//删除所有镜像
[root@VM-8-8-centos ~]# docker rmi -f $(docker images -aq)
// 解释:
-f 表示强制删除
docker images -aq 得到所有的镜像ID
docker history
查看镜像的构建过程(即镜像的历史变更记录)
docker history <镜像ID>
docker save/load
docker save
用于将镜像备份到一个tar包
docker load
用于从指定tar包中还原镜像
[root@VM-8-8-centos ~]# docker save --help
Usage: docker save [OPTIONS] IMAGE [IMAGE...]
Save one or more images to a tar archive (streamed to STDOUT by default)
Options:
-o, --output string Write to a file, instead of STDOUT
[root@VM-8-8-centos ~]# docker load --help
Usage: docker load [OPTIONS]
Load an image from a tar archive or STDIN
Options:
-i, --input string Read from tar archive file, instead of STDIN
-q, --quiet Suppress the load output
docker save
备份镜像:
docker load
还原镜像:
容器命令
先拉取容器,这里以centos:latest
镜像为例。
docker run
启动指定容器
docker run [可选参数] <image>
常用的可选参数说明:
--name="container name" //给容器起名字,用来区分容器
-d //后台方式运行
-it //使用交互式方式启动,可进入容器查看
-p //指定端口,也可作主机和容器的端口映射。
// e.g: -p ip:主机端口:容器端口
-p 主机端口:容器端口
-p 容器端口
-P //随机指定端口
--rm //用完即删 Automatically remove the container when it exits
docker ps
列出容器
docker ps [可选参数]
常用的可选参数说明:
-a //列出所有的容器,如果不加该参数,则只显示运行中的容器
-n int //列出最近创建的int个容器
-q //只显示容器ID
[root@VM-8-8-centos ~]# docker ps -n 1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be3b2ad39f46 centos:7.6.1810 "/bin/bash" 10 seconds ago Up 10 seconds centos_7.6
[root@VM-8-8-centos ~]# docker ps -n 2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be3b2ad39f46 centos:7.6.1810 "/bin/bash" 13 seconds ago Up 12 seconds centos_7.6
5ff746ad9c8a centos:latest "/bin/bash" About a minute ago Up About a minute centos_8
docker rm
删除指定容器
docker rm <容器ID> //删除指定容器,不能
docker rm -f $(docker ps -aq) //删除所有容器
docker ps -aq |xargs docker rm //也是删除所有容器
docker start/stop/restart/kill
启动、停止、重启和强制停止容器
docker start <容器id> //启动容器
docker stop <容器id> //停止容器
docker restart <容器id> //重启容器
docker kill <容器id> //强制停止容器
docker exec
在运行的容器中执行一条命令
可选命令:
Options:
-d, --detach Detached mode: run command in the background
--detach-keys string Override the key sequence for detaching a container
-e, --env list Set environment variables
--env-file list Read in a file of environment variables
-i, --interactive Keep STDIN open even if not attached
--privileged Give extended privileges to the command
-t, --tty Allocate a pseudo-TTY
-u, --user string Username or UID (format: <name|uid>[:<group|gid>])
-w, --workdir string Working directory inside the container
//示例
// 进入容器的交互式bash shell
$ sudo docker exec -it <容器id> /bin/bash
// 以root用户进入容器的交互式bash shell
$ sudo docker exec -u 0 -it <容器id> /bin/bash
docker attach
进入正在运行的容器。
与docker exec -it <容器id> /bin/bash 的区别:不会进入一个新的shell,而是当前容器运行用的shell。
docker attach <容器id>
常用的其它命令
docker logs
查看日志
Options:
--details Show extra details provided to logs
-f, --follow Follow log output
--since string Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative
(e.g. 42m for 42 minutes)
-n, --tail string Number of lines to show from the end of the logs (default "all")
-t, --timestamps Show timestamps
--until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative
(e.g. 42m for 42 minutes)
//示例:
[root@VM-8-8-centos ~]# docker logs -ft -n 1 centos_7.6
2021-09-20T01:39:07.127995518Z [root@be3b2ad39f46 /]#
docker top
查看容器中的进程信息
$ sudo docker top <容器id>
[root@VM-8-8-centos ~]# docker top be3b2ad39f46
UID PID PPID C STIME TTY TIME CMD
root 4398 4379 0 Sep20 pts/0 00:00:00 /bin/bash
docker inspect
查看容器的元数据
$ sudo docker inspect <容器id>
[root@VM-8-8-centos ~]# docker inspect 5ff746ad9c8a
[
{
"Id": "5ff746ad9c8a8e3642eb39e1d520003dbb7ac7141538484ddfa5d8cf83446273",
"Created": "2021-09-20T01:35:08.558366371Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 2939,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-09-20T01:35:08.791459407Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
"ResolvConfPath": "/var/lib/docker/containers/5ff746ad9c8a8e3642eb39e1d520003dbb7ac7141538484ddfa5d8cf83446273/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/5ff746ad9c8a8e3642eb39e1d520003dbb7ac7141538484ddfa5d8cf83446273/hostname",
"HostsPath": "/var/lib/docker/containers/5ff746ad9c8a8e3642eb39e1d520003dbb7ac7141538484ddfa5d8cf83446273/hosts",
"LogPath": "/var/lib/docker/containers/5ff746ad9c8a8e3642eb39e1d520003dbb7ac7141538484ddfa5d8cf83446273/5ff746ad9c8a8e3642eb39e1d520003dbb7ac7141538484ddfa5d8cf83446273-json.log",
"Name": "/centos_8",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": [
"196c4752f03e46c92a9f456c3c495a69653d8ef7221a603e6ffd71afd13459dc"
],
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/d29ea0e0ca0e9ab291d52b3b53416a7f057b719c792256c216d418681ec30bf1-init/diff:/var/lib/docker/overlay2/24b5f032294785128522bd7e768bcc6d43829e8dc659ca2c49c70c94ace55d55/diff",
"MergedDir": "/var/lib/docker/overlay2/d29ea0e0ca0e9ab291d52b3b53416a7f057b719c792256c216d418681ec30bf1/merged",
"UpperDir": "/var/lib/docker/overlay2/d29ea0e0ca0e9ab291d52b3b53416a7f057b719c792256c216d418681ec30bf1/diff",
"WorkDir": "/var/lib/docker/overlay2/d29ea0e0ca0e9ab291d52b3b53416a7f057b719c792256c216d418681ec30bf1/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "5ff746ad9c8a",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": true,
"OpenStdin": true,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "centos:latest",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20210915",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "7a2f54144ca594acbe782cbb3e88eb7459124bdad2276c9d5721a9881526ec1f",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/7a2f54144ca5",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "623ad66a1c64559d4149081b14b5408f54660e683daa5da5b1cc4f49cb824928",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "c3710726a487a0ce29f841cdbcc6eea5eda5a66e10fa85e8b6db3775ca8849d9",
"EndpointID": "623ad66a1c64559d4149081b14b5408f54660e683daa5da5b1cc4f49cb824928",
"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
}
}
}
}
]
docker cp
在容器和本地文件系统之间拷贝文件/目录
//从主机往容器里拷贝文件
docker cp bbb.txt be3b2ad39f46:/tmp/
//从容器往主机拷贝文件
docker cp be3b2ad39f46:/tmp/ks-script-6pKh_p /root
PS: 后面我们可以使用 -v (容器数据卷的技术)来实现容器目录和主机目录的自动同步。
docker stats
查看容器的cpu、内存等使用状态
docker stats //查看所有容器的cpu、内存等使用状态
docker stats <容器id> //查看指定容器的cpu、内存等使用状态
docker命令小结
前面主要讨论了容器、镜像相关的一些命令,还有很多命令在后面一些知识点会讲到,比如跟远程仓库、Dockerfile相关的…
作业
练习1
部署elasticsearch + kibana
按照官方文档(https://hub.docker.com/_/elasticsearch)下载并启动elasticsearch:
[root@VM-8-8-centos ~]# docker run -itd --name elasticsearch_v7.6.2 -p 19200:9200 -p 19300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
由于ES启动后会占用大量内存,docker stats
查看结果如下:
这对于1核CPU-2GB内存的云服务器来说(主要是穷o(╥﹏╥)o)负担较重。因此使用-e
参数传入ES的环境变量ES_JAVA_OPTS
来控制内存的使用量:
[root@VM-8-8-centos ~]# docker run -itd --name elasticsearch_v7.6.2 -p 19200:9200 -p 19300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
这下ES的内存占用就变小了:
部署好ES后,部署kibana。
思考:如何使用kibana连接es?
可视化
- Portainer
- Rancher
Docker镜像
镜像是什么
镜像是一种轻量级,可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,包括代码、运行时、库、环境变量和配置文件。
所有的应用,直接打包成docker镜像,就可以直接跑起来。
如何得到镜像?
- 从远程仓库下载
- 其他人拷贝给你
- 自己制作一个镜像Dockfile
Docker镜像的加载原理
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的的文件系统。它支持对文件系统的修改作为一次提交来一层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
Docker镜像加载原理
docker镜像实际上是由一层一层的文件系统组成,这种层级的文件系统叫UnionFS。
bootfs(boot file system) 主要包含bootloader和kernel,bootloader主要是引导并加载kernel。Linux刚启动时会加载bootfs文件系统。在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含bootloader和kernel。当bootloader加载完kernel后,kernel就在内存中了。此时内存的使用权就由bootfs交由kernel。
而rootfs(root file system)在 bootfs之上,包含的就是Linux系统中的/dev
,/proc
,/bin
,/etc
等标准目录和文件。rootfs就是各种不同的linux系统发行版,比如Ubuntu、OpenSUSE、CentOS等。
平时我们安装的到虚拟机的CentOS都是好几个G,为什么Docker里才200+M?
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了。因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以共用bootfs。
分层理解
在通过docker pull
下载镜像时,可以观察下载时的日志输出。可以看到是一层一层下载的,如下图:
所有的Docker镜像都是始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层上,创建新的镜像层。
举一个简单的例子,例如基于Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已包含3个镜像层,如下图(这只是一个简单的例子):
在添加额外镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图又是一个简单的例子:每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层级跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层的文件7是文件5个一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker在Windows上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和Copy on Write。
- 特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。这一层就是我们常说的容器层,容器层之下都叫镜像层。
commit镜像
docker commit //提交当前容器,成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" <容器id> 目标镜像名:[TAG]
练习
启动一个官方的tomcat容器。发现这个tomcat容器的
/usr/local/tomcat/webapps
目录是空的。往该目录拷贝文件后,再提交镜像。
[root@VM-8-8-centos ~]# docker commit -m "copy webapps.dist to webapps" -a "cloud-hacker" 1466e04bc744 tomcat9:v1.0
sha256:c5673696fcfadd7a7dffc41bf7959295116dd1fbeb17e679aff63d6ad7d82cc6
[root@VM-8-8-centos ~]#
commit后,docker images
查看本地镜像便能看到它。
综上,如果想要保存当前容器状态,就可以通过
docker commit
来提交获得一个镜像。
这就类似于虚拟机的快照。
学到这里,才算是入门了Docker!
学习方式说明:
理解概念(一开始可以不需要理解有多深入,可以模棱两可),然后一定要实践,最后实践+理论相结合一次搞定这个知识!