精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

在Kubernetes中部署高可用應用程序的實踐

云計算
Kubernetes 可以提供所需的編排和管理功能,以便您針對這些工作負載大規模部署容器。借助 Kubernetes 編排功能,您可以構建跨多個容器的應用服務、跨集群調度、擴展這些容器,并長期持續管理這些容器的健康狀況。有了 Kubernetes,您便可切實采取一些措施來提高 IT 安全性。

[[432705]]

真正的生產型應用會涉及多個容器。這些容器必須跨多個服務器主機進行部署。容器安全性需要多層部署,因此可能會比較復雜。但 Kubernetes 有助于解決這一問題。

Kubernetes 可以提供所需的編排和管理功能,以便您針對這些工作負載大規模部署容器。借助 Kubernetes 編排功能,您可以構建跨多個容器的應用服務、跨集群調度、擴展這些容器,并長期持續管理這些容器的健康狀況。有了 Kubernetes,您便可切實采取一些措施來提高 IT 安全性。

高可用性(High Availability,HA)是指應用系統無中斷運行的能力,通常可通過提高該系統的容錯能力來實現。一般情況下,通過設置 replicas 給應用創建多個副本,可以適當提高應用容錯能力,但這并不意味著應用就此實現高可用性。

眾所周知,在Kubernetes環境中部署一個可用的應用程序是一件輕而易舉的事。但另外一方面,如果要部署一個可容錯,高可靠且易用的應用程序則不可避免地會遇到很多問題。在本文中,我們將討論在Kubernetes中部署高可用應用程序并以簡潔的方式給大家展示,本文也會重點介紹在Kubernetes部署高可用應用所需要注意的原則以及相應的方案。

請注意,我們不會使用任何現有的部署方案。我們也不會固定特定的CD解決方案,我們將省略模板生成 Kubernetes 清單的問題。在本文中,我們只討論部署到集群時 Kubernetes 清單的最終內容,其它的部分本文不作過多的討論。

一、副本數量

通常情況下,至少需要兩個副本才能保證應用程序的最低高可用。但是,您可能會問,為什么單個副本無法做到高可用?問題在于 Kubernetes 中的許多實體(Node、Pod、ReplicaSet ,Deployment等)都是非持久化的,即在某些條件下,它們可能會被自動刪除或者重新被創建。因此,Kubernetes 集群本身以及在其中運行的應用服務都必須要考慮到這一點。

例如,當使用autoscaler服務縮減您的節點數量時,其中一些節點將會被刪除,包括在該節點上運行的 Pod。如果您的應用只有一個實例且在運行刪除的節點上,此時,您可能會發現您的應用會變的不可用,盡管這時間通常是比較短的,因為對應的Pod會在新的節點上重新被創建。

一般來說,如果你只有一個應用程序副本,它的任何異常停服都會導致停機。換句話說,您必須為正在運行的應用程序保持至少兩個副本,從而防止單點故障。

副本越多,在某些副本發生故障的情況下,您的應用程序的計算能力下降的幅度也就越小。例如,假設您有兩個副本,其中一個由于節點上的網絡問題而失敗。應用程序可以處理的負載將減半(只有兩個副本中的一個可用)。當然,新的副本會被調度到新的節點上,應用的負載能力會完全恢復。但在那之前,增加負載可能會導致服務中斷,這就是為什么您必須保留一些副本。

上述建議與未使用 HorizontalPodAutoscaler 的情況相關。對于有多個副本的應用程序,最好的替代方法是配置 HorizontalPodAutoscaler 并讓它管理副本的數量。本文的最后會詳細描述HorizontalPodAutoscaler。

二、更新策略

Deployment 的默認更新策略需要減少舊+新的 ReplicaSet Pod 的數量,其Ready狀態為更新前數量的 75%。因此,在更新過程中,應用程序的計算能力可能會下降到正常水平的 75%,這可能會導致部分故障(應用程序性能下降)。

該strategy.RollingUpdate.maxUnavailable參數允許您配置更新期間可能變得不可用的Pod的最大百分比。因此,要么確保您的應用程序在 25% 的Pod不可用的情況下也能順利運行,要么降低該maxUnavailable參數。請注意,該maxUnavailable參數已四舍五入。

默認更新策略 ( RollingUpdate)有一個小技巧:應用程序在滾動更新過程中,多副本策略依然有效,新舊版本會同時存在,一直到所有的應用都更新完畢。但是,如果由于某種原因無法并行運行不同的副本和不同版本的應用程序,那么您可以使用strategy.type: Recreate參數。在Recreate策略下,所有現有Pod在創建新Pod之前都會被殺死。這會導致短暫的停機時間。

其他部署策略(藍綠、金絲雀等)通常可以為 RollingUpdate 策略提供更好的替代方案。但是,我們沒有在本文中考慮它們,因為它們的實現取決于用于部署應用程序的軟件。

三、跨節點的統一副本分布

Kubernetes 的設計理念為假設節點不可靠,節點越多,發生軟硬件故障導致節點不可用的幾率就越高。所以我們通常需要給應用部署多個副本,并根據實際情況調整 replicas 的值。該值如果為1 ,就必然存在單點故障。該值如果大于1但所有副本都調度到同一個節點,仍將無法避免單點故障。

為了避免單點故障,我們需要有合理的副本數量,還需要讓不同副本調度到不同的節點。為此,您可以指示調度程序避免在同一節點上啟動同一 Deployment 的多個 Pod:

  1. affinity: 
  2.   PodAntiAffinity: 
  3.     preferredDuringSchedulingIgnoredDuringExecution: 
  4.     - PodAffinityTerm: 
  5.         labelSelector: 
  6.           matchLabels: 
  7.             app: testapp 
  8.         topologyKey: kubernetes.io/hostname 

最好使用preferredDuringSchedulingaffinity而不是requiredDuringScheduling。如果新Pod所需的節點數大于可用節點數,后者可能會導致無法啟動新 Pod。盡管如此,requiredDuringScheduling當提前知道節點和應用程序副本的數量并且您需要確保兩個Pod不會在同一個節點上結束時,親和性也就會派上用場。

四、優先級

priorityClassName代表您的Pod優先級。調度器使用它來決定首先調度哪些 Pod,如果節點上沒有剩余Pod空間,應該首先驅逐哪些 Pod。

