Monitorare il cluster Nexus Kubernetes

Ogni cluster Nexus Kubernetes è costituito da più livelli:

  • Macchine virtuali
  • Livello Kubernetes
  • Pod dell'applicazione

Screenshot of Sample Nexus Kubernetes cluster.

Figura: Cluster Nexus Kubernetes di esempio

In un'istanza, i cluster Nexus Kubernetes vengono forniti con una soluzione facoltativadi osservabilità di Container Insights . Container Insights acquisisce i log e le metriche da cluster e carichi di lavoro Nexus Kubernetes. È esclusivamente tua discrezione se abilitare questo strumento o distribuire uno stack di dati di telemetria personalizzato.

Il cluster Nexus Kubernetes con lo strumento di monitoraggio di Azure è simile al seguente:

Screenshot of Nexus Kubernetes cluster with Monitoring Tools.

Figura: Cluster Nexus Kubernetes con Strumenti di monitoraggio

Onboarding delle estensioni con l'interfaccia della riga di comando tramite l'autenticazione dell'identità gestita

Documentazione per iniziare con l'interfaccia della riga di comando di Azure, come installarla in più sistemi operativi e come installare le estensioni dell'interfaccia della riga di comando.

Installare la versione più recente delle estensioni dell'interfaccia della riga di comando necessarie.

Monitorare il cluster Nexus Kubernetes - Livello macchina virtuale

Questa guida pratica fornisce passaggi e script di utilità per connettere il cluster Nexus Kubernetes Macchine virtuali ad Azure e abilitare gli agenti di monitoraggio per la raccolta di log di sistema da queste macchine virtuali usando l'agente di monitoraggio di Azure. Le istruzioni illustrano ulteriormente come configurare la raccolta dei dati di log in un'area di lavoro Log Analytics.

Le risorse seguenti offrono supporto:

  • arc-connect.env: usare questo file di modello per creare le variabili di ambiente necessarie per gli script inclusi

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: usare questo script per creare una regola di raccolta dati (DCR) per configurare la raccolta syslog

#!/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: usare lo script per creare un criterio per associare il registro di dominio a tutti i server abilitati per Arc in un gruppo di risorse

