使用 Azure CLI 创建 Express.js 虚拟机
在本教程中,将为 Express.js 应用创建一个 Linux 虚拟机 (VM)。 VM 是使用 cloud-init 配置文件配置的,并且它包含 NGINX 以及 Express.js 应用的 GitHub 存储库。 使用 SSH 连接到 VM,将 Web 应用更改为包含跟踪日志记录,并在 Web 浏览器中查看公共 Express.js 服务器应用。
本教程包括以下任务:
- 使用 Azure CLI 登录到 Azure
- 使用 Azure CLI 创建 Azure Linux VM 资源
- 打开公用端口 80
- 从 GitHub 存储库安装演示版 Express.js Web 应用
- 安装 Web 应用依赖项
- 启动 Web 应用
- 使用 Azure CLI 创建 Azure 监视资源
- 使用 SSH 连接到 VM
- 使用 npm 安装 Azure SDK 客户端库
- 添加 Application Insights 客户端库代码以创建自定义跟踪
- 从浏览器查看 Web 应用
- 请求
/trace
路由以在 Application Insights 日志中生成自定义跟踪 - 使用 Azure CLI 查看日志中收集的跟踪计数
- 使用 Azure 门户查看跟踪列表
- 请求
- 使用 Azure CLI 删除资源
先决条件
- Azure 用户帐户和订阅:创建免费订阅。
- 使用 SSH 连接到 VM:使用 Azure Cloud Shell 或现代终端(例如 bash shell),包括 SSH。
在 Azure Cloud Shell 中使用 Bash 环境。 有关详细信息,请参阅 Azure Cloud Shell 中的 Bash 快速入门。
如需在本地运行 CLI 参考命令,请安装 Azure CLI。 如果在 Windows 或 macOS 上运行,请考虑在 Docker 容器中运行 Azure CLI。 有关详细信息,请参阅如何在 Docker 容器中运行 Azure CLI。
如果使用的是本地安装,请使用 az login 命令登录到 Azure CLI。 若要完成身份验证过程,请遵循终端中显示的步骤。 有关其他登录选项,请参阅使用 Azure CLI 登录。
出现提示时,请在首次使用时安装 Azure CLI 扩展。 有关扩展详细信息,请参阅使用 Azure CLI 的扩展。
运行 az version 以查找安装的版本和依赖库。 若要升级到最新版本,请运行 az upgrade。
1. 为每个网页创建 Application Insights 资源
为所有 Azure 资源创建一个 Azure 资源组,并创建一个 Monitor 资源以将 Web 应用的日志文件收集到 Azure 云。 通过创建资源组,可以轻松找到资源,并在完成后将其删除。 Azure Monitor 是 Azure 服务的名称,而 Application Insights 是本教程使用的客户端库的名称。
可选,如果有多个订阅,请使用 az account set 设置默认订阅,然后再完成剩余的命令。
az account set \ --subscription "ACCOUNT NAME OR ID"
使用 az group create 创建 Azure 资源组。 使用名称
rg-demo-vm-eastus
:az group create \ --location eastus \ --name rg-demo-vm-eastus
使用 Azure CLI 创建 Azure Monitor 资源
向 Azure CLI 安装 Application Insights 扩展。
az extension add -n application-insights
使用以下命令创建监视资源,其中使用 az monitor app-insights component create:
az monitor app-insights component create \ --app demoWebAppMonitor \ --location eastus \ --resource-group rg-demo-vm-eastus \ --query instrumentationKey --output table
从输出复制结果,稍后
instrumentationKey
时将需要该值。保持终端打开,在下一步中会使用终端。
2. 使用 Azure CLI 创建 Linux 虚拟机
使用 cloud-init 配置文件创建 NGINX 反向代理服务器和 Express.js 服务器。 NGINX 用于将 Express.js 端口 (3000) 转发到公用端口 (80)。
创建一个名为
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
查看文件的
runcmd
部分以了解其用途。runcmd
具有多个任务:- 下载并安装 Node.js
- 将示例 Express.js 存储库从 GitHub 克隆到
myapp
目录中 - 安装应用程序依赖项
- 使用 PM2 启动 Express.js 应用
创建虚拟机资源
在终端输入 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
请稍候,此过程可能需要几分钟时间。
保留响应中的 publicIpAddress 值,在浏览器中查看 Web 应用程序并连接到 VM 时需要该值。 如果丢失此 IP,请使用 Azure CLI 命令 az vm list-ip-addresses 再次获取。
此过程创建了 SSH 密钥,但它们位于响应中声明的位置。
转到该位置并创建
authorized_keys
文件:cd <SSH-KEY-LOCATION> && cat id_rsa >> authorized_keys
打开虚拟机端口
第一次创建时,虚拟机未打开任何端口。 使用以下 Azure CLI 命令 az vm open-port 打开端口 80,以便 Web 应用公开可用:
az vm open-port \
--port 80 \
--resource-group rg-demo-vm-eastus \
--name demo-vm
浏览到网站
在 Web 浏览器中使用公共 IP 地址,以确保虚拟机可用且正在运行。 更改 URL 以使用
publicIpAddress
中的值。http://YOUR-VM-PUBLIC-IP-ADDRESS
如果资源由于网关错误而失败,请稍后重试,Web 应用可能需要一分钟时间才能启动。
虚拟机的 Web 应用将返回以下信息:
- VM 名称
- 客户端 IP
- 当前日期/时间
Web 应用的初始代码文件有一个路由,该路由通过 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 是随多种新式 shell(包括 Azure Cloud Shell)提供的常用工具。
使用 SSH 连接并更改 Web 应用
使用以下命令连接到远程虚拟机。
将
YOUR-VM-PUBLIC-IP
替换为自己的虚拟机的公共 IP。ssh azureuser@YOUR-VM-PUBLIC-IP
此过程假设 SSH 客户端可以找到 SSH 密钥,这些密钥是在创建 VM 的过程中创建的并且放置在本地计算机上。
如果系统询问是否确定要连接,请接听
y
或yes
继续。使用以下命令了解你在虚拟机上的位置。 你应位于 azureuser 根目录:
/home/azureuser
。pwd
连接完成后,终端提示符应更改,以指示远程虚拟机的用户名和资源名称。
azureuser@demo-vm:
Web 应用位于子目录
myapp
。 切换到myapp
目录并列出内容:cd myapp && ls -l
应该会看到代表克隆到虚拟机中的 GitHub 存储库的内容和 npm 包文件:
-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
在连接到虚拟机的 SSH 终端中,安装适用于 Application Insights 的 Azure SDK 客户端库。
sudo npm install --save applicationinsights
等待命令完成,然后继续。
添加监视检测密钥
在连接到虚拟机的 SSH 终端中,使用 Nano 编辑器打开
package.json
文件。sudo nano package.json
将
APPINSIGHTS_INSTRUMENTATIONKEY
环境变量添加到 Start 脚本的开头。 在下面的示例中,将REPLACE-WITH-YOUR-KEY
替换为检测密钥值。"start": "APPINSIGHTS_INSTRUMENTATIONKEY=REPLACE-WITH-YOUR-KEY pm2 start index.js --watch --log /var/log/pm2.log"
仍然是在 SSH 终端中,使用控件 + X 将文件保存在 Nano 编辑器中。
如果 Nano 编辑器中出现提示,请输入 Y 以保存。
如果 Nano 编辑器中出现提示,请在出现提示时接受文件名。
停止 VM 以更改应用程序
Azure 客户端库现在位于 node_modules 目录中,密钥将作为环境变量传递到应用中。 下一步以编程方式使用 Application Insights。
使用以下命令停止 PM2,它是 Node.js 应用程序的生产进程管理器:
sudo npm run-script stop
使用 Application Insights 将原始
index.js
替换为文件。sudo npm run-script appinsights
系统提供了客户端库和日志记录代码。
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()}`) })
使用 PM2 重启应用以选取下一个环境变量。
sudo npm start
使用应用验证日志记录
在 Web 浏览器中,使用新的
trace
路由测试应用:http://YOUR-VM-PUBLIC-IP-ADDRESS/trace
浏览器将显示响应
trace route demo-vm YOUR-CLIENT-IP VM-DATE-TIME
以及你的 IP 地址。
查看 NGINX 的日志
虚拟机 (VM) 会收集 NGINX 的日志,这些日志可供查看。
服务 | 日志位置 |
---|---|
NGINX | /var/log/nginx/access.log |
- 仍然是在 SSH 终端中,使用以下命令查看 NGINX 代理服务的 VM 日志,以查看该日志:
cat /var/log/nginx/access.log
- 日志包含来自本地计算机的调用。
"GET /trace HTTP/1.1" 200 10 "-"
查看 PM2 的日志
虚拟机会收集 PM2 的日志,这些日志可供查看。
服务 | 日志位置 |
---|---|
PM2 | /var/log/pm2.log |
查看 PM2 服务(Express.js Node Web 应用)的 VM 日志。 在同一 bash shell 中,使用以下命令查看日志:
cat /var/log/pm2.log
日志包含来自本地计算机的调用。
grep "Hello world app listening on port 3000!" /var/log/pm2.log
该日志还包括传入 npm 启动脚本的环境变量(包括 ApplicationInsights 密钥)。 使用以下 grep 命令验证你的密钥是否在环境变量中。
grep APPINSIGHTS_INSTRUMENTATIONKEY /var/log/pm2.log
这会显示 PM2 日志,其中以不同的颜色突出显示
APPINSIGHTS_INSTRUMENTATIONKEY
。
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 日志。 最近的错误位于文件底部。 如果确定这些文件正确无误,请在 package.json 中使用 npm 脚本停止并启动 PM2。 |