Docker安装及容器管理
一、Docker 简介
Docker是什么?
Docker的英语本意是“搬运工”,在程序员的世界里,Docker搬运的是集装箱(Container),集装箱里装的是任意类型的App,开发者通过Docker可以将APP变成一种标准化的、可移植的、自管理的组件,可以在任何主流中开发、调试和运行。
说白了,docker是一种用了新颖方式实现的轻量级虚拟机,类似于VM,但是在原理上和应用和VM的差别还是很大的,并且docker的专业叫法是一应用容器(Application Container)。
为什么要用容器?
应用容器是个什么样子呢,一个做好的应用容器就像一个装好了一组特定的应用的虚拟机一样,比如我现在想用MySQL,那我就找个装好了MySQL的容器就可以了,然后运行起来,我就能使用MySQL了。
为什么不直接安装一个MySQL?安装一个SQL Server也可以啊,可是有的时候根据每个人电脑的不同,在安装的时候可能会出现各种各样的错误,万一你的电脑中毒了,你的电脑挂了,你所有的服务都需要重新安装,但是有了docker,或者说有了容器就不同了,你就相当于有了一个可以运行起来的虚拟机,只要运行容器,MySQL的配置就可以省了,而且如果你想换个电脑,直接把容器“搬过来”就可以使用容器里面的服务。
Docker基于Go语言开发的,代码托管在Github上,并遵循Apache2.0开原协议。Docker容器可以封装任何有效负载,几乎可以在任何服务器之间进行一致性运行。话句话说,开发者构建的应用只需一次构建,即可多平台运行。运营人员只需要配置他们的服务,即可运行所有的应用。
若是利用容器的话,那么开发直接在容器里开发,测试的时候把整个容器给测试,测试好了把测试后容器再上线就好了,通过容器,整个开发,测试和生产环境可以保持高度一致。
此外容器也像VM一样具有一定的隔离性,各个容器之间的数据和内存空间相互隔离,可以保证一定的安全性。
Hyper-v、KVM和Xen等虚拟机管理程序都“基于虚拟化硬件仿真机制”, 这意味着,他们对系统的要求很高,然而容器却使用共享的操作系统。这意味他们在使用系统资源方面比虚拟机管理程序要高效的多。容器 不是对硬件进行虚拟化处理,而是驻留在一个Linux实例上。
Docker 可以解决虚拟机能够解决的问题,同时也能够解决虚拟机由于资源要求过高而无法解决的问题。
为什么使用Docker?
1. 快速支付应用程序
* 开发者使用一个 标准的image 来构建开发容器,开发完成之后,系统管理员就可以使用这个容器来部署代码。
* docker可以快速创建容器,快速迭代应用程序,并让整个过程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。
*docker容器很轻!很快!容器的启动是秒级的,节约开发、测试、部署的时间
2.更容易部署和扩展
*docker容器可以在几乎所有的环境中运行 ,物理机、虚拟机、公有云、私有云、个人电脑、服务器等。
* docker容器兼容很多平台,这样就可以把一个应用程序从一个平台迁移到另外一个。
3.效率更高
*docker 容器不需要hypervisor,他是内核级的虚拟化。
4.快速部署也意味着更简单的管理
*通常只需要小小的改变就可以替代以往巨型和大量的更新工作
Docker的常用案例包括:
* 自动打包和部署应用
* 创建轻量、私有的PaaS环境
* 自动化测试和持续集成/部署
* 部署并扩展Web应用、数据库和后端服务器
那么为何不用VM?
那么既然容器和VM这么类似为啥不用VM? docker容器相对于VM还是有很多优点的:
1 启动速度快,容器通常一秒内可以启动
2 资源利用率高,一台普通的服务器可以跑上千个容器
3 性能开销小,
为什么相似的功能在性能上会有如此大的差距?接下来看一下他们的各自设计图。
可见容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统的方式则是在硬件层面实现。
Docker与传统虚拟机对比总结:
二、Docker的体系结构
docker使用c/s架构,docker daemon 作为server端接受client的请求,并处理(创建、运行、分发容器),他们可以运行在一个机器中,也通过socket或者RESTful API通信
docker daemon 一般在宿主机后台运行。
docker client 以系统命令的形式存在,用户用docker命令来跟docker daemon 交互。
docker守护进程(docker daemon)
如上图所示,docker守护进程运行在一台主机上。用户并不直接和守护进程进行交互,而是通过docker 客户端间接和其他通信。
docker 客户端(docker client)
docker 客户端,实际上是docker的二进制程序,是用户与docker交互方式。它接受用户指令并且与背后的docker守护进程通信。
docker 内部:
要理解docker内部结构,需要理解以下三种部件:
docker 镜像----docker images
docker 仓库----docker registeries
docker 容器----docker containers
docker 镜像
docker镜像是docker容器运行时的只读模板,镜像可以用来创建docker 容器。每一个镜像由一系列的层(layers)组成。docker使用UnionFS (联合文件系统)来将这些层联合到单独的镜像中。UnionFS允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统。正因为有了这些层的存在,docker是如此的轻量。当你改变了一个docker镜像,比如升级到某个程序的新版本,一个新的层会被创建。因此,不用替换整个原先的镜像或重新建立(在使用虚拟机时你可能会这么做),只是一个新的层被添加或升级了。现在你不用重新发布镜像,只需要升级,层使得分发docker镜像变得简单和快速。
每个docker都有很多层次构成,docker使用 union systems 将这些不同的层结合到一个image中去。
例如:centos镜像中安装了Nginx,就成了Nginx镜像,其实在此时docker镜像的层级概念就体现出来了。底层一个centos操作系统镜像,上面叠加一个Nginx层,就完成了一个Nginx镜像的构建。层级概念就不难理解,此时我们一般centos操作系统镜像称为Nginx镜像层的父镜像。
docker 仓库
docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。同样的,docker 仓库也有公有和私有的概念。公有的docker仓库名字是docker Hub。docker Hub提供了庞大的镜像集合供使用。这些镜像可以是自己创建,或者在别人的镜像基础上创建。
仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像由不同的标签(teg)。
仓库分为公开仓库(Public)和私有仓库(Private)两种模式。
最大的公开仓库是docker Hub,存放数量庞大的镜像供用户下载。国内的公开仓库包括docker Pool等,可以提供大陆用户更稳定快速的访问。
当然,用户也可以在本地网络内创建一个私有仓库。
当用户创建了自己的镜像之后就可以使用 push命令将他上传到共有或私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。
* 注 : docker仓库的概念跟Git类似,注册服务器可以理解为GitHub这样的托管服务。
docker 容器
docker利用容器来运行应用,一个docker容器包含了所有的某个应用运行所需要的坏境。每一个docker容器都是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每一个docker容器都是独立和安全的应用平台。
容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除、每个容器都是相互隔离的、保证安全的平台。
可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
* 注:镜像是只读的,容器在启动的时候创建一层可写层作为上层。
与虚拟机相比,容器有一个很大的差异,它们被设计用来运行“单进程”,无法很好地模拟一个完整的环境。docker设计师极力推崇“一个容器一个进程的方式”,如果你要选择在一个容器中运行多个进程,那唯一情况是:出于调试目的。
容器是设计来运行一个应用的,而非一台机器。你可能会把容器当虚拟机用,但你将失去很多灵活性,因为docker提供了用于分离应用于数据的工具,使得你可以快捷地更新运行中的代码/系统,而不影响数据。
docker 从0.9版本开始使用libcontainer替代lxc,libcontainer和linux系统的交互图如下:
docker 底层技术
docker 底层的2个核心技术分别是 Namespaces和Control groups
Namespaces用来隔离各个容器
1)pid namespace
不同用户的进程就是通过不同的pid namespace隔离开的 namespace中可以有相同的pid。所有的LXC进程在docker中的父进程为docker进程,每个lxc进程具有不同的namespace。
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),包括常见的信息量、消息队列和共享内存。container 的进程间交互实际上还是host上具有相同pid namespace中的进程间交互。
4)mnt namespace
类似chroot,将一个进程放到一个特定的目录执行。mnt namespace 允许不同namespace的进程看到的文件结构不同,这样每个namespace中的进程所看到的文件目录就被隔离开了。在container里头,看到的文件系统,就是一个完整的Linux系统,有/etc 、/lib等,通过chroot实现。
5)uts namespace
UTS(“UNIX time-sharing System”)namespace 允许每个container 拥有独立的hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非host上的一个进程。
6)user namespace
每个container 可以有不同的user 和 group id, 也就是说可以在container 内部用container 内部的用户执行程序而非host上的用户。
有了以上6种namespace从进程、网络、IPC、文件系统、UTS和用户角度的隔离,一个container 就可以对外展现出一个独立计算机的能力,并且不同container从OS层面实现了隔离。然而不同namespace之间资源还是相互竞争的,仍然需要类似ulimit来管理每个container 所能使用的资源--cgroup
cgroups(Control groups)实现了对资源的配额和度量。
三、 docker 安装
docker官网:https://docs.docker.com
docker 的特性:
* 文件系统隔离性:每个进程容器运行在一个完全独立的根文件系统里。
* 资源隔离: 系统资源,像CPU和内存等可以分配到不同的容器中,使用cgroup。
* 网络 隔离: 每个进程容器 运行在自己的网络空间,虚拟接口和IP地址。
* 日志记录: docker将进会收集和记录每个进程容器的标准流(stdout/stderr/stdin),用于实时检索或批量检索。
*变更管理:容器文件系统的变更可以提交到新的映像中,并可重复使用以创建更多的容器,无需使用模板或手动配置。
*交互式shell:docker可以分配一个虚拟终端并关联到任何容器的标准输入上。
centos系列安装docker,docker支持centos6及以后的版本 ,官方文档要求Linux kernel 至少3.8以上,且只能运行在64位系统中。
以下是centos7安装docker
1 查看内核
2 安装docker (可以使用RPM 或者YUM安装,这里用YUM装)
docker软件包已经包括在默认的Centos-Extras 软件源。因此想要安装docker,只需要使用下面yum命令(前提需要连接外网)。
[[email protected] ~]# yum -y install docker
3 安装完成后,启动docker ,并设置为开机自启
[[email protected] ~]# systemctl start docker
[[email protected] ~]# systemctl enable docker
4 查看docker版本
[[email protected] ~]# docker version
或者 [[email protected] ~]# docker info
docker默认使用Unix socket
5 查找images
docker的一个特点是很多人因为各种不同的用途创建了各种不同的images。它们都被上传到了docker Hub 共有仓库上,我们可以在docker hub的网站上来查找它们。使用docker search命令
这里以查找centos7为例:
[[email protected] ~]# docker search centos7
我们看到了很多包含centos7的images。其中包括images名字、描述、星级(表示受欢迎程度)、是否官方创建、是否自动创建。官方的images是stackbrew项目组创建和维护的,automated资源允许你的验证image的来源和内容。
6 获取images(以上图第一个centos7为例)
7 下载完成后 使用docker images 显示本机上的images
* REPOSITORY: 来自于那个仓库
* TAG 的标记,比如latest(最新版)
* IMAGE ID :镜像是它的ID
* CREATED:创建时间
* SIZE:镜像的大小
8 创建自己的images (有两种方法)
1)第一种方法:使用 docker commit来扩展一个image
先使用image启动容器,更新后提交到新的image。
[[email protected] ~]# docker run -i -t docker.io/centos /bin/bash
[[email protected]a07160d8b1d1 /]#
注意:记住容器ID,稍后还会用到
在容器中添加mariadb-server应用
[[email protected] /]# yun -y install mariadb-server
结束后,我们使用exit退出,现在我们的容器已经被改变了。使用docker commit命令来提交相应的副本。
[[email protected] ~]# docker commit -m "added mariadb app" -a "gy" a07160d8b1d1 centos:mariadb
sha256:250372101ecbe48a1d642a4ac85bfb6e5e5558fd497ebaf072c7d147285a9947
-m:指定提交的说明信息,跟我们使用的版本控制工具一样;-a:指定更新的用户信息;之后是用来创建镜像的容器ID;最后是指定目标镜像的仓库名和tag信息。创建成功后会返回这个镜像的ID信息。
使用docker images查看新创建的镜像
现在,可以使用新的镜像来启动容器
2)第二种方法:从dockerfile来创建image
使用docker commit来扩展一个image比较简单,但它不容易在一个团队中分享它。我们使用docker build来创建一个新的image。。为此我们需要创建一个dockerfile,包含一些如何创建我们的image的指令。现在我们来创建一个目录和一个dockerfile
[[email protected] ~]# mkdir -p /docker/httpd
[[email protected] ~]# cd /docker/httpd/
[[email protected] httpd]# vim Dockerfile
内容如下:
编写完,使用docker bulid来生成镜像
* 注意:一个镜像不能超过127层
查看生成的镜像
9 修改镜像的标签 docker tag
例如;修改下图标签
[[email protected] ~]# docker tag centos:mariadb mariadb:v1
10 存出和载入镜像
当需要把一台机器上的镜像迁移到另一台上,就需要存出和载入镜像。
1)存出 docker save
例如:存出下图docker.io/centos
[[email protected] ~]# docker save -o centos7.tar docker.io/centos:latest
可以使用[[email protected] ~]# sz centos7.tar 将压缩的包下载到本地目录,在本地电脑的“下载”中可以看到。
2)载入 镜像 docker load
先使用rz上传镜像
再使用docker load 载入
[[email protected] ~]# docker load < centos7.tar
之后可使用 [[email protected] ~]# docker images 查看
11 用docker rmi移除本地镜像
[[email protected] ~]# docker rmi [容器 ID]
12 查看容器
docker ps :只查看运行的容器
docker ps -a :显示所有容器
13 终止容器
docker stop [容器 ID]
docker kill [容器 ID]