Supervisión del clúster de Nexus Kubernetes

Cada clúster de Nexus Kubernetes consta de varias capas:

  • Virtual Machines (VM)
  • Capa de Kubernetes
  • Pods de la aplicación

Screenshot of Sample Nexus Kubernetes cluster.

Figura: clúster de Nexus Kubernetes de ejemplo

En una instancia, los clústeres de Nexus Kubernetes se entregan con una solución opcional de observabilidad de Container Insights. Container Insights captura los registros y las métricas de los clústeres y cargas de trabajo de Nexus Kubernetes. Queda a su discreción habilitar estas herramientas o implementar su propia pila de telemetría.

El clúster de Nexus Kubernetes con la herramienta de supervisión de Azure tiene el siguiente aspecto:

Screenshot of Nexus Kubernetes cluster with Monitoring Tools.

Figura: clúster de Nexus Kubernetes con herramientas de supervisión

Incorporación de extensiones con la CLI mediante la autenticación de identidad administrada

Documentación para empezar con la CLI de Azure, cómo instalarla en varios sistemas operativos y cómo instalar extensiones de la CLI.

Instale la versión más reciente de las extensiones necesarias de la CLI.

Supervisar el clúster de Nexus Kubernetes: capa de máquina virtual

En esta guía paso a paso se describen los pasos y los scripts de utilidad para permitir que Arc conecte las máquinas virtuales del clúster Nexus Kubernetes a Azure y habilite los agentes de supervisión para la recopilación de registros del sistema de estas máquinas virtuales mediante el agente de supervisión de Azure. Las instrucciones capturan más detalles sobre cómo configurar la recopilación de datos de registro en un área de trabajo de Log Analytics.

Los siguientes recursos proporcionan soporte técnico:

  • arc-connect.env: use este archivo de plantilla para crear variables de entorno necesarias para los scripts incluidos

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: use este script para crear una regla de recopilación de datos (DCR) para configurar la recopilación de 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: use el script para crear una directiva para asociar la DCR a todos los servidores habilitados para Arc en un grupo de recursos

#!/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: instale Azure Monitoring Agent en cada máquina virtual para recopilar datos de supervisión de 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

Requisitos previos de VM

  • Acceso de administrador de clústeres al clúster de Nexus Kubernetes.

  • Para usar servidores habilitados para Azure Arc, registre los siguientes proveedores de recursos de Azure en su suscripción:

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

Registre estos proveedores de recursos, si no lo ha hecho anteriormente:

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'
  • Asigne una entidad de servicio de Azure a los siguientes roles integrados de Azure, según sea necesario. Asigne la entidad de servicio al grupo de recursos de Azure que tiene las máquinas que se van a conectar:
Role Necesario para
Administrador de recursos de Azure Connected Machine o Colaborador Conectar servidor de VM de clúster de Nexus Kubernetes habilitado para Arc en el grupo de recursos e instalar el agente de supervisión de Azure (AMA)
Colaborador de supervisión o Colaborador Crear una regla de recopilación de datos (DCR) en el grupo de recursos y asociar servidores habilitados para Arc a él
Administrador de acceso de usuario y Colaborador de directiva de recursos o Colaborador Es necesario si desea usar la(s) asignación(es) de directiva(s) de Azure para asegurarse de que una DCR está asociada a máquinas habilitadas para Arc
Kubernetes Extension Contributor Necesario para implementar la extensión K8s para Container Insights

Configuración del entorno

Copie y ejecute los scripts incluidos. Puede ejecutarlos desde Azure Cloud Shell en Azure Portal. También puede ejecutarlos desde un símbolo del sistema de Linux donde se instala la herramienta de línea de comandos de Kubernetes (kubectl) y la CLI de Azure.

Antes de ejecutar los scripts incluidos, defina las siguientes variables de entorno:

Variable de entorno Descripción
SUBSCRIPTION_ID Id. de la suscripción de Azure que contiene el grupo de recursos
RESOURCE_GROUP Nombre del grupo de recursos donde se crean el servidor habilitado para Arc y los recursos asociados
LOCATION Región de Azure donde se crean los servidores habilitados para Arc y los recursos asociados
SERVICE_PRINCIPAL_ID AppId de la entidad de servicio de Azure con la(s) asignación(es) de roles adecuada(s)
SERVICE_PRINCIPAL_SECRET Contraseña de autenticación de la entidad de servicio de Azure
TENANT_ID Id. del directorio del inquilino donde existe la entidad de servicio
PROXY_URL Dirección URL del proxy que se va a usar para conectarse a los servicios de Azure
Espacio de nombres Espacio de nombres donde se crean los artefactos de Kubernetes

