初识Docker
什么是Docker
Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。
Docker是一个快速交付应用、运行应用的技术。
- Docker可以将应用程序、依赖、函数库、配置等一起打包为一个镜像,镜像包含完整运行环境,仅依赖系统的Linux内核,因此可以在任意Linux操作系统上运行
- Docker应用运行时利用沙箱机制形成隔离容器,各个应用互不干扰
- 启动、移除都可以通过一行命令完成,方便快捷
Docker与虚拟机
现在企业一般使用Docker进行容器化部署。
使用Docker的好处
-
面向产品:产品交付
-
面向开发:简化环境配置
-
面向测试:多版本测试
-
面向运维:环境一致性
-
面向架构:自动化扩容(微服务)
Docker架构
首先了解下docker中三个重要的概念
- image镜像——docker镜像就是一个只读模板,比如,一个镜像可以包含一个完整的centos,里面仅安装apache或用户的其他应用,镜像可以用来创建docker容器,另外docker提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下周一个已经做好的镜像来直接使用
- container容器——docker利用容器来运行应用,容器是从镜像创建的运行实例,它可以被启动,开始、停止、删除、每个容器都是互相隔离的,保证安全的平台,可以将容器看做是要给简易版的linux环境(包括root用户权限、镜像空间、用户空间和网络空间等)和运行再其中的应用程序
- repository仓库——仓库是集中存储镜像文件的沧桑,registry是仓库主从服务器,实际上参考注册服务器上存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)仓库分为两种,公有参考,和私有仓库,最大的公开仓库是docker Hub,存放了数量庞大的镜像供用户下周,国内的docker pool,这里仓库的概念与Git类似,registry可以理解为github这样的托管服务。
再来看下Docker的架构
Docker安装
本文以CentOS7为例
安装
yum install docker -y --安装
systemctl enable docker --开机自启动
systemctl start docker --启动
安装成功,查看版本
配置国内源加速地址,不然拉取镜像比较慢,配置文件/etc/docker/daemon.json,可以使用中国区官方加速地址或者各云服务商的加速地址。保存后使用systemctl daemon-reload重新加载配置参数,systemctl restart docker重启docker服务。
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://0dicnoc2.mirror.aliyuncs.com"
]
}
使用docker info命令可以看到配置生效
另外在学习Docker之前,最好关闭防火墙,因为docker容器运行可能需要占用各种不同的端口。还有就是多使用--help命令辅助查询docker相关命令及参数。
镜像命令
镜像操作主要命令:
镜像下载
镜像是运行容器的前提,我们可以使用 docker pull[IMAGE_NAME]:[TAG]
命令来下载镜像,其中 IMAGE_NAME
表示的是镜像的名称,而 TAG
是镜像的标签,也就是说我们需要通过 “镜像 + 标签” 的方式来下载镜像。
注意:不显式地指定 TAG的话, 它会默认下载 latest 标签,也就是下载仓库中最新版本的镜像。不过并不推荐您下载 latest 标签,因为该镜像的内容会跟踪镜像的最新版本,并随之变化,所以它是不稳定的。在生产环境中,可能会出现莫名其妙的 bug, 推荐您最好还是显示的指定具体的 TAG。
我们以mysql为例
docker pull mysql:5.7
如下图所示,代表镜像拉取成功
这里展开了解下,一个镜像一般是由多个层( layer
) 组成,类似 72a69066d2fe
这样的串表示层的唯一 ID。Docker 在下载之前,会去检测本地是否会有同样 ID 的层,如果本地已经存在了,就直接使用本地的就好了,避免了存储空间的浪费。
列出镜像
我们通过docker images命令可以查询已拉取的镜像的一些基础信息
-
REPOSITORY: 来自于哪个仓库;
-
TAG: 镜像的标签信息,比如 5.7、latest 表示不同的版本信息;
-
IMAGE ID: 镜像的 ID, 如果您看到两个 ID 完全相同,那么实际上,它们指向的是同一个镜像,只是标签名称不同罢了;
-
CREATED: 镜像最后的更新时间;
-
SIZE: 镜像的大小,优秀的镜像一般体积都比较小,这也是我更倾向于使用轻量级的 alpine 版本的原因;
注意:图中的镜像大小信息只是逻辑上的大小信息,因为一个镜像是由多个镜像层( layer
)组成的,而相同的镜像层本地只会存储一份,所以,真实情况下,占用的物理存储空间大小,可能会小于逻辑大小。
镜像标签
使用docker tag可以创建副本镜像
可以看到image id是一样的。
镜像详情
使用docker inspect命令查看镜像详细信息
镜像历史
使用docker history命令查看镜像历史
通过 docker history
命令,我们可以列出各个层(layer)的创建信息。
镜像查询
您可以通过下面命令进行搜索,可以通过help查看支持的查询参数
docker search [option] keyword
镜像删除
- 通过标签删除镜像,docker rmi 镜像名,同一个标签存在多个副本时,只会删除指定标签的镜像副本。当且仅当只有一个标签时,会同时删除该镜像的文件层。
- 通过镜像id删除镜像,docker rmi [image Id]。一旦制定了通过 ID 来删除镜像,它会先尝试删除所有指向该镜像的标签,然后再删除镜像本身。
清理镜像
我们在使用 Docker 一段时间后,系统一般都会残存一些临时的、没有被使用的镜像文件,可以通过以下命令进行清理:
docker image prune
创建镜像
Docker 创建镜像主要有两种:
-
基于已有的容器创建。命令:
docker commit [容器id] [镜像名]
-
基于 Dockerfile 来创建,推荐这种方式创建镜像。
docker image build -t [镜像名]:[标签] .
详细使用后面再介绍。
导出镜像
我们可以通过docker save
将镜像导出成 tar 包,分享给别人。
镜像加载
我们可以通过docker load将tar包加载生成镜像。
容器命令
那么镜像怎么去使用呢,自然是通过命令运行成一个容器啦。镜像image和容器container的关系类似java中类和对象的关系,镜像是静态的,不会改变,而容器可以由不同的配置参数去运行,通过一个镜像可以启动多个容器。
运行容器
创建容器命令:docker run,常用参数有
- -i:表示运行容器
- -t:表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即分配一个伪终端。
- --name : 为创建的容器命名。
- -v:表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录),可以使用多个-v做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,然后共享到容器上。
- -d:在run后面加上-d参数,则会创建一个守护式容器在后台运行(这样创建容器后不会自动登录容器,如果只加-i -t两个参数,创建后就会自动进去容器)。
- -p:表示端口映射,前者是宿主机端口,后者是容器内的映射端口。可以使用多个-p做多个端口映射
每个镜像的运行参数可能各不相同,建议学习初期通过https://hub.docker.com/官方仓库帮助文档查看运行示例。
测试下运行nginx
首先,拉取nginx镜像
运行命令
docker run --name mynginx -p 8888:80 -d nginx
运行容器
查看容器运行状态
docker ps //查看运行中的容器
docker ps -a //查看所有容器
docker ps -q //查看运行中的容器id 可以配合删除命令使用
docker ps -aq //查看所有的容器id 可以配合删除命令使用
可以看到,容器运行成功
从左到右依次为:容器id-镜像名称-启动命令-容器创建时间-状态-端口映射-容器名称
访问测试下,可以看到,nginx运行成功
查看日志
查看日志命令
docker logs [容器名或id]
查看nginx日志
docker logs -f 可以不间断的查看日志输出
容器操作
进入容器
docker exec -it mynginx bash
命令解读:
- docker exec:进入容器内部,执行一个命令
- -it:给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互
- mynginx:要进入的容器名称
- bash:进入容器后执行的命令,bash是一个linux终端交互命令
执行命令,如下图,可以看到成功进入容器,5a237b3b7c9c为容器id
在容器内部,我们可以执行一些常见的linux命令,如ls、pwd等,可以看到,容器内部也包含了一个类似linux操作系统的文件目录结构,但是它是精简版的,只包含nginx运行所必要的函数库及环境,有些目录文件和终端命令在容器内部是不存在的。
通过官方仓库文档可以看到,nginx首页存放于/usr/share/nginx/html目录下
我们进入/usr/share/nginx/html,可以看到,确实存在index.html
修改index.html,自定义首页内容
vi命令不存在,因为它不是nginx运行所必要的函数库依赖,所以没有默认安装。我们可以安装vi或vim命令,或者sed -i命令直接修改文件内容。
刷新页面,可以看到,修改成功
exit可以退出容器
停止容器
docker stop [容器名或id]
通过docker ps -a可以看到停止的容器
启动容器
docker start [容器名或id]
删除容器
docker rm [容器]
docker rm -f [容器] //强制删除运行中的容器 -f强制
docker rm -f $(docker ps -aq) //强制删除所有容器
数据卷
数据卷命令
上面修改容器内部文件的方式,有什么缺点呢?
- 不便于修改
- 数据不可复用
- 升级维护困难
而数据卷主要是解决了容器与数据耦合的问题。
数据卷(volume)是一个虚拟目录,指向宿主机文件系统中的某个目录。
数据卷的操作命令
docker volume [COMMAND]
docker volume命令是数据卷操作,根据命令后跟随的command来确定下一步执行的操作
- create:创建一个volume
- inspect:显示一个或多个volume的信息
- ls:列出所有的volume
- prune:删除未使用的volume
- rm:删除一个或多个指定的volume
测试下
数据卷默认目录时在/var/lib/docker/volumes下
数据卷挂载
我们在创建容器的时候,可以通过-v参数来挂载一个数据卷到某个容器目录
测试下
运行nginx容器,这里可以使用docker volume create先创建一个数据卷,在挂载,也可以直接挂载,docker判断数据卷不存在时会自动创建
docker run --name mynginx -p 8888:80 -v nginxhtml:/usr/share/nginx/html -d nginx
可以看到,nginx启动成功,并且创建了一个nginxhtml的数据卷。查看数据卷路径
进入数据卷目录,可以看到,nginx的html目录成功挂载到了宿主机目录。
使用vim命令修改index.html内容
保存文件,刷新页面,可以看到,修改成功,这样我们就完成了容器内部目录到外部的数据卷挂载。
目录挂载
除了数据卷挂载以外,我们还可以直接挂载宿主机目录或文件
docker run -v 宿主机文件:容器内文件
docker run -v 宿主机目录:容器内目录
测试
创建一个测试目录,我这里是/data/docker/nginx,然后创建logs日志目录
运行容器,将日志目录挂载到宿主机
docker run -d --name nginx2 -p 8889:80 -v /data/docker/nginx/logs:/var/log/nginx nginx
查看容器,测试访问
再来看下logs目录,成功挂载到宿主机的目录中,这样可以方便我们查看日志啦。
其实一般还需要把配置文件和html也挂载出来,有兴趣的话大家自行测试。