Consul部署手册(helm版本)

使用 Helm 部署 Consul 作为统一配置中心与服务发现平台

本文档旨在指导您使用 Helm 在 Kubernetes 集群中部署 Consul,并将其配置为一个专注于统一配置管理和服务发现的平台。此部署将优化服务发现功能,同时保持配置管理的核心能力。

1. 前提条件

  • 一个正在运行的 Kubernetes 集群 (版本 >= 1.20 推荐)
  • kubectl 命令行工具已安装并配置好,可以访问您的集群
  • helm (版本 3+) 命令行工具已安装
  • (可选,但推荐) 用于 Consul UI 的 TLS 证书和私钥 (例如 consultest.crtconsultest.key)
  • (可选) 一个支持 networking.k8s.io/v1 Ingress API 的 Ingress Controller (如 NGINX Ingress Controller) 已部署并运行

2. 添加 HashiCorp Helm 仓库

将 HashiCorp 官方 Helm 仓库添加到您的本地 Helm 客户端:

helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update

3. 准备配置文件

创建一个名为 consul-values.yaml 的文件,内容如下。请根据您的具体环境修改其中的 consul.XXX.com 域名和存储类名称。

3.1 优化配置说明

此配置专注于以下核心功能:

  • 服务发现:通过 DNS 和 gRPC 接口提供服务发现能力
  • 配置管理:支持动态配置存储和分发
  • 健康检查:内置服务健康检查机制
  • 高可用性:多节点集群部署,支持故障转移
# consul-values.yaml - 用于 Consul 统一配置管理和服务发现

# --- 全局设置 ---
global:
  # -- 设置所有组件的日志级别
  logLevel: "info"
  # -- 启用 JSON 格式日志
  logJSON: true
  # -- Consul Docker 镜像 (请根据需要指定版本)
  image: "hashicorp/consul:1.21.2"
  # -- Consul K8s Control Plane 镜像 (请根据需要指定版本)
  imageK8S: "hashicorp/consul-k8s-control-plane:1.7.2"

  # -- Consul 域名 (用于 DNS 查询和服务发现)
  domain: "consul"

  # -- 启用 ACLs (强烈推荐用于生产环境)
  acls:
    manageSystemACLs: true
    # bootstrapToken: # 如果预创建了引导令牌 Secret,可以在此指定
    #   secretName: "consul-bootstrap-acl-token"
    #   secretKey: "token"

  # -- 启用 TLS (强烈推荐用于生产环境)
  tls:
    enabled: false
    # enableAutoEncrypt: false # 可选:加密客户端与服务端通信
    # caCert: # 如果使用预创建的 CA 证书,可以在此指定
    #   secretName: "consul-ca-cert"
    # caKey: # 如果使用预创建的 CA 密钥,可以在此指定
    #   secretName: "consul-ca-key"

  # -- Gossip 加密 (强烈推荐)
  gossipEncryption:
    autoGenerate: true

  # -- 节点元数据
  nodeMeta:
    pod-name: ${HOSTNAME}
    host-ip: ${HOST_IP}

# --- 服务端配置 ---
server:
  enabled: true
  replicas: 3 # 推荐用于高可用 (HA)
  bootstrapExpect: 3 # 应与 replicas 匹配以实现 HA
  storage: "20Gi" # 持久卷大小
  storageClass: "nfs" # 指定存储类(如nfs)
  # PVC保留策略
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Retain
    whenScaled: Retain
  resources:
    requests:
      memory: "512Mi"
      cpu: "100m"
    limits:
      memory: "1Gi"
      cpu: "500m"
  connect: true      # 启用服务网格功能(用于服务发现)
  extraConfig: |     # 自定义配置(可选)
    {
      "log_level": "INFO",
      "disable_update_check": true,
      "enable_script_checks": false,
      "connect": {
        "enabled": true
      }
    }
  # -- 为服务端 Pod 设置反亲和性,防止调度到同一节点
  # 使用软性反亲和性(优先分散,但不强制)
  affinity: |
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: {{ template "consul.name" . }}
              release: "{{ .Release.Name }}"
              component: server
          topologyKey: kubernetes.io/hostname
  #使用硬性反亲和性(强制,推荐使用)
  #affinity: |
  #  podAntiAffinity:
  #    requiredDuringSchedulingIgnoredDuringExecution:
  #      - labelSelector:
  #          matchLabels:
  #            app: {{ template "consul.name" . }}
  #            release: "{{ .Release.Name }}"
  #            component: server
  #        topologyKey: kubernetes.io/hostname
  
