Desplegando aplicaciones Symfony en Heroku

4 Nov 2015

Alfonso Fernández

Gracias ;)

@alfonsofega

About

Alfonso Fernández

Responsable de I+D+i & Desarrollador & cofundador en Cloudman Labs

alfonso.fernandez@cloudmanlabs.com

Desarrollo de software en nube

Parte 2

Desplegando una aplicación Symfony en Heroku

$ git push heroku master

Un poco de teoría...

¿Qué es una aplicacion para Heroku?

Código fuente

Dependencias

Procfile

Variables de entorno

Add-ons

Gestores de dependencias...

pom.xml

Gemfile

package.json

composer.json

requirements.txt

Procfile

Declara los procesos de nuestra aplicación

Fichero que se crea en la raíz de nuestro proyecto

Tipos de procesos

web

Es un tipo especial

<process type>: <command>

otros tipos

Podemos llamarlos como queramos, pero es común usar worker (para realizar tareas) y clock (para scheduled task) como nombre.

 

Lo mejor de todo es que los procesos se escalan independientemente

Escalabilidad de procesos

$ heroku ps:scale worker=1
$ heroku ps:resize worker=standard-2x

Escalar dyno del proceso

Escalar proceso

Variables de entorno

Heroku provee un mecanismo de configuración de variables de entorno.

Principal diferencia entre entornos

(dev, staging, prod)

$ heroku config:set NAME=VALUE

Add-ons

Son los servicios que usa la aplicación

Base de datos (MySQL)

Cola de mensajes (RabbitMQ)

Cache (Redis)

...

No estamos limitados a los add-ons

Podemos usar cualquier servicio de terceros como Amazon S3 o Amazon Cloudfront

¡Ya sabemos que es una aplicación para Heroku!

Desplegando en Heroku

$ git push heroku master

pero hay mas...

pero...

¿qué hace Heroku para que sea tan fácil desplegar?

¿Es magia?

Cuando sube el código fuente, heroku detecta el "package manager", lanza un build pack especifico para el lenguaje, obtiene las dependencias, crea los archivos necesarios y ejecuta los procesos definidos en el archivo Procfile

es prestidigitación

¡No!

Mucha teoría pero todavía no hemos visto ninguna aplicación...

¡Vamos a desplegar una aplicación Symfony en Heroku!

Aplicación de ejemplo

Fork de "Cupon"

Es la aplicación que se desarrolla en el libro

¿Que necesitamos?

Una cuenta en Heroku: https://signup.heroku.com/

Heroku toolbet: https://toolbelt.heroku.com/

$ heroku login
Enter your Heroku credentials.
Email: example@example.com
Password: *******
...

Vamos a desplegar la aplicación de ejemplo

$ git clone https://github.com/afgar/Cupon.git
$ cd Cupon
$ heroku apps:create
$ git push heroku master
$ heroku open
$ heroku apps:create

¿Que ha ocurrido?

Crea una aplicación Heroku en la region de USA, le establece un nombre aleatorio y añade el git remote heroku

$ heroku apps:create <nombre app> --remote <nombre git remote> --region <region eu|us>
# Ejemplo para crear una app en produccion en Europa
$ heroku apps:create myapp --remote prod --region eu

# Ejemplo para crear una app staging en Europa
$ heroku apps:create myapp-staging --remote staging --region eu

Tip

# Si quieremos hacer deploy de otra rama
$ git push heroku <branch>:master

Tip

¿Qué le has hecho a la aplicación?

Crear el archivo Procfile

Realmente no es necesario, symfony 2.7 tiene un comando que detecta heroku y autogenera el Profile cuando se esta desplegando la aplicación

# Con apache
web: bin/heroku-php-apache2 web/

# Con nginx
web: bin/heroku-php-nginx -C nginx_app.conf web/
{
  # ...
  "scripts": {
    "post-install-cmd": [
      # ...
      "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget",
      # ...
    ],
    "post-update-cmd": [
      # ...
      "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget",
      # ...
    ]
  },
  # ...
}

Archivo composer.json

/**
 * Sets up deployment target specific features.
 * Could be custom web server configs, boot command files etc.
 *
 * @param $event CommandEvent An instance
 */
public static function prepareDeploymentTarget(CommandEvent $event)
{
    static::prepareDeploymentTargetHeroku($event);
}

