那些实现 Docker 的底层 Linux 技术

Docker 是现在最流行的虚拟化技术,解决了棘手的机器资源共享的问题,同时不需要特别了解原理也能轻松上手,所以自问世之后就不断蔓延开来。作为从业人员,为了对底层进行一定的修改,就不得不了解与它相关的技术。这篇文章我整理了相关的资料做个备忘。由于血衫的技术能力有限,如果有错误的地方,也请大家指正。

一、关于docker

Docker 技术使用 Linux内核 和内核功能(例如 Cgroupsnamespace)来隔离进程,以便它们可以独立运行。这种独立性使得我们更好地管理应用程序,同时又保留了单独系统所具有的安全性

1. docker和Linux容器的区别

docker和 传统的Linux容器是不相同的。

容器技术最初是建立在 LXC 技术上的。LXC是轻量级的虚拟化。LXC起源于cgroup和namespaces,使得进程之间相互隔离,即进程虚拟化。

img

如上图示意,LXC是一种基于容器的操作系统层级的虚拟化技术,包含了完整的操作系统。LXC 真正的实现是靠 Linux 内核的相关特性,LXC项目对此做了整合,可以

  • 为容器绑定特定的cpu和memory节点
  • 分配特定比例的cpu时间、IO时间
  • 限制可以使用的内存大小(包括内存和是swap空间)
  • 提供device访问控制
  • 提供独立的namespace(网络、pid、ipc、mnt、uts)

Docker 容器将应用和其依赖环境全部打包到一个单一对象中,在不包含完整的操作系统的情况下就能运行普通应用,更加轻量级,可移植性更好。Docker是一个应用程序容器,在2014年6月召开的 DockerCon 2014 技术大会上,吸引了 IBM、Google、RedHat 等业界知名公司的关注和技术支持。无论是从 GitHub 上的代码活跃度,还是开源巨头红帽宣布在 RHEL7 中正式支持 Docker 技术,都可以说明 Docker 技术是一项创新型的技术解决方案,就连 Google 公司的 Compute Engine 也很快支持 Docker 在其之上运行。国内 BATJ也相继推出容器服务紧追云计算发展趋势。

Docker 技术解决以下问题:

  • 复杂的环境配置管理:从各种 OS 环境到各种中间件环境以及各种应用环境。

    img

  • 新的软件管理方法:云计算时代的到来,解决了硬件管理的问题,然而软件配置和管理相关的问题依然存在。

  • 虚拟化手段的变化:云时代无论是 KVM 还是 Xen,在 Docker 看来都在浪费资源,因为用户需要的是高效运行环境而非 OS,GuestOS 既浪费资源又难于管理,轻量级的 LXC 更加灵活和快速。

    img

  • 容器技术的便携性。LXC 在 Linux2.6 的 Kernel 里就已经存在了,但是其设计之初并非为云计算考虑的,缺少标准化的描述手段和容器的可便携性,决定其构建出的环境难于分发和标准化管理(相对于 KVM 之类 image 和 snapshot 的概念)。Docker 就在这个问题上做出了实质性的创新方法。

2. Docker底层技术

早期Docker用LXC(Linux Container)做底层,所以LXC中使用到的技术,Docker基本也都使用了。 namespace,cgroup,chroot,UnionFS都用到了。【前两个是内核特性】

  • namespace:用于资源隔离,通过使用独立的namespace来实现进程隔离,网络隔离,挂载隔离(文件隔离)等。
  • cgroup:用于资源限制,对一组进程的cpu/内存/网络/IO等资源进行分配限制。
  • UnionFS:AUFS是一种联合文件系统(UnionFS),可以将多个目录合并 再mount到一个目录上。DockerFile 镜像分层结构具体就是利用了AUFS的特性。每一层都是一个目录。镜像的构建过程可以简单理解为将多个目录进行合并【Docker支持众多UnionFS,AUFS只是其中一种。】

二、Linux namespace

每个用户实例之间相互隔离,互不影响。一般的硬件虚拟化方法给出的方法是 VM,而 LXC 给出的方法是 container,更细一点讲就是 kernel namespace。其中 pid、net、ipc、mnt、uts、user 等 namespace 将 container 的进程、网络、消息、文件系统、UTS(“UNIX Time-sharing System”)和用户空间隔离开。

