コンテナレジストリ上にPREN（PostgreSQL、ReactJS、Express、NodeJS）アプリのCI/CDを設定する

このガイドでは、**Alibaba Cloud**のコンテナレジストリを使用してPREN(PostgreSQL, ReactJS, Express, NodeJS)アプリケーション用のCICDパイプラインをセットアップします。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/setting-up-cicd-for-a-pren-app-with-jenkins-docker-and-github-webhooks-on-container-registry_595029)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

[Alibaba Cloud Tech Share](https://www.alibabacloud.com/ja/campaign/techshare)執筆者 テミダヨ・オイェデレ（Temidayo Oyedele）著 [Tech Share](https://www.alibabacloud.com/ja/campaign/techshare)は、技術的な知識やベストプラクティスをクラウドコミュニティ内で共有することを奨励するAlibaba Cloudのインセンティブプログラムです。

[Jenkins](https://www.jenkins.io/doc/?spm=a2c65.11461447.0.0.44d520f9XMAX4C)は、自己完結型のオープンソース自動化サーバであり、ソフトウェアの構築、テスト、配信、デプロイに関連するあらゆる種類のタスクを自動化するために使用することができます。

Jenkinsは、ネイティブシステムパッケージ、Dockerを通じてインストールすることができ、Javaランタイム環境（JRE）がインストールされているマシンであれば、スタンドアロンでも実行することができます。

[Docker](https://docs.docker.com/get-started/?spm=a2c65.11461447.0.0.44d520f9XMAX4C)は、開発者やシステム管理者がコンテナを使ってアプリケーションを開発、デプロイ、実行するためのプラットフォームです。Linuxのコンテナを使ってアプリケーションをデプロイすることをコンテナ化と呼びます。コンテナは新しいものではありませんが、アプリケーションを簡単にデプロイするための使用は新しいものです。

このガイドでは、PREN (PostgreSQL, ReactJS, Express, NodeJS) アプリケーションのための継続的インテグレーションとデプロイのパイプラインを設定します。Jenkinsを使用してGitHub上のコード変更を検出し、継続的なデリバリを行い、PRENアプリはDockerを使用してコンテナ化し、Alibaba Cloud [Container Registry](https://www.alibabacloud.com/ja/product/container-registry)にプッシュします。今回使用するPRENアプリはこちらのGitHubでホストされています。

#前提条件と要件
1、アリババクラウドのアカウント
2、新たにデプロイされたAlibaba Cloud Ubuntu 16.04 64ビットサーバーインスタンス
3、最低2GBのRAM（Docker化されたアプリサイズのため2GBを強く推奨
4、最低20GBのディスク容量（ただし40GBを推奨)
5、インスタンス・セキュリティ・グループはポート8080での侵入を許可しなければなりません。
6、Alibaba Cloud Elastic Container Registryのリポジトリ

#ステップ1：Jenkinsの設定
Alibabaクラウドのエラスティックコンピュートサービス上にJenkinsサーバをセットアップします。[Alibaba Cloud ECSコンソール](https://account.alibabacloud.com/login/login.htm?oauth_callback=https%3A%2F%2Fecs.console.aliyun.com%2F%3Fspm%3Da2c65.11461447.0.0.44d520f9XMAX4C&lang=ja)にログインします。インスタンスが起動していない場合は、[こちらのリンク](https://www.alibabacloud.com/help/ja/doc-detail/25465.htm)をクリックしてAlibaba Cloudのコンピュートサービスを起動させます。

JenkinsをインストールするにはJava実行環境（JRE）が必要なので、まずはそれをインストールします。

Javaプログラムのコンパイルなどが必要になることもあるので、Java実行環境も含まれているJDK(Java開発キット)をインストールするのが良いと思います。唯一の欠点はサイズが大きくなることです。

SSHキーペアを使用してローカルターミナルからECSインスタンスにSSHするか、設定や好みの方法に応じてVNCコンソール経由でログインし、以下の手順でJenkinsをインストールします。

Oracle PPAを追加し、以下のコマンドを実行してパッケージインデックスを更新します。

```
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:webupd8team/java 
sudo apt-get update
```

あとでadd-apt-repositoryを使うことができるように、ソフトウェアのプロパティの共通部分をインストールする必要があります。最後に、JDK 8を実行してインストールします。

```
 sudo apt-get install oracle-java8-installer
```

注意：Jenkinsは特にJavaのバージョン8がインストールされている必要があります。

以下のコマンドでリポジトリキーをシステムに追加します。

```
wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -
```

次に、Debian パッケージのリポジトリのアドレスをサーバの sources.list に追加します。

```
echo deb https://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list
```

この両方が揃ったら、apt-getが新しいリポジトリを使うようにupdateを実行します。

```
sudo apt-get update
```

最後にJenkinsとその依存関係をインストールします。

```
sudo apt-get install jenkins
```

serviceを使って、Jenkinsを起動します。

```
sudo service jenkins start
```

Jenkinsのステータスは以下のコマンドで確認できます。

```
sudo service jenkins status
```

出力の中にJenkinsのオートメーションサーバのようなものが実行されているのがわかるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/2b1ebf51-b00b-064f-c7fd-a52d250ce756.png)


次に、Jenkinsのウェブコンソールからインストールの設定を行います。http://internet_ip_address_of_your_instance:8080 にアクセスして Jenkins のウェブコンソールに移動します。ポート8080はJenkinsのデフォルトポートです。

すると「Unlock Jenkins」というページが表示されるはずですが、そこには初期パスワードの場所が赤文字で表示されています。これに似たようなものが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/1268c79a-6c73-ad22-313f-1e98e497bd46.png)


VNCターミナルまたはECSインスタンスにログインしたローカルターミナルウィンドウに移動して、パスワードを表示するために`cat`コマンドを使用します。

```
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
```

ターミナルから出力された32文字の英数字のパスワードをコピーして、Jenkinsコンソールの「Administrator password」欄に貼り付け、「Continue」をクリックします。次の画面では、提案されたプラグインをインストールするか、特定のプラグインを選択するかのオプションが表示されます。ここでは、提案されたプラグインをインストールするオプションを選択することにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/da1d7391-b9a4-d727-f283-287291629df8.png)


インストールが完了すると、最初の管理ユーザーを設定するように促されます。このステップをスキップして、上で使用した初期パスワードを使用して管理者として続行することも可能ですが、ユーザーを作成するために少し時間がかかります。

覚えておく必要がある詳細を記入し、保存して次に進みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/da30635d-e52e-7158-bb64-c352e45466cf.png)


この段階では、このようなページが表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/1038d876-b151-80f4-b90e-cceec8eec070.png)


Save and Finishをクリックし、次のページでStart using Jenkinsをクリックします。ダッシュボードにリダイレクトされます。この段階でインストールは完了です。

#ステップ2：Dockerのセットアップ

まだVNCまたはあなたのターミナル/コマンドプロンプトからECSインスタンス上で。有効なdockerダウンロードを確実に取得するために、公式DockerリポジトリのGPGキーをシステムに追加します。

```
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
```

APTソースにDockerリポジトリを追加します。

```
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 
```

次に、新しく追加したリポジトリのDockerパッケージでパッケージデータベースを更新します。

```
sudo apt-get update
```

最後に、このコマンドでDockerをインストールします。

```
sudo apt-get install -y docker-ce
```

これでDockerがインストールされ、デーモンが起動し、起動時にプロセスが起動するようになったはずです。を使って実行していることを確認してください。

```
sudo service docker status
```

#ステップ3: JenkinsでGitHubのWebhookを設定する
WebブラウザからJenkinsダッシュボード「http://ECS_URL:8080」
にアクセスし、新規項目をクリックして新規Jenkinsジョブを作成します。適切な名前を入力し、フリースタイルプロジェクトを選択し、OKをクリックして次のページに移動します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/053faa59-070d-d269-ff2e-d9e8a4084db3.png)


次のページでは、ビルドトリガーの下で、トリガーのビルドをリモートで行うボックスにチェックを入れてください（例：スクリプトから）、認証トークンを提供する必要があります。自分にとっては覚えやすく、他の人にとってはかなり難しいであろう、任意のトークンを記入してください（パスワードのようなもの）。このトークンは、Jenkinsサーバーへのプッシュイベント（ここではGitHubから）を行うために必要です。入力欄の下にあるURLに注目してください。ビルドURLと呼ぶことにしますが、これは後ほどGitHubのwebhookに必要になります。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/becf9e4e-1e41-a59e-3f36-486bdeda4855.png)

ビルドセクションでは、ドロップダウンから[ビルドステップの追加]と[シェルの実行]を選択します。テキストエリアに以下のコマンドを貼り付けます。

```
set +x
if [ -d HelloBooks-Alibaba ]; then rm -rf HelloBooks-Alibaba; fi
git clone https://github.com/babadee001/HelloBooks-Alibaba 
cd HelloBooks-Alibaba 
sudo docker build -t hellobooks . 
sudo docker login --username=yourusername registry-intl.yourregion.aliyuncs.com -p $password
sudo docker tag [ImageId] registry-intl.yourregion.aliyuncs.com/yournamespace/yourrepositoryname:[tag]
sudo docker push registry-intl.yourregion.aliyuncs.com/yournamespace/yourrepositoryname:[tag]
```

私が使用しているサンプルプロジェクトでこのガイドに従っている場合、最初の5つのコマンドはそのままにしておいて、それ以外の場合は適宜修正してください。次の3つのコマンドは、Alibaba ECR (Elastic Container Registry) リポジトリから直接取得したものです。これについては、ECRを設定する次のステップ(ステップ4)で詳しく説明します。

