Deployment: Write a deployment recipe for TYPO3.Surf

In the last article we learned how to setup a basic FLOW3 installation and install the TYPO3.Surf package.

This time, we will see how a very basic deployment recipe for TYPO3.Surf looks like.

Deployment recipes

The deployment recipes are basically PHP files which are stored in „Build/Surf/“.

# setup FLOW3/Surf like shown in Part 1: http://etobi.de/blog/2012/05/deployment-setup-typo3-surf/
cd SurfNTurf
ls -l Build/Surf/

The TYPO3.Surf package ships with two preinstalled recipes: „flow3base-distribution.php“ and „phoenix-distribution.php“. These are not very „simple“, so we just ignore them for now.

Create your first deployment recipe

Start by creating a new file „foobar.php“ in „Build/Surf/“ and open it in your favorite editor.

When Surf executes our „foobar“ deployment, it will provide an instance of \TYPO3\Surf\Domain\Model\Deployment called $deployment within our recipe file. To get proper code completion for it (e.g. if you use PHPStorm), we start by adding a @var annotation for $deployment.

  1. <?php
  2. /**
  3.  * Deployment configuration for "foobar"
  4.  */
  5.  
  6. /** @var $deployment \TYPO3\Surf\Domain\Model\Deployment */

Surf need to know how to do the deployment. So we’re setting up a „workflow„. A workflow defines the „stages“ which happen during the deployment. These stages might be e.g. „initialize“, „update“, „test“, „switch“, „cleanup“. Surf will execute each stage one after the other and can decide after each stage to abort and rollback the deployment, or to continue with the next stage.

In our case we’re using a „SimpleWorkflow“, which is provided by TYPO3.Surf. It’s instanciated and assigned to the $deployment. Simple as this:

  1. // setup the workflow
  2. $workflow = new \TYPO3\Surf\Domain\Model\SimpleWorkflow();
  3. $deployment->setWorkflow($workflow)

Next the deployment needs to know, what to deploy. For that, we create an „application“ instance and add it to the deployment.

The application defines, which actual tasks need to be executed in each stage of the workflow. The single tasks defined in this application might be for example „checkout the code from a git repository“.

In our example we’ll create a „BasicApplication“ and add it to the $deployment. The application gets an title in the constructor, so we can identify it easily in the logs later. Some tasks will need configuration, like we configure the path to the git repository and the base deployment path (where we want to deploy to).

  1. // setup the application
  2. $application = new \TYPO3\Surf\Application\BaseApplication('foobarApp');
  3. $application
  4.           ->setOption('repositoryUrl', 'ssh://git.example.com/foobar.git')
  5.           ->setDeploymentPath('/var/www/foobar/');
  6. $deployment->addApplication($application);

Surf supports to deploy the same application with the same workflow to multiple servers with just one deployment run. So we need to tell TYPO3.Surf to which server/node we like to deploy our application to.

We create a „\TYPO3\Surf\Domain\Model\Node“ and give it a name („integration“) for the logging. The configuration of the node basically contains the hostname („int.example.com“). This will used to connect via ssh and execute the remote commands for the single tasks.

  1. // setup the target host
  2. $node = new \TYPO3\Surf\Domain\Model\Node('integration');
  3. $node->setHostname('int.example.com');
  4. $application->addNode($node);

If your ssh connection needs a special username or an unusual port, you might want to add the following lines to set those.

  1. $node->setOptions(array(
  2.      'username' => 'johndoe',
  3. //   'port' => '22',
  4. //   'password' => '', # avoid using password authentication, better use auth using a private/public key
  5. ));

Run the deployment

Now we have a basic reciped which we can use do run Surf. Remember to adjust the configuration for your needs (like the hostname, path and repository url).

# show some informations about the deployment
./flow3 surf:describe foobar
 
# 'dry-run' the deployment, to see what will be done.
./flow3 surf:simulate foobar
 
# actually run the deployment
./flow3 surf:deploy foobar

If everything works out, you will find the deployed application in „/var/www/foobar/“ on the host „int.example.com“.

See what’s happened

Lets have a look into the target directory:

ssh int.example.com
cd /var/www/foobar/
tree -L 2

.
├── cache
│   └── localgitclone
├── releases
│   ├── 20120925171518
│   ├── 20120925171518REVISION
│   └── current -> ./20120925171518
└── shared

The folder „cache“ holds a local clone of your git repository.

In „releases“ you will find one subfolder for each deployment (named by the time the deployment happened). Further there is a symlink called „current“ which points to the latest successful release. When configuring your virtual host in the webserver, „current“ is the path your document root should point to.

If you run another deployment later, you will notice another symlink called „previous“. It points to the.. well.. previous release. You might want to setup an additional virtual host, which shows the previous version of the application.

Also, during the actual deployment, while TYPO3.Surf is running, there is third symlink called „next“. This will point the the release TYPO3.Surf is currently working on. This can be very helpful fo testing and several automated checks.

Last but not least you have and (currently) empty folder called „shared“. This is the place for everything, which is not specific for a single release, but should be the same for all releases. Think of assets/uploaded files or specific configuration, which is not versioned in your git repository. These can be stored once in „shared“ and e.g. symlinked into the release folders.

That’s it. Have fun exprimenting with TYPO3.Surf and setup your first own deployment.

8 Gedanken zu „Deployment: Write a deployment recipe for TYPO3.Surf

  1. LittleHoopoe

    first thanks for your work here! I don’t get this line $node = new \TYPO3\Surf\Domain\Model\Node(‚integration‘); when I try to deploy or simulate, it’s always saying there is no ‚deploymentPath‘ at node integration, what did I wrong or didn’t understand?

    If you need the exact exception, i can post it tomorrow when I’m back at work.

    I hope you can help me! Thanks a lot in forward.

    Antworten
    1. etobi Artikelautor

      Did you set the deploymentPath (which is like the target directory). Also check if this directory already exists on your configured node.

      regards tobias

      Antworten
      1. LittleHoopoe

        thanks for your fast answer! I get it now but now I see this:

        Simulating myApplication (20140522080527) Stage initialize myNode (myApplication) typo3.surf:createdirectories myNode (myApplication) typo3.surf:generic:createDirectories Stage package Stage transfer myNode (myApplication) typo3.surf:gitCheckout

        Is there something I have to set for gitCheckout? Same SSH-Key? Sorry for my silly questions!

        Antworten
        1. LittleHoopoe

          After a while i got this => Got exception „Could not retrieve sha1 of git branch „master““ rolling back.

          Antworten
          1. etobi Artikelautor

            Is your git repository (URL) available from the destination node? When you try running surf with –verbose: „./flow3 surf:simulate –verbose foobar“ it prints out every single command it executes. Try to execute these one-by-one from your console.

            Hope this helps. regards tobias

  2. LittleHoopoe

    Hi Tobias,

    thanks for you help now I see the problem:

    > ssh: Could not resolve hostname bitbucket.org:LittleHoopoe: Name or service not known
    > fatal: The remote end hung up unexpectedly
    

    thanks for your help!

    Antworten

Schreib einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *