ソフトウェア開発の速い世界では、高品質のアプリケーションを迅速かつ信頼性をもって提供することが重要です。ここでCI/CD(継続的インテグレーションおよび継続的デリバリー/デプロイメント)が重要な役割を果たします。

CI/CDは、コード変更を統合し、テストし、本番環境に展開するプロセスを自動化し効率化するための一連のプラクティスとツールです。CI/CDを採用することで、チームは手動エラーを減らし、リリースサイクルを加速し、コードが常に展開可能な状態であることを確認できます。

このチュートリアルでは、Bitbucket、Linuxサーバー、およびPython with Flaskを使用して基本的なCI/CDパイプラインを設定する初心者向けのアプローチに焦点を当てます。具体的には、特定のブランチにプッシュまたはマージがあるときに、Bitbucketリポジトリから最新の変更をLinuxサーバーに自動的に取得するプロセスを作成します。

このプロセスは、Bitbucketウェブフックと、着信ウェブフックイベントをリッスンしデプロイメントをトリガーするシンプルなFlaskベースのPythonサーバーによって支えられます。

CI/CDは広範で複雑な分野であることに注意することが重要であり、このチュートリアルは包括的なガイドではなく、基礎的な理解を提供するよう設計されています。

初心者にアクセス可能なツールを使用してCI/CDパイプラインを設定する基本をカバーします。ただし、実際のCI/CDシステムは、コンテナ化、オーケストレーション、およびマルチステージのテスト環境など、より高度なツールや構成が関わることがあります。

このチュートリアルの最後までに、Bitbucket、Linux、およびPythonを使用してデプロイを自動化する方法の作業例を持つようになります。これは、CI/CDの概念により快適になるにつれて構築できます。

目次:

  1. CI/CDの重要性

  2. ステップ1: BitbucketでWebhookを設定する

  3. ステップ2: Linuxサーバー上でFlaskリスナーを設定する

  4. ステップ3: Flaskアプリを公開する(オプション)

  5. ステップ4: セットアップをテストする

  6. ステップ5:セキュリティ考慮事項

  7. まとめ

CI/CDが重要な理由

CI/CDは、いくつかの理由から現代のソフトウェア開発の基盤となっています。まず、開発プロセスを加速させます。テストやデプロイなどの繰り返し作業を自動化することで、開発者はコードの記述に集中し、手作業のプロセスにあまり時間を費やす必要がありません。これにより、新機能やバグ修正の迅速な提供が可能となります。これは、スピードが差別化要因となる競争の激しい市場では特に重要です。

CI/CDのもう1つの重要な利点は、エラーの削減と信頼性の向上です。自動化されたテストにより、すべてのコード変更が主要なコードベースに統合される前に厳密にチェックされます。これにより、後で高コストな修正が必要になったり、アプリケーションの混乱を招く可能性のあるバグを導入するリスクが最小限に抑えられます。自動化された展開パイプラインも、リリースプロセス中の人為的ミスの可能性を軽減し、展開が一貫性があり予測可能であることを確保します。

CI/CDはチームメンバー間のより良い協力を促進します。従来の開発ワークフローでは、複数の開発者からのコード変更を統合することは時間がかかりエラーの発生しやすいプロセスです。CI/CDでは、コードが頻繁に統合およびテストされ、1日に何度も実行されます。これにより、競合が早期に検出および解決され、コードベースが安定した状態に保たれます。その結果、チームはより効率的に作業し、より多くの信頼を持って作業することができます。たとえ複数の貢献者がプロジェクトの異なる部分に取り組んでいる場合でもです。

最後に、CI/CDは継続的な改善と革新を支援します。展開プロセスを自動化することで、チームはより頻繁にアップデートを本番環境にリリースし、リスクを減らすことができます。これにより、ユーザーからのフィードバックをより速く収集し、製品を効果的に改善することができます。

このチュートリアルでは何をカバーするか

このチュートリアルでは、BitbucketリポジトリからLinuxサーバーにコード変更を自動デプロイするシンプルなCI/CDパイプラインの設定プロセスを解説します。以下で学ぶことは次のとおりです。

  1. 特定のブランチにプッシュまたはマージがあるたびにBitbucketリポジトリからウェブフック通知を送信する方法。

  2. Linuxサーバー上のFlaskベースのPythonサーバーを設定して、受信ウェブフックイベントをリッスンする方法。

  3. リポジトリから最新の変更を取得し、それをサーバーにデプロイするスクリプトの書き方。

  4. 自動デプロイメントプロセスをテストし、トラブルシューティングする方法。

このチュートリアルの終わりまでに、必要に応じてカスタマイズおよび拡張できる基本的なCI/CDパイプラインの動作例を持つことができます。それでは始めましょう!

ステップ1: BitbucketでWebhookを設定する

設定を始める前に、Webhookとは何か、そしてそれが私たちのCI/CDプロセスにどのように関わるのかを簡単に説明しましょう。

Webhookは、あるシステムが別のシステムにリアルタイムでイベントを通知することを可能にするメカニズムです。Bitbucketのコンテキストでは、Webhookは、リポジトリ内で特定のイベント(例えば、ブランチへのプッシュやプルリクエストのマージ)が発生するたびに、指定されたURLにHTTPリクエスト(通常はペイロードデータを含むPOSTリクエスト)を送信するように設定できます。

私たちの場合、Webhookは特定のブランチへのプッシュやマージが行われるたびに、FlaskベースのPythonサーバー(Linuxサーバー上で実行)に通知します。この通知は、サーバー上でリポジトリから最新の変更を取得し、自動的にデプロイするスクリプトをトリガーします。本質的に、WebhookはBitbucketとサーバーの間の橋渡しを行い、デプロイメントプロセスのシームレスな自動化を可能にします。

Webhookの役割を理解したので、Bitbucketで設定してみましょう:

  1. Bitbucketにログインし、リポジトリに移動します。

  2. 左側のサイドバーで、設定をクリックします。

  3. ワークフローセクションの下にある、Webhooksを見つけてクリックします。

  4. Webhookの追加ボタンをクリックします。

  5. Webhookの名前を入力します(例: “自動プル”)。

  6. URL欄に、Webhookがリクエストを送信するサーバーのURLを入力します。ローカルでFlaskアプリを実行している場合、http://your-server-ip/pull-repoのようなものになります(本番環境では、Bitbucketとサーバー間の通信を保護するためにHTTPSを使用することを強く推奨します)。

  7. トリガーセクションで、リッスンするイベントを選択してください。この例では、Pushを選択します(必要に応じて、マージ後にデプロイしたい場合はPull Request Mergedも選択します)。

  8. Webhookには説明的な名前を付けて保存し、後で簡単に識別できるようにしてください。

Webhookが設定されると、Bitbucketは選択したイベントが発生するたびに指定されたURLにPOSTリクエストを送信します。次の手順では、これらの受信リクエストを処理し、デプロイプロセスをトリガーするためのFlaskサーバーを設定します。

Bitbucket webhookを設定すると、以下の手順で何を見るべきかがわかります

ステップ2:LinuxサーバーにFlaskリスナーを設定します

次のステップでは、Linuxマシン上でシンプルなウェブサーバーを設定し、BitbucketからのWebhookを待機させます。通知を受信すると、リポジトリを更新するためにgit pullまたは(ローカルの変更がある場合は)force pullを実行します。

Flaskのインストール:

Flaskアプリケーションを作成するには、まず次のコマンドを実行してFlaskをインストールします:

pip install flask

Flaskアプリの作成:

サーバー上に新しいPythonスクリプト(例:app_repo_pull.py)を作成し、以下のコードを追加します:

from flask import Flask
import subprocess

