😺

Ops Agent Policy を Terraformで管理する際の注意点

に公開

Ops Agent のインストールについて

Compute Engine VMに Ops Agent をインストールすることでテレメトリーデータを収集することができます。

インストール方法は個々のVM毎にインストールする方法とVM Manager/エージェントポリシーを利用した一括インストールの方式があります。

今回は後者の方についての記事となります。ちなみに数ヶ月前に取得した Professional Cloud DevOps Engineerの試験でも Agent Policy による Ops Agentで管理手間を減らすといった趣旨の問題が出た記憶でして、FleetでのOps Agentインストールは推奨されている方式だという認識です。

今回はOps Agent Policy を Terraform で管理する方法と注意ポイントを解説します。

Ops Agent Policy の Terraform resource/module

まず該当のTerraform resourceはこちらです。
https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/os_config_os_policy_assignment

「Ops Agent Policy」 というピンポイントのリソースは存在せず、あくまで OS Policy という、より汎用的なリソースです。この OS Policy で、条件に合致するVMに対してOps Agentのインストールを発動させるように設定します。

一方で、Google Cloud Cloud Foundation Toolkit (CFT) の公式モジュールでは、resource os_config_os_policy_assignment を利用した ops-agent-policy が公開されています。

https://github.com/terraform-google-modules/terraform-google-cloud-operations/tree/main/modules/ops-agent-policy

リソースを用いた実装例

まず、モジュールを利用せずに最もシンプルな Ops Agent のインストールはこちらです。
※ 今回はすべてのWindows VMを対象とした例を挙げます

resource "google_os_config_os_policy_assignment" "ops_agent_windows" {
  project  = var.project_id
  location = var.location

  name        = "ops-agent-windows-policy"
  description = "OS policy to install the Ops Agent on Windows VMs"

  instance_filter {
    # Target all Windows Server instances
    inventories {
      os_short_name = "windows"
    }
  }

  os_policies {
    id   = "ops-agent-installation-policy"
    mode = "ENFORCEMENT"

    resource_groups {

      resources {
        id = "add-repo"

        repository {
          goo {
            name = "Google Cloud Ops Agent"
            url  = "https://packages.cloud.google.com/yuck/repos/google-cloud-ops-agent-windows-all"
          }
        }
      }

      resources {
        id = "install-pkg"

        pkg {
          desired_state = "INSTALLED"

          googet {
            name = "google-cloud-ops-agent"
          }
        }
      }
    }
  }

  rollout {
    disruption_budget {
      fixed = 10
    }
    min_wait_duration = "61s"
  }
}

上記のように一旦、レポジトリーを追加してからでないとインストールはできませんでした。
ちなみに、Ops Agentでバージョン指定する際は以下のように指定が必要です。ドキュメント等には存在しなかったので自力で指定できるフォーマットを見つけました。

  name = "google-cloud-ops-agent.x86_64.2.56.1@1"

モジュールを用いた実装例

同様の設定に対して、モジュールを用いると以下のようになります。パラメーターはだいぶスッキリします。

module "ops_agent_policy" {
  source        = "github.com/terraform-google-modules/terraform-google-cloud-operations/modules/ops-agent-policy"
  project       = var.project_id
  zone          = var.location
  assignment_id = "ops-agent-windows-policy"

  agents_rule = {
    package_state = "installed"
    version       = "2.57.0"
  }
  instance_filter = {
    inventories = [{
      os_short_name = "windows"
      os_version    = ""
    }]
  }
}

Ops Agentのバージョン管理について

上記の例ではバージョン指定もあえて含めましたが、Ops AgentをAgent Policyでインストールする際はバージョン指定をした方が良いと考えています。

今回内部的に利用しているGoogle APIは GA Agent Policy のAPIで、こちらは Ops Agentの auto-upgrade がサポートされていないようです。

GA agent policies don't support an auto-upgrade operation.

Beta Policy と GA Policy の比較についての公式ドキュメントは以下です。
https://cloud.google.com/stackdriver/docs/solutions/agents/ops-agent/agent-policies-overview#oagent-beta-ga-policies

また、一般的なことではありますが予期せぬエージェントの更新による挙動変化を防ぎ、環境の安定性を保つために固定バージョン化というのはよくある方針かと思います。

したがって、Terraform 側でOps Agentのバージョンを指定してソースコード管理するのが適切なやり方だと考えています。

モジュールを使わずにバージョン指定でのインストールしたとき

前回の例で、モジュールを使わずともバージョン指定でのインストールができることは説明しました。

        pkg {
          desired_state = "INSTALLED"

          googet {
            name = "google-cloud-ops-agent.x86_64.2.56.1@1"
          }
        }

これで指定バージョンでのOps Agentのインストールはできるものの、VMのOS Policy適用状態が Non-Compliant になってしまう問題を発見しました。

バージョン指定しない場合は直接 Terraform resourceを利用する方式でも Compliantになるため正常そうです。

おそらく pkg ブロックの desired_state チェックの挙動がバージョンされた package name に対応されていないのではないかと思います。

モジュールを使ってバージョン指定でのインストールしたとき

一方でCFTモジュールのコードを確認すると、バージョン指定によるインストールではあえて pkg ブロックを利用せず exec ブロック内で validateenforce を行うことでインストール&state のチェックを行っているようです。
https://github.com/terraform-google-modules/terraform-google-cloud-operations/blob/main/modules/ops-agent-policy/pin_to_version_install/policy_pin_to_version_install.yaml#L231-L238

exec ブロックなのでインストール時にスクリプト(Windowsの場合はPowershell)を利用しています。
その結果、Stateがバージョン指定でもCompliantになりました。

外向き通信を塞いでいる場合はEgressファイアウォールルールで穴あけ

Ops AgentのインストールはデフォルトではPublic Repoから取ってくるので、もしFirewall で明示的にVMからのインターネットアクセスを拒否している場合は以下のドメインへのアクセス許可が必要です。Firewall Policy Rule の FQDN Objects を利用して容易にEgress許可できます。

  • dl.google.com
  • packages.cloud.google.com

Conclusion

最初はモジュールの方はスクリプトを使用しているため内部実装がやや複雑だと感じたので、直接Terraformリソースでのデプロイの方が構成としてシンプルになるのではないかと思いましたが、バージョン指定で正常に動かすためには 結局 execブロックでscriptによるインストールが必要なため、公式モジュールを使う方が無難だという結論になりました。
ただし、この公式モジュールには柔軟性が一部欠けている側面もあります。例えば、ポリシーをVMに展開するペースを制御するrollout設定(一度に適用するVM数を決めるdisruption_budgetや、適用間隔を定めるmin_wait_duration)が決め打ちで設定されており、変数で渡すことができません。

Instiny Tech Blog

Discussion