查找镜像
[root@docker01 ~]# docker search busybox
拉取镜像
[root@docker01 ~]# docker pull busybox
查看本地镜像
[root@docker01 ~]# docker images
PS:注意,一个完整的镜像,由镜像名称和TAG组成。如果只看到一个镜像的名称,没有接标签,意思是默认标签:latest。
虽然我们查看到的镜像标签为latest(最新的),但未必它一定是最新的。
把镜像导出到本地
[root@docker01 ~]# docker save -o busybox.tar busybox:latest
或者
[root@docker01 ~]# docker save > busybox.tar busybox:latest
删除镜像
[root@docker01 ~]# docker rmi busybox:latest
根据本地镜像包导入镜像
[root@docker01 ~]# docker load -i busybox.tar
或者
[root@docker01 ~]# docker load < busybox.tar
查看容器(正在运行的)
[root@docker01 ~]# docker ps
查看所有容器(包括正在运行和没有运行的容器)
[root@docker01 ~]# docker ps -a
删除容器
[root@docker01 ~]# docker rm container1
PS:强制删除正在运行的容器可以加上: -f 选项。
创建容器
[root@docker01 ~]# docker create -it --name test centos:7
PS:创建完成之后,容器是created的状态。
启动容器
[root@docker01 ~]# docker start test
停止容器运行
[root@docker01 ~]# docker stop test
重启容器
[root@docker01 ~]# docker restart test
挂起容器
[root@docker01 ~]# docker pause test
挂起状态恢复
[root@docker01 ~]# docker unpause test
强制删除所有容器(生产环境严禁使用)
[root@docker01 ~]# docker ps -a -q | xargs docker rm -f
PS: 强制启动所有容器
[root@docker01 ~]# docker ps -a -q | xargs docker start
同理,还可以有强制停止、重启、挂起等操作。
运行一个容器
[root@docker01 ~]# docker run -itd --name test centos:7
-i:可交互
-t:伪终端
-d:后台运行
–name:给容器命名 #首部双杠
–restart=always:始终保持运行(随着docker开启而运行) #首部双杠
–rm:会随着退出容器的操作而删除容器 #首部双杠
进入一个容器
[root@docker01 ~]# docker exec -it test /bin/bash
或者
[root@docker01 ~]# docker attach test
区别:
进入方式:
exec 进入的方式需要添加-i -t选项,后边还需要给容器一个shell环境。
但attach就不需要这么麻烦,可以直接进入。
退出状态:
exec 进入的方式: 如果执行exit退出,容器仍然保持运行。
attach : 如果执行exit退出,容器会被关闭。如果想要保持容器不被关闭,可以使用键盘: Ctrl + p Ctrl + q 可以实现。
本质上去区别:
exec 进入的方法,会生产新的进程。
attach不会生产新进程。
宿主机和容器之前,相互传东西
[root@docker01 ~]# docker cp nginx-1.16.0.tar.gz test:/root
将容器制作成镜像
[root@docker01 ~]# docker commit test test-web:01
Docker的基本操作逻辑
小实验:
1)基于Centos:7 镜像运行一个容器,并且,在这个容器内部署Nginx服务。
2)将运行完成的容器,制作成一个镜像,将此镜像导出到docker02上,在docker02上根据此镜像运行一个容器,测试访问界面内容。
1)下载镜像
[root@docker01 ~]# docker pull centos:7
2)运行容器
[root@docker01 ~]# docker run -itd --name webapp --restart=always centos:7
3)进入容器,开始部署nginx服务
将nginx包导入到容器内
[root@docker01 ~]# docker cp nginx-1.16.0.tar.gz web01:/root
[root@docker01 ~]# docker exec -it web01 /bin/bash
[root@452fcc8a1feb /]# tar zxf /root/nginx-1.16.0.tar.gz -C /usr/src/
[root@452fcc8a1feb /]# cd /usr/src/nginx-1.16.0/
[root@452fcc8a1feb nginx-1.16.0]# yum -y install gcc pcre pcre-devel openssl opessl-devel zlib zlib-devel
[root@452fcc8a1feb nginx-1.16.0]# useradd -M -s /sbin/nologin nginx
[root@452fcc8a1feb nginx-1.16.0]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx
[root@452fcc8a1feb nginx-1.16.0]# make && make install
[root@452fcc8a1feb nginx-1.16.0]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
[root@452fcc8a1feb nginx-1.16.0]# nginx
[root@452fcc8a1feb nginx-1.16.0]# yum provides ss
iproute-4.11.0-25.el7_7.2.x86_64 : Advanced IP routing and network device configuration tools
[root@452fcc8a1feb nginx-1.16.0]# yum install iproute
[root@452fcc8a1feb nginx-1.16.0]# ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:80
[root@452fcc8a1feb nginx-1.16.0]# cd /usr/local/nginx/html/
[root@452fcc8a1feb html]# vi index.html
<h1>This is a web01 in container</h1>
<div id="datetime">
<script>
setInterval("document.getElementById('datetime').innerHTML=new Date().toLocaleString();", 1000);
</script>
</div>
[root@452fcc8a1feb html]# curl 127.0.0.1
<h1>This is a web01 in container</h1>
<div id="datetime">
<script>
setInterval("document.getElementById('datetime').innerHTML=new Date().toLocaleString();", 1000);
</script>
</div>
4)把容器制作成镜像
[root@452fcc8a1feb html]# exit
exit
[root@docker01 ~]# docker commit web01 web01:001
sha256:bb609613ea713af01f2bdbe6c5a303be27977e3f4fce539739b6bac0cd5a218a
5)将镜像导出到docker02上,在docker02上根据此镜像运行一个容器,测试访问界面内容
[root@docker01 ~]# docker save -o web01-001.tar web01:001
[root@docker01 ~]# ls
web01-001.tar
[root@docker01 ~]# scp web01-001.tar 192.168.1.129:/
[root@docker02 ~]# ls /
web01-001.tar
[root@docker02 ~]# docker load -i /web01-001.tar
[root@docker02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web01 001 bb609613ea71 29 minutes ago 367MB
[root@docker02 ~]# docker run -it --name web02 web01:001
[root@0a8ff2b6adbd /]# nginx
[root@0a8ff2b6adbd /]# curl 127.0.0.1
<h1>This is a web01 in container</h1>
<div id="datetime">
<script>
setInterval("document.getElementById('datetime').innerHTML=new Date().toLocaleString();", 1000);
</script>
</div>
6)扩展:使其外网可以访问到
[root@0a8ff2b6adbd /]# exit
[root@docker02 ~]# docker run -itd --name web03 -p 80 web01:001 nginx -g "daemon off;"
b1b2396f46b281cb6301599d677deabcc41a5c4a612bfda82b456bef2836f591
[root@docker02 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b1b2396f46b2 web01:001 "nginx -g 'daemon of…" 42 seconds ago Up 42 seconds 0.0.0.0:32768->80/tcp web03
[root@docker02 ~]# curl 192.168.1.129:32768
<h1>This is a web01 in container</h1>
<div id="datetime">
<script>
setInterval("document.getElementById('datetime').innerHTML=new Date().toLocaleString();", 1000);
</script>
</div>
Windows浏览器访问测试:
Docker架构图
一、docker是一个C/S模式的架构,后端是一个松耦合架构,模块各司其职。
- 用户是使用Docker Client与Docker Daemon建立通信,并发送请求给后者。
- Docker Daemon作为Docker架构中的主体部分,首先提供Server的功能使其可以接受Docker Client的请求;
- Engine执行Docker内部的一系列工作,每一项工作都是以一个Job的形式的存在。
- Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动graphdriver将下载镜像以Graph的形式存储;
- 当需要为Docker创建网络环境时,通过网络管理驱动networkdriver创建并配置Docker容器网络环境;
- 当需要限制Docker容器运行资源或执行用户指令等操作时,则通过execdriver来完成。
- libcontainer是一项独立的容器管理包,networkdriver以及execdriver都是通过libcontainer来实现具体对容器进行的操作。
二、Docker各模块组件分析
(一)Docker Client【发起请求】
-
Docker Client是和Docker Daemon建立通信的客户端。用户使用的可执行文件为docker(类似可执行脚本的命令),docker命令后接参数的形式来实现一个完整的请求命令(例如docker images,docker为命令不可变,images为参数可变)。
-
Docker Client可以通过以下三种方式和Docker Daemon建立通信:tcp://host:port,unix://path_to_socket和fd://socketfd。
-
Docker Client发送容器管理请求后,由Docker Daemon接受并处理请求,当Docker Client接收到返回的请求相应并简单处理后,Docker Client一次完整的生命周期就结束了。[一次完整的请求:发送请求→处理请求→返回结果],与传统的C/S架构请求流程并无不同。
(二)Docker Daemon【后台守护进程】
- Docker Daemon的架构图
1、Docker Server【调度分发请求】
Docker Server的架构图
- Docker Server相当于C/S架构的服务端。功能为接受并调度分发Docker Client发送的请求。接受请求后,Server通过路由与分发调度,找到相应的Handler来执行请求。
- 在Docker的启动过程中,通过包gorilla/mux,创建了一个mux.Router,提供请求的路由功能。在Golang中,gorilla/mux是一个强大的URL路由器以及调度分发器。该mux.Router中添加了众多的路由项,每一个路由项由HTTP请求方法(PUT、POST、GET或DELETE)、URL、Handler三部分组成。
- 创建完mux.Router之后,Docker将Server的监听地址以及mux.Router作为参数,创建一个httpSrv=http.Server{},最终执行httpSrv.Serve()为请求服务。
- 在Server的服务过程中,Server在listener上接受Docker Client的访问请求,并创建一个全新的goroutine来服务该请求。在goroutine中,首先读取请求内容,然后做解析工作,接着找到相应的路由项,随后调用相应的Handler来处理该请求,最后Handler处理完请求之后回复该请求。
Engine
- Engine是Docker架构中的运行引擎,同时也Docker运行的核心模块。它扮演Docker container存储仓库的角色,并且通过执行job的方式来操纵管理这些容器。
- 在Engine数据结构的设计与实现过程中,有一个handler对象。该handler对象存储的都是关于众多特定job的handler处理访问。举例说明,Engine的handler对象中有一项为:{“create”: daemon.ContainerCreate,},则说明当名为"create"的job在运行时,执行的是daemon.ContainerCreate的handler。
job
- 一个Job可以认为是Docker架构中Engine内部最基本的工作执行单元。Docker可以做的每一项工作,都可以抽象为一个job。例如:在容器内部运行一个进程,这是一个job;创建一个新的容器,这是一个job。Docker Server的运行过程也是一个job,名为serveapi。
- Job的设计者,把Job设计得与Unix进程相仿。比如说:Job有一个名称,有参数,有环境变量,有标准的输入输出,有错误处理,有返回状态等。
(三)Docker Registry【镜像注册中心】
- Docker Registry是一个存储容器镜像的仓库(注册中心),可理解为云端镜像仓库,按repository来分类,docker pull 按照[repository]:[tag]来精确定义一个image。
- 在Docker的运行过程中,Docker Daemon会与Docker Registry通信,并实现搜索镜像、下载镜像、上传镜像三个功能,这三个功能对应的job名称分别为"search",“pull” 与 “push”。
- 可分为公有仓库(docker hub)和私有仓库。
(四)Graph【docker内部数据库】
- Graph的架构图
1、Repository
- 已下载镜像的保管者(包括下载镜像和dockerfile构建的镜像)。
- 一个repository表示某类镜像的仓库(例如Ubuntu),同一个repository内的镜像用tag来区分(表示同一类镜像的不同标签或版本)。一个registry包含多个repository,一个repository包含同类型的多个image。
- 镜像的存储类型有aufs,devicemapper,Btrfs,Vfs等。其中centos系统使用devicemapper的存储类型。
- 同时在Graph的本地目录中,关于每一个的容器镜像,具体存储的信息有:该容器镜像的元数据,容器镜像的大小信息,以及该容器镜像所代表的具体rootfs。
2、GraphDB
- 已下载容器镜像之间关系的记录者。
- GraphDB是一个构建在SQLite之上的小型图数据库,实现了节点的命名以及节点之间关联关系的记录
(五)Driver【执行部分】
Driver是Docker架构中的驱动模块。通过Driver驱动,Docker可以实现对Docker容器执行环境的定制。即Graph负责镜像的存储,Driver负责容器的执行。
graphdriver
- graphdriver架构图
- graphdriver主要用于完成容器镜像的管理,包括存储与获取。
- 存储:docker pull下载的镜像由graphdriver存储到本地的指定目录(Graph中)。
- 获取:docker run(create)用镜像来创建容器的时候由graphdriver到本地Graph中获取镜像。
networkdriver
- networkdriver的架构图
networkdriver的用途是完成Docker容器网络环境的配置,其中包括
- Docker启动时为Docker环境创建网桥;
- Docker容器创建时为其创建专属虚拟网卡设备;
- Docker容器分配IP、端口并与宿主机做端口映射,设置容器防火墙策略等。
execdriver
- execdriver的架构图
- execdriver作为Docker容器的执行驱动,负责创建容器运行命名空间,负责容器资源使用的统计与限制,负责容器内部进程的真正运行等。
- 现在execdriver默认使用native驱动,不依赖于LXC。
(六)libcontainer【函数库】
- libcontainer的架构图
- libcontainer是Docker架构中一个使用Go语言设计实现的库,设计初衷是希望该库可以不依靠任何依赖,直接访问内核中与容器相关的API。
- Docker可以直接调用libcontainer,而最终操纵容器的namespace、cgroups、apparmor、网络设备以及防火墙规则等。
- libcontainer提供了一整套标准的接口来满足上层对容器管理的需求。或者说,libcontainer屏蔽了Docker上层对容器的直接管理。
(七)docker container【服务交付的最终形式】
- container架构
Docker container(Docker容器)是Docker架构中服务交付的最终体现形式。
Docker按照用户的需求与指令,订制相应的Docker容器:
- 用户通过指定容器镜像,使得Docker容器可以自定义rootfs等文件系统;
- 用户通过指定计算资源的配额,使得Docker容器使用指定的计算资源;
- 用户通过配置网络及其安全策略,使得Docker容器拥有独立且安全的网络环境;
- 用户通过指定运行的命令,使得Docker容器执行指定的工作。
Docker架构图参考:
Docker源码分析(一)之整体架构图
Docker源码分析(一):Docker架构