app = Flask(__name__)

@app.route('/pull-repo', methods=['POST'])
def pull_repo():
    try:
        # リモートリポジトリから最新の変更を取得
        subprocess.run(["git", "-C", "/path/to/your/repository", "fetch"], check=True)
        # ローカルブランチをリモートの'test'ブランチに強制リセット
        subprocess.run(["git", "-C", "/path/to/your/repository", "reset", "--hard", "origin/test"], check=True)  # 'test'を使用して、ブランチ名を置換
        return "Force pull successful", 200
    except subprocess.CalledProcessError:
        return "Failed to force pull the repository", 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

このコードの機能は以下の通りです:

  • subprocess.run(["git", "-C", "/path/to/your/repository", "fetch"]): このコマンドは、ローカルの作業ディレクトリに影響を与えることなく、リモートリポジトリから最新の変更を取得します。

  • subprocess.run(["git", "-C", "/path/to/your/repository", "reset", "--hard", "origin/test"]): このコマンドはハードリセットを実行し、ローカルリポジトリをリモートのtestブランチに合わせます。 test をブランチの名前に置き換えてください。

実際のローカルGitリポジトリへのパスに/path/to/your/repositoryを置き換えてください。

ステップ3: Flaskアプリを公開する(オプション)

Flaskアプリをサーバーの外部からアクセス可能にしたい場合は、それを公開する必要があります。そのためには、NGINXを使用したリバースプロキシを設定することができます。以下がその方法です。

まず、次のコマンドを実行してNGINXをインストールします:

sudo apt-get install nginx

次に、NGINXを構成してリクエストをFlaskアプリにプロキシする必要があります。NGINXの設定ファイルを開いてください:

sudo nano /etc/nginx/sites-available/default

このブロックを含めるように構成を変更してください:

