dev-master
9999999-dev https://github.com/jordillonch/JordiLlonchDeployBundleA Symfony2 deploy bundle
MIT
The Requires
- php >=5.4.0
- yriveiro/php-fslock 0.1
The Development Requires
by Jordi Llonch
symfony2 deploy deployer
A Symfony2 deploy bundle
WIP, (*1)
This bundle aims to be a deploy system for your projects., (*3)
It is a Symfony2 Bundle but it can be used to deploy several kind of projects., (*4)
The bundle provides some commands to automatize deploy process. Here are main commands:, (*5)
Deployer have zones configured to deploy new code., (*6)
Zones are a project and environment (e.g. prod_api, our project Api for the production environment)., (*7)
Deployer uses GitHub repository, a configured branch, and HEAD as a target to deploy., (*8)
You can use this bundle adding it to your projects via composer (see installation section) but my recommendation is that you create a new project to deploy because you may be want to not have your production configurations in your repository project. So it is a good idea to delegate add productions configuration to the deploy system., (*9)
Furthermore this bundle offers helpers to automatize common operations like install composer dependencies, do a cache warm up for Symfony2 projects, refresh php-fpm after put code to production, get url to GitHub with diffs of new deployed code..., (*10)
There are two basic ideas that allows to deploy several code versions and put one of them to production and rollback between them., (*11)
When you want to deploy new code you have to do a "download" operation. That operation clones code from your git repository to a new directory (e.g. 20130704_180131_a618a56b08549794ec4c9d5db29058a01a58977f) then do adaptations to the code. Adaptations are the step where configurations are added, app cache is warned up, dependencies are downloaded and installed, symlinks are created to shared directoriesā¦, (*12)
Shared directories are directories where there are data that you want to keep between deploys. (e.g. logs, reports, generated images...), (*13)
After that, code is copied to configured servers. Ssh authorized keys are used to allow copy and execute commands to remote servers., (*14)
Then, when you want to use last downloaded code to production you have to execute "code to production" operation. This operation modify a symlink to the directory where last version are downloaded., (*15)
Usually, after that you should restart webserver or php-fpm., (*16)
Note: These ideas are taken from Capistrano., (*17)
php composer.phar create-project symfony/framework-standard-edition path/ 2.3.0
Add following lines to your composer.json
file:, (*18)
"require": { "jordillonch/deploy-bundle": "dev-master" }, "minimum-stability": "dev",
Execute:, (*19)
php composer.phar update
Add it to the AppKernel.php
class:, (*20)
new JordiLlonch\Bundle\DeployBundle\JordiLlonchDeployBundle(),
app/config/parameters.yml
, (*21)
jordi_llonch_deploy: config: project: MyProject vcs: git servers_parameter_file: app/config/parameters_deployer_servers.yml local_repository_dir: /home/deploy/local_repository clean_max_deploys: 7 ssh: user: myuser public_key_file: '/home/myuser/.ssh/id_rsa.pub' private_key_file: '/home/myuser/.ssh/id_rsa' private_key_file_pwd: 'mypassword' zones: prod_myproj: deployer: myproj environment: prod checkout_url: 'git@github.com:myrepo/myproj.git' checkout_branch: master repository_dir: /var/www/production/myproj/deploy production_dir: /var/www/production/myproj/code
app/config/parameters_deployer_servers.yml
, (*22)
prod_myproj: urls: - deploy@testserver1:8822 - deploy@testserver2:8822
parameters_deployers_servers.yml
) because this file contains a dynamic configuration that would be changed in a scalable environment like AWS.php app/console generate:bundle --namespace=MyProj/DeployBundle --dir=src --no-interaction
src/MyProj/DeployBundle/Service/Test.php:
, (*23)
<?php namespace MyProj/DeployBundle/Service; use JordiLlonch\Bundle\DeployBundle\Service\BaseDeployer; class Test extends BaseDeployer { public function downloadCode() { $this->logger->debug('Downloading code...'); $this->output->writeln('<info>Downloading code...</info>'); $this->downloadCodeVcs(); $this->logger->debug('Adapting code'); $this->output->writeln('<info>Adapting code...</info>'); // Here you can download vendors, add productions configuration, // do cache warm up, set shared directories... $this->logger->debug('Copying code to zones...'); $this->output->writeln('<info>Copying code to zones...</info>'); $this->code2Servers(); } public function downloadCodeRollback() { } protected function runClearCache() { $this->logger->debug('Clearing cache...'); $this->output->writeln('<info>Clearing cache...</info>'); $this->execRemoteServers('sudo pkill -USR2 -o php-fpm'); } }
jordi_llonch_deploy
<service id="myproj.deployer.test" class="MyProj/DeployBundle/Service/Test"> <tag name="jordi_llonch_deploy" deployer="myproj"/> </service>
myproj
is used in the configuration as deployer
value.It is necessary to add the public key of the deploy user to .ssh/authorized_keys
in remote servers in order to allow access to the deploy system., (*24)
After configure the deployer you have to do the initialization., (*25)
app/console deployer:initialize --zones=prod_myproj
Now you can download code from your repository and copy to your servers., (*26)
app/console deployer:download --zones=prod_myproj
After download you just need to put code into production., (*27)
app/console deployer:code2production --zones=prod_myproj
If there is any problem you can roll back to a previous version. See rollback command help., (*28)
Prepare deployer and remote servers creating a directories structure to host new code., (*29)
app/console deployer:initialize --zones=[zone1,zone2...]
Download code from repository, adapt, warn upā¦ and ship it to remote servers in order to put new code to production., (*30)
app/console deployer:download --zones=[zone1,zone2...]
Deploy new code to production atomically and reload web server, app..., (*31)
app/console deployer:code2production --zones=[zone1,zone2...]
Ensure that all downloaded versions of code are copied to all servers. Useful when you add a new server to a zone. If you not syncronize the new server the rollback operation will break the code in the new server., (*32)
app/console deployer:syncronize --zones=prod_myproj
If there is any problem and you need to roll back to a previous version you have two options:, (*33)
app/console deployer:rollback execute [steps_backward] --zones=[zone1]
steps_backward
should be 1
.1) Ask deploy for available versions to rollback., (*34)
app/console deployer:rollback list --zones=[zone1]
2) Execute rollback to specific version, (*35)
app/console deployer:rollback execute [version] --zones=[zone1]
Shows running version and last downloaded version prepared to put to production., (*36)
app/console deployer:status [--zones=[zone1,zone2...]]
Configure remote servers for zones. Useful for automatize scaling., (*37)
app/console deployer:configure zone [add, set, rm, list, list_json] [url]
Remove old code. Left clean_max_deploys
deploys., (*38)
app/console deployer:clean
Executes command passed as argument to all configured servers., (*39)
app/console deployer:exec2servers [command]
Deployer configurations are set in parameters.yml
., (*40)
You must set general configurations and zones., (*41)
app/config/parameters.yml
, (*42)
jordi_llonch_deploy: config: project: MyProject vcs: git local_repository_dir: /home/deploy/deploy_repository clean_max_deploys: 7 sudo: true ssh: user: myuser public_key_file: '/home/myuser/.ssh/id_rsa.pub' private_key_file: '/home/myuser/.ssh/id_rsa' private_key_file_pwd: 'mypassword'
Your project name., (*43)
Mail from., (*44)
Mail to send emails about deployments. It is an array., (*45)
Path where the servers parameters file is. A common configuration could be app/config/parameters_deployer_servers.yml
., (*46)
Servers urls are in this file because it contains a dynamic configuration that would be changed in a scalable environment like AWS by some script., (*47)
Directory where deployer clone your repositories, adapt code and save data about versions in the deploy system., (*48)
Used in the clean command to remove previous downloaded versions. Left clean_max_deploys
downloaded versions., (*49)
Add sudo
to all commands send to remote servers. If you want to use, you should set your deploy user to sudoers on all remote servers with NOPASSWD:, (*50)
/etc/sudoers
:, (*51)
deployer_user ALL=(ALL) NOPASSWD: ALL
Ssh configuration to establish connections on remote servers to execute commands., (*52)
Here an example of configuration:, (*53)
ssh: proxy: cli user: jllonch password: 'mypassword' public_key_file: '/home/myuser/.ssh/id_rsa.pub' private_key_file: '/home/myuser/.ssh/id_rsa' private_key_file_pwd: 'mykeypassword'
Client to use to execute remote commands., (*54)
It could be:, (*55)
pecl
: php-ssh2 extensioncli
: console ssh commandIf it is not defined it will try to use pecl
if it is installed, otherwise it will use cli
., (*56)
Username used in auth by password and auth by public key., (*57)
Password used in auth by password., (*58)
Public key file path., (*59)
Private key file path., (*60)
Private key password., (*61)
Helper parameters that can be get in your deploy class., (*62)
You need to set a minimum of one zone. Here is created your zone prod_myproj
:, (*63)
app/config/parameters.yml
, (*64)
jordi_llonch_deploy: ... zones: prod_myproj: deployer: myproj environment: prod checkout_url: 'git@github.com:myrepo/myproj.git' checkout_branch: master checkout_proxy: true repository_dir: /var/www/production/myproj/deploy production_dir: /var/www/production/myproj/code custom: my_key1: value1 my_key2: value2
app/config/parameters_deployer_servers.yml
, (*65)
prod_myproj: urls: - deploy@testserver1:8822 - deploy@testserver2:8822
Name of the service used to deploy the zone., (*66)
<service id="myproj.deployer.test" class="MyProj/DeployBundle/Service/Test"> <tag name="jordi_llonch_deploy" deployer="myproj"/> </service>
Environment., (*67)
Remote servers where deployed code will be copied and set to production., (*68)
Format is: [user]@[server]:[port]
, (*69)
Url to git repository., (*70)
Git branch to clone., (*71)
Deployer always clone a repository for every deploy. If you want to avoid to download from remote server you can clone your repository locally, then set checkout_url
to your local local repository (file:///home/deploy/proxy_repositories/myproj
). Then before download operation, deployer execute a git pull
to your local repository., (*72)
Path on remote servers where to copy new deployed code., (*73)
Path that is updated by deployer when new deployed code is set to production. So you must set this path to your webserver as a root path., (*74)
Custom parameters that can be get in your deploy class., (*75)
Helper parameters that must be set to use some helpers., (*76)
If helper parameters are set in general configuration those configuration are merged here., (*77)
Hepers automatize common operations like to install composer dependencies, to do a cache warm up for Symfony2 projects, to restart php-fpm after to put code to production, to get url to GitHub with differences of new deployed code..., (*78)
You can use Helpers
in your Deployer classes to execute common operartions., (*79)
Here and example:, (*80)
src/MyProj/DeployBundle/Service/Test.php:
, (*81)
<?php namespace MyProj/DeployBundle/Service; use JordiLlonch\Bundle\DeployBundle\Service\BaseDeployer; class Test extends BaseDeployer { public function initialize() { parent::initialize(); // Shared dirs $this->getHelper('shared_dirs')->initialize('logs'); } public function downloadCode() { $this->logger->debug('Downloading code...'); $this->output->writeln('<info>Downloading code...</info>'); $this->downloadCodeVcs(); $this->logger->debug('Adapting code'); $this->output->writeln('<info>Adapting code...</info>'); // composer $this->getHelper('composer')->install(); $this->getHelper('composer')->executeInstall(); // cache warm:up $this->getHelper('symfony2')->cacheWarmUp(); // shared directories $this->getHelper('shared_dirs')->set('app/logs', 'logs'); $this->logger->debug('Copying code to zones...'); $this->output->writeln('<info>Copying code to zones...</info>'); $this->code2Servers(); } public function downloadCodeRollback() { } protected function runClearCache() { $this->logger->debug('Clearing cache...'); $this->output->writeln('<info>Clearing cache...</info>'); $this->getHelper('phpfpm')->refresh(); } }
helperā¦
to install composer dependencies, doing cache warm up, setting shared directories and restarting php-fpm.Easy way to manage shared directories., (*82)
$this->getHelper('shared_dirs')->initialize($path)
, (*83)
$this->getHelper('shared_dirs')->set($pathInAppToLink, $pathInSharedDir)
, (*84)
Provides methods to restart php-fpm gracefully., (*85)
$this->getHelper('phpfpm')->refresh()
, (*86)
$this->getHelper('phpfpm')->refreshCommand()
, (*87)
Helpers to manage composer installation and some commands., (*88)
$this->getHelper('composer')->install()
, (*89)
$this->getHelper('composer')->executeInstall()
, (*90)
For now only provides a method to do a cache warm up., (*91)
$this->getHelper('symfony2')->cacheWarmupOnServers()
, (*92)
$this->getHelper('symfony2')->cacheWarmUp()
, (*93)
Useful methods to have feedback of your deploy in GitHub., (*94)
$this->getHelper('github')->getCompareUrl($gitUidFrom, $gitUidTo)
, (*95)
helper: github: url: https://github.com/YourUser/Repository
$this->getHelper('github')->getCompareUrlFromCurrentCodeToNewRepository()
, (*96)
Provides a method to send messages to a room in a HipChat., (*97)
$this->getHelper('hipchat')->send($msg, $color='purple')
, (*98)
helper: hipchat: token: your_token room_id: your_room_id
Jordi Llonch - llonch.jordi at gmail dot com, (*99)
DeployBundle is licensed under the MIT License. See the LICENSE file for full details., (*100)
A Symfony2 deploy bundle
MIT
symfony2 deploy deployer