サービスメッシュを実現するIstioをEKS上で動かす - その3 EKSでRDSなど外部サービスと接続してみる
山崎 雅斗
これまでは、EKSクラスタ内で完結するBookinfoアプリケーションを使ってIstioの検証を進めてきました。ここでは、Istio上で外部サービスと連携するアプリケーションを動かしてみます。
なお、簡便化のために今回はmTLSを無効にした状態で進めていきます。
検証用に、外部のデータベースを利用する簡単なWebアプリケーションを作成し、それをEKSクラスタ上にデプロイしておきます。テスト用のアプリケーションのソースコードは、GitHubの mas9612/sampleapp に置いてあります。
シリーズ一覧
- まずはMinikubeでサンプルアプリケーションを動かしてみる
- EKSでサンプルを動かしてみる
- EKSでRDSなど外部サービスと接続してみる 👈 この記事
- データの可視化について
- 実運用中のサービスをIstioにのせてみる
- Datadogと連携する
サンプルアプリケーションのデプロイ
まず、サンプルアプリケーションをデプロイしていきます。次のようなmanifestを用意して、 kubectl
コマンドで適用します。なお、データベースはAWSのサービスの1つであるRDSを使用しています。
apiVersion: v1
kind: Service
metadata:
name: sampleapp
spec:
ports:
- name: sampleapp-port
port: 8080
protocol: TCP
targetPort: sampleapp-port
selector:
app: sampleapp
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sampleapp
spec:
replicas: 1
selector:
matchLabels:
app: sampleapp
template:
metadata:
name: sampleapp
labels:
app: sampleapp
spec:
containers:
- image: mas9612/sampleapp:latest
name: sampleapp
ports:
- containerPort: 8080
name: sampleapp-port
protocol: TCP
env:
- name: SAMPLEAPP_DB_HOST
value: xxxxxx.ap-northeast-1.rds.amazonaws.com
- name: SAMPLEAPP_DB_USER
value: sampleapp
- name: SAMPLEAPP_DB_PASS
value: xxxxxxx
- name: SAMPLEAPP_DB_NAME
value: sampleapp
このmanifestを適用すると、ServiceリソースとDeploymentリソースが1つずつ作成されます。
Istioのネットワーク設定
アプリケーション本体をデプロイしたら、次はGatewayリソースとVirtualServiceリソースを作成していきます。
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: sampleapp-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "sample.example.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: sampleapp
spec:
hosts:
- "sample.example.com"
gateways:
- sampleapp-gateway
http:
- route:
- destination:
host: sampleapp
port:
number: 8080
このmanifestを適用したら、istio-ingressgatewayに向けて Host: sample.example.com
ヘッダを付けてリクエストを送信するとサンプルアプリケーションに接続できるようになります。
$ curl -H "Host: sample.example.com" xxxxxx.ap-northeast-1.elb.amazonaws.com
しかし、この状態でsampleappに接続してもエラーとなります。特に何も設定をしない場合、サービスメッシュ外にあるデータベースにうまく接続できずにエラーとなってしまいます。
サービスメッシュ外のサービスに接続するためには、サービスごとにServiceEntryと呼ばれるリソースを作成する必要があります。
ServiceEntryリソースを作成すると、サービスメッシュ内のアプリケーションが外部のサービスへアクセスできるように、Istioが持っているサービスレジストリにその情報を登録してくれます。
それでは、データベース用のServiceEntryリソースを作成していきます。次のようなmanifestを作成し、 kubectl
コマンドで適用します。spec.addresses
にはデータベースのIPアドレスを指定する必要があるので、事前に nslookup
コマンド等でIPアドレスを調べておきます。
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: mysql
spec:
hosts:
- xxxxxx.ap-northeast-1.rds.amazonaws.com
addresses:
- 10.0.0.1/32
ports:
- number: 3306
name: mysql
protocol: TCP
location: MESH_EXTERNAL
このマニフェストでは spec.hosts
と spec.addresses
をそれぞれ指定しています。実際には、プロトコルがHTTPもしくはHTTPS以外の場合、 spec.hosts
は無視されて spec.addresses
に書いてあるアドレスが用いられるようになっています。HTTPやHTTPSの場合、Hostヘッダをみればその通信の宛先がどのホストであるかがわかります。しかし、TCPの場合はHostヘッダのように宛先のドメイン名を示している部分はありません。そのため、HTTP/HTTPS以外では spec.hosts
が無視される仕様となっています。
基本的に、ServiceEntryリソースでHTTP/HTTPS以外のサービスを利用する際は、 spec.addresses
にそれらのIPアドレスをCIDR表記(プレフィックス /32
)で指定します。しかし、IPアドレスが動的に変わる環境の場合、これが難しい場合もあると思います。そのような場合は、次のような対応策があります。
- 対象サービスを名前解決した結果複数のIPアドレスが得られて、かつその内のいくつかは固定されている場合、固定されているIPアドレスを
spec.addresses
に指定する - 対象サービスが取りうるIPアドレスの範囲がわかっている場合、その範囲をCIDR表記で
spec.addresses
に指定する - KubernetesのServiceリソースを、type ExternalNameで作成する
これら3つにも当てはまらない場合は、ServiceEntryリソースを利用することができません。その場合は、Sidecar Proxyをバイパスして直接外部のサービスと通信するという手段を取ることになります。
このリソースを作成した後に再度サービスへ接続しに行くと、正常にデータベースとの接続が正常に確立されて 200 OK
が返ってくるようになります。
$ curl -H "Host: sample.example.com" xxxxxx.ap-northeast-1.elb.amazonaws.com
Consuming External TCP Services
まとめ
外部のデータベースを参照するようなアプリケーションを使って、Istioのサービスメッシュ上で外部サービスとの連携で必要となる設定について見てきました。
次回は、Istioで取得できる様々なデータを可視化するアプリケーションについて見ていこうと思います。