開発者ドキュメント

Ubuntu16.04でのWebhookとSlackを使用したReactアプリケーションのデプロイ

著者は、 Write forDOnationsプログラムの一環として寄付を受け取るためにTechEducationFundを選択しました。

序章

開発者がアプリケーションに継続的な変更を加える場合、Webhookを備えたデプロイメントシステムは、特にチームの開発を合理化できます。 チームの一部がAPIなどのバックエンドソフトウェアに依存している場合は、コード変更のSlack通知をチームのワークフローに統合することも役立ちます。

このチュートリアルでは、create-react-appnpmパッケージを使用してReactアプリケーションをビルドします。 このパッケージは、構文をトランスパイルし、依存関係と前提条件ツールを使用して作業を合理化することにより、Reactプロジェクトのブートストラップ作業を簡素化します。 アプリケーションコードをGitHubリポジトリに追加した後、更新されたプロジェクトファイルを提供するようにNginxを構成します。 次に、Webhookサーバーをダウンロードしてセットアップし、コードが変更されたときにGitHubと通信するように構成します。 最後に、別のWebhookサーバーとして機能するようにSlackを構成します。このサーバーは、デプロイが成功したときに通知を受け取ります。

最終的に、この記事で構築しているデプロイメントシステムは次のようになります。

この短いビデオは、空のコミットとGitHubリポジトリへのプッシュを示しています。これにより、Slackでアプリケーションのビルドと通知がトリガーされます。

前提条件

このチュートリアルを完了するには、次のものが必要です。

ステップ1—create-react-appを使用してReactアプリケーションを作成する

まず、create-react-appを使用してWebhookをテストするために使用するアプリケーションを作成しましょう。 次に、GitHubリポジトリを作成し、プロジェクトコードをそこにプッシュできます。

ローカルマシンで、create-react-appノードモジュールをグローバルリポジトリに追加し、create-react-appコマンドをシェル環境で使用できるようにします。

  1. sudo npm install -g create-react-app

次に、create-react-appを実行して、do-react-example-appというプロジェクトを作成します。

  1. create-react-app do-react-example-app

ディレクトリdo-react-example-appに移動します。

  1. cd do-react-example-app

nanoまたはお気に入りのテキストエディタを使用して、package.jsonファイルを開きます。

  1. nano package.json

ファイルは次のようになります。

〜/ do-react-example-app / package.json

