kubernetes入门案例

kubernetes入门案例

本文我们通过一个 Java Web 应用例子来介绍 kubernetes 的使用,可以让新手快速上手和实践。

此 Java Web 应用的结构比较简单,是一个运行在 Tomcat 里的 Web App,JSP 页面通过 JDBC 直接访问 MySQL

数据库并展示数据。出于演示和简化的目的,只要程序正确连接到了数据库,就会自动完成对应的 Table 的创建与

初始化数据的准备工作。所以,当我们通过浏览器访问此应用时,就会显示一个表格的页面,数据则来自数据库。

kubernetes入门案例_第1张图片

此应用需要启动两个容器:Web App 容器和 MySQL 容器,并且 Web App 容器需要访问 MySQL 容器。在

Docker 时代,假设我们在一个宿主机上启动了这两个容器,就需要把 MySQL 容器的 IP 地址通过环境变量注入

Web App 容器里;同时,需要将 Web App 容器的 8080 端口映射到宿主机的 8080 端口,以便在外部访问。在本

文的这个例子里,我们介绍在 Kubernetes 时代是如何达到这个目标的。

1、环境准备

首先需要安装 kubernetes 集群,这里我们将不在介绍安装,安装请参考其它文章,本文的环境:

[root@master ~]# kubectl get nodes
NAME      STATUS   ROLES                  AGE     VERSION
master    Ready    control-plane,master   6m5s    v1.21.0
master2   Ready    control-plane,master   4m57s   v1.21.0
slave1    Ready    <none>                 5m30s   v1.21.0
slave2    Ready    <none>                 5m28s   v1.21.0
[root@master ~]# kubectl get pods --all-namespaces
NAMESPACE     NAME                                      READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-b86879b9b-mb6hk   1/1     Running   0          24s
kube-system   calico-node-6v5kp                         1/1     Running   0          24s
kube-system   calico-node-c8l7v                         1/1     Running   0          24s
kube-system   calico-node-grlqh                         1/1     Running   0          24s
kube-system   calico-node-mr8rk                         1/1     Running   0          24s
kube-system   coredns-545d6fc579-42cxc                  1/1     Running   0          5m33s
kube-system   coredns-545d6fc579-lzgbz                  1/1     Running   0          5m33s
kube-system   etcd-master                               1/1     Running   0          5m49s
kube-system   etcd-master2                              1/1     Running   0          4m45s
kube-system   kube-apiserver-master                     1/1     Running   0          5m49s
kube-system   kube-apiserver-master2                    1/1     Running   0          4m49s
kube-system   kube-controller-manager-master            1/1     Running   1          5m49s
kube-system   kube-controller-manager-master2           1/1     Running   0          4m49s
kube-system   kube-proxy-8gj54                          1/1     Running   0          5m22s
kube-system   kube-proxy-9vc8c                          1/1     Running   0          4m49s
kube-system   kube-proxy-lpfnx                          1/1     Running   0          5m33s
kube-system   kube-proxy-mvphs                          1/1     Running   0          5m20s
kube-system   kube-scheduler-master                     1/1     Running   1          5m49s
kube-system   kube-scheduler-master2                    1/1     Running   0          4m49s

本文使用的 Docker 镜像地址: https://hub.docker.com/u/kubeguide/

2、启动MySQL服务

为 MySQL 服务创建一个 RC 定义文件 mysql-rc.yaml

apiVersion: v1
# 副本控制器RC
kind: ReplicationController
metadata:
  # RC的名称,全局唯一
  name: mysql
spec:
  # Pod副本的期待数量
  replicas: 1
  selector:
    # 符合目标的Pod拥有此标签
    app: mysql
    # 根据此模板创建Pod的副本(实例)
  template:
    metadata:
      labels:
        # Pod副本拥有的标签,对应RC的Selector
        app: mysql
    spec:
      # Pod内容器的定义部分
      containers:
        # 容器的名称
        - name: mysql
          # 容器对应的Docker Image
          image: mysql:5.7
          ports:
            # 容器应用监听的端口号
            - containerPort: 3306
          # 注入容器内的环境变量
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "123456"

以上 YAML 定义文件中的 kind 属性用来表明此资源对象的类型,比如这里的值为 ReplicationController,表示这

