介绍
本教程介绍了使用 Ansible 配置基本 PHP 应用程序的过程。 本教程结束时的目标是让您的新 Web 服务器为基本的 PHP 应用程序提供服务,而无需在目标 Droplet 上运行单个 SSH 连接或手动命令。
我们将使用 Laravel 框架 作为示例 PHP 应用程序,但是如果您已经拥有自己的框架和应用程序,可以轻松修改这些说明以支持其他框架和应用程序。
先决条件
在本教程中,我们将使用 Ansible 在 Ubuntu 14.04 Droplet 上安装和配置 Nginx、PHP 和其他服务。 本教程建立在 Ansible 基础知识之上,所以如果您是 Ansible 新手,可以先通读 this basic Ansible tutorial。
要遵循本教程,您将需要:
- 一个任意大小的 Ubuntu 14.04 Droplet,我们将使用它来配置和部署我们的 PHP 应用程序。 本机的 IP 地址将在整个教程中称为
your_server_ip
。 - 一个将用于 Ansible 的 Ubuntu 14.04 Droplet。 这是您将在整个教程中登录的 Droplet。
- Sudo 非 root 用户 为两个 Droplet 配置。
- Ansible Droplet 用于授权登录 PHP 部署 Droplet 的 SSH 密钥,您可以按照 本教程 在您的 Ansible Droplet 上进行设置。
第 1 步 — 安装 Ansible
第一步是安装 Ansible。 这很容易通过安装 PPA(Personal Package Archive)和使用 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
配置选项。
ansible.cfg
[defaults] hostfile = hosts
保存并关闭 ansible.cfg
文件。 接下来,我们将创建 hosts
文件,该文件将包含我们将部署应用程序的 PHP Droplet 的 IP 地址。
nano hosts
复制以下内容以添加 php
部分,将 your_server_ip
替换为您的服务器 IP 地址,将 sammy
替换为您在 PHP 的先决条件中创建的 sudo 非 root 用户水滴。
主机
[php] your_server_ip ansible_ssh_user=sammy
保存并关闭 hosts
文件。 让我们通过调用新的 php
组上的 ping
模块来运行一个简单的检查,以确保 Ansible 能够按预期连接到主机。
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
部分中添加两个处理程序。 处理程序非常适合这一点,因为它们仅在任务更改时才被触发。 它们也在剧本的末尾运行,因此多个任务可以调用同一个处理程序并且它只会运行一次。
执行上述操作的部分将如下所示:
- 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 错误
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
用户身份运行任务,以确保权限正确。 为此,我们可以使用 sudo
告诉 Ansible 以特定用户身份运行命令。 最终任务将如下所示:
- 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
命令,它安装所有必需的依赖项,然后运行 composer.json
文件的 post-create-project-cmd
部分中定义的项目创建步骤。 这是确保应用程序在首次使用时正确设置的最佳方式。
我们可以使用以下 Ansible 任务以 /usr/local/bin/composer
的形式全局下载并安装 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
任务是 Changed,那么我们运行 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
变量。
nginx.conf
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
文件现在应该如下所示:
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
保存并再次运行 playbook:
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 并运行单个手动命令。