Azure CLI를 사용하여 Express.js 가상 머신 만들기

이 자습서에서는 Express.js 앱용 Linux VM(가상 머신)을 만듭니다. VM은 cloud-init 구성 파일로 구성되며 Express.js 앱에 대한 NGINX 및 GitHub 리포지토리를 포함합니다. SSH를 사용하여 VM에 커넥트 추적 로깅을 포함하도록 웹앱을 변경하고 웹 브라우저에서 공용 Express.js 서버 앱을 봅니다.

이 자습서에는 다음 작업이 포함됩니다.

  • Azure CLI를 사용하여 Azure에 로그인
  • Azure CLI를 사용하여 Azure Linux VM 리소스 만들기
    • 공용 포트 80 열기
    • GitHub 리포지토리에서 데모 Express.js 웹앱 설치
    • 웹앱 종속성 설치
    • 웹앱 시작
  • Azure CLI를 사용하여 Azure 모니터링 리소스 만들기
    • SSH를 사용하여 VM에 커넥트
    • npm을 사용하여 Azure SDK 클라이언트 라이브러리 설치
    • Application Insights 클라이언트 라이브러리 코드를 추가하여 사용자 지정 추적 만들기
  • 브라우저에서 웹앱 보기
    • Application Insights 로그에서 사용자 지정 추적을 생성하는 요청 /trace 경로
    • Azure CLI를 사용하여 로그에서 수집된 추적 수 보기
    • Azure Portal을 사용하여 추적 목록 보기
  • Azure CLI를 사용하여 리소스 제거

기존 Azure 구독 만들기 또는 사용

활성 구독이 있는 Azure 사용자 계정이 필요합니다. 체험 계정 만들기

필수 조건

  • SSH를 사용하여 VM에 연결: Azure Cloud Shell 또는 SSH를 포함하는 bash 셸과 같은 최신 터미널을 사용합니다.

1. 웹 페이지에 대한 Application Insights 리소스 만들기

모든 Azure 리소스에 대한 Azure 리소스 그룹 및 Monitor 리소스를 만들어 웹앱의 로그 파일을 Azure 클라우드로 수집합니다. 리소스 그룹을 만들면 리소스를 쉽게 찾고 완료되면 삭제할 수 있습니다. Azure Monitor는 Azure 서비스의 이름이고, Application Insights는 자습서에서 사용하는 클라이언트 라이브러리의 이름입니다.

  1. 선택 사항으로, 둘 이상의 구독이 있는 경우 다시 기본 명령을 완료하기 전에 az account set를 사용하여 기본 구독을 설정합니다.

    az account set \
        --subscription "ACCOUNT NAME OR ID" 
    
  2. az group create를 사용하여 Azure 리소스 그룹을 만듭니다. 이름 rg-demo-vm-eastus사용:

    az group create \
        --location eastus \
        --name rg-demo-vm-eastus 
    

Azure CLI를 사용하여 Azure Monitor 리소스 만들기

  1. Azure CLI의 Application Insights 확장을 설치합니다.

    az extension add -n application-insights
    
  2. az monitor app-insights 구성 요소를 사용하여 모니터링 리소스 를 만들려면 다음 명령을 사용합니다.

    az monitor app-insights component create \
      --app demoWebAppMonitor \
      --location eastus \
      --resource-group rg-demo-vm-eastus \
      --query instrumentationKey --output table
    
  3. 출력에서 결과를 복사합니다. 나중에 해당 값 instrumentationKey 이 필요합니다.

  4. 터미널을 열어 두면 다음 단계에서 사용합니다.

2. Azure CLI를 사용하여 Linux 가상 머신 만들기

cloud-init 구성 파일을 사용하여 NGINX 역방향 프록시 서버와 Express.js 서버를 모두 만듭니다. NGINX는 Express.js 포트(3000)를 공용 포트(80)로 전달하는 데 사용됩니다.

  1. 명명된 cloud-init-github.txt 로컬 파일을 만들고 다음 내용을 파일에 저장하거나 리포지토리의 파일을 로컬 컴퓨터에 저장할 수 있습니다. cloud-init 형식의 파일은 Azure CLI 명령의 터미널 경로와 동일한 폴더에 있어야 합니다.

    #cloud-config
    package_upgrade: true
    packages:
      - nginx
    write_files:
      - owner: www-data:www-data
        path: /etc/nginx/sites-available/default
        content: |
          server {
            listen 80 default_server;
            server_name _;
            location / {
              # First, try if the file exists locally, otherwise request it from the app
              try_files $uri @app;
            }
            location @app {
              proxy_pass http://localhost:3000;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header X-Forwarded-For $remote_addr;
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
            }
          }
    runcmd:
      # install Node.js
      - 'curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -'
      - 'sudo apt-get install -y nodejs'
      # clone GitHub Repo into myapp directory
      - 'cd /home/azureuser'
      - git clone "https://github.com/Azure-Samples/js-e2e-vm" myapp
      # Start app
      - 'cd myapp && npm install && npm start'
      # restart NGINX
      - systemctl restart nginx
    
  2. 파일의 runcmd 섹션을 검토하여 수행하는 작업을 파악합니다.

    여기에는 runcmd 다음과 같은 여러 작업이 있습니다.

    • Node.js 다운로드 및 설치
    • GitHub에서 myapp 디렉터리로 샘플 Express.js 리포지토리를 복제합니다.
    • 애플리케이션 종속성 설치
    • PM2를 사용하여 Express.js 앱 시작