Linux 的命名空间机制提供了以下七种不同的命名空间,包括

  • CLONE_NEWCGROUP
  • CLONE_NEWIPC
  • CLONE_NEWNET
  • CLONE_NEWNS
  • CLONE_NEWPID
  • CLONE_NEWUSER
  • CLONE_NEWUTS

通过这七个选项我们能在创建新的进程时设置新进程应该在哪些资源上与宿主机器进行隔离。

pid namespace

不同用户的进程就是通过 pid namespace 隔离开的,且不同 namespace 中可以有相同 pid。所有的 LXC 进程在 Docker中的父进程为 Docker 进程,每个 lxc 进程具有不同的 namespace。同时由于允许嵌套,因此可以很方便的实现 Docker in Docker。

net namespace

有了 pid namespace,每个 namespace 中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net namespace 实现的,每个 net namespace 有独立的 network devices,IP addresses,IP routing tables,/proc/net 目录。这样每个 container 的网络就能隔离开来。Docker 默认采用 veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge:docker0连接在一起。

ipc namespace

container 中进程交互还是采用 linux 常见的进程间交互方法(interprocess communication - IPC),包括常见的信号量、消息队列和共享内存。然而同 VM 不同的是,container 的进程间交互实际上还是 host 上具有相同 pid namespace 中的进程间交互,因此需要在 IPC 资源申请时加入 namespace 信息——每个 IPC 资源有一个唯一的32位 ID。

mnt namespace

类似 chroot,将一个进程放到一个特定的目录执行。mnt namespace 允许不同 namespace 的进程看到的文件结构不同,这样每个 namespace 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个 namespace 中的 container 在/proc/mounts 的信息只包含所在 namespace 的 mount point。

uts namespace

UTS(“UNIX Time-sharing System”)namespace 允许每个 container 拥有独立的 hostname 和 domain name,使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。

user namespace

每个 container 可以有不同的 user 和 group id,也就是说可以在 container 内部用 container 内部的用户执行程序而非 Host 上的用户。

三、Linux cgroup

cgroups 实现了对资源的配额和度量。 cgroups 的使用非常简单,提供类似文件的接口,在/cgroup 目录下新建一个文件夹即可新建一个 group,在此文件夹中新建 task 文件,并将pid 写入该文件,即可实现对该进程的资源控制。groups 可以限制 blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns 九大子系统的资源,以下是每个子系统的详细说明:

  1. 有序列表 blkio 这个子系统设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及 usb 等等。
  2. cpu 这个子系统使用调度程序为 cgroup 任务提供 cpu 的访问。
  3. cpuacct 产生 cgroup 任务的 cpu 资源报告。
  4. cpuset 如果是多核心的 cpu,这个子系统会为 cgroup 任务分配单独的 cpu 和内存。
  5. devices 允许或拒绝 cgroup 任务对设备的访问。
  6. freezer 暂停和恢复 cgroup 任务。
  7. memory 设置每个 cgroup 的内存限制以及产生内存资源报告。
  8. net_cls 标记每个网络包以供 cgroup 方便使用。
  9. ns 名称空间子系统。

以上九个子系统之间也存在着一定的关系。详情请参阅官方文档。

四、 Linux AUFS

AUFS(AnotherUnionFS),简单来说就是支持将不同目录挂载到同一个虚拟文件系统下的文件系统。

更进一步地理解,AUFS 支持为每一个成员目录(类似Git Branch)设定 readonly、readwrite 和 whiteout-able 权限。同时 AUFS 里有一个类似分层的概念,对 readonly 权限的 branch 可以逻辑上进行修改(增量地,不影响 readonly 部分的)。

通常 Union FS 有两个用途:

  • 可以实现不借助 LVM、RAID 将多个 disk 挂到同一个目录下;
  • 将一个 readonly 的 branch 和一个 writeable 的 branch 联合在一起,Live CD 正是基于此方法可以在 OS image 不变的基础上允许用户在其上进行一些写操作。

Docker 在 AUFS 上构建的 container image 和 Live CD类似。

Linux启动说明

启动Linux运行需要两个FS:

  • bootfs

    bootfs(boot file system)主要包含 bootloader 和 kernel,bootloader 主要是引导加载 kernel,当 boot 成功后 kernel 被加载到内存中后 bootfs 就被 umount 了。

  • rootfs

    rootfs(root file system)包含的就是典型 Linux 系统中的/dev,/proc,/bin,/etc 等标准目录和文件。Linux 在启动后,首先将 rootfs 设置为 readonly,进行一系列检查,然后将其切换为 “readwrite”供用户使用。

