Dockerで個人用のWebアプリを作る(備忘録)
概要
Dockerの仮想環境を使ってWebアプリを作成する。
方針: 自分用の備忘録用。今までの行いを見直して、何をしてたか思い出す用なので見た目とか気にしない。
利用する技術
- python
- Docker
- Flask
登場するマシン
- ローカルマシン → 自分のPC
- リモートマシン → gcpのVMインスタンス(ここではgcpのlinux環境を利用。無料枠がまだあったのと、リモートサーバーの仮想マシンという体で動かす。)
必要だった知識
- dockerの利用方法(コマンド・言葉の意味など)
- ポ-ト番号などの通信面の知識
- ssh接続
- html(必要あればcss,java scriptなどの知識)
手順(概要)
- リモートサーバーの作成
- ローカルPCとリモートサーバーのssh接続設定
- リモートサーバーにDockerファイルと関連するファイルを作成・アップロード
- リモートサーバー上で仮想環境構築+webアプリ起動
- ローカルPCでsshトンネル接続を行う
- 完成!
リモートサーバーの作成
まずGCPにアクセスしてCompute Engineにアクセス
VMインスタンスに移動し、「インスタンスを作成」で好きなサーバーを作成する。
自分の場合は、無料体験で使用できる金額を消費したかったので、ちょっと豪華にした。
インスタンスを作成ボタン
(https://storage.googleapis.com/zenn-user-upload/4676c58ab651-20240613.png)」
VM作成画面
ここではコア数4・RAM32GBのリモートマシンを作成(コア数4・32GBのRAMだけでも常時稼働するだけで月額約15000円になる。実験だったり個人で使う分には少し高い...)
作成出来たらしばらく待つと起動するので、SSHボタンからアクセスする。すると以下の画面が出てくる。
SSHボタン
認証画面
コマンド画面
初期ではdockerはインストールされていないので以下のコマンドでdockerをインストール。
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker compose-plugin
sudo docker
などで、dockerが問題なくインストールされているかを確認する。
ローカルPCとリモートサーバーのssh接続設定
ssh-keygen
で公開鍵・秘密鍵を作成
ssh接続を行うために、リモートサーバーに公開鍵を送付する必要がある。方法は以下の2通り。
- GCPのブラウザ上で作成したサーバを選択し「編集」ボタンを押下→SSH認証鍵の「項目を追加」で作成した公開鍵のテキストを追加する。
- gcpのサーバーに接続し、ユーザーとディレクトリと.sshファイルを作成する方法。
2.は別途メモを作成する。
ユーザー一覧のディレクトリに移動し、そこにssh接続用のユーザーのディレクトリを作成。そこに.sshファイルを作成して、そこにアップロードした公開鍵を移動する。
移動したらローカルPC上で、ssh -i 秘密鍵のパス 外部 IP
を入力
リモートサーバーにDockerファイルと関連するファイルを作成・アップロード
ファイルのアップロード
gcpの「ファイルのアップロード」を使う方法とscpによるデータの送付方法の二つがある。
scp -i 秘密鍵のパス -r "アップロードしたいディレクトリのパス" アップロード先のサーバー:アップロード先のサーバーのパス
アップロードするファイルは以下の2つ
Dockerファイルの設定
既存のイメージをプルしてもよいが、今回は勉強も兼ねて自作してみる。
Dockerファイルは以下のものを使用。python3.9の環境でflaskを動かすことを想定する。
FROM python:3.9
WORKDIR /app
ADD . /app
RUN pip install Flask
EXPOSE 3000
CMD ["python", "sample_app.py"]
flaskのコード
from flask import Flask
# 簡単なwebappの作成
app = Flask(__name__)
@app.route("/", methods=['GET'])
def root():
return "index"
if __name__ == "__main__":
# This is used when running locally only. When deploying to Google App
# Engine, a webserver process such as Gunicorn will serve the app. This
# can be configured by adding an `entrypoint` to app.yaml.
# Flask's development server will automatically serve static files in
# the "static" directory. See:
# http://flask.pocoo.org/docs/1.0/quickstart/#static-files. Once deployed,
# App Engine itself will serve those files as configured in app.yaml.
app.run(host="0.0.0.0", port=3000, debug=True)
flaskも備忘録として書こうとしたが、仮想環境で色々できることを目標にしたので、flaskの解説はせずにとりあえずindexを表示させるだけのコードを作成
ポート番号
ポート番号とは、インターネットや他のマシンに接続する際に使用する番号である。16bitで管理されており、65536通りの番号が用意されている。
何故番号が必要かというと、データを送付する時に、どこにデータを送付するかを決める必要があるため。
ポート番号は郵便によく例えられる。ハガキを出すときに「どこの差出」か「どこで受け取る」かを定義しないとハガキは送れない。差出人は不明でもハガキは送れるが、「どこ」に送るかを指示しない限り送ることは出来ない。
ただ、普通にPCを使っていると、「どこに接続すれば良いか」を聞かれても、「目的のマシン」に接続できれば良いので、「ポート番号なんてなくとも一つでも十分ではないのか?」とも思ってしまう。(現に自分はそう思っていた。)
しかしコンピュータ内では60000以上の番号からどのように通信をやり取りしているのかを確認する必要があり、ポート番号がないと、どこにデータを送れば良いかわからなくなる。これはコンピューターのルールだと思った方が良い。
例えばdockerでポート番号を設定する場合以下のような記載をする。(想定としてローカルマシンからリモートマシンを接続する想定とする)
port: 3000:8000
上記の記載と例の場合、ローカルマシン3000番ポートからリモートマシンの8000番ポートにデータを送付している。
この場合、通信の差出はローカルマシンの3000番から送信され、リモートの受信は8000番となる。
仮想環境の構築
今までは言われるがままにコマンドを打っていたが、自分で考えてコマンドを打って勉強しようと決意。
そもそもまずイメージとコンテナの違いが判らなかったり、キャッシュの意味が解らなかったのでそこからの勉強となった。基礎を書くと長々となるので、ここではどのようにコマンドを打てば仮想環境を構築できるのかを記載する。
詳細な内容についてはスクラップにまとめる予定。
仮想環境の構築方法
- dockerイメージの構築を行う
docker build Dockerfileが存在するパス
- dockerイメージが作成できているかどうかを確認
docker images
- イメージが作成できていれば以下のコマンドを実行。
docker run イメージ名 -p 10000:3000
- コンテナが問題なく作成できているかを以下のコマンドで確認※
docker ps
- コンテナが存在していればwebアプリは構築できている。
curl localhost:10000
などで接続を確認する。問題なければIndexが出力される。
docker rm コンテナID
docker rmi イメージID
docker build Dockerfileのあるパス --no-cache
Tips: docker-composeを使う
基本的にdockerはdocker build
→docker run
でイメージとコンテナを構築できるが、いちいち2つのコマンドを連続で実行するのも面倒な時がある。またdocker run
でコンテナを実行する時には、様々なオプションがつく時があるが、それをコマンド上で長々と書くのは面倒。
この場合docker dompose
を使うとイメージの構築からコンテナの作成まで一貫して実行してくれる。
イメージとコンテナを作成して、バックグランドで実行するコマンド(キャッシュを無視して実行できない)
docker compose up -d
キャッシュを無視する場合は、イメージの構築とコンテナの構築を分ける必要がある。
docker compose build --no-chace
→docker compose up- d
ローカルマシンから接続
以下の流れで接続する
- コマンドプロンプトの
ssh-keygen
でsshキーをローカルマシンで作成 - リモートサーバーにsshの公開鍵をアップロードしsshファイルに保存
- ローカルマシンから
ssh -i 秘密鍵 リモートサーバーのアドレス
でssh接続 - 接続を確認したら、一度切断
- sshでトンネル接続を行う。
ssh -i 秘密鍵のパス -L ローカルマシンのポート番号:0.0.0.0:3000
- ローカルのブラウザで、
localhost:ローカルマシンのポート番号
を入力 - Indexの文字が載ったWebページが返ってくると成功!
Next Action
- 安いミニPCをサーバ仕様にして同じことをやってみよう
gcpやawsは便利だしで業務のスキルアップにもなるが、従量課金がどうしても気になるので安心して使えない。
ミニPCなら20000円くらいで買えるものもあるので、それなら買い切りなので安心。
試しに計算してみる。
GCP
- CPU: N100(コア数4, RAM16GBと想定)
- RAM: 16GB
- ストレージ(SSD): 1TB
→1か月255.51ドル(約38000円)
当然gcpは動作の保証やスケールアップにも対応しているので、そのサービスを加味すると何とも言えないが、自宅で遊ぶようならミニPCを使った方が圧倒的に安い。
もしかして古いノートパソコンを使うこともできるかも?
Discussion