01 . Docker原理部署及常用操作命令

时间:2022-07-25
本文章向大家介绍01 . Docker原理部署及常用操作命令,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Docker的来源及构造:

容器是一种基础工具:泛指任何用于容纳其他物品的工具,可以部分或完全封闭,被用于容纳,储存,运输物品: 物品可以被放置在容器中,而容器可以保护内容物: 人类使用容器的历史有十万年,甚至可能有数百万年的历史:

     #   容器类型:
     #     瓶,罐,箱,篮,桶,袋

但我们重点在LXC这里; 虚拟化和容器的关系: 主机级虚拟化:虚拟化的是整个完整的物理硬件平台,比如VMware,KVM.里面跑的是与宿主机不一样的系统 两种类型: 类型一: 直接在硬件上装一个虚拟机管理器,不装宿主机,在虚拟机管理器上跑需要的操作系统: 类型二: Vmware,kvm 完整意义的操作系统: 我们自己在上面装一个内核,内核上面有一个用户空间,用户空间里面跑进程。 但是运行内核并不是我们主要目的,内核核心作用在于资源分配和管理。 就是说真正在应用空间跑的应用程序才是能产生生产力的,就好比我们跑一个web服务,内核其实很少提供服务。 而出于通用目的的而设计的资源管理平台,操作系统管理内核。我们并不太需要: 但是内核也不得不有,原因在于要想在一组硬件平台跑软件程序,而现在的软件都是针对于内核调用和系统调用,库调用研发的,而不安装这些没法运行程序,所以内核看上去没多大用,但是也必不可少; 更何况,我们一旦有了用户空间后,里面运行很多进程,这些进程为了协调也需要内核。 但假设我们创建一个虚拟机,只为了运行一个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用途

Docker主要用途,目前有三大类

# 1 . 提供一次性的环境。本地测试的软件、持续集成的时候提供单元测试和构建的环境。
# 2 . 提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
# 3 . 组建微服务架构。一台机器可以跑多个服务,在本机可以模拟出微服务架构。
应用场景
# 1 . Web 应用的自动化打包和发布。
# 2 . 自动化测试和持续集成、发布。
# 3 . 在服务型环境中部署和调整数据库或其他的后台应用。
# 4 . 从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境。
具体能干什么?
  • 简化配置:这是Docker公司宣传的Docker的主要使用场景。虚拟机的最大好处是能在你的硬件设施上运行各种配置不一样的平台(软件、系统),Docker在降低额外开销的情况下提供了同样的功能。它能让你将运行环境和配置放在代码中然后部署,同一个Docker的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。
  • 代码流水线管理:前一个场景对于管理代码的流水线起到了很大的帮助。代码从开发者的机器到最终在生产环境上的部署,需要经过很多的中间环境。而每一个中间环境都有自己微小的差别,Docker给应用提供了一个从开发到上线均一致的环境,让代码的流水线变得简单不少。
  • 提高开发效率:这就带来了一些额外的好处:Docker能提升开发者的开发效率。如果你想看一个详细一点的例子,可以参考Aater在DevOpsDays Austin 2014 大会或者是DockerCon上的演讲。 不同的开发环境中,我们都想把两件事做好。一是我们想让开发环境尽量贴近生产环境,二是我们想快速搭建开发环境。 理想状态中,要达到第一个目标,我们需要将每一个服务都跑在独立的虚拟机中以便监控生产环境中服务的运行状态。然而,我们却不想每次都需要网络连接,每次重新编译的时候远程连接上去特别麻烦。这就是Docker做的特别好的地方,开发环境的机器通常内存比较小,之前使用虚拟的时候,我们经常需要为开发环境的机器加内存,而现在Docker可以轻易的让几十个服务在Docker中跑起来。
  • 隔离应用: 有很多种原因会让你选择在一个机器上运行不同的应用,比如之前提到的提高开发效率的场景等。我们经常需要考虑两点,一是因为要降低成本而进行服务器整合,二是将一个整体式的应用拆分成松耦合的单个服务(译者注:微服务架构)。如果你想了解为什么松耦合的应用这么重要,请参考Steve Yege的这篇论文,文中将Google和亚马逊做了比较。
  • 整合服务器:正如通过虚拟机来整合多个应用,Docker隔离应用的能力使得Docker可以整合多个服务器以降低成本。由于没有多个操作系统的内存占用,以及能在多个实例之间共享没有使用的内存,Docker可以比虚拟机提供更好的服务器整合解决方案。
  • 调试能力:Docker提供了很多的工具,这些工具不一定只是针对容器,但是却适用于容器。它们提供了很多的功能,包括可以为容器设置检查点、设置版本和查看两个容器之间的差别,这些特性可以帮助调试Bug。你可以在《Docker拯救世界》的文章中找到这一点的例证。
  • 多租户: 另外一个Docker有意思的使用场景是在多租户的应用中,它可以避免关键应用的重写。我们一个特别的关于这个场景的例子是为IoT(译者注:物联网)的应用开发一个快速、易用的多租户环境。这种多租户的基本代码非常复杂,很难处理,重新规划这样一个应用不但消耗时间,也浪费金钱。使用Docker,可以为每一个租户的应用层的多个实例创建隔离的环境,这不仅简单而且成本低廉,当然这一切得益于Docker环境的启动速度和其高效的diff命令。
  • 快速部署: 在虚拟机之前,引入新的硬件资源需要消耗几天的时间。虚拟化技术(Virtualization)将这个时间缩短到了分钟级别。而Docker通过为进程仅仅创建一个容器而无需启动一个操作系统,再次将这个过程缩短到了秒级。这正是Google和Facebook都看重的特性。你可以在数据中心创建销毁资源而无需担心重新启动带来的开销。通常数据中心的资源利用率只有30%,通过使用Docker并进行有效的资源分配可以提高资源的利用率。
Docker优点
  1. 更快速的交付和部署:Docker在整个开发周期都可以完美的辅助你实现快速交付。Docker允许开发者在装有应用和服务本地容器做开发。可以直接集成到可持续开发流程中。例如:开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。 Docker 可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。 Docker 容器很轻很快!容器的启动时间是秒级的,大量地节约开发、测试、部署的时间。
  2. 高效的部署和扩容:Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。
  3. 更高的资源利用率:Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。
  4. 更简单的管理:使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。

镜像管理基础

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,除非我们修改默认;

Docker 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。

Docker的部署

初始化环境
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 "33[32m [安全配置] ==> OK 33[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 "33[32m [YUM Source] ==> OK 33[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
安装并启动Docker-ce
# 安装前可以先更新 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

CentOS/RHEL的用户需要注意的事项

在 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镜像使用

管理命令

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     恢复一个或多个容器内所有被暂停的进程

Docker服务管理

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容器服务管理
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>

小知识

使用docker命令需要管理员权限,如果希望每次输入docker相关命令时,不用sudo,可通过以下命令进行设置

sudo usermod -a -G docker $USER
sudo service docker restart
newgrp - docker

官方提供的ubuntu系统镜像,工具命令很少,如希望内部安装ping、ifconfig网卡等工具,可以通过以下命令进行设置[需要联网,而且耗时]

apt-get update
apt install net-tools        # ifconfig 
apt install iputils-ping     # ping