Azure: VM с NGINX в роли reverse-прокси к WebApp

Автор: | 04/30/2016
 

azure_logoЗадача – поднять реверс-прокси на NGINX, который будет проксировать данные к WebApp в Azure.

NGINX будет работать на виртуальной машине.

Создание VM

Используем Azure CLI  для создания машины.

Логинимся:

$ azure  login

Проверяем режим Azure CLI – нужен arm (Resource Manager mode):

$ azure config list | grep arm
data:    mode     arm  

Если сейчас CLI находится в режиме Service Management mode – переключиться можно с помощью:

$ azure config mode arm
info:    Executing command config mode
info:    New mode is arm
info:    config mode command OK

Переключаемся на нужную подписку:

$ azure account list
info:    Executing command account list
data:    Name           Id                                    Current  State   
data:    -------------  ------------------------------------  -------  --------
data:    Free Trial     97214f99-***-***-***-715556cd5906  true     Enabled 
data:    Pay-As-You-Go  fe37db50-***-***-***-66145cdbd735  false    Disabled
data:    Pay-As-You-Go  0a4f2b9c-***-***-***-40b17ef8c3ab  false    Enabled 
$ azure account set 97214f99-***-***-***-715556cd5906
info:    Executing command account set
info:    Setting subscription to "Free Trial" with id "97214f99-***-***-***-715556cd5906".
info:    Changes saved

Для создания виртуальной машины (далее – VM) – используем vm quick-create, подробнее – тут>>>:

$ azure vm quick-create -h
help:    Create a virtual machine with default resources in a resource group
help:    
help:    Usage: vm quick-create [options] <resource-group> <name> <location> <os-type> <image-urn> <admin-username> <admin-password>
help:    
help:    Options:
help:      -h, --help                                     output usage information
help:      -v, --verbose                                  use verbose output
help:      -vv                                            more verbose with debug output
help:      --json                                         use json output
help:      -g, --resource-group <resource-group>          the resource group name
help:      -n, --name <name>                              the virtual machine name
help:      -l, --location <location>                      the location
help:      -y, --os-type <os-type>                        the operating system Type, valid values are Windows, Linux
help:      -Q, --image-urn <image-urn>                    the image URN in the form "publisherName:offer:skus:version",
help:                                                     or the VHD link of a user image,
help:                                                     e.g. https://foo.blob.core.windows.net/bar/vhds/baz.vhd
help:      -z, --vm-size <vm-size>                        the virtual machine size [Standard_D1]
help:      -u, --admin-username <admin-username>          the user name
help:      -p, --admin-password <admin-password>          the password, skipped if SSH public key file is specified for Linux VMs
help:      -M, --ssh-publickey-file <ssh-publickey-file>  the path to public key file for SSH authentication,
help:                                                     & this parameter is valid only when os-type is Linux.
help:      -s, --subscription <subscription>              the subscription identifier
help:    
help:    Current Mode: arm (Azure Resource Management)

Проверяем доступные локации:

$ azure location list   
info:    Executing command location list
warn:    The "location list" commands is changed to list subscription's locations. For old information, use "provider list or show" commands.
info:    Getting locations...
data:    Name                Display Name         Latitude  Longitude
data:    ------------------  -------------------  --------  ---------
data:    eastasia            East Asia            22.267    114.188  
data:    southeastasia       Southeast Asia       1.283     103.833  
data:    centralus           Central US           41.5908   -93.6208 
data:    eastus              East US              37.3719   -79.8164 
data:    eastus2             East US 2            36.6681   -78.3889 
data:    westus              West US              37.783    -122.417 
data:    northcentralus      North Central US     41.8819   -87.6278 
data:    southcentralus      South Central US     29.4167   -98.5    
data:    northeurope         North Europe         53.3478   -6.2597  
data:    westeurope          West Europe          52.3667   4.9      
data:    japanwest           Japan West           34.6939   135.5022 
data:    japaneast           Japan East           35.68     139.77   
data:    brazilsouth         Brazil South         -23.55    -46.633  
data:    australiaeast       Australia East       -33.86    151.2094 
data:    australiasoutheast  Australia Southeast  -37.8136  144.9631 
data:    southindia          South India          12.9822   80.1636  
data:    centralindia        Central India        18.5822   73.9197  
data:    westindia           West India           19.088    72.868   

Выбираем группу ресурсов:

$ azure group list
info:    Executing command group list
+ Listing resource groups                                                      
data:    Name                    Location    Provisioning State  Tags:
data:    ----------------------  ----------  ------------------  -----
data:    CDN_testing             westus      Succeeded           null 
data:    D2                      westeurope  Succeeded           null 
data:    Default-Storage-EastUS  eastus      Succeeded           null 

Находим URN образа с Ubuntu 14.04:

$ azure vm image list westeurope canonical ubuntuserver | grep 14.04
data:    canonical  ubuntuserver  14.04.0-LTS        Linux  14.04.201404140  westeurope  canonical:ubuntuserver:14.04.0-LTS:14.04.201404140  
...

Подробнее – тут>>> и в посте Azure: деплой VM из образа с помощью Azure CLI.

И обращайте внимание на последние цифры версии – *.201604060 – последний билд.

Создаем машину:

$ azure vm quick-create -g D2 -n gw -l westeurope -y Linux -Q canonical:ubuntuserver:14.04.4-LTS:14.04.201604060 -u setevoy -p p@ssw0rd
info:    Executing command vm quick-create
+ Looking up the VM "gw"
info:    Using the VM Size "Standard_D1"
info:    The [OS, Data] Disk or image configuration requires storage account
+ Looking up the storage account cli3879857892351853844
info:    Could not find the storage account "cli3879857892351853844", trying to create new one
+ Creating storage account "cli3879857892351853844" in "westeurope"
+ Looking up the storage account cli3879857892351853844
+ Looking up the NIC "gw-weste-387985789-nic"
info:    An nic with given name "gw-weste-387985789-nic" not found, creating a new one
+ Looking up the virtual network "gw-weste-387985789-vnet"
info:    Preparing to create new virtual network and subnet
+ Creating a new virtual network "gw-weste-387985789-vnet" [address prefix: "10.0.0.0/16"] with subnet "gw-weste-387985789-snet" [address prefix: "10.0.1.0/24"]
+ Looking up the virtual network "gw-weste-387985789-vnet"
+ Looking up the subnet "gw-weste-387985789-snet" under the virtual network "gw-weste-387985789-vnet"
info:    Found public ip parameters, trying to setup PublicIP profile
+ Looking up the public ip "gw-weste-387985789-pip"
info:    PublicIP with given name "gw-weste-387985789-pip" not found, creating a new one
+ Creating public ip "gw-weste-387985789-pip"
+ Looking up the public ip "gw-weste-387985789-pip"                            
+ Creating NIC "gw-weste-387985789-nic"                                        
+ Looking up the NIC "gw-weste-387985789-nic"                                  
+ Creating VM "gw"                                                             
+ Looking up the VM "gw"                                                       
+ Looking up the NIC "gw-weste-387985789-nic"                                  
+ Looking up the public ip "gw-weste-387985789-pip"                            
data:    Id                              :/subscriptions/97214f99-***-***-***-715556cd5906/resourceGroups/D2/providers/Microsoft.Compute/virtualMachines/gw
data:    ProvisioningState               :Succeeded
data:    Name                            :gw
data:    Location                        :westeurope
data:    Type                            :Microsoft.Compute/virtualMachines
data:    
data:    Hardware Profile:
data:      Size                          :Standard_D1
data:    
data:    Storage Profile:
data:      Image reference:
data:        Publisher                   :canonical
data:        Offer                       :ubuntuserver
data:        Sku                         :14.04.4-LTS
data:        Version                     :14.04.201604060
data:    
data:      OS Disk:
data:        OSType                      :Linux
data:        Name                        :cli6f0fe23acedc08d4-os-1462018191934
data:        Caching                     :ReadWrite
data:        CreateOption                :FromImage
data:        Vhd:
data:          Uri                       :https://cli3879857892351853844.blob.core.windows.net/vhds/cli6f0fe23acedc08d4-os-1462018191934.vhd
data:    
data:    OS Profile:
data:      Computer Name                 :gw
data:      User Name                     :setevoy
data:      Linux Configuration:
data:        Disable Password Auth       :false
data:    
data:    Network Profile:
data:      Network Interfaces:
data:        Network Interface #1:
data:          Primary                   :true
data:          MAC Address               :00-0D-3A-23-20-8B
data:          Provisioning State        :Succeeded
data:          Name                      :gw-weste-387985789-nic
data:          Location                  :westeurope
data:            Public IP address       :13.80.9.248
data:            FQDN                    :gw-weste-387985789-pip.westeurope.cloudapp.azure.com
data:    
data:    Diagnostics Profile:
data:      BootDiagnostics Enabled       :true
data:      BootDiagnostics StorageUri    :https://cli3879857892351853844.blob.core.windows.net/
data:    
data:      Diagnostics Instance View:
info:    vm quick-create command OK

