#+SETUPFILE: ~/Dropbox/Doc/Org_Templates/level-1.org
OpenStack 的容器历史
自容器技术变为目前云计算最火热和最前沿的技术以来,OpenStack 作为一个云计算管理平台(亦或是云计算生态系统), 怎么将容器管理纳入到其内,成为了近两年 OpenStack 发展的一个热门方向。
OpenStack 的容器整合之路先后经历了以下几种历程:
目前 Magnum 和 Murano 是 OpenStack 中血统最正的容器项目。
可以通过 gitstatus 的分析结果看一下 magnum 的开发活跃度
由上面的分析可以看到,magnum 目前开发非常活跃。
Magnum 介绍
Magnum 利用 Keystone, Nova, Heat, Neutron 等已有的 OpenStack组件,整合容器的 集群管理系统如 kubernetes, Mesos 等, 为用户更加简单灵活,多租户的容器服务.
在 Magnum 中的设计中,容器和虚拟机一样为一等公民, 有自己独立的逻辑实现,而不是像 nova docker driver 那样仅仅是 nova 的后端实现。
目前 Magnum 主要为用户提供以下功能:
- 容器管理集群的部署: 支持 Kubernetes, Docker Swarm, Mesos 这三种容器管理集群类型的部署
- 容器管理集群的管理: 对容器管理集群进行弹性扩容, 修改配置,提供访问容器管理集群的认证信息
Magnum 的主要概念:
- Bay: 表示一个集群,比如一个 Mesos 集群,新版本中已经改为 cluster
- BayModel: 集群的 flavor, 类似于虚拟机的 flavor, BayModel 定义 Docker 集群的一些规格, 比如节点使用的 k8s 或者 mesos 镜像, 网络参数等. 新版本中已经改为 ClusterTemplate
- Cluser: 同 bay
- ClusterTemplate: 同 BayModel
- Node: 指 bay 中的某个节点,即 nova 中的虚拟机, 容器在该 node 里面运行.
- COE: Container Orchestration Engine, 容器集群管理后端,目前支持的有 k8s, Swarm 和 Mesos. magnum 的主要工作就是将用户的请求转发到 COE, 完成容器的管理。
以下是 k8s 中的一些概念扫盲(下文中的演示部分使用 k8s 来举例)
- Pod: k8s 的部署调度单元, 一般多个容器组成一个 Pod, Pod 里的容器运行相同的应用, 属于同一 Pod的容器运行在同一个Minion(Host)上,作为一个统一管理单元,共享相同的 volume 和 network namespace/IP和Port空间。详细信息参考 k8s 中的介绍。在新版本中 Pod 的相关管理 命令已经从 magnum 中移除, 要管理 Pod 需要使用 k8s 提供的 kubectl 工具。
- Replication controller: 用来保证用户定义数量的 Pod 副本在任何时候都是处于 正常运行状态的。也即他的职责是用来管理 Pod 的伸缩
- Service: 可以理解为是pod网关,因为pod在运行中可能被删除或者ip发生变化,service可以 保证pod的动态变化对访问端是透明的。
安装
可以采用 devstack 或者手动安装的方式安装,下面是使用 devstack 安装 magnum 部分的相关配置
# magnum 需要 heat 来编排调度 node
enable_plugin heat http://git.trystack.cn/openstack/heat.git
ENABLED_SERVICES+=,h-eng,h-api,h-api-cfn,h-api-cw
# magnum 需要负载均衡组件来做集群管理,特别的,这里使用 v2 的 lbaas 服务
enable_plugin neutron-lbaas http://git.trystack.cn/openstack/neutron-lbaas.git
enable_plugin octavia http://git.trystack.cn/openstack/octavia
disable_service q-lbaas
ENABLED_SERVICES+=,q-lbaasv2
ENABLED_SERVICES+=,octavia,o-cw,o-hk,o-hm,o-api
# 启用 magnum 和 magnum-u 插件
enable_plugin magnum http://git.trystack.cn/openstack/magnum.git
enable_plugin magnum-ui http://git.trystack.cn/openstack/magnum-ui.git
安装完成后,可以通过以下命令确认 magnum 服务正常运行。
$ magnum service-list
+----+-----------------------+------------------+-------+----------+-----------------+---------------------------+---------------------------+
| id | host | binary | state | disabled | disabled_reason | created_at | updated_at |
+----+-----------------------+------------------+-------+----------+-----------------+---------------------------+---------------------------+
| 1 | localhost.localdomain | magnum-conductor | up | | - | 2017-01-03T10:48:14+00:00 | 2017-01-04T06:45:33+00:00 |
+----+-----------------------+------------------+-------+----------+-----------------+---------------------------+---------------------------+
创建容器管理集群
在容器的世界中,容器是运行在操作系统之上的特殊的 “应用程序”, 由在此操作系统上运行的容器管理程序 k8s 或者 mesos 管理. 在 magnum 中,这个操作系统(和管理程序)是 nova 中的虚拟机。不难理解这样使用 带来的好处,可以复用 nova,glance,cinder,neutron 等等的功能。反正容器本身只需要一个运行时的操作 系统,不管这个操作系统实在虚拟机还是物理机上。
创建容器管理集群的规格
类似于虚拟机的使用,在创建容器管理集群的时候,需要有一个规格,也即上面说过的 ClusterTemplate, 根据此规格的定义来创建容器管理集群。
$ nova keypair-add --pub-key ~/.ssh/id_rsa.pub testkey
$ magnum cluster-template-create \
--name k8s-cluster-template \ <-- 规格的名字
--image fedora-atomic-latest \ <-- 运行 node 的镜像
--keypair testkey \ <-- 导入一个密钥到 k8s node 上, 方便后续的访问
--external-network public \ <-- 给每个 node 分配浮动 IP时用到的外部网络
--dns-nameserver 192.168.2.64 \ <-- node 里面的 dns 配置, 我这里选用一台内网的地址,是为了防止集群初始化的时候访问 google 的服务失败,在这里做翻墙处理 :)
--flavor m1.small \ <-- node 虚拟机的规格
--docker-volume-size 5 \ <-- 给 docker 预留的 volume 的大小
--network-driver flannel \ <-- 容器使用的网络后端,这里选用 flannel
--coe kubernetes <-- 容器的管理后端,这里选择 k8s
创建 k8s 集群
$ magnum cluster-create --name k8s-cluster --cluster-template k8s-cluster-template --node-count 2
$ magnum cluster-list # 等到 status 变为 CREATE_COMPLETE 说明集群创建成功。
+--------------------------------------+-------------+---------+------------+--------------+-----------------+
| uuid | name | keypair | node_count | master_count | status |
+--------------------------------------+-------------+---------+------------+--------------+-----------------+
| dd483a45-2b7a-4294-b918-680e1399a7cc | k8s-cluster | testkey | 2 | 1 | CREATE_COMPLETE |
+--------------------------------------+-------------+---------+------------+--------------+-----------------+
$ magnum cluster-show k8s-cluster
+---------------------+------------------------------------------------------------+
| Property | Value |
+---------------------+------------------------------------------------------------+
| status | CREATE_COMPLETE |
| cluster_template_id | 8538544b-c809-478f-a98d-e0c35bfeef9c |
| node_addresses | ['192.168.5.136', '192.168.5.134'] | <-- k8s 的 minion node
| uuid | dd483a45-2b7a-4294-b918-680e1399a7cc |
| stack_id | b9e815a8-a746-49b0-a307-755c17415324 |
| status_reason | Stack CREATE completed successfully |
| created_at | 2017-01-04T09:07:45+00:00 |
| updated_at | 2017-01-04T09:10:05+00:00 |
| coe_version | v1.2.0 |
| keypair | testkey |
| api_address | https://192.168.5.137:6443 | <-- k8s api endpoint
| master_addresses | ['192.168.5.137'] | <-- k8s 的master node
| create_timeout | 60 |
| node_count | 2 |
| discovery_url | https://discovery.etcd.io/6a6004c6a9730be2e0896e412caea0a9 |
| master_count | 1 |
| container_version | 1.9.1 |
| name | k8s-cluster |
+---------------------+------------------------------------------------------------+
由于 magnum 后端使用 heat 来做集群的编排,所以也可以通过 heat 来查看相关状态:
$ heat stack-list
+--------------------------------------+--------------------------+-----------------+----------------------+--------------+
| id | stack_name | stack_status | creation_time | updated_time |
+--------------------------------------+--------------------------+-----------------+----------------------+--------------+
| 5fb85534-54fe-407d-ac2d-f3c319024735 | k8s-cluster-644272c22n6h | CREATE_COMPLETE | 2017-01-05T02:28:43Z | None |
+--------------------------------------+--------------------------+-----------------+----------------------+--------------+
在 horizon 上也可以看到用到的资源的拓扑图:
配置集群的访问方式
注入 k8s 的访问密钥到 k8s 集群中,这里利用 magnum 提供的 cluster-config 命令, 该命令会生成三个 *.pem证书文件和一个 k8s 客户端的配置文件 config, 并将相应的公钥注入到 k8s 中. 将这四个文件拷贝到任何想访问 k8s 集群的终端即可。
<pre lang="bash">
# Set kubectl to use the correct certs
$ magnum cluster-config k8s-cluster
$ ls *.pem config
ca.pem cert.pem config key.pem
</pre>
使用容器管理集群
严格来讲上面已经完成了容器管理集群的部署,照着 k8s 的文档就可以开始使用容器了。
安装配置 k8s 客户端
$ wget https://github.com/kubernetes/kubernetes/releases/download/v1.0.1/kubernetes.tar.gz
$ tar -xvzf kubernetes.tar.gz
$ sudo cp -a kubernetes/platforms/linux/amd64/kubectl /usr/bin/kubectl
拷贝 k8s 的证书文件到当前目录下,再导入 k8s 的配置文件即可开始使用,例如下面的实例:
$ export KUBECONFIG=config
$ kubectl cluster-info
Kubernetes master is running at https://192.168.5.131:6443
KubeUI is running at https://192.168.5.131:6443/api/v1/proxy/namespaces/kube-system/services/kube-ui
创建容器集群
我们以 k8s 源码目录 kubernetes/examples/redis 下的 redis 集群为例子。
$ kubectl create -f redis-master.yaml
$ kubectl create -f redis-sentinel-service.yaml
$ kubectl create -f redis-controller.yaml
$ kubectl create -f redis-sentinel-controller.yaml
创建完成之后可以看到所有资源的状态都就绪了。
$ kubectl get pods,rc,services
NAME READY STATUS RESTARTS AGE
redis-master 2/2 Running 0 2h
redis-ptvgd 1/1 Running 0 1h
redis-sentinel-6wiha 1/1 Running 0 3m
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
redis redis kubernetes/redis:v1 name=redis 2
redis-sentinel sentinel kubernetes/redis:v1 redis-sentinel=true 2
NAME LABELS SELECTOR IP(S) PORT(S)
kubernetes component=apiserver,provider=kubernetes <none> 10.254.0.1 443/TCP
redis-sentinel name=sentinel,role=service redis-sentinel=true 10.254.38.28 26379/TCP
验证我们创建的redis集群:
首先进入容器中设置一个 key:
$ kubectl exec redis-master -ti /bin/bash
root@redis-master:/data# redis-cli
127.0.0.1:6379> set var "hello world"
OK
找另外一台机器作为 redis 客户端
dunrong@localhost$ kubectl port-forward -p redis-master 6380:6379 <-- 将 k8s 中 redis 的服务端口(6379) 端口映射到本地6380
I0110 17:56:55.657227 2903 portforward.go:225] Forwarding from 127.0.0.1:6380 -> 6379
I0110 17:56:55.657335 2903 portforward.go:225] Forwarding from [::1]:6380 -> 6379
然后用 redis-cli 访问:
dunrong@localhost$ redis-cli -p 6380
127.0.0.1:6380> GET var
"hello world"
127.0.0.1:6380>
that’s it!
小结
从上面的介绍和 demo 来看,目前用 magnum 作为容器的方案是完全可行的。 但由于容器在 OpenStack 中还属于快速开发阶段,在我看来他的作用目前仅仅是一个 k8s, mesos 之类的的容器管理集群的部署脚本,且在使用中存在各种各样的 bug。如果用户具有 一定的 OpenStack 和容器技术的经验,那么使用 OpenStack 在生产中管理部署容器是可行的。
tips
在 k8s 初始化的时候,默认情况下件会到 google的镜像仓库去下载一些 docker 镜像, 由于 你懂的 的原因,在大中华区这步肯定会失败。解决方案无外乎是让整个集群都能 科学上网 , 我这里使用一种最简单的方式。在创建 ClusterTemplate 的时候,指定 DNS 为另外一台机器,并这台机器上安装 dnsmasq, 将 gcr 的域名请求做本地解决即可。