Go 配置提供程序

Azure 应用配置是一项托管服务,可帮助开发人员轻松且安全地集中管理其应用程序配置。 Go 配置提供程序库允许以托管方式从 Azure 应用配置存储加载配置。 此客户端库在 Azure SDK for Go 的基础上添加了其他 功能

加载配置

Azure 应用配置 Go 提供程序允许将配置值从 Azure 应用配置存储加载到 Go 应用程序中。 可以使用 Microsoft Entra ID 身份验证或连接字符串进行连接。

若要使用 Go 配置提供程序,请安装包:

go get github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration

从包调用 Load 函数 azureappconfiguration 以从 Azure 应用配置加载配置。 该 Load 函数接受身份验证选项和配置选项来自定义加载行为。

您可以使用 DefaultAzureCredential 或其他任何 令牌凭据实现,以对您的应用配置存储进行身份验证。 按照说明为凭据分配“应用程序配置数据读取者”角色。

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)

func main() {
	ctx := context.Background()

	// Get the endpoint from environment variable
	endpoint := os.Getenv("AZURE_APPCONFIG_ENDPOINT")

	// Create a credential using DefaultAzureCredential
	credential, err := azidentity.NewDefaultAzureCredential(nil)
	if err != nil {
		log.Fatalf("Failed to create credential: %v", err)
	}

	// Set up authentication options
	authOptions := azureappconfiguration.AuthenticationOptions{
		Endpoint:   endpoint,
		Credential: credential,
	}

	// Load configuration from Azure App Configuration
	appConfig, err := azureappconfiguration.Load(ctx, authOptions, nil)
	if err != nil {
		log.Fatalf("Failed to load configuration: %v", err)
	}
}

使用选择器加载特定键值

默认情况下,配置提供程序加载应用配置中没有标签的所有键值。 可以通过在结构中Selectors配置Options字段来有选择地加载键值。

options := &azureappconfiguration.Options{
	Selectors: []azureappconfiguration.Selector{
		{
			// Load configuration values with prefix "App:" and no label
			KeyFilter:   "App:*",
			LabelFilter: "",
		},
		{
			// Load configuration values with prefix "App:" and "Prod" label
			KeyFilter:   "App:*",
			LabelFilter: "Prod",
		},
	},
}

appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)

Selector 结构支持以下字段:

  • KeyFilter:确定要包含的配置密钥。 使用完全匹配、前缀匹配和 *逗号分隔的多个键。
  • LabelFilter:选择具有特定标签的键值。 如果为空,则加载无标签的键值。

注释

当多个选择器包含重叠键时,后续选择器优先于以前的选择器。

去除键中的前缀

加载具有特定前缀的配置值时,可以使用 TrimKeyPrefixes 此选项从配置中的密钥中删除这些前缀。 这会在你的应用程序中创建更清晰的配置密钥,同时保持应用程序配置存储的有序性。

options := &azureappconfiguration.Options{
	// Load configuration values with prefix "TestApp:" and trim the prefix
	Selectors: []azureappconfiguration.Selector{
		{
			KeyFilter: "TestApp:*",
		},
	},
	TrimKeyPrefixes: []string{"TestApp:"},
}

appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)

例如,如果你的应用程序配置存储区包含名为 TestApp:Settings:Message 的键,它将可以在剪裁掉 Settings:Message 前缀之后在应用程序中作为 TestApp: 被访问。

JSON 内容类型处理

可以在应用配置中创建 JSON 键值。 读取包含内容类型 "application/json" 的键值时,配置提供程序会将它分析为嵌套结构。 有关详细信息,请转到 “使用内容类型”在应用配置中存储 JSON 键值

使用配置

AzureAppConfiguration函数返回Load的类型提供了几种方法来访问配置数据:

非结构

该方法 Unmarshal 提供了一种类型安全的方法来将配置值加载到 Go 结构中。 此方法可防止运行时错误键入的配置密钥,并使代码更易于维护。 该方法接受可选 ConstructionOptions 参数来自定义如何将配置键映射到结构字段。

type Config struct {
	Message string
	App     struct {
		Name     string
		Debug    bool
		Settings struct {
			Timeout    int
			RetryCount int
		}
	}
}

