一个简单的例子
  • 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
    
    • 其中metadata.name是Service的服务名(ServiceName),port属性定义了Service的虚端口;spec.selector确定了哪些pod副本(实例)对应到本服务。类似地,我们通过kubectl create 命令创建Service对象
    kubectl create -f mysql-svc.yaml
    

    查看

    [root@node2 test]# kubectl get svc | grep mysql
    mysql        ClusterIP   10.96.114.38    <none>        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       <none>        443/TCP          3d19h
    mysql        ClusterIP   10.96.114.38    <none>        3306/TCP         165m
    myweb        NodePort    10.107.166.10   <none>        8080:30001/TCP   139m
    

Deployment

创建一个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随版本的改变而改变:

  • 1.6版本之前 apiVsersion:extensions/v1beta1
  • 1.6版本到1.9版本之间:apps/v1beta1
  • 1.9版本之后:apps/v1

创建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

Service

创建一个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相同。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