{
  "name": "do-react-example-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-scripts": "1.0.17"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

package.jsonファイルには、次のスクリプトが含まれています。

コードの検査が終了したら、ファイルを閉じます。

次に、プロジェクトのGitHubリポジトリを作成しましょう。 ガイダンスとして、GitHubリポジトリの作成に関するこのチュートリアルに従うことができます。 リポジトリの起源に注意してください(つまり そのGitHubURL)。

do-react-example-appディレクトリに戻り、gitでリポジトリを初期化します。

  1. git init

次に、GitHubのURLを使用してリモートオリジンを追加します。

  1. git remote add origin your-github-url

プロジェクトディレクトリ内のすべてのファイルをステージングします。

  1. git add .

それらをコミットします:

  1. git commit -m "initial commit"

そしてそれらをリポジトリにプッシュします:

  1. git push origin master

GitHubリポジトリの作成と、gitを使用した既存のアプリケーションの初期化の詳細については、GitHubのドキュメントを参照してください。

リポジトリのセットアップが完了したら、サーバーでの構成の詳細の指定に進むことができます。

ステップ2—ディレクトリのセットアップとNginxの構成

リポジトリを配置すると、GitHubからアプリケーションコードをプルして、アプリケーションを提供するようにNginxを構成できるようになります。

サーバーにログインし、ホームディレクトリに移動して、リポジトリのクローンを作成します。

  1. cd ~
  2. git clone your-github-url

複製されたプロジェクトに移動します。

  1. cd do-react-example-app

Nginxが提供するプロジェクトとファイル内にビルドディレクトリを作成するには、yarn buildコマンドを実行する必要があります。 これにより、プロジェクトのビルドスクリプトが実行され、ビルドディレクトリが作成されます。 このフォルダには、特にindex.htmlファイル、JavaScriptファイル、およびCSSファイルが含まれています。 yarnコマンドは、プロジェクトに必要なすべてのノードモジュールをダウンロードします。

  1. yarn && yarn build

次に、/var/www/ディレクトリに~/do-react-example-appディレクトリへのシンボリックリンクを作成しましょう。 これにより、アプリケーションはホームディレクトリに保持され、Nginxは/var/wwwディレクトリからサービスを提供できるようになります。

  1. sudo ln -s ~/do-react-example-app /var/www/do-react-example-app

これは、頻繁に変更されるビルドディレクトリではなく、プロジェクトディレクトリにリンクしていることに注意してください。 このリンクを作成すると、アプリケーションの新しいバージョンをデプロイするシナリオで特に役立ちます。安定したバージョンへのリンクを作成することで、後で追加のバージョンをデプロイするときに、リンクをスワップアウトするプロセスを簡素化できます。 問題が発生した場合は、同じ方法で以前のバージョンに戻すこともできます。

Nginxがシンボリックリンクを適切に提供できるように、シンボリックリンクにいくつかの権限を設定する必要があります。

  1. sudo chmod -R 755 /var/www

次に、ビルドディレクトリを提供するようにNginxサーバーブロックを構成しましょう。 次のように入力して、新しいサーバー構成を作成します。

  1. sudo nano /etc/nginx/sites-available/test-server

次の構成をコピーし、your_server_ip_or_domainをIPまたはドメイン(該当する場合)に置き換えます。

/ etc / nginx / sites-available / test-server
server {
        listen 80;

        root /var/www/do-react-example-app/build;
        index index.html index.htm index.nginx-debian.html;

        server_name your_server_ip_or_domain;

        location / {
                try_files $uri /index.html;
        }
}

このファイルのディレクティブは次のとおりです。

次に、sites-enabledディレクトリにシンボリックリンクを作成します。

  1. sudo ln -s /etc/nginx/sites-available/test-server /etc/nginx/sites-enabled/test-server

これにより、sites-availableフォルダーからサーバーブロック構成を有効にするようにNginxに指示されます。

構成が有効かどうかを確認します。

  1. sudo nginx -t

最後に、Nginxを再起動して、新しい構成を適用します。

  1. sudo systemctl restart nginx

これらの構成の詳細が整ったら、Webhookの構成に進むことができます。

ステップ3—Webhookのインストールと構成

Webhookは、hooksと呼ばれる構成可能なエンドポイントを持つ単純なHTTPサーバーです。 HTTPリクエストを受信すると、Webhookサーバーは一連の構成可能なルールに準拠するカスタマイズ可能なコードを実行します。 Slackを含め、インターネット上のアプリケーションに統合されたWebhookサーバーはすでに多数あります。

Webhookサーバーの最も広く使用されている実装は、Goで記述されたWebhookです。 このツールを使用して、Webhookサーバーをセットアップします。

サーバーのホームディレクトリにいることを確認してください。

  1. cd ~

次に、webhookをダウンロードします。

  1. wget https://github.com/adnanh/webhook/releases/download/2.6.6/webhook-linux-amd64.tar.gz

それを抽出します:

  1. tar -xvf webhook-linux-amd64.tar.gz

バイナリを/usr/local/binに移動して、ご使用の環境で使用できるようにします。

  1. sudo mv webhook-linux-amd64/webhook /usr/local/bin

最後に、ダウンロードしたファイルをクリーンアップします。

  1. rm -rf webhook-linux-amd64*

次のように入力して、ご使用の環境でwebhookの可用性をテストします。

  1. webhook -version

出力には、webhookバージョンが表示されます。

Output
webhook version 2.6.5

次に、/optディレクトリにhooksフォルダとscriptsフォルダを設定します。このフォルダには、通常、サードパーティアプリケーションのファイルがあります。 /optディレクトリは通常rootによって所有されているため、root権限でディレクトリを作成してから、所有権をローカルの$USERに譲渡できます。

まず、ディレクトリを作成します。

  1. sudo mkdir /opt/scripts
  2. sudo mkdir /opt/hooks

次に、所有権を$USERに譲渡します。

  1. sudo chown -R $USER:$USER /opt/scripts
  2. sudo chown -R $USER:$USER /opt/hooks

次に、hooks.jsonファイルを作成して、webhookサーバーを構成しましょう。 nanoまたはお気に入りのエディタを使用して、/opt/hooksディレクトリにhooks.jsonファイルを作成します。

  1. nano /opt/hooks/hooks.json

GitHubがHTTPリクエストを送信したときにwebhookがトリガーされるようにするには、ファイルにルールのJSON配列が必要です。 これらのルールは、次のプロパティで構成されています。

{
    "id": "",
    "execute-command": "",
    "command-working-directory": "",
    "pass-arguments-to-command": [],
    "trigger-rule": {}
}

具体的には、これらのルールは次の情報を定義します。

/opt/hooks/hooks.jsonファイルには、次の情報が含まれている必要があります。

/opt/hooks/hooks.json
[
  {
    "id": "redeploy-app",
    "execute-command": "/opt/scripts/redeploy.sh",
    "command-working-directory": "/opt/scripts",
    "pass-arguments-to-command":
    [
      {
        "source": "payload",
        "name": "head_commit.message"
      },
      {
        "source": "payload",
        "name": "pusher.name"
      },
      {
        "source": "payload",
        "name": "head_commit.id"
      }
    ],
    "trigger-rule": {}
  }
]

GitHub HTTP POSTリクエストのペイロードには、head_commit.messagepusher.name、およびhead_commit.idプロパティが含まれています。 構成されたイベント(PUSHなど)がGitHubリポジトリで発生すると、GitHubはイベントに関する情報を含むJSON本文を含むPOSTリクエストを送信します。 これらのPOSTペイロードの例は、GitHubイベントタイプドキュメントにあります。

構成ファイルの最後のプロパティはtrigger-ruleプロパティです。これは、フックがトリガーされる条件をWebhookサーバーに通知します。 空のままにすると、フックは常にトリガーされます。 この例では、GitHubがPOSTリクエストをWebhookサーバーに送信したときにトリガーされるようにフックを構成します。 具体的には、HTTPリクエストのGitHubシークレット(ここではyour-github-secretと表記)がルールのシークレットと一致し、コミットがmasterブランチで発生した場合にのみトリガーされます。

次のコードを追加してtrigger-ruleを定義し、your-github-secretを選択したパスワードに置き換えます。

... 
    "trigger-rule":
    {
      "and":
      [
        {
          "match":
          {
            "type": "payload-hash-sha1",
            "secret": "your-github-secret", 
            "parameter":
            {
              "source": "header",
              "name": "X-Hub-Signature"
            }
          }
        },
        {
          "match":
          {
            "type": "value",
            "value": "refs/heads/master",
            "parameter":
            {
              "source": "payload",
              "name": "ref"
            }
          }
        }
      ]
    }
  }
]

