如何在 Ubuntu 14.04 上使用 Ansible 部署高级 PHP 应用程序

介绍

本教程是关于在 Ubuntu 上使用 Ansible 部署 PHP 应用程序的系列中的第二部 14.04. 第一篇教程(https://andsky.com/tech/tutorials/how-to-deploy-a-basic-php-application-using-ansible-on-ubuntu-14-04)涵盖了部署应用程序的基本步骤,是本教程中描述的步骤的起点。

在本教程中,我们将涵盖设置SSH密钥以支持代码部署/发布工具,配置系统防火墙,提供和配置数据库(包括密码!),并设置任务编程程序(crons)和排队员。

就像最后一本教程一样,我们将使用Laravel框架(https://github.com/laravel/laravel)作为我们的PHP应用程序示例,但是,这些说明可以很容易地修改以支持其他框架和应用程序,如果你已经有自己的。

前提条件

此教程直接从 系列中的第一个教程,和所有配置和文件生成的该教程是必需的。 如果你还没有完成该教程,请先这样做,然后继续这个教程。

步骤 1 – 切换应用程序存储库

在此步骤中,我们将更新 Git 存储库到一个稍微自定义的示例存储库。

由于默认的Laravel安装不需要我们将在本教程中设置的先进功能,我们将从标准存储库切换到一个示例存储库,添加了一些调试代码,只是为了显示情况如何工作。

如果您尚未这样做,请从上一个教程中更改目录为ansible-php

1cd ~/ansible-php/

打开我们的现有游戏图书来编辑。

1nano php.yml

查找并更新克隆 git 存储库任务,以便它看起来像这样。

 1[label Updated Ansible task]
 2- name: Clone git repository
 3  git: >
 4    dest=/var/www/laravel
 5    repo=https://github.com/do-community/do-ansible-adv-php
 6    update=yes
 7    version=example
 8  sudo: yes
 9  sudo_user: www-data
10  register: cloned

保存并运行Playbook。

1ansible-playbook php.yml --ask-sudo-pass

当它完成运行时,请访问您的网络浏览器中的服务器(即:http://your_server_ip/`)。

这意味着我们已经成功地替换了我们的示例存储库的默认存储库,但应用程序无法连接到数据库。

步骤 2 — 设置 SSH 密钥用于部署

在此步骤中,我们将设置可用于应用程序代码部署脚本的 SSH 密钥。

虽然 Ansible 非常适合维护配置和设置服务器和应用程序,但诸如 EnvoyRocketeer 等工具通常用于将代码更改推向您的服务器并远程运行应用程序命令。大多数这些工具都需要 SSH 连接,可以直接访问应用程序安装。在我们的情况下,这意味着我们需要为www-data用户配置 SSH 密钥。

我们将需要用户的公共密钥文件,您希望将您的代码推出. 此文件通常在 ~/.ssh/id_rsa.pub. 将该文件复制到 ansible-php 目录。

1cp ~/.ssh/id_rsa.pub ~/ansible-php/deploykey.pub

我们可以使用Ansibleauthorized_key模块在/var/www/.ssh/authorized_keys中安装我们的公钥,这将允许部署工具连接和访问我们的应用程序。

1[label New Ansible task]
2- name: Copy public key into /var/www
3  authorized_key: user=www-data key="{{ lookup('file', 'deploykey.pub') }}"

我们还需要设置用户的www-data壳,这样我们就可以实际上登录。否则,SSH将允许连接,但不会向用户呈现壳。

1[label New Ansible task]
2- name: Set www-data user shell
3  user: name=www-data shell=/bin/bash

现在,打开编辑播放簿以添加新任务。

1nano php.yml

将上述任务添加到您的php.yml播放簿中;文件的尽头应与以下相匹配。

 1[label Updated php.yml]
 2. . .
 3
 4  - name: Configure nginx
 5    template: src=nginx.conf dest=/etc/nginx/sites-available/default
 6    notify:
 7      - restart php5-fpm
 8      - restart nginx
 9
10  - name: Copy public key into /var/www
11    authorized_key: user=www-data key="{{ lookup('file', 'deploykey.pub') }}"
12
13  - name: Set www-data user shell
14    user: name=www-data shell=/bin/bash
15
16  handlers:
17
18. . .

保存并运行Playbook。

1ansible-playbook php.yml --ask-sudo-pass

当 Ansible 完成时,您应该能够使用www-data用户进行 SSH。

1ssh www-data@your_server_ip

如果您成功登录,它正在起作用!您现在可以通过输入登录或按 CTRL+D 来重新登录。

我们不需要在本教程中的任何其他步骤中使用该连接,但如果您正在设置其他工具,如上所述,或根据需要进行一般调试和应用维护,它将是有用的。

第3步:设置防火墙

在此步骤中,我们将配置服务器上的防火墙,仅允许 HTTP 和 SSH 连接。

Ubuntu 14.04 配备了默认安装的 UFW (Uncomplicated Firewall) 和 Ansible 支持它与) 和端口 22 (SSH) 打开。

UFW模块有许多不同的选项,可以执行不同的任务,我们需要执行的不同任务是:

  1. 启用 UFW 并默认地拒绝所有输入的流量 2. 打开 SSH 端口但限制其速度以防止暴力攻击 3. 打开 HTTP 端口。

可以分别完成以下任务。

1[label New Ansible tasks]
2- name: Enable UFW
3  ufw: direction=incoming policy=deny state=enabled
4
5- name: UFW limit SSH
6  ufw: rule=limit port=ssh
7
8- name: UFW open HTTP
9  ufw: rule=allow port=http

如前所述,打开php.yml文件进行编辑。

1nano php.yml

将上述任务添加到播放簿中;文件的结尾应与以下相匹配。

 1[label Updated php.yml]
 2. . .
 3
 4  - name: Copy public key into /var/www
 5    authorized_key: user=www-data key="{{ lookup('file', 'deploykey.pub') }}"
 6
 7  - name: Set www-data user shell
 8    user: name=www-data shell=/bin/bash
 9
10  - name: Enable UFW
11    ufw: direction=incoming policy=deny state=enabled
12
13  - name: UFW limit SSH
14    ufw: rule=limit port=ssh
15
16  - name: UFW open HTTP
17    ufw: rule=allow port=http
18
19  handlers:
20
21. . .

保存并运行Playbook。

1ansible-playbook php.yml --ask-sudo-pass

一旦成功完成,您仍然可以通过SSH(使用Ansible)或HTTP连接到您的服务器;其他端口现在将被阻止。

您可以随时通过运行此命令来验证 UFW 的状态:

1ansible php --sudo --ask-sudo-pass -m shell -a "ufw status verbose"

打破上面的 Ansible 命令:

  • ansible: 运行原始的 Ansible 任务,没有播放本. * php: 对本组中的主机运行任务. * --sudo: 运行命令为 sudo. * --ask-sudo-pass: 提示为 sudo 密码. * -m shell: 运行 shell 模块. * -a 'ufw status verbose': 将要传入模块的选项. 因为这是一个 shell命令,我们将原始命令(即ufw status verbose)直接传入,没有任何 key=value` 选项。

它应该返回这样的东西。

 1[label UFW status output]
 2your_server_ip | success | rc=0 >>
 3Status: active
 4Logging: on (low)
 5Default: deny (incoming), allow (outgoing), disabled (routed)
 6New profiles: skip
 7
 8To Action From
 9--                         ------      ----
1022 LIMIT IN Anywhere
1180 ALLOW IN Anywhere
1222 (v6)                    LIMIT IN Anywhere (v6)
1380 (v6)                    ALLOW IN Anywhere (v6)

第4步:安装MySQL包

在此步骤中,我们将为我们的应用程序设置一个MySQL数据库。

第一步是确保MySQL安装在我们的服务器上,简单地将所需的包添加到我们玩本顶部的安装包任务中。我们需要的包是mysql-server,mysql-clientphp5-mysql

当我们添加包时,我们需要重新启动nginxphp5-fpm,以确保应用程序可以使用新的包。

关于Ansible的奇妙之处之一是,您可以修改任何任务并重新运行播放簿,并将应用这些更改,这包括选项列表,就像我们在apt任务中一样。

如前所述,打开php.yml文件进行编辑。

1nano php.yml

查找安装包任务,并更新它以包括上述包:

 1[label Updated php.yml]
 2. . .
 3
 4- name: install packages
 5  apt: name={{ item }} update_cache=yes state=latest
 6  with_items:
 7    - git
 8    - mcrypt
 9    - nginx
10    - php5-cli
11    - php5-curl
12    - php5-fpm
13    - php5-intl
14    - php5-json
15    - php5-mcrypt
16    - php5-sqlite
17    - sqlite3
18    - mysql-server
19    - mysql-client
20    - php5-mysql
21    - python-mysqldb
22  notify:
23    - restart php5-fpm
24    - restart nginx
25
26. . .

保存并运行 Playbook:

1ansible-playbook php.yml --ask-sudo-pass

第5步:创建MySQL数据库

在此步骤中,我们将为我们的应用程序创建一个MySQL数据库。

Ansible 可以直接使用)与 MySQL 交谈。

1[label New Ansible task]
2- name: Create MySQL DB
3  mysql_db: name=laravel state=present

我们还需要一个有已知密码的有效用户帐户,以便我们的应用程序连接到数据库。

我们将使用 Ansible 在服务器本身生成密码,并在需要时直接使用它。 为了生成密码,我们将使用makepasswd命令行工具,并要求一个32个字符的密码。

我们还会告诉 Ansible 记住命令的输出(即密码),所以我们可以在我们的播放簿中使用它。然而,因为 Ansible 不知道它是否已经运行了命令,我们也会在运行该命令时创建一个文件。

任务看起来像这样:

1[label New Ansible task]
2- name: Generate DB password
3  shell: makepasswd --chars=32
4  args:
5    creates: /var/www/laravel/.dbpw
6  register: dbpwd

接下来,我们需要使用我们指定的密码创建实际的MySQL数据库用户,这是通过使用mysql_user模块完成的,我们可以使用我们在密码生成任务中定义的变量上的stdout选项来获得壳命令的原始输出,如:dbpwd.stdout

mysql_user命令接受用户的名称和所需的权限。在我们的情况下,我们想要创建一个名为laravel的用户,并在laravel表中给他们完整的权限。

任务应该是这样的:

1[label New Ansible task]
2- name: Create MySQL User
3  mysql_user: name=laravel password={{ dbpwd.stdout }} priv=laravel.*:ALL state=present
4  when: dbpwd.changed

把这一点放在一起,打开php.yml文件进行编辑,这样我们就可以添加上面的任务。

1nano php.yml

首先,找到安装包任务,并更新它以包括makepasswd包。

 1[label Updated php.yml]
 2. . .
 3
 4- name: install packages
 5  apt: name={{ item }} update_cache=yes state=latest
 6  with_items:
 7    - git
 8    - mcrypt
 9    - nginx
10    - php5-cli
11    - php5-curl
12    - php5-fpm
13    - php5-intl
14    - php5-json
15    - php5-mcrypt
16    - php5-sqlite
17    - sqlite3
18    - mysql-server
19    - mysql-client
20    - php5-mysql
21    - python-mysqldb
22    - makepasswd
23  notify:
24    - restart php5-fpm
25    - restart nginx
26
27. . .

然后,在底部添加密码生成、MySQL数据库创建和用户创建任务。

 1[label Updated php.yml]
 2. . .
 3
 4  - name: UFW limit SSH
 5    ufw: rule=limit port=ssh
 6
 7  - name: UFW open HTTP
 8    ufw: rule=allow port=http
 9
10  - name: Create MySQL DB
11    mysql_db: name=laravel state=present
12
13  - name: Generate DB password
14    shell: makepasswd --chars=32
15    args:
16      creates: /var/www/laravel/.dbpw
17    register: dbpwd
18
19  - name: Create MySQL User
20    mysql_user: name=laravel password={{ dbpwd.stdout }} priv=laravel.*:ALL state=present
21    when: dbpwd.changed
22
23  handlers:
24
25. . .

**您可能已经注意到,虽然我们已经创建了 MySQL 用户和数据库,但我们没有用密码做任何事情,我们将在下一步处理此问题。 当您在 Ansible 中使用任务时,重要的是在运行任务前完成处理任务的全部工作流程/结果,以免需要手动登录和重置状态。

第6步:为数据库配置PHP应用程序

在此步骤中,我们将将MySQL数据库密码保存到应用程序的.env文件中。

正如我们在上一本教程中所做的那样,我们将更新.env 文件以包括我们新创建的数据库凭据。

1[label Laravel .env file]
2DB_HOST=localhost
3DB_DATABASE=homestead
4DB_USERNAME=homestead
5DB_PASSWORD=secret

我们可以将DB_HOST行留为,但将使用以下三个任务来更新其他三个任务,这些任务非常类似于我们在上一个教程中使用的任务来设置APP_ENVAPP_DEBUG

 1[label New Ansible tasks]
 2- name: set DB_DATABASE
 3  lineinfile: dest=/var/www/laravel/.env regexp='^DB_DATABASE=' line=DB_DATABASE=laravel
 4
 5- name: set DB_USERNAME
 6  lineinfile: dest=/var/www/laravel/.env regexp='^DB_USERNAME=' line=DB_USERNAME=laravel
 7
 8- name: set DB_PASSWORD
 9  lineinfile: dest=/var/www/laravel/.env regexp='^DB_PASSWORD=' line=DB_PASSWORD={{ dbpwd.stdout }}
10  when: dbpwd.changed

与MySQL用户创建任务一样,我们使用生成的密码变量(‘dbpwd.stdout’)将文件填充到密码中,并添加了‘何时’选项,以确保它只在‘dbpwd’更改时运行。

现在,由于.env 文件在我们添加密码生成任务之前已经存在,我们将需要将密码保存到另一个文件中。

1[label New Ansible task]
2- name: Save dbpw file
3  lineinfile: dest=/var/www/laravel/.dbpw line="{{ dbpwd.stdout }}" create=yes state=present
4  sudo: yes
5  sudo_user: www-data
6  when: dbpwd.changed

打开php.yml文件进行编辑。

1nano php.yml

将上述任务添加到播放簿中;文件的结尾应与以下相匹配。

 1[label Updated php.yml]
 2
 3. . .
 4
 5  - name: Create MySQL User
 6    mysql_user: name=laravel password={{ dbpwd.stdout }} priv=laravel.*:ALL state=present
 7    when: dbpwd.changed
 8
 9  - name: set DB_DATABASE
10    lineinfile: dest=/var/www/laravel/.env regexp='^DB_DATABASE=' line=DB_DATABASE=laravel
11
12  - name: set DB_USERNAME
13    lineinfile: dest=/var/www/laravel/.env regexp='^DB_USERNAME=' line=DB_USERNAME=laravel
14
15  - name: set DB_PASSWORD
16    lineinfile: dest=/var/www/laravel/.env regexp='^DB_PASSWORD=' line=DB_PASSWORD={{ dbpwd.stdout }}
17    when: dbpwd.changed
18
19  - name: Save dbpw file
20    lineinfile: dest=/var/www/laravel/.dbpw line="{{ dbpwd.stdout }}" create=yes state=present
21    sudo: yes
22    sudo_user: www-data
23    when: dbpwd.changed
24
25  handlers:
26
27. . .

再次,不要运行播放簿! 在我们可以运行播放簿之前,我们还有一个步骤要完成。

第7步:迁移数据库

在此步骤中,我们将运行数据库迁移以设置数据库表。

在Laravel中,这是通过在Laravel目录中运行)来完成的。

执行这个任务的 Ansible 看起来是这样的。

1[label New Ansible task]
2  - name: Run artisan migrate
3    shell: php /var/www/laravel/artisan migrate --force
4    sudo: yes
5    sudo_user: www-data
6    when: dbpwd.changed

现在是时候更新我们的播放簿了,打开php.yml文件进行编辑。

1nano php.yml

将上述任务添加到播放簿中;文件的结尾应与以下相匹配。

 1[label Updated php.yml]
 2. . .
 3
 4  - name: Save dbpw file
 5    lineinfile: dest=/var/www/laravel/.dbpw line="{{ dbpwd.stdout }}" create=yes state=present
 6    sudo: yes
 7    sudo_user: www-data
 8    when: dbpwd.changed
 9
10  - name: Run artisan migrate
11    shell: php /var/www/laravel/artisan migrate --force
12    sudo: yes
13    sudo_user: www-data
14    when: dbpwd.changed
15
16  handlers:
17
18. . .

最后,我们可以保存和运行游戏簿。

1ansible-playbook php.yml --ask-sudo-pass

当完成执行时,刷新浏览器中的页面,你应该看到一个消息说:

1[label http://your_server_ip/]
2Queue: NO
3Cron: NO

这意味着数据库设置正确,并按预期工作,但我们尚未设置 cron 任务或排队员。

步骤8 - 配置 cron 任务

在此步骤中,我们将设置需要配置的任何 cron 任务。

Cron 任务是按照设置的时间表运行的命令,可用于执行应用程序的任何任务,例如执行维护任务或发送电子邮件活动更新 - 基本上任何需要定期执行的命令,而无需用户手动干预。

Laravel 提供了一个名为schedule:run的工匠命令,该命令被设计为每分钟运行,并在应用程序中执行定义的计划任务,这意味着如果我们的应用程序利用此功能,我们只需要添加一个Cron任务。

Ansible有一个cron模块,有许多不同的选项,可以直接转化为您可以通过cron配置的不同选项:

  • job: 要执行的命令. 要求如果 state=present. * minute, hour, day, month, and weekday: 工作应该运行的分钟、小时、日、月或周日,分别。

默认情况下,它会创建一个每分钟运行的任务,这就是我们想要的。

1[label New Ansible task]
2- name: Laravel Scheduler
3  cron: >
4    job="run-one php /var/www/laravel/artisan schedule:run 1>> /dev/null 2>&1"
5    state=present
6    user=www-data
7    name="php artisan schedule:run"

运行一个命令是Ubuntu中的一个小助手,它确保命令只运行一次,这意味着如果以前的schedule:run命令仍在运行,它将不会再次运行,这有助于避免一个 cron 任务被锁定在循环中的情况,随着时间的推移,越来越多的相同任务的实例被启动,直到服务器耗尽资源。

如前所述,打开php.yml文件进行编辑。

1nano php.yml

将上述任务添加到播放簿中;文件的结尾应与下列相匹配。

 1[label Updated php.yml]
 2. . .
 3
 4  - name: Run artisan migrate
 5    shell: php /var/www/laravel/artisan migrate --force
 6    sudo: yes
 7    sudo_user: www-data
 8    when: dbpwd.changed
 9
10  - name: Laravel Scheduler
11    cron: >
12      job="run-one php /var/www/laravel/artisan schedule:run 1>> /dev/null 2>&1"
13      state=present
14      user=www-data
15      name="php artisan schedule:run"
16
17  handlers:
18
19. . .

保存并运行 Playbook:

1ansible-playbook php.yml --ask-sudo-pass

现在,刷新您的浏览器中的页面,在一分钟内,它将更新,看起来像这样。

1[label http://your_server_ip/]
2Queue: NO
3Cron: YES

作为示例应用程序的一部分,有一个 cron 任务,每分钟运行,更新数据库中的状态条目,以便应用程序知道它正在运行。

步骤9 - 配置队列戴蒙

与步骤 8 的 schedule:run 手工艺人命令一样,Laravel 还配备了一个队列工人,可以用queue:work --daemon 手工艺人命令启动。

队列工作者与 cron 工作相似,因为他们在背景中运行任务。区别在于应用程序将任务推入队列,无论是通过用户执行的操作,还是通过 cron 工作安排的任务。队列任务由员工一次执行,并在队列中发现时将按需处理。

与)是常见的方法,但这种方法需要了解如何配置和管理该系统。 使用 cron 和运行一命令来实现它,有更简单的方法。

我们将创建一个Cron输入来启动队列工人戴蒙,并使用运行一个来运行它,这意味着Cron将第一次启动过程,随后的Cron运行将被运行一个忽略,而工人正在运行。一旦工人停止,运行一个将允许命令再次运行,队列工人将重新启动。

考虑到这一切,我们将创建另一个 cron 任务来运行我们的队列工人。

1[label New Ansible task]
2- name: Laravel Queue Worker
3  cron: >
4    job="run-one php /var/www/laravel/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1>> /dev/null 2>&1"
5    state=present
6    user=www-data
7    name="Laravel Queue Worker"

如前所述,打开php.yml文件进行编辑。

1nano php.yml

将上述任务添加到播放簿中;文件的结尾应如下:

 1[label Updated php.yml]
 2. . .
 3
 4  - name: Laravel Scheduler
 5    cron: >
 6      job="run-one php /var/www/laravel/artisan schedule:run 1>> /dev/null 2>&1"
 7      state=present
 8      user=www-data
 9      name="php artisan schedule:run"
10
11  - name: Laravel Queue Worker
12    cron: >
13      job="run-one php /var/www/laravel/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1>> /dev/null 2>&1"
14      state=present
15      user=www-data
16      name="Laravel Queue Worker"
17
18  handlers:
19. . .

保存并运行 Playbook:

1ansible-playbook php.yml --ask-sudo-pass

如前所述,请在浏览器中刷新页面,一分钟后,它会更新,看起来像这样:

1[label http://your_server_ip/]
2Queue: YES
3Cron: YES

这意味着队列工作者在后台工作正确。我们在最后一步开始的 cron 工作将任务推到队列中。

我们现在有一个工作示例Laravel应用程序,其中包括运作的Cron工作和队列工人。

结论

本教程涵盖了使用Ansible部署PHP应用程序时的一些更先进的主题,所有使用的任务都可以轻松修改,以适应大多数PHP应用程序(取决于它们的具体要求),并且应该为您提供一个良好的起点,为您的应用程序设置自己的播放书。

我们没有使用单个SSH命令作为本教程的一部分(除了检查),而且一切 - 包括MySQL用户密码 - 已自动设置。

Published At
Categories with 技术
comments powered by Disqus