工作中有聊到容器安全相关的话题,专门研究了一下容器安全见上一篇博文Docker容器安全性分析,文章详尽的分析了容器相关的安全如图所示:
针对其中的容器逃逸问题,之前关注过Openstack的一个项目Kata container项目:
Kata container是一个开源社区,致力于使用轻量级虚拟机构建安全的容器运行时,这些虚拟机感觉和执行起来都像容器,但是使用硬件虚拟化技术作为第二层防御,提供更强的工作负载隔离。
上一次部署k8s还是去年使用的是v1.17版本,这次打算重新安装一次k8s v1.18版本并搭配kata container试验一下。
这里简要介绍一下docker的组件,为后续的kata containe做一个铺垫。
docker在 1.11 之 后,被拆分成了多个组件以适应 OCI 标准。拆分之后,其包括 docker daemon, containerd,containerd-shim 以及 runC。组件 containerd 负责集群节点上容器 的生命周期管理,并向上为 docker daemon 提供 gRPC 接口。
container-shim,shim的翻译是垫片,就是修自行车的时候,用来夹在螺丝和螺母之间的小铁片。关于shim本身,网上介绍的文章很少,但是作者在 Google Groups 里有解释到shim的作用[2]:
关于docker组件的详细介绍这里不再赘述了,想深入了解可以查看[2]。主要关注的是runc
,后续的kata containe也主要是替换runc
为Hyper的runv
。
Kata container使用的是Rust
语言编写,特性如下:
安全:运行在专用的内核中,提供网络、I/O和内存隔离,可以利用虚拟化VT扩展中的硬件强制隔离。
兼容:支持行业标准,包括OCI容器格式、Kubernetes CRI接口以及传统虚拟化技术。
性能:提供与标准Linux容器一致的性能;增强了隔离性,没有标准虚拟机的性能负担。
简单:消除了在完整的虚拟机内部嵌套容器的要求; 标准接口使插入和入门变得容易。
kata container基于轻量级虚拟机的容器,不同容器跑在一个个不同的虚拟机(kernel)上,比起传统容器提供了更好的隔离性和安全性,同时继承了容器快速启动和快速部署等优点。这也是本次想使用kata 的原因,能够提供比原生docker更好的隔离性,Kata 容器每个容器都使用专有内核,避免容器逃逸后影响宿主机的内核。
废话不多说,开始体验一下kata
这里使用ubuntu 18.04安装kata最新的版本Kata Container 1.12.0
参考kata官方安装手册[3]
1 | admin@k8smaster:~$ ARCH=$(arch) |
安装完成后测试一下
1 | admin@k8smaster:~$ kata-runtime --version |
为了保持安装的docker能够使用,这里默认仍然使用runc
,但是增加kata-runtime
做为可选的docker runtime。相关配置可参考官网kata install。
1 | admin@k8smaster:~$ sudo mkdir -p /etc/systemd/system/docker.service.d/ |
下面创建两个容器,一个使用 kata runtime,另一个使用默认的 runc。创建完容器之后,查看一下 kata container 的一些信息。
1 | admin@k8smaster:~$ docker run -d --name kata-test -p 8080:80 --runtime kata-runtime httpd:alpine |
查看一下两个容器的内核版本
1 | admin@k8smaster:~$ docker exec -it kata-test sh |
查看一下kata容器的虚拟机,可以看到kata专门给容器启动了一个虚拟机沙盒
1 | admin@k8smaster:~$ ps -ef | grep qemu | grep -v 'grep' |
kata 不直接与 k8s 通信,因为对于 k8s 来说,它只跟实现了 CRI 接口的容器管理进程打交道,比如 docker-engine,rkt, containerd(使用 cri plugin) 或 CRI-O,而 kata 跟 runc 是同一个级别的进程。所以如果要与 k8s 集成,则需要安装 CRI-O 或 CRI-containerd 来支持 CRI 接口,本文使用 CRI-O。CRI-O 的 O 的意思是 OCI-compatible,即 CRI-O 是实现 CRI 接口来跑 OCI 容器的[4]。
由于ubuntu 18.04 的suse源中含有相关软件的包,这里展示如何直接用apt快速安装体验,相关软件的版本如表3.1所示
表3.1 相关软件版本
软件名 | 版本 |
---|---|
kubelet、kubeadm、kubectl | 1.18.6 |
cri-o | 1.17 |
kata | 1.12-alpha0 |
CRI-O - OCI-based implementation of Kubernetes Container Runtime Interface
这是cri-o的github标题,符合OCI基准实现的Kubernetes容器运行时接口,从这个标题很容易看出,这是一个专门服务k8s的容器实现。
1)安装cri-o
1 | admin@k8smaster:~$ CRIO_VERSION=1.17 # 当前ubuntu只有1.17 |
2)修改crio配置文件/etc/crio/crio.conf
,增加kata runtime
1 | admin@k8smaster:~$ sudo vim /etc/crio/crio.conf |
3)修改crio systemd配置,设置自启动
1 | admin@k8smaster:~$ sudo vim /usr/lib/systemd/system/crio.service |
4)测试crio
1 | admin@k8smaster:~$ cat /etc/crictl.yaml |
1)添加k8s源并安装k8s
1 | # 使得 apt 支持 ssl 传输 |
2)配置k8s使用crio
根据官方手册,通过cri-o运行k8s需要修改相应文件
1 | admin@k8smaster:~$ sudo cat /etc/default/kubelet |
修改kubeadm配置,修改cgroup驱动为systemd
1 | admin@k8smaster:~$ sudo vim /etc/systemd/system/kubelet.service.d/10-kubeadm.conf |
重启kubelet
1 | admin@k8smaster:~$ sudo systemctl daemon-reload; systemctl restart kubelet |
3)初始化k8s集群
这里通过制定k8s容器仓库为阿里云镜像仓库避免被墙而无法下载镜像,由于阿里云的镜像与官方不同步,因此这里镜像的版本指定为v1.18.0
,稍微与kubeadm的镜像版本v1.18.6
不一致。
1 | admin@k8smaster:~$ sudo kubeadm init --image-repository=registry.aliyuncs.com/google_containers --pod-network-cidr=192.168.0.0/16 --kubernetes-version=v1.18.0 --apiserver-advertise-address=10.37.129.3 --cri-socket=/var/run/crio/crio.sock --v=5 |
--pod-network-cidr=192.168.0.0/16
,若于主机所在网络冲突可修改
--apiserver-advertise-address=10.37.129.3
,可不指定API地址,本次安装为了避免网络影响,给机器新增了一块网口
【NOTE】
1)想查看k8s对应镜像版本可以通过如下命令查看
1 | admin@k8smaster:~$ kubeadm config images list |
对于离线情况下,亦可手动下载镜像再导入,这里推荐一个博客Docker/Kubernetes镜像,详细介绍了如何获取gcr.io
镜像
2)手动安装相关软件最新版本可参考Katacontainers 与 Docker 和 Kubernetes 的集成,文中相关软件版本较老,这里列出相关软件的最新realease版本
这里选用calico网络,参考calico官网
1)安装Tigera Calico操作符和自定义资源定义
1 | admin@k8smaster:~$ kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml |
2)通过创建必要的自定义资源来安装Calico
1 | admin@k8smaster:~$ kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml |
这里需要注意,若k8s集群初始化时CIDR
指定的不是192.168.0.0/16
需要修改custom-resources.yaml
文件中的CIDR
地址
3)确认所有pod都在运行
1 | admin@k8smaster:~$ watch kubectl get pods -n calico-system |
等待所有pod的状态为running
4)本次安装只使用了一个节点,需要配置master节点“无污点”
1 | admin@k8smaster:~$ kubectl taint nodes --all node-role.kubernetes.io/master- |
5)查看所有master节点状态
1 | admin@k8smaster:~$ kubectl get nodes -o wide |
6)查看所有pod状态
1 | admin@k8smaster:~$ kubectl get pods -A -o wide |
k8s从1.14版本开始设置了runt imeclass ,同时crio从1.14版本开始增加RuntimeHandler以取代trusted/untrusted runtime,因此k8s使用kata不能再使用如下配置了。
1 | annotations: |
1)首先创建kata runtime class
编写kata runtime class配置文件
1 | # k8s-runtimecleass.yaml |
创建kata runtime class
1 | admin@k8smaster:~$ kubectl apply -f k8s-runtimecleass.yaml |
2)创建kata runtime pod
1 | admin@k8smaster:~$ cat kata-test.yaml |
等待kata pod 启动,查看pod状态
1 | admin@k8smaster:~$ kubectl get pod -o wide |
【参考链接】
1)Docker组件介绍(二):shim, docker-init和docker-proxy
2)Docker组件介绍(一):runc和containerd
]]>最近在研究k8s搭配kata container,对于其中的CRI很是困惑,借由这篇文章学习一下CRI及其相关概念。
容器运行时插件(Container Runtime Interface,简称 CRI)是 Kubernetes v1.5 引入的容器运行时接口,它将 Kubelet 与容器运行时解耦,将原来完全面向 Pod 级别的内部接口拆分成面向 Sandbox 和 Container 的 gRPC 接口,并将镜像管理和容器管理分离到不同的服务。
CRI 主要定义了两个 grpc interface.
RuntimeService
:容器(container) 和 (Pod)Sandbox 运行时管理ImageService
:拉取、查看、和移除镜像OCI (开放容器标准): 定义了 ImageSpec(镜像格式, 比如文件夹结构,压缩方式)和 RuntimeSpec(如何运行,比如支持 create, start, stop, delete)。代表实现有:runC,Kata(以及它的前身 runV 和 Clear Containers),gVisor。
CRI 区别于 OCI,CRI的定义比较简单直接,只是定义了一套协议(grpc 接口)。代表实现有 kubernetest 内置的 dockershim, CRI-containerd(或者 containerd with CRI plugin), cri-o
在 kubernetes 中:
在和OCI,调度层的角度看:
1 | graph LR |
经典的 kubernetes runtime 执行流程
经典的 dockershim -> containerd 的流程 (称为 docker cri)
直接对接 cri-containerd/cri-o 的运行时
使用 cri-containerd 的调用流程更为简洁, 省去了上面的调用流程的 1,2 两步
常见 CRI runtime 实现
CRI容器运行时 | 维护者 | 主要特性 | 容器引擎 |
---|---|---|---|
Dockershim | Kubernetes | 内置实现、特性最新 | docker |
cri-o | Kubernetes | OCI标准 | OCI(runc、kaata、gVisor) |
cri-containerd | Containerd | 基于containerd | OCI(runc、kaata、gVisor) |
Frakti | Kubernetes | 虚拟化容器 | hyperd、docker |
rktlet | Kubernetes | 支持rkt | rkt |
PouchContainer | Alibaba | 富容器 | OCI(runc、kata) |
Virlet | Mirantis | 虚拟机和QCOW2镜像 | Libvirt(KVM) |
Cri-containerd
执行流程为:
2)K8S Runtime CRI OCI contained dockershim 理解
7)critools
]]>我们为什么使用容器?
我们为什么使用虚拟机(云主机)? 为什么使用物理机? 这一系列的问题并没有一个统一的标准答案。因为以上几类技术栈都有自身最适用的场景,在最佳实践之下,它们分别都是不可替代的。 原本没有虚拟机,所有类型的业务应用都直接跑在物理主机上面,计算资源和存储资源都难于增减,要么就是一直不够用,要么就一直是把过剩的资源浪费掉,所以后来我们看到大家越来越多得使用虚拟机(或云主机),物理机的使用场景被极大地压缩到了像数据库系统这样的特殊类型应用上面。
原本也没有容器,我们把大部分的业务应用跑在虚拟机(或云主机)上面,把少部分特殊类型的应用仍然跑在物理主机上面。但现在所有的虚拟机技术方案,都无法回避两个主要的问题,一个问题是虚拟化Hypervisor管理软件本身的资源消耗与磁盘IO性能降低,另一个是虚拟机仍然还是一个独立的操作系统,对很多类型的业务应用来说都显得太重了,导致我们在处理虚拟机的扩缩容与配置管理工作时效率低下。所以,我们后来发现了容器的好处,所有业务应用可以直接运行在物理主机的操作系统之上,可以直接读写磁盘,应用之间通过计算、存储和网络资源的命名空间进行隔离,为每个应用形成一个逻辑上独立的“容器操作系统”。除此之外,容器技术还有以下优点:简化部署、多环境支持、快速启动、服务编排、易于迁移。
容器技术的一些缺点:仍然不能做到彻底的安全隔离,技术栈复杂度飚升,尤其是在应用了容器集群技术之后。所以如果只是小规模的使用,做实验或测试是可以的,上生产环境需要三思而后行。
Docker容器主要基于以下三个关键技术实现的:
容器引擎(Engine)或者容器运行时(Runtime)是容器系统的核心,也是很多人使用“容器”这个词语的指代对象。容器引擎能够创建和运行容器,而容器的定义一般是以文本方式保存的,比如 Dockerfile。
注:RunC在各个CaaS厂商的推动下在生产环境得到广泛的应用。Kubernetes目前基本只支持RunC容器,对于Docker超出其容器抽象层之外的功能,一概不支持。同样,Mesos也通过其Unified Containerizer只支持RunC容器,目前还支持Docker,但是未来的规划是只支持Unified Containerizer。CF也通过Garden只支持RunC,不支持Docker超出RunC之前的功能。
【笔者注】:目前还有runv为代表的容器runtime,k8s也是支持的。
为什么在容器的启动或运行过程中需要一个 docker-containerd-shim 进程呢?
其目的有如下几点:
rkt与containerd的区别是什么?
一个主要的不同之处是,rkt作为一个无守护进程的工具(daemonless tool),可以用来在生产环境中,集成和执行那些特别的有关键用途的容器。举个例子,CoreOS Container Linux使用rkt来以一个容器镜像的方式执行Kubernetes的agent,即kublet。更多的例子包括在Kubernetes生态环境中,使用rkt来用一种容器化的方式挂载volume。这也意味着rkt能被集成进并和Linux的init系统一起使用,因为rkt自己并不是一个init系统。kubernets支持容器进行部署,其所支持的容器不只是仅仅局限于docker,CoreOS的rkt也是容器玩家之一,虽然跟docker比起来还是明显处于绝对下风,但有竞争总要好过没有。
容器是很轻量化的技术,相对于物理机和虚机而言,这意味着在等量资源的基础上能创建出更多的容器实例出来。一旦面对着分布在多台主机上且拥有数百套容器的大规模应用程序时,传统的或单机的容器管理解决方案就会变得力不从心。另一方面,由于为微服务提供了越来越完善的原生支持,在一个容器集群中的容器粒度越来越小、数量越来越多。在这种情况下,容器或微服务都需要接受管理并有序接入外部环境,从而实现调度、负载均衡以及分配等任务。 简单而高效地管理快速增涨的容器实例,自然成了一个容器编排系统的主要任务。
容器集群管理工具能在一组服务器上管理多容器组合成的应用,每个应用集群在容器编排工具看来是一个部署或管理实体,容器集群管理工具全方位为应用集群实现自动化,包括应用实例部署、应用更新、健康检查、弹性伸缩、自动容错等等。 容器编排和管理系统的分层结构图
容器编排和管理系统界的主要选手:
注:国内外有很多公司在从事基于上面三个基础技术平台的创新创业,为企业提供增值服务,其中做得不错的如Rancher,其产品可以同时兼容 kubernetes、mesos 和 swarm 集群系统,此外还有很多商用解决方案,如OpenShift。
中国市场的表现 在中国市场,2017 年 6 月 Kubernetes 中国社区 K8SMeetup 曾组织了国内首个针对中国容器开发者和企业用户的调研。近 100 个受访用户和企业中给我们带来了关于 Kubernetes 在中国落地状况的一手调查资料显示:
主要的容器技术厂商(包括 Docker、CoreOS、Google、Mesosphere、RedHat 等)成立了 Cloud Native Computing Foundation (CNCF) 。 CNCF对云原生的定义是: – 云原生技术帮助公司和机构在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。 – 这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术可以使开发者轻松地对系统进行频繁并可预测的重大变更。 – 云原生计算基金会(CNCF)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式普惠,让这些创新为大众所用。
注:上图只截取了原图的核心组件部分,完整图表详见https://landscape.cncf.io/images/landscape.png
如下为k8s核心组件示意图
创建Pod的整个流程时序图
容器的大规模使用,也对网络提供了更高的要求。网络的不灵活也是很多企业的短板,目前也有很多公司和项目在尝试解决这些问题,希望提出容器时代的网络方案。 Docker采用插件化的网络模式,默认提供bridge、host、none、overlay、macvlan和Network plugins这几种网络模式,运行容器时可以通过--network
参数设置具体使用那一种模式。
bridge:这是Docker默认的网络驱动,此模式会为每一个容器分配Network Namespace和设置IP等,并将容器连接到一个虚拟网桥上。如果未指定网络驱动,这默认使用此驱动。 – host:此网络驱动直接使用宿主机的网络。
none:此驱动不构造网络环境。采用了none 网络驱动,那么就只能使用loopback网络设备,容器只能使用127.0.0.1的本机网络。
overlay:此网络驱动可以使多个Docker daemons连接在一起,并能够使用swarm服务之间进行通讯。也可以使用overlay网络进行swarm服务和容器之间、容器之间进行通讯,
macvlan:此网络允许为容器指定一个MAC地址,允许容器作为网络中的物理设备,这样Docker daemon就可以通过MAC地址进行访问的路由。对于希望直接连接网络网络的遗留应用,这种网络驱动有时可能是最好的选择。
Network plugins:可以安装和使用第三方的网络插件。可以在Docker Store或第三方供应商处获取这些插件。
在默认情况,Docker使用bridge网络模式。
容器网络模型(CNM)
CNM在2015年由Docker引入,CNM有IP 地址管理(IPAM)和网络插件功能。IPAM插件可以创建IP地址池并分配,删除和释放容器IP。网络插件API用于创建/删除网络,并从网络中添加/删除容器。
容器网络接口(CNI)
CNI诞生于2015年4月,由CoreOS公司推出,CNI是容器中的网络系统插件,它使得类似Kubernetes之类的管理平台更容易的支持IPAM、SDN或者其它网络方案。CNI实现的基本思想为:Contianer runtime在创建容器时,先创建好network namespace,这在实际操作过程中,首先创建出来的容器是Pause容器。之后调用CNI插件为这个netns配置网络,最后在启动容器内的进程。
CNI Plugin负责为容器配置网络,包括两个基本接口:
每个CNI插件只需实现两种基本操作:创建网络的ADD操作,和删除网络的DEL操作(以及一个可选的VERSION查看版本操作)。所以CNI的实现确实非常简单,把复杂的逻辑交给具体的Network Plugin实现。
从理论上说,这些CNI工具的网络速度应该可以分为3个速度等级。
Flannel网络通信原理示意图
因为容器存活时间很短的特点,容器的状态(存储的数据)必须独立于容器的生命周期,也因为此,容器的存储变得非常重要。
Ceph:分布式存储系统,同时支持块存储、文件存储和对象存储,发展时间很久,稳定性也得到了验证。之前在 OpenStack 社区被广泛使用,目前在容器社区也是很好的选项。
GlusterFS:RedHat 旗下的产品,部署简单,扩展性强。
商业存储:DELL EMC,NetApp等。
CSI(Container Storage Interface):定义云应用调度平台和各种存储服务接口的项目,核心的目标就是存储 provider 只需要编写一个 driver,就能集成到任何的容器平台上。
Rook:基于 Ceph 作为后台存储技术,深度集成到 Kubernetes 容器平台的容器项目,因为选择了 Ceph 和 Kubernetes 这两个都很热门的技术,并且提供自动部署、管理、扩展、升级、迁移、灾备和监控等功能
k8s支持以下存储类型
Kubernetes以in-tree plugin的形式来对接不同的存储系统,满足用户可以根据自己业务的需要使用这些插件给容器提供存储服务。同时兼容用户使用FlexVolume和CSI定制化插件。
一般来说,Kubernetes中Pod通过如下三种方式来访问存储资源:
容器和微服务的结合创造了另外的热潮,也让服务发现成功了热门名词。可以轻松扩展微服务的同时,也要有工具来实现服务之间相互发现的需求。 DNS 服务器监视着创建新 Service 的 Kubernetes API,从而为每一个 Service 创建一组 DNS 记录。 如果整个集群的 DNS 一直被启用,那么所有的 Pod应该能够自动对 Service 进行名称解析。在技术实现上是通过kubernetes api监视Service资源的变化,并根据Service的信息生成DNS记录写入到etcd中。dns为集群中的Pod提供DNS查询服务,而DNS记录则从etcd中读取。
目前主要有三种工具,大部分的容器管理系统也都是同时可以支持这三种工具。
这些工具的主要作用就是保证这个集群的动态信息能统一保存,并保证一致性,这样每个节点和容器就能正确地获取到集群当前的信息。
Kubernetes提供两种类型的健康检查,支持进行三种类型的探测:HTTP、Command和TCP。
我们习惯于在两个层次监控:应用以及运行它们的主机。现在由于容器处在中间层,以及 Kubernetes 本身也需要监控,因此有 4 个不同的组件需要监控并且搜集度量信息。
1)cAdvisor + InfluxDB + Grafana:一个简单的跨多主机的监控系统Cadvisor:将数据,写入InfluxDBInfluxDB :时序数据库,提供数据的存储,存储在指定的目录下Grafana :提供了WEB控制台,自定义查询指标,从InfluxDB查询数据,并展示。
2)Heapster + InfluxDB + Grafana:Heapster是一个收集者,将每个Node上的cAdvisor的数据进行汇总,然后导到InfluxDB,支持从Cluster、Node、Pod的各个层面提供详细的资源使用情况。Heapster:在Kubernetes集群中获取Metrics和事件数据,写入InfluxDB,Heapster收集的数据比cAdvisor多,而且存储在InfluxDB的也少。InfluxDB:时序数据库,提供数据的存储,存储在指定的目录下。Grafana:提供了WEB控制台,自定义查询指标,从InfluxDB查询数据,并展示。
3)Prometheus+Grafana:Prometheus是个集DB、Graph、Statistics、Alert 于一体的监控工具。提供多维数据模型(时序列数据由metric名和一组key/value组成)和在多维度上灵活的查询语言(PromQl),提供了很高的写入和查询性能。对内存占用量大,不依赖分布式存储,单主节点工作,所以不具有高可用性,支持pull/push两种时序数据采集方式。
考虑到Prometheus在扩展性和高可用方面的缺点,在超大规模应用时可以考察下thanos这样的面向解决Prometheus的长时间数据存储与服务高可用解决方案的开源项目:https://github.com/improbable-eng/thanos
容器集群的四个监控层次
镜像 registry 是存储镜像的地方,可以方便地在团队、公司或者世界各地分享容器镜像,也是运行容器最基本的基础设施。
每种对应技术几乎都有自己的基础镜像,例如:
1)中国开源云联盟容器工作组-容器技术及其应用白皮书v1.0
2)从风口浪尖到十字路口,写在 Kubernetes 两周年之际
3)白话Kubernetes网络
4)主机和容器的监控方案
5)云原生容器生态系统概要
6)存储系统介绍及机制实现
7)内部组件工作原理介绍
8)Containerd、RunC…:你应该知道的所有
9)从 docker 到 runC
Docker是目前最具代表性的容器技术之一,对云计算及虚拟化技术产生了颠覆性的影响。本文对Docker容器在应用中可能面临的安全问题和风险进行了研究,并将Docker容器应用环境中的安全机制与相关解决方案分为容器虚拟化安全、容器安全管理、容器网络安全三部分进行分析。
虚拟化技术是实现硬件基础设施资源的充分利用、合理分配和有效调度的重要技术手段。例如,在基于OpenStack的典型IaaS服务中,云服务提供商可通过搭建设备集群建立资源池,并将服务器、存储和网络等底层资源进行弹性虚拟化提供给租户。
传统虚拟化技术以虚拟机为管理单元,各虚拟机拥有独立的操作系统内核,不共用宿主机的软件系统资源,因此具有良好的隔离性,适用于云计算环境中的多租户场景。
容器技术可以看作一种轻量级的虚拟化方式,将应用与必要的执行环境打包成容器镜像,使得应用程序可以直接在宿主机(物理机或虚拟机)中相对独立地运行。容器技术在操作系统层进行虚拟化,可在宿主机内核上运行多个虚拟化环境。相比于传统的应用测试与部署,容器的部署无需预先考虑应用的运行环境兼容性问题;相比于传统虚拟机,容器无需独立的操作系统内核就可在宿主机中运行,实现了更高的运行效率与资源利用率。
Docker是目前最具代表性的容器平台之一,它模糊了传统的IaaS和PaaS的边界,具有持续部署与测试、跨云平台支持等优点。在基于Kubernetes等容器编排工具实现的容器云环境中,通过对跨主机集群资源的调度,容器云可提供资源共享与隔离、容器编排与部署、应用支撑等功能。
Docker容器技术以宿主机中的容器为管理单元,但各容器共用宿主机内核资源,分别通过Linux系统的Namespaces
和CGroups
机制实现资源的隔离与限制。
1)Namespaces
为了保证容器进程之间的资源隔离,避免相互影响和干扰,Linux内核的Namespaces(命名空间)机制提供了UTS、User、Mount、Network、PID、IPC
等命名空间实现了主机名、用户权限、文件系统、网络、进程号、进程间通信等六项资源隔离功能。通过调用clone()函数并传入相应的系统调用参数创建容器进程,可实现对应资源内容的隔离,具体情况如表1所示。
表1:Namespaces隔离机制
命名空间 | 系统调用参数 | 隔离内容 | Linux内核版本 |
---|---|---|---|
UTS | CLONE_NEWUTS | 主机名和域名 | 2.6.19 |
IPC | CLONE_NEWIPC | 信号量、信息队列和共享内存 | 2.6.19 |
PID | CLONE_NEWPID | 进程编号 | 2.6.24 |
Network | CLONE_NEWNET | 网络设备、网络栈、端口等 | 2.6.29 |
Mount | CLONE_NEWNS | 挂载点(文件系统) | 2.4.19 |
User | CLONE_NEWUSER | 用户和用户组 | 3.8 |
对于某个进程而言,可通过查看/proc/[PID]/ns文件,获取该进程下的命名空间隔离情况,如图1所示。其中,每一项命名空间都拥有一个编号对其进行唯一标识,如果宿主机中两个进程指向的命名空间编号相同,则表示他们同在一个命名空间之下。
图1:进程命名空间
2)CGroups
CGroups(Control Groups,控制组)机制最早于2006年由Google提出,目前是Linux内核的一种机制,可以实现对任务组(进程组或线程组)使用的物理资源(CPU、内存、I/O等)进行限制和记录,通过多种度量标准为各个容器相对公平地分配资源,以防止资源滥用的情况。
在实际应用中,CGroups会为每个执行任务创建一个钩子,在任务执行的过程中涉及到资源分配使用时,就会触发钩子上的函数并对相应的资源进行检测,从而对资源进行限制和优先级分配。
CGroups提供了资源限制(Resource Limitation)、优先级分配(Prioritization)、资源统计(Accounting)、任务控制(Control)四个功能,包含blkio、cpu、cpuacct、cpuset、devices、freezer、memory、perf_event、net_cls、net_prio、ns、hugetlb
等子系统,每种子系统独立地控制一种资源,可分别实现块设备输入/输出限制、CPU使用控制、生成CPU资源使用情况报告、内存使用量限制等功能。几个主要子系统的具体功能如表2所示。
表2:CGroups子系统
子系统 | 功能 |
---|---|
blkio | 为块设备(如磁盘、固态硬盘等物理驱动设备)设定输入/输出限制 |
cpu | 通过调度程序控制任务对CPU的使用 |
cpuacct | 生成任务对CPU资源使用情况的报告 |
cpuset | 为任务分配独立的CPU和内存 |
devices | 开启或关闭任务对设备的访问 |
freezer | 挂起或恢复任务 |
memory | 设定任务对内存的使用量限制,生成任务对内存资源使用情况的报告 |
传统虚拟化技术与Docker容器技术在运行时的安全性差异主要体现在隔离性方面,包括进程隔离、文件系统隔离、设备隔离、进程间通信隔离、网络隔离、资源限制等。
在Docker容器环境中,由于各容器共享操作系统内核,而容器仅为运行在宿主机上的若干进程,其安全性特别是隔离性与传统虚拟机相比在理论上与实际上都存在一定的差距。
根据Docker容器的主要特点及其在安全应用中的实际问题,本文将Docker容器技术应用中可能存在的技术性安全风险分为镜像安全风险、容器虚拟化安全风险、网络安全风险等类型进行具体分析,如图2所示。
图2:容器安全风险分类
Docker镜像是Docker容器的静态表示形式,镜像的安全决定了容器的运行时安全。
Docker容器官方镜像仓库Docker Hub中的镜像可能由个人开发者上传,其数量丰富、版本多样,但质量参差不齐,甚至存在包含恶意漏洞的恶意镜像,因而可能存在较大的安全风险。具体而言,Docker镜像的安全风险分布在创建过程、获取来源、获取途径等方方面面。
1)Dockerfile安全问题
Docker镜像的生成主要包括两种方式,一种是对运行中的动态容器通过docker commit命令进行打包,另一种是通过docker build命令执行Dockerfile文件进行创建。为了确保最小安装原则,同时考虑容器的易维护性,一般推荐采用Dockerfile文件构建容器镜像,即在基础镜像上进行逐层应用添加操作。
Dockerfile是包含用于组合镜像命令的文本文件,一般由基础镜像信息(FROM)、维护者信息(MAINTAINER)、镜像操作指令(RUN、ADD、COPY等)、容器启动时执行指令(CMD等)四个部分组成,Docker可通过读取Dockerfile中的命令创建容器镜像。
Dockerfile文件内容在一定程度上决定了Docker镜像的安全性,其安全风险具体包括但不限于以下情况:
如果Dockerfile存在漏洞或被插入恶意脚本,那么生成的容器也可能产生漏洞或被恶意利用。例如,攻击者可构造特殊的Dockerfile压缩文件,在编译时触发漏洞获取执行任意代码的权限。
如果在Dockerfile中没有指定USER,Docker将默认以root用户的身份运行该Dockerfile创建的容器,如果该容器遭到攻击,那么宿主机的root访问权限也可能会被获取。
如果在Dockerfile文件中存储了固定密码等敏感信息并对外进行发布,则可能导致数据泄露的风险。
如果在Dockerfile的编写中添加了不必要的应用,如SSH、Telnet等,则会产生攻击面扩大的风险。
2)镜像漏洞
对于大多数一般的开发者而言,通常需要获取一系列基础镜像进行容器云的部署和进一步开发,因此,基础镜像的安全性在一定程度上决定了容器云环境的安全性。
镜像漏洞安全风险具体包括镜像中的软件含有CVE漏洞、攻击者上传含有恶意漏洞的镜像等情况。
① CVE漏洞
由于镜像通常由基础操作系统与各类应用软件构成,因此,含有CVE漏洞的应用软件同样也会向Docker镜像中引入CVE漏洞。
镜像的获取通常是通过官方镜像仓库Docker Hub或网易、阿里云等提供的第三方镜像仓库。然而,根据对Docker Hub中镜像安全漏洞的相关研究,无论是社区镜像还是官方镜像,其平均漏洞数均接近200个,包括nginx、mysql、redis在内的常用镜像都含有高危漏洞。
② 恶意漏洞
恶意用户可能将含有后门、病毒等恶意漏洞的镜像上传至官方镜像库。2018年6月,安全厂商Fortinet和Kromtech在Docker Hub上发现17个包含用于数字货币挖矿恶意程序的Docker镜像,而这些恶意镜像当时已有500万次的下载量。目前,由于Docker应用在世界范围内具有广泛性,全网针对Docker容器的攻击很多都被用于进行数字货币挖矿,为攻击者带来实际经济利益,损害Docker用户的正常使用。
3)镜像仓库安全
作为搭建私有镜像存储仓库的工具,Docker Registry的应用安全性也必须得到保证。镜像仓库的安全风险主要包括仓库本身的安全风险和镜像拉取过程中的传输安全风险。
仓库自身安全:如果镜像仓库特别是私有镜像仓库被恶意攻击者所控制,那么其中所有镜像的安全性将无法得到保证。例如,如果私有镜像仓库由于配置不当而开启了2357端口,将会导致私有仓库暴露在公网中,攻击者可直接访问私有仓库并篡改镜像内容,造成仓库内镜像的安全隐患。
镜像拉取安全:如何保证容器镜像从镜像仓库到用户端的完整性也是镜像仓库面临的一个重要安全问题。由于用户以明文形式拉取镜像,如果用户在与镜像仓库交互的过程中遭遇了中间人攻击,导致拉取的镜像在传输过程中被篡改或被冒名发布恶意镜像,会造成镜像仓库和用户双方的安全风险。Docker已在其1.8版本后采用内容校验机制解决中间人攻击的问题。
与传统虚拟机相比,Docker容器不拥有独立的资源配置,且没有做到操作系统内核层面的隔离,因此可能存在资源隔离不彻底与资源限制不到位所导致的安全风险。
1)容器隔离问题
对于Docker容器而言,由于容器与宿主机共享操作系统内核,因此存在容器与宿主机之间、容器与容器之间隔离方面的安全风险,具体包括进程隔离、文件系统隔离、进程间通信隔离等。
虽然Docker通过Namespaces进行了文件系统资源的基本隔离,但仍有/sys、/proc/sys、/proc/bus、/dev、time、syslog等重要系统文件目录和命名空间信息未实现隔离,而是与宿主机共享相关资源。
针对容器隔离安全风险问题,主要存在以下两种隔离失效的情况:
攻击者可能通过对宿主机内核进行攻击达到攻击其中某个容器的目的。
由于容器所在主机文件系统存在联合挂载的情况,恶意用户控制的容器也可能通过共同挂载的文件系统访问其他容器或宿主机,造成数据安全问题。
2)容器逃逸攻击
容器逃逸攻击指的是容器利用系统漏洞,“逃逸”出了其自身所拥有的权限,实现了对宿主机和宿主机上其他容器的访问。由于容器与宿主机共享操作系统内核,为了避免容器获取宿主机的root权限,通常不允许采用特权模式运行Docker容器。
在容器逃逸案例中,最为著名的是shocker.c程序,其通过调用open_by_handle_at函数对宿主机文件系统进行暴力扫描,以获取宿主机的目标文件内容。由于Docker1.0之前版本对容器能力(Capability)使用黑名单策略进行管理,并没有限制CAP_DAC_READ_SEARCH能力,赋予了shocker.c程序调用open_by_handle_at函数的能力,导致容器逃逸的发生。因此,对容器能力的限制不当是可能造成容器逃逸等安全问题的风险成因之一。所幸的是,Docker在后续版本中对容器能力采用白名单管理,避免了默认创建的容器通过shocker.c案例实现容器逃逸的情况。
此外,在Black Hat USA 2019会议中,来自Capsule8的研究员也给出了若干Docker容器引擎漏洞与容器逃逸攻击方法,包括CVE-2019-5736、CVE-2018-18955、CVE-2016-5195等可能造成容器逃逸的漏洞。
CVE-2019-5736是runC的一个安全漏洞,导致18.09.2版本前的Docker允许恶意容器覆盖宿主机上的runC二进制文件。runC是用于创建和运行Docker容器的CLI工具,该漏洞使攻击者能够以root身份在宿主机上执行任意命令。
CVE-2018-18955漏洞涉及到User命名空间中的嵌套用户命名空间,用户命名空间中针对uid(用户ID)和gid(用户组ID)的ID映射机制保证了进程拥有的权限不会逾越其父命名空间的范畴。该漏洞利用创建用户命名空间的子命名空间时损坏的ID映射实现提权。
CVE-2016-5195脏牛(Dirty CoW)Linux内核提权漏洞可以使低权限用户在多版本Linux系统上实现本地提权,进而可能导致容器逃逸的发生。Linux内核函数get_user_page在处理Copy-on-Write时可能产生竞态条件,导致出现向进程地址空间内只读内存区域写数据的机会,攻击者可进一步修改su或者passwd程序以获取root权限。
3)拒绝服务攻击
由于容器与宿主机共享CPU、内存、磁盘空间等硬件资源,且Docker本身对容器使用的资源并没有默认限制,如果单个容器耗尽宿主机的计算资源或存储资源(例如进程数量、存储空间等)可能导致宿主机或其他容器的拒绝服务。
① 计算型DoS攻击
Fork Bomb是一类典型的针对计算资源的拒绝服务攻击手段,其可通过递归方式无限循环调用fork()系统函数快速创建大量进程。由于宿主机操作系统内核支持的进程总数有限,如果某个容器遭到了Fork Bomb攻击,那么就有可能存在由于短时间内在该容器内创建过多进程而耗尽宿主机进程资源的情况,宿主机及其他容器就无法再创建新的进程。
② 存储型DoS攻击
针对存储资源,虽然Docker通过Mount命名空间实现了文件系统的隔离,但CGroups并没有针对AUFS文件系统进行单个容器的存储资源限制,因此采用AUFS作为存储驱动具有一定的安全风险。如果宿主机上的某个容器向AUFS文件系统中不断地进行写文件操作,则可能会导致宿主机存储设备空间不足,无法再满足其自身及其他容器的数据存储需求。
网络安全风险是互联网中所有信息系统所面临的重要风险,不论是物理设备还是虚拟机,都存在难以完全规避的网络安全风险问题。而在轻量级虚拟化的容器网络环境中,其网络安全风险较传统网络而言更为复杂严峻。
1)容器网络攻击
Docker提供桥接网络、MacVLAN、覆盖网络(Overlay)等多种组网模式,可分别实现同一宿主机内容器互联、跨宿主机容器互联、容器集群网络等功能。
① 网桥模式
Docker默认采用网桥模式,利用iptables进行NAT转换和端口映射。Docker将所有容器都通过虚拟网络接口对连接在一个名为docker0的虚拟网桥上,作为容器的默认网关,而该网桥与宿主机直接相连。
容器内部的数据包经过虚拟网络接口对到达docker0,实现同一子网内不同容器间的通信。在网桥模式下,同一宿主机内各容器间可以互相通信,而宿主机外部无法通过分配给容器的IP地址对容器进行外部访问。
由于缺乏容器间的网络安全管理机制,无法对同一宿主机内各容器之间的网络访问权限进行限制。具体而言,由于各容器之间通过宿主机内部网络的docker0网桥连接以实现路由和NAT转换,如果容器间没有防火墙等保护机制,则攻击者可通过某个容器对宿主机内的其他容器进行ARP欺骗、嗅探、广播风暴等攻击,导致信息泄露、影响网络正常运行等安全后果。
因此,如果在同一台宿主机上部署的多个容器没有进行合理的网络配置进行访问控制边界隔离,将可能产生容器间的网络安全风险。
② MacVLAN
MacVLAN是一种轻量级网络虚拟化技术,通过与主机的网络接口连接实现了与实体网络的隔离性。
MacVLAN允许为同一个物理网卡配置多个拥有独立MAC地址的网络接口并可分别配置IP地址,实现了网卡的虚拟化。MacVLAN模式无需创建网桥,即无需NAT转换和端口映射就可以直接通过网络接口连接到物理网络,不同MacVLAN网络间不能在二层网络上进行通信。
然而,处于同一虚拟网络下各容器间同样没有进行访问权限控制,因此MacVLAN模式依然存在与网桥模式类似的内部网络攻击的安全风险。
③ Overlay网络
Overlay网络架构主要用于构建分布式容器集群,通过VxLAN技术在不同主机之间的Underlay网络上建立虚拟网络,以搭建跨主机容器集群,实现不同物理主机中同一Overlay网络下的容器间通信。
与其他组网模式一样,Overlay网络也没有对同一网络内各容器间的连接进行访问控制。此外,由于VxLAN网络流量没有加密,需要在设定IPSec隧道参数时选择加密以保证容器网络传输内容安全。
因此,无论采用何种网络连接模式,都难以避免容器间互相攻击的安全风险。
2)网络DoS攻击
由于网络虚拟化的存在,容器网络面临着与传统网络不同的DoS攻击安全风险。Docker容器网络的DoS攻击分为内部威胁和外部威胁两种主要形式。
内部威胁:针对Docker容器网络环境,DoS攻击可不通过物理网卡而在宿主机内部的容器之间进行,攻击者通过某个容器向其他容器发起DoS攻击可能降低其他容器的网络数据处理能力。因此,存在容器虚拟网络间的DoS攻击风险。
外部威胁:由于同一台宿主机上的所有容器共享宿主机的物理网卡资源,若外部攻击者使用包含大量受控主机的僵尸网络向某一个目标容器发送大量数据包进行DDoS攻击,将可能占满宿主机的网络带宽资源,造成宿主机和其他容器的拒绝服务。
在传统虚拟化技术架构中,Hypervisor虚拟机监视器是虚拟机资源的管理与调度模块。而在容器架构中,由于不含有Hypervisor层,因此需要依靠操作系统内核层面的相关机制对容器进行安全的资源管理。
1)容器资源隔离与限制
在资源隔离方面,与采用虚拟化技术实现操作系统内核级隔离不同,Docker通过Linux内核的Namespace机制实现容器与宿主机之间、容器与容器之间资源的相对独立。通过为各运行容器创建自己的命名空间,保证了容器中进程的运行不会影响到其他容器或宿主机中的进程。
在资源限制方面,Docker通过CGroups实现宿主机中不同容器的资源限制与审计,包括对CPU、内存、I/O等物理资源进行均衡化配置,防止单个容器耗尽所有资源造成其他容器或宿主机的拒绝服务,保证所有容器的正常运行。
但是,CGroups未实现对磁盘存储资源的限制。若宿主机中的某个容器耗尽了宿主机的所有存储空间,那么宿主机中的其他容器无法再进行数据写入。Docker提供的–storage-opt=[]磁盘限额仅支持Device Mapper文件系统,而Linux系统本身采用的磁盘限额机制是基于用户和文件系统的quota技术,难以针对Docker容器实现基于进程或目录的磁盘限额。因此,可考虑采用以下方法实现容器的磁盘存储限制:
为每个容器创建单独用户,限制每个用户的磁盘使用量;
选择XFS等支持针对目录进行磁盘使用量限制的文件系统;
为每个容器创建单独的虚拟文件系统,具体步骤为创建固定大小的磁盘文件,并从该磁盘文件创建虚拟文件系统,然后将该虚拟文件系统挂载到指定的容器目录。
此外,在默认情况下,容器可以使用主机上的所有内存。可以使用内存限制机制来防止一个容器消耗所有主机资源的拒绝服务攻击,具体可使用使用-m或-memory参数运行容器。
1 | (命令示例:docker run [运行参数] -memory [内存大小] [容器镜像名或ID] [命令]) |
2)容器能力限制
Linux内核能力表示进程所拥有的系统调用权限,决定了程序的系统调用能力。
容器的默认能力包括CHOWN、DAC_OVERRIDE、FSETID、SETGID、SETUID、SETFCAP、NET_RAW、MKNOD、SYS_REBOOT、SYS_CHROOT、KILL、NET_BIND_SERVICE、AUDIT_WRITE
等等,具体功能如表3所示。
表3:容器默认能力
容器默认能力 | 作用 |
---|---|
CHOWN | 允许任意更改文件UID以及GID |
DAC_OVERRIDE | 允许忽略文件的读、写、执行访问权限检查 |
FSETID | 允许文件修改后保留setuid/setgid标志位 |
SETGID | 允许改变进程组ID |
SETUID | 允许改变进程用户ID |
SETFCAP | 允许向其他进程转移或删除能力 |
NET_RAW | 允许创建RAW和PACKET套接字 |
MKNOD | 允许使用mknod创建指定文件 |
SYS_REBOOT | 允许使用reboot或者kexec_load |
SYS_CHROOT | 允许使用chroot |
KILL | 允许发送信号 |
NET_BIND_SERVICE | 允许绑定常用端口号(端口号小于1024) |
AUDIT_WRITE | 允许审计日志写入 |
如果对容器能力不加以适当限制,可能会存在以下安全隐患:
内部因素:在运行Docker容器时,如果采用默认的内核功能配置可能会产生容器的隔离问题。
外部因素:不必要的内核功能可能导致攻击者通过容器实现对宿主机内核的攻击。
因此,不当的容器能力配置可能会扩大攻击面,增加容器与宿主机面临的安全风险,在执行docker run命令运行Docker容器时可根据实际需求通过–cap-add或–cap-drop配置接口对容器的能力进行增删。
1 | (命令示例:docker run --cap-drop ALL --cap-add SYS_TIME ntpd /bin/sh) |
3)强制访问控制
强制访问控制(Mandatory Access Control, MAC)是指每一个主体(包括用户和程序)和客体都拥有固定的安全标记,主体能否对客体进行相关操作,取决于主体和客体所拥有安全标记的关系。在Docker容器应用环境下,可通过强制访问控制机制限制容器的访问资源。Linux内核的强制访问控制机制包括SELinux、AppArmor等。
① SELinux机制
SELinux(Security-Enhanced Linux)是Linux内核的强制访问控制实现,由美国国家安全局(NSA)发起,用以限制进程的资源访问,即进程仅能访问其任务所需的文件资源。因此,可通过SELinux对Docker容器的资源访问进行控制。
在启动Docker daemon守护进程时,可通过将–selinux-enabled参数设为true,从而在Docker容器中使用SELinux。SELinux可以使经典的shocker.c程序失效,使其无法逃逸出Docker容器实现对宿主机资源的访问。
1 | (命令示例:docker daemon --selinux-enabled = true) |
② AppArmor机制
与SELinux类似,AppArmor(Application Armor,应用程序防护)也是Linux的一种强制访问控制机制,其作用是对可执行程序进行目录和文件读写、网络端口访问和读写等权限的控制。
在Docker daemon启动后会在/etc/apparmor.d/docker自动创建AppArmor的默认配置文件docker-default,可通过在该默认配置文件中新增访问控制规则的方式对容器进行权限控制,同时可在启动容器时通过–security-opt指定其他配置文件。例如,在配置文件中加入一行deny /etc/hosts rwklx限制对/etc/hosts的获取,同样可使shocker.c容器逃逸攻击失效。
1 | (命令示例:docker run --rm -ti --cap-add=all --security-opt apparmor:docker-default shocker bash) |
4)Seccomp机制
Seccomp(Secure Computing Mode)是Linux内核提供的安全特性,可实现应用程序的沙盒机制构建,以白名单或黑名单的方式限制进程能够进行的系统调用范围。
在Docker中,可通过为每个容器编写json格式的seccomp profile实现对容器中进程系统调用的限制。在seccomp profile中,可定义以下行为对进程的系统调用做出响应:
SCMP_ACT_KILL:当进程进行对应的系统调用时,内核发出SIGSYS信号终止该进程,该进程不会接受到这个信号;
SCMP_ACT_TRAP:当进程进行对应的系统调用时,该进程会接收到SIGSYS信号,并改变自身行为;
SCMP_ACT_ERRNO:当进程进行对应的系统调用时,系统调用失败,进程会接收到errno返回值;
SCMP_ACT_TRACE:当进程进行对应的系统调用时,进程会被跟踪;
SCMP_ACT_ALLOW:允许进程进行对应的系统调用行为。
默认情况下,在Docker容器的启动过程中会使用默认的seccomp profile,可使用security-opt seccomp选项使用特定的seccomp profile。
1 | (命令示例:docker run --rm -it --security-opt seccomp:/path/to/seccomp/profile.json hello-world) |
1)镜像仓库安全
① 内容信任机制
Docker的内容信任(Content Trust)机制可保护镜像在镜像仓库与用户之间传输过程中的完整性。目前,Docker的内容信任机制默认关闭,需要手动开启。内容信任机制启用后,镜像发布者可对镜像进行签名,而镜像使用者可以对镜像签名进行验证。
具体而言,镜像构建者在通过docker build命令运行Dockerfile文件前,需要通过手动或脚本方式将DOCKER_CONTENT_TRUST环境变量置为1进行启用。在内容信任机制开启后,push、build、create、pull、run等命令均与内容信任机制绑定,只有通过内容信任验证的镜像才可成功运行这些操作。例如,Dockerfile中如果包含未签名的基础镜像,将无法成功通过docker build进行镜像构建。
1 | (命令示例:export DOCKER_CONTENT_TRUST = 1) |
② Notary项目
Notary是一个从Docker中剥离的独立开源项目,提供数据收集的安全性。Notary用于发布内容的安全管理,可对发布的内容进行数字签名,并允许用户验证内容的完整性和来源。Notary的目标是保证服务器与客户端之间使用可信连接进行交互,用于解决互联网内容发布的安全性,并未局限于容器应用。
在Docker容器场景中,Notary可支持Docker内容信任机制。因此,可使用Notary构建镜像仓库服务器,实现对容器镜像的签名,对镜像源认证、镜像完整性等安全需求提供更好的支持。
2)镜像安全扫描
为了保证容器运行的安全性,在从公共镜像仓库获取镜像时需要对镜像进行安全检查,防止存在安全隐患甚至恶意漏洞的镜像运行,从源头端预防安全事故的发生。镜像漏洞扫描工具是一类常用的镜像安全检查辅助工具,可检测出容器镜像中含有的CVE漏洞。
针对Docker镜像的漏洞扫描,目前已经有许多相关工具与解决方案,包括Docker Security Scanning、Clair、Anchore、Trivy、Aqua等等。
① Docker Security Scanning服务
Docker Security Scanning是Docker官方推出的不开源镜像漏洞扫描服务,用于检测Docker Cloud服务中私有仓库和Docker Hub官方仓库中的镜像是否安全。
Docker Security Scanning包括扫描触发、扫描器、数据库、附加元件框架以及CVE漏洞数据库比对等服务。当仓库中有镜像发生更新时,会自动启动漏洞扫描;当CVE漏洞数据库发生更新时,也会实时更新镜像漏洞扫描结果。
② Clair工具
Clair是一款开源的Docker镜像漏洞扫描工具。与Docker Security Scanning类似,Clair通过对Docker镜像进行静态分析并与公共漏洞数据库关联,得到相应的漏洞分析结果。Clair主要包括以下模块:
Fetcher(获取器):从公共的CVE漏洞源收集漏洞数据;
Detector(检测器):对镜像的每一个Layer进行扫描,提取镜像特征;
Notifier(通知器):用于接收WebHook从公开CVE漏洞库中的最新漏洞信息并进行漏洞库更新;
Databases(数据库):PostSQL数据库存储容器中的各个层和CVE漏洞;
③ Trivy工具
Trivy是一个简单而全面的开源容器漏洞扫描程序。Trivy可检测操作系统软件包(Alpine、RHEL、CentOS等)和应用程序依赖项(Bundler、Composer、npm、yarn等)的漏洞。此外,Trivy具有较高的易用性,只需安装二进制文件并指定扫描容器的镜像名称即可执行扫描。Trivy提供了丰富的功能接口,相比于其他容器镜像漏洞扫描工具更适合自动化操作,可更好地满足持续集成的需求。
1 | (命令示例:trivy [镜像名]) |
3)容器运行时监控
为了在系统运维层面保证容器运行的安全性,实现安全风险的即时告警与应急响应,需要对Docker容器运行时的各项性能指标进行实时监控。
针对Docker容器监控的工具与解决方案包括docker stats、cAdvisor、Scout、DataDog、Sensu等等,其中最常见的是Docker原生的docker stats命令和Google的cAdvisor开源工具。
① docker stats命令
docker stats是Docker自带的容器资源使用统计命令,可用于对宿主机上的Docker容器的资源使用情况进行手动监控,具体内容包括容器的基本信息、容器的CPU使用率、内存使用率、内存使用量与限制、块设备I/O使用量、网络I/O使用量、进程数等信息。用户可根据自身需求设置--format
参数控制docker stats 命令输出的内容格式。
1 | (命令示例:docker stats [容器名]) |
② cAdvisor工具
由于docker stats只是简单的容器资源查看命令,其可视化程度不高,同时不支持监控数据的存储。cAdvisor是由Google开源的容器监控工具,优化了docker stats在可视化展示与数据存储方面的缺陷。
cAdvisor在宿主机上以容器方式运行,通过挂载在本地卷,可对同一台宿主机上运行的所有容器进行实时监控和性能数据采集,具体包括CPU使用情况、内存使用情况、网络吞吐量、文件系统使用情况等信息,并提供本地基础查询界面和API接口,方便与其他第三方工具进行搭配使用。cAdvisor默认将数据缓存在内存中,同时也提供不同的持久化存储后端支持,可将监控数据保存Google BigQuery、InfluxDB或Redis等数据库中。
cAdvisor基于Go语言开发,利用CGroups获取容器的资源使用信息,目前已被集成在Kubernetes中的Kubelet组件里作为默认启动项。
1 | (命令示例:docker run -v /var/run:/var/run:rw -v/sys:/sys:ro -v/var/lib/docker:/var/lib/docker:ro -p8080:8080 -d --name cadvisor google/cadvisor) |
4)容器安全审计
① Docker守护进程审计
在安全审计方面,对于运行Docker容器的宿主机而言,除需对主机Linux文件系统等进行审计外,还需对Docker守护进程的活动进行审计。由于系统默认不会对Docker守护进程进行审计,需要通过主动添加审计规则或修改规则文件进行。
1 | (命令示例:auditctl -w /usr/bin/docker -k docker或修改/etc/audit/audit.rules文件) |
② Docker相关文件目录审计
除Docker守护进程之外,还需对与Docker的运行相关的文件和目录进行审计,同样需要通过命令行添加审计规则或修改规则配置文件,具体文件和目录如表4所示。
表4:Docker相关文件和目录审计
需要审计的文件或目录 | 备注 |
---|---|
/var/lib/docker | 包含有关容器的所有信息 |
/etc/docker | 包含Docker守护进程和客户端TLS通信的密钥和证书 |
docker.service | Docker守护进程运行参数配置文件 |
docker.socket | 守护进程运行socket |
/etc/default/docker | 支持Docker守护进程各种参数 |
/etc/default/daemon.json | 支持Docker守护进程各种参数 |
/usr/bin/docker-containerd | Docker可用containerd生成容器 |
/usr/bin/docker-runc | Docker可用runC生成容器 |
Docker公司与美国互联网安全中心(CIS)联合制定了Docker最佳安全实践CIS Docker Benchmark,目前最新版本为1.2.0。为了帮助Docker用户对其部署的容器环境进行安全检查,Docker官方提供了Docker Bench for Security安全配置检查脚本工具docker-bench-security,其检查依据便是CIS制定的Docker最佳安全实践。
1)容器间流量限制
由于Docker容器默认的网桥模式不会对网络流量进行控制和限制,为了防止潜在的网络DoS攻击风险,需要根据实际需求对网络流量进行相应的配置。
① 完全禁止容器间通信
在特定的应用场景中,如果宿主机中的所有容器无需在三层或四层进行网络通信交互,可通过将Docker daemon的–icc参数设为false以禁止容器与容器间的通信。
1 | (命令示例:dockerd --icc = false) |
② 容器间流量控制
在存在多租户的容器云环境中,可能存在单个容器占用大量宿主机物理网卡抢占其他容器带宽的情况。为了保证容器之间的正常通信,同时避免异常流量造成网络DoS攻击等后果,需要对容器之间的通信流量进行一定的限制。
由于Docker通过创建虚拟网卡对(eth0和veth)将容器与虚拟网桥docker0连接,而容器之间的通信需要经由虚拟网卡对eth0和veth通过网桥连接,因此,可采用Linux的流量控制模块traffic controller对容器网络进行流量限制。
traffic controller的原理是建立数据包队列并制定发送规则,实现流量限制与调度的功能。为了在一定程度上减轻容器间的DoS攻击的危害,可将traffic controller的dev设置为宿主机中与各容器连接的veth*虚拟网卡,以此进行宿主机上容器间流量限制。
2)网桥模式下的网络访问控制
在默认的网桥连接模式中,连接在同一个网桥的两个容器可以进行直接相互访问。因此,为了实现网络访问控制,可按需配置网络访问控制机制和策略。
① 为容器创建不同的桥接网络
为了实现容器间的网络隔离,可将容器放在不同的桥接网络中。当在Docker中使用docker network create命令创建新的桥接网络时,会在iptables中的DOCKER-ISOLATION新增DROP丢弃规则,阻断与其他网络之间的通信流量,实现容器网络之间隔离的目的。
1 | (命令示例:docker network create --subnet 102.102.0.0/24 test) |
② 基于白名单策略的网络访问控制
为了保证容器间的网络安全,可默认禁止容器间的通信,然后按需设置网络访问控制规则。
具体而言,在同一虚拟网络内,不同Docker容器之间的网络访问可通过iptables进行控制。在将Docker daemon的–icc参数设为false后,iptables的FORWARD链策略为默认全部丢弃。此时,可采用白名单策略实现网络访问控制,即根据实际需要在iptables中添加访问控制策略,以最小化策略减小攻击面。
3)集群模式下的网络访问控制
与通过OpenStack建立的虚拟化集群通过VLAN对不同租户进行子网隔离不同,基于Overlay网络的容器集群在同一主机内相同子网中的不同容器之间默认可以直接访问。
如需控制宿主机外部到内部容器应用的访问,可通过在宿主机iptables中的DOCKER-INGRESS链手动添加ACL访问控制规则以控制宿主机的eth0到容器的访问,或者在宿主机外部部署防火墙等方法实现。
然而,在大型的容器云环境中,由于存在频繁的微服务动态变化更新,通过手动的方式配置iptables或更新防火墙是不现实的。因此,可通过微分段(Micro-Segmentation)实现面向容器云环境中的容器防火墙。微分段是一种细粒度的网络分段隔离机制,与传统的以网络地址为基本单位的网络分段机制不同,微分段可以以单个容器、同网段容器、容器应用为粒度实现分段隔离,并通过容器防火墙对实现微分段间的网络访问控制。
与虚拟化技术相比,Docker容器技术具有敏捷化、轻量化等特点,在推进云原生应用方面具有不可替代性。与此同时,容器技术对于高效性的追求也牺牲了隔离性等安全要求,在安全性方面与虚拟化技术相比还存在较大差距,且所涉及的面较广,涉及到容器的镜像安全、内核安全、网络安全、虚拟化安全、运行时安全等各个层面。
在应用容器技术进行系统部署时,应充分评估安全风险,根据应用场景制定相应安全需求,并整合相关安全解决方案,形成容器安全应用最佳实践。
]]>因需要在创建的容器内使用IPv6网络进行测试,详细记录一下Docker如何开始IPv6,以及一些调试的奇淫技巧。
方案一:直接使用宿主机的网络在容器启动时加入--host
参数;
1 | docker run -d --name=busybox --net=host busybox top |
显然方案一,太low,这里就不在介绍了。
方案二:将宿主机IPv6网络下划分一个子段,通过nd代理容器流量;
1)查看宿主机IPv6地址
1 | xdnsadmin@ubuntu:~$ ifconfig ens3 |
2)划分子段并配置docker
配置/etc/docker/daemon.json
,重启容器进程
1 | xdnsadmin@ubuntu:~$ sudo cat /etc/docker/daemon.json |
3)配置转发
配置NDP(邻居发现协议)代理。关于这部分内容,请参见 Using NDP proxying。
1 | xdnsadmin@ubuntu:~$ sudo ip -6 neigh add proxy 2001:eb:8001:e01:2::2 dev ens3 |
4)测试IPv6
启动ubuntu 18.04镜像测试是否有IPv6网络,由于18.04镜像内无ifconfig
和ip
命令,可以安装相应工具或在宿主机上ping测试。
1 | xdnsadmin@ubuntu:~$ docker run -itd ubuntu:18.04 |
如需在镜像内测试,需要安装相应工具
1 | xdnsadmin@ubuntu:~$ docker exec -it 78604aa6c229 bash |
【奇淫技巧】也可以在宿主机上测试通过namespace的方式测试
1 | xdnsadmin@ubuntu:~$ docker ps -a |
上述操作可以保存为一个脚本
1 | id=docker inspect -f '{{.State.Pid}}' $1 |
方案二的一个缺点是每创建一个容器或重启机器都需要添加ip -6 neigh add proxy <ipv6_addr> dev ens3
,对于自动化构建较为麻烦。
【Tips】:检查宿主机DNS配置,在配置过程中出现宿主机仅配置了IPv6的DNS导致容器在开启IPv6服务后容器无法解析域名的情况。
方案三:创建支持IPv6的网桥
IPv6地址需要依据宿主机地址段来修改。
1 | xdnsadmin@ubuntu:~$ docker network create -d bridge --ipv6 --subnet "2001:eb:8001:e01:3::/120" --gateway="2001:eb:8001:e01:3::1" --subnet=172.30.0.0/16 --gateway=172.30.0.1 IPv6Net |
容器仍然无法访问v6网络,需要向方案二一样添加配置NDP(邻居发现协议)代理
1 | xdnsadmin@ubuntu:~$ sudo ip -6 neigh add proxy 2001:eb:8001:e01:3::2 dev ens3 |
相比方案二方案三的好处是能够指定容器的IP,可以预先配置好NPD代理。同样都有的缺点是IPv6无法像IPv4一样仅暴漏端口,IPv6下地址全端口都开放。
【参考链接】
]]>litght reading
的NFV已死,也尝试进行了翻译NFV已死,从文中不断看到SASE、云原生这样的词汇。2017年初由于工作原因从IOT转向了NFV相关工作,随后接触到了Openstack、OPNFV、ONAP,这段时间的工作使自己对于网络、云计算、NFV、docker容器、k8s有了很多的认识,也为自己在超级算力中心的整体规划设计以及建设中积累了宝贵的经验。话说回来,在从事NFV研究的一年多时间里,NFV始终是雷声大雨点小,我所在的OPNFV社区主要关注NFV中的基础设计层即NFVI层的测试,我参与了OPNFV的Pharos项目以及OVP项目的首批内测。在多次测试活动中也了解了三大运营商以及国内主流厂商如华为、中兴、华三等厂商的NFV产品。但是NFV呼声虽高,却没有看到太多的市场,运营商期望通过通用x86+软件的方式来去除厂商黑盒的绑定,但是最后还是掉落到了硬件厂商的陷阱里,期望的硬件+虚拟化+云平台的三层解耦在现实中也只是泡影,最终还是被厂商的硬件(x86)+云平台(Openstack)+网元(VNF)所绑定。运营商都会有自研的NFVO编排器,期望通过自己的编排器与厂商A的VNF和厂商B的云平台层进行解耦调度。在我们的测试中基本的网元LCM生命管理都没什么问题,但是涉及到高级的特性如:自愈、热迁移等都会出现问题[1]。同时在ONAP的设想中有一个VNF测试项目,期望将厂商自研的VNF网元做成一个类似于应用市场的APP,使得运营商可以直接在应用市场里选择需要的网元,但也面临许多的挑战。
NFV已死的文中提到了SASE(Secure Access Service Edge,安全访问服务边缘)将会取代NFV,我找了下关于SASE的描述,在Cato and the Secure Access Service Edge: Where Your Digital Business Network Starts中提到了SASE的四个特点。
它提供了一个单一网络,可在任何地方连接并保护任何企业资源(物理,云和移动)。 在这种情况下,SASE Cloud具有四个主要特征:它是身份驱动的,“云原生”的,支持所有边缘的并且在全球范围内分布:
身份驱动。用户和资源身份,而不仅仅是IP地址,决定了网络体验和访问权限级别。服务质量,路由选择,应用风险驱动的安全控制-所有这些都由与每个网络连接关联的身份驱动。通过让公司为用户开发一套网络和安全策略,而不论设备或位置如何,该方法都可以减少运营开销。
云原生架构。 SASE体系结构利用了关键的云功能(包括弹性,适应性,自修复和自维护),提供了一个可分摊客户成本以实现最大效率的平台,可轻松适应新兴业务需求,并可在任何地方使用。
支持所有边缘。 SASE为所有公司资源(数据中心,分支机构,云资源和移动用户)创建一个网络。例如,SD-WAN设备支持物理边缘,而移动客户端和无客户端浏览器访问则可以连接用户。
全球分布。为确保全面的网络和安全功能随处可用,并向所有边缘提供最佳体验,SASE云必须在全球范围内分布。因此,Gartner指出,他们必须扩展自己的足迹,以向企业边缘提供低延迟的服务。
云原生也是这两年来提到的非常多的概念,结合云计算以及火热的docker容器、k8s编排、微服务等,服务提供商在开发应用时要更多的结合云和容器的一些特性来提供服务。边缘计算也是近来热门的话题,从18年ETSI将MEC的定义为Multi-Access Edge Computing 多接入边缘计算而不是先前大家都认为的Mobile Edge Compute移动边缘计算。这样看起来SASE确实很适应潮流的发展。
但是这并不是说NFV已经死亡,借助虚拟化技术的发展,网络功能虚拟化仍将继续发展,在云中东西向流量防护以及安全方面NFV还是有发展余地的,此外5G 的各个网元也是NFV的主场。NFV现在的冷淡也只是没有像最开始吹的那么神,什么网络功能都能虚拟化,由于性能和稳定的的不足,一些核心网络还是没有办法全上NFV,但是在边缘接入上NFV仍然能够有的放矢。我认为更多的只是NFV技术的慢慢趋于成熟,概念上不再新颖,炒的人少了而已。
Ps:话又说回来,确实NFV的市场前景越来越不乐观,因此我也么有更多的专注在NFV方面了 - -。
]]>Enterprises are demanding a new generation of cloud-based wide-area networking services that’s swallowing up SD-WAN, killing network functions virtualization (NFV) and challenging existing telco business and technology models, according to Gartner analysts.
根据Gartner的分析师,企业需要新一代的基于云的广域网服务,这些服务将吞噬SD-WAN,杀死网络功能虚拟化(NFV)并挑战现有的电信业务和技术模型。
Gartner has given the new network delivery business model a name, and it’s an ugly one: SASE, pronounced “sassy,” which stands for the “Secure Access Service Edge.” And if Gartner is right, the effect on service providers’ business is going to be ugly too.
Gartner给新的网络交付业务模型起了一个名字,一个非常丑陋的名字:SASE,发音为“ sassy”,代表“安全访问服务边缘”(Secure Access Service Edge)。 如果Gartner是正确的,那么对服务提供商业务的影响也将是丑陋的。
The SASE transformation has been building for years. Five years ago, almost all enterprise applications and data lived in the data center, Gartner analyst Joe Skorupa tells Light Reading. Branch office networking connected to the data center, as did remote workers. Whatever cloud access was necessary then went to the data center first, then out to the public Internet.
SASE转型已经进行了多年。 Gartner分析师Joe Skorupa告诉Light Reading,五年前,几乎所有企业应用程序和数据都存在于数据中心。 分支机构网络连接到数据中心,远程工作者也是如此。 无论需要什么云访问权限,然后都首先访问数据中心,然后再访问公共Internet。
“Now, applications are pretty much everywhere,” Skorupa says. Some are in the data center, some are outside of it. Mission-critical applications live in the cloud, including Workday, Microsoft Office 365, and custom applications written for Microsoft Azure and Amazon Web Services. “The data center is no longer the center of the universe,” he says.
“现在,到处都有应用程序,” Skorupa说。 有些在数据中心内,有些在数据中心外。 关键任务应用程序存在于云中,包括Workday,Microsoft Office 365和为Microsoft Azure和Amazon Web Services编写的自定义应用程序。 他说:“数据中心不再是宇宙的中心。”
Skorupa adds, “We have gone from having a ‘data center’ to having ‘centers of data,’ and they are all over the place.”
Skorupa补充说:“我们已经从拥有“数据中心”变为拥有“中心的数据”,并且它们遍布各处。”
Likewise, consumers of data aren’t just branch offices. Endpoints are mobile. “They’re a sales executive sitting in a car with a cup of coffee and an iPad,” Skorupa says. “They’re not funneling through the data center. It’s a hub and spoke. But the hub is the individual, which could be a person, could be an IoT device, and could be software.”
同样,数据的使用者不仅仅是分支机构。 端点是移动的。 Skorupa说:“他们是一名销售主管,坐在汽车上喝着咖啡和iPad。” “他们并没有通过数据中心进行传输。它是一个枢纽。但是枢纽是个体,可以是人,可以是IoT设备,也可以是软件。”
The new network architecture requires different technologies to suit different needs, Skorupa says. For example, a home worker doesn’t need SD-WAN because they’re not balancing multiple links, but that worker does need quality-of-service guarantees to make video calls. On the other hand, a branch office requires SD-WAN for security and path selection.
Skorupa说,新的网络架构需要不同的技术来满足不同的需求。 例如,家庭工作者不需要SD-WAN,因为他们没有多个链接需要平衡,但是该工作者确实需要服务质量保证才能进行视频通话。 另一方面,分支机构需要SD-WAN进行安全性和路径选择。
The changing nature of business requires changing security policies and technology as well, Skorupa says. “If it’s a contractor using an untrusted laptop logging in from Southeast Asia at two o’clock Sunday morning directly into Salesforce, trying to get at the entire client database, you want to apply a lot of security policy against that,” Skorupa says.
Skorupa说,业务性质的变化也需要安全策略和技术的变化。 Skorupa说:“如果承包商使用的是不受信任的笔记本电脑,则需要在周日凌晨两点从东南亚直接登录到Salesforce,以获取整个客户数据库,那么您将对此应用大量的安全策略。”
Additionally, enterprise locations need intrusion detection and prevention services (IDS/IPS), data loss prevention (DLP), anti-spam, anti-malware, whitelisting, blacklisting and so on. “The overhead of trying to keep that stuff patched is a nightmare. You’re always out of date. You’re not going to put seven boxes stacked up – and duct them to the back of my iPad when I’m traveling,” Skorupa says. Cloud delivery is the only model that makes sense.
此外,企业场所需要入侵检测和预防服务(IDS / IPS),数据丢失预防(DLP),反垃圾邮件,反恶意软件,白名单,黑名单等。 “试图修补这些东西的开销是一场噩梦。您总是错过最佳防护时机。您不会愿意在旅行时将他们七个盒子叠在一起并放在iPad的背面, ” Skorupa说。 云交付是唯一有意义的模型。
He adds, “The only way to apply policy anywhere and everywhere, scaling up and scaling down as needed, delivering a set of functions you need on demand, is to deliver it primarily cloud-based.”
他补充说:“在任何地方和任何地方应用策略,按需扩展和按比例缩小,提供按需提供的功能集的唯一方法是基于云来提供它。”
R.I.P. CPE
That means on-premises equipment needs to go from being the standard way of delivering enterprise services to a specialized case, says the Gartner man.
Gartner负责人说,这意味着本地设备需要从提供企业服务的标准方式转变为特殊情况。
“The model says on-prem only when you must, cloud-delivered whenever you can,” Skorupa says.
Skorupa说:“该模型仅在必要时才在企业内部显示,并在可能的情况下通过云交付。”
This “represents an existential threat to NFV” because NFV depends on selling expensive boxes that happen to be x86-based. The cost benefits promised initially for NFV failed to materialize because vendors simply refused to lower their prices by a lot, Skorupa says.
这“代表对NFV的生存威胁”,因为NFV依赖出售恰好基于x86的昂贵盒子。 Skorupa说,最初承诺为NFV提供的成本收益未能实现,因为供应商只是拒绝大幅降低价格。
NFV proved “incredibly complicated,” and while the telco industry struggled to make it work, “application consumption patterns changed and the branch was no longer the center of the universe, and a solution that was non-scalable and hard to maintain and expensive and complex winds up being obsoleted by something that is elastic and easy to maintain and it’s cloud delivered,” Skorupa says.
事实证明NFV“异常复杂”,而电信业正努力使之运转,“应用程序消费模式发生了变化,分支机构不再是整个领域的中心, 一个不可扩展、难以维护且价格昂贵的解决方案,将被弹性、易于维护的东西淘汰了,并且使用了云交付,” Skorupa说。
There are cases where NFV makes sense. “But by and large the days of NFV have already come and gone. It’s basically stillborn,” Skorupa says.
在某些情况下,NFV是有意义的。 “但是总的来说,NFV的时代已经过去了。它基本上已经死了,” Skorupa说。
In a July note, Gartner recommends several steps for technology and service providers to succeed in the new market. They need to transform offerings to a cloud-native architecture, transform business models to “cloud-native-as-a service,” deliver “a clear vision” to the market, fill out their “portfolio organically, with the fewest acquisitions possible to minimize integration challenges and inconsistencies across services,” and invest in distributed real estate, such as PoPs and colocation facilities, to place service as close to the access point as required.
在7月的一份报告中,Gartner建议技术和服务提供商在新市场上取得成功的几个步骤。 他们需要将产品转变为云原生架构,将业务模型转变为“云原生即服务”,向市场提供“清晰的愿景”,通过最少的收购来有机地组合产品组合,以最大程度地减少集成挑战和服务之间的不一致,并投资于分布式资产(例如PoP和托管设施),以根据需要将服务放置在靠近接入点的位置。
Gartner names several vendors as already network-security focused, including Cato Networks, Fortinet, Forcepoint, Juniper and Versa Networks. Other SD-WAN vendors without cloud-delivered security are partnering with Zscaler, Palo Alto Networks and others.
Gartner列出了多家已经关注网络安全的供应商,包括Cato Networks,Fortinet,Forcepoint,Juniper和Versa Networks。 其他没有云交付安全性的SD-WAN供应商正在与Zscaler,Palo Alto Networks等合作。
Of course, the industry being what it is, these vendors are going into paroxysms of joy by merely being mentioned by Gartner. Versa and Cato Networks put out press releases and statements on their websites, and zScaler devoted some discussion to the subject on an earnings call.
当然,无论是什么行业,这些供应商都只是被Gartner提及而陷入欢乐的阵营。 Versa和Cato Networks在其网站上发布了新闻稿和声明,而zScaler在财报电话会议上对该主题进行了一些讨论。
Telcos behind the eight-ball
电信公司陷入困境
Cato Networks, for one, sees the shift to SASE as a competitive advantage. “Telcos are behind the eight-ball,” Yishah Yovel, Cato CMO and chief strategist, tells Light Reading. Telco networks are based on appliances, and they’re two years behind catching up on the cloud networking model.
例如,Cato Networks将向SASE的转变视为一种竞争优势。 Cato首席营销官兼首席策略师Yishah Yovel对Light Reading表示:“电信公司陷入困境。” 电信网络是基于设备的,比追赶云网络模型落后了两年。
Telcos are disadvantaged because they don’t own the code. “If I’m a Palo Alto or Zscaler, I have my own code. I already have some percentage of the SASE platform. Telcos don’t operate this way. They integrate other people’s code. That’s very dangerous for them, unless they become more of a software player.”
电信公司处于不利地位,因为它们不拥有代码。 “如果我是Palo Alto或Zscaler,我有我自己的代码。我已经拥有一定比例的SASE平台。电信公司无法以这种方式运行。它们会集成其他人的代码。这对他们来说非常危险,除非他们变得 更多的软件播放器。”
Looked at one way, Gartner’s SASE pitch is nothing new. Indeed, when a Cato Networks spokesman brought it to my attention a few weeks ago, I initially scoffed.
从一种角度看,Gartner的SASE呼声渐涨并不是什么新鲜事物。 确实,几周前,当Cato Networks的一位发言人提请我注意时,我开始嘲笑它。
Normally I would have been more polite, but I was in a bad mood on account of being still jet-lagged and sleep deprived from a trip to Dallas, to Light Reading’s Network Virtualization & Software Defined Networking conference, which was all about the trends Gartner had apparently just discovered. And it wasn’t the first year we’ve done that conference; far from it. So my first reaction to the tip was, “Thank you, Captain Obvious!“
通常,我本来会比较有礼貌,但是由于刚到达拉斯的时差,无法参加Light Reading的网络虚拟化和软件定义网络会议,所以我心情很不好,这也与Gartner刚刚发现的趋势有关。 这不是我们召开会议的第一年。所以我对小费的第一反应是:“谢谢,上尉船长!”
The software-defined networking (SDN) movement, launched at the beginning of the decade, was all about moving network intelligence into software for increased agility; the reason we don’t hear much about that anymore is because the philosophy has become mainstream.
十年之初发起的软件定义网络(SDN)运动就是将网络智能转移到软件中以提高敏捷性。 我们之所以不再听到太多的原因是因为该哲学已成为主流。
More recently, AT&T, Orange and startup Rakuten are aggressively moving their networks to cloud architectures. Just last week, Colt launched a new line of universal CPE (uCPE) equipment, providing SD-WAN, firewall and other services to enterprises, based on NFV.
最近,AT&T,Orange和创业公司Rakuten正在积极地将其网络迁移到云架构。 就在上周,Colt推出了新的通用CPE(uCPE)设备系列,为基于NFV的企业提供SD-WAN,防火墙和其他服务。
Still, NFV has attracted skeptics almost since its founding in 2012, and at about the same time Gartner issued its SASE note, we reported that critics were saying the technology is too rigid and monolithic for the cloud era, (though Prayson Pate, CTO, Edge Cloud, ADVA Optical Networking took issue with our report).
尽管如此,NFV几乎自2012年成立以来就一直引起怀疑论者的关注,并且大约在同一时间,Gartner发布了SASE说明,据我们报道,批评者称该技术对于云时代而言过于僵化和整体化(尽管 Prayson Pate (ADVA光网络公司Edge Cloud 的CTO)对我们的报告对提出了质疑)。
However, my initial dismissal was misplaced. Gartner does a good job of weaving together and articulating several long-term trends shaping the service provider business and networks. Gartner deserves credit for stepping back and summarizing a decade of trends in a few pages.
但是,我最初的解雇是错误的。 Gartner很好地组织并阐明了影响服务提供商业务和网络的几种长期趋势。 Gartner值得一提的是在几页中后退并总结了十年的趋势。
Also, Gartner is influential, particularly among enterprises who are service provider customers. Gartner’s SASE coinage means ideas about wide-area network virtualization and cloudification have gone mainstream. Telcos are going to start hearing demand for SASE, and need to be prepared to meet it.
此外,Gartner很有影响力,特别是在服务提供商客户企业中。 Gartner的SASE概念意味着有关广域网虚拟化和云化的想法已成为主流。 电信公司将开始听到对SASE的需求,并且需要做好准备以满足它。
For more about how AT&T, Orange, Rakuten and other service providers already cloudifying and virtualizing their networks, see these articles:
看到“GitHubDaily”公众号推送一个关于Python-100-Days的一个项目,觉得里面的东西蛮有意思,之前由于工作需要也玩过一段时间的python,但是没有很系统的学习,所以打算花上一段时间根据这个项目进行较为系统的学习。
在教程的第一节就是关于python之禅的介绍,搜索了一下网上的翻译,觉得很有意思这里也转载记录一下。
看到很对提及此事的文章中都提到了python禅道出自PEP20,这里也顺带介绍一下PEP[1]
PEP 是 Python 增强提案(Python Enhancement Proposal)的缩写。社区通过PEP来给 Python 语言建言献策,每个版本你所看到的新特性和一些变化都是通过PEP提案经过社区决策层讨论、投票决议,最终才有我们看到的功能。
如果你还不知道PEP8是什么,可能还算不上一位合格的Python程序员,PEP8是每个Python程序员必读的提案,Python虽然以语法简洁著称,但并不意味着你就一定能写出简洁优雅的代码,PEP8风格指南定义了编写 Python 代码的规范和应该遵守的编码原则,大家都应该按照此规范约束代码,多读几遍此规范,做到了然于心。网上有各种版本的中译版,可选择性参考阅读。
Tim Peter 回答过什么是好的Python代码?
有个通用的约定应该是可维护的、清晰可懂的、满足一致性的,同时也应该是好的编程习惯的基础。它不会违背你的意愿来强制要求你遵循那些规则。这就是Python!”
地址:[pep-0008][https://www.python.org/dev/peps/pep-0008/]
打开终端输入python
,import this
即可看到Tim Peters的Then Zen of Python
1 | python3 |
在网上找到关于这段话的翻译,转载自豆瓣The Zen of Python ,
Python之禅
赖勇浩翻译Beautiful is better than ugly.
优美胜于丑陋(Python 以编写优美的代码为目标)
Explicit is better than implicit.
明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)
Simple is better than complex.
简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)
Complex is better than complicated.
复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)
Flat is better than nested.
扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)
Sparse is better than dense.
间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)
Readability counts.
可读性很重要(优美的代码是可读的)
Special cases aren’t special enough to break the rules. Although practicality beats purity.
即便假借特例的实用性之名,也不可违背这些规则(这些规则至高无上)
Errors should never pass silently. Unless explicitly silenced.
不要包容所有错误,除非你确定需要这样做(精准地捕获异常,不写 except:pass 风格的代码)
In the face of ambiguity, refuse the temptation to guess.
当存在多种可能,不要尝试去猜测
There should be one– and preferably only one –obvious way to do it.
而是尽量找一种,最好是唯一一种明显的解决方案(如果不确定,就用穷举法)
Although that way may not be obvious at first unless you’re Dutch.
虽然这并不容易,因为你不是 Python 之父(这里的 Dutch 是指 Guido )
Now is better than never. Although never is often better than right now.
做也许好过不做,但不假思索就动手还不如不做(动手之前要细思量)
If the implementation is hard to explain, it’s a bad idea. If the implementation is easy to explain, it may be a good idea.
如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然(方案测评标准)
Namespaces are one honking great idea – let’s do more of those!
命名空间是一种绝妙的理念,我们应当多加利用(倡导与号召)
也有简洁版的如下:
The Zen of Python,
蛇宗三字经
作者:Tim Peters
翻译:元创Beautiful is better than ugly.
美胜丑
Explicit is better than implicit.
明胜暗
Simple is better than complex.
简胜复
Complex is better than complicated.
复胜杂
Flat is better than nested.
浅胜深
Sparse is better than dense.
疏胜密
Readability counts.
辞达意
Special cases aren’t special enough to break the rules.
不逾矩
Although practicality beats purity.
弃至清
Errors should never pass silently.
无阴差
Unless explicitly silenced.
有阳错
In the face of ambiguity, refuse the temptation to guess.
拒疑数
There should be one– and preferably only one –obvious way to do it.
求完一
Although that way may not be obvious at first unless you’re Dutch.
虽不至,向往之
Now is better than never.
敏于行
Although never is often better than right now.
戒莽撞
If the implementation is hard to explain, it’s a bad idea.
差难言
If the implementation is easy to explain, it may be a good idea.
好易说
Namespaces are one honking great idea – let’s do more of those!
每师出,多有名
在查找的过程中也看到了比较有意思的是上面那段话在python源码this.py中并不是明文存储的,而是使用了凯撒加密法,将每个字符前移13位然后再跟26取余,源码如下:
1 | s = """Gur Mra bs Clguba, ol Gvz Crgref |
大致的对应如下:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm
这里也简单的作为一个学习开始的记录,勉励自己能够坚持学习下去,用python做一些有意思的小项目玩一玩。
加油↖(^ω^)↗
【参考资料】
]]>最近研究区块链时,突然发现没法连接区块链服务器,一检查发现是区块链程序进程退出了,重启之后仍然退出,再次检查发现是磁盘空间不够了,因为部署在Openstack环境中,因此可以直接使用Openstack的Resize扩展一下磁盘空间,但是点击Resize后并没有改变flavor大小,dashboard上并没有报错,控制节点也看不到错误,进入到计算节点查看才发现有如下报错:
2019-07-05 11:12:12.599 21343 ERROR oslo_messaging.rpc.server File “/usr/lib/python2.7/contextlib.py”, line 35, in exit
2019-07-05 11:12:12.599 21343 ERROR oslo_messaging.rpc.server self.gen.throw(type, value, traceback)
2019-07-05 11:12:12.599 21343 ERROR oslo_messaging.rpc.server File “/usr/lib/python2.7/dist-packages/nova/compute/manager.py”, line 7958, in _error_out_instance_on_exception
2019-07-05 11:12:12.599 21343 ERROR oslo_messaging.rpc.server raise error.inner_exception
2019-07-05 11:12:12.599 21343 ERROR oslo_messaging.rpc.server ResizeError: Resize error: not able to execute ssh command: Unexpected error while running command.
2019-07-05 11:12:12.599 21343 ERROR oslo_messaging.rpc.server Command: ssh -o BatchMode=yes 10.0.0.62 mkdir -p /var/lib/nova/instances/6119b573-1b02-4c72-87c9-14e1fd645449
2019-07-05 11:12:12.599 21343 ERROR oslo_messaging.rpc.server Exit code: 255
错误显示是计算节点cmp002无法登录cpm001,因此无法在另外一个节点重建虚机。
通过允许计算节点间nova用户免密登录解决。
对nova用户进行配置[1]。
使用root用户在所有计算节点上执行以下操作
1 | usermod -s /bin/bash nova |
检查修改,确保nova用户具备shell执行权限:
1 | cat /etc/passwd | grep nova |
在任一个计算节点上,用nova用户登录,创建密钥
1 | su - nova |
在该节点上,配置nova用户的SSH配置,不执行主机密钥验证,
1 | cat << EOF > ~/.ssh/config |
拷贝id_rsa.pub为authorized_keys,并修改权限
1 | cat ~/.ssh/id_rsa.pub > .ssh/authorized_keys |
1)直接拷贝公钥
将计算节点的nova根目录下/var/lib/nova/.ssh/id_rsa.pub
内容拷贝其他所有计算节点的/var/lib/nova/.ssh/authorized_keys
即可。
2)使用命令上传
若计算节点的nova用户设置的有密码也可直接用命令上传,
1 | nova@cmp002:~$ ssh-copy-id -i ~/.ssh/id_rsa.pub nova@cmp001 |
在任意节点验证,到其他所有计算节点可否SSH登录
1 | su - nova |
重试resize,即可完成,发现resize完成后,虚拟机迁移到目标计算节点上。
以上的操作需要配置计算点间无密码访问,但是那么多计算节点相互访问配置较为麻烦,有提到通过修改nova配置文件,允许在同一台服务器上进行resize和migrate操作配置项,如下[2]:
1 | vim /etc/nova/nova.conf |
然后重启nova-api和nova-compute服务:
1 | systemctl restart nova-compute |
1 | systemctl restart nova-api |
但在计算节点配置后,重启nova-compute服务,重试resize没有效果。后来才发现,这仅适用于计算节点只有一台的测试环境,多计算节点的生产环境并不适用,仍需要ssh到其他计算节点。
OPNFV与5月发布了第八个版本Hunter,随即升级了实验室的环境,同时也测试一下即将发布的OVP 第三个版本。官方社区的安装工具也减少到只剩下MCP (Fuel)和TripleO两个了,Fuel的安装方式没有太多的改变,只是引入了Docker将原来的fuel和MAAS两个安装虚拟机换成了Docker容器。实际在部署过程中发现与先前的OPNFV Euphrates部署 02和OPNFV Euphrates部署 03没有区别,在配置好网络、PDF以及IDF后可以很顺利的安装。同时看到Fuel部署的文档写的更加详细了,参见:
OVP也将发布第三个版本OVP-2019.08增强测试内容,因此这里一并整理一下使用与问题排查办法。
Fuel的Hunter部署和Euphrates以及Gambia没有太大的差别,完全可以参考先前的OPNFV Euphrates部署 02和OPNFV Euphrates部署 03,这里主要介绍一下加快部署的办法。
部署过程中遇到的最大的问题就是MAAS每次都会去重新获取最新的ubuntu镜像,常常因为镜像下载缓慢导致部署超时,这里可以参看MAAS本地源设置,配置本地MAAS源以加快部署
修改mcp/reclass/classes/cluster/all-mcp-arch-common/infra/maas.yml.j2
1 | boot_sources: |
本次安装在解决完MAAS本地源后安装十分顺利,但是安装完后无法使用dashboard,给社区提了一个jira Fuel-408看后续修复吧,尝试在本地解决了一些问题,使得访问prx01/prx02的的8078端口可以看到正常的页面,但是使用密码无法登录。
这里记录一下在无dashboard的情况下配置并测试openstack环境
1 | openstack image create cirros --file cirros-0.3.5.qcow2 --container-format bare --public |
1 | openstack subnet create --network floating_net --allocation-pool start=192.168.20.100,end=192.168.20.200 --dns-nameserver 10.2.2.20 --gateway 192.168.20.1 --subnet-range 192.168.20.0/1 floating_subnet |
1 | openstack network create test |
1 | openstack floating ip create floating_net |
1 | openstack security group rule create <default group id> --protocol tcp --dst-port 22:22 --remote-ip 0.0.0.0/0 |
1 | openstack flavor create m1.tiny --ram 64 --disk 0 --vcpus 1 --public |
1 | nova boot --flavor m1.tiny --image cirros --nic net-id=<floating_net id> test |
1 | openstack floating ip create floating_net |
OVP测试使用参考:OVP用户手册
选择一台机器,安装配置好docker,并确保机器可以访问OPNFV环境的keystone API
1 | mkdir -p ${HOME}/dovetail |
1 | mkdir -p ${DOVETAIL_HOME}/pre_config |
填写配置文件内容
该文件的内容可以从控制节点ctl0x的/root/keystonercv3
获取。
1 | cat ${DOVETAIL_HOME}/pre_config/env_config.sh |
配置Tempest
所需的配置文件,编辑文件$DOVETAIL_HOME/pre_config/tempest_conf.yaml
1 | compute: |
节点描述信息,dovetail在测试时会获取节点信息,同时在HA测试部分会重启节点也需要用到节点信息
1 | nodes: |
process_info表明在测试相应HA用例时yardstick重启哪些进程或节点
这里给出相应测试用例攻击的进程名
Test Case Name | Attack Process Name |
---|---|
yardstick.ha.cinder_api | cinder-api |
yardstick.ha.database | mysql |
yardstick.ha.glance_api | glance-api |
yardstick.ha.haproxy | haproxy |
yardstick.ha.keystone | keystone |
yardstick.ha.neutron_l3_agent | neutron-l3-agent |
yardstick.ha.neutron_server | neutron-server |
yardstick.ha.nova_api | nova-api |
yardstick.ha.rabbitmq | rabbitmq-server |
这里仅以OVP-2.2为例
1 | wget -nc http://download.cirros-cloud.net/0.4.0/cirros-0.4.0-x86_64-disk.img -P ${DOVETAIL_HOME}/images |
1 | sudo docker run --privileged=true -it \ |
其中:
-e
指定DOVETAIL_HOME变量-v
映射DOVETAIL_HOME目录进入容器查看测试用例
1 | docker exec -it dovetail bash |
执行测试用例
简单测试
1 | dovetail run --offline --debug --testcase functest.vping.userdata --deploy-scenario os-nosdn-ovs-ha --report |
其中:
完整测试
OVP认证测试内容分为mandatory
和optional
,可以单独执行
1 | dovetail run --mandatory --report |
执行完测试后在$DOVETAIL_HOME/results
可以获得完整的测试记录,执行不通过的测试用例也可在相应的目录获得日志文件
tempest_logs/functest.tempest.XXX.html
and security_logs/functest.security.XXX.html
respectively, which has the passed, skipped and failed test cases results.vping_logs/functest.vping.XXX.log
.ha_logs/yardstick.ha.XXX.log
.stress_logs/bottlenecks.stress.XXX.log
.snaps_logs/functest.snaps.smoke.log
.vnf_logs/functest.vnf.XXX.log
.节点信息获取失败并不影响测试执行,可以在dovetail容器中执行以下命令查找失败原因
1 | ansible all -m setup -i XX/results/inventory.ini --tree XX/results/sut_hardware_info |
我的测试环境是os-nosdn-ovs-ha
使用了DPDK网卡,有时由于变量传递的原因导致测试过程中,虚机的flavor没有设置'hw:mem_page_size':'large'
,因此导致虚拟创建后无法连接而报错,可以在测试过程中查看openstack flavor list --debug
查看是否是此问题,如果是此类问题只能报告官方修复了。
通过dovetail的不清除选项保留测试过程中启动的容器,然后一步一步排查
1 | dovetail run --offline --debug --testcase xxx -n |
随后进入调用的容器,执行dovetail测试过程中调用的命令,如
1 | container.Container - DEBUG - Executing command: 'sudo docker run -id --privileged=true -e INSTALLER_TYPE=unknown -e DEPLOY_SCENARIO=os-nosdn-ovs-ha -e NODE_NAME=unknown -e TEST_DB_URL=file:///home/opnfv/functest/results/functest_results.txt -e CI_DEBUG=true -e BUILD_TAG=daily-master-7c89eac6-829e-11e9-85e8-0242ac140002-functest.tempest.vm_lifecycle -v /nfs/NFV_TEST/dovetail/data/pre_config/env_config.sh:/home/opnfv/functest/conf/env_file -v /nfs/NFV_TEST/dovetail/data/pre_config/os_cacert:/nfs/NFV_TEST/dovetail/data/pre_config/os_cacert -v /nfs/NFV_TEST/dovetail/data:/home/opnfv/userconfig -v /nfs/NFV_TEST/dovetail/data/results:/home/opnfv/functest/results -v /nfs/NFV_TEST/dovetail/data/images:/home/opnfv/functest/images opnfv/functest-smoke:opnfv-7.1.0 /bin/bash' |
可以进入到75cd8d85a13a
容器中执行run_tests -t tempest_custom -r
进一步排查,
对于functest,其代码目录位于容器中的/usr/lib/python2.7/site-packages/functest
,可以修改/usr/lib/python2.7/site-packages/functest/ci/logging.ini
中的配置来打开相应组件的日志记录,进行更深层次的排查。
最近在创建虚拟机时VM创建非常的慢并且出现创建失败的情况,计算节点报错显示块设备映射超时,在尝试了61次207秒后失败,此时查看Openstack的卷设备创建,发现volume显示是downloading状态,即未创建完成。
ERROR nova.compute.manager [req-94c955d9-9c94-4536-90e2-d21928344444 381fdf4b65aa45ef98a2ad20bc4bd079 4353036cc27542cf84e1bccf1b4bfe33 - default default] [ instance: 655eccd6-cafb-4291-b55a-c53dd000a8e4] Build of instance 655eccd6-cafb-4291-b55a-c53dd000a8e4 aborted: Volume 0e4150db-567f-4ae0-a947-8fc7a0d624f0 did not finish being created even after we waited 207 seconds or 61 attempts. And its status is downloading.: BuildAbortException: Build of instance 655eccd6-cafb-4291-b55a-c53dd000a8e4 aborted: Volume 0e4150db-567 f-4ae0-a947-8fc7a0d624f0 did not finish being created even after we waited 207 seconds or 61 attempts. And its status is downloading.
该错误原因是Openstack卷创建时间过长与所需卷存储设置大小有关。
根据[1]增大block_device_allocate_retries
参数即可,修改计算节点的/etc/nova/nova.conf
1 | block_device_allocate_retries = 180 |
重启nova服务即可。
在修改block_device_allocate_retries
时意外发现注释中有一段标注
Number of times to retry block device allocation on failures. Starting with
Liberty, Cinder can use image volume cache. This may help with block device
allocation performance. Look at the cinder image_volume_cache_enabled
configuration option.
从L版本Openstack加入了镜像券存储缓存的功能,通过这个功能可以快速创建镜像卷存储。根据文档[2][3]修改块存储节点的/etc/cinder/cinder.conf
,加入以下内容
1 | [DEFAULT] |
其中:
cinder_internal_tenant_project_id和cinder_internal_tenant_user_id是为了配置块存储的内部租户。这个租户拥有这些缓存并且可以进行管理。这可以保护用户不必看到这些缓存,但是也没有全局隐藏。cinder_internal_tenant_user_id
选择cinder用户可以保证admin用户看不到缓存镜像,这里设置为admin用户是便于查看修改效果
1 | xdnsadmin@ctl01:~$ openstack project list |
如图所示,image-88e73002-a4e6-4aff-88cf-2711aa7f24c8
为ubuntu-16.04镜像的缓存文件,当需要创建基于该镜像的新volume时可以快速clone,创建速度大大提升。
【参考链接】
]]>最近在研究OpenStack和Kubernetes融合相关的方法,通过查阅[1]发现openstack与k8s融合无外乎两种方法:一是K8S部署在OpenStack平台之上,二是K8S和OpenStack组件集成。方案一的优点是k8s容器借用虚机的多租户具有很好的隔离性,但缺点也很明显K8S使用的是在虚机网络之上又嵌套的一层overlay网络,k8s的网络将难以精细化的管控。方案二将k8s与openstack的部分组件进行集成,是的K8S与openstack具备很好的融合性,从而实现1+1>2的效果。openstack中的magnum是一个典型的解决方案,通过magnum可以镜像容器编排,同时可以快速部署一个Swarm、K8S、Mesos集群。
本文仅介绍如何在openstack中安装部署magnum以及安装中遇到的问题。
此外,我还想吐槽一句,OpenStack
社区从Pike
版本开始弃用了auth_uri
以及keystone的35357
端口全部改为公开的5000
端口和使用www_authenticate_uri
来进行keystone认证,社区的核心组件已经更换完成,但是非核心组件并未完全跟进,如Magnum-api
、Heat
安装时就出现过这类问题。
根据官方组件说明[2],必须的组件有:
可选组件有:
本次安装使用的Rocky版本,Neutron网络架构采用的是ovs+vxlan的方式
我的openstack环境采用纯手工的方式按照官方指导文档进行安装,同样Magnum也是Manual的方式安装,系统版本为Ubuntu-18.04 LTS
,因为Rocky版本的deb
包只有18.04才有。Magnum-api 版本为7.0.1-0ubuntu1~cloud0
。
按照指导手册[3],进行安装,安装和配置方式极其简单,但是官方的配置文档没有来的及更新,以及deb包更新不及时遇到了很多奇奇怪怪的bug,在查找原因时也很难确定关键词而无法搜索到正确的答案。
按照官方文档在安装完Magnum后通过openstack coe service list
来查看是否安装成功,如果该命令执行失败通过查看/var/log/magnum/magnum-api.log
来排查问题。但是,该命令执行成功也不代表这Magnum的服务能够正常使用,后续使用中主要查看的是Magnum调度的日志/var/log/magnum/magnum-conductor.log
。
Magnum API报错 ,如下所示,根据[4],新的稳定版代码已修复但是安装的deb包并不是最新的代码
File “/usr/lib/python2.7/dist-packages/magnum/common/keystone.py”, line 47, in auth_url
return CONF[ksconf.CFG_LEGACY_GROUP].auth_uri.replace(‘v2.0’, ‘v3’)AttributeError: ‘NoneType’ object has no attribute ‘replace’
解决方法如下如Add support for www_authentication_uri所示,添加如下patch
1 | vim /usr/lib/python2.7/dist-packages/magnum/common/keystone.py +47 |
修改完成后需要重启magnum服务,否则修改的代码不生效。
1 | service magnum-* restart |
按照文档创建一个集群模板时出现如下报错:
1 | root@ctl01:/home/xdnsadmin# openstack coe cluster template create swarm-cluster-template --image fedora-atomic-latest --external-network Provider --dns-nameserver 223.5.5.5 --master-flavorm1.small --flavor m1.small --coe swarm |
解决办法是指定一个volume size,按照官方的说法没有cinder服务也可以使用magnum,这个我并未验证,我的集群安装的cinder服务。
1 | openstack coe cluster template create swarm-cluster-template --image fedora-atomic-latest --external-network Provider --dns-nameserver 223.5.5.5 --master-flavor m1.small --flavor m1.small --coe swarm --docker-volume-size 10 |
同时这里仍有一个问题,查看2.5
在安装过程出现无效的volumetype的错误,按照[5]需要设置volumetype同时进行相关配置
ERROR heat.engine.resource raise exception.ResourceFailure(message, self, action=self.action)
ERROR heat.engine.resource ResourceFailure: resources[0]: Property error: resources.docker_volume.properties.volume_type: Error validating value ‘’: The VolumeType () could not be found.
1)Check if you have any volume types defined.
1 | openstack volume type list |
2)If there are none, create one:
1 | openstack volume type create volType1 --description "Fix for Magnum" --public |
3)Then in /etc/magnum/magnum.conf add this line in the [cinder] section:
1 | default_docker_volume_type = volType1 |
Barbican
服务未安装按照文档在选择[certificates]
时使用推荐的barbican
来存储认证证书,而我的openstack集群并未安装barbican
服务,因此收到了如下报错,但是我当时并未发现原因所在,我一直以为是keystone的publicURL endpoint
无法访问。
2019-04-09 18:42:26.505 32428 ERROR magnum.conductor.handlers.common.cert_manager [req-ffd4b077-80ee-4846-bdc0-84817aa699a5 - - - - -] Failed to generate certificates for Cluster: 03cd9a72-c980-4947-b273-d9bcb88a6913: AuthorizationFailure: unexpected keystone client error occurred: publicURL endpoint for key-manager service not found
……….
2019-04-09 18:42:26.505 32428 ERROR magnum.conductor.handlers.common.cert_manager connection = get_admin_clients().barbican()
2019-04-09 18:42:26.505 32428 ERROR magnum.conductor.handlers.common.cert_manager File “/usr/lib/python2.7/dist-packages/magnum/common/exception.py”, line 65, in wrapped
2019-04-09 18:42:26.505 32428 ERROR magnum.conductor.handlers.common.cert_manager % sys.exc_info()[1])
2019-04-09 18:42:26.505 32428 ERROR magnum.conductor.handlers.common.cert_manager AuthorizationFailure: unexpected keystone client error occurred: publicURL endpoint for key-manager service not found
该问题的解决方法很简单,安装barbican
服务,或者使用x509keypair
或local
方式存储证书
1 | [certificates] |
若使用local方式,还需创建目录/var/lib/magnum/certificates/
,并将其所属组改为magnum,sudo chown -R magnum:magnum /var/lib/magnum/certificates/
,否则会出现如下报错:
2019-04-10 15:40:50.675 20235 ERROR magnum.conductor.handlers.common.cert_manager [req-c31e7588-a486-4ea8-8adc-16ff8f37b284 - - - - -] Failed to generate certificates for Cluster: e579 0f96-e8c5-49c5-82f9-87faf8438585: CertificateStorageException: Could not store certificate: [Errno 2] No such file or directory: ‘/var/lib/magnum/certificates/5e8beb02-9378-4e8c-8b4d-1 cae933de665.crt’
同时,在修复此问题的过程中查看到一个警告,该警告对于使用过程也造成了很大的影响Auth plugin and its options for service user must be provided in [keystone_auth] section. Using values from [keystone_authtoken] section is deprecated.: MissingRequiredOptions: Auth plugin requires parameters which were not given: auth_url
需要在/etc/magnum/magnum.conf
中 添加keystone_auth
项 ,此外,这里的还涉及到接下来的问题2.4
1 | [keystone_auth] |
在处理完以上的magnum conductor问题后,开始创建swarm集群,但是出现创建超时(超时时长为60分钟)集群的stack启动失败的问题。原因是按照之前的官方文档创建所有服务的endpoint都是使用http://ctl01:xxx
而此处创建的swarm集群需要与opensatck相关服务进行通信,无法识别ctl01
域名,解析不到服务地址IP,因此需要将所有的endpiont服务的public地址都是用公开的IP替换。
ERROR oslo_messaging.rpc.server [req-4a8e8e2d-cae0-4113-a49d-57bb91c03b8d - - - - -] Exception during message handling: EndpointNotFound: http://ctl01:9511/v1 endpoint for identity service not found
….
ERROR oslo_messaging.rpc.server File “/usr/lib/python2.7/dist-packages/magnum/conductor/handlers/cluster_conductor.py”, line 68, in cluster_create
ERROR oslo_messaging.rpc.server cluster_driver.create_cluster(context, cluster, create_timeout)
….
ERROR oslo_messaging.rpc.server File “/usr/lib/python2.7/dist-packages/keystoneauth1/access/service_catalog.py”, line 464, in endpoint_data_for
ERROR oslo_messaging.rpc.server raise exceptions.EndpointNotFound(msg)
ERROR oslo_messaging.rpc.server EndpointNotFound: http://ctl01:9511/v1 endpoint for identity service not found
使用命令openstack endpoint list | grep public
查看相关的endpoint。
在解决完2.4的问题后又迎来了新的问题,swarm-cluster集群启动创建成功,但是服务报错。这是能够通过floating ip
登录swarm master节点使用fedora
用户以及密钥mykey
登录。查看cloud init
日志/var/log/cloud-init-output.log
,会发现如下的报错:
/var/lib/cloud/instance/scripts/part-006: line 13: /etc/etcd/etcd.conf: No such file or directory
/var/lib/cloud/instance/scripts/part-006: line 26: /etc/etcd/etcd.conf: No such file or directory
/var/lib/cloud/instance/scripts/part-006: line 38: /etc/etcd/etcd.conf: No such file or directory
etcd
初始失败从而导致swarm-manager
启动失败,这个问题还是相当的严重的,因为很难排查原因,最终在opensatck的讨论邮件列表中找到的答案[6],根本原因是coe
使用错误,应该使用swarm-mode
而不是安装手册里写的swam
,这点实在是太坑人了。
$openstack coe cluster template show docker-swarm
| docker_storage_driver | devicemapper |
| network_driver | docker |
| coe | swarm-mode |Never got the “swarm” driver to work, you should use “swarm-mode” instead which uses native Docker clustering without etcd.
同时需要注意的是,使用的Fedora
镜像必须是Fedora-Atomic-27-xx
,Frdora 27
之后的镜像改变较大,cloud init
脚本无法正常工作。还需添加必要的patch swarm-mode allow TCP port 2377 to swarm master node,修改magnum/drivers/swarm_fedora_atomic_v2/templates/swarmcluster.yaml
的Line 247,添加一下内容。
1 | - protocol: tcp |
随后,
1)重新创建swarm-cluster
模板
1 | root@ctl01:/home/xdnsadmin/workplace/magnum/swarm/cluster# openstack coe cluster template create swarm-cluster-template --image fedora-atomic-latest --external-network Provider --dns-nameserver 223.5.5.5 --master-flavor m1.small --flavor m1.small --coe swarm-mode --docker-volume-size 10 |
2)启动swarm-cluster
实例
1 | root@ctl01:/home/xdnsadmin/workplace/magnum/swarm/cluster# openstack coe cluster create swarm-cluster --cluster-template swarm-cluster-template --master-count 1 --node-count 1 --keypair mykey |
等待集群实例创建完成
3)配置swarm-cluster
访问
首先,生成证书,然后导入环境变量即可访问swarm集群(控制节点需要安装docker客户端)
1 | root@ctl01:/home/xdnsadmin/workplace/magnum/swarm/cluster# $(openstack coe cluster config swarm-cluster --dir /home/xdnsadmin/workplace/magnum/swarm/cluster) |
该错误与swarm节点的存储格式有关,由于之前解决swarm无法启动而被带偏添加了--docker-storage-driver overlay
参数在swarm-cluster
模板中,导致容器无法启动,通过查看[7]得知与其支持的存储驱动有关
1 | root@ctl01:/home/xdnsadmin/workplace/magnum/swarm/cluster# docker -H 10.253.0.111:2375 run busybox echo "Hello from Docker!" |
目前Docker
支持如下几种storage driver:
Technology | Storage driver name |
---|---|
OverlayFS | overlay |
AUFS | aufs |
Btrfs | btrfs |
Device Mapper | devicemapper |
VFS | vfs |
ZFS | zfs |
详细的对比可以参看:Docker之几种storage-driver比较
以上,就是Openstack Rocky版本Magnum安装与排坑的过程,不说啦,刚刚安装完Rocky版本,Stein版本就放出来了,我接着去踩雷啦 - -!开源真香
【参考链接】
1)如何把OpenStack和Kubernetes结合在一起来构建容器云平台
2)Magnum -Container Orchestration Engine Provisioning
4)magnum-api not working with www_authenticate_uri
5)magnum cluster create k8s cluster Error: ResourceFailure
6)Fwd: openstack queens magnum error
7)standard_init_linux.go:175: exec user process caused “permission denied”
]]>自从接触到markdown
文本标记语言后一直使用Markdown Pad2编辑器,其直接预览以及在线生成图片链接的功能非常受用,可是该软件的更新一直停留在2014年,在我的工作电脑从win7切换成win10后预览功能就无法使用,我使用typra作为替代,但是还是保留着Markdown Pad2
因为其在线生成图片链接的功能还能使用。终于,我担心的情况出现了 - - ,Markdown Pad2
上传的图挂了,先前写的文章图片全部看不到了。(Ps:好像不是图床Imgur
挂了,而是国内无法访问)
没办法,只能更换图床了,这里使用Github
作为图床,配合PicGo上传图片。
这里直接引用PicGo+GitHub图床,让Markdown飞博客设置的内容了,不再重复配置啦。
]]>在研究Helm
时发现其创建的随机容器名跟docker类似都是左右形式的组合,因此想到Docker随机容器名的上限是多少,会不会因为随机容器名的重复而导致无法再创建随机容器名的容器实例而达到容器的上限。
根据my2cents的How does Docker generate default container names?
文章介绍,得知docker随机容器名的生成是分为左右值的,即拥有两个独立的数组。查看docker容器名生成的源代码可以看到左值都是一些形容词,共计100个,右值都是一些amazing man
,并且给出了wiki百科的介绍页面,共计235位。(统计截止到2019年3月7日)
有意思的是代码的最后一行,当容器名为boring_wozniak
时会重新生成,Steve Wozniak是Apple I和Apple II的发明人,看来码代码的人十分推崇Wozniak,加了专门的彩蛋。
1 | if name == "boring_wozniak" /* Steve Wozniak is not boring */ { |
根据容器名规则以及容器名实例不能重复原则使用排列组合可以得知能够创建的随机容器名实例上限是100*235-1=23499个。
这种容器名生成的优势是什么?
通过使用形容词-单词的组合方式生成的容器名比枯燥的hash数字更为好看也便于记忆。
问题来了,在单一主机中到底能够运行多少个容器?
根据stack overflow
上的Is there a maximum number of containers running on a Docker host?回答,翻译如下[1]
docker容器创建实例有很多的系统限制,一些重要的信息如下:
详细的运行限制如下:
Container 服务
总的资源消耗取决于你容器内运行的程序,而不是docker本身,如果你在虚拟机中运行应用程序node,ruby,python,java,内存的消耗将是主要问题。
1000个进程会消耗大大量的IO 链接。1000个进程同时运行也会引起大量的上下文交换,
1023 Docker busybox images
1 | nc -l -p 80 -e echo |
共计使用约1G的内核空间和3.5G的系统内存
1023 普通进程
1 | nc -l -p 80 -e echo |
将会消耗约75MB的内核空间和125MB的系统内存
此外,
连续启动1023个容器预计耗费约8分钟,关闭1023个容器预计耗费约6分钟
有文章做了一个实验来启动500个容器,感兴趣的可以查看docker 启动500个容器测试
根据以上信息可以得知随机容器名的限制不会是容器创建上限的障碍,容器实例本身所消耗的资源如内存、网络等才是最关键的影响。
【参考链接】
1)Is there a maximum number of containers running on a Docker host?
]]>一年前研究过一段时间的K8S,最开始看k8s的概念一头雾水,随着学习的深入有一些了解,跟着cloudman的教程尝试搭建k8s集群,但是当时由于墙的原因搭建一个k8s集群颇为费劲,在做完实验对k8s有一个了解后就没有继续深入。最近由于新的项目需要重新研究k8s环境,正好做一下笔记,记录搭建的过程,在搭建过程中一个好消息就是k8s的docker容器在国内有镜像提供商,像阿里云、dockerhub上都有,简直是一大救星。由于有一定的知识了解,本文不再介绍k8s的基本概念和相关的命令含义。
搭建过程主要参考的是molscar的使用kubeadm 部署 Kubernetes(国内环境)。
k8s集群的安装,至少需要一个master节点和一个slave节点,节点配置如下
本文搭建时使用的系统是ubuntu 16.04.5,一个master节点4个slave节点,安装的是当前k8s最新的v1.13版本。
master和slave节点都需要安装docker
我的网络在教育网访问更快,这里使用清华源来进行安装
安装依赖:
1 | sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common |
信任 Docker 的 GPG 公钥:
1 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - |
对于 amd64 架构的计算机,添加软件仓库:
1 | sudo add-apt-repository \ |
最后安装
1 | sudo apt-get update |
安装完成后通过命令查看
1 | xdnsadmin@k8smaster:~$ docker --version |
为了使普通用户免sudo使用docker命令
将当前用户加入 docker
组:
1 | sudo usermod -aG docker $USER |
对于使用 systemd 的系统,请在 /etc/docker/daemon.json
中写入如下内容(如果文件不存在请新建该文件)
这里使用Docker 官方加速器 ,也可以使用阿里云或者中科大的加速
1 | { |
重新启动服务
1 | sudo systemctl daemon-reload |
该步骤只需要在master节点执行即可
对于禁用
swap
内存,具体原因可以查看Github上的Issue:Kubelet/Kubernetes should work with Swap Enabled
临时关闭方式:
1 | sudo swapoff -a |
永久关闭方式:
编辑/etc/fstab
文件,注释掉引用swap
的行
1 | <file system> <mount point> <type> <options> <dump> <pass> |
随后重启机器
测试:输入top
命令,若 KiB Swap一行中 total 显示 0 则关闭成功
master和slave节点都需要安装三个软件
这里可以选择使用清华源或中科大源加速安装
首先添加软件源认证
1 | apt-get update && apt-get install -y apt-transport-https curl |
随后添加中科大源仓库地址并安装软件
1 | cat <<EOF > /etc/apt/sources.list.d/kubernetes.list |
在Master节点中配置 cgroup driver
查看 Docker 使用 cgroup driver:
1 | docker info | grep -i cgroup |
而 kubelet 使用的 cgroupfs 为system,不一致故有如下修正:
1 | sudo vim /etc/systemd/system/kubelet.service.d/10-kubeadm.conf |
加上如下配置:
1 | Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=cgroupfs" |
或者
1 | Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=cgroupfs --pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google_containers/pause-amd64:3.1" |
重启 kubelet
1 | systemctl daemon-reload |
这里使用kubeadm
来进行自动化集群安装和配置,在安装过程中会从google仓库中下载镜像,由于墙的原因镜像下载会失败,这里预选将相应的镜像下载下来再重新改tag
Master 和 Slave 启动的核心服务分别如下:
Master 节点 | Slave 节点 |
---|---|
etcd-master | Control plane(如:calico,fannel) |
kube-apiserver | kube-proxy |
kube-controller-manager | other apps |
kube-dns | |
Control plane(如:calico,fannel) | |
kube-proxy | |
kube-scheduler |
使用如下命令:
1 | kubeadm config images list |
获取当前版本kubeadm 启动需要的镜像,示例如下:
1 | xdnsadmin@k8smaster:~$ kubeadm config images list |
从dockerhub
的mirrorgooglecontainers仓库下载相应镜像,如
1 | xdnsadmin@k8smaster:~$ docker pull mirrorgooglecontainers/kube-apiserver:v1.13.3 |
这里分享一个脚本来自动完成镜像下载并改tag的操作
1 | xdnsadmin@k8smaster:~$ cat k8s_images_get.sh |
Master 节点
Protocol | Direction | Port Range | Purpose | Used By |
---|---|---|---|---|
TCP | Inbound | 6443* | Kubernetes API server | All |
TCP | Inbound | 2379-2380 | etcd server client API | kube-apiserver, etcd |
TCP | Inbound | 10250 | Kubelet API | Self, Control plane |
TCP | Inbound | 10251 | kube-scheduler | Self |
TCP | Inbound | 10252 | kube-controller-manager | Self |
Worker节点
Protocol | Direction | Port Range | Purpose | Used By |
---|---|---|---|---|
TCP | Inbound | 10250 | Kubelet API | Self, Control plane |
TCP | Inbound | 30000-32767 | NodePort Services** | All |
在初始化过程中需要coredns
的支持,同样需要预先下载,随着安装的k8s版本不同所需的coredns
版本也会相应改变,可以先执行kubeadm init
查看报错
1 | xdnsadmin@k8smaster:~$ docker pull docker pull coredns/coredns:1.2.6 |
集群master节点初始化:
1 | xdnsadmin@k8smaster:~$ sudo kubeadm init --apiserver-advertise-address=<your ip> --pod-network-cidr=10.244.0.0/16 |
init 常用主要参数:
--pod-network-cidr=10.244.0.0/16
,需要注意的该CIDR不可修改。1 | mkdir -p $HOME/.kube |
master节点测试:
1 | curl https://127.0.0.1:6443 -k 或者 curl https://<master-ip>:6443 -k |
回应如下:
1 | { |
重置初始化
1 | xdnsadmin@k8smaster:~$ kubeadm reset |
忘记了token,可以通过命令查看
1 | xdnsadmin@k8smaster:~$ kubeadm token list |
插件可选类型有很多,参考官方pod网络插件,这里选用flannel
网络,网络选择在后续可以修改
1 | xdnsadmin@k8smaster:~$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml |
在slave节点执行一下命令即可自动加入集群
1 | kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash> |
查看节点加入情况
1 | xdnsadmin@k8smaster:~$ kubectl get nodes |
若有节点未加入查看相关节点的镜像是否下载成功。
k8s集群安装后可以安装dashboard面板便于查看
1 | k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1 |
同样的方式先从dockerhub
上下载镜像再改tag
安装dashboard,不同版本配置模板的链接会有所修改,以官方的安装链接为准
1 | xdnsadmin@k8smaster:~$ kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml |
安装过程中可能出现dashboard重新下载而无法连接gcr.k8s.io
的情况,则将部署配置文件下载下来手动修改镜像名称
1 | xdnsadmin@k8smaster:~$ wget https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml |
将type: ClusterIP
改成type: NodePort
1 | xdnsadmin@k8smaster:~$ kubectl -n kube-system edit service kubernetes-dashboard |
查询dashboard状态
1 | xdnsadmin@k8smaster:~/workplace/k8s/dashboard$ kubectl -n kube-system get service kubernetes-dashboard |
可以看到k8s将集群内部的10.97.229.208:443
端口映射到31090
端口,通过浏览器访问https://<Mater IP>:31090
创建kubernetes-dashboard-admin.yaml
并填入以下内容
1 |
|
之后:kubectl create -f kubernetes-dashboard-admin.yml
Kubeconfig登录
创建 admin 用户
file: admin-role.yaml
1 | kind: ClusterRoleBinding |
随后kubectl create -f admin-role.yaml
1 | xdnsadmin@k8smaster:~/workplace/k8s/dashboard$ kubectl -n kube-system get secret|grep admin-token |
设置 Kubeconfig文件
1 | copy ~/.kube/config Kubeconfig |
内容如下:
Token登录
获取token:
1 | xdnsadmin@k8smaster:~/workplace/k8s/dashboard$ kubectl -n kube-system describe $(kubectl -n kube-system get secret -n kube-system -o name | grep namespace) | grep token |
获取admin-token:
1 | xdnsadmin@k8smaster:~/workplace/k8s/dashboard$ kubectl -n kube-system describe secret/$(kubectl -n kube-system get secret | grep kubernetes-dashboard-admin | awk '{print $1}') | grep token |
当前heapster
已经被废弃,但是还有维护,这里也仍然可以使用。
1 | mkdir heapster |
之后修改 heapster.yaml
1 | --source=kubernetes:https://10.0.0.1:6443 --------改成自己的ip |
或者
1 | --source=kubernetes.summary_api:https://kubernetes.default.svc?inClusterConfig=false&kubeletHttps=true&kubeletPort=10250&insecure=true&auth= |
修改镜像为mirrorgooglecontainers
1 | sed -i "s/k8s.gcr.io/mirrorgooglecontainers/" *.yaml |
添加heapster api访问权限,修改heapster-rbac.yaml文件
1 | xdnsadmin@k8smaster:~/workplace/k8s/heapster$ cat heapster-rbac.yaml |
随后部署应用
1 | kubectl create -f . |
效果如下:
选用Sock Shop进行应用部署测试,演示一个袜子商城,以微服务的形式部署起来
1 | kubectl create namespace sock-shop |
等待 Pod 变为 Running 状态,便安装成功
1 | xdnsadmin@k8smaster:~/workplace/k8s/heapster$ kubectl -n sock-shop get deployment |
官方已将其端口做了映射,不需要修改即可直接访问。如果未做端口映射手动修改即可
1 | xdnsadmin@k8smaster:~$ kubectl -n sock-shop edit svc front-end |
如果加购物车功能够跑通,就说明集群搭建成功
卸载 socks shop: kubectl delete namespace sock-shop
OPNFV社区保持着每半年发布一个大版本的劲头,在2018年11月发布了第7个版本 Gambia,在观察社区中各个安装软件后,由于compass项目会支持较多的部署策略及新特性[1],如k8s等。此外,compass也是少有的支持最少一个计算节点和一个控制节点的OPNFV部署工具。本次尝试使用compass4nfv来部署OPNFV的Gambia版本。在部署过程中也遇到了很多的坑,同样的官方的部署指导文档总会在很自然的忽略掉一些很关键的点,这里选择记录一下部署安装以及排错的过程。
Ps:compass4nfv的部署真的是一波N多折,修复一个问题又出现另一个问题,时不时的网络下载失败让人崩溃至极。
首先需要克隆compass4nfv的代码,链接地址如下
1 | git clone https://gerrit.opnfv.org/gerrit/compass4nfv |
随后切换到Gambia的稳定分支版本
1 | git checkout -b stable/gambia |
Compass4nfv支持离线部署模式,离线部署需要预先下载以下镜像系统,链接为:https://artifacts.opnfv.org/compass4nfv.html
然后选定相应的版本镜像即可,这里选择compass4nfv/gambia/opnfv-2018-11-19_08-25-04.tar.gz
准备好以上安装文件后,修改部署配置文件
1) 部署脚本配置
compass4nfv/deploy.sh
中指明镜像路径
1 | export TAR_URL=file:///home/opnfv/opnfv-2018-11-19_08-25-04.tar.gz |
接下来就要进行相应网络及节点的配置。
不同于Fuel的MAAS和saltstack部署,Compass使用的是cobbler和ansible部署,不了解cobbler的可以查阅下相关资料。不同版本的安装可能会稍有不同,请以官方指导手册为准。
部署中可以参考代码仓库中默认的其他节点网络及相应配置compass4nfv/deploy/conf/hardware_environment
下面分别详细介绍网络配置network.yml
和部署策略os-nosdn-nofeature-ha.yml
部署中的节点网络配置都在此文件进行描述,实际的硬件网络拓扑可以参看先前的Fuel部署,依旧是第一块网卡作为PXE,第二块网卡作为External网络,第三块网卡作为私有网络通信,承载存储、管理、虚机间通信等,需要注意的是以上的所有的网卡都可以合一,即最少一块网卡也能部署。下面的网络配置字面意思也很好理解,这里不做过多介绍了,详细介绍参考官方Configure network,PXE网络设置为10.20.0.0/24
(后续安装中发现管理网络也在这个网段),外网设置为192.168.20.0/24
,需要额外指明的是租户网络和存储网络配置的有vlan_tag,必须在交换机上配置好。
1 | opnfv@ubuntu:~/compass4nfv/deploy/conf/hardware_environment/bii-pod1$ cat network.yml |
该文件主要是电源管理以及针对各个节点的角色分配,详细介绍见官方Nodes Configuration (Bare Metal Deployment)
1 | opnfv@ubuntu:~/compass4nfv/deploy/conf/hardware_environment/bii-pod1$ cat os-nosdn-nofeature-ha.yml |
1) DNS及时区设置
考虑到网络等原因可以自定义DNS和时区,修改配置文件compass4nfv/deploy/conf/compass.conf
中的DNS和时区,同时在这里我们也可以看到compass的web界面的账号和密码
1 | export COMPASS_DECK_PORT="5050" |
访问安装节点的5050端口即可打开页面查看部署节点信息
2)docker镜像配置
compass在部署过程中会安装docker并下载相应镜像,可以配置国内源加速镜像下载
修改compass4nfv/deploy/prepare.sh
中的docker配置部分,增加中科大的docker镜像源或者其他源均可。(采用离线部署时所需的docker镜像都打包下载了,所以是否修改不影响)
1 | sudo cat << EOF > /etc/docker/daemon.json |
部署脚本为deploy.sh
文件,主要修改的地方节选如下
1 | Set OS version for target hosts |
本节会分析并记录部署中出现的问题以及排查解决办法。
进入节点的方法,首先进入到compass-tasks
容器中,然后直接使用ssh登录
1 | opnfv@ubuntu:~$ docker exec -it compass-tasks bash |
在后续的排错中也发现了节点可以使用密码登录,密码记录在compass4nfv/deploy/adapters/cobbler/kickstarts/default16.seed
中的root-password
一行,为user/passwd:root/root
。
【Note】
在后续部署中出现错误可以查看对应的ansible任务task,首先在compass4nfv/deploy/adapters/ansible
目录下查看对应的task
详细执行命令,其次在compass-tasks
的容器中的/etc/ansible
目录下查看。
我在安装过程中一直被ubuntu安装时的“setting up the clock”卡住,无法自动跳过,只能手动跳过,这个是ubuntu 16.04的一个bug,可能是跟配置网络的其他ntp服务器有关。
根据[2]修改系统安装时的prseed文件,屏蔽掉系统安装时的ntp检查,修改compass4nfv/deploy/adapters/cobbler/kickstarts
下的default16.seed
文件中的
d-i clock-setup/ntp boolean true
改成
d-i clock-setup/ntp boolean false
【Note】
Fuel部署工具使用的是Debian系的MAAS来进行无人值守安装系统(免费版可以安装ubuntu,但是安装centos则需要付费),而Compass4nfv使用的是RedHat系的kickstart和cobbler来进行无人值守部署系统,深入阅读可以查看KICKSTART无人值守安装
,Ubuntu系统批量自动安装或者其他相关资料。
由于ubuntu的本地源使用率较高,考虑到网络带宽以及资源复用的方面,可以在本地建立ubuntu源,ubuntu源的搭建可以参考我的之前文章MAAS+ubuntu私有源环境搭建。这里为了加快安装后系统的ubuntu软件安装,使用本地源进行软件安装。
主要修改的如下两个文件的仓库IP地址
1)compass4nfv/deploy/adapters/ansible/roles/config-compute/vars/main.yml
2)compass4nfv/deploy/adapters/ansible/roles/config-controller/vars/main.yml
LOCAL_REPOSITORY_IP: “192.168.137.222”
将IP地址修改为本地镜像仓库地址,Compass在部署过程中会去检测这个IP的连通性,若IP地址不通仍然使用ubuntu官方的镜像源地址,如文件compass4nfv/deploy/adapters/ansible/roles/config-controller/templates/sources.list.official
所示。
我的网络是带有IPv6,ubuntu在源更新时会优先走IPv6,但是IPv6网络无法更新(部署执行中报错,但是我登陆节点直接执行apt update
却能成功,目前原因未知)只能现行禁用apt源更新走IPv6[3].
解决方法1:
增加配置文件99force-ipv4
,加入Acquire::ForceIPv4 "true";
,配置文件放置在compass4nfv/deploy/adapters/ansible/roles/config-controller/files
随后在compass4nfv/deploy/adapters/ansible/roles/config-controller/vars/Ubuntu.yml
的任务中添加拷贝文件的命令
1 | - name: apt force IPv4 |
解决办法2:
使用alias在apt命令后增加-o Acquire::ForceIPv4=true
选项,修改compass4nfv/deploy/adapters/ansible/roles/config-controller/vars/Ubuntu.yml
,在name: add apt.conf
前添加
1 | - name: add apt-get alias |
【NOTE】
同时也能注意到compass/deploy/adapters/ansible/roles/config-compute/files/apt.conf
为了避免apt软件安装中出现[y/N]
这样的交互,采用以下参数来配置apt安装,相关资料链接传送门
APT::Get::Assume-Yes “true”;
APT::Get::force-yes “true”;
我在安装过程中出现无法ping通内网仓库IP的以及后续初始apt更新源失败的情况,原因是网卡重启后网络未连通导致,这里适当延长了网卡重启后的时间,修改compass4nfv/deploy/adapters/ansible/roles/config-controller/tasks/Ubuntu.yml
1 | - name: check apt source |
后续的安装中除了多次出现无法下载Openstack官方的Git仓库代码而报错外,并未遇到什么大的问题,而对于这个问题我暂时也没有太好的解决办法,只能进入容器内部尝试查看具体的网络错误原因。
compass4nfv在安装OPNFV采用的是lxc的容器安装的,会在每个节点生成对应服务的lxc容器,可以通过lxc-attach --name ctl02_repo_container-5df4d773
进入到容器进行查看。
1 | root@ctl02:/openstack/ctl02_repo_container-5df4d773/repo/openstackgit# lxc-ls |
同样的,会将openstack官方的稳定版代码下载到本地的/openstack/ctl02_repo_container-5df4d773/repo/openstackgit
对应项目目录下,而对应容器内部则是在/var/www/repo/opensatck
目录下。
1 | root@ctl02-repo-container-5df4d773:/var/www/repo/openstackgit# ls |
由于国内网络原因在ceph的安装过程中会由于网络不通或者下载过慢超时等出现ceph安装出错,这里修改ceph的源[4][5],可以选择的国内源有:
这里以阿里云的源为例,各大源只有rethat
系和debian
系两种分类,这里的ubuntu 16.04
使用的是debian-luminous
的版本,查看ctl
节点新增的apt源可以确认,后续随着安装使用的ubuntu版本升级会有所改变,需要灵活处理
1 | root@ubuntu:~# ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@10.20.0.51 |
安装的源码修改如下:
由于这部分操作是在容器compass-tasks
中操作的,可以在部署源码中添加修改,也可以在部署过程中直接在容器中修改
方法一:
1)新增文件
路径为compass4nfv/util/docker-compose/roles/compass/files/debian_community_repository.yml
1 | opnfv@ubuntu:~/compass4nfv/util/docker-compose/roles/compass/files$ cat debian_community_repository.yml |
2)增加ansible的task
修改文件compass4nfv/deploy/deploy_host.sh
,在export AYNC_TIMEOUT=20
后增加以下内容
1 | docker cp \ |
方法二:
由于部署ceph在靠后的阶段,因此可以在容器compass-tasks
起来后直接修改
1 | root@ubuntu:/home/opnfv/compass4nfv/deploy# docker exec -it compass-tasks bash |
依然是网络原因导致节点无法下载Hatop安装文件
1 | fatal: [ctl02 -> localhost]: FAILED! => {"changed": false, "failed": true, "msg": "Failed to connect to storage.googleapis.com at port 443: [ Errno 99] Cannot assign requested address"} |
可以预选下载Hatop放在本地的一个文件服务器上,直接修改compass-tasks
中/etc/ansible/roles/haproxy_server/defaults/main.yml
的haproxy_hatop_download_url
为自定义的文件服务器。
1 | root@ubuntu:~# docker exec -it compass-tasks bash |
或者跟3.3.5
节一样在文件compass4nfv/deploy/deploy_host.sh
,在export AYNC_TIMEOUT=20
后增加以下内容
1 | docker exec compass-tasks bash -c \ |
compass在部署时设定了超时时间为300分钟即5个小时,但是由于由内网络下载等原因会导致部署超时,出现如下错误
Traceback (most recent call last):
File “/home/opnfv/compass4nfv/deploy/client.py”, line 1136, in
main()
File “/home/opnfv/compass4nfv/deploy/client.py”, line 1131, in main
deploy()
File “/home/opnfv/compass4nfv/deploy/client.py”, line 1086, in deploy
client.get_installing_progress(cluster_id, ansible_print)
File “/home/opnfv/compass4nfv/deploy/client.py”, line 1029, in get_installing_progress
_get_installing_progress()
File “/home/opnfv/compass4nfv/deploy/client.py”, line 1026, in _get_installing_progress
raise RuntimeError(“installation timeout”)
RuntimeError: installation timeout
我在部署时其时长都会超过300分钟,因此这里加大部署超时时间,修改compass4nfv/deploy/conf/baremetal.conf
1 | export DEPLOYMENT_TIMEOUT="1000" |
compass部署过程中会从openstack的官方仓库下载稳定分支的代码用于部署,同样是国内网络的原因会出现clone失败的情况,如下所示当计数变为1时仍未下载完成就会部署失败。
2018-12-20 06:49:01,341 p=33580 u=root | FAILED - RETRYING: Wait for git clones to complete (1 retries left).
2018-12-20 06:49:06,574 p=33580 u=root | FAILED - RETRYING: Wait for git clones to complete (1 retries left).
2018-12-20 06:49:11,796 p=33580 u=root | FAILED - RETRYING: Wait for git clones to complete (1 retries left).
上述错误并不是每次都会出现,为了简单解决我选择将下载成功的代码打包备份到Master部署节点,随后在安装过程中拷贝至控制节点解压,需要等到控制节点上的,这里将拷贝和解压直接集成到部署代码中。ctl02_repo_container-xxxx
容器(由于ctl02是默认的主控制节点,因此只用传给ctl02即可)创建成功后才行
压缩代码,将repo
目录下的其他文件夹删除只留下openstackgit,随后将整个repo目录打包为repo.tar.gz
压缩代码(800M起)。
1 | root@ctl02:/openstack/ctl02_repo_container-10dffa61/repo# ls |
将repo.tar.gz
上传至master节点待用,修改部署脚本,在部署中首先将repo.tar.gz
拷贝到compass-tasks
容器中,随后游部署脚本将其拷贝到ctl02_repo_container-xxxxx容器中解压到/var/www
目录下
1)首先创建ansible任务,
1 | root@ubuntu:/home/opnfv/compass4nfv# cat deploy/adapters/ansible/customer/git_repo_pre.yml |
2)修改部署脚本
在文件compass4nfv/deploy/deploy_host.sh
,在export AYNC_TIMEOUT=20
后增加以下内容
1 | git repo |
打开文件deploy/adapters/ansible/roles/config-compute/templates/ifcfg-br-external
,修改dns配置即可,比如使用国内阿里云的dns,同理修改控制节点文件
1 | DNS1=223.5.5.5 |
2018-12-21 02:46:31,836 p=4989 u=root | FAILED - RETRYING: Ensure image has been pre-staged (1 retries left).
2018-12-21 02:46:36,923 p=4989 u=root | FAILED - RETRYING: Ensure image has been pre-staged (1 retries left).
2018-12-21 02:46:37,015 p=4989 u=root | FAILED - RETRYING: Ensure image has been pre-staged (1 retries left).
2018-12-21 02:46:37,017 p=4989 u=root | FAILED - RETRYING: Ensure image has been pre-staged (1 retries left).
又是一个网络引起的部署错误,每次部署都会去下载最新的ubuntu lxc
镜像,由于网络原因,有时能够下载成功,有时下载失败,如图所示的小水管,虽然只有70M,但是也会出现无法在限定时间300s内下载完成
这里使用清华源的lxc镜像,其会自动同步LXC官方镜像,并保持相同的链接格式(对链接格式感兴趣的可以看3.3.10.1小节),镜像地址在compass-tasks
镜像的/etc/ansible/roles/lxc_hosts/defaults/main.yml
第160行。
由于部署工具会依据官方的镜像列表筛选出符合要求的最新镜像,
1 | aria2c --max-connection-per-server=4 --allow-overwrite=true --dir=/tmp --out=index-system --check-certificate=true https://mirrors.tuna.tsinghua.edu.cn/lxc-images/meta/1.0/index-system |
这里在容器启动后修改,同样是修改文件compass4nfv/deploy/deploy_host.sh
,在export AYNC_TIMEOUT=20
后增加以下内容。
1 | docker exec compass-tasks bash -c \ |
修改后的测试,如图所示,直接从80K/s飙到了9.4M/s
1 | aria2c --max-connection-per-server=4 --allow-overwrite=true --dir=/tmp/test --out=rootfs.tar.xz --check-certificate=true https://mirrors.tuna.tsinghua.edu.cn/lxc-images/images/ubuntu/xenial/amd64/default/20190106_07:43/rootfs.tar.xz |
由于LXC官方会更新最新的镜像,因此下载的链接会稍有不同,LXC镜像链接:Linux Containers - Image server
以ubuntu;xenial;amd64;default;20190106_07:43;
为例,其下载链接组成为ubuntu/xenial/amd64/default/20190106_07:43
,完整的下载地址为:
https://us.images.linuxcontainers.org/images/ubuntu/xenial/amd64/default/20190106_07:43/rootfs.tar.xz
在安装的后期阶段由于external网络从linux bridge切换到ovs会出现lxc容器无法连接网络而导致安装失败,这里采用lxc网络自检工具定时检测网络状态,在lxc容器创建完成后,分别在三个控制节点添加定时任务
1 | root@ctl02:~# crontab -e |
亦可以修改部署脚本自动添加lxc veth网卡检查
compass4nfv/deploy/adapters/ansible/custome/lxc_veth_check.yml
,写入如下内容1 | - name: Add lxc veth check cron job |
lxc_veth_check.yml
并增加ansible部署修改compass4nfv/deploy/deploy_host.sh
,在export AYNC_TIMEOUT=20
后增加以下内容
1 | lxc veth check |
在费劲千辛万苦终于安装好OPNFV后下面要面对的就是如何使用,可以参考compass的使用手册[6]
根据之前network.yml
中配置的public_vip
地址进行访问即可,账号密码在控制节点的openrc
文件中,选择一个控制节点即可看到,如果没有可以去容器ctl02_utility_container-xxxx
中查看
1 | root@ctl02:~# ls |
【未完待续】
5)ceph国内源
]]>最近由于工作需要,要写一篇RFC draft,谨以此文记录一下过程中查到的资料以及相关工作。
在通信和计算机行业一谈到标准提到最多的就是RFC,没接触RFC之前一直不明白RFC到底是什么。RFC的英文是“Request for Comments”,即“请求建议”,当某家机构或团体开发出了一套标准或提出对某种标准的设想,想要征询外界的意见时,就会在Internet上发放一份RFC,对这一问题感兴趣的人可以阅读该RFC并提出自己的意见;绝大部分网络标准的指定都是以RFC的形式开始,经过大量的论证和修改过程,由主要的标准化组织所指定的,但在RFC中所收录的文件并不都是正在使用或为大家所公认的,也有很大一部分只在某个局部领域被使用或并没有被采用,一份RFC具体处于什么状态都在文件中作了明确的标识。
IETF互联网工程任务小组(英语:Internet Engineering Task Force)负责互联网标准的开发和推动。它的组织形式主要是大量负责特定议题的工作组,每个都有一个指定主席(或者若干副主席)。工作组再用主题组织为领域(area);每个领域都有一个领域指导(area director,AD),大多数领域还有两个副AD;AD任命工作组主席。AD和IETF主席构成Internet Engineering Steering Group(IESG),负责IETF的整体运作。[1]
关于IETF的更多详细介绍可以查看《IETF之道》[2][3],里面详细介绍了IETF的运作及相关组织架构。下面摘录一下专业术语如下:
术语 | 含义 | Meaning |
---|---|---|
AD | 领域负责人 | Area Director |
BCP | 当前最佳实践 | Best Current Practice |
BOF | 专题讨论会 | Birds of a Feather |
FAQ | 常见问题 | Frequently Asked Question(s) |
FYI | 仅供参考(RFC) | For Your Information (RFC) |
IAB | 互联网架构委员会 | Internet Architecture Board |
IAD | IETF行政主管 | IETF Administrative Director |
IANA | 互联网号码分配机构 | Internet Assigned Numbers Authority |
IAOC | IETF行政监督委员会 | IETF Administrative Oversight Committee |
IASA | IETF行政支持活动 | IETF Administrative Support Activity |
ICANN | 互联网名称与数字地址分配机构 | Internet Corporation for Assigned Names and Numbers |
I-D | 互联网草案 | Internet-Draft |
IESG | 互联网工程指导组 | Internet Engineering Steering Group |
IETF | 互联网工程任务组 | Internet Engineering Task Force |
IPR | 知识产权 | Intellectual property rights |
IRTF | 互联网研究任务组 | Internet Research Task Force |
ISOC | 互联网协会 | Internet Society |
RFC | IETF正式发布的文稿名称 | Request for Comments |
STD | 标准(RFC) | Standard (RFC) |
WG | 工作组 | Working Group |
在撰写RFC之前需要先了解一下RFC的流程,首先需要撰写一个符合IETF格式的文档xml、txt、pdf格式都可以,但是推荐使用xml格式,后续借助xml2rfc能够更好的转换成标准格式草案。
RFC处理过程:一个RFC文件在成为官方标准前一般至少要经历三个阶段:建议标准、草案标准、因特网标准。
第一步RFC的出版是作为一个Internet草案发布,可以阅读并对其进行注释。准备一个RFC草案,我们要求作者先阅读IETF的一个文档”Considerations for Internet Drafts”. 它包括了许多关于RFC以及Internet草案格式的有用信息。作者还应阅读另外一个相关的文档RFC 2223 “Instructions to Authors”一旦文档有了一个ID号后,你就可以向rfc-editor@rfc-editor.org发送e-mail,说你觉得这个文档还可以,能够作为一个有价值或有经验的RFC文档。RFC编辑将会向IESG请求查阅该文档并给其加上评论和注释。你可以通过RFC队列来了解你的文档的进度。一旦你的文档获得通过,RFC编辑就会将其编辑并出版。如果该文档不能出版,则会有email通知作者是什么原因。作者有48个小时来校对RFC编辑的意见。我们强烈建议作者要检测拼写错误和丢字的错误,应该确保有引用,联系和更新相关的信息。如你的文档是一个MIB,我们则要你对你的代码作最后一次检测。一旦RFC文档出版,我们就不会对其进行更改,因此你应该对你的文档仔细的检查。有时个别的文档会被正从事同一个项目的IETF工作组收回,如是这种情况,则该作者会被要求和IETF进行该文档的开发。在IETF中, Area Directors (ADs) 负责相关的几个工作组。这些工作者所开发的文档将由ADs进行校阅,然后才作为RFC的出版物。如要获得关于如何写RFC文档和关于RFC的Internet标准制定过程的更多详细信息,请各位参见:RFC 2223 “Instructions to RFC Authors”。
流程图如下:
撰写草案并希望草案成为IETF标准的人必须阅读BCP9,以便能够跟进其文档在整个过程中的进展情况。您可以在IETF Datatracker上跟踪文档进展情况,网址为http://datatracker.ietf.org。 BCP9(以及对它进行更新的各种其他文档)对常常被人误解、甚至是被资深IETF参与者误解的话题进行详细论述: 不同类型的RFC将经历不同的流程并有不同的排名。有六种RFC:
英文 | 中文 |
---|---|
Proposed standards | 建议的标准 |
Internet standards (sometimes called “full standards”) | 互联网标准(有时称为“完全标准”) |
Best current practices (BCP) documents | 当前最佳实践 (BCP) 文档 |
Informational documents | 信息性文档 |
Experimental documents | 实验性文档 |
Historic documents | 历史性文档 |
[NOTE]Only the first two, proposed and full, are standards within the IETF. A good summary of this can be found in the aptly titled [RFC 1796], “Not All RFCs Are Standards”.
[备注]只有前面两种标准(建议的标准和完全标准)属于IETF内的标准。在题为《并非所有RFC都是标准》RFC 1796的文档中可找到相关摘要。
撰写一篇标准的IETF draft除了需要对想要撰写的Draft内容有规划外还需要了解Draft提交的标准格式,但是其相关内容繁杂且啰嗦(如果想优雅的撰写一篇RFC Draft请参阅如何优雅的撰写一篇RFC Dratf),本着太长不看原则,这里使用简单“粗暴”的方式完成一篇标准格式的Draft就是接下来要介绍的(ps.这里的粗暴仅只将Draft格式转换为IETF的RFC格式)
首先需要参照标准的RFC格式自行完善想要写的RFC draft内容可以是word格式,主要包括:摘要(Abstract)、说明(Introduction)、正文(Content)、引用(Reference)、作者信息(Author’s Address)、致谢(Acknowledgement)等。需要额外指出的是作图必须用ASCII码的形式画图,内容必须是全英文,尤其是标点符号这点会在xml转换成rfc时尤为重要。
选择一份RFC draft的xml格式作为模板将写好的文档套用进去,如使用draft-wang-nfvrg-network-slice-diverse-standards-00.xml,将其保存在本地,推荐使用notepad++
或者sublime txt
打开,当然如果你熟练使用记事本
也没问题,关于xml格式的官方说明见RFC7749,下面做简要说明。
以下部分为xml模板头文件,除了文档名docName
其他不需要更改。
1 |
|
Draft的命名遵循如下的格式
draft name: draft-’authorname’-‘groupname’-‘drafttopic’-‘version’.xml
(example: draft-long-nfvrg-nfv-decoupling-test-00.xml
-
间隔00
,随着后续的改进,版本号逐次增加作者的信息,如下所示基本都是正常填空即可
1 | <author fullname="xxx" initials="Y." surname="Long"> |
效果图
文档信息包括:
1 | <date day="26" month="Dec" year="2018"/> |
<middle>xxxx </middle>
格式<section>xxx</section>
格式即可,多级标题直接嵌套即可<t>xxx</t>
的格式,保证tag闭合即可<xref target="ETSI_NFV_GS_002"/>
,需要指出的是参考文献需要显示列出该参考文献信息,否则会在xml转rfc时出现warnning
列表格式如下所示,使用<list> </list>
标签
1 | <t><list style="symbols"> |
效果图
对于列表的格式使用style
标签,可选参数有
“empty”
For unlabeled list items; it can also be used for indentation purposes (this is the default value when there is an enclosing list where the style is specified).
“hanging”
For lists where the items are labeled with a piece of text.
The label text is specified in the “hangText” attribute of the <t> element (Section 2.38.2).
“letters”
For ordered lists using letters as labels (lowercase letters followed by a period; after “z”, it rolls over to a two-letter format). For nested lists, processors usually flip between uppercase and lowercase.
“numbers”
For ordered lists using numbers as labels.
“symbols”
For unordered (bulleted) lists.
The style of the bullets is chosen automatically by the processor (some implementations allow overriding the default using a Processing Instruction).
2.3.1.7 图示格式
图例格式如下所示,采用<figure> </figure>
标签,配合<artwork></artwork>
CDATA表示直接显示的数据
1 | <t><figure align="center"> |
效果图
2.3.1.8 表格格式
表格格式如下所示,采用<texttable> </texttable>
标签,标题使用<ttcol> </ttcol>
,单元格使用<c> </c>
1 | <texttable align="center"> |
效果图
正文后的标签<back></back>
,填写引用文献信息,文献的格式参见Reference Examples,需要给出文章名、作者、时间等信息。
1)RFC文档引用方式
如果是标准的RFC文献可以使用官方参考直接导出。
格式如下
1 | include="https://www.rfc-editor.org/refs/bibxml/reference.RFC.8174.xml" rfc |
效果图
2)非RFC文档引用
非RFC文档需要手动填写相关信息,如下所示
1 | <reference anchor="ETSI_GS_NFV_002" target="https://www.etsi.org/deliver/etsi_gs/NFV/001_099/002/01.02.01_60/gs_NFV002v010201p.pdf"> |
效果图
2.3.1.8 其他注意事项
转义符,文章中出现的如下字符必须转义,否则在转换过程中或出错,注意字符后的;
也是需要的
转义后字符 | 转义前字符 |
---|---|
& 或 & | & |
< 或 < | < |
> 或 > | > |
" | “ |
| 空格 |
© | 版权符 © |
® | 注册符 ® |
【Note】其中<和>最常用,对于I-D内容中包含的xml元素时,需要对<和>进行转义。 |
还有最重要的是务必不要出现中文字符,在后续检测中报错的很大一部分问题出在未知的中文标点符号中。
在完成以上步骤后,需要进行xml转rfc检测,检测过后的xml格式才能提交,简单点的是使用线上的xml2rfc工具进行debug测试
如果出现问题就看debug信息,最基本的错误是tag没有闭合,中文字符,引用错误等。
如果转换没有问题,则可以提交审阅了,链接:Internet-Draft submission
想要优雅的撰写Draft,你只需要仔细阅读以下文献即可
2)IETF之道中文
]]>使用Hexo一年多了,页面样式主题都是好久之前的一直没有更改过。闲来想换换新货,体验下新的代码,同时加入一些羡慕已久的页面特效,本文记录一下升级的过程。以一个新建立的blog开始记录,至于Hexo的安装则跳过了。
为了记录自定义的修改这里预先建立的一个blog的git仓库,方便记录修改的地方。
使用Hexo命令建立一个初始blog,随后加入到仓库中。
1 | louie@ubuntu:~/workplace$ hexo init blog |
下载主题,这里使用next主题,使用v6.1.0的版本方便后续升级也便于记录修改起始的版本。
1 | louie@ubuntu:~/workplace/blog/themes$ git clone --branch v6.1.0 https://github.com/theme-next/hexo-theme-next.git next |
Next 主题官网更新后给出了一波自定义教程,总结的非常全面,可以直接参考官方的配置:传送门
_config.yml
修改默认主题
1 | # Site |
设置网站图标,在souce目录下创建一个uploads目录(因为next搜索指定了目录路径),将图片等都放置在这个目录同一管理。修改next主题的配置文件themes/next/_config.yml
,avatar为图像图片,favicon为网站icon图片 ,推荐一个好用的ico 制作网站。apple和safari的像素要高许多可以参考原主题ico大小。
favicon:
small: /uploads/favicon-16x16.ico
medium: /uploads/favicon-32x32.ico
apple_touch_icon: /uploads/favicon-48x48.ico
safari_pinned_tab: /uploads/favicon-48x48.icoavatar: /uploads/shadian.png
blog首页底部的版权信息,直接修改themes/next/_config.yml
的footer
内容
1 | footer: |
根据需求自行修改,英文也很简单易懂^-^。
创建标签、关于、分类、归档等页面,只需要调用hexo的命令在blog/source
目录下生成指定的目录文件即可
1 | hexo new page "tags" |
随后即会在source目录下生成相应的目录及文件,修改对应的文件如about/index.md
,将comments设为false
,禁止在该页面进行评论。
1 | cat categories/index.md |
设置完成后可以通过hexo g
和hexo s
进行效果查看,这里不再赘述了。同时需要在主题中打开相应的开关themes/next/_config.yml
about: /about/ || user
tags: /tags/ || tags
categories: /categories/ || th
archives: /archives/ || archive
commonweal: /404/ || heartbeat
安装相关插件,可以看到package.json
中的信息有修改,显示新加入的插件
1 | npm install --save hexo-generator-index |
修改全局配置文件blog/_config.yml
,增加以下内容
index_generator:
per_page: 10archive_generator:
per_page: 20
yearly: true
monthly: truetag_generator:
per_page: 10
其中per_page
字段是期望每页显示的篇数。index
, archive
及tag
开头分表代表主页,归档页面和标签页面。
Next主题集成了Word Count 功能,首先安装插件
1 | npm install hexo-symbols-count-time --save |
插件主要功能:
安装完插件后仅需要修改根配置文件blog/_config.yml
即可
symbols_count_time:
symbols: true
time: true
total_symbols: true
total_time: true
Next主题支持Google、Algolia、Swiftype三种搜索,这里选用Algolia搜索。设置方式也很多,随便搜一下就可以找到。首先需要到Algolia官网进行注册,然后获得API Key填入根配置文件中。
参考Algolia GitHub链接,安装algolia插件
1 | npm install --save hexo-algolia |
在blog/_config.yml
配置文件添加如下信息
algolia:
applicationID: ‘Application ID’
apiKey: ‘Search-only API key’
indexName: ‘indexName’
chunkSize: 5000
将Application ID
、Search-only API key
以及indexName
都替换成自己的信息。同时需要将next主题中algolia搜索开关打开
algolia_search:
enable: true
执行下述命令
1 | export HEXO_ALGOLIA_INDEXING_KEY=Search-Only API key # Use Git Bash |
开启主题的摘要功能,length
表示显示摘要的截取字符串长度。
auto_excerpt:
enable: true
length: 150
如图所示的效果,看起来很酷炫
参考leanclond next配置指南,首先安装leanclound
插件
1 | npm install hexo-leancloud-counter-security --save |
这里需要用到leancloud,注册及配置查考链接:传送门,首先注册账号,经过注册创建应用等过程后拿到key填入到next主题中
leancloud_visitors:
enable: true
app_id: M8d5yPXQ5l0kwFz1bO6cF***
app_key: QEarlHm5c8XcuF22*****
将统计结果修改为热度,修改themes/next/languages/zh-CN.yml
文件中post
段中view
中文翻译为热度
。
打开themes/next/layout/_macro/post.swig
搜索leancloud-visitors-count
字段,添加<span>sheshid</span>
后续还有一些关于Leanclound的设置,为节省篇幅,请直接访问:传送门
全站访客统计使用不蒜子,在themes/next/layout/_partials/footer.swig
中添加如下内容。
1 | <script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"> |
修改文件themes/next/layout/_macro/post.swig
,找到rel="tag">#
,将#
替换为<i class="fa fa-tag"></i>
即可。
1)添加“本文结束”标记
效果图:
创建文件themes/next/layout/_macro/passage-end-tag.swig
,填入一下内容
1 | {% if not is_index %} |
随后修改themes/next/layout/_macro/post.swig
,在``之前添加
1 | {% if not is_index %} |
2)添加文末版权声明
效果如下
在themes/next/layout/_macro/
生成一个custome-cc.swig
文件,填入一下内容
1 | {% if not is_index %} |
需要在source/uploads
下上传图片如下
同样修改themes/next/layout/_macro/post.swig
,在post-footer
之前添加
1 | <div> |
next主题集成了集中动态背景效果,如下所示
1) canvas_nest
next 5.1.1以上可以直接在主题配置文件中将canvas_nest: false
改成canvas_nest: true
,随后下载动态背景js即可
参考链接:传送门
下载代码带主题的lib库中
1 | git clone https://github.com/theme-next/theme-next-canvas-nest themes/next/source/lib/canvas-nest |
随后使能canvas_nest
即可,随后生成看效果,有几个参数可以自己修改themes/next/source/lib/canvas-nest/canvas-nest.min.js
参数 | 含义 |
---|---|
zIndex | 背景的z-index属性,css属性用于控制所在层的位置,默认:-1 |
opacity | 线条透明度(0~1), 默认:0.5 |
color | 线条颜色, 默认: ‘0,0,0’;三个数字分别为(R,G,B) |
count | 线条的总数量, 默认: 99 |
2) 3-D 效果
参考链接:传送门
同样是下载相应的js脚本开启开关即可,非常简单
1 | git clone https://github.com/theme-next/theme-next-three themes/next/source/lib/three |
随后只需要开启单个效果开关
1 | # JavaScript 3D library. |
修改themes/next/source/css/_custom/custom.styl
,在末尾添加如下css样式
1 | // 文章内链接文本样式 |
颜色可以自定义修改。
修改themes/next/source/css/_custom/custom.styl
,添加以下内容
1 | // Custom styles. |
修改themes/next/source/css/_custom/custom.styl
,添加以下内容
1 | // 主页文章添加阴影效果 |
打开主题配置文件themes/next/_config.yml
,搜索Social
,在图标库找自己喜欢的小图标,并将名字复制在||
之后即可。
GitHub: https://github.com/louielong || github
next的主题中已经预置的相关配置,仅仅只需要打开相应的开关并下载lib库即可,方法参见:pace特效传送门
克隆代码带主题的lib库中
1 | git clone https://github.com/theme-next/theme-next-pace themes/next/source/lib/pace |
随后修改themes/next/_config.yml
,将pace: false
改为pace: true
,然后选择满意的特效选项即可。
pace_theme: pace-theme-flash
仅需要开启打赏功能并上传二维码即可
修改themes/next/_config.yml
中的Reward
字段下开启一个标签,并上传图二维码至source/uploads
或者themes/next/source/images
目录下,并相应的修改路径即可。
开启后发现打赏字体闪动很频繁碍眼,可以注释掉,themes/next/source/css/_common/components/post/post-reward.styl
,如下注释掉或者修改 roll后的参数值,降低闪动频率。
1 | /* 注释文字闪动函数 |
安装RSS订阅插件
1 | npm install --save hexo-generator-feed |
搜索rss
字样,添加rss: /atom.xml
,重新hexo g
生成一遍即可。
本来想添加SEO加速搜索的,但是登录到百毒上一看需要这么多信息,果断放弃了,顺带给一个鄙视的眼神。
当新创建文章是希望可以默认生成一些头部字段,修改scaffolds/post.md
文件增加一些自定义填充字段。
1 | --- |
使用hexo new test
创建文章时则会自动填充相应信息,如下图所示
若想在主页显示文章的总结图片,在themes/next/layout/_macro/post.swig
中的post.description
前加入如下内容
1 | {% if post.summary_img %} |
重新生成博客即可看到文章缩略图。
博客的字体配置在themes/next/_config.yml
找到Font Settings
,修改对应字段可以配置相应的字体效果。默认使用的是谷歌的字体。
如我想修改代码段的字体格式
1 | # Font settings for <code> and code blocks. |
Next的Mist主题默认隐藏了副标题的显示,通过修改themes/next/source/css/_schemes/Mist/_logo.styl
可以打开副标题的显示。
1 | .site-subtitle { display: yes; } |
修改Next主题文件themes/next/source/css/_schemes/Mist/_posts-expanded.styl
,找到.posts-expand
中的.post-body img
加入auto
字段。
1 | .post-body img { margin: 0, auto; } |
在themes/next/source/js/src
下新建文件clicklove.js
,随后将链接下的代码拷贝粘贴到clicklove.js
文件中
在themes/next/layout/_layout.swig
文件末尾添加:
1 | <!-- 页面点击小红心 --> |
统一修改next预留的自定义文件themes/next/source/css/_custom/custom.styl
1)静态图片
1 | body { |
设置静态背景图片
2)动态图片
unsplash网站提供大量高清图片,可随机选择
1 | body { |
不透明度设定
1 | .main-inner { |
给侧边栏添加背景图片,只需要修改themes/next/source/css/_common/components/sidebar/sidebar.styl
的background
的值即可,同时为了让图片平铺可以增加一些设置。同样的,图片可以是在线的也可以是本地。
1 | background: url('/uploads/sidebar.jpg'); |
【Note】
由于使用的黑色的背景,这里将侧边栏的字体设置为白色,需要修改一些配置文件
1)themes/next/source/css/_common/components/sidebar/sidebar-toc.styl
的Line 23,此处影响的是文章目录
字体颜色
1 | color: $whitesmoke; |
2)修改themes/next/source/css/_variables/base.styl
的 line 265,此处影响的是站点概览
的字体颜色
1 | $sidebar-nav-color = $whitesmoke |
MySQL复制中较常见的复制架构有“一主一从”、“一主多从”、“双主”、“多级复制”和“多主环形机构”等,在项目实施中遇到需要进行故障转移的需求:两台服务器每台都安装MySQL,当一个MySQL服务器故障时另一个MySQL服务器能够继续提供服务,这要求两个MySQL之间能够进行数据复制同时需要监控两台服务器的状态。
本次使用MySQL的双主复制以及keepalived的HA机制来实现。
两台服务器:
服务器MySQL-HA-1(主) 192.168.10.101
服务器MySQL-HA-2(主) 192.168.10.102
虚拟服务节点IP 192.168.10.103
Mysql版本:mysql Ver 14.14 Distrib 5.7.21
System OS:ubuntu 16.04
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件。
MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言[1]。
1 | apt install -y mysql-server |
【Tips】:安装过程需要输入数据库密码,出于后续部署的自动化考虑,希望自动化部署中不被打断,解决这个问题有两种方法:
1) 预先设置密码
使用debconf-set-selections
工具预先将密码写入
1 | sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password your_password' |
将your_password
替换为想要设置的mysql root账户密码,针对不同的mysql版本会有相应的改变,参见传送门
2)静默安装
使用如下命令通过非交互的方式静默安装mysql
1 | sudo DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server |
在安装完成后mysql是没有密码的,root用户下是可以免密进入命令行的,然后再修改mysql的root用户访问密码
1 | mysql -uroot -e"SET PASSWORD FOR 'root'@'localhost' = PASSWORD('passwd');" |
将passwd
替换为自己的密码即可。
3.2 数据库初始化配置
在修改配置前最好先备份mysql配置文件
1 | cp /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/mysql.conf.d/mysqld.cnf-bak |
1)设置时区
在mysqld.cnf
的[mysqld]
后加入default-time-zone = '+8:00'
1 | sed -i "/^\[mysqld\]/a\default-time-zone = \'+8:00\'" /etc/mysql/mysql.conf.d/mysqld.cnf |
设置需要同步的数据库,此处以数据库test
为例
1)修改MySQL-HA-1服务器数据库配置
主要修改的地方如下
1 | bind-address= :: # 指定允许数据库访问的IP,"::"表明允许v4和v6访问 |
完整的配置文件如下,这里将原配置文件的注释屏蔽掉
1 | root@HA-1:~# cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep -v '#' |
其他参数含义可参考mysql配置文件详解
2)修改MySQL-HA-2服务器数据库配置
修改HA-2节点的数据库配置文件,大致内容一致,只是在server-id
和auto-increment-increment
需要修改。
1 | root@HA-2:~# cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep -v '#' |
修改完成后两个节点的数据库都需要重启
1 | service mysql restart |
【Note】
为了提升数据库的写入性能,可以适当修改同步数据间隔,加入以下参数[4]
1 | innodb_flush_log_at_trx_commit=2 |
有关两个参数的含义可以查看链接:传送门
1)将HA-1设置为HA-2的主数据库
首先在HA-1节点数据库创建同步账户
1 | root@HA-1:~# mysql -uroot -p |
随后查看数据库状态信息
1 | mysql> show master status; |
记录下File
和Position
两个参数值,这是数据库主从同步的关键,也是告诉从数据自那哪个起点开始同步
在HA-2节点的数据库输入以下信息,切记是在HA-2节点输入
1 | mysql> change master to master_host='192.168.10.101',master_user='sync',master_password='sync',master_log_file='mysql-bin.000001',master_log_pos=465; |
随后在HA-2节点开启从机同步即可
1 | start slave |
然后在HA-2节点查看mysql的slave信息,确保下述两个值为yes
Slave_IO_Running:Yes
Slave_SQL_Running:Yes
1 | show slave status\G; |
2)将HA-2设置为HA-1的主数据库
设置过程与上一步一致,首先创建同步账户随后添加主数据库信息,需要注意的是IP地址的修改
在HA-2上创建同步账户
1 | root@HA-2:~# mysql -uroot -p |
随后查看数据库状态信息
1 | mysql> show master status; |
记录下File
和Position
两个参数值,这是数据库主从同步的关键,也是告诉从数据自那哪个起点开始同步
在HA-1节点的数据库输入以下信息,切记是在HA-1节点输入
1 | mysql> change master to master_host='192.168.10.102',master_user='sync',master_password='sync',master_log_file='mysql-bin.000001',master_log_pos=465; |
随后开启HA-1的从机同步
1 | start slave |
然后在HA-1节点查看mysql的slave信息,确保下述两个值为yes
Slave_IO_Running:Yes
Slave_SQL_Running:Yes
1 | show slave status\G; |
【Note】:
若因为输入错误或网络变动等其他原因导致同步出错需要先停止同步
1 | stop slave |
然后重置从机同步
1 | reset slave |
再重复上述的主从同步配置,但需要注意的是主从同步并不会同步原来的数据,只会同步从当前时刻起始的binlog的数据库操作记录,如果同步中断后仍有数据写入会导致两个数据库的数据起始内容不一致,这时需要先停止数据库写入
1 | mysql> LOCK TABLES; |
然后备份出数据库
1 | mysqldump -uroot -p<passwd> <table> > mysql_table_bak.sql |
先drop table <tablename>
再将数据导入到另一台数据库服务器中
1 | mysql -uroot -p<passwd> <table> < mysql_table_bak.sql |
在配置完主从同步后解锁表
1 | mysql> UNLOCK TABLES |
在HA-1节点创建一个数据库test
1 | mysql> create database test; |
查看HA-2主机是否同步了HA-1上的数据变化
1 | mysql> show databases; |
可以看出HA-2节点的数据库同步了HA-1节点的数据库,在配置成双主复制后任一节点数据库发生改变另一节点数据库都会进行同步。
在配置完成数据库后若想对数据库进行访问只能访问单一节点数据库的IP,如果希望访问一个固定IP让数据库并能够实现故障自动切换就需要配合keepalived或者HAproxy进行代理。
Keepalived软件起初是专为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点的状态,后来又加入了可以实现高可用的VRRP功能。因此,Keepalived除了能够管理LVS软件外,还可以作为其他服务(例如:Nginx、Haproxy、MySQL等)的高可用解决方案软件。
Keepalived软件主要是通过VRRP协议实现高可用功能的。VRRP是Virtual Router RedundancyProtocol(虚拟路由器冗余协议)的缩写,VRRP出现的目的就是为了解决静态路由单点故障问题的,它能够保证当个别节点宕机时,整个网络可以不间断地运行。
所以,Keepalived 一方面具有配置管理LVS的功能,同时还具有对LVS下面节点进行健康检查的功能,另一方面也可实现系统网络服务的高可用功能。
这里借用博客[4]的有关keepalived的集群工作原理示意图
Keepalived高可用对之间是通过 VRRP进行通信的, VRRP是遑过竞选机制来确定主备的,主的优先级高于备,因此,工作时主会优先获得所有的资源,备节点处于等待状态,当主挂了的时候,备节点就会接管主节点的资源,然后顶替主节点对外提供服务。
在 Keepalived服务对之间,只有作为主的服务器会一直发送 VRRP广播包,告诉备它还活着,此时备不会枪占主,当主不可用时,即备监听不到主发送的广播包时,就会启动相关服务接管资源,保证业务的连续性.接管速度最快可以小于1秒。
安装方式分为两种:apt直接安装和手动编译安装
1)手动编译安装
手动编译的好处是可以使用较新的源码,首先下载源码
1 | wget http://www.keepalived.org/software/keepalived-1.4.2.tar.gz |
安装必要的编译包
1 | apt-get install -y gcc build-essential make curl libssl-dev libnl-3-dev libnl-genl-3-dev libsnmp-dev |
配置编译,prefix指明需要安装在哪里,也可以不配置使用默认路径
1 | tar xf keepalived-1.4.2.tar.gz |
配置完成后直接编译二连make
和make install
即可
2) apt安装
1 | apt install keepalived |
keepalived服务安装完成之后,后面的主要工作就是在keepalived.conf文件中配置HA和负载均衡。一个功能比较完整的常用的keepalived配置文件,主要包含三块:全局定义块、VRRP实例定义块和虚拟服务器定义块。全局定义块是必须的,如果keepalived只用来做ha,虚拟服务器是可选的。下面数据库HA的配置文件模板:
HA-1主机上的keepalived.conf文件的修改:
1 | root@HA-1:~# cat /etc/keepalived/keepalived.conf |
创建脚本存放目录
1 | root@HA-1:~# mkdir -p /etc/keepalived/bin |
1)keepalived状态脚本
创建脚本/etc/keepalived/bin/kpad_notify.sh
内容如下
1 | root@HA-1:~# cat /etc/keepalived/bin/kpad_notify.sh |
设置脚本运行权限
1 | root@HA-1:~# chmod +x /etc/keepalived/bin/kpad_notify.sh |
2)配置mysql健康检查脚本
编辑/etc/keepalived/bin/chk_mysql.sh
脚本内容如下,脚本的大致思路是如果在master和backup状态下mysqld进程不存在则尝试重启mysql,若重启失败则任务该节点的mysql彻底故障,进行故障转移。
1 |
|
然后执行
1 | root@HA-1:~# chmod +x /etc/keepalived/bin/chk_mysql.sh |
随后重启keepalived服务
1 | root@HA-1:~# service keepalived restart |
基本配置个HA-1节点上一样,两个健康监测脚本完全一致,不同的是keepalived.conf脚本中权重值和节点初始属性
1 | root@HA-2:~# cat /etc/keepalived/keepalived.conf |
在拷贝/etc/keepalived/bin/kpad_notify.sh
和/etc/keepalived/bin/chk_mysql.sh
两个脚本后重启keepalived服务
1 | root@HA-2:~# service keepalived restart |
在HA-1和HA-2分别执行ip addr show dev enp0s9命令查看HA-1和HA-2对VIP(群集虚拟IP)的控制权。HA-1主的查看结果:
1 | root@HA-1:~# ip addr show dev enp0s9 |
可以看到生成了192.168.10.101这个虚拟IP。
停止HA-1的keepalived服务,HA-2将会成为新的主节点,HA-2主的查看结果:
1 | root@HA-2:~# ip addr show dev enp0s9 |
可以看到生成了192.168.10.103这个虚IP。
MySQL远程登录测试:
1 | root@HA-2:~# mysql -h192.168.10.103 -uroot -p |
说明在客户端访问VIP地址,由HA-2主机提供响应的,当前状态下HA-2充当主服务器。
【Note】
经过测试在纯IPv6的环境下上述HA依然可以正常运行。
【参考链接】
1)mysql介绍
]]>在建立Linux主机集群时,为了避免集群主机时间不同以及长时间运行下所导致的时间偏差,需要进行时间同步(synchronize)。Linux系统下,一般使用ntp服务来同步不同机器的时间。NTP(Network Time Protocol)即网络时间协议,就是通过网络协议使计算机之间的时间同步化。
时间同步方式
NTP在linux下有两种时钟同步方式,分别为直接同步和平滑同步[1]:
使用ntpdate命令进行同步,直接进行时间变更。如果服务器上存在一个12点运行的任务,当前服务器时间是13点,但标准时间时11点,使用此命令可能会造成任务重复执行。因此使用ntpdate同步可能会引发风险,因此该命令也多用于配置时钟同步服务时第一次同步时间时使用,如:系统重启时。
使用ntpd进行时钟同步,可以保证一个时间不经历两次,它每次同步时间的偏移量不会太陡,是慢慢来的,这正因为这样,ntpd平滑同步可能耗费的时间比较长。对ntp时间同步修正原理感兴趣的可以查看官方文档:How NTP Works
时钟的跃变,对于某些程序会导致很严重的问题。许多应用程序依赖连续的时钟,取得的时间是线性的,一些操作,例如数据库事务,通常会地依赖这样的事实:时间不会往回跳跃。不幸的是,ntpdate调整时间的方式就是我们所说的”跃变“:在获得一个时间之后,ntpdate使用settimeofday(2)设置系统时间,这有几个非常明显的问题[2]:
第一,这样做不安全。ntpdate的设置依赖于ntp服务器的安全性,攻击者可以利用一些软件设计上的缺陷,拿下ntp服务器并令与其同步的服务器执行某些消耗性的任务。由于ntpdate采用的方式是跳变,跟随它的服务器无法知道是否发生了异常(时间不一样的时候,唯一的办法是以服务器为准)。
第二,这样做不精确。一旦ntp服务器宕机,跟随它的服务器也就会无法同步时间。与此不同,ntpd不仅能够校准计算机的时间,而且能够校准计算机的时钟。
第三,这样做不够优雅。由于是跳变,而不是使时间变快或变慢,依赖时序的程序会出错(例如,如果ntpdate发现你的时间快了,则可能会经历两个相同的时刻,对某些应用而言,这是致命的)。因而,唯一一个可以令时间发生跳变的点,是计算机刚刚启动,但还没有启动很多服务的那个时候。其余的时候,理想的做法是使用ntpd来校准时钟,而不是调整计算机时钟上的时间。
NTPD 在和时间服务器的同步过程中,会把 BIOS 计时器的振荡频率偏差——或者说 Local Clock 的自然漂移(drift)——记录下来。这样即使网络有问题,本机仍然能维持一个相当精确的走时。
ntp的安装是服务器和客户端集成在一起的,在ubuntu或centos下安装ntp服务器都非常简单,这里以ubuntu为例,使用NTP命令即可:
1 | sudo apt install -y ntp |
如果需要ntpdate工具则需要额外安装ntpdate
1 | sudo apt install -y ntpdate |
ntp的配置文件存放在/etc/ntp.conf
,打开文件并进行修改,部分参数说明如下
设定方式:
1 | server [address] [options...] |
在server后面填写服务器地址(可以使IP或主机名),之后是命令参数主要包括autokey,brust,ibrust,key,minpoll ,maxpoll。这里最长使用的是ibrust和prefer。
参数 | 含义 |
---|---|
brust | 当时间服务器不可达时,将发送间隔为2秒的连续八个包 |
ibrust | 当时间服务器不可达时,将发送间隔为2秒的连续八个包 |
prefer | 当其他数据相同时该节点将作为首选时间同步 |
其它参数的详细说明可参考NTP的帮助文档(man 5 ntp.conf
)。
设定方式:
1 | restrict [address] mask [mask] [parameter] |
其中parameter的参数主要有以下这些:
如果你没有在 parameter 的地方加上任何参数的话,这表示该 IP 或网段不受任何限制。
设定方式:
1 | driftfile [可以被ntpd写入的目录与档案] |
因为预设的 NTP Server 本身的时间计算是依据 BIOS 的芯片震荡周期频率来计算的,但是这个数值与上层 Time Server 不见得会一致啊!所以 NTP 这个 daemon (ntpd) 会自动的去计算我们自己主机的频率与上层 Time server 的频率,并且将两个频率的误差记录下来,记录下来的档案就是在 driftfile 后面接的完整档名当中了!关于档名你必须要知道:
driftfile 后面接的档案会被 ntpd 自动更新,所以他的权限一定要能够让 ntpd 写入才行。
设定方式:
1 | statsdir directory_path |
当打开统计分析是会在directory_path目录下产生filegen中所设定的统计文件。
ntp服务开启时默认监听所有的接口,如果想指定ip段或者接口则按照一下方式
1 | interface [listen | ignore | drop] [all | ipv4 | ipv6 | wildcard | name | address[/prefixlen]] |
listen指定监听接口,ignore忽略该接口,drop丢弃接口的请求数据包,接口类型可以指定为v4、v6或接口名。
为了支持IPv6这里添加清华源的NTP服务器,清华源官方链接:传送门
配置文件完整示例如下:
1 | # /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help |
启动ntp服务
1 | sudo service ntp restart |
通过ntpq命令查看ntp同步状态
1 | watch ntpq -p |
上述字段的含义如下:
ntpdate 强制同步时间
如果本机与时间同步服务器时间间隔太大可以通过ntpdate命令来进行同步,需要指出的是ntpdate使用前需要停止ntpd的进程。
1 | sudo ntpdate ntp1.ailiyun.com |
【Note】
ntp监听的是123端口,部分操作系统或防火墙等可能限制123端口因此需要放开端口限制。
【参考链接】
]]>