完全に、/opt/hooks/hooks.jsonは次のようになります。

/opt/hooks/hooks.json
[
  {
    "id": "redeploy-app",
    "execute-command": "/opt/scripts/redeploy.sh",
    "command-working-directory": "/opt/scripts",
    "pass-arguments-to-command":
    [
      {
        "source": "payload",  
        "name": "head_commit.message"
      },
      {
        "source": "payload",
        "name": "pusher.name"
      },
      {
        "source": "payload",
        "name": "head_commit.id"
      }
    ],
    "trigger-rule":
    {
      "and":
      [
        {
          "match":
          {
            "type": "payload-hash-sha1",
            "secret": "your-github-secret", 
            "parameter":
            {
              "source": "header",
              "name": "X-Hub-Signature"
            }
          }
        },
        {
          "match":
          {
            "type": "value",
            "value": "refs/heads/master",
            "parameter":
            {
              "source": "payload",
              "name": "ref"
            }
          }
        }
      ]
    }
  }
]

チェックする最後の構成項目の1つは、サーバーのファイアウォール設定です。 Webhookサーバーはポート9000でリッスンします。 これは、ファイアウォールがサーバーで実行されている場合、このポートへの接続を許可する必要があることを意味します。 現在のファイアウォールルールのリストを表示するには、次のように入力します。

  1. sudo ufw status