您將需要添加多個PriorityClass(https://kubernetes.io/docs/concepts/configuration/Pod-priority-preemption/#priorityclass)類型資源并使用priorityClassName。以下是如何PriorityClasses變化的示例:

  • Cluster. Priority > 10000:集群關鍵組件,例如 kube-apiserver。
  • Daemonsets. Priority: 10000:通常不建議將 DaemonSet Pods 從集群節點中驅逐,并替換為普通應用程序。
  • Production-high. Priority: 9000:有狀態的應用程序。
  • Production-medium. Priority: 8000:無狀態應用程序。
  • Production-low. Priority: 7000:不太重要的應用程序。
  • Default. Priority: 0:非生產應用程序。

設置優先級將幫助您避免關鍵組件的突然被驅逐。此外,如果缺乏節點資源,關鍵應用程序將驅逐不太重要的應用程序。

五、停止容器中的進程

STOPSIGNAL中指定的信號(通常為TERM信號)被發送到進程以停止它。但是,某些應用程序無法正確處理它并且無法正常停服。對于在 Kubernetes 中運行的應用程序也是如此。

例如下面描述,為了正確關閉 nginx,你需要一個preStop這樣的鉤子:

  1. lifecycle: 
  2. preStop: 
  3.   exec
  4.     command: 
  5.     - /bin/sh 
  6.     - -ec 
  7.     - | 
  8.       sleep 3 
  9.       nginx -s quit 

上述的簡要說明:

  1. sleep 3 可防止因刪除端點而導致的競爭狀況。
  2. nginx -s quit正確關閉nginx。鏡像中不需要配置此行,因為 STOPSIGNAL: SIGQUIT參數默認設置在鏡像中。

STOPSIGNAL的處理方式依賴于應用程序本身。實際上,對于大多數應用程序,您必須通過谷歌搜索或者其它途徑來獲取處理STOPSIGNAL的方式。如果信號處理不當,preStop鉤子可以幫助您解決問題。另一種選擇是用應用程序能夠正確處理的信號(并允許它正常關閉)從而來替換STOPSIGNAL。

terminationGracePeriodSeconds是關閉應用程序的另一個重要參數。它指定應用程序正常關閉的時間段。如果應用程序未在此時間范圍內終止(默認為 30 秒),它將收到一個KILL信號。因此,如果您認為運行preStop鉤子和/或關閉應用程序STOPSIGNAL可能需要超過 30 秒,您將需要增加 terminateGracePeriodSeconds 參數。例如,如果來自 Web 服務客戶端的某些請求需要很長時間才能完成(比如涉及下載大文件的請求),您可能需要增加它。

值得注意的是,preStop hook 有一個鎖定機制,即只有在preStop hook 運行完畢后才能發送STOPSIGNAL信號。同時,在preStop鉤子執行期間,terminationGracePeriodSeconds倒計時繼續進行。所有由鉤子引起的進程以及容器中運行的進程都將在TerminationSeconds結束后被終止。

此外,某些應用程序具有特定設置,用于設置應用程序必須終止的截止日期(例如,在Sidekiq 中的--timeout 選項)。因此,您必須確保如果應用程序有此配置,則它的值略應該低于terminationGracePeriodSeconds。

六、預留資源

調度器使用 Pod的resources.requests來決定將Pod調度在哪個節點上。例如,無法在沒有足夠空閑(即非請求)資源來滿足Pod資源請求的節點上調度Pod。另一方面,resources.limits允許您限制嚴重超過其各自請求的Pod的資源消耗。

一個很好的方式是設置limits等于 requests。將limits設置為遠高于requests可能會導致某些節點的Pod無法獲取請求的資源的情況。這可能會導致節點(甚至節點本身)上的其他應用程序出現故障。Kubernetes 根據其資源方案為每個Pod分配一個 QoS 類。然后,K8s 使用 QoS 類來決定應該從節點中驅逐哪些 Pod。

因此,您必須同時為 CPU 和內存設置requests 和 limits。如果Linux 內核版本早于 5.4(https://engineering.indeedblog.com/blog/2019/12/cpu-throttling-regression-fix/)。在某些情況下,您唯一可以省略的是 CPU 限制(在 EL7/CentOS7 的情況下,如果要支持limits,則內核版本必須大于 3.10.0-1062.8.1.el7)。

此外,某些應用程序的內存消耗往往以無限的方式增長。一個很好的例子是用于緩存的 Redis 或基本上“獨立”運行的應用程序。為了限制它們對節點上其他應用程序的影響,您可以(并且應該)為要消耗的內存量設置限制。

唯一的問題是,當應用程序達到此限制時應用程序將會被KILL。應用程序無法預測/處理此信號,這可能會阻止它們正常關閉。這就是為什么除了 Kubernetes 限制之外,我們強烈建議使用專門針對于應用程序本身的機制來限制內存消耗,使其不會超過(或接近)在 Pod的limits.memory參數中設置的數值。

這是一個Redis配置案例,可以幫助您解決這個問題:

  1. maxmemory 500mb   # if the amount of data exceeds 500 MB... 
  2. maxmemory-policy allkeys-lru   # ...Redis would delete rarely used keys 

至于 Sidekiq,你可以使用 Sidekiq worker killer(https://github.com/klaxit/sidekiq-worker-killer):

  1. require 'sidekiq/worker_killer' 
  2. Sidekiq.configure_server do |config| 
  3. config.server_middleware do |chain| 
  4.   # Terminate Sidekiq correctly when it consumes 500 MB 
  5.   chain.add Sidekiq::WorkerKiller, max_rss: 500 
  6. end 
  7. end 

很明顯,在所有這些情況下,limits.memory需要高于觸發上述機制的閾值。

七、探針

在 Kubernetes 中,探針(健康檢查)用于確定是否可以將流量切換到應用程序(readiness probes)以及應用程序是否需要重新啟動(liveness probes)。它們在更新部署和啟動新Pod方面發揮著重要作用。

首先,我們想為所有探頭類型提供一個建議:為timeoutSeconds參數設置一個較高的值 。一秒的默認值太低了,它將對 readiness Probe 和 liveness probes 產生嚴重影響。

如果timeoutSeconds太低,應用程序響應時間的增加(由于服務負載均衡,所有Pod通常同時發生)可能會導致這些Pod從負載均衡中刪除(在就緒探測失敗的情況下),或者,更糟糕的是,在級聯容器重新啟動時(在活動探測失敗的情況下)。

7.1. 活性探針(liveness probes)

在實踐中,活性探針的使用并不像您想象的那樣廣泛。它的目的是在應用程序被凍結時重新啟動容器。然而,在現實生活中,應用程序出現死鎖是一個意外情況,而不是常規的現象。如果應用程序出于某種原因導致這種異常的現象(例如,它在數據庫斷開后無法恢復與數據庫的連接),您必須在應用程序中修復它,而不是“增加”基于 liveness probes 的解決方法。

雖然您可以使用 liveness probes 來檢查這些狀態,但我們建議默認情況下不使用 liveness Probe或僅執行一些基本的存活的探測,例如探測 TCP 連接(記住設置大一點的超時值)。這樣,應用程序將重新啟動以響應明顯的死鎖,而不會進入不停的重新啟動的死循環(即重新啟動它也無濟于事)。

不合理的 liveness probes 配置引起的風險是非常嚴重的。在最常見的情況下, liveness probes 失敗是由于應用程序負載增加(它根本無法在 timeout 參數指定的時間內完成)或由于當前正在檢查(直接或間接)的外部依賴項的狀態。

在后一種情況下,所有容器都將重新啟動。

在最好的情況下,這不會導致任何結果,但在最壞的情況下,這將使應用程序完全不可用,也可能是長期不可用。如果大多數Pod的容器在短時間內重新啟動,可能會導致應用程序長期完全不可用(如果它有大量副本)。一些容器可能比其他容器更快地變為 READY,并且整個負載將分布在這個有限數量的運行容器上。這最終會導致 liveness probes 超時,也將觸發更多的重啟。

另外,如果應用程序對已建立的連接數有限制并且已達到該限制,請確保liveness probes不會停止響應。通常,您必須為liveness probes指定一個單獨的應用程序線程/進程來避免此類問題。例如,如果應用程序有11個線程(每個客戶端一個線程),則可以將客戶端數量限制為10個,以確保liveness probes有一個空閑線程可用。

另外,當然,不要向 liveness Probe 添加任何外部依賴項檢查。

7.2. 就緒探針(Readiness probe)

事實證明,readinessProbe 的設計并不是很成功。readinessProbe 結合了兩個不同的功能:

  • 它會在容器啟動期間找出應用程序是否可用;
  • 它檢查容器成功啟動后應用程序是否仍然可用。

在實踐中,絕大多數情況下都需要第一個功能,而第二個功能的使用頻率僅與 liveness Probe 一樣。配置不當的 readiness Probe 可能會導致類似于 liveness Probe 的問題。在最壞的情況下,它們最終還可能導致應用程序長期不可用。

當 readiness Probe 失敗時,Pod 停止接收流量。在大多數情況下,這種行為沒什么用,因為流量通常或多或少地在 Pod 之間均勻分布。因此,一般來說,readiness Probe 要么在任何地方都有效,要么不能同時在大量 Pod 上工作。在某些情況下,此類行為可能有用。但是,根據我的經驗,這也主要是在某些特殊情況下才有用。

盡管如此,readiness Probe 還具有另一個關鍵功能:它有助于確定新創建的容器何時可以處理流量,以免將負載轉發到尚未準備好的應用程序。這個 readiness Probe 功能在任何時候都是必要的。

換句話說,readiness Probe的一個功能需求量很大,而另一個功能根本不需要。startup Probe的引入解決了這一難題。它最早出現在Kubernetes 1.16中,在v1.18中成為beta版,在v1.20中保持穩定。因此,最好使用readiness Probe檢查應用程序在Kubernetes 1.18以下版本中是否已就緒,而在Kubernetes 1.18及以上版本中是否已就緒則推薦使用startup Probe。同樣,如果在應用程序啟動后需要停止單個Pod的流量,可以使用Kubernetes 1.18+中的readiness Probe。

7.3. 啟動探針

startup Probe 檢查容器中的應用程序是否準備就緒。然后它將當前 Pod 標記為準備好接收流量或繼續更新/重新啟動部署。與 readiness Probe 不同,startup Probe 在容器啟動后停止工作。

我們不建議使用 startup Probe 來檢查外部依賴:它的失敗會觸發容器重啟,這最終可能導致 Pod 處于CrashLoopBackOff狀態。在這種狀態下,嘗試重新啟動失敗的容器之間的延遲可能高達五分鐘。這可能會導致不必要的停機時間,因為盡管應用程序已準備好重新啟動,但容器會繼續等待,直到因CrashLoopBackOff而嘗試重新啟動的時間段結束。

如果您的應用程序接收流量并且您的 Kubernetes 版本為 1.18 或更高版本,則您應該使用 startup Probe。

另請注意,增加failureThreshold配置而不是設置initialDelaySeconds是配置探針的首選方法。這將使容器盡快可用。

八、檢查外部依賴

如您所知,readiness Probe 通常用于檢查外部依賴項(例如數據庫)。雖然這種方法理應存在,但建議您將檢查外部依賴項的方法與檢查 Pod 中的應用程序是否滿負荷運行(并切斷向其發送流量)的方法分開也是個好主意)。

您可以使用initContainers在運行主容器的 startupProbe/readinessProbe 之前檢查外部依賴項。很明顯,在這種情況下,您將不再需要使用 readiness Probe 檢查外部依賴項。initContainers不需要更改應用程序代碼。您不需要嵌入額外的工具來使用它們來檢查應用程序容器中的外部依賴項。通常,它們相當容易實現:

  1. initContainers: 
  2.   - name: wait-postgres 
  3.     image: postgres:12.1-alpine 
  4.     command: 
  5.     - sh 
  6.     - -ec 
  7.     - | 
  8.       until (pg_isready -h example.org -p 5432 -U postgres); do 
  9.         sleep 1 
  10.       done 
  11.     resources: 
  12.       requests: 
  13.         cpu: 50m 
  14.         memory: 50Mi 
  15.       limits: 
  16.         cpu: 50m 
  17.         memory: 50Mi 
  18.   - name: wait-redis 
  19.     image: redis:6.0.10-alpine3.13 
  20.     command: 
  21.     - sh 
  22.     - -ec 
  23.     - | 
  24.       until (redis-cli -u redis://redis:6379/0 ping); do 
  25.         sleep 1 
  26.       done 
  27.     resources: 
  28.       requests: 
  29.         cpu: 50m 
  30.         memory: 50Mi 
  31.       limits: 
  32.         cpu: 50m 
  33.         memory: 50Mi 

九、完整示例

下面是無狀態應用程序的生產級部署的完整示例,其中包含上面提供的所有建議。可以作為大家生成的參考。

您將需要 Kubernetes 1.18 或更高版本以及內核版本為 5.4 或更高版本的基于 Ubuntu/Debian 的Kubernetes節點。

  1. apiVersion: apps/v1 
  2. kind: Deployment 
  3. metadata: 
  4. name: testapp 
  5. spec: 
  6. replicas: 10 
  7. selector: 
  8.   matchLabels: 
  9.     app: testapp 
  10. template: 
  11.   metadata: 
  12.     labels: 
  13.       app: testapp 
  14.   spec: 
  15.     affinity: 
  16.       PodAntiAffinity: 
  17.         preferredDuringSchedulingIgnoredDuringExecution: 
  18.         - PodAffinityTerm: 
  19.             labelSelector: 
  20.               matchLabels: 
  21.                 app: testapp 
  22.             topologyKey: kubernetes.io/hostname 
  23.     priorityClassName: production-medium 
  24.     terminationGracePeriodSeconds: 40 
  25.     initContainers: 
  26.     - name: wait-postgres 
  27.       image: postgres:12.1-alpine 
  28.       command: 
  29.       - sh 
  30.       - -ec 
  31.       - | 
  32.         until (pg_isready -h example.org -p 5432 -U postgres); do 
  33.           sleep 1 
  34.         done 
  35.       resources: 
  36.         requests: 
  37.           cpu: 50m 
  38.           memory: 50Mi 
  39.         limits: 
  40.           cpu: 50m 
  41.           memory: 50Mi 
  42.     containers: 
  43.     - name: backend 
  44.       image: my-app-image:1.11.1 
  45.       command: 
  46.       - run 
  47.       - app 
  48.       - --trigger-graceful-shutdown-if-memory-usage-is-higher-than 
  49.       - 450Mi 
  50.       - --timeout-seconds-for-graceful-shutdown 
  51.       - 35s 
  52.       startupProbe: 
  53.         httpGet: 
  54.           path: /simple-startup-check-no-external-dependencies 
  55.           port: 80 
  56.         timeoutSeconds: 7 
  57.         failureThreshold: 12 
  58.       lifecycle: 
  59.         preStop: 
  60.           exec
  61.             ["sh""-ec""#command to shutdown gracefully if needed"
  62.       resources: 
  63.         requests: 
  64.           cpu: 200m 
  65.           memory: 500Mi 
  66.         limits: 
  67.           cpu: 200m 
  68.           memory: 500Mi 

十、PodDisruptionBudget

PodDisruptionBudget(PDB:https://kubernetes.io/docs/concepts/workloads/Pods/disruptions/#Pod-disruption-budgets)機制是在生產環境中運行的應用程序的必備工具。它為您提供了一種方法,可以指定同時不可用的應用程序Pod數量的最大限制。在上文中,我們討論了一些有助于避免潛在風險情況的方法:運行多個應用程序副本,指定PodAntiAffinity(以防止多個Pod被分配到同一節點),等等。

但是,您可能會遇到多個 K8s 節點同時不可用的情況。例如,假設您決定將實例節點切換升級到更高配置的的實例節點。除此之外可能還有其他原因,本文不做更詳細的描述。最終的問題都是多個節點同時被刪除。你可能會認為,Kubernetes里的一切都是曇花一現的!哪怕節點異常或被刪除,節點上面的Pod 將會被自動重建到其他節點上,因此,這又會有什么關系呢?好吧,讓我們來繼續往下看看。

假設應用程序有三個副本。負載在它們之間均勻分布,而 Pod 則分布在節點之間。在這種情況下,即使其中一個副本出現故障,應用程序也將繼續運行。然而,兩個副本的故障則會導致服務整體降級:一個單獨的 Pod 根本無法單獨處理整個負載。客戶端將開始收到 5XX 錯誤。(當然,您可以在 nginx 容器中設置速率限制;在這種情況下,錯誤將是429 Too Many Requests。不過,服務仍然會降級)。

這就是 PodDisruptionBudget 可以提供幫助的地方。我們來看看它的配置清單:

  1. apiVersion: policy/v1beta1 
  2. kind: PodDisruptionBudget 
  3. metadata: 
  4. name: app-pdb 
  5. spec: 
  6. maxUnavailable: 1 
  7. selector: 
  8.   matchLabels: 
  9.     app: app 

上述的配置清單非常簡單;你可能熟悉它的大部分配置,maxUnavailable是其中最有趣的。此字段描述可同時不可用的最大 Pod 數。這可以是數字也可以是百分比。

假設為應用程序配置了 PDB。如果出于某種原因,兩個或多個節點開始驅逐應用程序 Pod,會發生什么?上述 PDB 一次只允許驅逐一個 Pod。因此,第二個節點會等到副本數量恢復到驅逐前的水平,然后才會驅逐第二個副本。

作為替代方案,您還可以設置minAvailable參數。例如:

  1. apiVersion: policy/v1beta1 
  2. kind: PodDisruptionBudget 
  3. metadata: 
  4. name: app-pdb 
  5. spec: 
  6. minAvailable: 80% 
  7. selector: 
  8.   matchLabels: 
  9.     app: app 

此參數可確保集群中至少有 80% 的副本始終可用。因此,如有必要,只能驅逐 20% 的副本。minAvailable可以是絕對數或百分比。

但有一個問題:集群中必須有足夠的節點滿足PodAntiAffinity條件。否則,您可能會遇到副本被逐出的情況,但由于缺少合適的節點,調度程序無法重新部署它。因此,排空一個節點將需要很長時間才能完成,并且會為您提供兩個應用程序副本而不是三個。當然,你可以使用用命令kubectl describe來查看一個一致在等待中的Pod,看看發生了什么事情,并解決問題。但是,最好還是盡量去避免這種情況發生。

總而言之,請始終為系統的關鍵組件配置 PDB。

十一、HorizontalPodAutoscaler

讓我們考慮另一種情況:如果應用程序的意外負載明顯高于平時,會發生什么情況?是的,您可以手動擴展集群,但這不是我們推薦使用的方法。

這就是HorizontalPodAutoscaler(HPA,https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/)的用武之地。借助 HPA,您可以選擇一個指標并將其用作觸發器,根據指標的值自動向上/向下擴展集群。想象一下,在一個安靜的夜晚,您的集群突然因流量大幅上升而爆炸,例如,Reddit 用戶發現了您的服務,CPU 負載(或其他一些 Pod 指標)增加,達到閾值,然后 HPA 開始發揮作用。它擴展了集群,從而在大量 Pod 之間均勻分配負載。

也正是多虧了這一點,所有傳入的請求都被成功處理。同樣重要的是,在負載恢復到平均水平后,HPA 會縮小集群以降低基礎設施成本。這聽起來很不錯,不是嗎?

讓我們看看 HPA 是如何計算要添加的副本數量的。這是官方文檔中提供的公式:

  1. desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )] 

現在假設:

  • 當前副本數為3;
  • 當前度量值為 100;
  • 度量閾值為 60。

在這種情況下,結果則為3 * ( 100 / 60 ),即“大約”5 個副本(HPA 會將結果向上舍入)。因此,應用程序將獲得額外的另外兩個副本。當然,HPA操作還會繼續:如果負載減少,HPA 將繼續計算所需的副本數(使用上面的公式)來縮小集群。

另外,還有一個是我們最關心的部分。你應該使用什么指標?首先想到的是主要指標,例如 CPU 或內存利用率。如果您的 CPU 和內存消耗與負載成正比,這將起作用。但是如果 Pod 處理不同的請求呢?有些請求需要較大的 CPU 周期,有些可能會消耗大量內存,還有一些只需要最少的資源。

例如,讓我們看一看RabbitMQ隊列和處理它的實例。假設隊列中有十條消息。監控顯示消息正在穩定且定期地退出隊列(按照RabbitMQ的術語)。也就是說,我們覺得隊列中平均有10條消息是可以的。但是負載突然增加,隊列增加到100條消息。然而,worker的CPU和內存消耗保持不變:他們穩定地處理隊列,在隊列中留下大約80-90條消息。

但是如果我們使用一個自定義指標來描述隊列中的消息數量呢?讓我們按如下方式配置我們的自定義指標:

  • 當前副本數為3;
  • 當前度量值為 80;
  • 度量閾值為 15。

因此,3 * ( 80 / 15 ) = 16。在這種情況下,HPA 可以將 worker 的數量增加到 16,并且它們會快速處理隊列中的所有消息(此時 HPA 將再次減少它們的數量)。但是,必須準備好所有必需的基礎架構以容納此數量的 Pod。也就是說,它們必須適合現有節點,或者在使用Cluster Autoscaler(https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler)的情況下,必須由基礎設施供應商(云提供商)提供新節點。換句話說,我們又回到規劃集群資源了。

現在讓我們來看看一些清單:

  1. apiVersion: autoscaling/v1 
  2. kind: HorizontalPodAutoscaler 
  3. metadata: 
  4. name: php-apache 
  5. spec: 
  6. scaleTargetRef: 
  7.   apiVersion: apps/v1 
  8.   kind: Deployment 
  9.   name: php-apache 
  10. minReplicas: 1 
  11. maxReplicas: 10 
  12. targetCPUUtilizationPercentage: 50 

這個很簡單。一旦 CPU 負載達到 50%,HPA 就會開始將副本數量擴展到最多 10 個。

下面是一個比較有趣的案例:

  1. apiVersion: autoscaling/v1 
  2. kind: HorizontalPodAutoscaler 
  3. metadata: 
  4. name: worker 
  5. spec: 
  6. scaleTargetRef: 
  7.   apiVersion: apps/v1 
  8.   kind: Deployment 
  9.   name: worker 
  10. minReplicas: 1 
  11. maxReplicas: 10 
  12. metrics: 
  13. - type: External 
  14.   external: 
  15.     metric: 
  16.       name: queue_messages 
  17.     target: 
  18.       type: AverageValue 
  19.       averageValue: 15 

請注意,在此示例中,HPA 使用自定義指標(https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/#support-for-custom-metrics)。它將根據隊列的大小(queue_messages指標)做出擴展決策。鑒于隊列中的平均消息數為 10,我們將閾值設置為 15。這樣可以更準確地管理副本數。如您所見,與基于 CPU 的指標相比,自定義指標可實現更準確的集群自動縮放。

附加的功能:

HPA 配置選項是多樣化。例如,您可以組合不同的指標。在下面的清單中,同時使用CPU 利用率和隊列大小來觸發擴展決策。

  1. apiVersion: autoscaling/v1 
  2. kind: HorizontalPodAutoscaler 
  3. metadata: 
  4. name: worker 
  5. spec: 
  6. scaleTargetRef: 
  7.   apiVersion: apps/v1 
  8.   kind: Deployment 
  9.   name: worker 
  10. minReplicas: 1 
  11. maxReplicas: 10 
  12. metrics: 
  13. - type: Resource 
  14.   resource: 
  15.     name: cpu 
  16.     target: 
  17.       type: Utilization 
  18.       averageUtilization: 50 
  19. - type: External 
  20.   external: 
  21.     metric: 
  22.       name: queue_messages 
  23.     target: 
  24.       type: AverageValue 
  25.       averageValue: 15 

這種情況下,HPA又該采用什么計算算法?好吧,它使用計算出的最高副本數,而不考慮所利用的指標如何。例如,如果基于 CPU 指標的值顯示需要添加 5 個副本,而基于隊列大小的指標值僅給出 3 個 Pod,則 HPA 將使用較大的值并添加 5 個 Pod。

隨著Kubernetes 1.18的發布,你現在有能力來定義scaleUp和scaleDown方案(https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/#support-for-configurable-scaling-behavior)。例如:

  1. behavior: 
  2. scaleDown: 
  3.   stabilizationWindowSeconds: 60 
  4.   policies: 
  5.   - type: Percent 
  6.     value: 5 
  7.     periodSeconds: 20 
  8.   - type: Pods 
  9.     value: 5 
  10.     periodSeconds: 60 
  11.   selectPolicy: Min 
  12. scaleUp: 
  13.   stabilizationWindowSeconds: 0 
  14.   policies: 
  15.   - type: Percent 
  16.     value: 100 
  17.     periodSeconds: 10 

正如您在上面的清單中看到的,它有兩個部分。第一個 ( scaleDown) 定義縮小參數,而第二個 ( scaleUp) 用于放大。每個部分都有stabilizationWindowSeconds. 這有助于防止在副本數量持續波動時出現所謂的“抖動”(或不必要的縮放)。這個參數本質上是作為副本數量改變后的超時時間。

現在讓我們談談這兩者的策略。scaleDown策略允許您指定在type: Percent特定時間段內縮減的 Pod 百分比 。如果負載具有周期性現象,您必須做的是降低百分比并增加持續時間。在這種情況下,隨著負載的減少,HPA 不會立即殺死大量 Pod(根據其公式),而是會逐漸殺死對應的Pod。此外,您可以設置type: Pods在指定時間段內允許 HPA 殺死的最大 Pod 數量 。

注意selectPolicy: Min參數。這意味著 HPA 使用影響最小 Pod 數量的策略。因此,如果百分比值(上例中的 5%)小于數字替代值(上例中的 5 個 Pod),HPA 將選擇百分比值。相反,selectPolicy: Max策略會產生相反的效果。

scaleUp部分中使用了類似的參數。請注意,在大多數情況下,集群必須(幾乎)立即擴容,因為即使是輕微的延遲也會影響用戶及其體驗。因此,在本節中StabilizationWindowsSeconds設置為0。如果負載具有循環模式,HPA可以在必要時將副本計數增加到maxReplicas(如HPA清單中定義的)。我們的策略允許HPA每10秒(periodSeconds:10)向當前運行的副本添加多達100%的副本。

最后,您可以將selectPolicy參數設置Disabled為關閉給定方向的縮放:

  1. behavior: 
  2. scaleDown: 
  3.   selectPolicy: Disabled 

大多數情況下,當 HPA 未按預期工作時,才會使用策略。策略帶來了靈活性的同時,也使配置清單更難掌握。

最近,HPA能夠跟蹤一組 Pod 中單個容器的資源使用情況(在 Kubernetes 1.20 中作為 alpha 功能引入)(https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/#container-resource-metrics)。

HPA:總結

讓我們以完整的 HPA 清單示例結束本段:

  1. apiVersion: autoscaling/v1 
  2. kind: HorizontalPodAutoscaler 
  3. metadata: 
  4. name: worker 
  5. spec: 
  6. scaleTargetRef: 
  7.   apiVersion: apps/v1 
  8.   kind: Deployment 
  9.   name: worker 
  10. minReplicas: 1 
  11. maxReplicas: 10 
  12. metrics: 
  13. - type: External 
  14.   external: 
  15.     metric: 
  16.       name: queue_messages 
  17.     target: 
  18.       type: AverageValue 
  19.       averageValue: 15 
  20. behavior: 
  21.   scaleDown: 
  22.     stabilizationWindowSeconds: 60 
  23.     policies: 
  24.     - type: Percent 
  25.       value: 5 
  26.       periodSeconds: 20 
  27.     - type: Pods 
  28.       value: 5 
  29.       periodSeconds: 60 
  30.     selectPolicy: Min 
  31.   scaleUp: 
  32.     stabilizationWindowSeconds: 0 
  33.     policies: 
  34.     - type: Percent 
  35.       value: 100 
  36.       periodSeconds: 10 

請注意,此示例僅供參考。您將需要對其進行調整以適應您自己的操作的具體情況。

Horizontal Pod Autoscaler 簡介:HPA 非常適合生產環境。但是,在為 HPA 選擇指標時,您必須謹慎并盡量多的考慮現狀。錯誤的度量標準或錯誤的閾值將導致資源浪費(來自不必要的副本)或服務降級(如果副本數量不夠)。密切監視應用程序的行為并對其進行測試,直到達到正確的平衡。

十二、VerticalPodAutoscaler

VPA(https://github.com/kubernetes/autoscaler/tree/master/vertical-Pod-autoscaler)分析容器的資源需求并設置(如果啟用了相應的模式)它們的限制和請求。

假設您部署了一個新的應用程序版本,其中包含一些新功能,結果發現,比如說,導入的庫是一個巨大的資源消耗者,或者代碼沒有得到很好的優化。換句話說,應用程序資源需求增加了。您在測試期間沒有注意到這一點(因為很難像在生產中那樣加載應用程序)。

當然,在更新開始之前,相關的請求和限制已經為應用程序設置好了。現在,應用程序達到內存限制,其Pod由于OOM而被殺死。VPA可以防止這種情況!乍一看,VPA看起來是一個很好的工具,應該是被廣泛的使用的。但在現實生活中,情況并非是如此,下面會簡單說明一下。

主要問題(尚未解決)是Pod需要重新啟動才能使資源更改生效。在未來,VPA將在不重啟Pod的情況下對其進行修改,但目前,它根本無法做到這一點。但是不用擔心。如果您有一個“編寫良好”的應用程序,并且隨時準備重新部署(例如,它有大量副本;它的PodAntiAffinity、PodDistributionBudget、HorizontalPodAutoscaler都經過仔細配置,等等),那么這并不是什么大問題。在這種情況下,您(可能)甚至不會注意到VPA活動。

遺憾的是,可能會出現其他不太令人愉快的情況,如:應用程序重新部署得不太好,由于缺少節點,副本的數量受到限制,應用程序作為StatefulSet運行,等等。在最壞的情況下,Pod的資源消耗會因負載增加而增加,HPA開始擴展集群,然后突然,VPA開始修改資源參數并重新啟動Pod。因此,高負載分布在其余的Pod中。其中一些可能會崩潰,使事情變得更糟,并導致失敗的連鎖反應。

這就是為什么深入了解各種 VPA 操作模式很重要。讓我們從最簡單的開始——“Off模式”。

Off模式:

該模式所做的只是計算Pod的資源消耗并提出建議。我們在大多數情況下都使用這種模式(我們建議使用這種模式)。但首先,讓我們看幾個例子。

一些基本清單如下:

  1. apiVersion: autoscaling.k8s.io/v1 
  2. kind: VerticalPodAutoscaler 
  3. metadata: 
  4. name: my-app-vpa 
  5. spec: 
  6. targetRef: 
  7.   apiVersion: "apps/v1" 
  8.   kind: Deployment 
  9.   name: my-app 
  10. updatePolicy:  
  11.   updateMode: "Recreate" 
  12.   containerPolicies: 
  13.     - containerName: "*" 
  14.       minAllowed: 
  15.         cpu: 100m 
  16.         memory: 250Mi 
  17.       maxAllowed: 
  18.         cpu: 1 
  19.         memory: 500Mi 
  20.       controlledResources: ["cpu""memory"
  21.       controlledValues: RequestsAndLimits 

我們不會詳細介紹此清單的參數:文章(https://povilasv.me/vertical-Pod-autoscaling-the-definitive-guide/)詳細描述了 VPA 的功能和細節。簡而言之,我們指定 VPA 目標 ( targetRef) 并選擇更新策略。

此外,我們指定了 VPA 可以使用的資源的上限和下限。主要關注updateMode部分。在“重新創建”或“自動”模式下,VPA 將重新創建 Pod ,因此需要考慮由此帶來的短暫停服風險(直到上述用于 Pod的 資源參數更新的補丁可用)。由于我們不想要它,我們使用“off”模式:

  1. apiVersion: autoscaling.k8s.io/v1 
  2. kind: VerticalPodAutoscaler 
  3. metadata: 
  4. name: my-app-vpa 
  5. spec: 
  6. targetRef: 
  7.   apiVersion: "apps/v1" 
  8.   kind: Deployment 
  9.   name: my-app 
  10. updatePolicy:  
  11.   updateMode: "Off"   # !!! 
  12. resourcePolicy: 
  13.   containerPolicies: 
  14.     - containerName: "*" 
  15.       controlledResources: ["cpu""memory"

VPA 開始收集指標。您可以使用kubectl describe vpa命令查看建議(只需讓 VPA 運行幾分鐘即可):

  1. Recommendation: 
  2.   Container Recommendations: 
  3.     Container Name: nginx 
  4.     Lower Bound: 
  5.       Cpu:     25m 
  6.       Memory: 52428800 
  7.     Target: 
  8.       Cpu:     25m 
  9.       Memory: 52428800 
  10.     Uncapped Target: 
  11.       Cpu:     25m 
  12.       Memory: 52428800 
  13.     Upper Bound: 
  14.       Cpu:     25m 
  15.       Memory: 52428800 

運行幾天(一周、一個月等)后,VPA 建議將更加準確。然后是在應用程序清單中調整限制的最佳時機。這樣,您可以避免由于缺乏資源而導致的 OOM 終止并節省基礎設施(如果初始請求/限制太高)。

現在,讓我們談談使用 VPA 的一些細節。

其他 VPA 模式:

請注意,在“Initial”模式下,VPA 在 Pod 啟動時分配資源,以后不再更改它們。因此,如果過去一周的負載相對較低,VPA 將為新創建的 Pod 設置較低的請求/限制。如果負載突然增加,可能會導致問題,因為請求/限制將遠低于此類負載所需的數量。如果您的負載均勻分布并以線性方式增長,則此模式可能會派上用場。

在“Auto”模式下,VPA 重新創建 Pod。因此,應用程序必須正確處理重新啟動。如果它不能正常關閉(即通過正確關閉現有連接等),您很可能會捕獲一些可避免的 5XX 錯誤。很少建議使用帶有 StatefulSet 的 Auto 模式:想象一下 VPA 試圖將 PostgreSQL 資源添加到生產中……

至于開發環境,您可以自由試驗以找到您可以接受的(稍后)在生產中使用的資源級別。假設您想在“Initial”模式下使用 VPA,并且我們在Redis集群中使用maxmemory參數 。您很可能需要更改它以根據您的需要進行調整。問題是 Redis 不關心 cgroups 級別的限制。

換句話說,如果您的 Pod 的內存上限為 1GB,那么maxmemory 設置的是2GB ,您將面臨很大的風險。但是你怎么能設置maxmemory成和limit一樣呢?嗯,有辦法!您可以使用 VPA 推薦的值:

  1. apiVersion: apps/v1 
  2. kind: Deployment 
  3. metadata: 
  4. name: redis 
  5. labels: 
  6.   app: redis 
  7. spec: 
  8. replicas: 1 
  9. selector: 
  10.   matchLabels: 
  11.     app: redis 
  12. template: 
  13.   metadata: 
  14.     labels: 
  15.       app: redis 
  16.   spec: 
  17.     containers: 
  18.     - name: redis 
  19.       image: redis:6.2.1 
  20.       ports: 
  21.       - containerPort: 6379 
  22.       resources: 
  23.           requests: 
  24.             memory: "100Mi" 
  25.             cpu: "256m" 
  26.           limits: 
  27.             memory: "100Mi" 
  28.             cpu: "256m" 
  29.       env: 
  30.         - name: MY_MEM_REQUEST 
  31.           valueFrom: 
  32.             resourceFieldRef: 
  33.               containerName: app 
  34.               resource: requests.memory 
  35.         - name: MY_MEM_LIMIT 
  36.           valueFrom: 
  37.             resourceFieldRef: 
  38.               containerName: app 
  39.               resource: limits.memory 

您可以使用環境變量來獲取內存限制(并從應用程序需求中減去 10%)并將結果值設置為maxmemory。您可能需要對sed用于處理 Redis 配置的 init 容器做一些事情,因為默認的 Redis 容器映像不支持maxmemory使用環境變量進行傳遞。盡管如此,這個解決方案還是很實用的。

最后,我想將您的注意力轉移到 VPA 一次性驅逐所有 DaemonSet Pod 的事實。我們目前正在開發修復此問題的補丁(https://github.com/kubernetes/kubernetes/pull/98307)。

最終的 VPA 建議:

“OFF”模式適用于大多數情況。您可以在開發環境中嘗試“Auto”和“Initial”模式。

只有在您已經積累了大量的經驗并對其進行了徹底測試的情況下,才能在生產中使用VPA。此外,你必須清楚地了解你在做什么以及為什么要這樣做。

與此同時,我們熱切期待 Pod 資源的熱(免重啟)更新功能。

請注意,同時使用 HPA 和 VPA 存在一些限制。例如,如果基于 CPU 或基于內存的指標用作觸發器,則 VPA 不應與 HPA 一起使用。原因是當達到閾值時,VPA 會增加資源請求/限制,而 HPA 會添加新副本。

因此,負載將急劇下降,并且該過程將反向進行,從而導致“抖動”。官方文件(https://github.com/kubernetes/autoscaler/tree/master/vertical-Pod-autoscaler#known-limitations)更清楚地說明了現有的限制。。

結論:

我們分享了一些 Kubernetes 高可用部署應用的的一些建議以及相關的案例,這些機制有助于部署高可用性應用程序。我們討論了調度器操作、更新策略、優先級、探針等方面。最后一部分我們深入討論了剩下的三個關鍵主題:PodDisruptionBudget、HorizontalPodAutoscaler 和 VerticalPodAutoscaler。

問題中提到的大量案例都是基于我們生成的真實場景,如使用,請根據自生的環境進行調整。

通過本文,我們也希望讀者能夠根據自有的環境進行驗證,能夠一起分享各自的生成經驗,能偶一起推進Kubernetes相關技術的發展與進步。再次也感謝讀者能夠花費大量的時間認真讀完本文。

參考文章: 

  • https://blog.flant.com/best-practices-for-deploying-highly-available-apps-in-kubernetes-part-1/
  • https://blog.flant.com/best-practices-for-deploying-highly-available-apps-in-kubernetes-part-2/
  • Migrating your app to Kubernetes: what to do with files?
  • ConfigMaps in Kubernetes: how they work and what you should remember
  • Best practices for deploying highly available apps in Kubernetes. Part 1
  • Comparing Ingress controllers for Kubernetes
  • How we enjoyed upgrading a bunch of Kubernetes clusters from v1.16 to v1.19
  • Best practices for deploying highly available apps in Kubernetes. Part 2
責任編輯:武曉燕 來源: 新鈦云服
相關推薦

2011-11-25 09:55:00

MPLSWeb應用加速WAN優化

2020-12-11 19:06:03

Kubernetes工具應用程序

2023-06-04 17:28:19

數字驅動開發Azure

2017-08-08 11:14:47

AzureKubernetes多容器應用程序

2021-03-17 10:05:42

KubernetesRedis數據庫

2021-07-30 10:11:14

HelmKubernetes包管理

2022-07-08 14:17:18

Kubernetes集群高可用Linux

2024-03-05 08:00:00

人工智能Kuberneste

2022-08-31 08:30:32

kubernetesMetalLB

2020-03-24 14:45:17

程序員技能開發者

2020-11-25 15:49:38

Kubernetes程序技巧

2025-04-28 01:22:00

2021-03-04 13:10:32

KubernetesRedisLinux

2023-05-25 16:20:03

Kubernetes集群

2025-03-19 09:04:39

2012-05-29 11:02:23

ibmdw

2023-08-21 15:28:36

云原生Kubernetes

2010-03-09 13:27:23

Web 2.0應用程序

2023-10-27 12:11:33

2009-08-05 10:16:54

部署ASP.NET應用
點贊
收藏

51CTO技術棧公眾號

亚洲wwwww| 国产乱人乱偷精品视频| 婷婷五月色综合香五月| 在线欧美一区二区| 中国人体摄影一区二区三区| www.国产视频| 日韩专区在线视频| 精品自在线视频| 国产中文字幕一区二区| 国产极品一区| 亚洲国产精品一区二区久久恐怖片 | 国产一区二区高清不卡 | 欧美性做爰猛烈叫床潮| 99精品一区二区三区的区别| 亚洲欧洲精品视频| 久久国产精品免费| 午夜精品理论片| 国产传媒视频在线 | 快播亚洲色图| a级片在线视频| 久久天堂精品| 欧美二区在线播放| 日本成人免费在线观看| 国产精品色呦| 欧美久久久久久蜜桃| 久久久999免费视频| 国精产品一区| 中文字幕成人av| 好吊色欧美一区二区三区视频| 中文字幕av网站| 亚洲清纯自拍| 久久在线观看视频| 精品人妻中文无码av在线| 国产伦理久久久久久妇女| 欧美精品18+| 久久九九国产视频| 超碰在线视屏| 亚洲黄色小视频| 一区二区欧美日韩| 春暖花开成人亚洲区| 99视频超级精品| 国产精品高清一区二区三区| 91片黄在线观看喷潮| 视频一区二区不卡| 97精品在线观看| 久久久久成人片免费观看蜜芽| 第一sis亚洲原创| 亚洲欧美视频在线| 国产熟女高潮一区二区三区| 视频精品二区| 欧美成人免费网站| 深夜做爰性大片蜜桃| 亚瑟国产精品| 欧美精品 国产精品| 国产九九热视频| 成人涩涩视频| 欧美亚洲丝袜传媒另类| 熟妇人妻无乱码中文字幕真矢织江| 国产黄大片在线观看| 亚洲线精品一区二区三区八戒| 国产成人免费高清视频| 国产1区在线| 日韩毛片一二三区| 午夜探花在线观看| 26uuu亚洲电影在线观看| 亚洲乱码一区二区三区在线观看| 在线天堂一区av电影| 91福利在线视频| 自拍偷拍国产亚洲| 激情五月婷婷六月| 国产99在线| 色综合咪咪久久| 九九热免费精品视频| 国产极品一区| 欧美成人伊人久久综合网| 韩国三级视频在线观看| 久久porn| 成人免费无遮挡无码黄漫视频| 粉嫩久久久久久久极品| 精品国产一区二区亚洲人成毛片 | av免费不卡| 高跟丝袜一区二区三区| 无码人妻精品一区二区三区在线| 欧美电影h版| 欧美丝袜自拍制服另类| 免费黄频在线观看| 国产suv精品一区| 亚洲欧美日韩精品久久奇米色影视 | 国产经典欧美精品| 精品人伦一区二区三区| 黄色电影免费在线看| 国产精品久久久久久久久果冻传媒| 中文字幕日韩精品久久| 蜜臀av在线| 色噜噜狠狠一区二区三区果冻| 成人免费xxxxx在线视频| 99综合久久| 亚洲护士老师的毛茸茸最新章节| 亚洲国产无码精品| 手机亚洲手机国产手机日韩| 欧美黑人国产人伦爽爽爽| 欧美啪啪小视频| 国产一区二区调教| 久久精品日产第一区二区三区| 91社区在线| 午夜私人影院久久久久| 九九热免费精品视频| 国产精品宾馆| 最新国产精品拍自在线播放| 久久久久久久伊人| 麻豆成人久久精品二区三区小说| 国产精品18毛片一区二区| 超碰国产在线| 午夜精品久久久久久久99樱桃| 欧美日韩亚洲自拍| 国产区精品视频在线观看豆花| 中文字幕日韩在线视频| 国产系列精品av| 精品一区二区三区在线观看 | 激情五月俺来也| 国产伦精品一区二区三区免费优势| 中文字幕亚洲自拍| 久久99精品波多结衣一区| 韩国视频一区二区| 青青成人在线| av资源网在线播放| 欧美精品 国产精品| 精品无码国产污污污免费网站 | 国产精品免费无遮挡| 99精品视频在线播放观看| 欧美日韩一区二区三区电影| 91精品店在线| 国产丝袜高跟一区| 国产香蕉在线视频| 国产高清在线精品| 成人免费看片视频在线观看| 国产一区高清| 一个色综合导航| 日韩精品久久久久久免费| 成人动漫中文字幕| 青青草国产免费| 亚洲国产欧美国产第一区| 自拍偷拍亚洲欧美| 黄色大全在线观看| 国产午夜精品美女毛片视频| 狠狠97人人婷婷五月| 91精品导航| 欧美日韩成人网| 成人福利小视频| 一个色在线综合| 中文字幕1区2区| 国内在线观看一区二区三区| 99re6在线| 污污视频在线| 日韩精品在线看片z| 久草视频免费在线| 国产成都精品91一区二区三| 超碰10000| 伊人www22综合色| 欧美激情精品久久久久久蜜臀| 亚洲第一天堂影院| 五月天激情综合| 一女三黑人理论片在线| 国产精品久久久久9999高清| 精品一区2区三区| 少妇淫片在线影院| 亚洲欧美中文字幕| 国产精品sm调教免费专区| 国产三级精品三级在线专区| 亚洲天堂2018av| 一区二区三区在线| 国产精品久久久久久久久婷婷| www欧美xxxx| 日韩精品免费视频| 亚洲av无码乱码国产精品fc2| 中文一区一区三区高中清不卡| 国产精品自拍视频在线| 亚洲xxx拳头交| 国产精品对白刺激久久久| 高潮在线视频| 永久免费看mv网站入口亚洲| 一区二区www| 亚洲永久精品大片| 日韩人妻一区二区三区| 七七婷婷婷婷精品国产| 日本免费黄色小视频| 91麻豆精品国产91久久久久推荐资源| 午夜免费在线观看精品视频| 精品电影在线| 制服丝袜av成人在线看| 日韩精品视频免费播放| 国产日韩欧美综合一区| 男人操女人下面视频| 99在线精品视频在线观看| 五月婷婷综合色| 91蝌蚪精品视频| 国产精品www色诱视频| a视频在线播放| 亚洲美女动态图120秒| 亚洲综合精品在线| 午夜电影网一区| 日本成人免费在线观看| yourporn久久国产精品| 久久久久久久久久一区二区| 亚洲欧洲一区| 午夜啪啪免费视频| 日韩深夜福利| 亚洲精品免费av| 欧美xxxx做受欧美护士| 欧美国产第一页| 3p在线观看| 亚洲国产欧美在线成人app| 中文字幕一区2区3区| 亚洲第一福利一区| 91久久久久久久久久久久久久| 成人av在线一区二区三区| 亚洲娇小娇小娇小| 噜噜噜在线观看免费视频日韩 | 一区二区动漫| 欧洲精品视频在线| 国产一区二区三区91| 国产一区精品在线| 无码国模国产在线观看| 国产精品视频xxx| 在线女人免费视频| 国内成人精品一区| 日本在线观看高清完整版| 日韩小视频网址| 成人av毛片| 亚洲欧美国产精品专区久久| 韩国av永久免费| 欧美xxxxxxxx| 精品国自产在线观看| 欧美美女视频在线观看| 波多野结衣毛片| 色欧美日韩亚洲| 久久久国产高清| 亚洲图片欧美综合| 免费无码毛片一区二区app| 国产精品免费丝袜| 日韩欧美视频免费观看| 国产欧美一区二区精品性色| 中文字幕丰满孑伦无码专区| caoporn国产一区二区| 男人的天堂免费| 国产精品一区二区在线观看网站 | 成人毛片视频在线观看| 被黑人猛躁10次高潮视频| 精品在线观看免费| 992kp免费看片| 国产在线视频不卡二| 国产又粗又长又爽又黄的视频| 毛片基地黄久久久久久天堂| 亚洲这里只有精品| 麻豆国产精品777777在线| 永久免费的av网站| 黄色小说综合网站| 在线观看网站黄| 国产精品91一区二区| 蜜桃视频无码区在线观看| 成人国产精品视频| 成人性生活免费看| 久久色视频免费观看| 成人精品999| 欧美高清在线一区| 亚洲色偷偷综合亚洲av伊人| 亚洲天堂精品在线观看| 麻豆一区产品精品蜜桃的特点| 亚洲一区二区三区国产| 日韩网红少妇无码视频香港| 狠狠躁夜夜躁人人爽天天天天97| 日韩综合在线观看| 欧美日韩中文精品| 国产成人久久精品77777综合 | 一区二区国产视频| 日韩欧美视频在线免费观看| 精品久久久久久久大神国产| 黄色av一区二区| 欧美精品v日韩精品v韩国精品v| 国产叼嘿视频在线观看| 日韩av在线电影网| 国产在线一二三区| 久久亚洲精品毛片| 国产夫妻在线| 国产情人节一区| av成人资源| 色婷婷精品国产一区二区三区| 久久精品国内一区二区三区水蜜桃| 成人在线国产视频| 日韩精彩视频在线观看| 极品人妻一区二区| 久久久久久夜精品精品免费| 成人免费黄色小视频| 婷婷开心激情综合| 一级黄色大片免费观看| 精品国产a毛片| 婷婷在线视频观看| 91精品国产91久久久久久不卡| 深夜视频一区二区| 国产精品久久久对白| 欧美午夜精彩| 国产九色porny| 久久国产三级精品| 中文字幕丰满孑伦无码专区| 日韩码欧中文字| 亚洲一区 视频| 欧美日韩一区精品| 先锋av资源站| 不卡av在线播放| 国产一区二区三区影视| 国产福利久久精品| 97偷自拍亚洲综合二区| 夫妻免费无码v看片| 国产精品一品二品| 欧美日韩生活片| 欧美性猛交xxxx黑人| 成人午夜视频一区二区播放| 日韩中文字幕免费看| xxxxxx欧美| 国内精品国语自产拍在线观看| 99久久影视| 久久国产这里只有精品| 久久久久久久久岛国免费| 国产精品30p| 日韩一级成人av| 麻豆av在线导航| 国产精品入口尤物| 精品国产不卡| 欧美色图另类小说| 北岛玲一区二区三区四区| 加勒比av在线播放| 91精品国产综合久久香蕉的特点 | 久久精品在这里| 尤物视频在线观看国产| 欧美成人a∨高清免费观看| 蜜芽在线免费观看| 国产女同一区二区| 成人同人动漫免费观看 | 欧美激情第一页在线观看| 亚洲二区精品| 色悠悠在线视频| 亚洲已满18点击进入久久| 精品人妻少妇AV无码专区| 久久成人精品视频| 精品国产一级| 无码人妻精品一区二区蜜桃百度| 激情都市一区二区| 欧美精品久久久久久久久46p| 欧美人牲a欧美精品| 米奇精品一区二区三区| 国产日韩欧美另类| 羞羞答答成人影院www| 手机精品视频在线| 亚洲男同性视频| 性欧美8khd高清极品| 欧美激情在线狂野欧美精品| 中文字幕一区二区三区四区久久| av日韩在线看| 成人午夜私人影院| 欧美三级一区二区三区| 精品亚洲一区二区三区在线观看 | 欧美日韩99| 中国特级黄色大片| 精品欧美一区二区三区| 邻居大乳一区二区三区| 国产精品成人免费电影| 日韩电影免费网站| 午夜影院免费版| 午夜精品影院在线观看| 免费在线超碰| 国产深夜精品福利| 欧美成人一区二免费视频软件| 成人在线观看一区二区| 欧美日韩国产一中文字不卡 | 久久久国产成人精品| 亚洲精品国产九九九| 欧美日韩成人免费视频| 久久久久久久免费视频了| 正在播放亚洲精品| 欧美成人精品一区二区三区| 狠狠久久伊人| 成人亚洲视频在线观看| 成人免费一区二区三区在线观看| 国产黄色av片| 欧美亚洲国产视频| 色天天综合网| 成年人小视频在线观看| 欧美午夜在线一二页| mm1313亚洲国产精品美女| 精品毛片久久久久久| 免费观看在线综合色| 国产亚洲小视频| 亚洲一区二区福利| 亚洲啊v在线免费视频| 亚欧在线免费观看| 亚洲一区二区在线视频| 成人综合影院| 国内一区在线| 激情五月婷婷综合网| 日本三级一区二区|