Istio 1.10 で StatefulSets がより簡単に

Istio 1.10 を使用して StatefulSets を簡単にデプロイする方法を学びましょう。

2021年5月19日 | 執筆者: Lin Sun - Solo.io, Christian Posta - Solo.io, John Howard - Google, Zhonghu Xu - Huawei

Kubernetes の StatefulSets は、ステートフルアプリケーションの管理によく使用されます。 StatefulSets は、一連の Pod のデプロイとスケーリングを管理するだけでなく、それらの Pod の順序と一意性についても保証を提供します。 StatefulSets で使用される一般的なアプリケーションには、ZooKeeper、Cassandra、Elasticsearch、Redis、NiFi などがあります。

Istio コミュニティは、自動 mTLS から、DestinationRuleServiceEntry リソースを作成する必要性の排除、そして最新の Istio 1.10 での Pod ネットワーキングの変更 まで、StatefulSets のゼロコンフィギュレーションサポートに向けて徐々に進歩を遂げてきました。

サービスメッシュで StatefulSets を使用することの独自性は何でしょうか? StatefulSets の Pod は同じ仕様から作成されますが、交換可能ではありません。各 Pod は、再スケジューリングを通して維持される永続的な識別子を持っています。 StatefulSets で実行される種類のアプリは、多くの場合、Pod 間で通信する必要があり、ハードコードされた IP アドレスの世界から来ているため、0.0.0.0 ではなく、Pod IP のみでリッスンする場合があります。

たとえば、ZooKeeper はデフォルトで、クォーラム通信のためにすべての IP でリッスンしないように構成されています。

quorumListenOnAllIPs=false

過去数回のリリースで、Istio コミュニティは、StatefulSets で実行されているアプリケーションのサポートに関する 多くの問題を報告 してきました。

Istio 1.10 より前の StatefulSets の動作

Kubernetes 1.19 を実行している GKE クラスタでは、Istio 1.9.5 がインストールされています。 default 名前空間で自動サイドカーインジェクションを有効にし、インタラクティブなデバッグのために Istio の sleep Pod とともに、Bitnami が提供する Helm チャート を使用して ZooKeeper をインストールしました。

$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm install my-release bitnami/zookeeper --set replicaCount=3
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/sleep/sleep.yaml

数分後、すべての Pod がサイドカープロキシと共に正常に起動します。

$ kubectl get pods,svc
NAME                             READY   STATUS    RESTARTS   AGE
my-release-zookeeper-0           2/2     Running   0          3h4m
my-release-zookeeper-1           2/2     Running   0          3h4m
my-release-zookeeper-2           2/2     Running   0          3h5m
pod/sleep-8f795f47d-qkgh4        2/2     Running   0          3h8m

NAME                            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                            AGE
my-release-zookeeper            ClusterIP   10.100.1.113   <none>        2181/TCP,2888/TCP,3888/TCP         3h
my-release-zookeeper-headless   ClusterIP   None           <none>        2181/TCP,2888/TCP,3888/TCP         3h
service/sleep                   ClusterIP   10.100.9.26    <none>        80/TCP                             3h

ZooKeeper サービスは機能しており、ステータスは Running ですか? 確認してみましょう! ZooKeeper は 3 つのポートでリッスンします。

デフォルトでは、ZooKeeper のインストールでは、ポート 2181 は 0.0.0.0 でリッスンするように構成されていますが、ポート 2888 と 3888 は Pod IP のみでリッスンします。 これらの各ポートのネットワークステータスを ZooKeeper Pod の 1 つから確認してみましょう。

$ kubectl exec my-release-zookeeper-1 -c istio-proxy -- netstat -na | grep -E '(2181|2888|3888)'
tcp        0      0 0.0.0.0:2181            0.0.0.0:*               LISTEN
tcp        0      0 10.96.7.7:3888          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:2181          127.0.0.1:37412         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37486         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37456         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37498         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37384         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37514         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37402         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37434         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37526         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37374         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37442         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:37464         TIME_WAIT

ポート 2888 または 3888 に ESTABLISHED なものはありません。次に、ZooKeeper サーバーステータスを取得しましょう。

$ kubectl exec my-release-zookeeper-1 -c zookeeper -- /opt/bitnami/zookeeper/bin/zkServer.sh status
/opt/bitnami/java/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/bitnami/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Error contacting service. It is probably not running.

上記の出力から、ZooKeeper サービスが正常に機能していないことがわかります。 ZooKeeper Pod の 1 つのクラスタ構成を確認しましょう。

