Ubuntu 14.04でTerraformを使用してNode.jsアプリをデプロイする方法

Streamからの記事

前書き

オーケストレーションツールの助けを借りて、DevOpsの専門家は、いくつかのAPI呼び出しを活用してスタックを展開できます。 Terraformは非常にシンプルでありながら強力なツールであり、スタックをコードとして記述し、httpsを使用して定義ファイルをコミットすることで共有し、最新の状態に保つことができます。 //git-scm.com/[Git]。 Terraformは、https://www.vagrantup.com/ [Vagrant]、https://www.packerなどの一般的なオープンソースツールの作成者であるhttps://www.hashicorp.com/[HashiCorp]によって作成されています。 io / [Packer]、およびhttps://www.consul.io/[Consul]。

Terraformは、物理サーバーや仮想サーバーから電子メールやDNSプロバイダーまで、インフラストラクチャを起動するための共通の構成を提供します。 Terraformは、起動されると、構成の進化に合わせてインフラストラクチャを安全かつ効率的に変更します。

このチュートリアルでは、https://digitalocean.com [DigitalOcean]、https:// wwwを使用して、完全に機能する洗練されたhttps://nodejs.org/en/[Node.js]アプリケーションの環境を設定する方法を示します。 terraform.io/[Terraform]、https://cloudinit.readthedocs.io/en/latest/[Cloud-init]、およびhttp://pm2.keymetrics.io/[PM2] Ubuntu 14.04。 サンプルアプリケーションとして、http://cabin.getstream.io [Cabin]、オープンソースhttps://facebook.github.io/react/[React]およびhttp://redux.jsを使用します。 org / docs / basics / UsageWithReact.html [Redux] http://getstream.io [GetStream.io]によって開発されたNode.jsアプリケーション。 最終的な出力は、機能が豊富でスケーラブルなソーシャルネットワークアプリです。

Terraformを使用して、事前定義された構成を使用してキャビンを展開することから始めます。 次に、その構成を深く掘り下げて、どのように機能するかを理解します。

DigitalOceanサーバーにTerraformをインストールするだけの場合は、https://www.digitalocean.com/community/tutorials/how-to-use-terraform-with-digitalocean [TerraformをDigitalOceanで使用する方法]をご覧ください。

前提条件

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

  • このチュートリアルでTerraformを使用して作成する2 GB Ubuntu 14.04サーバー1台。

  • ローカルマシンにインストールされているhttps://git-scm.com/[Git]クライアント。

  • キャビンはログインにFacebookを使用するため、Facebookアカウント。Facebookアプリケーションを作成できます。

  • `+ cabin.example.com +`などのドメイン。このドメインをステップ4で取得するIPv4アドレスにポイントし、FacebookのサイトURLに必要になります。

要件ではありませんが、このチュートリアルでは、http://cabin.getstream.io/ [Stream’s Cabin tutorial series]を完了していることを前提としています。 キャビンがキャビンの機能に不可欠な役割を果たすため、キャビンが本番環境で動作するために必要ないくつかのプロバイダーのAPIキーと設定が必要になります。

これらのサービスの詳細については、Streamの次のブログ投稿をご覧ください。

手順1-サンプルアプリケーションの取得

キャビンサンプルアプリケーションをhttps://github.com/GetStream/stream-react-example[GitHub]からローカルマシン上の任意のディレクトリに複製します。 Macを使用していますが、あなたもそうであると仮定しています。

最初に、ホームディレクトリに移動します。

cd ~

次に、 `+ git +`を使用してリポジトリのクローンを作成します。

git clone https://github.com/GetStream/stream-react-example.git

これにより、サンプルアプリケーションが「+ stream-react-example 」という新しいフォルダーに複製されます。 CabinのTerraformプロジェクトが含まれている ` stream-react-example / terraform / do / cabin +`フォルダーに移動します。

cd stream-react-example/terraform/do/cabin

このフォルダで少し作業します。 しかし、最初にTerraformをセットアップしましょう。

ステップ2-Terraformのインストール

OSXに簡単にインストールする場合は、次のコマンドを発行してhttp://brew.sh/[Homebrew]を使用してTerraformをインストールできます。

brew install terraform

または、http://terraform.ioからTerraformをダウンロードできます。 ダウンロードしたら、以下に示すように、コマンドパスで使用できるようにします。

PATH=:$PATH

これにより、Terraformが一時的にパスに追加されます。 この変更を永続的にしたい場合は、OSXでファイル `+〜/ .bash_profile +`を編集し、次の行を追加します。

〜/ .bash_profile

export PATH=:$PATH

次に、Terraformが適切にインストールされたことを確認するには、次のコマンドを実行します。

