1
1

More than 1 year has passed since last update.

Docker環境のFlaskとVueをHerokuにデプロイする【備忘録】

Posted at

ディレクトリ構成

ディレクトリ構成
.
├─ dist
|  └─ static
│  └─ index.html
└─ frontend
|  └─ node_modules
| └─ src
|  └─ package.json
|  └─ Dockerfile
|  └─ etc...
└─ app.py
└─ docker-compose.yml
└─ Dockerfile
└─ requirements.txt
└─ .gitignore

Docker環境を整える

docker-composeとDockerfileをルートディレクトリに作成。

bash
$ git init
$ touch {docker-compose.yml,Dockerfile}
docker-compose.yml
version: "3"
services:
  frontend:
    container_name: frontend
    build:
      context: .
      dockerfile: ./frontend/Dockerfile
    volumes:
      - ./:/app
    ports:
      - "8080:8080"
    tty: true
    stdin_open: true

  backend:
    container_name: backend
    build:
      context: .
      dockerfile: ./Dockerfile
    volumes:
      - ./:/app
    ports:
      - "5000:5000"
    stdin_open: true
    tty: true
Dockerfile
FROM python:3.8

WORKDIR /app

COPY . .

RUN pip3 install flask

EXPOSE 5000

CMD python app.py

ここで起動コマンドCMD python app.pyを記述していないとHerokuにデプロイした時にエラーになる

バックエンド準備

ルートディレクトリにPythonファイルを作成して、以下のように記述。
render_templateはVueのnpm run buildで書き出されたものを相対パスで指定する。

app.py
from flask import Flask, render_template
import os

app = Flask(__name__, static_folder='dist/static', template_folder='dist')

# ルートの設定
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def index(path):
    return render_template("index.html")

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port, debug=True)

フロントエンド準備

frontendフォルダにDockerfileを作成
VueCLIをインストールしておく

Dockerfile
FROM node:lts-alpine

WORKDIR /app

RUN npm install -g @vue/cli && \
    npm install -g @vue/cli-init

ENV HOST 0.0.0.0

コンテナを起動

bash
$ docker-compose up -d --build

nodeコンテナに入る。

bash
$ docker-compose exec frontend sh

nodeコンテナに入ったらVueCLIをたたく。
マニュアルを選択してvue-routerをインストールして必要な環境は適時導入しておく

frontend/sh
$ vue create frontend

Vue CLI v4.5.13
? Please pick a preset:
  Default ([Vue 2] babel, eslint)
  Default (Vue 3) ([Vue 3] babel, eslint)
❯ Manually select features
frontend/sh
Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project:
 ◉ Choose Vue version
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
❯◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◯ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

vueフォルダが生成されるので中身をすべてfrontendの中に移す。

ディレクトリ構成
└─ frontend
   └─ vue
   |  ├─ node_modules
  |  ├─ src
   |  ├─ package.json
   |  └─ etc...
   └─ Dockerfile

   ||
   \/

└─ frontend
   ├─ node_modules
  ├─ src
   ├─ package.json
   ├─ Dockerfile
   └─ etc...

vue.config.jsを作成

staticフォルダが生成されるようにする。

frontend/sh
$ touch vue.config.js
vue.config.js
module.exports = {
  assetsDir: "static",
};

package.jsonを編集

package.json
"scripts": {
    "serve": "vue-cli-service serve",
-    "build": "vue-cli-service build",
+    "build": "vue-cli-service build --dest ../dist",
  },

.gitignoreを編集

今回はDockerコンテナをHerokuにPushするので必要ないが、Gitでデプロイする場合を考慮して一応.gitignoreから/distを除外しておく。

.gitignore
.DS_Store
node_modules
- /dist

# local env files
.env.local
.env.*.local

faviconをstaticに移動

ディレクトリ構成
frontend
└─ public
   ├─ favicon.ico
   └─ index.html

   ||
   \/

frontend
└─ public
   ├─ static
   |   └─ favicon.ico
   └─ index.html

ローカルで確認してみる

frontend/sh
$ cd frontend
$ npm run serve

localhost:8080をブラウザで開いてVueの初期画面が出れば成功

screenshot-tranquil-forest-19074.herokuapp.com-2021.09.19-18_42_59.png

ルートディレクトリにdistを作成

frontend/sh
$ cd frontend
$ npm run build
ディレクトリ構成
.
├─ dist              // 生成
├─ frontend
├─ app.py
├─ docker-compose.yml
├─ Dockerfile
├─ requirements.txt
└─ .gitignore

requirements.txtの書き出し

requirements.txtを作成していないとHerokuでstackを読み込んでくれなかったためルートディレクトリに書き出しておく

コンテナに入る

bash
$ docker-compose exec backend bash 

入ったら下記を実行

backend/bash
pip freeze > requirements.txt

Herokuにデプロイ

CLIを使ってHerokuにログインする

bash
$ heroku login

アプリをHeroku上に作成

bash
$ heroku create

Gitでもデプロイすることができるが今回はDockerでデプロイする

bash
$ heroku container:login

コンテナをHerokuにプッシュ

bash
$ heroku container:push web

アプリをデプロイ

bash
$ heroku container:release web

ハマったところ

次スタックしないための備忘録

Dockerコンテナのアクセス権限

Docker-composeでVolumeをルートにせずにディレクトリ指定しているとバックエンドからアクセスできなかった。

変更前
    volumes:
      - frontend:/app
変更後
    volumes:
      - ./:/app

ディレクトリ構成

Herokuにデプロイの関係上Dockerfileはルートディレクトリに置いておかないとうまくプッシュできなかった。
当初はディレクトリ構成をフロントとバックエンドで分けていたがバックエンドのファイル群をルートに移すことで解決した。

変更前
.
├─ dist
├─ frontend
├─ backend
└─ docker-compose.yml
変更後
.
├─ dist
├─ frontend
├─ app.py
├─ docker-compose.yml
├─ Dockerfile
├─ requirements.txt
└─ .gitignore

Vue構築時の注意

自分の環境だとvue init webpack アプリ名でVueを構築するとHrokuにデプロイした時にindex.htmlが見つからないエラーがでた。

log
jinja2.exceptions.TemplateNotFound: index.html

試行錯誤の末vue create アプリ名でVueプロジェクトを作成するとうまくいった。

起動コマンド

Herokuにデプロイするときは起動コマンドを記述してあげる必要がある。
色々ありそうだが今回はbackendのDockerfileにCMDで記述した。

Dockerfile
FROM python:3.8

WORKDIR /app

COPY . .

RUN pip3 install flask

EXPOSE 5000

CMD python app.py

番外編

Gitでデプロイする場合はrequirements.txtがルートディレクトリにないとHerokuが何の言語を使っているのか判断できない。
さらに.gitignoreからdistを削除しておかないとdistを読み込んでくれないためindex.htmlを参照しない。

1
1
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
1
1