はじめに

普段Linuxばかり構築しているのですが、Windows ServerにNew Relicエージェントを入れる機会がありました。
Windows Serverを普段あまり触らない人間にとっては、手間取った点があるため内容をまとめています。
また、New Relicを入れるのはAnsibleロール「newrelic.newrelic_install」を使っていますが、「newrelic.newrelic-infra」とは少し勝手が違うようでしたのでそこについても触れます。

できること

  • AnsibleをAWS Systems Manager Session Manager (SSM) 経由で実行できる
  • Ansibleロール「newrelic.newrelic_install」でNew RelicエージェントのインストールとConf設定まで行う

前提

AWS構成

内容は割愛しますが、セッションマネージャー接続ができるEC2(Windows Server)が存在することを前提とします。

①AnsibleをAWS Systems Manager Session Manager (SSM) 経由で実行できる

まずは、Ansibleの実行環境からターゲットのWindows ServerへSession Manager経由で接続できるように設定します。

Inventoryの設定

動的にEC2インスタンスの情報を取得するため、aws_ec2インベントリプラグインを使用します。
以下のようなaws_ec2.ymlファイルを作成します。

plugin: aws_ec2

regions:
  - ap-northeast-1

filters:
  instance-state-name: running

keyed_groups: #ホストグループを動的に作成
  # サーバタイプ別グループのみ作成(ホスト名重複を避ける)
  - key: tags.get('HostName', 'unknown')
    prefix: 'server'
    separator: '_'

hostnames:
  - tag:HostName
  - tag:Name

compose: # 変数
  ansible_host: instance_id
  ansible_connection: "{{ ansible_connection }}"
  ansible_aws_ssm_bucket_name: "{{ ansible_aws_ssm_bucket_name }}"
  ansible_aws_ssm_region: "{{ ansible_aws_ssm_region }}"
ポイント説明

instance-state-name: running

起動中のインスタンスのみを対象としています

keyed_groups

EC2のタグ情報を元に、Ansibleのホストグループを動的に作成します。
ここではHostNameタグの値(例:xxxx)を元に、xxxxのようなグループを自動生成しています。
これにより、後続のPlaybookで「xxxxサーバー群にだけ、この設定を適用する」といった柔軟な条件分岐が可能になります。

グルーピングの設定は、必要に応じて読み替えてください。

ansible_connection

変数は、group_vars内で指定しています。

ansible_connectionは、今回SSM接続で必要なプラグインであるcommunity.aws.aws_ssmを指定しています。

接続テスト

ansible -i aws_ec2.yml -m win_ping <ホスト名>

AWS認証済みの状態で接続テストを行ってみてください。
SUCCESSの応答と"changed": false, "ping": "pong"の結果が返ってくれば成功です。

②newrelic.newrelic_installでインストールとConf設定を行う

newrelic.newrelic_installとnewrelic.newrelic-infra

今回利用するnewrelic.newrelic_installは公式ドキュメントでも案内がある最新のインストール用ロールとなっています。
一方で、newrelic.newrelic-infraは昔使われていたようですが、数年アップデートが行われていません。
なので、newrelic.newrelic_installを利用しようとしたところある課題に直面しました。

それは、Conf設定がロール内の機能として用意されていないことです。
変数のtargetsでinfrastructureを指定するのですが、このロールの仕様では、エージェントインストールのみでConfの配置は別のやり方が必要です。
今回用意したplaybookでは、ロールを利用したエージェントインストールとwin_templateを利用したConf配置を実行します。

Playbookの実装

インストール用とConf配置用のplaybookは分けます。
こうすることで、Confの修正を行う際はConf配置用のplaybookのみを実行できるようにしています。
handlerのコードは割愛しますが、restart用のコードを用意しています。

group_vars(all.yml)にはnewrelic_winservices_templatesで、サービス監視で必要なファイルを参照するように定義しています。

newrelic_winservices_templates:
xxxx: "winservices-config-xxxx.yml.j2"
zzzz: "winservices-config-zzzz.yml.j2"
ツリー構造
├── site.yml                    # マスタープレイブック(インストール + 設定)
├── newrelic_install.yml        # インストール専用プレイブック
├── newrelic_config.yml         # 設定専用プレイブック
└── roles/newrelic/
    ├── tasks/main.yml          # メインタスク
    ├── templates/
    │   ├── newrelic-infra.yml.j2
    │   └── winservices-config-adfp.yml.j2
    └── handlers/main.yml