terraform

Terraformのオプションを示す次の出力が表示されます。

Outputusage: terraform [--version] [--help] <command> [<args>]

Available commands are:
   apply       Builds or changes infrastructure
   destroy     Destroy Terraform-managed infrastructure
   fmt         Rewrites config files to canonical format
   get         Download and install modules for the configuration
   graph       Create a visual graph of Terraform resources
   init        Initializes Terraform configuration from a module
   output      Read an output from a state file
   plan        Generate and show an execution plan
   push        Upload this Terraform module to Atlas to run
   refresh     Update local state file against real resources
   remote      Configure remote state storage
   show        Inspect Terraform state or plan
   taint       Manually mark a resource for recreation
   untaint     Manually unmark a resource as tainted
   validate    Validates the Terraform files
   version     Prints the Terraform version

Terraformがインフラストラクチャを開始する前に、2つのことを構成する必要があります。

まず、DigitalOceanトークンの世話をしましょう。

手順2-DigitalOceanアクセストークンの構成

Terraformでは、DigitalOcean APIを使用するためにDigitalOceanアクセストークンが必要です。

DigitalOceanアカウントにログインし、* API *リンクをクリックします。 次に、[新しいトークンを生成]ボタンをクリックします。 * Write Access *を必ず確認してください。 ユーザーインターフェースには新しいアクセスキーが表示されます。このアクセスキーはクリップボードにコピーする必要があります。ページに再度アクセスするとキーが表示されなくなるためです。

次に、お気に入りのテキストエディタでファイル `+ variables.tf `を開き、 ` token +`セクションを見つけます。

variables.tf

variable "token" {
 description = "DO Token"
}

テキスト「+ default = +」で始まる新しい行を追加し、DigitalOcean APIトークンを含めます。 トークンを引用符で囲むことを忘れないでください。

variables.tf

variable "token" {
 description = "DO Token"

}

ファイルを保存して閉じます。

それでは、SSHキーペアを使用するようにTerraformを構成しましょう。

ステップ3-SSHキーペアを追加する

Terraformは、作成されたサーバーに接続するためにSSHキーを必要とするため、パッケージをインストールしてアプリケーションをデプロイできます。

`+〜/ .ssh +`ディレクトリを見て、すでにキーペアがあるかどうかを確認します。

ls -al ~/.ssh

ほとんどの場合、秘密キーと公開キーで構成されるキーペアが少なくとも1つあります。 たとえば、 `+ id_rsa.pub `と ` id_rsa +`があります。

キーペアがない場合、または所有しているキーがDigitalOceanアカウントに既に関連付けられている場合は、https://www.digitalocean.com/community/tutorials/how-to-use-ssh-をご覧ください。 keys-with-digitalocean-droplets [SSHキーのセットアップに関するDigitalOceanのチュートリアル]をセットアップします。

APIトークンで行ったように、 `+ .pub `ファイルの内容を ` variables.tf +`ファイルに貼り付ける必要があります。 Macを使用している場合は、次のコマンドを発行して、SSH公開キーをクリップボードにコピーできます。

pbcopy < ~/.ssh/

また、 `+ cat +`コマンドを使用して公開キーの内容を画面に表示し、手動でクリップボードにコピーすることもできます。

cat  ~/.ssh/

次に、エディターでファイル `+ variables.tf `を開き、SSH公開キーファイルの内容を ` sshkey +`設定に追加します。

variables.tf

variable "sshkey" {
 description = "Public ssh key (for Cabin user)"

}

この手順を完了したら、ファイルを保存して終了します。

TerraformとDigitalOceanで使用する新しいキーを生成した場合、これらの2つのコマンドを実行して、デフォルトキーの代わりに新しいキーを使用する必要があります。

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/your_id_rsa

代替キーペアを使用している場合は、新しいシェルを開くたびにこれを実行する必要があります。

Terraformに必要な変数を提供したので、サーバーを作成し、Terraformでアプリを展開する準備ができました。

ステップ4-Terraformの実行

ここからが楽しいところです! 構築するインフラストラクチャを見てみましょう。 Terraformは、サーバーのセットアップからアプリの展開まで、多くの作業を行います。 Terraformに、次のコマンドで何をするかを正確に示すことができます。

terraform plan

このコマンドの出力は非常に詳細なので、次のステートメントに注目してください。

Output+ digitalocean_droplet.cabin-web
...
+ digitalocean_floating_ip.cabin-web-ip
...
+ digitalocean_ssh_key.cabin-ssh-key
...
+ template_file.pm2_processes_conf
...
+ template_file.userdata_web
...