가상 머신 리소스 만들기

  1. 터미널에서 Azure CLI 명령 az vm create를 입력하여 Linux 가상 머신의 Azure 리소스를 만듭니다. 이 명령은 cloud-init 파일에서 VM을 만들고 SSH 키를 생성합니다. 실행 중인 명령은 키가 저장되는 위치를 표시합니다.

    az vm create \
      --resource-group rg-demo-vm-eastus \
      --name demo-vm \
      --location eastus \
      --public-ip-sku Standard \
      --image UbuntuLTS \
      --admin-username azureuser \
      --generate-ssh-keys \
      --custom-data cloud-init-github.txt
    
  2. 프로세스가 몇 분 정도 걸릴 수 있는 동안 기다립니다.

  3. 응답에서 publicIpAddress 값을 유지합니다. 브라우저에서 웹앱을 보고 VM에 연결해야 합니다. 이 IP가 손실되면 Azure CLI 명령인 az vm list-ip-addresses 를 사용하여 다시 가져옵니다.

  4. 프로세스는 SSH 키를 만들었지만 응답에 명시된 위치에 해당 키를 만들었습니다.

  5. 해당 위치로 이동하여 파일을 만듭니다.authorized_keys

    cd <SSH-KEY-LOCATION> && cat id_rsa >> authorized_keys
    

가상 머신에 대한 포트 열기

처음 만들 때 가상 머신에 열려 있는 포트가 없습니다 . 웹앱을 공개적으로 사용할 수 있도록 다음 Azure CLI 명령인 az vm open-port를 사용하여 포트 80을 엽니다.

az vm open-port \
  --port 80 \
  --resource-group rg-demo-vm-eastus \
  --name demo-vm

웹 사이트로 이동

  1. 웹 브라우저에서 공용 IP 주소를 사용하여 가상 머신을 사용할 수 있고 실행 중인지 확인합니다. 에서 값을 사용하도록 URL을 변경합니다 publicIpAddress.

    http://YOUR-VM-PUBLIC-IP-ADDRESS
    
  2. 게이트웨이 오류로 리소스가 실패하는 경우 1분 후에 다시 시도하면 웹앱을 시작하는 데 1분 정도 걸릴 수 있습니다.

  3. 가상 머신의 웹앱은 다음 정보를 반환합니다.

    • VM 이름
    • 클라이언트 IP
    • 현재 날짜/시간

    Screenshot of web browser showing simple app served from Linus virtual machine on Azure.

  4. 웹앱에 대한 초기 코드 파일에는 NGINX 프록시를 통해 전달되는 단일 경로가 있습니다.

    const os = require('os');
    const express = require('express')
    const app = express()
    
    app.use('/public', express.static('public'))
    app.get('/', function (req, res) {
    
        const clientIP = req.headers['x-forwarded-for'];
        const msg = `HostName: ${os.hostname()}<br>ClientIP: ${clientIP}<br>DateTime: ${new Date()}<br><img width='200' height='200' src='/public/leaves.jpg' alt='flowers'>`
        console.log(msg)
    
        res.send(msg)
    })
    app.listen(3000, function () {
        console.log(`Hello world app listening on port 3000! ${Date.now()}`)
    })
    

3. SSH를 사용하여 Linux 가상 머신에 커넥트

자습서의 이 섹션에서는 터미널에서 SSH를 사용하여 가상 머신에 연결합니다. SSH 는 Azure Cloud Shell을 비롯한 많은 최신 셸과 함께 제공되는 일반적인 도구입니다.

