Docker优势
- Docker容器秒级启动
- 对系统资源利用率高,一台主机可以同时运行上千Docker容器
- 更快速的交付和部署,一次创建或配置,可以在任何地方运行
- 更高效的虚拟化,Docker应用内核级虚拟化技术
- 更轻松的迁移和拓展,不受运行环境限制,可在任意平台上运行
- 更简单的管理
Docker应用场景
- 简化配置
- 提高开发效率
- 代码流水线管理,给应用提供了一个从开发到上线均一致的环境
- 应用隔离,将一个整体式应用拆分成松耦合的单个服务
- 整合服务器,可以同时整合多个服务器资源来降低成本
- 多租户环境,避免关键应用的重写
- 调试能力,Docker提供了很多调试工具
- 快速部署,仅创建一个容器而无需启动一个系统
Docker启动
安装docker:apt-get install docker
- 根据系统不同命令也不同
启动Docker:systemctl start docker
重启Docker:systemctl restart docker
开机启动Docker:systemctl enable docker
查看Docker状态:syetemctl status docker
获取Docker帮助:docker -h
Mac系统下使用brew install docker
即可快速安装Docker图形化软件,安装完成后打开Docker,出现以下状态Docker即启动成功:
Docker基本组件
核心组件:
Docker客户端与服务器(C/S架构)
Docker镜像
在Docker的术语里,一个只读层被称为镜像,一个镜像是永久不会变的。
由于Docker使用一个统一文件系统,Docker进程认为整个文件系统是以读写方式挂载的。但是所有的变更都发生顶层的可写层,而下层的原始的只读镜像文件并未变化。由于镜像不可写,所以镜像是无状态的。
Docker镜像可用于创建Docker容器。
Docker镜像是由文件系统叠加而成,最底层是一个文件引导系统(bootfs)。Docker用户几乎永远不会与引导系统有交互。
Docker镜像是一个只读的文件,若要修改镜像内容只能重新制作或生成镜像。
在Docker镜像创建为Docker容器后,最底层的文件引导系统(bootfs)便会被卸载,此时的容器是可以进行读写操作的。
在利用Docker镜像创建容器时会在镜像的只读层上创建一层可写层作为最顶层,如下图所示:
每一个镜像都可能依赖于由一个或多个下层的组成的另一个镜像,下层镜像是上层镜像的父镜像。
一个没有任何父镜像的镜像,谓之基础镜像(Base Image),如下图所示:
图中的add emacs
便是add Apache
镜像的父镜像,而Debian
没有任何父镜像,我们便认为Debian
是基础镜像(Base Image)(文件引导系统在这里不视作一层镜像)
Registry(Docker仓库)
Docker仓库是集中存储镜像的场所。有时会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。事实上,仓库注册服务器往往存放着多个仓库,每个仓库又包含了多个镜像,每个镜像有着不同的TAG
。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
DockerHub是最大的公开仓库,国内的公开仓库包括DockerPool等,可供国内用户更加快速稳定的访问使用。用户也可在服务器上创建一个私有仓库。
当用户创建了一个Docker镜像时,可以使用push
命令将镜像上传至公开仓库或私有仓库中,这样在另一台机器使用时,使用pull
命令从仓库中拉取该镜像即可。
以向DockerHub上传名为test的镜像为例:docker push 用户名/test
用户名为用户在DockerHub注册时的用户名
Docker容器
Docker容器是从镜像启动的运行实例,它可以被启动、运行、停止、删除。每个容器都是相互隔离,保证安全的平台。
镜像是只读的,而容器启动时会在镜像的只读层上创建一层可写层作为最顶层
基本组件的简单使用过程
Docker简单使用
拉取镜像:docker pull 镜像仓库/镜像名称
eg:docker pull hello-world
- 拉取hello-world镜像
示例命令省略了仓库地址,Docker便默认从官方仓库(registry.hub.docker.com)拉取镜像,实际命令等价于
docker pull registry.hub.docker.com/hello-world
有时候官方仓库注册服务器下载较慢,可以从其他仓库下载。 从其它仓库下载时需要指定完整的仓库注册服务器地址。
下载过程中,会输出获取镜像的每一层信息。
下载完成后可以在Docker Desktop看到本地拉取到的镜像:
查看本地镜像:docker images
REPOSITOR -> 镜像源仓库
TAG -> 镜像标记信息
IMAGE ID -> 镜像ID号(唯一)
CREATED -> 创建时间
SIZE -> 镜像大小
其中镜像的 ID
唯一标识了镜像,所有镜像都是通过一个 64 位十六进制字符串 (内部是一个 256 bit 的值)来标识的。
为简化使用,前 12 个字符可以组成一个短ID,可以在命令行中使用。短ID还是有一定的 碰撞机率,所以服务器总是返回长ID。具有相同的镜像 ID
的镜像实际上即为同一镜像。
TAG
信息用来标记来自同一个仓库的不同镜像。例如 ubuntu
仓库中有多个镜像,通过 TAG
信息来区分发行版本,例如 10.04
、12.04
、12.10
、13.04
、14.04
等。
例如下面的命令指定使用镜像 ubuntu:14.04
来启动一个容器:
docker run -t -i ubuntu:14.04 /bin/bash
如果不指定具体的标记,则默认使用 latest
标记信息。
利用镜像创建Docker容器:docker run 镜像名称
查看当前运行的所有容器:docker ps -a
Docker镜像的使用
拉取镜像
例如拉取一个Ubuntu 18.04的镜像作为基础镜像:docker pull ubuntu:18.04
在这条命令中ubuntu
为仓库名,18.04
为标签TAG
列出镜像
拉取到基础镜像后,我们可以使用docker images
列出镜像:
创建容器
仍旧以第一步的镜像为例,我们利用Docker镜像来创建一个容器
docker run -ti ubuntu:18.04 /bin/bash
在这条命令中,-t
代表终端,-i
代表交互式,在Docker中,单字母参数可以合并,因而前面的两个参数可以合并为-ti
使用
ubuntu:18.04
指刚才拉取的镜像,而/bin/bash
则是执行的命令,在这里即为得到一个Shell
同时ubuntu:18.04
也可以用镜像ID(即列出镜像时看到的IMAGE ID
)替代,那么上面命令的等价命令为:docker run -ti fbf60236a8e3:18.04 /bin/bash
这样我们便得到了一个以Ubuntu 18.04为基础镜像而创建的Docker容器,在Shell中输入exit
即可停止该镜像回到原命令行。
除此之外我们还常用到-v
参数来将本地目录的文件复制到Docker容器之中,在创建容器时只需要加上该参数即可完成文件操作,具体用法如下:
-v 本地目录:容器目录
删除镜像
docker rmi 镜像名称/镜像ID
,例如docker rmi ubuntu:18.04
便可删除刚才我们拉取的镜像
注意:在删除镜像之前要先用 docker rm
删掉依赖于这个镜像的所有容器。
修改标签
使用docker tag
命令来修改镜像的标签,例如:
docker tag fbf60236a8e3 xiaoyesec/ubuntu:newtag
用法为docker tag 镜像ID 用户名/镜像名称:新标签
搜索镜像
使用docker search
命令来检索公开仓库中的镜像,例如
docker search php
其中php
为搜索的关键词
Docker镜像的创建
创建Docker镜像主要有三种方式:
修改已有镜像
先创建一个容器:docker run -ti ubuntu:18.04 /bin/bash
注意:记住容器的 ID,稍后还会用到。
在容器的终端中输入:apt-get update
来更新软件列表
然后执行apt-get install nmap
安装扫描工具nmap
结束后输入exit
来退出容器,现在我们的容器已经被我们改变了,在容器Shell中root@容器ID
便可以看到容器ID,例如我这里的容器ID便是b70f3162e24e
:
使用 docker commit
命令来提交更新后的副本:
docker commit -m "Added nmap" -a "xiaoyesec" b70f3162e24e ubuntu/nmap
其中,-m
来指定提交的说明信息,跟我们使用的版本控制工具一样,-a
可以指定更新的用户信息,之后是用来创建镜像的容器的ID,最后指定目标镜像的仓库名和 tag 信息。
创建成功后会返回这个镜像的ID信息:
再次查看镜像信息便可以看到我们刚刚提交的装有nmap的镜像:
利用这个新镜像来创建一个容器:docker run -ti bb062ffdc85e
尝试运行nmap,可以看到nmap已经被提前预装在了我们的docker镜像中:
利用 Dockerfile 来创建镜像
本部分已在[Docker学习笔记补充] dockerfile编写一文中重新整理撰写,故此处不再描述。
从本地文件系统导入镜像
要从本地文件系统导入一个镜像,可以使用 openvz(容器虚拟化的先锋技术)的模板来创建: openvz 的模板下载地址为 templates 。
比如,先下载了一个 ubuntu14.04 的镜像,之后使用以下命令导入:
sudo cat ubuntu-14.04-x86_64-minimal.tar.gz | docker import - ubuntu:14.04
然后查看新导入的镜像:
docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 14.04 05ac7c0b9383 17 seconds ago 215.5 MB
用户可以通过 docker push
命令,把自己创建的镜像上传到仓库中来共享。
例如,用户在 DockerHub上完成注册后,可以推送自己的镜像到仓库中:
docker push xiaoyesec/testimages
如果要导出镜像到本地文件,可以使用 docker save
命令:
docker save -o ubuntu_18.04.tar ubuntu:18.04
其中ubuntu_14.04.tar
为导出镜像的本地文件名称,ubuntu:18.04
为导出的镜像。
可以使用 docker load
从导出的本地文件中再导入到本地镜像库,例如:
docker load --input ubuntu_18.04.tar
或docker load < ubuntu_18.04.tar
其中ubuntu_18.04.tar
为本地镜像文件的名称。
这将导入镜像以及其相关的元数据信息(包括标签等)。
Docker镜像相关命令图示:
Docker容器的使用
启动容器我们共有两种方式:一种是基于镜像新建一个容器并启动,另外一种是将在中止状态(Exited)的容器重新启动
创建容器并启动
在之前的学习中我们可以使用docker run
命令来创建一个容器,在我们使用该命令创建容器时,Docker在后台的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件引导系统(bootfs),并在只读的镜像层外挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个IP地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
启动已中止的容器
启动已中止的容器我们可以使用docker start 容器ID
命令来启动已中止的容器,操作过程如下
先使用docker ps -a
来查看所有容器,注意该容器此时的状态为中止状态:
然后运行docker start 0e9ce91fed68
来启动已中止的容器,注意此时容器的状态变化:
中止已启动的容器
相应的,我们也可以使用docker stop/kill 容器ID
命令来停止运行中的容器:
同时需要注意的是,我们在容器终端中输入exit
或Ctrl+D来退出终端时,容器也会自动中止。
重启容器
除此之外还可以使用docker restart 容器ID
命令来重启容器:
守护态(后台)运行容器
我们可以在利用镜像创建容器时加上-d
参数来实现后台运行容器,如下命令便是在后台运行ubuntu18.04容器并控制Shell每隔1秒输出一句hello:
docker run -it -d ubuntu:18.04 /bin/sh -c "while true; do echo hello; sleep 1; done"
可以看到我们的容器已经在以守护态运行了,接着我们使用docker logs 容器ID
命令来查看容器的输出信息,执行docker logs b0454aa2b3f6
:
我们便读取到了容器输出的hello字符串。
那么在后台运行容器后,我们需要对容器进行操作时,可以使用docker attach 容器ID
命令来对容器进行操作:
也可以使用docker exec -it 容器ID 所执行命令
来操作容器:
可以看到在使用docker exec
命令后,退出终端时,容器依旧保持运行状态,而在docker attach
命令打开终端退出后,容器便会中止。
因而我们更推荐使用docker exec
命令来对后台运行的容器进行操作
删除容器
我们可以使用docker rm 容器ID
命令来删除容器,注意区别于删除镜像的docekr rmi
命令:
注意,在删除容器前必须停止容器,如果要删除一个运行中的容器,可以添加-f
参数来关闭并删除容器。
导出容器快照
我们可以使用docker export 容器ID > 快照文件名称
将某一状态的容器导出为本地镜像文件,类似于虚拟机中的快照:
导入容器快照
我们也可以使用docker import 快照文件 镜像名称:标签信息
来将容器快照重新导入为镜像。
同时,该命令也支持导入远程容器快照文件:docker import URL 镜像名称:标签信息
这里我们讲一讲docker import
命令和docker load
命令的区别,两者都是将文件导入为Docker镜像,那么两者有什么区别?
这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像储存文件将保存完整记录,相比之下文件体积更大。
此外,利用容器快照文件导入镜像时,我们可以重新制定标签信息等元数据信息。
值得一提的是,以上的几条命令在输入容器ID时不必输入完整ID,前几位Hash依旧可以确定目标容器,这便依赖于我们先前提到容器ID的唯一性。
Docker仓库的使用
Docker仓库注册
在DockerHub免费注册一个Docker账号。
Docker用户登录
使用docker login
命令后依次输入注册的用户名及密码即可完成登录。
Docker用户退出
使用docker logout
即可退出账号。
查找镜像
使用docker search 关键词
即可从DockerHub查找指定镜像。
拉取镜像
使用docker pull 镜像名称:标签信息
即可从DockerHub拉取目标镜像。
推送镜像
使用docker push
命令即可向DockerHub推送镜像,例如:
docker push Username/Image:Tag
推送完毕后可以执行docker search Username/Image
查找自己推送的镜像。
配置Docker镜像加速
以Mac系统为例,打开Docker Desktop,找到如图所示配置:
在文件编辑框的第一个大括号下增加以下内容:
"registry-mirrors":["加速站点链接"],
编辑完成后点击“Apply&Restart”按钮即可完成配置
配置完成后在命令行输入docker info
查看是否配置成功,出现如下所示信息即配置成功:
Docker网络
网络模式
Docker四种网络模式:
- Bridge - 桥接网络模式
- Host - 开放式网络模式
- Container - 联合挂载式网络模式(Host网络模式的延伸)
- None - 封闭式网络模式
可以通过docker network ls
命令查看:
Docker默认存在Bridge、Host、None三种网络模式,而Container需额外配置。
Docker网络模式的指定
我们在使用docker run
创建容器时可以增加--net
参数来指定容器的网络模式,具体使用如下:
- Bridge模式(默认):
--net=bridge
- Host模式:
--net=host
- None模式:
--net=none
- Container模式:
--net=container:NAME_or_ID
外部访问
Docker容器端口映射
我们在运行网络应用时往往需要外部访问这些应用,可以在创建容器时使用-p
参数来指定端口映射,例如
docker run -it -p 端口 镜像名称:标签信息
此时容器的端口便映射到了物理机的同端口上。
docker run -it -p 物理机端口:容器端口 镜像名称:标签信息
此时指定的容器端口便映射到了指定的物理机端口上。
docker run -it -p 指定IP:端口 镜像名称:标签信息
此时容器端口便映射到了物理机指定IP的同端口上。
docker run -it -p 指定IP:物理机端口:容器端口 镜像名称:标签信息
此时容器的指定端口便映射到了物理机指定IP的指定端口上。
我们运行docker run -itd -p 80:81 ubuntu:18.04
来测试端口映射:
可以看到在容器的端口信息中显示出了端口映射的关系,说明我们成功设置了容器与物理机之间的端口映射。
同时-p
可以多次使用来绑定多个端口映射关系。
当我们使用-P
参数时,Docker会随机映射一个端口到内部容器开放的网络端口(避免产生服务端口冲突)
使用docker log -f adoring_bell
可以查看容器的请求日志。
使用docker port 容器ID 端口
即可查看当前映射的端口配置。注意,容器有自己的内部网络和IP地址,使用docker inspect
可以获取所有变量。
容器互联
容器的连接系统时除了端口映射外另一种跟容器中应用交互的方式。该系统会在源容器和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息。
自定义容器命名
在使用docker run
命令时增加--name
参数即可为容器自定义命名,例如:
docker -tid -P --name web ubuntu:18.04
这样我们建立的ubuntu:18.04
容器便被自定义命名为web
容器互联
在使用docker run
命令时增加--link
参数即可连接容器,例如目前有命名为web
的容器,我们创建一个命名为db
的容器并与web
容器互联的命令如下:
docker run -dP --name db --link web:web ubuntu:18.04
这样我们新建立的db
容器便与web
容器建立了连接,两容器间便可以进行交互。
网络配置
-b BRIDGE
或--bridge=BRIDGE
:指定容器挂载的网桥
-bip=CIDR
:定制docker的掩码
-H SOCKET
或--host=SOCKET
:Docker服务端接收命令的通道
--icc=true|false
:是否支持容器间进行通信
--ip-forward=true|false
:容器是否开启转发
--iptables=true|false
:是否允许Docker添加iptables规则
--mtu=BYTES
:容器网络中的MTU
--dns=IP_ADDRESS
:使用指定的DNS服务器
--dns-search=DOMAIN
:指定DNS搜索域
-h HOSTNAME
或--hostanem=HOSTNAME
:配置容器主机名
--link=CONTAINER_NAME:ALIAS
:添加到另一个容器的连接
--net=bridge|none|container:NAME_or_ID|host
:配置主机的桥接模式
-p SPEC
或--publish=SPEC
:映射容器端口到宿主主机
-P
或--publish-all=true|false
:映射容器所有端口到宿主主机
访问控制
容器的访问控制主要通过Linux上的iptables防火墙来实现管理和实现,iptables时Linux上默认的防火墙软件,在大多数发行版中都自带
容器访问外部网络
容器要想访问外部网络,需要本地系统的转发支持。在Linux系统中,检查转发是否打开:
sysctl net.ipv4.ip_forward
返回值为1
则说明转发打开,为0
则说明未开启转发,需要手动开启:
sysctl -w net.ipv4.ip_forward=1
除了这个命令,在创建容器时我们也可以使用ip_forward=true
参数来开启转发。
容器之间互联
一、容器的网络拓扑是否已经互联,默认情况下,所有容器都会被连接到docker0网桥上。
二、iptables是否允许通过。
访问所有端口
启动Docker服务时,默认会添加一条iptables的转发策略到FORWARD链上。
策略为通过(ACCEPT)还是禁止(DROP)取决于参数--icc
的值为true
还是false
。
当手动置顶--iptables=false
时则不会添加iptables策略。
由此可见,默认情况下,不同容器之间是允许网络互通的。
访问指定端口
在--icc=false
关闭网络访问后,还可以通过--link=CONTAINER_NAME:ALIAS
参数来访问容器的开放端口。
例如,在启动Docker服务时,可以同时使用--icc=false --iptalbes=true
参数来关闭相互间的网络访问,并让Docker可以修改iptalbes的规则:
iptables -nL
之后,在使用docker run
时使用--link=CONTAINER_NAME:ALIAS
参数,Docker会在iptables中为两个容器分别添加一条ACCEPT规则,允许相互访问开放的端口(开放的端口取决于Dockerfile中的EXPOSE命令)
即当使用了--link
参数后,添加了对应的iptables规则。
Docker清理
容器、镜像等数据删除
- 查看Docker磁盘使用情况:
docker system df
- 清除Docker未使用的容器、网络、镜像等数据(不含数据卷):
docker system prune
- 清除Docker含数据卷在内的未使用数据:
docker system prune --volumes
- 清除停止的容器:
docker container prune
- 清除未使用的数据卷:
docker volumes prune
- 清除未使用的镜像:
docker images prune
- 结束所有正在运行的容器:
docker kill $(docker ps -a -q)
//-q
参数作用为返回容器的ID - 删除所有已经停止的容器:
docker rm $(docker ps -a -q)
- 删除所有不含KEYWORD标签的镜像:
docker rmi $(docker images -q -f KEYWORD='true')
日志文件删除
- 修改日志文件最大大小:打开
daemon.json
文件,修改log-opts
下的max-size
参数 - 修改docker-compose
- 命令行限制日志文件大小:创建容器时增加
--log-opts max-size=最大大小
参数 - 删除指定容器日志文件:
sudo rm $(docker inspect 容器ID --format '{{.LogPath}}')
//docker inspect 容器ID --format '{{.LogPath}}'
作用为返回指定容器日志路径