xjpresley
作者xjpresley2017-10-30 13:53
软件开发工程师, erwefsdfsd

基于容器微服务的PaaS云平台设计(二)通过kubernetes实现微服务容器管理

字数 14329阅读 3792评论 1赞 2

个人博客地址:http://www.cnblogs.com/SuperXJ/
作者个人微信号 superiter


上篇:基于容器微服务的PaaS云平台设计(一) 实现容器微服务和持续集成

上一章描述了基于spring cloud的微服务实例(实现微服务的自动发现、自动注册、负载均衡等),同时描述了基于jenkins从代码提交后自动化构建并自动化部署微服务容器的例子,但是从上一章不难看出微服务都是直接部署在docker上,实际生产环境微服务数量会非常多,直接用docker部署会非常繁琐不好管理,且容器本身并没有高可用、服务发现、负载均衡和监控机制,虽然微服务本身具备一定的高可用、负载均衡和服务发现机制,但是仍然无法完全避免由于基础环境故障和版本升级等情况导致微服务可用性降低甚至中断,而kubernetes可以解决这些问题,同时还有更多美妙的功能,比如水平扩展、数据持久化,自动发布回滚、秘钥配置管理、批处理执行,结合jenkins极大的加速生产的构建和部署速度,可以说k8s是专为devops而生,本章就开始k8s之旅,先介绍几个kubernetes核心概念:

Label:标签,其实就是给资源分组,然后可以执行一定的组策略,例如我们可以给node打标签,可以让Pod运行在指定标签的node上,也可以给pod打标签。

Pod:kubernetes最小调度单位,一般来说一个POD只运行一个容器,也可以一个Pod里运行一组容器,k8s中我们不直接操作容器,而是操作Pod。

replication controller:副本控制器,保证pod个数始终与设定值一致,如果遇到pod故障,节点离线等,控制器会删除这些状态异常的pod,重新调度生成新的pod。通过label匹配pod,在弹性伸缩、滚动升级中发挥重要作用,本实验使用新版上功能更强大的Deployment代替replication controller。

service:服务,是一个虚拟概念,逻辑上代理后端pod。众所周知,pod生命周期短,状态不稳定,pod异常后新生成的pod ip会发生变化,之前pod的访问方式均不可达。通过service对pod做代理,service有固定的ip和port,ip:port组合自动关联后端pod,即使pod发生改变,kubernetes内部更新这组关联关系,使得service能够匹配到新的pod。这样,通过service提供的固定ip,用户再也不用关心需要访问哪个pod,以及pod会否发生改变,大大提高了服务质量。如果pod使用rc创建了多个副本,那么service就能代理多个相同的pod,通过kube-proxy,实现负载均衡。

Volumes:K8s数据持久化解决方案,pod可以像挂载文件系统一样挂载volumes,volumes支持本地存储、ceph、gluster等等。

Namespace:让应用有自己的隐私,每个租户有独享的servicepodvolumeDeployment空间。

flanneld:跨主机的POD无法直接通信,需要使用第三方解决方案,我这里用的是flanneld,当然也可以用其他的,由于容器无法跨node通信,所以引入flanneld,一个overlay技术,让容器可以跨node通信,原理是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址 ,Flannel实质上是一种"覆盖网络(overlay network)",也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,目前已经支持UDP、VxLAN、AWS VPC和GCE路由等数据转发方式

Skydns:为了能够通过服务的名字在集群内部进行服务的相互访问,需要创建一个虚拟的DNS服务来完成服务名到ClusterIP的解析,Skydns通过下面组成1)etcd:NDS存储2)kube2sky:将kubernetes Master中的Service(服务)注册到etcd 3)skyDNS:提供NDS域名解析服务 4)healthz:提供对skydns服务的健康检查功能

Ingress:7层路由,简单说就是通过识别URL将不同URL转到不同service,例如,http://xiongjian/a 转到server_1,http://xiongjian/b 转到server_2,其实和上一章说的spring cloud微服务的功能重复了。建议使用微服务的就行了。

本章是基于上一节的环境,确认机器已经完成docker部署、关闭防火墙和selinux、使用上一节的微服务应用eurekaserver,服务端口8761。同样本篇会在每个环节对新概念再做一点简单介绍,关于详细情况了解有需要的话,可以网上搜索一下相关资料。

本次实验环境为两台虚机 IP分别为192.168.226.131和130,其中131为k8s master, 130为k8s nodes(本该至少启两个node的,无奈电脑配置实在太低),开始准备工作

配置本地镜像仓库(不用镜像库,后面的yaml文件会找不到本地镜像)

Master节点上运行:

Docker pull registry

Docker run -d -p 5000:5000 registry

Docker tag eureka centos-master:5000/eureka

Docker push centos-master:5000/eureka

检测是否成功:

curl -XGET http://centos-master:5000/v2/_catalog

显示{"repositories": ["eureka"]}

配置访问模式(不配置后面会报错,运维K8s创建pod默认使用的是https,这里改成http,同时指向centos-master主机的本地镜像仓库)

Master节点上 /etc/sysconfig/docker 文件里加上

OPTIONS='--insecure-registry centos-master:5000'

ADD_REGISTRY='--add-registry centos-master:5000'

Service docker restart

Node节点上/etc/docker/daemon.json

{"insecure-registries": ["centos-master:5000"]}

Service docker restart

1、安装k8s

master上部署etcd(一个分布式强一致性的key/value存储,可以理解为一个存储k8s信息的数据库)、kube-apiserver(管理k8s集群的统一入口、提供restful API支持,校验和配置Pod、Service和Replication Controller),kube-scheduler(负责资源调度、负责Pods在各个节点上的分配 ),kube-controller-manager(负责容错、扩容缩容、定期关联replicationController和pod,保证定义的复制数量与实际运行pod的数量总是一致的,实际上我使用Deployment,它主要职责同样是为了保证pod的数量和健康,90%的功能与Replication Controller完全一样,可以看做新一代的Replication Controller。但是,它又具备了Replication Controller之外的很多新特性 )。

Nodes上部署Kube-proxy(服务发现 、定期从etcd获取所有的service根据service信息创建代理、客户pod访问其他pod都经过proxy转发 )、Kubelet(管理容器的守护进程、管理Docker主机来启动容器的管理程序、定期从etcd获取分配到本机的pod信息,启动或停止容器、接收apiserver的HTTP请求,汇报pod的运行状态)和 flanneld

1.1 两台虚机上 /etc/hosts 增加

centos-master = 192.168.226.131

centos-minion-1 = 192.168.226.130

1.2 两台虚机上配置yum源并安装

配置yum:

[virt7-docker-common-release]

name=virt7-docker-common-release

baseurl=http://cbs.centos.org/repos/virt7-docker-common-release/x86_64/os/gpgcheck=0

安装:yum -y install kubernetes etcd flannel

1.3 在两台虚机上配置 /etc/kubernetes/config

# logging to stderr means we get it in the systemd journal

KUBE_LOGTOSTDERR="--logtostderr=true" # journal message level, 0 is debug

KUBE_LOG_LEVEL="--v=0" # Should this cluster be allowed to run privileged docker containers

KUBE_ALLOW_PRIV="--allow-privileged=false" # How the replication controller and scheduler find the kube-apiserver 主节点的地址,主要为replication controller和scheduler可以顺利找到apiserver

KUBE_MASTER="--master=http://centos-master:8080"

1.4 在两台虚机上配置/etc/sysconfig/flanneld

# etcd url location. Point this to the server where etcd runs

FLANNEL_ETCD_ENDPOINTS="http://centos-master:2379" # etcd config key. This is the configuration key that flannel queries# For address range assignment

FLANNEL_ETCD_PREFIX="/kube-centos/network"

1.5 在master主机上配置

1.5.1 /etc/etcd/etcd.conf

# [member]

ETCD_NAME=default

ETCD_DATA_DIR="/var/lib/etcd/default.etcd"

ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" #[cluster]

ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379"

1.5.2 /etc/kubernetes/apiserver

# The address on the local server to listen to. master监听所有IP

KUBE_API_ADDRESS="--address=0.0.0.0" # The port on the local server to listen on. 监听端口

KUBE_API_PORT="--port=8080" # Port kubelets listen on从节点上kubelet进程监听的端口号

KUBELET_PORT="--kubelet-port=10250" # Comma separated list of nodes in the etcd cluster 配置ETCD服务地址

KUBE_ETCD_SERVERS="--etcd-servers=http://centos-master:2379" # Address range to use for services service可以分配的IP地址范围

KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16" # Add your own!

KUBE_API_ARGS=""

1.5.3 配置etcd

etcd里保存了Flannel分配给每个node docker0的IP地址范围,可通过查看ifconfig docker0 发现每个机器都是 172.30. ,但是不会冲突。

systemctl start etcd etcdctl mkdir /kube-centos/network etcdctl mk /kube-centos/network/config "{ \"Network\": \"172.30.0.0/16\", \"SubnetLen\": 24, \"Backend\": { \"Type\": \"vxlan\" } }"

1.6 nodes上配置

1.6.1 /etc/kubernetes/kubelet

# The address for the info server to serve on

KUBELET_ADDRESS="--address=0.0.0.0" # The port for the info server to serve on

KUBELET_PORT="--port=10250" # You may leave this blank to use the actual hostname# Check the node number!

KUBELET_HOSTNAME="--hostname-override=centos-minion-1" # Location of the api-server

KUBELET_API_SERVER="--api-servers=http://centos-master:8080" # Add your own!

KUBELET_ARGS=""

1.6.2 /etc/sysconfig/flanneld

# etcd url location. Point this to the server where etcd runs

FLANNEL_ETCD_ENDPOINTS="http://centos-master:2379" # etcd config key. This is the configuration key that flannel queries# For address range assignment

FLANNEL_ETCD_PREFIX="/kube-centos/network"

1.7 启动服务

Master上

systemctl restart kube-apiserver

systemctl restart kube-controller-manager

systemctl restart kube-scheduler

systemctl restart flanneld

systemctl restart docker

kubectl config set-cluster default-cluster --server=http://centos-master:8080 kubectl config set-context default-context --cluster=default-cluster --user=default-admin kubectl config use-context default-context

Node上

systemctl restart kube-proxy

systemctl restart kubelet

systemctl restart flanneld

systemctl restart docker

1.8 测试一下

[root@centos-master k8s]# kubectl get nodes

NAME STATUS AGE

centos-minion-1 Ready 5m

[root@centos-master k8s]# docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

euraka 0.1 22432d0e5013 20 days ago 206.4 MB

可以看到刚刚启动的node节点centos-minion-1,另外在回顾一下我们之前创建的euraka的镜像,这就是上一节的eurekaserver容器镜像,用于微服务注册的,这个镜像会自动启动一个eurekaserver服务,端口是8761映射到主机的8761。

2、运行一个Pod

2.1创建eureka.yaml文件,用于创建Pod(方便长期维护与跟踪,建议使用yaml配置文件方式来运行pods )

apiVersion: v1

kind: Pod

metadata:

labels:

name: eurekaserver

spec:

containers:

  • name: eurekaserver

image: centos-mater:5000/eureka

创建一个pod,这个pod和容器的名字是eurekaserver,使用的image是我们私有仓库的 centos-mater/eureka

2.2 创建Pod

Kubectl create -f eureka.yaml

然后kubectl get pod查看eurekaserver一直处于ContainerCreating 状态,kubectl describe pod eurekaserver 显示如下报错,查看一下,,原来依赖于googlepause,不FQ连不上,大坑。。

"StartContainer" for "POD" with ErrImagePull: "image pull failed for gcr.io/google_containers/pause-amd64:3.0, this may be because there are no credentials on this request. details: (Get https://gcr.io/v1/_ping: dial tcp 74.125.23.82:443: getsockopt: connection refused)"

自己下载pause,然后打tag,也就是本地建一个image伪装成google的pause image,这里感谢阿里云。

[root@centos-master k8s]#docker pull registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0

[root@centos-master k8s]# docker tag registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0 gcr.io/google_containers/pause-amd64:3.0

好了删除pod之后再次运行

Kubectl delete -f eureka.yaml

Kubectl create -f eureka.yaml

[root@centos-master k8s]# kubectl get pods

NAME READY STATUS RESTARTS AGE

eurekaserver 1/1 Running 0 26m

[root@centos-master k8s]# kubectl describe pod eurekaserver

Name: eurekaserver

Namespace: default

Node: centos-minion-1/192.168.226.130

Labels: <none>

Status: Running

IP: 172.30.81.2

Controllers: <none>

Containers:

eurekaserver:

Container ID: docker://dad09de860ee5756c57a1454c65854278b3d7c90cb2bed0d43f7734673eb1424

Image: centos-master:5000/eureka

Image ID: docker-pullable://centos-master:5000/eureka@sha256:0afc1a6d7e24f594a36087bf83adcecc34ed6ac5a59f11b75d6557c30e777a98

Port: 8761/TCP

State: Running

Ready: True

Restart Count: 0

Volume Mounts: <none>

Environment Variables: <none>

Conditions:

Type Status

Initialized True

Ready True