Para mayor comodidad, puede modificar el archivo de plantilla, arc-connect.env, para establecer los valores de la variable de entorno.

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

Agregue una regla de recopilación de datos (DCR)

Asocie los servidores habilitados para Arc a una DCR para habilitar la recopilación de datos de registro en un área de trabajo de Log Analytics. Puede crear la DCR a través de Azure Portal o la CLI. La información sobre cómo crear una DCR para recopilar datos de las máquinas virtuales está disponible aquí.

El script de dcr.sh incluido crea una DCR, en el grupo de recursos especificado, que configurará la recopilación de registros.

  1. Asegúrese de que la configuración del entorno y los requisitos previos de rol para la entidad de servicio son adecuados. La DCR se crea en el grupo de recursos especificado.

  2. Cree o identifique un área de trabajo de Log Analytics para la ingesta de datos de registro según la DCR. Establezca una variable de entorno LAW_RESOURCE_ID en su id. de recurso. Recupere el id. de recurso de un nombre del área de trabajo de Log Analytics conocido:

export LAW_RESOURCE_ID=$(az monitor log-analytics workspace show -g "${RESOURCE_GROUP}" -n <law name> --query id -o tsv)
  1. Ejecute el script dcr.sh. Crea una DCR en el grupo de recursos especificado con el nombre ${RESOURCE_GROUP}-syslog-dcr
./dcr.sh

Vea o administre la DCR desde Azure Portal o la CLI. De forma predeterminada, el nivel de registro de Syslog de Linux se establece en "INFO". Puede cambiar el nivel de registro según sea necesario.

Nota:

Manualmente, o a través de una directiva, asocie los servidores creados antes de la creación de la DCR. Consulte tarea de corrección.

Asociar recursos de servidor habilitados para Arc a DCR

Asocie los recursos de servidor habilitados para Arc a la DCR creada para que los registros fluyan al área de trabajo de Log Analytics. Hay opciones para asociar servidores a las DCR.

Usar Azure Portal o la CLI para asociar servidores habilitados para Arc seleccionados a la DCR

En Azure Portal, agregue el recurso de servidor habilitado para Arc a la DCR mediante su sección Recursos.

Use este vínculo para obtener información sobre cómo asociar los recursos a través de la CLI de Azure.

Usar la directiva de Azure para administrar asociaciones de DCR

Asigne una directiva al grupo de recursos para aplicar la asociación. Hay una definición de directiva integrada para asociar máquinas de Arc de Linux a una DCR. Asigne la directiva al grupo de recursos con la DCR como parámetro. Garantiza la asociación de todos los servidores habilitados para Arc, dentro del grupo de recursos, con la misma DCR.

En Azure Portal, seleccione el botón Assign en la página de definición de directiva.

Para mayor comodidad, el script assign.sh proporcionado asigna la directiva integrada al grupo de recursos especificado y a la DCR creada con el script dcr.sh.

  1. Asegúrese de que la configuración del entorno y los requisitos previos del rol son los adecuados para que la entidad de servicio pueda asignar directivas y roles.
  2. Cree la DCR, en el grupo de recursos, mediante el script dcr.sh tal y como se describe en la sección Agregar una regla de recopilación de datos.
  3. Ejecute el script assign.sh. Crea la asignación de directivas y las asignaciones de roles necesarias.
./assign.sh

Instalar el agente de supervisión de Azure

Use el install.sh incluido, que crea un DaemonSet de Kubernetes en el clúster de Nexus Kubernetes. Implementa un pod en cada nodo de clúster e instala el agente de supervisión de Azure (AMA). El daemonSet también incluye un sondeo de ejecución que supervisa la conexión del servidor y los procesos de AMA.

Nota:

