Python

VPSを使ってウェブアプリを作りたい2(Github ActionsでCI/CD)

はじめに

前回→VPSを使ってウェブアプリを作りたい1

githubを使って開発する流れを考える。
エディタはVScodeかCursorか。

少し触ってみた感想としては、
VScode+chatGPTは、初心者向け。聴きながら少しずつ学習できるが、チャットが長くなるとファイル間の整合性が取れなくなってくる。

Cursorは、中級者以上向け。ファイル全体を見て自動でコードを作成してくれるが、エラーが出ても知識がないと修正できない。

今回はVScodeでやってみる。

※githubアカウント作成とVScodeをインストールした前提です。

VScodeの設定

VScodeのプラグインを入れる

  • Python:Lint/補完
  • Remote — SSH:VPS 上のコードを直接編集する

Remote-SSHで接続する

  • ターミナルで設定ファイルを作成
    nano ~/.ssh/config
  • ファイルの中身
    Host my-vps # わかりやすい名前をつける
    HostName 123.45.67.890 # VPSのIP
    User youruser # ログインユーザー名
    Port 2222 # 実際のポート番号
    IdentityFile ~/.ssh/key.pem # 鍵がある場合は鍵の場所
  • コマンドパレット(Ctrl+Shift+P / Cmd+Shift+P)で
    Remote-SSH: Connect to Host…を選択
    my-vps(上でつけた名前)を選択

これで、VPS上のファイルをVScodeで編集できる。

もし出てこない場合

  • コマンドパレットで
    Remote-SSH: Add New SSH Host…を選択
    「Select SSH configuration file to update」で ~/.ssh/config を選び、接続コマンド欄に
  • ssh youruser@123.45.67.890 -p 2222 -i ~/.ssh/key.pem
  • と入力、保存すると候補に現れる。

githubでリポジトリを作る

  • githubで新しいリポジトリmyappを作る(private)
  • https://github.com/username/myapp.gitのようなパスをコピー

新しく GitHub 用の鍵を作る

  1. VPS上で鍵ペアを生成
    ssh-keygen -t ed25519 -C "your_email@example.com"# これで ~/.ssh/id_ed25519(秘密鍵) と id_ed25519.pub(公開鍵) ができる
    # パスフレーズを指定する場合はあとで使う。

  2. 公開鍵を GitHub に登録
    cat ~/.ssh/id_ed25519.pub # 中身をコピー
    GitHub の Settings → SSH and GPG keys → New SSH key に貼り付け。

  3. SSH-Agent or ~/.ssh/config で秘密鍵を指定
    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/id_ed25519
    # 上で指定したぱすフレーズを使う

    # または ~/.ssh/config に
    Host github.com
    User git
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

これで ssh -T git@github.com が成功し、git push/git pull が通る。

ターミナルで以下を実行(ユーザーログインしてから)
# プロジェクトディレクトリに移動
cd ~/myapp

# Git リポジトリの初期化
git init

# main ブランチに名称を合わせる(Git のデフォルトが master の場合)
git branch -m main

# GitHub リモートを登録
git remote add origin https://github.com/username/myapp.git # コピーしたパス
# git remote add origin git@github.com:username/myapp.git # SSH鍵をgithubに登録済みならこっちでも可

# 5. 追跡させたいファイルをすべてステージに載せる
git add .

# 6. 初回コミットを作成
git commit -m "Initial commit"

# 7. GitHub へプッシュ(-u で upstream 登録)
git push -u origin main

これで VPS の ~/myapp がまるごと GitHub で管理できる。
以降は
ファイルを編集 → git add/commitgit push
でコードを同期できる。

originに登録するURLをhttpsからSSHに変更したい場合。

1. 現在の origin URL を確認
cd ~/myapp
git remote -v

出力例:
origin https://github.com/username/myapp.git (fetch)
origin https://github.com/username/myapp.git (push)


2. SSH URL に変更する
git remote set-url origin git@github.com:username/myapp.git

再度 git remote -v を実行して、
origin git@github.com:username/myapp.git (fetch)
origin git@github.com:username/myapp.git (push)

になっていれば OK 。


3. 動作確認
git push -u origin main
  • プロンプトが出ずに push が通れば SSH キー認証が正しく働いている。
  • エラーが出る場合は ssh -T git@github.com で鍵認証をテストし、GitHub に VPS 公開鍵が登録されているか確認。

Github actionsで自動テスト・デプロイの設定

ローカルで SSH キーを作成(Deploy Key)

# ローカル(自分のパソコン)のターミナルで
cd ~/.ssh
ssh-keygen -t ed25519 -f deploy_key -C "github-deploy" -N ""
  • -f deploy_key:鍵ファイル名(~/.ssh/deploy_key と deploy_key.pub が作られる)
  • -N "":パスフレーズなし

