Terraform(を含むHashiCorp社のソフトウェア製品)のライセンスがBusiness Source License (BSL, or BUSL)になりました。
一般ユーザーはライセンス変更前にリリースされたソフトウェアについてはこれまでと同じように使えるものの、これからリリースされるバージョンについては一定の制限が加わるようです。
FAQの次の3項にあるように、社内内部や個人的な利用で使う場合は従来どおり使えるという記述があります。一方で依頼を受けて自社所有ではないインフラに対してTerraformを使う場合、どうなのかは正直よくかわかりません。
3. What are the implications of this change for end users of HashiCorp’s open source products? For end users who are using HashiCorp’s current open source products and new releases using the BSL license for their internal or personal usage, there is no change. Last updated: August 10, 2023 (参考訳) 3.この変更は、HashiCorpのオープンソース製品のエンドユーザーにどのような影響がありますか? HashiCorpの現在のオープンソース製品と、内部または個人的な使用にBSLライセンスを使用する新しいリリースを使用しているエンドユーザーについては、変更はありません。
...というわけで(どういうわけで?)、最近話題になったOpenTofuを使ってみます。
OpenTofuとは?
OpenTofuはTerraformのフォークです。コマンドがopentofu
であるほかはTerraformと使い勝手は一緒です。
そのため、Terraformプラグインの多くがそのまま利用できます。
最近プロジェクトがLinux Foundation傘下になったのもメディアに取り上げられていました。
OpenTofuは成果物を引き続きMozilla Public License v2.0(MPL2.0)のオープンソースライセンスで開発されるようです。 OpenTofuとフォーク元のTerraformがどうなっていくかは見守りたいと思います。
OpenTofuをインストールしてみる
OpenTofuのドキュメントを見ても、Linux以外のインストール方法が書かれていません。そもそもLinuxもaptとyumを使ってパッケージをインス トールする方法以外は書かれていません。他のディストリビューションではどうするのでしょうか。
TerraformもOpenTofuもGo言語で書かれているので、Goをインストールしてビルド、インストールすればどのOSにもインストールできるようです。OSごとのインストール方法の詳細は今回省略しますが、ざっくり書くと次のような手順です。
まず、Goをインストールします。 Goのバージョンはここ を参考に、それに近いバージョンを公式サイトからダウンロードしてインストールします。
ちなみに私はGo 1.20.8をインストールしました。
ただ、Go 1.21系を使った場合も大丈夫だったと社内で聞いたので、そこまで厳格にバージョンを指定する必要はないのかもしれません。
Goをインストールしたあと、次を実行します。
git clone https://github.com/opentofu/opentofu.git cd opentofu make go install
今後はアップデートする場合は上記を実行して、変更点はgit log
などで確認していく感じでしょうか。なにか動かなくてOpenTofu側の問題であればIssue登録する感じですかね。
Dockerでつかってみる
まずはチュートリアルとして、Dcoekr DesktopでNGINXコンテナーを動かしてみましょう。
チュートリアルサイトにはいくつかのプロバイダー向けのハンズオンが用意されています。
まずはこちらを試してみます。
Terraformのインストールの部分は行わず、OpenTofuを使います。 というわけでこのページから始めます。
以下はviエディタを使っていますが、お好きなエディターで次のようなマニフェストを書いてください。
$ mkdir learn-terraform-docker-container $ cd learn-terraform-docker-container $ vi main.tf terraform { required_providers { docker = { source = "kreuzwerker/docker" version = "~> 3.0.1" } } } provider "docker" {} resource "docker_image" "nginx" { name = "nginx:latest" keep_locally = false } resource "docker_container" "nginx" { image = docker_image.nginx.image_id name = "tutorial" ports { internal = 80 external = 8000 } }
Dockerのチュートリアル を見ながら、次のように順に実行してみます。すると、Docker DesktopにNGINXコンテナーが作成されてアクセスできるようになります。
$ opentofu init $ opentofu apply
要らなくなったら、destroyを実行してください。コンテナーが終了(削除?)します。
$ opentofu destroy
OpenStackで使ってみる
社内で個人用にOpenStackを動かしているので、ここにインタンスをOpenTofuで作ってみようと思います。 使うのはTerraformのOpenStack Providerです。
注意点
TerraformのOpenStack Providerを使う場合にハマったポイントをここにまとめました。
- OpenStack CLIを使えるようにするため、次のようにダウンロードした証明書をopenrcに指定しました。
ちなみにOpenStack CLIはTerraformでOpenStackをいじるときに必須ではないようです(あると便利ですが)。 使う必要がなければ上の処理は不要です。
「insecure true」は使えなかったので、「sudo snap get microstack config.tls」で証明書のパスを確認して、 手元の環境にダウンロードしました。
TerraformのOpenStack Providerはこれが最新
ググると古い情報が出てくることがあります。 例えばこのような記述をすると、この頃のこのモジュールはdarwin_arm64に対応していないというエラーが発生するので注意です。
特にApple M1以降のMacを使っている人は注意ですね。
terraform { required_providers { openstack = { source = "terraform-provider-openstack/openstack" version = "~> 1.35.0" } } }
用意するマニフェスト
書いたTerraformマニフェストは以下のとおりです。基本的に公式のままです。 2つ目のブロックの認証情報関連は、Dashboard右上からダウンロードできるopenrcに書いてあるので、それを転記します。
terraform { required_providers { openstack = { source = "terraform-provider-openstack/openstack" version = "~> 1.51.1" } } } # Configure the OpenStack Provider provider "openstack" { user_name = "openstackuser" tenant_name = "admin" password = "hogehugahogeeee" auth_url = "https://172.17.28.71:5000/v3/" cacert_file = "ssl/cacert.pem" key = "ssl/key.pem" region = "microstack" } # Create a web server resource "openstack_compute_instance_v2" "test-server" { name = "my_instance" image_id = "93719fbf-e12e-4cad-b15e-cdd8250d75ba" flavor_id = "2" key_pair = "mykey" availability_zone = "nova" security_groups = ["default"] network { uuid = "10c3220f-7679-4ac5-97af-764c1a9705a4" } }
あとはいつもの流れでinit, fmt, validate, plan, deployを実行していくだけです。
Terraformを使っていたときはコマンド'terraform'のところをopentofu
にするだけで、あとは一緒です。
$ opentofu init Initializing the backend... Initializing provider plugins... - Reusing previous version of terraform-provider-openstack/openstack from the dependency lock file - Using previously-installed terraform-provider-openstack/openstack v1.51.1 OpenTofu has been successfully initialized! You may now begin working with OpenTofu. Try running "tofu plan" to see any changes that are required for your infrastructure. All OpenTofu commands should now work. If you ever set or change modules or backend configuration for OpenTofu, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. $ opentofu fmt openstack-demo.tf $ opentofu validate Success! The configuration is valid. $ opentofu plan OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create OpenTofu will perform the following actions: # openstack_compute_instance_v2.test-server will be created + resource "openstack_compute_instance_v2" "test-server" { + access_ip_v4 = (known after apply) + access_ip_v6 = (known after apply) + all_metadata = (known after apply) + all_tags = (known after apply) + availability_zone = "nova" + created = (known after apply) + flavor_id = "2 " + flavor_name = (known after apply) + force_delete = false + id = (known after apply) + image_id = "93719fbf-e12e-4cad-b15e-cdd8250d75ba" + image_name = (known after apply) + key_pair = "mykey" + name = "my_instance" + power_state = "active" + region = (known after apply) + security_groups = [ + "default", ] + stop_before_destroy = false + updated = (known after apply) + network { + access_network = false + fixed_ip_v4 = (known after apply) + fixed_ip_v6 = (known after apply) + floating_ip = (known after apply) + mac = (known after apply) + name = (known after apply) + port = (known after apply) + uuid = "10c3220f-7679-4ac5-97af-764c1a9705a4" } } # openstack_networking_floatingip_v2.external will be created + resource "openstack_networking_floatingip_v2" "external" { + address = (known after apply) + all_tags = (known after apply) + dns_domain = (known after apply) + dns_name = (known after apply) + fixed_ip = (known after apply) + id = (known after apply) + pool = "public" + port_id = (known after apply) + region = (known after apply) + subnet_id = (known after apply) + tenant_id = (known after apply) } Plan: 2 to add, 0 to change, 0 to destroy. ──────────────────────────────────────────────────────────────────────────────────────────────────────── Note: You didn't use the -out option to save this plan, so OpenTofu can't guarantee to take exactly these actions if you run "tofu apply" now. $ opentofu apply OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create OpenTofu will perform the following actions: # openstack_compute_instance_v2.test-server will be created + resource "openstack_compute_instance_v2" "test-server" { + access_ip_v4 = (known after apply) + access_ip_v6 = (known after apply) + all_metadata = (known after apply) + all_tags = (known after apply) + availability_zone = "nova" + created = (known after apply) + flavor_id = "2" + flavor_name = (known after apply) + force_delete = false + id = (known after apply) + image_id = "93719fbf-e12e-4cad-b15e-cdd8250d75ba" + image_name = (known after apply) + key_pair = mykey" + name = "my_instance" + power_state = "active" + region = (known after apply) + security_groups = [ + "default", ] + stop_before_destroy = false + updated = (known after apply) + network { + access_network = false + fixed_ip_v4 = (known after apply) + fixed_ip_v6 = (known after apply) + floating_ip = (known after apply) + mac = (known after apply) + name = (known after apply) + port = (known after apply) + uuid = "10c3220f-7679-4ac5-97af-764c1a9705a4" } } # openstack_networking_floatingip_v2.external will be created + resource "openstack_networking_floatingip_v2" "external" { + address = (known after apply) + all_tags = (known after apply) + dns_domain = (known after apply) + dns_name = (known after apply) + fixed_ip = (known after apply) + id = (known after apply) + pool = "external" + port_id = (known after apply) + region = (known after apply) + subnet_id = (known after apply) + tenant_id = (known after apply) } Plan: 2 to add, 0 to change, 0 to destroy. Do you want to perform these actions? OpenTofu will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes openstack_compute_instance_v2.test-server: Creating... openstack_compute_instance_v2.test-server: Still creating... [10s elapsed] openstack_compute_instance_v2.test-server: Still creating... [20s elapsed] openstack_compute_instance_v2.test-server: Still creating... [30s elapsed] openstack_compute_instance_v2.test-server: Creation complete after 37s [id=8225be20-8efe-4b40-80c7-bef88f0d674a]
あとはそのインスタンスにFlating IPアドレスを設定すればアクセスできます。
$ openstack floating ip list $ openstack server add floating ip my_instance 172.16.214.209 $ ping 172.16.214.209 PING 172.16.214.209 (172.16.214.209): 56 data bytes 64 bytes from 172.16.214.209: icmp_seq=0 ttl=62 time=21.701 ms 64 bytes from 172.16.214.209: icmp_seq=1 ttl=62 time=22.057 ms ^C --- 172.16.214.209 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 21.701/21.879/22.057/0.178 ms
要らなくなったら、次のようにインスタンスを消します。
$ opentofu destroy openstack_compute_instance_v2.test-server: Refreshing state... [id=2e63312c-6fe0-4018-9d9a-8c640834cdad] OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: - destroy OpenTofu will perform the following actions: # openstack_compute_instance_v2.test-server will be destroyed - resource "openstack_compute_instance_v2" "test-server" { - access_ip_v4 = "192.168.222.133" -> null - all_metadata = {} -> null - all_tags = [] -> null - availability_zone = "nova" -> null - created = "2023-09-26 04:08:52 +0000 UTC" -> null - flavor_id = "2" -> null - flavor_name = "m1.small" -> null - force_delete = false -> null - id = "2e63312c-6fe0-4018-9d9a-8c640834cdad" -> null - image_id = "93719fbf-e12e-4cad-b15e-cdd8250d75ba" -> null - image_name = "ubuntu-20.04" -> null - key_pair = "mykey" -> null - name = "my_instance" -> null - power_state = "active" -> null - region = "microstack" -> null - security_groups = [ - "default", ] -> null - stop_before_destroy = false -> null - tags = [] -> null - updated = "2023-09-26 04:09:15 +0000 UTC" -> null - network { - access_network = false -> null - fixed_ip_v4 = "192.168.222.133" -> null - mac = "fa:16:3e:cd:0f:32" -> null - name = "test" -> null - uuid = "10c3220f-7679-4ac5-97af-764c1a9705a4" -> null } } Plan: 0 to add, 0 to change, 1 to destroy. Do you really want to destroy all resources? OpenTofu will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes openstack_compute_instance_v2.test-server: Destroying... [id=2e63312c-6fe0-4018-9d9a-8c640834cdad] openstack_compute_instance_v2.test-server: Still destroying... [id=2e63312c-6fe0-4018-9d9a-8c640834cdad, 10s elapsed] openstack_compute_instance_v2.test-server: Destruction complete after 11s Destroy complete! Resources: 1 destroyed.
OpenTofuでほぼ問題なくTerraformマニフェストを使ってデプロイ出来ることは確認していますが、 唯一Terraformマニフェストでrequired_versionを指定している場合は、調整が必要かもしれません。
terraform { required_version = "~> 1.1.0" required_providers { ... } } }
とはいえ今回のパターンでは特に変更することなくデプロイ出来ることが確認できました。 これなら、移行しても大丈夫そうですね。