Magallanes is a deployment tool made with PHP and for PHP applications, it's quite simple to use and manage.
Just like typing bin/mage deploy production
If you have used Magallanes, and you found it useful, then let's grab some coffee!
Overview
Magallanes is a deployment tool for PHP applications built with PHP itself, it's quite simple to use, manage and extend. It will get your application to a safe harbor. You can instruct Magallanes to deploy your code to all the servers you want, and run tasks for that freshly deployed code. You can also instruct Magallanes to run tasks before the deployment starts (e.g: a vendors install) and after the deployment is done (e.g: clear some caches).
The mission with Magallanes is very simple, to move code from point A to point B (or several Bs) and group common tasks associated with the deployment workflow. Some of this tasks are quite common, like installing vendors and warming a cache, so there are some Built In Tasks for common usage. But you are encouraged to build your own... and share them!
As it has always been, Magallanes is open to Pull Requests, just make sure you write tests for any new feature and all the new code has the appropriate coverage, we have 100% coverange and I plan on staying there. Also read the contribution document.
The current version of Magallanes (v4) has been refactored to work with Symfony4 Components, in particular Console, Process, FileSystem, YAML, and Finder, and PHP 7.1. Also the logging is delegated to Monolog, and of course all the power of Composer to glue all together.
The version 3 will be still maintained for bugs and compatibility with Symfony 3. If possible I will add back any new feature of v4, but no promises!
Installation
Installing Magallanes is quite simple, just add the dependency to your Composer configuration, update and you are done!
"require-dev": {
"andres-montanez/magallanes": "^5.0"
}
Also you can execute: composer require andres-montanez/magallanes:^5.0
After installing you can invoke Magallanes with the vendor/bin/mage executable,
or you can configure Composer to link all vendors binaries into a more friendly directory,
for example under bin
adding this configuration to your composer.json
"config": {
"bin-dir": "bin"
}
You will have to purge your vendors and install them again. Or you could just simply symlink to the binary ln -s vendor/bin/mage bin/mage
For the rest of the documentation let's assume your Magallanes executable is bin/mage
The most simple test is to check the installed version
bin/mage version
Magallanes v5.0.0 [Galactica]
Pro Tip: Global Install!
You can configure Composer to install Magallanes globally:
composer global require "andres-montanez/magallanes"Just make sure your global vendor binaries directory is in your $PATH
environment variable, you can get its location with the following command:
Find out more about globals in Composer official documentation.
Warning
If you install Magallanes globally, you won't be able to use custom tasks, because your app autoloader will not be used. You have been warned!
Configuration
All configuration is handled by one single YAML file in the root of the project: .mage.yml
This file contains environment definitions, options and tasks configurations.
The following example is a very basic configuration with just one environment:
magephp:
environments:
production:
user: app
branch: master
from: ./
host_path: /var/www/myapp
releases: 4
exclude:
- ./var/cache/*
- ./var/log/*
- ./web/app_dev.php
hosts:
- webserver1
- webserver2
- webserver3
pre-deploy:
- git/update
- composer/install
- composer/dump-autoload
on-deploy:
- symfony/cache-warmup: { env: 'dev' }
- symfony/assets-install: { env: 'dev' }
on-release:
post-release:
post-deploy:
The first element of the configuration must be the magephp
node.
Then the environments
section will hold all the configuration for your environments.
An environment is a set of configurations, there you will define where you want to deploy the code to, with which user, to which folder, to which hosts, of you need to checkout a specific branch (if using git), if you want to keep a history of the releases (deployed code) just in case you may need to rollback, also you have the chance to exclude some files if needed. And then a set of tasks to execute in specific order and stages of the deployment.
Also there are many configuration options which can be overwritten for your convenience.
Environments
The key of your environment will be it's name, so in the example above it is production
,
therefore you will deploy with bin/mage deploy production
Let's take a look at the configuration options
Option | Description |
---|---|
user |
It's the username to use on SSH and Rsync commands. Use a user who has enough privileges to write on the host. If undefined then the current user (read with |
branch |
If you are using Git, and this option is defined, then Magallanes will try to checkout this branch for the deployment. It's useful if you have a development branch and environment. If left undefined no git task will be executed. |
from |
This is the starting point/path from which the Tar or Rsync will be executed. The default value is This only affects the tar and rsync commands execution. |
copyDirectory |
This option is used for Tar, if set to true the content of However, if set to false the directory itself will be copied. The default value is false to keep it backward compatible. Experiment with it to better fit your needs. This only affects the tar command execution. |
host_path |
It's the path on the remote hosts to where the code is going to be deployed. This parameter is shared with all hosts. If left undefined a |
ssh |
Configuration overwrite for SSH commands. See following section Configuration » SSH. |
sudo |
If set to true all remote commands will be prefixed with sudo. Default is false |
tar_create |
Configuration overwrite for flags on Tar creation. See following section Configuration » Tar. If left undefined a |
tar_extract |
Configuration overwrite for flags on Tar extraction. See following section Configuration » Tar. If left undefined a |
rsync |
Configuration overwrite for Rsync flags. See following section Configuration » Rsync. If left undefined a |
releases |
If you want to enable Releases and in consequence the option to perform Rollback, then define this parameter indicating how many releases you want to leave on the hosts. The greater the number the more back in time you will be able to rollback, but it will also consume more storage. By default releases are disabled. |
symlink |
When using Releases, the symbolic link name will be If left undefined |
exclude |
A list of files or directories to exclude when doing Rsync or when creating the Tar for the deployment.
Be careful with the use of wildcards, also rsync and tar take Also you can define this option globally and all your environments will inherit it.
|
hosts |
The list of hosts to which the code is going to be deployed. It can be an empty list, if so all deployment tasks will be skipped. Make sure you can connect passwordless to all of them using SSH keys. |
|
The list tasks to be executed on each stage. The list can be empty, Magallanes still will add some tasks by itself in order to run the deployment process. |
You can have as many environments as you want. If using several branches make sure to always have the same .mage.yml
file across then all,
otherwise the in-memory configuration will not be updated.
SSH
Many tasks rely on SSH connection, like scp, rsync and of course executing remote commands with ssh. You can configure the following options for each environment. Each options is shown with it's default value.
magephp:
environments:
production:
ssh:
port: 22
flags: -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
timeout: 60
You can use the flags option to tweak your SSH connection as best fits your needs. The best way to make your connection is by using SSH Keys across your servers. These flags are also inherited by the Rsync and Tar tasks.
The timeout options is the amount of time in seconds for the underlying ssh process to run. The default value is 300
seconds.
Pro Tip: Port in Host
You can configure the port of the host in it's definition by using the colon notation:
magephp:
environments:
production:
hosts:
- webserver1
- webserver2:2222
- webserver3
In the example below the host webserver2 will use port 2222 instead of the default.
Warning
Be careful if you overwrite these flags, otherwise you may experience problems when connecting to the hosts.
Some flags options for ssh are incompatible with scp, so if you need to split these flags, you can define the option scp_flags
to be used with scp only.
magephp:
environments:
production:
ssh:
port: 22
flags: -t -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
scp_flags: -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
timeout: 60
In the example above, the ssh option -t
is defined, but it is incompatible with scp, so we define the scp_flags
without it.
Warning
If you use the scp_flags
options, please remember to add the default values -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no to avoid issues when copying files.
Tar
The Tar tasks uses two set of flags, one for creation of the file, and another for it's extraction. By default the creation flags are cfzop
and the extraction flags are zfzop
, you can overwrite them if you need to in the environment section.
Also you can specify the path to the tar binary for creation and extraction, by default the binary used is tar.
magephp:
environments:
production:
tar_create: cfh
tar_create_path: tar
tar_extract: xf
tar_extract_path: tar
Warning
Be careful if you overwrite these flags, the creation flags should always have at least cf
which stands for Create and File.
And the extraction flags should always have at least xf
which stands for eXtract File.
Rsync
The Rsync task uses by default the -avz
flags, you can overwrite them if you need to in the environment section.
magephp:
environments:
production:
rsync: -avz
Logging
Logging is optional but encouraged nonetheless, you can enable them by defining this general option:
magephp:
log_dir: /path/to/my/logs
log_limit: 10
The log_dir
option is a directory where all the logs will be generated,
at the beginning of the deployment the current log file will be informed. If the directory doesn't exists, an error will be thrown, so make sure the directory for logs is available.
The log_limit
option is how many log files will be kept. If left undefined it will default to 30 log files.
Releases
When using Releases you have to take into account that Magallanes will create a releases
directory
in the host_path
directory, and a symbolic link current
which will point to a release inside releases
.
The code will be deployed to a directory named after a Release Id, which is just a convenient timestamp.
This is a directory tree example:
/var/www/app/
current -> releases/20170102121530
-
releases/
20170101061530/
20170101081530/
20170102061530/
20170102121530/
File/Folder | Purpose |
---|---|
/var/www/app/ |
The host_path directory, defined in the configuration |
releases/ |
Contains all the deployed releases |
releases/20170102121530/ |
A deployed release |
current |
A symbolic link pointing to the live release |
Take into account this when configuring Virtual Hosts, cronjob paths, etc.
Regarding Symlinks, Part I
If you are going to use relative symlinks inside your release directory, remember that the real path is /var/www/app/releases/20170102121530/
and not /var/www/app/current
So if you want to go "one directory down", for example to /var/www/app/shared
, the symlink will be ../../shared
Workflow
Overview
Nice flowcharts coming soon ¯\_(ツ)_/¯
...or not
Stages
Magallanes works in Stages. Each stage is a step in the deployment process. Each stage has a context of execution, and within that context, some tasks will be executed.
The Local context is when by default tasks will operate on the directory where you are launching the deployment. On the other end, Remote context is when by default tasks will be executed on the current working remote host, to which the code is being deployed to.
Name | Code | Context | Description | Examples |
---|---|---|---|---|
Pre Deploy | pre-deploy |
Local | This is the first stage in the deployment. Tasks in this stage will be the firsts to be executed. | Pulling from repository, switching branches, installing vendors |
On Deploy | on-deploy |
Remote | This is the second stage. Tasks in this stage will be the firsts to be executed on each host. This stage will be triggered for each defined deployment host. | Warming cache, installing assets, switching configuration |
On Release | on-release |
Remote | This stage is optional, and will be executed only if Releases are enabled. Tasks in this stage will be executed on each host at the moment of swapping the current release. This stage will be triggered for each defined deployment host. | Puring APC Cache |
Post Release | post-release |
Remote | This stage is optional, and will be executed only if Releases are enabled, and after all releases where swapped successfully on each host. Tasks in this stage will be executed on each host after the swapping the current release. This stage will be triggered for each defined deployment host. | Removing locks, purging cache |
Post Deploy | post-deploy |
Local | This is the last stage in the deployment. Tasks in this stage will be the lasts to be executed. | Purging cache |
Strategies
Magallanes uses two strategies for making the deployments. This is inferred from the configuration and currently can not be configured. If you have releases enabled then the Releases Strategy will be used, which copy the code using a tar file and scp.
On the other hand if you don't use Releases then Magallanes will use the Rsync Strategy which copy the code using rsync command.
Also there are a few restrictions with the Rsync Strategy, the tasks defined on the on-release
and post-release
stages
will not be executed because releases are not enabled so it doesnt' make sense to execute tasks associated with releases stages.
Commands
Version
Quite self explanatory, this command will tell you which version of Magallanes is being used.
bin/mage version
Magallanes v5.0.0 [Galactica]
Config
The Config is useful for debugging, it offers two subcommands: dump and environments
Dump
This will dump your .mage.yml
file as interpreted by the Yaml component, in a PHP array export.
This is the interpreted output of the sample configuration. This can be useful for debuging config errors, like bad indentation in the yaml file.
bin/mage config:dump
Starting Magallanes array ( 'environments' => array ( 'production' => array ( 'user' => 'app', 'branch' => 'master', 'host_path' => '/var/www/myapp', 'releases' => 4, 'exclude' => array ( 0 => './var/cache/*', 1 => './var/log/*', 2 => './web/app_dev.php', ), 'hosts' => array ( 0 => 'webserver1', 1 => 'webserver2', 2 => 'webserver3', ), 'pre-deploy' => array ( 0 => 'git/update', 1 => 'composer/install', 2 => 'composer/dump-autoload', ), 'on-deploy' => array ( 0 => array ( 'symfony/cache-warmup' => array ( 'env' => 'dev', ), ), 1 => array ( 'symfony/assets-install' => array ( 'env' => 'dev', ), ), ), 'on-release' => NULL, 'post-release' => NULL, 'post-deploy' => NULL, ), ), ) Finished Magallanes
Environments
This other option will list all the defined environments and some handy information: defined user, branch, and hosts list. This is the output for the sample configuration.
bin/mage config:environments
Starting Magallanes +-------------+------+--------+------------+ | Environment | User | Branch | Hosts | +-------------+------+--------+------------+ | production | app | master | webserver1 | | | | | webserver2 | | | | | webserver3 | +-------------+------+--------+------------+ Finished Magallanes
Pro Tip!
Magallanes Commands are in fact Symfony Console Commands, so you can shortcut them like this:
bin/mage conf:env
Deploy
Well, this is the big one! The deploy command will start the deployment of your code. You just have to provide to which environment you want to deploy to:
bin/mage deploy production and that's it! You have done it!!
Optionally you can set a branch with --branch and a branch name, which will override your configuration, if you don't have a branch configured it will be set to the one provided.
Here is a complete output based on the sample configuration form above
bin/mage deploy production --branch test
Starting Magallanes Environment: production Release ID: 20170104042540 Strategy: Releases Branch: test Starting Pre Deploy tasks: Running [Git] Change Branch (test) ... OK Running [Git] Update ... OK Running [Composer] Install ... OK Running [Composer] Generate Autoload ... OK Running [Deploy] Preparing Tar file ... OK Finished 5/5 tasks for Pre Deploy. Starting On Deploy tasks on host webserver1: Running [Release] Preparing Release ... OK Running [Deploy] Copying files with Tar ... OK Running [Symfony] Cache Warmup ... OK Running [Symfony] Assets Install ... OK Finished 5/5 tasks for On Deploy. Starting On Deploy tasks on host webserver2: Running [Release] Preparing Release ... OK Running [Deploy] Copying files with Tar ... OK Running [Symfony] Cache Warmup ... OK Running [Symfony] Assets Install ... OK Finished 5/5 tasks for On Deploy. Starting On Deploy tasks on host webserver3: Running [Release] Preparing Release ... OK Running [Deploy] Copying files with Tar ... OK Running [Symfony] Cache Warmup ... OK Running [Symfony] Assets Install ... OK Finished 5/5 tasks for On Deploy. Starting On Release tasks on host webserver1: Running [Release] Creating Symlink ... OK Finished 1/1 tasks for On Release. Starting On Release tasks on host webserver2: Running [Release] Creating Symlink ... OK Finished 1/1 tasks for On Release. Starting On Release tasks on host webserver3: Running [Release] Creating Symlink ... OK Finished 1/1 tasks for On Release. Starting Post Release tasks on host webserver1: Running [Release] Cleaning up old Releases ... OK Finished 1/1 tasks for On Release. Starting Post Release tasks on host webserver2: Running [Release] Cleaning up old Releases ... OK Finished 1/1 tasks for Post Release. Starting Post Release tasks on host webserver3: Running [Release] Cleaning up old Releases ... OK Finished 1/1 tasks for Post Release. Starting Post Deploy tasks: Running [Deploy] Cleanup Tar file ... OK Running [Git] Change Branch (master) ... OK Finished 2/2 tasks for Post Deploy. Finished Magallanes
As you can see there are many tasks added by Magallanes. This configuration has Releases enabled so
the deployment will be executed with a Tar file copied to all defined hosts. On the Pre Deploy
stage the Tar file is created,
then on each On Deploy
iteration the file is copied, and finally the file is deleted on the Post Deploy
stage.
Also, because Releases are enabled, Magallanes needs to create the release directory, swap the current symlink, and then delete old releases.
On the same fashion, the first task of the On Deploy
stage is to create the directory, then the On Release
stage the symlink is swapped,
and after all releases were completed successfully the delete process is triggered on the Post Release
stage.
A similar process is made for changing branches, but on the Pre Deploy
and Post Deploy
stages.
Also, if you want to deploy a specific tag, you can pass the option --tag and a tag name which will override your configuration and checkout the specified tag.
Here is the header output when deploying a tag.
bin/mage deploy production --tag v1.0.3
Starting Magallanes Environment: production Release ID: 20170104042540 Strategy: Releases Tag: v1.0.3 ...
Warning
Take into account that the --branch and --tag options are mutually exclusive.
Releases
The Releases command is in charge of managing your deployed releases, it offers two subcommands: list and rollback
List
This will list your releases on a given environment. This is the list output for the sample configuration.
bin/mage releases:list production
Starting Magallanes Environment: production Releases on host webserver1: Release ID: 20170102121530 - Date: 2017-01-02 12:15:30 [2 hour(s) ago] [current] Release ID: 20170102061530 - Date: 2017-01-02 06:15:30 [8 hour(s) ago] Release ID: 20170101081530 - Date: 2017-01-01 08:15:30 [1 day(s) ago] Release ID: 20170101061530 - Date: 2017-01-01 06:15:30 [1 day(s) ago] Releases on host webserver2: Release ID: 20170102121530 - Date: 2017-01-02 12:15:30 [2 hour(s) ago] [current] Release ID: 20170102061530 - Date: 2017-01-02 06:15:30 [8 hour(s) ago] Release ID: 20170101081530 - Date: 2017-01-01 08:15:30 [1 day(s) ago] Release ID: 20170101061530 - Date: 2017-01-01 06:15:30 [1 day(s) ago] Releases on host webserver3: Release ID: 20170102121530 - Date: 2017-01-02 12:15:30 [2 hour(s) ago] [current] Release ID: 20170102061530 - Date: 2017-01-02 06:15:30 [8 hour(s) ago] Release ID: 20170101081530 - Date: 2017-01-01 08:15:30 [1 day(s) ago] Release ID: 20170101061530 - Date: 2017-01-01 06:15:30 [1 day(s) ago] Finished Magallanes
The [current]
label indicates that that's the release being used at the moment.
Rollback
Rollback is the other big command, it allows you to swap the current deployment to another release, already stored on your hosts.
The command besides needing the environment it also requires the Release Id to which you want to change the current deployment. It must exists on all your hosts. This is the rollback output for the sample configuration.
bin/mage releases:rollback production 20170101081530
Starting Magallanes Environment: production Rollback to Release ID: 20170101081530 Strategy: Releases Starting Pre Deploy tasks: Running [Git] Update ... SKIPPED Running [Composer] Install ... SKIPPED Running [Composer] Generate Autoload ... SKIPPED Finished 3/3 tasks for Pre Deploy. No tasks defined for On Deploy stage Starting On Release tasks on host webserver1: Running [Release] Creating Symlink ... OK Finished 1/1 tasks for On Release. Starting On Release tasks on host webserver2: Running [Release] Creating Symlink ... OK Finished 1/1 tasks for On Release. Starting On Release tasks on host webserver3: Running [Release] Creating Symlink ... OK Finished 1/1 tasks for On Release. No tasks defined for Post Release stage No tasks defined for Post Deploy stage Finished Magallanes
As you can compare with the output from the deployment, many of the tasks are skipped because they only make sense when doing a deployment.
Also take notice that all stages are executed, but many will not have tasks.
BuiltIn Tasks
Deploy
The Deployment Tasks are automatically used by Magallanes when preparing the tasks that needs to be executed for the deployment.
You can use this tasks to tweak the order of execution. For example, on a deployment without releases, Magallanes adds deploy/rsync
as the first task of the On Deploy stage,
but you may want to run a custom task before that, so you can add deploy/rsync
as the second task in the list and Magallanes will respect the order you defined.
In most cases you will not need to manually use these tasks.
Name | Stage | Description |
---|---|---|
deploy/release/prepare |
On Deploy | When releases are enabled, this task will create the appropriate directory on each host. |
deploy/release |
On Release | When releases are enabled, this task will create the symlink current to the appropriate directory on each host. |
deploy/release/cleanup |
Post Release | When releases are enabled, this task will look up all the releases directories on all hosts and if it has passed the number of defined releases it will delete the oldest. |
deploy/rsync |
On Deploy | When releases are not enabled the deployment will be copied with rsync, this task will sync the code to all hosts. |
deploy/tar/prepare |
Pre Deploy | When releases are enabled, this task will create a zipped tarball file with tar. |
deploy/tar/copy |
On Deploy | When releases are enabled, this task will copy with scp the tarball file created earlier to all defined hosts. |
deploy/tar/cleanup |
Post Deploy | When releases are enabled, after the deployment is complete, this task will delete the tarball file created earlier. |
GIT
This task are for interacting with your GIT repository, it's most likely that you will use git/update
at the beginning of your Pre Deploy tasks.
Magallanes will automatically add the git/change-branch
task if needed.
Name | Stage | Parameters | Description |
---|---|---|---|
git/update |
Pre Deploy | - | Use this task to update your branch on the Pre Deploy stage, it will git pull the code for you. |
git/change-branch |
Pre Deploy Post Deploy |
branch |
This task is automatically added by Magallanes at the beginning of the Pre Deploy stage if you have the option branch defined.
It will look if the current checked out branch and skip if it's the same as branch or change to it with git checkout branch.
If the switch was made, the task will remember the original branch and reverse it at the Post Deploy stage. This is handled automatically by Magallanes.
|
Composer
Composer has become an integral part of our PHP applications, so is handy to have some built in tasks for interacting with Composer.
By default it is assumed that Composer is installed globally so it will be invoked with composer, but if you have it in an
specific path you can configure it at root level or at environment level under the composer
section with the path
parameter.
magephp:
composer:
path: /alternative/path-to/composer.phar
environments:
production:
composer:
path: /usr/bin/composer
The following tasks are available in Magallanes for using Composer.
Name | Parameters | Description |
---|---|---|
composer/install |
|
Will execute composer install plus the given flags. If your composer install takes too much time, you can increase the task timeout. |
composer/dump-autoload |
|
Will execute composer dump-autoload plus the given flags. |
The parameters can be specified at the task level, for instance if you want to change the default flags for the composer/install
task, you could do the following.
magephp:
environments:
production:
pre-deploy:
- composer/install: { flags: '--no-dev' }
Symfony
Magallaes is built with Symfony4 Components, so I like the framework a lot! It seems only fair to have some built in tasks for common Symfony integration.
By default it is assumed that the Symfony Console is located in bin/console, following the Symfony4 directory structure, but if you have it in an
specific path you can configure it at root level under the symfony
section with the console
parameter.
magephp:
symfony:
console: app/api-console
Name | Parameters | Description |
---|---|---|
symfony/cache-clear |
|
Will clear the appropriate environment's cache by executing bin/console cache:clear --env=<env> plus any given flags. |
symfony/cache-warmup |
|
Will warm up the appropriate environment's cache by executing bin/console cache:warmup --env=<env> plus any given flags. |
symfony/cache-pool-clear |
|
Will clear the given pool or pools of cache by executing bin/console cache:pool:clear <pools> --env=<env> plus any given flags.
The pools parameter is treated like a string so you can pass any number of pools there, like pool1 pool2 pool3.
|
symfony/cache-pool-prune |
|
Will prune all the caches by executing bin/console cache:pool:prune --env=<env> plus any given flags. |
symfony/assets-install |
|
Will install the assets defined by the loaded bundles by executing bin/console assets:install <target> --env=<env> plus the given flags. |
Defining flags or environments at a global level is not useful, so you can define these parameters right along the task, just like the following example.
magephp:
environments:
test:
on-deploy:
- symfony/cache-warmup: { env: 'test' }
On the other hand, Symfony parameters can also exists at the Environment's level, so you could define an environment's env
parameter for all you Symfony tasks and save a bit of configuration, just like this.
magephp:
environments:
production:
symfony: { env: 'prod' }
on-deploy:
- symfony/cache-warmup
File System
Simple file system operations are common in the workflow of a deployment, for example coping a configuration file for a specific environment, or removing a lock file, or moving one file around.
Magallanes provides three simple operations: copy, move, and remove. Besides adding this operations to your deployment process you gain the advantage of defining the file paths with variables dependant of the deployment.
magephp:
environments:
production:
on-deploy:
- fs/copy: { from: 'app/config/envs/%environment%.yml', to: 'app/config/parameters.yml' }
The example above, when ran with bin/mage deploy production the from
path will be converted to app/config/envs/production.yml
The supported variables are: %environment%
, %host%
, %release%
.
Name | Parameters | Description |
---|---|---|
fs/copy |
|
Will copy a file executing cp -p <from> <to>, be careful if changing the flags. |
fs/link |
|
Will symlink a file executing ln -snf <from> <to>, be careful if changing the flags. |
fs/move |
|
Will move a file executing mv <from> <to>, plus the given flags. |
fs/remove |
|
Will delete a file executing rm <file>, plus the given flags. |
fs/chmod |
|
Will change a file's mode executing chmod <mode> <file>, plus the given flags. |
These commands are executed according to the stage they are placed on. If defined on pre-deployment
and post-deployment
the tasks are going to be executed locally,
otherwise they are going to be executed on each host inside the host_path
plus the release directory path if releases are enabled.
Regarding Symlinks, Part II
If you are going to use relative symlinks inside your release directory, remember that the real path is /var/www/app/releases/20170102121530/
and not /var/www/app/current
So if you want to go "one directory down", for example to /var/www/app/shared
, the symlink will be ../../shared
, also this is without taking into account the levels added by
the link you are making, you have to take those into account too.
Suppose you want to link a directory at the host_path
level while using releases, then you should write the task as follows:
magephp:
environments:
production:
host_path: /var/www
releases: 4
on-deploy:
- fs/link: { from: '../../../shared/images', to: 'web/images' }
The path ../../../shared/images
when taking the extra level of web
(the directory where the symlink will be created) and releases are enabled it is treated as /var/www/releases/20170101061530/web/../../../shared/images
which resolves to /var/www/shared/images
,
this is valid even if you are in current
, because it is a symlink inside a symlink, it's like an inception thing. Same logic applies when leveling up directories.
Execute
Sometimes you need to execute a command, a shell script, or perhaps restart a service. You could create a custom task for that, but with this task you can configure Magallanes to do it easily.
magephp:
environments:
production:
post-deploy:
- exec: { cmd: './reload-docker.sh', desc: 'Reload Docker instances' }
The example above, when ran with ./reload-docker.sh locally on the post-deploy
stage.
The command will be executed locally or remotely based on the stage in which the task is defined.
The following are the parameters available for this task.
Parameter | Default | Description |
---|---|---|
cmd |
empty | The command line to execute. This parameter is mandatory. |
desc |
empty | A description to output on the task execution. |
timeout |
120 | Time out wait for the command execution, if the task takes too long you can tweak it here. |
Variable interpolation is supported at the cmd
parameter for the following variables: %environment%
and %release%
.
Sleep
If you need to hold on the deployment for a few seconds, perhaps to allow some syncing or purging, you can use this task to sleep for some time. But don't be greedy!
magephp:
environments:
production:
post-deploy:
- sleep: { seconds: 60 }
The example above will hold execution for 60 seconds.
The following are the parameters available for this task.
Parameter | Default | Description |
---|---|---|
seconds |
1 | Amount of seconds to sleep. |
Cookbook
Custom Tasks
Magallanes is a powerful tool just as it is, but to really unleash it's potential you have to push it a little more. With custom tasks you can do whatever you want whenever you want.
Just like the built in tasks you can create your own, anywhere in your code. These tasks must comply two requirements: extend the class Mage\Task\AbstractTask
and be loaded with Composer's autoload, and just that!
Let's see a very basic example.
<?php
namespace AppBundle\Library\Deployment;
use Symfony\Component\Process\Process;
use Mage\Task\Exception\ErrorException;
use Mage\Task\AbstractTask;
class PurgeMemcachedTask extends AbstractTask {
public function getName()
{
return 'custom/purge-memcached';
}
public function getDescription()
{
return '[Custom] Purging Memcached';
}
public function execute()
{
if (!array_key_exists('server', $this->options) || !array_key_exists('port', $this->options)) {
throw new ErrorException('Parameters "server" and "port" are required.');
}
$cmd = sprintf('echo "flush_all" | netcat %s %d', $this->options['server'], $this->options['port']);
/** @var Process $process */
$process = $this->runtime->runCommand($cmd);
return $process->isSuccessful();
}
}
You will be able to use this task as follows
magephp:
environments:
production:
post-deploy:
- 'AppBundle\Library\Deployment\PurgeMemcachedTask': { server: '10.0.0.50', port: 11211 }
Highlighted in the PHP code above you will notices some interesting things. First of all the Task Class is pretty simple, it extends Mage\Task\AbstractTask
and implements three methods: getName
, getDescription
, and execute
. Then the $this->options
property is an array filled
with the parameters defined on the task declaration, { server: '10.0.0.50', port: 11211 }
in this example.
The server
and port
parameters are needed for the execution of the task, so if these weren't defined an exception is thrown, false
could have been returned at that point but the advantage of throwing ErrorException
is that the message will be displayed.
All tasks have access to the $this->runtime
property, which is an instance of Mage\Runtime\Runtime
, this instance has everything about what's going on
in Magallanes, and also allows you to execute command line sentences. When you invoke the runCommand
method the Runtime instance will lookup in which stage it is,
if it is Pre Deploy or Post Deploy then the command will be execute locally, otherwise it will be executed remotely on each defined host. The process
returned is an instance of the Process Symfony Component.
Finally a boolean status is returned based on the execution of the command, the isSuccessful
will return true
or false
and this will
mark the task as OK
or FAIL
respectively.
Learn more about Tasks
Building tasks is a massive content, the best way to learn how to make your own tasks is by looking at the already built in tasks.
Warning
If you install Magallanes globally, you won't be able to use custom tasks, because your app autoloader will not be used.
Custom Configuration
In the same lines as Custom Tasks, having an elastic configuration is also handy. Suppose you have a Custom Task that needs a bunch of parameters, or that you want to configure it globally and not for each environment. Well that's just plain easy.
Let's go for the first case, and following the Custom Task defined earlier, you want to be able to set the server
and port
on each environment and call the task twice.
magephp:
environments:
production:
memcached: { server: '10.0.0.50', port: 11211 }
pre-deploy:
- 'AppBundle\Library\Deployment\PurgeMemcachedTask'
post-deploy:
- 'AppBundle\Library\Deployment\PurgeMemcachedTask'
In theory this will trigger your custom task at the beginning and at the end of the deployment, and you have added a memcached
section at the environment level.
Now let's tweak the Custom Task to read from that definition.
<?php
namespace AppBundle\Library\Deployment;
use Symfony\Component\Process\Process;
use Mage\Task\Exception\ErrorException;
use Mage\Task\AbstractTask;
class PurgeMemcachedTask extends AbstractTask {
public function getName()
{
return 'custom/purge-memcached';
}
public function getDescription()
{
return '[Custom] Purging Memcached';
}
public function execute()
{
$options = $this->runtime->getEnvOption('memcached', []);
if (!is_array($options) || !array_key_exists('server', $options) || !array_key_exists('port', $options)) {
throw new ErrorException('Parameters "server" and "port" are required.');
}
$cmd = sprintf('echo "flush_all" | netcat %s %d', $options['server'], $options['port']);
/** @var Process $process */
$process = $this->runtime->runCommand($cmd);
return $process->isSuccessful();
}
}
Only three lines of code changed! Amazing! The getEnvOption
method will look for the given key at the current environment, and return the second argument as default.
Given that the value returned can be anything there is the extra check is_array($options)
to make sure we are dealing with an array.
In the folloing case let's move the configuration globally.
magephp:
memcached: { server: '10.0.0.50', port: 11211 }
environments:
production:
post-deploy:
- 'AppBundle\Library\Deployment\PurgeMemcachedTask'
pre-production:
post-deploy:
- 'AppBundle\Library\Deployment\PurgeMemcachedTask'
<?php
namespace AppBundle\Library\Deployment;
use Symfony\Component\Process\Process;
use Mage\Task\Exception\ErrorException;
use Mage\Task\AbstractTask;
class PurgeMemcachedTask extends AbstractTask {
public function getName()
{
return 'custom/purge-memcached';
}
public function getDescription()
{
return '[Custom] Purging Memcached';
}
public function execute()
{
$options = $this->runtime->getConfigOption('memcached', []);
if (!is_array($options) || !array_key_exists('server', $options) || !array_key_exists('port', $options)) {
throw new ErrorException('Parameters "server" and "port" are required.');
}
$cmd = sprintf('echo "flush_all" | netcat %s %d', $options['server'], $options['port']);
/** @var Process $process */
$process = $this->runtime->runCommand($cmd);
return $process->isSuccessful();
}
}
With the getConfigOption
method will look for the given key at the root of the configuration, and return the second argument as default.
Having a configuration in this level can be useful if you need a shared key for all the environments or a common path to a binary, etc.
Pro Tip!
If you want a very extensible configuration, you can combine everything, the method Runtime::getMergedOption
will combine the ConfigOption and the EnvOption (in that order)
so you can overwrite a global config entry at the environment entry, like this:
$options = array_merge(
$this->runtime->getMergedOption('memcached'),
$this->options
);
In this example the $options
variable will have a combination of all three levels of configuration, giving priority to the most granular level.
Runtime::getMergedOption
default value is []
.
Pre Register Custom Tasks
It will be very likely that you will use a Custom Task several times across your configuration, and defining it by it's class can be cumbersome.
Another option is to pre register your tasks, then you will be able to use them by it's name.
In the previous section we defined a custom class which returns the name custom/purge-memcached
, now we are going to pre register it!
magephp:
environments:
production:
pre-deploy:
- custom/purge-memcached: { server: '10.0.0.50', port: 11211 }
post-deploy:
- custom/purge-memcached: { server: '10.0.0.50', port: 11211 }
custom_tasks:
- 'AppBundle\Library\Deployment\PurgeMemcachedTask'
By registering your Custom Tasks in the custom_tasks
section of the configuration you can invoke them by the value you defined in the name section.
Now if you change your class or move it around you just need to change it in one place.
Changelog
Galactica - v5 Series
v5.0.0
- v5 series release.
- Refactored for Symfony 6 and PHP 8.
- Added strong types.
- Removed task
composer/self-update
. - Allow
exec
task to interpolate%environment%
and%release%
variables. - Added new
sleep
task to day execution [PR#414]. - Added new
symlink
option to define the name of symbolic link on the Release [PR#425]. - Improved Windows compatibility [PR#427].
- Added new
log_limit
option to limit how many logs are kept [Issue#403]. - Add new deploy option --tag to specify deploying a specific tag [Issue#192] [Issue#315].
- Added new
scp_flags
option for thescp
command when SSH flags are incompatible with [Issue#439].
What about Discovery One docs?
The documentation of the Discovery One series (v4) of Magallanes is still available in https://v4.magephp.com
Thanks
I want to give thanks to all the PHP community, those unsung heroes who continuously push the boundaries of technology.