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集群验证来保证应用程序的安全传输
Docker能够简化资源调配,部署和更新等操作,迁移到Docker容器后可以节省部署时间
在结构上,Docker容器共享底层操作系统内核,资源消耗要比虚拟机少,相对轻量。通过容器隔离来防止应用程序冲突,这样IT管理员就能提高现有基础结构的负载密度,优化现有虚拟机和服务器的利用率
P.S.不需要管理程序的额外负载,而是直接在主机的内核中运行,更节省资源,比虚拟机轻量,甚至可以在虚拟机环境运行Docker
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进程间通信,要么通过网络远程通信)
守护进程(dockerd
)监听Docker API请求,并管理Docker对象,比如镜像(image),容器(container),网络和目录(volume,文件系统中的概念,卷)。此外,守护进程还能与其它守护进程通信以管理Docker服务
客户端(docker
)是Docker用户与Docker交互的基本方式,比如使用docker run
命令,客户端把这些命令发送给dockerd
来执行,一个client可以与多个守护进程通信
类似于npm registry,Docker registry用来存放公共Docker镜像,默认在Docker Hub查找镜像
执行docker pull
或docker run
命令时,会从配置好的registry取所需镜像,docker push
用来发布本地镜像到配置指向的registry
另外,与npm package不同的是,公共镜像仍然是镜像级的(黑盒),而不像npm package源码都是公开的。所以Docker还发展出了付费生态Docker store,能够直接买一个可靠的模块/应用程序包过来,并且能够获得升级维护(镜像更新)等服务,很有意思
P.S.比如Foopipes就是个收费的镜像
包括镜像(image),容器(container),服务(service),网络,volume(目录),插件等等,经常打交道的是镜像和容器
镜像是一份只读的模版,带有创建Docker容器的说明
具有3个特点:
一般通过在另一个镜像的基础上,附加一些额外定制来创建新镜像。比如可以基于ubuntu镜像构建一个镜像,装上Apache和自己的应用程序,并指定需要的Apache配置项
创建自己的镜像需要创建Dockerfile,通过简单的语法定义其创建及运行所需步骤。Dockerfile中的每个指都会在镜像中创建一个层(layer),在修改Dockerfile并重新构建镜像时,只构建那些发生变化的层。相比其它虚拟化技术,更轻巧更快
容器是映像的可运行实例
容器也有3个特点:
可以通过Docker API或CLI创建,启动,停止,移动和删除容器,可以把容器连接到多个网络,给他附加存储,甚至可以基于容器的当前状态创建新的镜像
容器是由其镜像以及创建和启动时给定的配置项定义的,容器被删除时,其所有未被持久存储的状态变化都会丢失
例如:
docker run -i -t ubuntu /bin/bash
执行这条命令时发生了6件事:
ubuntu
镜像的话,从registry拉取(跟手动执行docker pull ubuntu
一样)docker create
一样)/bin/bash
。容器以可交互的方式运行(-i
)并连接到终端(-t
),之后可以通过键盘输入并把输出记录到终端exit
终止/bin/bash
命令时,容器将会停止,但不会被删除,可以重新启动它或将其删除服务允许跨多Docker守护进程做容器扩展,就像多个管理者和工人作为一个集群协同工作。集群中的每个成员都是Docker守护进程,所有守护进程都通过Docker API通信。服务允许定义所需的状态,例如在给定时间内容必须提供的服务副本数量。默认情况下,服务在所有工作节点之间是负载均衡的。对使用者来说,Docker服务看起来就像个单一应用程序
Docker实现上利用了一些Linux内核特性:
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创建自定义镜像比较合理
首先创建一个:
mkdir -p ~/projs/docker/rsshelper/
vi ~/projs/docker/rsshelper/Dockerfile
编辑内容:
FROM centos:latest
MAINTAINER ayqy "nwujiajie@163.com"ENV NODE_VERSION 4.6.2RUN 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工作流:
几个示例应用场景: