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で実行されます。
クラスター情報:
私は同じ問題を抱えており、この種の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
への変更中に次のことが起こります。
"localEndpoints": 0
で503を返します--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クラスタでテストされています。
コメントで共有したスクリーンショットを見ると、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