NUTMEGの、のせ(市之瀬)です。 アドカレ2024の22日を担当します。
インターンを通して学んだIaCを最近NUTMEGでも作っていたので、NUTMEG内に宣伝する意味も込めてIaCについての解説と今回作った内容の紹介をします。
コードはこのリポジトリにあります。
IaCは「Infrastructure as Code」の略で、インフラの構成や設定をコードで管理することです。一昔前まで、サーバやネットワークの設定の管理は手動で行っていましたが。手動なためミスが起こりやすく、行う人の時間が奪われるデメリットがありました。インフラ構成をより早く、再現性のある形にするためにIaCという機能が生まれました。
コードで管理する恩恵として、以下の2つを挙げます。 今回作成したものは、「インフラ構成の一貫性の向上」を網羅します。
AWS、GCPなどのクラウドサービスのコンソール画面や、NUTMEGで使っているProxmoxのコンソール画面からもインフラを作ることはできます。しかし、何人がまったく同じ構成を作れるでしょうか、今あるインフラの構成を理解しているでしょうか。あまりいないのが正直なところだと思います。 インフラをコードで管理することで、完璧な再現性を作ることができます。これにより、急にインフラエンジニアが飛んでしまっても現状のインフラがどうなっているのか、どう作ればよいかの情報を最低限残すことができます。 私もあと1年でいなくなる立場なので、この気にIaCとしてインフラの情報を残そうと思って今回取り組みました。
現状のNUTMEGのデプロイは、インフラチームのメンバーがproxmoxの中のコンテナに訪れて最新版への更新を行うのが大半です。そのため、即座にデプロイできません。本番環境へ即座に反映できないのはアプリの開発を行う上で非常に面倒です。
インフラがコード化できていれば、この作業は人間以外にもやってもらうことができます。いわゆるDevOpsです。githubでMergeするだけで本番環境へアプリが反映させることができれば、開発効率の改善が行えます。 ここは今回の内容では網羅できていない部分なので、今後作るか、後輩が作ってくれるはずです。
今回IaCを行うために利用したものになります。terraformが行うのは、インフラ構成の中でもリソースの管理になります。そのため、先ほど述べていたメリットの「インフラ構成の一貫性の向上」を行うためのものになります。
「デプロイの高速化」をNUTMEGで行うためにはk8sを使う必要があるのですが・・・長くなるので完成したときにでもまたブログにしようと思います。
今回は、NUTMEGクラウドで使用しているバージョンのインストール方法を載せておきます。
macOSの場合
brew install tfenv
tfenv install 1.10.0
tfenv use 1.10.0
windows(WSL)の場合
このサイトのコピペなので失敗したらごめんなさい
git clone <https://github.com/tfutils/tfenv.git> ~/.tfenv
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
tfenv install 1.10.0
tfenv use 1.10.0
確認
terraform -v
以下のようにでるはずです。
Terraform v1.10.0
on darwin_arm64
Your version of Terraform is out of date! The latest version
is 1.10.1. You can update by downloading from <https://www.terraform.io/downloads.html>
ここでは最低限の使い方を紹介します。NUTMEG用のものはMakefileを作ってあるので、そちらを使ってください。
terraform init
リポジトリをterraform用に初期化するための機能です。terraformにはproviderという概念があり、それに応じて必要なファイルを取得します。NUTMEGではproxmox 3.0.1-rc5を利用しています。基本、このページを見ながら機能を追加しています。
terraform plan
作成したterraformのファイルが行う変更差分を出力します。ポイントは、変更差分を出力するのみで、実際に変更自体は行われないことです。
terraform apply
planとは異なり、実際に変更まで行う機能です。作成したterraformのコードで実際にリソースを作成することができます。
terraform destroy
作成していたリソースを削除するための機能です。
今回開発した内容は、NUTMEGサーバと呼ばれるproxmoxを利用しているサーバで、terraformを利用してコンテナ(以降LXC)、バーチャルマシン(以降VM)を作成するための機能です。これを利用することで、誰でも簡単にNUTMEGサーバでインフラを用意することができます。
今回は、特に利用が多いであろうLXCについて紹介していきます。
以下のディレクトリ構成になっています。
.
├── Makefile
├── README.md
├── envs
│ └── group-manager-2
│ ├── lxc
│ ├── main.tf
│ ├── terraform.tfstate
│ ├── terraform.tfvars
│ └── variables.tf
├── modules
│ ├── lxc
│ │ ├── main.tf
│ │ └── provider.tf
│ └── vm
│ ├── main.tf
│ └── provider.tf
└── template
├── lxc
│ ├── main.tf
│ ├── terraform.tfvars
│ └── variables.tf
└── vm
├── main.tf
├── terraform.tfvars
└── variables.tf
それぞれのファイルが何を行うのか解説します。
modules/lxc/main.tf
variable "settings" {
type = map(object({
vmid = number
target_node = string
hostname = string
ssh_keys = list(string)
template = string
cores = number
memory = number
swap = number
disk_size = string
ip_address = string
}))
}
resource "proxmox_lxc" "basic" {
for_each = var.settings
vmid = each.value.vmid
target_node = each.value.target_node
hostname = each.value.hostname
ssh_public_keys = join("\n", each.value.ssh_keys)
ostemplate = "local:vztmpl/${each.value.template}.tar.zst"
cores = each.value.cores
memory = each.value.memory
swap = each.value.swap
unprivileged = true
rootfs {
storage = "local-lvm"
size = each.value.disk_size
}
network {
name = "eth0"
bridge = "vmbr0"
firewall = true
ip = "${each.value.ip_address}/24"
ip6 = "auto"
}
}
このファイルがlxcを作成するためのメインの機能になります。後述する変数ファイルから値を受け取り、その値を代入してリソースを作成します。 注目するべきは以下の行です。
resource "proxmox_lxc" "basic" {
今回利用しているproxmox 3.0.1-rc5では、以下の4つの機能があります。
その中でも、今回はlxcを作成するための機能であるをproxmox_lxc
利用していることが先ほどの行でわかります。作成する際や修正するときは以下のこちらの内容を読んでください。
modules/lxc/provider.tf
terraform {
required_providers {
proxmox = {
source = "telmate/proxmox"
version = "3.0.1-rc5"
}
}
}
provider "proxmox" {
pm_api_token_id = "hogehoge@pam!hoho-hoho"
pm_api_token_secret = "examplepmapitokensecret"
pm_api_url = "https://example_domain/api2/json"
pm_tls_insecure = true
}
このファイルはクレデンシャルファイルのためgithubには上がっていません。 NUTMEGのメンバーはsettingsリポジトリから取得して配置してください。
このファイルでは、前述したproviderの指定と、proxmoxへリソースを作るためのtoken情報を書き込みます。
template/lxc/main.tf
module "vm_module" {
source = "../../modules/lxc"
settings = var.settings
}
各環境を作成する際(terraform apply,plan)に、実際に実行されるファイルになります。 内容としては、変数ファイルから変数を受け取り、受け取った変数をmodulesのmain.tfに渡して呼び出しているだけです。
template/lxc/terraform.tfvars
settings = {
"vm1" = {
# 作成するVMのID
# 既存のVMと重複しないようにする
# 先頭はPVEのIDと同じにする
# 例:pveがpve02の場合、201,202,203...とする
vmid = xxx
# どのサーバに作成するかを指定する
# pve02~06のどれかを指定する
target_node = "pve0x"
# ディレクトリの名前と同じにする
hostname = "プロダクト名"
# SSHの公開鍵
# アクセスするPCの公開鍵をListに追加する
ssh_keys = [
"ssh-ed25519 sshed25519examplepublickey hoge@hoge",
]
# 基本的に固定
template = "ubuntu-24.04-standard_24.04-2_amd64"
# 基本的に固定
username = "nutmeg"
# CPUの数
cores = 1
# メモリのサイズ
memory = 1024
# スワップのサイズ
swap = 1024
# ディスクのサイズ
disk_size = "16G"
# IPアドレス
# /24なので、最後の数字を変える
ip_address = "192.168.1.xxx"
}
}
各環境ごとに設定する変数ファイルです。
各変数はコメントアウトの内容を読みながら設定してください。
この変数ファイルは、複数の環境を用意できます。なので、“vm1"のように"vm2"を用意すれば、一度に複数の環境を用意することができます。
基本は、make init
で用意されたこのファイルのみ編集することになります。
template/lxc/variables.tf
variable "settings" {
type = map(object({
vmid = number
target_node = string
hostname = string
ssh_keys = list(string)
template = string
cores = number
memory = number
swap = number
disk_size = string
ip_address = string
}))
description = "A map of VM settings"
}
上記で紹介した変数ファイルの値の型定義をしているファイルです。
今回は、新規で環境を作成したい場合の手順になります。
事前に、以下を満たす必要があります。
新規作成するためにtemplateから新たにディレクトリを用意します。以下のコマンドを実行してください。
# コンテナを作りたいとき
make init resource_type=lxc product=example
# VMを作りたいとき
make init resource_type=vm product=example
exampleにはプロダクト名や用途など、わかるように設定してください。 このコマンドが成功すると、envsディレクトリの中にexampleというディレクトリが用意され、必要なファイルが揃った状況になります。
/envs/example/terraform.tfvars
を修正します。
コメントを読みながら作成してください。
スペックに関する部分(cpu,cores,memory,swap,disksize)は相談しながら決めましょう。
下のコマンドを実行します。
make plan product=example
planはドライランなので、本当に実行した際に起きる差分を出してくれます。 この結果をPRやslackに貼り付けてインフラの誰かに見てもらってください。
male apply product=example
terraformで書いた変数の内容で「example」という環境が作成されます。 sshをしてアクセスしてみましょう。
なお、sshするにはproxmoxのサーバを利用して二段sshをする必要があります。以下の設定を各々の~/.ssh/config
に書き足してください。
Host pve01-nutmeg
HostName <tailscaleで割り当てられたIP>
User root
Host *.nutmeg
User nutmeg
IdentityFile ~/.ssh/id_ed25519
Host <好きな名前>.nutmeg
User root
HostName 192.168.1.xxx
ProxyJump pve01-nutmeg
今回はIaCについて、概要の説明と実際に作成例を紹介しました。 まだまだ完璧なインフラ構成には遠いですが、卒業するまでになるべく良くしていきたいです。