Проверяем:

$ azure vm list
info:    Executing command vm list
+ Getting virtual machines
data:    ResourceGroupName  Name  ProvisioningState  PowerState  Location    Size
data:    -----------------  ----  -----------------  ----------  ----------  -----------
data:    D2                 gw    Succeeded          VM running  westeurope  Standard_D1
info:    vm list command OK

Находим IP, который потребуется при создании субдомена:

$ azure vm show -g D2 -n gw | grep IP
data:            Public IP address       :13.80.9.248

Пробуем подключиться:

$ ssh setevoy@13.80.9.248
The authenticity of host '13.80.9.248 (13.80.9.248)' can't be established.
ECDSA key fingerprint is 20:a7:0b:33:61:11:ec:98:3a:83:77:2b:e3:0f:7e:83.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '13.80.9.248' (ECDSA) to the list of known hosts.
setevoy@13.80.9.248's password: 
Welcome to Ubuntu 14.04.4 LTS (GNU/Linux 3.19.0-58-generic x86_64)
...
setevoy@gw:~$

Там же находим Network interface – его Name понадобится при создании Security group:

...
data:    Network Profile:
data:      Network Interfaces:
data:        Network Interface #1:
data:          Primary                   :true
data:          MAC Address               :00-0D-3A-23-20-8B
data:          Provisioning State        :Succeeded
data:          Name                      :gw-weste-387985789-nic
data:          Location                  :westeurope
data:            Public IP address       :13.80.9.248
data:            FQDN                    :gw-weste-387985789-pip.westeurope.cloudapp.azure.com
...

Далее треубется открыть порт 80 для входящих соединений, т.к. по умолчанию доступ открыт только на порт 22:

$ telnet 13.80.9.248 80
Trying 13.80.9.248...
telnet: Unable to connect to remote host: Connection timed out

Проверяем текущие Security группы:

$ azure network nsg list
info:    Executing command network nsg list
+ Getting the network security groups                                          
warn:    No network security groups found

Создаем новую группу с именем gw_in:

$ azure network nsg create -g D2 -n gw_in -l westeurope
info:    Executing command network nsg create
+ Looking up the network security group "gw_in"                                
+ Creating a network security group "gw_in"                                    
data:    Id                              : /subscriptions/97214f99-***-***-***-715556cd5906/resourceGroups/D2/providers/Microsoft.Network/networkSecurityGroups/gw_in
data:    Name                            : gw_in
data:    Type                            : Microsoft.Network/networkSecurityGroups
data:    Location                        : westeurope
data:    Provisioning state              : Succeeded
data:    Security rules:
data:    Name                           Source IP          Source Port  Destination IP  Destination Port  Protocol  Direction  Access  Priority
data:    -----------------------------  -----------------  -----------  --------------  ----------------  --------  ---------  ------  --------
data:    AllowVnetInBound               VirtualNetwork     *            VirtualNetwork  *                 *         Inbound    Allow   65000   
data:    AllowAzureLoadBalancerInBound  AzureLoadBalancer  *            *               *                 *         Inbound    Allow   65001   
data:    DenyAllInBound                 *                  *            *               *                 *         Inbound    Deny    65500   
data:    AllowVnetOutBound              VirtualNetwork     *            VirtualNetwork  *                 *         Outbound   Allow   65000   
data:    AllowInternetOutBound          *                  *            Internet        *                 *         Outbound   Allow   65001   
data:    DenyAllOutBound                *                  *            *               *                 *         Outbound   Deny    65500   

