Teenagers, it's time to deploy your php code in a more elegant way

Keywords: PHP git ssh Web Server

Let's recall how you released your code last time:

1. First, back up the online code with ftp

2. Upload modified files

3. Test whether the function is normal.

4. The website is 500. Replace it with a backup as soon as possible.

5. The replacement is wrong/the replacement is missing.

6. A successful server release

7. Log on to each station to perform a publishing operation once

8. Overtime

9. The boss is furious

...

Especially in the Internet industry nowadays, it pays attention to fast iteration and fast trot. Versions like bug fixes or minor features are released almost every day, and versions of large features are iterated almost once a week. I believe that many of my colleagues will release their own code as I said above. Or maybe a little more advanced, just go to the server and execute a command like git pull and drag down the code in the warehouse, but what if your code runs in the cluster? Does each machine log in and perform git pull once? What if you find something wrong with the code and need to roll back?

If you're still deploying your code in the way I said above, I hope you'll have the patience to read this article and get rid of the pain of code deployment.

 

In fact, around this circle, today I want to introduce to you the code publishing tool written in php: deployer.

deployer has the following attractive features:

- Fast: Using technologies such as concurrent publishing, ssh channel reuse, caching when available to accelerate code deployment

- Atomic Deployment: Performing all defined operations such as download dependencies and setting file access rights in the newly released version will not directly affect the online code. Only after all the successful deployment, will the last step of setting up a soft chain really replace the online code.

- Quick rollback. Because of atomic deployment, rollback is just to reset the soft chain pointing.

- Concurrent deployment: In a cluster environment, the same deployment process is executed concurrently on all machines

- Consistency: In a clustered environment, success is achieved only if all machines perform successfully, and all failures occur if one fails.

- Built-in release templates for multiple frameworks such as Laravel, Yii, Symfony, CodeIgniter, Zend Framework, etc.

- Extensible: It's easy to write publishing processes using Common templates based on your own projects

Installation:

composer global require deployer/deployer

After installation, switch to your own project directory, execute dep init, and select the generated deployment template according to the framework used by your project:

tb dep init
Please select your project type (defaults to common):
  [0] Common
  [1] Laravel
  [2] Symfony
  [3] Yii
  [4] Zend Framework
  [5] CakePHP
  [6] CodeIgniter
  [7] Drupal
 > 0

If your framework does not use any of the frameworks listed above, select 0 and return to generate a generic release template.

This step should generate a deploy.php file in your project root directory. All you need to do is edit the script, fill in some of your own servers and project configurations, and then customize some task s.

Next, I will introduce the use of deployer with a specific configuration file, which is as follows:

 

<?php
namespace Deployer;

use Symfony\Component\Console\Input\InputOption;

require 'recipe/common.php';

option('tag', null, InputOption::VALUE_OPTIONAL, 'Published tag');

// Global Profile   
set('ssh_type', 'native');    // There are three ways to log on to a remote host: phpseclib (default), native, ext-ssh2
set('ssh_multiplexing', true);  // Whether to turn on ssh channel multiplexing technology (opening can reduce server and local load, and speed up)
set('keep_releases', 10); //    Error report 10 previous versions, set to - 1 to indicate that the historical version has been saved
set('repository', 'git@xxxxxxx.com:loc/loc-api.git');    // Code repository address, git only
set('branch', 'master');    // Branches used by default when publishing code
set('shared_files', []);    // Shared File List The files listed above will be moved to the shared directory of the project root directory and made into a soft chain.
set('shared_dirs', []);     // Shared directory, ibid.
set('writable_mode', 'chmod');  // There are four ways to control writable permissions: chown, chgrp, chmod, acl (default mode)
set('writable_chmod_mode', '0755'); // Writable permission values given when chmod is used to control writable permissions
set('writable_dirs', []);   // Writable directories specify which directories need to be writable by web server
set('clear_path', []);  // Set the directory to be deleted when the code is published
set('http_user', 'nginx');  // Users of web server generally do not need to set up, deployer will automatically judge
set('release_name', function () {   // Set the publishing name. tag is preferred here. Date + time is used to indicate the publishing time if not transmitted.
    if (input()->hasOption('tag')) {
        return input()->getOption('tag');
    }
    return date('Ymd-H:i');
});

// Multiple servers can be set up and sent to multiple servers synchronously according to the settings at the time of publication.
// For each server, parameters can be set individually, and the parameters set will cover the global parameters.
server('prod_1', 'xxx.xxx.xxx.xxx')
    ->user('root')
    ->password('xxxxx')
    ->set('deploy_path', '/var/www/tb')   // Code deployment directory, note: your web server, such as nginx, should set the root directory to be / var/www/tb/current.
                                          // Because current is a soft chain that points to the version actually used on the current line.
    ->stage('prod');  // Identify the server type for server grouping

server('prod_2', 'xxx.xxx.xxx.xxx')
    ->user('root')
    ->password('xxxxx')
    ->set('deploy_path', '/var/www/tb')
    ->set('branch', 'master')   // Specifying the branch to this server overrides the branch parameter set globally
    ->set('extra_stuff', '...') // Specify any other parameters at will
    ->stage('prod');
    
