1. 什么是docker
docker的英文意思是 码头工人,意思就是搬运东西的意思,其实这和docker的特点是一样的,docker提供的就是一种容器化搬运东西(我们的软件、程序)的过程。docker自己本来是运行在操作系统上一个程序软件,它会提供一个容器环境,使我们的程序独立地运行在容器中,所以说,官方给docker起的这个名字也真是应景。
2.docker中的核心概念
2.1 镜像(Image)
镜像到底是个什么东西呢,很多人在学习docker的时候都是一头雾水的,可是是歪果仁对镜像情有独钟吧,好多东西都有镜像的概念。比如我们安装系统的.iso文件,其实就是镜像,这里你就可以把镜像认为是一种模板。我们可以使用docker根据这个模板创建容器来运行,其实更可以理解为镜像是好比github上的仓库一样,我们可以克隆下来源代码然后运行,运行起来的代码可以是一个网站、一个应用程序啥的,这就可以叫做容器。说白了,镜像就是一堆静态的模板,运行起来的镜像就是容器。镜像一般需要我们拉取下来,是只读的,这个我们克隆github上的仓库是一样一样的。
docker镜像中有分层的概念,就是一个镜像可能基于好几个镜像,比如一个web运行环境可能需要操作系统ubuntu、数据库mysql、.net core runtime运行时,那我们拉取的这个镜像就会包好这好几个镜像,这就好像我们前边说的打包好的运行环境一样,直接就拉下来一个小电脑一样。
2.2 容器(Container)
当我们拉取了一个镜像,然后run一下,就会根据这个镜像运行出来一个容器,运行的容器就好像我们的应用程序一样,可以访问可以停止,我们运用多次run命令,就运行了很多很多容器,也可以说是镜像的实例。从这个角度来看,我们可以把镜像看作是类,容器看作new出来的实例,也是很合适的。
2.3 仓库(Repository)
存放镜像的地方就是仓库,就好比存放代码的地方是github一样,我们就把github称为代码的仓库,github算是最大的仓库。那么存放docker镜像的地方我们叫做dockerhub,是docker的中央仓库。其实已经有dockerhub这个网站了(https://hub.docker.com/),这就是 存放docker镜像的官方仓库,好多官方的也保存在这里,保证了镜像的安全性和可靠性,我们可以从上边拉取一下镜像来运行我们的软件。当然我们也可以制作好我们自己镜像推送上去,不过这些肯定是要官方审核的,防止有些人写入一些恶意代码。不过我们可以推到我们自己的dockerhub上去,供我们自己使用,这个就好我们的github账号一样了,属于私有镜像了。
2.4 数据卷(Volumn)
实际上我们的容器就好像是一个简易版的操作系统,只不过系统中只安装了我们的程序运行所需要的环境,前边说到我们的容器是new出来的实例,既然是new出来的实例那就会销毁,那如果销毁了我们的程序产生出的需要持久化的数据怎么办呢,容器运行的时候我们可以进容器去查看,容器一旦销毁就什么都没有了。所以数据卷就是来解决这个问题的,是用来做数据持久化到我们的宿主机上容器间的数据共享,简单的说就是将宿主机的目录映射到容器中的目录,应用程序在容器中的目录读写数据会同步到宿主机上,这样容器产生的数据就可以持久化了,比如我们的数据库容器,就可以把数据存到我们宿主机上的真实磁盘上了。
docker中基本的概念已经说了,下面我们就可以来使用docker了。
3. docker的命令
3.1 镜像命令
- docker images 查看本机的镜像。
名称 | 介绍 |
---|---|
REPOSITORY | 仓库 ,也是镜像名称 |
TAG | 标签,也是版本号,镜像会有不同的版本号 |
IMAGE ID | 镜像id,根据这个id我们可以区分不同的镜像,也可以对某个镜像进行操作 |
CREATED | 创建时间 |
SIZE | 镜像的大小 |
- docker rmi 删除本地的镜像,加上一个参数-f表示强制删除,因为有时候若有运行的相关容器的时候是不能删除的,如:docker rmi -f nginx 强行停止容器并删除镜像,不管是否有占用情况。
- docker search 根据镜像名称搜索远程仓库中的镜像,可以看一下查到所有相关名称的镜像,可以选择我们要拉取哪个镜像,下边是搜索nignx相关的镜像,红色部分ok 说明是官方镜像。
- docker pull <镜像名称>:[标签名称]:拉取镜像,默认不写标签名称拉取最新的镜像。
- docker push 推送镜像,当我们制作了我们自己的镜像时,我们就可以推送到我们自己的docker hub上去。
3.2 容器命令
有了镜像我们就可以new一个镜像实例了,也就是我们所说的容器。
-
docker run :基于某个镜像运行一个容器,如果本地有这个镜像就根据本地的镜像创建,如果没有,就去远程拉取一个镜像再创建,参数如下:
-d:启动一个容器,后台运行,不会占用我们当前的控制台,一般都要加上,之前我们启动nginx没有指定这个参数,就会占用当前控制台,会一直挂起,有了这个命令就不会占用了。
-i:以交互模式运行容器,通常会和-t一起来使用(-it)。
-t:为容器也创建一个命令行窗口,是容器内容的命令行窗口,比如我们拉取一个ubuntu的镜像,我们想要在这个操作系统镜像里边执行一些命令,那就需要这个参数了。
-P:这个是大写的P,指定宿主机的随机端口映射到容器内部的端口。
-p:这个是小写的p,指定某个具体端口映射到容器内部端口,比如前边我们用-p 8080:80,就是让宿主机的8080端口映射到容器内的80端口,这样我们就可以在外部用8080端口访问我们容器内部的nginx了(默认容器必须有一个外部的映射端口,不然访问不了)。
-v:指定宿主机与容器内部的目录映射,就是之前的数据卷所需要的参数,好实现数据的持久化和同步。
–name=“mynginx”:为容器指定一个名称,如果没有指定,那就分配一个随机名称。
- docker ps 显示正在运行的容器,加一个参数-a 可以看到所有的容器
- docker start 启动容器 。
- docker stop 停止容器 。
- docker kill 强制停止容器。
- docker restart 重启容器。
- docker rm 删除容器,删除后容器就不在了,就不能重启和停止了。
- docker inspect 查看容器的详细信息。
4. 数据卷与数据卷容器
4.1 什么是数据卷
为了了解什么是Docker Volume,首先我们需要明确Docker内的文件系统是如何工作的。Docker镜像被存储在一系列的只读层。当我们开启一个容器,Docker读取只读镜像并添加一个读写层在顶部。如果正在运行的容器修改了现有的文件,该文件将被拷贝出底层的只读层到最顶层的读写层。在读写层中的旧版本文件隐藏于该文件之下,但并没有被不破坏 - 它仍然存在于镜像以下。当Docker的容器被删除,然后重新启动镜像时,将开启一个没有任何更改的新的容器 - 这些更改会丢失。此只读层及在顶部的读写层的组合被Docker称为Union File System(联合文件系统)。为了能够保存(持久)数据以及共享容器间的数据,Docker提出了Volumes的概念。很简单,volumes是目录(或者文件),它们是外部默认的联合文件系统或者是存在于宿主文件系统正常的目录和文件。
4.2 为什么使用数据卷volume
Docker的镜像是由一系列的只读层组合而来,当启动一个容器的时候,Docker加载镜像的所有只读层,并在最上层加入一个读写层。这个设计使得Docker可以提高镜像构建、存储和分发的效率,节省了时间和存储空间,然而也存在如下问题。
- 容器中的文件在宿主机上存在形式复杂,不能在宿主机上很方便的对容器中的文件进行访问
- 多个容器之间的数据无法共享
- 当删除容器时,容器产生的数据将丢失
为了解决这些问题,Docker引入了数据卷(volume)机制。volume是存在一个或多个容器中的特定文件或文件夹,这个目录能够独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久提供一下便利。
- volume在容器创建时就初始化,在容器运行时就可以使用其中的文件
- volume能在不同的容器之间共享和重用
- 对volume中的数据的操作会马上生效
- volume中数据操作不会影响到镜像本身
- volume的生存周期独立于容器的生存周期,即使删除容器,volume仍然会存在,没有任何容器使用的volume也不会被Docker删除
4.3 配置数据卷
4.3.1 配置单个数据卷:
创建容器时,使用-v 参数设置数据卷
docker run -it -v /宿主机目录绝对路径:/容器内目录路径 --name="xx" 镜像名 —privileged=true
注意事项:
- 目录必须是绝对路径
- 如果目录不存在,会自动创建
- 可以挂载多个数据卷
- 如果出现 cannot open directory:permission denied 时,需要多加一个 —privileged=true参数即可(有些系统里面可能会认为挂载目录时不安全的所以就被禁止了,而加入参数后会将这一限制打开)
案例如下
第一步,创建启动容器
docker run -it --privileged=true -v /Users/xxxxx/host_data:/tmp/docker_data --name=test1 13b66b487594
## /Users/xxxxx/host_data 表示宿主机绝对路径
## /tmp/docker_data 容器目录路径
第二步,确定容器是否开启成功
docker ps
第三步,查看数据卷是否挂在成功,输入如下命令
docker inspect 容器名
找到Mounts(表示挂载)信息,其中
type:bind 表示绑定型的
Source 表示宿主机路径
destination 表示容器内路径
上述过程就可以实现容器和宿主机之间数据共享啦。
- 当在容器目录内输入一些内容时,数据卷(宿主机目录)中的内容也会随即更新;当更新数据卷中的内容时,容器目录中的内容也会随即更新;这种方式也叫做映射。将容器目录映射到宿主机。
- 当容器被停止时,在宿主机中修改文件,当再进去容器时,文件也同样被修改。
4.3.2 配置多个数据卷
docker run -it -v /宿主机目录绝对路径1:/容器内目录路径1 -v /宿主机目录绝对路径2:/容器内目录路径2 -v /宿主机目录绝对路径3:/容器内目录路径3 -name="xx" 镜像名 —privileged=true
4.3.3 多个容器挂载同一个数据卷
docker run -it -v /宿主机目录绝对路径:/容器内目录路径 --name="xx" 镜像名 —privileged=true
或者
docker run -it -v /宿主机目录绝对路径:/容器内目录路径 --name="xx" 镜像名 —privileged=true
4.4 容器的数据卷
多容器间进行数据交换,有两种方式:
- 多个容器挂载同一个数据卷(缺点:操作比较麻烦,因为当容器过多时,需要一个个的挂载)
- 数据卷容器
相比,数据卷容器方式更胜一筹,同时数据卷容器也体现了数据卷的继承关系。
4.4.1 数据卷容器概念
见名知意,容器的数据卷,也可以称为数据卷容器或者容器卷,表示这个容器是用来共享数据的。
可以看下图,
- 在 c3 容器挂载了一个数据卷,
- c1 和 c2 容器再分别挂载到 c3 容器上,
- 这样 c1 和 c2 容器相当于挂载到了数据卷上,这样的话 c1、c2 c3 可以相互通信,即使 c3 挂了,c1 和 c2也可以通过数据卷进行通信。
4.4.2 如何配置数据卷容器
第一步,创建启动 c3 数据卷容器,使用-v 参数设置数据卷
docker run -it -v /容器目录 —name="c3" 镜像名 /bin/bash
## /容器目录 表示当没有指定宿主机目录时,docker会自动分配
第二步,数据卷继承
docker run -it --name="c1" --volumes-from c3 镜像名
docker run -it --name="c2" --volumes-from c3 镜像名