server {
    listen 80;
    server_name your-server-ip;

    location /pull-repo {
        proxy_pass http://localhost:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

変更を適用するためにNGINXをリロードしてください:

sudo systemctl reload nginx

ステップ4: セットアップのテスト

すべてが設定されたので、このPythonスクリプトを実行してFlaskアプリを起動してください:

python3 app_repo_pull.py

今、すべてが機能しているかテストします:

  1. コミットを作成:Bitbucketリポジトリのtestブランチにコミットをプッシュします。このアクションによりWebフックがトリガーされます。
  1. Webフックのトリガー:WebフックはPOSTリクエストをサーバーに送信します。Flaskアプリケーションはこのリクエストを受信し、testブランチから強制的にプルを実行し、ローカルリポジトリを更新します。

  2. プルの確認:Flaskアプリケーションのログ出力を確認するか、ローカルリポジトリを調査して、変更が正常にプルされ適用されたことを確認します。

ステップ5:セキュリティに関する考慮事項

Flaskアプリケーションをインターネットに公開する際は、サーバーとアプリケーションのセキュリティを確保し、不正アクセス、データ漏洩、攻撃から保護することが重要です。以下は焦点を当てるべき主要な領域です:

1. 適切なファイアウォールルールを備えたセキュアサーバーの使用

セキュアサーバーとは、外部の脅威への露出を最小限に抑えるように構成されたサーバーです。これにはファイアウォールルールの使用、不要なサービスの最小化、必要なポートのみを通信に開いていることなどが含まれます。

セキュアサーバーのセットアップ例:
  • 最小限のソフトウェア: 必要なソフトウェアのみをインストールする(例: Python、Flask、NGINX)不要なサービスを削除する。

  • オペレーティングシステムの更新: サーバーのオペレーティングシステムが最新のセキュリティパッチで更新されていることを確認する。

  • ファイアウォールの構成: ファイアウォールを使用して入出力トラフィックを制御し、サーバーへのアクセスを制限する。

例えば、Ubuntuでの基本的な<UFW(Uncomplicated Firewall)の構成は次のようになります:

# SSH(ポート22)をリモートアクセス用に許可
sudo ufw allow ssh

# HTTP(ポート80)およびHTTPS(ポート443)をウェブトラフィック用に許可
sudo ufw allow http
sudo ufw allow https

# ファイアウォールを有効にする
sudo ufw enable

# ファイアウォールの状態を確認する
sudo ufw status

この場合:

  • ファイアウォールはポート22でのSSH接続、ポート80でのHTTP、ポート443でのHTTPSを受け入れます。

  • 不要なポートやサービスは、攻撃への露出を制限するためにデフォルトでブロックする必要があります。

追加のファイアウォールルール:
  • Webhookエンドポイントへのアクセスを制限: 理想的には、外部アクセスを防ぐために、BitbucketのIPアドレスからのみWebhookエンドポイントへのトラフィックを許可する必要があります。これはファイアウォールまたはWebサーバー(例えば、NGINX)で設定し、BitbucketのIP範囲からのリクエストのみを受け入れることで実現できます。

  • 他のすべての着信トラフィックを拒否: インターネットに公開する必要がないサービス(例えば、データベースポート)については、これらのポートがブロックされていることを確認してください。

2. Flaskアプリに認証を追加

FlaskアプリはWebhook URLを介して公開アクセス可能であるため、認証を追加して、承認されたユーザー(例えば、Bitbucketのサーバー)のみがプルをトリガーできるようにすることを検討する必要があります。

基本認証の例:

Webhook エンドポイントを保護するために、シンプルなトークンベースの認証を使用できます。Flask アプリを変更して認証トークンを要求する方法の例です:

from flask import Flask, request, abort
import subprocess

app = Flask(__name__)

# Webhook 検証のための秘密トークンを定義
SECRET_TOKEN = 'your-secret-token'

@app.route('/pull-repo', methods=['POST'])
def pull_repo():
    # リクエストに正しいトークンが含まれているかをチェック
    token = request.headers.get('X-Hub-Signature')
    if token != SECRET_TOKEN:
        abort(403)  # トークンが不正確な場合は拒否

    try:
        subprocess.run(["git", "-C", "/path/to/your/repository", "fetch"], check=True)
        subprocess.run(["git", "-C", "/path/to/your/repository", "reset", "--hard", "origin/test"], check=True)
        return "Force pull successful", 200
    except subprocess.CalledProcessError:
        return "Failed to force pull the repository", 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
動作方法:
  • X-Hub-Signature は、Bitbucket の webhook を設定する際にリクエストに追加するカスタムヘッダーです。

  • 正しいトークンを持つリクエストのみがプルをトリガーできます。トークンが欠落しているか不正確な場合、リクエストは 403 Forbidden の応答で拒否されます。

また、OAuth や HMAC (Hash-based Message Authentication Code) などの複雑な認証形式を使用することもできますが、このシンプルなトークンアプローチは多くのケースで機能します。

3. 通信の安全性のために HTTPS を使用

Flask アプリと Bitbucket webhook 間、およびネットワークを介して送信されるトークンやパスワードなどの機密データを暗号化することが重要です。これにより、攻撃者がデータを傍受または変更できなくなります。

なぜHTTPSを使用するのか?
  • データの暗号化:HTTPSは通信を暗号化し、認証トークンなどの機密データが中間者攻撃にさらされないようにします。

  • 信頼性と整合性:HTTPSは、サーバーが受信したデータが改ざんされていないことを確認するのに役立ちます。

Let’s Encryptを使用してFlaskアプリをSSLでセキュアにする方法:
  1. Certbotをインストール(Let’s Encrypt証明書を取得するツール):
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx

ドメインの無料SSL証明書を取得

sudo certbot --nginx -d your-domain.com
  • このコマンドにより、NginxがLet’s Encryptからの無料SSL証明書を使用するように自動的に構成されます。

  • HTTPSを使用することを確認:FlaskアプリまたはNginx構成がすべてのトラフィックをHTTPSで送信するように強制することを確認します。これはNginxでリダイレクションルールを設定することで行えます。

server {
    listen 80;
    server_name your-domain.com;

    # HTTPをHTTPSにリダイレクト
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    # その他のNginx設定...
}

自動更新: Let’s Encryptの証明書は90日間有効なので、自動更新を設定することが重要です:

sudo certbot renew --dry-run

このコマンドは更新プロセスをテストして、すべてが正常に動作しているか確認します。

4. ロギングとモニタリング

Flaskアプリケーションのためにロギングとモニタリングを実装して、未承認の試行、エラー、または異常なアクティビティを追跡します:

  • リクエストを記録: IPアドレス、リクエストヘッダー、およびレスポンスステータスを含むすべての着信リクエストを記録して、疑わしいアクティビティを監視できます。

  • モニタリングツールの使用: PrometheusGrafana、またはNew Relicなどのツールを設定して、サーバーのパフォーマンスとアプリケーションの健康状態をモニタリングします。

まとめ

このチュートリアルでは、Bitbucket、Linuxサーバー、およびPython with Flaskを使用してデプロイを自動化する初心者向けの簡単なCI/CDパイプラインの設定方法を探りました。学んだ内容をまとめると、以下のとおりです:

  1. CI/CDの基礎:私たちは、コードの統合、テスト、展開を自動化するための基本的な継続的インテグレーション(CI)および継続的デリバリー/デプロイメント(CD)について話し合いました。CI/CDが開発を加速し、エラーを減らし、開発者間の協力を向上させる方法を学びました。

  2. Bitbucket Webhooksの設定:特定のブランチにプッシュまたはマージがあった場合にサーバーに通知するためのBitbucket Webhookの設定方法を学びました。このWebhookは、展開プロセスを自動的に開始するトリガーとして機能します。

  3. FlaskベースのWebhookリスナーの作成:Linuxサーバー上でFlaskアプリを設定して、Bitbucketからの着信Webhookリクエストを待機する方法を紹介しました。このFlaskアプリは通知を受信し、最新の変更をプルして展開するために必要なGitコマンドを実行します。

  4. 展開プロセスの自動化: PythonとFlaskを使用して、Bitbucketリポジトリから変更をプルし、最新のコードがデプロイされるように強制プルを実行するプロセスを自動化しました。また、Flaskアプリを公開してリクエストを安全に受け入れるためのサーバーの設定方法も学びました。

  5. セキュリティに関する考慮事項: デプロイプロセスを保護するための重要なセキュリティ手順について説明しました:

    • ファイアウォールルール: ファイアウォールルールを構成して露出を制限し、(Bitbucketからの)許可されたトラフィックのみがサーバーにアクセスできるようにしました。

    • 認証: トークンベースの認証を追加して、許可されたリクエストのみがデプロイをトリガーできるようにしました。

    • HTTPS: Let’s EncryptからのSSL証明書を使用して、サーバーとBitbucket間の通信を保護する方法について説明しました。

    • ログ記録とモニタリング: 最後に、異常なアクティビティやエラーを追跡するためにログ記録とモニタリングの設定をお勧めしました。

次のステップ

このチュートリアルの最後までに、自動デプロイパイプラインの動作する例を持つことができました。これは基本的な実装ですが、構築できる基盤となります。CI/CDにより快適になれると、次のような高度なトピックを探求できます:

  • マルチステージのデプロイパイプライン

  • Dockerのようなコンテナ化ツールとの統合

  • より複雑なテストとデプロイ戦略

  • スケーリングのためのKubernetesなどのオーケストレーションツールの使用

CI/CDのプラクティスは常に進化しており、基本をマスターすることで、この分野のスキルを拡大する際に成功への道を築くことができます。自動化を楽しんで、お読みいただきありがとうございます!

ここからコードをフォークできます