ポート9000がリストに含まれていない場合は、次のように有効にします。

  1. sudo ufw allow 9000

ufwの詳細については、この ufwEssentialsの概要を参照してください。

次に、このエンドポイントにHTTPリクエストを送信するようにGitHubリポジトリを設定しましょう。

ステップ4—GitHub通知を構成する

マスターへのコミットが発生したときにHTTPリクエストを送信するようにGitHubリポジトリを構成しましょう。

これで、誰かがコミットをリポジトリにプッシュすると、GitHubはコミットイベントに関する情報を含むペイロードを含むPOSTリクエストを送信します。 他の便利なプロパティの中でも、トリガールールで定義したプロパティが含まれるため、WebhookサーバーはPOSTリクエストが有効かどうかを確認できます。 含まれている場合は、pusher.nameなどの他の情報が含まれます。

ペイロードとともに送信されるプロパティの完全なリストは、GitHubWebhookページにあります。

ステップ5—デプロイ/再デプロイスクリプトの作成

この時点で、Webhookにredeploy.shスクリプトを指定しましたが、スクリプト自体は作成していません。 リポジトリから最新のマスターブランチをプルし、ノードモジュールをインストールし、ビルドコマンドを実行する作業を行います。

スクリプトを作成します。

  1. nano /opt/scripts/redeploy.sh

まず、スクリプトの先頭に、作成したファイルをクリーンアップする関数を追加しましょう。 再デプロイが正常に行われなかった場合に、Slackなどのサードパーティソフトウェアに通知する場所としてこれを使用することもできます。

/opt/scripts/redeploy.sh
#!/bin/bash -e

function cleanup {
      echo "Error occoured"
      # !!Placeholder for Slack notification
}
trap cleanup ERR

これは、bashインタープリターに、スクリプトが突然終了した場合、cleanup関数でコードを実行する必要があることを通知します。

次に、スクリプトの実行時にwebhookがスクリプトに渡すパラメーターを抽出します。

/opt/scripts/redeploy.sh
...

commit_message=$1 # head_commit.message
pusher_name=$2 # pusher.name
commit_id=$3 # head_commit.id


# !!Placeholder for Slack notification

パラメータの順序は、hooks.jsonファイルのpass-arguments-to-commandプロパティに対応していることに注意してください。

最後に、アプリケーションの再デプロイに必要なコマンドを呼び出しましょう。

/opt/scripts/redeploy.sh
...

cd ~/do-react-example-app/
git pull origin master
yarn && yarn build

# !!Placeholder for Slack notification

完全なスクリプトは次のようになります。

/opt/scripts/redeploy.sh
#!/bin/bash -e

function cleanup {
      echo "Error occoured"
      # !!Placeholder for Slack notification
}
trap cleanup ERR

commit_message=$1 # head_commit.message
pusher_name=$2 # pusher.name
commit_id=$3 # head_commit.id

# !!Placeholder for Slack notification

cd ~/do-react-example-app/
git pull origin master
yarn && yarn build

# !!Placeholder for Slack notification

スクリプトはフォルダーに移動し、最新のマスターブランチからコードをプルし、新しいパッケージをインストールして、アプリケーションの製品版をビルドします。

!!Placeholder for Slack notificationに注意してください。 これは、このチュートリアルの最後のステップのプレースホルダーです。 通知がないと、スクリプトが正しく実行されたかどうかを知る実際の方法はありません。

フックがスクリプトを実行できるように、スクリプトを実行可能にします。

  1. chmod +x /opt/scripts/redeploy.sh

Nginxは/var/www/do-react-example-app/buildからのファイルを提供するように構成されているため、このスクリプトを実行すると、ビルドディレクトリが更新され、Nginxは自動的に新しいファイルを提供します。

これで、構成をテストする準備が整いました。 Webhookサーバーを実行してみましょう。

  1. webhook -hooks /opt/hooks/hooks.json -verbose

-hooksパラメーターは、webhookに構成ファイルの場所を通知します。

次の出力が表示されます。

