GitHubからJenkinsとTerraformを使って仮想マシンをデプロイしてみた
2021年12月17日 金曜日
CONTENTS
【IIJ 2021 TECHアドベントカレンダー 12/18(土)の記事です】
あいさつ
こんにちは、IIJの韮塚(にらづか)です。
私は基盤エンジニアリング本部 基盤技術部に所属しており、普段は「サービス基盤運用の自動化」や「社内GitHubやCI/CDツールの管理人」を行っています。
みなさん、仮想マシン(以下VM)払い出しの自動化は進んでいますか?
VM払い出しにESXiのGUIにアクセスして、リソース払い出しを行っていませんか?
某クラウドベンダーのようにESXiに直接アクセスせずとも、必要な項目をポチポチ選択するだけでVMが払い出される理想の世界を作ってみませんか?
今回は、我が家で導入されているGitHubから直接ESXi上にVM(Virtual Machine)を払い出す方法を紹介します。
※本構成は私の自宅に設置してあるサーバ群の運用方法であり、IIJのサービス構成とは一切関係がございません。
モチベーション
今回VM払い出しをするにあたって以下のようなモチベーションで自動化に取り組みました。
- ユーザからVM払い出しを依頼されてVM払い出しに足りない項目をヒアリングをしながら構築するのが手間だし時間の無駄。
- よくあるのはIPアドレスやホスト名の指定
- フォーマットはユーザによってバラバラ
- 管理人としては払い出し操作はユーザにやってほしいけど、管理コンソールにユーザを自由にアクセスさせるわけにはいかない。
- 理想としては某クラウドベンダーのVPSみたいにユーザが自由にVMのスペックを決めてそのままデプロイできるようにしたい。管理者は承認ボタンを押すだけにしたい。
事前準備
使うツール(ハード)
- ESXiの入ったサーバ
- インターネット
使うツール(ソフト)
- Terraform(IaC構成管理ツール:https://www.terraform.io/)
- Jenkins(CI/CDツール:https://www.jenkins.io/)
- GitHub(バージョン管理ツール:https://github.com/)
- VMware ESXi(ベアメタルハイパーバイザー:https://www.vmware.com/jp/products/esxi-and-esx.html)
- Prometheus(メトリクス監視ツール:https://prometheus.io/)
- Grafana(メトリクス可視化ツール:https://grafana.com/)
※ 自宅のDCは商用利用を行っていないためすべて無償ライセンスの範囲で行っています。
構成
GitHub更新からVMデプロイまでの簡単な流れ
- ユーザはデプロイ先サーバのリソースをGrafanaで見ながら、自分たちが建てたいVMのスペックを決定する
- 決まったスペックに沿って構築したいサーバ情報をGitHubから入力し、ユーザから管理人に対してPullRequestを投げる
- 管理人はリソースに問題が無いかをGrafanaを見ながら判断し、問題なければPullRequestを承認する
- PullRequestが承認され、mergeされたことをWebhookとしてGitHubがJenkinsに対して情報を送信する
- Webhookを受け取ったJenkinsはWebHookをトリガーにユーザが構築したいサーバ情報をGitHubから入手する
- 入手したサーバ情報を基にTerraformでVM構築ジョブを起動する
- TerraformはVMware ESXiに対してOSインストールやユーザ作成といった基本設定を含むVM作成を入手したサーバ情報を基に実施する
- 作成されたVMは基本設定がすべて完了しており、ユーザがアクセスできる状態にあるので、デプロイが完了する
構成図
解説
【注意事項】
上記の仕組みについて解説を行いますが、その前にこの記事で詳しく解説しないことを取り上げます。
- 監視の仕組み:Prometheusがリソース監視を行い、Grafanaがそれを可視化しているだけです。詳しくは解説しません。
- GitHubの設定:PullRequestに起因するWebhookを設定しているだけです。PullRequestはJenkins側でMainブランチだけを対象に絞ることもできますが、GitHub Actionsを使っても実装できます。
TerraformによるVMデプロイについて
TerraformはHashiCorp社によって開発された、コードを使ってインフラを動的に構築、管理するツールです。いわゆるIaC(Infrastructure as Code)を実現するツールで、Ansibleよりも若干ハードウェア寄りの場面で利用されることが多いです。
Terraformは各インフラ基盤ごとにproviderと呼ばれるプラグインを公式や有志の手によって提供されており、インフラ基盤に合わせてproviderをインストールして構築/管理を行います。
例えばAWSではEC2、Lambda、EKS、ECS、VPC、S3、RDS、DynamoDBなどを含むAWSリソースを管理するproviderとして「terraform-provider-aws」というものがあります。
今回はproviderの中でも特にVMware ESXiの管理に特化したterraform-provider-esxiというプラグインを利用します。(https://github.com/josenk/terraform-provider-esxi)
ユーザが書いたサーバ情報はTerraformに読み取られたのち、その情報に沿ってTerraform + terraform-provider-esxiがESXiにVMとしてデプロイされます。
その際、VMにはサーバ情報に記載のあるOSがインストールされ、同時にUser/Passwordといった基本設定がすでに設定されたされた状態で払い出されます。
そのため、管理人がわざわざ手動でVM構築しなくても、ユーザはIPアドレスからSSHでアクセスするだけで利用可能な状態になります。
ユーザが書くパラメータは以下になります。
[main.tf]
terraform { required_version = ">= 0.12" } provider "esxi" { esxi_hostname = "${var.esxi_hostname}" esxi_hostport = "${var.esxi_hostport}" esxi_hostssl = "${var.esxi_hostssl}" esxi_username = "${var.esxi_username}" esxi_password = "${var.esxi_password}" } resource "esxi_guest" "vmtest" { guest_name = "vmtest" disk_store = "${var.disk_store}" power = "on" memsize = "2048" numvcpus = "2" boot_disk_size = "50" ovf_source = "focal-server-cloudimg-amd64.ova" ovf_properties_timer = "60" network_interfaces { virtual_network = "VM Network" } ovf_properties { key = "password" value = "${var.user_pw}" } }
ユーザはこのコードの中の以下の箇所を編集することで、それに沿ったVMを払い出すことが出来ます。括弧内は上記のパラメータに沿った内容です。
- guest_nameではVM名(vmtest)
- memsizeではメモリの量(2048MB)
- numvcpusではvCPUの数(2core)
- boot_disk_sizedeではディスクサイズ(50GB)
- ovf_sourceではインストールOSのイメージファイル(URL指定でもOK)
- イメージファイルを指定した場合はOSイメージを添付する必要あり
このほかにも細かく設定できますが(NICの設定など)、一旦は上記のみのパラメータで実装します。(コンフィグリファレンス:https://github.com/josenk/terraform-provider-esxi#configuration-reference)
ユーザに見せたくない部分(VMware ESXiのパスワードなど)は別ファイルに変数として格納されており、.gitignoreで編集/閲覧できるファイルから除外しています。(コード内では${var.hogehoge}という形で記載)
[variable.tf]
variable "disk_store" { default = "datastore0" } variable "esxi_hostname" { default = "xxx.xxx.xxx.xxx" } variable "user_pw" { default = "assault_lily" } ...
Jenkinsの設定
JenkinsはCI(継続的インデグレーション)/CD(継続的デリバリー)に特化したGUIツールです。
あらかじめ用意しておいたスクリプトなどをジョブとして、定期的に実行することが出来ます。
また、GitHubといった外部のツールと連携してトリガーベースのジョブ実行も行うことが出来ます。
Jenkinsは管理人の承認をトリガーとして、GitHubに書かれたコードを手元にクローンし、そのコードをそのままTerraformを使って実行するというジョブを遂行します。
単発的なジョブ実行にはコンテナを使ったほうがメンテナンスが楽なので、今回のジョブはあらかじめ用意しておいたDockerコンテナを起動するだけになります。
Jenkinsは以下のdocker-compose.ymlを実行するだけで、Terraform + terraform_prvide_esxi + ovftoolが揃ったコンテナがビルドされ、GitHubから入手したサーバ情報を基にTerraformのコマンドを順に実行していきます。
[docker-compose.yml]
version: '3' services: terraform_env: build: . volumes: - ./data:/data working_dir: /data command: > bash -c "terraform init && terraform plan && terraform apply -auto-approve && terraform show"
以上の設定により管理人がGitHub上でPullRequestを承認するだけで、VMがESXi上に払い出されてユーザがアクセスできるようになる仕組みが出来あがります。
おわりに
課題と展望
以下の点が今後の課題として挙げられます
- 払い出されるOSはクラウドイメージとしてova/ovfファイルとして提供されているものに限るため、公式がその拡張子で提供していないものは(カスタムしない限り)払い出すことが出来ない
- 対策としてはあらかじめ用意したVMをクローンする形でデプロイするという手段もあるが、数回限りしか使われないなら本末転倒である
- 管理人だけ見ると工数が減っているようにみえるが、ユーザ側にOS用意やリソース把握などの負担が移っていることを考えると、全体的な効率化にはそれほど及んでいない
今後の展望としては以下の機能の実装を勧めたいと考えています。
- ユーザのID/PASS設定だけではなく、パッケージのインストールやSSH認証鍵の配置なども同時に行いたい
- メモリ不足やディスク不足を人の目ではなく、CIツールを使って自動チェックできるようにしたい
- サーバをESXiだけで運用するのは現実的ではないので、vCenterを視野に入れたprovider-vSphereでの構築(https://github.com/hashicorp/terraform-provider-vsphere)
- VMUG Advantageに登録して、vCenterを手に入れようかな……
まとめ
今回の記事ではVM払い出しを「GitHub」「Jenkins」「Terraform」を使って自動化しました。
様々なツールを検証して今回の実装に至りましたが、いままでのVM払い出しの手順を如何にしてTerraformで巻き取ることができるかが今回のキーとなっています。
どのような自動化もそうですが、いままで自分たちが手で行ってきた動作をちゃんと洗い出してから自動化に臨まないと、あとからツールなどの調整が大変になってきます……。(実際、使えるOSが課題としてあがっています)
加えて、自動化したあとの工数の方が自動化する前よりもかかってしまう状況は本末転倒なので、大域的に見た全体の負担軽減も含めて改善していきたいと思います。
実業務においても、様々なシーンでのシステムの自動化を任されることがありますが、この2点に関してはいま一度意識しておきたい点であると感じました。