Nexus Kubernetes クラスターの監視

各 Nexus Kubernetes クラスターは、複数のレイヤーで構成されます。

  • 仮想マシン (VM)
  • Kubernetes レイヤー
  • アプリケーション ポッド

Screenshot of Sample Nexus Kubernetes cluster.

図: Nexus Kubernetes クラスターのサンプル

インスタンスでは、Nexus Kubernetes クラスターは、オプションの Container Insights 監視ソリューションと共に提供されます。 Container Insights では、Nexus Kubernetes クラスターとワークロードからログとメトリックをキャプチャします。 このツールを有効にするか、独自のテレメトリ スタックをデプロイするかは、お客様の判断です。

Azure 監視ツールを使用した Nexus Kubernetes クラスターは次のようになります。

Screenshot of Nexus Kubernetes cluster with Monitoring Tools.

図: 監視ツールを使用した Nexus Kubernetes クラスター

マネージド ID 認証を使用した CLI での拡張機能のオンボード

Azure CLI 以降のドキュメントで、複数のオペレーティング システムにインストールする方法、および CLI 拡張機能をインストールする方法について説明します。

必要な CLI 拡張機能の最新バージョンをインストールします。

Nexus Kubernetes クラスターの監視 - VM レイヤー

このハウツー ガイドでは、Nexus Kubernetes クラスター仮想マシンを Azure に Arc 接続し、Azure Monitoring Agent を使用してこれらの VM からシステム ログを収集するための監視エージェントを有効にする手順とユーティリティ スクリプトについて説明します。 この手順では、Log Analytics ワークスペースにログ データ収集を設定する方法について詳しく説明します。

サポートを提供するリソースを次に示します。

  • arc-connect.env: このテンプレート ファイルを使用して、含まれているスクリプトに必要な環境変数を作成します

export SUBSCRIPTION_ID=""
export SERVICE_PRINCIPAL_ID=""
export SERVICE_PRINCIPAL_SECRET=""
export RESOURCE_GROUP=""
export TENANT_ID=""
export LOCATION=""
export INSTALL_AZURE_MONITOR_AGENT="true"
export PROXY_URL=""
export NAMESPACE=""
export AZURE_MONITOR_AGENT_VERSION="1.24.2"
export CONNECTEDMACHINE_AZCLI_VERSION="0.6.0"
  • dcr.sh: このスクリプトを使用して、Syslog コレクションを構成するデータ収集規則 (DCR) を作成します

#!/bin/bash
set -e

SUBSCRIPTION_ID="${SUBSCRIPTION_ID:?SUBSCRIPTION_ID must be set}"
SERVICE_PRINCIPAL_ID="${SERVICE_PRINCIPAL_ID:?SERVICE_PRINCIPAL_ID must be set}"
SERVICE_PRINCIPAL_SECRET="${SERVICE_PRINCIPAL_SECRET:?SERVICE_PRINCIPAL_SECRET must be set}"
RESOURCE_GROUP="${RESOURCE_GROUP:?RESOURCE_GROUP must be set}"
TENANT_ID="${TENANT_ID:?TENANT_ID must be set}"
LOCATION="${LOCATION:?LOCATION must be set}"
LAW_RESOURCE_ID="${LAW_RESOURCE_ID:?LAW_RESOURCE_ID must be set}"
DCR_NAME=${DCR_NAME:-${RESOURCE_GROUP}-syslog-dcr}

az login --service-principal -u "${SERVICE_PRINCIPAL_ID}" -p "${SERVICE_PRINCIPAL_SECRET}" -t "${TENANT_ID}"

az account set -s "${SUBSCRIPTION_ID}"

az extension add --name monitor-control-service

RULEFILE=$(mktemp)
tee "${RULEFILE}" <<EOF
{
  "location": "${LOCATION}",
  "properties": {
    "dataSources": {
      "syslog": [
        {
          "name": "syslog",
          "streams": [
            "Microsoft-Syslog"
          ],
          "facilityNames": [
            "auth",
            "authpriv",
            "cron",
            "daemon",
            "mark",
            "kern",
            "local0",
            "local1",
            "local2",
            "local3",
            "local4",
            "local5",
            "local6",
            "local7",
            "lpr",
            "mail",
            "news",
            "syslog",
            "user",
            "uucp"
          ],
          "logLevels": [
            "Info",
            "Notice",
            "Warning",
            "Error",
            "Critical",
            "Alert",
            "Emergency"
          ]
        }
      ]
    },
    "destinations": {
      "logAnalytics": [
        {
          "workspaceResourceId": "${LAW_RESOURCE_ID}",
          "name": "centralWorkspace"
        }
      ]
    },
    "dataFlows": [
      {
        "streams": [
          "Microsoft-Syslog"
        ],
        "destinations": [
          "centralWorkspace"
        ]
      }
    ]
  }
}

EOF

az monitor data-collection rule create --name "${DCR_NAME}" --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --rule-file "${RULEFILE}" -o tsv --query id

