openstack web界面magnum 有ui界面吗

Magnum is an OpenStack API service developed by the
making container orchestration engines such as Docker Swarm, Kubernetes, and Apache Mesos available as first class resources in OpenStack.
Magnum uses Heat to orchestrate an OS image which contains Docker and Kubernetes and runs that image in either virtual machines or bare metal in a cluster configuration. Click below for a ~2 minute demo of how the Magnum CLI works.
To get started with Magnum, see:
Downloads:
The project is under active development by our OpenStack Containers Team. We .
We want you to !
Bay Create/Update/Delete
Launchpad Project Pages
for Blueprints
for Blueprints
Mailing List
for project related discussion
Add [Magnum] to the subject line of new posts about this project.
for current discussion.
Code Reviews
Code Repository
References
Our developers use IRC in #openstack-containers on freenode for development discussion.
The weekly Containers
is held on Tuesdays at 1600 UTC .
- details on the
(your group or organization here)
1) How is Magnum is different from Nova?
Magnum provides a purpose built API to manage application containers orchestration engines, which have a distinctly different life cycle and operations than Nova (machine) Instances. We actually use Nova instances to compose our Bays.
2) How is Magnum different than Docker or Kubernetes?
Magnum offers an asynchronous API that's compatible with Keystone, and a complete multi-tenancy implementation. It does not perform orchestration internally, and instead relies on OpenStack Orchestration. Magnum does leverage both Kubernetes and Docker as components.
3) Is this the same thing as Nova-Docker?
No, Nova-Docker is a virt driver for Nova that allows containers to be created as Nova instances. This is suitable for use cases when you want to treat a container like a lightweight machine. Magnum provides container orchestration engine management that is beyond the scope of Nova's API, and implements its own API to surface these features in a way that is consistent with other OpenStack services. Containers started on Magnum Bays are run on top of Nova instances that are created using Heat.
4) Who is Magnum for?
Magnum is for OpenStack cloud operators (public or private) who want to offer a self-service solution to provide a hosted containers service to their cloud users. Magnum simplifies the required integration with OpenStack, and allows for cloud users who can already launch cloud resources such as Nova Instances, Cinder Volumes, Trove Databases, etc. to also create container clusters (Bays) to run applications in an environment that provides advanced features that are beyond the scope of existing cloud resources.
5) Will I get the same thing if I use the Docker resource in Heat?
No, the Docker Heat resource does not provide a resource scheduler, or a choice of container technology used. It is specific to Docker, and uses Glance to store container images. It does not currently allow for layered image features, which can cause containers to take longer to start than if layered images are used with a locally cached base image. Magnum leverages all of the speed benefits that Docker offers, and implements Kubernetes and Mesos as alternate choices to Docker Swarm for container orchestration.
6) What does multi-tenancy mean in Magnum (Is Magnum Secure)?
Resources such as Bays started by Magnum can only be viewed and accessed by users of the tenant that created them. Bays are not shared, meaning that containers will not run on the same kernel as neighboring tenants. This is a key security feature that allows containers belonging to the same tenant to be tightly packed within the same Pods and Bays, but runs separate kernels (in separate Nova Instances) between different tenants. This is different than using a system like Kubernetes without Magnum, which was originally designed to be used only by a single tenant, and leaves the security isolation design up to the implementer. Using Magnum provides the same level of security isolation as Nova provides when running Virtual Machines belonging to different tenants on the same compute nodes.OpenStack Magnum及Liberty新功能简介
发表于 21:03|
来源《程序员》电子刊|
作者刘光亚 陆鸿斌 吴开强
摘要:到L版为止,可以为用户提供Kubernetes-as-a-Service、Swarm-as-aService和Mesos-as-a-Service,用户可以很方便地通过Magnum来管理Kubernetes、Swarm和Mesos集群,通过Magnum和后台的COE来交互获取容器服务。
容器技术,特别是Docker,是最近最热门的技术。Docker是一种在Linux容器里运行应用的开源工具,一种轻量级的虚拟机。它帮助用户提供了一个非常有效的运行、打包和部署应用的方法。容器技术也推动了容器集群管理技术的高速发展,包括Mesos、 Google的Kubernetes、 OpenStack和Docker Swarm等等。
图1 Mesos、Google
Kubernetes、OpenStack和Docker
Swarm的竞争如图1所示,现在Mesos、 Google Kuber netes、OpenStack和Docker Swarm这四大开源软件在云计算、容器服务等领域的竞争非常激烈,并且他们的功能也有一些重复,但是各自的侧重点也很明显。一个很大的区别,是OpenStack主要集中在IaaS层,其它三个主要集中在PaaS层。 Mesos的目标是下一代数据中心操作系统(DCOS),但是现在随着Docker的发展,Mesos中加入了大量和Docker集成的功能,包括将Mesos的主要服务、 task运行在Docker Container等等。Google Kubernetes是一个Docker集群管理工具,主要提供了资源管理、部署运行、服务发现和扩容缩容等功能。OpenStack主要是负责最底层基础设的管理。Docker也在加入一些集群管理、应用管理、 Orchestration的功能,并且推出了Docker Swarm、Docker Compose等项目,相应的社区也很活跃。在今年5月份的OpenStack温哥华峰会上, OpenStack提出了要做一个“集成引擎”,同时OpenStack为了保证自己在云计算领域的地位,花费了大量时间和精力和Docker去集成,包括Nova
Docker Driver、 Heat Docker Driver、OpenStack Magnum等等。Magnum是一个将OpenStack作为“集成引擎”的很典型的例子,因为Magnum通过OpenStack和Mesos、Google Kubernetes、 Docker Swarm去集成,为用户通过OpenStack提供容器服务。Magnum简介Magnum目前的功能比较简单,到L版为止,可以为用户提供Kubernetes-as-a-Service、Swarm-as-aService和Mesos-as-a-Service,用户可以很方便地通过Magnum来管理Kubernetes、Swarm和Mesos集群,通过Magnum和后台的COE( Container OrchestrationEngine,包括Kubernetes、 Swarm和Mesos)来交互获取容器服务。Magnum架构图2&Magnum架构图图2是Magnum的架构图,首先介绍Magnum的主要概念,在图2的右上角,主要有Bay、 Baymodel、 Node、Pod、 Service、 RC、 Container。Bay: Bay在Magnum主要表示一个集群,现在通过Magnum可以创建Kubernetes和Swarm的Bay,也就是Kubernetes和Swarm集群。Baymodel: Baymodel是Flavor的一个扩展, Flavor主要是定义虚拟机或者物理机的规格, Baymodel主要是定义一个Docker集群的一些规格,例如这个集群的管理节点的Flavor、计算节点的Flavor、集群使用的Image等等,都可以通过Baymodel来定义。Node:主要是指Bay中的某个节点。Container:就是具体的某个Docker容器。Pod、 Replication Controller和Service这三个概念的意思和他们在Kubernetes中的意思是一样的,这里简单介绍如下。Pod是Kubernetes最基本的部署调度单元,可以包含多个Container,逻辑上表示某种应用的一个实例。比如一个web站点应用由前端、后端及数据库构建而成,这三个组件将运行在各自的容器中,那么我们可以创建三个Pod,每个Pod运行一个服务。或者也可以将三个服务创建在一个Pod,这取决于用户的应用需求。一个Pod会包含n+1个Container,多出来的那一个Container是Net Container,专门做路由的。Service:可以理解为Pod的一个路由,因为Pod在运行中可能被删除或者IP发生变化, Service可以保证Pod的动态变化对访问端是透明的。Replication Controller:是Pod的复制抽象,用于解决Pod的扩容缩容问题。通常,分布式应用为了性能或高可用性的考虑,需要复制多份资源,并且根据负载情况动态伸缩。通过Replication Controller,用户可以指定一个应用需要几份复制, Kubernetes将为每份复制创建一个Pod,并且保证实际运行的Pod数量总是与预先定义的数量是一致的 (例如,当前某个Pod宕机时,自动创建新的Pod来替换) 。Magnum主要功能图3 Magnum主要功能图3展示了Magnum的主要功能。Provisioning用户通过Magnum CLI调用Magnum API来创建用户需要的Bay,在CLI中可以制定当前Bay的节点数量,创建Bay使用的Baymodel等等。 Magnum主要是利用了OpenStack Heat的功能来创建Bay,每个Bay就是一个OpenStack Heat的Stack。扩展/收缩Bay用户可以调用Magnum
API来调整当前Bay的节点数量,可以为当前的Bay动态地添加、删除节点。扩展、收缩Bay主要是利用了OpenStack Heat的Stack Update功能。通过Swarm来管理Container用户可以通过Magnum
API和后台的Swarm Bay来交互管理(创建、删除、更改、查询) DockerContainer。 Magnum本身对容器的创建是没有调度的,但是和Swarm集成后,可以利用Swarm本身的调度机制来帮助Magnum实现容器的资源调度的功能。因为Magnum支持多租户,每个租户可以创建自己的Swarm Bay(集群),所以当用户在通过Swarm创建容器时,需要指定当前用户需要的Swarm Bay,在指定的Swarm Bay创建Container。通过Kubernetes来管理Container用户可以通过Magnum
API来和Kubernetes交互,帮助用户管理(创建、删除、更改、查询)Kubernetes的对象,包括Pod、 Service和Replication Controller。Magnum主要是通过其API将Kubernetes的API做一层封装,让用户可以通过Magnum直接和后端的Kubernetes交互。当Kubernetes Bay创建完成后,用户也可以通过Magnum查看Kubernetes的Endpoint,如果用户能拿到Kubernetes的Endpoint,就可以直接通过Kubernetes
API来和后端的Kubernetes来交互。可以看到Magnum提供了两种方法来和后端的Kubernetes交互,通过Magnum封装的API或者直接通过Kubernetes API。现在OpenStack Dev List在讨论一个问题:既然可以让用户直接通过Kubernetes API来和后台的Kubernetes集群来交互,为什么还要通过Magnum再做一层封装呢?有人建议Magnum抛弃针对Kubernetes Pod、Service和Replication Controller的API,将Magnum作为一个COED-as-a-Service的工具( COED:Container Orchestration Engine
Deployment)。这个topic会在东京OpenStack峰会上讨论,笔者的观点是Magnum聚焦于容器服务,如果仅仅专注在COED的话,Magnum就成为了另外一个Puppet/Chef/Ansible,这和Magnum的设计初衷是背离的。笔者理想中的Magnum应该是另外一个“ Nova”,但是这个“ Nova”只专注在容器服务。现实中的Nova API很简单,是因为不管是KVM、 Hyper-V还是VMware,他们对外界暴露的对象都是VM,所以在Nova API主要提供了对VM的一些操作( Nova也加入了对Ironic的支持,这块暂时略过)。但是对于Docker COE来说,因为不同的COE管理工具都对Docker Container做了封装,例如Kubernetes有Pod、 Service和Replication Controller,Swarm只有Docker
Container,这就导致了Magnum
API很难对后台不同的COE的Container对象做抽象,这块还有大量的工作要做。Magnum在L版的新功能与Mesos集成在Liberty中,Magnum引进了一个新的Bay:Mesos Bay。Mesos Bay和其它的Bay是一样的,都是由Nova instance组成的。Mesos Bay架构因为Mesos需要依赖于上层的Framework来向外界提供容器服务,Marathon是一个很流行的分布式init服务,所以Magnum在L版的Mesos Bay主要包含Mesos和Marathon,未来可能会在Mesos上运行其他的Framework。Mesos用来做资源管理、任务执行的功能,Mesos可以让用户所有的任务在Docker Container中运行;Marathon主要是做服务管理。用户可以通过Marathon利用Mesos将服务运行在Docker Container中。
图4 Mesos Bay架构Mesos Bay的工作流程■创建一个Mesos的Baymodel创建一个Mesos的Baymodel,将这个Baymodel的COE设置为Mesos。图5 创建一个Mesos的Baymodel■创建一个Mesos Bay通过以上创建的Baymodel创建一个两节点的MesosBay,当Mesos Bay创建完成后,会同时包含Mesos和Marathon。
图6 创建一个Mesos Bay■
获取Mesos Bay的Endpoint当Mesos Bay创建完成后,用户可以通过“ Magnumbay-show”获取Mesos Bay的详细信息, Mesos Bay详细信息中的api_address表示Marathon Web UI的Endpoint。用户可以通过该IP访问Marathon创建服务。
图7 通过“Magnum bay-show”获取Mesos Bay的详细信息■访问Marathon Web UIMesos Bay创建完成后,用户可以通过Mesos
Bay中的api_address来访问Marathon Web UI, 通过MarathonWeb
UI来编写应用的模板,将自己的应用服务运行在Docker Container中。
图8 访问Marathon Web UIKubernetes高可用功能■Kubernetes高可用简介Kuber netes在1.0加入了对HA的支持,但是现在Kubernetes的HA方案并不是很成熟,
Kubernetes官方不建议在生产环境中使用。图9所示是Kubernetes
HA的架构图,
Kubernetes的HA主要是利用etcd实现master选举,从多个Master中得到一个api server, 保证至少有一个master可用,实现高可用。对外以Load
Balancer的方式提供入口。有以下几点需要注意:1. 当前的HA方案采用不同的方式处理读操作和写操作。2. 对于读操作,Kubernetes的HA集群会有多个apiserver,Load Balancer会将用户的请求转发到对应的api server。3. 对于写操作,因为每次只允许一个master去和etcd交互,所以需要通过etcd挑选一个master,只有这个master才可以与scheduler和controller manager去交互,修改etcd的状态。在每一个api server的节点上,都运行了一个podmaster。 Podmaster的主要作用是使用etcd的“ compare and swap”机制选举master,如果某个api server的节点被选中,这个api server会启动当前节点的scheduler和controller manager;如果选举失败,该api server需要将当前节点的scheduler和controller manager停掉。Kubernetes社区正在计划将HA的功能做一些改进,例如引进Active-Active的master模式。具体可以参考这里:
图9 Kubernetes HA架构图■
Magnum Kubernetes Bay HA简介图10是Magnum Kubernetes Bay的HA方案,可以看到Magnum Kubernetes Bay的HA主要是利用了Neutron的Load
Balancer实现了Kubernetes HA方案中的LoadBalancer,其它的逻辑都是利用的Kubernetes本身的功能。 Magnum CLI和Kubernetes的客户端都是通过Neutron的Load Balancer来和后端的Kubernetes
图10 Magnum Kubernetes Bay的HA方案■创建Kubernetes HA Bay创建Kubernetes HA Bay和创建普通的Kubernetes
Bay的唯一区别是在创建HA Bay的时候,需要创建多个master节点,至少包含3个master节点,只有这样才能保证etcd能正常工作。
图11 创建Kubernetes HA Bay智能收缩Bay节点Magnum支持动态调整Bay的节点数量。用户只需要通过“
Magnum bay-update”就可以更新节点数量,可以删除或者添加节点。但是在删除节点的时候,可能会删除一些有Container在运行的节点,对客户的作业造成影响,所以Magnum在L版引入了智能收缩Bay节点的功能。当用户想删除某些Bay的节点时,智能收缩可以保证先删除没有Container运行的节点,如果数量不够,再删除有Container运行的节点,保证动态删除节点对用户的作业影响最小。
图12 智能收缩Bay节点的例子图12是一个例子,当前有5个节点,其中两个节点有Container在运行。当用户想删除两个节点时,Magnum会优先选择没有运行Container的两个节点进行删除。Bay自动伸缩Magnum在L版前只支持手动调整Bay节点数量,但是这对系统管理员来说很不方便,因为管理员需要实时的监控集群来判断什么时候需要添加节点,什么时候需要删除节点等等。Magnum在L版加入了Bay自动伸缩的功能,大大减少了管理员的工作量。主要的设计思想是实时监控Bay的资源利用率来决定添加还是删除Bay节点。用户可以定义自己Bay的高水/低水来作为添加/删除节点的阈值。在L版只支持Swarm Bay的自动伸缩。
图13 Magnum Swarm Bay自动收缩的原理图图13是Magnum Swarm Bay自动收缩的原理图,具体流程如下所示:1.Magnum从Swarm Bay获取一些用于自动收缩的数据,现在只支持基于内存利用率的自动收缩。Magnum主要通过Swarm的Docker API获取所有Container和Docker Server的内存信息,例如每个Container使用的内存大小以及每个Docker Server的内存总量。2.Magnum根据第一步获取的内存数据,计算一些metrics。现在只支持内存利用率。当前某个Bay的内存利用率是所有节点上Container的内存总和除以Bay中所有节点的内存总和。3.Ceilomter会根据第二步的内存利用率来判断需不需要触发告警。例如我们可以定义当内存利用率高于70%时,自动扩展Bay;当内存利用率低于30%时,自动收缩Bay。4.当Ceilomter发出告警后,Heat会对Ceilomter的告警做出动作。Magnum会调用Heat API来更新Bay的节点数量。Magnum网络改进容器的网络生态系统正在发生着日新月异的变化。在今天的容器的部署中使用的网络工具和技术与几个月前的技术有很大的不同,并且这些网络工具和技术将继续发展。以Flannel为例,Flannel在2014年7月刚release的时候,被Kubernetes视为其容器管理的首选网络,但是到2015年初,Flannel已经不再是Kubernetes的首选。除此之外,不同COE的网络管理很难达成一致,而且未来也不太可能保证所有的COE使用同样的网络管理工具,因为不同的用户对网络有不同的需求,对不同网络管理工具的熟悉程度决定了COE的网络管理必须可配置,从而使不同用户根据自己的需求使用不同的网络管理工具。但是现在Magnum不同COE的网络配置都是硬编码在Heat Template中,这部分对用户是透明的,如果用户想定制自己COE的网络管理,那么需要用户对HeatTemplate很熟悉,自己在Heat中加入一些script或者user data来对自己的网络进行定制,这对用户来说很不方便。针对上述问题, Magnum
L版中加入了让用户定制COE网络的功能。用户可以在创建Baymodel的时候通过参数network-driver指定自己COE需要的网络管理工具。具体如下所示:magnum baymodel-create --name k8sbaymodel \
--image-id fedora-21-atomic-5 \
--keypair-id testkey \
--external-network-id 1hsdhs88sddds889 \
--dns-nameserver 8.8.8.8 \
--flavor-id m1.small \
--docker-volume-size 5 \
--coe kubernetes \
--libnetwork-driver flannel最后一个字段表示当前创建的Kubernetes
Baymodel使用的网络管理工具是Flannel,用户可以根据自己的需求定制自己的Network Driver。同时因为不同的Network Driver在创建的时候,可能需要一些输入参数,所以Magnum的baymodel-create还支持在创建Baymodel的时候通过“ labels”指定Network Driver创建时需要的参数,下面是一个例子:magnum baymodel-create --name k8sbaymodel \
--image-id fedora-21-atomic-5 \
--keypair-id testkey \
--external-network-id ${NIC_ID} \
--dns-nameserver 8.8.8.8 \
--flavor-id m1.small \
--docker-volume-size 5 \
--coe kubernetes \
--libnetwork-driver flannel \
--labels network-cidr=10.0.0.0/8,\
network-subnetlen=22,\
backend=vxlan这个例子通过labels指定了创建Flannel网络需要的一些参数,给了用户更大的空间来定制自己COE的网络。现在L版只是把COE网络定制的框架完成了,支持的Network Driver只有Flannel,在未来会加入对Weave、Caliao、 Libnetwork、
Midonet等的支持。另外Neutron社区也在推动Kuryr这样一个新项目,具体可以参考:
Kuryr背后的理念是能够利用抽象层、Neutron及其插件与服务中的所有工作,为容器应用案例提供一个生产级的网络。
Kuryr本身并不是一个网络解决方案,同时它也没有尝试成为一个网络解决方案。
Kuryr将重点放在了“信使”功能上,以向Docker传递Neutron网络和服务。 Magnum社区正在和Kuryr社区合作,最终目标是期望Kuryr能成为libnetworkdriver的默认选项。公共( public) BaymodelMagnum也增加了public
Baymodel的支持,创建Baymodel的时候,可以通过指定——public来创建公共类型的Baymodel,这样就实现了管理员创建的公共的Baymodel,不同用户可以很方便地直接使用。例子如下:$ magnum baymodel-create --name k8sbaymodel_
--image-id fedora-21-atomic-5 \
--keypair-id testkey \
--external-network-id public \
--dns-nameserver 8.8.8.8 \
--flavor-id m1.small \
--docker-volume-size 5 \
--network-driver flannel \
--coe kubernetes --public可以看到这个命令行加入了一个新的选项“ --public”,这样可以保证当前创建的是一个public的Baymodel,这个Baymodel可以为当前的所有用户去使用。Magnum UIMagnum现在只支持命令行操作,这对用户来说很不方便。所以在L版, OpenStack添加了一个新的项目Magnum UI,其主要目的是在OpenStack Horizon上能对Magnum做一些操作。现在已经有了一个基本的雏形,具体如图14所示,用户可以通过Horizon查看所有的Bay、 Baymodel等等,未来还会加入通过MagnumUI做一些容器相关操作的特性,真正实现让用户通过Magnum UI实现CaaS。期望在M版能有一个可用的Magnum
UI呈现给大家。
图14 Magnum UI雏形其它Magnum在L版还对安全性做了很大的改进,这块笔者参与不是太多,所以在这就不详细介绍了,如果大家感兴趣,可以参考这里:https://blueprints.launchpad.net/magnum/+spec/secure-kubernetesMagnum展望总体来说, Magnum在L版做了很大的改进,但是毕竟Magnum到今年11月份才一周岁,还不是很成熟,但是大家可以看到Magnum一直在紧跟Docker社区的步伐,积极地将一些比较热门的Docker集群管理工具集成进来,例如在L版新添加的Mesos、 Kubernetes HA的支持。 L版发布之后, M版也要开始了。在M版,笔者期望Magnum能在以下几个方面有一些突破:■ 平滑集成不同COE的容器管理能力。现在Magnum主要功能集中在对COE的部署上,但是对不同COE提供容器服务的功能集成不是很完善,主要是对不同的COE API通过Magnum做了一些封装,并没有给用户带来实质的好处。在M版, Magnum会在这方面做一些改进。■Magnum网络和Kuryr的集成,这主要取决于Kuryr的发展,希望Kuryr能顺利发展,成为Magnum COE默认的libnetwork driver。■Magnum UI,这是一个很重要的特性, Magnum UI会大大简化用户的一些工作,为Magnum进入生产环境打好基础。■公共的Bay,让不同的租户共享同一个Bay。这个需求主要是针对在某些情况下,不同的租户想共享一个Bay获取容器服务。一个很典型的例子是在同一个部门的不同的组想通过一个Magnum
Bay获取容器服务,这个时候我们就需要让这些不同的组(可以看成是租户)共享同一个Bay。■Magnum对容器服务和底层基础设施层的自动扩展,简称为双层扩展。目标是通过对上层的容器服务进行监控扩展的同时,根据一定的条件同时实现对底层基础设施的扩展。以Kubernetes为例,如果上层的Replication Controller在对Pod数量进行扩展的时候,发现Kubernetes节点数量不够,这个时候就需要Magnum能够对底层的基础设施扩展以保证上层的Replication
Controller能够对Pod进行扩展。■Mesos深度集成。Magnum现在对Mesos的支持仅仅局限在用户可以通过 Magnum部署一个Mesos+Marathon的集群,部署完后,用户可以通过Marathon来操作。Magnum没有对Mesos的API做任何封装,在M版,可能需要考虑怎样和Mesos深度集成,用户如何通过Magmum API来和Mesos交互获取容器服务。■ 最重要的一条,希望大家积极参与Magum社区。参与Magnum社区的方式很多,不仅仅局限在为Magnum提Patch,还可以参与邮件列表讨论,为Magnum提一些需求、建议等。作者简介刘光亚,2008年于西安交通大学软件学院获得硕士学位,目前就职于IBM Platform Computing 系统科技部云计算部门,担任云计算开发部架构师。自2013年5月开始参与OpenStack社区的开发工作,已为OpenStack社区贡献了200多个patch,涉及Nova、Cinder、Heat、Blazar和Magnum等项目,并担任Magnum的Core Member。同时自2014年12月参与Mesos生态系统的调研以及Mesos社区的开发工作。西安OpenStack Meetup和Mesos
Meetup组织者,多次在Meetup介绍OpenStack及Mesos热门话题。陆鸿斌,2014年毕业于加拿大约克大学,硕士学位,现在就职于华为加拿大研究所,担任软件工程师。目前从事于OpenStack Magnum项目的开发,是该项目的Core reviewer。在Libertycycle,代码贡献度排行第一,并且完成了Liberty release的好几个重要的Features。包括Mesos Integration, HA Kubernetes Bay, metric
notification, smart scale down等等。吴开强,2011年毕业于西安交通大学电子与信息工程学院并获得硕士学位,现在就职于IBM北京软件开发中心,担任云计算软件工程师。目前从事于OpenStack开源社区相关的工作,是Magnum社区活跃的Developer和Core
Reviewer。(责编/周建丁 zhoujd at csdn dot net)本文选自程序员电子版2015年11月A刊,该期更多文章请查看。2000年创刊至今所有文章目录请查看。欢迎(含iPad版、Android版、PDF版)。
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章}

我要回帖

更多关于 openstack ui 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信