行の先頭にある「」記号は、リソースが作成されることを意味します。 「 digitalocean +」というプレフィックスが付いたリソースは、DigitalOceanで作成されるリソースです。 この特定のケースでは、TerraformはDroplet、フローティングIPを作成し、SSHキーを追加します。

それでは、Terraformを実行して、Dropletでキャビンをスピンします。

terraform apply

しばらくすると、Terraformが次を印刷するのが表示されます。

OutputApply complete! Resources: 6 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

Expected output:

 web_ipv4 =

`+ web_ipv4 +`は、Dropletへのアクセスに使用できるフローティングIPアドレスです。

`++`に表示される値を使用して、新しく作成されたドロップレットにログインします。

ssh cabin@

コマンドを使用することもできます

terraform output web_ipv4

逃した場合、その値に関連付けられたIPアドレスを表示します。

ログインすると、次のウェルカムメッセージが表示されます。

  _____      _     _
 / ____|    | |   (_)
| |     __ _| |__  _ _ __
| |    / _` | '_ \| | '_ \
| |___| (_| | |_) | | | | |
 \_____\__,_|_.__/|_|_| |_|

Initializing Cabin. Please wait... (up 1 minute) | CTRL+C to interrupt

DigitalOceanがインスタンスをプロビジョニングし、 `+ cloud-init +`がCabinに必要なパッケージをインストールするまで数分待つ必要がある場合があります。 しかし、準備ができたら、これが表示されます:

Cabin initialized!
Check running processes...
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid   │ status │ restart │ uptime │ memory      │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ api      │ 0  │ fork │ 14105 │ online │ 0       │ 36s    │ 75.898 MB   │  enabled │
│ app      │ 1  │ fork │ 14112 │ online │ 0       │ 36s    │ 34.301 MB   │  enabled │
│ www      │ 2  │ fork │ 14119 │ online │ 0       │ 36s    │ 50.414 MB   │  enabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app

キャビンが稼働したら、モバイルブラウザで「+ http:// +」を指定します。 キャビンはライブであり、ロード画面が表示されます。 しかし、それは、サーバー上のコードにいくつかの変更を加えるまでです。

ステップ5-(オプション)キャビンの構成

Cabinアプリケーションはデプロイされていますが、まだ使用できません。 Cabinを完全に機能させるには、Facebookおよびその他のいくつかのサービスを構成する必要があります。

最初に、インストールプロセス中に生成された「+ web_ipv4 」アドレスにマッピングされる「 cabin.example.com 」などの有効なドメイン名を使用してFacebookアプリを作成する必要があります。 DNSにレコードを追加するか、ドメインをIPアドレスにマッピングする ` / etc / hosts +`ファイルにエントリを追加します。

Facebookアプリを作成するには、次の手順を実行します。

  1. https://developers.facebook.com/docs/apps/register#step-by-step-guideにアクセスしてください。

  2. Facebookにログインします。

  3. [マイアプリ]で、[新しいアプリを追加]をクリックします。

  4. アプリケーションの名前を入力します(例: + Cabin-My Example App +)。

  5. *連絡先メールアドレス*を入力してください。

  6. *カテゴリ*では、ドロップダウンメニューを使用してアプリのカテゴリを選択します。 私たちの場合、それは*ライフスタイル*です。

  7. [*アプリIDの作成]ボタンをクリックします。

  8. 必要に応じて、キャプチャを完了します。

  9. `+ appId +`をコピーします。 画面の上部にある数値になります。 まもなく必要になります。

  10. 左側のサイドバーから[ダッシュボード]を選択します。

  11. 見出し* Facebook SDKの開始*の下で、*プラットフォームの選択*をクリックします。

  12. プラットフォームに* Web *を選択します。

  13. * Site URL *フィールドを見つけて、「+ http://cabin.example.com+」と入力します。

  14. [次へ]をクリックします。

問題が発生した場合は、https://developers.facebook.com/docs/apps/register#step-by-step-guide [このステップバイステップガイド]に従ってください。 行き詰まった場合は、Facebookでのアプリケーション設定のデバッグに関する素晴らしい記事があります。https://www.facebook.com/help/community/question/?id = 589302607826562 [こちら]をご覧ください。

`+ appID `を取得したら、サーバーのデフォルトの ` appID +`設定を置き換える必要があります。

そのため、サーバーにログインしていることを確認してください。 そうでない場合は、再度ログインしてください:

ssh cabin@

ログインしたら、ファイル `+〜/ stream-react-example / app / views / index.ejs +`を開きます:

nano ~/stream-react-example/app/views/index.ejs

デフォルトの `+ appId +`をFacebookが提供するものに変更します。

strea-react-example / app / views / index.ejs

FB.init({
   appId   : ,
   xfbml   : true,
   version : 'v2.6',
   status  : true,
   cookie  : true,
})

このファイルを保存して閉じます。

次に、サーバーを作成したときにTerraformによって生成されたキャビンのデータベースパスワードを知る必要があります。 この値を取得するには、次のコマンドを入力します。

grep DB_PASSWORD processes.yml

このパスワードをコピーしてください。間もなく必要になります。

ファイル「+ env.sh +」は、キャビンが依存するさまざまなプロバイダーおよびサービスの資格情報を入力する場所です。 このファイルはこれらの資格情報を環境変数に配置し、環境変数はアプリケーションによって読み取られます。 これは、パスワードとキーをGitから保護するため、セキュリティ上の予防措置です。

`+ env.sh +`を開きます:

nano env.sh

次のコンテンツが表示されます。

Outputexport NODE_ENV=production
export JWT_SECRET=ABC123
export DB_USERNAME=cabin
export DB_HOST=localhost
export DB_PASSWORD=VALUE
export DB_PORT=3306
export MAPBOX_ACCESS_TOKEN=ADD_VALUE_HERE
export S3_KEY=ADD_VALUE_HERE
export S3_SECRET=ADD_VALUE_HERE
export S3_BUCKET=ADD_VALUE_HERE
export STREAM_APP_ID=ADD_VALUE_HERE
export STREAM_KEY=ADD_VALUE_HERE
export STREAM_SECRET=ADD_VALUE_HERE
export ALGOLIA_APP_ID=ADD_VALUE_HERE
export ALGOLIA_SEARCH_ONLY_KEY=ADD_VALUE_HERE
export ALGOLIA_API_KEY=ADD_VALUE_HERE
export KEEN_PROJECT_ID=ADD_VALUE_HERE
export KEEN_WRITE_KEY=ADD_VALUE_HERE
export KEEN_READ_KEY=ADD_VALUE_HERE
export IMGIX_BASE_URL=https://react-example-app.imgix.net/uploads
export API_URL=http://localhost:8000

ご覧のとおり、このファイルは、キャビンが必要とするさまざまなサービスに関する情報を保持する一連の環境変数をエクスポートします。 キャビンを本番環境で使用するには、これらのすべての値を入力する必要があります。

これらの設定の簡単な内訳は次のとおりです。

  1. * NODE_ENV *:Node.jsが実行される環境。 (生産では速度が向上します)。

  2. * JWT_SECRET *:APIとWeb(アプリ)インターフェース間のJSON Web Token認証の認証シークレット。

  3. * DB_USERNAME *:データベースのユーザー名。

  4. * DB_HOST *:データベースのホスト名。

  5. * DB_PASSWORD *:データベースのパスワード。`+ processes.yml + `を見て表示したばかりです。

  6. * DB_PORT *:データベースポート(MySQLのデフォルトポート3306)。

  7. * MAPBOX_ACCESS_TOKEN *:MapBoxのアクセストークン(写真の場所のマッピング用)。

  8. * S3_KEY *:イメージストレージ用のAmazon S3キー。

  9. * S3_SECRET *:イメージストレージのAmazon S3シークレット。

  10. * S3_BUCKET *:イメージストレージ用のAmazon S3バケット。 このバケットが存在することを確認してください。

  11. * STREAMAPPID *:ストリームアプリID。 このIDに関連付けられているアプリに、必要なフィードグループがすべて存在することを確認してください。

  12. * STREAM_KEY *:ストリームAPIキー。

  13. * STREAM_SECRET *:アプリシークレットをストリーミングします。

  14. * ALGOLIA_APP_ID *:検索用のアルゴリアアプリID。

  15. * ALGOLIA_SEARCH_ONLY_KEY *:検索用のアルゴリア検索専用キー。

  16. * ALGOLIA_API_KEY *:検索用のAlgolia APIキー。

  17. * KEEN_PROJECT_ID *:Keen追跡プロジェクトID(統計用)。

  18. * KEEN_WRITE_KEY *:キーン追跡書き込みキー(統計用)。

  19. * KEEN_READ_KEY *:キーントラッキング読み取りキー(統計用)。

  20. * IMGIX_BASE_URL *:ImgixベースURL(特定のサイズで写真をレンダリングするため)。

  21. * API_URL *:このアプリケーションがAPIに使用するURL。 これを「+ localhost 」から「 cabin.example.com +」などのIPアドレスを指すドメインに変更する必要があります。

参照される環境変数とサービスの詳細については、次のブログ投稿を参照して、指定されたとおりに各アプリケーションを構成してください。

すべてのプロバイダーを構成したら、データベースのパスワードとプロバイダーの値を `+ env.sh +`ファイルに入力します。

終了して、 `+ env.sh +`ファイルを保存します。 次に、ファイルを入手し、キャビンが使用する環境値に値をロードします。

source ./env.sh

次に、 `+ webpack `コマンドを実行する必要があります。 Webpackは、キャビンのフロントエンドコードを管理するJavaScriptビルドツールです。 Webpackは、変更したばかりの ` env.sh `ファイルによって設定された値に基づいてJavaScriptファイルとCSSファイルを再生成します。 したがって、 ` app +`ディレクトリに移動します。

cd app

そして、 `+ webpack +`コマンドを実行して、フロントエンドJavaScriptファイルを再構築します。 これにより、プロバイダートークンの一部がフロントエンドコードに挿入されます。

webpack --progress --color

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

OutputHash: 64dcb6ef9b46a0243a8c
Version: webpack 1.13.1
Time: 21130ms
                 Asset     Size  Chunks             Chunk Names
    ./public/js/app.js  2.22 MB       0  [emitted]  app
./public/css/styles.css    23 kB       0  [emitted]  app
  [0] multi app 28 bytes {0} [built]
   + 685 hidden modules
Child extract-text-webpack-plugin:
       + 2 hidden modules
Child extract-text-webpack-plugin:
       + 2 hidden modules

設定が完了したら、PM2を実行してすべてのアプリケーションプロセスをリロードし、すべてのコンポーネントが新しい設定を使用するようにします。

pm2 restart all
Output[PM2] Applying action restartProcessId on app [all](ids: 0,1,2)
[PM2] [api](0) ✓
[PM2] [app](1) ✓
[PM2] [www](2) ✓
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid   │ status │ restart │ uptime │ memory      │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ api      │ 0  │ fork │ 30834 │ online │ 516     │ 0s     │ 39.027 MB   │  enabled │
│ app      │ 1  │ fork │ 30859 │ online │ 9       │ 0s     │ 22.504 MB   │  enabled │
│ www      │ 2  │ fork │ 30880 │ online │ 9       │ 0s     │ 19.746 MB   │  enabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘

それでおしまい! これで、リモートサーバーからログアウトできます。

exit

最後に、ブラウザでもう一度「+ http:// +」にアクセスしてサイトを表示します。 これにより、Facebookにログインするためのリンクを含むカバー画像が表示されます。 ログインすると、後でアプリを調べることができます。

次に、この展開を可能にしたTerraformの構成を詳しく見てみましょう。

ステップ6-構成タイルの調査

では、これはどのように機能しますか? ローカルマシンにクローンを作成したリポジトリ内のファイルを見てみましょう。 このセクションでは変更する必要はありませんが、各部分がどのように組み合わされるかを感じることができるように、自分のマシンで実行する必要があります。

Terraformプロジェクトは複数のファイルとディレクトリに分割されており、アプリケーションをクリーンで理解しやすくしています。 DigitalOceanファイルはすべて、リポジトリの `+ terraform / do +`ディレクトリ内に配置しました。このディレクトリの構造は次のとおりです。

テラフォルムフォルダー

do
└── cabin
   ├── files
   │   ├── cabin-web-nginx.conf
   │   └── cabin_mysql_init.sh
   ├── main.tf
   ├── outputs.tf
   ├── templates
   │   ├── processes.tpl
   │   └── web.tpl
   └── variables.tf

`+ main.tf +`で始まる上記のファイルを見てみましょう。 お気に入りのテキストエディタで開きます。

最初に行うことは、使用するクラウドプロバイダーをTerraformに伝えることです。

main.tf

provider "DigitalOcean" {
 token = "${var.token}"
}

DigitalOceanプロバイダーの定義は、それと同じくらい簡単です。 サポートされているプロバイダーの完全なリストは、https://www.terraform.io/docs/providers/index.html [Terraform documentation]にあります。

変数構成

Terraformでは、変数を定義できます。つまり、展開のデフォルトを設定できます。 そうすれば、毎回詳細を入力したり、設定全体に値をハードコーディングしたりする必要がなくなります。 DigitalOceanに展開するための変数の設定方法を見てみましょう。

Cabinアプリケーションの実行に必要な変数を定義した場所である `+ variables.tf +`を見てください。

variables.tf

variable "token" {
 description = "DO Token"
}

variable "region" {
 description = "DO Region"
}

Terraform内で変数がどのように処理されるかをよりよく理解するために、上記の例を見てみましょう。

リージョン変数には、デフォルト値を指定しました。 デフォルト値を指定しない場合、Terraformは次の例に示すように、デフォルト値を要求します。

Outputterraform plan
var.token
 DO Token

 Enter a value:

`+ terraform apply `を実行するときに変数を指定することもできます。 たとえば、別の地域を指定する場合は、 ` var +`引数を指定してTerraformを実行できます。

terraform -var 'region=ams3' apply

これは、構成された設定をオーバーライドします。

液滴のセットアップ

`+ main.tf +`では、TerraformにDigitalOceanにドロップレットをプロビジョニングするように指示します。 デフォルトでは、次の特性を持つサーバーをデプロイします。

main.tf

resource "digitalocean_droplet" "cabin-web" {
 image = "ubuntu-14-04-x64"
 name = "cabin-web"
 region = "${var.region}"
 size = "2gb"
 ssh_keys = [ "${digitalocean_ssh_key.cabin-ssh-key.id}" ]
 user_data = "${template_file.userdata_web.rendered}"
}
  • cabin-web と呼ばれる2GBのRAMを備えた新しいDigitalOcean Dropletを作成し、画像 ubuntu-14-04-x64 *を使用しています。 上記のリソース定義を見ると、サーバーの画像とサイズを簡単に変更できることがわかります。

ユーザーデータとCloud-Init

さて、「+ user-data」とは正確には何ですか? ブート時にクラウドインスタンスにコマンドと指示を送信する最も簡単な方法です。 `+ cloud-init +`と組み合わせると、https://www.chef.io/chef/ [Chef]やhttps://puppet.com/などの不要なサードパーティアプリケーションを活用せずにインスタンスを設定する強力な方法になります[傀儡]。

`+ cloud-init +`プログラムは多くのLinuxディストリビューションに組み込まれています。 ユーザーの追加、グループの管理、ファイルの作成、root権限でのスクリプトまたはシェルコマンドの実行などの簡単なタスクを実行できるようにする簡単な手順があります。

`+ user_data +`属性に飛び込んで、それが何であるかをよりよく理解できるようにしましょう。

main.tf

resource "digitalocean_droplet" "cabin-web" {
 ...
 user_data = "${template_file.userdata_web.rendered}"
}

私たちの目標は、キャビンを稼働させた状態で新しいDropletを起動し、 `+ cloud-init `が私たちのために重荷を処理することです。 ` user_data `フィールドはテンプレートファイルを指し、変数は ` main.tf +`の別の宣言を指します。

main.tf

resource "template_file" "userdata_web" {
 template = "${file("${path.module}/templates/web.tpl")}"

 vars {
   userdata_sshkey = "${var.sshkey}"
   userdata_nginx_conf = "${base64encode(file("${path.module}/files/cabin-web-nginx.conf"))}"
   userdata_mysql_init = "${base64encode(file("${path.module}/files/cabin_mysql_init.sh"))}"
   userdata_pm2_conf = "${base64encode("${template_file.pm2_processes_conf.rendered}")}"
   userdata_env = "${base64encode("${template_file.env.rendered}")}"
   userdata_motd = "${base64encode(file("${path.module}/files/motd"))}"
   userdata_motd_script = "${base64encode(file("${path.module}/files/motd.sh"))}"
   userdata_giturl = "${var.git_url}"
   userdata_index = "${base64encode(file("${path.module}/files/index.html"))}"
 }
}

Terraformは、テキストを変換できる機能を提供します。 この機能を使用して、ファイルを読み取り、内容をBase64でエンコードされた文字列に変換して、API呼び出しで転送できるようにすることで、テンプレートに値を挿入できます。

この特定のセクションは、サーバーで実行するすべての設定とコマンドを含むテンプレート「+ templates / web.tpl +」のデータを準備します。

`+ web.tpl +`ファイルを見て、それが何をするのか見てみましょう。

最初の部分では、初期ユーザーを設定し、ルートアクセスを無効にします。

templates / web.tpl

#cloud-config
users:
 - name: cabin
   groups: sudo
   sudo: ['ALL=(ALL) NOPASSWD:ALL']
   shell: /bin/bash
   home: /home/cabin
   lock_passwd: true
   ssh-authorized-keys:
     - ${userdata_sshkey}

disable_root: true

+ web.tpl`の最初のステートメントは #cloud-config`でなければなりません。 これを追加するのを忘れると、 ` cloud-init +`は設定を取得せず、指定されたコマンドはターゲットインスタンスで実行されません。