site.yml
- import_playbook: newrelic_install.yml
- import_playbook: newrelic_config.yml
newrelic_install.yml
---
- name: Install New Relic Infrastructure Agent
  hosts: all
  become: false
  gather_facts: true

  pre_tasks:
    - name: Check if HostName tag exists
      set_fact:
        hostname: "{{ hostvars[inventory_hostname]['tags']['HostName'] | default('') | upper }}"

    - name: Skip hosts without HostName tag
      meta: end_host
      when: hostname == ''

  environment:
    NEW_RELIC_API_KEY: "{{ newrelic_api_key }}"
    NEW_RELIC_ACCOUNT_ID: "{{ newrelic_account_id }}"
    NEW_RELIC_REGION: "{{ newrelic_region }}"

  roles:
    - role: newrelic.newrelic_install
      vars:
        targets:
          - infrastructure
        newrelic_entity_tags:
          HostName: "{{ hostname }}"
        install_timeout_seconds: 300

newrelic_config.yml
---
- name: Configure New Relic Infrastructure Agent
  hosts: all
  become: false
  gather_facts: true

  roles:
    - role: newrelic
      vars:
        template_file: "newrelic-infra.yml.j2"
task/main.yml

このPlaybookは、大きく分けて2つのステップで構成されています。

【共通設定】全サーバーに基本設定を配布
まず、ライセンスキーなどの基本的な情報が含まれた共通の設定ファイル (newrelic-infra.yml.j2) を、対象となる全てのWindowsサーバーに配布します。
これは、どのサーバーにも必須となる土台の設定です。

【個別設定】特定のサーバーに追加設定を配布
次に、サーバーを識別し、そのサーバーにだけ必要となる追加の設定ファイル(例:Windowsサービス監視用の設定)を配布します。

---
- name: Determine Windows Services Integration template file based on hostname mapping from all.yml
  set_fact:
    winservices_template_file: "{{ newrelic_winservices_templates[inventory_hostname] | default('') }}"

- name: Display Windows Services Integration template file
  debug:
    msg: "Windows Services Integration template file: {{ winservices_template_file }} for host: {{ inventory_hostname }}"
  when: winservices_template_file != ""

- name: Deploy common New Relic configuration file
  win_template:
    src: "newrelic-infra.yml.j2"
    dest: "{{ newrelic_windows_config.config_path }}"
    backup: true
  register: config_deployment
  notify: restart newrelic-infra
  failed_when: config_deployment is failed

- name: Deploy Windows Services Integration configuration file
  win_template:
    src: "{{ winservices_template_file }}"
    dest: "C:\\Program Files\\New Relic\\newrelic-infra\\integrations.d\\winservices-config.yml"
    backup: true
  register: winservices_deployment
  notify: restart newrelic-infra
  failed_when: winservices_deployment is failed
  when: winservices_template_file != ""
「どのサーバーに、どの設定を?」を自動で判断する仕組み

このPlaybookは、inventory_hostname(サーバーのホスト名)をキーとして、どのサーバーにどの追加設定ファイルが必要かを定義した対応表(変数)を参照します。

処理の流れ

1.Playbook実行時、まず最初に「このサーバー用の追加設定ファイルはあるか?」を対応表で確認します。
2.対応するファイルが見つかったサーバーにのみ、追加の設定ファイルを配布するタスクが実行されます。
3.対応するファイルが見つからなかったサーバーでは、追加設定のタスクは安全にスキップされます。

newrelic-infra.yml.j2

必要に応じて設定項目を入れて下さい。
license_keyだけは必須項目となります。

license_key: {{ newrelic_license_key }}
enable_process_metrics: {{ nrinfragent_config.enable_process_metrics }}
disable_zero_mem_process_filter: {{ nrinfragent_config.disable_zero_mem_process_filter }}
log_to_stdout: {{ nrinfragent_config.log_to_stdout }}

winservices-config-xxxx.yml.j2

W32Timeのサービスを監視する設定となります。

integrations:
  - name: nri-winservices
    config:
      exporter_bind_address: 127.0.0.1
      exporter_bind_port: 9182
      include_matching_entities:
        windowsService.name:
          - "W32Time"
      scrape_interval: 60s
    timeout: 60s

実行コマンド

インストール+Conf配置

ansible-playbook -i inventory/prd/aws_ec2.yml site.yml

Conf配置のみ

ansible-playbook -i inventory/prd/aws_ec2.yml newrelic_config.yml

補足

特定ホストのみに対して実行する場合は、–limitをつけてHostname指定を行ってください。

おわりに

本記事では、普段Linuxを扱うエンジニアがAnsibleとAWS Session Managerを使い、Windows ServerへNew Relicエージェントを自動導入する手順をご紹介しました。

公式のインストール用ロール「newrelic.newrelic_install」が設定ファイルを直接扱えないという課題に対し、
インストールと設定のPlaybookを分離することで、柔軟な構成管理を実現しました。

この記事が、同じようにWindows環境のNew Relicエージェント導入に取り組む方のヒントになれば幸いです。