# --- 客户端配置 ---
client:
  enabled: true
  grpc: true  # 启用 gRPC 端口,用于服务发现和连接
  resources:
    requests:
      memory: "128Mi"
      cpu: "100m"
    limits:
      memory: "512Mi"
      cpu: "500m"
  # -- 客户端额外配置
  extraConfig: |
    {
      "leave_on_terminate": true,
      "skip_leave_on_interrupt": false,
      "enable_script_checks": false,
      "connect": {
        "enabled": true
      }
    }

# --- UI 配置 (可选,方便查看配置和服务发现状态) ---
ui:
  enabled: true
  service:
    enabled: true
    type: "ClusterIP" # 或 LoadBalancer, NodePort
  # Ingress配置(对外暴露UI)
  ingress:
    enabled: true    # 启用Ingress
    ingressClassName: "nginx"  # 指定Ingress Controller类型
    pathType: Prefix
    annotations: |    # 自定义注解(如配置重定向规则)
      nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    hosts:
      - host: "consul.XXX.com"  # 访问域名
        paths:
          - /            
    tls:             # TLS配置(建议生产环境启用)
      - hosts:
          - consul.XXX.com   

# --- DNS 配置 (服务发现核心) ---
dns:
  enabled: true # 启用Consul DNS服务
  enableRedirection: true  # 启用DNS重定向(服务发现需要)

# --- Connect Inject 配置 (服务网格和服务发现) ---
connectInject:
  enabled: true     # 启用自动sidecar注入
  default: false  # 默认不注入,需要注解显式启用
  replicas: 2 # 注入器副本数(高可用)
  transparentProxy:
    defaultEnabled: true  # 启用透明代理
    defaultOverwriteProbes: true  # 覆盖健康检查
  metrics:
    defaultEnabled: true  # 启用指标收集
    defaultPrometheusScrapePort: 20200
    defaultPrometheusScrapePath: "/metrics"
  # -- 资源设置
  resources:
    requests:
      memory: "200Mi"
      cpu: "50m"
    limits:
      memory: "200Mi"
      cpu: "50m"

# --- 服务目录同步配置 (K8S服务与Consul服务双向同步) ---
syncCatalog:
  enabled: true     # 启用K8S服务与Consul服务的同步
  toConsul: true   # 同步K8S服务到Consul
  toK8S: true       # 同步Consul服务到K8S
  default: true     # 默认同步所有服务
  k8sAllowNamespaces: ["*"]  # 允许所有命名空间
  k8sDenyNamespaces: ["kube-system", "kube-public"]  # 排除系统命名空间
  consulNodeName: "k8s-sync"  # Consul节点名称
  # -- 同步策略
  nodePortSyncType: ExternalFirst
  syncClusterIPServices: true
  syncLoadBalancerEndpoints: false
  # -- 资源设置
  resources:
    requests:
      memory: "50Mi"
      cpu: "50m"
    limits:
      memory: "50Mi"
      cpu: "50m"
  # -- 日志级别
  logLevel: "info"

# --- 网关配置 (服务网格) ---
meshGateway:
  enabled: false     # 禁用网格网关(如不需要可以保持关闭)

ingressGateways:
  enabled: false     # 禁用入口网关(如不需要可以保持关闭)

terminatingGateways:
  enabled: false     # 禁用终止网关(如不需要可以保持关闭)

# --- 其他配置 ---
prometheus:
  enabled: false     # 禁用Prometheus(如需要可以启用)

telemetryCollector:
  enabled: false     # 禁用遥测收集器(如需要可以启用)

tests:
  enabled: false     # 禁用测试Pod

# --- 证书管理器 ---
webhookCertManager:
  resources:
    requests:
      memory: "50Mi"
      cpu: "100m"
    limits:
      memory: "50Mi"
      cpu: "100m"

# --- 生产环境建议配置 ---
# 1. 启用TLS加密
# 2. 配置适当的资源限制
# 3. 设置Pod反亲和性
# 4. 配置持久化存储
# 5. 启用ACLs
# 6. 监控和日志配置

4. 部署Consul

