|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
1. 引言
在当今快速变化的数字化时代,企业需要能够快速响应市场变化、持续交付价值。传统的单体应用架构已经难以满足现代业务的需求,微服务架构应运而生。微服务架构将复杂的应用拆分为一组小型、独立的服务,每个服务都可以独立开发、部署和扩展。然而,微服务架构也带来了新的挑战,如服务发现、负载均衡、故障恢复等问题。
Kubernetes作为容器编排的事实标准,为微服务提供了理想的运行环境。它能够自动化容器的部署、扩展和管理,为微服务架构提供了强大的支持。微服务与Kubernetes的结合,能够帮助企业构建更加灵活、可靠、可扩展的系统,从而加速数字化转型和业务创新。
本文将从架构设计到部署运维,全面解析容器化微服务治理的核心技术与方法,探讨微服务与Kubernetes结合的最佳实践,助力企业实现数字化转型与业务创新。
2. 微服务架构基础
2.1 微服务概念
微服务架构是一种将应用程序构建为一系列小型服务的方法,每个服务运行在自己的进程中,通过轻量级机制(通常是HTTP/REST API)进行通信。这些服务围绕业务能力构建,可以独立部署和维护。
微服务的主要特征包括:
• 服务小而专注:每个微服务专注于解决特定业务问题。
• 独立部署:每个微服务可以独立于其他服务进行部署。
• 技术异构性:不同的微服务可以使用不同的技术栈。
• 去中心化治理:团队可以自主选择最适合其服务的技术。
• 数据分离:每个微服务管理自己的数据存储。
• 智能端点与哑管道:服务之间的通信应该尽量简单,避免复杂的中间件。
• 容错设计:服务应该能够优雅地处理故障。
• 演进式设计:系统应该能够随时间推移而演进。
2.2 微服务优缺点
1. 敏捷开发:小团队可以独立开发和部署服务,加快开发速度。
2. 技术灵活性:每个服务可以选择最适合的技术栈。
3. 弹性扩展:可以根据需求独立扩展特定服务。
4. 故障隔离:一个服务的故障不会导致整个系统崩溃。
5. 易于维护:代码库更小,更易于理解和维护。
6. 持续部署:可以频繁部署单个服务而不影响整个系统。
1. 分布式系统复杂性:需要处理网络延迟、消息格式、负载均衡等问题。
2. 数据一致性:跨服务的数据一致性更难保证。
3. 测试复杂性:集成测试更加复杂。
4. 运维复杂性:需要监控和管理更多的服务。
5. 服务间通信开销:网络通信比进程内调用更慢。
6. 安全挑战:服务间的通信需要安全措施。
2.3 微服务设计原则
设计微服务时,应遵循以下原则:
1. 单一职责原则:每个服务应该专注于单一业务功能。
2. 领域驱动设计:基于业务领域边界划分服务。
3. 去中心化数据管理:每个服务管理自己的数据。
4. 自动化文化:自动化构建、测试、部署和监控。
5. 容错设计:设计能够处理故障的服务。
6. 设计为失败:假设网络会失败,服务会不可用。
7. API版本控制:管理API的变更,确保向后兼容性。
3. Kubernetes基础
3.1 Kubernetes简介
Kubernetes(常简称为K8s)是一个开源的容器编排平台,用于自动化容器化应用程序的部署、扩展和管理。它最初由Google设计,现在由云原生计算基金会(CNCF)维护。
Kubernetes提供了以下核心功能:
• 服务发现和负载均衡:Kubernetes可以使用DNS名称或自己的IP地址公开容器,并可以在容器之间分配负载。
• 存储编排:Kubernetes允许你自动挂载你选择的存储系统,如本地存储、云提供商等。
• 自动部署和回滚:你可以描述Kubernetes中容器的部署状态,它可以以受控的速率将实际状态更改为所需状态。
• 自动装箱:Kubernetes允许你指定每个容器所需的CPU和内存,当容器指定了资源请求时,Kubernetes可以做出更好的决策来管理容器的资源。
• 自我修复:Kubernetes能够重新启动失败的容器,替换和重新调度容器,杀死不响应用户定义的健康检查的容器。
• 密钥和配置管理:Kubernetes允许你存储和管理敏感信息,如密码、OAuth令牌和SSH密钥。
3.2 Kubernetes架构
Kubernetes由控制平面(Control Plane)和节点(Node)组成。
1. kube-apiserver:API服务器是Kubernetes控制平面的组件,公开了Kubernetes API。
2. etcd:一致且高可用的键值存储,用作Kubernetes的所有集群数据的后备存储。
3. kube-scheduler:调度程序负责监视新创建的Pod,并为它们选择节点来运行。
4. kube-controller-manager:运行控制器进程的组件。
5. cloud-controller-manager:嵌入特定于云的控制器的控制平面组件。
1. kubelet:在集群中每个节点上运行的代理,确保容器在Pod中运行。
2. kube-proxy:维护节点上的网络规则,实现Kubernetes服务概念。
3. 容器运行时:负责运行容器的软件,如Docker、containerd等。
3.3 Kubernetes核心概念
1. Pod:Kubernetes中最小的可部署单元,包含一个或多个容器。
2. Service:定义了一组Pod的逻辑集合和访问它们的策略。
3. Volume:Pod中容器可以访问的存储。
4. Namespace:在多个用户之间划分集群资源的虚拟分组。
5. Deployment:描述Pod的期望状态,Deployment控制器将实际状态更改为期望状态。
6. StatefulSet:用于管理有状态应用的工作负载API对象。
7. DaemonSet:确保所有(或一些)节点运行一个Pod副本。
8. ConfigMap:用于存储非机密数据的键值对。
9. Secret:用于存储敏感数据的键值对。
10. Ingress:管理对集群中服务的外部访问。
4. 微服务与Kubernetes结合的架构设计
4.1 微服务架构模式
在Kubernetes上设计微服务架构时,可以考虑以下几种模式:
API网关是微服务架构中的常见模式,它为客户端提供统一的入口点,处理请求路由、组合、协议转换等功能。
在Kubernetes中,可以使用Ingress Controller或Service Mesh(如Istio)来实现API网关。
- # 示例:使用Nginx Ingress Controller作为API网关
- apiVersion: networking.k8s.io/v1
- kind: Ingress
- metadata:
- name: api-gateway
- annotations:
- nginx.ingress.kubernetes.io/rewrite-target: /
- nginx.ingress.kubernetes.io/ssl-redirect: "true"
- spec:
- tls:
- - hosts:
- - api.example.com
- secretName: api-tls
- rules:
- - host: api.example.com
- http:
- paths:
- - path: /user
- pathType: Prefix
- backend:
- service:
- name: user-service
- port:
- number: 80
- - path: /order
- pathType: Prefix
- backend:
- service:
- name: order-service
- port:
- number: 80
复制代码
服务网格是一种基础设施层,用于处理服务间通信。它使服务之间的通信可靠、快速和安全,并提供服务发现、负载均衡、加密、认证和授权、监控等功能。
Istio是最流行的服务网格实现之一,它与Kubernetes紧密集成。
- # 示例:Istio Gateway和VirtualService配置
- apiVersion: networking.istio.io/v1alpha3
- kind: Gateway
- metadata:
- name: microservices-gateway
- spec:
- selector:
- istio: ingressgateway
- servers:
- - port:
- number: 80
- name: http
- protocol: HTTP
- hosts:
- - "*"
- ---
- apiVersion: networking.istio.io/v1alpha3
- kind: VirtualService
- metadata:
- name: user-service
- spec:
- hosts:
- - "*"
- gateways:
- - microservices-gateway
- http:
- - match:
- - uri:
- prefix: /user
- route:
- - destination:
- host: user-service
- port:
- number: 80
复制代码
事件驱动架构是一种设计模式,其中服务之间通过异步事件进行通信,而不是直接调用。这种模式在Kubernetes中可以通过消息队列(如Kafka、RabbitMQ)来实现。
- # 示例:部署Kafka作为事件总线
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: kafka
- spec:
- serviceName: kafka
- replicas: 3
- selector:
- matchLabels:
- app: kafka
- template:
- metadata:
- labels:
- app: kafka
- spec:
- containers:
- - name: kafka
- image: confluentinc/cp-kafka:latest
- ports:
- - containerPort: 9092
- env:
- - name: KAFKA_ZOOKEEPER_CONNECT
- value: "zookeeper:2181"
- - name: KAFKA_ADVERTISED_LISTENERS
- value: "PLAINTEXT://kafka:9092"
- - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
- value: "3"
复制代码
4.2 微服务拆分策略
在Kubernetes上设计微服务时,服务拆分是关键决策。以下是几种常见的拆分策略:
根据业务能力拆分服务是最常见的方法。每个服务负责特定的业务功能,如用户管理、订单处理、支付等。
- # 示例:基于业务能力拆分的微服务部署
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:latest
- ports:
- - containerPort: 8080
- env:
- - name: DATABASE_URL
- valueFrom:
- secretKeyRef:
- name: user-service-secret
- key: database-url
- ---
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: order-service
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: order-service
- template:
- metadata:
- labels:
- app: order-service
- spec:
- containers:
- - name: order-service
- image: myregistry/order-service:latest
- ports:
- - containerPort: 8080
- env:
- - name: DATABASE_URL
- valueFrom:
- secretKeyRef:
- name: order-service-secret
- key: database-url
复制代码
领域驱动设计(DDD)提供了一种基于领域模型拆分服务的方法。通过识别限界上下文(Bounded Context),可以将系统划分为多个内聚的服务。
根据数据的所有权和访问模式拆分服务。每个服务拥有自己的数据存储,并通过API提供访问。
4.3 微服务通信模式
在Kubernetes环境中,微服务之间的通信可以采用以下几种模式:
同步通信是最直接的通信方式,一个服务直接调用另一个服务。在Kubernetes中,可以通过Service资源实现服务发现和负载均衡。
- # 示例:服务定义,用于服务发现和负载均衡
- apiVersion: v1
- kind: Service
- metadata:
- name: user-service
- spec:
- selector:
- app: user-service
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: ClusterIP
复制代码
异步通信通过消息队列或事件总线实现,服务之间不直接调用,而是通过发送和接收消息进行通信。
- // 示例:使用Spring Boot和Kafka实现异步通信
- // 生产者服务
- @Service
- public class OrderEventProducer {
- @Autowired
- private KafkaTemplate<String, OrderEvent> kafkaTemplate;
- public void sendOrderEvent(OrderEvent event) {
- kafkaTemplate.send("order-events", event);
- }
- }
- // 消费者服务
- @Service
- public class OrderEventConsumer {
- @KafkaListener(topics = "order-events", groupId = "notification-service")
- public void handleOrderEvent(OrderEvent event) {
- // 处理订单事件,发送通知
- sendNotification(event);
- }
- }
复制代码
命令查询职责分离(CQRS)是一种将读写操作分离的模式。在Kubernetes中,可以通过部署不同的服务来处理命令和查询。
- # 示例:CQRS模式的微服务部署
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: order-command-service
- spec:
- replicas: 2
- selector:
- matchLabels:
- app: order-command-service
- template:
- metadata:
- labels:
- app: order-command-service
- spec:
- containers:
- - name: order-command-service
- image: myregistry/order-command-service:latest
- ports:
- - containerPort: 8080
- ---
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: order-query-service
- spec:
- replicas: 2
- selector:
- matchLabels:
- app: order-query-service
- template:
- metadata:
- labels:
- app: order-query-service
- spec:
- containers:
- - name: order-query-service
- image: myregistry/order-query-service:latest
- ports:
- - containerPort: 8080
复制代码
5. 容器化微服务的开发实践
5.1 Dockerfile最佳实践
在Kubernetes上运行微服务,首先需要将应用容器化。以下是编写Dockerfile的最佳实践:
- # 使用官方基础镜像
- FROM openjdk:11-jre-slim
- # 设置工作目录
- WORKDIR /app
- # 复制依赖
- COPY target/dependency/ ./BOOT-INF/lib
- COPY target/classes ./BOOT-INF/classes
- # 设置环境变量
- ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
- # 暴露端口
- EXPOSE 8080
- # 设置启动命令
- ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -cp /app org.springframework.boot.loader.JarLauncher"]
复制代码
5.2 多阶段构建
多阶段构建可以减小镜像大小,提高安全性和部署效率。
- # 第一阶段:构建应用
- FROM maven:3.8.1-openjdk-11 AS build
- WORKDIR /app
- COPY pom.xml .
- COPY src ./src
- RUN mvn package -DskipTests
- # 第二阶段:创建运行时镜像
- FROM openjdk:11-jre-slim
- WORKDIR /app
- COPY --from=build /app/target/*.jar app.jar
- EXPOSE 8080
- ENTRYPOINT ["java", "-jar", "app.jar"]
复制代码
5.3 健康检查
在Kubernetes中,可以为容器配置健康检查,确保服务可用性。
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:latest
- ports:
- - containerPort: 8080
- livenessProbe:
- httpGet:
- path: /actuator/health/liveness
- port: 8080
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- httpGet:
- path: /actuator/health/readiness
- port: 8080
- initialDelaySeconds: 5
- periodSeconds: 5
复制代码
5.4 配置管理
在Kubernetes中,可以使用ConfigMap和Secret来管理应用配置。
- # ConfigMap示例
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: user-service-config
- data:
- application.yml: |
- server:
- port: 8080
- spring:
- datasource:
- url: jdbc:postgresql://${DB_HOST}:5432/userdb
- username: ${DB_USERNAME}
- password: ${DB_PASSWORD}
- logging:
- level:
- com.example.userservice: DEBUG
- # Secret示例
- apiVersion: v1
- kind: Secret
- metadata:
- name: user-service-secret
- type: Opaque
- data:
- db-host: cG9zdGdyZXNxbA== # base64编码的"postgresql"
- db-username: dXNlcg== # base64编码的"user"
- db-password: cGFzc3dvcmQ= # base64编码的"password"
复制代码
5.5 资源限制
为微服务设置资源限制,确保公平使用集群资源。
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:latest
- ports:
- - containerPort: 8080
- resources:
- requests:
- memory: "512Mi"
- cpu: "250m"
- limits:
- memory: "1Gi"
- cpu: "500m"
复制代码
6. 微服务在Kubernetes上的部署策略
6.1 滚动更新
滚动更新是Kubernetes的默认部署策略,它逐步替换旧版本的Pod,确保服务不中断。
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service
- spec:
- replicas: 3
- strategy:
- type: RollingUpdate
- rollingUpdate:
- maxUnavailable: 1
- maxSurge: 1
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:v2.0
- ports:
- - containerPort: 8080
复制代码
6.2 蓝绿部署
蓝绿部署通过维护两个相同的生产环境(蓝色和绿色)来实现零停机部署。
- # 蓝环境部署
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service-blue
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- version: blue
- template:
- metadata:
- labels:
- app: user-service
- version: blue
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:v1.0
- ports:
- - containerPort: 8080
- ---
- # 绿环境部署
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service-green
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- version: green
- template:
- metadata:
- labels:
- app: user-service
- version: green
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:v2.0
- ports:
- - containerPort: 8080
- ---
- # 服务,指向当前活动环境(蓝色)
- apiVersion: v1
- kind: Service
- metadata:
- name: user-service
- spec:
- selector:
- app: user-service
- version: blue
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: ClusterIP
复制代码
6.3 金丝雀发布
金丝雀发布是一种渐进式部署策略,先将新版本部署到一小部分用户,验证无误后再全面推广。
- # 使用Istio进行金丝雀发布
- apiVersion: networking.istio.io/v1alpha3
- kind: VirtualService
- metadata:
- name: user-service
- spec:
- hosts:
- - user-service
- http:
- - route:
- - destination:
- host: user-service
- subset: v1
- weight: 90
- - destination:
- host: user-service
- subset: v2
- weight: 10
- ---
- apiVersion: networking.istio.io/v1alpha3
- kind: DestinationRule
- metadata:
- name: user-service
- spec:
- host: user-service
- subsets:
- - name: v1
- labels:
- version: v1.0
- - name: v2
- labels:
- version: v2.0
复制代码
6.4 A/B测试
A/B测试是一种将用户分流到不同版本服务的方法,用于比较不同版本的效果。
- # 使用Istio进行A/B测试
- apiVersion: networking.istio.io/v1alpha3
- kind: VirtualService
- metadata:
- name: user-service
- spec:
- hosts:
- - user-service
- http:
- - match:
- - headers:
- user-group:
- exact: premium
- route:
- - destination:
- host: user-service
- subset: v2
- - route:
- - destination:
- host: user-service
- subset: v1
复制代码
7. 微服务的服务治理
7.1 服务发现
在Kubernetes中,服务发现主要通过Service资源实现。每个Service都有一个稳定的DNS名称,其他服务可以通过这个名称访问它。
- # 创建Service以实现服务发现
- apiVersion: v1
- kind: Service
- metadata:
- name: user-service
- spec:
- selector:
- app: user-service
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: ClusterIP
复制代码
7.2 负载均衡
Kubernetes提供了多种负载均衡策略:
1. ClusterIP:在集群内部暴露服务,通过集群内部IP访问。
2. NodePort:在每个节点的IP上静态端口暴露服务。
3. LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。
4. ExternalName:将服务映射到外部DNS名称。
- # 使用LoadBalancer类型的Service
- apiVersion: v1
- kind: Service
- metadata:
- name: user-service
- spec:
- selector:
- app: user-service
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: LoadBalancer
复制代码
7.3 断路器模式
断路器模式可以防止级联故障,提高系统的弹性。在Kubernetes中,可以使用Istio等服务网格实现断路器。
- # 使用Istio实现断路器
- apiVersion: networking.istio.io/v1alpha3
- kind: DestinationRule
- metadata:
- name: user-service
- spec:
- host: user-service
- trafficPolicy:
- connectionPool:
- tcp:
- maxConnections: 100
- connectTimeout: 30ms
- tcpKeepalive:
- time: 7200s
- interval: 75s
- http:
- http1MaxPendingRequests: 100
- http2MaxRequests: 1000
- maxRequestsPerConnection: 10
- maxRetries: 3
- idleTimeout: 90s
- h2UpgradePolicy: UPGRADE
- outlierDetection:
- consecutiveGatewayErrors: 5
- consecutive5xxErrors: 5
- interval: 30s
- baseEjectionTime: 30s
- maxEjectionPercent: 50
复制代码
7.4 限流与熔断
限流和熔断是保护微服务免受过载的重要机制。
- // 使用Resilience4j实现限流和熔断
- // 限流配置
- RateLimiterConfig config = RateLimiterConfig.custom()
- .limitRefreshPeriod(Duration.ofMillis(1))
- .limitForPeriod(100)
- .timeoutDuration(Duration.ofSeconds(1))
- .build();
- RateLimiter rateLimiter = RateLimiter.of("userService", config);
- // 熔断配置
- CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
- .failureRateThreshold(50)
- .waitDurationInOpenState(Duration.ofMillis(1000))
- .ringBufferSizeInHalfOpenState(2)
- .ringBufferSizeInClosedState(4)
- .build();
- CircuitBreaker circuitBreaker = CircuitBreaker.of("userService", circuitBreakerConfig);
- // 使用限流和熔断
- Supplier<User> supplier = RateLimiter.decorateSupplier(rateLimiter, () -> {
- return userService.findById(userId);
- });
- Supplier<User> decoratedSupplier = CircuitBreaker.decorateSupplier(circuitBreaker, supplier);
- User user = Try.ofSupplier(decoratedSupplier)
- .recover(throwable -> fallbackUser)
- .get();
复制代码
7.5 服务网格与Istio
服务网格如Istio提供了高级的服务治理功能,包括流量管理、安全、可观察性等。
- # Istio安装示例
- apiVersion: install.istio.io/v1alpha1
- kind: IstioOperator
- spec:
- profile: default
- components:
- ingressGateways:
- - name: istio-ingressgateway
- enabled: true
- k8s:
- serviceAnnotations:
- service.beta.kubernetes.io/aws-load-balancer-type: nlb
- egressGateways:
- - name: istio-egressgateway
- enabled: true
复制代码
8. 监控、日志与故障排查
8.1 监控系统
在Kubernetes环境中,Prometheus和Grafana是常用的监控组合。
- # Prometheus部署示例
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: prometheus
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: prometheus
- template:
- metadata:
- labels:
- app: prometheus
- spec:
- containers:
- - name: prometheus
- image: prom/prometheus:latest
- ports:
- - containerPort: 9090
- volumeMounts:
- - name: prometheus-config
- mountPath: /etc/prometheus
- volumes:
- - name: prometheus-config
- configMap:
- name: prometheus-config
- ---
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: prometheus-config
- data:
- prometheus.yml: |
- global:
- scrape_interval: 15s
- scrape_configs:
- - job_name: 'kubernetes-pods'
- kubernetes_sd_configs:
- - role: pod
- relabel_configs:
- - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
- action: keep
- regex: true
复制代码
8.2 日志收集
ELK(Elasticsearch、Logstash、Kibana)或EFK(Elasticsearch、Fluentd、Kibana)是常用的日志收集解决方案。
- # Fluentd部署示例
- apiVersion: apps/v1
- kind: DaemonSet
- metadata:
- name: fluentd
- namespace: kube-system
- labels:
- k8s-app: fluentd-logging
- spec:
- selector:
- matchLabels:
- name: fluentd-logging
- template:
- metadata:
- labels:
- name: fluentd-logging
- spec:
- tolerations:
- - key: node-role.kubernetes.io/master
- effect: NoSchedule
- containers:
- - name: fluentd
- image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1
- env:
- - name: FLUENT_ELASTICSEARCH_HOST
- value: "elasticsearch"
- - name: FLUENT_ELASTICSEARCH_PORT
- value: "9200"
- resources:
- limits:
- memory: 200Mi
- requests:
- cpu: 100m
- memory: 200Mi
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- - name: varlibdockercontainers
- mountPath: /var/lib/docker/containers
- readOnly: true
- terminationGracePeriodSeconds: 30
- volumes:
- - name: varlog
- hostPath:
- path: /var/log
- - name: varlibdockercontainers
- hostPath:
- path: /var/lib/docker/containers
复制代码
8.3 分布式追踪
分布式追踪系统如Jaeger或Zipkin可以帮助追踪请求在微服务之间的流转。
- # Jaeger部署示例
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: jaeger
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: jaeger
- template:
- metadata:
- labels:
- app: jaeger
- spec:
- containers:
- - name: jaeger
- image: jaegertracing/all-in-one:latest
- ports:
- - containerPort: 16686
- - containerPort: 14268
- env:
- - name: COLLECTOR_ZIPKIN_HOST_PORT
- value: ":9411"
- ---
- apiVersion: v1
- kind: Service
- metadata:
- name: jaeger-query
- spec:
- selector:
- app: jaeger
- ports:
- - name: query
- port: 16686
- targetPort: 16686
- type: LoadBalancer
复制代码
8.4 故障排查
在Kubernetes环境中,可以使用以下命令进行故障排查:
- # 查看Pod状态
- kubectl get pods
- # 查看Pod详细信息
- kubectl describe pod <pod-name>
- # 查看Pod日志
- kubectl logs <pod-name>
- # 查看特定容器的日志
- kubectl logs <pod-name> -c <container-name>
- # 查看前一个容器的日志(如果容器崩溃)
- kubectl logs <pod-name> --previous
- # 在Pod中执行命令
- kubectl exec -it <pod-name> -- /bin/bash
- # 查看Service
- kubectl get svc
- # 查看Ingress
- kubectl get ingress
- # 查看事件
- kubectl get events
- # 查看节点状态
- kubectl get nodes
- # 查看集群信息
- kubectl cluster-info
复制代码
9. 持续集成与持续部署(CI/CD)
9.1 CI/CD流水线设计
在Kubernetes环境中,CI/CD流水线通常包括以下阶段:
1. 代码提交
2. 构建和测试
3. 容器镜像构建
4. 镜像推送
5. 部署到测试环境
6. 自动化测试
7. 部署到生产环境
9.2 Jenkins与Kubernetes集成
Jenkins是一个流行的CI/CD工具,可以与Kubernetes紧密集成。
- // Jenkinsfile示例
- pipeline {
- agent {
- kubernetes {
- label 'jenkins-slave'
- defaultContainer 'jnlp'
- yaml """
- apiVersion: v1
- kind: Pod
- metadata:
- labels:
- component: ci
- spec:
- containers:
- - name: maven
- image: maven:3.8.1-openjdk-11
- command:
- - cat
- tty: true
- - name: docker
- image: docker:latest
- command:
- - cat
- tty: true
- volumeMounts:
- - mountPath: /var/run/docker.sock
- name: docker-sock
- volumes:
- - name: docker-sock
- hostPath:
- path: /var/run/docker.sock
- """
- }
- }
- stages {
- stage('Build') {
- steps {
- container('maven') {
- sh 'mvn clean package'
- }
- }
- }
- stage('Build Docker Image') {
- steps {
- container('docker') {
- script {
- def app = docker.build("myregistry/user-service:${env.BUILD_ID}")
- app.push()
- }
- }
- }
- }
- stage('Deploy to Kubernetes') {
- steps {
- container('docker') {
- sh 'kubectl set image deployment/user-service user-service=myregistry/user-service:${env.BUILD_ID}'
- }
- }
- }
- }
- }
复制代码
9.3 GitOps与ArgoCD
GitOps是一种使用Git作为声明式基础架构和应用程序的单一事实来源的方法。ArgoCD是一个流行的GitOps工具。
- # ArgoCD Application示例
- apiVersion: argoproj.io/v1alpha1
- kind: Application
- metadata:
- name: user-service
- namespace: argocd
- spec:
- project: default
- source:
- repoURL: 'https://github.com/myorg/microservices-deployment.git'
- targetRevision: HEAD
- path: user-service
- destination:
- server: 'https://kubernetes.default.svc'
- namespace: production
- syncPolicy:
- automated:
- prune: true
- selfHeal: true
复制代码
9.4 自动化测试策略
在CI/CD流水线中,自动化测试是确保代码质量的关键。
- # 使用Kubernetes运行自动化测试
- apiVersion: v1
- kind: Pod
- metadata:
- name: user-service-test
- spec:
- containers:
- - name: test-runner
- image: maven:3.8.1-openjdk-11
- command: ["mvn", "test"]
- volumeMounts:
- - name: source-code
- mountPath: /app
- volumes:
- - name: source-code
- persistentVolumeClaim:
- claimName: source-code-pvc
复制代码
10. 安全性考虑
10.1 容器安全
容器安全是微服务安全的基础。以下是一些容器安全最佳实践:
- # 使用非root用户运行容器
- FROM openjdk:11-jre-slim
- WORKDIR /app
- # 创建非root用户
- RUN groupadd -r appuser && useradd -r -g appuser appuser
- # 复制应用文件
- COPY --chown=appuser:appuser target/*.jar app.jar
- # 切换到非root用户
- USER appuser
- EXPOSE 8080
- ENTRYPOINT ["java", "-jar", "app.jar"]
复制代码
10.2 Kubernetes安全
Kubernetes提供了多种安全机制,包括RBAC、Network Policies、Pod Security Policies等。
- # RBAC示例
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: user-service-account
- ---
- apiVersion: rbac.authorization.k8s.io/v1
- kind: Role
- metadata:
- name: user-service-role
- rules:
- - apiGroups: [""]
- resources: ["pods", "services"]
- verbs: ["get", "list", "watch"]
- ---
- apiVersion: rbac.authorization.k8s.io/v1
- kind: RoleBinding
- metadata:
- name: user-service-role-binding
- subjects:
- - kind: ServiceAccount
- name: user-service-account
- roleRef:
- kind: Role
- name: user-service-role
- apiGroup: rbac.authorization.k8s.io
复制代码
10.3 网络安全
网络策略用于控制Pod之间的通信。
- # Network Policy示例
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: user-service-netpol
- spec:
- podSelector:
- matchLabels:
- app: user-service
- policyTypes:
- - Ingress
- - Egress
- ingress:
- - from:
- - podSelector:
- matchLabels:
- app: api-gateway
- ports:
- - protocol: TCP
- port: 8080
- egress:
- - to:
- - podSelector:
- matchLabels:
- app: database
- ports:
- - protocol: TCP
- port: 5432
复制代码
10.4 密钥管理
密钥管理是微服务安全的重要组成部分。Kubernetes提供了Secret资源来管理敏感信息。
- # 使用Secret管理数据库凭据
- apiVersion: v1
- kind: Secret
- metadata:
- name: database-credentials
- type: Opaque
- data:
- username: dXNlcm5hbWU= # base64编码的"username"
- password: cGFzc3dvcmQ= # base64编码的"password"
- ---
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:latest
- env:
- - name: DB_USERNAME
- valueFrom:
- secretKeyRef:
- name: database-credentials
- key: username
- - name: DB_PASSWORD
- valueFrom:
- secretKeyRef:
- name: database-credentials
- key: password
复制代码
10.5 服务间通信安全
使用mTLS(双向TLS)保护服务间通信。
- # Istio PeerAuthentication策略
- apiVersion: security.istio.io/v1beta1
- kind: PeerAuthentication
- metadata:
- name: default
- namespace: production
- spec:
- mtls:
- mode: STRICT
复制代码
11. 性能优化
11.1 资源优化
合理设置资源请求和限制,优化资源使用。
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:latest
- resources:
- requests:
- memory: "512Mi"
- cpu: "250m"
- limits:
- memory: "1Gi"
- cpu: "500m"
- env:
- - name: JAVA_OPTS
- value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -XX:MinRAMPercentage=50.0"
复制代码
11.2 自动扩展
Kubernetes提供了多种自动扩展机制:
1. Horizontal Pod Autoscaler (HPA):根据CPU使用率或其他指标自动扩展Pod数量。
2. Vertical Pod Autoscaler (VPA):自动调整Pod的资源请求和限制。
3. Cluster Autoscaler:根据需要自动扩展集群节点。
- # HPA示例
- apiVersion: autoscaling/v2beta2
- kind: HorizontalPodAutoscaler
- metadata:
- name: user-service-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: user-service
- minReplicas: 3
- maxReplicas: 10
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 50
- - type: Resource
- resource:
- name: memory
- target:
- type: Utilization
- averageUtilization: 70
复制代码
11.3 缓存策略
缓存是提高微服务性能的有效手段。
- // 使用Spring Cache实现缓存
- @Service
- public class UserService {
-
- @Cacheable(value = "users", key = "#id")
- public User findById(Long id) {
- return userRepository.findById(id);
- }
-
- @CacheEvict(value = "users", key = "#id")
- public void update(User user) {
- userRepository.update(user);
- }
-
- @CacheEvict(value = "users", allEntries = true)
- public void clearCache() {
- // 清除所有缓存
- }
- }
复制代码
11.4 数据库优化
数据库性能优化是微服务性能的关键。
- # 使用StatefulSet部署数据库
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: postgresql
- spec:
- serviceName: postgresql
- replicas: 3
- selector:
- matchLabels:
- app: postgresql
- template:
- metadata:
- labels:
- app: postgresql
- spec:
- containers:
- - name: postgresql
- image: postgres:13
- ports:
- - containerPort: 5432
- env:
- - name: POSTGRES_DB
- value: userdb
- - name: POSTGRES_USER
- value: user
- - name: POSTGRES_PASSWORD
- valueFrom:
- secretKeyRef:
- name: postgresql-secret
- key: password
- volumeMounts:
- - name: postgresql-data
- mountPath: /var/lib/postgresql/data
- resources:
- requests:
- memory: "1Gi"
- cpu: "500m"
- limits:
- memory: "2Gi"
- cpu: "1000m"
- volumeClaimTemplates:
- - metadata:
- name: postgresql-data
- spec:
- accessModes: [ "ReadWriteOnce" ]
- resources:
- requests:
- storage: 10Gi
复制代码
12. 案例分析
12.1 电商平台的微服务架构
让我们以一个电商平台为例,分析如何在Kubernetes上设计和部署微服务架构。
电商平台可以拆分为以下微服务:
1. 用户服务(User Service)
2. 产品服务(Product Service)
3. 订单服务(Order Service)
4. 支付服务(Payment Service)
5. 库存服务(Inventory Service)
6. 通知服务(Notification Service)
7. API网关(API Gateway)
- # 用户服务部署
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: user-service
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:latest
- ports:
- - containerPort: 8080
- env:
- - name: DATABASE_URL
- valueFrom:
- secretKeyRef:
- name: user-service-secret
- key: database-url
- resources:
- requests:
- memory: "512Mi"
- cpu: "250m"
- limits:
- memory: "1Gi"
- cpu: "500m"
- livenessProbe:
- httpGet:
- path: /actuator/health/liveness
- port: 8080
- initialDelaySeconds: 30
- periodSeconds: 10
- readinessProbe:
- httpGet:
- path: /actuator/health/readiness
- port: 8080
- initialDelaySeconds: 5
- periodSeconds: 5
- ---
- apiVersion: v1
- kind: Service
- metadata:
- name: user-service
- spec:
- selector:
- app: user-service
- ports:
- - protocol: TCP
- port: 80
- targetPort: 8080
- type: ClusterIP
复制代码
服务间通信可以通过同步HTTP调用或异步消息队列实现。
- // 订单服务调用用户服务的示例
- @Service
- public class OrderService {
-
- @Autowired
- private RestTemplate restTemplate;
-
- @Autowired
- private KafkaTemplate<String, OrderEvent> kafkaTemplate;
-
- public Order createOrder(OrderRequest orderRequest) {
- // 获取用户信息
- User user = restTemplate.getForObject(
- "http://user-service/users/" + orderRequest.getUserId(),
- User.class
- );
-
- // 创建订单
- Order order = createOrderEntity(orderRequest, user);
-
- // 发送订单创建事件
- OrderEvent event = new OrderEvent(order.getId(), "CREATED", order);
- kafkaTemplate.send("order-events", event);
-
- return order;
- }
- }
复制代码
使用Kubernetes的Deployment和HPA进行部署和自动扩展。
- # 订单服务的HPA配置
- apiVersion: autoscaling/v2beta2
- kind: HorizontalPodAutoscaler
- metadata:
- name: order-service-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: order-service
- minReplicas: 3
- maxReplicas: 10
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 50
- - type: Resource
- resource:
- name: memory
- target:
- type: Utilization
- averageUtilization: 70
- behavior:
- scaleDown:
- stabilizationWindowSeconds: 300
- policies:
- - type: Percent
- value: 10
- periodSeconds: 60
- scaleUp:
- stabilizationWindowSeconds: 60
- policies:
- - type: Percent
- value: 100
- periodSeconds: 60
复制代码
12.2 金融科技公司的微服务迁移
让我们看一个金融科技公司如何从单体应用迁移到Kubernetes上的微服务架构。
采用绞杀者模式(Strangler Pattern)逐步迁移:
1. 识别边界上下文
2. 创建API网关
3. 逐步提取微服务
4. 重构数据库
5. 实现服务间通信
- # API网关配置
- apiVersion: networking.k8s.io/v1
- kind: Ingress
- metadata:
- name: api-gateway
- annotations:
- nginx.ingress.kubernetes.io/rewrite-target: /
- nginx.ingress.kubernetes.io/ssl-redirect: "true"
- spec:
- tls:
- - hosts:
- - api.fintech.com
- secretName: fintech-tls
- rules:
- - host: api.fintech.com
- http:
- paths:
- - path: /auth
- pathType: Prefix
- backend:
- service:
- name: auth-service
- port:
- number: 80
- - path: /accounts
- pathType: Prefix
- backend:
- service:
- name: account-service
- port:
- number: 80
- - path: /transactions
- pathType: Prefix
- backend:
- service:
- name: transaction-service
- port:
- number: 80
- - path: /
- pathType: Prefix
- backend:
- service:
- name: legacy-app
- port:
- number: 80
复制代码
数据库迁移是微服务迁移中最复杂的部分之一。
- // 使用Debezium进行CDC(Change Data Capture)
- @Service
- public class AccountMigrationService {
-
- @Autowired
- private KafkaTemplate<String, AccountEvent> kafkaTemplate;
-
- @EventListener
- public void handleAccountChange(AccountChangeEvent event) {
- // 处理账户变更事件
- AccountEvent accountEvent = new AccountEvent(
- event.getAccountId(),
- event.getChangeType(),
- event.getData()
- );
-
- // 发送到Kafka
- kafkaTemplate.send("account-events", accountEvent);
-
- // 更新微服务数据库
- if (event.getChangeType() == ChangeType.UPDATE) {
- accountRepository.update(event.getData());
- } else if (event.getChangeType() == ChangeType.CREATE) {
- accountRepository.create(event.getData());
- } else if (event.getChangeType() == ChangeType.DELETE) {
- accountRepository.delete(event.getAccountId());
- }
- }
- }
复制代码
建立全面的监控和可观察性系统。
- # Prometheus监控配置
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: prometheus-config
- data:
- prometheus.yml: |
- global:
- scrape_interval: 15s
- scrape_configs:
- - job_name: 'kubernetes-pods'
- kubernetes_sd_configs:
- - role: pod
- relabel_configs:
- - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
- action: keep
- regex: true
- - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
- action: replace
- target_label: __metrics_path__
- regex: (.+)
- - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
- action: replace
- regex: ([^:]+)(?::\d+)?;(\d+)
- replacement: $1:$2
- target_label: __address__
- - action: labelmap
- regex: __meta_kubernetes_pod_label_(.+)
- - source_labels: [__meta_kubernetes_namespace]
- action: replace
- target_label: kubernetes_namespace
- - source_labels: [__meta_kubernetes_pod_name]
- action: replace
- target_label: kubernetes_pod_name
复制代码
13. 企业数字化转型与业务创新
13.1 微服务与数字化转型的关系
微服务架构是企业数字化转型的重要技术基础。它提供了以下优势:
1. 敏捷性:微服务使企业能够快速响应市场变化,加速产品迭代。
2. 可扩展性:可以根据业务需求独立扩展特定功能。
3. 技术灵活性:每个微服务可以选择最适合的技术栈。
4. 团队自治:小团队可以负责特定微服务的全生命周期。
5. 弹性:单个服务的故障不会导致整个系统崩溃。
13.2 Kubernetes如何支持业务创新
Kubernetes作为微服务的理想运行平台,支持业务创新的方式包括:
1. 快速部署:自动化部署流程,缩短从开发到上线的周期。
2. 资源优化:高效利用资源,降低IT成本。
3. 多云战略:Kubernetes的云无关性使企业能够在不同云提供商之间迁移。
4. DevOps实践:促进开发和运维的协作,加速交付。
5. 自动化运维:减少手动操作,提高系统稳定性。
13.3 成功案例分析
Netflix是微服务架构的先驱,其成功经验包括:
1. 文化转型:建立”自由与责任”的文化,鼓励创新。
2. 技术栈:开发了Eureka、Ribbon、Hystrix等微服务框架。
3. DevOps实践:实施持续交付,每天部署数百次。
4. 混沌工程:主动注入故障,提高系统弹性。
Uber的微服务架构支持了其全球业务的快速扩展:
1. 领域驱动设计:基于业务领域划分微服务。
2. 服务网格:使用内部开发的服务网格管理服务间通信。
3. 数据平台:构建了强大的数据平台支持业务决策。
4. 全球化:微服务架构支持了Uber在全球的快速扩张。
13.4 数字化转型路线图
企业数字化转型可以遵循以下路线图:
1. 评估现状:分析现有系统、流程和文化。
2. 制定战略:明确转型目标和关键指标。
3. 试点项目:选择低风险、高价值的项目作为试点。
4. 建立平台:构建基于Kubernetes的云原生平台。
5. 能力建设:培训团队,建立DevOps文化。
6. 规模化推广:将成功经验推广到更多项目。
7. 持续优化:不断改进技术、流程和文化。
14. 未来发展趋势
14.1 Serverless与微服务
Serverless(无服务器)架构是微服务的演进方向,它进一步抽象了基础设施管理。
- # Knative Serving示例
- apiVersion: serving.knative.dev/v1
- kind: Service
- metadata:
- name: user-service
- spec:
- template:
- spec:
- containers:
- - image: myregistry/user-service:latest
- env:
- - name: DATABASE_URL
- valueFrom:
- secretKeyRef:
- name: user-service-secret
- key: database-url
- resources:
- limits:
- cpu: "500m"
- memory: "512Mi"
复制代码
14.2 Service Mesh的演进
服务网格技术将继续演进,提供更强大的服务治理能力。
- # Istio 1.10+的新特性示例
- apiVersion: networking.istio.io/v1alpha3
- kind: Telemetry
- metadata:
- name: default
- namespace: istio-system
- spec:
- # 不需要选择器,适用于整个命名空间
- # 覆盖工作区范围的遥测配置
- metrics:
- - providers:
- - name: prometheus
- overrides:
- - match:
- metric: ALL_METRICS
- tagOverrides:
- destination_service_name:
- operation: UPSERT
- value: "destination_service_name | 'unknown'"
复制代码
14.3 多集群与多云管理
随着企业采用多云战略,多集群和多云管理将成为关键。
- # KubeFed多集群联邦示例
- apiVersion: types.kubefed.io/v1beta1
- kind: KubeFedCluster
- metadata:
- name: cluster2
- namespace: kube-federation-system
- spec:
- apiEndpoint: https://cluster2.example.com
- secretRef:
- name: cluster2-secret
- provider: cluster-provider
- ---
- apiVersion: types.kubefed.io/v1beta1
- kind: FederatedDeployment
- metadata:
- name: user-service
- namespace: default
- spec:
- template:
- metadata:
- labels:
- app: user-service
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: user-service
- template:
- metadata:
- labels:
- app: user-service
- spec:
- containers:
- - name: user-service
- image: myregistry/user-service:latest
- ports:
- - containerPort: 8080
- placement:
- clusters:
- - name: cluster1
- - name: cluster2
复制代码
14.4 AI/ML与微服务结合
人工智能和机器学习将与微服务架构深度融合,提供智能化服务。
- # 使用TensorFlow Serving部署ML模型作为微服务
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: tensorflow-serving
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: tensorflow-serving
- template:
- metadata:
- labels:
- app: tensorflow-serving
- spec:
- containers:
- - name: tensorflow-serving
- image: tensorflow/serving:latest-gpu
- ports:
- - containerPort: 8500
- env:
- - name: MODEL_NAME
- value: user-preference-model
- volumeMounts:
- - name: model-storage
- mountPath: /models/user-preference-model
- volumes:
- - name: model-storage
- persistentVolumeClaim:
- claimName: model-pvc
复制代码
15. 总结
微服务与Kubernetes的结合为企业数字化转型提供了强大的技术支持。通过本文的全面解析,我们了解了从架构设计到部署运维的完整流程,掌握了容器化微服务治理的核心技术与方法。
微服务架构提供了灵活性、可扩展性和弹性,使企业能够快速响应市场变化。Kubernetes作为容器编排平台,为微服务提供了理想的运行环境,自动化了部署、扩展和管理过程。
在实践中,企业需要根据自身情况选择合适的微服务拆分策略、通信模式和部署策略。同时,监控、日志、故障排查、安全性和性能优化也是微服务治理的重要组成部分。
通过案例分析,我们看到了微服务与Kubernetes结合在不同行业的应用,以及它们如何支持企业的数字化转型和业务创新。未来,随着Serverless、Service Mesh、多云管理和AI/ML等技术的发展,微服务架构将继续演进,为企业提供更强大的技术支持。
在数字化转型的道路上,技术只是手段,真正的成功需要企业文化的转变、组织结构的调整和业务流程的重构。微服务与Kubernetes的结合,为企业提供了实现这些变革的技术基础,助力企业在数字化时代保持竞争优势。
版权声明
1、转载或引用本网站内容(微服务与Kubernetes结合的最佳实践 从架构设计到部署运维全面解析容器化微服务治理的核心技术与方法助力企业实现数字化转型与业务创新)须注明原网址及作者(威震华夏关云长),并标明本网站网址(https://www.pixtech.cc/)。
2、对于不当转载或引用本网站内容而引起的民事纷争、行政处理或其他损失,本网站不承担责任。
3、对不遵守本声明或其他违法、恶意使用本网站内容者,本网站保留追究其法律责任的权利。
本文地址: https://www.pixtech.cc/thread-34774-1-1.html
|
|