趣味で作っている 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 8080
FastAPI ならこんな感じ……らしいが、うまくいかなかった
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.toml
docker-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 . /backend
Python のイメージから必要なものを入れているだけ
-
main.py
main.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.txt
requirements.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 install
node のイメージから必要なものを入れているだけ
-
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 less
nginx のイメージから必要なものを入れているだけ
-
ポートの設定
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
で橋渡しをして、接続できるようにする