Surveiller un cluster Nexus Kubernetes

Chaque cluster Nexus Kubernetes est constitué de plusieurs couches :

  • Machines virtuelles
  • Couche Kubernetes
  • Pods d’application

Screenshot of Sample Nexus Kubernetes cluster.

Illustration : exemple de cluster Nexus Kubernetes

Sur une instance, les clusters Nexus Kubernetes sont fournis avec une solution d’observabilité Container Insightsfacultative. Container Insights capture les journaux et les métriques des clusters Nexus Kubernetes et des charges de travail. Il vous appartient d'activer cet outil ou de déployer votre propre pile de télémétrie.

Le cluster Nexus Kubernetes avec l’outil de surveillance Azure ressemble à ce qui suit :

Screenshot of Nexus Kubernetes cluster with Monitoring Tools.

Illustration : cluster Nexus Kubernetes avec outils de surveillance

Intégration d’extension à l’interface CLI en utilisant l’authentification de l’identité managée

Documentation pour commencer avec Azure CLI, comment l’installer sur plusieurs systèmes d’exploitation et comment installer des extensions CLI.

Installez la dernière version des extensions CLI nécessaires.

Surveiller un cluster Nexus Kubernetes : couche de machine virtuelle

Ce guide pratique fournit des étapes et des scripts utilitaires pour connecter les machines virtuelles de cluster Nexus Kubernetes à Azure et activer les agents de surveillance pour la collecte des journaux système à partir de ces machines virtuelles en utilisant Azure Monitoring Agent. Les instructions décrivent en détail comment configurer la collecte de données dans un espace de travail Log Analytics.

Les ressources suivantes vous apportent un soutien :

  • arc-connect.env : utilisez ce fichier de modèle pour créer des variables d’environnement nécessaires aux scripts inclus

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 : utilisez ce script pour créer une règle de collecte de données (DCR) pour configurer la collecte 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 : utilisez le script pour créer une stratégie pour associer la DCR à tous les serveurs avec Arc dans un groupe de ressources

#!/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 : installez Azure Monitoring Agent sur chaque machine virtuelle pour collecter des données de surveillance à partir de machines virtuelles Azure.
#!/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

Conditions préalables de machines virtuelles

  • Accès de l’administrateur du cluster au cluster Nexus Kubernetes.

  • Pour utiliser des serveurs Azure Arc, enregistrez les fournisseurs de ressources Azure suivants dans votre abonnement :

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

Enregistrez ces fournisseurs de ressources, si ce n’est pas déjà fait :

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'
  • Attribuez un principal de service Azure aux rôles intégrés Azure suivants, si nécessaire. Attribuez le principal de service au groupe de ressources Azure qui contient les machines à connecter :
Rôle Nécessaire pour
Administrateur des ressources de la machine connectée à Azure ou Contributeur Connecter le serveur de machines virtuelles Nexus Kubernetes cluster compatible avec Arc dans le groupe de ressources et installer l'agent de surveillance Azure (AMA)
Contributeur de supervision ou Contributeur Créez une règle de collecte de données (DCR) dans le groupe de ressources et associez des serveurs avec Arc à celui-ci
Administrateur de l’accès utilisateur et Contributeur de stratégie de ressources ou Contributeur Nécessaire si vous souhaitez utiliser des attributions de stratégie Azure pour vous assurer qu’un DCR est associé à des machines avec Arc
Contributeur d’extension Kubernetes Nécessaire pour déployer l’extension K8s pour Container Insights

Configuration de l’environnement

Copiez et exécutez les scripts inclus. Vous pouvez les exécuter depuis un Azure Cloud Shell, dans le portail Azure. Vous pouvez également les exécuter à partir d'une invite de commande Linux où l'outil de ligne de commande Kubernetes (kubectl) et Azure CLI sont installés.

Avant d’exécuter les scripts inclus, définissez les variables d’environnement suivantes :

Variable d’environnement Description
SUBSCRIPTION_ID L’identifiant de l’abonnement Azure qui contient le groupe de ressources
RESOURCE_GROUP Le nom du groupe de ressources dans lequel le serveur Arc et les ressources associées sont créés
LOCATION La région Azure dans laquelle les serveurs Arc et les ressources associées sont créés
SERVICE_PRINCIPAL_ID L’appId du principal de service Azure avec les attributions de rôles appropriées
SERVICE_PRINCIPAL_SECRET Le mot de passe d’authentification pour le principal de service Azure
TENANT_ID L’identifiant du répertoire du locataire dans lequel le principal de service existe
PROXY_URL L’URL du proxy à utiliser pour se connecter aux services Azure
ESPACE DE NOMS L’espace de noms dans lequel les artefacts Kubernetes sont créés

