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/".

如果无法打开一般原因如下:

  1. 防火墙阻断了30001端口,测试可以选择关闭防火墙
  2. 因为通过代理服务器上网,浏览器可能会把虚拟机IP当作远程地址,可在虚拟机上运行curl 192.168.18.131:30001验证能都访问,如果不能,可能是自身K8S集群没有安装好。

接下来尝试单击ADD按钮,提交一条数据如图:

至此,我们完成了在kubernetes上部署一个web app和数据库的例子,可以看到,相对于传统的分布式应用部署方式,在kubernets之上仅通过容易理解的配置文件和命令就可以进行集群部署。

posted @ 2021-11-23 12:46  头发重要  阅读(203)  评论(0编辑  收藏  举报