是一个 RC ;在 spec 一节中是 RC 的相关属性定义,比如 spec.selector 是 RC 的 Pod 标签选择器,即监控和管

理拥有这些标签的 Pod 实例,确保在当前集群中始终有且仅有 replicas 个 Pod 实例在运行,这里设置

replicas=1,表示只能运行一个 MySQL Pod 实例。当在集群中运行的 Pod 数量少于 replicas 时,RC 会根据在

spec.template 一节中定义的 Pod 模板来生成一个新的 Pod 实例,spec.template.metadata.labels 指定了该

Pod 的标签,需要特别注意的是:这里的 labels 必须匹配之前的 spec.selector,否则此 RC 每创建一个无法匹配

Label 的 Pod,就会不停地尝试创建新的 Pod,陷入恶性循环中。

在创建好 mysql-rc.yaml 文件后,将它发布到 kubernetes 集群中,我们在 master 上执行如下命令:

[root@master cha1]# kubectl create -f mysql-rc.yaml
replicationcontroller/mysql created

接下来,用 kubectl 命令查看刚刚创建的 RC:

[root@master cha1]# kubectl get rc -o wide
NAME    DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES                    SELECTOR
mysql   1         1         1       7m37s   mysql        mysql:5.7                 app=mysql

查看 Pod 的创建情况时,可以运行下面的命令:

# NODE=slave2表示该pod在slave2节点上创建
[root@master cha1]# kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE    IP               NODE     NOMINATED NODE   READINESS GATES
mysql-8mwkz   1/1     Running   0          8m8s   10.244.140.65    slave2   <none>           <none>

我们看到一个名为 mysql-8mwkz 的 Pod 实例,这是 kubernetes 根据 mysql 这个 RC 的定义自动创建的 Pod。

由于 Pod 的调度和创建需要花费一定的时间,比如需要一定的时间来确定调度到哪个节点上,以及下载 Pod 里的

容器镜像需要一段时间,所以我们一开始看到Pod的状态显示为 Pending。在 Pod 成功创建完成以后,状态最终

会被更新为 Running。

我们通过 docker ps 指令查看正在运行的容器,发现提供 MySQL 服务的 Pod 容器已经创建并正常运行了,此外

会发现 MySQL Pod 对应的容器还多创建了一个来自谷歌的 pause 容器,这就是 Pod 的根容器。

[root@slave2 ~]# docker ps | grep mysql
9b799e33f346   c20987f18b13                                          "docker-entrypoint.s…"   7 minutes ago    Up 7 minutes              k8s_mysql_mysql-8mwkz_default_b494d65f-2ee8-436b-8a09-ef0b220ba916_0
d18de886ae4e   registry.aliyuncs.com/google_containers/pause:3.4.1   "/pause"                 7 minutes ago    Up 7 minutes              k8s_POD_mysql-8mwkz_default_b494d65f-2ee8-436b-8a09-ef0b220ba916_85

创建一个与之关联的 kubernetes service,service 的定义文件 mysql-svc.yaml如下:

apiVersion: v1
# 表明是Kubernetes Service
kind: Service
metadata:
  # Service的全局唯一名称
  name: mysql
spec:
  ports:
    # Service提供服务的端口号
    - port: 3306
  # Service对应的Pod拥有这里定义的标签
  selector:
    app: mysql

其中,metadata.name 是 Service 的服务名;port 属性则定义了 Service 的端口;spec.selector 确定了哪些 Pod

副本(实例)对应本服务。通过下面的命令创建 service:

[root@master cha1]# kubectl create -f mysql-svc.yaml
service/mysql created

运行 kubectl 命令查看刚刚创建的 Service:

[root@master cha1]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE     SELECTOR
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          15m     <none>
mysql        ClusterIP   10.110.148.221   <none>        3306/TCP         7m12s   app=mysql

可以发现,MySQL 服务被分配了一个值为 10.110.148.221 的 Cluster IP 地址。随后,Kubernetes 集群中其他

新创建的 Pod 就可以通过 Service 的 Cluster IP+端口号3306 来连接和访问它了。

通常,Cluster IP 是在 Service 创建后由 Kubernetes 系统自动分配的,其他 Pod 无法预先知道某个 Service 的

