Deployment 资源详解

  1. 使用yaml创建Deployment
  2. k8s deployment资源创建流程:
  3. 1. 用户通过 kubectl 创建 Deployment
  4. 2. Deployment 创建 ReplicaSet
  5. 3. ReplicaSet 创建 Pod
对象的命名方式是:子对象的名字 = 父对象名字 + 随机字符串或数字

image.png

Deployment是一个定义及管理多副本应用(即多个副本 Pod)的新一代对象,与Replication Controller相比,它提供了更加完善的功能,使用起来更加简单方便。

如果Pod出现故障,对应的服务也会挂掉,所以Kubernetes提供了一个Deployment的概念 ,目的是让Kubernetes去管理一组Pod的副本,也就是副本集 ,这样就能够保证一定数量的副本一直可用,不会因为某一个Pod挂掉导致整个服务挂掉。
Deployment 还负责在 Pod 定义发生变化时,对每个副本进行滚动更新(Rolling Update)。

这样使用一种 API 对象(Deployment)管理另一种 API 对象(Pod)的方法,在 k8s 中,叫作"控制器"模式(controller pattern)。Deployment 扮演的正是 Pod 的控制器的角色。
例1:
apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-deployment
spec:
 selector:
   matchLabels:
     app: nginx
 replicas: 2
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: nginx:1.7.9
       ports:
       - containerPort: 80
例2:在上面yaml的基础上添加了volume
[root@kub-k8s-master prome]# vim deployment.yaml
apiVersion: apps/v1  #注意版本号
kind: Deployment
metadata:
 name: nginx-deployment
spec:
selector:  #属性,选择器
  matchLabels:
    app: nginx
replicas: 2  #管理的副本个数
template:  #模板属性
  metadata:
    labels:
      app: nginx
  spec:
    containers:
    - name: nginx
      image: daocloud.io/library/nginx
      ports:
      - containerPort: 80
      volumeMounts:  #定义挂载卷
      - mountPath: "/usr/share/nginx/html"
        name: nginx-vol
    volumes:   #定义共享卷
    - name: nginx-vol
      emptyDir: {}
创建Deployment:
将上述的YAML文件保存为deployment.yaml,然后创建Deployment:
[root@kub-k8s-master prome]# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created

检查Deployment的列表:启动之后需要创建时间比较长
通过 kubectl get 命令检查这个 YAML 运行起来的状态:
[root@kub-k8s-master prome]# kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           2m22s

[root@kub-k8s-master prome]# kubectl get pods -l app=nginx
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-59c4b86474-2llrt   1/1     Running   0          2m51s
nginx-deployment-59c4b86474-n2r2m   1/1     Running   0          2m51s

在这里加上了一个 -l 参数,即获取所有匹配 app: nginx 标签的 Pod。需要注意的是,在命令行中,所有 key-value 格式的参数,都使用"="而非":"表示。

删除Deployment:
[root@k8s-master ~]# kubectl delete deployments nginx-deployment
deployment "nginx-deployment" deleted
或者
[root@k8s-master ~]# kubectl delete -f deployment.yaml
apiVersion:注意这里apiVersion对应的值是extensions/v1beta1或者apps/v1.这个版本号需要根据安装的Kubernetes版本和资源类型进行变化,记住不是写死的。此值必须在kubectl apiversion中 
[root@kub-k8s-master prome]# kubectl api-versions
    apps/v1beta1
    authentication.k8s.io/v1beta1
    authorization.k8s.io/v1beta1
    autoscaling/v1
    batch/v1
    certificates.k8s.io/v1alpha1
    extensions/v1beta1
    policy/v1beta1
    rbac.authorization.k8s.io/v1alpha1
    storage.k8s.io/v1beta1
    v1

kind:资源类型:这里指定为Deployment。

metadata:指定一些meta信息,包括名字或标签之类的。每一个 API 对象都有一个叫作 Metadata 的字段,这个字段是 API 对象的"标识",即元数据,也是我们从 Kubernetes 里找到这个对象的主要依据。

