DOCKER概览

举报
docker君 发表于 2016/11/16 16:04:39 2016/11/16
【摘要】 Docker服务端是个daemon进程,管理Docker容器并与客户端交互。服务端监听/var/run/docker.sock这个套接字,提供命令行交互和RESTful API两种方式。

Docker概览

核心组件

DOCKER客户端与服务器

Docker服务端是个daemon进程,管理Docker容器并与客户端交互。服务端监听/var/run/docker.sock这个套接字,提供命令行交互和RESTful API两种方式。
Docker的daemon进程需要用root运行,docker用户组有root用户相同的权限,所以是种安全隐患。另外,默认通信方式是非认证的模式,所以也是不安全的,但是可以设置TLS认证。

Docker镜像

镜像的概念不是Docker发明的,甚至可以参照理解windows系统的ghost盗版方式。
Docker镜像是基于Union文件系统的一种分层结构,可以由一步一步的构建出来。可以参照理解纯净版的ghost windows(基础镜像),和安装了office等软件的ghost windows(FROM基础镜像)
镜像也可以理解为容器的“源代码”,后面会稍微展开一些。

Registry

上面说了镜像是容器的源代码,那么Registry就可以理解为代码库。
Registry官方提供一个公共库,是收费的。企业也可以搭建自己的私有Registry。

Docker容器

容器就涉及Docker大名鼎鼎的集装箱概念了,容器就是集装箱,镜像是货物。容器不关心具体镜像是什么,容器会按照相同的方式去管理镜像,如创建、启动、关闭、重启、销毁。
容器可以包含一个或多个进程,但是当前的主流做法(微服务)是单容器单进程。

底层依赖

