介绍
你有你的应用程序写,现在你需要部署它。你可以创建一个生产环境并在虚拟机上设置你的应用程序,但是当它变得流行时你如何扩展呢?如何推出新版本?负载平衡怎么样?而且,最重要的是,你如何确定配置是否正确?我们可以自动化所有这一切,以节省自己很多时间。 在本教程中,我们将向您介绍如何在Salt Cloud映射文件中定义应用程序,包括使用自定义Salt grain为您的服务器分配角色并动态配置逆向代理。 在本教程结尾处,您将有两个基本的应用程序服务器,一个Nginx逆向代理和一个动态构建的配置,并且能够在几分钟内扩展应用程序。先决条件
要遵循本教程,您需要:- 一个1 GB CentOS 7Droplet。本教程中的所有命令都将以root身份执行,因此您不需要创建sudo非root用户。
- 在Droplet上SSH密钥为root用户(即在Droplet上创建一个新的密钥对)。 在DigitalOcean控制面板中添加此SSH密钥,以便您可以使用它从主Droplet登录其他DigitalOcean Droplet。 您可以使用如何使用DigitalOceanDropletSSH密钥教程的说明。 记下在DigitalOcean控制面板中为键分配的名称。 在本教程中,我们使用的名称Salt主根密钥 。 您还应该记下私钥位置; 默认情况下,它的
/root/.ssh/id_rsa
。 - 个人访问令牌,您可以按照此步骤中的说明创建如何使用DigitalOcean APIv2 。请确保将范围设置为读写。
第1步 - 安装Salt和Salt-Cloud
首先,您需要在服务器上安装和配置Salt Cloud。对于本教程,我们将使用Salt引导脚本。 首先,蚀刻Salt bootstrap脚本以安装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
脚本配置的回购协议对我们来说,这样我们就可以只安装
salt-cloud
使用yum:
yum install salt-cloud
现在我们可以检查Salt Cloud的版本以确认安装成功:
salt-cloud --version
你应该看到这样的输出:
Salt-Cloud - 版本输出
salt-cloud 2015.5.3 (Lithium)
请注意,Salt正在滚动发布周期,因此您的版本可能与上述略有不同。
第2步 - 配置Salt Cloud
在本节中,我们将配置Salt Cloud连接到DigitalOcean并为我们的Droplet定义一些配置文件。配置DigitalOcean提供程序文件
Salt-Cloud 提供商的文件是你定义其中新的虚拟机将被创建。 供应商在规定的/etc/salt/cloud.providers.d
目录 创建和使用打开DigitalOcean提供程序文件
nano
或您喜爱的文本编辑器。
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: your_server_ip
# DigitalOcean Access Token
personal_access_token: your_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: salt-master-root-key
# This is the path on disk to the private key for your Digital Ocean account
ssh_key_file: /root/.ssh/id_rsa
您需要锁定SSH密钥文件的权限。否则,SSH将拒绝使用它。假设你是在默认位置,
/root/.ssh/id_rsa
,你可以这样做有:
chmod 600 /root/.ssh/id_rsa
配置可部署服务器的配置文件
Salt-Cloud, 型材是被绑定到供应商(例如“512 MB的Ubuntu VM上DigitalOcean”),单个虚拟机的描述。 这些是在定义/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
保存并关闭文件。此文件定义两个配置文件:
- 一个Ubuntu 14.04虚拟机,512 MB内存,部署在纽约3区。
- 具有1 GB内存的Ubuntu 14.04 VM,部署在纽约3地区。
salt-cloud --list-images do
这将显示所有标准的DigitalOcean映像,以及您使用快照工具保存在您的帐户中的自定义图像。您可以将我们在提供程序文件中使用的图像名称或区域替换为此列表中的其他图像名称。如果你这样做,一定要使用
slug字段从这个输出在配置文件中
图像设置。 使用快速查询测试配置。
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帐户通信,并且您配置了两个基本配置文件。
第三步 - 编写一个简单的地图文件
地图文件是一个YAML文件,其中列出了您要创建的配置文件和服务器数量。我们将从一个简单的地图文件开始,然后在下一节中创建它。 使用上述配置文件,假设您想要两个1 GB的应用服务器由一个单一的512 MB反向代理面对。我们会让一个名为映射文件/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
在地图文件中成功创建虚拟机后,删除它们同样简单:
salt-cloud -d -m /etc/salt/cloud.maps.d/do-app-with-rproxy.map
一定要谨慎使用该命令!这将删除该地图文件中指定的
所有虚拟机。
第四步 - 写一个更现实的地图文件
该映射文件工作正常,但即使一个shell脚本可以启动一组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
现在我们到了某个地方!它看起来很多,但我们只添加了两件事。让我们在两个加法走了过来:在
mine_functions
部分和
grains
部分。 我们已经告诉Salt-Cloud修改SaltMinion配置这些虚拟机,并添加一些自定义的
谷物 。 具体来说,谷物给反向代理虚拟机
rproxy
作用,给应用服务器的
appserver
的角色。当我们需要动态配置逆向代理时,这将派上用场。 该
mine_functions
也将添加到SaltMinion配置。 它指示Minion发送
eth0上发现回Salt Master存储在IP地址
Salt矿 。这意味着Salt Master将自动知道新创建的Droplet的IP,而无需配置它。我们将在下一部分中使用它。
第五步 - 定义反向代理
我们现在有一个常见的任务:安装反向代理Web服务器并配置它。在本教程中,我们将使用Nginx作为反向代理。写NginxSalt状态
是时候让我们的手脏,写几个Salt状态。首先,使默认Salt状态树位置:mkdir /srv/salt
导航到该目录,并为nginx创建一个更多的目录:
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正在运行。
编写Nginx反向代理配置文件
让我们为我们的配置文件再创建一个目录: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']()[1] }}; # <-- change the '1' to '0' if you're not using
# 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;
}
}
我们使用
.jin
扩展告诉自己,该文件包含
神社模板 。 Jinja模板允许我们把少量的逻辑放入我们的文本文件,所以我们可以动态生成配置详细信息。 此配置文件指示Nginx获取所有端口80 HTTP流量,并将其转发到我们的应用程序场。它有两个部分:上游(我们的应用程序场)和配置,作为用户和我们的应用程序场之间的代理。 让我们谈谈上游。正常的,非模板化的上游指定IP的集合。但是,我们不知道我们的minions的IP地址将会存在,我们不会手动编辑配置文件。 (否则,没有理由使用Salt!) 还记得
mine_function
在我们的地图文件中的行?Minion们正在给他们的IP的Salt主,存储他们只是这样的场合。让我们来看看Jinja行:
Jinja节选
{% for server, addrs in salt['mine.get']('roles:appserver', 'network.ip_addrs', expr_form='grain').items() %}
这是Jinja的for循环,运行一个任意的Salt函数。在这种情况下,它的运行
mine.get
。参数为:
roles:appserver
-这是说,只得到谁拥有“应用程序服务器”的角色Minion的细节。network.ip_addrs
-这就是我们想要走出矿井的数据。我们在我们的地图文件中也指定了。expr_form='grain'
-这是告诉我们要根据他们的谷物我们的目标Salt的Minion。 更多关于在粮所匹配的Saltstack目标文档 。
{{addrs}}
包含的IP地址的列表(即使只有一个地址)。 因为它是一个列表,我们必须抓住的第一个元素
[0]
这是上游。至于服务器名称:
server_name {{ salt['network.ip_addrs']()[0] }};
这和Salt mine调用是一样的(在Jinja中调用Salt函数)。这只是更简单。它调用的
network.ip_addrs
并采取返回列表的第一个元素。这也使我们避免手动编辑我们的文件。
第六步 - 定义App Farm
如果没有一个应用程序,反向代理不意味着很多。让我们做一个小的Node.js应用程序,只是报告它所在的服务器的IP(所以我们可以确认我们到达两个机器)。 创建一个新的目录名为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安装
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');
这是一个简单的Node.js服务器,它做一件事:在端口1337上接受HTTP请求,并使用服务器的IP进行响应。 此时,您应该有一个如下所示的文件结构:
文件结构
/srv/salt
├── awesome-app
│ ├── app.sls
│ └── files
│ └── app.js
└── nginx
├── rproxy.sls
└── files
└── awesome-app.conf.jin
第七步 - 部署应用程序
剩下的只是部署应用程序。使用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
一旦你有你的虚拟机,是时候给他们工作。
构建应用程序
接下来,发出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状态,并在两个应用服务器上执行它。这导致两台具有相同配置的机器运行相同版本的代码。 第二个命令(反向代理)执行我们为Nginx写的Salt状态。它安装Nginx和配置文件,在配置文件中动态填充我们的应用程序场的IP。 一旦这些Salt运行完成,您可以测试以确认成功部署。查找反向代理的IP:
salt -G 'roles:rproxy' network.ip_addrs
如果您在Droplet上使用专用网络,您可能会收回两个IP。 将公共IP插入您的浏览器并访问网页!点击刷新几次,以确认Nginx实际上是在您构建的两个应用程序服务器之间代理。您应该看到IP更改,确认您确实连接到多个应用程序服务器。 如果尽管刷新,但仍获得相同的IP,可能是由于浏览器缓存。您可以尝试使用
curl
,而不是表明Nginx的是你的应用服务器之间的代理。多次运行此命令并观察输出:
curl http://ip-of-nginx-rproxy
我们可以进一步借此几步之遥,
完全自动化通过应用程序部署
夸大 。这将让我们构建一个单独的命令告诉Salt建立,比如说,应用服务器,然后继续构建反向代理,保证我们的构建过程的顺序。
第八步 - 向上扩展(可选)
使用Salt的意义在于自动化你的构建过程;使用Salt Cloud和映射文件的要点是轻松扩展您的部署。如果您想在部署中添加更多应用服务器(例如两个),您可以更新地图文件,如下所示:
/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
使得该更新后,您会重新运行
Salt-Cloud命令和第6步的二
Salt命令:
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
现有的服务器不会受到重复Salt运行的影响,新的服务器将被构建为spec,并且Nginx配置将更新以开始将流量路由到新的应用服务器。