Cluster IP地址,因此需要一个服务发现机制来找到这个服务。为此,最初时,Kubernetes 巧妙地使用了 Linux

环境变量来解决这个问题。现在只需知道,根据 Service 的唯一名称,容器可以从环境变量中获取 Service 对应的

Cluster IP 地址和端口,从而发起 TCP/IP 连接请求。

3、启动Tomcat应用

上面定义和启动了 MySQL 服务,接下来采用同样的步骤完成 Tomcat 应用的启动过程。首先,创建对应的 RC 文

myweb-rc.yaml,内容如下:

apiVersion: v1
# 副本控制器RC
kind: ReplicationController
metadata:
  # RC的名称,全局唯一
  name: myweb
spec:
  # Pod副本的期待数量
  replicas: 2
  selector:
    # 符合目标的Pod拥有此标签
    app: myweb
    # 根据此模板创建Pod的副本(实例)
  template:
    metadata:
      labels:
        # Pod副本拥有的标签,对应RC的Selector
        app: myweb
    spec:
      # Pod内容器的定义部分
      containers:
        # 容器的名称
        - name: myweb
          # 容器对应的 Docker Image
          image: kubeguide/tomcat-app:v1
          ports:
            # 容器应用监听的端口号
            - containerPort: 8080
          env:
            - name: MYSQL_SERVICE_HOST
              value: 'mysql'
            - name: MYSQL_SERVICE_PORT
              value: '3306'

注意:在 Tomcat 容器内,应用将使用环境变量 MYSQL_SERVICE_HOST 的值连接MySQL服务。更安全可靠的用

法是使用服务的名称 mysql。运行下面的命令,完成RC的创建和验证工作:

[root@master cha1]# kubectl create -f myweb-rc.yaml
replicationcontroller/myweb created
[root@master cha1]# kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
mysql-8mwkz   1/1     Running   0          10m     10.244.140.65    slave2   <none>           <none>
myweb-clht2   1/1     Running   0          8m18s   10.244.140.193   slave1   <none>           <none>
myweb-sjdhr   1/1     Running   0          8m18s   10.244.140.194   slave1   <none>           <none>

最后,创建对应的 Service,定义文件 myweb-svc.yaml

apiVersion: v1
# 表明是Kubernetes Service
kind: Service
metadata:
  # Service的全局唯一名称
  name: myweb
spec:
  type: NodePort
  ports:
    # Service提供服务的端口号
    - port: 8080
      nodePort: 30001
  # Service对应的Pod拥有这里定义的标签
  selector:
    app: myweb

type=NodePort 和 nodePort=30001 的两个属性表明此 Service 开启了 NodePort 方式的外网访问模式。在

Kubernetes 集群之外,比如在本机的浏览器里,可以通过 30001 这个端口访问myweb(对应到8080的虚端口

上)。使用下面的命令进行创建:

[root@master cha1]# kubectl create -f myweb-svc.yaml
service/myweb created

查看 service:

[root@master cha1]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE     SELECTOR
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          17m     <none>
mysql        ClusterIP   10.110.148.221   <none>        3306/TCP         8m55s   app=mysql
myweb        NodePort    10.101.194.99    <none>        8080:30001/TCP   8m33s   app=myweb

至此,我们的第1个 Kubernetes 例子便搭建完成了。

4、通过浏览器访问网页

经过上面的几个步骤,我们终于成功实现了 Kubernetes 上第1个例子的部署搭建工作。现在一起来见证成果吧!

打开浏览器输入http://192.168.43.201:30001/demo/,可以看到如下图所示的网页界面:

kubernetes入门案例_第2张图片

接下来,可以尝试单击 Add… 按钮添加一条记录并提交,如图所示,在提交以后,数据就被写入 MySQL 数据库

中了。

kubernetes入门案例_第3张图片

kubernetes入门案例_第4张图片
kubernetes入门案例_第5张图片

至此,我们终于完成了 Kubernetes 上的 Tomcat 例子,这个例子并不是很复杂。我们也看到,相对于传统的分布

式应用的部署方式,在 Kubernetes 之上我们仅仅通过一些很容易理解的配置文件和相关的简单命令就完成了对整

个集群的部署,这让我们惊诧于 Kubernetes 的创新和强大。

你可能感兴趣的:(kubernetes,kubernetes)