k8sもDockerもちゃんとやらないままに、k8s上でちょっとしたAPIサーバをたてることになった。なので、手始めにGKE上にAPIサーバを構築することにした。FirebaseでしかGCP使っていなかったので、辿々しくコンソール画面をいじっている……。
フレームワークはなんでもよかったが、Pythonを使い慣れているので、Flask + nginx を行くことにする。
前提
- GCPにプロジェクトを作成している
- 使用するプロジェクトに、CLIでGKE上にクラスターを作成している
- 費用が発生するので終わったら消す
全体像
今回は、下図のようなものを作成する。
GKE上にリソースを展開するうえで、予めローカルでビルドしたDocker ImageをGCRにアップロードしておく、くらいかな。
知識がないので、情報が多かったGCRにアップロードしたんだけれど、GCPを見ると「Artifact Registryを使って」とのことだった。なので、多分そのほうがいいんだろうとは思う。ただまぁ、何もかもわからん状態なので、まずは言われるままGCRを使ったという感じ。
Dockerイメージの作成
まず、Dockerのイメージを作成から。
Dockerfile
flaskを動かすだけのシンプルなコンテナ。あくまで検証用であるので、flaskをそのまま使う。
FROM python:3.6-slim
RUN apt-get clean \
&& apt-get -y update
RUN apt-get -y install \
nginx \
python3-dev \
build-essential
WORKDIR /app
COPY requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt --src /usr/local/src
COPY . .
EXPOSE 5000
CMD [ "python", "flaskapi.py"]
flaskapi.py
GET / でHello, worldを返すだけの漢のREST API。
import os
import requests
from flask import jsonify, request, Flask
app = Flask(__name__)
@app.route("/")
def index():
"""Function to test functionality of the API"""
return "Hello, world"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
イメージの作成とアップロード
この状態でビルドする。なお、以下はfishです。( ... ) の部分はbashだと$( ... ) かな。
export PROJECT_ID=(gcloud config get-value project -q)
docker build . -t gcr.io/$PROJECT_ID/flask-api:v1
このイメージをGKEで使いたいので、GCRにpushする。
docker push gcr.io/$PROJECT_ID/flask-api:v1
しばらく待つ。
GKEにデプロイ
GKE上にリソースを展開する。
flaskapp-deployment.yaml
ServiceとDeploymentだけのシンプルなもの。アプリはGCRにpushしたやつをそのまま使う。
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: flaskapi-deployment
labels:
app: flaskapi
spec:
replicas: 2
selector:
matchLabels:
app: flaskapi
template:
metadata:
labels:
app: flaskapi
spec:
containers:
- name: flaskapi
image: gcr.io/プロジェクトID/flask-api:v1
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: flask-service
spec:
ports:
- port: 5000
protocol: TCP
targetPort: 5000
selector:
app: flaskapi
type: LoadBalancer
コンテナのイメージのところだけ、プロジェクトIDに書き換える。
kubectl apply -f flaskapp-deployment.yaml
ここで、もしかすると「Imageがない」というエラーが出るかもしれない。この場合、恐らくGKEからGCRのリポジトリがあるバケットへのアクセス権限の問題と思われる。
「IAMを管理」の「IAM」より、「Google提供のロール付与を含みます」をチェックしてサービスアカウントのプリンシパルを確認しておく。
Cloud Storageで、イメージを置いているバケットの権限について確認し、確認したプリンシパルに読み取り権限を付与してやればいける……はず。
テスト
GKEは特に何もしなくてもServiceのLBにIPアドレス付与されるはずなので、get servicesで調べる。
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
flask-service LoadBalancer xx.xx.xx.xx ここのIP 5000:30939/TCP 23h
EXTERNAL-IPを見て、curlで叩く
curl http://IPアドレス/
Hello, worldが返ってきたらOK。
動作を検証しおわったら、忘れずに後始末しておく。コンソールからクラスタごと削除してしまえばよいかな。
参考サイト
助かりまくりました。ありがとうございます。
コメント