img

容器启动说明

  • 初始化时也是将 rootfs 以 readonly 方式加载并检查
  • 利用 union mount 的方式将一个 readwrite 文件系统挂载在 readonly 的 rootfs 之上
  • 继续将一个 readwrite 文件系统挂载在刚才的FS层之上,并将刚才的FS层设置为readonly
  • 持续进行上一个动作直至所有层次完成
  • 将所有 readonly 和一个 writeable 的结构构成一个 container 的运行时态,每一个 FS 被称作一个 FS 层。

对于 container 而言整个 rootfs 都是 read-write 的,但事实上所有的修改都写入最上层的 writeable 层中,image 不保存用户状态,只用于模板、新建和复制使用。

img

参考资料


云计算虚拟化技术

原文:虚拟化技术的分类及介绍,有删减。

虚拟化是云计算系统中的一种基础技术,可以说当前一个云计算服务必定是构建在虚拟化的基础上的。

现代计算机系统是一个庞大的整体,整个计算机系统被分成了多个自下而上的层次,每一个层次都向上一层次呈现一个抽象,并且每一层只需知道下层抽象的接口,而不需要了解其内部运作机制。这样以层的方式抽象资源的好处是每一层只需要考虑本层设计以及与相邻层间的相互交互,从而大大降低了系统设计的复杂性,提高了软件的移植性。

本质上,虚拟化就是由位于下层的软件模块,通过向上一层软件模块提供一个与它原先所期待的运行环境完全一致的接口的方法,抽象出一个虚拟的软件或硬件接口,使得上层软件可以直接运行在虚拟的环境上。虚拟化可以发生在现代计算机系统的各个层次上,不同层次的虚拟化会带来不同的虚拟化概念。

虚拟化技术起始于IBM370体系结构,经过四十余年的发展,当前存在诸多实现在不同层次的虚拟化技术,原理不尽相同,且每一种技术都相当复杂。血衫整理了一些资料,大部分来源于本文开头提到的文章——虚拟化技术的分类及介绍,对目前存在的较流行的虚拟化技术进行分类,并对其原理进行初步介绍,以便对纷繁复杂的虚拟化技术有个整体认识,厘清不同虚拟化技术之间的相互关系。

零、虚拟化的分类

在虚拟化的语境中,物理资源通常有一个定语称为宿主(Host),而虚拟出来的资源通常有一个定语称为客户(Guest)。

在计算机系统中,从底层至高层依次可分为:

  1. 硬件层
  2. 操作系统层
  3. 函数库层
  4. 应用程序层

在对某层实施虚拟化时,该层和上一层之间的接口不发生变化,而只变化该层的实现方式。

从使用虚拟资源的Guest的角度来看,虚拟化可发生在上述四层中的任一层。

应当注意,在对Guest的某一层进行虚拟化时,并未对Host在哪一层实现它作出要求,这一点是时常引起混淆的地方。

一、硬件层虚拟化/系统级虚拟化

实现在此层的虚拟化技术可以对整个计算机系统进行虚拟,即可将一台物理计算机系统虚拟化为一台或多台虚拟计算机系统,故又可称作系统级虚拟化。

每个虚拟计算机系统(简称为虚拟机)都拥有自己的虚拟硬件(如CPU、内存和设备等),来提供一个独立的虚拟机执行环境。

每个虚拟机中的操作系统可以完全不同,并且它们的执行环境是完全独立的。由于客户机操作系统所能看到的是硬件抽象层,因此,客户机操作系统的行为和在物理平台上没有什么区别。

在每台虚拟机中都有属于它的虚拟硬件,通过虚拟化层的模拟,虚拟机中的操作系统认为自己仍然是独占一个系统在运行,这个虚拟化层被称为虚拟机监控器(Virtual Machine Monitor,VMM)。VMM对物理资源的虚拟可以归结为三个主要任务:处理器虚拟化、内存虚拟化和I/O虚拟化。其中,处理器虚拟化是VMM中最核心的部分,因为访问内存或进行I/O本身就是通过一些指令来实现的。

