<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Juan Carlos Mejías Rodríguez</title>
    <description>The latest articles on DEV Community by Juan Carlos Mejías Rodríguez (@greenled).</description>
    <link>https://dev.to/greenled</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F71018%2F8553e120-6663-491d-8e9c-90160be3d3f4.jpeg</url>
      <title>DEV Community: Juan Carlos Mejías Rodríguez</title>
      <link>https://dev.to/greenled</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/greenled"/>
    <language>en</language>
    <item>
      <title>Gradual Migration from Traefik 1.x to 2.x</title>
      <dc:creator>Juan Carlos Mejías Rodríguez</dc:creator>
      <pubDate>Sun, 19 Jul 2020 02:48:33 +0000</pubDate>
      <link>https://dev.to/greenled/gradual-migration-from-traefik-1-x-to-2-x-21ik</link>
      <guid>https://dev.to/greenled/gradual-migration-from-traefik-1-x-to-2-x-21ik</guid>
      <description>&lt;p&gt;&lt;em&gt;This post first appeared at Countainous' blog at &lt;a href="https://containo.us/blog/gradual-migration-from-traefik-1-to-2/"&gt;https://containo.us/blog/gradual-migration-from-traefik-1-to-2/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Are you a happy Traefik user? Join the club! I use Traefik as a reverse proxy to manage the ingress of several dozen services in a Docker Swarm cluster, and couldn't be happier with it. Since its introduction in early 2015, Traefik has grown in maturity and popularity (don't take my word, look at &lt;a href="https://star-history.t9t.io/#containous/traefik"&gt;the project's stargazers over time&lt;/a&gt;. When Traefik v2 was released I couldn't help but think about migrating, but I had one major concern: downtime.&lt;/p&gt;

&lt;p&gt;Traefik's documentation explains how to migrate configurations from 1.x format to 2.x format however, as in any system with some degree of complexity, migrating is not just about changing configurations but managing them. You have to make sure everything keeps running smoothly and be prepared to rollback in case something goes wrong -have you heard of Murphy's Law? Also, you probably don't want to migrate the whole system at a time, or you could quickly find yourself trying to put out more fires than you can handle.&lt;/p&gt;

&lt;p&gt;In this post, I will share a migration strategy that helped me move to Traefik 2 with very little downtime, one service at a time, with an easy way to rollback. For the sake of clarity and brevity, I will start from a single Traefik instance with two backend services and will keep everything in a single Docker Swarm stack. The same strategy could be used in a clustered Traefik deployment with many more backend services as well. In fact, this scenario is where Traefik shines the brightest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial setup
&lt;/h2&gt;

&lt;p&gt;Let's start from the following setup, with a Traefik 1 instance as a reverse proxy and two Nginx services, all running on Docker Swarm:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2hb8VbIW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/194s0f4mgvcqenai6dro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2hb8VbIW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/194s0f4mgvcqenai6dro.png" alt="Initial setup. Traefik 1 handling all routing"&gt;&lt;/a&gt;&lt;/p&gt;
Initial setup. Traefik 1 handling all routing



&lt;p&gt;This configuration can be deployed to the swarm with the following stack definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yaml&lt;/span&gt;

&lt;span class="c1"&gt;# Version &amp;gt;= 3.3 so configs are available&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.4"&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik-public&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;index1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Contains string "1"&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./index1.html&lt;/span&gt;
  &lt;span class="na"&gt;index2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Contains string "2"&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./index2.html&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik:v1.7&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# So that Traefik can listen to the Docker events&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;--docker&lt;/span&gt;
      &lt;span class="s"&gt;--docker.swarmmode&lt;/span&gt;
      &lt;span class="s"&gt;--entrypoints='Name:http Address::80'&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik-public&lt;/span&gt;

  &lt;span class="na"&gt;web1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1-alpine&lt;/span&gt;
    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.frontend.rule=Host:web1.docker.local&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.port=80&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.webservice.frontend.entryPoints=http&lt;/span&gt;
    &lt;span class="na"&gt;configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index1&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/share/nginx/html/index.html&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik-public&lt;/span&gt;

  &lt;span class="na"&gt;web2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1-alpine&lt;/span&gt;
    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.frontend.rule=Host:web2.docker.local&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.port=80&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.webservice.frontend.entryPoints=http&lt;/span&gt;
    &lt;span class="na"&gt;configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index2&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/share/nginx/html/index.html&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik-public&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Files &lt;code&gt;index1.html&lt;/code&gt; and &lt;code&gt;index1.html&lt;/code&gt; contain strings &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt; respectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;1 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index1.html
&lt;span class="nb"&gt;echo &lt;/span&gt;2 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index2.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the above configuration, you can now create a Docker Swarm (if you don't already have one), an overlay network for Traefik and deploy the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker swarm init
docker network create &lt;span class="nt"&gt;--driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;overlay traefik-public
docker stack deploy &lt;span class="nt"&gt;-c&lt;/span&gt; docker-compose.yaml traefik
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When the stack deployment finishes you will be able to query the defined Nginx services as &lt;code&gt;web1.docker.local&lt;/code&gt; and &lt;code&gt;web2.docker.local&lt;/code&gt;. In the example below I’m using curl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; Host:web1.docker.local http://127.0.0.1
&lt;span class="c"&gt;# 1&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; Host:web1.docker.local http://127.0.0.1
&lt;span class="c"&gt;# 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It may take a few seconds to start the containers so if you get a &lt;code&gt;404 page not found&lt;/code&gt; response just wait and try again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traefik 2 with fallback to Traefik 1
&lt;/h2&gt;

&lt;p&gt;You now have a working Traefik 1.x reverse proxy and two backend services. Let's migrate it to 2.x! Next you are going to add a Traefik 2 service which will run alongside and proxy requests to the existing one. Incoming requests will be routed to the Traefik 2 service and if no routes are matched they will then be routed to the Traefik 1 service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tY4LR7JG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xhhpqq469k6jz88x1hc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tY4LR7JG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xhhpqq469k6jz88x1hc7.png" alt="Traefik 2 routing all requests to Traefik 1"&gt;&lt;/a&gt;&lt;/p&gt;
Traefik 2 routing all requests to Traefik 1



&lt;p&gt;Deploy these changes to the stack definition file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt; # docker-compose.yaml

 ...
 configs:
   ...
&lt;span class="gi"&gt;+  # Dynamic configuration for Traefik 2 (see below)
+  traefik2-providers:
+    file: ./traefik2-providers.yaml
&lt;/span&gt;
 services:
   traefik1:
     image: traefik:v1.7
&lt;span class="gd"&gt;-    ports:
-      - "80:80"
&lt;/span&gt;   ...
&lt;span class="gi"&gt;+  traefik2:
+    image: traefik:v2.1
+    ports:
+      # The HTTP port
+      - "80:80"
+    volumes:
+      # So that Traefik can listen to the Docker events
+      - /var/run/docker.sock:/var/run/docker.sock
+    command: &amp;gt;
+      --providers.docker
+      --providers.docker.swarmMode
+      --providers.file.directory=/etc/traefik
+      --providers.file.filename=providers.yaml
+      --entryPoints.http.address=:80
+      --api.insecure
+    configs:
+      - source: traefik2-providers
+        target: /etc/traefik/providers.yaml
+    networks:
+      - traefik-public
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;traefik2-providers.yaml&lt;/code&gt; file used in the &lt;code&gt;traefik2-providers&lt;/code&gt; config directive for the &lt;code&gt;traefik2&lt;/code&gt; service defines a catch-all route that forwards unmatched requests to the &lt;code&gt;traefik1&lt;/code&gt; service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# traefik2-providers.yaml&lt;/span&gt;

&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;routers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Define a catch-all router that forwards requests to legacy Traefik&lt;/span&gt;
    &lt;span class="na"&gt;to-traefik1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Catch all domains (regex matches all strings)&lt;/span&gt;
      &lt;span class="c1"&gt;# See https://github.com/google/re2/wiki/Syntax&lt;/span&gt;
      &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HostRegexp(`{domain:.+}`)"&lt;/span&gt;
      &lt;span class="c1"&gt;# If the rule matches, forward to the traefik1 service (see below)&lt;/span&gt;
      &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik1&lt;/span&gt;
      &lt;span class="c1"&gt;# Set the lowest priority, so this route is only used as a last resort&lt;/span&gt;
      &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Define how to reach legacy Traefik&lt;/span&gt;
    &lt;span class="na"&gt;traefik1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;loadBalancer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="c1"&gt;# Legacy Traefik is part of the same stack so,&lt;/span&gt;
          &lt;span class="c1"&gt;# hostname defaults to service name&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://traefik1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Redeploy the stack and check everything is still working as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stack deploy &lt;span class="nt"&gt;-c&lt;/span&gt; docker-compose.yaml traefik
&lt;span class="c"&gt;# ...&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; Host:web1.docker.local http://127.0.0.1
&lt;span class="c"&gt;# 1&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; Host:web2.docker.local http://127.0.0.1
&lt;span class="c"&gt;# 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Traefik 2 replacing Traefik 1
&lt;/h2&gt;

&lt;p&gt;Next let's set up Traefik 2 to handle requests to &lt;code&gt;web1&lt;/code&gt;, as in Image 3:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ulEIvwQG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w4y36sorphcje0v8u8qe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ulEIvwQG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w4y36sorphcje0v8u8qe.png" alt="Traefik 2 handling web1 service's routing"&gt;&lt;/a&gt;&lt;/p&gt;
Traefik 2 handling web1 service's routing



&lt;p&gt;This setup can be achieved by updating &lt;code&gt;web1&lt;/code&gt; service labels to match Traefik 2 format as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;web1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="s"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.web1.rule=Host(`web1.docker.local`)&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.services.web1.loadbalancer.server.port=80&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Redeploy the stack and again check everything is still working as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stack deploy &lt;span class="nt"&gt;-c&lt;/span&gt; docker-compose.yaml traefik
&lt;span class="c"&gt;# ...&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; Host:web1.docker.local http://127.0.0.1
&lt;span class="c"&gt;# 1&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; Host:web2.docker.local http://127.0.0.1
&lt;span class="c"&gt;# 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now repeat the process for &lt;code&gt;web2&lt;/code&gt; service. If something goes wrong, you just need to revert to a previous working configuration for the affected service, redeploy, and start over. In a real-world scenario with lots of services, migration can take place one service at a time like this, reducing downtime.&lt;br&gt;&lt;br&gt;
When you finish migrating to Traefik 2, take down the Traefik 1 service. You will then end up with this scenario:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d92PPwDs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nkf1xvq3l20t8thiuj8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d92PPwDs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nkf1xvq3l20t8thiuj8m.png" alt="Traefik 2 handling all routing"&gt;&lt;/a&gt;&lt;/p&gt;
Traefik 2 handling all routing



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;And that's it! You’ve successfully migrated from &lt;a href="https://containo.us/traefik/"&gt;Traefik&lt;/a&gt; 1.x to 2.x one service at a time. This step by step migration strategy comes from the StranglerFigApplication pattern, as &lt;a href="https://martinfowler.com/bliki/StranglerFigApplication.html"&gt;described by Martin Fowler&lt;/a&gt;. As a final note, I would highly recommend putting your configurations under version control as that would make it very easy to roll back changes when needed.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;em&gt;Cover image by &lt;a href="https://unsplash.com/@heidifin?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Heidi Fin&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
