在 Azure 重建 AWS 技能的一週:概念相同,名稱不同
Same Ideas, Different Names: A Week of Rebuilding My AWS Skills on Azure
作者在 Azure 重建 AWS 上的三層 Book Review 應用,指出雲端服務名稱和操作介面雖然不同,網絡分層、權限邊界及驗證方法等概念仍可沿用。過程中,他以逐段測試排查配置和連線問題,並用 Claude Code 技能執行唯讀雲端安全審核;修正設定則由人工處理。

Last week I built a highly available app on AWS. This week I did it again on Azure, and nothing carried over except the thinking. The names changed, the console changed, and the error messages changed. What stayed the same were the questions I had to ask: Where is the boundary? Who is allowed to talk to whom? What proves it works?
Here's what the week actually looked like, including the parts that didn't go to plan.
Part 1: Learning Azure's rules before building anything
My first real lesson came before a single resource existed. The portal's default VM size cost about $70 a month. The size the assignment asked for, a B1s, cost about $8. Then B1s showed as unavailable, first because of an availability zone setting, then because one region had no capacity for my subscription at all.
Instead of clicking through regions, I opened Cloud Shell and asked the CLI where B1s was allowed for my account. That became a habit all week: when the portal gives a vague error, query the platform directly.
Quotas were the next surprise. My subscription allowed only three public IPs per region, and leftovers from earlier work were silently using them up. A load balancer failed to create with a limit error until I deleted old resource groups. In the same cleanup I found a Bastion host I never meant to create, one that bills around $140 a month while sitting idle. Deleting a VM in Azure doesn't delete the IP, the network interface, the disk, or the Bastion. Resource groups exist for exactly this reason, and I now delete the whole group instead of hunting for pieces.
Part 2: The same three tiers, rebuilt
The main project was a three-tier Book Review app: a Next.js frontend behind Nginx, a Node/Express API, and a managed MySQL database, each in its own subnet.
- Web tier: a public Standard load balancer in front of one VM running Nginx and the frontend.
- App tier: a VM with no public IP, behind an internal load balancer. Outbound traffic goes through a NAT gateway, and I reached the VM only by jumping through the web server.
- Database tier: Azure Database for MySQL with private access, in a subnet with no internet route.
- Security: one NSG per subnet, so each tier accepts traffic from exactly one neighbour. Secrets belong in Key Vault, not in a config file on disk.
It mirrors what I built on AWS: security groups become NSGs, an ALB becomes a load balancer plus Nginx, and RDS becomes Flexible Server. Seeing the mapping made the concepts feel like mine and not just the console's.
Part 3: Debugging by walking the chain
Nearly every problem this week was solved the same way: test each hop in order and stop guessing.
- NAT gateway refused my public IP. The SKUs have to match. Creating a new IP with the right SKU fixed it.
-
The backend said "using password: NO". My database password started with
#, and a.envfile reads an unquoted#as the start of a comment. The value was empty. Wrapping it in quotes fixed it. -
PM2 wasn't surviving restarts.
pm2 startuponly prints a command, and it doesn't run it. I had saved the process list but never installed the service. -
The frontend called
/api/api/books. One line added/apion top of an environment variable that already contained it. The build bakes that value in, so the fix needed a rebuild. -
The page hung on "Loading books...". The frontend was fine and the API was fine, but every request through the internal load balancer timed out. I curled each hop from the web server in turn: the app VM directly worked, the load balancer didn't. The load balancer's frontend IP was
10.0.2.5, and my Nginx config pointed at10.0.2.50. One digit.
The assignment guide also contradicted itself in places, with port 5000 in some steps and 3001 in others, and an App route that was described one way and then corrected later. Reading instructions critically, instead of pasting them, saved me hours.
Part 4: Auditing my own cloud with Claude Code
The last assignment turned the lens on my own infrastructure. I wrote a read-only Bash script that checks four things: NSG rules open to the internet on SSH or RDP, storage accounts that allow public blob access, whether VM disks are encrypted at rest, and whether the MySQL server accepts public connections. It writes a PASS/WARN/FAIL report and returns a different exit code for each outcome.
Then I wrapped it in a Claude Code skill with a tool list of Bash, Read, and Grep, and deliberately no Write. Claude runs the audit, reads the report, explains the risk of each finding, and recommends a fix. It never runs the fix. That boundary is enforced by what the skill is allowed to do, not by asking it nicely.
I ran the remediation myself: restrict SSH to my own IP as a /32, then run the audit again and watch the finding turn from FAIL to PASS. Gather evidence, analyze it, let a human act, verify. A tool that can both find a misconfiguration and fix it unsupervised is one bad recommendation away from an outage, so keeping those jobs separate is what makes the recommendations trustworthy.
A small Windows lesson came with it: the Azure CLI on Git Bash adds hidden carriage returns to its text output, which made string comparisons in my script fail and report false warnings. Adding tr -d '\r' after each call fixed it, and the same script works on Linux.
What I'm taking away
Moving between clouds taught me more than staying in one would have. The vocabulary is a one-evening problem. The patterns are what matter: least-privilege network rules, private data tiers, secrets kept out of config files, health checks, and a human in the loop for anything that changes the account.
I also learned to treat cost as part of the design. Every NAT gateway, load balancer, and managed database in this stack bills by the day whether anyone uses it or not. The most important command of the week was the one at the end: delete the resource group.
P.S. This post is part of the DevOps Micro Internship (DMI) with Agentic AI, Cohort 3, by Pravin Mishra. You can follow my graded progress throughout the cohort. Start your DevOps journey: https://dmi.pravinmishra.com/?utm_source=student&utm_medium=ps-blog&utm_campaign=cohort3
DMIByPravinMishra #Azure #DevOps #AgenticAI
來源:DEV Community · dev.to