server('beta', 'xxx.xxx.xxx.xxx')
    ->user('root')
    ->password('xxxxx')
    ->set('deploy_path', '/var/www/test')
    ->set('branch', 'beta')   // Test environments use beta branches
    ->stage('beta');    // Grouping in beta


// Configured tasks
task('success', function () {
    Deployer::setDefault('terminate_message', '<info>Successful release!</info>');
})->once()->setPrivate();   // Increase the once call so that the task will be performed locally, not remotely, and only once

desc('restart php-fpm');    // You can add a description to the task, which you will see when you execute dep list
task('php-fpm:restart', function () {
    run('systemctl restart php-fpm.service');  // The run function defines the operations performed on the server, usually a shell command, which can return values and print commands.
});     // Smart as you must have found, you can use run functions to create batch management server tasks, such as batch overloading of all nginx configuration files, batch execution of scripts on the server, etc.

after('deploy:symlink', 'php-fpm:restart'); // Hook function, which means to perform php-fpm restart task after executing the task of setting up the soft chain

desc('Publishing projects');
task('deploy', [    // Composite tasks can be set, and the second parameter is all subtasks included in the composite task, which will be executed in turn.
    'deploy:prepare',   // Prepare before publishing, check if some directories need to exist, nonexistence will be created automatically
    'deploy:lock',  // Generate lock files to avoid confusion by executing two publishing processes on one server at the same time
    'deploy:release',   // Create Code Storage Directory
    'deploy:update_code',   // Update code, usually git, you can also rewrite the task, using upload method, using sftp upload method
    'deploy:shared',    // Processing shared files or directories
    'deploy:writable',  // Setting directory writable permissions
    'deploy:vendors',   // Installation dependencies based on composer configuration
    'deploy:clear_paths',   // Perform deletion based on the clear_path parameter set
    'deploy:symlink',   // Setting symbols to connect to the latest updated code, online access at this time is the code of this release.
    'deploy:unlock',     // Delete lock files for next release
    'cleanup',  // According to keep_releases parameter, clear the old version and release the server disk space
    'success'   // Performing successful tasks, as defined above, is generally used as a reminder
]);


after('deploy:failed', 'deploy:unlock');    // If the publication fails, delete the lock file for the next retry

 

The above is a relatively complete automated deployment script configuration, do you feel very simple? Because most of the configuration work is already done for you when you execute dep init!

The next thing you need to do is add the ssh-key of the server you want to deploy to your git account authentication library. You can also create an account with only git pull and git clone privileges of the warehouse, keeping the principle of minimum privileges. It's important to note that the first time you execute git clone on the server after adding key may require you to enter yes, so the safest way is to execute git clone once on each server to be deployed and drag the warehouse code to another directory.

After doing the above, all the preparations will be completed. Deployment tests can then be conducted.

First of all, check if there is any problem with the configuration:

 

dep config:dump beta    // Configuration of Print beta Environment
dep config:dump prod    // Configuration of Printing Production Environment

If there is no problem with the printed configuration, then perform the publishing task:

dep deploy beta // Publish the current beta branch to the beta environment
dep --tag=v1.1 deploy prod // Publish v1.1 tag code to production environment, add - p option, and send it to all servers

A successful deployment should have output similar to the following:

 

➜  tb git:(master) ✗ dep --tag=v1.1 deploy prod_1
✔ Executing task deploy:prepare
✔ Executing task deploy:lock
✔ Executing task deploy:release
✔ Executing task deploy:update_code
✔ Executing task deploy:shared
✔ Executing task deploy:writable
✔ Executing task deploy:vendors
✔ Executing task deploy:clear_paths
✔ Executing task deploy:symlink
✔ Executing task php-fpm:restart
✔ Executing task deploy:unlock
✔ Executing task cleanup
✔ Executing task success
 Release success!

View which version of the current production environment is in use

dep current prod  //This should output v1.1 

See which version of the current production environment is used:

 

dep current prod  //This should output v1.1 

If a problem is found before and after publishing to the online site, it needs to be rolled back and only need to be executed:

dep rollback prod   // In fact, it just modifies the pointing of the soft chain, so it can be executed quickly and can hardly fail.

With dep current Pro again, you should be able to see the rollback to the previous version.

Another example is that the previous execution had a problem, was interrupted, and another execution might prompt: Deploy locked, then only execution:

 

dep deploy:unlock prod // Delete lock files

If online disk space is tight (usually not), you can delete earlier versions by executing the following commands:

dep cleanup

 

Here's all you need to know about deployer. Although the first configuration does take some time, it may take half an hour or half a day. But in return for a more elegant, fast, secure and rollback release process, is it a little exciting to think about it?

If there are any problems in the installation and use process, we can add a group: 632109190 for discussion. Students interested in php, java, operations and maintenance can join us. I'm waiting for you here.

Posted by jordanwb on Sat, 06 Jul 2019 19:11:39 -0700