Добавляем к ней правило для входящих соединений на порт 80 с именем 80inallow:

$ azure network nsg rule create -g D2 -a gw_in -n 80inallow -p tcp -o '*' -u 80 -c Allow
info:    Executing command network nsg rule create
warn:    Using default source port: 80
warn:    Using default source address prefix: *
warn:    Using default destination address prefix: *
warn:    Using default priority: 100
warn:    Using default direction: Inbound
+ Looking up the network security group "gw_in"                                
+ Looking up the network security rule "80inallow"                             
+ Creating a network security rule "80inallow"                                 
data:    Id                              : /subscriptions/97214f99-***-***-***-715556cd5906/resourceGroups/D2/providers/Microsoft.Network/networkSecurityGroups/gw_in/securityRules/80inallow
data:    Name                            : 80inallow
data:    Type                            : Microsoft.Network/networkSecurityGroups/securityRules
data:    Provisioning state              : Succeeded
data:    Source IP                       : *
data:    Source Port                     : 80
data:    Destination IP                  : *
data:    Destination Port                : 80
data:    Protocol                        : Tcp
data:    Direction                       : Inbound
data:    Access                          : Allow
data:    Priority                        : 100
info:    network nsg rule create command OK

Аналогично – для порта 22, SSH, но с более высоким приоритетом, что бы избежать ошибки вида:

error:   Security rule 80inallow conflicts with rule sshallow. Rules cannot have the same Priority and Direction.

$ azure network nsg rule create -g D2 -a gw_in -n sshallow -p tcp -o '*' -u 22 -c Allow -y 101

Подключаем интерфейс к этой группе безопасности:

$ azure network nic set -g D2 -n gw-weste-387985789-nic --network-security-group-name gw_in
info:    Executing command network nic set
+ Looking up the network interface "gw-weste-387985789-nic"                    
+ Looking up the network security group "gw_in"                                
+ Updating network interface "gw-weste-387985789-nic"                          
data:    Id                              : /subscriptions/97214f99-***-***-***-715556cd5906/resourceGroups/D2/providers/Microsoft.Network/networkInterfaces/gw-weste-387985789-nic
data:    Name                            : gw-weste-387985789-nic
data:    Type                            : Microsoft.Network/networkInterfaces
data:    Location                        : westeurope
data:    Provisioning state              : Succeeded
data:    MAC address                     : 00-0D-3A-23-20-8B
data:    Enable IP forwarding            : false
data:    Network security group          : /subscriptions/97214f99-***-***-***-715556cd5906/resourceGroups/D2/providers/Microsoft.Network/networkSecurityGroups/gw_in
data:    Virtual machine                 : /subscriptions/97214f99-***-***-***-715556cd5906/resourceGroups/D2/providers/Microsoft.Compute/virtualMachines/gw
data:    IP configurations:
data:      Name                          : ipconfig1462018264060
data:      Provisioning state            : Succeeded
data:      Public IP address             : /subscriptions/97214f99-***-***-***-715556cd5906/resourceGroups/D2/providers/Microsoft.Network/publicIPAddresses/gw-weste-387985789-pip
data:      Private IP address            : 10.0.1.4
data:      Private IP allocation method  : Dynamic
data:      Subnet                        : /subscriptions/97214f99-***-***-***-715556cd5906/resourceGroups/D2/providers/Microsoft.Network/virtualNetworks/gw-weste-387985789-vnet/subnets/gw-weste-387985789-snet