SSH를 통해 연결하고 웹앱 변경

  1. 다음 명령을 사용하여 원격 가상 머신에 연결합니다.

    YOUR-VM-PUBLIC-IP를 자신의 가상 머신 공용 IP로 바꿉니다.

    ssh azureuser@YOUR-VM-PUBLIC-IP
    

    이 프로세스에서는 SSH 클라이언트가 VM 만들기의 일부로 만들어지고 로컬 컴퓨터에 배치된 SSH 키를 찾을 수 있다고 가정합니다.

  2. 연결, 답변 y 또는 yes 계속할 것인지 묻는 메시지가 표시되면

  3. 다음 명령을 사용하여 가상 머신에서 현재 있는 위치를 파악합니다. azureuser 루트 /home/azureuser에 있어야 합니다. .

    pwd
    
  4. 연결이 완료되면 터미널 프롬프트가 변경되어 원격 가상 머신의 사용자 이름 및 리소스 이름을 나타내야 합니다.

    azureuser@demo-vm:
    
  5. 웹앱이 하위 디렉터리에 myapp있습니다. 디렉터리로 myapp 변경하고 내용을 나열합니다.

    cd myapp && ls -l
    
  6. 가상 머신 및 npm 패키지 파일에 복제된 GitHub 리포지토리를 나타내는 콘텐츠가 표시됩니다.

    -rw-r--r--   1 root root   891 Nov 11 20:23 cloud-init-github.txt
    -rw-r--r--   1 root root  1347 Nov 11 20:23 index-logging.js
    -rw-r--r--   1 root root   282 Nov 11 20:23 index.js
    drwxr-xr-x 190 root root  4096 Nov 11 20:23 node_modules
    -rw-r--r--   1 root root 84115 Nov 11 20:23 package-lock.json
    -rw-r--r--   1 root root   329 Nov 11 20:23 package.json
    -rw-r--r--   1 root root   697 Nov 11 20:23 readme.md
    

모니터링 SDK 설치

  1. 가상 머신에 연결된 SSH 터미널에서 Application Insights용 Azure SDK 클라이언트 라이브러리를 설치 합니다.

    sudo npm install --save applicationinsights
    
  2. 계속하기 전에 명령이 완료될 때까지 기다립니다.

모니터링 계측 키 추가

  1. 가상 머신에 연결된 SSH 터미널에서 Nano 편집기를 사용하여 package.json 파일을 엽니다.

    sudo nano package.json
    
  2. 시작 스크립트의 시작 부분에 APPINSIGHTS_INSTRUMENTATIONKEY 환경 변수를 추가합니다. 다음 예제에서 REPLACE-WITH-YOUR-KEY를 계측 키 값으로 바꿉니다.

    "start": "APPINSIGHTS_INSTRUMENTATIONKEY=REPLACE-WITH-YOUR-KEY pm2 start index.js --watch --log /var/log/pm2.log"
    
  3. 여전히 SSH 터미널에서 컨트롤 + X를 통해 Nano 편집기에 파일을 저장합니다.

  4. Nano 편집기에서 메시지가 표시되면 Y를 입력하여 저장합니다.

  5. Nano 편집기에서 메시지가 표시되면 메시지가 표시되면 파일 이름을 수락합니다.

VM을 중지하여 애플리케이션 변경

Azure 클라이언트 라이브러리는 이제 node_modules 디렉터리에 있으며 키는 환경 변수로 앱에 전달됩니다. 다음 단계에서는 Application Insights를 프로그래밍 방식으로 사용합니다.

  1. 다음 명령을 통해 Node.js 애플리케이션의 프로덕션 프로세스 관리자인 PM2를 중지합니다.

    sudo npm run-script stop 
    
  2. Application Insights를 사용하여 원본 index.js 을 파일로 대체합니다.

    sudo npm run-script appinsights
    
  3. 클라이언트 라이브러리 및 로깅 코드가 제공됩니다.

    const express = require('express')
    const app = express()
    const os = require('os');
    
    console.log(JSON.stringify(process.env));
    
    const AppInsights = require('applicationinsights');
    
    if (process.env.APPINSIGHTS_INSTRUMENTATIONKEY) {
        console.log(`AppInsights configured with key ${process.env.APPINSIGHTS_INSTRUMENTATIONKEY}`);
    } else{
        console.log(`AppInsights not configured`);
    }
    
    AppInsights.setup(process.env.APPINSIGHTS_INSTRUMENTATIONKEY)
        .setAutoDependencyCorrelation(true)
        .setAutoCollectRequests(true)
        .setAutoCollectPerformance(true, true)
        .setAutoCollectExceptions(true)
        .setAutoCollectDependencies(true)
        .setAutoCollectConsole(true)
        .setUseDiskRetryCaching(true)
        .setSendLiveMetrics(false)
        .setDistributedTracingMode(AppInsights.DistributedTracingModes.AI)
        .start();
    
    const AppInsightsClient = AppInsights.defaultClient;
    
    
    app.get('/trace', (req, res) => {
    
        const clientIP = req.headers['x-forwarded-for'];
        const msg = `trace route ${os.hostname()} ${clientIP} ${new Date()}`;
    
        console.log(msg)
    
        if (process.env.APPINSIGHTS_INSTRUMENTATIONKEY) {
            AppInsightsClient.trackPageView();
            AppInsightsClient.trackTrace({ message: msg })
            AppInsightsClient.flush();
        } else {
            msg += ' AppInsights not configured';
        }
    
        res.send(`${msg}`)
    })
    
    app.get('/', function (req, res) {
    
        const clientIP = req.headers['x-forwarded-for'];
        const msg = `root route ${os.hostname()} ${clientIP} ${new Date()}`
    
        console.log(msg)
    
        res.send(msg)
    
    })
    app.listen(3000, function () {
        console.log(`Hello world app listening on port 3000! ${os.hostname()}`)
    })
    
  4. PM2를 통해 앱을 다시 시작하여 다음 환경 변수를 선택합니다.

    sudo npm start
    