func main() {
	// ... load configuration ...

	// Create a configuration struct and unmarshal into it
	var config Config
	if err := appConfig.Unmarshal(&config, nil); err != nil {
		log.Fatalf("Failed to unmarshal configuration: %v", err)
	}

	// Access configuration values
	fmt.Printf("Message: %s\n", config.Message)
	fmt.Printf("App Name: %s\n", config.App.Name)
	fmt.Printf("Debug Mode: %t\n", config.App.Debug)
	fmt.Printf("Timeout: %d seconds\n", config.App.Settings.Timeout)
}

自定义键分隔符

可以使用 自定义配置键映射到结构字段的方式 ConstructionOptions。 当配置键使用与默认点不同的分隔符时,这非常有用(.):

// Configuration keys using colon separator: "App:Name", "App:Settings:Timeout"
constructionOptions := &azureappconfiguration.ConstructionOptions{
	Separator: ":",
}

var config Config
if err := appConfig.Unmarshal(&config, constructionOptions); err != nil {
	log.Fatalf("Failed to unmarshal configuration: %v", err)
}

结构ConstructionOptions支持以下分隔符:.、、,;-___、。 /: 如果未指定,则使用默认分隔符 .

获取原始 JSON 字节

该方法 GetBytes 将检索配置作为原始 JSON 数据,从而灵活地与 JSON 处理库或配置框架(例如 viper)集成。 此方法还接受用于控制密钥层次结构映射的可选 ConstructionOptions 参数。

// Get configuration as JSON bytes with default separator
jsonBytes, err := appConfig.GetBytes(nil)
if err != nil {
	log.Fatalf("Failed to get configuration as bytes: %v", err)
}

fmt.Println("Raw JSON Configuration:")
fmt.Println(string(jsonBytes))

// Get configuration with custom separator
constructionOptions := &azureappconfiguration.ConstructionOptions{
	Separator: ":",
}
jsonBytes, err = appConfig.GetBytes(constructionOptions)
if err != nil {
	log.Fatalf("Failed to get configuration as bytes: %v", err)
}

// Example: Use with viper
v := viper.New()
v.SetConfigType("json")
if err := v.ReadConfig(bytes.NewBuffer(jsonBytes)); err != nil {
	log.Fatalf("Failed to read config into viper: %v", err)
}

配置刷新

配置刷新使应用程序能够从应用程序配置存储区拉取最新值,而无需重启。 可以使用结构中的RefreshOptions字段配置刷新选项Options。 当服务器上检测到所选键值发生更改时,将更新加载的配置。 默认使用 30 秒刷新间隔,但你可以使用 Interval 属性重写此间隔。

options := &azureappconfiguration.Options{
	// Load all keys that start with `TestApp:` and have no label
	Selectors: []azureappconfiguration.Selector{
		{
			KeyFilter:   "TestApp:*",
			LabelFilter: "",
		},
	},
	// Trigger full configuration refresh when any selected key changes
	RefreshOptions: azureappconfiguration.KeyValueRefreshOptions{
		Enabled:  true,
		// Check for changes no more often than every 60 seconds
		Interval: 60 * time.Second,
	},
}

appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)

仅仅是设置 RefreshOptions 不会自动刷新配置。 需要在实例上Refresh调用AzureAppConfiguration该方法来触发刷新。

// Trigger a refresh
if err := appConfig.Refresh(ctx); err != nil {
	log.Printf("Failed to refresh configuration: %v", err)
}

此设计可防止应用程序处于空闲状态时对应用程序配置发出不必要的请求。 应在发生应用程序活动时包含 Refresh 调用。 这称为活动驱动的配置刷新。 例如,可以在处理传入请求时或在执行复杂任务的迭代中调用 Refresh

注释

即使刷新调用因任何原因而失败,应用程序也会继续使用缓存的配置。 当配置的刷新间隔已过,并且应用程序活动触发刷新调用时,将再次尝试。 在配置的刷新间隔过去之前调用 Refresh 是一个空操作,因此,即使频繁调用,它的性能影响也很小。

刷新 Sentinel 键