Проверяем:

$ telnet 13.80.9.248 80
Trying 13.80.9.248...
Connected to 13.80.9.248.
Escape character is '^]'.

Создание WebApp

В WebApp у нас будет работать приложение, к которому мы будем проксировать данные через созданную VM.

Проверяем имеющиеся приложения:

$ azure webapp list -g D2
info:    Executing command webapp list
+ Listing webapps                                                              
info:    No web apps found.

Создаем WebApp:

$ azure webapp create -g D2 -n backappforgw -l westeurope -p WEgwapp
info:    Executing command webapp create
+ Creating webapp backappforgw                                                 
info:    Webapp backappforgw has been created 

Проверяем:

$ azure webapp show -g D2 -n backappforgw
info:    Executing command webapp show
+ Getting webapp                                                               
data:    Web app Name  : backappforgw
data:    SKU           : Standard
data:    Enabled       : true
data:    Last Modified : 2016-04-30T13:52:36.29
data:    Location      : West Europe
data:    
data:    Host Name                     
data:    ------------------------------
data:    backappforgw.azurewebsites.net
$ curl -sr 0-1024 http://backappforgw.azurewebsites.net
<!DOCTYPE html><html><head>    <title>Microsoft Azure Web App - Welcome</title> 
...

Настройка DNS

Далее будут использоваться два субдомена:

  1. gw.setevoy.org.ua: шлюз с NGINX;
  2. app.setevoy.org.ua: созданное приложение, к которому будет проксироваться трафик, но с IN A созданной VM;

Что бы подключить внешний домен к приложению в Azure – необходимо создать запись авторизации вида:

awverify.app.setevoy.kiev.ua CNAME awverify.backappforgw.azurewebsites.net

При создания app.setevoy.org.ua – указываем IP шлюза, в результате получается примерно такая картина:

azure_nginx_proxy_2

Подключаем новый субдомен в Portal > App Services > backappforgw  > Settings > Custom domains and SSL > Bring External Domains:

azure_nginx_proxy_3

И оттуда же записываем IP – 104.47.151.115, который далее используем при настройке NGINX.

Настройка NGINX

На созданной VM устанавливаем NGINX:

$ sudo -s
# apt-get update
# apt-get install nginx

Создаем файл конфигурации /etc/nginx/sites-available/app.setevoy.kiev.ua.conf:

server {
    server_name app.setevoy.kiev.ua;

    access_log /var/log/nginx/app.setevoy.kiev.ua-access.log;
    error_log /var/log/nginx/app.setevoy.kiev.ua-error.log;

    root /usr/share/nginx/html;

    location / {
        proxy_redirect          off;
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://104.47.151.115;
    }
}

Создаём симлинк в каталог sites-enabled (Debian/Ubuntu):

# ln -s /etc/nginx/sites-available/app.setevoy.kiev.ua.conf /etc/nginx/sites-enabled/

Проверяем:

# ls -l /etc/nginx/sites-enabled/
total 0
lrwxrwxrwx 1 root root 51 Apr 30 14:23 app.setevoy.kiev.ua.conf -> /etc/nginx/sites-available/app.setevoy.kiev.ua.conf
lrwxrwxrwx 1 root root 34 Apr 30 13:06 default -> /etc/nginx/sites-available/default
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Перегружаем конфиги:

# service nginx reload
 * Reloading nginx configuration nginx

И пробуем зайти:

azure_nginx_proxy_4

Готово.

Ссылки по теме

Create a Linux VM on Azure using the CLI

Navigate and select Linux virtual machine images in Azure with CLI or Powershell

Configure a custom domain name in Azure App Service

Create a Linux VM from the ground up using the Azure CLI (замечательный почти cheat-sheet)

How to create NSGs in the Azure CLI

Azure: деплой VM из образа с помощью Azure CLI

Reverse Proxy on Windows Azure using Nginx