前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第4课 在k8s集群运行一个极简的web APP

第4课 在k8s集群运行一个极简的web APP

作者头像
辉哥
修改2021-11-24 13:36:15
5530
修改2021-11-24 13:36:15
举报
文章被收录于专栏:区块链入门
摘要

本文是《Kubernetes权威指南:从Docker到Kubernetes实践全接触》的实践篇,把该书的第一个案例在环境上完整跑起来,补充一些比较的信息,便于学习者参考。

实践内容

本示例是一个运行在Tomcat里的Web App,如图1.1所示,JSP页面通过JDBC直接访问MySQL数据库并展示数据。出于演示和简化的目的,只要程序正确连接到了数据库,就会自动完成对应的Table的创建与初始化数据的准备工作。所以,当我们通过浏览器访问此应用时,就会显示一个表格的页面,数据则来自数据库。

JAVA WEB APP

2.1.2.1.1 MySQL容器

(1)下载docker镜像

代码语言:javascript
复制
# 本案例有一个大坑,kubeguide/mysql-master:latest对应的是mysql8.0的版本,跟java无法匹配。
# 需要采用5.7的版本。
#docker pull kubeguide/mysql-master:latest

$ docker pull mysql:5.7

(2)创建编辑RC资源文件

mysql-rc.yaml:

代码语言:javascript
复制
apiVersion: v1
kind: ReplicationController
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        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,陷入恶性循环中。

(3)发布到kubernetes集群中:

代码语言:javascript
复制
$ kubectl create -f mysql-rc.yaml

(4)查看资源创建情况

用kubectl命令查看刚刚创建的RC

代码语言:javascript
复制
$ kubectl get rc
NAME    DESIRED   CURRENT   READY   AGE
mysql   1         1         0       9s

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

代码语言:javascript
复制
$ kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE    IP           NODE        NOMINATED NODE   READINESS GATES
mysql-dcr5z   1/1     Running   0          114s   10.244.2.2   k8s-node1   <none>           <none>

可以看到其在k8s-node1节点运行。在k8s-node1节点,我们通过docker ps指令查看正在运行的容器:

代码语言:javascript
复制
$ docker ps |grep mysql
167e968bd621        mysql                  "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes                            k8s_mysql_mysql-dcr5z_default_55c116e6-aa2c-402e-87dd-2fcbc4877010_0
51ae0f275c3c        k8s.gcr.io/pause:3.2   "/pause"                 3 minutes ago       Up 3 minutes                            k8s_POD_mysql-dcr5z_default_55c116e6-aa2c-402e-87dd-2fcbc4877010_0

(4)创建ubernetes Service

创建一个与之关联的Kubernetes Service——MySQL的定义文件,完整的内容和解释如下:

mysql-svc.yaml :

代码语言:javascript
复制
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql

(5)运行kubectl命令,创建Service:

代码语言:javascript
复制
$ kubectl create -f mysql-svc.yaml

(6)查看创建的Service情况

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

代码语言:javascript
复制
$  kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    22h
mysql        ClusterIP   10.107.219.146   <none>        3306/TCP   14s

可以发现,MySQL服务被分配了一个值为10.107.219.146的Cluster IP地址。随后,Kubernetes集群中其他新创建的Pod就可以通过Service的Cluster IP+端口号3306来连接和访问它了。通常,Cluster IP是在Service创建后由Kubernetes系统自动分配的,其他Pod无法预先知道某个Service的Cluster IP地址,因此需要一个服务发现机制来找到这个服务。为此,最初时,Kubernetes巧妙地使用了Linux环境变量(Environment Variable)来解决这个问题,后面会详细说明其机制。现在只需知道,根据Service的唯一名称,容器可以从环境变量中获取Service对应的Cluster IP地址和端口,从而发起TCP/IP连接请求。

(7)其他Kubectl命令测试

我们可以执行下述命令查看在集群中有多少个Node:

代码语言:javascript
复制
$  kubectl get nodes
NAME         STATUS   ROLES                  AGE   VERSION
k8s-master   Ready    control-plane,master   22h   v1.20.5
k8s-node1    Ready    worker                 14h   v1.20.5
k8s-node2    Ready    worker                 22h   v1.20

通过kubectl describe node <node_name>查看某个Node的详细信息:

代码语言:javascript
复制
$  kubectl describe node k8s-master

可以用kubectl describepod xxxx来查看它的描述信息,以定位问题的成因:

代码语言:javascript
复制
$ kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
mysql-dcr5z   1/1     Running   0          7m3s

$ kubectl describe pod mysql-dcr5z

Name:         mysql-dcr5z
Namespace:    default
Priority:     0
Node:         k8s-node1/192.168.0.3
Start Time:   Tue, 17 Aug 2021 11:39:20 +0800
Labels:       app=mysql
Annotations:  <none>
Status:       Running
...

可以通过执行kubectl scale命令来一键完成:

代码语言:javascript
复制
$  kubectl scale rc mysql --replicas=3

$ kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE   IP           NODE        NOMINATED NODE   READINESS GATES
mysql-4gnp5   1/1     Running   0          60s   10.244.2.4   k8s-node1   <none>           <none>
mysql-7pv7f   1/1     Running   0          60s   10.244.2.3   k8s-node1   <none>           <none>
mysql-dcr5z   1/1     Running   0          10m   10.244.2.2   k8s-node1   <none>           <none>

可知,这3个pods都被k8s自动分配到k8s-node1节点了。

需要注意的是,删除RC并不会影响通过该RC已创建好的Pod。为了删除所有Pod,可以设置replicas的值为0,然后更新该RC。另外,kubectl提供了stop和delete命令来一次性删除RC和RC控制的全部Pod。