Sentinel 键是完成所有其他键的更改后更新的键。 配置提供程序将监视 sentinel 键,而不是所有选定的键值对。 检测到更改时,应用会刷新所有配置值。

更新多个键值时,此方法非常有用。 只有在完成所有其他配置更改后才会更新 sentinel 密钥,可确保应用程序仅重新加载配置一次,从而保持一致性。

options := &azureappconfiguration.Options{
	// Load all keys that start with `TestApp:` and have no label
	Selectors: []azureappconfiguration.Selector{
		{
			KeyFilter:   "TestApp:*",
			LabelFilter: "",
		},
	},
	// Trigger full configuration refresh only if the `SentinelKey` changes
	RefreshOptions:  azureappconfiguration.KeyValueRefreshOptions{
		Enabled: true,
		WatchedSettings: []azureappconfiguration.WatchedSetting{
			{
				Key:   "SentinelKey",
				Label: "",
			},
		},
	},
}

自定义刷新回叫

该方法 OnRefreshSuccess 注册一个回调函数,该函数将在配置成功刷新并检测到实际更改时执行。

var config Config
if err := appConfig.Unmarshal(&config, nil); err != nil {
    log.Fatalf("Failed to unmarshal configuration: %v", err)
}

// Register refresh callback
appConfig.OnRefreshSuccess(func() {
    // Re-unmarshal the configuration
    err := appConfig.Unmarshal(&config, nil)
    if err != nil {
        log.Printf("Failed to unmarshal updated configuration: %s", err)
        return
    }
})

功能标志

Azure 应用配置中的功能标志提供了一种新式方法来控制应用程序中的功能可用性。 与常规配置值不同,必须使用结构中的FeatureFlagOptions字段显式加载Options功能标志。

options := &azureappconfiguration.Options{
	FeatureFlagOptions: azureappconfiguration.FeatureFlagOptions{
		Enabled: true,
		// Load feature flags that start with `TestApp:` and have `dev` label
		Selectors: []azureappconfiguration.Selector{
			{
				KeyFilter:   "TestApp:*",
				LabelFilter: "dev",
			},
		},
		RefreshOptions: azureappconfiguration.RefreshOptions{
			Enabled:  true,
			Interval: 60 * time.Second,
		},
	},
}

appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)

小窍门

当在 FeatureFlagOptions 中未指定选择器时,它会加载应用配置存储库中所有无标签的功能开关。 功能标志的默认刷新间隔为 30 秒。

重要

若要有效地使用和管理从 Azure 应用配置加载的功能标志,请安装和使用该 featuremanagement 包。 此库提供了一种结构化方法来控制应用程序中的功能行为。

功能管理

功能管理 Go 库提供了基于功能标志开发和公开应用程序功能的结构化方法。 功能管理库旨在与配置提供程序库结合使用。

若要将功能标志与功能管理库配合使用,请安装所需的包:

go get github.com/microsoft/Featuremanagement-Go/featuremanagement
go get github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfig

以下示例演示如何将功能管理库与配置提供程序集成,以动态控制功能可用性:

import (
	"github.com/microsoft/Featuremanagement-Go/featuremanagement"
	"github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfig"
)

func main() {
	// Set up authentication options
	authOptions := azureappconfiguration.AuthenticationOptions{
		Endpoint:   endpoint,
		Credential: credential,
	}

	// Load configuration with feature flags enabled
	options := &azureappconfiguration.Options{
		FeatureFlagOptions: azureappconfiguration.FeatureFlagOptions{
			Enabled: true,
			RefreshOptions: azureappconfiguration.RefreshOptions{
				Enabled: true,
			},
		},
	}

	appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)
	if err != nil {
		log.Fatalf("Failed to load configuration: %v", err)
	}

	// Create feature flag provider using the Azure App Configuration
	featureFlagProvider, err := azappconfig.NewFeatureFlagProvider(appConfig)
	if err != nil {
		log.Fatalf("Error creating feature flag provider: %v", err)
	}

	// Create feature manager
	featureManager, err := featuremanagement.NewFeatureManager(featureFlagProvider, nil)
	if err != nil {
		log.Fatalf("Error creating feature manager: %v", err)
	}

	// Use the feature manager to check feature flags
	isEnabled, err := featureManager.IsEnabled("Beta")
	if err != nil {
		log.Printf("Error checking feature flag: %v", err)
		return
	}

	if isEnabled {
		fmt.Println("Beta feature is enabled!")
		// Execute beta functionality
	} else {
		fmt.Println("Beta feature is disabled")
		// Execute standard functionality
	}
}

