前書き
アプリを作成したら、今すぐデプロイする必要があります。 実稼働環境を作成してアプリをVMにセットアップすることもできますが、人気が出たときにどのようにスケーリングしますか? 新しいバージョンをどのように展開しますか? 負荷分散はどうですか? そして、最も重要なのは、構成が正しいことをどのように確認できるかということです。 これをすべて自動化して、時間を大幅に節約できます。
このチュートリアルでは、Salt Cloudマップファイルでアプリケーションを定義する方法を示します。これには、カスタムSaltグレインを使用してサーバーにロールを割り当て、リバースプロキシを動的に構成することが含まれます。
このチュートリアルの最後には、2つの基本的なアプリサーバー、動的に構築された構成を持つNginxリバースプロキシ、および数分でアプリケーションをスケーリングする機能があります。
前提条件
このチュートリアルを実行するには、次のものが必要です。
-
1 GB CentOS 7ドロップレット1つ。 このチュートリアルのすべてのコマンドはrootとして実行されるため、sudoの非rootユーザーを作成する必要はありません。
-
* root *ユーザーのDroplet上のSSHキー(つまり、 ドロップレットで作成された新しいキーペア)。 このSSHキーをDigitalOceanコントロールパネルに追加して、それを使用してマスタードロップレットから他のDigitalOceanドロップレットにログインできるようにします。 手順については、https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets [DigitalOcean DropletsでSSHキーを使用する方法]チュートリアルを使用できます。 + DigitalOceanコントロールパネルでキーに割り当てた名前を書き留めます。 このチュートリアルでは、名前を使用しています。 秘密鍵の場所も書き留めてください。デフォルトでは、 `+ / root / .ssh / id_rsa +`です。
-
https://www.digitalocean.com/community/tutorials/how-to-use-the-digitalocean-api-v2#how-to-generateのこの手順の指示に従って作成できる個人用アクセストークン-a-personal-access-token [DigitalOcean APIv2の使用方法]。 読み取りと書き込みのスコープを設定してください。
手順1-SaltおよびSalt Cloudのインストール
開始するには、サーバーにSalt Cloudをインストールして構成する必要があります。 このチュートリアルでは、Saltブートストラップスクリプトを使用します。
最初に、Saltブートストラップスクリプトをエッチングして、Saltをインストールします。
wget -O install_salt.sh https://bootstrap.saltstack.com
Saltブートストラップスクリプトを実行します。 `+ -M `フラグを使用して、 ` salt-master +`もインストールします。
sh install_salt.sh -M
Salt CloudコードベースはコアのSaltプロジェクトに統合されていますが、CentOS用に個別にパッケージ化されています。 幸いなことに、 `+ install_salt `スクリプトがリポジトリを設定してくれたので、yumで ` salt-cloud +`をインストールするだけです。
yum install salt-cloud
これで、Salt Cloudのバージョンを確認して、インストールが成功したことを確認できます。
salt-cloud --version
次のような出力が表示されます。
salt-cloud –versionの出力
salt-cloud 2015.5.3 (Lithium)
Saltはローリングリリースサイクルにあるため、バージョンが上記と若干異なる場合があります。
ステップ2-Salt Cloudの構成
このセクションでは、DigitalOceanに接続するようにSalt Cloudを構成し、ドロップレットのプロファイルを定義します。
DigitalOceanプロバイダーファイルの構成
Salt Cloudでは、_provider files_は、新しいVMを作成する場所を定義する場所です。 プロバイダーは `+ / etc / salt / cloud.providers.d +`ディレクトリで定義されます
`+ nano +`またはお好みのテキストエディターを使用して、DigitalOceanプロバイダーファイルを作成して開きます。
nano /etc/salt/cloud.providers.d/digital_ocean.conf
以下のテキストを挿入し、変数を自分のものに置き換えます。つまり、サーバーIPとアクセストークン、およびカスタマイズした場合はSSHキー名とファイルです。
/etc/salt/cloud.providers.d/digital_ocean.conf
### /etc/salt/cloud.providers.d/digital_ocean.conf ###
######################################################
do:
provider: digital_ocean
minion:
master:
# DigitalOcean Access Token
personal_access_token:
# This is the name of your SSH key in your Digital Ocean account
# as it appears in the control panel.
ssh_key_name:
# This is the path on disk to the private key for your Digital Ocean account
ssh_key_file:
SSHキーファイルの権限をロックダウンする必要があります。 そうしないと、SSHはその使用を拒否します。 yoursがデフォルトの場所 `+ / root / .ssh / id_rsa +`にあると仮定すると、次のようにできます:
chmod 600 /root/.ssh/id_rsa
デプロイ可能なサーバーのプロファイルの構成
Salt Cloudでは、_profiles_は、プロバイダーに関連付けられている個々のVMの説明です(例: 「DigitalOcean上の512 MB Ubuntu VM」)。 これらは `+ / etc / salt / cloud.profiles.d +`ディレクトリで定義されています。
プロファイルファイルを作成して開きます。
nano /etc/salt/cloud.profiles.d/digital_ocean.conf
以下をファイルに貼り付けます。 変更は不要です。
/etc/salt/cloud.profiles.d/digital_ocean.conf
### /etc/salt/cloud.profiles.d/digital_ocean.conf ###
#####################################################
ubuntu_512MB_ny3:
provider: do
image: ubuntu-14-04-x64
size: 512MB
location: nyc3
private_networking: True
ubuntu_1GB_ny3:
provider: do
image: ubuntu-14-04-x64
size: 1GB
location: nyc3
private_networking: True
ファイルを保存して閉じます。 このファイルは2つのプロファイルを定義します。
-
512 MBのメモリを搭載したUbuntu 14.04 VM。ニューヨーク3リージョンに展開されています。
-
ニューヨーク3リージョンに展開された、1 GBのメモリを備えたUbuntu 14.04 VM。
Ubuntu 14.04以外のイメージを使用する場合は、Salt Cloudを使用して、次のコマンドでDigitalOceanで使用可能なすべてのイメージ名をリストできます。
salt-cloud --list-images do
これにより、すべての標準DigitalOceanイメージと、スナップショットツールでアカウントに保存したカスタムイメージが表示されます。 プロバイダーファイルで使用したイメージ名またはリージョンを、このリストとは異なるイメージ名に置き換えることができます。 その場合は、プロファイルファイルの設定でこの出力のフィールドを必ず使用してください。
クイッククエリで構成をテストします。
salt-cloud -Q
次のようなものが見えるはずです。
salt-cloud -Qの出力例
[INFO ] salt-cloud starting
do:
----------
digital_ocean:
----------
centos-salt:
----------
id:
2806501
image_id:
6372108
public_ips:
192.241.247.229
size_id:
63
state:
active
これは、Salt CloudがDigitalOceanアカウントと通信しており、2つの基本プロファイルが構成されていることを意味します。
ステップ3-単純なマップファイルの作成
マップファイルは、作成するプロファイルとサーバーの数をリストするYAMLファイルです。 単純なマップファイルから始めて、次のセクションでその上に構築します。
上記のプロファイルを使用して、1つの512 MBリバースプロキシを前面に配置した2つの1 GBアプリサーバーが必要だとします。 `+ / etc / salt / cloud.maps.d / do-app-with-rproxy.map +`という名前のマップファイルを作成し、アプリを定義します。
まず、ファイルを作成します。
nano /etc/salt/cloud.maps.d/do-app-with-rproxy.map
次のテキストを挿入します。 変更は不要です。
/etc/salt/cloud.maps.d/do-app-with-rproxy.map
### /etc/salt/cloud.maps.d/do-app-with-rproxy.map ####
######################################################
ubuntu_512MB_ny3:
- nginx-rproxy
ubuntu_1GB_ny3:
- appserver-01
- appserver-02
それでおしまい! これは、マップファイルと同じくらい簡単です。 先に進み、これらのサーバーを次のもので展開します。
salt-cloud -m /etc/salt/cloud.maps.d/do-app-with-rproxy.map
コマンドが終了したら、簡単なpingで成功を確認します。
salt '*' test.ping
以下が表示されるはずです。
[label salt '*' test.ping
appserver-01:
True
appserver-02:
True
nginx-rproxy:
True
マップファイルにVMを正常に作成したら、それらを削除するのも簡単です。
salt-cloud -d -m /etc/salt/cloud.maps.d/do-app-with-rproxy.map
ただし、このコマンドは注意して使用してください。 そのマップファイルで指定されたVMをすべて削除します。
ステップ4-より現実的なマップファイルの作成
そのマップファイルは正常に機能しましたが、シェルスクリプトでさえVMのセットを起動できました。 必要なのは、アプリケーションのフットプリントを定義することです。 マップファイルに戻り、さらにいくつかを追加しましょう。マップファイルを再度開きます。
nano /etc/salt/cloud.maps.d/do-app-with-rproxy.map
ファイルの以前の内容を削除し、次の内容をその中に配置します。 変更する必要はありません。
/etc/salt/cloud.maps.d/do-app-with-rproxy.map
### /etc/salt/cloud.maps.d/do-app-with-rproxy.map ###
#####################################################
ubuntu_512MB_ny3:
- nginx-rproxy:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: rproxy
ubuntu_1GB_ny3:
- appserver-01:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
- appserver-02:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
今、私たちはどこかに到達しています! たくさん見えますが、追加したのは2つだけです。 2つの追加項目、「+ mine_functions 」セクションと「 grains +」セクションを見ていきましょう。
これらのVMのSalt Minion構成を変更し、カスタムのhttp://docs.saltstack.com/en/latest/topics/targeting/grains.html[grains]を追加するように、Salt Cloudに指示しました。 具体的には、グレインはリバースプロキシVMに「+ rproxy 」ロールを付与し、アプリサーバーに「 appserver +」ロールを付与します。 これは、リバースプロキシを動的に構成する必要がある場合に便利です。
`+ mine_functions +`もSalt Minionの設定に追加されます。 Minionに、* eth0 *で見つかったIPアドレスをhttp://docs.saltstack.com/en/latest/topics/mine/[Salt mine]に保存されるSalt Masterに送信するよう指示します。 これは、Salt Masterが新しく作成したDropletのIPを自動的に認識するため、設定する必要はありません。 これは次のパートで使用します。
ステップ5-リバースプロキシの定義
目の前に共通のタスクがあります。リバースプロキシWebサーバーをインストールして構成します。 このチュートリアルでは、Nginxをリバースプロキシとして使用します。
Nginx Saltステートの記述
手を汚し、いくつかのソルトの状態を書きます。 最初に、デフォルトのソルト状態ツリーの場所を作成します。
mkdir /srv/salt
そのディレクトリに移動し、nginx専用のディレクトリをもう1つ作成します。
cd /srv/salt
mkdir /srv/salt/nginx
そのディレクトリに移動し、お気に入りのエディターを使用して、 `+ rproxy.sls +`という新しいファイルを作成します。
cd /srv/salt/nginx
nano /srv/salt/nginx/rproxy.sls
そのファイルに以下を配置します。 変更する必要はありません。
/srv/salt/nginx/rproxy.sls
### /srv/salt/nginx/rproxy.sls ###
##################################
### Install Nginx and configure it as a reverse proxy, pulling the IPs of
### the app servers from the Salt Mine.
nginx-rproxy:
# Install Nginx
pkg:
- installed
- name: nginx
# Place a customized Nginx config file
file:
- managed
- source: salt://nginx/files/awesome-app.conf.jin
- name: /etc/nginx/conf.d/awesome-app.conf
- template: jinja
- require:
- pkg: nginx-rproxy
# Ensure Nginx is always running.
# Restart Nginx if the config file changes.
service:
- running
- enable: True
- name: nginx
- require:
- pkg: nginx-rproxy
- watch:
- file: nginx-rproxy
# Restart Nginx for the initial installation.
cmd:
- run
- name: service nginx restart
- require:
- file: nginx-rproxy
この状態は次のことを行います。
-
Nginxをインストールします。
-
カスタム設定ファイルを `+ / etc / nginx / conf.d / awesome-app.conf +`に配置します。
-
Nginxが実行されていることを確認します。
Saltの状態は、Nginxをインストールし、構成ファイルをドロップするだけです。本当に興味深いコンテンツは設定にあります。
Nginxリバースプロキシ設定ファイルの作成
構成ファイル用にもう1つディレクトリを作成しましょう。
mkdir /srv/salt/nginx/files
cd /srv/salt/nginx/files
そして設定ファイルを開きます:
nano /srv/salt/nginx/files/awesome-app.conf.jin
構成ファイルに次を入力します。 プライベートネットワーキングを使用していない場合を除き、変更する必要はありません。その場合は、インラインに記載されているように「1」を「0」に変更します。
/srv/salt/nginx/files/awesome-app.conf.jin
### /srv/salt/nginx/files/awesome-app.conf.jin ###
##################################################
### Configuration file for Nginx to act as a
### reverse proxy for an app farm.
# Define the app servers that we're in front of.
upstream awesome-app {
{% for server, addrs in salt['mine.get']('roles:appserver', 'network.ip_addrs', expr_form='grain').items() %}
server {{ addrs[0] }}:1337;
{% endfor %}
}
# Forward all port 80 http traffic to our app farm, defined above as 'awesome-app'.
server {
listen 80;
server_name {{ salt['network.ip_addrs']()[] }}; #
# DigitalOcean's private networking.
access_log /var/log/nginx/awesome-app.access.log;
error_log /var/log/nginx/awesome-app.error.log;
## forward request to awesome-app ##
location / {
proxy_pass http://awesome-app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
ファイルにhttp://docs.saltstack.com/en/latest/ref/renderers/all/salt.renderers.jinja.html[Jinja templating]が含まれていることを伝えるために、 `+ .jin +`拡張機能を使用します。 Jinjaテンプレートを使用すると、テキストファイルに少量のロジックを追加して、構成の詳細を動的に生成できます。
この構成ファイルは、すべてのポート80 HTTPトラフィックを取得してアプリファームに転送するようにNginxに指示します。 2つの部分があります:アップストリーム(アプリファーム)と、ユーザーとアプリファーム間のプロキシとして機能する構成です。
アップストリームについて話しましょう。 通常の、テンプレート化されていないアップストリームは、IPのコレクションを指定します。 ただし、ミニオンのIPアドレスが存在するまでは、そのIPアドレスがどうなるかはわかりません。また、設定ファイルを手動で編集することもありません。 (そうでなければ、Saltを使用する理由はありません!)
マップファイルの `+ mine_function +`行を覚えていますか? ミニオンはソルトマスターにIPを提供して、そのような機会にそれらを保存します。 そのJinjaラインをもう少し詳しく見てみましょう。
ジンジャ抜粋
{% for server, addrs in salt['mine.get']('roles:appserver', 'network.ip_addrs', expr_form='grain').items() %}
これは、Jinjaのforループであり、任意のSalt関数を実行します。 この場合、http://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.mine.html#salt.modules.mine.get [+ mine.get +
]を実行しています。 パラメーターは以下のとおりです。
-
+ roles:appserver +
-これは、「appserver」ロールを持つミニオンからのみ詳細を取得することを意味します。 -
+ network.ip_addrs +
-これは、鉱山から取り出したいデータです。 マップファイルでもこれを指定しました。 -
+ expr_form = 'grain' +
-これは、Saltに、グレインに基づいてミニオンをターゲットにしていることを伝えます。 穀物によるマッチングの詳細については、http://docs.saltstack.com/en/latest/topics/targeting/grains.html [Saltstackターゲティングドキュメント]をご覧ください。
このループに続いて、変数 `+ {{addrs}} `にはIPアドレスのリストが含まれます(アドレスが1つだけであっても)。 リストであるため、最初の要素を ` [0] +`で取得する必要があります。
それが上流です。 サーバー名について:
server_name {{ salt['network.ip_addrs']()[0] }};
これは、Salt mine呼び出し(JinjaでSalt関数を呼び出す)と同じトリックです。 単純です。 http://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.network.html#salt.modules.network.ip_addrs [+ network.ip_addrs +
]を呼び出して最初の要素を取得しています返されたリストの。 これにより、手動でファイルを編集する必要がなくなります。
ステップ6-アプリファームの定義
リバースプロキシは、背後にアプリがなければ意味がありません。 使用しているサーバーのIPを報告するだけの小さなNode.jsアプリケーションを作成しましょう(両方のマシンに到達していることを確認できます)。
`+ awesome-app +`という新しいディレクトリを作成して、そこに移動します。
mkdir -p /srv/salt/awesome-app
cd /srv/salt/awesome-app
`+ app.sls +`という新しいアプリ状態ファイルを作成します。
nano /srv/salt/awesome-app/app.sls
ファイルに次を配置します。 変更は不要です。
/srv/salt/awesome-app/app.sls
### /srv/salt/awesome-app/app.sls ###
#####################################
### Install Nodejs and start a simple
### web application that reports the server IP.
install-app:
# Install prerequisites
pkg:
- installed
- names:
- node
- npm
- nodejs-legacy # workaround for Debian systems
# Place our Node code
file:
- managed
- source: salt://awesome-app/files/app.js
- name: /root/app.js
# Install the package called 'forever'
cmd:
- run
- name: npm install forever -g
- require:
- pkg: install-app
run-app:
# Use 'forever' to start the server
cmd:
- run
- name: forever start app.js
- cwd: /root
この状態ファイルは次のことを行います。
-
+ nodejs
、` + npm`、および `+ nodejs-legacy`パッケージをインストールします。 -
シンプルなアプリになるJavaScriptファイルを追加します。
-
NPMを使用してhttps://www.npmjs.org/package/forever [
+ Forever +
]をインストールします。 -
アプリを実行します。
(小さな)アプリコードを作成します。
mkdir /srv/salt/awesome-app/files
cd /srv/salt/awesome-app/files
ファイルを作成します。
nano /srv/salt/awesome-app/files/app.js
以下を入れます。 変更する必要はありません。
/srv/salt/awesome-app/files/app.js
/* /srv/salt/awesome-app/files/app.js
A simple Node.js web application that
reports the server's IP.
Shamefully stolen from StackOverflow:
http://stackoverflow.com/questions/10750303/how-can-i-get-the-local-ip-address-in-node-js
*/
var os = require('os');
var http = require('http');
http.createServer(function (req, res) {
var interfaces = os.networkInterfaces();
var addresses = [];
for (k in interfaces) {
for (k2 in interfaces[k]) {
var address = interfaces[k][k2];
if (address.family == 'IPv4' && !address.internal) {
addresses.push(address.address)
}
}
}
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(JSON.stringify(addresses));
}).listen(1337, '0.0.0.0');
console.log('Server listening on port 1337');
これは、1つのことを行う単純なNode.jsサーバーです。ポート1337でHTTP要求を受け入れ、サーバーのIPで応答します。
この時点で、次のようなファイル構造が必要です。
ファイル構造
/srv/salt
├── awesome-app
│ ├── app.sls
│ └── files
│ └── app.js
└── nginx
├── rproxy.sls
└── files
└── awesome-app.conf.jin
ステップ7-アプリケーションのデプロイ
あとは、アプリケーションを展開するだけです。
Salt Cloudを使用してサーバーを展開する
以前と同じ展開コマンドを実行します。これにより、これまでに行ったすべての構成が使用されます。
salt-cloud -m /etc/salt/cloud.maps.d/do-app-with-rproxy.map
Salt Cloudが完了するまで待ちます。これにはしばらく時間がかかります。 戻ったら、アプリサーバーにpingを実行して、展開が成功したことを確認します。
salt -G 'roles:appserver' test.ping
君は見るべきだ:
アプリサーバーのping出力
appserver-02:
True
appserver-01:
True
リバースプロキシのping:
salt -G 'roles:rproxy' test.ping
君は見るべきだ:
リバースプロキシping出力
nginx-rproxy:
True
VMを作成したら、それらを機能させる時間です。
アプリケーションを構築する
次に、Saltコマンドを発行して、アプリファームとリバースプロキシを自動的に構築します。
アプリファームを構築します。
salt -G 'roles:appserver' state.sls awesome-app.app
かなりの量の出力がありますが、次で終わるはずです。
Summary
------------
Succeeded: 6 (changed=6)
Failed: 0
------------
Total states run: 6
リバースプロキシを構築します。
salt -G 'roles:rproxy' state.sls nginx.rproxy
繰り返しますが、かなりの量の出力があり、次で終わります。
Summary
------------
Succeeded: 4 (changed=4)
Failed: 0
------------
Total states run: 4
では、ここで何が起きたのでしょうか?
最初のコマンド(アプリサーバーを使用するコマンド)は、以前に記述したSalt状態を取得し、2つのアプリサーバーで実行しました。 これにより、同一バージョンのコードを実行する同一構成の2台のマシンが作成されました。
2番目のコマンド(リバースプロキシ)は、Nginx用に記述したSalt状態を実行しました。 Nginxと構成ファイルをインストールし、構成ファイルにアプリファームのIPを動的に入力しました。
これらのSaltが完了したら、テストして展開の成功を確認できます。 リバースプロキシのIPを見つけます。
salt -G 'roles:rproxy' network.ip_addrs
Dropletでプライベートネットワークを使用している場合、2つのIPを取得できます。
パブリックIPをブラウザーに接続して、Webページにアクセスしてください! 更新を数回押して、構築した2つのアプリサーバー間でNginxが実際にプロキシしていることを確認します。 IPが変化し、実際に複数のアプリサーバーに接続していることを確認します。
更新しても同じIPを取得する場合は、ブラウザのキャッシュが原因である可能性があります。 代わりに `+ curl +`を使用して、Nginxがアプリサーバー間でプロキシしていることを示すことができます。 このコマンドを数回実行して、出力を観察します。
curl http://
これをさらに数ステップ進め、http://docs.saltstack.com/en/latest/topics/tutorials/states_pt5.html#states-overstate [OverState]を介してアプリケーションのデプロイを_完全に自動化できます。 これにより、1つのコマンドを作成してSaltに、たとえばアプリサーバーを最初にビルドしてからリバースプロキシのビルドに進み、ビルドプロセスの順序を保証するように指示できます。
ステップ8-スケールアップ(オプション)
Saltを使用するポイントは、ビルドプロセスを自動化することです。 Salt Cloudとマップファイルを使用するポイントは、デプロイメントを簡単にスケーリングすることです。 展開にさらにアプリサーバー(たとえば、2つ)を追加する場合は、マップファイルを次のように更新します。
/etc/salt/cloud.maps.d/do-app-with-rproxy.map
### /etc/salt/cloud.maps.d/do-app-with-rproxy.map ###
#####################################################
ubuntu_512MB_ny3:
- nginx-rproxy:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: rproxy
ubuntu_1GB_ny3:
- appserver-01:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
- appserver-02:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
- appserver-03:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
- appserver-04:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
その更新を行った後、ステップ6のコマンドと2つのコマンドを再実行します。
salt-cloud -m /etc/salt/cloud.maps.d/do-app-with-rproxy.map
salt -G 'roles:appserver' state.sls awesome-app.app
salt -G 'roles:rproxy' state.sls nginx.rproxy
既存のサーバーは、繰り返し実行されるソルトの影響を受けず、新しいサーバーは仕様に合わせて構築され、Nginxの構成は更新されて、新しいアプリサーバーへのトラフィックのルーティングが開始されます。
結論
サーバーのIPを報告するだけのアプリを展開することはあまり役に立ちません。 幸いなことに、このアプローチはNode.jsアプリケーションに限定されません。 Saltは、アプリの言語を気にしません。
このフレームワークを使用して独自のアプリをデプロイする場合、サーバーにアプリをインストールするタスクを自動化するだけで(スクリプトまたはソルトステートを使用)、サンプルを独自の自動化に置き換えることができます。
SaltがDropletのプロセスを自動化するように、Salt Cloudはクラウドのプロセスを自動化します。 楽しい!