labels:Labels是最主要的字段,是一组 key-value 格式的标签,k8s中的所有资源都支持携带label,默认情况下,pod的label会复制rc的label
    k8s使用用户自定义的key-value键值对来区分和标识资源集合(就像rc、pod等资源),这种键值对称为label。
     像 Deployment 这样的控制器对象,就可以通过这个 Labels 字段从 Kubernetes 中过滤出它所关心的被控制对象。

    关于Annotations:在 Metadata 中,还有一个与 Labels 格式、层级完全相同的字段叫 Annotations,它专门用来携带 key-value 格式的内部信息。所谓内部信息,指的是对这些信息感兴趣的,是 Kubernetes 组件本身,而不是用户。所以大多数 Annotations,都是在 Kubernetes 运行过程中,被自动加在这个 API 对象上。

selector:过滤规则的定义,是在 Deployment 的"spec.selector.matchLabels"字段。一般称之为:Label Selector。
    pod的label会被用来创建一个selector,用来匹配过滤携带这些label的pods。

使用labels定位pods
[root@kub-k8s-master prome]# kubectl get pods -l app=nginx -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP            NODE       
nginx-deployment-59c4b86474-2llrt   1/1     Running   0          16m   10.244.2.15   kub-k8s-node2   
nginx-deployment-59c4b86474-n2r2m   1/1     Running   0          16m   10.244.1.39   kub-k8s-node1   

