如何在 Ubuntu 14.04 上使用 Ansible 部署基本的 PHP 应用程序
介绍
本教程介绍了使用 Ansible 配置基本 PHP 应用程序的过程。本教程结束时的目标是让您的新 Web 服务器为基本的 PHP 应用程序提供服务,而无需在目标 Droplet 上运行单个 SSH 连接或手动命令。
我们将使用 Laravel 框架作为示例 PHP 应用程序,但如果您已经拥有自己的框架和应用程序,则可以轻松修改这些说明以支持其他框架和应用程序。
先决条件
对于本教程,我们将使用 Ansible 在 Ubuntu 14.04 Droplet 上安装和配置 Nginx、PHP 和其他服务。本教程建立在基本的 Ansible 知识之上,因此如果您是 Ansible 的新手,您可以先通读这个基本的 Ansible 教程。
要学习本教程,您需要:
- <李> 一个任意大小的 Ubuntu 14.04 Droplet,我们将使用它来配置和部署我们的 PHP 应用程序。本机的 IP 地址将在整个教程中称为
your_server_ip
。 <李> 一个将用于 Ansible 的 Ubuntu 14.04 Droplet。这是您将在整个教程中登录的 Droplet。 <李> 为两个 Droplet 配置的 Sudo 非 root 用户。 <李> Ansible Droplet 的 SSH 密钥授权登录 PHP 部署 Droplet,您可以按照本教程在 Ansible Droplet 上进行设置。 第 1 步 — 安装 Ansible
第一步是安装 Ansible。这可以通过安装 PPA(个人包存档)并使用 apt
安装 Ansible 包轻松实现。
首先,使用 apt-add-repository
命令添加 PPA。
- sudo apt-add-repository ppa:ansible/ansible
完成后,更新 apt
缓存。
- sudo apt-get update
最后,安装 Ansible。
- sudo apt-get install ansible
安装 Ansible 后,我们将创建一个新目录以在其中工作并设置基本配置。默认情况下,Ansible 使用位于 /etc/ansible/hosts
的主机文件,其中包含它管理的所有服务器。虽然该文件适用于某些用例,但它是全局的,这不是我们在这里想要的。
对于本教程,我们将创建一个本地主机文件并使用它。我们可以通过在我们的工作目录中创建一个新的 Ansible 配置文件来做到这一点,我们可以使用它来告诉 Ansible 在同一目录中查找主机文件。
创建一个新目录(我们将在本教程的其余部分使用它)。
- mkdir ~/ansible-php
移动到新目录。
- cd ~/ansible-php/
创建一个名为 ansible.cfg
的新文件,然后使用 nano
或您喜欢的文本编辑器打开它进行编辑。
- nano ansible.cfg
通过将以下内容复制到 ansible.cfg 中,在
文件。[defaults]
组中添加值为 hosts
的 hostfile
配置选项
[defaults]
hostfile = hosts
保存并关闭 ansible.cfg
文件。接下来,我们将创建 hosts
文件,其中包含我们将部署应用程序的 PHP Droplet 的 IP 地址。
- nano hosts
复制以下内容以添加 php
部分,将 your_server_ip
替换为您的服务器 IP 地址和 sammy
使用您在 PHP Droplet 的先决条件中创建的 sudo 非根用户。
[php]
your_server_ip ansible_ssh_user=sammy
保存并关闭 hosts
文件。让我们运行一个简单的检查,以确保 Ansible 能够通过调用新 php
组上的 ping
模块按预期连接到主机。
- ansible php -m ping
您可能会获得 SSH 主机身份验证检查,具体取决于您之前是否登录过该主机。 ping 应该返回一个成功的响应,看起来像这样:
111.111.111.111 | success >> {
"changed": false,
"ping": "pong"
}
现在已经安装并配置了 Ansible;我们可以继续设置我们的网络服务器。
第 2 步 — 安装所需的软件包
在此步骤中,我们将使用 Ansible 和 apt
安装一些必需的系统包。特别是,我们将安装 git
、nginx
、sqlite3
、mcrypt
和几个 php5 -*
包。
在我们添加 apt
模块来安装我们想要的包之前,我们需要创建一个基本的剧本。在完成本教程时,我们将以此剧本为基础。创建一个名为 php.yml
的新剧本。
- nano php.yml
粘贴以下配置。前两行指定我们希望使用的主机组 (php
) 并确保它默认运行带有 sudo
的命令。其余的添加到一个模块中,其中包含我们需要的包。您可以为自己的应用程序自定义它,或者如果您正在跟随示例 Laravel 应用程序,则使用下面的配置。
---
- hosts: php
sudo: yes
tasks:
- name: install packages
apt: name={{ item }} update_cache=yes state=latest
with_items:
- git
- mcrypt
- nginx
- php5-cli
- php5-curl
- php5-fpm
- php5-intl
- php5-json
- php5-mcrypt
- php5-sqlite
- sqlite3
保存 php.yml
文件。最后,运行 ansible-playbook
在 Droplet 上安装包。如果您的 PHP Droplet 上的 sudo 用户需要密码,请不要忘记使用 --ask-sudo-pass
选项。
- ansible-playbook php.yml --ask-sudo-pass
第 3 步 — 修改系统配置文件
在本节中,我们将修改 PHP Droplet 上的一些系统配置文件。要更改的最重要的配置选项(除了 Nginx 的文件,将在后面的步骤中介绍)是 php5-fpm
中的 cgi.fix_pathinfo
选项,因为默认价值是一种安全风险。
我们将首先解释我们要添加到该文件的所有部分,然后包含整个 php.yml
文件供您复制和粘贴。
lineinfile 模块可用于确保文件中的配置值完全符合我们的预期。这可以使用通用正则表达式来完成,以便 Ansible 可以理解参数可能采用的大多数形式。我们还需要重新启动 php5-fpm
和 nginx
以确保更改生效,因此我们还需要在新的 handlers
部分中添加两个处理程序。处理程序非常适合此操作,因为它们仅在任务更改时才会被触发。它们也在 playbook 的末尾运行,因此多个任务可以调用同一个处理程序并且它只会运行一次。
执行上述操作的部分将如下所示:
- name: ensure php5-fpm cgi.fix_pathinfo=0
lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0
notify:
- restart php5-fpm
- restart nginx
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
Ansible 版本 1.9.1 存在一个错误,阻止 php5-fpm
使用 service
模块重新启动,正如我们在处理程序中使用的那样。
在发布修复程序之前,您可以通过将 restart php5-fpm
处理程序从使用 service
命令更改为使用 shell
来解决此问题命令,像这样:
- name: restart php5-fpm
shell: service php5-fpm restart
这将绕过问题并正确重启 php5-fpm
。
接下来,我们还需要确保启用了 php5-mcrypt
模块。这是通过使用 shell 任务运行 php5enmod
脚本,并在启用时检查 20-mcrypt.ini
文件位于正确的位置来完成的。请注意,我们告诉 Ansible 该任务创建了一个特定文件。如果该文件存在,任务将不会运行。
- name: enable php5 mcrypt module
shell: php5enmod mcrypt
args:
creates: /etc/php5/cli/conf.d/20-mcrypt.ini
现在,再次打开 php.yml
进行编辑。
- nano php.yml
添加上述任务和处理程序,使文件匹配以下内容:
---
- hosts: php
sudo: yes
tasks:
- name: install packages
apt: name={{ item }} update_cache=yes state=latest
with_items:
- git
- mcrypt
- nginx
- php5-cli
- php5-curl
- php5-fpm
- php5-intl
- php5-json
- php5-mcrypt
- php5-sqlite
- sqlite3
- name: ensure php5-fpm cgi.fix_pathinfo=0
lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0
notify:
- restart php5-fpm
- restart nginx
- name: enable php5 mcrypt module
shell: php5enmod mcrypt
args:
creates: /etc/php5/cli/conf.d/20-mcrypt.ini
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
最后,运行剧本。
- ansible-playbook php.yml --ask-sudo-pass
Droplet 现在已经安装了所有必需的包,并设置了基本配置并准备就绪。
第 4 步 — 克隆 Git 存储库
在本节中,我们将使用 Git 将 Laravel 框架存储库克隆到我们的 Droplet 上。与第 3 步一样,我们将解释要添加到剧本中的所有部分,然后包含整个 php.yml
文件供您复制和粘贴。
在我们克隆我们的 Git 存储库之前,我们需要确保 /var/www
存在。我们可以通过使用文件模块创建一个任务来做到这一点。
- name: create /var/www/ directory
file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700
如上所述,我们需要使用 Git 模块将存储库克隆到我们的 Droplet 上。这个过程很简单,因为对于 git clone
命令,我们通常只需要源存储库。在这种情况下,我们还将定义目的地,并通过设置 update=no
告诉 Ansible 如果存储库已经存在则不要更新。因为我们使用的是 Laravel,所以我们将使用的 git 存储库 URL 是 https://github.com/laravel/laravel.git
。
但是,我们需要以 www-data
用户身份运行任务,以确保权限正确。为此,我们可以告诉 Ansible 使用 sudo
作为特定用户运行命令。最终任务将如下所示:
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
注意:对于基于 SSH 的存储库,您可以添加 accept_hostkey=yes
以防止 SSH 主机验证挂起任务。
和以前一样,打开 php.yml
文件进行编辑。
- nano php.yml
将上述任务添加到剧本中;文件末尾应匹配以下内容:
...
- name: enable php5 mcrypt module
shell: php5enmod mcrypt
args:
creates: /etc/php5/cli/conf.d/20-mcrypt.ini
- name: create /var/www/ directory
file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
保存并关闭剧本,然后运行它。
- ansible-playbook php.yml --ask-sudo-pass
第 5 步 — 使用 Composer 创建应用程序
在此步骤中,我们将使用 Composer 安装 PHP 应用程序及其依赖项。
Composer 有一个 create-project
命令,可以安装所有必需的依赖项,然后运行 post-create-project-cmd
部分中定义的项目创建步骤>composer.json 文件。这是确保应用程序在首次使用时正确设置的最佳方式。
我们可以使用以下 Ansible 任务将 Composer 全局下载并安装为 /usr/local/bin/composer
。然后任何使用 Droplet 的人都可以访问它,包括 Ansible。
- name: install composer
shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
args:
creates: /usr/local/bin/composer
安装 Composer 后,我们可以使用一个 Composer 模块。在我们的例子中,我们想告诉 Composer 我们的项目在哪里(使用 working_dir
参数),并运行 create-project
命令。我们还需要添加 optimize_autoloader=no
参数,因为 create-project
命令不支持此标志。与 git
命令一样,我们也希望以 www-data
用户身份运行它以确保权限有效。把它们放在一起,我们得到了这个任务:
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
注意:create-project
任务可能会在新的 Droplet 上花费大量时间,因为 Composer 将有一个空缓存并且需要下载所有新的东西。
现在,打开 php.yml
文件进行编辑。
- nano php.yml
在 tasks
部分的末尾添加上面的任务,在 handlers
之上,以便 playbook 的末尾匹配以下内容:
...
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
- name: install composer
shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
args:
creates: /usr/local/bin/composer
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
最后,运行剧本。
- ansible-playbook php.yml --ask-sudo-pass
如果我们现在再次运行 Ansible 会发生什么? composer create-project
将再次运行,对于 Laravel,这意味着一个新的 APP_KEY
。所以我们想要的是将该任务设置为仅在新克隆之后运行。我们可以通过使用 git clone
任务的结果注册一个变量来确保它只运行一次,然后在 composer create-project
任务中检查这些结果。如果 git clone
任务已更改,那么我们运行 composer create-project
,如果没有,则跳过它。
注意:在某些版本的 Ansible composer
模块中似乎存在一个错误,它可能会输出 OK 而不是 Changed,因为它忽略了即使没有安装依赖项,脚本也会被执行。
打开 php.yml
文件进行编辑。
- nano php.yml
找到 git clone
任务。添加 register
选项以将任务结果保存到 cloned
变量中,如下所示:
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
register: cloned
接下来,找到 composer create-project
任务。添加 when
选项以检查 cloned
变量以查看它是否已更改。
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
when: cloned|changed
保存剧本,然后运行它:
- ansible-playbook php.yml --ask-sudo-pass
现在 Composer 将停止在每次运行时更改 APP_KEY
。
第 6 步 — 更新环境变量
在此步骤中,我们将为应用程序更新环境变量。
Laravel 带有一个默认的 .env
文件,它将 APP_ENV
设置为 local
并将 APP_DEBUG
设置为 true
。我们想将它们分别替换为 production
和 false
。这可以通过以下任务简单地使用 lineinfile
模块来完成。
- 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
打开 php.yml
文件进行编辑。
- nano php.yml
将此任务添加到剧本中;文件末尾应匹配以下内容:
...
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
when: cloned|changed
- 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
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
保存并运行剧本:
- ansible-playbook php.yml --ask-sudo-pass
lineinfile
模块对于快速调整任何文本文件非常有用,而且对于确保正确设置此类环境变量非常有用。
第 7 步 — 配置 Nginx
在本节中,我们将配置 Nginx 来为 PHP 应用程序提供服务。
如果您现在在网络浏览器中访问您的 Droplet(即 http://your_server_ip/
),您将看到 Nginx 默认页面而不是 Laravel 新项目页面。这是因为我们仍然需要配置我们的 Nginx Web 服务器来为 /var/www/laravel/public
目录中的应用程序提供服务。为此,我们需要使用该目录更新我们的 Nginx 默认配置,并添加对 php-fpm
的支持,以便它可以处理 PHP 脚本。
创建一个名为 nginx.conf
的新文件:
- nano nginx.conf
将此服务器块保存在该文件中。您可以查看本教程的第 4 步,了解有关此 Nginx 配置的更多详细信息;下面的修改是指定 Laravel 公共目录的位置,并确保 Nginx 使用我们在 hosts
文件中定义的主机名作为 server_name
和 inventory_hostname
变量。
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /var/www/laravel/public;
index index.php index.html index.htm;
server_name {{ inventory_hostname }};
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/laravel/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;
}
}
保存并关闭 nginx.conf
文件。
现在,我们可以使用模板模块来推送我们的新配置文件。 template
模块看起来和听起来与copy
模块非常相似,但是有很大的不同。 copy
将复制一个或多个文件而不做任何更改,而 template
复制单个文件并将解析文件中的所有变量。因为我们在配置文件中使用了 {{ inventory_hostname }}
,所以我们使用了 template
模块,因此它被解析为我们在 hosts 中使用的 IP 地址
文件。这样,我们就不需要对 Ansible 使用的配置文件进行硬编码。
然而,正如通常在编写任务时一样,我们需要考虑在 Droplet 上会发生什么。因为我们正在更改 Nginx 配置,所以需要重启 Nginx 和 php-fpm
。这是使用 notify
选项完成的。
- name: Configure nginx
template: src=nginx.conf dest=/etc/nginx/sites-available/default
notify:
- restart php5-fpm
- restart nginx
打开你的 php.yml
文件:
- nano php.yml
在任务部分的末尾添加这个 nginx 任务。整个 php.yml
文件现在应该如下所示:
---
- hosts: php
sudo: yes
tasks:
- name: install packages
apt: name={{ item }} update_cache=yes state=latest
with_items:
- git
- mcrypt
- nginx
- php5-cli
- php5-curl
- php5-fpm
- php5-intl
- php5-json
- php5-mcrypt
- php5-sqlite
- sqlite3
- name: ensure php5-fpm cgi.fix_pathinfo=0
lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0
notify:
- restart php5-fpm
- restart nginx
- name: enable php5 mcrypt module
shell: php5enmod mcrypt
args:
creates: /etc/php5/cli/conf.d/20-mcrypt.ini
- name: create /var/www/ directory
file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
register: cloned
- name: install composer
shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
args:
creates: /usr/local/bin/composer
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
when: cloned|changed
- 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
- name: Configure nginx
template: src=nginx.conf dest=/etc/nginx/sites-available/default
notify:
- restart php5-fpm
- restart nginx
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
保存并再次运行剧本:
- ansible-playbook php.yml --ask-sudo-pass
完成后,返回浏览器并刷新。您现在应该看到 Laravel 新项目页面!
结论
本教程介绍如何使用公共存储库部署 PHP 应用程序。虽然它非常适合学习 Ansible 的工作原理,但您不会总是在使用开放存储库的完全开源项目上工作。这意味着您需要使用您的私有存储库对第 3 步中的 git clone
进行身份验证。使用 SSH 密钥可以非常轻松地完成此操作。
例如,一旦您在存储库上创建并设置了 SSH 部署密钥,就可以在 git clone
任务之前使用 Ansible 在您的服务器上复制和配置它们:
- name: create /var/www/.ssh/ directory
file: dest=/var/www/.ssh/ state=directory owner=www-data group=www-data mode=0700
- name: copy private ssh key
copy: src=deploykey_rsa dest=/var/www/.ssh/id_rsa owner=www-data group=www-data mode=0600
这应该允许服务器正确验证和部署您的应用程序。
您刚刚使用 Composer 管理依赖项,在基于 Ubuntu 的 Nginx Web 服务器上部署了一个基本的 PHP 应用程序!所有这些都已完成,无需直接登录到您的 PHP Droplet 并运行单个手动命令。