国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

如何部署一個生產(chǎn)級別的 Kubernetes 應(yīng)用

共 41660字,需瀏覽 84分鐘

 ·

2021-06-22 23:57

本文我們用一個 Wordpress 示例來盡可能將前面的知識點串聯(lián)起來,我們需要達到的目的是讓 Wordpress 應(yīng)用具有高可用、滾動更新的過程中不能中斷服務(wù)、數(shù)據(jù)要持久化不能丟失、當(dāng)應(yīng)用負載太高的時候能夠自動進行擴容、當(dāng)然還有 HTTPS 訪問等等,這些是我們的應(yīng)用部署到線上環(huán)境基本上要具備的一些能力,接下來我們就來一步一步完成這些需求。

原理

首先要部署 Wordpress 應(yīng)用,我們肯定需要知道 Wordpress 是如何運行起來的,Wordpress 是一個基于 PHP 和 MySQL 的流行的開源內(nèi)容管理系統(tǒng),擁有豐富的插件和模板系統(tǒng)。到這里我們應(yīng)該就清楚應(yīng)該如何去運行 Wordpress 了,一個能夠解析 PHP 的程序,和 MySQL 數(shù)據(jù)庫就可以了,我們要想在 Kubernetes 系統(tǒng)中來運行,肯定需要使用到 Docker 鏡像了,對于 Wordpress 應(yīng)用程序本身官方提供了鏡像 https://hub.docker.com/_/wordpress,也給出了說明如何運行,可以通過一系列環(huán)境變量去指定 MySQL 數(shù)據(jù)庫的配置,只需要將這些參數(shù)配置上直接運行即可。我們知道 Wordpress 應(yīng)用本身會頻繁的和 MySQL 數(shù)據(jù)庫進行交互,這種情況下如果將二者用容器部署在同一個 Pod 下面是不是要高效很多,因為一個 Pod 下面的所有容器是共享同一個 network namespace 的,下面我們就來部署我們的應(yīng)用,將我們的應(yīng)用都部署到 kube-example 這個命名空間下面,所以首先創(chuàng)建一個命名空間:(namespace.yaml)

apiVersion: v1
kind: Namespace
metadata:
  name: kube-example

然后編寫部署到 Kubernetes 下面的資源清單:(deployment.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  namespace: kube-example
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
      - name: wordpress
        image: wordpress:5.3.2-apache
        ports:
        - containerPort: 80
          name: wdport
        env:
        - name: WORDPRESS_DB_HOST
          value: localhost:3306
        - name: WORDPRESS_DB_USER
          value: wordpress
        - name: WORDPRESS_DB_PASSWORD
          value: wordpress
      - name: mysql
        image: mysql:5.7
        imagePullPolicy: IfNotPresent
        args:  # 新版本鏡像有更新,需要使用下面的認證插件環(huán)境變量配置才會生效
        - --default_authentication_plugin=mysql_native_password
        - --character-set-server=utf8mb4
        - --collation-server=utf8mb4_unicode_ci
        ports:
        - containerPort: 3306
          name: dbport
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: rootPassW0rd
        - name: MYSQL_DATABASE
          value: wordpress
        - name: MYSQL_USER
          value: wordpress
        - name: MYSQL_PASSWORD
          value: wordpress

由于我們這里 MySQL 和 Wordpress 在同一個 Pod 下面,所以在 Wordpress 中我們指定數(shù)據(jù)庫地址的時候是用的 localhost:3306,因為這兩個容器已經(jīng)共享同一個 network namespace 了,這點很重要,然后如果我們要想把這個服務(wù)暴露給外部用戶還得創(chuàng)建一個 Service 或者 Ingress 對象,這里我們一步一步來,暫時先創(chuàng)建一個 NodePort 類型的 Service:(service.yaml)

apiVersion: v1
kind: Service
metadata:
  name: wordpress
  namespace: kube-example
spec:
  selector:
    app: wordpress
  type: NodePort
  ports:
  - name: web
    port: 80
    targetPort: wdport

因為只需要暴露 Wordpress 這個應(yīng)用,所以只匹配了一個名為 wdport 的端口,現(xiàn)在我們來創(chuàng)建上面的幾個資源對象:

$ kubectl apply -f namespace.yaml
$ kubectl apply -f deployment.yaml
$ kubectl apply -f service.yaml

接下來就是等待拉取鏡像,啟動 Pod:

$ kubectl get pods -n kube-example
NAME                         READY   STATUS    RESTARTS   AGE
wordpress-77dcdb64c6-zdlb8   2/2     Running   0          12m
$ kubectl get svc -n kube-example
NAME        TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
wordpress   NodePort   10.106.237.157   <none>        80:30892/TCP   2m2s

當(dāng) Pod 啟動完成后,我們就可以通過上面的 http://<任意節(jié)點IP>:30892 這個 NodePort 端口來訪問應(yīng)用了。我們仔細想一想這一種方式有什么問題?首先一個 Pod 中的所有容器并沒有啟動的先后順序,所以很有可能當(dāng) wordpress 這個容器啟動起來去連接 mysql 這個容器的時候,mysql 還沒有啟動起來;另外一個問題是現(xiàn)在我們的應(yīng)用是不是只有一個副本?會有單點問題,應(yīng)用的性能也是一個問題,由于 Wordpress 應(yīng)用本身是無狀態(tài)應(yīng)用,所以這種情況下一般我們只需要多部署幾個副本即可,比如這里我們在 Deployment 的 YAML 文件中加上 replicas:3 這個屬性,這個時候有一個什么問題呢?由于 MySQL 是有狀態(tài)應(yīng)用,每一個 Pod 里面的數(shù)據(jù)庫的數(shù)據(jù)都是獨立的,他們并沒有共享,也就是說這3個 Pod 相當(dāng)于是獨立的3個 Wordpress 實例,所以應(yīng)該怎么辦呢?拆分,把 Wordpress 和 MySQL 這兩個容器部署成獨立的 Pod 就可以了,這樣我們只需要對 Wordpress 應(yīng)用增加副本,而數(shù)據(jù)庫 MySQL 還是一個實例,所有的應(yīng)用都連接到這一個數(shù)據(jù)庫上面,是不是就可以解決這個問題了。

高可用

現(xiàn)在我們將 Pod 中的兩個容器進行拆分,將 Wordpress 和 MySQL 分別部署,然后 Wordpress 用多個副本進行部署就可以實現(xiàn)應(yīng)用的高可用了,由于 MySQL 是有狀態(tài)應(yīng)用,一般來說需要用 StatefulSet 來進行管理,但是我們這里部署的 MySQL 并不是集群模式,而是單副本的,所以用 Deployment 也是沒有問題的,當(dāng)然如果要真正用于生產(chǎn)環(huán)境還是需要集群模式的(MySQL 集群模式可以使用 Operator 部署或者直接使用外部鏈接):(mysql.yaml)

apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  namespace: kube-example
  labels:
    app: wordpress
spec:
  ports:
  - port: 3306
    targetPort: dbport
  selector:
    app: wordpress
    tier: mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-mysql
  namespace: kube-example
  labels:
    app: wordpress
    tier: mysql
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        imagePullPolicy: IfNotPresent
        args:  # 新版本鏡像有更新,需要使用下面的認證插件環(huán)境變量配置才會生效
        - --default_authentication_plugin=mysql_native_password
        - --character-set-server=utf8mb4
        - --collation-server=utf8mb4_unicode_ci
        ports:
        - containerPort: 3306
          name: dbport
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: rootPassW0rd
        - name: MYSQL_DATABASE
          value: wordpress
        - name: MYSQL_USER
          value: wordpress
        - name: MYSQL_PASSWORD
          value: wordpress

我們這里給 MySQL 應(yīng)用添加了一個 Service 對象,是因為 Wordpress 應(yīng)用需要來連接數(shù)據(jù)庫,之前在同一個 Pod 中用 localhost 即可,現(xiàn)在需要通過 Service 的 DNS 形式的域名進行連接。直接創(chuàng)建上面資源對象:

$ kubectl apply -f mysql.yaml    
service/wordpress-mysql created
deployment.apps/wordpress-mysql created

接下來創(chuàng)建獨立的 Wordpress 服務(wù),對應(yīng)的資源對象如下:(wordpress.yaml)

apiVersion: v1
kind: Service
metadata:
  name: wordpress
  namespace: kube-example
  labels:
    app: wordpress
spec:
  selector:
    app: wordpress
    tier: frontend
  type: NodePort
  ports:
  - name: web
    port: 80
    targetPort: wdport
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  namespace: kube-example
  labels:
    app: wordpress
    tier: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - name: wordpress
        image: wordpress:5.3.2-apache
        ports:
        - containerPort: 80
          name: wdport
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql:3306
        - name: WORDPRESS_DB_USER
          value: wordpress
        - name: WORDPRESS_DB_PASSWORD
          value: wordpress

注意這里的環(huán)境變量 WORDPRESS_DB_HOST 的值將之前的 localhost 地址更改成了上面 MySQL 服務(wù)的 DNS 地址,完整的域名應(yīng)該是 wordpress-mysql.kube-example.svc.cluster.local:3306,由于這兩個應(yīng)該都處于同一個命名空間,所以直接簡寫成 wordpress-mysql:3306 也是可以的。創(chuàng)建上面資源對象:

$ kubectl apply -f wordpress.yaml 
service/wordpress created
deployment.apps/wordpress created
$ kubectl get pods -l app=wordpress -n kube-example
NAME                              READY   STATUS              RESTARTS   AGE
wordpress-6554f9f96c-24rl7        0/1     ContainerCreating   0          6m12s
wordpress-6554f9f96c-4qm5c        1/1     Running             0          6m12s
wordpress-6554f9f96c-wsjhh        0/1     ContainerCreating   0          6m12s
wordpress-mysql-8bbc78ddc-l4c28   1/1     Running             0          13m

可以看到都已經(jīng)是 Running 狀態(tài)了,然后我們需要怎么來驗證呢?是不是我們能想到的就是去訪問下我們的 Wordpress 服務(wù)就可以了,我們這里還是使用的一個 NodePort 類型的 Service 來暴露服務(wù):

$ kubectl get svc -l app=wordpress -n kube-example
NAME              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
wordpress         NodePort    10.96.154.86   <none>        80:30012/TCP   8m15s
wordpress-mysql   ClusterIP   10.107.5.168   <none>        3306/TCP       15m

可以看到 wordpress 服務(wù)產(chǎn)生了一個 30012 的端口,現(xiàn)在我們就可以通過 http://<任意節(jié)點的NodeIP>:30012 訪問我們的應(yīng)用了,在瀏覽器中打開,如果看到 wordpress 跳轉(zhuǎn)到了安裝頁面,證明我們的安裝是正確的,如果沒有出現(xiàn)預(yù)期的效果,那么就需要去查看下 Pod 的日志來排查問題了,根據(jù)頁面提示,填上對應(yīng)的信息,點擊“安裝”即可,最終安裝成功后,我們就可以看到熟悉的首頁界面了:

wordpres home

穩(wěn)定性

現(xiàn)在 Wodpress 應(yīng)用已經(jīng)部署成功了,那么就萬事大吉了嗎?如果我們的網(wǎng)站訪問量突然變大了怎么辦,如果我們要更新我們的鏡像該怎么辦?所以要保證我們的網(wǎng)站能夠非常穩(wěn)定的提供服務(wù),我們做得還不夠,我們可以通過做些什么事情來提高網(wǎng)站的穩(wěn)定性呢?

避免單點故障

為什么會有單點故障的問題呢?我們不是部署了多個副本的 Wordpress 應(yīng)用嗎?當(dāng)我們設(shè)置 replicas=1 的時候肯定會存在單點故障問題,如果大于 1 但是所有副本都調(diào)度到了同一個節(jié)點的是不是同樣就會存在單點問題了,這個節(jié)點掛了所有副本就都掛了,所以我們不僅需要設(shè)置多個副本數(shù)量,還需要讓這些副本調(diào)度到不同的節(jié)點上,來打散避免單點故障,這個利用 Pod 反親和性來實現(xiàn)了,我們可以加上如下所示的配置:

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:  # 軟策略
    - weight: 1
      podAffinityTerm:
        topologyKey: kubernetes.io/hostname
        labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - wordpress

這里的意思就是如果一個節(jié)點上面有 app=wordpress 這樣的 Pod 的話,那么我們的 Pod 就盡可能別調(diào)度到這個節(jié)點上面來,因為我們這里的節(jié)點并不多,所以我使用的是軟策略,因為如果使用硬策略的話,如果應(yīng)用副本數(shù)超過了節(jié)點數(shù)就必然會有 Pod 調(diào)度不成功,如果你線上節(jié)點非常多的話(節(jié)點數(shù)大于 Pod 副本數(shù)),建議使用硬策略,更新后我們可以查看下 3 個副本被分散在了不同的節(jié)點上。

使用 PDB

有些時候線上的某些節(jié)點需要做一些維護操作,比如要升級內(nèi)核,這個時候我們就需要將要維護的節(jié)點進行驅(qū)逐操作,驅(qū)逐節(jié)點首先是將節(jié)點設(shè)置為不可調(diào)度,這樣可以避免有新的 Pod 調(diào)度上來,然后將該節(jié)點上的 Pod 全部刪除,ReplicaSet 控制器檢測到 Pod 數(shù)量減少了就會重新創(chuàng)建一個新的 Pod,調(diào)度到其他節(jié)點上面的,這個過程是先刪除,再創(chuàng)建,并非是滾動更新,因此更新過程中,如果一個服務(wù)的所有副本都在被驅(qū)逐的節(jié)點上,則可能導(dǎo)致該服務(wù)不可用。

如果服務(wù)本身存在單點故障,所有副本都在同一個節(jié)點,驅(qū)逐的時候肯定就會造成服務(wù)不可用了,這種情況我們使用上面的反親和性和多副本就可以解決這個問題。但是如果我們的服務(wù)本身就被打散在多個節(jié)點上,這些節(jié)點如果都被同時驅(qū)逐的話,那么這個服務(wù)的所有實例都會被同時刪除,這個時候也會造成服務(wù)不可用了,這種情況下我們可以通過配置 PDB(PodDisruptionBudget)對象來避免所有副本同時被刪除,比如我們可以設(shè)置在驅(qū)逐的時候 wordpress 應(yīng)用最多只有一個副本不可用,其實就相當(dāng)于逐個刪除并在其它節(jié)點上重建:(pdb.yaml)

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: wordpress-pdb
  namespace: kube-example
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: wordpress
      tier: frontend

直接創(chuàng)建這個資源對象即可:

$ kubectl apply -f pdb.yaml 
poddisruptionbudget.policy/wordpress-pdb created
$ kubectl get pdb -n kube-example
NAME            MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
wordpress-pdb   N/A             1                 1                     10s

關(guān)于 PDB 的更多詳細信息可以查看官方文檔:https://kubernetes.io/docs/tasks/run-application/configure-pdb/。

健康檢查

我們的應(yīng)用現(xiàn)在還有一個非常重要的功能沒有提供,那就是健康檢查,我們知道健康檢查是提高應(yīng)用健壯性非常重要的手段,當(dāng)我們檢測到應(yīng)用不健康的時候我們希望可以自動重啟容器,當(dāng)應(yīng)用還沒有準備好的時候我們也希望暫時不要對外提供服務(wù),所以我們需要添加我們前面經(jīng)常提到的 liveness proberediness probe 兩個健康檢測探針,檢查探針的方式有很多,我們這里當(dāng)然可以認為如果容器的 80 端口可以成功訪問那么就是健康的,對于一般的應(yīng)用提供一個健康檢查的 URL 會更好,這里我們添加一個如下所示的可讀性探針,為什么不添加存活性探針呢?這里其實是考慮到線上錯誤排查的一個問題,如果當(dāng)我們的應(yīng)用出現(xiàn)了問題,然后就自動重啟去掩蓋錯誤的話,可能這個錯誤就會被永遠忽略掉了,所以其實這是一個折衷的做法,不使用存活性探針,而是結(jié)合監(jiān)控報警,保留錯誤現(xiàn)場,方便錯誤排查,但是可讀寫探針是一定需要添加的(最好使用 http 接口進行檢查):

readinessProbe:
  tcpSocket:
    port: 80
  initialDelaySeconds: 5
  periodSeconds: 5

增加上面的探針,每 5s 檢測一次應(yīng)用是否可讀,這樣只有當(dāng) readinessProbe 探針檢測成功后才表示準備好接收流量了,這個時候才會更新 Service 的 Endpoints 對象。

服務(wù)質(zhì)量 QoS

QoSQuality of Service 的縮寫,即服務(wù)質(zhì)量。為了實現(xiàn)資源被有效調(diào)度和分配的同時提高資源利用率,Kubernetes 針對不同服務(wù)質(zhì)量的預(yù)期,通過 QoS 來對 Pod 進行服務(wù)質(zhì)量管理。對于一個 Pod 來說,服務(wù)質(zhì)量體現(xiàn)在兩個具體的指標:CPU 和內(nèi)存。當(dāng)節(jié)點上內(nèi)存資源緊張時,Kubernetes 會根據(jù)預(yù)先設(shè)置的不同 QoS 類別進行相應(yīng)處理。

QoS 主要分為 Guaranteed、BurstableBest-Effort三類,優(yōu)先級從高到低。我們先分別來介紹下這三種服務(wù)類型的定義。

Guaranteed(有保證的)

屬于該級別的 Pod 有以下兩種:

  • Pod 中的所有容器都且設(shè)置了 CPU 和內(nèi)存的 limits
  • Pod 中的所有容器都設(shè)置了 CPU 和內(nèi)存的 requests 和 limits ,且單個容器內(nèi)的requests==limits(requests不等于0)

Pod 中的所有容器都且僅設(shè)置了 limits,如下所示:

containers:
  - name: foo
    resources:
      limits:
        cpu: 10m
        memory: 1Gi
  - name: bar
    resources:
      limits:
        cpu: 100m
        memory: 100Mi

Pod 中的所有容器都設(shè)置了 requests 和 limits,且單個容器內(nèi)的 requests==limits 的情況:

containers:
  - name: foo
    resources:
      limits:
        cpu: 10m
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 1Gi
  - name: bar
    resources:
      limits:
        cpu: 100m
        memory: 100Mi
      requests:
        cpu: 100m
        memory: 100Mi

容器 foo 和 bar 內(nèi) resourcesrequestslimits 均相等,該 Pod 的 QoS 級別屬于 Guaranteed。

Burstable(不穩(wěn)定的)

Pod 中只要有一個容器的 requests 和 limits 的設(shè)置不相同,那么該 Pod 的 QoS 即為 Burstable。如下所示容器 foo 指定了 resource,而容器 bar 未指定:

containers:
  - name: foo
    resources:
      limits:
        cpu: 10m
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 1Gi
  - name: bar

容器 foo 設(shè)置了內(nèi)存 limits,而容器 bar 設(shè)置了CPU limits:

containers:
  - name: foo
    resources:
      limits:
        memory: 1Gi
  - name: bar
    resources:
      limits:
        cpu: 100m

需要注意的是如果容器指定了 requests 而未指定 limits,則 limits 的值等于節(jié)點資源的最大值,如果容器指定了 limits 而未指定 requests,則 requests 的值等于 limits。

Best-Effort(盡最大努力)

如果 Pod 中所有容器的 resources 均未設(shè)置 requests 與 limits,該 Pod 的 QoS 即為 Best-Effort。如下所示容器 foo 和容器 bar 均未設(shè)置requests 和 limits:

containers:
  - name: foo
    resources:
  - name: bar
    resources:

資源回收策略

Kubernetes 通過 CGroup 給 Pod設(shè)置 QoS 級別,當(dāng)資源不足時會優(yōu)先 kill 掉優(yōu)先級低的 Pod,在實際使用過程中,通過 OOM 分數(shù)值來實現(xiàn),OOM 分數(shù)值范圍為 0-1000,OOM 分數(shù)值根據(jù) OOM_ADJ參數(shù)計算得出。

對于 Guaranteed 級別的 Pod,OOM_ADJ 參數(shù)設(shè)置成了-998,對于 Best-Effort 級別的 Pod,OOM_ADJ 參數(shù)設(shè)置成了1000,對于 Burstable 級別的 Pod,OOM_ADJ 參數(shù)取值從 2 到 999。

QoS Pods 被 kill 掉的場景和順序如下所示:

  • Best-Effort Pods:系統(tǒng)用完了全部內(nèi)存時,該類型 Pods 會最先被 kill 掉
  • Burstable Pods:系統(tǒng)用完了全部內(nèi)存,且沒有 Best-Effort 類型的容器可以被 kill 時,該類型的 Pods 會被 kill 掉
  • Guaranteed Pods:系統(tǒng)用完了全部內(nèi)存,且沒有 Burstable 與 Best-Effort 類型的容器可以被 kill 時,該類型的 pods 會被 kill 掉

所以如果資源充足,可將 QoS Pods 類型設(shè)置為 Guaranteed,用計算資源換業(yè)務(wù)性能和穩(wěn)定性,減少排查問題時間和成本。如果想更好的提高資源利用率,業(yè)務(wù)服務(wù)可以設(shè)置為 Guaranteed,而其他服務(wù)根據(jù)重要程度可分別設(shè)置為 Burstable 或 Best-Effort,這就要看具體的場景了。

比如我們這里如果想要盡可能提高 Wordpress 應(yīng)用的穩(wěn)定性,我們可以將其設(shè)置為 Guaranteed 類型的 Pod,我們現(xiàn)在沒有設(shè)置 resources 資源,所以現(xiàn)在是 Best-Effort 類型的 Pod。

現(xiàn)在如果要想給應(yīng)用設(shè)置資源大小,就又有一個問題了,應(yīng)該如何設(shè)置合適的資源大小呢?其實這就需要我們對自己的應(yīng)用非常了解才行了,一般情況下我們可以先不設(shè)置資源,然后可以根據(jù)我們的應(yīng)用的并發(fā)和訪問量來進行壓力測試,基本上可以大概計算出應(yīng)用的資源使用量,我們這里可以使用 Apache Bench(AB Test) 或者 Fortio(Istio 測試工具) 這樣的測試工具來測試,我們這里使用 Fortio 這個測試工具,比如每秒 1000 個請求和 8 個并發(fā)的連接的測試命令如下所示:

$ fortio load -a -c 8 -qps 1000 -t 60s "http://k8s.qikqiak.com:30012"
Starting at 1000 qps with 8 thread(s) [gomax 2] for 1m0s : 7500 calls each (total 60000)
Ended after 1m0.687224615s : 5005 calls. qps=82.472
Aggregated Sleep Time : count 5005 avg -27.128368 +/- 16 min -55.964246789 max -0.050576982 sum -135777.482
[......]
Sockets used: 53 (for perfect keepalive, would be 8)
Code 200 : 5005 (100.0 %)
Response Header Sizes : count 5005 avg 292.17083 +/- 1.793 min 292 max 311 sum 1462315
Response Body/Total Sizes : count 5005 avg 27641.171 +/- 1.793 min 27641 max 27660 sum 138344060
Saved result to data/2020-02-15-125121_Fortio.json (graph link)
All done 5005 calls 95.872 ms avg, 82.5 qps

也可以通過瀏覽器查看到最終測試結(jié)果:

fortio result

在測試期間我們可以用如下所示的命令查看應(yīng)用的資源使用情況:

$ kubectl top pods -l app=wordpress -n kube-example
NAME                              CPU(cores)   MEMORY(bytes)
wordpress-5cc66f986b-2jv7h        569m         72Mi
wordpress-5cc66f986b-nf79l        997m         71Mi
wordpress-d4c885d5d-gtvhd         895m         87Mi

我們可以看到內(nèi)存基本上都是處于 100Mi 以內(nèi),而 CPU 消耗就非常大了,但是由于 CPU 是可壓縮資源,也就是說超過了限制應(yīng)用也不會掛掉的,只是會變慢而已。所以我們這里可以給 Wordpress 應(yīng)用添加如下所示的資源配置,如果你集群資源足夠的話可以適當(dāng)多分配一些資源:

resources:
  limits:
    cpu: 200m
    memory: 100Mi
  requests:
    cpu: 200m
    memory: 100Mi

滾動更新

Deployment 控制器默認的就是滾動更新的更新策略,該策略可以在任何時間點更新應(yīng)用的時候保證某些實例依然可以正常運行來防止應(yīng)用 down 掉,當(dāng)新部署的 Pod 啟動并可以處理流量之后,才會去殺掉舊的 Pod。在使用過程中我們還可以指定 Kubernetes 在更新期間如何處理多個副本的切換方式,比如我們有一個3副本的應(yīng)用,在更新的過程中是否應(yīng)該立即創(chuàng)建這3個新的 Pod 并等待他們?nèi)繂?,或者殺掉一個之外的所有舊的 Pod,或者還是要一個一個的 Pod 進行替換?

如果我們從舊版本到新版本進行滾動更新,只是簡單的通過輸出顯示來判斷哪些 Pod 是存活并準備就緒的,那么這個滾動更新的行為看上去肯定就是有效的,但是往往實際情況就是從舊版本到新版本的切換的過程并不總是十分順暢的,應(yīng)用程序很有可能會丟棄掉某些客戶端的請求。比如我們在 Wordpress 應(yīng)用中添加上如下的滾動更新策略,隨便更改以下 Pod Template 中的參數(shù),比如容器名更改為 blog:

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

然后更新應(yīng)用,同時用 Fortio 工具在滾動更新過程中來測試應(yīng)用是否可用:

$ kubectl apply -f wordpress.yaml
$ fortio load -a -c 8 -qps 1000 -t 60s "http://k8s.qikqiak.com:30012"
Starting at 1000 qps with 8 thread(s) [gomax 2] for 1m0s : 7500 calls each (total 60000)
Ended after 1m0.006243654s : 5485 calls. qps=91.407
Aggregated Sleep Time : count 5485 avg -17.626081 +/- 15 min -54.753398956 max 0.000709054 sum -96679.0518
[...]
Code 200 : 5463 (99.6 %)
Code 502 : 20 (0.4 %)
Response Header Sizes : count 5485 avg 213.14166 +/- 13.53 min 0 max 214 sum 1169082
Response Body/Total Sizes : count 5485 avg 823.18651 +/- 44.41 min 0 max 826 sum 4515178
[...]

