🎄

TerraformでConoHaのインスタンスを手軽に管理する

2023/12/16に公開

この投稿はConoHa Advent Calendar 2023の15日目の参加記事です.

あいさつ

ConoHa10周年おめでとうございます!
壁紙も設定させていただきました(かわいい)

はじめに

さて,ConoHaの特徴の一つとしてOpenStack準拠APIを提供してくれているのですが,これを使うことでTeraformでお手軽にサーバーを管理できます.
できることは知っていたのですが今まで試したことがなかったので,今回はTerraformを使ってインスタンスを管理してみました.

前準備

まずはConoHaのアカウントを作成してAPI情報を取得します.
ConoHaのコンソールに移動します.

この状態で,「+ユーザー」をクリックして任意のパスワードしてAPIで利用するユーザーを作成します.
この画面で表示される情報のうち,

  • テナントID
  • Compute Serviceのエンドポイント
  • Identity Serviceのエンドポイント
  • APIユーザーのユーザー名
    の4つをメモしておきます.

利用できるImageとFlavorの確認

APIを利用して利用できるImageとFlavorを確認します.OpenStackでは,IMageとFlavorと呼ばれる仮想マシンのテンプレートの基づいてインスタンスを立てます.
ImageはUbuntu 22.04などの仮想マシンイメージのことで,Flavorは立てる仮想マシンのスペック(メモリ1GB,CPU2Core,SSD100GBなど)です.
利用できるオプションは,Web上のコンソールで見えるものと同じです.

ImageとFlavorを確認するためにはConoHa APIを叩きます.ドキュメントに詳しい仕様が書いてあります.

まずは各種APIを叩くために必要なTokenを取得します.公式ドキュメントに手順が載ってるので参考にしましょう!
ここでは,以下のスクリプトを実行してあげると,API_TOKENという環境変数にトークンが入ります.
[Identity Serviceのエンドポイント]などは先ほどメモリしておいた値に適宜置き換えてください.

AUTH_URL=[Identity Serviceのエンドポイント]
COMPUTE_URL=[Compute Serviceのエンドポイント]
TENANT_ID=[テナントID]
API_TOKEN=`curl -X POST \
-H "Accept: application/json" \
-d '{ "auth": { "passwordCredentials": { "username": "[APIユーザーのユーザー名]", "password": "[APIユーザーのパスワード]" }, "tenantId": "[テナントID]" } }'  \
"${AUTH_URL}/tokens" \
| jq ".access.token.id"  \
| sed 's/"//g'`

echo $API_TOKENしてみるとAPI Tokenが入っていると思います.
まずは,imageを取得してみます.

curl -X GET \
-H 'Content-Type: application/json' \
-H "Accept: application/json" \
-H "X-Auth-Token:${API_TOKEN}" \
"${COMPUTE_URL}/images" \
| jq ".images | sort_by(.name) | map(.name)" 

以下のような感じで色々なリストが取得できます.

[
  ~~~
  "vmi-ubuntu-20.04-amd64-100gb",
  "vmi-ubuntu-20.04-amd64-30gb",
  "vmi-ubuntu-22.04-amd64-100gb",
  "vmi-ubuntu-22.04-amd64-30gb",
  ~~~
]

今回は、vmi-ubuntu-22.04-amd64-30gbのImageを選択しました.
次に,Flavorを取得します.

curl -X GET \
-H 'Content-Type: application/json' \
-H "Accept: application/json" \
-H "X-Auth-Token:${API_TOKEN}" \
"${COMPUTE_URL}/flavors" \
| jq ".flavors | sort_by(.name) | map(.name)"

次のような感じで取得できます.

[
  "g-c12m32d100",
  "g-c1m512d30",
  "g-c24m64d100",
  "g-c2m1d100",
  "g-c3m2d100",
  "g-c4m4d100",
  "g-c6m8d100",
  "g-c8m16d100"
]

おそらくg-c[コア数]m[メモリ容量]d[ディスク容量]のような命名規則になっている気がします.
Ubuntu 22.04を使うためにはメモリが1GB以上必要なようだったので,今回はg-c2m1d100(2Core メモリ1GB ディスク100GB)を選択しました.

TerraformによるDeploy

今回はハンズオンを想定して参加者分のインスタンスを用意するという場合を想定したTerraformの定義を用意しました.

# Define required providers
terraform {
  required_version = ">= 0.14.0"
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "~> 1.52.0"
    }
  }
}

# 作成する参加者ユーザーリスト
locals {
  users = [
    "alice",
    "mike",
    "k1h"
  ]
}

provider "openstack" {
  user_name = "[APIユーザーのユーザー名]"
  password  = "[APIユーザーのパスワード]"
  tenant_id = "[テナントID]"
  auth_url  = "[Identity Serviceのエンドポイント]"
}

resource "openstack_compute_keypair_v2" "keypair" {
  name       = "master-keypair"
  public_key = "[rootログインに利用する公開鍵]"
}

resource "openstack_compute_instance_v2" "vm" {
  for_each        = toset(local.users)
  name            = "handson-vm-${each.value}"
  image_name      = "vmi-ubuntu-22.04-amd64-30gb" # 利用するImage
  flavor_name     = "g-c2m1d100" # 利用するFlabvor
  key_pair        = "master-keypair"
  security_groups = ["gncs-ipv4-ssh"] # SSH用に22ポートを公開する
  user_data       = filebase64("./cloud-config.yml")

  metadata = {
    instance_name_tag = "handson-vm-${each.value}"
  }
}

また,今回は参加者ユーザーの作成などをあらかじめ自動化するためcloud-configのファイルも作成しました.

#cloud-config
package_update: true
package_upgrade: true
ssh_pwauth: True
users:
  - default
  - name: student
    groups: wheel,adm,systemd-journal
    sudo: ["ALL=(ALL) NOPASSWD:ALL"]
    shell: /bin/bash
chpasswd:
  list: |
    student:password
  expire: False

また,今回はTerraform v1.6.6を利用しました.

定義ファイルを適当なファイルに設定した上で,

terraform init

を実行して初期化してあげます.
次に,

terraform plan

すると新しくデプロイされるリソースの差分が表示されるのでエラーがないか確認しましょう.
問題なければ,

terraform apply

すると確認が出るのでyesとタイプします.

openstack_compute_keypair_v2.keypair: Creating...
openstack_compute_instance_v2.vm["mike"]: Creating...
openstack_compute_instance_v2.vm["alice"]: Creating...
openstack_compute_instance_v2.vm["k1h"]: Creating...
openstack_compute_keypair_v2.keypair: Creation complete after 1s [id=master-keypair]
openstack_compute_instance_v2.vm["mike"]: Still creating... [10s elapsed]
openstack_compute_instance_v2.vm["alice"]: Still creating... [10s elapsed]
openstack_compute_instance_v2.vm["k1h"]: Still creating... [10s elapsed]

こんな感じのログが出てデプロイが開始されます.
コンソールでも構築中になってますね!

最後にApply complete! Resources: 4 added, 0 changed, 0 destroyed.と表示されればデプロイ完了です.

動作確認

デプロイが完了したインスタンスはterraform showコマンドを利用して設定されたグローバルIPアドレスなどを確認することができます.
以下のようなコマンドを実行してあげると,

terraform show -json | jq '.values.root_module.resources[] | select(.type == "openstack_compute_instance_v2") | {name: .index, ip: .values.access_ip_v4}'

ユーザーごとのインスタンスのIPアドレスを確認できますね.

{
  "name": "alice",
  "ip": "157.7.200.224"
}
{
  "name": "k1h",
  "ip": "157.7.85.118"
}
{
  "name": "mike",
  "ip": "157.7.89.17"
}

試しに,aliceさんのインスタンスにrootとしてログインしてみます.

ssh root@157.7.200.224

Terraformの定義ファイルに設定したSSH鍵でログインできるはずです.
次に,参加者としてログインします.

ssh student@157.7.200.224

パスワードはcloud-configで指定した,passwordでログインできます.
Terraformで定義ファイルを書いておけば,参加者がいくら増えても僅か数分のうちにインスタンスを用意することができて非常に便利ですね!

リソースの削除

ConoHaは「利用時間に応じた従量課金」なので,ハンズオンなどで利用する時も講習中だけの料金しかかかりません.
複数のWebコンソールでインスタンスを作ると,1つづつ消していくのは面倒ですがTerraformでDeployしておけば削除も一発でできます!

terraform destroy

コマンドを実行するとDeploy時と同じく確認されるのでyesを入力します.
以下のようにログが出てDestroy complete!すればOKです.

openstack_compute_keypair_v2.keypair: Destroying... [id=master-keypair]
openstack_compute_instance_v2.vm["k1h"]: Destroying... [id=6b5796ef-a23c-41e7-9742-f843d3cb2258]
openstack_compute_instance_v2.vm["alice"]: Destroying... [id=6b1f3eac-377f-4813-a551-c01c706004bd]
openstack_compute_instance_v2.vm["mike"]: Destroying... [id=28e64f77-f2ae-47aa-8165-eced7a514c5c]
openstack_compute_keypair_v2.keypair: Destruction complete after 1s
openstack_compute_instance_v2.vm["k1h"]: Still destroying... [id=6b5796ef-a23c-41e7-9742-f843d3cb2258, 10s elapsed]
openstack_compute_instance_v2.vm["mike"]: Still destroying... [id=28e64f77-f2ae-47aa-8165-eced7a514c5c, 10s elapsed]
openstack_compute_instance_v2.vm["alice"]: Still destroying... [id=6b1f3eac-377f-4813-a551-c01c706004bd, 10s elapsed]
openstack_compute_instance_v2.vm["mike"]: Destruction complete after 14s
openstack_compute_instance_v2.vm["k1h"]: Destruction complete after 14s
openstack_compute_instance_v2.vm["alice"]: Destruction complete after 14s

Destroy complete! Resources: 4 destroyed.

ちゃんと消えてますね

最後に

今回はConoHaのOpenStack APIとTerraformを利用してインスタンスのデプロイを試してみました.OpenStack互換なので情報も多く,思ったよりもすんなり動かすことができました.今回は間に合わなかったのですが,Ansibleと組み合わせてk8sクラスタを構築してみたりといったことも試してみたいなと思います.

参考にさせていただいたサイト

https://qiita.com/kaminchu/items/d0776c381213d54a3a69
https://blog.adachin.me/archives/10378

Discussion