このセクションのコマンドは次のことを行います。

  • スーパーユーザーになるための許可を得て、システムに `+ cabin +`ユーザーを追加します

  • `+ lock-passwd:true `はパスワード認証を拒否するため、 ` cabin +`ユーザーはサーバーにアクセスするためにSSHキー認証を使用する必要があります。

  • `+ ssh-authorized-keys +`は、ユーザーのssh-keyをauthorized_keysファイルにインストールします。

  • `+ disable_root:true +`はルートとしてのSSHアクセスを無効にするために使用されます

`+ $ {userdata_sshkey} `は、 ` main.tf +`でテンプレートを呼び出したときに設定された変数であることに注意してください。

次に、MySQL、Nginx、Git、およびアプリケーションに必要な他のパッケージをインストールします。

package_update: true
packages:
- mysql-server-5.6
- libmysqlclient-dev
- iptables-persistent
- git
- nginx
- npm
- pwgen

`+ cloud-init `でパッケージをインストールする最も簡単な方法は、Packageモジュールを利用して特定のパッケージのリストをインストールすることです。 このモジュールは、配布にデフォルトのパッケージマネージャーを使用します。 Ubuntuを使用しているため、このプロセスでは ` apt +`でパッケージがインストールされます。

次に、テンプレートに渡したデータをファイルコンテンツとして使用して、いくつかのファイルをファイルシステムに書き込みます。