Pour plus de commodité, vous pouvez modifier le fichier de modèle, arc-connect.env, pour définir les valeurs des variables d’environnement.

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

Ajouter une règle de collecte de données (DCR)

Associez les serveurs Arc à une DCR pour permettre la collecte de données de journalisation dans un espace de travail Log Analytics. Vous pouvez créer la DCR via le portail Azure ou l’interface CLI. Des informations sur la création d’une DCR pour collecter des données à partir des machines virtuelles sont disponibles ici.

Le script dcr.sh inclus crée une DCR, dans le groupe de ressources spécifié, qui configure la collecte de journaux.

  1. Assurez-vous que la configuration de l’environnement et les prérequis de rôle appropriés pour le principal de service. La DCR est créée dans le groupe de ressources spécifié.

  2. Créez ou identifiez un espace de travail Log Analytics pour l'ingestion des données de journal conformément à la DCR. Définissez une variable d’environnement, LAW_RESOURCE_ID à son identifiant de ressource. Récupérez l’identifiant de la ressource pour un nom d’espace de travail Log Analytics connu :

export LAW_RESOURCE_ID=$(az monitor log-analytics workspace show -g "${RESOURCE_GROUP}" -n <law name> --query id -o tsv)
  1. Exécutez le script dcr.sh. Il crée une DCR dans le groupe de ressources spécifié avec le nom ${RESOURCE_GROUP}-syslog-dcr
./dcr.sh

Affichez ou gérez la DCR à partir du portail Azure ou de l’interface CLI. Par défaut, le niveau de journalisation de Linux Syslog est défini sur « INFO ». Vous pouvez modifier le niveau de journal en fonction des besoins.

Remarque

Associez manuellement, ou via une stratégie, les serveurs créés avant la création de la DCR. Consultez tâche de correction.

Associez les ressources de serveur Arc à la DCR

Associez les ressources serveur activées par Arc à la DCR créée pour que les journaux soient transmis à l'espace de travail Log Analytics. Il existe des options pour associer les serveurs aux DCR.

Utilisez le portail Azure ou l’interface CLI pour associer les serveurs Arc sélectionnés à la DCR

Dans le portail Azure, ajoutez une ressource serveur compatible avec Arc à la DCR en utilisant la section Ressources.

Utilisez ce lien pour plus d’informations sur l’association des ressources via Azure CLI.

Utilisez la stratégie Azure pour gérer les associations DCR

Attribuez une stratégie au groupe de ressources pour appliquer l’association. Il existe une définition de stratégie intégrée pour associer des machines Linux Arc à une DCR. Attribuez la stratégie au groupe de ressources avec une DCR en tant que paramètre. Elle garantit l’association de tous les serveurs Arc, au sein du groupe de ressources, avec la même DCR.

Dans le portail Azure, sélectionnez le bouton Assign dans la page de définition de stratégie.

Pour plus de commodité, le script assign.sh fourni affecte la stratégie intégrée au groupe de ressources et à la DCR spécifiés créés avec le script dcr.sh.

  1. Assurez-vous que la configuration de l’environnement et les prérequis de rôle appropriés pour que le principal de service puisse procéder à l’attribution des stratégies et des rôles.
  2. Créez la DCR, dans le groupe de ressources, à l’aide d’un script dcr.sh, comme décrit dans la section Ajout d’une règle de collecte de données.
  3. Exécutez le script assign.sh. Il crée l’attribution de la stratégie et les attributions de rôles nécessaires.
./assign.sh

Installer un agent de surveillance Azure

Utilisez le install.sh inclus qui crée un daemonSet Kubernetes sur le cluster Kubernetes Nexus. Il déploie un pod sur chaque nœud de cluster et installe Azure Monitoring Agent (AMA). Le daemonSet inclut également une sonde liveness qui surveille la connexion du serveur et les processus AMA.

Remarque

