はじめてのAzure

みなさんこんにちは!6日担当のChihiroです。

まずは簡単に自己紹介をさせてください。
・文系学部に所属する大学1年生
・プログラミング経験ゼロから今年の4月にPlay Groundに参加
・データサイエンスコースを修了したばかり
・最近インターンでAzureを使った社内システム設計を始めた

ということで、今回のブログはインターンでの経験をもとに、初めてのAzureというテーマでお届けします!Play Groundに参加して約8か月、初めて自主的に取り組んだ内容をまとめてみましたので、是非ご覧ください!

ちなみに…
Zoomでのオンライン会議において録音した音声をもとに議事録を作成したり、それをアーカイブ動画と共にデータベース化し、チャットボットで呼び出せるようにすることを最終的には目指しています。
それはあくまで未来の目標で、現状はそこまで開発が進んでいません。
今回のブログは、今後開発していくにあたって必要になるであろうリソースをいくつかピックアップし、Terraformをもちいて作成を行うまでの工程までを取り扱うこととしており、本当に初歩段階までに絞った内容になっています。

ですのでクラウドサービスゼロ知識の方にも、というより「にこそ」ぜひ読んでいただきたい記事になっています…!


1. はじめに

Azureとは、Microsoftが提供するクラウドサービスのこと。
AWSやGoogle Cloudといった他のクラウドサービスと比較すると、Office 365製品(WordやExcelなど)との親和性が高いのが特長。ただし、日本語の学習コンテンツがやや少ないため、基本的には公式のMicrosoft Learnをメインに学習を進めていくこととなる。

クラウドサービスはオンプレミスに比べて柔軟性が高く、従量課金制であることにより初期投資額を抑えやすいなどのメリットがある。こうした理由から現在クラウドサービス自体が注目を集めていることに加え、まずは1つのクラウドサービスに触れてみることで他のクラウドサービス(AWSやGoogle Cloud)の理解もスムーズになるはずであるという考えから、今回はしっかりと「理解」することに重点を置きながら学習を進めた。

2. Azureの利用にあたっての準備

Azureを使うためには、ほぼすべてのリソース作成においてサブスクリプション契約が必要となる。
今回は、インターン先の企業がすでにサブスクリプション契約済みのMicrosoftアカウントを持っていたため、そのアカウントに権限を付与してもらい作業を進めた。自身で契約をしたわけではないことから、私自身の知識が不足しており、この記事では詳細な説明を省略する形とする。

3.Terraformとは?

<概要>

  • HashiCorp社によって開発されたインフラの設定をコードで管理するためのIaCツール
      - ※IaC = Infrastructure as Code

  • HCLという言語で定義を記述しインフラ構築をおこなうことができる 
      - ※HCL = HashiCorp Configration Language

  • AWSやMicrosoft Azure、Google Cloud Plattformなど様々なパブリッククラウドに対応

<利用価値 (CUI VS GUI)>

CUIツール(TerraformやAzureCLI)

リソース管理をするうえで、大規模管理の実現性を高め、スクリプト化により効率的な操作・再現性・自動化を可能とする

GUIツール(Azureポータル)

直感的で簡単に操作できるため、小規模で迅速な作業が可能となる

<利用価値 (Terraform VS Azure CLI)>

Terraform

大量のリソースの取扱やチーム運用が想定されたり再現性が重要視されたりする場合など、よりCUIの強みを生かしたい場合に適している

Azure CLI

手軽さとCUIならではの利点を兼ね備えたツールとしての利用価値がある

