1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Kubernetesでhttpエラー503を回避するための設定を入れる

Last updated at Posted at 2022-05-06

前提として、httpエラー503というのは、ロードバランサーからみてバックエンドの応答がない、どこかで処理が詰まっているのかリソースが足らないのかという話という認識です。
これは要は、クラスタ更新・イメージ更新・ノードのドレイン・部分障害時に部分的にでもアクセスが可能なように設定を入れておくための備忘録です。
用いることがある環境はAKSです。書いてる時点ではkubernetes本体バージョンは1.21です。ご自身で動作を確かめてみてください。

---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: test-st
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: test-st
  minReplicas: 2
  maxReplicas: 5
  metrics:
  - type: Resource
    resource:
      name: memory
      targetAverageUtilization: 90
  - type: Resource
    resource:
      name: cpu
      targetAverageUtilization: 85

クラスタ本体ノードプール側のスケーリングも気にする↓
https://docs.microsoft.com/ja-jp/azure/aks/cluster-autoscaler#create-an-aks-cluster-and-enable-the-cluster-autoscaler
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#max_count
例えば特定の時間だけバーストして時間がはっきりわかってるような場合はそういう機能があるわけではなさそうなのでノードプール追加してAutomationかDevOpsかなにかでスケールノード数の制御をする時限設定を仕込んでおくといいのかもとは思ったけど試してはないです。

  • PodDisruptionBudget
    https://kubernetes.io/docs/tasks/run-application/configure-pdb/
    同じ種類のPodの最低必要稼働数を定義し更新時のサービス影響を予防する。(ただしテスト環境でノードが1台の場合にminAvailable: 1を指定するとノードがドレインできなくなったりはする。要は、最低限必要なPod数を稼働させ続けるための動きをするがノードの数が少ないとPodが刺さったままノードがドレインできなくなるので注意が必要。)
pod-disruption-budget.yaml
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: test-ingress-error
  namespace: default
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: test-ingress-error
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-ingress-error
spec:
  selector:
    matchLabels:
      app: test-ingress-error
  replicas: 1
  template:
    metadata:
      labels:
        app: test-ingress-error
        nginx: allowed
    spec:
      terminationGracePeriodSeconds: 30
      containers:
      - name: test-ingress-error
#~略~
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh","-c","echo prestop.; date; sleep 20"]

terminationGracePeriodSeconds = sleep秒数 + コンテナ停止にかかる秒数
に定義する。特別な終了処理を指定できる場合はsleepじゃなくてそのコマンドを指定するとより良いが、sleepだけでも503エラーが結構減ってることが計測できてたのでやらないよりマシではないかと思われる。
terminationGracePeriodSecondsを増やしすぎるとノードのドレインにその分時間がかかりクラスタアップデート時のノードプール更新時間が増える。

# 起動にMax202秒かかる場合
startupProbe:
  httpGet:
    path: /health
    port: 21099
  #initialDelaySeconds: 120 #不要の認識
  timeoutSeconds: 2 #Probeがタイムアウトになるまでの秒数
  failureThreshold: 20 #Probeが失敗した場合、KubernetesはfailureThresholdに設定した回数までProbeを試行
  successThreshold: 1 #1のみ選択可能
  periodSeconds: 12 #Probeが実行される頻度(秒数)
  #起動完了までfailureThreshold * periodSeconds=20x12=240秒猶予がある認識
    spec:
      affinity:
        podAntiAffinity:
          #requiredDuringSchedulingIgnoredDuringExecution:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
            - labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - test-stat
              topologyKey: "kubernetes.io/hostname"
      terminationGracePeriodSeconds: 30
      containers:
      - name: test-stat

※requiredDuringSchedulingIgnoredDuringExecutionだと必須なので違反するPodはスケジュールされないが、preferredDuringSchedulingIgnoredDuringExecutionは必須でなく推奨になるためweightに従って計算されて違反しても配置はされるのでちょっと安全。(ingress-nginxのhelmチャートのvalues.yamlのコメントに書かれてる初期値がそうなっている)
※AntiAffinityはノード数百台だと負荷に問題出るらしいのとtopologySpreadConstraints(1.19から)はzoneの分散も可能らしいが確かめてはいない。
※上記はPod作成時のみ効果があるため、DeschedulerでPodのスケジューリングに違反する偏ってるPodを落とすという機能を追加する必要がある。
https://github.com/kubernetes-sigs/descheduler
helmチャートをpullしてきてchartsに入れてvalues.yamlで上書きする場合こんなかんじ↓

descheduler:
  deschedulerPolicy:
    strategies:
      RemoveDuplicates:
        enabled: true
      RemovePodsViolatingNodeTaints:
        enabled: false
      RemovePodsViolatingNodeAffinity:
        enabled: false
      RemovePodsViolatingInterPodAntiAffinity:
        enabled: true
      LowNodeUtilization:
        enabled: false
      RemovePodsViolatingTopologySpreadConstraint:
        enabled: true
      RemovePodsHavingTooManyRestarts:
        enabled: true

ポリシーの意味とかは以下のあたりに。
https://github.com/kubernetes-sigs/descheduler/blob/master/docs/user-guide.md
https://github.com/kubernetes-sigs/descheduler/blob/master/examples/policy.yaml
テストするときは設定入れるまえに偏った状態をノードドレインとかで再現しておいてから。

余談で、503じゃなくて403なんですが、ingressコントローラのPodのServiceで指定するloadBalancerIPを固定にしていて、externalTrafficPolicy: "Local"の場合に再送時にSNATでEgressのIPから届く関係で、もしIP制限している場合はEgressのIPをWhitelistとかに追加しないとアップデート時等にhttpエラー403で再送失敗します。

以上です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?