2.1.2.2.2 Tomcat应用

(1)下载镜像:

代码语言:javascript
复制
$ docker search kubeguide
NAME                   DESCRIPTION             STARS           OFFICIAL       AUTOMATED
kubeguide/redis-master             redis-master with "Hello World!"                33     
kubeguide/tomcat-app               Tomcat image for Chapter 1                      30     kubeguide/guestbook-php-frontend   Guestbook PHP website                           25     
kubeguide/guestbook-redis-slave    Guestbook redis slave                           23     
kubeguide/mysql-master             mysql master                                    6  [OK]
kubeguide/hadoop                                                                   5     
kubeguide/centos7-ansible          ansible with sshpass tool installed and sshk…   4     

$ docker pull kubeguide/tomcat-app:v2

(2)创建对应的RC文件myweb-rc.yaml:

代码语言:javascript
复制
apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb
spec:
  replicas: 3
  selector:
    app: myweb
  template:
    metadata:
      labels:
        app: myweb
    spec:
      containers:
      - name: myweb
        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。

(3)发布到集群中:

代码语言:javascript
复制
$ kubectl create -f myweb-rc.yaml

(4)创建对应的Service(myweb-svc.yaml):

代码语言:javascript
复制
apiVersion: v1
kind: Service
metadata:
  name: myweb
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 31330
  selector:
    app: myweb

type=NodePort和nodePort=31330的两个属性表明此Service开启了NodePort方式的外网访问模式。在Kubernetes集群之外,比如在本机的浏览器里,可以通过31330这个端口访问myweb(对应到8080的虚端口上)。

采用netstat -nltp|grep 31330 命令来确认在service运行前,端口是否已被占用。

(5)运行kubectl create命令进行创建:

代码语言:javascript
复制
$ kubectl create -f myweb-svc.yaml

注意:记得防火墙打开31330端口。

(6)运行kubectl命令,查看创建的Service:

代码语言:javascript
复制
$ kubectl get services -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          23h   <none>
mysql        ClusterIP   10.107.219.146   <none>        3306/TCP         12m   app=mysql
myweb        NodePort    10.109.12.156    <none>        8080:31330/TCP   36s   app=myweb

查看pods情况:

代码语言:javascript
复制
$ kubectl get pods -o wide

NAME          READY   STATUS    RESTARTS   AGE     IP           NODE        NOMINATED NODE   READINESS GATES
mysql-4gnp5   1/1     Running   0          8m5s    10.244.2.4   k8s-node1   <none>           <none>
mysql-7pv7f   1/1     Running   0          8m5s    10.244.2.3   k8s-node1   <none>           <none>
mysql-dcr5z   1/1     Running   0          17m     10.244.2.2   k8s-node1   <none>           <none>
myweb-b2kfl   1/1     Running   0          3m46s   10.244.1.4   k8s-node2   <none>           <none>
myweb-nblv5   1/1     Running   0          3m46s   10.244.1.3   k8s-node2   <none>           <none>
myweb-rxws6   1/1     Running   0          3m46s   10.244.1.2   k8s-node2   <none>           <none>

可知,有3个mysql分布在k8s-node1上,3个myweb分布在k8s-node2上。

2.1.2.2.3 测试

请确认对应的网络安全组已打开端口31330. 例如在windows下采用 psping 114.67.107.240:31330 确认端口已打开。

在浏览器输入http://虚拟机IP(外网):31330/demo/。比如虚拟机IP为114.67.107.240 (可以通过#ip a命令进行查询),在浏览器里输入地址http://114.67.107.240:31330/demo/后,可以看到如图1.2所示的网页界面。

问题描述:

先测试下服务是否联通。

代码语言:javascript
复制
# 测试获取web服务是否已启动。
curl http://192.168.0.3:31330/demo/


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
...
<h3> Error:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.</h3>

此时表示无法跟MySql服务器链接。查看pods的打印信息:

代码语言:javascript
复制
p# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
mysql-ppzgm   1/1     Running   0          48m
myweb-87j84   1/1     Running   0          28m
myweb-drqg9   1/1     Running   0          28m
myweb-dtfdt   1/1     Running   0          28m
myweb-gcfh5   1/1     Running   0          28m
myweb-kzcxc   1/1     Running   0          28m
root@k8s-master:/data/k8s/JavaWebApp# kubectl logs myweb-87j84
30-Jul-2021 06:33:35.868 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/8.0.35
30-Jul-2021 06:33:35.869 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          May 11 2016 21:57:08 UTC
...
30-Jul-2021 06:33:45.065 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 746 ms
Connecting to database...
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    
    ... 39 more
Goodbye!

说明:

从github issue:https://github.com/kubeguide/K8sDefinitiveGuide-V4-Sourcecode/issues/7 找到原因:

1.3.3 myweb-rc.yaml 镜像用的mysql-connector-java-5.1.37.jar,不兼容1.3.2 mysql-rc.yaml默认镜像 mysql 8,导致连接失败,需要将1.3.2 mysql-rc.yaml 指定mysql5.7版本。

代码语言:javascript
复制
# 需要采用5.7的版本。
docker pull mysql:5.7

# 删除已运行的RC
kubectl delete -f mysql-rc.yaml

# 删除已运行的RC
kubectl delete -f myweb-svc.yaml
参考

(1)本书示例中的Docker镜像下载地址为: https://hub.docker.com/u/kubeguide/

(2)https://github.com/kubeguide/K8sDefinitiveGuide-V4-Sourcecode

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/8/17 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 摘要
  • 实践内容
    • 2.1.2.1.1 MySQL容器
      • 2.1.2.2.2 Tomcat应用
        • 2.1.2.2.3 测试
        • 参考
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档