系统级虚拟化又可以按照实现方法分类和实现结构进行:

  • 实现方法

    如果一个体系结构上存在敏感指令不属于特权指令,那么其就存在虚拟化漏洞。从解决虚拟化漏洞的实现方法出发分为如下三类:

    • 仿真(Bochs),所有指令都采用模拟来实现,就是取一条指令,就模拟出这条指令执行的效果。这种方法称作仿真。使用仿真方法的主要问题是速度会非常慢。由于每条指令都必须在底层硬件上进行仿真,因此速度减慢100倍的情况也并不稀奇。

    • 完全虚拟化,无须对操作系统进行任何修改,因此这种方式被称为完全虚拟化。

      Intel的VT-x和AMD的AMD-V是这一方向的代表。以VT-x为例,其在处理器上引入了一个新的执行模式用于运行虚拟机,当虚拟机执行在这个特殊模式中时,它仍然面对的是一套完整的处理器寄存器集合和执行环境。

      完全虚拟化的任何敏感操作都会被处理器截获并报告给VMM,以此来避免虚拟化漏洞,典型的有知名的产品有:

      • VirtualBox
      • KVM
      • VMware Workstation和VMware vSphere
      • Xen
    • 类虚拟化/半虚拟化(Xen和微软的Hyper-V),通过修改操作系统内核的代码,使得操作系统内核完全避免这些难以虚拟化的指令,避免了虚拟化漏洞。

      类虚拟化可以自定义出高度优化的协议I/O。这种I/O协议完全基于事务,可以达到近似物理机的速度。

  • 实现结构

    从Host实现VMM(是否偷懒?)的角度出发,还可以将当前主流的虚拟化技术按照实现结构分为如下三类:

    • Hypervisor模型(VMware vSphere)

      在早期计算机界,操作系统被称为Supervisor,因而能够在其他操作系统上运行的操作系统被称为 Hypervisor。在Hypervisor模型中,VMM首先可以被看做是一个完备的操作系统,不过和传统操作系统不同的是,VMM是为虚拟化而设计的,因此还具备虚拟化功能:

      • 所有的物理资源如处理器、内存和I/O设备等都归VMM所有,因此,VMM承担着管理物理资源的责任
      • VMM需要向上提供虚拟机用于运行客户机操作系统,因此,VMM还负责虚拟环境的创建和管理。

      由于设备驱动开发的工作量是很大的,在实际的产品中,基于Hypervisor模型的VMM通常会根据产品定位,有选择地挑选一些I/O设备来支持,而不是支持所有的I/O设备。

    • 宿主模型(KVM、VirtualBox和VMware Workstation)

    在宿主模型中,物理资源由宿主机操作系统管理。VMM通常是宿主机操作系统独立的内核模块。 VMM通过调用宿主机操作系统的服务来获得资源, 实现处理器、内存和I/O设备的虚拟化。VMM创建出虚拟机之后,通常将虚拟机作为宿主机操作系统的一个进程参与调度。

    由于物理资源由宿主机操作系统控制,因此,VMM虚拟化的效率和功能会受到一定影响。

    安全方面,由于VMM是宿主机操作系统内核的一部分,虚拟机的安全不仅依赖于VMM的安全,也依赖于宿主机操作系统的安全。

    • 混合模型(Xen)

    混合模型是上述两种模式的汇合体。VMM依然位于最低层,拥有所有的物理资源,但VMM 会主动让出大部分I/O设备的控制权,将它们交由一个运行在特权虚拟机中的特权操作系统控制。相应地,VMM 虚拟化的职责也被分担.处理器和内存的虚拟化依然由VMM来完成,而I/O的虚拟化则由VMM和特权操作系统共同合作来完成。

    混合模型集中了上述两种模型的优点。 VMM可以利用现有操作系统的I/O设备驱动程序,不需要另外开发。VMM直接控制处理器、内存等物理资源,虚拟化的效率也比较高。

    采用这种模型的典型是。

另外,不是所有处理器架构都能够虚拟化的。

相同体系结构的系统虚拟化通常会有比较好的性能,并且VMM实现起来也会比较简单。这种情况下虚拟机的大部分指令可以在处理器上直接运行,只有那些与硬件资源关系密切的敏感指令才会由VMM进行处理。

此时面前的一个问题是,要能将这些敏感指令很好地筛选出来。但事实上,某些处理器在设计之初并没有充分考虑虚拟化的需求,导致没有办法识别出所有的敏感指令,因而不具备一个完备的可虚拟化结构。

为了VMM可以完全控制系统资源,它不允许虚拟机上操作系统直接执行敏感指令。如果一个系统上所有敏感指令都是特权指令,则能够用一个很简单的方法来实现一个虚拟环境:将VMM运行在系统的最高特权级上,而将客户机操作系统运行在非最高特权级上,当客户机操作系统因执行敏感指令而陷入到VMM时,VMM模拟执行引起异常的敏感指令。

判断一个架构是否可虚拟化,其核心就在于该结构对敏感指令的支持上。如果一个架构中所有敏感指令都是特权指令,则称其为可虚拟化架构,否则称为不可虚拟化架构。

在x86架构中,所有的特权指令都是敏感指令,然而并不是所有的敏感指令都是特权指令。

二、操作系统层虚拟化

操作系统层上的虚拟化是指操作系统的内核可以提供多个互相隔离的用户态实例。这些用户态实例(经常被称为容器)对于它的用户来说就像是一台真实的计算机,有自己独立的文件系统、网络、系统设置和库函数等。

由于这是操作系统内核主动提供的虚拟化,因此操作系统层上的虚拟化通常非常高效,它的虚拟化资源和性能开销非常小,也不需要有硬件的特殊支持。

但它的灵活性相对较小,每个容器中的操作系统通常必须是同一种操作系统。另外,操作系统层上的虚拟化虽然为用户态实例间提供了比较强的隔离性,但其粒度是比较粗的。

在操作系统虚拟化技术中,每个节点上只有唯一的系统内核,不虚拟任何硬件设备。通过使用操作系统提供的功能,多个虚拟环境之间可以相互隔离。

通常所说的容器(Container)技术,如目前为止最流行的容器系统Docker,即属于操作系统级虚拟化。

相比较于硬件层虚拟化,操作系统层虚拟化有以下优点:

  • 操作系统领域一直以来面临的一个主要挑战来自于应用程序间的相互独立性和资源共享之间的矛盾,即每个应用程序都希望能运行在一个相对独立的系统环境下,不受到其他程序的干扰,同时又能以方便快捷的方式与其他程序交换和共享系统资源。

    当前通用操作系统更强调程序间的互操作性,而缺乏对程序间相对独立性的有效支持,然而对于许多分布式系统如Web服务、数据库、游戏平台等应用领域,提供高效的资源互操作同保持程序间的相对独立性具有同等重要的意义。

    主流虚拟化产品VMware和Xen等均采用Hypervisor模型。该模型通过将应用程序运行在多个不同虚拟机内,实现对上层应用程序的隔离。但由于Hypervisor 模型倾向于每个虚拟机都拥有一份相对独立的系统资源,以提供更为完全的独立性,这种策略造成处于不同虚拟机内的应用程序间实现互操作非常困难。例如, 即使是运行在同一台物理机器上,如果处于不同虚拟机内,那么应用程序间仍然只能通过网络进行数据交换,而非共享内存或者文件。而如果使用容器技术,由于各容器共享同一个宿主操作系统,能够在满足基本的独立性需求的同时提供高效的系统资源共享支持。

  • 容器技术还可以更高效地使用系统资源,由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。

  • 容器还具有更快速的启动时间,传统的虚拟机技术启动应用服务往往需要数分钟,而对于容器由于,直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间,大大的节约了应用开发、测试、部署的时间。

操作系统级的虚拟化实现包括:

  1. chroot

    容器的概念始于 1979 年的 UNIX chroot,它是一个 UNIX 操作系统上的系统调用,用于将一个进程及其子进程的根目录改变到文件系统中的一个新位置,让这些进程只能访问到该目录。这个功能的想法是为每个进程提供独立的磁盘空间。其后在 1982年,它被加入到了 BSD 系统中。

  2. LXC

    LXC 的意思是 LinuX Containers,它是第一个最完善的 Linux 容器管理器的实现方案,是通过 cgroups 和 Linux namespace 实现的。

    LXC 存在于 liblxc 库中,提供了各种编程语言的 API 实现,包括 Python3、Python2、Lua、Go、Ruby 和 Haskell 等。与其它容器技术不同的是, LXC 可以工作在普通的 Linux 内核上,而不需要增加补丁。现在 LXC project 是由 Canonical 公司赞助并托管的。

  3. Docker

    Docker 是到现在为止最流行和使用广泛的容器管理系统。它最初是一个叫做 dotCloud 的 PaaS 服务公司的内部项目,后来该公司改名为 Docker。Docker 开始阶段使用的也是 LXC ,之后采用自己开发的 libcontainer 替代了它。不像其它的容器平台,Docker 引入了一整个管理容器的生态系统,这包括高效、分层的容器镜像模型、全局和本地的容器注册库、清晰的 REST API、命令行等等。

  4. Linux VServer

    Linux-VServer 也是一个操作系统级虚拟化解决方案。Linux-VServer 对 Linux 内核进行虚拟化,这样多个用户空间环境—又称为 Virtual Private Server(VPS) 就可以单独运行,而不需要互相了解。Linux-VServer 通过修改 Linux 内核实现用户空间的隔离。

    Linux-VServer 也使用了 chroot 来为每个 VPS 隔离 root 目录。虽然 chroot 允许指定新 root 目录,但还是需要其他一些功能(称为 Chroot-Barrier)来限制 VPS 脱离其隔离的 root 目录回到上级目录。给定一个隔离的 root 目录之后,每个 VPS 就可以拥有自己的用户列表和 root 密码。

  5. Virtuozzo/OpenVZ

    Virtuozzo是SWsoft公司(目前SWsoft已经改名为Parallels)的操作系统虚拟化软件的命名,Virtuozzo是商业解决方案,而OpenVZ是以Virtuozzo为基础的开源项目,它们采用的也是操作系统级虚拟化技术。OpenVZ 类似于 Linux-VServer,它通过对 Linux 内核进行补丁来提供虚拟化、隔离、资源管理和状态检查。每个 OpenVZ 容器都有一套隔离的文件系统、用户及用户组等。

