介绍
本教程是在Ubuntu 14.04上使用Ansible部署PHP应用程序的系列中的第三篇。 在第一个教程涵盖了部署应用程序的基本步骤; 在第二个教程涵盖更高级的主题,例如数据库,队列守护进程和任务调度(crons)。
在本教程中,我们将基于之前教程中学到的内容,将单一应用程序Ansible playbook转换为支持在一个或多个服务器上部署多个PHP应用程序的playbook。 这是最后一个难题,当谈到使用Ansible以最小的努力部署您的应用程序。
我们将使用一些简单的流明的应用,作为我们的例子中的一部分。 但是,如果您已经拥有自己的框架和应用程序,则可以轻松修改这些指令以支持其他框架和应用程序。 建议您使用示例应用程序,直到您对剧本进行更改为止。
先决条件
要遵循本教程,您需要:
一个新的(第三)的Ubuntu 14.04Droplet定像原来PHPDroplet在第一个教程 ,用sudo的非root用户和SSH密钥。 此Droplet将用于显示如何使用一个Ansible游戏手册将多个应用程序部署到多个服务器。 我们将把原来的PHPDroplet和这个新的PHPDroplet的IP地址作为
your_first_server_ip
和your_second_server_ip
分别。更新的
/etc/hosts
在本地计算机上的文件与以下行补充说。 您可以了解更多关于此文件在本教程中的第6步 。
your_first_server_ip laravel.example.com one.example.com two.example.com
your_second_server_ip laravel.example2.com two.example2.com
我们将在本教程中使用的示例网站是laravel.example.com
, one.example.com
和two.example.com
。 如果你想使用自己的域名,你需要更新你的主动DNS记录来代替。
第1步 - 设置游戏变量
在此步骤中,我们将设置剧本变量以定义我们的新应用程序。
在前面的教程中,我们对所有配置细节进行了硬编码,这对于为特定应用程序执行特定任务的许多剧本而言是正常的。 但是,当您希望支持多个应用程序或扩大您的剧本的范围时,对所有内容进行硬编码就没有意义了。
如前所述,Ansible提供了可以在任务定义和文件模板中使用的变量。 我们还没有看到的是如何手动设置变量。 在你的剧本的顶部,旁边的hosts
和tasks
参数,可以定义一个vars
参数,设置你的变量存在。
如果你还没有这样做的话,将目录切换到ansible-php
从以前的教程。
cd ~/ansible-php/
打开我们现有的剧本进行编辑。
nano php.yml
文件的顶部应如下所示:
---
- hosts: php
sudo: yes
tasks:
. . .
要定义变量,我们可以只添加在vars
的部分,沿着hosts
, sudo
和tasks
。 为了简单起见,我们将在一个非常基本的变量开头www-data
的用户名,比如:
---
- hosts: php
sudo: yes
vars:
wwwuser: www-data
tasks:
. . .
接下来,经过和更新的所有出现www-data
用户与新变量{{ wwwuser }}
这种格式应该是熟悉的,因为我们已经在外观和查找中使用它。
要查找和使用纳米更换,按CTRL+\
。 你会看到一个提示,它说搜索(更换)。 键入www数据 ,然后按ENTER
。 该提示将更改与替换。 在这里,类型{{wwwuser}},然后按ENTER
一次。 nano将带你穿越的每个实例www-data
,并要求替换该instanace? 您可以按y
一个更换每一个,或a
全部更换。
注 :确保我们只是在上面添加的变量声明不会改变太多。 应该有11个实例www-data
需要被更换。
在我们继续前进之前,我们需要小心处理变量。 通常我们可以只是添加他们在这样,当他们在一个较长的行:
- name: create /var/www/ directory
file: dest=/var/www/ state=directory owner={{ wwwuser }} group={{ wwwuser }} mode=0700
但是,如果变量是字符串中的唯一值,我们需要将其换成引号,以便YAML解析器可以正确理解它:
- name: Run artisan migrate
shell: php /var/www/laravel/artisan migrate --force
sudo: yes
sudo_user: "{{ wwwuser }}"
when: dbpwd.changed
在你的剧本,这需要发生您有任何时间sudo_user: {{ wwwuser }}
您可以使用全局查找和替换以同样的方式,取代sudo_user:{{wwwuser}}与sudo_user:“{{wwwuser}}”。 应该有四行需要这个更改。
一旦您更改了所有出现的内容,请保存并运行剧本:
ansible-playbook php.yml --ask-sudo-pass
应该没有改变的任务,这意味着我们的wwwuser
变量是否正常工作。
第2步 - 为复杂配置定义嵌套变量
在本节中,我们将讨论复杂配置选项的嵌套变量。
在上一步中,我们设置了一个基本变量。 但是,也可以嵌套变量和定义变量列表。 这提供了我们需要定义我们希望在我们的服务器上设置的网站的列表的功能。
首先,让我们考虑我们在playbook中设置的现有git存储库:
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/do-community/do-ansible-adv-php.git
update=yes
version=example
我们可以提取以下有用的信息:名称(目录),存储库,分支和域。 因为我们设置了多个应用程序,我们还需要一个域名来响应。 在这里,我们将使用laravel.example.com
,但如果你有自己的域名,可以替代它。
这导致我们可以为此应用程序定义以下四个变量:
name: laravel
repository: https://github.com/do-community/do-ansible-adv-php.git
branch: example
domain: laravel.example.com
现在,打开您的剧本进行编辑:
nano php.yml
在顶部vars
部分,我们可以在我们的应用程序添加到一个新的应用程序列表:
---
- hosts: php
sudo: yes
vars:
wwwuser: www-data
applications:
- name: laravel
domain: laravel.example.com
repository: https://github.com/do-community/do-ansible-adv-php.git
branch: example
...
如果你现在运行你的剧本(使用ansible-playbook php.yml --ask-sudo-pass
),什么都不会改变,因为我们还没有建立我们的任务,使用我们的新的applications
变量呢。 但是,如果你去http://laravel.example.com/
在您的浏览器,它应该显示我们的原始应用程序。
第3步 - 在任务中循环变量
在本节中,我们将学习如何在任务中循环变量列表。
正如前面提到的,变量列表需要,我们希望在使用它们的每个任务循环结束了。当我们和看到install packages
的任务,我们需要定义项的循环,然后应用任务列表中的每个项目。
打开您的剧本进行编辑:
nano php.yml
我们将从一些简单的任务开始。 在你的剧本的中间,你会发现这两个env
任务:
- name: set APP_DEBUG=false
lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false
- name: set APP_ENV=production
lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production
你会发现,他们目前硬编码的laravel
目录。 我们要更新它使用的name
属性为每个应用程序。 要做到这一点,我们在添加with_items
选项遍历我们的applications
列表。 在任务本身,我们将换出laravel
的变量引用{{ item.name }}
这应该是从我们以前使用的格式熟悉。
它应该看起来像这样:
- name: set APP_DEBUG=false
lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false
with_items: applications
- name: set APP_ENV=production
lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^APP_ENV=' line=APP_ENV=production
with_items: applications
接下来,向下移动到两个Laravel工匠cron任务。 他们可以在我们刚刚与没有进行更新完全相同的env
任务。 我们也将增加在item.name
到name
为的cron项参数,因为Ansible使用此字段来唯一地标识每个cron项。 如果我们保留原样,我们将不能在同一台服务器上有多个站点,因为它们会不断覆盖每个站点,只保存最后一个站点。
任务应如下所示:
- name: Laravel Scheduler
cron: >
job="run-one php /var/www/{{ item.name }}/artisan schedule:run 1>> /dev/null 2>&1"
state=present
user={{ wwwuser }}
name="{{ item.name }} php artisan schedule:run"
with_items: applications
- name: Laravel Queue Worker
cron: >
job="run-one php /var/www/{{ item.name }}/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1>> /dev/null 2>&1"
state=present
user={{ wwwuser }}
name="{{ item.name }} Laravel Queue Worker"
with_items: applications
如果您保存并立即运行剧本(使用ansible-playbook php.yml --ask-sudo-pass
),你应该只看到两个更新cron
任务更新。 这是由于在改变name
参数。 除此之外,没有任何变化,这意味着我们的应用程序列表正常工作,我们还没有对我们的服务器进行任何更改,因为重构我们的手册。
第4步 - 在模板中应用循环变量
在本节中,我们将介绍如何在模板中使用循环变量。
在模板中循环变量非常容易。 它们的使用方式与在任务中使用的方式完全相同,就像所有其他变量一样。 复杂性出现在你考虑文件路径以及变量时,因为在一些使用中,我们需要考虑文件名,甚至运行其他命令,因为新的文件。
在Nginx的情况下,我们需要为每个应用程序创建一个新的配置文件,并告诉Nginx应该启用它。 我们也希望删除我们原来/etc/nginx/sites-available/default
配置文件中的过程。
首先,打开您的剧本进行编辑:
nano php.yml
查找Configure Nginx
任务(靠近剧本的中间),并对其进行更新,我们与其他任务完成:
- name: Configure nginx
template: src=nginx.conf dest=/etc/nginx/sites-available/{{ item.name }}
with_items: applications
notify:
- restart php5-fpm
- restart nginx
虽然我们在这里,我们还将增加两个以上提到的任务。 首先,我们将告诉Nginx我们的新网站配置文件。 这是用一间做符号链接sites-available
和sites-enabled
目录中/var/nginx/
。
后加入该任务Configure nginx
任务:
- name: Configure nginx symlink
file: src=/etc/nginx/sites-available/{{ item.name }} dest=/etc/nginx/sites-enabled/{{ item.name }} state=link
with_items: applications
notify:
- restart php5-fpm
- restart nginx
接下来,我们要删除的default
启用的站点配置文件,因此它不会导致我们的新网站的配置文件的问题。 这是通过容易地进行file
模块:
- name: Remove default nginx site
file: path=/etc/nginx/sites-enabled/default state=absent
notify:
- restart php5-fpm
- restart nginx
需要注意的是,我们并不需要循环applications
,因为我们正在寻找一个单一的文件。
您的剧本中的Nginx块现在应该如下所示:
- name: Configure nginx
template: src=nginx.conf dest=/etc/nginx/sites-available/{{ item.name }}
with_items: applications
notify:
- restart php5-fpm
- restart nginx
- name: Configure nginx symlink
file: src=/etc/nginx/sites-available/{{ item.name }} dest=/etc/nginx/sites-enabled/{{ item.name }} state=link
with_items: applications
notify:
- restart php5-fpm
- restart nginx
- name: Remove default nginx site
file: path=/etc/nginx/sites-enabled/default state=absent
notify:
- restart php5-fpm
- restart nginx
保存您的剧本,并打开nginx.conf
文件进行编辑:
nano nginx.conf
更新配置文件,使其使用我们的变量:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /var/www/{{ item.name }}/public;
index index.php index.html index.htm;
server_name {{ item.domain }};
location / {
try_files $uri $uri/ =404;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/{{ item.name }}/public;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
但是,我们还没有完成。 注意default_server
顶部? 我们希望只包括为laravel
应用,它设置为默认。 要做到这一点,我们可以使用一个基本的IF检查语句if item.name
等于laravel
,如果是这样,显示default_server
。
它将如下所示:
server {
listen 80{% if item.name == "laravel" %} default_server{% endif %};
listen [::]:80{% if item.name == "laravel" %} default_server ipv6only=on{% endif %};
更新您的nginx.conf
因此并保存。
现在是时候运行我们的剧本:
ansible-playbook php.yml --ask-sudo-pass
您应该注意到Nginx任务已标记为已更改。 当它完成运行时,刷新浏览器中的网站,它应该显示与上一教程结束时相同:
Queue: YES
Cron: YES
第5步 - 一起循环多个变量
在这一步中,我们将在任务中将多个变量一起循环。
现在是时候处理一个更复杂的循环示例,特别是注册变量。 为了支持不同的状态,并防止任务运行不必要的,你会记得,我们使用的register: cloned
在我们的克隆Git仓库任务来注册变量cloned
与任务的状态。 然后,我们使用when: cloned|changed
了下列任务有条件触发任务。 现在我们需要更新这些引用以支持应用程序循环。
首先,打开您的剧本进行编辑:
nano php.yml
往下看的克隆Git仓库任务:
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/do-community/do-ansible-adv-php.git
update=yes
version=example
sudo: yes
sudo_user: "{{ wwwuser }}"
register: cloned
当我们在这个任务中注册变量时,我们不需要做任何我们还没有做过的事情:
- name: Clone git repository
git: >
dest=/var/www/{{ item.name }}
repo={{ item.repository }}
update=yes
version={{ item.branch }}
sudo: yes
sudo_user: "{{ wwwuser }}"
with_items: applications
register: cloned
现在,直到找到下移你的剧本composer create-project
的任务:
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: "{{ wwwuser }}"
when: cloned|changed
现在,我们需要通过双方将其更新循环applications
和cloned
。 这是通过使用完成with_together
选项,并通过在这两个applications
和cloned
。 由于with_together
遍历两个变量,访问项目与做item.#
其中#
是它被定义的变量指标。 例如:
with_together:
- list_one
- list_two
item.0
将指list_one
,和item.1
将指list_two
。
这意味着对于applications
,我们可以通过访问属性: item.0.name
。 对于cloned
,我们需要从任务,可以通过访问结果通过cloned.results
,然后我们就可以检查它是否是通过改变item.1.changed
。
这意味着任务变成:
- name: composer create-project
composer: command=create-project working_dir=/var/www/{{ item.0.name }} optimize_autoloader=no
sudo: yes
sudo_user: "{{ wwwuser }}"
when: item.1.changed
with_together:
- applications
- cloned.results
现在保存并运行您的剧本:
ansible-playbook php.yml --ask-sudo-pass
这个运行应该没有更改。 然而,我们现在有一个注册变量在一个循环内工作得很好。
第6步 - 复杂的注册变量和循环
在本节中,我们将了解更复杂的注册变量和循环。
最复杂的部分转换是处理我们用于为MySQL数据库生成密码的注册变量。 也就是说,我们还没有在这一步中做的更多,我们没有覆盖,我们只需要立即更新一些任务。
打开您的剧本进行编辑:
nano php.yml
找到MySQL任务,在我们的初始遍,我们将只是添加在基本变量,像我们在之前的任务中做的:
- name: Create MySQL DB
mysql_db: name={{ item.name }} state=present
with_items: applications
- name: Generate DB password
shell: makepasswd --chars=32
args:
creates: /var/www/{{ item.name }}/.dbpw
with_items: applications
register: dbpwd
- name: Create MySQL User
mysql_user: name={{ item.name }} password={{ dbpwd.stdout }} priv={{ item.name }}.*:ALL state=present
when: dbpwd.changed
- name: set DB_DATABASE
lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_DATABASE=' line=DB_DATABASE={{ item.name }}
with_items: applications
- name: set DB_USERNAME
lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_USERNAME=' line=DB_USERNAME={{ item.name }}
with_items: applications
- name: set DB_PASSWORD
lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_PASSWORD=' line=DB_PASSWORD={{ dbpwd.stdout }}
when: dbpwd.changed
- name: Save dbpw file
lineinfile: dest=/var/www/{{ item.name }}/.dbpw line="{{ dbpwd.stdout }}" create=yes state=present
sudo: yes
sudo_user: "{{ wwwuser }}"
when: dbpwd.changed
- name: Run artisan migrate
shell: php /var/www/{{ item.name }}/artisan migrate --force
sudo: yes
sudo_user: "{{ wwwuser }}"
when: dbpwd.changed
下一步,我们将在增加with_together
所以我们可以用我们的数据库密码。 对于我们的密码生成,我们需要循环dbpwd.results
,并且将能够从访问密码item.1.stdout
,因为applications
将通过以下方式访问item.0
。
我们可以相应地更新我们的手册:
- name: Create MySQL DB
mysql_db: name={{ item.name }} state=present
with_items: applications
- name: Generate DB password
shell: makepasswd --chars=32
args:
creates: /var/www/{{ item.name }}/.dbpw
with_items: applications
register: dbpwd
- name: Create MySQL User
mysql_user: name={{ item.0.name }} password={{ item.1.stdout }} priv={{ item.0.name }}.*:ALL state=present
when: item.1.changed
with_together:
- applications
- dbpwd.results
- name: set DB_DATABASE
lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_DATABASE=' line=DB_DATABASE={{ item.name }}
with_items: applications
- name: set DB_USERNAME
lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_USERNAME=' line=DB_USERNAME={{ item.name }}
with_items: applications
- name: set DB_PASSWORD
lineinfile: dest=/var/www/{{ item.0.name }}/.env regexp='^DB_PASSWORD=' line=DB_PASSWORD={{ item.1.stdout }}
when: item.1.changed
with_together:
- applications
- dbpwd.results
- name: Save dbpw file
lineinfile: dest=/var/www/{{ item.0.name }}/.dbpw line="{{ item.1.stdout }}" create=yes state=present
sudo: yes
sudo_user: "{{ wwwuser }}"
when: item.1.changed
with_together:
- applications
- dbpwd.results
- name: Run artisan migrate
shell: php /var/www/{{ item.0.name }}/artisan migrate --force
sudo: yes
sudo_user: "{{ wwwuser }}"
when: item.1.changed
with_together:
- applications
- dbpwd.results
更新您的剧本后,请保存并运行:
ansible-playbook php.yml --ask-sudo-pass
尽管我们对我们的剧本进行了所有的更改,但应该不会更改数据库任务。 随着这一步的改变,我们应该已经完成了从单个应用程序手册到多个应用程序手册的转换。
第7步 - 添加更多应用程序
在这一步中,我们将在我们的剧本中配置两个应用程序。
现在我们已经重构了我们的剧本以使用变量来定义应用程序,向我们的服务器添加新应用程序的过程非常容易。 简单地将它们添加到applications
变量列表。 这就是Ansible变量的力量真正闪耀的地方。
打开您的剧本进行编辑:
nano php.yml
在顶部,在vars
部分,找到applications
块:
applications:
- name: laravel
domain: laravel.example.com
repository: https://github.com/do-community/do-ansible-adv-php.git
branch: example
现在添加两个应用程序:
applications:
- name: laravel
domain: laravel.example.com
repository: https://github.com/do-community/do-ansible-adv-php.git
branch: example
- name: one
domain: one.example.com
repository: https://github.com/do-community/do-ansible-php-example-one.git
branch: master
- name: two
domain: two.example.com
repository: https://github.com/do-community/do-ansible-php-example-two.git
branch: master
保存您的手册。
现在是时候运行你的剧本:
ansible-playbook php.yml --ask-sudo-pass
此步骤可能需要一段时间,因为编辑器设置新的应用程序。 当它完成,你会注意到一些任务被改变,如果你仔细看你会注意到,每个循环的项目将列出。 首先,我们原来的应用应该说是ok
或skipped
,而新的两个应用程序应该说changed
。
更重要的是,如果您在Web浏览器中访问配置的网站的所有三个域,您应该注意到三个不同的网站。
第一个应该看起来很熟悉。 其他两个应显示:
This is example app one!
和
This is example app two!
因此,我们只是通过更新应用程序列表来部署了两个新的Web应用程序。
第8步 - 使用主机变量
在这一步中,我们将提取我们的变量来托管变量。
退一步,剧本变量是好的,但如果我们想使用同一个剧本在不同的服务器上部署不同的应用程序呢? 我们可以做条件检查每个任务制定出哪台服务器正在运行任务,或者我们可以使用主机变量 。 主机变量只是它们的声音:适用于特定主机的变量,而不是整个剧本中的所有主机。
主机变量可以内嵌定义,内部的hosts
文件,就像我们在做ansible_ssh_user
变量,也可以在专门的文件中定义的内每台主机host_vars
目录。
首先,创建一个新的目录与我们的hosts
文件,我们的剧本。 调用目录host_vars
:
mkdir host_vars
接下来,我们需要为我们的主机创建一个文件。 Ansible使用的约定是为文件名匹配的主机名hosts
文件。 因此,举例来说,如果你的hosts
文件看起来是这样的:
[php]
your_first_server_ip ansible_ssh_user=sammy
那么你应该创建一个名为host_vars/your_first_server_ip
。 让我们现在创建:
nano host_vars/your_first_server_ip
和我们的剧本一样,主机文件使用YAML进行格式化。 这意味着我们可以复制我们的applications
清单到我们新的主机文件,所以它看起来是这样的:
---
applications:
- name: laravel
domain: laravel.example.com
repository: https://github.com/do-community/do-ansible-adv-php.git
branch: example
- name: one
domain: one.example.com
repository: https://github.com/do-community/do-ansible-php-example-one.git
branch: master
- name: two
domain: two.example.com
repository: https://github.com/do-community/do-ansible-php-example-two.git
branch: master
保存您的新主机文件,并打开您的剧本进行编辑:
nano php.yml
更新前删除整个applications
部分:
---
- hosts: php
sudo: yes
vars:
wwwuser: www-data
tasks:
. . .
保存剧本,然后运行:
ansible-playbook php.yml --ask-sudo-pass
即使我们已经将我们的变量从我们的剧本移动到我们的主机文件,输出应该看起来完全相同,并且没有报告Ansible的更改。 正如你所看到的, host_vars
在完全相同的方式工作vars
在剧本做; 它们只是特定于主机。
在定义的变量host_vars
文件也将是跨管理服务器,这是常见的选项和设置都非常有用访问剧本。 但是,注意不要使用通用名称,这可能意味着不同的剧本在不同的剧本。
第9步 - 在另一个服务器上部署应用程序
在此步骤中,我们将使用我们的新主机文件并在第二个服务器上部署应用程序。
首先,我们需要更新我们的hosts
与我们的新的主机文件。 打开它进行编辑:
nano hosts
并添加到您的新主机:
[php]
your_first_server_ip ansible_ssh_user=sammy
your_second_server_ip ansible_ssh_user=sammy
保存并关闭文件。
接下来,我们需要创建一个新的主机文件,就像我们做的第一个。
nano host_vars/your_second_server_ip
您可以选择一个或多个示例应用程序,并将它们添加到主机文件中。 例如,如果您想将我们的原始示例和示例二部署到新服务器,则可以使用:
---
applications:
- name: laravel
domain: laravel.example2.com
repository: https://github.com/do-community/do-ansible-adv-php.git
branch: example
- name: two
domain: two.example2.com
repository: https://github.com/do-community/do-ansible-php-example-two.git
branch: master
保存您的手册。
最后,我们可以运行我们的剧本:
ansible-playbook php.yml --ask-sudo-pass
Ansible将需要一段时间才能运行,因为它正在第二个服务器上设置一切。 当它已经完成,在浏览器中打开你选择的应用程序(在本例中,我们使用laravel.example2.com
two.example2.com
),并确认他们已正确设置。 您应该看到为主机文件选择的特定应用程序,并且原始服务器应该没有更改。
结论
本教程采用一个功能齐全的单一应用程序剧本,并将其转换为支持多个服务器上的多个应用程序。 结合以前教程中涵盖的主题,您应该拥有为部署应用程序编写完整手册所需的一切。 根据以前的教程,我们仍然没有直接登录到使用SSH的服务器。
你会注意到,添加在更多的应用程序和另一个服务器是多么简单,一旦我们有剧本的结构。 这是Ansible的力量,它是如此的灵活和易于使用。