helm upgrade --install consul \
hashicorp/consul \
-n consul \
--create-namespace \
-f consul-values.yaml \
--version 1.7.2

5. 验证部署

5.1 基本检查

部署后,检查 Pod 和 Service 是否正常运行:

kubectl get pods,svc -n consul 

您应该看到 Consul Server Pod (状态为 Running) 和相关的 Service。

5.2 服务发现验证

检查服务发现相关组件:

# 检查服务
kubectl get svc -n consul

5.3 Ingress 验证

检查 Ingress 是否创建:

kubectl get ingress -n consul

6. 服务发现功能验证

6.1 DNS 服务发现测试

# 在集群内部测试DNS解析
kubectl run -it --rm dns-test --image=busybox --restart=Never -- sh -c "nslookup consul-consul-server.consul.svc.cluster.local"

6.2 服务目录同步验证

# 查看同步的Consul服务
kubectl logs -n consul -l app=consul,component=sync-catalog

# 查看Consul中的K8S服务
kubectl exec -n consul -it <consul-server-pod> -- consul catalog services

6.3 Connect 服务验证

# 检查Connect服务状态
kubectl exec -n consul -it <consul-server-pod> -- consul catalog services -connect

7. 访问 Consul UI

  1. 确保您的 DNS 或 /etc/hosts 文件已将 consul.XXX.com 指向您的 Ingress Controller 的 IP 地址
  2. 在浏览器中访问 http://consul.XXX.com (如果配置了 TLS 且 Secret 存在,则访问 https://consul.XXX.com)
  3. 如果启用了 ACL (global.acls.manageSystemACLs: true),首次访问 UI 时需要提供 ACL Token。引导令牌可以通过以下方式获取:
kubectl get secret <RELEASE_NAME>-consul-bootstrap-acl-token -n <NAMESPACE> -o jsonpath={.data.token} | base64 --decode

(将 <RELEASE_NAME><NAMESPACE> 替换为实际值,例如 consul-consul-bootstrap-acl-tokenconsul)

8. 服务发现使用示例

8.1 在应用中使用Consul服务发现

8.1.1 C#应用示例

using Consul;
using System;
using System.Net;
using System.Threading.Tasks;

namespace ConsulServiceDiscovery
{
    public class ConsulServiceDiscovery
    {
        private static readonly string ConsulHost = "consul-consul-server.consul.svc.cluster.local";
        private static readonly int ConsulPort = 8500;

        public async Task DiscoverServices()
        {
            // 创建Consul客户端配置
            var consulConfig = new
            {
                Address = $"{ConsulHost}:{ConsulPort}"
            };

            // 创建Consul客户端
            using (var consul = new ConsulClient(config => config.Address = new Uri($"http://{consulConfig.Address}")))
            {
                try
                {
                    // 获取服务列表
                    var services = await consul.Catalog.Services();

                    Console.WriteLine("Available services:");
                    foreach (var service in services.Response)
                    {
                        Console.WriteLine($"- {service.Key}");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error discovering services: {ex.Message}");
                }
            }
        }

        public async Task DiscoverSpecificService(string serviceName)
        {
            var consulConfig = new
            {
                Address = $"{ConsulHost}:{ConsulPort}"
            };

            using (var consul = new ConsulClient(config => config.Address = new Uri($"http://{consulConfig.Address}")))
            {
                try
                {
                    // 获取特定服务的健康实例
                    var healthyServices = await consul.Health.Service(serviceName, "", true);

                    Console.WriteLine($"Found {healthyServices.Response.Length} healthy instances of {serviceName}:");
                    foreach (var serviceEntry in healthyServices.Response)
                    {
                        var service = serviceEntry.Service;
                        Console.WriteLine($"- {service.Address}:{service.Port} (ID: {service.ID}, Service: {service.Service})");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error discovering service {serviceName}: {ex.Message}");
                }
            }
        }

        public async Task RegisterService()
        {
            var consulConfig = new
            {
                Address = $"{ConsulHost}:{ConsulPort}"
            };

            using (var consul = new ConsulClient(config =>
            {
               config.Address = new Uri($"http://{consulConfig.Address}");
               config.Token = "改为自己的token";
            }))
            {
                try
                {
                    // 注册服务
                    var registration = new AgentServiceRegistration
                    {
                        Name = "my-service",
                        ID = "my-service-1",
                        Address = "service-host",
                        Port = 8080,
                        Tags = new[] { "web", "api" },
                        Check = new AgentServiceCheck
                        {
                            HTTP = "http://service-host:8080/health",
                            Interval = TimeSpan.FromSeconds(10),
                            Timeout = TimeSpan.FromSeconds(5),
                            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(30)
                        }
                    };

                    await consul.Agent.ServiceRegister(registration);
                    Console.WriteLine("Service registered successfully");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error registering service: {ex.Message}");
                }
            }
        }
    }

    // 使用示例
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var discovery = new ConsulServiceDiscovery();

            // 发现所有服务
            await discovery.DiscoverServices();

            // 发现特定服务
            await discovery.DiscoverSpecificService("database-service");

            // 注册服务
            await discovery.RegisterService();
        }
    }
}