앱을 사용하여 로깅 확인

  1. 웹 브라우저에서 새 trace 경로를 사용하여 앱을 테스트합니다.

    http://YOUR-VM-PUBLIC-IP-ADDRESS/trace
    

    브라우저에 IP 주소와 함께 trace route demo-vm YOUR-CLIENT-IP VM-DATE-TIME 응답이 표시됩니다.

NGINX에 대한 로그 보기

VM(가상 머신)은 볼 수 있는 NGINX에 대한 로그를 수집합니다.

서비스 로그 위치
NGINX /var/log/nginx/access.log
  1. SSH 터미널에서 다음 명령을 사용하여 NGINX 프록시 서비스에 대한 VM 로그를 보고 로그를 확인합니다.
cat /var/log/nginx/access.log
  1. 로그에는 로컬 컴퓨터의 호출이 포함됩니다.
"GET /trace HTTP/1.1" 200 10 "-"

PM2에 대한 로그 보기

가상 머신은 볼 수 있는 PM2에 대한 로그를 수집합니다.

서비스 로그 위치
PM2 /var/log/pm2.log
  1. Express.js 노드 웹앱인 PM2 서비스에 대한 VM 로그를 봅니다. 동일한 bash 셸에서 다음 명령을 사용하여 로그를 봅니다.

    cat /var/log/pm2.log
    
  2. 로그에는 로컬 컴퓨터의 호출이 포함됩니다.

    grep "Hello world app listening on port 3000!" /var/log/pm2.log
    
  3. 로그에는 npm 시작 스크립트에 전달된 ApplicationInsights 키를 비롯한 환경 변수도 포함됩니다. 다음 grep 명령을 사용하여 환경 변수에 키가 있는지 확인합니다.

    grep APPINSIGHTS_INSTRUMENTATIONKEY /var/log/pm2.log
    

    그러면 APPINSIGHTS_INSTRUMENTATIONKEY가 다른 색으로 강조 표시된 PM2 로그가 강조 표시됩니다.

VM 로깅 및 클라우드 로깅

이 애플리케이션에서 console.log를 사용하면 VM에만 있는 PM2 로그에 메시지가 기록됩니다. 로그 또는 VM을 삭제하면 해당 정보가 손실됩니다.

가상 머신의 수명이 지난 후에도 로그를 보존하려면 Application Insights를 사용합니다.

5. 리소스 정리

이 자습서를 완료한 후에는 더 이상 사용 요금이 청구되지 않도록 모든 리소스를 포함하는 리소스 그룹을 제거해야 합니다.

동일한 터미널에서 Azure CLI 명령인 az group delete를 사용하여 리소스 그룹을 삭제합니다.

az group delete --name rg-demo-vm-eastus -y

이 명령이 완료될 때까지 몇 분 정도 걸립니다.

문제 해결

문제가 있는 경우 다음 표를 사용하여 문제를 해결하는 방법을 파악합니다.

문제 해결
502 게이트웨이 오류 index.js 또는 package.js 파일에 오류가 있음을 나타낼 수 있습니다. 자세한 내용은 /var/log/pm2.log에서 PM2 로그를 참조하세요. 가장 최근의 오류는 파일 맨 아래에 있습니다. 해당 파일이 올바르다고 확신하는 경우 다음의 npm 스크립트를 사용하여 PM2를 중지하고 시작합니다 package.json.

샘플 코드

다음 단계