🍣

Azure CLI + VS Codeで作る検証用Webサーバ

2022/02/13に公開

はじめに

Azureで検証用のサーバ環境を構築する際、最初はAzure Portal上で構築すると思いますが、たまにしか利用しないAzure環境をずっと残しておくと、それなりの月額費用になってしまいます。そこで、Azure CLI + VS Codeを活用し、必要なときにVMを自動構築し、不要なときは必要最低限のディスク領域のみ保管しておく方法について、紹介します。

Terraformもどこかで公開したいな...と思いながら、勉強中です。

今回のサーバ構成

今回、構築するサーバ構成は以下の通りになります。Load BalancerやPublicIPは、SNAT(アウトバウンド規制)を利用するためにStandardを利用していますので、利用料金には注意してください。また、VM上で動かすDockerコンテナ(Web,DB,GitLabなど)の構築は省略していますので、過去の記事を参考にしてください。

Azure CLIでのサーバ構築

WSL上にAzure CLIをインストールし、以下のシェルを実行するだけで、今回のサーバ構成が5分程度で完了します。最初は、1つずつコマンドを実行しつつ、構築内容を確認しながら実行するのをお勧めします。

SSHを利用する際の鍵は、以下のコマンドで事前に作成してください。

$ ssh-keygen -t rsa -b 4096
azure_devops.sh
#!/bin/sh
# ドメイン名(被らないような名前に変更)
DOMAIN="XXXXXX"

# SSH, known_hosts削除
rm ~/.ssh/known_hosts

# リソースグループ作成
az group create \
  --name DevOpsRg \
  --location japaneast

# WEB用AGS作成
az network asg create \
  --resource-group DevOpsRg \
  --name DevOpsAgsWeb

# NGS作成
az network nsg create \
  --resource-group DevOpsRg \
  --name DevOpsNgs

## SSH用NGS規制を追加
az network nsg rule create \
  --resource-group DevOpsRg \
  --nsg-name DevOpsNgs \
  --name AllowSsh \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --priority 100 \
  --source-address-prefix Internet \
  --destination-port-range 22

## WEB用NGS規制を追加
az network nsg rule create \
  --resource-group DevOpsRg \
  --nsg-name DevOpsNgs \
  --name AllowWeb \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --priority 110 \
  --source-address-prefix Internet \
  --destination-port-range 8080 \
  --destination-asgs DevOpsAgsWeb

# 仮想ネットワーク作成
az network vnet create \
  --resource-group DevOpsRg \
  --name DevOpsVnet \
  --address-prefixes 10.0.0.0/16

## サブネット作成
az network vnet subnet create \
  --resource-group DevOpsRg \
  --vnet-name DevOpsVnet \
  --name DevOpsSubnet \
  --address-prefix 10.0.0.0/24 \
  --network-security-group DevOpsNgs

# SSHキー作成(公開鍵アップロード)
az sshkey create \
  --resource-group DevOpsRg \
  --name DevOpsSshKey \
  --public-key @$HOME/.ssh/id_rsa.pub

# ロードバランサ構築

## パブリックIPアドレス
az network public-ip create \
  --resource-group DevOpsRg \
  --name DevOpsPublicIp \
  --dns-name $DOMAIN \
  --version IPv4 \
  --allocation-method Static \
  --sku Standard \
  --zone 1

## ロードバランサ作成
az network lb create \
  --resource-group DevOpsRg \
  --name DevOpsLb \
  --sku Standard \
  --public-ip-address DevOpsPublicIp

### バックエンドプール追加
az network lb address-pool create \
  --resource-group DevOpsRg \
  --lb-name DevOpsLb \
  --name DevOpsLbPool \
  --vnet DevOpsVnet

### 送信NAT規制作成
az network lb outbound-rule create \
  --resource-group DevOpsRg \
  --lb-name DevOpsLb \
  --name DevOpsLbOutbound \
  --address-pool DevOpsLbPool \
  --protocol Tcp \
  --frontend-ip-configs LoadBalancerFrontEnd

# Webサーバ構築

## 受信NAT規則(SSH)作成
az network lb inbound-nat-rule create \
  --resource-group DevOpsRg \
  --lb-name DevOpsLb \
  --name DevOpsLbWebSsh \
  --protocol Tcp \
  --frontend-port 8001 \
  --backend-port 22

