K8S权威指南之从一个例子开始
从一个简单的例子开始
考虑到kubernetes提供的PHP+redis留言板的hello world例子对于绝大多数新手来说比较复杂,在这里替换成一个简单得多的java web应用的例子,可以快速上手。
该应用是在一个运行在tomcat里的web app结构比较简单,如图所示,JSP页面通过JDBC直接访问mysql数据库并展示数据。为了简化,这里只要连接上数据库就会创建相关的table。所以访问时会显示一个表格,来自数据库。
不懂java的朋友可能不知道JDBC,这个是JAVA连接数据库的程序并且可以进行操作,是一个接口程序,避免直接在终端直接操作。
环境准备
这里先安装K8S和下载相关镜像,这里可以用VMware或者virtualbox虚拟机。使用NAT模式。
启动MYSQL服务创建一个Deloyment定义文件mysql-deployment.yaml,下面给出该文件完整的内容说明:
apiVersion: apps/v1 # apiserver的版本
kind: Deployment # 副本控制器deployment,管理pod和RS
metadata:
label: #标签
app: mysql
name: mysql # deployment的名称,全局唯一
spec:
replicas: 1 # Pod副本期待数量
selector:
matchLabels: # 定义RS的标签
app: mysql # 符合目标的Pod拥有此标签
strategy: # 定义升级的策略
type: RollingUpdate # 滚动升级,逐步替换的策略
template: # 根据此模板创建Pod的副本(实例)
metadata:
labels:
app: mysql # Pod副本的标签,对应RS的Selector
spec:
nodeName: ysp1 # 指定pod运行在的node
containers: # Pod里容器的定义部分
- name: mysql # 容器的名称
image: mysql:5.7 # 容器对应的docker镜像
volumeMounts: # 容器内挂载点的定义部分
- name: time-zone # 容器内挂载点名称
mountPath: /etc/localtime # 容器内挂载点路径,可以是文件或目录
- name: mysql-data
mountPath: /var/lib/mysql # 容器内mysql的数据目录
- name: mysql-logs
mountPath: /var/log/mysql # 容器内mysql的日志目录
ports:
- containerPort: 3306 # 容器暴露的端口号
env: # 写入到容器内的环境容量
- name: MYSQL_ROOT_PASSWORD # 定义了一个mysql的root密码的变量
value: "456789"
volumes: # 本地需要挂载到容器里的数据卷定义部分
- name: time-zone # 数据卷名称,需要与容器内挂载点名称一致
hostPath:
path: /etc/localtime # 挂载到容器里的路径,将localtime文件挂载到容器里,可让容器使用本地的时区
- name: mysql-data
hostPath:
path: /data/mysql/data # 本地存放mysql数据的目录
- name: mysql-logs
hostPath:
path: /data/mysql/logs # 本地存入mysql日志的目录
以上YAML定义文件中的kind属性用来表明此资源对象的类型,比如这里的属性值表示这是一个Deployment; spec部分是Deployment的相关属性定义,比如spec.selector是Deployment的pod选择器,符合条件的pod实例会受到Deployment的管理,确保在当前集群中始终有且仅有replicas个实例在运行(这里设置replicas=1,表示只能运行一个mysql实例)。当在集群中运行的pod的数量少于replicas时,Deployment控制器会根据在spec.template部分定义的pod模板生成一个新的pod实例,spec.template.metadata.labels指定了该pod的标签,labels必须匹配之前的spec.selector.
创建好mysql-deployment.yaml文件后,为了将它发布到kubernetes集群中,我们在master上运行如下命令:
可以看到一个mysql的pod实例,这是kubernetes根据mysql这个deployment的定义自动创建的pod,由于pod的调度和创建需要花费一定的时间,比如需要调度的节点,下载实例镜像,所以开始pod的状态为pending。在pod成功创建启动后,其状态最终会更新为running。
我们可以在kubernetes节点服务器上通过docker ps指令查看正在运行的容器,发现提供mysql服务的pod已经创建而且正常运行,并且mysql pod对应的容器多创建了一个pause容器,该容器就是pod的根容器。其它容器会复用它的网络存储。
最后创建一个与之关联的kubernetes service-mysql的定义文件(文件名为mysql-svc.yaml)完整说明如下
apiVersion: v1
kind: Service #表明是kubernetes service
metadata:
name: mysql-service #service的全局唯一名称
spec:
ports:
- port: 3306 #service提供服务的端口号
selector: #service对应的pod拥有这里定义的标签
app: mysql
其中,metadata.name是service的服务名(serviceName);spec.port属性定义了service的虚端口;spec.selector确定了哪些pod副本(实例)对应本服务。类似地,我们通过kubectl create命令创建service对象:
可以发现,mysql服务被分配了一个值为10.245.161.22的clusterIP地址(在不同环境分配的IP地址可能不同)。随后,在kubernetes集群中新创建的其它pod就可以通过service的clusterIP+端口号3306来连接和访问它。
一般来说,clusterIP地址是service创建后由kubernetes系统自动分配的,其它pod无法预知某个service的clusterip地址,因此需要一个服务发现机制来找到这个服务。为此,kubernetes巧妙的使用了linux环境变量来解决这个问题。根据service的唯一名称,容器可以从环境变量中获取service对应的ClusterIP地址和端口号,从而发起TCP/IP连接请求。
启动Tomcat应用
前面定义和启动mysql服务,接下来采用同样的步骤完成tomcat应用的启动。首先,创建对应的RCs文件myweb-deploy.yaml,内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myweb
name: myweb
spec:
replicas: 2
selector:
matchLabels:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- image: kubeguide/tomcat-app:v1
name: myweb
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_HOST
value: 10.245.161.22
注意:在tomcat容器内,在应用将使用环境变量MYSQL_SERVICE_HOST的值连接mysql服务,但这里为什么没有注册该环境变量呢,这是因为会自动将已存在的service对象以环境变量的形式展现在新生成的pod中。其更安全,可靠的方法使用服务的名称mysql,这就要求集群内的DNS服务(kube-dns)正常运行。运行下面的命令,完成deployment的创建和验证工作:
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
selector:
app: myweb
"type:Nodeport"和"nodePort:30001"表明service开启了NodePort格式的外网访问模式,比如,在kubernetes集群外,客户端的浏览器通过30001端口访问myweb(对应8080)的需端口。运行kubectl create命令创建
通过浏览器访问网页
经过上面的流程,我们终于成功实现了kubernetes上第一个例子的部署,搭建工作。现在在浏览器上输入http://虚拟机IP:30001/demo/".
如果无法打开一般原因如下:
-
防火墙阻断了30001端口,测试可以选择关闭防火墙
-
因为通过代理服务器上网,浏览器可能会把虚拟机IP当作远程地址,可在虚拟机上运行curl 192.168.18.131:30001验证能都访问,如果不能,可能是自身K8S集群没有安装好。
接下来尝试单击ADD按钮,提交一条数据如图:
至此,我们完成了在kubernetes上部署一个web app和数据库的例子,可以看到,相对于传统的分布式应用部署方式,在kubernets之上仅通过容易理解的配置文件和命令就可以进行集群部署。