PodScheduled True

No volumes.

QoS Class: BestEffort

Tolerations: <none>

Events:

可以看到pod在节点上centos-minion-1运行成功,IP为172.30.81.2就是上面flanneld分配的,对外服务端口为8761,使用的是我们私有镜像库的eureka

验证一下,访问http://192.168.226.130:8761:eureka

3、Deployment

运行一个Deployment,如果在yaml中指定了标签,就可以让pod运行到指定的node上或者一组指定的node中。(Deployment 的作用是管理一组pod副本,可以在Deployment对象中描述所期望的运行状态,Deployment控制器为您将现在的实际状态转换成您期望的状态 ,Deployment是一个非常强大的工具,集成了上线部署、滚动升级、创建副本、暂停上线任务,恢复上线任务,回滚到以前某一版本(成功/稳定)的Deployment等功能,在某种程度上,Deployment可以帮我们实现无人值守的上线,大大降低我们的上线过程的复杂沟通、操作风险。)

3.1 编写deployment.yaml

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

name: eurekaserver-deploy

spec:

replicas: 2

template:

metadata:

labels:

app: eurekaserver

spec:

containers:

- name: eureka

image: centos-master:5000/eureka

ports:

- containerPort: 8761

- hostPort:8761

容器的8761端口映射到node的8761端口。

3.2 运行查看结果

[root@centos-master k8s]# kubectl create -f deployment.yaml

[root@centos-master k8s]# kubectl get pods

NAME READY STATUS RESTARTS AGE

eurekaserver-deploy-252831566-cb1gn 1/1 Running 0 2m

eurekaserver-deploy-252831566-kbdf7 1/1 Running 0 2m

[root@centos-master k8s]# kubectl describe deployment eurekaserver-deploy

Name: eurekaserver-deploy

Namespace: default

Labels: app=eurekaserver

Selector: app=eurekaserver

Replicas: 2 updated | 2 total | 2 available | 0 unavailable

StrategyType: RollingUpdate

MinReadySeconds: 0

RollingUpdateStrategy: 1 max unavailable, 1 max surge

Conditions:

Type Status Reason


Available True MinimumReplicasAvailable

OldReplicaSets: <none>

NewReplicaSet: eurekaserver-deploy-252831566 (2/2 replicas created)

Events:

FirstSeen LastSeen Count From SubObjectPath Type Reason Message


3m 3m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set eurekaserver-deploy-252831566 to 2

[root@centos-master k8s]#kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE rss-site 2 2 2 2 1m

Replica Set(简称RS)是k8s新一代的Pod controller。与RC相比仅有selector存在差异,RS支持了set-based selector(可以使用in、notin、key存在、key不存在四种方式来选择满足条件的label集合)。Deployment是基于RS实现的,我们可以使用kubectl get rs命令来查看Deployment创建的RS:

[root@centos-master k8s]# kubectl get rs

NAME DESIRED CURRENT READY AGE

eurekaserver-deploy-252831566 2 2 2 34m

两个提供同样服务的eurekaserver pod都启动了。

3.3 微服务在线滚动升级

当集群中的某个服务需要升级时,我们需要停止目前与该服务相关的所有Pod,然后重新拉取镜像并启动。如果集群规模比较大,则这个工作就变成了一个挑战,而且先全部停止然后逐步升级的方式会导致较长时间的服务不可用。老版本的Kubernetes提供了rolling-update(滚动升级)功能来解决上述问题。滚动升级通过执行kubectl rolling-update命令一键完成,该命令创建了一个新的RC,然后自动控制旧的RC中的Pod副本数量逐渐减少到0,同时新的RC中的Pod副本数量从0逐步增加到目标值,最终实现了Pod的升级。需要注意的是,系统要求新的RC需要与旧的RC在相同的命名空间(Namespace)内,即不能把别人的资产偷偷转移到自家名下,现在使用deployment,只需要用如下办法即可实现滚动升级:

假如后续我们eurekaserver 微服务有更新了,我们可以更新deployment.yaml 中 image: centos-master:5000/eureka 例如修改为2.0新版本image: centos-master:5000/eureka:v2.0 (前提创建了这个新版镜像)[root@centos-master k8s]#kubectl apply -f deployment.yaml deployment "eurekaserver-deploy" configured

这样就完成了滚动升级,同时deployment可以支持升级暂停等。

3.4 微服务在线扩容

将pods拉伸至5,只需修改配置文件中的replicas: 5 就会从2个POD扩容到5个