Output
[webhook] 2017/12/10 13:32:03 version 2.6.5 starting [webhook] 2017/12/10 13:32:03 setting up os signal watcher [webhook] 2017/12/10 13:32:03 attempting to load hooks from /opt/hooks/hooks.json [webhook] 2017/12/10 13:32:03 os signal watcher ready [webhook] 2017/12/10 13:32:03 found 1 hook(s) in file [webhook] 2017/12/10 13:32:03 loaded: redeploy-app [webhook] 2017/12/10 13:32:03 serving hooks on http://0.0.0.0:9000/hooks/{id}

これは、すべてが正しくロードされ、サーバーがURLhttp://0.0.0.0:9000/hooks/redeploy-appを介してフックredeploy-appを提供していることを示しています。 これにより、実行可能なサーバー上のパスまたはフックが公開されます。 このURLを使用して単純なREST呼び出し(GETなど)を実行すると、フックルールが満たされていないため、特別なことは何も起こりません。 フックを正常にトリガーするには、hooks.jsonで定義したtrigger-ruleを満たす必要があります。

ローカルプロジェクトディレクトリの空のコミットでこれをテストしてみましょう。 Webhookサーバーを実行したまま、ローカルマシンに戻り、次のように入力します。

  1. git commit --allow-empty -m "Trigger notification"

コミットをマスターブランチにプッシュします。

  1. git push origin master

サーバーに次のような出力が表示されます。

Output
[webhook] 2018/06/14 20:05:55 [af35f1] incoming HTTP request from 192.30.252.36:49554 [webhook] 2018/06/14 20:05:55 [af35f1] redeploy-app got matched [webhook] 2018/06/14 20:05:55 [af35f1] redeploy-app hook triggered successfully [webhook] 2018/06/14 20:05:55 200 | 726.412µs | 203.0.113.0:9000 | POST /hooks/redeploy-app [webhook] 2018/06/14 20:05:55 [af35f1] executing /opt/scripts/redeploy.sh (/opt/scripts/redeploy.sh) with arguments ["/opt/scripts/redeploy.sh" "Trigger notification" "sammy" "82438acbf82f04d96c53cd684f8523231a1716d2"] and environment [] using /opt/scripts as cwd

ここで、Slack通知を追加し、フックが通知を使用してビルドを成功させたときに何が起こるかを見てみましょう。

ステップ6—Slack通知を追加する

アプリが再デプロイされたときにSlack通知を受信するには、redeploy.shスクリプトを変更してHTTPリクエストをSlackに送信します。 また、Slack構成パネルで Webhook統合を有効にして、サーバーから通知を受信するようにSlackを構成する必要があります。 SlackからWebhookURL を取得したら、SlackWebhookサーバーに関する情報をスクリプトに追加できます。

Slackを設定するには、次の手順を実行します。

その後、SlackWebhook設定を表示する画面が表示されます。 SlackWebhookサーバーによって生成されるエンドポイントであるWebhookURLをメモします。 このURLのメモやその他の変更が終了したら、必ずページ下部の[設定の保存]ボタンを押してください。

サーバーに戻り、redeploy.shスクリプトを開きます。

  1. nano /opt/scripts/redeploy.sh

前の手順では、!!Placeholder for Slack notificationとして示されるSlack通知のスクリプトにプレースホルダーを残しました。 これらを、SlackWebhookサーバーにPOSTHTTPリクエストを行うcurl呼び出しに置き換えます。 SlackフックはJSON本体を想定しており、JSON本体が解析され、チャネルに適切な通知が表示されます。

!!Placeholder for slack notificationを次のcurl呼び出しに置き換えます。 your_slack_webhook_urlを前述のWebhookURLに置き換える必要があることに注意してください。

/opt/scripts/redeploy.sh
#!/bin/bash -e

function cleanup {
      echo "Error occoured"
      curl -X POST -H 'Content-type: application/json' --data "{
              \"text\": \"Error occoured while building app with changes from ${pusher_name} (${commit_id} -> ${commit_message})\",
              \"username\": \"buildbot\",
              \"icon_url\": \"https://i.imgur.com/JTq5At3.png\"
      }" your_slack_webhook_url
}
trap cleanup ERR