protected static function prepareDeploymentTargetHeroku(CommandEvent $event)
{
    $options = static::getOptions($event);
    if (($stack = getenv('STACK')) && ($stack == 'cedar' || $stack == 'cedar-14')) {
        $fs = new Filesystem();
        if (!$fs->exists('Procfile')) {
            $event->getIO()->write('Heroku deploy detected; creating default Procfile for "web" dyno');
            $fs->dumpFile(
                'Procfile', 
                sprintf('web: $(composer config bin-dir)/heroku-php-apache2 %s/', 
                    $options['symfony-web-dir'])
            );
        }
    }
}

Sensio\Bundle\DistributionBundle\Composer\ScriptHandler

Cambiar el destino de los log a stderr en producción

# app/config/config_prod.yml
monolog:
    # ...
    handlers:
        # ...
        nested:
            # ...
            path: "php://stderr" # antes "%kernel.logs_dir%/%kernel.environment%.log"

No queremos que nuestros log vayan a un fichero ya que el almacenamiento de las dynos es efímero y no se comparte. 

Establecer como dependencia las extensiones PHP necesarias

"require": {
    # ...
    "ext-intl"     : "*",
    "ext-mbstring" : "*",
    "ext-apcu"     : "*", # Para cache de doctrine
    # ...
},

Lista completa de extensiones que soporta Heroku

https://devcenter.heroku.com/articles/php-support#extensions

composer.json

$ heroku config:set SYMFONY_ENV=prod

Establecer la variable de entorno SYMFONY_ENV

Si no declaramos explicitamente en entorno en Symfony se ejecuta dev, lo que puede causar problemas. Para ello definimos la variable de entorno SYMFONY_ENV

¡No olvidemos el parámetro secret!

$ heroku config:set SECRET=c3fe8824310c1467432e0636c33b94354c1c91ac

Pasos built adiccionales

# composer.json
{
    "scripts": {
        "compile": [
            "rm web/app_dev.php",          # Elimina app_dev.php
            "php app/console assetic:dump" # Ejecuta assetic:dump
        ]
    }
}

Si queremos ejecutar pasos de compilaccion adiccionales durante la contruccion del programa no debemos utilizar post-install-cmd para ello tenemos el comando compile personalizado que ejecutará heroku

Configuraciones de la aplicación

{
    "extra": {
        "incenteev-parameters": {
            "file": "app/config/parameters.yml",
            "env-map": {
                "database_url": "CLEARDB_DATABASE_URL",
                "secret": "SECRET"
            }
        }
    }
}

Deberemos mapear las variables de entorno a nuestras variables que necesitemos del archivo parameters.yml

Addons utilizados

Papertrail

$ heroku addons:create papertrail:choklad

Gestiona logs del sistema, dado que logplex solo emite un stream de logs.

Para mi es la mas simple

Nos permite:

  • Ver los últimos mensajes
  • Buscar en el log y guardar búsquedas
  • Enviar alertas
  • Automáticamente crea archivos de log comprimidos que son descargables o los envia a amazon S3.

ClearDB MySQL

$ heroku addons:create cleardb:ignite
  • El servicio de MySQL más económico
  • Es gratis hasta 5MB
  • Backup diario automatico

Heroku Scheduler

Sustituye al cron

Es escalable

"best effort"

$ heroku addons:create scheduler:standard

Mantenimiento y gestión de la aplicación

Logs del sistema

$ heroku logs --tail

¡Ya esta asi de simple! En nuestra console empezamos a ver los logs en streaming

Quiero ejecutar comandos de Symfony

¿Cómo lo hago?

Para eso tenemos las one-off dynos!!

$ heroku run "php app/console doctrine:schema:create"

$ heroku run "php app/console doctrine:fixtures:load"

$ heroku run "php app/check.php"

$ heroku run bash

Rollback!

$ heroku releases
$ heroku rollback vXX

pero...

...queda trabajo pendiente

  • Utilizar un servicio para enviar emails: mandrill, sendgrid, etc...
  • Utilizar Amazon S3 como sistema de ficheros

TODO LIST

Conclusiones

¿Preguntas?

Desplegando aplicaciones Symfony en Heroku

By Alfonso Fernández

Desplegando aplicaciones Symfony en Heroku

Parte 2. ¿Cómo desplegar una aplicación Symfony en Heroku?

  • 5,342