write_files:
- encoding: b64
  content: ${userdata_nginx_conf}
  path: /tmp/cabin-web.conf
- encoding: b64
  content: ${userdata_pm2_conf}
  path: /tmp/processes.yml
- encoding: b64
  content: ${userdata_mysql_init}
  path: /tmp/cabin_mysql_init.sh
  permissions: '0554'

このセクションはファイルを作成するために `+ write_file +`モジュールを活用します。 上記の例では、次のファイルを作成しています。

  • `+ cabin-web.conf +`にはNGINX設定が含まれています。

  • Node.jsプロセスを処理するためにPM2によって使用される「+ processes.yml +」。

  • `+ cabin_mysql_init.sh +`は、MySQLデータベースを初期化するために使用されるカスタムスクリプトです。

データをテンプレートに渡すときに、Base64としてエンコードしたことに注意してください。 ファイルを書き込むときにエンコードを指定して、コンテンツをデコードできるようにします。

次のセクションでは、 `+ runcmd `モジュールを使用していくつかのシェルコマンドを実行し、 ` iptables +`を使用してファイアウォールルールを作成します。

runcmd:
- iptables -A INPUT -i lo -j ACCEPT
- iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
- iptables -A INPUT -p tcp --dport ssh -j ACCEPT
- iptables -A INPUT -p tcp --dport 80 -j ACCEPT
- iptables -A INPUT -p tcp --dport 8000 -j ACCEPT
- iptables -A INPUT -p tcp --dport 3000 -j ACCEPT
- iptables -A INPUT -j DROP
- iptables -A OUTPUT -j ACCEPT
- invoke-rc.d iptables-persistent save
…

次に、コードは、インスタンスが再起動した場合にファイアウォール設定を利用可能にするために、 `+ iptables-persistent +`を使用します。

ファイアウォールルールが設定された後、キャビンをセットアップして起動する残りのコマンドが実行されます。

- apt-get update --fix-missing
- curl -sL https://deb.nodesource.com/setup_5.x | bash && apt-get install -y nodejs
- npm install pm2 webpack -g
- cd /home/cabin && sudo -u cabin git clone ${userdata_giturl}
- mv /tmp/env.sh /home/cabin/stream-react-example/env.sh
- cd /home/cabin/stream-react-example/api && sudo -u cabin npm install
- cd /home/cabin/stream-react-example/app && sudo -u cabin npm install
- cd /home/cabin/stream-react-example/www && sudo -u cabin npm install
- chown cabin.cabin /home/cabin/stream-react-example/env.sh && /home/cabin/stream-react-example/env.sh
- mv /tmp/processes.yml /home/cabin/stream-react-example/processes.yml
- chown cabin.cabin /home/cabin/stream-react-example/processes.yml
- /tmp/cabin_mysql_init.sh
- cd /home/cabin/stream-react-example && sudo -u cabin pm2 start processes.yml
- mv /tmp/cabin-web.conf /etc/nginx/sites-available/cabin-web
- rm /etc/nginx/sites-enabled/default
- ln -s /etc/nginx/sites-available/cabin-web /etc/nginx/sites-enabled
- service nginx reload

