<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jose Armesto&#39;s Blog</title>
    <link>https://blog.armesto.net/tags/deployment/index.xml</link>
    <description>Recent content on Jose Armesto&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>es-es</language>
    <copyright>Powered by [Hugo](//gohugo.io). Theme by [PPOffice](https://github.com/ppoffice).</copyright>
    <atom:link href="https://blog.armesto.net/tags/deployment/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Introducing Wimpy</title>
      <link>https://blog.armesto.net/introducing-wimpy/</link>
      <pubDate>Sat, 20 May 2017 21:00:31 +0000</pubDate>
      
      <guid>https://blog.armesto.net/introducing-wimpy/</guid>
      <description>&lt;p&gt;Today I want to share with you &lt;a href=&#34;https://github.com/wimpy&#34;&gt;the project I&amp;rsquo;ve been working on for the last year&lt;/a&gt; in my free time. For me, the project has already been a success: it&amp;rsquo;s a pet project that has allowed me to learn a lot about Amazon Web Services, Docker and Ansible. But letting that aside, I believe is a useful project that can help you deploy your software better!&lt;/p&gt;

&lt;p&gt;
&lt;a href=&#34;https://github.com/wimpy&#34;&gt;Wimpy is an open source Platform as a Service&lt;/a&gt; that you run from your terminal to deploy your applications to AWS, following cloud best practices.&lt;/p&gt;

&lt;p&gt;Heavily inspired on the great &lt;a href=&#34;https://github.com/ansistrano/deploy&#34;&gt;Ansistrano&lt;/a&gt;, it&amp;rsquo;s built as a set of Ansible roles and it&amp;rsquo;s executed using an Ansible playbook in your application&amp;rsquo;s repository.&lt;/p&gt;

&lt;p&gt;Wimpy&amp;rsquo;s goal is to make it easy to follow AWS best practices, embracing &lt;a href=&#34;https://martinfowler.com/bliki/ImmutableServer.html&#34;&gt;immutable infrastructure patterns&lt;/a&gt; where your servers are considered to be immutable. Whenever a new version is released, the servers get never updated but replaced by new servers containing the new released version.&lt;/p&gt;

&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s see an example for a playbook, where you can configure how Wimpy will deploy your application:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- hosts: all
  connection: local
  vars:
    # Name of the application, used to name resources in AWS
    wimpy_application_name: &amp;quot;awesome-application&amp;quot;
    # Where your application is listening for HTTP requests
    wimpy_application_port: &amp;quot;80&amp;quot;
    # It will create a new DNS for awesome-application.armesto.net
    wimpy_aws_hosted_zone_name: &amp;quot;armesto.net&amp;quot;
  roles:
    - role: wimpy.environment
    - role: wimpy.build
    - role: wimpy.deploy

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now you can just run the playbook using Ansible, or, if you don&amp;rsquo;t have Ansible installed, you can just use &lt;a href=&#34;https://hub.docker.com/r/fiunchinho/wimpy/&#34;&gt;our Docker image that contains Ansible and all Wimpy roles&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ docker run -v /var/run/docker.sock:/var/run/docker.sock \
    -v &amp;quot;$PWD:/app&amp;quot; fiunchinho/wimpy /app/deploy.yml \
    --extra-vars &amp;quot;wimpy_release_version=`git rev-parse HEAD` \
                  wimpy_deployment_environment=production&amp;quot;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this case, there are two variables that we want to pass on every deploy we make: the version being deployed and in which environment we want to deploy it. In this case, the version being deployed is the SHA1 commit hash from Git, but you can choose any arbitrary tag for your version, like &amp;ldquo;v1.4.2&amp;rdquo; or whatever.&lt;/p&gt;

&lt;p&gt;Once executed, you can browse to &lt;a href=&#34;http://awesome-application.armesto.net&#34;&gt;http://awesome-application.armesto.net&lt;/a&gt; to see your application, and you will have a bunch of resources in your AWS account.&lt;/p&gt;

&lt;h2 id=&#34;what-happened&#34;&gt;What happened&lt;/h2&gt;

&lt;p&gt;As I said earlier, Wimpy has been build with modularity in mind, so it&amp;rsquo;s not an &lt;em&gt;all-or-nothing&lt;/em&gt; kind of tool. You can choose which roles to execute. Let&amp;rsquo;s see what these roles do.&lt;/p&gt;

&lt;h3 id=&#34;wimpy-environment&#34;&gt;wimpy.environment&lt;/h3&gt;

&lt;p&gt;First of all, this role will enable &lt;a href=&#34;https://aws.amazon.com/cloudtrail/&#34;&gt;CloudTrail for your account&lt;/a&gt;, an audit log so you can track &lt;em&gt;who-did-what-when&lt;/em&gt; in your account.
It also registers &lt;a href=&#34;https://aws.amazon.com/kms/&#34;&gt;a master key in KMS&lt;/a&gt; for applications to encrypt and decrypt secrets.&lt;/p&gt;

&lt;p&gt;Your AWS account must be prepared before you can deploy your applications. By executing this role, your accout gets two different isolated environments called &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt;. Each environment gets its own &lt;a href=&#34;https://aws.amazon.com/vpc/&#34;&gt;Virtual Private Cloud&lt;/a&gt;, meaning that applications in one environment can&amp;rsquo;t connect to applications in a different environment. Total isolation between environments right from the start.&lt;/p&gt;

&lt;p&gt;The same applies for &lt;a href=&#34;https://aws.amazon.com/s3/&#34;&gt;S3&lt;/a&gt;. Wimpy creates a single bucket for all your applications, but each application will only be able to access the application folder in the environment where is running. For example, if your S3 bucket is called &lt;code&gt;storage&lt;/code&gt;, the application called &lt;code&gt;cats-api&lt;/code&gt; will have access to the &lt;code&gt;storage/production/cats-api/&lt;/code&gt; folder when deployed in &lt;code&gt;production&lt;/code&gt;, but it will have access only to &lt;code&gt;storage/staging/cats-api/&lt;/code&gt; when deployed in the &lt;code&gt;staging&lt;/code&gt; environment.&lt;/p&gt;

&lt;p&gt;Last but not least, this role creates the needed security groups to allow traffic to your applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the internet to the Load Balancer specified port.&lt;/li&gt;
&lt;li&gt;From the Load Balancer to your application exposed port.&lt;/li&gt;
&lt;li&gt;From the application to the databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, any other access it not allowed, so for example, databases can&amp;rsquo;t be accesed from the internet.&lt;/p&gt;

&lt;h3 id=&#34;wimpy-build&#34;&gt;wimpy.build&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://www.docker.com/&#34;&gt;Docker&lt;/a&gt; is not only great for running applications but for packaging as well. By using Docker for packaging, Wimpy is language agnostic and can deploy any application written in any language.&lt;/p&gt;

&lt;p&gt;By default, this role will use an &lt;a href=&#34;https://aws.amazon.com/ecr/&#34;&gt;Elastic Container Registry&lt;/a&gt; on AWS to store your applications images, but you can choose any Docker Registry that you like.&lt;/p&gt;

&lt;p&gt;On every deployment, it will package your application as a Docker image that can be run anywhere. Not only is available for the deployments in production, but different teams within your organization can start sharing their applications to make development easier.&lt;/p&gt;

&lt;h3 id=&#34;wimpy-deploy&#34;&gt;wimpy.deploy&lt;/h3&gt;

&lt;p&gt;This is probably the most interesting part!
This role will deploy your application as an &lt;a href=&#34;https://docs.aws.amazon.com/autoscaling/latest/userguide/AutoScalingGroup.html&#34;&gt;Auto Scaling Group&lt;/a&gt; with &lt;a href=&#34;https://docs.aws.amazon.com/autoscaling/latest/userguide/policy_creating.html&#34;&gt;Scaling Policies&lt;/a&gt; that will scale up and down the number of instances. Each instance will run the application&amp;rsquo;s Docker container, supervised by systemd.&lt;/p&gt;

&lt;p&gt;If you want, it will create a new &lt;a href=&#34;https://aws.amazon.com/route53/&#34;&gt;Route53 DNS&lt;/a&gt; register pointing to your &lt;a href=&#34;https://aws.amazon.com/elasticloadbalancing/&#34;&gt;Load Balancer&lt;/a&gt;, which will balance the traffic between all the instances in your Auto Scaling Group.&lt;/p&gt;

&lt;p&gt;The end result would be something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.armesto.net/images/wimpy_deploy.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The role offers two different deployment strategies.&lt;/p&gt;

&lt;h4 id=&#34;rolling-update&#34;&gt;Rolling Update&lt;/h4&gt;

&lt;p&gt;Using this deployment strategy, we rely &lt;a href=&#34;https://cloudonaut.io/rolling-update-with-aws-cloudformation/&#34;&gt;on the built-in Rolling Update mechanism for Auto Scaling Groups&lt;/a&gt;, where each instance of the Auto Scaling Group is replaced by a new instance that contains the version being deployed.&lt;/p&gt;

&lt;p&gt;If something fails while replacing old instances with new ones, AWS will handle the rollback for us.&lt;/p&gt;

&lt;h4 id=&#34;blue-green-red-black-deployment&#34;&gt;Blue / Green (Red / Black) deployment&lt;/h4&gt;

&lt;p&gt;In this strategy, we create a new CloudFormation for every deploy. &lt;a href=&#34;https://martinfowler.com/bliki/BlueGreenDeployment.html&#34;&gt;This means that every deploy will generate a new Auto Scaling Group&lt;/a&gt; (which instances contain the version being deployed), a new Load Balancer and a new DNS register. Since now we have two different registers for the same domain name (one for each version deployed), Wimpy uses Route53 weighted registers to control how much traffic goes to every version.&lt;/p&gt;

&lt;p&gt;You can tune how much traffic goes to new versions, so you can use this feature for &lt;a href=&#34;https://martinfowler.com/bliki/CanaryRelease.html&#34;&gt;canary releases&lt;/a&gt;. This is great for testing in production with real traffic.&lt;/p&gt;

&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve two examples that show Wimpy in action&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/wimpy/symfony-demo&#34;&gt;Fork of the Symfony demo project&lt;/a&gt;, but adding Wimpy to deploy the application from Travis.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/wimpy/spring-petclinic&#34;&gt;Fork of the Spring pet-clinic demo project&lt;/a&gt;, also just adding Wimpy to be executed on every merge to master.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Wimpy tries to help you automate your deployments and infrastructure best practices in the AWS, making sure that different teams within your organization all deploy applications the same way.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s composed by different roles that you can combine, or even extend, building your own roles/tasks.&lt;/p&gt;

&lt;p&gt;Everything is created on your own AWS account. That means that you are in full control of your resources, and if you don&amp;rsquo;t want to use Wimpy anymore, you won&amp;rsquo;t lose anything.&lt;/p&gt;

&lt;p&gt;You can learn more about the project &lt;a href=&#34;https://wimpy.github.io/docs/&#34;&gt;in the documentation page&lt;/a&gt;.
Feel free to read through &lt;a href=&#34;https://github.com/wimpy&#34;&gt;the code in the Github organization&lt;/a&gt;. Contributions are really welcomed!&lt;/p&gt;

&lt;iframe src=&#34;https://docs.google.com/presentation/d/1vywHZrOgDfkpKeE_AaUQ5M9ZiJ1uspaDYwKGjxq99ZE/embed?start=false&amp;loop=false&amp;delayms=3000&#34; frameborder=&#34;0&#34; width=&#34;480&#34; height=&#34;299&#34; allowfullscreen=&#34;true&#34; mozallowfullscreen=&#34;true&#34; webkitallowfullscreen=&#34;true&#34;&gt;&lt;/iframe&gt;

&lt;h2 id=&#34;acknowledgements&#34;&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;Finally, I&amp;rsquo;d like to thank all the people that have helped me during the development of this project. This would&amp;rsquo;ve never happened without them, specially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ismFerDev&#34;&gt;Ismael Fernández&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/aramirez-es&#34;&gt;Alberto Ramírez&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/victuxbb&#34;&gt;Víctor Caldentey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Hyunk3l&#34;&gt;Fabrizio Di Napoli&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Problemas desplegando código si usas Apache, symlinks y opcache</title>
      <link>https://blog.armesto.net/problemas-desplegando-codigo-si-usas-apache-symlinks-y-opcache/</link>
      <pubDate>Fri, 01 May 2015 12:14:32 +0000</pubDate>
      
      <guid>https://blog.armesto.net/problemas-desplegando-codigo-si-usas-apache-symlinks-y-opcache/</guid>
      <description>&lt;p&gt;Muchas de las soluciones disponibles en el mercado para desplegar aplicaciones se basan en el uso de enlaces simbólicos (o symlinks) para activar la última versión de código en el servidor.&lt;/p&gt;

&lt;p&gt;Simplificando mucho, podríamos decir que un flujo habitual a la hora de desplegar sería el siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ejecutamos comando para iniciar el proceso de despliegue de código nuevo.&lt;/li&gt;
&lt;li&gt;Se descarga el código del repositorio y se construye la aplicación. Esto suele significar instalar dependencias, generar ficheros, etc.&lt;/li&gt;
&lt;li&gt;Se mueve el resultado del paso anterior al servidor y se pone en una carpeta nueva.&lt;/li&gt;
&lt;li&gt;La carpeta a la que apunta el &lt;em&gt;document root&lt;/em&gt; de nuestro servidor web es en realidad un enlace simbólico a otra carpeta que contiene código en la versión anterior. Por tanto solo nos queda cambiar ese enlace simbólico para que apunte a la nueva que acabamos de crear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como el cambio de enlace simbólico es practicamente instantáneo, conseguimos reducir la ventana de tiempo en la que el servidor está en un estado inconsistente, por ejemplo, porque todavía no se hayan terminado de copiar ficheros. Mientras se están subiendo la versión nueva, seguimos sirviendo la versión vieja, sin dejar de dar servicio. Y solo cuando la nueva está lista, hacemos el cambio de forma casi instantánea.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&#34;problemas-con-este-enfoque&#34;&gt;Problemas con este enfoque&lt;/h2&gt;

&lt;p&gt;Esta manera de desplegar, que parece sencilla y perfecta, tiene algunas complicaciones. Con la que la gente más suele pelearse es con el hecho de que a pesar de haber desplegado una versión nueva en el servidor, a veces siguen viendo la versión vieja, debido a la extensión &lt;a href=&#34;https://www.google.es/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=0CCUQFjAA&amp;url=http%3A%2F%2Fphp.net%2Fmanual%2Fes%2Fbook.opcache.php&amp;ei=HlFDVZfPI8T2Us6sgLAI&amp;usg=AFQjCNF9sKlRWdBbTEBKa1M2w25s5TBQGw&amp;sig2=6xMwOb3cZagbFnheUWkDTQ&amp;bvm=bv.92291466,d.d24&#34; target=&#34;_blank&#34;&gt;Opcache&lt;/a&gt; (antiguo APC) que guarda la compilación del código PHP interpretado en memoria. Por tanto, aunque la versión nueva ya está activa, PHP sigue tirando de esta caché para no tener que leer del disco y volver a compilar código PHP, así que se sirve el código de la versión vieja hasta que caduque esta caché (si es que lo tenemos configurado para que caduque), o hasta que reiniciemos el servidor dejando de dar servicio mientras dure el reinicio del servidor.&lt;/p&gt;

&lt;p&gt;Antes de ver cómo solventarlo, vamos a ver un par de detalles interesantes.&lt;/p&gt;

&lt;h2 id=&#34;te-presento-a-tu-nueva-amiga-realpath-cache&#34;&gt;Te presento a tu nueva amiga realpath_cache&lt;/h2&gt;

&lt;p&gt;Cada vez que utilizas una ruta del sistema de archivos, por ejemplo porque vas a hacer un require/include de ese archivo, o porque vas lees/escribir en esa ruta, &lt;strong&gt;el sistema tiene que resolver esa ruta&lt;/strong&gt;: saber donde es exactamente, si es un directorio o un archivo, etc.&lt;/p&gt;

&lt;p&gt;Para mejorar su rendimiento y minimizar lecturas de disco, PHP utiliza una caché interna donde guarda información sobre el sistema de archivos. No estoy hablando de Opcache, sino de otra caché llamada &lt;a href=&#34;https://php.net/manual/es/ini.core.php#ini.realpath-cache-size&#34; target=&#34;_blank&#34;&gt;realpath_cache&lt;/a&gt;. Si intentas resolver la misma ruta dos veces seguidas, solo en la primera PHP le pedirá información al lentísimo sistema de archivos: la segunda se leerá directamente de la caché, mejorando mucho el rendimiento.&lt;/p&gt;

&lt;p&gt;Esto es bueno, ¿no?&lt;/p&gt;

&lt;p&gt;Sí, claro. El tema es que, como con todas las cachés del mundo, el problema viene a la hora de invalidar la caché y decirle que queremos utilizar contenido nuevo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cuando desplegamos código nuevo, el contenido de la ruta de nuestro &lt;em&gt;Document Root&lt;/em&gt; cambia. Aunque en nuestro código siempre usemos la misma ruta para hacer algo, piensa por ejemplo la ruta relativa que usas para incluir el autoload, despues de cada deploy, &lt;strong&gt;esa ruta se resuelve a un lugar distinto en el disco&lt;/strong&gt;, porque el enlace simbólico apunta a otro sitio. Esto evitará que veamos la versión nueva del código desplegado, hasta que esta caché no caduque o hagamos algo al respecto.&lt;/p&gt;

&lt;h2 id=&#34;cómo-funciona-apache&#34;&gt;Cómo funciona Apache&lt;/h2&gt;

&lt;p&gt;A diferencia de Opcache, que se guarda en memoria compartida por todos los procesos, la realpath_cache es local para cada proceso del sistema. Este detalle es importante porque si utilizas Apache &lt;em&gt;prefork&lt;/em&gt; para servir tu aplicación, cuando inicias Apache, este crea varios procesos hijos, tantos como le hayas configurado. Cada proceso hijo creado servirá X número de peticiones en su vida (esto también es configurable), y una vez que ha cumplido su deber, Apache lo matará y lo reemplazará con otro proceso hijo, poco a poco renovando todos los procesos que sirven páginas.&lt;/p&gt;

&lt;p&gt;Es decir, &lt;strong&gt;no podemos preveer exactamente cuando los procesos dejarán de existir&lt;/strong&gt;. Sumado a que la realpath_cache es local a cada proceso,&lt;strong&gt; la nueva versión que acabamos de desplegar se irá sirviendo aleatoriamente&lt;/strong&gt;, dependiendo de qué proceso de Apache te haya asignado el servidor.&lt;/p&gt;

&lt;p&gt;Como dijimos antes, podríamos solventarlo haciendo un reinicio de Apache despues de cada despliegue, pero dejaríamos de servir páginas el tiempo que tardase en reiniciar.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mal, mal, mal, verdadera mal, por no deci borchenoso&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;reiniciando-elegantemente&#34;&gt;Reiniciando elegantemente&lt;/h2&gt;

&lt;p&gt;Pero tranquilo, no sufras, hay solución. Apache nos ofrece una variante al reinicio, llamada &lt;em&gt;graceful restart&lt;/em&gt;. Esta variante, en vez de matar al proceso de Apache y todos sus hijos para reiniciarlo, lo que hace es que el proceso padre revisa a los procesos hijos de forma que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si no están haciendo nada, los sustituye por un proceso nuevo.&lt;/li&gt;
&lt;li&gt;Si está sirviendo una petición en este momento, cuando termine lo sustituye por un proceso nuevo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como dijimos que realpath_cache era local a cada proceso, cuando Apache levanta un nuevo proceso hijo &lt;strong&gt;la realpath_cache está vacía para ese proceso y las rutas se resolverán al código nuevo que acabamos de desplegar&lt;/strong&gt;. Todo esto sin dejar de dar servicio, porque siempre hay procesos sirviendo páginas.&lt;/p&gt;

&lt;h2 id=&#34;pesao-que-yo-venía-aquí-a-solventar-el-problema-de-opcache&#34;&gt;&lt;em&gt;Pesao&lt;/em&gt;. Que yo venía aquí a solventar el problema de Opcache&lt;/h2&gt;

&lt;p&gt;Cierto. Opcache no es más que un diccionario (piensa en un array PHP), en el que cada &lt;em&gt;key&lt;/em&gt; es la ruta del fichero compilado, y el &lt;em&gt;value&lt;/em&gt; es el resultado de esa compilación. Cuando se va a ejecutar un fichero PHP, se ve si la ruta de ese archivo ya es una de las _keys_ en el diccionario, si ya lo está significa que ya lo hemos compilado antes, y se utiliza directamente el &lt;em&gt;value&lt;/em&gt;. Si no, se compila y se guarda en el diccionario.&lt;/p&gt;

&lt;p&gt;El &amp;#8216;&lt;em&gt;final plot twist&amp;#8217;&lt;/em&gt; de todo esto es que &lt;strong&gt;Opcache utiliza realpath_cache internamente para resolver la ruta de los ficheros&lt;/strong&gt;. Por tanto, si hacemos un &lt;em&gt;graceful restart&lt;/em&gt; después de cada despliegue, la ruta del archivo habrá cambiado, resuelve a una carpeta distinta, así que &lt;strong&gt;será como un fichero totalmente nuevo para Opcache y volverá a compilarlo, haciendo que sirvamos la versión nueva&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img class=&#34;alignnone&#34; src=&#34;https://s-media-cache-ak0.pinimg.com/originals/ce/9c/94/ce9c949d6c73dbfb889f6036bac022dd.jpg&#34; alt=&#34;Mind Blown&#34; width=&#34;480&#34; height=&#34;360&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;conclusión&#34;&gt;Conclusión&lt;/h2&gt;

&lt;p&gt;Lo que hemos visto hoy es tan solo uno de los posibles problemas a la hora de desplegar código. Otro problema, por ejemplo, sería el que se produce cuando iniciamos un despliegue, un visitante entra en la web, justo después se cambia el enlace simbólico y estamos sirviendo archivos estáticos como javascript o css. Es posible que algunos archivos hayan sido de la versión vieja, y otros de la versión nueva, llevando a posibles inconsistencias. &lt;a href=&#34;https://codeascraft.com/2013/07/01/atomic-deploys-at-etsy/&#34; target=&#34;_blank&#34;&gt;Hay módulos de apache que intentan solventar este tipo de problemas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El despliegue de código es un tema complicado y muy interesante. Últimamente está avanzando mucho con conceptos como servidores inmutables y los contenedores, pero eso ya es tema de otro post.&lt;/p&gt;</description>
    </item>
    
  </channel>
</rss>