從上面的輸出可以看出有部分請求處理失敗了(502),要弄清楚失敗的原因就需要弄明白當(dāng)應(yīng)用在滾動更新期間重新路由流量時,從舊的 Pod 實例到新的實例究竟會發(fā)生什么,首先讓我們先看看 Kubernetes 是如何管理工作負載連接的。

失敗原因

我們這里通過 NodePort 去訪問應(yīng)用,實際上也是通過每個節(jié)點上面的 kube-proxy 通過更新 iptables 規(guī)則來實現(xiàn)的。

kubernetes kube-proxy

Kubernetes 會根據(jù) Pods 的狀態(tài)去更新 Endpoints 對象,這樣就可以保證 Endpoints 中包含的都是準備好處理請求的 Pod。一旦新的 Pod 處于活動狀態(tài)并準備就緒后,Kubernetes 就將會停止就的 Pod,從而將 Pod 的狀態(tài)更新為 “Terminating”,然后從 Endpoints 對象中移除,并且發(fā)送一個 SIGTERM 信號給 Pod 的主進程。SIGTERM 信號就會讓容器以正常的方式關(guān)閉,并且不接受任何新的連接。Pod 從 Endpoints 對象中被移除后,前面的負載均衡器就會將流量路由到其他(新的)Pod 中去。因為在負載均衡器注意到變更并更新其配置之前,終止信號就會去停用 Pod,而這個重新配置過程又是異步發(fā)生的,并不能保證正確的順序,所以就可能導(dǎo)致很少的請求會被路由到已經(jīng)終止的 Pod 上去了,也就出現(xiàn)了上面我們說的情況。

零宕機

那么如何增強我們的應(yīng)用程序以實現(xiàn)真正的零宕機遷移更新呢?

首先,要實現(xiàn)這個目標的先決條件是我們的容器要正確處理終止信號,在 SIGTERM 信號上實現(xiàn)優(yōu)雅關(guān)閉。下一步需要添加 readiness 可讀探針,來檢查我們的應(yīng)用程序是否已經(jīng)準備好來處理流量了。為了解決 Pod 停止的時候不會阻塞并等到負載均衡器重新配置的問題,我們還需要使用 preStop 這個生命周期的鉤子,在容器終止之前調(diào)用該鉤子。

生命周期鉤子函數(shù)是同步的,所以必須在將最終停止信號發(fā)送到容器之前完成,在我們的示例中,我們使用該鉤子簡單的等待,然后 SIGTERM 信號將停止應(yīng)用程序進程。同時,Kubernetes 將從 Endpoints 對象中刪除該 Pod,所以該 Pod 將會從我們的負載均衡器中排除,基本上來說我們的生命周期鉤子函數(shù)等待的時間可以確保在應(yīng)用程序停止之前重新配置負載均衡器:

readinessProbe:
  # ...
lifecycle:
  preStop:
    exec:
      command: ["/bin/bash", "-c", "sleep 20"]

我們這里使用 preStop 設(shè)置了一個 20s 的寬限期,Pod 在真正銷毀前會先 sleep 等待 20s,這就相當(dāng)于留了時間給 Endpoints 控制器和 kube-proxy 更新去 Endpoints 對象和轉(zhuǎn)發(fā)規(guī)則,這段時間 Pod 雖然處于 Terminating 狀態(tài),即便在轉(zhuǎn)發(fā)規(guī)則更新完全之前有請求被轉(zhuǎn)發(fā)到這個 Terminating 的 Pod,依然可以被正常處理,因為它還在 sleep,沒有被真正銷毀。

現(xiàn)在,當(dāng)我們?nèi)ゲ榭礉L動更新期間的 Pod 行為時,我們將看到正在終止的 Pod 處于 Terminating 狀態(tài),但是在等待時間結(jié)束之前不會關(guān)閉的,如果我們使用 Fortio 重新測試下,則會看到零失敗請求的理想狀態(tài)。

HPA

現(xiàn)在應(yīng)用是固定的3個副本,但是往往在生產(chǎn)環(huán)境流量是不可控的,很有可能一次活動就會有大量的流量,3個副本很有可能抗不住大量的用戶請求,這個時候我們就希望能夠自動對 Pod 進行伸縮,直接使用前面我們學(xué)習(xí)的 HPA 這個資源對象就可以滿足我們的需求了。

直接使用kubectl autoscale命令來創(chuàng)建一個 HPA 對象

$ kubectl autoscale deployment wordpress --namespace kube-example --cpu-percent=20 --min=3 --max=6
horizontalpodautoscaler.autoscaling/hpa-demo autoscaled
$ kubectl get hpa -n kube-example
NAME        REFERENCE              TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
wordpress   Deployment/wordpress   <unknown>/20%   3         6         0          13s

此命令創(chuàng)建了一個關(guān)聯(lián)資源 wordpress 的 HPA,最小的 Pod 副本數(shù)為3,最大為6。HPA 會根據(jù)設(shè)定的 cpu 使用率(20%)動態(tài)的增加或者減少 Pod 數(shù)量。同樣,使用上面的 Fortio 工具來進行壓測一次,看下能否進行自動的擴縮容:

$ fortio load -a -c 8 -qps 1000 -t 60s "http://k8s.qikqiak.com:30012"

在壓測的過程中我們可以看到 HPA 的狀態(tài)變化以及 Pod 數(shù)量也變成了6個:

$ kubectl get hpa -n kube-example
NAME        REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
wordpress   Deployment/wordpress   98%/20%   3         6         6          2m40s
$ kubectl get pods -n kube-example                
NAME                              READY   STATUS    RESTARTS   AGE
wordpress-79d756cbc8-f6kfm        1/1     Running   0          21m
wordpress-79d756cbc8-kspch        1/1     Running   0          32s
wordpress-79d756cbc8-sf5rm        1/1     Running   0          32s
wordpress-79d756cbc8-tsjmf        1/1     Running   0          20m
wordpress-79d756cbc8-v9p7n        1/1     Running   0          32s
wordpress-79d756cbc8-z4wpp        1/1     Running   0          21m
wordpress-mysql-5756ccc8b-zqstp   1/1     Running   0          3d19h

當(dāng)壓測停止以后正常5分鐘后就會自動進行縮容,變成最小的3個 Pod 副本。

安全性

安全性這個和具體的業(yè)務(wù)應(yīng)用有關(guān)系,比如我們這里的 Wordpress 也就是數(shù)據(jù)庫的密碼屬于比較私密的信息,我們可以使用 Kubernetes 中的 Secret 資源對象來存儲比較私密的信息:

$ kubectl create secret generic wordpress-db-pwd --from-literal=dbpwd=wordpress -n kube-example
secret/wordpress-db-pwd created

然后將 Deployment 資源對象中的數(shù)據(jù)庫密碼環(huán)境變量通過 Secret 對象讀?。?/p>

env:
- name: WORDPRESS_DB_HOST
  value: wordpress-mysql:3306
- name: WORDPRESS_DB_USER
  value: wordpress
- name: WORDPRESS_DB_PASSWORD
  valueFrom:
    secretKeyRef:
      name: wordpress-db-pwd
      key: dbpwd

這樣我們就不會在 YAML 文件中看到明文的數(shù)據(jù)庫密碼了,當(dāng)然安全性都是相對的,Secret 資源對象也只是簡單的將密碼做了一次 Base64 編碼而已,對于一些特殊場景安全性要求非常高的應(yīng)用,就需要使用其他功能更加強大的密碼系統(tǒng)來進行管理了,比如 Vault。

持久化

現(xiàn)在還有一個比較大的問題就是我們的數(shù)據(jù)還沒有做持久化,MySQL 數(shù)據(jù)庫沒有做,Wordpress 應(yīng)用本身也沒有做,這顯然不是一個合格的線上應(yīng)用。這里我們直接使用前面章節(jié)中創(chuàng)建的 rook-ceph-block 這個 StorageClass 來創(chuàng)建我們的數(shù)據(jù)庫存儲后端:(pvc.yaml)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: kube-example
  labels:
    app: wordpress
spec:
  storageClassName: rook-ceph-block
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

但是由于 Wordpress 應(yīng)用是多個副本,所以需要同時在多個節(jié)點進行讀寫,也就是 accessModes 需要 ReadWriteMany 模式,而 Ceph RBD 模式是不支持 RWM 的,所以需要使用 CephFS,首先需要在 Ceph 中創(chuàng)建一個 Filesystem,這里我們可以通過 Rook 的 CephFilesystem 資源對象創(chuàng)建,如下所示:

apiVersion: ceph.rook.io/v1
kind: CephFilesystem
metadata:
  name: myfs
  namespace: rook-ceph
spec:
  metadataPool:
    replicated:
      size: 3
  dataPools:
  - replicated:
      size: 3
  metadataServer:
    activeCount: 1
    activeStandby: true

創(chuàng)建完成后還會生成一個名為 myfs-data0 的存儲池,也會自動生成兩個 MDS 的 Pod 服務(wù):

$ kubectl get pods -n rook-ceph |grep myfs
rook-ceph-mds-myfs-a-7948557994-44c4f                  1/1     Running     0          11m
rook-ceph-mds-myfs-b-5976b868cc-gl86g                  1/1     Running     0          11m

這個時候就可以創(chuàng)建我們的 StorageClass 對象了:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-cephfs
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
  clusterID: rook-ceph
  # 上面創(chuàng)建的 CephFS 文件系統(tǒng)名稱
  fsName: myfs
  # 自動生成的
  pool: myfs-data0 
  # Root path of an existing CephFS volume
  # Required for provisionVolume: "false"
  # rootPath: /absolute/path
  # The secrets contain Ceph admin credentials. These are generated automatically by the operator
  # in the same namespace as the cluster.
  csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
  csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph

reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:

同樣直接創(chuàng)建上面的 StorageClass 資源對象即可,現(xiàn)在 Wordpress 的 PVC 對象使用我們這里的 csi-cephfs 這個 StorageClass 對象:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wordpress-pvc
  namespace: kube-example
  labels:
    app: wordpress
spec:
  storageClassName: csi-cephfs
  accessModes:
  - ReadWriteMany  # 由于是多個Pod所以要用 RWM
  resources:
    requests:
      storage: 2Gi

直接創(chuàng)建上面的資源對象:

$ kubectl get pvc -n kube-example
NAME            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
mysql-pvc       Bound    pvc-93e0b186-da20-4e5e-8414-8cc73e00bf64   20Gi       RWO            rook-ceph-block   45m
wordpress-pvc   Bound    pvc-87675c58-407a-4b7e-be9d-0733f67c4835   2Gi        RWX            csi-cephfs        5s

在使用 CephFS 的過程中遇到了上面的 PVC 一直處于 Pending 狀態(tài),然后 describe 后發(fā)現(xiàn)有如下所示的錯誤信息:

從錯誤信息上面來看是在通過 StorageClass 去自動創(chuàng)建 PV 的時候就出現(xiàn)了問題,所以我們需要去檢查 CSI 的 attach 階段:

$ kubectl get pods -n rook-ceph |grep csi-cephfsplugin-provisioner
csi-cephfsplugin-provisioner-56c8b7ddf4-4s7fd          4/4     Running     0          18m
csi-cephfsplugin-provisioner-56c8b7ddf4-55sg6          4/4     Running     0          39m

然后查看這兩個 Pod 的日志發(fā)現(xiàn)都是類似于下面的錯誤:

I0304 10:04:04.823171       1 leaderelection.go:246] failed to acquire lease rook-ceph/rook-ceph-cephfs-csi-ceph-com
I0304 10:04:14.344109       1 leaderelection.go:350] lock is held by csi-cephfsplugin-provisioner-56c8b7ddf4-rq4t6 and has not yet expired

因為我們這里有兩個副本的 Provisioner,正常應(yīng)該是有一個提供服務(wù),另外一個作為備用的,通過獲取到分布式鎖來表示當(dāng)前的 Pod 是否是 leader,這里兩個 Pod 都沒獲取到,應(yīng)該就是出現(xiàn)了通信問題,然后將兩個 Pod 都重建后,其中一個 Pod 便獲取到了 lease 對象,然后 PVC 也成功綁定上了 PV。

可以看到上面的 PVC 已經(jīng)自動綁定到 PV 上面去了,這個就是上面的 StorageClass 完成的工作。然后在 Wordpress 應(yīng)用上添加對 /var/www/html 目錄的掛載聲明:

  volumeMounts:
  - name: wordpress-data
    mountPath: /var/www/html
volumes:
- name: wordpress-data
  persistentVolumeClaim:
    claimName: wordpress-pvc

在 MySQL 應(yīng)用上添加對 /var/lib/mysql 目錄的掛載聲明:

  volumeMounts:
  - name: mysql-data
    mountPath: /var/lib/mysql
volumes:
- name: mysql-data
  persistentVolumeClaim:
    claimName: mysql-pvc

重新更新應(yīng)用即可,在更新的過程中發(fā)現(xiàn) MySQL 啟動失敗了,報如下所示的錯誤:

......
[ERROR] --initialize specified but the data directory has files in it. Aborting.

意思就是 /var/lib/mysql 目錄下面已經(jīng)有數(shù)據(jù)了,當(dāng)然可以清空該目錄然后重新創(chuàng)建即可,這里可能是 mysql:5.7 這個鏡像的 BUG,所以我們更改成 mysql:5.6 這個鏡像,去掉之前添加的一個認證參數(shù):

containers:
- image: mysql:5.6
  name: mysql
  imagePullPolicy: IfNotPresent
  args:
  - --character-set-server=utf8mb4
  - --collation-server=utf8mb4_unicode_ci

重新更新就可以正常啟動了。

Ingress

對于一個線上的應(yīng)用對外暴露服務(wù)用一個域名顯然是更加合適的,上面我們使用的 NodePort 類型的服務(wù)不適合用于線上生產(chǎn)環(huán)境,這里我們通過 Ingress 對象來暴露服務(wù),由于我們使用的是 Traefik2.1 這個 Ingress 控制器,所以通過 IngressRoute 對象來暴露我們的服務(wù),此外為了安全我們還使用了 ACME 來自動獲取 https 的證書,并且通過一個中間件將 http 強制跳轉(zhuǎn)到 https 服務(wù):(ingressroute.yaml)

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: wordpress-https
  namespace: kube-example
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`wordpress.qikqiak.com`)
    kind: Rule
    services:
    - name: wordpress
      port: 80
  tls:
    certResolver: ali
    domains:
    - main: "*.qikqiak.com"
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: redirect-https
  namespace: kube-example
spec:
  redirectScheme:
    scheme: https
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: wordpress-http
  namespace: kube-example
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`wordpress.qikqiak.com`)
    kind: Rule
    services:
    - name: wordpress
      port: 80
    middlewares: 
    - name: redirect-https

直接創(chuàng)建上面的資源對象即可:

$ kubectl apply -f ingressroute.yaml 
ingressroute.traefik.containo.us/wordpress-https created
middleware.traefik.containo.us/redirect-https created
ingressroute.traefik.containo.us/wordpress-http created

然后對域名 wordpress.qikqiak.com 加上對應(yīng)的 DNS 解析即可正常訪問了,這樣即使我們的數(shù)據(jù)庫或者 Wordpress 應(yīng)用掛掉了也不會丟失數(shù)據(jù)了,到這里就完成了我們一個生產(chǎn)級別應(yīng)用的部署,雖然應(yīng)用本身很簡單,但是如果真的要部署到生產(chǎn)環(huán)境我們需要關(guān)注的內(nèi)容就比較多了,當(dāng)然對于線上應(yīng)用除了上面我們提到的還有很多值得我們關(guān)注的地方,比如監(jiān)控報警、日志收集等方面都是我們關(guān)注的層面。

wordpress deploy flow


瀏覽 87
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報
評論
圖片
表情
推薦
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 婷婷久久综合久色| 天堂在线v| 三级片在线观看网站| 国产精品秘久久久久久免费播放| 中文字幕人妻丰满熟妇| 91丨九色丨老农村| 亚洲电影在线| 免费日韩黄色电影| 亚洲成人无码高清| 国精产品一区二区三区在线观看| 日韩欧AV| 丁香五月天婷婷| 99久久婷婷国产综合精品电影| 中文字幕不卡无码| AV乱伦小说| 国产免费av网站| 久草电影网站| 先锋久久资源| 少妇456| 日韩成人在线视频| 国内老熟妇对白XXXXHD| 国产熟女乱伦视频| 逼逼爱| 东京热网站在线观看| 91在线无码精品秘蜜桃入口| 成人精品视频在线| 草榴在线视频| 免费福利在线视频| 久久精品视频99| 丁香五月婷婷啪啪| 国产精品扒开腿做爽爽爽A片唱戏 中文字幕一区二区三区精华液 | 一品国精和二品国精的文化意义| 天天干夜夜操| 日韩三级电影| 无码一级片| 高清无码视频在线播放| 天天操狠狠操| 国产精品久久久久久久久久久久久久 | 奇米色婷婷| 亚洲中文字幕日韩| 7x7x7x人成免费观学生视频| 高清无码小视频| 国产男女无套免费| 无码人妻91| 伊人色爱| 国产精品无码久久久久成人app | 成人黄网在线观看| 国产精品久久久久久久久久二区三区 | 大地资源38页| 天天射夜夜操| 亚洲AV无码专区在线播放中文 | 欧美性爱一区二区三区| 夜夜夜操| 国产午夜在线视频| 亚洲无码成人在线观看| 欧美在线黄片| 无码爱爱| 九九激情| 加勒比无码在线播放| 天天操天天射天天日| 成人网址大全| 牛牛精品一区| 欧美老女人性爱视频| 亚洲AV无码专区在线播放中文 | 影音先锋天堂| 久久草在线观看| 婷婷成人电影| 青青草在线视频免费观看| 五月天福利视频| 一级特黄大片录像i| 口爆吞精在线观看| 成人免费在线观看| 91人妻在线视频| 欧洲成人免费视频| HEZ-502搭讪绝品人妻系列| 欧美日韩在线视频播放| 日韩一区二区免费视频| 婷久久| 中文字幕久久人妻无码精品蜜桃| 国产亚洲激情| 亚州精品人妻一二三区| 欧美成人大香蕉| 九色精品| 一级电影网站| 天天干天天干天天日| 永久免费一区二区三区| 97超碰大香蕉| 日本日韩欧美| 日韩一级二级| 欧美一级A片高清免费播放| 精品一二三区| 国产无码av| 亚洲一区二区黄色电影视频网站| 亚洲性爱工厂| 久久久中文字幕| 亚洲黄色视频免费| 又大又长又粗91| 亚洲国产精品自| 午夜日屄| 亚洲无码av网站| 尤物网站在线观看| 国产三级视频在线| 翔田千里在线播放| 嫩草视频网站| 青青草视频黄| 国产视频你懂的| 日韩中文字幕AV| 麻豆91视频| 69无码| 亚洲任你操超碰在线| 天天操天天干欧美精品| 小黃片秘嗯嗯啊| 先锋影音亚洲无码av| 自拍偷拍1| 日韩精品无码人妻| 午夜激情久久| 亚洲欧美在线免费观看| 国产美女全裸网站| 成人特级毛片全部免费播放| 成人性生活免费视频| 中文字幕视频2023| 91蝌蚪久久| 人人爽亚洲AV人人爽AV人人片| 大香蕉美女视频| 久久中文无码| 黄色福利视频在线观看| AV免费网址| 人人射在线| 69视频国产| 午夜三级福利| 91无码精品| 操逼综合网| 亚洲国产另类精品| 日本久久不卡| 人人天天久久| www俺来也com| 久久综合五月天| 中文在线高清字幕| www.插插插| 日韩黄色网| 爱爱帝国综合社区| 麻豆视屏| 人妻丰满精品一区二区| 99做爱| 熟妇综合| 成人网站一区| 五月婷婷在线观看| 搡BBBB搡BBB搡五十粉嫩| 亚洲影院第一页在线观看| 精品国产香蕉| 久久免费视频,久久免费视频| 国产精品久久久久精| 91精品久久久久久粉嫩| 18XXX亚洲HD护士JD| 国产操逼网| 成人无码小电影| 波多野结衣无码AV专区| 亚洲无码AV在线观看| 黄片小视频在线观看| 日产无码久久久久久| 午夜福利院| 久久午夜无码鲁丝片午夜精品偷窥 | 无码人妻系列| 神马午夜51| 亚州AV操屄| 西西西444www无码视频| 久久激情av| 久久偷拍网| 日韩一区在线视频| 亚洲精品在线视频| 褒姒AV无玛| 十八禁网站在线观看| 国产精品国产三级囯产普通话2| 国产又爽又黄免费| 亚洲欧美国产日韩字幕| 丝袜一区| 性爱二区| 国产精品自拍视频| 微拍福利一区二区| 你懂得在线视频| 亚洲区一| 激情五月天影院| 97精品| 婷婷激情中文字幕| 激情人妻网站| 婷婷久久婷婷| 日韩午夜| 韩国GOGOGO高清| 色婷婷Av一区| 亚洲黄色免费观看| 在线亚洲免费| 操嫩逼| 免费AV网站观看| 亚洲免费小电影| 亚州操逼片| 军人妓女院BD高清片在线播放| 青草福利视频| 国产91黄色| 91久久久久久久18| 99人人操| 国产在线激情| 一二三区| 日韩免费AV电影| 国产又大又粗| 日韩av在线免费观看| 黄片免费无码| 亚洲精品久久久久毛片A级绿茶| 久久久久久穴| 五月婷婷影院| 蜜桃av久久久亚洲精品| 国产69久久精品成人看| 日本亚洲黄色视频| 天天日天天干天天操| 日韩三级片网址| 欧美成人精品网站| 五月丁香大香蕉| av干在线| 婷婷五月色播| 老熟妇一区二区三区啪啪| 在线免费看av| 99re视频精品| 久久久波多野结衣| 国精产品一二四区黑人| 色噜噜狠狠一区二区三区Av蜜芽| 久久久久中文字幕| 久久99精品久久久久久水蜜桃| 91精品丝袜久久久久久久久久粉嫩 | 中文字幕永久| 天天射综合| 国产一区在线观看视频| 三上悠亚无码破解69XXX| 麻豆免费视频| 米奇电影777无码| 亚洲成人无码视频在线观看| 亚洲欧美国产日韩字幕| 中文字幕在线免费观看| av天堂中文| 黄片在线免费播放| 色婷婷综合网| 成年人免费公开视频| 日韩精品久久久| 国产三级无码| 亚洲欧洲自拍| 人人操人人搞| 天天做天天爱天天高潮| 日本性爱网址| 亚洲AV中文无码| 亚洲激情网| 草碰在线视频| 91久久成人| 中文字幕1区| 抠逼网站| 成人爱爱免费视频| 九色91视频| 五月天丁香婷婷视频| 精品人伦一区二区三区| 麻豆乱码国产一区二区三区| 97爱爱视频| 超碰免费91| 一级A片在线观看| 天堂综合网久久| 久久久久久久久久国产| 99视频网站| 西西人体444www| 在线黄色av| 18禁网址| 北条麻妃AV观看| 在线中文无码| 一区二区三区四区不卡| 日本电影一区二区三区| 日皮免费视频| 怡红院在线观看| 特级西西444www大精品| 免费毛片视频| 亚洲色图88| 日韩小视频在线观看| 青青操国产乱伦| 91欧美性爱| 小處女末发育嫩苞AV| 丁香花中文字幕| 久操视频免费在线观看| 日韩无码视频一区| 亚洲黄色小电影| 91人妻无码精品蜜桃| 天天干强奸视频在线综合| 久热9| 青青草成人在线| 精品久久三级片| 2025精品视频| 日本成人视频在线免费播放| 午夜乱伦福利| 欧美在线一区二区三区| 国产一级AA片| 麻豆激情| 国产精品久久久久久久久久二区三区 | 国产激情在线观看| 国产久久久久久久久久| 制服丝袜乱伦| 欧美色图视频在线观看| 久久成人导航| 天天添夜夜添| www.日批| 国产精品毛片| 欧美日韩在线视频一区| 爽好紧别夹喷水网站| 五月精品在线| 翔田AV无码秘三区| 无码精品一区二区三区在线观看| 粉嫩护士小泬18p| 日韩99| 色吧av| 国产无码久久| 久久综合大香蕉| 91成人福利| 男女啪网站| 97精品国产97久久久久久免费| 亚洲免费在线婷婷| 一区二区有限公司| 一区二区三区久久| 免费国产黄色视频| 人妻第一页| 17c白丝喷水自慰| 波多野结衣av无码| 五月丁香激情在线| 欧美大香蕉在线| 偷拍亚洲综合| 中文字幕在线不卡| 日韩色图在线观看| 成人无码视频在线观看| 中字幕视频在线永久在线观看免费 | 日本免费在线黄色视频| 国产成人精品视频免费| 欧美三级欧美一级| 国产精品一卡二卡| 天天日天天干天天爽| 国产在线观看无码免费视频| 欧美性大香蕉| 91网站免费观看| 免费欧美三级片| 高潮国产视频| 欧美日本一区二区三区| 青娱乐伊人| 亚洲精品无码永久| 无码人妻精品一区二区三区蜜臀百度 | 97色色得| 丝瓜av| 日韩99热| 色色777| 中字av| 日本一区二区视频| 特一级黄A片| 亚洲成人福利| 91AV天天在线观看| 九九综合久久| 亚洲黄色小电影| 狠狠久| 中国丰满妇BBwBBwHD| 国产乱伦免费| 一级香蕉视频| 内射在线播放| 在线免费观看视频黄| 在线观看AV91| 国产无码一二三| 亚洲AV无码国产精品二区| 无码精品久久| 1024手机在线视频| 一级片黄色| 久操免费在线观看| 双飞少妇| 亚洲视频福利| 久草视频在线播放| 欧美性爱怡红院| 五月无码视频| 91香蕉国产在线观看软件| 国产精品一区二区黑人巨大| 久热官网| 九热精品| 亚洲美女视频| 草莓av| 久久1234| 亚洲AV无码成人| 婷婷精品秘进入| 国产在线拍揄自揄拍无码福利| 偷拍视频图片综合网| av在线免费播放| 亚洲性无码| 丝袜美女足交| 天堂网2014| 精品国产免费无码久久噜噜噜AV| 精品91海角乱| 中文字幕亚洲天堂| 色婷婷在线无码精品秘人口传媒| 亚洲无码理论片| 成人怡红院| 午夜成人福利剧场| 中国人妻HDbute熟睡| 日韩在线电影| 午夜视频免费| 精品欧美激情精品一区| 18岁毛片| 99国产免费视频| 大香蕉av一区二区三区在线观看 | 亚洲男人天堂网| 中文字幕无码日韩| 国产日韩91| 久久夜色精品| 欧美va在线| 日韩av电影免费在线观看| 亚洲人妻在线视频| 国产又大又粗又黄| 欧美精品毛片| 精品国产乱码久久久久久郑州公司 | 狼人综合网| 影音先锋天堂网| 好屌肏| 五月婷婷综合网| Japanese在线观看| 五月天婷婷小说| 操B在线| 亚洲一区二区三区视频| 国产精品一区二区AV日韩在线 | 97精品国产97久久久久久免费| 在线免费观看黄色网址| 一级片在线| 日韩AV在线免费| 日本黄色电影在线播放| 国产av高清| 99综合视频| 韩国gogogo高清在线完整版| 蜜桔视频嫩草蜜桃| 欧美成人精品欧美一级私黄| 黄片网站免费在线观看| 婷婷开心色四房播播在线| 国产一级a一级a免费视频| 国内自拍视频网| 成人在线91| 国产h视频在线观看| 撸一撸在线观看| 亚洲美女视频在线| 神马午夜51| 欧美一级黄色大片| 高潮无码在线观看| 欧美性爱精品一区| 日韩免费无码视频| 亚洲国产欧美日韩在线| 老司机午夜电影| 国产欧美日韩在线| 一道本一区二区三区| 成人性爱视频在线| 午夜艹| 亚洲AV永久无码精品| 东方av在线播放| 韩国一区二区三区在线观看| av在线免费播放| 国产婷婷色| 亚洲香蕉影院| 久久久久久久毛片| 国产1区2区| 亚洲www在线| 少妇喷水在线观看| 美国操逼片| 撸一撸在线视频| 亚洲成人视频在线免费观看| 骚逼国产| 日本高清一区二区高清免费视频| 亚洲精品456| 肏屄一区| 99re88| 最新精品视频| 亚洲天堂无码视频| 欧美一级黄色大片| 美女被操网站免费| 亚洲精品字幕久久久久| caobi视频| 午夜福利久久| 亚洲色综合网| 狠狠狠狠狠| 91网站免费| 91伊人在线| 国产欧美一区二区三区特黄手机版 | www.国产| 伊人久久精品| 激情五月天小说网| 日韩av免费| 毛片三级片| 精品无码一区二区人妻久久蜜桃| 中文字幕在线资源| 波多野结衣无码一区| 亚洲高清无码视频| 一级a一级a免费观看视频Al明星| 无码A级片| 日韩无码黄色电影| 午夜大香蕉| 在线aaa| 久久国产日韩| 无码一二三区| R四虎18| 偷拍亚洲综合| 手机看片福利一区二区| 亚洲精品免费视频| 青青草免费观看视频| 精品九九九| 日韩欧美黄色电影| 国产乱码精品一区二区三区的特点 | 7799精品视频| 黄色免费看| 日产精品久久| 久久夜色精品| 一二区视频| 91久久成人| AV黄色网| 国产免费黄色视频网站| 成人在线乱码视频| 久热精品视频在线观看| 日产无码| 国产区一区| 一级AAAAA片裸体做受| 日韩精彩视频| 国产黄色大片| 99热18| 91在线无精精品秘白丝| 自拍偷拍影音先锋| 久久福利视频导航| 亚洲砖区| 最新AV在线播放| 四虎精品一区二区三区| 狠狠五月| 亚洲成人无码av| 99re66| 国产69视频在线观看| 成人性生活影视av| 天堂VA蜜桃一区二区三区| 俺来也俺也啪www色| 五月丁香婷婷在线| 婷婷五月无码| 久久精品观看| 一区二区三区四区成人| 99久久久久久久无码| 偷偷操穴| 嫩BBB嫩BBB嫩BBB| 日韩午夜剧场| 91农村站街老熟女露脸| 乱子伦国产精品视频一级毛 | 久久久精品一区| 人人爱人人看| 小草久久95| 啪啪啪啪网站| 成人午夜福利网站| 国产欧美综合一区二区三区| 骚熟妇| 日韩免费小视频| 69色色| 99在线小视频| 国产免费操逼| 4444操| 日本免费A片| www.狠狠撸| 操日韩| 久久黄色免费视频| 狼人综合在线| 蜜桃久久av一区| 五月天婷婷网址| 成人才看的在线视频| 91香蕉国产在线观看| 老妇性BBWBBWBBWBBW | 成人做爰A片一区二区| 豆花视频成人网站入口免费观看| 大香蕉久热| 欧美久久视频| Av黄色| 亚洲AV无码久久寂寞少妇多毛| 欧美精品成人网站| 亚欧美日韩| 欧一美一伦一A片| 成人禁区| 4虎亚洲人成人网www| 欧美口爆| 亚洲黄色影院| 中文字幕亚洲日韩| 亚洲精品乱码久久久久久蜜桃91 | 天堂色播| 久久久WWW成人免费无遮挡大片| 日韩免费在线观看| yy午夜福利| 欧美日韩国产不卡视频| 天天干天天日天天操| 青青草视频在线观看| 天天天操| 99er热精品视频| 国产美女自拍视频| 日韩人妻视频| 精品久久久久久久久久久| 国产人人色| 亚洲福利一区| 99久久久国产| 亚洲AV无码精品国产| 91干干| 成人亚洲综合| 欧美性爱18| 成年人视频网| 国产黄片在线视频| 国产婬片lA片www777| 日韩蜜桃视频| h在线网站| 一级片电影网站| 亚洲无码一区二区三区蜜桃| 日本特黄一级| 久久六月天| 久久草草热国产精| 欧美亚洲黄色| 黄色片久久久| 日本黄色视频官网| 亚洲AV秘一区二区色盗战流出| 欧美夜夜草视频| 日本久久久久久久久视频在线观看| 国产成人精品视频| 欧美午夜精品| 18禁黄网站| 内射视频网站| 一道本在线| 五月天黄色电影| 黄色在线网站| 午夜婷婷| 日韩小电影| 国产免费黄色| 亚洲天堂AB| 婷婷五月天激情俺来也| 亚洲AV在线人妻| 国产亚洲视频完整在线观看| 日本操逼在线播放| 色999网址| 激情av天堂| 日本欧美中文| 99热碰碰热| 99热中文字幕在线观看| 在线成人视频网站大香蕉在线网站 | 91视频美女模特| 欧美成人图片视频在线| 亚洲女与黑人正在播放| 亚洲Japanese办公室制服| 另类老妇性BBBWBBW| A一级黄色| 丁香五月天在线播放| 国产AV久| 欧美精品一区二区三区蜜臀| 国产精品视频久久久久| 欧美特黄AAAAAA| 伊人久久久久久久久久久| 国产一区在线观看视频| 四虎成人精品永久免费AV九九| A级视频免费观看| 伊人久久五月| 成人AV在线资源| 久久AV网站| 免费二区| 好男人WWW一区二区三区| 成人黄色视频免费| www.激情| 色xxxx| 亚洲性爱av| 日韩视频在线观看免费| 中文字幕欧美日韩| 天天干夜夜操| 欧美91熟| 尤物视频网站在线观看| 亚洲欧洲自拍| 天堂AV无码AV| 亚洲群交视频| 中文字幕在线一区二区a| 亚州视频在线| 黄色大片免费在线观看| 午夜福利10000| 91三级视频| 影音先锋三级片| 一级无码毛片| 殴殴美日韩在线| 91在线91| 欧美色逼| 激情视频在线播放| 少妇人妻AV| 18禁污网站| 91蝌蚪在线观看| 美女天堂网| 97国产精品视频| 日本精品视频在线观看| 综合一区二区| 中文爱爱视频| 亚洲色图一区二区| 亚洲成人精品一区| 久久尹人| 人人做人人操| 老妇槡BBBB槡BBBB槡| 国产精品视频福利| 成人无码一区二区| 香蕉成人网| 日韩人妻无码一区二区三区七区 | 五月乱伦| 91男女| 日韩黄色电影网址| 熟妇槡BBBB槡BBBB| 亚洲成人国产| 久久永久免费精品人妻专区| 99久久精品一区二区成人| 亚洲欧美日韩免费| 国产精品久久久久无码AV | 日韩无码一区二区三区四区| 精品无码一区二区三| 六月婷| 败火老熟女ThePorn视频| 国产精品2025| 日韩无码一二三区| 日韩激情一区| 色先锋av| 99在线精品视频免费观看软件| 日日天天| 操逼逼一区二区三区| 操小逼视频| 在线久操| 国产欧美黄片| 免费操逼视频在线观看| 3D动漫精品啪啪一区二区下载| 91无码人妻传媒tv| 日韩无任何视频在线观看| 四川BBB搡BBB爽爽爽欧美| 免费黄视频在线观看| 中国熟女HD| 亚洲欧美国产毛片在线| 99久久婷婷国产综合精品hsex,亚| 色色天堂| 综合成人在线| 久久蜜桃成人| 激情综合视频| 成人无遮挡| 51午夜| 天天操操操| 国内自拍99| 精品一区二区三区四区五区| 久久精品黄色| 亚洲A级片| 老女人的逼| 国产偷拍精品视频| 午夜毛片| 亚洲高清人妻| 女人BBBB| 91亚洲精品国偷拍自产在线观看 | 日本二区三区| 亚洲AV第二区国产精品| 国产日韩欧美在线| 91香蕉国产在线观看| 中国毛片视频| 日韩在线观看一区二区| 免费69视频| 成人网站在线免费看| 午夜福利干B在线免费小视频| 日韩人妻精品一区二区| 日本中文字幕在线观看视频| 国产亚洲天堂| 2014AV天堂网| 男女av在线| 日韩成人无| 操老骚逼视频| 日韩无码视频免费| 中国黄色大片| 国产成人秘免费观看一区二区三区 | 青娱乐国产精品| 亚洲无码在线观看网站| 青青草成人电影| 西西西444www无码视| 亚洲av免费| 久久6热| 欧美成人免费观看| 中文字幕无码网站| 中文字幕+乱码+中文乱码电影| 日韩欧美网站| 国内自拍激情视频| 国产AV电影网| 国内精品一区二区三区| 欧一美一婬一伦一区二区三区黑人| 超碰在线99| 欧美成人中文字幕| 九色PORNY丨自拍蝌蚪| 日本无码在线视频| 丁香五月成人| 日韩黄色中文字幕| 一级一级a免一级a做免费线看内裤| 三级无码片| 国产精品国产精品国产专区 | 热久久视频| 亚洲天堂大香蕉| 亚洲老鸭窝| 99视频网站| 成人尤物网站| 国产青草视频| 亚洲成人免费在线观看| 97无码| 先锋影音一区| 欧美三级理论片| 久久成人网站| 亚洲精品成人无码| 欧美三级不卡| 婷婷五月国产| 黄色A片在线观看| 男人色天堂| 四虎影院最新地址| 日韩福利网| 第一福利视频导航| 一级色色片| 天堂视频在线观看亚洲美女| 又大又粗又爽| 大香蕉久操| 伊人丁香| 午夜特级| 丁香五月社区| 五月丁香久久| 青青久久91| 欧美日韩黄色片| 日韩一级免费视频| 麻豆91久久久| 特级西西西88大胆无码| 国产又大又粗| 91成人在线视频| 无码AV天堂| 9l视频自拍蝌蚪9l成人| 波多野结衣无码AV在线| 特级毛片在线观看| 亚洲丰满熟妇| 日韩高清无码人妻| 黄片免费大全| 成人免费一级视频| 中文字幕第9页| 九九热精品视频在线观看| 欧美性猛交一区二区三区精品| 国产精品国产三级国产AⅤ中文| 乱伦无码视频| 成人无码区免费A片久久鸭| 三级片AAAA| XXXXⅩHD亚洲人HD| 国产suv精品一区二区6| 一道本视频在线免费观看| 久久免费视频,久久免费视频 | 亚洲在线视频免费观看| 亚洲色图狠狠撸| 色片免费| 亚洲va视频| 国产精品毛片| 国产系列精品AV| 综合色婷婷一区二区亚洲欧美国产 | 天天色天天干天天| 日韩精品视频一区二区三区| 日韩午夜| 蜜臀99| 波多野吉衣高清无码| 中文字幕日韩在线观看| 欧美偷拍一区二区| 婷婷五月国产| 亚洲自拍偷拍视频| 欧美性猛交XXXX乱大交| 99re超碰| 国产精品操逼视频| 日韩性无码| 丁香婷婷六月| 午夜激情在线观看| 四虎无码视频| 久久精品国产精品| 777AV| 成人精品福利| 国产看片网站| 日韩黄色中文字幕| 国产精品日韩高清北条麻衣| 最新中文字幕在线视频| 久草在在线视频| 青草视频网| 国产av天堂| 日韩免费在线观看| 一区二区三区四区免费看| 青青草手机在线视频| 天天毛片| 91精品婷婷国产综合久久| 欧美99| 日韩精品在线一区| 国产AⅤ爽aV久久久久成人| 亚洲欧美日韩性爱| AV福利在线观看| 天天干天天射天天操| 91综合在线观看| 无码三| 五月天青青草超碰免费公开在线观看| 国产精品久久久大香蕉| 欧美日韩三区| 国产精品特级毛片| 亚洲中文字幕免费在线观看| 狠狠干狠狠干| 国产无遮挡又黄又爽又色视频软件| 视频在线观看一区| 国产高清做爱| 亚洲激情自拍| 亚洲AV在线免费观看| 97精产国品久久蜜桃臀| 神马影院午夜福利| 免费一区二区三区|