Traffic mirroring by NGINX mirror module

Alexandr K - Dec 23 '19 - - Dev Community

Hi everyone.

A few months ago I've decided to work on migrating one of our company services from Php to Go services because of no engineers to continue to develop or support our endpoints, the new endpoints were coming by developers using Go instead. As for me, I have good enough experience in Ruby/Go/JS but I don't think I wanted to increase in pretty old endpoints written for years ago.

Let's say if you have high load usage of your services what is the best way to make the migration. The idea came to me while I was reading the docs from Nginx website about the mirror module ( https://nginx.org/en/docs/http/ngx_http_mirror_module.html ).

Probably it would be a reasonable way to use it in my case. To make the prototype I used docker-compose where I put all of my services in one place and attached log during the making the basic requests.

The simplified version below:

version: "3"

services:
  entry:
    image: nginx
    volumes:
     - ./v2/nginx.template:/etc/nginx/conf.d/default.conf
    links:
      - v1
      - v2_backend
    ports:
     - "80:80"
    environment:
     - NGINX_PORT=80
    command: /bin/bash -c "exec nginx -g 'daemon off;'"

  v1:
    image: nginx
    volumes:
     - ./v1/nginx.template:/etc/nginx/conf.d/default.conf
    links:
      - v1_backend
    expose:
     - "80"
    environment:
     - NGINX_PORT=80
    command: /bin/bash -c "exec nginx -g 'daemon off;'"

  v1_backend:
    image: example-image1:latest
    expose:
      - "9000"

  v2_backend:
    image: example-image2:latest
    expose:
      - "5000"
Enter fullscreen mode Exit fullscreen mode

v1/nginx.template is Php Nginx configuration file that's using FastCGI.

upstream backend {
  server v1_backend:9000;
}

server {
    listen       80;
    server_name  _;
    root /var/www/html;

    location / {
        try_files $uri $uri/ @rewrite;
    }

    location @rewrite {
      rewrite ^/(.*)$ /index.php?q=$1 last;
    }

    error_page  404              /404.html;
    error_page   500 502 503 504  /50x.html;

    location ~ .php$ {
        try_files  $uri =404;

        fastcgi_pass   backend;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
        include        fastcgi_params;

        fastcgi_max_temp_file_size 0;

        fastcgi_buffers 32 256k;
    }
}
Enter fullscreen mode Exit fullscreen mode

v2/nginx.template is Go Nginx template to serve our new v2 API and attaching mirror to feed our V2 API

upstream v1.backend {
    server v1;
}

upstream v2.backend {
    server v2_backend:5000;
}

server {
    listen 80;
    server_name _;

    location / {
      mirror /mirror;
      mirror_request_body on;

      proxy_pass http://v1.backend;
    }

    location = /mirror {
      internal;

      proxy_pass http://v2.backend$request_uri;
      proxy_set_header X-SERVER-PORT $server_port;
      proxy_set_header X-SERVER-ADDR $server_addr;
      proxy_set_header X-Original-URI $request_uri;
      proxy_set_header HOST $http_host;
      proxy_set_header X-REAL-IP $remote_addr;
    }
}
Enter fullscreen mode Exit fullscreen mode

I think it's the basic example of how to achieve the goal by having the primary APP like in my case it was Php application and Go app as V2 API.

mirror /mirror; - is an instruction to use location /mirror as the next step to process request than upstream it to v2 backend and we are ready to verify the traffic from the console application.

Once V2 application is working fine we can fully remove the V1 and replace Nginx template by the new version without mirror.

Thank you for reading!

. . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player