Java Web应用:
是一个运行在 tomcat里的 Web App,如图1.1所示,JSP页面通过JDBC直接访问 MYSQL数据库并展示数据。为了演示和简化的目的,只要程序正确连接到了数据库上,它就会自动完成对应的 Table的创建与初始化数据的准备工作。所以,当我们通过浏览器访问此应用的时候,就会显示一个表格的页面,数据则来自数据库。
此应用需要启动两个容器: Web App容器和 MYSQL容器,并且 Web App容器需要访问MYSQL容器。在 Docker I时代,假设我们在一个宿主机上启动了这两个容器,则我们需要把MYSQL容器的IP地址通过环境变量的方式注入 Web App容器里;同时,需要将 Web App容器的8080端口映射到宿主机的8080端口,以便能在外部访问。
安装好k8s,启动好各种服务后,首先为MySQL服务创建一个RC定义文件:mysql-rc.yaml
apiVersion: v1
kind: ReplicationController #副本控制器RC
metadata:
name: mysql #RC的名称,全局唯一
spec:
replicas: 1 #Pod副本期待数量
selector:
app: mysql #符合目标的pod拥有此标签
template: #根据此模板创建pod的副本(实例)
metadata:
labels:
app: mysql #pod副本拥有的标签,对应RC的Selector
spec:
containers: #pod内容起的定义部分
- name: mysql #容器的名称
image: registry:5000/pre_images/mysql:5.5 #容器对应的docker image
ports:
- containerPort: 3306 #容器暴露的端口号
env: #注入到容器内的环境变量
- name: MYSQL_ROOT_PASSWORD
value: "123456"
yaml定义文件中的kind属性,用来表明此资源对象的类型,比如这里的值为“ Replication Controller,表示这是一个RC;
spec一节中是RC的相关属性定义,比如spec. selector是RC的Pod标签( Label)选择器,即监控和管理拥有这些标签的Pod实例,确保当前集群上始终有且仅有 replicas个Pod实例在运行,这里我们设置 replicas=1表示只能运行一个 MYSQLPod实例。
当集群中运行的Pod数量小于 replicas时,RC会根据 spec.template一节中定义的Pod模板来生成一个新的Pod实例, spec template. metadata.labels指定了该Pod的标签,需要特别注意的是:这里的 labels必须匹配之前的spe. selector,否则此RC每次创建了一个无法匹配 Label的Pod,就会不停地尝试创建新的Pod.
创建好redis-master-controller.yaml文件以后,在Master节点用命令将它发布到k8s集群中:
[root@node2 test]# kubectl create -f mysql-rc.yaml
replicationcontroller/mysql created
查看RC和Pod
[root@node2 test]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 1 1 1 3m49s
[root@node2 test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-g2mqw 1/1 Running 0 3m49s
docker ps查看正在运行的容器,发现mysql容器已正常运行,除此之外,还有一个来自谷歌的pause容器,这就是pod的“根”容器。
然后创建一各Service——MySQL的定义文件,mysql-svc.yaml。
apiVersion: v1
kind: Service #表明是k8s Service
metadata:
name: mysql #Service的全局唯一名称
spec:
ports:
- port: 3306 #Service提供服务的端口号
selector: #Service对应的Pod拥有这里定义的标签
app: mysql
kubectl create -f mysql-svc.yaml
查看
[root@node2 test]# kubectl get svc | grep mysql
mysql ClusterIP 10.96.114.38 3306/TCP 152m
mysql服务被分配了一个虚拟地址,随后k8s集群中其他新创建的Pod就可以通过Service的Cluster IP+端口号来连接和访问它。
启动tomcat的启动,创建一个myweb-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: myweb
spec:
replicas: 1
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'
注意到引用了MYSQL_SERVICE_HOST=mysql环境变量,而“MySQL”恰好是我们之前定义的MySQL服务的服务名,运行命令,完成创建和验证
kubectl create -f myweb-rc.yaml
[root@node2 test]# kubectl get pods | grep myweb
myweb-hlmxz 1/1 Running 0 103m
创建对应的Service
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
selector:
app: myweb
注意type=NodePort和nodePort=30001两个属性,标明此Service开启了NodePort访问的外网访问模式,在k8s集群之外,比如在本机的浏览器里,可以通过30001这个端口访问myweb9对应到8080的虚端口上)。
kubectl create -f myweb-svc.yaml
[root@node2 test]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 3d19h
mysql ClusterIP 10.96.114.38 3306/TCP 165m
myweb NodePort 10.107.166.10 8080:30001/TCP 139m
创建一个tomcat-deployment.yaml的Deployment描述文件,内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
template:
metadata:
labels:
app: app-demo
tier: frontend
spec:
containers:
- name: tomcat-demo
image: tomcat
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
apiVersion随版本的改变而改变:
创建Deployment
kubectl apply -f tomcat-deployment.yaml
查看Deployment
[root@node2 test]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
frontend 1/1 1 1 9m28s
UP-TO-DATE:最新版本的Pod的副本数量,用于指示在滚动升级的过程中,有多少个Pod副本已经成功升级。
AVAILABLE:当前集群中可用的Pod副本数量,即集群中当前存活的Pod数量。
运行命令查看Replica Set,可看到它的命名和Deployment名字有关系
[root@node2 test]# kubectl get rs
NAME DESIRED CURRENT READY AGE
frontend-797f47d685 1 1 1 13m
然后查看pod,发现pod命名以Deployment对应的Replica Set的名字为前缀,这种命名很清晰地表明了一个Replica Set创建了哪些Pod
[root@node2 test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
frontend-797f47d685-fx466 1/1 Running 0 18m
创建一个tomcat-service.yaml的定义文件,内容为:
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
ports:
- port: 8080
selector:
tier: frontend
创建
[root@node2 test]# kubectl apply -f tomcat-service.yaml
之前在tomcat-deployment.yaml里定义的Tomcat的Pod刚好拥有这个标签,所以我们刚才创建的tomcat-service已经对应到一个Pod实例,运行下面的命令可以查看tomcat-service的Endpoint列表
[root@node2 test]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 192.168.242.132:6443 5d16h
tomcat-service 10.244.3.83:8080 3m55s
其中10.244.3.83是Pod的IP地址,端口8080是Container暴露的端口。
运行以下命令即可看到tomcat-service被分配的Cluster-IP:
[root@node2 test]# kubectl get svc tomcat-service -o yaml
apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"tomcat-service","namespace":"default"},"spec":{"ports":[{"port":8080}],"selector":{"tier":"frontend"}}}
creationTimestamp: "2021-11-25T02:21:32Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.: {}
f:kubectl.kubernetes.io/last-applied-configuration: {}
f:spec:
f:ports:
.: {}
k:{"port":8080,"protocol":"TCP"}:
.: {}
f:port: {}
f:protocol: {}
f:targetPort: {}
f:selector:
.: {}
f:tier: {}
f:sessionAffinity: {}
f:type: {}
manager: kubectl
operation: Update
time: "2021-11-25T02:21:32Z"
name: tomcat-service
namespace: default
resourceVersion: "252606"
selfLink: /api/v1/namespaces/default/services/tomcat-service
uid: 5aa2c1f2-008f-4229-a220-0dc5d3eb10d3
spec:
clusterIP: 10.110.156.40
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
tier: frontend
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
在spec.ports的定义中,targetPort属性用来确定提供该服务的容器所暴露(EXPOSE)的端口号,及具体业务进程在容器内的targetPort上提供TCP/IP接入,而port属性则定义了Service的虚端口。前面定义Tomcat服务的时候,没有指定targetPort,则默认targetPort与port相同。