GKE + Flask で REST API

k8sもDockerもちゃんとやらないままに、k8s上でちょっとしたAPIサーバをたてることになった。なので、手始めにGKE上にAPIサーバを構築することにした。FirebaseでしかGCP使っていなかったので、辿々しくコンソール画面をいじっている……。

フレームワークはなんでもよかったが、Pythonを使い慣れているので、Flask + Gunicorn + 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のリポジトリがあるバケットへのアクセス権限の問題と思われる。

GCRからimage pullできない – Qiita

「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。

動作を検証しおわったら、忘れずに後始末しておく。コンソールからクラスタごと削除してしまえばよいかな。

参考サイト

助かりまくりました。ありがとうございます。

関連記事

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。