$ istioctl proxy-config cluster my-release-zookeeper-1 --port 3888 --direction inbound -o json
[
    {
        "name": "inbound|3888||",
        "type": "STATIC",
        "connectTimeout": "10s",
        "loadAssignment": {
            "clusterName": "inbound|3888||",
            "endpoints": [
                {
                    "lbEndpoints": [
                        {
                            "endpoint": {
                                "address": {
                                    "socketAddress": {
                                        "address": "127.0.0.1",
                                        "portValue": 3888
                                    }
                                }
                            }
                        }
                    ]
                }
            ]
        },
...

ここで興味深いのは、ポート 3888 のインバウンドのエンドポイントが 127.0.0.1 であることです。これは、変更に関するブログ記事 で説明されているように、Istio 1.10 より前のバージョンの Envoy プロキシがインバウンドトラフィックを loopback インターフェースにリダイレクトするためです。

Istio 1.10 での StatefulSets の動作

これで、クラスタが Istio 1.10 にアップグレードされ、default 名前空間が 1.10 サイドカーインジェクションを有効にするように構成されました。 ZooKeeper StatefulSet をローリング再起動して、Pod を新しいバージョンのサイドカープロキシを使用するように更新しましょう。

$ kubectl rollout restart statefulset my-release-zookeeper

ZooKeeper Pod が実行状態になったら、ZooKeeper Pod のいずれかからこれらの 3 つのポートのネットワーク接続を確認しましょう。

$ kubectl exec my-release-zookeeper-1 -c istio-proxy -- netstat -na | grep -E '(2181|2888|3888)'
tcp        0      0 0.0.0.0:2181            0.0.0.0:*               LISTEN
tcp        0      0 10.96.8.10:2888         0.0.0.0:*               LISTEN
tcp        0      0 10.96.8.10:3888         0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.6:42571         10.96.8.10:2888         ESTABLISHED
tcp        0      0 10.96.8.10:2888         127.0.0.6:42571         ESTABLISHED
tcp        0      0 127.0.0.6:42655         10.96.8.10:2888         ESTABLISHED
tcp        0      0 10.96.8.10:2888         127.0.0.6:42655         ESTABLISHED
tcp        0      0 10.96.8.10:37876        10.96.6.11:3888         ESTABLISHED
tcp        0      0 10.96.8.10:44872        10.96.7.10:3888         ESTABLISHED
tcp        0      0 10.96.8.10:37878        10.96.6.11:3888         ESTABLISHED
tcp        0      0 10.96.8.10:44870        10.96.7.10:3888         ESTABLISHED
tcp        0      0 127.0.0.1:2181          127.0.0.1:54508         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54616         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54664         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54526         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54532         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54578         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54634         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54588         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54610         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54550         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54560         TIME_WAIT
tcp        0      0 127.0.0.1:2181          127.0.0.1:54644         TIME_WAIT

ポート 2888 と 3888 の両方に ESTABLISHED 接続があります!次に、ZooKeeper サーバーステータスを確認しましょう。

$ kubectl exec my-release-zookeeper-1 -c zookeeper -- /opt/bitnami/zookeeper/bin/zkServer.sh status
/opt/bitnami/java/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/bitnami/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower

ZooKeeper サービスが稼働しています!

sleep Pod から各 ZooKeeper Pod に接続し、以下のコマンドを実行して、StatefulSet 内の各 Pod のサーバーステータスを検出できます。 ZooKeeper Pod の ServiceEntry リソースを作成する必要はなく、sleep Pod から DNS 名(例:my-release-zookeeper-0.my-release-zookeeper-headless)を使用してこれらの Pod を直接呼び出すことができます。.

$ kubectl exec -it deploy/sleep -c sleep -- sh  -c 'for x in my-release-zookeeper-0.my-release-zookeeper-headless my-release-zookeeper-1.my-release-zookeeper-headless my-release-zookeeper-2.my-release-zookeeper-headless; do echo $x; echo srvr|nc $x 2181; echo; done'
my-release-zookeeper-0.my-release-zookeeper-headless
Zookeeper version: 3.7.0-e3704b390a6697bfdf4b0bef79e3da7a4f6bac4b, built on 2021-03-17 09:46 UTC
Latency min/avg/max: 1/7.5/20
Received: 3845
Sent: 3844
Connections: 1
Outstanding: 0
Zxid: 0x200000002
Mode: follower
Node count: 6

my-release-zookeeper-1.my-release-zookeeper-headless
Zookeeper version: 3.7.0-e3704b390a6697bfdf4b0bef79e3da7a4f6bac4b, built on 2021-03-17 09:46 UTC
Latency min/avg/max: 0/0.0/0
Received: 3856
Sent: 3855
Connections: 1
Outstanding: 0
Zxid: 0x200000002
Mode: follower
Node count: 6

my-release-zookeeper-2.my-release-zookeeper-headless
Zookeeper version: 3.7.0-e3704b390a6697bfdf4b0bef79e3da7a4f6bac4b, built on 2021-03-17 09:46 UTC
Latency min/avg/max: 0/0.0/0
Received: 3855
Sent: 3854
Connections: 1
Outstanding: 0
Zxid: 0x200000002
Mode: leader
Node count: 6
Proposal sizes last/min/max: 48/48/48

ZooKeeper サービスが稼働しているので、Istio を使用して、通常サービスとヘッドレスサービスへのすべての通信を保護しましょう。 default 名前空間に相互 TLS を適用します。

$ kubectl apply -n default -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "default"
spec:
  mtls:
    mode: STRICT
EOF

sleep Pod からトラフィックを送信し続け、Kiali ダッシュボードを表示して default 名前空間のサービスを視覚化します。

Visualize the ZooKeeper Services in Kiali
Kiali で ZooKeeper サービスを視覚化する

トラフィックフローの南京錠アイコンは、接続が安全であることを示しています。

まとめ

Istio 1.10 の新しいネットワーキングの変更により、サイドカーを持つ Kubernetes Pod は、サイドカーを持たない Pod と同じネットワーキング動作をします。 この変更により、この投稿で示したように、ステートフルアプリケーションが Istio で正しく機能するようになります。 これは、透過的なサービスメッシュとゼロコンフィギュレーション Istio を提供するという Istio の目標に向けた大きな一歩だと信じています。

この記事を共有する