## 受信NAT規則(HTTP)作成
az network lb inbound-nat-rule create \
  --resource-group DevOpsRg \
  --lb-name DevOpsLb \
  --name DevOpsLbWebHttp \
  --protocol Tcp \
  --frontend-port 8080 \
  --backend-port 8080

## NIC作成
az network nic create \
  --resource-group DevOpsRg \
  --name DevOpsWebNic \
  --vnet-name DevOpsVnet \
  --subnet DevOpsSubnet \
  --lb-address-pools DevOpsLbPool \
  --lb-name DevOpsLb \
  --lb-inbound-nat-rules DevOpsLbWebSsh \
  --application-security-group DevOpsAgsWeb

az network nic ip-config inbound-nat-rule add \
  --resource-group DevOpsRg \
  --nic-name DevOpsWebNic \
  --lb-name DevOpsLb \
  --ip-config-name ipconfig1 \
  --inbound-nat-rule DevOpsLbWebHttp

## VM作成
az vm create \
  --resource-group DevOpsRg \
  --name DevOpsWeb \
  --image canonical:0001-com-ubuntu-server-focal:20_04-lts-gen2:latest \
  --admin-username azureuser \
  --ssh-key-name DevOpsSshKey \
  --priority Spot \
  --size Standard_D2as_v4 \
  --os-disk-name DevOpsWebOsDisk \
  --storage-sku StandardSSD_LRS \
  --public-ip-sku Basic \
  --nics DevOpsWebNic

# DB用VM構築

## 受信NAT規則(SSH)作成
az network lb inbound-nat-rule create \
  --resource-group DevOpsRg \
  --lb-name DevOpsLb \
  --name DevOpsLbDbSsh \
  --protocol Tcp \
  --frontend-port 8002 \
  --backend-port 22

## NIC作成
az network nic create \
  --resource-group DevOpsRg \
  --name DevOpsDbNic \
  --vnet-name DevOpsVnet \
  --subnet DevOpsSubnet \
  --lb-address-pools DevOpsLbPool \
  --lb-name DevOpsLb \
  --lb-inbound-nat-rules DevOpsLbDbSsh

## VM作成
az vm create \
  --resource-group DevOpsRg \
  --name DevOpsDb \
  --image canonical:0001-com-ubuntu-server-focal:20_04-lts-gen2:latest \
  --admin-username azureuser \
  --ssh-key-name DevOpsSshKey \
  --priority Spot \
  --size Standard_D2as_v4 \
  --os-disk-name DevOpsDbOsDisk \
  --storage-sku StandardSSD_LRS \
  --public-ip-sku Basic \
  --nics DevOpsDbNic

  • ネットワークについて

    • 実際の運用では、VPN GatewayやBastionを選択するべきだが、コスト重視でLB経由のSSH接続にした。
    • インバウンドNAT規制を利用すると、1つのPublicIPで複数サーバへの接続が可能になる。NGSのPort許可も忘れずに。
    • アウトバウンドNAT規制(SNAT)を利用すると、PublicIPを持たない複数サーバでもInternetでの接続が可能になる。
  • VMについて

    • OSイメージは、WSL2と同じUbuntu20.4を選択。通常(az vm image list --output table)だと18.4が選択されるため、Azure Portal上でVM構築し、「パブリッシャー:オファー:プラン:latest」を指定する。
    • Spotインスタンスで構築すると、80%のコスト削減ができる。
    • OSディスクは、デフォルトではPremiumSSDが選択されるが、128G未満の場合、IOPSなどを比較すると、StandardSSDのほうが早いかも。参考記事

追加パッケージの自動インストール

サーバ構築後、ssh経由で自動的に追加パッケージをインストールする場合、Install用のシェルを用意し、以下のコマンド追加することで、自動インストールできます。更に、docker-compose.ymlでコンテナを実行する場合は、scpコマンドを利用します。

ここでは、Dockerを自動インストールし、Webサーバに対して、httpdを自動実行する手順を紹介します。これにより、http://XXXXXX.japaneast.cloudapp.azure.com:8080 で「It works!」が表示されるはずです。

# Dockerインストール
ssh -p 8001 -oStrictHostKeyChecking=no azureuser@XXXXXX.japaneast.cloudapp.azure.com sh < dockerInstall.sh
ssh -p 8002 -oStrictHostKeyChecking=no azureuser@XXXXXX.japaneast.cloudapp.azure.com sh < dockerInstall.sh
# httpd起動
scp -P 8001 docker-compose.yml azureuser@XXXXXX.japaneast.cloudapp.azure.com:~
ssh -p 8001 azureuser@XXXXXX.japaneast.cloudapp.azure.com docker-compose up -d

※ -oStrictHostKeyChecking=noを付与すると、y/nが聞かれずに~/.ssh/known_hostsに追加される。2回目以降は不要。

DockerInstall.sh
#!/bin/sh
# Set up the repository
sudo apt-get update
sudo apt-get -y install \
  ca-certificates \
  curl \
  gnupg \
  lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install docker engine
sudo apt-get update
sudo apt-get -y install docker-ce docker-ce-cli containerd.io
# Install docker compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# Add docker group
sudo gpasswd -a $USER docker
sudo service docker start
sudo chmod 666 /var/run/docker.sock
docker-compose.yml
version: '3'
services:
  httpd:
    image: httpd:latest
    ports:
      - 8080:80

VS CodeでのRemote SSH接続

VS Codeの拡張機能、Remote SSHを利用して、作成したサーバに対してSSH接続を行います。昔のリモート接続はTeraTermが主流でしたが、Remote SSHを利用すると、SSH経由でファイルやDocker, DBの操作がGUIでできるようになります。

  1. WSLで作成した秘密鍵をCドライブにコピーする。(Remote SSHは、Cドライブを参照するため)
\\wsl$\Ubuntu\home\<ユーザ名>\.ssh\id_rsa
↓
C:\Users\<ユーザ名>\.ssh\
  1. サイドバーにあるリモート エクスプローラで、プルダウンをSSH Targetsに変更する。
  2. SSH TARGETSで+ボタンを押し、以下のコマンドでSSH接続できるか確認する。PORTは8001がWEB, 8002がDBとなる。
ssh -p 8001 azureuser@XXXXXX.japaneast.cloudapp.azure.com
  1. SSH TARGETSで設定ファイルを開き、ホスト名を修正する。
config
Host web
  HostName XXXXXX.japaneast.cloudapp.azure.com
  Port 8001
  StrictHostKeyChecking no
  User azureuser
Host db
  HostName XXXXXX.japaneast.cloudapp.azure.com
  Port 8002
  StrictHostKeyChecking no
  User azureuser

※VMを再作成した場合、接続エラーになるので、StrictHostKeyChecking noを追加。

データ保存方法

検証で作成したデータを保存したい場合は、追加ディスクを作成し、全リソース削除時に削除されないようにロックを行う。その後、対象のVM上でパーティション分割およびマウント設定を行う。

# ディスク追加
az vm disk attach \
  --resource-group DevOpsRg \
  --vm-name DevOpsDb \
  --name DevOpsDbDisk \
  --sku StandardSSD_LRS \
  --new \
  --size-gb 10

# 追加したディスクが削除できないようにロック作成
# az resource list --location japaneast --output tableでリソース確認。
az lock create \
  --resource-group DevOpsRg \
  --name DevOpsDbDiskLock \
  --lock-type CanNotDelete \
  --resource-type Microsoft.Compute/disks \
  --resource DevOpsDbDisk
# ディスク確認
lsblk
# パーティション分割(初回のみ)
sudo parted /dev/sdc --script mklabel gpt mkpart xfs 0% 100%
sudo mkfs.xfs /dev/sdc1
sudo partprobe /dev/sdc1
# マウント
sudo mount /dev/sdc1 /mnt/disk

全リソース削除

単純に全リソースを削除する場合は、以下のコマンドを実行します。もし、ロックしたリソースがある場合は削除ができないので、az resource deleteで1つずつ削除するしかなさそうです。他にもいい方法がないかは、引き続き調査中です。

$ az group delete --name DevOpsRg

おわりに

AzureでIaaSベースのWebサーバを構築する際の手順について、今回は紹介しました。以前、紹介したgitlabも同じようにVMで構築できるので、その際の参考資料になればと思います。

Discussion