<基礎知識>

  • tfstateファイル [ Terraform 状態ファイル ]

    • 例)terraform.tfstate

    • Terraformで管理しているリソースの現状の構成を記録するためのJSON形式のファイルのこと( 拡張子は .tfstate)

    • 基本的に手動で変更を加えることは非推奨である

    • 保存先はローカルバックエンドorリモートバックエンド

      • ローカルバックエンド(default)

        • ローカル環境のterraformで実行した場合、tfstateファイルが自動的に生成され、デフォルトで保存先を実行時のカレントディレクトリに指定される(保存先の指定も可能)
        • 小規模なプロジェクトや個人使用に向いているが、複数人での運用には不向き
      • リモートバックエンド

        • terraformの設定ファイル(backendブロック)で設定変更を行い、保存先を指定する
        • 状態の共有やロック機能、バックアップの観点から大規模なチームプロジェクトなどに有利
        • 代表例
          • Amazon S3 + DynamoDB: AWS S3バケットに状態ファイルを保存し、DynamoDBでロックを管理
          • Azure Blob Storage: AzureのBlob Storageに状態ファイルを保存
          • Google Cloud Storage: GCPのCloud Storageに状態ファイルを保存
          • Terraform Cloud/Enterprise: HashiCorpが提供する専用のTerraform管理サービスで、状態管理やロック機能を提供
  • tfファイル [ Terraform 設定ファイル ]

    • 例)main.tf / variables.tf / outputs.tf
    • インフラのリソース定義や設定が書かれたファイルのこと( 拡張子は .tf)
    • 仮想マシン、ネットワーク、データベースなど、インフラの各リソースがどのように構成されるべきか、またはどう変更すべきかを手動で記述していく
  • Terraformにおけるリソース管理

    • Terraformを用いてAzureリソースで作成し管理する場合 ☑今回はこちらを扱う

      作成段階

      1. tfファイルを作成しコードを書くことによりリソースを定義する
      2. それらを適用(terraform apply)することでクラウド上でのリソースの払い出しが完了する

      ※2の段階でtfstateファイルが自動的に生成される

      管理段階

      1. terraformコマンドで管理を行う
    • GUI(例・Azureポータル)で作成したAzureリソースをTerraformで管理したい場合

      作成段階

      1. Azureポータル上でリソースを作成

      管理段階

      1. terraform importをすることにより、リソースをTerraformの管理下に置く

      ※1の段階でtfstateファイルが自動的に生成される

      2. terraformコマンドで管理を行う

4.リソース作成に向けた準備

―操作環境―
Windows PC 使用 (Ubuntu,WSLをインストール済み)
Ubuntu上ですべての操作を行った

ファイルの作成

  • 以下の構築例を参考にファイルを作成する

  • 詳細
    • Azure(プロジェクトのルートディレクトリ)

      • このディレクトリは、Terraformプロジェクト全体の管理を行う
      • 主に、プロジェクト全体の設定や共通設定を定義する場所
    • main.tf

      • 主要なリソース設定を記述するファイル
      • 一般的にはリソースのプロバイダ設定や子モジュールを参照したリソースの作成を行う
    • output.tf

      • リソース作成時の出力値を決める
      • 子モジュールの出力値を参照することも可能
    • modules(モジュールディレクトリ)

      • modulesディレクトリ内には、再利用可能なリソースの構成が含まれているため、異なるインフラのリソースを繰り返し使えるようにすることが可能となる
      • モジュールは、特定のリソースや関連リソースの構成を独立して管理できるため、プロジェクト全体の管理が容易になる
    • <リソース名>(子モジュール)

      • main.tf:
        • このファイルでTerraformリソースを定義する
        • 例)Azure Storage Accountや関連するリソースを作成するコードが含まれる
      • variables.tf:
        • 必要なパラメータ(名前、リソースグループ、リージョンなど)を変数として定義する
        • このファイルで変数の型やデフォルト値などを指定することもある
      • output.tf:
        • 作成するリソースに関連する出力値を定義する
        • 例えば、リソースの名前や、作成したリソースのURLなどを出力値として定義し、他のリソースで参照できるようにするなどがあげられる