GitHub に公開鍵を登録

  1. cat ~/.ssh/deploy_key.pub で公開鍵の中身を表示し、クリップボードにコピー
  2. GitHub の開発中のリポジトリ → Settings → Deploy keys → Add deploy key
  • Title:VPS Deploy Key など
  • Key:公開鍵の中身
  • Allow write access:チェックを入れる(プッシュにも使いたい場合)

3. GitHub Actions 用シークレットを設定

GitHub 上で Settings → Secrets and variables → Actions に移動し、以下を追加します。

Name Value 説明
DEPLOY_KEY deploy_key(秘密鍵) の中身全体) プライベート鍵。文字列全部を貼り付け
KNOWN_HOSTS ssh-keyscan -p 2222 YOUR_VPS_IP の出力結果 GitHub→VPS のホスト鍵検証用(StrictHostKeyChecking)
# 例: ローカルで known_hosts 用の文字列を取得
ssh-keyscan -p 2222 your.vps.ip.address

ワークフロー定義(.github/workflows/deploy.yml

リポジトリのルートにファイル(.github/workflows/deploy.yml)を作成。
必要なテストやデプロイの工程を記述。

mkdir -p .github/workflows # ワークフローディレクトリを作成
ls -R .github # 作成できたかどうかチェック
sudo nano .github/workflows/deploy.yml # ファイルを作り以下を入力

name: CI / CD to VPS

on:
  push:
    branches: [ main ] # mainブランチでpushされた時に実行される。

jobs: # 実行される内容
  build: # 構築
    name: Test & Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Set up Python # pythonのセットアップ
        uses: actions/setup-python@v4
        with:
          python-version: '3.x'
          cache: 'pip'

      - name: Install dependencies # 依存環境のインストール
        run: |
          pip install --upgrade pip
          pip install -r requirements.txt
          pip install pytest

      - name: Run tests # テストを実行
        run: |
          # リポジトリルートをモジュール検索パスに追加
          export PYTHONPATH="${{ github.workspace }}"
          # pytest をモジュール呼び出しで確実に実行
          python -m pytest
         

  deploy: # 本番環境に展開
    name: Deploy to VPS
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Prepare SSH # SSH接続するための鍵とホストを取得
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key
          echo "${{ secrets.KNOWN_HOSTS }}" > ~/.ssh/known_hosts
          chmod 600 ~/.ssh/known_hosts

      - name: Deploy via SSH # 取得したデプロイ用の鍵を使ってユーザーログインし、反映と再起動
        run: |
          ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=yes -p 2222 youruser@YOUR_VPS_IP << 'EOF'
            cd ~/myapp
            git pull origin main
            source venv/bin/activate
            pip install -r requirements.txt
            sudo systemctl restart myapp.service
          EOF
  • on.push.branchesmain にプッシュされたときだけ動く
  • build: テスト・リンティング
  • deploy:  VPS に SSH 接続し、最新コードを pull → 再起動

開発ブランチ(develop)で CI(テストだけ)を回したい場合

普段の開発はdevelopブランチで行い、完成したらmainブランチにマージするような運用の場合は、開発(develop)ブランチと本番(main)ブランチでテストを分ける。

テスト用ワークフローファイル(.github/workflows/ci.yml)を作成
sudo nano .github/workflows/ci.yml # ファイルを作成して以下を入力

name: CI
# developブランチにpushした時に起動する
on:
  push:
    branches: [ develop ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.x'
          cache: 'pip'

      - name: Install dependencies
        run: |
          pip install --upgrade pip
          pip install -r requirements.txt
          pip install pytest

      - name: Add project root to PYTHONPATH
        run: echo "PYTHONPATH=${{ github.workspace }}" >> $GITHUB_ENV

      - name: Run tests
        run: pytest

 

requirements.txt を作成する

開発マシン(あるいは Remote-SSH 接続している VPS)で、プロジェクトの仮想環境を有効化したうえで依存パッケージ一覧ファイルを作る。
cd ~/myapp # プロジェクトのルートディレクトリ
source venv/bin/activate
pip freeze > requirements.txt

pip freezeで現在インストールされているパッケージとバージョンがすべて requirements.txt に書き出せる。

デプロイ用鍵の公開鍵を VPS に登録する

  • Actionsでデプロイする場合、デプロイ用の鍵が必要。GitHub リポジトリの「Deploy keys」に公開鍵 (deploy_key.pub) の中身を登録
    GitHub Actions の「Secrets」に秘密鍵 (deploy_key) の中身を DEPLOY_KEY として登録
  • VPS の~/.ssh/authorized_keys に公開鍵(deploy_key.pub)を追記
    VPSのターミナルで、
    mkdir -p ~/.ssh
    echo "公開鍵の中身" >> ~/.ssh/authorized_keys

    chmod 700 ~/.ssh
    chmod 600 ~/.ssh/authorized_keys
  • # 鍵の中身の確認方法
    cat ~/.ssh/deploy_key.pub # 公開鍵
    cat ~/.ssh/deploy_key # 秘密鍵

デプロイでエラーが出る場合

sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
sudo: パスワードが必要です

上記のようなエラーが出る時は、
CI/CD で SSH ログインして実行しているコマンド内で sudo systemctl restart … を使うためのパスワードを要求されている状態。

解決法:特定のコマンドのみパスワードを不要にする
  • which systemctl でsystemctlのパスを確認。
    表示例)/bin/systemctl
  • visudo コマンドで新しい sudoers ファイルを作成

    sudo visudo -f /etc/sudoers.d/deploy

     

  • 以下の一行を追加(username はログインユーザーに置き換え)
    username ALL=(root) NOPASSWD: /bin/systemctl restart myapp.service
  • ファイルのパーミッションを確認
    sudo chmod 440 /etc/sudoers.d/deploy

これで、sudo systemctl restart testapp.service のときだけパスワードなしで実行できる。

動作確認

  1. GitHub にコミット&push
  2. Actions タブでジョブが走るのを待つ
  3. 成功ログが出れば、自動で VPS にデプロイされる

Actionsでの自動デプロイが確認できたら、開発用のdevelopブランチを作って流れを確認。

開発用ブランチを作って、開発の一連の流れを確認

  1. ローカルにリポジトリ(mainブランチ)をクローンして、開発用developブランチを作る
  2. ローカルのdevelopブランチで開発
  3. developにcommit & push して ActionsのCIテストワークフローが起動
  4. 問題なければPull Request で developmain をマージする
  5. mainにcommitされると、ActionsのCI/CDワークフローが起動
  6. 自動的にデプロイ(本番環境が更新)される

ローカルにリポジトリをクローン

開発はローカル(PC)で行うので、githubからアプリのリポジトリをクローン(コピー)する。

# クローンをつくるディレクトリに移動
cd ~/desktop

# リポジトリをクローン
git clone git@github.com:user/myapp.git

# アプリのディレクトリに移動
cd myapp

Python の仮想環境を作成
※システムに python3 コマンドがある前提。

python3 -m venv venv

# もしくは
# /usr/bin/python3 -m venv venv

 

仮想環境を有効化

source venv/bin/activate

 

pip を最新化

pip install --upgrade pip

requirements.txt から依存をインストール

pip install -r requirements.txt

動作確認

flask run --host=127.0.0.1 --port=5000
# または
python app.py

ブラウザで http://localhost:5000 にアクセスして動けば OK!

リモートに develop ブランチを作る

# main から派生して develop を作成して切り替え
git checkout -b develop     

# リモートにも develop をプッシュ&追跡設定(upstream)
git push -u origin develop

開発作業はdevelopブランチで行う。
pushする時は以下のようにする

git add . # 変更を追加する
git commit -m "メッセージ" # メッセージを入れてコミット
git push origin develop # 開発ブランチにpushする

pushすると、GithubActionsのCIワークフローが起動し、テストが開始する。

GitHubでの Pull Request

  • “Compare & pull request” ボタンを押す
    developブランチをpushするとリポジトリの上部に“Compare & pull request” ボタンが出るので押す。
    もし出ていなければ、上部の “Pull requests” タブをクリック → “New pull request”
  • ベースと比較対象を設定
    base: main(取り込み先)
    compare: develop(変更元)
  • タイトル&説明を入力
    Title: 「機能追加:~」など短く明快に
    Write:  何を/なぜ変更したのか。テストが通っていること、動作確認済みのこと
  • レビュワー、ラベル、プロジェクトを設定(任意)
    自分一人のプロジェクトなら省略可
  • Create pull request をクリック
  • CI(テスト)結果を確認
    PR ページの下部に、Actions が走った結果(success/failure)が出る
    失敗しているテストがあればコードを修正 → コミット → 再度 push
  • CI がすべて green になったら、 “Merge pull request” ボタンを押す
    ダイアログで “Confirm merge” を押せば、main ブランチに develop の変更が取り込まれる。

ActionsのCI/CDが起動 → 本番環境が更新

  • CI/CDワークフローが起動して、変更が反映されて本番環境が再起動する
  • (任意)develop ブランチの削除
    マージ完了時に「Delete branch」ボタンが表示されるので、不要ならクリックして削除。
    削除後に必要になれば、また git checkout -b develop main で作り直す。
    今後も使うので消さない方がいいかも。

以降は、developブランチで開発を進め、pushするとActionsでCIワークフローのみ起動する。
開発が進み本番環境に反映させたい時は、プルリクエストでmainブランチにマージすることでActionsでCI/CD to VPSワークフローが起動し、本番環境にデプロイされる。

ABOUT ME
いなさく
住んでる家が崩れそうなので、建て替え費用をまかなうために 副業をがんばるサラリーマン
ブログランキング・にほんブログ村へ

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA