如何在Ubuntu14.04上使用Ansible部署基本PHP应用程序

来自菜鸟教程
跳转至:导航、​搜索

介绍

本教程介绍了使用 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] 组中添加值为 hostshostfile 配置选项。

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 安装一些必需的系统包。 特别是,我们将安装 gitnginxsqlite3mcrypt 和几个 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-fpmnginx 以确保更改生效,因此我们还需要在新的 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 设置为 localAPP_DEBUG 设置为 true。 我们想分别将它们换成 productionfalse。 这可以通过以下任务简单地使用 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_nameinventory_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 并运行单个手动命令。