rm -rf "${RULEFILE}"
  • assign.sh: このスクリプトを使用して、DCR をリソース グループ内のすべての Arc 対応サーバーに関連付けるポリシーを作成します

#!/bin/bash
set -e

SUBSCRIPTION_ID="${SUBSCRIPTION_ID:?SUBSCRIPTION_ID must be set}"
SERVICE_PRINCIPAL_ID="${SERVICE_PRINCIPAL_ID:?SERVICE_PRINCIPAL_ID must be set}"
SERVICE_PRINCIPAL_SECRET="${SERVICE_PRINCIPAL_SECRET:?SERVICE_PRINCIPAL_SECRET must be set}"
RESOURCE_GROUP="${RESOURCE_GROUP:?RESOURCE_GROUP must be set}"
TENANT_ID="${TENANT_ID:?TENANT_ID must be set}"
LOCATION="${LOCATION:?LOCATION must be set}"
DCR_NAME=${DCR_NAME:-${RESOURCE_GROUP}-syslog-dcr}
POLICY_NAME=${POLICY_NAME:-${DCR_NAME}-policy}

az login --service-principal -u "${SERVICE_PRINCIPAL_ID}" -p "${SERVICE_PRINCIPAL_SECRET}" -t "${TENANT_ID}"

az account set -s "${SUBSCRIPTION_ID}"

DCR=$(az monitor data-collection rule show --name "${DCR_NAME}" --resource-group "${RESOURCE_GROUP}" -o tsv --query id)

PRINCIPAL=$(az policy assignment create \
  --name "${POLICY_NAME}" \
  --display-name "${POLICY_NAME}" \
  --resource-group "${RESOURCE_GROUP}" \
  --location "${LOCATION}" \
  --policy "d5c37ce1-5f52-4523-b949-f19bf945b73a" \
  --assign-identity \
  -p "{\"dcrResourceId\":{\"value\":\"${DCR}\"}}" \
  -o tsv --query identity.principalId)

required_roles=$(az policy definition show -n "d5c37ce1-5f52-4523-b949-f19bf945b73a" --query policyRule.then.details.roleDefinitionIds -o tsv)
for roleId in $(echo "$required_roles"); do
  az role assignment create \
    --role "${roleId##*/}" \
    --assignee-object-id "${PRINCIPAL}" \
    --assignee-principal-type "ServicePrincipal" \
    --scope /subscriptions/"$SUBSCRIPTION_ID"/resourceGroups/"$RESOURCE_GROUP"
done
  • install.sh: 各 VM に Azure Monitor エージェントをインストールして、Azure Virtual Machines から監視データを収集します。
#!/bin/bash
set -e

function create_secret() {
  kubectl apply -f - -n "${NAMESPACE}" <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: naks-vm-telemetry
type: Opaque
stringData:
  SUBSCRIPTION_ID: "${SUBSCRIPTION_ID}"
  SERVICE_PRINCIPAL_ID: "${SERVICE_PRINCIPAL_ID}"
  SERVICE_PRINCIPAL_SECRET: "${SERVICE_PRINCIPAL_SECRET}"
  RESOURCE_GROUP: "${RESOURCE_GROUP}"
  TENANT_ID: "${TENANT_ID}"
  LOCATION: "${LOCATION}"
  PROXY_URL: "${PROXY_URL}"
  INSTALL_AZURE_MONITOR_AGENT: "${INSTALL_AZURE_MONITOR_AGENT}"
  VERSION: "${AZURE_MONITOR_AGENT_VERSION}"
  CONNECTEDMACHINE_AZCLI_VERSION: "${CONNECTEDMACHINE_AZCLI_VERSION}"
EOF
}

function create_daemonset() {
  kubectl apply -f - -n "${NAMESPACE}" <<EOF
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: naks-vm-telemetry
  labels:
    k8s-app: naks-vm-telemetry
spec:
  selector:
    matchLabels:
      name: naks-vm-telemetry
  template:
    metadata:
      labels:
        name: naks-vm-telemetry
    spec:
      hostNetwork: true
      hostPID: true
      containers:
        - name: naks-vm-telemetry
          image: mcr.microsoft.com/oss/mirror/docker.io/library/ubuntu:20.04
          env:
            - name: SUBSCRIPTION_ID
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: SUBSCRIPTION_ID
            - name: SERVICE_PRINCIPAL_ID
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: SERVICE_PRINCIPAL_ID
            - name: SERVICE_PRINCIPAL_SECRET
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: SERVICE_PRINCIPAL_SECRET
            - name: RESOURCE_GROUP
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: RESOURCE_GROUP
            - name: TENANT_ID
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: TENANT_ID
            - name: LOCATION
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: LOCATION
            - name: PROXY_URL
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: PROXY_URL
            - name: INSTALL_AZURE_MONITOR_AGENT
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: INSTALL_AZURE_MONITOR_AGENT
            - name: VERSION
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: VERSION
            - name: CONNECTEDMACHINE_AZCLI_VERSION
              valueFrom:
                secretKeyRef:
                  name: naks-vm-telemetry
                  key: CONNECTEDMACHINE_AZCLI_VERSION
          securityContext:
            privileged: true
          command:
            - /bin/bash
            - -c
            - |
              set -e
              WORKDIR=\$(nsenter -t1 -m -u -n -i mktemp -d)
              trap 'nsenter -t1 -m -u -n -i rm -rf "\${WORKDIR}"; echo "Azure Monitor Configuration Failed"' ERR
              nsenter -t1 -m -u -n -i mkdir -p "\${WORKDIR}"/telemetry

              nsenter -t1 -m -u -n -i tee "\${WORKDIR}"/telemetry/telemetry_common.py > /dev/null <<EOF
              #!/usr/bin/python3
              import json
              import logging
              import os
              import socket
              import subprocess
              import sys

              arc_config_file = "\${WORKDIR}/telemetry/arc-connect.json"


              class AgentryResult:
                  CONNECTED = "Connected"
                  CREATING = "Creating"
                  DISCONNECTED = "Disconnected"
                  FAILED = "Failed"
                  SUCCEEDED = "Succeeded"


              class OnboardingMessage:
                  COMPLETED = "Onboarding completed"
                  STILL_CREATING = "Azure still creating"
                  STILL_TRYING = "Service still trying"


              def get_logger(logger_name):
                  logger = logging.getLogger(logger_name)
                  logger.setLevel(logging.DEBUG)
                  handler = logging.StreamHandler(stream=sys.stdout)
                  format = logging.Formatter(fmt="%(name)s - %(levelname)s - %(message)s")
                  handler.setFormatter(format)
                  logger.addHandler(handler)
                  return logger


              def az_cli_cm_ext_install(logger, config):
                  logger.info("Install az CLI connectedmachine extension")
                  proxy_url = config.get("PROXY_URL")
                  if proxy_url is not None:
                      os.environ["HTTP_PROXY"] = proxy_url
                      os.environ["HTTPS_PROXY"] = proxy_url
                  cm_azcli_version = config.get("CONNECTEDMACHINE_AZCLI_VERSION")
                  logger.info("Install az CLI connectedmachine extension: {cm_azcli_version}")
                  ext_cmd = f'/usr/bin/az extension add --name connectedmachine --version "{cm_azcli_version}" --yes'
                  run_cmd(logger, ext_cmd)


              def get_cm_properties(logger, config):
                  hostname = socket.gethostname()
                  resource_group = config.get("RESOURCE_GROUP")

                  logger.info(f"Getting arc enrollment properties for {hostname}...")

                  az_login(logger, config)

                  property_cmd = f'/usr/bin/az connectedmachine show --machine-name "{hostname}" --resource-group "{resource_group}"'

                  try:
                      raw_property = run_cmd(logger, property_cmd)
                      cm_json = json.loads(raw_property.stdout)
                      provisioning_state = cm_json["provisioningState"]
                      status = cm_json["status"]
                  except:
                      logger.warning("Connectedmachine not yet present")
                      provisioning_state = "NOT_PROVISIONED"
                      status = "NOT_CONNECTED"
                  finally:
                      az_logout(logger)

                  logger.info(
                      f'Connected machine "{hostname}" provisioningState is "{provisioning_state}" and status is "{status}"'
                  )

                  return provisioning_state, status


              def get_cm_extension_state(logger, config, extension_name):
                  resource_group = config.get("RESOURCE_GROUP")
                  hostname = socket.gethostname()

                  logger.info(f"Getting {extension_name} state for {hostname}...")

                  az_login(logger, config)

                  state_cmd = f'/usr/bin/az connectedmachine extension show --name "{extension_name}" --machine-name "{hostname}" --resource-group "{resource_group}"'

                  try:
                      raw_state = run_cmd(logger, state_cmd)
                      cme_json = json.loads(raw_state.stdout)
                      provisioning_state = cme_json["provisioningState"]
                  except:
                      logger.warning("Connectedmachine extension not yet present")
                      provisioning_state = "NOT_PROVISIONED"
                  finally:
                      az_logout(logger)

                  logger.info(
                      f'Connected machine "{hostname}" extenstion "{extension_name}" provisioningState is "{provisioning_state}"'
                  )

                  return provisioning_state


              def run_cmd(logger, cmd, check_result=True, echo_output=True):
                  res = subprocess.run(
                      cmd,
                      shell=True,
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE,
                      universal_newlines=True,
                  )

                  if res.stdout:
                      if echo_output:
                          logger.info(f"[OUT] {res.stdout}")

                  if res.stderr:
                      if echo_output:
                          logger.info(f"[ERR] {res.stderr}")

                  if check_result:
                      res.check_returncode()

                  return res  # can parse out res.stdout and res.returncode


              def az_login(logger, config):
                  logger.info("Login to Azure account...")
                  proxy_url = config.get("PROXY_URL")
                  if proxy_url is not None:
                      os.environ["HTTP_PROXY"] = proxy_url
                      os.environ["HTTPS_PROXY"] = proxy_url

                  service_principal_id = config.get("SERVICE_PRINCIPAL_ID")
                  service_principal_secret = config.get("SERVICE_PRINCIPAL_SECRET")
                  tenant_id = config.get("TENANT_ID")
                  subscription_id = config.get("SUBSCRIPTION_ID")
                  cmd = f'/usr/bin/az login --service-principal --username "{service_principal_id}" --password "{service_principal_secret}" --tenant "{tenant_id}"'
                  run_cmd(logger, cmd)
                  logger.info(f"Set Subscription...{subscription_id}")
                  set_sub = f'/usr/bin/az account set --subscription "{subscription_id}"'
                  run_cmd(logger, set_sub)


              def az_logout(logger):
                  logger.info("Logout of Azure account...")
                  run_cmd(logger, "/usr/bin/az logout --verbose", check_result=False)

              EOF

              nsenter -t1 -m -u -n -i tee "\${WORKDIR}"/telemetry/setup_azure_monitor_agent.py > /dev/null <<EOF
              #!/usr/bin/python3
              import json
              import os
              import socket
              import time

              import telemetry_common


              def run_install(logger, ama_config):
                  logger.info("Install Azure Monitor agent...")
                  resource_group = ama_config.get("RESOURCE_GROUP")
                  location = ama_config.get("LOCATION")
                  proxy_url = ama_config.get("PROXY_URL")
                  hostname = socket.gethostname()
                  if proxy_url is not None:
                      os.environ["HTTP_PROXY"] = proxy_url
                      os.environ["HTTPS_PROXY"] = proxy_url
                      settings = (
                          '{"proxy":{"mode":"application","address":"'
                          + proxy_url
                          + '","auth": "false"}}'
                      )
                      cmd = f'/usr/bin/az connectedmachine extension create --no-wait --name "AzureMonitorLinuxAgent" --publisher "Microsoft.Azure.Monitor" --type "AzureMonitorLinuxAgent" --machine-name "{hostname}" --resource-group "{resource_group}" --location "{location}" --verbose --settings \'{settings}\''
                  else:
                      cmd = f'/usr/bin/az connectedmachine extension create --no-wait --name "AzureMonitorLinuxAgent" --publisher "Microsoft.Azure.Monitor" --type "AzureMonitorLinuxAgent" --machine-name "{hostname}" --resource-group "{resource_group}" --location "{location}" --verbose'

                  version = ama_config.get("VERSION")
                  if version is not None:
                      cmd += f' --type-handler-version "{version}"'

                  logger.info("Installing Azure Monitor agent...")
                  telemetry_common.az_login(logger, ama_config)

                  try:
                      telemetry_common.run_cmd(logger, cmd)
                  except:
                      logger.info("Trying to install Azure Monitor agent...")
                  finally:
                      telemetry_common.az_logout(logger)


              def run_uninstall(logger, ama_config):
                  logger.info("Uninstall Azure Monitor agent...")
                  resource_group = ama_config.get("RESOURCE_GROUP")
                  hostname = socket.gethostname()
                  cmd = f'/usr/bin/az connectedmachine extension delete --name "AzureMonitorLinuxAgent" --machine-name "{hostname}" --resource-group "{resource_group}" --yes --verbose'

                  telemetry_common.az_login(logger, ama_config)
                  logger.info("Uninstalling Azure Monitor agent...")

                  try:
                      telemetry_common.run_cmd(logger, cmd)
                  except:
                      print("Trying to uninstall Azure Monitor agent...")
                  finally:
                      telemetry_common.az_logout(logger)


              def ama_installation(logger, ama_config):
                  logger.info("Executing AMA extenstion installation...")
                  telemetry_common.az_cli_cm_ext_install(logger, ama_config)

                  # Get connected machine properties
                  cm_provisioning_state, cm_status = telemetry_common.get_cm_properties(
                    logger, ama_config
                  )

                  if (
                    cm_provisioning_state == telemetry_common.AgentryResult.SUCCEEDED
                    and cm_status == telemetry_common.AgentryResult.CONNECTED
                  ):
                    # Get AzureMonitorLinuxAgent extension status
                    ext_provisioning_state = telemetry_common.get_cm_extension_state(
                      logger, ama_config, "AzureMonitorLinuxAgent"
                    )
  
                    if ext_provisioning_state == telemetry_common.AgentryResult.SUCCEEDED:
                      logger.info(telemetry_common.OnboardingMessage.COMPLETED)
                      return True
                    elif ext_provisioning_state == telemetry_common.AgentryResult.FAILED:
                      run_uninstall(logger, ama_config)
                      logger.warning(telemetry_common.OnboardingMessage.STILL_TRYING)
                      return False
                    elif ext_provisioning_state == telemetry_common.AgentryResult.CREATING:
                      logger.warning(telemetry_common.OnboardingMessage.STILL_CREATING)
                      return False
                    else:
                      run_install(logger, ama_config)
                      logger.warning(telemetry_common.OnboardingMessage.STILL_TRYING)
                      return False
                  else:
                    logger.error("Server not arc enrolled, enroll the server and retry")
                    return False


              def main():
                  timeout = 60  # TODO: increase when executed via systemd unit
                  start_time = time.time()
                  end_time = start_time + timeout

                  config_file = telemetry_common.arc_config_file

                  logger = telemetry_common.get_logger(__name__)

                  logger.info("Running setup_azure_monitor_agent.py...")

                  if config_file is None:
                      raise Exception("config file is expected")

                  ama_config = {}

                  with open(config_file, "r") as file:
                      ama_config = json.load(file)

                  ama_installed = False

                  while time.time() < end_time:
                      logger.info("Installing AMA extension...")
                      try:
                          ama_installed = ama_installation(logger, ama_config)
                      except Exception as e:
                          logger.error(f"Could not install AMA extension: {e}")
                      if ama_installed:
                          break
                      logger.info("Sleeping 30s...")  # retry for Azure info
                      time.sleep(30)


              if __name__ == "__main__":
                  main()

              EOF


              nsenter -t1 -m -u -n -i tee "\${WORKDIR}"/arc-connect.sh > /dev/null <<EOF
              #!/bin/bash
              set -e

              echo "{\"VERSION\": \"\${VERSION}\", \"SUBSCRIPTION_ID\": \"\${SUBSCRIPTION_ID}\", \"SERVICE_PRINCIPAL_ID\": \"\${SERVICE_PRINCIPAL_ID}\", \"SERVICE_PRINCIPAL_SECRET\": \"\${SERVICE_PRINCIPAL_SECRET}\", \"RESOURCE_GROUP\": \"\${RESOURCE_GROUP}\", \"TENANT_ID\": \"\${TENANT_ID}\", \"LOCATION\": \"\${LOCATION}\", \"PROXY_URL\": \"\${PROXY_URL}\", \"CONNECTEDMACHINE_AZCLI_VERSION\": \"\${CONNECTEDMACHINE_AZCLI_VERSION}\"}" > "\${WORKDIR}"/telemetry/arc-connect.json

              if [ "\${INSTALL_AZURE_MONITOR_AGENT}" = "true" ]; then
                echo "Installing Azure Monitor agent..."
                /usr/bin/python3 "\${WORKDIR}"/telemetry/setup_azure_monitor_agent.py > "\${WORKDIR}"/setup_azure_monitor_agent.out
                cat "\${WORKDIR}"/setup_azure_monitor_agent.out
                if grep "Could not install AMA extension" "\${WORKDIR}"/setup_azure_monitor_agent.out > /dev/null; then
                  exit 1
                fi
              fi
              EOF

              nsenter -t1 -m -u -n -i sh "\${WORKDIR}"/arc-connect.sh
              nsenter -t1 -m -u -n -i rm -rf "\${WORKDIR}"
              echo "Server monitoring configured successfully"
              tail -f /dev/null
          livenessProbe:
            initialDelaySeconds: 600
            periodSeconds: 60
            timeoutSeconds: 30
            exec:
              command:
                - /bin/bash
                - -c
                - |
                  set -e
                  WORKDIR=\$(nsenter -t1 -m -u -n -i mktemp -d)
                  trap 'nsenter -t1 -m -u -n -i rm -rf "\${WORKDIR}"' ERR EXIT
                  nsenter -t1 -m -u -n -i tee "\${WORKDIR}"/liveness.sh > /dev/null <<EOF
                  #!/bin/bash
                  set -e

                  # Check AMA processes
                  ps -ef | grep "\\\s/opt/microsoft/azuremonitoragent/bin/agentlauncher\\\s"
                  ps -ef | grep "\\\s/opt/microsoft/azuremonitoragent/bin/mdsd\\\s"
                  ps -ef | grep "\\\s/opt/microsoft/azuremonitoragent/bin/amacoreagent\\\s"

                  # Check Arc server agent is Connected
                  AGENTSTATUS="\\\$(azcmagent show -j)"
                  if [[ \\\$(echo "\\\${AGENTSTATUS}" | jq -r .status) != "Connected" ]]; then
                    echo "azcmagent is not connected"
                    echo "\\\${AGENTSTATUS}"
                    exit 1
                  fi

                  # Verify dependent services are running
                  while IFS= read -r status; do
                    if [[ "\\\${status}" != "active" ]]; then
                      echo "one or more azcmagent services not active"
                      echo "\\\${AGENTSTATUS}"
                      exit 1
                    fi
                  done < <(jq -r '.services[] | (.status)' <<<\\\${AGENTSTATUS})

                  # Run connectivity tests
                  RESULT="\\\$(azcmagent check -j)"
                  while IFS= read -r reachable; do
                    if [[ ! \\\${reachable} ]]; then
                      echo "one or more connectivity tests failed"
                      echo "\\\${RESULT}"
                      exit 1
                    fi
                  done < <(jq -r '.[] | (.reachable)' <<<\\\${RESULT})

                  EOF

                  nsenter -t1 -m -u -n -i sh "\${WORKDIR}"/liveness.sh
                  nsenter -t1 -m -u -n -i rm -rf "\${WORKDIR}"
                  echo "Liveness check succeeded"

      tolerations:
        - operator: "Exists"
          effect: "NoSchedule"

EOF
}

SUBSCRIPTION_ID="${SUBSCRIPTION_ID:?SUBSCRIPTION_ID must be set}"
SERVICE_PRINCIPAL_ID="${SERVICE_PRINCIPAL_ID:?SERVICE_PRINCIPAL_ID must be set}"
SERVICE_PRINCIPAL_SECRET="${SERVICE_PRINCIPAL_SECRET:?SERVICE_PRINCIPAL_SECRET must be set}"
RESOURCE_GROUP="${RESOURCE_GROUP:?RESOURCE_GROUP must be set}"
TENANT_ID="${TENANT_ID:?TENANT_ID must be set}"
LOCATION="${LOCATION:?LOCATION must be set}"
PROXY_URL="${PROXY_URL:?PROXY_URL must be set}"
INSTALL_AZURE_MONITOR_AGENT="${INSTALL_AZURE_MONITOR_AGENT:?INSTALL_AZURE_MONITOR_AGENT must be true/false}"
NAMESPACE="${NAMESPACE:?NAMESPACE must be set}"
AZURE_MONITOR_AGENT_VERSION="${AZURE_MONITOR_AGENT_VERSION:-"1.24.2"}"
CONNECTEDMACHINE_AZCLI_VERSION="${CONNECTEDMACHINE_AZCLI_VERSION:-"0.6.0"}"

create_secret
create_daemonset

前提条件 - VM

  • Nexus Kubernetes クラスターへのクラスター管理者アクセス。

  • Azure Arc 対応サーバーを使用するには、次の Azure リソース プロバイダーをサブスクリプションに登録します。

    • Microsoft.HybridCompute
    • Microsoft.GuestConfiguration
    • Microsoft.HybridConnectivity

以前に次のリソース プロバイダーを登録していない場合は、登録します。

az account set --subscription "{the Subscription Name}"
az provider register --namespace 'Microsoft.HybridCompute'
az provider register --namespace 'Microsoft.GuestConfiguration'
az provider register --namespace 'Microsoft.HybridConnectivity'
  • 必要に応じて、Azure サービス プリンシパルを次の Azure 組み込みロールに割り当てます。 接続するマシンがある Azure リソース グループにサービス プリンシパルを割り当てます。
役割 必要な操作
Azure Connected Machine のリソース管理者または共同作成者 リソース グループ内の Arc 対応 Nexus Kubernetes クラスター VM サーバーを接続し、Azure Monitoring Agent (AMA) をインストールする
共同作成者の監視または共同作成者 リソース グループにデータ収集規則 (DCR) を作成し、それに Arc 対応サーバーを関連付ける
ユーザー アクセス管理者、およびリソース ポリシー共同作成者または共同作成者 Azure ポリシー割り当てを使用して、DCR が Arc 対応マシンに関連付けられていることを確認する場合に必要
Kubernetes 拡張機能共同作成者 Container Insights の K8s 拡張機能をデプロイするために必要

環境のセットアップ

含まれているスクリプトをコピーして実行します。 これらは、Azure portal の Azure Cloud Shell から実行できます。 または、Kubernetes コマンド ライン ツール (kubectl) と Azure CLI がインストールされている Linux コマンド プロンプトから実行することもできます。

含まれているスクリプトを実行する前に、次の環境変数を定義します。

環境変数 説明
SUBSCRIPTION_ID リソース グループを含む Azure サブスクリプションの ID
RESOURCE_GROUP Arc 対応サーバーと関連リソースが作成されるリソース グループ名
LOCATION Arc 対応サーバーと関連リソースが作成される Azure リージョン
SERVICE_PRINCIPAL_ID 適切なロールの割り当てを持つ Azure サービス プリンシパルの appId
SERVICE_PRINCIPAL_SECRET Azure サービス プリンシパルの認証パスワード
TENANT_ID サービス プリンシパルが存在するテナント ディレクトリの ID
PROXY_URL Azure サービスへの接続に使用するプロキシ URL
NAMESPACE Kubernetes アーティファクトが作成される名前空間

便宜上、テンプレート ファイル (arc-connect.env) を変更して環境変数の値を設定できます。

# Apply the modified values to the environment
 ./arc-connect.env

データ収集ルール (DCR) を追加する

Arc 対応サーバーを DCR に関連付けて、Log Analytics ワークスペースへのログ データの収集を有効にします。 DCR は、Azure portal または CLI を使用して作成できます。 VM からデータを収集する DCR の作成については、こちらを参照してください。

含まれる dcr.sh スクリプトでは、指定されたリソース グループ内に、ログ収集を構成する DCR が作成されます。

  1. 適切な環境セットアップと、サービス プリンシパルのロールの前提条件を確認します。 DCR は指定したリソース グループに作成されます。

  2. DCR に従ってログ データ インジェスト用の Log Analytics ワークスペースを作成または識別します。 環境変数 LAW_RESOURCE_ID をそのリソース ID に設定します。 既知の Log Analytics ワークスペース名のリソース ID を取得します。

export LAW_RESOURCE_ID=$(az monitor log-analytics workspace show -g "${RESOURCE_GROUP}" -n <law name> --query id -o tsv)
  1. dcr.sh スクリプトを実行します。 これは、指定したリソース グループに ${RESOURCE_GROUP}-syslog-dcr という名前の DCR を作成します
./dcr.sh

Azure portal または CLI から DCR を表示または管理します。 既定では、Linux Syslog ログ レベルは "INFO" に設定されています。 必要に応じてログ レベルを変更できます。

Note

手動でまたはポリシーを使用して、DCR の作成前に作成されたサーバーを関連付けます。 修復タスクに関する記事を参照してください。

Arc 対応サーバー リソースを DCR に関連付ける

ログを Log Analytics ワークスペースにフローさせるために、Arc 対応サーバー リソースを作成された DCR に関連付けます。 サーバーを DCR に関連付けるためのオプションがあります。

Azure portal または CLI を使用して選択した Arc 対応サーバーを DCR に関連付ける

Azure portal で、[リソース] セクションを使用して、Arc 対応サーバー リソースを DCR に追加します。

Azure CLI を使用したリソースの関連付けの詳細については、このリンクを使用してください。

Azure ポリシーを使用して DCR の関連付けを管理する

関連付けを適用するポリシーをリソース グループに割り当てます。 Linux Arc マシンを DCR に関連付ける組み込みのポリシー定義があります。 DCR をパラメーターとして使用して、リソース グループにポリシーを割り当てます。 これにより、リソース グループ内のすべての Arc 対応サーバーが同じ DCR に関連付けられます。

Azure portal で、[ポリシー定義] ページから Assign ボタンを選択します。

利便性を高めるため、指定された assign.sh スクリプトは、指定されたリソース グループと、dcr.sh スクリプトで作成された DCR に組み込みポリシーを割り当てます。

  1. ポリシーとロールの割り当てを実行するために、適切な環境セットアップと、サービス プリンシパルのロールの前提条件を確認します。
  2. データ収集ルールの追加」セクションの説明に従って、dcr.sh スクリプトを使用して、リソース グループに DCR 作成します。
  3. assign.sh スクリプトを実行します。 ポリシーの割り当てと必要なロールの割り当てが作成されます。
./assign.sh

Azure Monitor エージェントをインストールする

付属の install.sh を使用します。これにより、Nexus Kubernetes クラスターに Kubernetes daemonSet が作成されます。 各クラスター ノードにポッドをデプロイし、Azure Monitor エージェント (AMA) をインストールします。 daemonSet には、サーバー接続と AMA プロセスを監視する liveness probe も含まれています。

Note

Azure Monitor エージェントをインストールするには、先に Nexus Kubernetes クラスター VM を Arc 対応にする必要があります。 最新のバージョン バンドルを使用している場合、このプロセスは自動的に行われます。 ただし、使用するバージョン バンドルでクラスター VM の Arc 登録が既定でサポートされていない場合は、クラスターを最新のバージョン バンドルにアップグレードする必要があります。 バージョン バンドルの詳細については、Nexus Kubernetes クラスターのサポートされているバージョンに関するページを参照してください。

  1. 環境のセットアップ」で指定された環境を設定します。 Nexus Kubernetes クラスター VM の現在の kubeconfig コンテキストを設定します。
  2. Nexus Kubernetes クラスターへの Kubectl アクセスを許可します。

    Note

    Nexus Kubernetes クラスターを作成すると、Nexus によってクラスター リソースの格納専用の管理対象リソース グループが自動的に作成され、このグループ内に Arc 接続クラスター リソースが確立されます。

    クラスターにアクセスするには、クラスター接続 kubeconfig を設定する必要があります。 関連する Microsoft Entra エンティティを使用して Azure CLI にログインした後、それを囲むファイアウォールの外側であっても、どこからでもクラスターと通信するために必要な kubeconfig を取得できます。
    1. CLUSTER_NAME 変数、RESOURCE_GROUP 変数、および SUBSCRIPTION_ID 変数を設定します。

      CLUSTER_NAME="myNexusK8sCluster"
      RESOURCE_GROUP="myResourceGroup"
      SUBSCRIPTION_ID=<set the correct subscription_id>
      
    2. az を使用して管理対象リソース グループにクエリを実行し、MANAGED_RESOURCE_GROUP に格納します

       az account set -s $SUBSCRIPTION_ID
       MANAGED_RESOURCE_GROUP=$(az networkcloud kubernetescluster show -n $CLUSTER_NAME -g $RESOURCE_GROUP --output tsv --query managedResourceGroupConfiguration.name)
      
    3. 次のコマンドは、指定された Nexus Kubernetes クラスターの Kubernetes API サーバーに接続できる connectedk8s プロキシを起動します。

      az connectedk8s proxy -n $CLUSTER_NAME  -g $MANAGED_RESOURCE_GROUP &
      
    4. kubectl を使用して、クラスターに要求を送信します。

      kubectl get pods -A
      

      これで、すべてのノードの一覧が含まれているクラスターからの応答が表示されます。

    注意

    "アクセス トークンをクライアント プロキシに投稿できませんでした。MSI に接続できませんでした" というエラー メッセージが表示された場合は、az login を実行して Azure で再認証する必要がある場合があります。

  3. コマンド プロンプトから、Nexus Kubernetes クラスターへの kubectl アクセスを使用して install.sh スクリプトを実行します。

このスクリプトでは、クラスターに daemonSet をデプロイします。 次のように進行状況を監視します。

# Run the install script and observe results
./install.sh
kubectl get pod --selector='name=naks-vm-telemetry'
kubectl logs <podname>

完了すると、"Server monitoring configured successfully" というメッセージがログに記録されます。

Note

これらの接続されたサーバーを DCR に関連付けます。 ポリシーを構成した後、Azure Log Analytics ワークスペースのログを監視するために多少の遅延が発生する場合があります

Nexus Kubernetes クラスターの監視 - K8s レイヤー

前提条件 - Kubernetes

オペレーターが Nexus Kubernetes クラスターで監視ツールを構成するために確認する必要がある前提条件がいくつかあります。

Container Insights では、そのデータを Log Analytics ワークスペースに保存します。 ログ データは、「データ収集ルール (DCR) の追加」セクションで説明されている初期スクリプトの実行中に指定したリソース ID を持つワークスペースにフローします。 それ以外の場合は、(Azure の場所に基づいて) サブスクリプションに関連付けられているリソース グループ内の既定のワークスペースにデータが流し込まれます。

米国東部の例を次に示します。

  • Log Analytics ワークスペース名: DefaultWorkspace-<GUID>-EUS
  • リソース グループ名: DefaultResourceGroup-EUS

既存の Log Analytics ワークスペースのリソース ID を取得するには、次のコマンドを実行します。

az login

az account set --subscription "<Subscription Name or ID the Log Analytics workspace is in>"

az monitor log-analytics workspace show --workspace-name "<Log Analytics workspace Name>" \
  --resource-group "<Log Analytics workspace Resource Group>" \
  -o tsv --query id

Container Insights をデプロイし、該当する Log Analytics ワークスペースにデータを表示するには、アカウントで特定のロールの割り当てが必要です。 たとえば、"共同作成者" ロールの割り当てです。 必要なロールを割り当てる手順を参照してください。

  • Log Analytics 共同作成者ロール: CNF (プロビジョニング済み) クラスターでコンテナーの監視を有効にするために必要なアクセス許可。
  • Log Analytics 閲覧者ロール: Log Analytics 共同作成者ロールの非メンバーは、コンテナーの監視を有効にすると、Log Analytics ワークスペース内のデータを表示するためのアクセス許可を受け取ります。

クラスター拡張機能をインストールする

Azure Cloud Shell にサインインして、クラスターにアクセスします。

az login

az account set --subscription "<Subscription Name or ID the Provisioned Cluster is in>"

次の 2 つのコマンドのいずれかを使用して、プロビジョニングされた Nexus Kubernetes クラスターに Container Insights 拡張機能をデプロイします。

顧客が事前に作成した Log Analytics ワークスペースを使用する

az k8s-extension create --name azuremonitor-containers \
  --cluster-name "<Nexus Kubernetes cluster Name>" \
  --resource-group "<Nexus Kubernetes cluster Resource Group>" \
  --cluster-type connectedClusters \
  --extension-type Microsoft.AzureMonitor.Containers \
  --release-train preview \
  --configuration-settings logAnalyticsWorkspaceResourceID="<Log Analytics workspace Resource ID>" \
  amalogsagent.useAADAuth=true

既定の Log Analytics ワークスペースを使用する

az k8s-extension create --name azuremonitor-containers \
  --cluster-name "<Nexus Kubernetes cluster Name>" \
  --resource-group "<Nexus Kubernetes cluster Resource Group>" \
  --cluster-type connectedClusters \
  --extension-type Microsoft.AzureMonitor.Containers \
  --release-train preview \
  --configuration-settings amalogsagent.useAADAuth=true

クラスター拡張機能を検証する

次のコマンドを使用して、Nexus Kubernetes クラスターでの監視エージェントの有効化が正常にデプロイされたことを検証します。

az k8s-extension show --name azuremonitor-containers \
  --cluster-name "<Nexus Kubernetes cluster Name>" \
  --resource-group "<Nexus Kubernetes cluster Resource Group>" \
  --cluster-type connectedClusters

拡張機能の "成功" のプロビジョニング状態を探します。 "k8s-extension create" コマンドも状態を返している可能性があります。

ログとメトリックの収集をカスタマイズする

Container Insights には、Nexus Kubernetes クラスターからのログとメトリックの収集を微調整するエンドユーザー機能が用意されています (「Container Insights のエージェント データ収集を構成する」)。

その他のリソース