Terraformのセッティング

  1. terraformのインストール

    • APTリポジトリのTerraformに対応するGPG公開鍵をダウンロードし、バイナリ形式に変換したうえで、公開鍵自体をシステムに保存

      wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
      
      • 詳細
        • wgetコマンドはURLからデータをダウンロードするものであり、ここではHashiCorpのAPTリポジトリのGPG鍵(公開鍵)をダウンロードしている
        • -O -オプションは、ダウンロードしたデータを標準出力(-)に送るように指示している
        • |(パイプ)は、前のコマンドの出力を次のコマンドの入力として渡すために使う
        • gpg --dearmorは、ダウンロードしたGPG鍵(通常はASCII形式)をバイナリ形式(=コンピュータが直接処理できる2進数のデータ形式)に変換するコマンドである
        • o /usr/share/keyrings/hashicorp-archive-keyring.gpgは、変換した鍵を指定した場所に保存するものであり、この場所はAPTパッケージマネージャーがリポジトリを認証するために使用される
    • 公開鍵を用いたAPTパッケージマネージャーによるレポジトリの正当性検証を行ったうえで、TerraformのAPTリポジトリの位置を示す文字列をファイルに書き込む

      echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] [https://apt.releases.hashicorp.com](https://apt.releases.hashicorp.com/) $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
      
      • 詳細
        • echoコマンドは、指定した文字列を出力するものであり、ここではHashiCorpのAPTリポジトリを指定する行を作成している

        • $(lsb_release -cs)は、現在使用しているUbuntuのコードネームを取得するための記述であり、これにより、リポジトリが適切なUbuntuバージョンに対応するようになる

        • debは、Debianベースのディストリビューション用のAPTリポジトリ形式を示す

        • [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg]は、先ほどダウンロードしたGPG鍵を使用し、https://apt.releases.hashicorp.comにアクセスすることを示している

          • GPG鍵を使用してレポジトリにアクセスする際に、パッケージ自体をダウンロードする前後でGPG署名の検証を行う
          • 署名が無効だった場合、APTはそのリポジトリを信用せず、パッケージのダウンロードやインストールを中止する
          • 署名が有効であれば、ダウンロードしたパッケージがHashiCorp公式によるもので、改ざんされていないことを保証できる
        • sudo tee /etc/apt/sources.list.d/hashicorp.listは、先ほどのechoコマンドの出力を/etc/apt/sources.list.d/hashicorp.listというファイルに書き込むことを示し、このファイルにHashiCorpのAPTリポジトリの設定が追加される

    • terraformのインストール

      sudo apt update && sudo apt install terraform
      
      • 詳細
        • sudo apt updateは、パッケージリストを最新の状態に更新する
        • sudo apt install terraformは、APTは事前に追加していたHashiCorpのリポジトリからTerraformをインストールすることを示す
    • インストールしたterraformのバージョン確認(確認できたら完了)
      terraform -v

  2. terraformのPathを通す

    • which terraformコマンドを用いて、terraformのインストール位置を把握する

      • 典型例
        • /usr/local/bin/terraform → パッケージ管理システムが配置した場合の典型
        • /usr/bin/terraform    → デフォルトのシステムパスに配置された場合
    • 新規でPathを追加する

      • 基本的にはインストール位置を調べた段階(先述)の結果をもとに入力する
      • ただし、/usr/local/bin/terraform/usr/bin/terraform などといった、デフォルトの実行可能パスディレクトリに配置されている場合、環境変数PATHに特に表示されなくても動作することがある

Azure CLIのインストール

※Terraformを使用するにあたって必須ではない作業ではあるものの、併用による利便性の観点からこちらに記述しておく

  • 理想的な使い分け
    • Azure CLIは即時的な操作や手動作業に便利であるため、以下の場合に有用
      • Terraformの適用が重い場合
      • 単純なタスク(例・既存リソースの確認/一時的な設定変更等
        )を素早く実行したい場合
  1. Azure CLI のインストール

    • 基本的にはTerraformのインストール手順と同様

    • APTリポジトリのAzure CLIに対応するGPG公開鍵をダウンロードし、システムに保存

      curl -sL https://packages.microsoft.com/keys/microsoft.asc | sudo gpg --dearmor -o /usr/share/keyrings/microsoft-archive-keyring.gpg
      
    • Azure CLIのAPTリポジトリの位置を示す文字列をファイルに書き込む

      echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
      
    • パッケージリストを更新し、Azure CLIをインストールする

      sudo apt update && sudo apt install azure-cli
      
    • インストールしたazure-cliのバージョン確認(確認できたら完了)
      az -version

  2. Azure CLI のPathを通す

    • こちらも基本的にはTerraformのパス申請と同様である
    • which azコマンドを用いて、azure-cli のインストール位置を把握する
    • 新規でPathを追加する

Azureへのログイン

  1. テナントIDをAzureポータルから取得
    ポータルの設定画面から、「ディレクトリID」として表記されているものをコピーする

  2. ターミナル上でAzureにログイン ※Azure CLIを用いたログインをする
    az login --tenant <テナントID>

    • 詳細
      テナントIDの指定が必要な理由は?
      • az loginだけで実行すると、下記の理由でサブスクリプションが認識されないことがある為
      • 自身のアカウントが直接サブスクリプションに紐づけられていない状態で会社からテナントへのアクセス権だけを与えられている場合、最初にログインした時点ではそのアカウントがサブスクリプションに関連付けられていないため、サブスクリプションが表示されないことがある

5. 各リソースの作成

実際のファイル構造は以下の通り

カレントディレクトリ:Azure

上記のようなファイル構造を仮定し"storage_account""storage_container""cognitive_account"の作成を目指す
※以下、任意の値である場合は*/*で囲まれて表記されている

<1> main.tf

provider "azurerm" {
features {}
subscription_id = "*00000000*"   #サブスクリプションID
}
  • Azure RM (リソースマネージャー) プロバイダーを設定している
    • subscription_id では、利用する Azure サブスクリプションの ID を指定する
    • features では、プロバイダーの追加機能に関する設定をするが、空の {} を渡すことでデフォルトのままで使用することとなる
resource "azurerm_resource_group" "*testtest1*" {
name     = "*rg-testtest-dev-066*"
location = "*Japan East*"
}
  • リソースグループを作成している
    • リソースグループとは、Azure内のリソースをグループ化するための単位のこと
    • azurerm_resource_group.*testtest1* で参照可能になるように設定している
      • azurerm_resource_groupはリソースタイプを示す
      • *testtest1*はリソースの識別子を示す
    • name: リソースグループの名前を命名する
      - 命名規則を参照すること
    • location: Azure のリージョン (ここでは Japan East)
module "storage_account" {
source                = "./modules/storage_account"  # 子モジュールのパス
resource_group_name   = azurerm_resource_group.*testtest1*.name
location              = azurerm_resource_group.*testtest1*.location
storage_account_name  = "*sttest001*"
}
  • ストレージアカウントを管理するモジュールを呼び出している
    • Azureのデータストレージ機能を提供する基本的なリソースのこと
    • source: モジュールのパス (ローカルの modules/storage_account ディレクトリを指定)
    • resource_group_name /location: 先に作成したリソースグループの情報を獲得し、子モジュール内で使用される変数”resource_group_name”と”location”に代入する
    • storage_account_name: ストレージアカウントの名前を指定し、モジュール内で使用される変数”storage_account_name”に代入する
    • 本来指定すべきパラメータはリソースグループの定義を行った際と同様にnameであるが、わかりやすくするためにstorage_account_nameという名前の変数を介しており、子モジュール内でしっかりとnameを定義しているので問題ない
module "storage_container" {
source                 = "./modules/storage_container"
storage_account_name   = "*sttest001*"
storage_container_name = "*containertest1*"
}
  • コンテナを管理するモジュールを呼び出している
    • ストレージアカウント内でデータを整理するための単位のこと
    • source: モジュールのパス (ローカルの modules/storage_container ディレクトリを指定)
    • storage_account_name: 特定のストレージアカウントを参照するために、子モジュール内で使用される変数storage_account_nameに実際の名前を代入する
    • storage_container_name: コンテナの名前を指定し、モジュール内で使用される変数”storage_container_name”に代入する
    • ストレージアカウントの参照によって、先に作成したリソースグループの情報を情報(resource_group_name,location等)はすでに獲得した状態になるため、記述は不要
module "cognitive_account" {
source                   = "./modules/cognitive_account"
resource_group_name      = azurerm_resource_group.*testtest1*.name
location                 = azurerm_resource_group.*testtest1*.location
cognitive_account_name  = "*speech_servicetest1*"
}
  • Azure Cognitive Servicesアカウントを作成するリソースを管理するモジュールを呼び出している
  • Azure Cognitive Servicesは、機械学習を活用したAIサービスの集合体で、自然言語処理、音声認識、画像分析、翻訳などを簡単に利用できるようにするサービスのこと
  • 今回は中でも音声認識のサービスを活用する
    • ※他のリソースと同様の手順で定義していく

<2> output.tf

output "*storage_account_name*" {
value = module.storage_account.child_storage_account_name
}
output "*storage_container_name*" {
value = module.storage_container.child_storage_container_name
}
output  "*congnitive_account_name*" {
value = module.cognitive_account.child_cognitive_account_name
}
  • value: 子モジュールが出力した値を取得して、最終的な出力値を定める

<3> main.tf (modules/storage_account)

resource "azurerm_storage_account" "*example*" {
name  = var.storage_account_name
location = var.location
resource_group_name  = var.resource_group_name
account_tier = "*Standard*"
account_replication_type  = "*LRS*"
}
  • 主要パラメータ5つを定義している(上3つは変数を用いた定義)
  • account_tier
    • "Standard": コスト最適化向け(ほとんどの用途で適用可能)
    • "Premium": 高パフォーマンスを求める場合
  • account_replication_type
    • "LRS": コスト重視のローカル冗長性
    • "ZRS": ゾーンレベルで高可用性が必要な場合
    • "GRS": 地理的にデータを冗長化し、災害対策を重視
    • "RA-GRS": GRSに加えてデータの読み取りアクセスが必要な場合

<4> variables.tf (modules/storage_account)

variable "resource_group_name" {
description = "*The name of the resource group*"
type        = string
}
variable "location" {
description = "*The Azure region to create the resource in*"
type        = string
}
variable "storage_account_name" {
description = "*The name of the storage account*"
type        = string
}

<5> output.tf (modules/storage_account)

output "child_storage_account_name" {
value = azurerm_storage_account.example.name
}

<6> main.tf (modules/storage_container)

resource "azurerm_storage_container" "*example*" {
name = var.storage_container_name
storage_account_name  = var.storage_account_name
container_access_type = "*private*"
}
  • container_access_type
    • セキュリティ重視: 可能な限りprivateを使用
    • 限定公開: URL共有でアクセスさせたい場合はblobを使用
    • 完全公開: 全体を誰でも閲覧できるようにする場合はcontainerを使用

<7> variables.tf (modules/storage_container)

variable "storage_account_name" {
description = "*The name of the storage account*"
type        = string
}
variable "storage_container_name" {
description = "*The name of the storage container*"
type        = string
}

<8> output.tf (modules/storage_container)

output "*child_storage_container_name*" {
value = azurerm_storage_container.*example*.name
}

<9> main.tf (modules/cognitive_account)

resource "azurerm_cognitive_account" "*example*" {
name                = var.cognitive_account_name
location            = var.location
resource_group_name = var.resource_group_name
kind                = "*SpeechServices*"
sku_name            = "*F0*"
} 
  • sku_name: "F1"(無料プラン)、"B1"(ベーシック)、"P1"(プレミアム)
  • kind  : "SpeechServices"(音声認識)、"App"(Webアプリ)、"FunctionApp"(関数アプリ)

<10> variables.tf (modules/cognitive_account)

variable "resource_group_name" {
description = "*The name of the resource group*"
type        = string
}
variable "location" {
description = "*The Azure region to create the resource in*"
type        = string
}
`variable "cognitive_account_name" {
description = "*The name of the cognitive account*"
type        = string
}

<11> output.tf (modules/cognitive_account)

output "*child_cognitive_account_name*" {
value = azurerm_cognitive_account.*example*.name
}

ローカルでの作業をAzureに反映

<1>~<11>までtfファイルの作成が完了したら、以下の操作を行う

terraform init  #プロジェクトの初期化
terraform plan  #実行計画を作成
terraform apply #実行

ここまでお読みいただいた方々、ありがとうございました…!
次回は、@taku07200さんの記事です。お楽しみに!