引子
现在微服务非常火,也带火了 Docker。因为微服务很适合用 Docker 容器实现,每个容器承载一个服务。一台计算机同时运行多个容器,从而就能很轻松地模拟出复杂的微服务架构。于是乎 Docker 的人气迅速攀升,速度之快,令人瞠目结舌。
就在 Docker 容器技术被炒得热火朝天之时,大家发现,如果想要将 Docker 应用于具体的业务实现,是存在困难的——编排、管理和调度等各个方面,都不容易。于是,人们迫切需要一套管理系统,对 Docker 及容器进行更高级更灵活的管理。
就在这个时候,K8S 出现了。
K8S,就是基于容器的集群管理平台,它的全称,是kubernetes。
Kubernetes 是谷歌开源的 Docker 容器集群管理系统,主要为容器化的服务提供资源调度、扩容、缩容以及部署等功能。
其实从 Kuberbetes 就可以看出了它的用途,这个单词源于古希腊,意思是舵手,Docker的 logo 是一条鲸鱼,那么 Kubernetes 就是鲸鱼赖以生存的地方-海洋的领导者;它诞生的时间有点晚,15 年 7 月份才出现第一个版本,不过一出生就大受欢迎,很多包括 IBM、红帽、微软等巨头都纷纷参与进来。
下面就带你认识一下 Kubernetes,并用他来实现革命性的hello,world!
Kubernetes一直被雪藏的前身
过去十几年,谷歌一直有个秘密武器:Borg
。Borg 一直以来都是谷歌内部使用的大规模集群管理系统,Borg 是基于容器技术发展起来的,主要还是实现资源管理的自动化和在跨多个数据中心的背景下的提高资源的利用率,谷歌一直视 Borg 为传家宝,哪怕员工离职都不能透漏给外界,直到 2015 年谷歌才公开,也就是说 Kubernetes 其实是 Borg 的一个开源版本。
使用Kubernetes?给我一个理由!
第一,方便。如果我们的系统设计遵循了 Kubernetes 的设计思想,那么传统系统架构中与业务没有什么关系的底层代码、功能模块之类的我们都可以不用考虑了,我们不用再把精力耗费在负载均衡器的选型和部署实施等问题,也不用考虑引入甚至是自己开发一个复杂的服务治理框架,更不用为这些头疼了:服务监控、故障处理等。总之,Kubernetes 就是解放我们的精力的,好让我们更加专注于业务本身来做开发。
第二,开放。Kubernetes 可以兼容所有的语言,所有的编程接口也都能兼容,不管你用什么语言写的都可以映射为 Kubernetes 的 Service 以及通过标准的 TCP 通信协议进行交互,更大好处是,现有的系统也可以改造升级并迁移到 Kubernetes 平台上;
第三,强大。经过十几年的发展,Kubernetes 已经成为了非常完备的分布式系统支撑平台,拥有极其强大的集群管理能力:多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建智能负载均衡器、还能够及时发现故障并自我修复、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制、多粒度的资源配额管理……太多了,不一而足!
IT 我们都知道技术更新换代快得比你换衣服都快,Docker 这个容器化技术的明星已经如此普及,从单机到集群这已经是个不可逆转的大趋势,云计算也是如火如荼的进行着,Kubernetes 是业界公认的目前为止唯一一个 Docker 分布式系统解决方案。
开始之前你总得知道这些!
不过先别着急,再开始之前你总得先有点知识储备才行,就像学习 Java 的时候也不是上来就写hello,world
而是先学一些与或非、数据类型等知识才开始。
在 Kubernetes 中 Service 就是分布式集群架构的核心,一个 Service 具有一下几个关键的特征:
-
拥有一个位置指定的名字,就如同数据库中的主键;
-
拥有一个虚拟的 IP 和端口号;
-
拥有提供远程服务的能力并能够映射到提供这种服务的一组容器应用上;
目前,Service 都是基于 Socket 通信方式或者是实现了某个具体业务的一个特定 TCP Server 进程来提供服务的,虽然一个 Service 通常都是由多个相关的服务进程来提供服务,而且每个服务进程都有一个独立的 EndPoint(IP + Port)访问点,但是!但是 Kubernetes 可以让我们通过虚拟 Cluster IP + Service Port 连接到指定的 Service上。
有了 Kubernetes 内建的透明负载均衡和故障恢复机制,哪怕后端有再多的服务进程,哪怕有再多的服务进程会由于故障而重新部署到其他的机器,都不会影响到我们对服务的正常调用;
Kubernetes 一旦创建就不会再发生变化,这也意味着,在 Kubernetes 集群中我们再也不用为了 IP 地址的频繁变动而头疼了。
容器的其中一个好处就是拥有强大的隔离功能,所以必须把为 Service 提供服务的这组进程放到容器中进行隔离,Kubernetes 的 Pod 对象就是干这事的,每个服务进程包装到相应的 Pod 中使其成为 Pod 中运行的一个 Container(容器)。
为了建立 Service 和 Pod 之间的关联,Kubernetes 会给每个 Pod 贴身一个 Label(标签),然后给相应的 Service 定义 Label Selector(标签选择器)。
那么,Pod 又是个什么东东?
Pod 运行在 Node(节点)中,这个节点既可以是物理机也可以是公有云或者是私有云中的虚拟机,通常一个节点上运行着几百个 Pod。
每个 Pod 中都运行着一个叫做 Pause 的容器和一些业务容器,为了提高通信和数据交换的效率,这些业务容器共享 Pause 容器的网络栈和 Volume 挂载卷,我们可以利用这个特性把一组密切相关的服务进程放到同一个 Pod 中。
不过,有一点需要注意:不是每一个 Pod 及其里面扥容器都能“映射”到一个 Service 上,只要那些提供对外或者队内的服务的一组 Pod 才能“映射”成一个服务。
在集群管理方面,Kubernetes 把集群中的机器划分成一个 Master 节点和一群工作节点,前者运行着与集群管理相关的进程,工作节点运行着应用程序。
在 Kubernetes 集群中,扩容的话你只需要为与 Service 关联的 Pod 创建一个 Replication Controller,Replication Controller 文件至少包含一下信息:
-
目标 Pod 定义;
-
目标 Pod 需要运行的副本数量;
-
要监控的目标 Pod 的标签;
创建好 Replication Controller 后。Kubernetes 会通过 Replication Controller 中定义的标签来筛选出对应的Pod实例并实时监控状态和数量,如果实例数量少少于副本数量则会根据 Replication Controller 中定义的 Pod 模板来创建一个新的 Pod,再把这个 Pod 调度到合适的 Node 上启动运行,直到 Pod 实例数量达到预定目标。
凡事都得从hello,world开始
这里hello,world
是一个 Web 留言板应用,是个基于 PHP + Redis 的两层分布式架构的 Web 应用,这是留言板的系统部署架构图:
Web留言板的系统部署架构图
三个 Docker 镜像:
-
redis-master
:用于前端 Web 应用进行写留言的操作,其中已经保存了一条“hello,world”。 -
guestbook-redis-slave
:用于前端 Web 应用进行读留言的操作,并且和 redis-master 的数据保持同步。 -
guestbook-php-frontend
:PHPWeb 服务,在网页上显示留言内容,同时提供一个文本输入框供访问者添加留言。
这是 Kubernetes 部署架图:
Kubernetes 部署架图
下面我们一起开始手把手的教大家利用 k8s 搭建一个hello,world
应用。注意,本文使用的是 centos 操作系统。
首先,我们需要开启路由转发功能,如果不执行此步骤容器不能访问外网:
echo 1 > /proc/sys/net/ipv4/ip_forward
然后,我们在配置 yum 源:
yum install -y epel-release
yum clean all
yum list
再接着,我们安装 Docker。
yum install -y docker-io
Docker 安装完毕后,我们就开始搭建 Kunernetes 运行环境了。
## 关闭防火墙
systemctl disable firewalld
suystemctl stop firewalld
## 再安装 etcd 和 Kubernetes 软件
yum install -y etcd
yum install -y kubernetes
然后修改 Docker 的配置文件 /etc/sysconfig/docker,OPTIONS 修改如下:
OPTIONS='--selinux-enabled=false --insecure-registry gcr.io'
注意,Docker 镜像源建议采用国内的镜像源。通用的方法就是编辑/etc/docker/daemon.json
:
{
"registry-mirrors" : [
"http://ovfftd6p.mirror.aliyuncs.com",
"http://registry.docker-cn.com",
"http://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com"
],
"insecure-registries" : [
"registry.docker-cn.com",
"docker.mirrors.ustc.edu.cn"
],
"debug" : true,
"experimental" : true
}
然后重启 Docker 的 daemon 即可。
systemctl daemon-reload
systemctl restart docker
再接着修改 Kubernetes 的 apiserver 配置文件 /etc/kubernetes/apiserver:
将 –admission_control 参数中的 ServiceAccount 删除。
然后按照顺序启动所有的服务:
systemctl start etcd
systemctl start docker
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl start kubelet
systemctl start kube-proxy
检查上述服务是否都已经启动成功,如果都已经成功则 kubernetes 集群环境就已经安装完毕。
为 Redis-master 服务创建 RC 文件,语法格式为 ymal。
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 1
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: kubeguide/redis-master
ports:
- containerPort: 6379
然后在 Master 节点中执行命令:Kubectl create -f<config_file>
,并把它发布到 Kubernetes 集群中:
$ kubectl create -f redis-master-controller.yaml
replicationcontrollers/redis-master
然后再创建与之关联的 Service。service 对应的文件 redis-master-service.yaml,内容如下:
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
name: redis-master
spec:
ports:
- port: 6379
targetPort: 6379
selector:
name: redis-master
创建 redis-master service。
kubectl create -f redis-master-service.yaml
接着,再创建 redis-slave 服务,与前者一样,先创建 redis-slave 的 RC 定义文件 redis-salve-controller.yaml
。
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-slave
labels:
name: redis-slave
spec:
replicas: 2
selector:
name: redis-slave
template:
metadata:
labels:
name: redis-slave
spec:
containers:
- name: slave
image: kubeguide/guestbook-redis-slave
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 6379
然后创建 redis-salve 对应的 Pod。
kubectl create -f redis-salve-controller.yaml
Pod 创建完成后,创建对应的 service。先创建 service 的配置文件redis-salve-service.yaml
,内容如下:
apiVersion: v1
kind: Service
metadata:
name: redis-slave
labels:
name: redis-slave
spec:
ports:
- port: 6379
selector:
name: redis-slave
然后根据配置文件,创建 service。
kubectl create -f redis-slave-service.yaml
为了实现 Redis 集群的主从数据同步,redis-slave 需要知道 redis-master 的地址,所以我们需要在 redis-slave 镜像的启动命令/run.sh
中添加:
redis-server --slaveof ${REDIS_MASTER_SERVICE_HOST} 6379
最后,创建 frontend 的 RC 文件frontend-controller.yaml
,内容如下:
apiVersion: v1
kind: ReplicationController
metadata:
name: frontend
labels:
name: frontend
spec:
replicas: 3
selector:
name: frontend
template:
metadata:
labels:
name: frontend
spec:
containers:
- name: frontend
image: kubeguide/guestbook-php-frontend
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 80
然后在运行kubectl create
命令创建 RC:
$ kubectl create -f frontend-controller.yaml
replcationcontrollers/frontend
再创建与之关联的 Service,frontend-service.yaml
内容如下:
apiVersion: v1
kind: Service
metadata:
name: frontend
labels:
name: frontend
spec:
type: NodePort
ports:
- port: 80
nodePort: 30001
selector:
name: frontend
最后一步,创建 service。
$ kubectl create -f frontend-service.yaml
services/frontend
下面就可以打开浏览器输入:http://虚拟机IP:30001
之后就会出现hello,world
,成功了就这这样:
Web留言板界面运行效果图
总结
这就是 Kubernetes,实现了hello,world
就算是一只脚踏进来了,Kubernetesde 的好处太多了,最直接的好处就是可以轻装上阵开发复杂的系统,架构师专注于“服务组件”,剩下的人则负责业务代码的开发,而且 Kubernetes 还是实现微服务的利器,微服务其实就是一个巨无霸给拆成一个个小单体的过程,Kubernetes 来做这事无疑是最佳人选!