更新日:2022-02-04
文字数:3816字
Web サービスで最適化を行う際、データベースからデータをとってきて、最適化を実行しその結果をフィードバックするというような一連のサイクルを考慮する必要があります。
今回は最適化を行うにあたり、ざっと以下のような要件がありました。
今回はこれら要件を踏まえた上で扱いやすそうな FastAPI
を使用することにしました。
FastAPI を用いた API の実装は別の記事にするとして、今回は構築した API の Docker 化
から Cloud Run
へのデプロイと CI/CDパイプライン
までやります。
盛りだくさん!!
まずはサービスを Docker 化していきます。
今回は python のパッケージ管理に pip ではなく、poetry
を使用したのでそこが一番詰まりました。
処理の流れはシンプルです。
以下のような Dockerfile に落ち着きました。
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8 ENV PYTHONDONTWRITEBYTECODE 1 EXPOSE 8080 COPY ./src /src COPY ./src/pyproject.toml ./src/poetry.lock* WORKDIR /src/ RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/opt/poetry python3 - && \ cd /usr/local/bin && \ ln -s /opt/poetry/bin/poetry && \ poetry config virtualenvs.create false ARG INSTALL_DEV=false RUN bash -c "if [ $INSTALL_DEV == 'true' ] ; then poetry install --no-root ; else poetry install --no-root --no-dev ; fi" ARG INSTALL_JUPYTER=false RUN bash -c "if [ $INSTALL_JUPYTER == 'true' ] ; then pip install jupyterlab ; fi" ENV PYTHONPATH=/src CMD [ "uvicorn", "app.main:app", "--reload","--host", "0.0.0.0", "--port", "8080"]
また同じディレクトリ内に、run.sh を作成し、ローカルで簡単に Docker プロセスを実行できるようにしています。 optimize_service というコンテナが local になければビルド後実行し、あればそのまま実行するというスクリプトです。
#!/bin/bash NAME='optimize_service' trap "docker stop $NAME" SIGINT if [ "$(docker ps -q -a -f name=$NAME)" ];then echo 'run local docker container' docker start $NAME && docker logs -f $NAME exit 1 else docker build -t $NAME . docker run --log-opt max-size=10m --log-opt max-file=3 --name $NAME -v ${PWD}/src/:/src -p 8008:8080 $NAME fi
Docker 化が終わったので、早速デプロイをしていきます。
GCP のコンテナ管理は Container Registry を拡張したAritifact Registry
を使用します。
ざっくり全体の流れは以下です。
1,2,3 は GCP の管理画面をぽちぽちします。そのほかは gcloud
コマンドを使います。具体的なコマンドは下記 gitlab CI のスクリプトを参考にしてみてください。
ここまでやってしまえば、あとはローカルで実行したコマンドをベースに CI/CD のためのスクリプトを書けば OK です。
下記のような ci スクリプトを作成しました。やっていることは各種環境変数の設定と上記ローカルでデプロイした一つ一つの処理の記述です。
image: google/cloud-sdk stages: - deploy deploy-prot: stage: deploy services: - name: docker:19.03.8-dind variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" environment: name: prot only: - develop script: - echo GMAP_KEY=$GMAP_KEY > .env - echo SLACK_URL=$DEV_SLACK_URL >> .env - echo CLIENT_URL=$DEV_CLIENT_URL >> .env - echo $DEV_SERVICE_ACCOUNT > service-account.json - cp service-account.json src - cp .env src - gcloud auth activate-service-account --key-file service-account.json - gcloud config set project $PROJECT_NAME - gcloud auth configure-docker $REGION_URL - docker build -t $IMAGE_PATH . - docker push $IMAGE_PATH - gcloud run deploy $CLOUD_RUN_SERVICE_NAME --image $IMAGE_PATH --region $REGION --allow-unauthenticated --timeout 3000s --memory 4Gi --cpu 4
必要に応じて、ブランチによる環境切り替えやテストの実行などを記述すれば、それなりの CI/CD パイプラインが組めてしまいます!
トライ&エラーをたくさんしましたが、CI スクリプトは一度書いてしまえば開発体験はめちゃめちゃ上がるので早めに書いておいた方がいいですね! また Serverless といえば、AWS Lambda や Cloud Functions ばかり使ってましたが、最適化のような処理時間がネックになるようなケースでは Cloud Run という選択肢はとても良い気がします。 以上、お疲れ様でした!
tech