Docker简介

一.目标

Bring Portability, Security, And Efficiency To Your Traditional Applications Without Changing Application Code

不改变源码就能让传统应用程序获得可移植性,安全性和高成本效益

二.特性

Docker提供了在宽松隔离环境(称之为容器)中打包和运行应用程序的能力,以及用来管理容器生命周期的工具和平台

P.S.Docker是用Go编写的

混合云可移植性

把应用程序的源码及其依赖项一起打包到轻量级的独立容器,容器解决了works on my machine的问题,如图:

(图片来自Digging Into the “Works On My Machine” Problem

这样应用程序就能正常地在新环境里跑起来,而不用考虑环境之间的差异。打包好之后,用一条简单的Docker命令就能轻易地把容器部署到任何环境。能够快速启用云迁移,加快技术更新周期或突然迁移到(公有)云

提升应用程序安全性

把现有的应用程序打包到Docker容器中,无需修改源码就能获得Docker内置的安全特性。Docker提供了容器隔离,通过限制性的配置,减少应用程序的攻击面,并允许设置合适的资源配额,节省主机资源

另外,Docker还对容器应用程序的创建,扫描,签名,共享和部署提供了安全的供应链。比如安全扫描能够提供所有依赖项的公开漏洞清单,在定期报告中会通知Docker管理员修复相关的已知公开漏洞。还能对容器做数字签名,通过启用Docker集群验证来保证应用程序的安全传输

CapEx(资本性支出)和OpEx(运营成本)效益

Docker能够简化资源调配,部署和更新等操作,迁移到Docker容器后可以节省部署时间

在结构上,Docker容器共享底层操作系统内核,资源消耗要比虚拟机少,相对轻量。通过容器隔离来防止应用程序冲突,这样IT管理员就能提高现有基础结构的负载密度,优化现有虚拟机和服务器的利用率

P.S.不需要管理程序的额外负载,而是直接在主机的内核中运行,更节省资源,比虚拟机轻量,甚至可以在虚拟机环境运行Docker

DevOps

DevOps (a clipped compound of “development” and “operations”) is a software engineering culture and practice that aims at unifying software development (Dev) and software operation (Ops). The main characteristic of the DevOps movement is to strongly advocate automation and monitoring at all steps of software construction, from integration, testing, releasing to deployment and infrastructure management. DevOps aims at shorter development cycles, increased deployment frequency, more dependable releases, in close alignment with business objectives.

一种软件工程文化和实践,想要统一开发和操作(测试、运维),进一步缩短产品发布周期,提高效率,同时通过自动化和监控来保证可靠性

容器技术是DevOps中的重要一环,如下图:

(图片来自Red Hat OpenShift V3 Overview and Deep Dive

正如前面提到的,把源码和依赖项打包到容器,能够简化资源调配,部署,更新等一系列运维操作,达到You build it, you run it,减少从开发到发布之间的不确定环节

P.S.关于DevOps的更多信息,请查看DevOps的前世今生

三.结构及概念

一种C/S架构,Client发出指令,Server(守护进程)接收并执行相应操作,管理容器和镜像。Server可以与Client位于同一物理机器上,也可以位于另一个远程机器,通过REST API通信(要么通过UNIX socket进程间通信,要么通过网络远程通信)

Docker守护进程

守护进程(dockerd)监听Docker API请求,并管理Docker对象,比如镜像(image),容器(container),网络和目录(volume,文件系统中的概念,卷)。此外,守护进程还能与其它守护进程通信以管理Docker服务

Docker客户端

客户端(docker)是Docker用户与Docker交互的基本方式,比如使用docker run命令,客户端把这些命令发送给dockerd来执行,一个client可以与多个守护进程通信

Docker注册中心

类似于npm registry,Docker registry用来存放公共Docker镜像,默认在Docker Hub查找镜像

执行docker pulldocker run命令时,会从配置好的registry取所需镜像,docker push用来发布本地镜像到配置指向的registry

另外,与npm package不同的是,公共镜像仍然是镜像级的(黑盒),而不像npm package源码都是公开的。所以Docker还发展出了付费生态Docker store,能够直接买一个可靠的模块/应用程序包过来,并且能够获得升级维护(镜像更新)等服务,很有意思

P.S.比如Foopipes就是个收费的镜像

Docker对象

包括镜像(image),容器(container),服务(service),网络,volume(目录),插件等等,经常打交道的是镜像和容器

镜像

镜像是一份只读的模版,带有创建Docker容器的说明

具有3个特点:

  • 可移植:能发布到registry,或保存成压缩文件

  • 分层的:生成镜像的步骤就是(往镜像中)添加层,这样除了最后几步外,大多数镜像都可以通过共享父级层来减少磁盘占用

  • 静态的(只读的):内容不可变,除非创建一个新的镜像

一般通过在另一个镜像的基础上,附加一些额外定制来创建新镜像。比如可以基于ubuntu镜像构建一个镜像,装上Apache和自己的应用程序,并指定需要的Apache配置项

创建自己的镜像需要创建Dockerfile,通过简单的语法定义其创建及运行所需步骤。Dockerfile中的每个指都会在镜像中创建一个层(layer),在修改Dockerfile并重新构建镜像时,只构建那些发生变化的层。相比其它虚拟化技术,更轻巧更快

容器

容器是映像的可运行实例

容器也有3个特点:

  • 运行时的概念:进程所处的环境

  • 可变的(可写的):实质上是一种短暂存储

  • 分层的:镜像就是容器的“层”

可以通过Docker API或CLI创建,启动,停止,移动和删除容器,可以把容器连接到多个网络,给他附加存储,甚至可以基于容器的当前状态创建新的镜像

容器是由其镜像以及创建和启动时给定的配置项定义的,容器被删除时,其所有未被持久存储的状态变化都会丢失

例如:

docker run -i -t ubuntu /bin/bash

执行这条命令时发生了6件事:

  1. 本地没有ubuntu镜像的话,从registry拉取(跟手动执行docker pull ubuntu一样)

  2. 创建个新容器(跟手动执行docker create一样)

  3. 给容器分配读写文件系统,作为最终层,允许运行的容器操作本地文件

  4. 创建网络接口,并把容器连接到默认网络(没指定网络选项的话)。这样会给容器分配一个IP地址,默认容器能够通过主机的网络连接连接到外网

  5. 启动容器并执行/bin/bash。容器以可交互的方式运行(-i)并连接到终端(-t),之后可以通过键盘输入并把输出记录到终端

  6. 输入exit终止/bin/bash命令时,容器将会停止,但不会被删除,可以重新启动它或将其删除

服务

服务允许跨多Docker守护进程做容器扩展,就像多个管理者和工人作为一个集群协同工作。集群中的每个成员都是Docker守护进程,所有守护进程都通过Docker API通信。服务允许定义所需的状态,例如在给定时间内容必须提供的服务副本数量。默认情况下,服务在所有工作节点之间是负载均衡的。对使用者来说,Docker服务看起来就像个单一应用程序

底层技术

Docker实现上利用了一些Linux内核特性:

  • Namespaces实现独立工作空间(container)

  • Control groups实现容器可用资源限制

  • Union file systems实现层(layer)

  • Container format实现容器管理(把上面3个特性综合利用起来,抽象出的概念)

四.示例

环境

cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)

安装并启用

# 安装
yum install docker
# 启动
sudo service docker start
# 开机自启
sudo chkconfig docker on

试玩

我们在CentOS镜像基础上建立新的镜像:

# 获取CentOS镜像
docker pull centos
# 确认镜像存在
docker images centos

正常的话,会得到如下输出,表明本地存在最新CentOS镜像:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/centos    latest              3fa822599e10        3 weeks ago         203.5 MB

运行Docker容器

docker run -i -t centos /bin/bash

在新创建的终端(处于centos容器环境)做想做的事情:

# 装nvm
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
# 更新环境变量
source ~/.bashrc
# 装node v4.6.2
nvm install 4.6.2
# 装全局module
npm install -g ionic@1.7.16
npm install -g cordova@6.2.0
# ...一顿猛操作
# 退出可交互终端
exit

P.S.为什么这里的node版本号和全局模块版本号都是固定的?因为有个旧玩具,只能在这个环境才跑得起来。Docker很适合这种场景,不然别人很难在其本地环境跑起来。所以对环境有特殊要求的开源项目,不如发布一份Docker镜像,或者自带一份Dockerfile

最后从当前状态创建镜像:

# 查看刚才改动的容器ID
docker ps -a -q -l
# 提交改动并创建新的镜像
docker commit 887a377fa369 ayqy/rsshelper

这样会在本地创建一个基于centos镜像的ayqy/rsshelper自定义镜像:

# 查看新生成的镜像
docker images ayqy/rsshelper
# 一键进入RSSHelper运行所需环境
docker run -it ayqy/rsshelper /bin/bash
# 验证一下环境
node -v
# v4.6.2没错

最基本的可以这么玩,实际应用中还是通过Dockerfile创建自定义镜像比较合理

Dockerfile

首先创建一个:

mkdir -p ~/projs/docker/rsshelper/
vi ~/projs/docker/rsshelper/Dockerfile

编辑内容:

FROM centos:latest
MAINTAINER ayqy "nwujiajie@163.com"

ENV NODE_VERSION 4.6.2

RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash \
&& source ~/.bashrc \
&& nvm install "$NODE_VERSION" \
&& nvm alias default "$NODE_VERSION" \
&& nvm use default \
&& nvm install -g ionic@1.7.16 cordova@6.2.0

注意

  • 第一行FROM指令必不可少,用来指定源镜像,而且指定的镜像必须是本地存在的,FROM相当于docker run

  • RUN指令默认用/bin/bash,而且每条RUN都起一个新的bash进程,所以为了共享环境变量需要用&&连接,而不用多条RUN指令

创建镜像:

docker build -t="ayqy/rsshelper_image" ~/projs/docker/rsshelper/
# 创建完成后查看新的镜像
docker images ayqy/rsshelper_image

注意,如果有任何一条命令返回值不为0,镜像就会构建失败

P.S.关于Dockerfile的更多信息,请查看快速掌握dockerfile

常用命令

# 从registry拉取指定镜像
docker pull fedora
# 查看本地镜像
docker images
# 从Dockerfile创建镜像,要求当前目录下有Dockerfile
docker build -t myimage .
# 以可交互的方式运行容器
docker run -it myimage
# 查看正在运行的容器
docker ps -l
# 停止容器运行(id从docker ps输出里找)
docker kill <id>
# 删除容器
docker rm <id>

P.S.通过docker help查看更多Docker客户端命令

五.应用场景

容器技术消除了本地开发环境与真实生产环境的差异,有助于简化保障CI/CD工作流:

  1. 用容器开发应用程序并管理依赖项

  2. 把容器作为发布和测试的基本单元

  3. 部署到生产环境,无论生产环境具体是什么样子的(本地数据中心,云供应商还是二者混合的)

几个示例应用场景:

  • Demo共享

    把开发Demo打包到容器分享出去,别人能在其本地环境立即跑起来

  • 自动化测试

    把开发环境的应用程序部署到测试环境,进行人工测试/自动化测试,而不用考虑环境差异

  • 快速重新部署/发布

    开发环境修复bug后,重新部署到测试环境进行测试验证,测试通过后,把最新镜像部署到生产环境

  • 优化资源利用率

    通过限制各应用程序的资源配额,或者用Docker容器代替虚拟机来进一步提高资源利用率

参考资料

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code