三、函数库层虚拟化

操作系统通常会通过应用级的库函数提供给应用程序一组服务,例如文件操作服务、时间操作服务等。这些库函数可以隐藏操作系统内部的一些细节,使得应用程序编程更为简单。

不同的操作系统库函数有着不同的服务接口,例如Linux的服务接口是不同于Windows的。

库函数层上的虚拟化就是通过虚拟化操作系统的应用级库函数的服务接口,使得应用程序不需要修改,就可以在不同的操作系统中无缝运行,从而提高系统间的互操作性。

例如,Wine就是在Linux上模拟了Windows的库函数接口,使得一个Windows应用程序能够在Linux上正常运行。

四、应用程序虚拟化

编程语言层上的虚拟机称为语言级虚拟机,例如JVM(Java Virtual Machine)和微软的CLR(Common Language Runtime)。

这一类虚拟机运行的是进程级的作业,所不同的是这些程序所针对的不是一个硬件上存在的体系结构,而是一个虚拟体系结构。这些程序的代码首先被编译为针对其虚拟体系结构的中间代码,再由虚拟机的运行时支持系统翻译为硬件的机器语言进行执行。


VPS 一键安装纯净 Debian Ubuntu CentOS

以前转载过一篇《 Debian(Ubuntu)网络安装/重装系统一键脚本 - 萌咖》,许久没看,最近由于被滴滴服务器的探针问题弄得心猿意马,重新捡起来dd了一下。发现作者也更新了版本,遂再记录一遍。

背景

由于各种原因,VPS 商家的操作系统可能是经过“改装”过的,有可能有内核版本与软件不兼容的问题。 具体到我当前遇到的问题,滴滴云存在一个无法卸载的预设探针,只好使用dd重装官方系统。

不仅是当前,我还计划未来无论哪家的服务器,都要使用dd的方式安装纯净版系统,一来防止商家夹带私货,二来也能让自己的环境变得一致,维护起来更简单一些。

准备

#先运行:
#Debian/Ubuntu:
apt-get update

#RedHat/CentOS:
yum update

#确保安装了所需软件:
#Debian/Ubuntu:
apt-get install -y xz-utils openssl gawk file

#RedHat/CentOS:
yum install -y xz openssl gawk file

#下载:
wget --no-check-certificate -qO InstallNET.sh 'https://moeclub.org/attachment/LinuxShell/InstallNET.sh' && chmod a+x InstallNET.sh

用法

#全自动安装debian 9 64位
bash InstallNET.sh -d 9 -v 64 -a --mirror 'http://mirrors.ustc.edu.cn/debian/'

# 实际上是去这个地址下载了两个文件: http://mirrors.ustc.edu.cn/debian/dists/Debian9.13/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz
http://mirrors.ustc.edu.cn/debian/dists/Debian9.13/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux

#全自动安装ubuntu 18.10 64位
bash InstallNET.sh -u 18.10 -v 64 -a --mirror 'http://archive.ubuntu.com/ubuntu/'

#全自动安装CentOS 6.10 64位
bash InstallNET.sh -c 6.10 -v 64 -a --mirror 'http://mirror.centos.org/centos'