检查你的Pod的IPs:
[root@kub-k8s-master prome]# kubectl get pods -l app=nginx -o json | grep podIP
                "podIP": "10.244.2.15",
                "podIPs": [
                "podIP": "10.244.1.39",
                "podIPs": [

spec : 一个 k8s 的 API 对象的定义,大多可以分为 Metadata 和 Spec 两个部分。前者存放的是这个对象的元数据,对所有 API 对象来说,这一部分的字段和格式基本上是一样的;而后者存放的,则是属于这个对象独有的定义,用来描述它所要表达的功能。
这里定义需要两个副本,此处可以设置很多属性,主要是受此Deployment影响的Pod的选择器

replicas:定义的 Pod 副本个数 (spec.replicas) 是:2

template:定义了一个 Pod 模版(spec.template),这个模版描述了想要创建的 Pod 的细节。例子里,这个 Pod 里只有一个容器,这个容器的镜像(spec.containers.image)是 nginx:latest,这个容器监听端口(containerPort)是 80。

volumes:是属于 Pod 对象的一部分。需要修改 template.spec 字段
    例2中,在 Deployment 的 Pod 模板部分添加了一个 volumes 字段,定义了这个 Pod 声明的所有 Volume。它的名字叫作 nginx-vol,类型是 emptyDir。

关于emptyDir 类型:等同于 Docker 的隐式 Volume 参数,即:不显式声明宿主机目录的 Volume。所以,Kubernetes 也会在宿主机上创建一个临时目录,这个目录将来就会被绑定挂载到容器所声明的 Volume 目录上。
k8s 的 emptyDir 类型,只是把 k8s 创建的临时目录作为 Volume 的宿主机目录,交给了 Docker。这么做的原因,是 k8s 不想依赖 Docker 自己创建的那个 _data 目录。

volumeMounts:Pod 中的容器,使用的是 volumeMounts 字段来声明自己要挂载哪个 Volume,并通过 mountPath 字段来定义容器内的 Volume 目录,比如:/usr/share/nginx/html。

hostPath:k8s 也提供了显式的 Volume 定义,它叫做 hostPath。比如下面的这个 YAML 文件:
    ...   
        volumes:
          - name: nginx-vol
            hostPath: 
              path: /var/data
    这样,容器 Volume 挂载的宿主机目录,就变成了 /var/data

创建SERVICE

三台安装iptables:
[root@kub-k8s-master prome]# yum install -y iptables iptables-services
1.创建一个depl
[root@kub-k8s-master prome]# kubectl delete -f deployment.yaml
[root@kub-k8s-master prome]# vim nginx-depl.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dep01
spec:
  selector:
    matchLabels:    #必须设定的
      app: web
  replicas: 2
  template:
      metadata:
        name: testnginx9
        labels:
          app: web
      spec:
        containers:
          - name: testnginx9
            image: daocloud.io/library/nginx
            ports:
              - containerPort: 80
[root@kub-k8s-master prome]# kubectl apply -f nginx-depl.yml 
deployment.apps/nginx-deployment created
2. 创建service并且以nodePort的方式暴露端口给外网:
[root@kub-k8s-master prome]# vim nginx_svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysvc
spec:
  type: NodePort  #类型
  ports:
    - port: 8080
      nodePort: 30001
      targetPort: 80
  selector:   #选择器
    app: web

[root@kub-k8s-master prome]# kubectl apply -f nginx_svc.yaml 
service/mysvc created

3.测试
[root@kub-k8s-master prome]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          5d18h
mysvc        NodePort    10.100.166.208   <none>        8080:30001/TCP   21s

端口详解

安装iptables(但是需要关闭iptables),创建service之后k8s会自动添加规则到Iptables里面,而且会生效(虽然iptables处于关闭状态)

服务中的3个端口设置
这几个port的概念很容易混淆,比如创建如下service:
apiVersion: v1
kind: Service
metadata:
  name: mysvc
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30001
      targetPort: 80
  selector:
    app: web
port
这里的port表示:service暴露在cluster ip上的端口,cluster ip:port 是提供给集群内部客户访问service的入口。
nodePort
首先,nodePort是kubernetes提供给集群外部客户访问service入口的一种方式(另一种方式是LoadBalancer),所以,<nodeIP>:nodePort 是提供给集群外部客户访问service的入口。
targetPort
targetPort很好理解,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。
port、nodePort总结
总的来说,port和nodePort都是service的端口,前者暴露给集群内客户访问服务,后者暴露给集群外客户访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的targetPod,从而到达pod上的容器内。

kube-proxy反向代理

kube-proxy与iptables

当service有了port和nodePort之后,就可以对内/外提供服务。那么其具体是通过什么原理来实现的呢?原因就在kube-proxy在本地node上创建的iptables规则。

Kube-Proxy 通过配置 DNAT 规则(从容器出来的访问,从本地主机出来的访问两方面),将到这个服务地址的访问映射到本地的kube-proxy端口(随机端口)。然后 Kube-Proxy 会监听在本地的对应端口,将到这个端口的访问给代理到远端真实的 pod 地址上去。

不管是通过集群内部服务入口:port还是通过集群外部服务入口:nodePort的请求都将重定向到本地kube-proxy端口(随机端口)的映射,然后将到这个kube-proxy端口的访问给代理到远端真实的 pod 地址上去。

RC资源(了解)

Replication Controller(简称rc)用来管理Pod的副本,保证集群中存在指定数量的Pod副本。集群中副本的数量大于指定数量,则会停止指定数量之外的多余容器数量,反之,则会启动少于指定数量个数的容器,保证数量不变。Replication Controller是实现弹性伸缩、动态扩容和滚动升级的核心。

RC 的主要功能点:
确保pod数量:指定某个服务在Kubernetes中有相应数量的Pod在运行;
确保pod健康:当pod不健康,运行出错或者无法提供服务时,会杀死不健康pod并重新创建,保持pod数量一致;
弹性伸缩:当业务高峰期的时候可以设置扩增pod数量,配合监控就可以做自动伸缩了;
滚动升级:也就是蓝绿发布,当一个pod使用的镜像更新,采用滚动升级模式,RC会自动一个个pod的进行升级,关闭一个pod的同时进行升级,且在原镜像基础上创建一个新pod,当一个pod更新完成再关闭一个旧镜像pod。

1.使用yaml创建并启动replicas集合

k8s通过Replication Controller来创建和管理各个不同的重复容器集合(实际上是重复的pods)。
Replication Controller会确保pod的数量在运行的时候会一直保持在一个特殊的数字,即replicas的设置。
[root@kub-k8s-master ~]# cd prome/
[root@kub-k8s-master prome]# vim nginx-rc.yml
---
apiVersion: v1
kind: ReplicationController
metadata:
 name: my-nginx
spec:
 replicas: 2
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: daocloud.io/library/nginx
       ports:
       - containerPort: 80
和定义一个pod的YAML文件相比,不同的只是kind的值为ReplicationController,replicas的值需要指定,pod的相关定义在template中,pod的名字不需要显式地指定,因为它们会在rc中创建并赋予名字

创建rc:

[root@kub-k8s-master prome]# kubectl apply -f nginx-rc.yml 
replicationcontroller/my-nginx created

和直接创建pod不一样,rc将会替换因为任何原因而被删除或者停止运行的Pod,比如说pod依赖的节点挂了。所以我们推荐使用rc来创建和管理复杂应用,即使你的应用只要使用到一个pod,在配置文件中忽略replicas字段的设置即可

2、查看Replication Controller的状态

[root@kub-k8s-master prome]# kubectl get rc
NAME       DESIRED   CURRENT   READY   AGE
my-nginx   2         2         2       11

这个状态表示,你创建的rc将会确保你一直有两个nginx的副本。

也可以和直接创建Pod一样查看创建的Pod状态信息:

[root@kub-k8s-master prome]# kubectl get pods
NAME                                READY   STATUS             RESTARTS   AGE
dep01-58f6d4d4cb-g6vtg              1/1     Running            0          3h8m
dep01-58f6d4d4cb-k6z47              1/1     Running            0          3h8m
my-nginx-7kbwz                      1/1     Running            0          2m49s
my-nginx-jkn8l                      1/1     Running            0          2m49s

3、删除Replication Controller

当你想停止你的应用,删除你的rc,可以使用:
[root@kub-k8s-master prome]# kubectl delete rc my-nginx
replicationcontroller "my-nginx" deleted

默认的,这将会删除所有被这个rc管理的pod,如果pod的数量很大,将会花一些时间来完成整个删除动作,如果你想使这些pod停止运行,请指定—cascade=false。

如果你在删除rc之前尝试删除pod,rc将会立即启动新的pod来替换被删除的pod

K8S之暴露IP给外网

转发K8S后端服务的四种方式

方式1:ClusterIP 

此类型会提供一个集群内部的虚拟IP(与Pod不在同一网段),以供集群内部的pod之间通信使用。ClusterIP也是Kubernetes service的默认类型。
方式2:NodePort
外网client--->nodeIP+nodePort--->podIP+PodPort

为每个节点暴露一个端口,通过nodeip + nodeport可以访问这个服务,同时服务依然会有cluster类型的ip+port。内部通过clusterip方式访问,外部通过nodeport方式访问。

方式3:loadbalance
LoadBalancer在NodePort基础上,K8S可以请求底层云平台创建一个负载均衡器,将每个Node作为后端,进行服务分发。

方式4:Ingress

Ingress是一种HTTP方式的路由转发机制,为K8S服务配置HTTP负载均衡器,通常会将服务暴露给K8S群集外的客户端。
作业:
1.用deployment+service方式  暴露tomcat容器,要求用web浏览器访问到
2.用rc+service方式  暴露tomcat容器,要求用web浏览器访问到
3.用deployment+service方式  暴露jenkins容器,要求用web浏览器访问到

完整TOMCAT实例

注意:本文中和上文中的NodePort没有完全解决外部访问Service的所有问题,比如负载均衡,假如我们又10个Node,则此时最好有一个负载均衡器,外部的请求只需访问此负载均衡器的IP地址,由负载局衡器负责转发流量到后面某个Node的NodePort上。这个负载均衡器可以是硬件,也可以是软件方式,例如HAProxy或者Nginx;

Java Web应用

注:Tomcat有可能无法正常启动,原因是虚机的内存和CPU设置过小,请酌情调大!

下载镜像

[root@kub-k8s-node1 ~]#  docker pull daocloud.io/library/tomcat

构建Tomcat RC定义文件

[root@kub-k8s-master prome]# vim myweb.rc.yml
---
apiVersion: v1
kind: ReplicationController
metadata:
 name: myweb
spec:
 replicas: 2
 selector:
   app: myweb
 template:
   metadata:
     labels:
       app: myweb
   spec:
     containers:
       - name: myweb
         image: daocloud.io/library/tomcat:7
         ports:
         - containerPort: 8080  #在8080端口上启动容器进程,PodIP与容器端口组成Endpoint,代表着一个服务进程对外通信的地址

发布到Kubernetes集群

创建RC

[root@kub-k8s-master prome]# kubectl apply -f myweb.rc.yml 
replicationcontroller/myweb created

查看RC

[root@kub-k8s-master prome]# kubectl get rc
NAME       DESIRED   CURRENT   READY   AGE
myweb      1         1         1       20s

查看Pod

[root@kub-k8s-master prome]# kubectl get pods
NAME                                READY   STATUS             RESTARTS   AGE
myweb-shjfn                         1/1     Running            0          52s

构建Tomcat Kubernetes Service定义文件

[root@kub-k8s-master prome]# vim myweb-svc.yaml
apiVersion: v1
kind: Service
metadata: 
 name: myweb
spec:
 type: NodePort
 ports:
   - port: 8081
     nodePort: 30009
     targetPort: 8080
 selector:
   app: myweb

创建

[root@kub-k8s-master prome]# kubectl apply -f myweb-svc.yaml 
service/myweb created

查看SVC

[root@kub-k8s-master prome]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          5d22h
mysvc        NodePort    10.110.160.108   <none>        8080:30001/TCP   3h37m
myweb        NodePort    10.96.19.61      <none>        8081:30009/TCP   33s

运行

浏览器中输入http://虚拟机IP:30009即可呈现如下内容:

image.png

注意在节点(node)中访问,不是master

[root@kub-k8s-node1 ~]# curl 192.168.246.166:30009

以上不行,应该是镜像的问题:

换成nginx镜像,创建rc:

创建rc
[root@k8s-master prome]# cat nginx-rc.yml 
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: daocloud.io/library/nginx
        ports:
        - containerPort: 80
[root@k8s-master prome]# kubectl apply -f nginx-rc.yml
通过创建service暴露端口
[root@k8s-master prome]# cat nginx-svc.yml 
apiVersion: v1
kind: Service
metadata: 
  name: mynginx
spec:
  type: NodePort
  ports:
    - port: 8082
      nodePort: 30010
      targetPort: 80
  selector:
    app: nginx
[root@k8s-master prome]# kubectl apply -f nginx-svc.yml

访问测试:

image.png

image.png

换一个Tomcat镜像测试

创建关于tomcat的rc
[root@k8s-master prome]# cat myweb.rc.yml 
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb
spec:
  replicas: 2
  selector:
    app: myweb
  template:
    metadata:
      labels:
        app: myweb
    spec:
      containers:
        - name: myweb
          image: hub.c.163.com/public/tomcat:7.0.28
          ports:
          - containerPort: 8080
[root@k8s-master prome]# kubectl apply -f myweb.rc.yml  

创建service通过NodePort的方式暴露tomcat容器的端口到外网
[root@k8s-master prome]# cat myweb-svc.yaml 
apiVersion: v1
kind: Service
metadata: 
  name: myweb
spec:
  type: NodePort
  ports:
    - port: 8081
      nodePort: 30009
      targetPort: 8080
  selector:
    app: myweb
[root@k8s-master prome]# kubectl apply -f myweb-svc.yml

访问测试,成功

image.png

image.png