これらのコマンドはすべてルート権限で実行され、最初のブート時にのみ実行されます。 マシンを再起動すると、 `+ runcmd +`は再度実行されません。

Terraformについてさらに学習したので、インフラストラクチャのライフサイクルを処理する方法を調べてみましょう。

ステップ7-スタックのライフサイクルを管理する

Terraformを使用すると、スタックの状態の保存、スタックの更新、破棄、およびコード変更の展開が可能になります。

「+ terraform apply 」を実行すると、「 terraform.tfstate 」というファイルが「 cabin +」ディレクトリに作成されることに気づいたかもしれません。

このファイルには、DigitalOceanで作成された実際のリソースへの参照が含まれているため、非常に重要です。 基本的に、このファイルはTerraformに管理するリソースの識別子を伝えます。

「+ terraform apply +」を再度実行すると、Terraformは最初からやり直さず、作成したすべてを消去します。 代わりに、まだ終了していない部分のみを実行します。 したがって、ネットワークの問題またはAPIの問題が原因でプロセスが途中で失敗した場合、問題に対処してコマンドを再実行できます。 Terraformは中断したところから再開します。

ドロップレット構成の変更

「+ terraform apply +」を使用して、ドロップレットの構成を変更することもできます。 たとえば、データセンターや地域を変更する必要がある場合、またはより多くのトラフィックに対応するためにDropletが使用するメモリを増やす場合、Terraformは両方のタスクを非常に簡単にします。