9. 监控与运维

9.1 健康检查

# 检查Consul集群状态
kubectl exec -n consul -it <consul-server-pod> -- consul members

# 检查Leader状态
kubectl exec -n consul -it <consul-server-pod> -- consul operator raft list-peers

# 检查服务健康状态
kubectl exec -n consul -it <consul-server-pod> -- consul health checks

9.2 日志监控

# 查看服务端日志
kubectl logs -n consul -l component=server

# 查看客户端日志
kubectl logs -n consul -l component=client

# 查看同步组件日志
kubectl logs -n consul -l app=consul,component=sync-catalog

9.3 性能监控

# 查看Consul性能指标
kubectl exec -n consul -it <consul-server-pod> -- consul monitor

# 查看Prometheus指标
curl http://localhost:8500/v1/agent/metrics

10. 故障排查

10.1 常见问题

10.1.1 服务发现不工作

症状: 应用无法发现其他服务

排查步骤:

  1. 检查DNS服务是否正常运行
  2. 检查服务注册是否正确
  3. 检查网络策略是否允许服务间通信
  4. 检查ACL配置是否正确
# 检查DNS服务
kubectl get pods -n consul -l component=client

# 测试DNS解析
kubectl run -it --rm dns-test --image=busybox --restart=Never -- sh -c "nslookup consul-consul-server.consul.svc.cluster.local"

# 检查服务注册
kubectl exec -n consul -it <consul-server-pod> -- consul catalog services

10.1.2 配置同步失败

症状: K8S服务无法同步到Consul

排查步骤:

  1. 检查sync-catalog Pod状态
  2. 检查日志中的错误信息
  3. 检查命名空间权限
# 检查sync-catalog日志
kubectl logs -n consul -l app=consul,component=sync-catalog

# 检查K8S服务
kubectl get svc -A | grep my-service

10.2 备份与恢复

10.2.1 数据备份

# 备份Consul数据
kubectl exec -n consul -it <consul-server-pod> -- consul snapshot save consul-backup.snap

# 导出配置
kubectl exec -n consul -it <consul-server-pod> -- consul kv get -recursive > config-backup.txt

10.2.2 数据恢复

# 恢复Consul数据
kubectl exec -n consul -it <consul-server-pod> -- consul snapshot restore consul-backup.snap

# 恢复配置
kubectl exec -n consul -it <consul-server-pod> -- consul kv import @config-backup.txt

11. 最佳实践

11.1 性能优化

  1. DNS缓存: 启用DNS缓存减少查询延迟
  2. 服务健康检查: 配置合适的心跳间隔和超时时间
  3. 资源限制: 为不同组件设置合适的资源限制
  4. 数据分片: 对于大型集群,考虑数据分片

11.2 安全配置

  1. 启用TLS: 生产环境必须启用TLS加密
  2. ACL配置: 配置细粒度的访问控制
  3. 网络隔离: 使用网络策略限制服务间通信
  4. 定期轮换密钥: 定期更新加密密钥

11.3 运维建议

  1. 监控告警: 设置关键指标的监控和告警
  2. 定期备份: 定期备份Consul数据和配置
  3. 版本升级: 定期升级Consul版本获取新功能和修复
  4. 容量规划: 根据业务增长规划集群容量

通过以上配置和优化,Consul将作为一个强大的统一配置中心和服务发现平台,为您的Kubernetes集群提供可靠的服务发现和配置管理能力。

posted @ 2025-07-25 13:42  怀恋小时候  阅读(175)  评论(0)    收藏  举报