Para instalar el agente de supervisión de Azure, primero debe conectar las máquinas virtuales del clúster de Nexus Kubernetes. Este proceso se automatiza si usa la agrupación de versiones más reciente. Sin embargo, si la agrupación de versiones que usa no admite la inscripción de Arc de VM de clúster de forma predeterminada, deberá actualizar el clúster a la agrupación de versiones más reciente. Para obtener más información sobre la agrupación de versiones, consulte Versiones compatibles de clúster de Nexus Kubernetes

  1. Establezca el entorno tal como se especifica en Configuración del entorno. Establezca el contexto kubeconfig actual para las máquinas virtuales del clúster de Nexus Kubernetes.
  2. Permita el acceso Kubectl al clúster de Nexus Kubernetes.

    Nota:

    Al crear un clúster de Kubernetes de Nexus, Nexus crea automáticamente un grupo de recursos administrado dedicado a almacenar los recursos del clúster. Dentro de este grupo, se establece el recurso de clúster conectado a Arc.

    Para acceder al clúster, es necesario configurar la conexión del clúster kubeconfig. Después de iniciar sesión en la CLI de Azure con la entidad Microsoft Entra pertinente, puede obtener el kubeconfig necesario para comunicarse con el clúster desde cualquier lugar, incluso fuera del firewall que lo rodea.
    1. Configure las variables CLUSTER_NAME, RESOURCE_GROUP y SUBSCRIPTION_ID.

      CLUSTER_NAME="myNexusK8sCluster"
      RESOURCE_GROUP="myResourceGroup"
      SUBSCRIPTION_ID=<set the correct subscription_id>
      
    2. Consulte el grupo de recursos administrados con az y almacénelo en 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. El siguiente comando inicia un proxy connectedk8s que le permite conectarse al servidor de la API de Kubernetes para el clúster Nexus Kubernetes especificado.

      az connectedk8s proxy -n $CLUSTER_NAME  -g $MANAGED_RESOURCE_GROUP &
      
    4. Use kubectl para enviar solicitudes al clúster:

      kubectl get pods -A
      

      Ahora debería ver una respuesta del clúster con la lista de todos los nodos.

    Nota

    Si aparece el mensaje de error " o se pudo enviar el token de acceso al proxy cliente. No se pudo conectar a MSI", es posible que tenga que realizar un az login para volver a autenticarse con Azure.

  3. Ejecute el script install.sh desde el símbolo del sistema con acceso kubectl al clúster de Nexus Kubernetes.

El script implementa daemonSet en el clúster. Supervise el progreso como se indica a continuación:

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

Al finalizar, el sistema registra el mensaje "Supervisión del servidor configurada correctamente".

Nota:

Asocie estos servidores conectados a la DCR. Después de configurar una directiva, puede haber algún retraso para observar los registros en el área de trabajo de Azure Log Analytics

Supervisar el clúster de Nexus Kubernetes: capa K8s

Requisitos previos de Kubernetes

Hay ciertos requisitos previos que el operador debe garantizar para configurar las herramientas de supervisión en clústeres de Nexus Kubernetes.

Container Insights almacena sus datos en un área de trabajo de Log Analytics. Los datos de registro fluyen al área de trabajo cuyo id. de recurso proporcionó durante los scripts iniciales descritos en la sección "Agregar una regla de recopilación de datos (DCR)". De lo contrario, los datos se embudan en un área de trabajo predeterminada en el grupo de recursos asociado a la suscripción (en función de la ubicación de Azure).

Un ejemplo para Este de EE. UU. puede tener el siguiente aspecto:

  • Nombre del área de trabajo de Log Analytics: DefaultWorkspace-<GUID>-EUS
  • Nombre del grupo de recursos: DefaultResourceGroup-EUS

Ejecute el comando siguiente para obtener un id. de recurso del área de trabajo de Log Analytics existente:

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

Para implementar Container Insights y ver los datos en el área de trabajo de Log Analytics aplicable, es necesario realizar determinadas asignaciones de roles en la cuenta. Por ejemplo, la asignación de roles "Colaborador". Consulte las instrucciones para asignar los roles necesarios:

  • Rol Colaborador de Log Analytics: permisos necesarios para habilitar la supervisión de contenedores en un clúster CNF (aprovisionado).
  • Rol Lector de Log Analytics: los usuarios que no cuentan con el rol Colaborador de Log Analytics reciben permisos para ver los datos en el área de trabajo de Log Analytics una vez que habilita la supervisión de contenedores.

Instalar la extensión de clúster

Inicie sesión en Azure Cloud Shell para acceder al clúster:

az login

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

Ahora, implemente la extensión de Container Insights en un clúster de Nexus Kubernetes aprovisionado mediante cualquiera de los dos comandos siguientes:

Con el área de trabajo de Log Analytics creada previamente por el 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

Usar el área de trabajo predeterminada de 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

Validar la extensión de clúster

Valide la implementación correcta de la habilitación de agentes de supervisión en clústeres de Nexus Kubernetes mediante el siguiente comando:

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

Busque un estado de aprovisionamiento "Correcto" para la extensión. Es posible que el comando "k8s-extension create" haya devuelto también el estado.

Personalizar recopilación de métricas y registros

Container Insights proporciona funcionalidad a los usuarios finales para ajustar la recopilación de registros y métricas de los clústeres de Nexus Kubernetes: Configurar recopilación de datos del agente de Container Insights.

Recursos adicionales