「+ terraform apply 」コマンドを実行し、「 region 」変数と「 droplet_size +」変数をオーバーライドすることで、ドロップレット領域を調整できます。 これにより、Terraformは既存のドロップレットを破棄する必要があることを認識し、要件を満たすために新しいドロップレットをプロビジョニングする必要があります。

ドロップレットを保持するリージョンまたはデータセンターを変更する場合は、次のコマンドを実行します。

terraform apply

また、ユーザーベースが拡大するにつれて、追加のトラフィックに対応するためにドロップレットのサイズを変更する必要があります。 次のように、 `+ droplet_size +`変数でそれを行うことができます:

terraform apply

ドロップレットが削除され、新しいドロップレットに置き換えられ、アプリケーションが再デプロイおよび構成されます。

スタックを破壊する

Terraformの驚くべきことの1つは、スタックのライフサイクル全体を処理することです。 1つの単純なTerraformコマンドを実行することで、構築したものを簡単に破棄できます(破棄)。

terraform destroy

Terraformは、すべてのリソースを実際に破棄することを確認するように求めます。

OutputDo you really want to destroy?
 Terraform will delete all your managed infrastructure.
 There is no undo. Only 'yes' will be accepted to confirm.

 Enter a value: yes

Terraformが完了すると、最終的な出力は次のようになります。

Outputdigitalocean_droplet.cabin-web: Destroying...
digitalocean_droplet.cabin-web: Still destroying... (10s elapsed)
digitalocean_droplet.cabin-web: Destruction complete
digitalocean_ssh_key.cabin-ssh-key: Destroying...
template_file.userdata_web: Destroying...
template_file.userdata_web: Destruction complete
template_file.pm2_processes_conf: Destroying...
template_file.pm2_processes_conf: Destruction complete
digitalocean_ssh_key.cabin-ssh-key: Destruction complete

Apply complete! Resources: 0 added, 0 changed, 5 destroyed.

ご覧のとおり、すべてのリソースが破壊されました。

新しいバージョンのコードの展開

コードベースに変更を加えた場合、ほとんど、またはまったくダウンタイムなしで変更をサーバーに反映する必要があります。 サーバーにPM2がインストールされており、それが私たちのために重荷を処理します。

PM2は、アプリケーションのファイルシステムの変更をリッスンします。 コードの新しいバージョンを実行するには、ドロップレットにSSHで接続し、アプリケーションを含むディレクトリで `+ git pull +`コマンドを発行します。 これにより、リポジトリからプルするようサーバーに指示します。 ファイルが変更されると、PMZはノードプロセスを自動的に再起動します。

たとえば、新しいバージョンのキャビンがあり、最新バージョンのコードをサーバーに展開する場合、サーバーにログインします。

ssh cabin@

次に、サーバー上で、キャビンアプリケーションを含むフォルダーに移動します。

cd ~/stream-react-example

そして最後に最新バージョンをプルダウンします。

git pull

新しいコードが配置されると、アプリは自動的に再起動し、訪問者には最新バージョンが表示されます。 何らかの理由でPM2が変更をキャッチしない場合は、

pm2 restart all

すべてのコンポーネントが再起動します。

結論

DigitalOcean、Terraform、Cloud-init、PM2を使用して、キャビンの実稼働環境を正常にセットアップしました。

Terraformを使用する場合、インフラストラクチャはすべてコードとして保存されます。 これにより、チームは簡単に変更を追跡して共同作業を行うことができます。 また、比較的簡単に大規模なインフラストラクチャの変更を行うことができます。

Related