精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

无码aⅴ精品一区二区三区浪潮| 91综合久久| 99综合视频| 欧美色图天堂网| 国模视频一区二区三区| 狠狠躁狠狠躁视频专区| 女人18毛片一区二区三区| 日韩一级毛片| 色噜噜狠狠成人中文综合| 99热在线国产| 成人在线观看免费完整| 欧美成人ⅴideosxxxxx| 成人午夜短视频| 欧美成年人视频| 一区二区三区 日韩| 黄色网页网址在线免费| 国产伦一区二区三区| 亚洲国产美国国产综合一区二区| 成人欧美一区二区三区在线| 自拍偷拍你懂的| 日韩中文视频| 久久精品一区二区| 性欧美xxxx视频在线观看| 奇米777在线视频| 午夜免费播放观看在线视频| 爽好多水快深点欧美视频| 亚洲国模精品私拍| 阿v天堂2018| 亚洲国产精品suv| 午夜欧美精品| 日韩精品一区二区三区在线| 丰满女人性猛交| 国产理论视频在线观看| 久久中文字幕二区| 亚洲国产精品一区二区三区| 九九精品久久久| 日本美女在线中文版| 99麻豆久久久国产精品免费| 57pao成人永久免费视频| 伊人网综合视频| 亚洲女同志freevdieo| 99国产精品国产精品毛片| 992tv成人免费影院| a级在线观看视频| 欧美黑人疯狂性受xxxxx野外| 又紧又大又爽精品一区二区| 国产高清不卡av| 日本视频免费在线| 妖精一区二区三区精品视频 | 亚洲自拍av在线| 成年人二级毛片| 国产一区二区三区探花 | 亚洲自拍偷拍精品| 国产高清中文字幕在线| 99久久久精品免费观看国产蜜| 91在线高清免费观看| 丰满少妇高潮久久三区| 99精品中文字幕在线不卡| 精品欧美一区二区三区| 日本午夜精品一区二区| 国产孕妇孕交大片孕| 日韩黄色一级片| 久久亚洲欧美日韩精品专区| 动漫av在线免费观看| 一个人看的www视频在线免费观看| 一区二区三区四区在线播放| 日本老太婆做爰视频| 天天插天天干天天操| 久久久综合网| 青青草原成人在线视频| 免费高清在线观看电视| 91久久国产| 日韩av中文字幕在线播放| 午夜国产一区二区三区| 日本成人片在线| 一区二区三区免费在线观看| 久久综合九色综合网站| 一区二区三区日| 国产亚洲欧洲| 伦伦影院午夜日韩欧美限制| 顶臀精品视频www| 影视先锋久久| 一区三区二区视频| 在线精品视频播放| 日韩电影不卡一区| 欧美一级二级在线观看| 日韩免费高清在线| 国产www视频在线观看| 国产精品免费av| 精品国产一区二区三区四区精华 | 97se在线视频| 欧美成人精品激情在线视频| 激情综合在线| www.久久色.com| 国产性生活毛片| 伊人春色之综合网| x99av成人免费| 日本少妇在线观看| 97视频精品| 欧美激情奇米色| 中文字幕人妻一区二| 影音国产精品| 国产精品精品一区二区三区午夜版| 久久久久成人精品无码| 91精品国产调教在线观看| 亚洲欧美国产精品专区久久| 手机免费看av片| 美女亚洲一区| 精品一区二区三区四区| 一边摸一边做爽的视频17国产 | 日韩一区二区在线播放| 国产精品成人无码专区| 日韩国产一区二区三区| 久久久久国产精品免费| 欧美日韩色视频| 亚洲经典自拍| 午夜美女久久久久爽久久| 中文字幕免费高清网站| 久久精品伊人| 日本老师69xxx| 日本一区二区三区精品| 亚洲人成在线影院| 国产精品一区二区性色av | 91手机视频在线观看| 秋霞av在线| 91在线视频播放地址| 一区二区三区四区欧美日韩| www在线观看免费视频| 91theporn国产在线观看| 国产一区二区在线电影| 91精品久久久久| 国产精品国产精品国产专区| 91在线丨porny丨国产| 久久久久亚洲av无码专区喷水| av大片在线观看| 国产精品美女久久久久久| 日本福利视频一区| 国产免费拔擦拔擦8x高清在线人 | eeuss鲁片一区二区三区| 影音先锋欧美精品| 丁香六月婷婷综合| 成人国产精品免费网站| 国产三区精品| 五月激情婷婷网| 久久久.com| 乱人伦xxxx国语对白| 成人福利视频| 欧美日韩成人综合| 杨幂一区二区国产精品| 国产在线观看91一区二区三区| 久久久亚洲网站| 亚洲a视频在线| 亚洲免费高清视频在线| 男人天堂手机在线视频| 免费一级欧美片在线观看网站| 精品第一国产综合精品aⅴ| 国产吞精囗交久久久| 久久福利影院| 国产精品久久久久久久久久新婚| 97久久人国产精品婷婷| 国产精品久久久久影院| 日本人视频jizz页码69| 日本道不卡免费一区| 久久国产精品影片| 国产精品欧美综合亚洲| 综合久久国产九一剧情麻豆| 无码专区aaaaaa免费视频| 99精品中文字幕在线不卡| 欧美黑人性生活视频| 亚洲伦理在线观看| 国产婷婷一区二区| 男女激烈动态图| 视频二区欧美毛片免费观看| 亚洲欧美成人网| 精品久久久久久久久久久国产字幕 | 强开小嫩苞一区二区三区网站 | 免费日韩精品中文字幕视频在线| 国产欧美在线观看| 日本激情在线观看| 日韩一区二区免费高清| 久久网一区二区| 播五月开心婷婷综合| av网站在线观看不卡| 国产精品视频一区二区三区| 亚洲视频999| 久久成人在线观看| 奇米一区二区三区av| 国产乱子伦精品| 成人高清网站| 欧美日韩精品中文字幕| 亚洲一区二区自偷自拍| 亚洲精品国产日韩| 欧美另类高清视频在线| 午夜伦理在线视频| 欧美日韩三级视频| 2018天天弄| 91麻豆swag| 亚洲精品无码国产| 久久99蜜桃| 国产一区二区丝袜| 18video性欧美19sex高清| 日韩一卡二卡三卡四卡| 中文字幕在线字幕中文| 国产精品免费久久| 国产精品久久久久久亚洲色 | 黄色片一区二区三区| 色综合欧美在线| 中国xxxx性xxxx产国| 日韩高清国产一区在线| 国产精品第157页| 亚洲精品国产九九九| 久久久精品在线观看| 国产又粗又猛又黄又爽| 亚洲国产毛片aaaaa无费看| 永久免费观看片现看| 成人精品视频一区| www.com操| 日韩精品免费| 精品国产一区二区三区日日嗨| 亚洲伦理久久| 久久精品2019中文字幕| 日韩资源在线| 精品日韩av一区二区| 久久久久久久9999| 国产欧美日本一区视频| 日本 片 成人 在线| 国产情侣一区| 国产在线视频在线| 国际精品欧美精品| 久久99国产精品| 一区二区三区短视频| 精品中文字幕乱| 丰满少妇被猛烈进入| 欧美色老头old∨ideo| 国产无遮挡又黄又爽又色| 国产一区二区三区精品欧美日韩一区二区三区 | 欧美一区二区高清在线观看| 91麻豆精品一二三区在线| 欧洲亚洲免费视频| 成人av影院在线观看| 亚洲视频国产视频| 亚洲人妻一区二区三区| 日韩写真欧美这视频| 中文字幕黄色av| 337p粉嫩大胆噜噜噜噜噜91av| 三日本三级少妇三级99| 久久久精品五月天| 国产黄色一级网站| 欧美xxxx在线| 久久久久久久久国产| 午夜视频在线| www.色综合| 北条麻妃在线| 亚洲视频免费一区| 国产中文字幕在线播放| 欧美特级限制片免费在线观看| 欧美性生给视频| 国产日本欧美一区二区| 久久国产精品无码一级毛片| 成人午夜视频网站| 成人一区二区三区仙踪林| 亚洲五月婷婷| 日韩欧美精品一区二区| 成人日韩精品| 国产精品91久久久久久| av电影在线网| 亚洲色图激情小说| 男人天堂综合| 亚洲欧美制服综合另类| 国产高清自拍视频在线观看| 日本久久一区二区三区| 久久免费激情视频| 久久久久久久久99精品| 毛片网站免费观看| 久久先锋影音av鲁色资源网| 久久久久狠狠高潮亚洲精品| 久久久水蜜桃av免费网站| 男人日女人下面视频| 一本一本久久| 黄色片视频在线免费观看| 国产欧美欧美| 国产日韩成人内射视频| 天堂成人国产精品一区| 91亚洲精品久久久蜜桃借种| 韩国精品一区二区| 精品视频在线观看一区二区| 欧美日韩一区二区三区视频播放| 成人国产精品一区二区| 白嫩亚洲一区二区三区| 99re6在线| 亚洲另类春色校园小说| 亚洲国产一区二区在线| 国产精品麻豆| 精品视频第一区| 亚洲三级性片| 性欧美大战久久久久久久免费观看 | 欧美激情视频播放| 美足av综合网| 俺去亚洲欧洲欧美日韩| 蜜桃视频网站在线| 欧美成人精品激情在线观看| 一个人看的www视频在线免费观看| 国产精品久久久| 久久久久久亚洲精品美女| 久久久久国产精品视频| 欧美丰满日韩| 欧美午夜性视频| 美女精品网站| 国产高清视频网站| 成人手机在线视频| 日本一卡二卡在线播放| 国产风韵犹存在线视精品| 日本黄色的视频| 成人国产在线观看| 精品人妻一区二区三区香蕉| 亚洲欧美日韩中文字幕一区二区三区 | 国产成人精品一区二三区| 在线一区二区三区四区五区| 国产毛片毛片毛片毛片毛片| 在线精品视频一区二区| 国产a级免费视频| 日韩欧美成人一区二区| 男女网站在线观看| 欧美激情第一页xxx| 欧美电影在线观看网站| 国产精品偷伦免费视频观看的| xxxx日韩| 成人手机在线播放| 日韩激情在线观看| 黄色av网址在线观看| 99视频精品免费视频| 午夜精品一区二区三级视频| 18成人在线观看| 免费在线观看国产精品| 欧美日韩中文字幕精品| 无码国产色欲xxxx视频| 久久中文久久字幕| 久久精品 人人爱| 欧美激情第一页在线观看| 91成人观看| 三级一区二区三区| 国产一区二区久久| 亚洲精品国产熟女久久久| 精品久久久久久亚洲精品| 国产超碰人人模人人爽人人添| 亚洲美女av黄| 成人片免费看| 国产三区精品| 欧美日韩1区2区3区| 性色av浪潮av| 自拍偷拍国产精品| 亚洲综合精品视频| 欧美一区二区免费| 性生交生活影碟片| 久久久国产影院| 二区三区精品| 中文字幕av导航| 精品一二线国产| 午夜成人亚洲理伦片在线观看| 欧美伊人久久久久久午夜久久久久| 国产在线三区| 国产999精品| 国产精品一区二区av交换| 久久手机在线视频| www.亚洲国产| 四虎成人永久免费视频| 亚洲视频视频在线| 伊人色综合一区二区三区影院视频| 99视频在线播放| 国产日韩亚洲| 美女100%无挡| 亚洲视频在线观看三级| 国产永久免费视频| 北条麻妃一区二区三区中文字幕| 香蕉久久久久久| 国产在线一区二区三区四区| 激情欧美亚洲| 添女人荫蒂视频| 色综合久久精品| 色开心亚洲综合| 3d动漫啪啪精品一区二区免费| 欧美日韩亚洲一区三区| 人妻激情偷乱频一区二区三区| 午夜精品久久久久影视| 亚洲一区 中文字幕| 久久精品99久久久久久久久| 欧美成人高清视频在线观看| 香港三级日本三级a视频| 成人av在线播放网址| 无码人妻av一区二区三区波多野 | 成人福利网站在线观看| 天天久久综合| 美女伦理水蜜桃4| 在线视频你懂得一区| 免费观看久久久久| 97神马电影| 久久看片网站| 狂野欧美性猛交| 日韩精品在线观| 色综合一区二区日本韩国亚洲|