说明一下用法:

        bash InstallNET.sh      -d/--debian [dist-name]
                                -u/--ubuntu [dist-name]
                                -c/--centos [dist-version]
                                -v/--ver [32/i386|64/amd64]
                                --ip-addr/--ip-gate/--ip-mask
                                -apt/-yum/--mirror
                                -dd/--image
                                -a/-m

# dist-name: 发行版本代号
# dist-version: 发行版本号
# -apt/-yum/--mirror : 使用定义镜像
# -a/-m : 询问是否能进入VNC自行操作. -a 为不提示(一般用于全自动安装), -m 为提示.

安装后默认root密码:MoeClub.org

参考资料


删除滴滴云服务器自带的探针

我发现我可以做成一个系列了,删除xxx云服务器探针系列。先前的几篇链接在这里:

滴滴云上也有自家的探针,同样首先来看一下服务器有哪些进程,系统为 Ubuntu 16.04.6 LTS:

pstree -a

可以查到与几个不明的进程,

systemd
  |-accounts-daemon
  |   |-{gdbus}
  |   `-{gmain}
  |-acpid
  |-agetty --keep-baud 115200 38400 9600 ttyS0 vt220
  |-agetty --noclear tty1 linux
  |-atd -f
  |-client                     # 流氓探针在此 卸载了
  |   |-client -type=agent
  |   |   |-php_scanner
  |   |   `-18*[{client}]
  |   `-10*[{client}]
  | ...
  | ...
  | ...
  |-irqbalance --pid=/var/run/irqbalance.pid  # 优化中断分配(可以卸载),自动迁移中断保持中断的平衡,同时会考虑到省电因素等等。 但是在实时系统中会导致中断自动漂移,对性能造成不稳定因素。
  |-iscsid
  |-iscsid
  |-lvmetad -f
  |-lxcfs /var/lib/lxcfs/
  |   `-10*[{lxcfs}]
  |-monitor-agent # 不知道是个什么神奇的东西,大概率也是探针。卸载了
  |   `-10*[{monitor-agent}]
  |-polkitd --no-debug  # 系统层级权限控制(可以卸载)
  |   |-{gdbus}
  |   `-{gmain}
  |-rsyslogd -n
  |   |-{in:imklog}
  |   |-{in:imuxsock}
  |   `-{rs:main Q:Reg}
  |-sga        # 不知道是个什么神奇的东西,大概率也是探针。卸载了
  |   `-5*[{sga}]
  |-sgd        # 不知道是个什么神奇的东西,大概率也是探针。卸载了
  |   `-8*[{sgd}]
  |-systemd-udevd
  `-unattended-upgr /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal     # Debian Linux 自动更新,卸载了
      `-{gmain}

整理了需要卸载这个几个组件,以下命令均需要root权限运行:

  • unattended-upgr

    apt-get remove unattended-upgrades apt-listchanges
    
  • Agent

    这个东西是真流氓。。。。官方都不提供卸载命令:https://help.didiyun.com/hc/kb/article/1136020/

    通过ps aux 可以查到它的具体命令:

    image-20200731235828737

    把pid最小的那个kill掉

    kill -9 7302
    

    我发现我自己没法kill掉。如果直接 mv,也不行,系统会不断报错:

    ERROR: ld.so: object '/usr/local/gundam/gundam_client/preload/$LIB/gundam_preload.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
    

    但是,因为我已经remove掉了,找不回来了。。。所以,就是每敲一个命令行,都会给弹出这样的错误。

  • irqbalance

    apt-get purge --auto-remove -y irqbalance
    
  • polkitd

    systemctl disable polkit.service
    systemctl stop polkit.service
    
  • monitor-agent

    继续用mv的方式不允许启动。
    

最后实在没办法了,由于滴滴使用的也是kvm架构,我DD安装了社区的镜像。可以参考我这篇文章:VPS 一键安装纯净 Debian Ubuntu CentOS


linux 路由表 - zqixiao_09

原文:Linux 网络协议栈开发番外篇(五)—— Linux路由表详解 有改动。

目录:

  • 路由表查看
  • 路由类型
  • 静态路由配置
  • 内核设置

查看 Linux 内核路由表

使用下面的 route 命令可以查看 Linux 内核路由表。

# route
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.0.0     *               255.255.255.0   U     0      0        0 eth0
169.254.0.0     *               255.255.0.0     U     0      0        0 eth0
default         192.168.0.1     0.0.0.0         UG    0      0        0 eth0

route 命令的输出项说明

输出项 说明
Destination 目标网段或者主机
Gateway 网关地址,”*” 表示目标是本主机所属的网络,不需要路由
Genmask 网络掩码
Flags 标记。一些可能的标记如下:
  U — 路由是活动的
  H — 目标是一个主机
  G — 路由指向网关
  R — 恢复动态路由产生的表项
  D — 由路由的后台程序动态地安装
  M — 由路由的后台程序修改
  ! — 拒绝路由
Metric 路由距离,到达指定网络所需的中转数(linux 内核中没有使用)
Ref 路由项引用次数(linux 内核中没有使用)
Use 此路由项被路由软件查找的次数
Iface 该路由表项对应的输出接口

3 种路由类型

主机路由

主机路由是路由选择表中指向单个IP地址或主机名的路由记录。主机路由的Flags字段为H。例如,在下面的示例中,本地主机通过IP地址192.168.1.1的路由器到达IP地址为10.0.0.10的主机。(单个主机)

Destination    Gateway       Genmask        Flags     Metric    Ref    Use    Iface
-----------    -------     -------            -----     ------    ---    ---    -----
10.0.0.10     192.168.1.1    255.255.255.255   UH       0    0      0    eth0

网络路由

网络路由是代表主机可以到达的网络。网络路由的Flags字段为N。例如,在下面的示例中,本地主机将发送到网络192.19.12的数据包转发到IP地址为192.168.1.1的路由器。(一个网段

Destination    Gateway       Genmask      Flags    Metric    Ref     Use    Iface
-----------    -------     -------         -----    -----   ---    ---    -----
192.19.12     192.168.1.1    255.255.255.0      UN      0       0     0    eth0

默认路由

当主机不能在路由表中查找到目标主机的IP地址或网络路由时,数据包就被发送到默认路由(默认网关)上。默认路由的Flags字段为G。例如,在下面的示例中,默认路由是IP地址为192.168.1.1的路由器。

Destination    Gateway       Genmask    Flags     Metric    Ref    Use    Iface
-----------    -------     ------- -----      ------    ---    ---    -----
default       192.168.1.1     0.0.0.0    UG       0        0     0    eth0

配置静态路由

route 命令

设置和查看路由表都可以用 route 命令,设置内核路由表的命令格式是:

# route  [add|del] [-net|-host] target [netmask Nm] [gw Gw] [[dev] If]

其中:

  • add : 添加一条路由规则
  • del : 删除一条路由规则
  • -net : 目的地址是一个网络
  • -host : 目的地址是一个主机
  • target : 目的网络或主机
  • netmask : 目的地址的网络掩码
  • gw : 路由数据包通过的网关
  • dev : 为路由指定的网络接口

route 命令使用举例

添加到主机的路由

# route add -host 192.168.1.2 dev eth0:0
# route add -host 10.20.30.148 gw 10.20.30.40

添加到网络的路由

# route add -net 10.20.30.40 netmask 255.255.255.248 eth0
# route add -net 10.20.30.48 netmask 255.255.255.248 gw 10.20.30.41
# route add -net 192.168.1.0/24 eth1

添加默认路由

# route add default gw 192.168.1.1

删除路由

# route del -host 192.168.1.2 dev eth0:0
# route del -host 10.20.30.148 gw 10.20.30.40
# route del -net 10.20.30.40 netmask 255.255.255.248 eth0
# route del -net 10.20.30.48 netmask 255.255.255.248 gw 10.20.30.41
# route del -net 192.168.1.0/24 eth1
# route del default gw 192.168.1.1

设置包转发

在 CentOS 中默认的内核配置已经包含了路由功能,但默认并没有在系统启动时启用此功能。开启 Linux的路由功能可以通过调整内核的网络参数来实现。要配置和调整内核参数可以使用 sysctl 命令。例如:要开启 Linux内核的数据包转发功能可以使用如下的命令。

# sysctl -w net.ipv4.ip_forward=1

这样设置之后,当前系统就能实现包转发,但下次启动计算机时将失效。为了使在下次启动计算机时仍然有效,需要将下面的行写入配置文件/etc/sysctl.conf。

# vi /etc/sysctl.conf
net.ipv4.ip_forward = 1

用户还可以使用如下的命令查看当前系统是否支持包转发。

# sysctl  net.ipv4.ip_forward