はじめに
GCP (Google Cloud Platform)を使ったお仕事をさせていただいているおじさんです。
GAE (Google Application Engine)からGKE(Google Kubernetes Engine)にアクセスできたので、興奮冷めやらぬ?うちにメモを残しておきます。
動作確認メモ
作戦は以下の通りです。行う実装・設定は
(1) Google の解説にある [内部 TCP / UDP ロードバランサの使用]
(https://cloud.google.com/kubernetes-engine/docs/how-to/internal-load-balancing) に従って、Kubernetes Cluster に外部IPを用意する
(2) 用意した外部IPにアクセスするための「サーバレスVPCコネクタ」を用意する
(3) GAEアプリケーションが用意した「サーバレスVPCコネクタ」を使えるようにする
用意したGAEがロードバランサを参照すると、GKEのポッドが返事をするのを確認します。
Cluster の外側にIPアドレスを設定(Load Balancer)
Kubernetes は Cluster の中でcontainer の管理を行います。その中にnode があり、ここにdeploy したり、container の数を増やしたり減らしたりします。一方で、service と呼ぶ仮想的なIPパケット通信を行うためのルータやスイッチのような役割を果たすものがあり、LoadBalancer も service の一つになります。
ここでは、Google の解説そのままですが、なぞった時のメモです。Cluster はひとつasia-northeast1 に作ってあり、そこで作業しています。
サンプルimage をデプロイ
以下のマニフェストをkubectl apply -f my-deployment.yaml
します。このサンプルGoogle の解説にあるものそのままです。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-app
spec:
selector:
matchLabels:
app: hello
replicas: 3
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: "gcr.io/google-samples/hello-app:2.0"
確かにpod ができていることを確認します。
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
hello-app 3/3 3 3 94s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-app-7f46745f74-24ldc 1/1 Running 0 82s
hello-app-7f46745f74-2xl25 1/1 Running 0 83s
hello-app-7f46745f74-z4hzc 1/1 Running 0 82s
Load Balancer の作成
つづいて、service (load balancer)を作ります。以下のマニフェストを kubectl apply -f my-service.yaml
します。
apiVersion: v1
kind: Service
metadata:
name: ilb-service
annotations:
cloud.google.com/load-balancer-type: "Internal"
labels:
app: hello
spec:
type: LoadBalancer
selector:
app: hello
ports:
- port: 80
targetPort: 8080
protocol: TCP
service が作られていることを確認します。EXTERNL-IPが割り当てられていることを確認します。
$ kubectl get service ilb-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ilb-service LoadBalancer 10.79.247.115 10.146.0.9 80:32456/TCP 3m14s
$ gcloud compute forwarding-rules list --filter="loadBalancingScheme=INTERNAL"
NAME REGION IP_ADDRESS
IP_PROTOCOL TARGET
a91aceace48744715a2391849b778aeb asia-northeast1 10.146.0.9 TCP asia-northeast1/backendServices/a91aceace48744715a2391849b778aeb
$ gcloud compute backend-services describe a91aceace48744715a2391849b778aeb --region asia-northeast1
...(略)
サーバレスVPCコネクタ
ここでは、コンソール(GCPのWEBブラウザからの操作)で行いました。「VPCネットワーク」から「サーバレスVPCアクセス」を選択します。
ここではに従い、深いことは何も考えず、default を選択して、以下のように作りました。
ここでネットワークというのがよくわかりませんでした。これはこのプロジェクト?で使われているdefault のネットワークのようで、以下のようなzone に対応したアドレスの総体のようでした。今回使用しているのは、asia-northeast1 なのですが、このアドレス空間(subnet)は10.146.0.0/20 で、さきほど作成したClustger の LoadBalancer は 10.146.0.9 がEXTERNAL IPとして割り振られていました。というわkで、何となく、GCPのあぷりから 10.146.0.9 にアクセスできそうな気がしてきます。
一方で、「サーバレス」なGAEはまた別のネットワークにいるのかもしれませんが、理解できていないことを先に書いておきます。
GAEからVPCコネクタを経由してCluster の Load Balancer にアクセスする
書くと長いですが、サンプルはごく簡単です。これもGoogle のサンプルをを少し修正しただけです。
ありものを修正して使います。コードに直書きです。同じディレクトリに3つのファイルを用意します。
├── app.yaml
├── main.py
└── requirements.txt
VPC コネクタの利用
app.yamlに2行記述します。
runtime: python37
vpc_access_connector:
name: projects/PROJECT_ID/locations/asia-northeast1/connectors/CONNECTEOR_NAME
接続テスト用flask サーバ
ずばり、HTTP GET が来たら、先ほどのCluster のEXTERNAL IPにHTTP リクエストを出して、その結果を返す、というものです。
from flask import Flask
import requests
app = Flask(__name__)
@app.route('/')
def hello():
try:
r = requests.get('http://10.146.0.9:80/')
print(r)
print(r.status_code)
print(r.headers)
print(r.content)
return "Hello World! response: (OK!)" + r.content.decode('utf-8')
except Exception as e:
return str(e)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080, debug=True)
Python3.8でrequests==2.25.1 としたらエラーが出たので、適当に変更しています。
Flask==1.1.2
requests>=2.22.0
これらが置いてあるディレクトリで
gcloud app deploy
します。
動作確認
ブラウザ
いざ、Chromeに https://PROJECT_ID.an.r.appspot.com/ を入れてみると、、、(GAE のサービス名が default のままの場合)
Hello World! response: (OK!)Hello, world! Version: 2.0.0 Hostname:
hello-app-7f46745f74-24ldc
と無事に表示されました。
GAEのログ
GAEのログでもHTTP 200を確認できます。
$ gcloud app logs tail -s default
...
2021-01-10 15:27:31 default[20210111t002221] "GET / HTTP/1.1" 200
2021-01-10 15:27:31 default[20210111t002221] <Response [200]>
2021-01-10 15:27:31 default[20210111t002221] 200
2021-01-10 15:27:31 default[20210111t002221] {'Date': 'Sun, 10 Jan 2021 15:27:31 GMT', 'Content-Length': '66', 'Content-Type':'text/plain; charset=utf-8'}
2021-01-10 15:27:31 default[20210111t002221] b'Hello, world!\nVersion: 2.0.0\nHostname: hello-app-7f46745f74-2xl25\n'
良かった。。。本当に、良かった。
おわりに
GAEからGKEとHTTP通信できることを確認しました。
- Kubernetes Cluster にService(load balancer)を用意すること
- GAEはサーバレスVPCコネクタに接続すること
がポイントのようでした。とりあえず動きましたが、VPCやアドレス空間をまだよく理解できていません。だれがルータなのか。。
情報源
もとは、この記事を参考にすれば簡単にできるだろう、と思っていました。
しかし、実際に自分で動かそうとテストしようとしても、できません。テスト用のプログラムが良くないのか、設定が良くないのか切り分けができず、数日を使ってしまいました。結果として、設定が良くなかったです。理由は以下のように考えています。
- 自分が作ったdeployment に対して用意したservice が適応されなかった。用意したservice のマニフェストのselector などでdeployment を参照するようになっていなかったのでは。
- また、この例では「限定公開のクラスタ」ということなので、独自に作ったネットワークをりようしていましたが、自分はdefault のものを利用していたので、azia-northeast1 にある10.146.....が外部IPになりましたが、サンプルでは、192.168... となっていました。これ自体は問題にはならないと思いますが。
以下も何度も?眺めました。
- GCPの解説:内部TCP/UDPロードバランサの使用 .... これは今回フォローしたものです。
- GCPの解説:GKEのサービスでLoadBalancer について
- GCPの解説:限定公開クラスタの作成
- GCPの解説:サービス ... GKEの。
- Kubernetesの解説:サービスとアプリケーションの接続
- こちらもLoad Balancer の設定についてサンプルを交えた解説になっていて良かったです。service についてDNS、HTTPSにする方法もあります。
- Kuberentes の解説:Creating External Load Balancer
TODO
とりあえず動いたレベルなので、もう少ししくみをよく理解したい。。。
- Service の Load Balancer のEXTERNAL IPはどこで決められるのか。これ、CI/CDにくこむときは、毎回このservice.yaml も実行することになるのかな。
- private のネットワークにクラスタを作っている記事があった。何故だろう。
- サーバレスVPCコネクタの役割、とGAEが属するネットワークについての情報。
あと、きじによると、Cloud DNSでCluseter のExternal IPを登録すると名前でアクセスできるようになる、というがあるので、それも合わせて試してみたい。
真夜中だぞ、、、体に悪いぞ、、、寝よう。
(2021/01/11)