Pour installer Azure Monitoring Agent, vous devez d'abord connecter à l'Arc les machines virtuelles du cluster Nexus Kubernetes. Ce processus est automatisé si vous utilisez la dernière version de l’offre groupée. Toutefois, si l’offre groupée de versions que vous utilisez ne prend pas en charge par défaut l'enrôlement de machine virtuelle Arc en cluster, vous devrez mettre à niveau votre cluster vers le dernier pack de versions. Pour plus d’informations sur l’offre groupée de versions, reportez-vous aux versions prises en charge du cluster Kubernetes Nexus

  1. Définissez l’environnement comme spécifié dans le programme d’installation de l’environnement. Définissez le contexte kubeconfig actuel pour les machines virtuelles de cluster Nexus Kubernetes.
  2. Autoriser à Kubectl l’accès au cluster Nexus Kubernetes.

    Remarque

    Lorsque vous créez un cluster Kubernetes Nexus, Nexus crée automatiquement un groupe de ressources managé dédié au stockage des ressources de cluster. Au sein de ce groupe, la ressource de cluster connectée à Arc est établie.

    Pour accéder à votre cluster, vous devez configurer le paramètre kubeconfig de connexion au cluster. Après la connexion à Azure CLI avec l’entité Microsoft Entra appropriée, vous pouvez obtenir le paramètre kubeconfig nécessaire pour communiquer avec le cluster n’importe où, même en dehors du pare-feu qui l’entoure.
    1. Définissez les variables CLUSTER_NAME, RESOURCE_GROUP et SUBSCRIPTION_ID.

      CLUSTER_NAME="myNexusK8sCluster"
      RESOURCE_GROUP="myResourceGroup"
      SUBSCRIPTION_ID=<set the correct subscription_id>
      
    2. Interroger un groupe de ressources managé avec az, puis stocker dans 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. La commande suivante démarre un proxy connectedk8s qui vous permet de vous connecter au serveur d’API Kubernetes du cluster Nexus Kubernetes spécifié.

      az connectedk8s proxy -n $CLUSTER_NAME  -g $MANAGED_RESOURCE_GROUP &
      
    4. Utilisez kubectl pour envoyer les requêtes au cluster :

      kubectl get pods -A
      

      Une réponse du cluster contenant la liste de tous les nœuds doit maintenant s’afficher.

    Notes

    Si le message d’erreur « Nous n’avons pas pu publier le jeton d’accès dans le proxy client. Nous n’avons pas pu nous connecter à MSI » s’affiche, vous devrez peut-être effectuer une opération az login pour vous authentifier de nouveau auprès d’Azure.

  3. Exécutez le script install.sh à partir de l’invite de commandes avec l’accès kubectl au cluster Kubernetes Nexus.

Le script déploie le daemonSet sur le cluster. Monitorez la progression comme suit :

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

Une fois l’opération terminée, le système affiche le message « Surveillance du serveur configurée avec succès ».

Remarque

Associez ces serveurs connectés à la DCR. Après avoir configuré une politique, il se peut que l'observation des journaux dans l'espace de travail Azure Log Analytics soit retardée

Surveiller un cluster Nexus Kubernetes : couche K8s

Prérequis : Kubernetes

L'opérateur doit s'assurer de certains prérequis pour configurer les outils de monitoring sur les Nexus Kubernetes Clusters.

Container Insights stocke ses données dans un espace de travail Log Analytics. Les données de journal sont transmises dans l’espace de travail dont vous avez fourni l’identifiant de ressource pendant les scripts initiaux couverts dans la section « Ajouter une règle de collecte de données (DCR) ». Dans le cas contraire, les données sont acheminées vers un espace de travail par défaut dans le groupe de ressources associé à votre abonnement (en fonction de l'emplacement d'Azure).

Un exemple pour USA Est peut se présenter comme suit :

  • Nom de l’espace de travail Log Analytics : DefaultWorkspace-<GUID>-EUS
  • Nom du groupe de ressources : DefaultResourceGroup-EUS

Exécutez la commande suivante pour obtenir un identifiant de ressource d’espace de travail Log Analytics pré-existant :

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

Le déploiement de Container Insights et l'affichage des données dans l'espace de travail Log Analytics applicable requièrent certaines attributions de rôles dans votre compte. Par exemple, l’attribution de rôle « Contributeur ». Consultez les instructions pour l’attribution de rôles requis :

  • Rôle Contributeur Log Analytics : autorisations nécessaires pour activer la surveillance des conteneurs sur un cluster CNF (provisionné).
  • Rôle Lecteur Log Analytics : non membre du rôle Contributeur Log Analytics, recevez des autorisations pour afficher les données dans l’espace de travail Log Analytics une fois que vous avez activé la surveillance du conteneur.

Installation de l’extension du cluster

Connectez-vous à Azure Cloud Shell pour accéder au cluster :

az login

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

Maintenant, déployez l'extension Container Insights sur un cluster Nexus Kubernetes provisionné en utilisant l'une des deux commandes suivantes :

Avec l’espace de travail Log Analytics pré-créé par le client

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

Utiliser l’espace de travail Log Analytics par défaut

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

Valider l’extension de cluster

Validez le déploiement réussi de l'activation des agents de surveillance sur les clusters Nexus Kubernetes à l'aide de la commande suivante :

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

Recherchez l’état d’approvisionnement « Réussi » pour l’extension. La commande « créer une k8s-extension » peut également avoir renvoyé l’état.

Personnaliser la collection de journaux et de métriques

Container Insights fournit des fonctionnalités aux utilisateurs finaux pour affiner la collecte des journaux et des métriques à partir des clusters Kubernetes Nexus : Configurer la collecte de données de l’agent Container Insights.

Ressources supplémentaires