(六):像谷歌一样部署你的应用
最后更新于:2022-04-01 04:46:37
> 原文:http://www.infoq.com/cn/articles/deploy-your-application-like-google
## 1.概述
谷歌发起的开源项目从来都是广受技术圈的关注和讨论,本文将介绍的就是最新的容器编排管理系统[ ](http://kubernetes.io/)[Kubernetes](http://kubernetes.io/)。Kubernetes开源项目版本更新频繁,对于初次使用者来说其定义大量的技术术语并且随时会有新术语出现。在这种不稳定的技术框架之下,对使用者来说确实带来了一定的技术门槛。为了掌握Kubernetes的核心技术概念,本文尝试通过深入阅读官方文档资料并整理出核心的使用实践思路,以飧国内Kubernetes技术爱好者参考研究。
### 1.1 Kubernetes是什么
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb26f31b.png)
Kubernetes是一个容器集群的编排管理系统。这里对于“编排”的理解应该基于如何在跨Docker主机的场景之下统一管理容器集群的方法。当前的Docker技术主要提供单机版的容器管理实践,很多第三方厂商通过自己以往的网络经验推出自己的容器编排工具,Google推出的Kubernetes技术是在这个背景下创立的开源项目。这个项目尝试要解决的问题就是简化开发和运维容器集群的工作,让开发和运维能把这个系统当一台电脑看待。这个思想在没有Docker容器技术之前,早已在分布式系统中得到大量应用,类如Hadoop、Mesos、Yarn。由于虚拟化技术的限制,对于更大实例规模仍然有很大的局限性。Docker技术出现后,本来已经很复杂的分布式系统开始尝试向更大规模的集群规模实现,这个实现标准的诱惑力让更多的厂商参与进来并尝试在原有Mesos、Yarn类集群调度系统中开始应用Docker技术。那么Kubernetes和Mesos类相比较,它的优势是没有资源调度算法,只关注容器的管理。而Mesos、Yarn之类调度系统本身有完善的调度系统经验,如何把Docker编排的架构加入到原有系统中,需要一些标准设计参考实现,这个时候Kubernetes的出现正好弥补了这个需要。
### 1.2 Kubernetes技术术语概览
第一,在Kubernetes的集群环境里Pods是最小的可部署单元,它表示同属于一个应用的容器群的逻辑集合。
第二,Master节点提供了集群统一视图的中心控制点。我们可以用一个Master节点来控制多个Minion节点。
第三,Minion是一个工作节点,它将运行Master节点交付的任务。Minions能运行一个或多个Pods。它提供了在容器环境下一个应用级别的虚拟机。
通过以下概念图,我们可以更加清晰的看到Kubernetes的技术全貌。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb28483a.png)
让我们再深入一点,讲一讲Kubernetes是如何做到这些特性的。
* Replication Controller 是Master上的资源控制器,确保创建、销毁Pods的请求能随时被Minions节点运行。这样可以保证集群中的Pod可以永远提供服务,而当Pod运行失败后可以立即开启新Pod实例,保证Pod实例服务的可用性可以保证。
* Service 提供统一的名称和地址,提供针对一组Pods的负载均衡。这个Service其实就是微服务的实现,它在我们创建的Pods的基础之上提供一层抽象。比如我们的Service是一个Job服务,前端应用可以直接发布任务到指定的Servcie IP就可以了,用户对于这个Job服务有多少个实例提供服务不需要关心。
* Label 是一个强制的键值对,保存在分布式存储服务etcd上,让Replication Controller能用它去实现服务发现。
* Kubelet 是在每个Minion上管理容器的守护进程,它是实际管理Docker主机来启动容器的管理程序。
* Master API Server 提供RESTful K8s API接口来校验和配置Pod、Service和Replication Controller,它是统一管理集群系统的入口。
### 1.3 与Docker工具链的关系
Docker近期推出的三大套件:Compose、Swarm、Machine都提供了一些Kubernetes的功能,我们需要了解他们之间的区别,让我们能更好的利用Kubernetes做好基础。
* Docker Machine是比较底层的入口,比Kubernetes的实现更底层一些。Machine提供了基础设施IaaS的能力,方便管理混合云状况下的Docker主机。类似Google Compute Engine。
* Docker Swarm完全基于Docker API之上定义的Cluster API。方向上是Docker API提供单机范围内的API,由Swarm提供Cluster级别的API。Google的Kubernetes团队在早期Swarm实现讨论上[提供了自己的意见](https://github.com/docker/docker/pull/8859)。
* Docker Compose还是单机版的开发套件,对于开发者来说,可以使用它把当前的代码构建出指定的Docker Image,然后运行在单机上。Kubernetes就是为了解决部署到容器集群的难度而定义的标准实现。当前Compose正在实现基于Swarm和Machine实现集群编排的能力,这种能力就是Kubernetes的直接竞争对手。
## 2.使用实战
我们可以参照官方提供的[各类平台安装脚本](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/cluster)来部署Kubernetes集群系统,本文采用Ubuntu系统作为基础系统用来安装Kubernetes集群。官方提供的脚本按照以下几步安装即可安装成功:
首先,把Kubernetes的源码下载到每一台集群机器上,自行构建最新版的套件。
~~~
$ cd cluster/ubuntu-cluster
$ sudo ./build.sh
$ sudo cp ./binaries/* /opt/bin #复制到/opt/bin目录,主要是为了方便部署脚本调用。
~~~
然后,配置Kubernetes集群组件,假设我们的机器清单如下:
| IP Address | Role |
|---|---|
| 192.168.100.30 | master |
| 192.168.100.31 | minion |
| 192.168.100.32 | minion |
只需要到cluster/ubuntu-cluster目录下执行一遍configue.sh就可以完成配置。
比如在master节点(192.168.100.30)上:
~~~
$ sudo ./configure.sh
Welcome to use this script to configure k8s setup
Please enter all your cluster node ips, MASTER node comes first
And separated with blank space like " ": 192.168.100.30 192.168.100.31 192.168.100.32
This machine acts as
both MASTER and MINION: 1
only MASTER: 2
only MINION: 3
Please choose a role > 2
IP address of this machine > 192.168.100.30
Configure Success
~~~
当你看到信息“Configure Success” 时代表这台机器的配置算完成了。
当然,在官方的Ubuntu例子中,它使用Flannel创建了一套覆盖网络(Overlay Network),通过这个网络实现了跨主机的容器互联互通。大家可以通过图1flannel网络截图知道flannel0和docker0被分在同一网段,Docker内部容器ip和docker0网关之间是有NAT的,通过flannel+etcd提供自定义的udp数据包,实现跨主机的容器之间的互联,通过这个例子可以帮我们深入的理解跨主机容器互联SDN的主要实现思路。
图1 flannel网络截图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb2a0399.png)
在部署完Kubernetes系统后我们可以通过内置的命令来验证服务是否正常。比如运行
~~~
$ kubectl get minions
NAME LABELS STATUS
192.168.100.30 NotReady
192.168.100.31 Ready
192.168.100.32 Ready
~~~
好了,系统成功了。我在部署的过程中发现,并不是每次都能顺利完成安装。比如端口被占用,关键服务没起来等情况。那么我把这些情况总结一下,方便大家排除故障:
* master节点,主要的服务是kube-apiserver、kube-controller-manager、kube-scheduler,如下截图显示需要保证能运行:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb2c341b.png)
如果没有看到运行的进程,应该去看一下运行日志,在Ubuntu的安装实例中,日志统一放在/var/log/upstart/目录下。
* slave节点,主要的服务是kube-proxy、kubelet两个服务,如下截图显示需要保证能运行:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb2d646d.png)
* 网络相关的组件,主要是etcd服务,还有SDN的组件服务类如Flannel。这一块出问题的情况很少,我遇到大多数问题都是集中在网络拓扑上,通过学习理解这种网络就可以基本解决问题。
* Kubernetes项目还不是生产级别的工程,没有在实际的场景中经过生产级别的验证。我们正好通过官方提供的example目录中的例子理解我们的场景中到底需要什么功能,然后反馈到社区,让Kubernetes越来越成熟。
## 3.总结
Kubernetes在2014年9月发布第一个版本之后,版本迭代都是按周实施的。官方还不建议用户在生产环境中使用这套系统。但是它的设计思想以及简洁的架构设计足以让我们借鉴到很多工程上的宝贵经验。在借鉴的成功案例中,红帽的Openshift最新版本V3中就成功应用了Kubernetes实现技术。所以,Kubernetes项目是一个值得大家借鉴学习的优秀开源项目,通过理解它的设计思想,可以很快应用到本地的容器编排集群系统实现中。
(五):基于Fig搭建开发环境
最后更新于:2022-04-01 04:46:35
> 原文:http://www.infoq.com/cn/articles/docker-build-development-environment-based-on-fig
## 1\. 概述
在搭建开发环境时,我们都希望搭建过程能够简单,并且一劳永逸,其他的同事可以复用已经搭建好的开发环境以节省开发时间。而在搭建开发环境时,我们经常会被复杂的配置以及重复的下载安装所困扰。在Docker技术未出现之前,我们可以使用Pupet、Chef、Ansible等配置管理工具把复杂的配置管理起来,这样的管理配置技术仍然是目前比较流行的方式之一。配置管理工具使用的都是自己的DSL语法定义,考虑到环境的复杂性,配置一套通用的开发环境需要针对各个系统定制,对于大部分开发环境这种维护成本仍然是很高的。Docker技术出现之后,系统的依赖问题得到了彻底的解决,我们可以通过镜像的方式简化环境的安装。结合Docker的开发部署工具Fig,我们可以使用fig.yml文件来定义所有的环境,一次定义,多处使用,简单而且高效。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb20e131.png)
### 1.1 打包的方式
Docker本省并不能创建一个真实的虚拟机,它只是基于Linux Kernel把额外的系统文件做了封装,并利用Linux Kernel相关的技术如Cgroup、Namespace隔离用户应用。应用Docker技术,团队之间通过共享Image或者Dockefile来复用开发环境。为了简化写Dockerfile的方式 ,Fig提供更加精简的DSL定义文件fig.yml,可以让新成员快速搭建开发环境并将精力投入到开发过程中去,而不是研究如何正确安装并配置诸如PostgreSQL之类的数据库。目前,软件开发需要的环境Image,大部分都可以在[Docker Hub](https://hub.docker.com/)中搜索到,需要使用时直接下载就可以使用。
### 1.2 应用组合的方式
使用Docker之后,我们不再需要在本地机器安装所有的软件包。我们可以根据项目需要在Docker Hub上搜索相关软件的Image,然后使用Fig pull从Docker Hub上直接下载并由Fig调用Docker的Link命令把Image关联起来,这样所有应用都可以直接调用指定端口的服务,比如Mysql的3306端口提供数据库服务。开发者并不需要对Docker有太多的了解,只需要掌握常用的几条Fig命令就可以随时调试自己的环境。
### 1.3 环境共享的方式
Fig直接定义好了Image,我们不需要过多的关心容器或者镜像。在分享环境时,只需要把对应的Dockerfile和fig.yml文件分享给同事,他们就可以在自己的机器上运行并搭建出需要的环境,且不用再担心环境依赖带来的意外调试烦恼。团队成员在git clone项目代码后,就可以如下图一样使用一条命令启动自己的开发环境:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb21df22.gif)
## 2\. Fig安装指南
首先,我们需要安装Docker Engine,官方针对主流的系统提供了对应的[安装手册](https://docs.docker.com/installation/)。这里,我的开发机系统是一台MacBook Pro,所以我需要[安装boot2docker](http://www.fig.sh/install.html)来支持Docker。
接下来,我们就可以安装对应系统版本的Fig运行文件。比如在Mac OS或者在64位的Linux上安装Fig:
~~~
$ curl -L https://github.com/docker/fig/releases/download/1.0.0/fig-`uname
-s`-`uname -m` > /usr/local/bin/fig; chmod +x /usr/local/bin/fig
~~~
当以上的安装方式不能成功的话,我们可以选择使用Python Package的安装方式:
~~~
$ sudo pip install -U fig
~~~
最后,不管使用什么Linux系统,安装完Fig之后通过运行以下命令来确保环境的一致性。
~~~
$ fig --version
~~~
如果一切顺利的话,恭喜你,Fig安装成功了。下面请随我一起学习如何使用Fig配置开发环境。
## 3\. Rails开发环境配置详解
我们来配置一套最常用的Rails+PostgreSQL项目。
第一步,确保Fig已经正确的安装到主机系统,如果还没有,请参考上一章节的安装指南。
第二步,在项目根目录下存放一个名为 Dockerfile 文件:
~~~
FROM ruby
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
RUN bundle install
ADD . /myapp
~~~
第三步,创建一个 Gemfile 文件用来定义Rails软件包。 内容如下所示:
~~~
source 'https://rubygems.org'
gem 'rails', '4.0.2'
~~~
第四步,创建一个fig.yml文件,并使用以下配置文件来做最后的环境初始化。
~~~
db:
image: postgres
ports:
- "5432"
web:
build: .
command: bundle exec rackup -p 3000
volumes:
- .:/myapp
ports:
- "3000:3000"
links:
- db
~~~
第五步,当前你目录下空空如也,使用如下命令可以生成一套Rails项目骨架:
~~~
$ fig run web rails new . --force --database=postgresql --skip-bundle
~~~
当你跑完以上命令,你就会得到一个崭新的Rails项目。
~~~
$ ls
Dockerfile Rakefile config fig.yml public vendor
Gemfile app config.ru lib test
README.rdoc bin db log tmp
~~~
编辑一下Gemfile文件,去掉therubyracer包的注释, 让Rails依赖的Javascript的运行时环境。
~~~
gem 'therubyracer', platforms: :ruby
~~~
所有的文件编辑都做完之后,运行命令创建开发环境image。
~~~
$ fig build
~~~
运行完build命令后,我们就有了可以立即使用的Image。这两个Image的名字分别是web和db。为了让db能连上web,我们通常还需要修改database.yml来支持数据库连接。
development: &default adapter: postgresql encoding: unicode database: postgres pool: 5 username: postgres password: host: db test: <<: *default database: myapp_test
好了,让我们运行一下:
~~~
$ fig up
~~~
命令行将显示如下日志:
~~~
Recreating figtest_db_1...
Creating figtest_web_1...
Attaching to figtest_db_1, figtest_web_1
db_1 | LOG: database system was shut down at 2014-10-01 23:53:11 UTC
db_1 | LOG: autovacuum launcher started
db_1 | LOG: database system is ready to accept connections
web_1 | [2014-10-01 23:53:16] INFO WEBrick 1.3.1
web_1 | [2014-10-01 23:53:16] INFO ruby 2.1.2 (2014-05-08) [x86_64-linux]
web_1 | [2014-10-01 23:53:16] INFO WEBrick::HTTPServer#start: pid=1 port=3000
db_1 | FATAL: database "myapp_development" does not exist
db_1 | FATAL: database "myapp_development" does not exist
web_1 | 192.168.59.3 - - [01/Oct/2014 23:53:40] "GET / HTTP/1.1" 500 13476 0.5112
web_1 | 192.168.59.3 - - [01/Oct/2014 23:53:40] "GET %2Ffavicon.ico HTTP/1.1" 200 - 0.0067
~~~
通过以上日志可以知道开发数据库还没有创建。这时我们可以开启另外一个terminal,创建开发数据库:
~~~
$ fig run web rake db:create
~~~
当以上所有步骤都成功运行后,就需要来验证开发环境的正确性了。通过访问http://localhost:3000/ 我们应该可以看到熟悉的Rails欢迎页面:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb22d10a.png)
## 4\. Django开发环境配置详解
接下来让我们使用Fig来配置一套运行Django/PostgreSQL的应用程序吧。
首先我们新建一个项目目录,并在目录里创建3个文件。第一个文件是Docker镜像的定义文件: Dockerfile,用来描述安装在Docker容器里软件依赖关系。文件如下:
~~~
FROM python:2.7
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
~~~
以上文件描述这个Image将安装requirements.txt指定的python依赖包。
第二个文件是requirements.txt,它是python依赖包定义描述文件,内容如下:
~~~
Django
psycopg2
~~~
最后,Fig需要把所有的环境都连接起来运行。这个文件名为 fig.yml 。它描述项目需要的服务组件、指定镜像的版本、如何连接服务、什么卷可以被载入容器内部、什么端口可以暴露出来等。内容形如:
~~~
db:
image: postgres
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db
~~~
到此处,我们就可以使用 fig run 来创建一个Django项目了:
~~~
$ fig run web django-admin.py startproject figexample .
~~~
当你运行完之后,可以在当前目录下看到创建的新项目文件:
~~~
$ ls
Dockerfile fig.yml figexample manage.py requirements.txt
~~~
接下来的事情就是创建数据库链接,修改 figexample/settings.py 的DATABASES = ...部分。
~~~
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
'PORT': 5432,
}
}
~~~
这个配置信息是用来连接postgres镜像服务。
然后,运行命令 fig up来启动容器。
~~~
Recreating myapp_db_1...
Recreating myapp_web_1...
Attaching to myapp_db_1, myapp_web_1
myapp_db_1 |
myapp_db_1 | PostgreSQL stand-alone backend 9.1.11
myapp_db_1 | 2014-01-27 12:17:03 UTC LOG: database system is ready to accept connections
myapp_db_1 | 2014-01-27 12:17:03 UTC LOG: autovacuum launcher started
myapp_web_1 | Validating models...
myapp_web_1 |
myapp_web_1 | 0 errors found
myapp_web_1 | January 27, 2014 - 12:12:40
myapp_web_1 | Django version 1.6.1, using settings 'figexample.settings'
myapp_web_1 | Starting development server at http://0.0.0.0:8000/
myapp_web_1 | Quit the server with CONTROL-C.
~~~
这个时候,你可以开启浏览器,然后输入 [localhost:8000](http://localhost:8000/) 就可以访问这个Django应用。
注意,当你跑起来应用之后,就可以初始化数据库了。这里,请一定要保证fig up是在运行中,并另外开启一个命令行窗口执行一下命令:
~~~
$ fig run web python manage.py syncdb
~~~
如果你反复使用了fig up之后,可以体会到它一次性会把web和db两个镜像一起启动,如果你CONTROL-C之后,数据库也会停止服务。你甚至可以fig run web /bin/bash的方式直接进入到容器里看看。
## 5\. Wordpress开发环境配置详解
Fig一样可以应付PHP应用的开发需求。
首先,创建一个Dockerfile来支持生成开发用Image。
~~~
$ curl https://wordpress.org/latest.tar.gz | tar -xvzf -
~~~
以上这条命令创建名为 wordpress 的目录。进入到此目录,创建镜像文件 Dockerfile,内容如下:
~~~
FROM stackbrew/ubuntu:13.10
RUN apt-get update && apt-get install php5 php5-mysql -y
ADD . /code
~~~
下一步创建 fig.yml,它将定义出web服务和mysql db服务。
~~~
web:
build: .
command: php -S 0.0.0.0:8000 -t /code
ports:
- "8000:8000"
links:
- db
volumes:
- .:/code
db:
image: mysql
environment:
MYSQL_DATABASE: wordpress
MYSQL_ROOT_PASSWORD: wordpress
~~~
wordpress有一个支持文件需要修改,它是wp-config.php:
~~~
<?php
define('DB_NAME', 'wordpress');
define('DB_USER', 'root');
define('DB_PASSWORD', 'wordpress');
define('DB_HOST', getenv("DB_1_PORT_3306_TCP_ADDR") . ":" . getenv("DB_1_PORT_3306_TCP_PORT"));
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');
define('AUTH_KEY', 'put your unique phrase here');
define('SECURE_AUTH_KEY', 'put your unique phrase here');
define('LOGGED_IN_KEY', 'put your unique phrase here');
define('NONCE_KEY', 'put your unique phrase here');
define('AUTH_SALT', 'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT', 'put your unique phrase here');
define('NONCE_SALT', 'put your unique phrase here');
$table_prefix = 'wp_';
define('WPLANG', '');
define('WP_DEBUG', false);
if ( !defined('ABSPATH') )
define('ABSPATH', dirname(__FILE__) . '/');
require_once(ABSPATH . 'wp-settings.php');
~~~
以上三个文件都修改后,就可以在此目录下运行 fig up来启动wordpress。可以使用浏览器访问[localhost:8000](http://localhost:8000/) 浏览Wordpress首页。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb247b1c.png)
## 6\. 结论
通过Fig来构建基于Docker的开发环境可以让我们的开发事半功倍。其实如果读者按照我的步骤一步一步搭建开发环境,仍然会有很多挑战。
首先,因为国内带宽的限制,从官方下载Image是一个长时间等待的过程。即使Docker公司已经使用了CDN服务,但在国内网络使用仍然很慢。为了能快速下载,我还常备一条VPN线路作为数据通道来下载Image。目前这是最理想的方式,可以节省很多开发时间。
第二,fig up并不能保证Image能一次成功。但不需要灰心。你可以fig run web /bin/bash直接到容器里面调试。我遇到过多次费解的问题都是直接在里面跑命令解决的。当你退出时,fig会自动更新到相应的Image里。当你再次fig up,它会使用新Image去创建这个运行容器。
第三,fig up会创建两个以上的容器实例,在退出容器后再次启动fig up,并不会重用之前退出的容器实例,而是新建容器实例。像fig up这类常用命令运行多次之后会导致过期的容器文件仍然存储在你的开发机器上并占用硬盘空间,并且Fig还没有提供对应的命令自动清理它们。目前可以解决的办法是直接使用Docker rm/rmi命令手工清除。
以上总结出的实战经验,仍然不能掩盖Fig特有的亮点:运用Fig可以定义统一运行步骤,让部署环境可以完全的隔离在一个独立的容器环境里,并且这个隔离环境可以在开发、测试、生产多个步骤中保持一致。当前Fig项目还很年轻,需要大家多参与项目的讨论,提出自己的问题才能让Fig更好使用,更多信息可以到这里[查阅](https://github.com/docker/fig)。
(四):Docker的集成测试部署之道
最后更新于:2022-04-01 04:46:33
> 原文:http://www.infoq.com/cn/articles/docker-integrated-test-and-deployment
## 1\. 背景
敏捷开发已经流行了很长时间,如今有越来越多的企业开始践行敏捷开发所提倡的以人为中心、迭代、循序渐进的开发理念。在这样的场景下引入Docker技术,首要目的就是使用Docker提供的虚拟化方式,给开发团队建立一套可以复用的开发环境,让开发环境可以通过Image的形式分享给项目的所有开发成员,以简化开发环境的搭建。但是,在没有Docker技术之前就已经有类如Vagrant的开发环境分发技术,软件开发者一样可以创建类似需求的环境配置流程。所以在开发环境方面,Docker技术的优势并不能很好的发挥出来。笔者认为Docker的优点在于可以简化CI(持续集成)、CD(持续交付)的构建流程,让开发者把更多的精力用在开发上。
每家公司都有自己的开发技术栈,我们需要结合实际情况对其进行持续改进,优化自己的构建流程。当我们准备迈出第一步时,我们首先要确立一张构建蓝图,做到胸有成竹,这样接下来的事情才会很快实现。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb153d33.png)
这张时序图概括了目前敏捷开发流程的所有环节。结合以上时序图给出的蓝图框架,本文的重点是讲解引入Docker技术到每个环节中的实践经验。
## 2\. 创建持续发布的团队
开发团队在引入Docker技术的时候,最大的问题是没有可遵循的业界标准。大家常常以最佳实践为口号,引入多种工具链,导致在使用Docker的过程中没有侧重点。涉及到Docker选型,又在工具学习上花费大量时间,而不是选用合适的工具以组建可持续发布产品的开发团队。基于这样的场景,我们可以把“简单易用”的原则作为评判标准,引入到Docker技术工具选型的参考中。开发团队在引入Docker技术的过程中,首先需要解决的是让团队成员尽快掌握Docker命令行的使用。在熟悉了Docker命令行之后,团队需要解决几个关键问题具体如下:
1)Base Image的选择, 比如[phusion-baseimage](https://phusion.github.io/baseimage-docker/)
2)配置管理Docker镜像的工具的选择,比如[Ansible](http://www.ansible.com/home)、[Chef](http://www.getchef.com/chef/)、[Puppet](http://puppetlabs.com/)
3)Host主机系统的选择,比如[CoreOS](https://coreos.com/)、[Atomic](http://www.projectatomic.io/)、[Ubuntu](http://docs.docker.com/installation/ubuntulinux/)
Base Image包括了操作系统命令行和类库的最小集合,一旦启用,所有应用都需要以它为基础创建应用镜像。Ubuntu作为官方使用的默认版本,是目前最易用的版本,但系统没有经过优化,可以考虑使用第三方有划过的版本,比如如phusion-baseimage。对于选择RHEL、CentOS分支的Base Image,提供安全框架SELinux的使用、块级存储文件系统devicemapper等技术,这些特性是不能和Ubuntu分支通用的。另外需要注意的是,使用的操作系统分支不同,其裁剪系统的方法也完全不同,所以大家在选择操作系统时一定要慎重。
配置管理Docker镜像的工具主要用于基于Dockerfile创建Image的配置管理。我们需要结合开发团队的现状,选择一款团队熟悉的工具作为通用工具。配置工具有很多种选择,其中[Ansible](http://www.ansible.com/home)作为后起之秀,在配置管理的使用中体验非常简单易用,推荐大家参考使用。
Host主机系统是Docker后台进程的运行环境。从开发角度来看,它就是一台普通的单机OS系统,我们仅部署Docker后台进程以及集群工具,所以希望Host主机系统的开销越小越好。这里推荐给大家的Host主机系统是[CoreOS](https://coreos.com/),它是目前开销最小的主机系统。另外,还有红帽的开源[Atomic](http://www.projectatomic.io/download/)主机系统,有基于[Fedora](http://www.projectatomic.io/download/)、[CentOS](http://www.projectatomic.io/blog/2014/06/centos-atomic-host-sig-propposed/)、[RHEL](http://rhelblog.redhat.com/2014/07/10/going-atomic-with-the-red-hat-enterprise-linux-7-high-touch-beta/)多个版本的分支选择,也是不错的候选对象。另外一种情况是选择最小安装操作系统,自己定制Host主机系统。如果你的团队有这个实力,可以考虑自己定制这样的系统。
## 3\. 持续集成的构建系统
当开发团队把代码提交到Git应用仓库的那一刻,我相信所有的开发者都希望有一个系统能帮助他们把这个应用程序部署到应用服务器上,以节省不必要的人工成本。但是,复杂的应用部署场景,让这个想法实现起来并不简单。
首先,我们需要有一个支持Docker的构建系统,这里推荐[Jenkins](http://jenkins-ci.org/)。它的主要特点是项目开源、方便定制、使用简单。Jenkins可以方便的安装各种第三方插件,从而方便快捷的集成第三方的应用。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb173723.png)
通过Jenkins系统的Job触发机制,我们可以方便的创建各种类型的集成Job用例。但缺乏统一标准的Job用例使用方法,会导致项目Job用例使用的混乱,难于管理维护。这也让开发团队无法充分利用好集成系统的优势,当然这也不是我们期望的结果。所以,敏捷实践方法提出了一个可以持续交付的概念 [DeploymentPipeline](http://martinfowler.com/bliki/DeploymentPipeline.html)(管道部署)。通过Docker技术,我们可以很方便的理解并实施这个方法。
Jenkins的管道部署把部署的流程形象化成为一个长长的管道,每间隔一小段会有一个节点,也就是Job,完成这个Job工作后才可以进入下一个环节。形式如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb18c12d.png)
image source: google image search
大家看到上图中的每一块面板在引入Docker技术之后,就可以使用Docker把任务模块化,然后做成有针对性的Image用来跑需要的任务。每一个任务Image的创建工作又可以在开发者自己的环境中完成,类似的场景可以参考下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb1adcdf.png)
image source: google image search
所以,使用Docker之后,任务的模块化很自然地被定义出来。通过管道图,可以查看每一步的执行时间。开发者也可以针对任务的需要,为每一个任务定义严格的性能标准,已作为之后测试工作的参考基础。
## 4.最佳的发布环境
应用经过测试,接下来我们需要把它发布到测试环境和生产环境。这个阶段中如何更合理地使用Docker也是一个难点,开发团队需要考虑如何打造一个可伸缩扩展的分发环境。其实,这个环境就是基于Docker的私有云,更进一步我们可能期望的是提供API接口的PaaS云服务。为了构建此PaaS服务,这里推荐几款非常热门的工具方便大家参考,通过这些工具可以定制出企业私有的PaaS服务。
### 1) [Apache Mesos](https://mesosphere.io/2013/09/26/docker-on-mesos/) + [marathon](https://mesosphere.github.io/marathon/)
Apache Mesos系统是一套资源管理调度集群系统,生产环境使用它可以实现应用集群。此系统是由Twitter发起的Apache开源项目。在这个集群系统里,我们可以使用Zookeeper开启3个Mesos master服务,当3个Mesos master通过zookeeper交换信息后会选出Leader服务,这时发给其它两台Slave Messos Master上的请求会转发到Messos master Leader服务。Mesos slave服务器在开启后会把内存、存储空间和CPU 资源信息发给Messos master。Mesos是一个框架,在设计它的时候只是为了用它执行Job来做数据分析。它并不能运行一个比如Web服务Nginx这样长时间运行的服务,所以我们需要借助marathon来支持这个需求。marathon有自己的REST API,我们可以创建如下的配置文件Docker.json:
~~~
{
"container": {
"type": "DOCKER",
"docker": {
"image": "libmesos/ubuntu"
}
},
"id": "ubuntu",
"instances": "1",
"cpus": "0.5",
"mem": "512",
"uris": [],
"cmd": "while sleep 10; do date -u +%T; done"
}
~~~
然后调用
curl -X POST -H "Content-Type: application/json" http://:8080/v2/apps -d@Docker.json
我们就可以创建出一个Web服务在Mesos集群上。对于Marathon的具体案例,可以[参考官方案例](https://mesosphere.github.io/marathon/)。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb1c3df1.png)
image source: google image search
## 2) [Google Kubernetes](https://github.com/GoogleCloudPlatform/kubernetes)
Google的一个容器集群管理工具,它提出两个概念:
1. Pods,每个Pod是一个容器的集合并部署在同一台主机上,共享IP地址和存储空间,比如Apache,Redis之类分为一组容器集合。
2. Labels,提供服务标签,方便Pod容器之间的调用协作。
通过官方[架构设计](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/DESIGN.md)文档的介绍,可以详细的了解每个组件的设计思想。这是目前业界唯一在生产环境部署经验的基础上推出的开源容器方案,可以预见到未来会成为容器管理系统的行业参考标准。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb1dd580.png)
image source: google image search
### 3) [Panamax](http://panamax.io/)
在琳琅满目的集群管理工具面前,如何管理单机的Docker容器也是一个需要解决问题。因为Docker占用内存小,在单机服务器上部署成百上千个容器也不足为奇。Panamax提供人性化的Web管理界面用来安装软件让部署变得更简单。并且,Panamax还提供丰富的[容器模板](https://github.com/CenturyLinkLabs/panamax-contest-templates),让在线创建服务成为可能。比如到DigitalOcean申请一台主机,安装一套Panamax启动为后台服务。然后通过Panamax Web界面安装Nginx、Mysql、Redis等服务镜像,这样可以快速搭建生产环境的应用场景。所有的操作都是在Web界面上完成,开发者只需要关注开发本身即可。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb1f26a9.png)
## 5\. 结论
Docker的集成部署方案,是一套灵活简单的工具集解决方案。它克服了之前集群工具复杂、难用的困境,使用统一的Docker应用容器的概念部署软件应用。通过引入Docker技术,开发团队在面对复杂的生产环境中,可以结合自己团队的实际情况,定制出适合自己基础架构的配套软件发布方案。
(三):Docker开源之路
最后更新于:2022-04-01 04:46:30
> 原文:http://www.infoq.com/cn/articles/docker-open-source-road
## 1\. 背景
Docker从一开始的概念阶段就致力于使用开源驱动的方式来发展,它的成功缘于国外成熟的开源文化氛围,以及可借鉴的社区运营经验。通过本文详细的介绍,让大家可以全面了解一个项目亦或者一项技术是如何通过开源的方式发展起来的。为了更准确的描述Docker的社区状况,请先看一份来自Docker官方的数据:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb083cb6.png)
图中数据的看点有:
1. 超过500个代码贡献者。代码的贡献者在社区发展过程中是非常重要的催化剂,它会不断加快产品迭代的速度,让项目更快的交付到最终用户的手里。
2. 20个全职开发。一般的开源项目一般都不会有如此多的全职开发人员,但是Docker却有20个全职开发人员来驱动一个社区项目。这也从侧面证明了国外公司对开源项目的支持力度,以至于一家初创公司都舍得投入20个全职开发来推动开源技术的发展。
3. 超过8000个创建在GitHub上的Docker相关项目。通过这个规模可以看到围绕Docker可以使用的项目已经非常丰富。
4. Docker技术聚会。30个国家超过90个城市举办超过250个Docker技术聚会,这样的技术聚会还在不断增加,Docker技术爱好者可以在线申请承办此类技术聚会。
5. 50万次的boot2docker下载。boot2docker为Docker官方推荐客户端,50万次也代表当前潜在的用户群体。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb0aa120.png)
Docker公司目前正式员工50多名,由开源老手Ben Golub(前GlusterFS CEO)主持运营。现在主要有以下几个赢利点:
1. 印有蓝鲸的T恤和贴纸的品牌价值
2. 通过Docker Hub服务提供SaaS的分发服务
3. 提供Docker技术支持和培训
通过了解Docker的社区现状和公司的运营状况,可以发现其在运营的方式上并没有什么特别的地方。除了支付公司员工的正常开支外,它并没有像一般商业公司那样在推广上投入很多资金。Docker在推广上主要是将开源社区和社交网络作为基础推广平台,结合全球范围的Docker技术聚会,形成了良好的良性的客户互动和口口相传的品牌效应。在Docker的开源历程中,通过分析观察用户社区、源代码管理、合作伙伴的生态圈这三种形式,梳理出一套实践经验的案例,方便大家参考学习。
## 2\. 用户社区维护
Docker技术首先考虑的是在技术社区里通过各种渠道来找到它的用户,而当前最流行的技术社交网络不是Twitter,而是GitHub。所以Docker第一步是向GitHub上提交自己的代码开始吸引自己的用户的。我们总说万事开头难,那么Docker的第一个Commit应该是什么,它是否需要包括测试、用户文档、用户开发指南、设计理念等一系列的文档和代码呢?如果参照常规的开源项目,它们都考虑的都很周到,完善的代码文档结构会让用户第一眼就知道这是一个成熟的项目,我们只要用就可以了。但Docker公司却不按套路出牌,第一个Commit仅包括6个主文件:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb0c77f6.png)
没有README,没有开发环境指南,开始阶段用户无法有效的了解Docker项目。但是,这其实也是对的,因为在一个小众的开源项目的初期,很难吸引到社区用户来为它贡献代码。在接下来的很长一段时间,Docker主要是由Docker之父Solomon Hykes开发维护。在没有社区用户参与的情况下,他每天不分昼夜地提交代码,也许是为了生活,也许是为了爱好,Solomon Hykes在拼命的实现心中那个目标:让LXC创建的容器更容易使用。用当下时髦的那句话讲就是不忘初衷。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb0d6d0d.png)
从 Solomon Hykes 贡献代码的趋势图,我们可以看到只有保证项目的活跃度(持续贡献代码)那么项目才有可能获得用户的认可和关注。试想,“三天打鱼,两天晒网”的开源项目会给用户怎么样的感觉?作者都不专注,用户怎么可能忠实?这种投入,并不是偶然性的,这是国外业界的开源文化,非常值得我们学习。
在代码贡献的同时,Docker.io的主站也在2013年的5月30日第一次提交到GitHub。这距离第一行代码提交到GitHub已经有5个月。总体来看,Docker从一开始仅仅是一个很酷的想法,到真正完成并可以对外发布版本,也是经历了小半年之久。开源的意义并不像国内大多数厂商发布开源项目一样,一定要在内部应用的很成功才发布到技术社区。我们通过以上数据,可以很容易的看出来,它一定是一个长期的、持续的过程。你越专注的投入,你的项目越有可能成功。
当然,如果仅仅Docker只在GitHub上提供代码来吸引用户,那也不会是最佳的实践。在网站建立后的下一步,它开始在全球各大城市的技术聚会上推广介绍Docker。Docker技术在全球推广的方法是通过线下的技术聚会,外加社交网络媒体传播才得到流行的。Docker官网通过发布“[创建Docker技术聚会指南](https://www.docker.com/community/meetups-organize/)”,引导Docker技术的爱好者自发申请承办技术聚会。Docker官网主要通过类似Twitter、Docker周报、用户论坛等渠道,及时的把每个城市即将开始的技术聚会时间和联系人发布出来,就可以把Docker的技术推广做下去。并且这种形式的最大好处是口碑相传,其长尾效应的结果是Docker技术开始在当地的技术圈得到关注。像这样的技术聚会,一般都在30到200人之间,对于商业项目的推广是无法参照这样推广的。但这种形式就像一颗种子散落在城市中间,一旦有人介绍Docker技术到这个城市的技术圈,就会有更多的用户去GitHub上关注Docker的项目进展。
## 3\. 源代码管理
Docker的源码是按照模块划分的,每一个模块都会单独放在一个目录里。并且每个目录都会包含一个MAINTAINERS.md。当你提交一个Pull Request的时候,子模块的维护者就会站出来回答“LGTM (Looks Good To Me)” 表示已经看了你的代码并接受你提交的代码。
每一个想参与Docker开发的开发者,你需要进入一个特殊的目录hack,这个目录包括了所有你想知道的开发相关信息。它把开发者分为4类人,
1. 代码贡献者,详细指南看CONTRIBUTORS.md。
2. 代码维护者,详细指南看MAINTAINERS.md。
3. 程序打包者,详细指南看PACKAGERS.md。
4. 负责发布版本的维护者,详细指南看RELEASE-CHECKLIST.md。
所有的指南文档都非常详细完整,可以做到看完此文档就可以开始相应角色的任务。除了这些文档之外,hack目录还包括了发布,开发,测试等环节需要的辅助脚本,让开发者可以得到很多开发上的便利。
Docker从一开始就是围绕LXC开发的,但在版本稳定后,使用Go重写了一套类LXC接口实现。也就是 [libcontainer](https://github.com/docker/libcontainer) 项目。它的代码管理方式与上面的Docker源代码管理方式一样,开发者可以很容易的导入到子项目libcontainer的开发。一致的管理方法可以提高流程的复用,这种管理方式希望能得到大家的借鉴参考。
## 4\. 创建合作伙伴生态圈
首先,Docker从一开始使用Ubuntu版本作为开发环境,主要是Ubuntu上支持aufs(advanced multi layered unification filesystem)文件系统。所以,Docker对Ubuntu的支持是最好的。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb0e4bf8.png)
还有就是大家非常熟悉的Google的GCE,在没有Docker之前,就已经使用自己开发的[类LXC容器](https://github.com/google/lmctfy)。在有了Docker之后, Google开发了[kubernetes](https://github.com/GoogleCloudPlatform/kubernetes)来管理Docker。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb0ef505.png)
商业版本Linux的领导者RedHat,也是Docker生态圈非常重要的合作伙伴。并且它支持的Fedora社区、CentOS社区会对推广Docker技术起到关键性作用。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb10a598.png)
还有就是OpenStack的建立者Rackspace,在混合云解决方案上具有全球领导地位。Docker与它的合作,可以帮助Docker技术在混合云的解决方案中得到推广。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb11ae16.png)
最后就是开源PaaS项目DEIS,基于Docker和CoreOS技术构建的类如Heroku发布流程的PaaS应用。与它的合作,可以让更多的企业看到一个使用Docker技术的范本。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb12e878.png)
#### 5\. 结论
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb13b2eb.jpg)
Docker的开源之路可以说是开源项目的最佳实践,它从屌丝瞬间变为高富帅的历程并不是偶然。Docker的开源之路还在进行中,从它的模式中我们可以学习到的东西并不仅仅局限于以上罗列的几点,读者可以在参与开源项目的过程中多体会,找到自己的“痛点”,然后参考Docker等开源项目的做法,相信可以很快解决你的问题。
(二):Docker命令行探秘
最后更新于:2022-04-01 04:46:28
> 原文:http://www.infoq.com/cn/articles/docker-command-line-quest
## 1\. Docker命令行
Docker官方为了让用户快速了解Docker,提供了一个[交互式教程](https://www.docker.com/tryit/#0),旨在帮助用户掌握Docker命令行的使用方法。但是由于Docker技术的快速发展,此交互式教程已经无法满足Docker用户的实际使用需求,所以让我们一起开始一次真正的命令行学习之旅。首先,Docker的命令清单可以通过运行docker ,或者 docker help 命令得到:
~~~
$ sudo docker
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb03702a.png)
在Docker容器技术不断演化的过程中,Docker的子命令已经达到34个之多,其中核心子命令(例如:run)还会有复杂的参数配置。笔者通过结合功能和应用场景方面的考虑,把命令行划分为4个部分,方便我们快速概览Docker命令行的组成结构:
| 功能划分 | 命令 |
|---|---|
| 环境信息相关 | 1. info<br/>2. version |
| 系统运维相关 | 1. attach<br/>2. build<br/>3. commit<br/>4. cp<br/>5. diff<br/>6. export<br/>7. images<br/>8. import / save / load<br/>9. inspect<br/>10. kill<br/>11. port<br/>12. pause / unpause<br/>13. ps<br/>14. rm<br/>15. rmi<br/>16. run<br/>17. start / stop / restart<br/>18. tag<br/>19. top<br/>20. wait |
| 日志信息相关 | 1. events<br/>2. history<br/>3. logs |
| Docker Hub服务相关 | 1. login<br/>2. pull / push<br/>3. search|
### 1.1 参数约定
单个字符的参数可以放在一起组合配置,例如
~~~
docker run -t -i --name test busybox sh
~~~
可以用这样的方式等同:
~~~
docker run -ti --name test busybox sh
~~~
### 1.2 Boolean
Boolean参数形式如: -d=false。注意,当你声明这个Boolean参数时,比如 docker run -d=true,它将直接把启动的Container挂起放在后台运行。
### 1.3 字符串和数字
参数如 --name=“” 定义一个字符串,它仅能被定义一次。同类型的如-c=0 定义一个数字,它也只能被定义一次。
### 1.4 后台进程
Docker后台进程是一个常驻后台的系统进程,值得注意的是Docker使用同一个文件来支持客户端和后台进程,其中角色切换通过-d来实现。这个后台进程是用来管理容器的,使用Docker --help可以得到更详细的功能参数配置, 如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bb05b854.png)
Docker后台进程参数清单如下表:
| 参数 | 解释 |
|---|---|
| --api-enable-cors=false | 开放远程API调用的 [CORS 头信息](https://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing)。这个接口开关对想进行二次开发的上层应用提供了支持。 |
| -b, --bridge="" | 挂载已经存在的网桥设备到 Docker 容器里。注意,使用 none 可以停用容器里的网络。 |
| --bip="" | 使用 [CIDR](https://en.wikipedia.org/wiki/CIDR_notation) 地址来设定网络桥的 IP。注意,此参数和 -b 不能一起使用。 |
| -D, --debug=false | 开启Debug模式。例如:docker -d -D |
| -d, --daemon=false | 开启Daemon模式。 |
| --dns=[] | 强制容器使用DNS服务器。例如: docker -d --dns 8.8.8.8 |
| --dns-search=[] | 强制容器使用指定的DNS搜索域名。例如: docker -d --dns-search example.com |
| -e, --exec-driver="native" | 强制容器使用指定的运行时驱动。例如:docker -d -e lxc |
| -G, --group="docker" | 在后台运行模式下,赋予指定的Group到相应的unix socket上。注意,当此参数 --group 赋予空字符串时,将去除组信息。 |
| -g, --graph="/var/lib/docker" | 配置Docker运行时根目录 |
| -H, --host=[] | 在后台模式下指定socket绑定,可以绑定一个或多个 tcp://host:port, unix:///path/to/socket, fd://* 或 fd://socketfd。例如:<br/>$ docker -H tcp://0.0.0.0:2375 ps 或者<br/>$ export DOCKER_HOST="tcp://0.0.0.0:2375"<br/>$ docker ps |
| --icc=true | 启用内联容器的通信。 |
| --ip="0.0.0.0" | 容器绑定IP时使用的默认IP地址 |
| --ip-forward=true | 启动容器的 net.ipv4.ip_forward |
| --iptables=true | 启动Docker容器自定义的iptable规则 |
| --mtu=0 | 设置容器网络的MTU值,如果没有这个参数,选用默认 route MTU,如果没有默认route,就设置成常量值 1500。 |
| -p, --pidfile="/var/run/docker.pid" | 后台进程PID文件路径。 |
| -r, --restart=true | 重启之前运行中的容器 |
| -s, --storage-driver="" | 强制容器运行时使用指定的存储驱动,例如,指定使用devicemapper, 可以这样:<br/>docker -d -s devicemapper |
| --selinux-enabled=false | 启用selinux支持 |
| --storage-opt=[] | 配置存储驱动的参数 |
| --tls=false | 启动TLS认证开关 |
| --tlscacert="/Users/dxiao/.docker/ca.pem" | 通过CA认证过的的certificate文件路径 |
| --tlscert="/Users/dxiao/.docker/cert.pem" | TLS的certificate文件路径 |
| --tlskey="/Users/dxiao/.docker/key.pem" | TLS的key文件路径 |
| --tlsverify=false | 使用TLS并做后台进程与客户端通讯的验证 |
| -v, --version=false | 显示版本信息 |
注意,其中带有[] 的启动参数可以指定多次,例如
~~~
$ docker run -a stdin -a stdout -a stderr -i -t ubuntu /bin/bash
~~~
## 2\. Docker命令行探秘
### 2.1 环境信息相关
info
使用方法: docker info
例子:
~~~
[fedora@docker-devel-cli docker]$ sudo docker -D info
Containers: 0
Images: 32
Storage Driver: devicemapper
Pool Name: docker-252:1-130159-pool
Data file: /var/lib/docker/devicemapper/devicemapper/data
Metadata file: /var/lib/docker/devicemapper/devicemapper/metadata
Data Space Used: 1616.9 Mb
Data Space Total: 102400.0 Mb
Metadata Space Used: 2.4 Mb
Metadata Space Total: 2048.0 Mb
Execution Driver: native-0.2
Kernel Version: 3.11.10-301.fc20.x86_64
Debug mode (server): false
Debug mode (client): true
Fds: 11
Goroutines: 14
EventsListeners: 0
Init SHA1: 2c5adb59737b8a01fa3fb968519a43fe140bc9c9
Init Path: /usr/libexec/docker/dockerinit
Sockets: [fd://]
~~~
使用说明:
这个命令在开发者报告Bug时会非常有用,结合docker vesion一起,可以随时使用这个命令把本地的配置信息提供出来,方便Docker的开发者快速定位问题。
version
使用方法: docker version
使用说明:
显示Docker的版本号,API版本号,Git commit, Docker客户端和后台进程的Go版本号。
### 2.2 系统运维相关
attach
使用方法: docker attach [OPTIONS] CONTAINER
例子:
~~~
$ ID=$(sudo docker run -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
top - 17:21:49 up 5:53, 0 users, load average: 0.63, 1.15, 0.78
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.0 us, 0.7 sy, 0.0 ni, 97.7 id, 0.7 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 2051644 total, 723700 used, 1327944 free, 33032 buffers
KiB Swap: 0 total, 0 used, 0 free. 565836 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 19748 1280 1008 R 0.0 0.1 0:00.04 top
$ sudo docker stop $ID
~~~
使用说明:
使用这个命令可以挂载正在后台运行的容器,在开发应用的过程中运用这个命令可以随时观察容器內进程的运行状况。开发者在开发应用的场景中,这个命令是一个非常有用的命令。
build
使用方法:docker build [OPTIONS] PATH | URL | -
例子:
~~~
$ docker build .
Uploading context 18.829 MB
Uploading context
Step 0 : FROM busybox
---> 769b9341d937
Step 1 : CMD echo Hello world
---> Using cache
---> 99cc1ad10469
Successfully built 99cc1ad10469
~~~
使用说明:
这个命令是从源码构建新Image的命令。因为Image是分层的,最关键的Base Image是如何构建的是用户比较关心的,Docker官方文档给出了构建方法,请参考[这里](http://docs.docker.com/articles/baseimages/)。
commit
使用方法:docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
例子:
~~~
$ sudo docker ps
ID IMAGE COMMAND CREATED STATUS PORTS
c3f279d17e0a ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
197387f1b436 ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
$ docker commit c3f279d17e0a SvenDowideit/testimage:version3
f5283438590d
$ docker images | head
REPOSITORY TAG ID CREATED VIRTUAL SIZE
SvenDowideit/testimage version3 f5283438590d 16 seconds ago 335.7 MB
~~~
使用说明:
这个命令的用处在于把有修改的container提交成新的Image,然后导出此Imange分发给其他场景中调试使用。Docker官方的建议是,当你在调试完Image的问题后,应该写一个新的Dockerfile文件来维护此Image。commit命令仅是一个临时创建Imange的辅助命令。
cp
使用方法: cp CONTAINER:PATH HOSTPATH
使用说明:
使用cp可以把容器內的文件复制到Host主机上。这个命令在开发者开发应用的场景下,会需要把运行程序产生的结果复制出来的需求,在这个情况下就可以使用这个cp命令。
diff
使用方法:docker diff CONTAINER
例子:
~~~
$ sudo docker diff 7bb0e258aefe
C /dev
A /dev/kmsg
C /etc
A /etc/mtab
A /go
A /go/src
A /go/src/github.com
A /go/src/github.com/dotcloud
....
~~~
使用说明:
diff会列出3种容器内文件状态变化(A - Add, D - Delete, C - Change )的列表清单。构建Image的过程中需要的调试指令。
export
使用方法:docker export CONTAINER
例子:
~~~
$ sudo docker export red_panda > latest.tar
~~~
使用说明:
把容器系统文件打包并导出来,方便分发给其他场景使用。
images
使用方法:docker images [OPTIONS] [NAME]
例子:
~~~
$ sudo docker images | head
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
<none> <none> 77af4d6b9913 19 hours ago 1.089 GB
committest latest b6fa739cedf5 19 hours ago 1.089 GB
<none> <none> 78a85c484f71 19 hours ago 1.089 GB
$ docker latest 30557a29d5ab 20 hours ago 1.089 GB
<none> <none> 0124422dd9f9 20 hours ago 1.089 GB
<none> <none> 18ad6fad3402 22 hours ago 1.082 GB
<none> <none> f9f1e26352f0 23 hours ago 1.089 GB
tryout latest 2629d1fa0b81 23 hours ago 131.5 MB
<none> <none> 5ed6274db6ce 24 hours ago 1.089 GB
~~~
使用说明:
Docker Image是多层结构的,默认只显示最顶层的Image。不显示的中间层默认是为了增加可复用性、减少磁盘使用空间,加快build构建的速度的功能,一般用户不需要关心这个细节。
import / save / load
使用方法:
~~~
docker import URL|- [REPOSITORY[:TAG]]
docker save IMAGE
docker load
~~~
使用说明:
这一组命令是系统运维里非常关键的命令。加载(两种方法: import, load),导出(一种方法: save)容器系统文件。
inspect
使用方法:
~~~
docker inspect CONTAINER|IMAGE [CONTAINER|IMAGE...]
~~~
例子:
~~~
$ sudo docker inspect --format='{{.NetworkSettings.IPAddress}}' $INSTANCE_ID
~~~
使用说明:
查看容器运行时详细信息的命令。了解一个Image或者Container的完整构建信息就可以通过这个命令实现。
kill
使用方法:
~~~
docker kill [OPTIONS] CONTAINER [CONTAINER...]
~~~
使用说明:
杀掉容器的进程。
port
使用方法:
~~~
docker port CONTAINER PRIVATE_PORT
~~~
使用说明:
打印出Host主机端口与容器暴露出的端口的NAT映射关系
pause / unpause
使用方法:
~~~
docker pause CONTAINER
~~~
使用说明:
使用cgroup的freezer顺序暂停、恢复容器里的所有进程。详细freezer的特性,请参考[官方文档](https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt)。
ps
使用方法:
~~~
docker ps [OPTIONS]
~~~
例子:
~~~
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c01db0b339c ubuntu:12.04 bash 17 seconds ago Up 16 seconds webapp
d7886598dbe2 crosbymichael/redis:latest /redis-server --dir 33 minutes ago Up 33 minutes 6379/tcp redis,webapp/db
~~~
使用说明:
docker ps打印出正在运行的容器,docker ps -a打印出所有运行过的容器。
rm
使用方法:
~~~
docker rm [OPTIONS] CONTAINER [CONTAINER...]
~~~
例子:
~~~
$ sudo docker rm /redis
/redis
~~~
使用说明:
删除指定的容器。
rmi
使用方法:
~~~
docker rmi IMAGE [IMAGE...]
~~~
例子:
~~~
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test1 latest fd484f19954f 23 seconds ago 7 B (virtual 4.964 MB)
test latest fd484f19954f 23 seconds ago 7 B (virtual 4.964 MB)
test2 latest fd484f19954f 23 seconds ago 7 B (virtual 4.964 MB)
$ sudo docker rmi fd484f19954f
Error: Conflict, cannot delete image fd484f19954f because it is tagged in multiple repositories
2013/12/11 05:47:16 Error: failed to remove one or more images
$ sudo docker rmi test1
Untagged: fd484f19954f4920da7ff372b5067f5b7ddb2fd3830cecd17b96ea9e286ba5b8
$ sudo docker rmi test2
Untagged: fd484f19954f4920da7ff372b5067f5b7ddb2fd3830cecd17b96ea9e286ba5b8
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test latest fd484f19954f 23 seconds ago 7 B (virtual 4.964 MB)
$ sudo docker rmi test
Untagged: fd484f19954f4920da7ff372b5067f5b7ddb2fd3830cecd17b96ea9e286ba5b8
Deleted: fd484f19954f4920da7ff372b5067f5b7ddb2fd3830cecd17b96ea9e286ba5b8
~~~
使用说明:
指定删除Image文件。
run
使用方法:
~~~
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
~~~
例子:
~~~
$ sudo docker run --cidfile /tmp/docker_test.cid ubuntu echo "test"
~~~
使用说明:
这个命令是核心命令,可以配置的参数多达28个参数。详细的解释可以通过docker run --help列出。官方文档中提到的 [Issue 2702](https://github.com/dotcloud/docker/issues/2702):"lxc-start: Permission denied - failed to mount" could indicate a permissions problem with AppArmor. 在最新版本的Dcoker中已经解决。
start / stop / restart
使用方法:
~~~
docker start CONTAINER [CONTAINER...]
~~~
使用说明:
这组命令可以开启(两个:start, restart),停止(一个:stop)一个容器。
tag
使用方法:
~~~
docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
~~~
使用说明:
组合使用用户名,Image名字,标签名来组织管理Image。
top
使用方法:
~~~
docker top CONTAINER [ps OPTIONS]
~~~
使用说明:
显示容器內运行的进程。
wait
使用方法:
~~~
docker wait CONTAINER [CONTAINER...]
~~~
使用说明:
阻塞对指定容器的其他调用方法,直到容器停止后退出阻塞。
### 2.3 日志信息相关
events
使用方法:
~~~
docker events [OPTIONS]
~~~
使用说明:
打印容器实时的系统事件。
history
使用方法:
~~~
docker history [OPTIONS] IMAGE
~~~
例子:
~~~
$ docker history docker
IMAGE CREATED CREATED BY SIZE
3e23a5875458790b7a806f95f7ec0d0b2a5c1659bfc899c89f939f6d5b8f7094 8 days ago
/bin/sh -c #(nop) ENV LC_ALL=C.UTF-8 0 B
8578938dd17054dce7993d21de79e96a037400e8d28e15e7290fea4f65128a36 8 days ago
/bin/sh -c dpkg-reconfigure locales && locale-gen C.UTF-8 &&
/usr/sbin/update-locale LANG=C.UTF-8 1.245 MB
be51b77efb42f67a5e96437b3e102f81e0a1399038f77bf28cea0ed23a65cf60 8 days ago /bin/sh
-c apt-get update && apt-get install -y git libxml2-dev python build-essential
make gcc python-dev locales python-pip 338.3 MB
4b137612be55ca69776c7f30c2d2dd0aa2e7d72059820abf3e25b629f887a084 6 weeks ago
/bin/sh -c #(nop) ADD jessie.tar.xz in / 121 MB
750d58736b4b6cc0f9a9abe8f258cef269e3e9dceced1146503522be9f985ada 6 weeks ago
/bin/sh -c #(nop) MAINTAINER Tianon Gravi <admwiggin@gmail.com>
- mkimage-debootstrap.sh -t jessie.tar.xz jessie http://http.debian.net/debian 0 B
511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158 9 months ago 0 B
~~~
使用说明:
打印指定Image中每一层Image命令行的历史记录。
logs
使用方法:
~~~
docker logs CONTAINER
~~~
使用说明:
批量打印出容器中进程的运行日志。
### 2.4 Dcoker Hub服务相关
login
使用方法:
~~~
docker login [OPTIONS] [SERVER]
~~~
使用说明:
登录Hub服务。
pull / push
使用方法:
~~~
docker push NAME[:TAG]
~~~
使用说明:
通过此命令分享Image到Hub服务或者自服务的Registry服务。
search
使用方法:
~~~
docker search TERM
~~~
使用说明:
通过关键字搜索分享的Image。
## 3\. 总结
通过以上Docker命令行的详细解释,可以强化对Docker命令的全面理解。考虑到Docker命令行的发展变化非常快,读者可以参考官方的[命令行解释](http://docs.docker.com/reference/commandline/cli/)文档更新相应的命令行解释。另外,通过以上Docker命令行的分析,可以知道Docker命令行架构设计的特点在于客户端和服务端的运行文件是同一个文件,内部实现代码应该是重用的设计。笔者希望开发者在开发类似的命令行应用时参考这样的设计,减少前后台容错的复杂度。
## 参考文献
[1] [https://docs.docker.com/reference/commandline/cli/](https://docs.docker.com/reference/commandline/cli/)
[2] [https://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing](https://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing)
[3] [https://en.wikipedia.org/wiki/CIDR_notation#CIDR_notation](https://en.wikipedia.org/wiki/CIDR_notation#CIDR_notation)
(一):Docker核心技术预览
最后更新于:2022-04-01 04:46:26
> 原文:http://www.infoq.com/cn/articles/docker-core-technology-preview
> 作者 肖德时
## 1\. 背景
### 1.1\. 由PaaS到Container
2013年2月,前Gluster的CEO Ben Golub和dotCloud的CEO Solomon Hykes坐在一起聊天时,Solomon谈到想把dotCloud内部使用的Container容器技术单独拿出来开源,然后围绕这个技术开一家新公司提供技术支持。28岁的Solomon在使用python开发dotCloud的PaaS云时发现,使用 LXC(Linux Container) 技术可以打破产品发布过程中应用开发工程师和系统工程师两者之间无法轻松协作发布产品的难题。这个Container容器技术可以把开发者从日常部署应用的繁杂工作中解脱出来,让开发者能专心写好程序;从系统工程师的角度来看也是一样,他们迫切需要从各种混乱的部署文档中解脱出来,让系统工程师专注在应用的水平扩展、稳定发布的解决方案上。他们越深入交谈,越觉得这是一次云技术的变革,紧接着在2013年3月Docker 0.1发布,拉开了基于云计算平台发布产品方式的变革序幕。
### 1.2 Docker简介
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429baef3ceb.png)
[Docker](http://www.docker.io/) 是 Docker.Inc 公司开源的一个基于 LXC技术之上构建的Container容器引擎, [源代码](https://github.com/dotcloud/docker)托管在 GitHub 上, 基于Go语言并遵从Apache2.0协议开源。 Docker在2014年6月召开DockerConf 2014技术大会吸引了IBM、Google、RedHat等业界知名公司的关注和技术支持,无论是从 GitHub 上的代码活跃度,还是Redhat宣布在[RHEL7中正式支持Docke](http://server.cnw.com.cn/server-os/htm2014/20140616_303249.shtml)r, 都给业界一个信号,这是一项创新型的技术解决方案。 就连 Google 公司的 Compute Engine 也[支持 docker 在其之上运行](http://googlecloudplatform.blogspot.com/2013/12/google-compute-engine-is-now-generally-available.html), 国内“BAT”先锋企业百度Baidu App Engine(BAE)平台也是[以Docker作为其PaaS云基础](http://blog.docker.com/2013/12/baidu-using-docker-for-its-paas/)。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429baf1ccf1.jpg)
Docker产生的目的就是为了解决以下问题:
1) 环境管理复杂: 从各种OS到各种中间件再到各种App,一款产品能够成功发布,作为开发者需要关心的东西太多,且难于管理,这个问题在软件行业中普遍存在并需要直接面对。Docker可以简化部署多种应用实例工作,比如Web应用、后台应用、数据库应用、大数据应用比如Hadoop集群、消息队列等等都可以打包成一个Image部署。如图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429baf41f1c.png)
2) 云计算时代的到来: AWS的成功, 引导开发者将应用转移到云上, 解决了硬件管理的问题,然而软件配置和管理相关的问题依然存在 (AWS cloudformation是这个方向的业界标准, 样例模板可[参考这里](https://s3-us-west-2.amazonaws.com/cloudformation-templates-us-west-2/LAMP_Single_Instance.template))。Docker的出现正好能帮助软件开发者开阔思路,尝试新的软件管理方法来解决这个问题。
3) 虚拟化手段的变化: 云时代采用标配硬件来降低成本,采用虚拟化手段来满足用户按需分配的资源需求以及保证可用性和隔离性。然而无论是KVM还是Xen,在 Docker 看来都在浪费资源,因为用户需要的是高效运行环境而非OS, GuestOS既浪费资源又难于管理, 更加轻量级的LXC更加灵活和快速。如图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429baf6074a.jpg)
4) LXC的便携性: LXC在 Linux 2.6 的 Kernel 里就已经存在了,但是其设计之初并非为云计算考虑的,缺少标准化的描述手段和容器的可便携性,决定其构建出的环境难于分发和标准化管理(相对于KVM之类image和snapshot的概念)。Docker就在这个问题上做出了实质性的创新方法。
### 1.3 Docker的Hello World
以Fedora 20作为主机为例,直接安装docker-io:
~~~
$ sudo yum -y install docker-io
~~~
启动docker后台Daemon:
~~~
$ sudo systemctl start docker
~~~
跑我们第一个Hello World容器:
~~~
$ sudo docker run -i -t fedora /bin/echo hello world
Hello world
~~~
可以看到在运行命令行后的下一行会打印出经典的Hello World字符串。
## 2\. 核心技术预览
Docker核心是一个[操作系统级虚拟化](http://en.wikipedia.org/wiki/Operating_system-level_virtualization)方法, 理解起来可能并不像VM那样直观。我们从虚拟化方法的四个方面:隔离性、可配额/可度量、便携性、安全性来详细介绍Docker的技术细节。
### 2.1\. 隔离性: Linux Namespace(ns)
每个用户实例之间相互隔离, 互不影响。 一般的硬件虚拟化方法给出的方法是VM,而LXC给出的方法是container,更细一点讲就是kernel namespace。其中pid、net、ipc、mnt、uts、user等namespace将container的进程、网络、消息、文件系统、UTS("UNIX Time-sharing System")和用户空间隔离开。
1) pid namespace
不同用户的进程就是通过pid namespace隔离开的,且不同 namespace 中可以有相同pid。所有的LXC进程在docker中的父进程为docker进程,每个lxc进程具有不同的namespace。同时由于允许嵌套,因此可以很方便的实现 Docker in Docker。
2) net namespace
有了 pid namespace, 每个namespace中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过net namespace实现的, 每个net namespace有独立的 network devices, IP addresses, IP routing tables, /proc/net 目录。这样每个container的网络就能隔离开来。docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge: docker0连接在一起。
3) ipc namespace
container中进程交互还是采用linux常见的进程间交互方法(interprocess communication - IPC), 包括常见的信号量、消息队列和共享内存。然而同 VM 不同的是,container 的进程间交互实际上还是host上具有相同pid namespace中的进程间交互,因此需要在IPC资源申请时加入namespace信息 - 每个IPC资源有一个唯一的 32 位 ID。
4) mnt namespace
类似chroot,将一个进程放到一个特定的目录执行。mnt namespace允许不同namespace的进程看到的文件结构不同,这样每个 namespace 中的进程所看到的文件目录就被隔离开了。同chroot不同,每个namespace中的container在/proc/mounts的信息只包含所在namespace的mount point。
5) uts namespace
UTS("UNIX Time-sharing System") namespace允许每个container拥有独立的hostname和domain name, 使其在网络上可以被视作一个独立的节点而非Host上的一个进程。
6) user namespace
每个container可以有不同的 user 和 group id, 也就是说可以在container内部用container内部的用户执行程序而非Host上的用户。
### 2.2 可配额/可度量 - Control Groups (cgroups)
cgroups 实现了对资源的配额和度量。 cgroups 的使用非常简单,提供类似文件的接口,在 /cgroup目录下新建一个文件夹即可新建一个group,在此文件夹中新建task文件,并将pid写入该文件,即可实现对该进程的资源控制。groups可以限制blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns九大子系统的资源,以下是每个子系统的详细说明:
1. blkio 这个子系统设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及usb等等。
2. cpu 这个子系统使用调度程序为cgroup任务提供cpu的访问。
3. cpuacct 产生cgroup任务的cpu资源报告。
4. cpuset 如果是多核心的cpu,这个子系统会为cgroup任务分配单独的cpu和内存。
5. devices 允许或拒绝cgroup任务对设备的访问。
6. freezer 暂停和恢复cgroup任务。
7. memory 设置每个cgroup的内存限制以及产生内存资源报告。
8. net_cls 标记每个网络包以供cgroup方便使用。
9. ns 名称空间子系统。
以上九个子系统之间也存在着一定的关系.详情请参阅[官方文档](https://www.kernel.org/doc/Documentation/cgroups/)。
### 2.3 便携性: AUFS
AUFS (AnotherUnionFS) 是一种 Union FS, 简单来说就是支持将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)的文件系统, 更进一步的理解, AUFS支持为每一个成员目录(类似Git Branch)设定readonly、readwrite 和 whiteout-able 权限, 同时 AUFS 里有一个类似分层的概念, 对 readonly 权限的 branch 可以逻辑上进行修改(增量地, 不影响 readonly 部分的)。通常 Union FS 有两个用途, 一方面可以实现不借助 LVM、RAID 将多个disk挂到同一个目录下, 另一个更常用的就是将一个 readonly 的 branch 和一个 writeable 的 branch 联合在一起,Live CD正是基于此方法可以允许在 OS image 不变的基础上允许用户在其上进行一些写操作。Docker 在 AUFS 上构建的 container image 也正是如此,接下来我们从启动 container 中的 linux 为例来介绍 docker 对AUFS特性的运用。
典型的启动Linux运行需要两个FS: bootfs + rootfs:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429baf76f40.png)
bootfs (boot file system) 主要包含 bootloader 和 kernel, bootloader主要是引导加载kernel, 当boot成功后 kernel 被加载到内存中后 bootfs就被umount了. rootfs (root file system) 包含的就是典型 Linux 系统中的 /dev, /proc,/bin, /etc 等标准目录和文件。
对于不同的linux发行版, bootfs基本是一致的, 但rootfs会有差别, 因此不同的发行版可以公用bootfs 如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429baf8b2ec.png)
典型的Linux在启动后,首先将 rootfs 设置为 readonly, 进行一系列检查, 然后将其切换为 "readwrite" 供用户使用。在Docker中,初始化时也是将 rootfs 以readonly方式加载并检查,然而接下来利用 union mount 的方式将一个 readwrite 文件系统挂载在 readonly 的rootfs之上,并且允许再次将下层的 FS(file system) 设定为readonly 并且向上叠加, 这样一组readonly和一个writeable的结构构成一个container的运行时态, 每一个FS被称作一个FS层。如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429baf9f456.png)
得益于AUFS的特性, 每一个对readonly层文件/目录的修改都只会存在于上层的writeable层中。这样由于不存在竞争, 多个container可以共享readonly的FS层。 所以Docker将readonly的FS层称作 "image" - 对于container而言整个rootfs都是read-write的,但事实上所有的修改都写入最上层的writeable层中, image不保存用户状态,只用于模板、新建和复制使用。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bafb22b0.png)
上层的image依赖下层的image,因此Docker中把下层的image称作父image,没有父image的image称作base image。因此想要从一个image启动一个container,Docker会先加载这个image和依赖的父images以及base image,用户的进程运行在writeable的layer中。所有parent image中的数据信息以及 ID、网络和lxc管理的资源限制等具体container的配置,构成一个Docker概念上的container。如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bafc895b.png)
### 2.4 安全性: AppArmor, SELinux, GRSEC
安全永远是相对的,这里有三个方面可以考虑Docker的安全特性:
1. 由kernel namespaces和cgroups实现的Linux系统固有的安全标准;
2. Docker Deamon的安全接口;
3. Linux本身的安全加固解决方案,类如AppArmor, SELinux;
由于安全属于非常具体的技术,这里不在赘述,请直接参阅[Docker官](http://docs.docker.com/articles/security/)[方文档](http://docs.docker.com/articles/security/)。
## 3\. 最新子项目介绍
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-11_56429bafea4b0.png)
我们再来看看Docker社区还有哪些子项目值得我们去好好研究和学习。基于这个目的,我把有趣的核心项目给大家罗列出来,让热心的读者能快速跟进自己感兴趣的项目:
1. Libswarm,是Solomon Hykes (Docker的CTO) 在DockerCon 2014峰会上向社区介绍的新“乐高积木”工具: 它是用来统一分布式系统的网络接口的API。Libswarm要解决的问题是,基于Docker构建的分布式应用已经催生了多个基于Docker的服务发现(Serivce Discovery)项目,例如etcd, fleet, geard, mesos, shipyard, serf等等,每一套解决方案都有自己的通讯协议和使用方法,使用其中的任意一款都会局限在某一个特定的技术范围內。所以Docker的CTO就想用libswarm暴露出通用的API接口给分布式系统使用,打破既定的协议限制。目前项目还在早期发展阶段,值得参与。
2. Libchan,是一个底层的网络库,为上层 Libswarm 提供支持。相当于给Docker加上了ZeroMQ或RabbitMQ,这里自己实现网络库的好处是对Docker做了特别优化,更加轻量级。一般开发者不会直接用到它,大家更多的还是使用Libswarm来和容器交互。喜欢底层实现的网络工程师可能对此感兴趣,不妨一看。
3. Libcontainer,Docker技术的核心部分,单独列出来也是因为这一块的功能相对独立,功能代码的迭代升级非常快。想了解Docker最新的支持特性应该多关注这个模块。
## 4\. 总结
Docker社区一直在面对技术挑战,从容地给出自己的解决方案。云计算发展至今,有很多重要的问题没有得到妥善解决,Docker正在尝试让主流厂商接受并应用它。至此,以上Docker技术的预览到此告一段落,笔者也希望读者能结合自己的实际情况,尝试使用Docker技术。因为只有在亲自体会的基础之上,像Docker这样的云技术才会产生更大的价值。
## 5\. 作者简介
肖德时, Red Hat Engineering Service/HSS 内部工具组Team Leader,Nodejs开源项目nodejs-cantas Lead Developer。擅长企业内部工具的设计以及实现。开源课程Rails Starter的发起人。rubygem: lazy_high_charts的Maintainer。twitter账号:xds2000,邮箱:xiaods@gmail.com
## 6\. 参考文献:
1. [https://tiewei.github.io/cloud/Docker-Getting-Start/](https://tiewei.github.io/cloud/Docker-Getting-Start/)
2. [http://docs.docker.com/articles/](http://docs.docker.com/articles/)
3. [http://www.slideshare.net/shykes/docker-the-road-ahead](http://www.slideshare.net/shykes/docker-the-road-ahead)
4. [http://www.centurylinklabs.com/meet-docker-ceo-ben-golub/](http://www.centurylinklabs.com/meet-docker-ceo-ben-golub/)
5. [http://lwn.net/Articles/531114/](http://lwn.net/Articles/531114/)
6. [http://en.wikipedia.org/wiki/Aufs](http://en.wikipedia.org/wiki/Aufs)
7. [http://docs.docker.io/en/latest/terms/filesystem/](http://docs.docker.io/en/latest/terms/filesystem/)
8. [http://docs.docker.io/en/latest/terms/layer/](http://docs.docker.io/en/latest/terms/layer/)
9. [http://docs.docker.io/en/latest/terms/image/](http://docs.docker.io/en/latest/terms/image/)
10. [http://docs.docker.io/en/latest/terms/container/](http://docs.docker.io/en/latest/terms/container/)
11. [https://stackoverflow.com/questions/17989306/what-does-docker-add-to-just-plain-lxc](https://stackoverflow.com/questions/17989306/what-does-docker-add-to-just-plain-lxc)
前言
最后更新于:2022-04-01 04:46:23
> 【编者按】Docker是PaaS供应商dotCloud开源的一个基于LXC 的高级容器引擎,源代码托管在 GitHub 上, 基于Go语言开发并遵从Apache 2.0协议开源。Docker提供了一种在安全、可重复的环境中自动部署软件的方式,它的出现拉开了基于云计算平台发布产品方式的变革序幕。为了更好的促进Docker在国内的发展以及传播,我们决定开设《[深入浅出Docker](http://www.infoq.com/cn/dockers)》专栏,邀请Docker相关的布道师、开发人员、技术专家来讲述Docker的各方面内容,让读者对Docker有更深入的了解,并且能够积极投入到新技术的讨论和实践中。另外,欢迎加入InfoQ Docker技术交流群交流Docker的最佳实践,QQ群号:124378115。
### 作者简介
**肖德时**, Red Hat Engineering Service/HSS 内部工具组Team Leader,Nodejs开源项目nodejs-cantas Lead Developer。擅长企业内部工具的设计以及实现。开源课程Rails Starter的发起人。rubygem: lazy_high_charts的Maintainer。twitter账号:xds2000,邮箱:xiaods@gmail.com