GKEでgRPCのサーバをenvoy使って外部公開したよ
GKEでマイクロサービスとかやってて、たまーーーにgRPCのサービスを外部に公開したくなることってありますよね?
でもGKEのL7LB(HTTPロードバランサ)はgRPCに対応してません(2018/03/18)。もうすぐ出るかも?
さらにはgRPCの通信は永続化されるので高負荷時にスケールさせられない問題があります。
そこで使えるのがenvoyproxyというわけです。
envoyはTLSのターミネーションにも対応しています。外部に公開したいgRPCサービスの前段にenvoyを噛ませればTLSのターミネーションからスケールアウト時のバランシングまで対応できちゃうというわけでとても便利です。
構成
L4LB -> envoy -> grpcService
grpcServiceはport:50051でGKE内にNodePortとして存在するとします。
この状態にenvoyを導入します。
TLSの準備
まず、TLSの鍵と証明書を用意します。何かしらの方法で用意して下さい。
用意された鍵と証明書をGKEのsecretとして登録します。
apiVersion: v1
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
kind: Secret
metadata:
name: tlssecret
namespace: default
type: Opaque
証明書と鍵をbase64に変換する必要があります。
base64への変換は下記のコマンドなんかを使うと良いでしょう。
$ base64 -i path/to/wildcard.example.com.key
envoyの設定
TLSの準備ができたらenvoyの設定を作ります。設定はconfigmapで管理すると良い感じです。
apiVersion: v1
kind: ConfigMap
metadata:
name: "envoy-config"
data:
envoy.json: |
{
"listeners": [
{
"address": "tcp://0.0.0.0:15001",
"ssl_context" : {
"cipher_suites" : "[ECDHE-RSA-AES256-GCM-SHA384|ECDHE-RSA-AES128-GCM-SHA256]",
"cert_chain_file" : "/etc/tlssecret/tls.crt",
"private_key_file" : "/etc/tlssecret/tls.key"
},
"filters": [
{
"type": "read",
"name": "http_connection_manager",
"config": {
"codec_type": "auto",
"stat_prefix": "ingress_http",
"route_config": {
"virtual_hosts": [
{
"name": "service",
"domains": ["*"],
"routes": [
{
"timeout_ms": 0,
"prefix": "/",
"cluster": "grpc"
}
]
}
]
},
"filters": [
{
"type": "decoder",
"name": "router",
"config": {}
}
]
}
}
]
}
],
"admin": {
"access_log_path": "/dev/stdout",
"address": "tcp://127.0.0.1:8001"
},
"cluster_manager": {
"clusters": [
{
"name": "grpc",
"features": "http2",
"connect_timeout_ms": 250,
"type": "strict_dns",
"lb_type": "round_robin",
"hosts": [{"url": "tcp://grpc-service:50051"}]
}
]
}
}
このように/etc/tlssecret
にTLSの設定を読みに行くような記述にします。(パスは別のところでもかまいません)
grpc-serviceのheadlessService化
上述のenvoyの設定で"hosts": [{"url": "tcp://grpc-service:50051"}]
このように記述しています。
これはkubernetesのheadlessServiceを利用してサービスディスカバリーするためです。
kubernetesのheadlessServiceは問い合わせるとPodのIPアドレス一覧を返す仕組みです。
つまり既存で用意していたgrpc-serviceをheadlessService化する必要があります。
apiVersion: v1
kind: Service
metadata:
labels:
name: "grpc"
name: "grpc-service"
spec:
clusterIP: None
selector:
app: "grpc"
ports:
- name: grpc
port: 50051
targetPort: 50051
protocol: TCP
このようにclusterIP: None
としてあげるとheadlessService化します。
envoyのDeployment
configmapとheadlessServiceができたらdeploymentを用意します。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: "envoy"
spec:
replicas: "2"
template:
metadata:
labels:
app: "envoy"
spec:
volumes:
- name: envoy
configMap:
name: "envoy-config"
- name: tls
secret:
secretName: tlssecret
containers:
- name: envoy
image: envoyproxy/envoy:latest
command:
- "/usr/local/bin/envoy"
args:
- "--config-path /etc/envoy/envoy.json"
resources:
limits:
memory: 512Mi
ports:
- containerPort: 15001
name: app
- containerPort: 8001
name: envoy-admin
volumeMounts:
- name: envoy
mountPath: /etc/envoy
- name: tls
mountPath: /etc/tlssecret
readOnly: true
ここではenvoyのDockerImageにTLSの情報とenvoyの設定をマウントしています。
/etc/envoy
にenvoyの設定を、/etc/tlssecret
にTLSの証明書等をマウントしているのがvolumeMounts等でわかるかと思います。
envoyのservice
次に用意したenvoyを外の世界と繋げるためにserviceを用意します。
apiVersion: v1
kind: Service
metadata:
labels:
name: "envoy"
name: "envoy-service"
spec:
type: LoadBalancer
loadBalancerIP: "192.0.2.3"
selector:
app: "envoy"
ports:
- name: tcp
port: 15001
targetPort: 15001
type:LoadBalancerでserviceを作ります。これでGCPのL4LBが立ち上がります。
外部に公開することを考えるとStaticIPAdressを用意したほうが良いでしょう。これはGCPの画面から(terraform等のが良いかも)で準備します。
準備したIPアドレスはloadBalancerIPに記述してあげます。
DNSの設定も別途行っておいて下さい。
これで完成です。無事TLSで暗号化されたgRPCの通信ができるはず!!
Author And Source
この問題について(GKEでgRPCのサーバをenvoy使って外部公開したよ), 我々は、より多くの情報をここで見つけました https://qiita.com/wataru420/items/b5d9948d6baba6b49dd8著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .