微服务安全、监控与可观测性实践
1. 安全相关
在微服务架构中,安全是至关重要的一个方面,下面从几个关键部分来介绍相关的安全措施和实践。
1.1 配置 AWS 凭证读取
在 Java 应用里,我们可以借助 Spring Boot 来配置从 Vault 读取 AWS 凭证。以下是示例代码:
import com.packtpub.microservices.ch06.attachment.config.Configuration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableConfigurationProperties(Configuration.class)
public class Application {
private final Configuration config;
public Application(Configuration config) {
this.config = config;
}
@Bean
public AmazonS3 getS3Client() {
AmazonS3ClientBuilder client = AmazonS3ClientBuilder.standard();
AWSCredentials credentials = new BasicAWSCredentials(config.getAwsAccessKeyId(), config.getAwsSecretAccessKey());
return client.withCredentials(new AWSStaticCredentialsProvider(credentials)).withRegion(Regions.US_WEST_2).build();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这段代码通过 Spring Boot 应用,从配置类
Configuration
中获取 AWS 凭证,进而创建 Amazon S3 客户端。
1.2 安全日志记录
日志是可观测系统的关键组成部分,不过在微服务架构下,日志也可能带来隐私和安全风险。过多的日志信息可能会泄露系统用户信息或者敏感的令牌、密钥等。所以,需要精心规划服务的日志记录策略。
日志通常按照级别进行组织,开发者可以根据需求调整日志的详细程度。例如,在生产环境中测试服务应对故障场景时,可以提高日志级别以获取更多系统事件的详细信息。
1.3 基础设施即代码(Infrastructure as Code)
微服务架构常常需要频繁地调配计算资源,系统中节点数量的增加会扩大攻击面。传统的配置管理方式,如使用自定义 shell 脚本,随着系统需求的增长,会变得难以维护,容易导致配置漂移,使系统的遗留部分面临攻击风险。
而基础设施即代码(Infrastructure as Code)通过机器可读的代码文件来管理基础设施的调配和维护。以 Terraform 为例,它是 HashiCorp 开发的开源工具,下面介绍使用 Terraform 调配 AWS 资源的步骤:
1.
安装 Terraform
:如果你使用的是 macOS X 并且使用 HomeBrew,可以使用以下命令进行安装:
$ brew install terraform
-
创建配置文件
:创建一个名为
example.tf的文件,其中包含 EC2 实例和 ElastiCache 实例的配置信息,示例如下:
provider "aws" {
access_key = "ACCESS_KEY"
secret_key = "SECRET_KEY"
region = "us-east-1"
}
resource "aws_instance" "example" {
ami = "ami-b374d5a5"
instance_type = "t2.micro"
}
resource "aws_elasticache_cluster" "example" {
cluster_id = "cluster-example"
engine = "redis"
node_type = "cache.m3.medium"
num_cache_nodes = 1
parameter_group_name = "default.redis3.2"
port = 6379
snapshot_window = "05:00-09:00"
snapshot_retention_limit = 5
}
请将
ACCESS_KEY
和
SECRET_KEY
替换为有效的 AWS 访问密钥对。
3.
初始化 Terraform
:执行以下命令初始化 Terraform,这将安装配置文件中引用的 AWS 提供程序:
$ terraform init
-
应用配置
:运行以下命令并在提示时输入
yes来应用配置:
$ terraform apply
-
销毁资源
:如果需要销毁创建的资源,可以运行以下命令并在提示时输入
yes:
$ terraform destroy
2. 监控与可观测性
在微服务架构中,监控和可观测性是非常重要的,它有助于我们及时发现系统中的问题并进行处理。下面介绍几个关键的监控和可观测性实践。
2.1 结构化 JSON 日志记录
输出有用的日志是构建可观测服务的关键部分。在微服务架构中,多个服务可能会将事件日志发送到集中式日志存储,因此输出结构化日志是非常有用的。JSON 是一种常见的消息传递标准,它轻量级且结构化,适合用于事件日志。
以下是使用 Logback 库将 Java 应用的日志输出为 JSON 格式的步骤:
1.
添加依赖
:在
build.gradle
文件中添加 Logback 库的依赖:
group 'com.packtpub.microservices'
version '1.0-SNAPSHOT'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'org.springframework.boot', name: 'spring-boot-gradle-plugin', version: '1.5.9.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
compile group: 'io.github.resilience4j', name: 'resilience4j-circuitbreaker', version: '0.11.0'
compile group: 'net.logstash.logback', name: 'logstash-logback-encoder', version: '4.7'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
-
创建配置文件
:创建
logback.xml配置文件,示例如下:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<logger name="jsonLogger" additivity="false" level="DEBUG">
<appender-ref ref="consoleAppender"/>
</logger>
<root level="INFO">
<appender-ref ref="consoleAppender"/>
</root>
</configuration>
-
添加测试日志
:在
Application.java中添加一个测试日志消息:
package com.packtpub.microservices.ch07.message;
import com.packtpub.microservices.ch07.message.clients.SocialGraphClient;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@SpringBootApplication
@EnableAsync
public class Application {
private Logger logger = LogManager.getLogger(Application.class);
@Bean
public MessageRepository messageRepository() {
return new MessageRepository();
}
@Bean
public SocialGraphClient socialGraphClient() {
return new SocialGraphClient("http://localhost:4567");
}
public static void main(String[] args) {
logger.info("Starting application");
SpringApplication.run(Application.class, args);
}
@Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("SocialServiceCall-");
executor.initialize();
return executor;
}
}
- 运行应用 :运行应用程序,你会看到日志消息以 JSON 格式输出:
$ ./gradlew bootRun
2.2 使用 StatsD 和 Graphite 收集指标
指标是随时间变化的数值测量,常见的指标类型有计数器、计时器和仪表。StatsD 是一个开源的网络守护进程,它将指标数据推送到服务器进行聚合,然后发送到持久化后端,Graphite 是常用的后端之一。
下面是使用 Spring Boot Actuator 和 Micrometer 结合 StatsD 和 Graphite 收集指标的步骤:
1.
更新依赖
:在
build.gradle
文件中更新 Spring Boot 版本并添加 Actuator 和 Micrometer 的依赖:
group 'com.packtpub.microservices'
version '1.0-SNAPSHOT'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'org.springframework.boot', name: 'spring-boot-gradle-plugin', version: '2.0.4.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.4.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.4.RELEASE'
compile group: 'io.micrometer', name: 'micrometer-core', version: '1.0.6'
compile group: 'io.micrometer', name: 'micrometer-registry-statsd', version: '1.0.6'
compile group: 'io.github.resilience4j', name: 'resilience4j-circuitbreaker', version: '0.11.0'
compile group: 'log4j', name: 'log4j', version: '1.2.17'
compile group: 'net.logstash.logback', name: 'logstash-logback-encoder', version: '5.2'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
-
配置应用
:在
application.yml文件中添加以下配置:
server:
port: 8082
management:
metrics:
export:
statsd:
enabled: true
flavor: "etsy"
host: 0.0.0.0
port: 8125
-
添加注解
:在
MessageController.java中添加Timed注解:
package com.packtpub.microservices.ch07.message.controllers;
import com.packtpub.microservices.ch07.message.MessageRepository;
import com.packtpub.microservices.ch07.message.clients.SocialGraphClient;
import com.packtpub.microservices.ch07.message.exceptions.MessageNotFoundException;
import com.packtpub.microservices.ch07.message.exceptions.MessageSendForbiddenException;
import com.packtpub.microservices.ch07.message.models.Message;
import com.packtpub.microservices.ch07.message.models.UserFriendships;
import io.micrometer.core.annotation.Timed;
import io.micrometer.statsd.StatsdMeterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import java.net.URI;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@RestController
@Timed
public class MessageController {
@Autowired
private MessageRepository messagesStore;
@Autowired
private SocialGraphClient socialGraphClient;
@Autowired
private StatsdMeterRegistry registry;
@Timed(value="get.messages")
@RequestMapping(path = "/{id}", method = RequestMethod.GET, produces = "application/json")
public Message get(@PathVariable("id") String id) throws MessageNotFoundException {
registry.counter("get_messages").increment();
return messagesStore.get(id);
}
@RequestMapping(path = "/", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<Message> send(@RequestBody Message message) throws MessageSendForbiddenException {
List<String> friendships = socialGraphClient.getFriendships(message.getSender());
if (!friendships.contains(message.getRecipient())) {
throw new MessageSendForbiddenException("Must be friends to send message");
}
Message saved = messagesStore.save(message);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest().path("/{id}")
.buildAndExpand(saved.getId()).toUri();
return ResponseEntity.created(location).build();
}
@Async
public CompletableFuture<Boolean> isFollowing(String fromUser, String toUser) {
// 方法体
}
}
通过以上的安全和监控实践,可以提高微服务架构的安全性和可观测性,帮助我们更好地管理和维护系统。
微服务安全、监控与可观测性实践(续)
2.3 使用 Prometheus 收集指标
Prometheus 是一个开源的系统监控和警报工具包,它以时间序列数据的形式收集和存储指标。与 StatsD 和 Graphite 不同,Prometheus 采用拉取模型,即主动从目标服务中拉取指标数据。
以下是使用 Spring Boot 和 Micrometer 集成 Prometheus 收集指标的步骤:
1.
添加依赖
:在
build.gradle
文件中添加 Prometheus 相关依赖:
group 'com.packtpub.microservices'
version '1.0-SNAPSHOT'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'org.springframework.boot', name: 'spring-boot-gradle-plugin', version: '2.0.4.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.4.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.4.RELEASE'
compile group: 'io.micrometer', name: 'micrometer-core', version: '1.0.6'
compile group: 'io.micrometer', name: 'micrometer-registry-prometheus', version: '1.0.6'
compile group: 'io.github.resilience4j', name: 'resilience4j-circuitbreaker', version: '0.11.0'
compile group: 'log4j', name: 'log4j', version: '1.2.17'
compile group: 'net.logstash.logback', name: 'logstash-logback-encoder', version: '5.2'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
-
配置应用
:在
application.yml文件中添加以下配置,启用 Prometheus 端点:
management:
endpoints:
web:
exposure:
include: prometheus
-
访问指标
:启动应用后,可以通过访问
/actuator/prometheus端点查看收集到的指标数据。
2.4 利用追踪简化调试
在微服务架构中,请求可能会经过多个服务和组件,当出现问题时,很难确定问题出在哪里。追踪(Tracing)可以帮助我们跟踪请求在系统中的流动,识别性能瓶颈和错误。
常见的追踪系统有 Jaeger、Zipkin 等。以下是一个简单的使用 Spring Cloud Sleuth 和 Zipkin 进行追踪的示例:
1.
添加依赖
:在
build.gradle
文件中添加相关依赖:
group 'com.packtpub.microservices'
version '1.0-SNAPSHOT'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'org.springframework.boot', name: 'spring-boot-gradle-plugin', version: '2.0.4.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.4.RELEASE'
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-sleuth', version: '2.0.2.RELEASE'
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-zipkin', version: '2.0.2.RELEASE'
compile group: 'io.github.resilience4j', name: 'resilience4j-circuitbreaker', version: '0.11.0'
compile group: 'log4j', name: 'log4j', version: '1.2.17'
compile group: 'net.logstash.logback', name: 'logstash-logback-encoder', version: '5.2'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
-
配置应用
:在
application.yml文件中配置 Zipkin 服务器地址:
spring:
zipkin:
base-url: http://localhost:9411
-
查看追踪信息
:启动 Zipkin 服务器和应用后,可以通过访问 Zipkin 的 Web 界面(通常是
http://localhost:9411)查看请求的追踪信息。
2.5 异常告警
当系统出现问题时,及时的告警可以帮助我们快速响应并解决问题。常见的告警系统有 Grafana、Alertmanager 等。
以下是一个使用 Spring Boot Actuator 和 Prometheus 结合 Alertmanager 进行告警的示例:
1.
配置 Prometheus 规则
:在 Prometheus 的配置文件中添加告警规则,例如:
groups:
- name: example-rules
rules:
- alert: HighRequestLatency
expr: http_request_duration_seconds_sum / http_request_duration_seconds_count > 1
for: 5m
labels:
severity: page
annotations:
summary: High request latency
description: The average request latency is above 1 second for 5 minutes.
- 配置 Alertmanager :在 Alertmanager 的配置文件中配置告警接收方式,如邮件、Slack 等。
- 启动服务 :启动 Prometheus、Alertmanager 和应用,当满足告警规则时,Alertmanager 会发送告警通知。
总结
微服务架构的安全、监控和可观测性是保障系统稳定运行的关键。通过合理配置安全措施,如安全日志记录和基础设施即代码,可以降低系统的安全风险;利用结构化日志、指标收集和追踪技术,可以更好地了解系统的运行状态,及时发现和解决问题;而异常告警则可以在系统出现问题时及时通知相关人员,减少故障对业务的影响。
以下是本文介绍的各项技术的对比表格:
| 技术 | 作用 | 特点 |
| ---- | ---- | ---- |
| 安全日志记录 | 记录系统事件,帮助排查问题,但需注意隐私和安全风险 | 可配置日志级别,按需调整详细程度 |
| 基础设施即代码(Terraform) | 通过代码管理基础设施的调配和维护 | 支持版本控制、审查和回滚,减少配置漂移 |
| 结构化 JSON 日志记录 | 输出结构化日志,便于分析和查询 | 采用 JSON 格式,易于集成到集中式日志存储 |
| StatsD 和 Graphite | 收集和可视化指标数据 | 开源,社区活跃,易于上手 |
| Prometheus | 收集和存储时间序列指标数据 | 采用拉取模型,支持告警规则配置 |
| 追踪(Spring Cloud Sleuth 和 Zipkin) | 跟踪请求在系统中的流动,简化调试 | 帮助定位性能瓶颈和错误 |
| 异常告警(Prometheus 和 Alertmanager) | 在系统出现问题时及时通知 | 可配置告警规则和接收方式 |
下面是一个简单的 mermaid 流程图,展示了微服务架构中监控和可观测性的整体流程:
graph LR
A[服务运行] --> B[日志记录]
A --> C[指标收集]
A --> D[请求追踪]
B --> E[集中式日志存储]
C --> F[指标存储]
D --> G[追踪系统]
E --> H[日志分析]
F --> I[指标可视化]
G --> J[追踪分析]
H --> K[问题排查]
I --> K
J --> K
K --> L[异常告警]
通过以上的实践和技术,我们可以构建一个更加安全、稳定和可观测的微服务架构。
超级会员免费看
889

被折叠的 条评论
为什么被折叠?