#!/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: macchine virtuali del cluster Nexus Kubernetes abilitano Arc e installano l'agente di monitoraggio di Azure in ogni macchina virtuale
#!/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_arc_for_servers.py > /dev/null <<EOF
              #!/usr/bin/python3
              import json
              import time

              import telemetry_common


              def run_connect(logger, arc_config):
                  logger.info("Connect machine to Azure Arc...")
                  service_principal_id = arc_config.get("SERVICE_PRINCIPAL_ID")
                  service_principal_secret = arc_config.get("SERVICE_PRINCIPAL_SECRET")
                  resource_group = arc_config.get("RESOURCE_GROUP")
                  tenant_id = arc_config.get("TENANT_ID")
                  subscription_id = arc_config.get("SUBSCRIPTION_ID")
                  location = arc_config.get("LOCATION")
                  connect_cmd = f'azcmagent connect --service-principal-id "{service_principal_id}" --service-principal-secret "{service_principal_secret}" --resource-group "{resource_group}" --tenant-id "{tenant_id}" --subscription-id "{subscription_id}" --location "{location}"'

                  cloudtype = arc_config.get("CLOUDTYPE")
                  if cloudtype is not None:
                      connect_cmd += f' --cloud "{cloudtype}"'

                  tags = arc_config.get("TAGS")
                  if tags is not None:
                      connect_cmd += f' --tags "{tags}"'

                  correlation_id = arc_config.get("CORRELATION_ID")
                  if correlation_id is not None:
                      connect_cmd += f' --correlation-id "{correlation_id}"'

                  proxy_url = arc_config.get("PROXY_URL")
                  if proxy_url is not None:
                      set_proxy_cmd = f'/usr/bin/azcmagent config set proxy.url "{proxy_url}"'
                      telemetry_common.run_cmd(logger, set_proxy_cmd)

                  # Hardcoding allowed extensions as these will only vary if NC team adds new extensions
                  allowed_extensions = "Microsoft.Azure.Monitor/AzureMonitorLinuxAgent,Microsoft.Azure.AzureDefenderForServers/MDE.Linux"
                  set_extensions_cmd = (
                      f'/usr/bin/azcmagent config set extensions.allowlist "{allowed_extensions}"'
                  )
                  telemetry_common.run_cmd(logger, set_extensions_cmd)

                  telemetry_common.az_login(logger, arc_config)
                  logger.info("Connecting machine to Azure Arc...")

                  try:
                      telemetry_common.run_cmd(logger, connect_cmd)
                  except:
                      logger.info("Trying to connect machine to Azure Arc...")
                  finally:
                      telemetry_common.az_logout(logger)


              def run_disconnect(logger, arc_config):
                  logger.info("Disconnect machine from Azure Arc...")
                  service_principal_id = arc_config.get("SERVICE_PRINCIPAL_ID")
                  service_principal_secret = arc_config.get("SERVICE_PRINCIPAL_SECRET")

                  cmd = f'/usr/bin/azcmagent disconnect --service-principal-id "{service_principal_id}" --service-principal-secret "{service_principal_secret}"'

                  telemetry_common.az_login(logger, arc_config)

                  try:
                      telemetry_common.run_cmd(logger, cmd)
                  except:
                      logger.info("Trying to disconnect machine from Azure Arc...")
                  finally:
                      telemetry_common.az_logout(logger)


              def arc_enrollment(logger, arc_config):
                  logger.info("Executing Arc enrollment...")

                  telemetry_common.az_cli_cm_ext_install(logger, arc_config)

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

                  if (
                      cm_provisioning_state == telemetry_common.AgentryResult.SUCCEEDED
                      and cm_status == telemetry_common.AgentryResult.CONNECTED
                  ):
                      logger.info(telemetry_common.OnboardingMessage.COMPLETED)
                      return True
                  elif cm_provisioning_state in [
                      telemetry_common.AgentryResult.FAILED,
                      telemetry_common.AgentryResult.DISCONNECTED,
                  ]:
                      run_disconnect(logger, arc_config)
                      logger.warning(telemetry_common.OnboardingMessage.STILL_TRYING)
                      return False
                  elif cm_provisioning_state == telemetry_common.AgentryResult.CREATING:
                      logger.warning(telemetry_common.OnboardingMessage.STILL_CREATING)
                      return False
                  else:
                      run_connect(logger, arc_config)
                      logger.warning(telemetry_common.OnboardingMessage.STILL_TRYING)
                      return False


              def main():
                  timeout = 300  # 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_arc_for_servers.py...")

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

                  arc_config = {}

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

                  arc_enrolled = False

                  while time.time() < end_time:
                      logger.info("Arc enrolling the server...")
                      try:
                          arc_enrolled = arc_enrollment(logger, arc_config)
                      except Exception as e:
                          logger.error(f"Could not arc enroll server: {e}")
                      if arc_enrolled:
                          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}"/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

              echo "Connecting machine to Azure Arc..."
              /usr/bin/python3 "\${WORKDIR}"/telemetry/setup_arc_for_servers.py > "\${WORKDIR}"/setup_arc_for_servers.out
              cat "\${WORKDIR}"/setup_arc_for_servers.out
              if grep "Could not arc enroll server" "\${WORKDIR}"/setup_arc_for_servers.out > /dev/null; then
                exit 1
              fi

              /usr/bin/azcmagent config set incomingconnections.ports 22
              /usr/bin/azcmagent config set extensions.allowlist Microsoft.Azure.Monitor/AzureMonitorLinuxAgent,Microsoft.Azure.AzureDefenderForServers/MDE.Linux,Microsoft.Azure.ActiveDirectory/AADSSHLoginForLinux

              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

Prerequisiti-VM

  • Accesso amministratore del cluster al cluster Nexus Kubernetes.

  • Per usare i server abilitati per Azure Arc, registrare i provider di risorse di Azure seguenti nella sottoscrizione:

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

Registrare questi provider di risorse, se non sono stati eseguiti in precedenza:

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'
  • Assegnare un'entità servizio di Azure ai ruoli predefiniti di Azure seguenti, in base alle esigenze. Assegnare l'entità servizio al gruppo di risorse di Azure con i computer da connettere:
Ruolo Necessario per
Risorsa del computer Connessione ed di Azure Amministrazione istrator o Collaboratore Connessione server vm del cluster Nexus Kubernetes abilitato per Arc nel gruppo di risorse e installare l'agente di monitoraggio di Azure
Collaboratore o Collaboratore per il monitoraggio Creare una regola di raccolta dati nel gruppo di risorse e associarvi i server abilitati per Arc
Accesso utente Amministrazione istrator e Collaboratore o Collaboratore ai criteri delle risorse Necessario se si vogliono usare le assegnazioni di criteri di Azure per assicurarsi che un controller di dominio sia associato ai computer abilitati per Arc
Collaboratore estensione Kubernetes Necessario per distribuire l'estensione K8s per Container Insights

Impostazione dell'ambiente

Copiare ed eseguire gli script inclusi. È possibile eseguirli da Azure Cloud Shell, nella portale di Azure. In alternativa, è possibile eseguirli da un prompt dei comandi Linux in cui sono installati lo strumento da riga di comando di Kubernetes (kubectl) e l'interfaccia della riga di comando di Azure.

Prima di eseguire gli script inclusi, definire le variabili di ambiente seguenti:

Variabile di ambiente Descrizione
SUBSCRIPTION_ID ID della sottoscrizione di Azure che contiene il gruppo di risorse
RESOURCE_GROUP Nome del gruppo di risorse in cui vengono creati il server abilitato per Arc e le risorse associate
LOCATION Area di Azure in cui vengono creati i server abilitati per Arc e le risorse associate
edizione StandardRVICE_PRINCIPAL_ID AppId dell'entità servizio di Azure con assegnazioni di ruolo appropriate
edizione StandardRVICE_PRINCIPAL_edizione Standard CRET Password di autenticazione per l'entità servizio di Azure
TENANT_ID ID della directory del tenant in cui esiste l'entità servizio
PROXY_URL URL proxy da usare per la connessione ai servizi di Azure
NAMESPACE Spazio dei nomi in cui vengono creati gli artefatti Kubernetes

Per praticità, è possibile modificare il file modello, arc-connect.env, per impostare i valori delle variabili di ambiente.

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

Aggiungere una regola di raccolta dati

Associare i server abilitati per Arc a un controller di dominio per abilitare la raccolta di dati di log in un'area di lavoro Log Analytics. È possibile creare il registro di dominio tramite il portale di Azure o l'interfaccia della riga di comando. Le informazioni sulla creazione di un registro di dominio per raccogliere dati dalle macchine virtuali sono disponibili qui.

Lo script incluso dcr.sh crea un record di controllo di dominio, nel gruppo di risorse specificato, che configurerà la raccolta di log.

  1. Assicurarsi che i prerequisiti di configurazione e ruolo dell'ambiente siano appropriati per l'entità servizio. Il record di controllo di dominio viene creato nel gruppo di risorse specificato.

  2. Creare o identificare un'area di lavoro Log Analytics per l'inserimento dei dati di log in base al Registro Azure Container. Impostare una variabile di ambiente, LAW_RESOURCE_ID sul relativo ID risorsa. Recuperare l'ID risorsa per un nome noto dell'area di lavoro Log Analytics:

export LAW_RESOURCE_ID=$(az monitor log-analytics workspace show -g "${RESOURCE_GROUP}" -n <law name> --query id -o tsv)
  1. Eseguire lo script di dcr.sh. Crea un record di dominio nel gruppo di risorse specificato con nome ${RESOURCE_GROUP}-syslog-dcr
./dcr.sh

Visualizzare o gestire il record di controllo dell'accesso dall'interfaccia della riga di comando o dall'portale di Azure. Per impostazione predefinita, il livello di log syslog linux è impostato su "INFO". È possibile modificare il livello di log in base alle esigenze.

Nota

Manualmente o tramite un criterio, associare i server creati prima della creazione del record di dominio. Vedere attività di correzione.

Associare le risorse del server abilitate per Arc a DCR

Associare le risorse del server abilitate per Arc al registro di registrazione dati creato per i log per il flusso all'area di lavoro Log Analytics. Sono disponibili opzioni per l'associazione di server a controller di dominio.

Usare portale di Azure o l'interfaccia della riga di comando per associare i server abilitati per Arc selezionati a DCR

In portale di Azure aggiungere la risorsa server abilitata per Arc al Registro Azure Container usando la relativa sezione Risorse.

Usare questo collegamento per informazioni sull'associazione delle risorse tramite l'interfaccia della riga di comando di Azure.

Usare Criteri di Azure per gestire le associazioni DCR

Assegnare un criterio al gruppo di risorse per applicare l'associazione. È disponibile una definizione di criteri predefinita, per associare Linux Arc Machines a un DCR. Assegnare i criteri al gruppo di risorse con DCR come parametro. Garantisce l'associazione di tutti i server abilitati per Arc, all'interno del gruppo di risorse, con lo stesso DCR.

Nella portale di Azure selezionare il Assign pulsante nella pagina di definizione dei criteri.

Per praticità, lo script fornito assign.sh assegna i criteri predefiniti al gruppo di risorse specificato e al registro di dominio creato con lo dcr.sh script.

  1. Assicurarsi che l'installazione dell'ambiente e i prerequisiti del ruolo appropriati per l'entità servizio eseseguono assegnazioni di criteri e ruoli.
  2. Creare il DCR nel gruppo di risorse usando dcr.sh lo script come descritto nella sezione Aggiunta di una regola di raccolta dati.
  3. Eseguire lo script assign.sh. Crea l'assegnazione dei criteri e le assegnazioni di ruolo necessarie.
./assign.sh

Connessione server abilitati per Arc e installare l'agente di monitoraggio di Azure

Usare lo script incluso install.sh per registrare tutte le macchine virtuali server che rappresentano i nodi del cluster Nexus Kubernetes. Questo script crea un daemonSet kubernetes nel cluster Nexus Kubernetes. Distribuisce un pod in ogni nodo del cluster, connettendo ogni macchina virtuale ai server abilitati per Arc e installando l'agente di monitoraggio di Azure. Include daemonSet anche un probe di attività che monitora la connessione al server e i processi AMA.

  1. Impostare l'ambiente come specificato nell'installazione dell'ambiente. Impostare il contesto corrente kubeconfig per le macchine virtuali del cluster Nexus Kubernetes.
  2. Consentire Kubectl l'accesso al cluster Nexus Kubernetes.

    Nota

    Quando si crea un cluster Nexus Kubernetes, Nexus crea automaticamente un gruppo di risorse gestito dedicato all'archiviazione delle risorse del cluster, all'interno di questo gruppo, viene stabilita la risorsa cluster connessa Arc.

    Per accedere al cluster, è necessario configurare il cluster connect kubeconfig. Dopo aver eseguito l'accesso all'interfaccia della riga di comando di Azure con l'entità Microsoft Entra pertinente, è possibile ottenere il kubeconfig necessario per comunicare con il cluster ovunque, anche all'esterno del firewall che lo circonda.
    1. Impostare CLUSTER_NAMEle variabili e RESOURCE_GROUPSUBSCRIPTION_ID .

      CLUSTER_NAME="myNexusK8sCluster"
      RESOURCE_GROUP="myResourceGroup"
      SUBSCRIPTION_ID=<set the correct subscription_id>
      
    2. Eseguire query sul gruppo di risorse gestite con az e archiviare in 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. Il comando seguente avvia un proxy connectedk8s che consente di connettersi al server API Kubernetes per il cluster Nexus Kubernetes specificato.

      az connectedk8s proxy -n $CLUSTER_NAME  -g $MANAGED_RESOURCE_GROUP &
      
    4. Usare kubectl per inviare richieste al cluster:

      kubectl get pods -A
      

      Verrà visualizzata una risposta dal cluster contenente l'elenco di tutti i nodi.

    Nota

    Se viene visualizzato il messaggio di errore "Failed to post access token to client proxyFailed to connect to MSI", potrebbe essere necessario eseguire un az login per eseguire di nuovo l'autenticazione con Azure.

  3. Eseguire lo install.sh script dal prompt dei comandi con l'accesso kubectl al cluster Nexus Kubernetes.

Lo script distribuisce l'oggetto daemonSet nel cluster. Monitorare lo stato di avanzamento come segue:

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

Al termine, il sistema registra il messaggio "Monitoraggio del server configurato correttamente". A questo punto, i server abilitati per Arc vengono visualizzati come risorse all'interno del gruppo di risorse selezionato.

Nota

Associare questi server connessi al Registro Azure Container. Dopo aver configurato un criterio, potrebbe verificarsi un ritardo per osservare i log nell'area di lavoro Log Analytics di Azure

Monitorare il cluster Nexus Kubernetes - Livello K8s

Prerequisiti-Kubernetes

Esistono alcuni prerequisiti che l'operatore deve assicurarsi di configurare gli strumenti di monitoraggio nei cluster Nexus Kubernetes.

Container Insights archivia i dati in un'area di lavoro Log Analytics. I dati di log passano all'area di lavoro il cui ID risorsa specificato durante gli script iniziali illustrati nella sezione "Aggiungere una regola di raccolta dati (DCR)". In caso contrario, i dati si incanala in un'area di lavoro predefinita nel gruppo di risorse associato alla sottoscrizione (in base alla posizione di Azure).

Un esempio per Gli Stati Uniti orientali può essere simile al seguente:

  • Nome dell'area di lavoro Log Analytics: DefaultWorkspace-GUID-EUS<>
  • Nome gruppo di risorse: DefaultResourceGroup-EUS

Eseguire il comando seguente per ottenere un ID risorsa dell'area di lavoro Log Analytics preesistente:

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

Per distribuire Informazioni dettagliate sui contenitori e visualizzare i dati nell'area di lavoro Log Analytics applicabile, sono necessarie determinate assegnazioni di ruolo nell'account. Ad esempio, l'assegnazione di ruolo "Collaboratore". Vedere le istruzioni per l'assegnazione dei ruoli obbligatori:

  • Ruolo Collaboratore Log Analytics: autorizzazioni necessarie per abilitare il monitoraggio dei contenitori in un cluster CNF (con provisioning).
  • Ruolo lettore di Log Analytics: non membri del ruolo Collaboratore Log Analytics, ricevere le autorizzazioni per visualizzare i dati nell'area di lavoro Log Analytics dopo aver abilitato il monitoraggio dei contenitori.

Installare l'estensione del cluster

Accedere ad Azure Cloud Shell per accedere al cluster:

az login

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

Distribuire ora l'estensione Container Insights in un cluster Nexus Kubernetes di cui è stato effettuato il provisioning usando uno dei due comandi seguenti:

Con l'area di lavoro Log Analytics creata in modo preliminare dal cliente

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

Usare l'area di lavoro Log Analytics predefinita

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

Convalidare l'estensione cluster

Convalidare la corretta distribuzione dell'abilitazione degli agenti di monitoraggio nei cluster Nexus Kubernetes usando il comando seguente:

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

Cercare lo stato di provisioning "Succeeded" per l'estensione. Anche il comando "k8s-extension create" potrebbe aver restituito lo stato.

Personalizzare la raccolta di log e metriche

Container Insights offre funzionalità per gli utenti finali per ottimizzare la raccolta di log e metriche da Nexus Kubernetes Clusters--Configurare la raccolta dati dell'agente di Informazioni dettagliate contenitori.

Risorse aggiuntive

  • Esaminare la documentazione delle cartelle di lavoro e quindi usare le cartelle di lavoro Operator Nexus di esempio Operator Nexus.
  • Vedere Avvisi di Monitoraggio di Azure, come creare regole di avviso di Monitoraggio di Azure e usare modelli di avviso Operator Nexus di esempio.