Set +xは、コマンドとその引数が印刷されたり、ターミナルに返されたりしないことを確認します。次の行では、プロジェクトフォルダが存在するかどうかをチェックし、真であれば削除します。これにより、常に更新されたレポフォルダがあることを確認します。次に、レポをクローンして、プロジェクトフォルダかディレクトリにcd(ディレクトリ変更)します。その後、イメージをビルドするためのdockerコマンドを実行します。

最後に、Jenkinsジョブを保存する前に、環境変数を追加する必要があります。Build Environmentの下のUse secret text(s) or file(s)ボックスにチェックを入れます。新しいセクションがそのすぐ下に表示されます(Bindings)。変数フィールドに秘密のテキストの名前を入力します。Add」ドロップダウンをクリックし、「secret text」を選択します。追加]をクリックし、[Jenkins]をクリックします。kindをsecret textに変更し、ECR Dockerのログインパスワードを貼り付けます。IDフィールドを記入します（この名前は、後でシークレットファイルを参照するために使用するものになるので注意してください。保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/7d3f69dc-aa9c-30f0-0356-8d66768d1e67.png)


GitHub、Gitlab、Bitbucket などのような多くのソースコードホスティングサービスは、新しいコミットがリポジトリにプッシュされたときにウェブフックを送信する機能を持っています。ウェブフックは通常、JSONペイロードを含むHTTP POSTリクエストです。

デフォルトでは、Jenkins 2.x以降では「Prevent Cross Site Request Forgery exploits」というセキュリティ機能が有効になっており、有効な「crumb」トークンが関連付けられていないすべてのPOSTリクエストを拒否します。これは素晴らしいセキュリティ機能です。

ほとんどの Git ホスティングサービスには crumb を取得したり処理したりする仕組みがないので、デフォルトの設定で Jenkins をインストールした場合には、POST リクエストがブロックされてしまいます。"Prevent Cross Site Request Forgery exploits" を手動で無効にするか、サービス固有のプラグインをインストールする必要があります。

Bitbucket や GitHub のような多くの一般的なホスト用に作られたプラグインで、Crumb Exclusions を提供しています。これらのプラグインは CSRF が有効になっていることを確認し、プッシュ通知を行うことができますが、このチュートリアルの目的のために、サードパーティ製のプラグインをインストールするのではなく、手動で CSRF を無効にします。

JenkinsダッシュボードでCSRFを無効にするには、Jenkinsダッシュボードからmanage Jenkinsをクリックし、グローバルセキュリティを設定します。Authorizationの下で上にスクロールし、Logged-in users can do anythingを選択し、Allow anonymous read accessボックスにチェックを入れます。続けて上にスクロールすると、CSRF保護が表示されるはずなので、チェックを外します。保存して、これで完了です。

最後に、イメージをコンテナレジストリに送信するためのdockerコマンドにはsudoer権限が必要なので、Jenkinsユーザにsudo権限を与える必要があります。これは、以下のコマンドを実行して sudoers ファイルを修正することで行うことができます。

```
visudo -f /etc/sudoers
```

そして、ファイルの最後に以下の行を追加して保存します。

```
jenkins ALL= NOPASSWD: ALL
```

GitHub のリポジトリに移動し、左のナビゲーションペインから設定タブをクリックして webhooks をクリックします。

「add webhook」をクリックして Jenkins の webhook を作成します。ペイロードのURLは、ステップ3のJenkinsビルドのURLになります。Just the pushイベントボックスにチェックを入れます。このチュートリアルの目的のために、私たちはちょうどそれを行います。Let me select individual events boxを選択することで、プロジェクトに合ったイベントを探索して設定することができます。次に、作成するWebhookを追加をクリックします。これで、このリポジトリに変更(プッシュ)があったときに、Jenkinsジョブがビルドできるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/b24cf93c-c3c9-97eb-cd43-4cd419da8159.png)


#ステップ4：コンテナレジストリの設定
ECR ダッシュボードに移動し、管理をクリックします。リポジトリセクションのプッシュイメージまでスクロールします。以下のようなものが表示されるはずです。

```
sudo docker login --username=yourusername registry-intl.yourregion.aliyuncs.com
sudo docker tag [ImageId] registry-intl.yourregion.aliyuncs.com/yournamespace/yourrepositoryname:[tag]
sudo docker push registry-intl.yourregion.aliyuncs.com/yournamespace/yourrepositoryname:[tag]
```

先ほどのJenkinsジョブでビルドステップに追加したものです。

この段階では、アプリケーションに簡単な変更を加えてGitHubにプッシュすることで、全体のセットアップをテストすることができます。GitHubは変更内容をJenkinsに通知し、JenkinsジョブはdockerイメージをビルドしてECRリポジトリに送信します。これはECRリポジトリのダッシュボードで確認できます。管理をクリックしてからタグをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/edc67bcb-aff0-5ca0-91e1-91839063a6e5.png)


#結論
これで、すべての設定と実行が完了しました。

ECRにログインしてイメージを取り出し、アプリケーションを起動すると、8000番ポートで動作します。また、KubernetesやSwarmのようなコンテナクラスタにデプロイすることもできます。

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*