如何使用云Salt Cloud Map文件来部署应用服务器和Nginx的反向代理

介绍

你有你的应用程序写,现在你需要部署它。你可以创建一个生产环境并在虚拟机上设置你的应用程序,但是当它变得流行时你如何扩展呢?如何推出新版本?负载平衡怎么样?而且,最重要的是,你如何确定配置是否正确?我们可以自动化所有这一切,以节省自己很多时间。 在本教程中,我们将向您介绍如何在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地区。
如果要使用Ubuntu 14.04以外的映像,可以使用Salt Cloud使用以下命令列出DigitalOcean上的所有可用映像名称:
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正在运行。
我们的Salt状态只是安装Nginx并丢弃一个配置文件;真正有趣的内容是在配置。

编写Nginx反向代理配置文件

让我们为我们的配置文件再创建一个目录:
mkdir /srv/salt/nginx/files
cd /srv/salt/nginx/files
并打开配置文件:
nano /srv/salt/nginx/files/awesome-app.conf.jin
将以下内容放在配置文件中。任何修改是必要的,除非你 使用专用网络; 在这种情况下,改变它的 10作为行指出:
/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
此状态文件执行以下操作:
  • 安装nodejsnpmnodejs-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配置将更新以开始将流量路由到新的应用服务器。

结论

部署仅报告服务器IP的应用程序不是非常有用。幸运的是,这种方法不限于Node.js应用程序。 Salt不在乎你的应用程序是用什么语言写的。 如果你想利用这个架构来部署自己的应用程序,你只需要自动化的服务器上安装的应用程序(无论是通过脚本或Salt的状态)的任务,并用自己的自动化取代我们 真棒应用的例子。 就像Salt自动化你的Droplets上的进程一样,Salt Cloud自动化你的云上的进程。请享用!
赞(52) 打赏
未经允许不得转载:优客志 » 系统运维
分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