Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖环境到一个可移植的容器中,然后发布到任何流行的 Linux 机器上。接下来我首先简单的解释一下docker的原理,然后了解一下docker镜像的构建基本操作,最后演示如何运行docker镜像。


1.原理篇

Docker可以把应用程序和它所依赖的从操作系统到软件包的环境打包成一个镜像文件。听起来好像一个典型的虚拟机,但是Docker要比虚拟机轻量的多。那么,Docker和一个完全的虚拟机有何区别?Docker是如何做到提供一个完整的文件系统,独立的网络环境等等这些功能,同时还没有如此庞大?

一个功能完整的虚拟机要在宿主机器上重新运行一个Guest Os已达到隔离环境的作用,在Docker的哲学里,这是严重的资源浪费。下图基本上描述了Docker容器和虚拟机的区别。

enter image description here

Docker核心是一个操作系统级虚拟化方法, 理解起来可能并不像VM那样直观。我们从虚拟化方法的四个方面:隔离性、资源限制性、便携性、安全性来详细介绍Docker的技术细节。

(1).隔离性

传统的vm用一个操作系统实现隔离性,而Docker基于LXC(linux container)实现隔离性。LXC是通过kernel namespace实现隔离性的。简单说就是同一个linux操作系统中可以存在多个不同的命名空间(容器),不同namesapce中可以存在相同的pid、net、ipc、mnt、uts等。

(2).资源限制性

Docker通过使用cgroups 实现了对资源的配额和度量。 cgroups 的使用非常简单,可实现对单个进程(容器)的资源控制。groups可以限制blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns九大子系统的资源

(3).便携性

Docker通过使用AUFS (AnotherUnionFS)实现便携性。AUFS(AnotherUnionFS) 是一种 Union FS, 简单来说就是支持将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)的文件系统, AUFS 里有一个类似分层的概念, 通过将一个 readonly 的 branch 和一个 writeable 的 branch 联合在一起,就可以实现对 readonly 权限的 branch 进行增量的进行修改(不影响 readonly 部分的)。

在Docker利用 union mount 的方式将一个 readwrite 文件系统挂载在 readonly 的rootfs之上,并且允许再次将下层的 FS(file system) 设定为readonly 并且向上叠加, 这样一组readonly和一个writeable的结构构成一个container的运行时态, 每一个FS被称作一个FS层。如下图:

enter image description here

(4).安全性

关于安全性相关文章请参考Docker官方文档


2.构建镜像

Docker需要linux kernel 3.8以上,安装过程非常简单,在此不再赘述,详细步骤参考官方安装文档

在Docker中开发者可以打包他们的应用以及依赖环境到一镜像中,并可以在任意docke容器中运行这个镜像。在docker的官方register中,有各种操作系统的镜像,我们可以基于这些镜像构建自己的镜像。构建镜像的有两种方法。

(1).通过Dockerfile创建镜像

Dockerfile基本上是自解释的,从一个基础镜像开始,通过RUN命令在基本镜像上安装环境,然后通过CMD命令指定镜像启动的命令。下面的Dockerfile从ubuntu14.04镜像开始,安装并配置好sshd服务。

FROM     ubuntu:14.04
MAINTAINER Thatcher R. Peskens "thatcher@dotcloud.com"
RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:screencast' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

编辑好Dockerfile后,可以通过docker build命令生成image。

sudo docker build -t test_sshd .

然后可以通过如下命令查看刚才生成的镜像。运行image的命令请参考docker官方文档

sudo docker images

(2).通过commit创建镜像

我们可以先以交互的方式启动一个操作系统镜像,然后在其中做各种修改,最后通过commit命令提交。具体步骤如下: 首先通过交互的方式启动一个镜像,这样会进入镜像操作系统shell中:

sudo docker run -t -i utuntu

然后在镜像操作系统中做各种修改,退出镜像操作系统。

root@040acbb6c8c:/# exit

记下镜像标志:040acbb6c8c,最后通过commit命令提交刚才所做的修改。

sudo docker commit -m 'your commit message' -a 'your author info' 040acbb6c8c your-image-name

这样一个新的image就生成了。通过以下命令就可以查看刚才生成的镜像了。

sudo docker images

3.运行镜像

镜像的运行还是比较简单的,比如如下命令运行ubuntu镜像并用echo输出hello world。

sudo docker run ubuntu echo 'hello world'

这条命令使用ubuntu镜像,如果本地docker镜像库中没有ubuntu镜像,会首先从docker的官方register中下载ubuntu镜像。echo输出完成后,改镜像就执行完成并退出了。

如何让一个镜像在docker容器中长期运行呢?比如如下命令启动一个带有sshd服务的镜像,并长期运行。

sudo docker run -d ubuntu-sshd /bin/bash -c ‘sshd -D’

两个方面保证了该镜像在容器中长期运行,第一是run命令的-d参数,表示容器以detach的方式运行;第二是镜像初始化脚本中sshd的-D参数,-D参数表示sshd以非daemonized,非detach的方式运行。镜像运行后,可以通过

sudo docker ps

查看运行的容器实例。并通过

sudo docker inspect

查看容器的ip地址等信息。docker运行image相关的参数有很多,包括容器和宿主机器之间的端口映射等参数,本文都没有涉及,请参考官方手册。


关于docker的虚拟化相关讨论问题可参考这篇文章

Unicode字符多种多样,除去ascii中的字母、数字、标点和中文字符,还包括其它多种语言和多种符号,有些符号甚至很难打出来,这时候该如何表示呢?接下来我们首先简单的介绍以下Unicode的编码特点,然后针对不同的场景分别介绍如何写正则表达式。


1.Unicode的编码特点

每一个Unicode字符都对应一个唯一的Unicode编码,一种语言的Unicode编码是在一个连续区间内的,除了这些基本特征外,Unicode编码还有三种属性Property、 Block、Script。我们可以用\p引用Unicode的属性,

Property用于表示字符本身的功能,比如符号,空格,字母等。可以用\p{L}表示字母、文字,而对应\P{L}表示不是字母、文字。Property是与语言无关的,即\p{L}用于表示所有语言的字符。比如:

L或者Letter:所有语言的字符
P或者Punctuation:所有语言的标点 
S或者Separator:所有语言的分隔符

Block表示Uincode的一个区间,某种语言的字符通常是落在同一区间的,所以可以通过Block粗略表示某类语言的字符,比如\p{InHebrew}表示希伯莱语字符,\p{InCJK_Compatibility}表示兼容CJK(汉语、韩语、日本语)的字符。如下表所示:每一个Block表示方法都对应一段编码区间:

InCJK_Compatibility:\u3300–\u33F
InHebrew:\u0590–\u05F

Script表示Uincode的一个书写系统,比如\p{Greek}表示希腊语字符,\p{Han}表示汉语(中文字符),比如如下列举了希腊,汉语和阿拉伯书写系统。

Greek
Han
Arabic

2.Unicode正则应用案例

  • 匹配单个Unicode字符,下面例子去掉"发"字。
String testStr = “发财了,发了”;
testStr.replaceAll("\u53d1",testStr);
  • 匹配所有标点符号,下面例子去掉所有标点符号
String testStr = “发财了,发了!<Software Engineer is great!>;
testStr.replaceAll("\\pP",testStr);
  • 匹配某种语言,下面例子去掉所有汉字
String testStr = “发财了,发了!<Software Engineer is great!>;
testStr.replaceAll("\\pHan",testStr);

关于uicode编码属性可以参考这篇文章
关于Unicode码表可以参考这里