趣味で作っている Web アプリの開発中に得られたいろいろをメモ
あとで整理するかもしれないし、しないかもしれない
fly.io
コマンドいろいろ
-
インストール
https://fly.io/docs/hands-on/install-flyctl/macOS$ brew install flyctl -
ログインする
https://fly.io/docs/flyctl/auth-login/$ fly auth login --email [email_address] -
ログアウトする
https://fly.io/docs/flyctl/auth-logout/#usage$ fly auth logoutどうやらトークンがローカルに保存されているようで、アカウントを切り替えたいときは競合を避けるために、ログアウトしたほうがよいみたい
-
flyctlのアップデート$ fly version update -
環境変数の確認
https://fly.io/docs/flyctl/secrets-list/#usage$ fly secrets list -
アプリのステータスの確認
https://fly.io/docs/flyctl/status/$ fly status -
アプリ (マシン) の起動
https://fly.io/docs/flyctl/machine-start/$ fly machine start [id] -
アプリ (マシン) の停止
https://fly.io/docs/flyctl/machine-stop/#usage$ fly machine stop [id] -
Web アプリを開く
$ fly open以下の URL になる模様 (無料枠だと開発用ということで
devがつく)
https://<application-name>.fly.dev/ -
WireGuard
https://fly.io/docs/flyctl/wireguard/$ fly wireguard [command] -
fly.io上で立てた DB への接続$ fly postgres connect -a [postgres-db-name] $ fly proxy 15432:5432 -a [postgres-db-name] -
fly.io上の DB のDATABASE_URLを参照する$ fly postgres attach [postgres-db-name] -a [app-name]- こんな感じで出力される
postgres://[app-name]:XXXXXXXXXXXXXXX@top2.nearest.of.[postgres-db-name].internal:5432/[app-name]?sslmode=disable Username: app-name-
Password: XXXXXXXXXXXXXXX
だと思われ...
設定を忘れて、改めてパスワードを参照したいときに使えると思います
- こんな感じで出力される
-
fly.ioのimageの更新
https://fly.io/docs/flyctl/image-update/$ fly image update
デプロイ手順
-
ローンチ
デプロイのために設定ファイル (fly.toml) を作成する$ fly launchここでアプリ名や DB の設定を行う
吐き出されたfly.tomlはDockerfileと同じ階層に入れておく -
デプロイ
$ fly deploy -
Procfile
Web アプリの実行コマンドを記述するProcfileweb: uvicorn main:app --host 0.0.0.0 --port 8080FastAPI ならこんな感じ……らしいが、うまくいかなかった
Dockerfileに直接実行コマンドを書いたら起動できたDockerfileCMD python main.pyこういうこと
ローカル開発環境構築
Web アプリをつくるのに用意した環境をまとめる
- ディレクトリ構成
以下にまとめるそれぞれの環境を
. ├── backend │ ├── app │ │ └── main.py │ ├── dev.dockerfile │ ├── requirements.txt │ └── vue │ └── dist/ ├── frontend │ ├── app/ │ └── dev.dockerfile ├── initdb/ ├── nginx │ ├── conf.d/ │ ├── dev.dockerfile │ └── nginx.conf ├── Dockerfile ├── docker-compose.yml └── fly.tomldocker-compose.ymlでいい感じにする
詳しくは後述する
バックエンド
FastAPI で API を用意した
-
コンテナ
dev.dockerfileFROM python:3.10.8-slim-buster WORKDIR /backend COPY ./requirements.txt requirements.txt RUN apt-get update && apt-get clean && apt-get install -y libpq-dev gcc git RUN pip install --upgrade pip && pip install -r requirements.txt COPY . /backendPython のイメージから必要なものを入れているだけ
-
main.pymain.pyfrom dotenv import load_dotenv from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from starlette.middleware.cors import CORSMiddleware import os import uvicorn app = FastAPI() load_dotenv() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/healthcheck") def read_root(): return {"status": "ok"} # 環境切り分け if os.environ["ENV"] != "dev": app.mount("/", StaticFiles(directory="vue/dist", html=True), name="html") if __name__ == "__main__": uvicorn.run( app="main:app", host="0.0.0.0", reload=True, port=8080, log_level="debug", )-
main.pyを動かすことでuvicornを実行している -
vue/distディレクトリに、本番用の静的ファイルを入れているので、実行環境がdevでなければそちらを読むように切り分けている
-
-
requirements.txtrequirements.txtfastapi==0.95.0 python-dotenv==1.0.0 uvicorn==0.21.1必要なパッケージを必要なだけ入れる
フロントエンド
Vue3 で UI をなんとかしているが Vuetify 3 を使いたかったのでちょっと構成が違う
Vuetify 3 の公式にしたがっていれば OK
-
コンテナ
dev.dockerfileFROM node:19-alpine3.16 WORKDIR /frontend/app COPY app /frontend/app RUN yarn installnode のイメージから必要なものを入れているだけ
-
Vue のプロジェクトの作成
以下の手順で進めていく-
公式にしたがって Vuetify 3 の環境をつくる
$ yarn create vuetify -
ホストから見れるようにコンフィグファイルをちょっといじる
以下をvite.config.jsに追記するvite.config.jsserver: { host: true, port: 3000, }要は
host: trueが大切ってコト -
API を叩く先を FastAPI にしてあげる
以下の内容でapp/src/plugins/axios.jsを作成するindex.jsexport let axios; export default { install(app) { // base url app.config.globalProperties.$http.defaults.baseURL = // 本番環境は、ここが本番環境の URL になっていれば OK "http://localhost:8080"; // request interceptor app.config.globalProperties.$http.interceptors.request.use((config) => { config.headers.Accept = "application/json"; return config; }); // response interceptor app.config.globalProperties.$http.interceptors.response.use( (response) => { return response; }, function (error) { return Promise.reject(error); } ); axios = app.config.globalProperties.$http; }, get(url) { return axios.get(url); }, post(url) { return axios.post(url); }, };
-
Web サーバー
nginx で開発用 Web サーバーを立てる
なくてもなんとかなるが、ホットリロードが効かないなど、あまりうれしくない
-
コンテナ
dev.dockerfileFROM nginx:1.23 RUN apt-get update && \ apt-get install -y vim lessnginx のイメージから必要なものを入れているだけ
-
ポートの設定
nginx.confworker_processes auto; events { worker_connections 512; multi_accept on; } http { include /etc/nginx/conf.d/server.conf; # 設定ファイルの棲み分け server_tokens off; send_timeout 60; # mimetype include /etc/nginx/mime.types; default_type application/octet-stream; }conf.d/server.confserver { listen 8000; location / { root /www/dist; index index.html; } }8000番で受ける
コンテナ設定
docker-compose.yml でこれまでのあれやこれやを立ち上げ、接続する
version: "3"
services:
fastapi:
build:
context: ./backend
dockerfile: dev.dockerfile
environment:
ENV: dev
volumes:
- ./backend:/backend
tty: true
command: python app/main.py
ports:
- 8080:8080
restart: on-failure
networks:
- dev
vue:
build:
context: ./frontend
dockerfile: dev.dockerfile
volumes:
- ./frontend:/frontend
tty: true
command: yarn dev
ports:
- 3000:3000
depends_on:
- fastapi
- postgres
- nginx
restart: on-failure
nginx:
build:
context: ./nginx
dockerfile: dev.dockerfile
ports:
- 8000:8000
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/log:/var/log/nginx
- ./frontend/app/dist:/www/dist
tty: true
restart: on-failure
postgres:
image: postgres:15
container_name: postgres
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: postgres
ports:
- 5432:5432
volumes:
- postgres:/var/lib/postgresql/data
- ./initdb:/docker-entrypoint-initdb.d
networks:
- dev
depends_on:
- fastapi
volumes:
django:
vue:
nginx:
postgres:
networks:
dev:
driver: bridge
- キーポイント
- それぞれのサービスのポートをホストで受けられるようにする
-
volumesでホスト側とファイルを共有する -
depends_onで、他のサービスの処理を待つ - 特にバックエンドと DB は
networksで橋渡しをして、接続できるようにする