你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
监视 Nexus Kubernetes 群集
每个 Nexus Kubernetes 群集都包含多个层:
- 虚拟机 (VM)
- Kubernetes 层
- 应用程序 Pod
图:示例 Nexus Kubernetes 群集
在实例上,Nexus Kubernetes 群集附带可选的容器见解可观测性解决方案。 容器见解从 Nexus Kubernetes 群集和工作负载捕获日志和指标。 是否启用此工具或部署你自己的遥测堆栈,完全由你自行决定。
带有 Azure 监视工具的 Nexus Kubernetes 群集如下所示:
图:带有监视工具的 Nexus Kubernetes 群集
使用托管标识身份验证通过 CLI 载入扩展
有关开始使用 Azure CLI、如何跨多个操作系统安装以及如何安装 CLI 扩展的文档。
安装最新版本的必要 CLI 扩展。
监视 Nexus Kubernetes 群集 - VM 层
本操作指南提供了 Arc 将 Nexus Kubernetes 群集虚拟机连接到 Azure 并启用监视代理以使用 Azure 监视代理从这些 VM 收集系统日志的步骤和实用工具脚本。 这些说明进一步捕获有关如何将日志数据收集设置到 Log Analytics 工作区的详细信息。
以下资源为你提供支持:
arc-connect.env
:使用此模板文件创建包含的脚本所需的环境变量
export SUBSCRIPTION_ID=""
export SERVICE_PRINCIPAL_ID=""
export SERVICE_PRINCIPAL_SECRET=""
export RESOURCE_GROUP=""
export TENANT_ID=""
export LOCATION=""
export INSTALL_AZURE_MONITOR_AGENT="true"
export PROXY_URL=""
export NAMESPACE=""
export AZURE_MONITOR_AGENT_VERSION="1.24.2"
export CONNECTEDMACHINE_AZCLI_VERSION="0.6.0"
dcr.sh
:使用此脚本创建数据收集规则 (DCR) 来配置 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
:使用脚本创建策略,将 DCR 与资源组中所有已启用 Arc 的服务器关联
#!/bin/bash
set -e
SUBSCRIPTION_ID="${SUBSCRIPTION_ID:?SUBSCRIPTION_ID must be set}"
SERVICE_PRINCIPAL_ID="${SERVICE_PRINCIPAL_ID:?SERVICE_PRINCIPAL_ID must be set}"
SERVICE_PRINCIPAL_SECRET="${SERVICE_PRINCIPAL_SECRET:?SERVICE_PRINCIPAL_SECRET must be set}"
RESOURCE_GROUP="${RESOURCE_GROUP:?RESOURCE_GROUP must be set}"
TENANT_ID="${TENANT_ID:?TENANT_ID must be set}"
LOCATION="${LOCATION:?LOCATION must be set}"
DCR_NAME=${DCR_NAME:-${RESOURCE_GROUP}-syslog-dcr}
POLICY_NAME=${POLICY_NAME:-${DCR_NAME}-policy}
az login --service-principal -u "${SERVICE_PRINCIPAL_ID}" -p "${SERVICE_PRINCIPAL_SECRET}" -t "${TENANT_ID}"
az account set -s "${SUBSCRIPTION_ID}"
DCR=$(az monitor data-collection rule show --name "${DCR_NAME}" --resource-group "${RESOURCE_GROUP}" -o tsv --query id)
PRINCIPAL=$(az policy assignment create \
--name "${POLICY_NAME}" \
--display-name "${POLICY_NAME}" \
--resource-group "${RESOURCE_GROUP}" \
--location "${LOCATION}" \
--policy "d5c37ce1-5f52-4523-b949-f19bf945b73a" \
--assign-identity \
-p "{\"dcrResourceId\":{\"value\":\"${DCR}\"}}" \
-o tsv --query identity.principalId)
required_roles=$(az policy definition show -n "d5c37ce1-5f52-4523-b949-f19bf945b73a" --query policyRule.then.details.roleDefinitionIds -o tsv)
for roleId in $(echo "$required_roles"); do
az role assignment create \
--role "${roleId##*/}" \
--assignee-object-id "${PRINCIPAL}" \
--assignee-principal-type "ServicePrincipal" \
--scope /subscriptions/"$SUBSCRIPTION_ID"/resourceGroups/"$RESOURCE_GROUP"
done
install.sh
:在每个 VM 上安装 Azure 监视代理,以便从 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
先决条件 - VM
群集管理员对 Nexus Kubernetes 群集的访问权限。
若要使用已启用 Azure Arc 的服务器,请在订阅中注册以下 Azure 资源提供程序:
- Microsoft.HybridCompute
- Microsoft.GuestConfiguration
- Microsoft.HybridConnectivity
注册这些资源提供程序(如果以前未完成):
az account set --subscription "{the Subscription Name}"
az provider register --namespace 'Microsoft.HybridCompute'
az provider register --namespace 'Microsoft.GuestConfiguration'
az provider register --namespace 'Microsoft.HybridConnectivity'
- 根据需要将 Azure 服务主体分配给以下 Azure 内置角色。 将服务主体分配给具有要连接的计算机的 Azure 资源组:
角色 | 需要 |
---|---|
Azure Connected Machine 资源管理员或参与者 | 在资源组中连接已启用 Arc 的 Nexus Kubernetes 群集 VM 服务器并安装 Azure 监视代理 (AMA) |
监视参与者或参与者 | 在资源组中创建数据收集规则 (DCR),然后将其关联到已启用 Arc 的服务器 |
用户访问管理员、资源策略参与者或参与者 | 要使用 Azure 策略分配来确保 DCR 与已启用 Arc 的计算机关联时需要 |
Kubernetes 扩展参与者 | 为容器见解部署 K8 扩展时需要 |
环境设置
复制并运行包含的脚本。 可以在 Azure 门户的 Azure Cloud Shell 中运行脚本。 或者,可以从已安装 Kubernetes 命令行工具 (kubectl) 和 Azure CLI 的 Linux 命令提示符运行脚本。
在运行包含的脚本之前,请定义以下环境变量:
环境变量 | 说明 |
---|---|
SUBSCRIPTION_ID | 包含资源组的 Azure 订阅的 ID |
RESOURCE_GROUP | 在其中创建已启用 Arc 的服务器和关联资源的资源组名称 |
LOCATION | 在其中创建已启用 Arc 的服务器和关联资源的 Azure 区域 |
SERVICE_PRINCIPAL_ID | 具有适当角色分配的 Azure 服务主体的 appId |
SERVICE_PRINCIPAL_SECRET | Azure 服务主体的身份验证密码 |
TENANT_ID | 服务主体所在的租户目录的 ID |
PROXY_URL | 用于连接到 Azure 服务的代理 URL |
命名空间 | 在其中创建 Kubernetes 项目的命名空间 |
为方便起见,可以修改模板文件 arc-connect.env
来设置环境变量值。
# Apply the modified values to the environment
./arc-connect.env
添加数据收集规则 (DCR)
将已启用 Arc 的服务器与 DCR 相关联,以便将日志数据收集到 Log Analytics 工作区中。 可以通过 Azure 门户或 CLI 创建 DCR。 此处提供了有关创建 DCR 以从 VM 收集数据的信息。
包含的 dcr.sh
脚本将在指定的资源组中创建一个 DCR,用于配置日志收集。
根据 DCR 创建或标识用于日志数据引入的 Log Analytics 工作区。 将环境变量 LAW_RESOURCE_ID 设置为其资源 ID。 检索已知 Log Analytics 工作区名称的资源 ID:
export LAW_RESOURCE_ID=$(az monitor log-analytics workspace show -g "${RESOURCE_GROUP}" -n <law name> --query id -o tsv)
- 运行 dcr.sh 脚本。 它在指定的名为 ${RESOURCE_GROUP}-syslog-dcr 的资源组中创建 DCR
./dcr.sh
从 Azure 门户或 CLI 查看/管理 DCR。 默认情况下,Linux Syslog 日志级别设置为“INFO”。 可以根据需要更改日志级别。
注意
手动或通过策略关联在创建 DCR 之前创建的服务器。 请参阅修正任务。
将已启用 Arc 的服务器资源关联到 DCR
将已启用 Arc 的服务器资源关联到已创建的 DCR,以便日志流向 Log Analytics 工作区。 有一些选项可用于将服务器与 DCR 关联。
使用 Azure 门户或 CLI 将选定的已启用 Arc 的服务器关联到 DCR
在 Azure 门户中,使用“资源”部分将已启用 Arc 的服务器资源添加到 DCR。
使用此链接,了解有关通过 Azure CLI 关联资源的信息。
使用 Azure 策略管理 DCR 关联
将策略分配给资源组以强制实施关联。 有一个内置策略定义,用于将 Linux Arc 计算机与 DCR 相关联。 使用 DCR 作为参数将策略分配给资源组。 它确保资源组中所有已启用 Arc 的服务器与同一 DCR 关联。
在 Azure 门户中,从策略定义页中选择 Assign
按钮。
为方便起见,提供的 assign.sh
脚本将内置策略分配给指定资源组和使用 dcr.sh
脚本创建的 DCR。
- 确保服务主体的环境设置和角色先决条件正确,以便服务主体执行策略和角色分配。
- 使用添加数据收集规则部分中所述的
dcr.sh
脚本在资源组中创建 DCR。 - 运行
assign.sh
脚本。 它创建策略分配和必要的角色分配。
./assign.sh
安装 Azure 监视代理
使用包含的 install.sh
在 Nexus Kubernetes 群集上创建 Kubernetes DaemonSet。
它将 Pod 部署到每个群集节点并安装 Azure 监视代理 (AMA)。
daemonSet
还包括监视服务器连接和 AMA 进程的运行情况探测。
注意
若要安装 Azure 监视代理,必须先通过 Arc 连接 Nexus Kubernetes 群集 VM。 如果使用最新版本的捆绑包,则此过程将自动执行。 但是,如果你使用的捆绑包版本默认不支持群集 VM Arc 注册,则需要将群集升级到最新捆绑包版本。 有关版本捆绑包的详细信息,请参阅 Nexus Kubernetes 群集支持的版本
- 按照环境设置中指定的值设置环境。 设置 Nexus Kubernetes 群集 VM 的当前
kubeconfig
上下文。 - 允许
Kubectl
访问 Nexus Kubernetes 群集。注意
创建 Nexus Kubernetes 群集时,Nexus 会自动创建专用于存储群集资源的托管资源组,在此组中,会建立 Arc 连接的群集资源。
kubeconfig
。 使用相关 Microsoft Entra 实体登录到 Azure CLI 后,可以获取从任意位置(甚至在群集周围的防火墙以外)与群集通信所需的kubeconfig
。设置
CLUSTER_NAME
、RESOURCE_GROUP
和SUBSCRIPTION_ID
变量。CLUSTER_NAME="myNexusK8sCluster" RESOURCE_GROUP="myResourceGroup" SUBSCRIPTION_ID=<set the correct subscription_id>
查询具有
az
的托管资源组并将其存储在MANAGED_RESOURCE_GROUP
中az account set -s $SUBSCRIPTION_ID MANAGED_RESOURCE_GROUP=$(az networkcloud kubernetescluster show -n $CLUSTER_NAME -g $RESOURCE_GROUP --output tsv --query managedResourceGroupConfiguration.name)
以下命令会启动 connectedk8s 代理,你可以通过该代理连接到指定 Nexus Kubernetes 群集的 Kubernetes API 服务器。
az connectedk8s proxy -n $CLUSTER_NAME -g $MANAGED_RESOURCE_GROUP &
使用
kubectl
将请求发送到群集:kubectl get pods -A
现在应会看到来自群集的响应,其中包含所有节点的列表。
注意
如果看到错误消息“无法将访问令牌发布到客户端代理,无法连接到 MSI”,则可能需要执行
az login
以使用 Azure 重新进行身份验证。 - 使用对 Nexus Kubernetes 群集的 kubectl 访问权限从命令提示符运行
install.sh
脚本。
该脚本将 daemonSet
部署到群集。 按如下所示监视进度:
# Run the install script and observe results
./install.sh
kubectl get pod --selector='name=naks-vm-telemetry'
kubectl logs <podname>
完成后,系统会记录消息“已成功配置服务器监视”。
注意
将这些连接的服务器关联到 DCR。 配置策略后,观察 Azure Log Analytics 工作区中的日志可能会有一些延迟
监视 Nexus Kubernetes 群集 - K8 层
先决条件 - Kubernetes
运营商应确保在 Nexus Kubernetes 群集上配置监视工具有某些先决条件。
容器见解将其数据存储在 Log Analytics 工作区中。 日志数据流入在“添加数据收集规则 (DCR)”部分中介绍的初始脚本期间提供的资源 ID 的工作区。 否则,数据会流入与订阅关联的资源组中的默认工作区(基于 Azure 位置)。
美国东部的示例如下所示:
- Log Analytics 工作区名称:DefaultWorkspace-GUID-EUS<>
- 资源组名称:DefaultResourceGroup-EUS
运行以下命令以获取预先存在的 Log Analytics 工作区资源 ID:
az login
az account set --subscription "<Subscription Name or ID the Log Analytics workspace is in>"
az monitor log-analytics workspace show --workspace-name "<Log Analytics workspace Name>" \
--resource-group "<Log Analytics workspace Resource Group>" \
-o tsv --query id
若要在适用的 Log Analytics 工作区中部署容器见解并查看数据,需要在帐户中分配某些角色。 例如,“参与者”角色分配。 请参阅分配所需的角色的说明:
- Log Analytics 参与者角色:在 CNF(预配)群集上启用容器监视所需的权限。
- Log Analytics 读者角色:非 Log Analytics 参与者角色的成员在启用容器监视后将获得查看 Log Analytics 工作区中的数据的权限。
安装群集扩展
登录到 Azure Cloud Shell 以访问群集:
az login
az account set --subscription "<Subscription Name or ID the Provisioned Cluster is in>"
现在,你使用以下两个命令之一在预配的 Nexus Kubernetes 群集上部署容器见解扩展:
使用客户预创建的 Log Analytics 工作区
az k8s-extension create --name azuremonitor-containers \
--cluster-name "<Nexus Kubernetes cluster Name>" \
--resource-group "<Nexus Kubernetes cluster Resource Group>" \
--cluster-type connectedClusters \
--extension-type Microsoft.AzureMonitor.Containers \
--release-train preview \
--configuration-settings logAnalyticsWorkspaceResourceID="<Log Analytics workspace Resource ID>" \
amalogsagent.useAADAuth=true
使用默认 Log Analytics 工作区
az k8s-extension create --name azuremonitor-containers \
--cluster-name "<Nexus Kubernetes cluster Name>" \
--resource-group "<Nexus Kubernetes cluster Resource Group>" \
--cluster-type connectedClusters \
--extension-type Microsoft.AzureMonitor.Containers \
--release-train preview \
--configuration-settings amalogsagent.useAADAuth=true
验证群集扩展
使用以下命令验证监视代理在 Nexus Kubernetes 群集上的启用是否成功部署:
az k8s-extension show --name azuremonitor-containers \
--cluster-name "<Nexus Kubernetes cluster Name>" \
--resource-group "<Nexus Kubernetes cluster Resource Group>" \
--cluster-type connectedClusters
查找扩展的“已成功”预配状态。 “k8s-extension create”命令也可能返回了状态。
自定义日志和指标收集
容器见解为最终用户提供了微调 Nexus Kubernetes 群集的日志和指标收集的功能 - 配置容器见解代理数据收集。
额外资源
- 查看工作簿文档,然后可以使用 Operator Nexus 遥测示例 Operator Nexus 工作簿。
- 查看 Azure Monitor 警报、如何创建 Azure Monitor 警报规则以及使用示例 Operator Nexus 警报模板。