Docker并不是凭空冒出来的,依赖于原来OS的一些功能。但是Docker也希望反向作用于容器标准化,于是有了libcontainer作为容器管理的抽象,后续好真正实现跨平台。
Docker底层依赖linux内核的namespace、cgroups、Union File System(可选:Device Manager、AUFS、vfs、btrfs),主要用于资源的隔离和控制,如文件系统、进程、网络等。所以Docker需要较新的内核版本,推荐是3.8以上。
Docker采用写时复制(https://en.wikipedia.org/wiki/Copy-on-write)技术,通过分层的文件系统保证高效率和很少占用空间。
Docker可以日志化容器中的标准输入输出,STDOUT/STDERR/STDIN,也支持伪tty终端,提供一个交互shell,可以用来定位和调试。
Docker底层依赖的设计思路可以参考公司内李国柱的博客:
http://3ms.huawei.com/hi/blog/11100_1899017.html?h=h
细节可参照陈皓的系列博客:
http://coolshell.cn/articles/17010.html
http://coolshell.cn/articles/17029.html
http://coolshell.cn/articles/17049.html
http://coolshell.cn/articles/17061.html
http://coolshell.cn/articles/17200.html

Docker命令

Docker命令大概分四类,参考:
http://www.infoq.com/cn/articles/docker-command-line-quest

功能划分 命令
环境信息相关 info version
系统运维相关 attach build commit cp diff export images import/save/load inspect kill port pause/unpause ps rm rmi run start/stop/restart tag top wait
日志信息相关 events history logs
Docker Hub服务相关 login pull/push search

其中大部分和LINUX命令相同的名字的命令,基本也是相似的语义。
info命令用于查看docker基本信息,会返回所有容器的镜像、执行和存储驱动、基本配置。容器保存在/var/lib/docker/containers 。

inspect命令可以查看容器的最详细信息。
images命令查看所有的镜像。镜像保存在宿主机的/var/lib/docker目录。
run命令是运行容器,-i参数保证STDIN开启,-t命令启动伪tty,两个参数可以保证启动容器后的交互。run指定的镜像,会先找本地,找不到会找仓库,找到一次就缓存到本地,整个过程类似maven的管理。
--name会给容器指定一个名字,这个很有用,会被很多地方引用,所以必须是唯一的,如果有重名,必须先rm掉旧的容器。-d表示daemon,创建一个长期运行的容器。-- rm表示一次性运行的容器,运行完容器的进程会自动删除容器。-h会指定容器的主机名,不指定的话默认是容器ID。--volumes-from指定从某个容器挂载所有的卷。
attach可以重新附着一个run的容器会话。
logs命令查看容器日志,-f参数使用和linux的tail –f类似。-t为日志加时间戳。
build构建镜像、history可以查看这个构建的过程。
exec命令在容器内启动新的进程,-d可以设置为daemon进程。

镜像和镜像的构建

镜像的原理

Docker镜像就是文件系统一层一层叠加出来的。
最底层是一个引导文件系统bootfs,类似linux的引导文件系统。docker用户不会和引导文件系统有交互,因为在容器启动后,就会被移到内存中,引导文件系统会被unmount,以便留出更多内存供initrd(boot loader initialized RAM disk)磁盘镜像使用。
引导文件系统上层是rootfs,rootfs是基于内存的文件系统,所有操作都在内存中完成;也没有实际的存储设备,所以不需要设备驱动程序的参与。基于以上原因,linux在启动阶段使用rootfs文件系统,当磁盘驱动程序和磁盘文件系统成功加载后,linux系统会将系统根目录从rootfs切换到磁盘文件系统。
linux引导过程中,root文件系统先按只读方式加载,引导完成,包括校验完成,会被切换为读写模式。但是Docker中,root文件系统永远都是只读模式,Docker用union mount技术又会在root文件系统之上加载其他的文件系统,这些也是只读的。
union mount会一次同时加载多个文件系统,但是从外看,只有一个文件系统。union mount把各层文件叠加到一起,这个看起来的最终的文件系统会包含所有底层的文件和目录。这个外观型的文件系统,就是镜像。
所以,容易理解,镜像也是可以一层一层叠加的,下层的镜像就是上层的parent image,最底层的镜像是base image。
当容器启动时,Docker在镜像的最顶层加载一个读写文件系统,在Docker中运行的程序就是在这个读写层执行的。刚启动时,这个读写层是空的,发生变化时,变化的部分会体现在这一层,这就是所谓的写时复制。
实际上,容器就是这个读写层+下面的镜像层+配置。

镜像的版本管理

镜像的版本管理貌似是参考了git的思路。
Docker Registry管理镜像,包含了镜像、层、和一些关于镜像的元数据。
Docker默认用的是官方的Registry,也就是Docker Hub,这个部分也是开源的,所以企业也可以搭建自己的私有Registry。Registry也可以运行在Docker中~
Docker Hub中有两种类型的仓库,user repository和top-level repository。用户仓库的镜像是Docker用户创建。顶级仓库是Docker内部人员管理,一般是由Docker合作厂家提供,如操作系统发行商。用户基于顶层的这些基础镜像来构建自己的镜像。
用户仓库的命名由用户名和仓库名两部分组成,如user/repo,顶层仓库只包含仓库名。
同一仓库中的镜像,可以通过加tag区分。相同镜像ID可以有多个TAG。
docker run命令从镜像启动一个容器时,如果镜像不在本地,docker默认会从Docker Hub下载镜像,如果没有显示指定tag,会默认下载latest标签的镜像。也可以通过docker pull命令,预先加载到本地。
docker search命令,查找所有Docker Hub上公共的可用镜像。docker push命令将镜像推送到docker hub。
Docker Hub还有个比较有意思的功能是“Trusted Build”,将Docker Hub关联GitHub上的Dockerfile文件,每次提交代码,都会触发一次构建,并创建新镜像。

构建镜像

https://docs.docker.com/engine/reference/builder/
这里边讲的“构建”,并不是说从零构建,这会复杂的多。一般说的构建镜像就是基于基础镜像去构建新镜像。从零构建可以参考.
https://docs.docker.com/engine/userguide/eng-image/baseimages/
构建镜像有两种方式:
1. 单步命令:docker commit
2. 批量方式:Dockerfile文件 + docker build命令
可以类比于java中的单个编译和ant脚本批量编译。commit命令一般不推荐使用,因为Dockerfile功能更强,也更灵活。
上面说Registry类似git仓库,其实commit命令其实类似git提交代码。下载镜像、基于它构建、构建镜像的过程,其实可以类比于下载代码,基于代码修改,提交代码的过程。
commit命令需要指定docker容器的ID(通过docker ps –l –q命令看刚创建的容器ID),一个目标仓库和镜像名。commit命令提交的只是差异部分,并不是全量提交,这也是分层的好处。

Dockerfile概览

Dockerfile实际上是定义了一种DSL,提供了一种批量构建镜像的方式。参考
Dockerfile所在的目录就是构建环境,被成文build context。Docker会在构建镜像时将这个目录和目录中的文件和子目录上传到Docker守护进程。Docker守护进程可以直接访问构建所需的任何代码、文件或其他的数据。
Dockerfile由一系列的指令和参数组成,每条指令,如FROM,都是大写字母。指令后面要加一个参数。Dockerfile中的指令从上到下按顺序执行。
每条指令都会创建一个新的镜像,并自动提交。相当于基于父镜像,每执行一条指令,就docker commit一次,然后新构建的镜像作为下一条指令的父镜像。直到所有指令执行完。
官方给了几个dockerfile的实例,举一个如下:

EXPOSE指定对外暴漏的接口,在实际宿主机上,还要做端口映射。方法是使用docker run命令的-p参数,可以随机分配,或指定端口映射,设置可以指定某个特定的宿主机的映射方式。也可以使用-P参数,直接暴露所有EXPOSE指令指定的端口。
RUN是最基本的运行指令,会在当前镜像中运行指定的指令。每条RUN都会创建一个新的镜像层,如果成功,就会提交镜像,然后继续执行下一条。
FROM会引入基础镜像,所有命令基于此开始构建。
# 开头是注释。

build dockerfile

docker build命令,会执行dockerfile,并返回最后一个成功的镜像。
build命令推荐指定镜像名和标签,没指定tag会默认打上latest标签。也可以打多个标签:
$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
build命令执行过程中,如上面所说,每一步都是独立的构建,每一步都会有一个镜像ID:
所以,在执行某一个指令失败时,会返回最后一个成功的镜像。可以在这个镜像的基础上,手工执行出错的指令,进行调试。而之前构建出来的镜像也会被作为缓存,再次构建不是从头开始,而是从失败的位置开始构建。如果需要关闭缓存,在build命令后加—no-cache参数。
构建的过程,也可以通过docker history命令回溯。

Dockerfile 指令

MAINTAINER

指明作者

CMD

CMD命令指定容器启动时要运行的命令;对应的,上面说的RUN是镜像构建时要运行的命令。参数格式和RUN命令相同,都支持数组形式参数:
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
CMD在一个dockerfile中只有一条,即使配置了多条,也只有最后一条生效。
要注意的是,启动命令可以被docker run命令指定的启动命令覆盖。

ENTRYPOINT

ENTRYPOINT和CMD非常类似,区别在于不能被覆盖。docker run命令指定的任何参数都会被当作参数再次船体给ENTRYPOINT指令中指定的命令。

ENV

ENV命令,顾名思义,设置构建镜像的环境变量。从构建的镜像启动容器,环境变量就会生效,且持久生效。对应的docker run命令-e指定的环境变量,只会在运行时有效。

WORKDIR

容器启动的工作目录。CMD和ENTRYPOINT都会从这个目录下执行。可以设置多次,运行不同指令,如:
WORKDIR /a RUN xxx WORKDIR b CMD xxx run命令的-w可以覆盖工作目录

USER

指定镜像以什么用户运行。run命令的-u选项可以覆盖

VOLUME

向容器添加卷。卷是docker设计的一种共享方式,可以绕过unionfs,在不同容器间持久化共享数据。可以用来存放调试代码、日志管理、数据共享等用途。
卷有几个特性:
1.卷在容器间共享和重用
2.对卷的修改是即时生效的
3.卷的修改不会对更新镜像产生影响
4.直到所有引用的容器都被删除,卷才会被删除(要注意删除容器,卷被误删)
5.卷这个参数不是必须的,容器可以选择不共享
可以通过数组参数,指定多个卷。
提交或创建镜像时,镜像中不包含卷。

ADD

ADD把构建目录下的文件和目录复制到镜像中。文件源支持正常路径和URL模式。目的路径如果不存在,会创建全路径。
ADD有个奇葩的隐藏功能,会根据地址参数末尾的字符来判断是文件还是目录,比如以/结尾,就认为是目录。
另一个奇葩的隐藏功能,如果将gzip等标准压缩格式作为源,ADD会自动解压。

COPY

COPY和ADD基本一样,只是不会自动解压。个人认为docker这种ADD/COPY,CMD/ENTRYPOINT的设计非常奇葩。这个命令创建的文件和目录的UID和GID都会设为0。拷贝的内容包含文件系统的元数据。

ONBUILD

这是个钩子,当镜像作为父镜像构建时,钩子会被调用。
ONBUILD后面可以加任何构建指令,插入的指令可以认为是紧跟在FROM之后执行的。
可以结合这个命令和构建缓存的功能,制作构建模板。

Docker网络和容器互联

Docker网络

docker支持两种网络驱动,bridge 和overlay ,默认是网桥模式。
如果不特意指定,守护进程管理所有容器的网络连接,都是通过docker0这个虚拟网桥:
ubuntu@ip-172-31-36-118:~$ ifconfig
docker0 Link encap:Ethernet HWaddr 02:42:47:bc:3a:eb
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:47ff:febc:3aeb/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:9001 Metric:1
RX packets:17 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1100 (1.1 KB) TX bytes:648 (648.0 B)
docker0接口有符合RFC1918的私有IP地址,范围是172.16~172.30,上例中的网关地址是172.17.0.1,也是所有docker容器的网关地址。
docker创建一个容器就会创建一组互联的网络接口,一端是容器的eth0,一段是docker0,这样Docker相当于管理了一个虚拟子网。
默认容器和宿主机网络是不通的,除非指定打开端口。

容器互联

docker容器重启,就会改变IP地址。这对需要互联的容器很不方便,所以docker提供了link功能。link可以把一个或多个docker容器连接起来,互相通信。
https://docs.docker.com/engine/userguide/networking/work-with-networks/#linking-containers-in-user-defined-networks
link需要引用容器的名字,所以上文也强调过名字的重要性。
docker run –link选项,可以创建两个容器间的父子连接,有两个参数,一个是要连接的容器名,另一个参数是连接后容器的别名。别名可以让使用者不关注底层容器的名字。
因为是父子连接,所以不是双向的,但是可以运行两个命令来达到双向的目的:
$ docker run --net=isolated_nw -itd --name=container4 --link container5:c5 busybox
01b5df970834b77a9eadbaff39051f237957bd35c4c56f11193e0594cfd5117c
$ docker run --net=isolated_nw -itd --name=container5 --link container4:c4 busybox
72eccf2208336f31e9e33ba327734125af00d1e1d2657878e2ee8154fbb23c7a
$ docker attach container4
/ # ping -w 4 c5
PING c5 (172.25.0.5): 56 data bytes
64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms
--- c5 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms
/ # ping -w 4 container5
PING container5 (172.25.0.5): 56 data bytes
64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms
--- container5 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms
$ docker attach container5
/ # ping -w 4 c4
PING c4 (172.25.0.4): 56 data bytes
64 bytes from 172.25.0.4: seq=0 ttl=64 time=0.065 ms
64 bytes from 172.25.0.4: seq=1 ttl=64 time=0.070 ms
64 bytes from 172.25.0.4: seq=2 ttl=64 time=0.067 ms
64 bytes from 172.25.0.4: seq=3 ttl=64 time=0.082 ms
--- c4 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.065/0.070/0.082 ms
/ # ping -w 4 container4
PING container4 (172.25.0.4): 56 data bytes
64 bytes from 172.25.0.4: seq=0 ttl=64 time=0.065 ms
64 bytes from 172.25.0.4: seq=1 ttl=64 time=0.070 ms
64 bytes from 172.25.0.4: seq=2 ttl=64 time=0.067 ms
64 bytes from 172.25.0.4: seq=3 ttl=64 time=0.082 ms
--- container4 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.065/0.070/0.082 ms
父容器可以直接访问自容器的任意公开端口,而且只有配置--link连接的容器才能访问。容器端口甚至不需要对宿主机开放。
连接只能运行在同个宿主机中,不能运行在不同宿主机。
配置link,会在父容器的dns配置文件,如/etc/hosts里写入IP,重启后,这个IP也会随着刷新。不过docker技术变化很快,这种底层的技术也可能变化很快。

Docker REST API

Docker生态有三种API:Registry API、Docker Hub API、Docker Remote API,前两个是与仓库交互,最后一个是与docker daemon进程交互。
REST API支持证书认证。
基本接口和docker命令都能一一对应,如/images/json返回结果和docker images命令非常类似。还可以控制容器,如/containers/start

容器编排

容器编排有两大类,一种是简单的把容器连起来,如Fig;一种是更强大的容器编排,包括服务发现,动态伸缩,调度等,如Consul(服务发现),kubernetes、mesos(集群调度和管理),swarm。
每个话题都很大,这里不展开。

邮件组的交流约定

描述问题一般有个约定,要给出背景信息:
docker info和docker version的输出
uname –a命令的输出
要描述你想要什么,希望它如何工作,尝试了什么。
提问前可以先搜索,参考提问的艺术。

作者 | 林钰鑫

转载请注明出处:华为云博客 https://portal.hwclouds.com/blogs

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。