commit_message=$1 # head_commit.message
pusher_name=$2 # pusher.name
commit_id=$3 # head_commit.id

curl -X POST -H 'Content-type: application/json' --data "{
        \"text\": \"Started building app with changes from ${pusher_name} (${commit_id} -> ${commit_message})\",
        \"username\": \"buildbot\",
        \"icon_url\": \"https://i.imgur.com/JTq5At3.png\"
}" your_slack_webhook_url

cd ~/do-react-example-app/
git pull origin master
yarn && yarn build

curl -X POST -H 'Content-type: application/json' --data "{
        \"text\": \"Build and deploy finished with changes from ${pusher_name} (${commit_id} -> ${commit_message})\",
        \"username\": \"buildbot\",
        \"icon_url\": \"https://i.imgur.com/JTq5At3.png\"
}" your_slack_webhook_url

各プレースホルダーをわずかに異なるcurl呼び出しに置き換えました。

Slackボットと統合の詳細については、SlackWebhookのドキュメントをご覧ください。

ここでも、ローカルプロジェクトディレクトリで空のコミットを使用してフックをテストできます。 Webhookサーバーを実行したまま、このディレクトリに戻り、空のコミットを作成します。

  1. git commit --allow-empty -m "Trigger notification"

コミットをマスターブランチにプッシュして、ビルドをトリガーします。

  1. git push origin master

ビルド情報を含む出力は、次のようになります。

Output
[webhook] 2018/06/14 20:09:55 [1a67a4] incoming HTTP request from 192.30.252.34:62900 [webhook] 2018/06/14 20:09:55 [1a67a4] redeploy-app got matched [webhook] 2018/06/14 20:09:55 [1a67a4] redeploy-app hook triggered successfully [webhook] 2018/06/14 20:09:55 200 | 462.533µs | 203.0.113.0:9000 | POST /hooks/redeploy-app [webhook] 2018/06/14 20:09:55 [1a67a4] executing /opt/scripts/redeploy.sh (/opt/scripts/redeploy.sh) with arguments ["/opt/scripts/redeploy.sh" "Trigger notification" "sammy" "5415869a4f126ccf4bfcf2951bcded69230f85c2"] and environment [] using /opt/scripts as cwd [webhook] 2018/06/14 20:10:05 [1a67a4] command output: % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 228 0 2 100 226 11 1324 --:--:-- --:--:-- --:--:-- 1329 okFrom https://github.com/sammy/do-react-example-app * branch master -> FETCH_HEAD 82438ac..5415869 master -> origin/master Updating 82438ac..5415869 Fast-forward yarn install v1.7.0 [1/4] Resolving packages... success Already up-to-date. Done in 1.16s. yarn run v1.7.0 $ react-scripts build Creating an optimized production build... Compiled successfully. File sizes after gzip: 36.94 KB build/static/js/main.a0b7d8d3.js 299 B build/static/css/main.c17080f1.css The project was built assuming it is hosted at the server root. You can control this with the homepage field in your package.json. For example, add this to build it for GitHub Pages: "homepage" : "http://myname.github.io/myapp", The build folder is ready to be deployed. You may serve it with a static server: yarn global add serve serve -s build Find out more about deployment here: http://bit.ly/2vY88Kr Done in 7.72s. % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 233 0 2 100 231 10 1165 --:--:-- --:--:-- --:--:-- 1166 ok [webhook] 2018/06/14 20:10:05 [1a67a4] finished handling redeploy-app

Slackでは、選択したチャネルに、アプリケーションのビルドが開始され、終了したことを通知するメッセージが届きます。

結論

これで、Webhook、Nginx、シェルスクリプト、およびSlackを使用したデプロイメントシステムのセットアップが完了しました。 これで、次のことができるようになります。

Webhookサーバーはモジュール式であり、 GitLab などの他のアプリケーションと連携するように構成できるため、このチュートリアルのシステムを拡張できます。 JSONを使用してWebhookサーバーを構成するのが多すぎる場合は、Hookdooを使用して同様のセットアップを構築できます。 webhookのトリガールールを構成する方法の詳細については、webhookプロジェクトサンプルフックページを参照してください。

モバイルバージョンを終了