一、Docker解决了什么问题
1、存在的问题
- 开发环境和生产环境存在差异性,相同的代码部署到不同环境,经常因为各种原因不能正常运行
- 代码可运行环境的配置复杂,耗时耗力,如果能”一次配置/构建,到处正常运行“就好了
- 不同业务代码包对环境和配置的要求会有冲突,使得在同一个物理环境中彼此不能共存,可是我们就是希望他们共存
2、解决方式
如果打包的时候,可以把开发时的环境和配置一起打包进来,并且保持彼此相互独立(隔离)、互不影响,就可以很好地解决这些问题。集装箱好像就有这样的特性,所以,Docker,一群码头工人来帮助解决这个问题了。
二、Docker是什么
1、前提须知
虚拟化技术:让一台物理机,拥有多个操作系统的技术。具体实现虚拟化技术的解决方案有虚拟机和容器化技术。
- 虚拟机:模拟完整的一套操作系统,包括内核+完整库+应用,它占用资源比较多,存在很多冗余的内容,使得运行起来很慢,尤其是PC性能不好的时候
- 容器化技术:仅模拟部分操作系统,包括必须库(部分库)+应用,占用资源少,体积小
虚拟机为什么要比容器化技术运行起来慢?
虚拟机是在操作系统上又加了一个操作系统,所以启动加载很慢,而docker通过docker引擎直接在现有操作系统上操作
2、Docker的概念
Docker是一项使用go语言实现的容器化技术。它可以将代码+环境+配置(即除内核以外应用所有需要的环境+应用本身)打包成一个”集装箱“,实现应用程序”一次打包,到处运行“。
3、使用Docker带来了哪些优势(除了解决问题)
- 可以实现应用的快速交付
- 便利升级和扩展(一个镜像一步到位升级,然后可以将镜像快速复制到不同的服务器上)
- 可以充分压榨一台服务器的计算能力
4、Docker的架构图
-
docker cli + docker server + docker DB(一种CS架构)
-
cli通过命令来操控docker守护进程,实现对容器的管理
-
名词解释
- 镜像:创建容器的模板,类比java中的类,类比“程序”
- 容器:镜像的一个实例,类比java中的对象,类比“进程”,进程可以启动、停止、删除
- 仓库:存放镜像的数据库
5、docker运行流程图
远程库指docker hub(https://hub.docker.com/),相当于docker的一个镜像商店
三、Docker安装使用
官网:https://www.docker.com/
文档:https://docs.docker.com/
1、安装(基于centos)
1)如果之前安装过,需要先卸载掉之前的旧版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
2)如果没有,首先需要建立docker仓库
sudo yum install -y yum-utils
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
3)安装docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io
4)启动docker引擎
sudo systemctl start docker
5)验证安装成功
sudo docker version //查看docker版本
sudo docker run hello-world
四、Docker常用命令
1.帮助命令
-
查看版本
docker version
-
查看容器详细信息
docker info
比docker version显示的信息更多 -
查看帮助
docker --help
命令的帮助文档: https://docs.docker.com/reference/
docker 具体命令 --help
2.镜像命令
1)查看本地镜像
docker images
- -a 所有
- -q 只列出镜像id
- –digests显示摘要信息,验证一致性完整性的hashcode
– –no-trunc显示完整信息
2)从docker hub上搜索镜像
docker search 镜像名
- -s 数字 点赞数大于数字的
- –automated 只列自动构建类型的
3)从hub下载镜像,就是从hub上将镜像拉取到本地库
docker pull 镜像名[:tag]
不写tag表示下载最新版本
分层下载
4) 删除镜像
docker rmi 镜像id/镜像名[:tag] [镜像id/镜像名[:tag]]
可同时删除多个- 版本不写默认最新
- -f强行删除
- tag为latest表示最新版本
- 删除全部时
docker rmi -f $(docker images -qa)
5) 查看镜像变更历史
docker history 镜像名
3.容器命令
1) 新建并启动容器
docker run [参数] 镜像名/镜像id
-
-i:交互式模式运行容器,常与t同时用
-
-t:为容器重新分配一个伪终端,常与i连用
-
–name 名字:为容器指定一个名字
-
-d:后台运行容器并饭后容器id,即启动守护式模式运行
- docker容器后台运行,就必须有一个前台进程,否则就会自动退出,除了一直挂起的命令(top、tail)
-
-P:随机一个端口号
-
-p:指定一个端口号
ip:主机端口:容器端口
ip::容器端口
主机端口:容器端口
容器端口
-
2) 列出当前所有正在运行的容器
docker ps
ps命令是看机器上所有进程信息,与top相区别
- -a:所有=现在+之前(历史)
- -l:最近创建
- -n= 数字:显示最近创建的数字个
- -q:静默模式,只显示容器id
- –no-trunc:不截断输出
3) 退出容器
exit(且容器关闭了)
快捷键(ctrl+p+q:只退出。没有关闭)
4) 启动和停止容器
- 启动容器(针对已经创建过的)
dockers start 容器id
- 重启容器
docker restart 容器id
- 停止容器
docker stop 容器id
- 强制停止容器
docker kill 容器id
5)删除的容器
docker rm 容器id
- -f:强制删除没停止的容器
- 批量删除
docker rm -f ${docker ps -aq}等价于docker -aq|xargs docker rm
4、其它常用命令
1)查看容器日志
docker logs -f -t --tail 容器id
- f:跟随最新的日志打印
- t:加入时间戳
- tail:最后几条
2)查看某个容器进程信息
docker top 容器id
查看具体某个进程,与ps相区别
3)查看容器内部细节
docker inspect 容器id
4)进入没关闭的容器,显示之前正在运行的命令行窗口
docker attach 容器id
5)进入没关闭的容器,但会打开一个全新的命令行窗口(非运行的cmd)
docker exec 容器id
6) 从容器内拷贝文件到主机上
docker cp 容器id:容器内路径 目的主机路径
7)将自己修改过的容器生成一个镜像
docker -a =author name -m= commit message 容器id 镜像名:版本
8)查看机器中容器的cpu占用情况
docker stats
五、Docker镜像底层原理
参考:
- 掘金:https://jishuin.proginn.com/p/763bfbd61dab
- 知乎:https://zhuanlan.zhihu.com/p/392508816
1.什么是联合文件系统
1)官方介绍
联合文件系统( UnionFS )是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下
2)自家介绍
联合文件系统是一种像“git”一样的文件系统,本质上是就是利用了增量式修改文件+读写分层+共享来实现的
- 增量式修改文件
- 像git一样,每commit一组修改,就增加一层,对应一个新版本,进行增量式记录
- 只能做”加法“,不能做”减法“
- 读写分层
- 所有已经提交的部分只读
- 最顶层,当前运行的那一层可写
- 共享
- 由于已经提交的部分只读,所以,这部分内容可以进行共享,减少冗余,同时减少了启动加载的时间
2.docker镜像加载原理
1)基于联合文件系统来实现的,采用的OverlayFS,这种堆叠文件系统依赖于其它文件系统。
2)可以通过docker info
查看docker所使用的文件系统和存储驱动器
3)镜像、容器、层的原理图
- 每一个镜像都是基于基础镜像(没有父镜像的镜像)如centos等来生成的,新镜像=commit(旧镜像(只读层)+ 修改层(可读可写))
- 修改层相当于容器层,如果要记录容器的状态,可以通过commit把它变成一个新镜像
- 对于镜像每新加的一层,只是逻辑上的概念,在联合文件系统中,都指向同一个文件系统
六、Docker容器数据卷
1、数据卷的存在是为了解决什么问题
那必然是解决联合文件系统存在的问题,哈哈哈哈哈:
- 问题1:容器中的数据,其实相当于是内存数据,如果想要保存下来,必须将其commit成为镜像。如果仅为了持久化数据,就将其commit,那镜像得多大啊!这样docker”集装箱“体量小的优势就会丢失。另外,如果没有及时commit,服务由于各种原因崩了,数据也会丢失。
- 问题2:对容器中各种服务进行配置,必须进入到容器里面,好麻烦,如果要是在主机中操作,可以同步到容器中就好了。
- 问题3:容器和容器之间是相互隔离的,如果想要数据共享怎么办呢。
2、数据卷是什么
卷就是目录或者文件,但是它不属于联合文件系统(UFS)。可以说,它绕过了UFS,让数据可以直接存储在宿主机上,不随容器的消失而消失。
特点:
- 生命周期更长,不会随容器生命周期结束而结束——实现数据持久化
- 实现数据持久化不影响镜像,解决问题1
- 实现容器与宿主机的双向”沟通“,在宿主机中的修改可以直接反馈到容器中,在容器中的修改也会直接影响到宿主机上
- 可以直接在主机上修改容器中应用服务配置,解决问题2
- 可以容器间共享数据,解决问题3
3、如何使用数据卷——挂载
1)挂载命令
-
docker run -v /主机路径:/容器路径
查看卷查不到,原因是 docker volume ls 命令查看的数据卷在主机 /var/lib/docker/volumes目录下
-
docker run -v 挂在数据卷名:/容器路径
具名挂载
-
docker run -v /容器路径
匿名挂载
-
须知
- 容器停止后,在主机对数据卷进行修改,重启重新开启后是可以看到对数据卷的修改的
- 可以设置容器对数据卷的权限命令:
docker run -it -v /主机绝对路径:/容器路径 :ro/rw 镜像名
- ro:read only,表示只容许从宿主机中进行写操作,在容器中不可以
- rw:read&write(默认),表示容器和宿主机都可以有写操作
2)查看具体数据卷的挂载路径命令
docker volume inspect 卷名
3)查看当前所有数据卷的命令
docker volume ls
4)查看具体容器的挂载信息命令
docker inspect 容器id
方式二
手动编写一个dockerfile文件→对文件进行build,生成文件对应的镜像→运行这个镜像
- 方式一不能直接在dockerfile中实现,因为它依赖于宿主机,而宿主机之间可能存在差异性,即目录结构不同
- 如果docker挂载主机目录访问时出现错误cannot open directory.:permission denied,则需要在挂载目录后多加一个参数–privileged=true
docker run -it -v /宿主机绝对路径目录:/容器内路径 --privileged=true 镜像名
3.容器间共享数据
数据卷容器:存放数据卷的容器,其它容器通过挂载这个容器实现数据共享
命令:docker run -it --name 容器名字 --volumes-from 数据卷容器名 镜像名
- 无论在哪个容器里对数据卷操作(芙蓉区或者子容器),都会显现出执行操作结果
- 具有传递性
- 父容器被删除不影响共享,因为其生命周期的特性
DockerFile解析
可以去docker hub上查看各种镜像对应的dockerfile文件内容
以centos为例
类比:docker镜像(java源文件)→ dockerFile(class文件)
概念:dockerFile是用来构建镜像的构建文件,是由一系列命令和参数构成的脚本
1.语法
- 每个保留字指令都必须大写,且其后至少有一个参数
- 指令从上到下一次执行
- 注释#表示
- 一个指令对应一个镜像层,指令→创建镜像层+新镜像进行提交
2.dockerfile执行流程
- 从基础镜像开始运行一个容器,祖先为scratch(类比Object)
- 一条指令对应一次对容器的修改并docker commit
- 基于新的容器再执行下一个指令
- 直到所有指令都执行完毕
3.dockerfile保留字指令
- FROM:基础镜像,基于哪个镜像开始构建新镜像
- MAINTAINER:维护者名字和邮箱
- RUN:构建时需要执行的相关命令(例如,镜像centos不支持vim,我们可以在其基础上修改,在这里加入yum -y install vim的指令,使它可以支持vim)
- EXPOSE:对外端口号,容器端口号
- WORKDIR:工作落脚目录,一登录进去所在的目录
- ENV:设置环境变量 (变量名 目录 eg JAVA_HOME /java/jdk)
- ADD:拷贝文件进入镜像,如果是压缩包自动解压缩
- COPY:只拷贝到指定路径下
- VOLUME:指定容器卷
- CMD:指定容器启动时自动要执行的命令,可以有多个,但是只有最后一个生效,cmd会被run之后的参数替代
- ENTRYPOINT:同cmd,但是run的话之后的参数只是追加
- ONBUILD:当构建的dockerfile是父,则在子继承后会触发的操作
Docker本地镜像发布到阿里云
编写dockerfile
build成镜像
将镜像push上去
- 登录阿里云开发者平台
- 创建仓库镜像
- 点击仓库镜像管理按钮,然后按照要求执行命令