容器是一种基础工具:泛指任何用于容纳其余物品的工具,能够部分或彻底封闭,被用于容纳,储存,运输物品: 物品能够被放置在容器中,而容器能够保护内容物:前端
人类使用容器的历史有十万年,甚至可能有数百万年的历史:java
# 容器类型: # 瓶,罐,箱,篮,桶,袋
但咱们重点在LXC这里;node
虚拟化和容器的关系:linux
主机级虚拟化:虚拟化的是整个完整的物理硬件平台,好比VMware,KVM.里面跑的是与宿主机不同的系统nginx
两种类型:
类型一: 直接在硬件上装一个虚拟机管理器,不装宿主机,在虚拟机管理器上跑须要的操做系统:
类型二: Vmware,kvm
完整意义的操做系统: 咱们本身在上面装一个内核,内核上面有一个用户空间,用户空间里面跑进程。web可是运行内核并非咱们主要目的,内核核心做用在于资源分配和管理。redis
就是说真正在应用空间跑的应用程序才是能产生生产力的,就比如咱们跑一个web服务,内核其实不多提供服务。sql
而出于通用目的的而设计的资源管理平台,操做系统管理内核。咱们并不太须要:docker
可是内核也不得不有,缘由在于要想在一组硬件平台跑软件程序,而如今的软件都是针对于内核调用和系统调用,库调用研发的,而不安装这些无法运行程序,因此内核看上去没多大用,可是也必不可少;shell
更况且,咱们一旦有了用户空间后,里面运行不少进程,这些进程为了协调也须要内核。
但假设咱们建立一个虚拟机,只为了运行一个nginx,tomcat,却不得不去安装内核,用户空间,再去跑tomcat,代价就有点大了。
而在这里若是咱们用二级虚拟化来分析的话:
若是为了运行一个进程,就要实现两级调度和资源分派。
第一,本身虚拟机有一个内核,已经实现了一次内存虚拟化,cpu调度以及IO调度和io 管理。
可是真正虚拟机也是被宿主机内核管理一次,这个中间浪费能够想一下。
传统的主机虚拟化技术,确实能让咱们一组硬件平台之上实现跨系统传进的隔离和试验,调试,资源高效利用。而带来的资源开销不容忽视的,而不少时候,咱们建立虚拟机只是为了运行一个和几个附有生产责任的进程而已,为此;
减小中间层就是一个好的办法,
好比在二级虚拟化咱们把虚拟机那一层给抽掉,只保留进程,可是咱们加虚拟机就是为了环境隔离,好比说一台机器跑两个或者五个nginx,咱们一台机器没有那么多套接字和80端口。
而咱们虚拟机就是为了资源隔离,就算把里面的nginx翻江倒海,坏的也是哪个虚拟机。
因此这里的隔离才是咱们的目标,咱们虽然想抽掉这一层内核,可是不能让他回到在一个锅里吃饭那个环境,因此要让每个组进程互相不可干扰的,只不过共享一个底层资源而已。
所以咱们想要的环境就是:
建立一个又一个隔离环境,咱们要运行隔离的程序就让他跑在隔离环境中,内核提供的是内核空间,进程试运行在用户空间,而这里就能实现将用户空间隔离成多个用户空间,互不干扰,这里通常都有一个空间是有特权的,通常第一个。而这里众多用户空间运行的都是同一个内核,被同一个内核管理的。可是运行时候能看到的边界只能是当前用户空间的边界,虽然没有主机级虚拟化隔离那么完全。
更重要是,这个用户空间放进程,给进程提供运行环境,而且保护内部进程不被其余进程所干扰.叫作容器.
虚拟的隔离环境管理器
一层硬件平台容器不是什么新概念,最先出如今2000年,当年叫jail,监狱,监禁之意,里面就像一个沙箱,就算里面那个程序bug,有了故障,异常行为,也没法影响这个容器以外的程序运行,这也是jail初衷。
容器并不是起源于 Linux,但开源世界的最精彩之处就在于借鉴、修改和改进,容器也不例外.
但这个概念很是有吸引力。
2001 年,经过 Jacques Gélinas 的 [VServer 项目,]隔离环境的实施进入了 Linux 领域。正如 Gélinas 所说,这项工做的目的是“在高度独立且安全的单一环境中运行多个通用 Linux 服务器 [sic]。” 在完成了这项针对 Linux 中多个受控制用户空间的基础性工做后,Linux 容器开始逐渐成形并最终发展成了如今的模样。
通常来说,就算一个程序被远程劫持在里面搞起破坏,他的边界也仅仅是哪一个容器的边界,最初只是为了应用的安全运行。
后来有人把这个技术山寨到Linux平台上,叫Vserver(chroot),在一个子目录定义一个根,让里面的程序觉得他就是根。
chroot他能实现的你看上去的那层空间,底层仍是同一个内核,进程运行是特权模式仍是普通模式,表面很简单,真正实现起来涉及东西至少要有;
在一个单独用户空间当中,它主要目的是隔离使用,要让里面进程觉得他就运行在底层内核之上,有六点:
# 1. 主机名和域名: UTS # 2. 根文件系统 : MOUNT # 3. 应该有本身的IPC,进程间的专用通道,若是能让两个用户空间进程能互相通讯,也没有意义了,共享内存,拒绝跨用户空间。 IPC # 4. 给每一个用户空间作一个假的init,只能有一个,pid,1,每一个系统正常来讲只有一个,为了隔离,给每一个空间假装一个。 # 5. 必须给每一个用户假装一个root,实现效果就是在真正系统只是普通用户,在他所属用户空间里面能够随心所欲,让进程看起来是root. # 6. IP地址,互相通讯,而在内核级别,tcp协议栈只有一个,
为了容器机制的实现,Linux内核对着六种明成空间原生支持,namespaces。直接经过系统调用对外进行输出,
直到今天,所谓的容器就是靠六个namespaces和chroot来实现的。
听上去容易,这六种名成空间有一个是到内核3.8才实现的,因此要想完美使用容器,要内核版本3.8以上。centos6自然排除在外.
namespace | 系统调用参数 | 隔离内容 | 内核版本 |
---|---|---|---|
UTS | clone_newuts | 主机名和域名 | 2.6.19 |
IPC | clone_newipc | 信号量、消息队列和共享内存 | 2.6.19 |
PID | clone_newpid | 进程编号 | 2.6.24 |
Network | clon_newnet | 网络设备、网络栈、端口等 | 2..29 |
Mount | clone_newns | 挂载点(文件系统) | 2.4.19 |
User | clone_newuser | 用户和用户组 | 3.8 |
容器级虚拟化:
资源限制: 咱们能够在总体资源作比例性分配,也能够在单一用户空间作核心绑定,你只能使用几个核;否则的话一个进程内存泄露整个系统都蹦了;或者一个进程占用了绝大部分CPU.
内存是压缩不了的,多一点都不能,一给就收不回来了,由于内存是压缩不了的;
实现这个Control Cgroups
blkio: # 块设备IO cpu: # CPU cpuacct: # CPU资源使用报告 cpuset: # 多处理器平台上的cpu集合 devices: # 设备访问 freezer: # 挂起或恢复任务 memory: # 内存用量及报告 perf_event: # 对cgroup中的任务进行统一性能测试 net_cls: # cgroup中的任务建立的数据报文的类别;
划分红组后,在不一样组内进行资源分配,组还能够再分。
即便有了chroot,nameespaces, control cgroups,容器的隔离能力比起主机级别虚拟化依然差不少,由于容器毕竟属于同一个内核,而主机级虚拟化那么好,由于内核原本就是自然的隔离,所以为了增强安全性,防止里面的进程经过漏洞绕过边界伸到别的用户空间,经过selinux各类安全机制增强容器的边界,为了支撑容器作的更加完善。
容器实现就是靠chroot,nameespaces,cgroups核心技术实现,而这些在内核已经实现了。
容器原本是靠jail启发有了vserver,后来为了让这种容器更加易用,
由于建立容器要本身写代码,系统调用,克隆等来实现的,但麻烦程度很大。
因此咱们最好把实现容器的这种功能作成一种工具,极大的简化容器的使用,因而就有了LXC的解决方案,
LXCx container,最先一批真正把完整的容器技术用一组简易使用的工具和摸板来极大的简化了容器的使用方案。
lxc-create : 建立一个容器,template,摸板一组脚本,
建立一个明成空间后,这脚本自动执行后,自动实现安装过程,指向了你所打算建立哪一类明成空间的系统发行版所属的仓库,从仓库中镜像下载过来,安装,生成这个新的名成空间,就能够像虚拟机同样使用。
全部的明成空间都这样实现,而lxc就靠这样这一组工具包快速实现建立空间,利用模板完成内部所须要各类文件的安装,同时还有些工具能够经过chroot切换来切换去,因而咱们就能够愉快的使用了,跟虚拟机没多大区别;
lxc在容器技术推广绝对功不可没,但依然有很高门槛:
# 1. 学好lxc命令 # 2. 必要时候须要定制模板, # 3. 若是在里面运行Mysql,若是服务在里面出现故障,如何迁移数据; # 4. 批量建立也不容易
虽然极大的简化了容器使用,可是在复杂程度没有多大下降的,更况且他的隔离性没有虚拟机那么好,
好处是性能资源方面的节约,让每个进程直接使用宿主机的性能。
因而后来出现了docker:
lxc加强版,也不是容器,容器的一个易用前端工具。
lxc批量建立挺难,docker就在这个上面找突破点,docker早期核心就是lxc,他是lxc的二次封装发行版。
功能上利用lxc作容器管理引擎,建立容器时再也不使用模板安装,而是使用一种镜像技术,
咱们尝试着把一个操做系统用户空间所须要用到的所须要全部组件事先准备编排好,编排好后总体打包成一个文件,叫作镜像文件,这个镜像文件是放在一个集中统一的仓库中的,我把你们都会用到的最小化centos,ubuntu分别放在仓库内;
而在这里咱们在这个最小化系统里面先装好源码nginx,再打包成一个镜像,也放入这个仓库中,当启动建立容器时候,需用镜像,把镜像拖到本地,基于镜像启动容器。因此docker极大的简化了容器使用程度;
好比说你想跑一个tomcat,nginx直接docker run就完成了
为了易于管理,docker还采用另一种方式,在一个用户空间当中,咱们尝试只运行一组进程或一个进程,咱们目的就是为了运行一个有生产力的程序,好比咱们在主机上要跑tomcat,nginx,nginx运行在nginx容器中,tomcat运行在tomcat容器中,两者用容器间通讯逻辑进行通讯,因此之后一个容器只运行一个进程,这也是docker的目的;
lxc就是当虚拟机使用,到时候管理极为不便;
而docker这里实现功能:
不用容器,一个内核之上运行各类进程 ,你们属于同一个用户空间,共享同一组主机名,用户,ipc,pid,在同一个可视范围内,若是一个黑客劫持一个进程以他作跳板能够威胁到其余进程
而docker,把他们给圈起来了,彼此间不可见,并且这个容器只为了这一个进程,最小化定义的;
坏处,占用更多空间,若是服务坏了,调试工具只针对一个容器有效,而若是加上调试工具违反了惟一进程目的,因此带来问题:原本调试一个进程极为简单,可能没有工具:
而要想调试得突破他的边界:
好处;删除了不影响别人:
给运维带来极大不便利,给开发带来巨大好处,分发容易了,一次编写处处运行。如今环境都是异构的,
centos5,6,7/Ubuntu/deepin/suse/kali/redhat/AIX
要开发一个软件,要开发每一种平台的软件,各自组织一个团队开发,只须要打包一个镜像,无论你是windows,linux,unix跟内核不要紧,跟操做系统不要紧,他有本身的明成空间
跟java相似这种效果,可是java有不少版本,6,7,8
之前部署须要发布,变动,故障处理
有了镜像,直接one,就好了,可是还须要接路由器和调度器,若是有一个容器编排工具,之间run结束,甚至连run都不须要你手动执行;
像之前的java容器只能支持java一种语言;
而docker不会管你是什么语言;
随之带来运维的问题,发布操做用编排工具来实现,docker必需要使用编排工具来管理,不用的话手动管理比咱们直接管理应用程序更麻烦,增长咱们运维环境复杂度;但确实是下降开发压力;
运维工做就是维稳,以往调试很容易,而容器可能没有调试工具,这么一来就意味着,我之后作镜像须要为每个镜像自带调试工具,这么一来意味着作镜像须要自带一些工具,之前能共享的,如今不能,但他们倒是隔离的;
docker还有一个好处: 批量建立,他建立容器采用
分层构建,联合挂载;使得咱们之后镜像分发没有那么庞大,好比说我在一个系统上运行三个容器,都是基于底层centos构建,在这里只用一个centos基础镜像,三个上层nginx,tomcat,mariadb,底层镜像是共享的,底层镜像是只读的,要想改,在每一层联合挂载镜像栈最顶层额外附加一个新层,这个层才是能读能写的;
迁移很困难,若是要把容器迁移到其余地方,但这里是有状态的,真正在使用容器时,不会在本地存储有效数据,他会在文件系统上共享存储,而用户存储数据,这个服务不当心宕掉了,再找一个主机从新数据加载就好了,再访问数据还在,因此数据脱离宿主机,脱离容器而持久,容器能够丢到任何主机上;
存储须要一个外置持久性存储,程序是由指令+数据组成,
把容器当进程使用,启动一个容器,就是为了运行一个进程,进程一终止,把容器删了,不要了,下次从新建立,从新挂载
容器不须要持久,容器和进程同样有生命周期,从建立而开始,从中止到结束,跟咱们主机都没多大关系,能够运行在任何主机上;
在docker之上建设一个层次,看那个主机更闲,来个调度法则,若是须要持久数据,给个web存储空间,挂载上去存储数据,一旦任务结束直接容器一删,结束,这个组件能帮咱们把要启动容器调度于整个底层集群环境中某一个docker主机之上,当要构建lnmp,谁先启动,docker就解决不来这种功能,咱们须要一个docker基础之上,可以把这种应用程序依赖关系,从属关系,隶属关系反映在启动关闭时的次序和管理逻辑中,这种功能叫容器编排工具;
# 在docker以后出现了各类编排工具, machine+swarm+compose: # compose只能单机编排, mesos: # 统一资源调度和分配的 + 实现编排须要加上 marathon kubernetes -- > k8s
google使用容器有十几年历史了,听说每一周销毁和新建容器多达几十亿。
docker因缘巧合摸到了这个门道,而且作成开源软件,谷歌就坐不住了,本身原本作为独门武器,那小子竟然找到一种办法还公开全部人使用,原本我最有话语权,秘而不宣藏起来,这样才能称为独门武器,必要时候必杀技;
可是docker已然独霸话语权了,好在docker也不是铁板一块,后来出来出来另外一个公司,谷歌就在后面大力扶植反对派,后来发现难以跟docker抗衡,上不来台面;
容器编排工具在谷歌已经跑了十几年了,该踩的坑都踩的差很少了;
docker三两年作不到;
因而kubemetes横空出世,占据了百分八十的市场,成为市场的标准,还成立了CNCF 容器标准组织,docker有一个问题,docker在编排上没有经验,义无建树,技术没走好,没有吸引更多的土豪进来投资,上市作独角兽,虽然互联网上火的不要不要的,可是没法变现,决定,把开源版拆分为企业版和社区版,将社区更名,把docker流量引入企业版,后来更名叫moby,把全部docker引入企业版,
之因此这样 docker是由于一家商业公司,谷歌在作k8s时候向你们代表我是没有任何意图的,因而把k8s源代码捐给了cncf,cncf是由不少组织联合成立的,主导权再也不属于谷歌,属于IMB,微软等等,不会被人说想把k8s私有化,一年四个版本发布,go研发的
后来docker研发了一个容器引擎,libcontainer,替换了lxc,docker已经被cncf挟持了,cncf本身玩,把docker排除在外,若是之后容器要走下去确定要开源,标准化,谁来负责标准化,cncf就能够作,定义标准,但这样太欺负docker了,因此给docker个机会,你来定标准化,同时作一款开源软件。
如今新的docker引擎已是runC了,
虽然k8s支持不少种容器,但常见的仍是docker+k8s;
docker架构形式:只考虑单机之上,总体架构是这样的:
总体是一个dockerhosts: docker server端
dockerhost 就是运行有docker进程(守护进程)的主机,被称为docerhost,dockerserver;
docker接收到建立和启动容器命令后,将在本地建立容器,一个dockerhost上能够启动多个容器,此处咱们可能运行的分别不属于各类不一样程序的容器,而容器取决于镜像来实现,若是本地没有,dockerdaemon自动连接到registries上,然后从中得到镜像后,先存储到本地一个可以专门存储所谓镜像存储空间中,要求得是特殊而且特殊的文件系统,overlay2,
这里面可能有多个镜像文件,镜像自己是只读的,并且镜像在registries放的时候仓库名就是应用程序名,然后仓库内能够放多个镜像,并且这些镜像一般属于同一个应用程序不一样版本,咱们用标签来识别;
docker镜像:
含有启动容器所须要的文件系统及其内容,所以,其用于建立并启动docker容器:
采用分层构建机制,大致分为两层,最底层为bootfs,其之为rootfs
真正让用户拿来去构建用户空间并运行进程容器的是rootfs;
bootfs: 用于系统引导的文件系统,包括bootloader和kernel ,容器启动完成后会被卸载以节约内存资源
这里的kernel仅仅用于引导并启动一个用户空间,启动完以后就没有了以节约内存资源,毕竟颇有可能咱们用户空间跟底层内核仍是有一点不一样之处的,向上就是rootfs了;
# rootfs: 位于bootfs之上,表现为docker容器的根文件系统; # rootfs: 位于bootfs之上,表现为docker容器的根文件系统
传统模式中,系统启动时,内核挂载bootfs时会首先将其挂载为只读模式,完整性自检完成后将其从新挂载为读写模式;
docker中,rootfs由内核挂载为“只读”模式,然后经过“联合挂载技术”额外挂载一个“可写层”;
这里的分层构建
咱们作一个apache镜像,运行httpd镜像,咱们颇有可能在一个底层的很是基础系统镜像之上一个纯净最小化centos版本,在他之上添加一个编辑器,至关于vim,除此以外添加一个httpd,每添加一个软件都是一个独立的层次,这里是三层,底下bootfs那一层在容器启动时,一旦被引导了完了rootfs时候再卸载并移除,不是删除文件,而是从内存中移除;
而这时候底层只有三层,base image 用来构建一个系统基本组成,/bin;若是要用到额外一个工具,须要额外安装;
可是对于咱们镜像来说,底层镜像是不会动的,额外安装一个vim 他会在里面额外生成一个vim 层,再装个nginx,生成个nginx层;叠加在一块儿挂载的,这三层都是只读的,所以,对于一个容器来说,仅能在writoble上能写,并且若是删除容器,writable也会被删除;
含有启动容器所须要的文件系统及其内容,所以,其用于建立并启动docker容器:
采用分层构建机制,大致分为两层,最底层为bootfs,其之为rootfs
真正让用户拿来去构建用户空间并运行进程容器的是rootfs;
bootfs: 用于系统引导的文件系统,包括bootloader和kernel ,容器启动完成后会被卸载以节约内存资源
这里的kernel仅仅用于引导并启动一个用户空间,启动完以后就没有了以节约内存资源,毕竟颇有可能咱们用户空间跟底层内核仍是有一点不一样之处的,向上就是rootfs了;
镜像分层构建和联合挂载依赖于文件系统的支撑
早起用到的是Aufs,高级多层统一文件系统:
最先被docker拿来用于实现联合挂载的Linux文件系统,
aufs是以前的unionfs从新实现,重写后依然很烂,三万行代码,一个ext4才四五千代码,这是要被整合进内核的,所以被申请时,次次被拒绝,一直到不申请,aufs一直都不是内核中自有的文件系统,想用须要向内核打补丁,centos不会干这种事情,由于他们以保守稳定为初衷,ubuntu是很早一批把aufs打包进内核,早些时候想要使用docker需使用ubuntu.
aufs的竞争产品是overlayfs(),后者自从3.18版本才开始被合并到linux内核;
docker的分层镜像,除了aufs,docker还支持btrfs,devicemapper和vsf等;
docker默认是aufs; centos7用的是devicemapper;在试用联合挂载不好,不稳定,由于它使用target driver;
比较成熟的支持的文件系统必需要可以是docker info当中的overlay2,xfs,overlay2是一种抽象的二级文件系统,他须要创建在本地文件系统之上;
构建镜像时,镜像作好以后,应该有一个统一存储的位置,叫作doceker registry
启动容器时,docker daemon会试图从本地获取相关的镜像: 本地镜像不存在时,将其从registry中下载该镜像并保存到本地;
若是咱们没有特别指定,那么他就是registry,若是要指向别的registry咱们必须在镜像的访问路径当中给明服务器地址;不然访问默认的registry,除非咱们修改默认;
# Registry用于保存docker镜像,包括镜像的层次结构和元数据 # 用户可自建Registry,也可使用官方的docker hub 分类: # Sponsor Registry 第三方的registry,供客户和docker社区使用 # Mirror Registry 第三方的registry,只让客户使用 # Vendor Registry 由发布docker 镜像的供应商提供的registry提供给买了红帽系统使用 # Private Registry # 经过设有防火墙和额外的安全层的私有实体提供的registry 不消耗互联网带宽,尤为是本地大规模容器自建本地registry;
OCI
由linux基金会于2015年6月创立
旨在围绕容器格式和运行时制定一个开放的工业化标准
RunC: 不管是客户端仍是服务端,都由docker一个程序提供,他有不少子程序,他能够监听在一个套件字之上;
docker有三种类型套接字,
docker启动容器就是基于镜像启动,在镜像基础之上,为一个容器建立一个专用可写层;
containers:容器,
lmages: 镜像 镜像来自于Registry,注册表,能够称为docker的镜像仓库,默认就是docker hub,默认本地是没有的,镜像是分层构建的,因此下载到本地后,能够共享多个上层镜像使用,由于镜像是只读的,因此启动容器就是基于镜像来启动,在镜像基础上为一个容器建立一个专用的可写层,从而来启动这个容器。
因此这里镜像也须要在docker本地存储,所以这有专门的仓库来放镜像,而镜像拥有几十万之多,因此放到一个公共的仓库,须要时候拉取过来加载到本地,这里的协议是http/https,默认是加密的,须要明肯定义成不安全才可使用;
docker的运行过程当中尤为是建立容器时可能有一点慢,缘由是他要下载一次镜像,取决于他的宽带;
由于服务器在国外, 为了能使加速访问,docker在大陆这边作了一个docker镜像服务器,docker.cn,加速不太好,可使用阿里,科大,因此要想使用docker,必需要能接入到互联网。
docker镜像是分层构建的
仓库: 一个docker拥有两重功能,第一,他提供镜像提供的仓库,第二,他还提供用户来获取镜像时的认证等功能,还提供了当前服务器全部可用镜像的索引;
因此镜像也会有应用到不一样程序版本的镜像,为了让镜像跟应用程序版本有必定的关联,给镜像外面加了一个标签,仓库名+标签才能惟一标识一个镜像。若是只给了仓库名,那就是默认最新版;一个镜像能够有多个标签,在仓库名+标签外面加上 stable最新版,稳定版什么的;
镜像是静态的;
# 容器: 动态,生命周期,相似于程序; #任何images,networks,volumes,plugins能够支持增删改查的,由于他们都是对象; # 依赖的基础环境: # 64 bits CPU # Linux KERNEL 3.10+ CentOS6也支持docker,2.6.32,打了补丁;
若是咱们要是 就使用docker,若是咱们要使用在这的仓库就下载docker,区别EE和CE;
Docker 从 1.13 版本以后采用时间线的方式做为版本号,分为社区版 CE 和企业版 EE,社区版是免费提供给我的开发者和小型团体使用的,企业版会提供额外的收费服务,好比通过官方测试认证过的基础设施、容器、插件等。
社区版按照 stable 和 edge 两种方式发布,每一个季度更新 stable 版本,如 17.06,17.09;每月份更新 edge 版本,如17.09,17.10。
init_security() { systemctl stop firewalld systemctl disable firewalld &>/dev/null setenforce 0 sed -i '/^SELINUX=/ s/enforcing/disabled/' /etc/selinux/config sed -i '/^GSSAPIAu/ s/yes/no/' /etc/ssh/sshd_config sed -i '/^#UseDNS/ {s/^#//;s/yes/no/}' /etc/ssh/sshd_config systemctl enable sshd crond &> /dev/null rpm -e postfix --nodeps echo -e "\033[32m [安全配置] ==> OK \033[0m" } init_security init_yumsource() { if [ ! -d /etc/yum.repos.d/backup ];then mkdir /etc/yum.repos.d/backup fi mv /etc/yum.repos.d/* /etc/yum.repos.d/backup 2>/dev/null if ! ping -c2 www.baidu.com &>/dev/null then echo "您没法上外网,不能配置yum源" exit fi curl -o /etc/yum.repos.d/163.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo &>/dev/null curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo &>/dev/null yum clean all timedatectl set-timezone Asia/Shanghai echo "nameserver 114.114.114.114" > /etc/resolv.conf echo "nameserver 8.8.8.8" >> /etc/resolv.conf chattr +i /etc/resolv.conf echo -e "\033[32m [YUM Source] ==> OK \033[0m" } init_yumsource
# 安装一些必要的系统工具 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加软件源信息 # docker 官方源 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 阿里云源 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安装前能够先更新 yum 缓存: sudo yum makecache fast # CentOS7安装 Docker-ce yum -y install docker-ce # CentOS 中安装 apt-get install docker-ce # Ubuntu 中安装 pacman -S docker # Arch 中安装 emerge --ask docker # Gentoo 中安装 # 若是想安装特定版本的Docker-ce版本,先列出repo中可用版本,而后选择安装 yum list docker-ce --showduplicates |sort -r Loading mirror speeds from cached hostfile Loaded plugins: fastestmirror Installed Packages docker-ce.x86_64 3:19.03.4-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.4-3.el7 @docker-ce-stable docker-ce.x86_64 3:19.03.3-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.2-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.1-3.el7 docker-ce-stable yum install docker-ce-<VERSION STRING> # 选择安装 docker-ce-18.06.1.ce yum install docker-ce-18.06.1.ce # Docker镜像加速 # 没有启动/etc/docker目录不存在,须要本身建立,docker启动也会本身建立 # 为了指望咱们的镜像下载快一点,应该定义一个镜像加速器,加速器在国内 mkdir /etc/docker vim /etc/docker/daemon.json { "registry-mirrors": ["https://registry.docker-cn.com"] } # 启动Docker后台服务 systemctl start docker && systemctl enable docker systemctl daemon-reload # 守护进程重启 # 经过运行hello-world镜像,验证是否正确安装了docker,或者经过查看版本 docker run hello-world docker version Client: Docker Engine - Community Version: 19.03.4 API version: 1.40 Go version: go1.12.10 Git commit: 9013bf583a Built: Fri Oct 18 15:52:22 2019 OS/Arch: linux/amd64 Experimental: false
在 Ubuntu/Debian 上有 UnionFS 可使用,如 aufs 或者 overlay2 ,而 CentOS 和 RHEL 的内核中没有相关驱动。所以对于这类系统,通常使用 devicemapper 驱动利用 LVM 的一些 机制来模拟分层存储。这样的作法除了性能比较差外,稳定性通常也很差,并且配置相对复 杂。Docker 安装在 CentOS/RHEL 上后,会默认选择 devicemapper ,可是为了简化配置, 其 devicemapper 是跑在一个稀疏文件模拟的块设备上,也被称为 loop-lvm 。这样的选择是 由于不须要额外配置就能够运行 Docker,这是自动配置惟一能作到的事情。可是 loop-lvm 的作法很是很差,其稳定性、性能更差,不管是日志仍是 docker info 中都会看到警告信 息。官方文档有明确的文章讲解了如何配置块设备给 devicemapper 驱动作存储层的作法,这 类作法也被称为配置 direct-lvm 。
除了前面说到的问题外, devicemapper + loop-lvm 还有一个缺陷,由于它是稀疏文件,所 以它会不断增加。用户在使用过程当中会注意到 /var/lib/docker/devicemapper/devicemapper/data 不断增加,并且没法控制。不少人会但愿删 除镜像或者能够解决这个问题,结果发现效果并不明显。缘由就是这个稀疏文件的空间释放 后基本不进行垃圾回收的问题。所以每每会出现即便删除了文件内容,空间却没法回收,随 着使用这个稀疏文件一直在不断增加。 因此对于 CentOS/RHEL 的用户来讲,在没有办法使用 UnionFS 的状况下,必定要配置 direct-lvm 给 devicemapper ,不管是为了性能、稳定性仍是空间利用率。 或许有人注意到了 CentOS 7 中存在被 backports 回来的 overlay 驱动,不过 CentOS 里的 这个驱动达不到生产环境使用的稳定程度,因此不推荐使用。
对于大部分企业来讲,搭建PaaS既没有那个精力,也没那个必要,用Docker作我的的sandbox用处又小了点。能够用Docker来标准化开发、测试、生产环境。
Docker占用资源小,在一台E5128G内存的服务器上部署100个容器都绰绰有余,能够单独抽一个容器或者直接在宿主物理主机上部署samba,利用samba的home分享方案将每一个用户的home目录映射到开发中心和测试部门的Windows机器上。
针对某个项目组,由架构师搭建好一个标准的容器环境供项目组和测试部门使用,每一个开发工程师能够拥有本身单独的容器,经过 docker run -v 将用户的home 目录映射到容器中。须要提交测试时,只须要将代码移交给测试部门,而后分配一个容器使用 -v加载测试部门的 home目录启动便可。这样,在公司内部的开发、测试基本就统一了,不会出现开发部门提交的代码,测试部门部署不了的问题。
测试部门发布测试经过的报告后,架构师再次检测容器环境,就能够直接交由部署工程师将代码和容器分别部署到生产环境中了。这种方式的部署横向性能的扩展性也极好。
Docker --help container 管理容器 image 管理镜像 network 管理网络 命令: attach 介入到一个正在运行的容器 build 根据 Dockerfile 构建一个镜像 commit 根据容器的更改建立一个新的镜像 cp 在本地文件系统与容器中复制 文件/文件夹 create 建立一个新容器 exec 在容器中执行一条命令 images 列出镜像 kill 杀死一个或多个正在运行的容器 logs 取得容器的日志 pause 暂停一个或多个容器的全部进程 ps 列出全部容器 pull 拉取一个镜像或仓库到 registry push 推送一个镜像或仓库到 registry rename 重命名一个容器 restart 从新启动一个或多个容器 rm 删除一个或多个容器 rmi 删除一个或多个镜像 run 在一个新的容器中执行一条命令 search 在 Docker Hub 中搜索镜像 start 启动一个或多个已经中止运行的容器 stats 显示一个容器的实时资源占用 stop 中止一个或多个正在运行的容器 tag 为镜像建立一个新的标签 top 显示一个容器内的全部进程 unpause 恢复一个或多个容器内全部被暂停的进程
service docker start # 启动 docker 服务,守护进程 service docker stop # 中止 docker 服务 service docker status # 查看 docker 服务状态 chkconfig docker on # 设置为开机启动 systemctl stop docker systemctl start docker systemctl enable docker systemctl daemon-reload # 守护进程重启
# 镜像能够看作咱们平时装系统的镜像,里面就是一个运行环境 # Docker Hub上有大量的高质量镜像能够用,这里就说一下怎么获取这些镜像, # 从镜像仓库获取镜像的命令是docker pull,其命令格式为: docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] docker search centos # 搜索docker官方提供的centos镜像 docker search centos --filter=stars=100 # 查找stars数至少为100的镜像 docker pull centos # 默认从官网拉取 docker pull centos:7.7.1908 # 默认拉取centos8,须要指定版本才能下载7. docker pull daocloud.io/library/centos # 从daocloud拉取 docker dao pull centos # 从daocloud拉取,国内仓库
注意
咱们使用docker image ls时候会发现,镜像体积的所占用空间在Docker Hub上看到的镜像大小不一样,好比nginx镜像在docker hub官网上是50多兆,而把他pull下来就变成一百多兆了,这是由于docker hub所显示大小是网络传输中更关心的流量大小,而docker image ls显示的是镜像下载到本地展开后的各层所占空间的综合,由于镜像下载到本地后,更关心的是磁盘空间占用的大小.
另外一个须要注意问题是,docker image ls列表中的镜像体积综合并不是是全部镜像实际硬盘消耗,因为Docker镜像是多层存储结构,而且能够继承、复用,所以不一样镜像可能由于使用相同的基础镜像,从而拥有共同的层,因为Docker使用UnionFS,相同的层只须要保存一份便可,所以实际占用硬盘空间极可能比这个列表镜像大小的总和小的多.
docker system df # 查看镜像、容器、数据卷所占用的空间. docker images # 查看已下载的镜像 docker rm image_id # 删除镜像,指定镜像id docker images # 查看已下载的镜像 docker images -q # 只查看全部镜像的id docker inspect imageID # 查看镜像详情
docker rm image_id # 删除镜像,指定镜像id docker rmi RepositoryName --force # 删除镜像,指定镜像名,<仓库名>:<标签> --force镜像在使用中强制删除 # 若是镜像正在被未运行的容器使用,则须要强制删除,可是若是正在被运行的容器使用,则强制删除也没法删除 docker image ls -a # 这样会看到不少无标签的镜像,这些无标签镜像不少都是中间层镜像, # 是其余镜像所须要依赖的镜像,这些无标签镜像不该该删除,不然会致使上层镜像由于缺失依赖而出错, # 实际上也不必删除,由于相同的层只会存一遍,而这些镜像是别的镜像的依赖, # 所以并不会由于他们被列出来而多存了一份,不管如何你也会须要他们, # 删除那些依赖他们的镜像,这些中间层镜像也会被连带删除. # 删除全部仓库名为redis的镜像: docker image rm $(docker image ls -q redis) # 删除全部镜像 # none 默认为 docker.io docker rmi $(docker images | grep none | awk '{print $3}' | sort -r) docker rmi $(docker images -q)
启动容器有两种方式,一种基于镜像新建一个容器并启动,另一个是将在终止状态(stopped)的容器从新启动.
由于docker的容器过轻量级了,不少时候用户都是随时删除和重建.
# 容器就像是一个类的实例(好比一个基于CentOS7镜像启动的虚拟机) # 链接进行进入命令行模式,exit命令退出。 docker run -t -i nginx:latest /bin/bash -i # 交互式操做,让容器的标准输入保持打开. -t # 让docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上 nginx:latest # 基于centos构建的nginx镜像 /bin/bash # 放在镜像后的命令,这里咱们但愿有个交互式shell,所以用的是/bin/bash # 当咱们基于镜像启动一个实例的时候,此时他就是容器了. # 就比如CentOS7.iso镜像和已经运行了的CentOS7虚拟机同样. # 同一个镜像能够启动多个容器 # 建立运行容器且链接到容器 docker run -it --rm -d --cidfile="id.txt" centos /bin/bash -i # 捕获标准输入输出,保持交互式的意思 -t # 分配一个终端或控制台,每个控制台都要伴随一个shell --rm # 退出时就删除该容器,默认状况下,每一个容器在退出时,他的文件系统会保存下来,这样一方面有利于调试, # 由于能够经过查看日志等方式来肯定最终状态;另外一方面,也能够报错容器所产生的数据, # 若是仅仅须要短暂的运行一个容器,且不须要保存容器中的数据, # 就能够在exit容器时自动清理掉容器及产生的数据,但此选项不能与-d共用 /bin/bash # 容器运行起来以后运行的程序,也能够是任何的命令,/bin/echo hello --cidfile # 指定容器运行以后container长id的存放文件位置 -d # 若是不使用-d参数运行容器,容器会把输出的结果(STDOUT)打印到宿主机上面, # 若是使用了-d参数会返回一个id,也能够经过docker ps 查看容器信息. # 要获取容器的输出信息,能够经过docker container logs命令查看 # 容器可否长久运行是和docker run指定的命令有关,和-d参数无关.
当利用docker run来建立容器时,Docker在后台运行的标准操做包括:
# 1. 检查本地是否有指定的镜像,不存在就从公有仓库下载 # 2. 利用镜像建立并启动一个容器 # 3. 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层. # 4. 从宿主主机配置的网桥接口中桥接一个虚拟接口道容器中去. # 5. 从地址池中配置一个ip地址给容器. # 6. 执行用户指定的应用程序. # 7. 执行完毕后容器被终止.
docker start my-nginx # 启动一个已经存在的容器 docker restart my-nginx # 重启容器 docker stop my-nginx # 中止运行一个容器 docker kill my-nginx # 杀死一个运行中的容器 docker rename my-nginx new-nginx # 重命名容器 docker rm new-nginx # 删除容器 docker stop $(docker ps -q) & docker rm $(docker ps -aq) # 停掉全部容器并删除 docker container prune # 删除全部处于终止状态的容器. docker logs [containerID/Names] # 查看日志 docker logs my-nginx # 查看 my-nginx 容器日志 # 使用docker exec命令进入一个已经在运行的容器 docker exec -it [containerID/Names] /bin/bash # 进入容器 docker attach 7968b44369 # 会附加该容器的标准输出到当前命令行 # 启动状态的容器,执行任务 # 经过exec命令能够建立两种任务:后台型任务和交互型任务 # 后台型任务:docker exec -it test /bin/bash # 交互型任务:docker attach 7968 docker run centos echo "hello world" # 在docker容器中运行hello world! docker run centos yum install -y wget # 在docker容器中,安装wget软件 docker ps # 列出包括未运行的容器 docker ps -a # 查看全部容器(包括正在运行和已中止的) docker ps -a -q # 查看全部容器的ID docker ps -s # 查看容器使用了多少内存 docker ps -qf status=running # 查看某种状态的容器ID docker ps -l # 列出最近一次启动的容器 docker inspect 7657b3785bcf # 查看容器详细配置信息,包含容器名,环境变量,运行命令,主机配置,网络配置,数据卷配置等,json格式; docker inspect -f {{.State.Pid}} 44fc0f0582d9 # 获取id为 44fc0f0582d9 的PID进程编号 docker inspect --format '{{.Config.Image}}' 7657b3485 # 获取当前运行镜像版本 docker inspect --format='{{.NetworkSettings.IPAddress}}' 7657b3485 # 获取当前运行镜像的IP地址
# 打印该容器输出 docker run -it -d --name test centos /bin/bash -c "while true; do echo hello world;sleep 2;done" docker logs test # 监控容器运行 docker logs container_id/container_name --tail: # 选项能够指定查看最后几条日志 -t: # 选项则能够对日志条目附加时间戳 -f: # 选项能够跟踪日志的输出,直到手动中止 # 运行远程机器上的容器 docker run -it -d -h 39.108.140.0 daocloud.io/centos:7 # 断开容器 # 断开与容器的链接,而且关闭容器 [root@7968b4436989 /]# exit [root@7968b4436989 /]# docker stop 7968b443 # 只断开和容器的链接而不关闭容器 # 快捷键: ctrl+p+q # 关闭运行中的容器 # 若是此时有其余终端正在对他进行交互会自动中断 # docker stop contrainer_id/name //发送SIGTERM信号,可忽略,15信号 # docker kill contrainer_id/name //发送SIGKILL信号,9信号
# 导出容器 # 镜像打包 # 方案一: export # 利用export把正在运行的容器直接导出为tar包的镜像文件,能够用-o或> docker run --name my-nginx -d -p 8080:80 some-centent-nginx:1.2 docker export my-nginx > youmen_nginx.tar && docker export -o youmen_nginx.tar my-nginx scp youmen_nginx.tar 120.77.248.31: docker import youmen_nginx.tar docker tag 121d8 mynginx:1 # 设置镜像名字 docker import youmen_nginx.tar mynginx:1.1 # 导入时即设置镜像名字 方案二: 利用save直接把镜像打包出来 docker save -o suibian.tar library/centos:latest scp suibian.tar 192.168.135.161: docker load < suibian.tar # 导入以后使用原名 # 导入也能够经过指定URL或者某个目录来导入 docker import http://example.com/exampleimage.tgz example/imagerepo ------------------------------------区别介绍------------------------------------- # docker save:将一个镜像导出为文件,保存的是该镜像的全部历史记录; # docker export:将一个容器导出为文件,保存的是容器当时的状态,即容器快照; # docker load:将镜像存储文件导入到本地镜像库; # docker import:导入一个容器快照到本地镜像库; docker save和docker export之间的区别: 1> docker save是将镜像保存为tar包,且会保存该镜像的父层、标签、全部历史等信息; docker export是将容器文件系统保存为tar包,仅仅保存的是容器当时的状态(快照); 2> docker save能够同时指定多个镜像名称;docker export只能指定一个容器名称; 3> docker save保存的镜像文件tar包使用docker load命令加载还原; docker export保存的容器快照tar包使用docker import命令导入还原; 4> docker save保存的tar包文件一般比docker export导出的文件要大; docker load和docker import之间的区别: 1)docker load将镜像存储文件导入到本地镜像库;docker import将容器快照文件导入到本地镜像库; 2)docker load不能指定url;而docker import能够指定url来进行导入;
# Docker容器开机启动设置 sudo docker run --restart=always -it centos /bin/bash --restart=always # 默认状况下docker重启以后全部容器会被关闭,这个选项的意思是容器随docker engine自启动 # 若是建立时候未指定--restart=always,可经过docker update命令设置: docker update --restart=always 7b5f30fe77c0 # 注意Docker服务开启启动 # restart参数介绍 # no:容器退出时候,不重启容器 # on-failure: 只有在非0状态退出时才从新启动容器 # always:不管退出状态是如何,都重启容器 # unless-stopped: 在容器退出时老是重启容器,可是不考虑在Docker守护进程启动时就已经中止了的容器 # 在使用on-failure策略时,指定Docker将尝试从新启动容器的最大次数; # 默认状况下,Docker将尝试永远从新启动容器 # sudo docker run --restart=on-failure:5 <image>