1、为什么使用Docker
在服务器中发布项目, 每次发布都需要布置项目所需要的环境特别麻烦,而且还有一台机器需要两个环境的状况,例如:发布java web 项目而言 需要下载安装jdk 和tomcat 安装Docker后只需要几个命令就轻松搞定, 还有两个环境的问题,我们有一台服务器需要发布两个java web项目 而有一个项目必须使用jdk1.7 而 另一个必须用jdk1.8,这个使用Docker都可以轻松解决
2、Docker介绍
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
Docker里面有三个概念分别是: 镜像,仓库,容器
容器: 就说运行java web项目,首先需要有运行环境,而这个容器就是我们的运行环境
镜像: 我把镜像理解为我们的操作系统,这个操作系统(镜像)运行起来后才会有我们程序运行的环境(容器)
仓库:这个仓库也就是我们下载操作系统(镜像)的地方,里面有各式各样的操作系统(镜像),redis,tomcat的镜像等等
3、Docker安装与启动
Docker
要求 CentOS
系统的内核版本高于 3.10
,需要CentOS7以上才可以安装,验证你的CentOS
版本是否支持 Docker
通过 uname -r 命令查看你当前的内核版本
确保 yum
包更新到最新(yum update)需要等待几分钟更新完成
安装所需的软件包
yum install -y yum-utils device-mapper-persistent-data lvm2
设置yum
源
-
官方源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
-
阿里云源
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
-
清华大学源
yum-config-manager --add-repo https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo
启用 edge 和 testing 镜像仓库:
yum-config-manager --enable docker-ce-edge
yum-config-manager --enable docker-ce-testing
更新yum软件包索引:
yum makecache fast
安装docker
yum install docker-ce
也可以查看所有仓库中所有docker
版本,并选择特定版本安装
yum list docker-ce --showduplicates
yum install docker-ce-版本号.ce
启动并加入开机启动
systemctl start docker
systemctl enable docker
验证安装是否成功
docker version
验证是否启动成功
docker run hello-world
国内从Docker Hub
拉取镜像有时会遇到困难,此时可以配置镜像加速器。Docker
官方和国内很多云服务商都提供了国内加速器服务,
国内加速地址有:
Docker中国区官方镜像
https://registry.docker-cn.com
ustc
https://docker.mirrors.ustc.edu.cn
中国科技大学
https://docker.mirrors.ustc.edu.cn
阿里云容器 服务
https://cr.console.aliyun.com/
以阿里云为例:
打开阿里云网址并登陆(阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台 ),然后点击镜像加速器,复制加速器地址,
然后修改/etc/docker/daemon.json 文件
保存文件,然后重启docker服务
systemctl restart docker.service
开启服务器IP转发功能
配置文件/etc/sysctl.conf
net.ipv4.ip_forward = 1
4、Docker镜像
搜索镜像
docker search 镜像名
搜索centos7的镜像:
拉取镜像
从Docker 镜像仓库获取镜像的命令是 docker pull
。其命令格式为:
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
具体的选项可以通过 docker pull --help
命令看到
-
Docker 镜像仓库地址:地址的格式一般是
<域名/IP>
[:端口号] 。默认地址是 Docker Hub。
仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>
。对于 Docker Hub
,如果不给出用户名,则默认为 library
,也就是官方镜像。
上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 ansible/centos7-ansible
,因此将会获取镜像 ansible仓库中的centos7-ansible镜像。
从下载过程中可以看到我们之前提及的分层存储的概念,镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 sha256
的摘要,以确保下载一致性。
在使用上面命令的时候,你可能会发现,你所看到的层 ID
以及 sha256
的摘要和这里不一样。这是因为官方镜像是一致在维护的,有任何新的 bug
,或者版本更新,都会进行修复再以原来的标签发布,这样可有确保任何使用这个标签的用户可以获得更安全、更稳定的镜像。
查看镜像
docker images 或 docker image ls
可以看到docker里共有两个镜像,一个是装好docker时测试拉取的hello-world,一个是刚刚拉去的centos7-ansible。
列表包含了 仓库名
、标签
、镜像 ID
、创建时间
、以及 所占用的空间
。其中仓库名就是这个镜像的镜像仓库,标签类似于版本号,镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个标签。这里标识的所占用空间是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和。在Docker Hub 中显示的体积是压缩后的体积,在镜像下载和上传过程中镜像是保持着压缩状态的。docker images
列表中的镜像体积总和并非是所有镜像实际硬盘消耗,由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。
可以通过以下命令来便捷的查看镜像、容器、数据卷所占用空间:
docker system df
虚悬镜像——尚明的镜像列表中,还可以看到一个特殊的镜像,这个镜像既没有仓库名,也没有标签,均为 <none>
。:
<none> <none> 00285df0df87 5 days ago 342 MB
这个镜像原本是有镜像名和标签的,原来为 mongo:3.2
,随着官方镜像维护,发布了新版本后,重新 docker pull mongo:3.2
时, mongo:3.2
这个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了 <none>
。除了 docker pull
可能导致这种情况, docker build
也同样可以导致这种现象。由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 <none>
的镜像。这类无标签镜像也被称之为 **虚悬镜像(dangling image)**,可以用下面的命令专门显示这类镜像:
docker image ls -f dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 00285df0df87 5 days ago 342 MB
一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除。
docker image prune
中间层镜像——为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像。所以在使用一段时间后,可能会看到一些依赖的中间层镜像。默认的 docker image ls
列表中只会显示顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加 -a
参数。
docker image ls -a
这样会看到很多无标签的镜像,与之前的虚悬镜像不同,这些无标签的镜像很多都是中间层镜像,是其他镜像所依赖的镜像。这些无标签镜像不应该删除,否者会导致上层镜像因为依赖丢失而出错。实际上,这些镜像也没必要删除,因为之前说过,相同的层只会存一遍,而这些镜像是别的镜像的依赖,因此并不会因为它们被列出来而多存了一份,无论如何你也会需要它们。只要删除那些依赖它们的镜像后,这些依赖的中间层镜像也会被连带删除。
列出部分镜像——不加任何参数的情况下,docker image ls
会列出所有顶级镜像,但是有时候我们只希望列出部分镜像。docker image ls
有好几个参数可以帮助做到这个事情。
根据仓库名列出镜像
列出特定的某个镜像——也就是说指定仓库名和标签
除此之外,docker image ls
还支持强大的过滤器参数 --filter
,或者简写 -f
。之前我们已经看到了使用过滤器来列出虚悬镜像的用法,塔还有更多的用法。比如,我们希望在 mongo:3.2
之后建立的镜像,可以用下面的命令:
$ docker image ls -f since=mongo:3.2
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 5f515359c7f8 5 days ago 183 MB
nginx latest 05a60462f8ba 5 days ago 181 MB
想查看某个位置之前的镜像也可以,只需要把 since
换成 before
即可、
此外,如果镜像构建时,定义了 LABEL
,还可以通过 LABEL
来过滤。
$ docker image ls -f label=com.example.version=0.1
...
以特定格式显示——默认情况下, docker image ls
会输出一个完整的表格,但是我们并非所有时候都会需要这些内容。比如,刚才删除虚悬镜像的时候,我们需要利用 docker image ls
把所有的虚悬镜像的 ID 列出来,然后才可以交给 docker image rm
命令作为参数来删除指定的这些镜像,这个时候就用到了 -q
参数。
$ docker image ls -q
5f515359c7f8
05a60462f8ba
fe9198c04d62
00285df0df87
f753707788c5
f753707788c5
1e0c3dd64ccd
--filter
配合 -q
产生出指定范围的 ID 列表,然后送给另一个 docker
命令作为参数,从而针对这组实体成批的进行某种操作的做法在 Docker 命令行使用过程中非常常见,不仅仅是镜像,将来我们会在各个命令中看到这类搭配已完成很强大的功能。因此每次在文档看到过滤器后,可以多注意一下它们的用法。
另外一些时候,我们可能只是对表格的结构不满意,希望自己组织列;或者不希望有标题,这样方便其它程序解析结果等,这就用到了 Go 的模板语法。
比如,下面的命令会直接列出镜像结果,并且只包含镜像ID 和仓库名:
$ docker image ls --format "{
{.ID}}: {
{.Repository}}"
5f515359c7f8: redis
05a60462f8ba: nginx
fe9198c04d62: mongo
00285df0df87: <none>
f753707788c5: ubuntu
f753707788c5: ubuntu
1e0c3dd64ccd: ubuntu
或者打算以表格等距显示,并且有标题行,和默认一样,不过自己定义列:
docker image ls --format "table {
{.ID}}\t{
{.Repository}}\t{
{.Tag}}"
删除本地镜像
如果想要删除本地的镜像,可以使用 docker image rm
命令,其格式为:
docker image rm [选项] <镜像1> [<镜像2> ...]
用 ID、镜像名、摘要删除镜像,其中,<镜像>
可以是 镜像
ID
、镜像名
或者 镜像摘要
。
我们可以用镜像的完整 ID
,也称为 长 ID
,来删除镜像。使用脚本的时候可能会用长 ID
,但是人工输入就太累了,所以更多的时候使用 短 ID
来删除镜像。docker image ls
默认列出的就已经是短 ID
了,一般取前 3 个字符以上,只要足够区分于别的镜像就可以了。
比如:
我们也可以用 镜像名
,也就是 <仓库名>:<标签>
,来删除镜像:
更精确的是使用 镜像摘要
删除镜像。
Untagged 和 Deleted
如果观察上面这几个命令的运行输出信息的话,你会注意到删除行为分为两类,一类是 Untagged
,另一类是 Deleted
。我们之前介绍过,镜像的唯一标识是其 ID
和摘要,而一个镜像可以有多个标签。
因此当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像。所以首先需要做的是将满足我们要求的所有镜像标签都取消,这就是我们看到的 Untagged
的信息。因为一个镜像可以对应多个标签,因此当我们删除了所指定的标签后,可能还有别的标签指向了这个镜像,如果是这种情况,那么 Delete
行为就不会发生。所以并非所有的 docker image rm
都会产生删除镜像的行为,有可能仅仅是取消了某个标签而已。
当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变动非常容易,因此很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。这就是为什么,有时候会奇怪,为什么明明没有别的标签指向这个镜像,但是它还是存在的原因,也是为什么有时候会发现所删除的层数和自己 docker pull
看到的层数不一样的源。
除了镜像依赖以外,还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。之前讲过,容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必然会导致故障。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。
用 docker image ls 命令来配合删除——像其它可以承接多个实体的命令一样,可以使用 docker image ls -q
来配合使用 docker image rm
,这样可以成批的删除希望删除的镜像。我们在 “镜像列表”章节介绍过很多过滤镜像列表的方式都可以拿过来使用。
比如,我们需要删除所有仓库名为 ansible/centos7-ansible的镜像:
或者删除所有在 mongo:3.2
之前的镜像:
docker image rm $(docker image ls -q -f before=mongo:3.2)
充分利用你的想象力和 Linux
命令行的强大,你可以完成很多非常赞的功能。
CentOS/RHEL 的用户需要注意的事项
在Ubuntu/Debian
上有 UnionFS
可以使用,如 aufs
或者 overlay2
,而 CentOS
和 RHEL
的内核中没有相关驱动。因此对于这类系统,一般使用 devicemapper
驱动利用LVM
的一些机制来模拟分层存储。这样的做法除了性能比较差外,稳定性一般也不好,而且配置相对复杂。Docker
安装在 CentOS/RHEL
上后,会默认选择 devicemapper
,但是为了简化配置,其 devicemapper
是跑在一个稀疏文件模拟的块设备上,也被称为 loop-lvm
。这样的选择是因为不需要额外配置就可以运行 Docker
,这是自动配置唯一能做到的事情。但是 loop-lvm
的做法非常不好,其稳定性、性能更差,无论是日志还是 docker info
中都会看到警告信息。官方文档有明确的文章讲解了如何配置块设备给 devicemapper
驱动做存储层的做法,这类做法也被称为配置 direct-lvm
。
除了前面说到的问题外,devicemapper
+ loop-lvm
还有一个缺陷,因为它是稀疏文件,所以它会不断增长。用户在使用过程中会注意到 /var/lib/docker/devicemapper/devicemapper/data
不断增长,而且无法控制。很多人会希望删除镜像或者可以解决这个问题,结果发现效果并不明显。原因就是这个稀疏文件的空间释放后基本不进行垃圾回收的问题。因此往往会出现即使删除了文件内容,空间却无法回收,随着使用这个稀疏文件一直在不断增长。
所以对于 CentOS/RHEL
的用户来说,在没有办法使用 UnionFS
的情况下,一定要配置 direct-lvm
给 devicemapper
,无论是为了性能、稳定性还是空间利用率。
或许有人注意到了 CentOS 7
中存在被 backports
回来的 overlay
驱动,不过 CentOS
里的这个驱动达不到生产环境使用的稳定程度,所以不推荐使用。
来源micromaple.blog.csdn.net/
article/details/125727576
5、Docker容器运行
创建容器并运行
#以指定镜像创建一个容器并运行:
docker run 镜像名
#以ansible/centos7-ansible镜像创建一个容器并打开shell
docker run -it ansible/centos7-ansible /bin/bash
使用exit退出容器
docker run :创建一个新的容器并运行一个命令
语法
docker run [参数] 镜像名 [命令]
参数说明:
-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
-d: 后台运行容器,并返回容器ID;
-i: 以交互模式运行容器,通常与 -t 同时使用;
-P: 随机端口映射,容器内部端口随机映射到主机的端口
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
--name="nginx-lb": 为容器指定一个名称;
--dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-h "mars": 指定容器的hostname;
-e username="ritchie": 设置环境变量;
--env-file=[]: 从指定文件读入环境变量;
--cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;
-m :设置容器使用内存最大值;
--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
--link=[]: 添加链接到另一个容器;
--expose=[]: 开放一个端口或一组端口;
--volume , -v: 绑定一个卷
查看正在运行的容器
# 查看所有运行中的容器
docker ps
# 查看所有容器包括未运行容器
docker ps -a
(注:Container容器中没有前台运行的进程以后,容器就会自动退出,并返回状态码为0显示为Exited (0)。这个地方的前台进程可以理解为一个长服务,也就是一个一直在运行的进程。比如说Linux服务器当中的守护进程。解决办法:容器启动时,增加一个可以长运行的服务。一般使用docker run -t -d Image可以解决。)
进入容器内部进行操作
进入容器
docker exec -it 容器ID bash
退出容器
exit
文件传输
如果我们想获取容器内的文件怎么办呢
容器 -----> 本机
docker cp ID全称:容器文件路径 本地路径
本机 -----> 容器
docker cp 本地文件路径 ID全称:容器路径
停止容器
docker stop 容器ID
删除容器
docker rm 容器id