有关如何使用 Go 功能管理库的详细信息,请转到 功能标志快速入门

密钥保管库引用

Azure 应用程序配置支持引用存储在 Azure Key Vault 中的机密。 在应用配置中,可以创建映射到 Key Vault 中存储的机密的密钥,但可以像加载任何其他配置一样访问密钥。

配置提供程序库可检索 Key Vault 引用,就如同检索存储在应用程序配置中的任何其他密钥一样。 需要使用结构中的KeyVaultOptions字段配置 Key Vault 访问Options

连接到 Key Vault

可以通过提供对 Key Vault 实例进行身份验证的凭据来配置 Key Vault 访问。

import (
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)

// Create a credential for Key Vault access
credential, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
	log.Fatalf("Failed to create credential: %v", err)
}

options := &azureappconfiguration.Options{
	KeyVaultOptions: azureappconfiguration.KeyVaultOptions{
		Credential: credential,
	},
}

appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)

自定义机密解析程序

如果默认基于凭据的方法不合适,还可以提供自定义机密解析程序函数来处理 Key Vault 引用:

options := &azureappconfiguration.Options{
	KeyVaultOptions: azureappconfiguration.KeyVaultOptions{
		SecretResolver: func(ctx context.Context, keyVaultReference url.URL) (string, error) {
			// Custom logic to resolve secrets
			// This could integrate with your existing secret management system
			// or provide fallback values for development environments

			if isDevelopment {
				return os.Getenv("FALLBACK_SECRET_VALUE"), nil
			}

			// Implement your custom secret retrieval logic here
			return retrieveSecret(keyVaultReference)
		},
	},
}

重要

如果应用程序加载密钥值(包含没有正确 Key Vault 配置的 Key Vault 引用),则会在加载作期间返回 错误 。 确保已正确配置 Key Vault 访问或机密解析程序。

密钥保管库机密刷新

Azure 应用配置使您可以在配置刷新周期之外独立配置机密刷新间隔。 这对安全性至关重要,因为虽然应用配置中的 Key Vault 引用 URI 保持不变,但 Key Vault 中的基础机密可能会作为安全做法的一部分轮换。

若要确保应用程序始终使用最新的机密值,请在结构中RefreshOptions配置KeyVaultOptions字段。

import (
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)

// Create a credential for Key Vault access
credential, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
	log.Fatalf("Failed to create credential: %v", err)
}

options := &azureappconfiguration.Options{
	KeyVaultOptions: azureappconfiguration.KeyVaultOptions{
		Credential: credential,
		RefreshOptions: azureappconfiguration.RefreshOptions{
			Enabled: true,
			Interval: 5 * time.Minute,
		},
	},
}

appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)

快照

快照 是一个应用配置存储库中的命名且不可变的键值子集。 构成快照的键值是在创建期间通过使用键和标签筛选器选择的。 创建快照后,其中的键值将保证保持不变。

SnapshotName结构体中配置Selector文件,以便从快照加载键值:

options := &azureappconfiguration.Options{
	Selectors: []azureappconfiguration.Selector{
		{KeyFilter: "app*", LabelFilter: "prod"},
		{SnapshotName: "my-snapshot"},
	},
}

appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)

异地复制

有关使用异地复制的信息,请转到启用异地复制

启动重试

配置加载是应用程序启动期间的关键路径操作。 为了确保可靠性,Azure 应用配置提供程序在初始配置加载期间实现可靠的重试机制。 这有助于保护应用程序免受暂时性网络问题的影响,否则可能会阻止成功启动。

可以通过以下方法 Options.StartupOptions自定义此行为:

options := &azureappconfiguration.Options{
	StartupOptions: azureappconfiguration.StartupOptions{
		Timeout: 5 * time.Minute,
	},
}

appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)

后续步骤

若要了解如何使用 Go 配置提供程序,请继续学习以下教程。