web-dev-qa-db-ja.com

デプロイ中にkubernetes接続が拒否されました

Kubernetesを使用してダウンタイムなしのデプロイを実現しようとしていますが、テスト中にサービスの負荷分散がうまくいきません。

私のkubernetesマニフェストは次のとおりです。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  template:
    metadata:
      labels:
        app: myapp
        version: "0.2"
    spec:
      containers:
      - name: myapp-container
        image: gcr.io/google-samples/hello-app:1.0
        imagePullPolicy: Always
        ports:
          - containerPort: 8080
            protocol: TCP
        readinessProbe:
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          successThreshold: 1

---

apiVersion: v1
kind: Service
metadata:
  name: myapp-lb
  labels:
    app: myapp
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: myapp

外部IPを使用してサービスをループする場合は、次のようにします。

$ kubectl get services
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      10.35.240.1    <none>           443/TCP        1h
myapp-lb     LoadBalancer   10.35.252.91   35.205.100.174   80:30549/TCP   22m

bashスクリプトを使用する:

while True
    do
        curl 35.205.100.174 
        sleep 0.2s
    done

connection refused展開中:

curl:(7)35.205.100.174ポート80への接続に失敗:接続が拒否されました

アプリケーションはデフォルトです helloapp Google Cloud Platformによって提供され、8080で実行されます。

クラスター情報:

  • Kubernetesバージョン:1.8.8
  • Googleクラウドプラットフォーム
  • マシンタイプ:g1-small
3
thoas

私は同じ問題を抱えており、この種のLoadBalancingのGKEネットワーク設定をもう少し掘り下げてみました。

私の疑いは、コンテナーを実行するノードのiptablesルールが早期に更新されていることです。あなたの例ではタイムアウトを少し増やして、リクエストがタイムアウトを取得している段階を見つけやすくしています。

展開に関する私の変更:

spec:
...
  replicas: 1         # easier to track the state of the system
  minReadySeconds: 30 # give the load-balancer time to pick up the new node
...
  template:
    spec:
      containers:
        command: ["sh", "-c", "./hello-app"] # ignore SIGTERM and keep serving requests for 30s

古いポッドがRunningからTerminatingに切り替わるまで、すべてがうまく機能します。終端ポッドでkubectl port-forwardを使用してテストしましたが、タイムアウトなしでリクエストが処理されました。

RunningからTerminatingへの変更中に次のことが起こります。

  • ポッドIPがサービスから削除されました
  • ノードのヘルスチェックは"localEndpoints": 0で503を返します
  • iptablesルールはそのノードに変更され、このサービスのトラフィックはドロップされます(--comment "default/myapp-lb: has no local endpoints" -j KUBE-MARK-DROP

ロードバランサーのデフォルト設定は2秒ごとにチェックし、ノードを削除するには5回失敗する必要があります。これは、少なくとも10秒間、パケットがドロップされることを意味します。間隔を1に変更した後、1回の失敗後にのみ、ドロップされたパッケージの量が減少しました。

クライアントのソースIPに関心がない場合は、次の行を削除できます。

externalTrafficPolicy: Local

サービス定義とデプロイメントでは、接続タイムアウトはありません。

4ノードとバージョンv1.9.7-gke.1のGKEクラスタでテストされています。

1

コメントで共有したスクリーンショットを見ると、k8sクラスターがHTTP GET /リクエストの受け入れと応答に失敗しているのではなく、Siegeの問題とその仕組みについて説明しています。私はこれに数回遭遇しました。

参照として、このgithubの問題を参照してください: https://github.com/JoeDog/siege/issues/127

問題は、デフォルトでsiegeが各接続を閉じ、ポートをTIME_WAIT状態にしておくため、しばらくの間再利用できないことです。サーバーで使用可能なポートが不足しています。

基本的に、使用可能なすべての一時ポートを使用したとき。利用可能なポート範囲は次のコマンドで確認できます。

sysctl net.ipv4.ip_local_port_range

そして、次のようにしてTIME_WAITからCLOSEに移動するのにかかる時間:

sysctl net.ipv4.tcp_fin_timeout

私が現時点で使用しているLinuxデスクトップでは、これらは値です。

sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768    60999
sysctl net.ipv4.tcp_fin_timeout
net.ipv4.tcp_fin_timeout = 60

これは、60秒未満で28231ソケット(32768〜60999の範囲で利用可能)を超えるソケットを使用できないことを意味します。 60秒後、a TCP接続が終了した時点からシステムが待機するその時間に達したものは、ソケットを実際に解放して新しい接続に使用できるようにします。

tcp_fin_timeout

ソケットが常に閉じられる前に最終FINを受信するのにかかる時間(秒単位)。これは厳密にTCP仕様の違反ですが、サービス拒否攻撃を防ぐために必要です。 http://www.tldp.org/LDP/Linux-Filesystem- Hierarchy/html/proc.html

これは、包囲が接続の形成をまったく停止するpoingに到達するだけでなく、断続的なエラーを再検出する理由です。

デプロイメントのストレステストをより厳しくすることに関心があり、製品で使用されないテストインスタンスからテストを起動することを検討している場合は、その値を一時的に低くすることができます。

sysctl net.ipv4.tcp_fin_timeout=30

また、一時的なprot範囲を最大化します。

Sudo sysctl -w net.ipv4.ip_local_port_range="1024 65535"

これにより、セッションが終了するまでこれらの値が変更され、サービスを再起動するとデフォルトに戻ります。

変更を永続的にする場合は、/ proc /の対応する値を上書きできます。

echo "your new port range" > /proc/sys/net/ipv4/ip_local_port_range
echo "your new timeout" > /proc/sys/net/ipv4/tcp_fin_timeout

実際にはこれらすべてがより複雑になりますが、これは少なくともテストをもう少し長く保持するには十分です。

また、一部のディストリビューションでソケットの統計と状態を確認したい場合、従来のnetstatはもう存在しません。その場合、次のように ss を使用して、TIME-WAITのソケットを確認できます。

 ss  state time-wait
0
Jordi Miralles