[root@centos-master k8s]# kubectl replace -f deployment.yaml

deployment "deployment.yaml " replaced

3.5 在线维护

我的测试环境只有一台node,这个无法测试 :( )

将要维护的Minion节点标识为SchedulingDisabled kubectl cordon centos-minion-1

迁移要维护Minion节点上的容器 kubectl drain centos-minion-1

维护完成后,撤销SchedulingDisabled 标识 kubectl uncordon centos-minion-1

3.6 计算节点宕机处理

无需任何操作,deployment有类似于vmware HA 的机制。

4、k8s service

前面描述了k8s pod、deployment、RS,结合jenkins可以实现容器自动部署、升级、回滚、扩容、和保持生产环境一直运行指定数量的pod等,接下来实现服务的发布和负载均衡,可以使用这一节的k8s service,我理解也可以使用上一章微服务架构中的zuul和feign。实际生产还是如果采用微服务架构,还是推荐使用feign,这样可以更好的和微服务其他服务单元配合。

在实际生产环境中,对Service的访问可能会有两种来源:Kubernetes集群内部的程序(Pod)和Kubernetes集群外部,为了满足上述的场景,Kubernetes service有以下三种类型:

ClusterIP:提供一个集群内部的虚拟IP以供Pod访问。

NodePort:在每个Node上打开一个端口以供外部访问。

LoadBalancer:通过外部的负载均衡器来访问。

以LoadBalancer service为例

创建文件eurekaserver-service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
ports:
- port: 80
targetPort: 8761
selector:
app: eurekaserver

创建service

[root@centos-master k8s]# kubectl create -f eurekaserver-service.yaml

这个service代理了所有具有app: eurekaserver标签的pod(这个标签需要在创建Pod或者deployment yaml文件中指定label: - app:eurekaserver 属性),服务对外端口是80,服务ip在创建service的时候生成,也可以指定,这组ip:port在service的生命周期里保持固定。访问192.168.226.130:80的流量会被重定向到后端pod的8761端口上,就是targetPort指定的。这样只要service没有被销毁,就可以通过访问http://192.168.226.130:80:eureka 进入eureka微服务服务发现主页了,无论后端pod或deployment 如何变化,这个主页都不变。

5、namespace、密钥管理等

生产环境作用很大,结合密钥等做多租户。

6、问题和展望

写到这里,有没有发现什么小问题,本章开始建的私有仓库没有做数据持久化,所有创建的容器也没有做数据持久化,导致每次只要服务重启就仓库的镜像就没有了需要重新创建,我总结了一下,实现容器数据持久化主要有如下一些方法:

1、容器通过访问当前宿主机上的指定目录实现同主机之间共享目录,将容器运行的数据存放在宿主机上实现容器数据持久化。

2、通过共享卷方式为容器提供持久化存储,共享卷分为块存储(如ceph、EMC VPLEX等)、文件存储(如NFS、HDFS、NETAPP等)、对象存储(OpenStack swift, ceph rgw等),共享型的卷存储能够很方便地支持容器在集群各节点之间的迁移,另外由于对象存储是通过URL访问的,是一种无状态的架构,符合云原生应用架构,应该是最符合容器持久化存储需求的,当然从性能上看肯定还是块存储最好,所以要根据容器应用的特点选择合适的共享存储。

3、将容器和持久化存储绑定在一起,实现同步运行和迁移。如ClusterHQ的Flocker,flocker将docker容器和数据卷目录整合在一起,当你用flocker管理你的有状态服务时,数据卷目录将会跟随你的容器在不同的主机上运行。

最简单的可以在创建pod时将容器的文件映射到node主机上实现,但是如果发生pod跨node迁移数据就没有了,这里我推荐使用Kubernetes的的 Persistent Volumes(就是开篇概念里面讲的那个Volumes),它可以实现以上集中方式的数据持久化,微服务容器数据持久化还是非常重要的,K8S看来一篇也写不完。实验环境机器的配置越来越捉襟见肘了,不知道再往后面能不能跑的动,准备自购服务器了。。。。。。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

2

添加新评论1 条评论

#doitroot研发工程师, nikoyo
2018-05-31 09:41
有用,Thanks a lot!
Ctrl+Enter 发表

关于TWT  使用指南  社区专家合作  厂商入驻社区  企业招聘  投诉建议  版权与免责声明  联系我们
© 2019  talkwithtrend — talk with trend,talk with technologist 京ICP备09031017号-30