3
0

More than 1 year has passed since last update.

fly.io にデプロイする Web アプリを開発するためのメモ

Last updated at Posted at 2023-04-09

趣味で作っている Web アプリの開発中に得られたいろいろをメモ
あとで整理するかもしれないし、しないかもしれない

fly.io

コマンドいろいろ

デプロイ手順

  • ローンチ
    デプロイのために設定ファイル (fly.toml) を作成する

    $ fly launch
    

    ここでアプリ名や DB の設定を行う
    吐き出された fly.tomlDockerfile と同じ階層に入れておく

  • デプロイ

    $ fly deploy
    
  • Procfile
    Web アプリの実行コマンドを記述する

    Procfile
    web: uvicorn main:app --host 0.0.0.0 --port 8080
    

    FastAPI ならこんな感じ……らしいが、うまくいかなかった
    Dockerfile に直接実行コマンドを書いたら起動できた

    Dockerfile
    CMD 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.dockerfile
    FROM 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.py
    from 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.txt
    fastapi==0.95.0
    python-dotenv==1.0.0
    uvicorn==0.21.1
    

    必要なパッケージを必要なだけ入れる

フロントエンド

Vue3 で UI をなんとかしているが Vuetify 3 を使いたかったのでちょっと構成が違う
Vuetify 3 の公式にしたがっていれば OK

  • コンテナ

    dev.dockerfile
    FROM node:19-alpine3.16
    WORKDIR /frontend/app
    
    COPY app /frontend/app
    RUN yarn install 
    

    node のイメージから必要なものを入れているだけ

  • Vue のプロジェクトの作成
    以下の手順で進めていく

    1. 公式にしたがって Vuetify 3 の環境をつくる

      $ yarn create vuetify
      
    2. ホストから見れるようにコンフィグファイルをちょっといじる
      以下を vite.config.js に追記する

      vite.config.js
         server: {
             host: true,
             port: 3000,
         }
      

      要は host: true が大切ってコト

    3. API を叩く先を FastAPI にしてあげる
      以下の内容で app/src/plugins/axios.js を作成する

      index.js
      export 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.dockerfile
    FROM nginx:1.23
    
    RUN apt-get update && \
    apt-get install -y vim less
    

    nginx のイメージから必要なものを入れているだけ

  • ポートの設定

    nginx.conf
    worker_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.conf
    server {
        listen 8000;
        location / {    
            root /www/dist;
            index index.html;
        }
    }
    

    8000 番で受ける

コンテナ設定

docker-compose.yml でこれまでのあれやこれやを立ち上げ、接続する

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 で橋渡しをして、接続できるようにする
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0