Este artículo lo comparte el autor " Implementación de la gestión del tráfico de múltiples clústeres basado en Istio " de la comunidad de la nube de Huawei: Puedes hacer un amigo.
un fondo
La gobernanza de servicios para infraestructura heterogénea, como la nube múltiple y la nube híbrida, es uno de los escenarios en los que Istio se centra en respaldar. Para mejorar la disponibilidad del servicio y evitar la dependencia de los proveedores, las empresas generalmente optan por implementar aplicaciones en múltiples clústeres en múltiples regiones, o incluso en múltiples entornos de nube, como las soluciones de múltiples nubes y de múltiples clústeres que se han convertido gradualmente en las mejores. elección para la implementación de aplicaciones empresariales. Por lo tanto, cada vez más usuarios tienen fuertes demandas de gobernanza de servicios entre clústeres. En este contexto, Istio, como estándar de facto en el campo ServiceMesh, ha lanzado una variedad de soluciones de gestión de múltiples clústeres.
2. Introducción
Actualmente, Istio admite 4 modelos de múltiples clústeres.
- Modelo de plano de control único de red plana
- Modelo de plano multicontrol de red plana
- Modelo de plano de control único de red no plana
- Modelo de plano de control múltiple de red no plana
El modelo de plano de control único de múltiples clústeres significa que varios clústeres comparten el mismo plano de control de Istio. El modelo de plano de control múltiple de múltiples clústeres significa que cada clúster debe usar de forma independiente un conjunto de planos de control de Istio, ya sea un control único. plano o un modelo de plano de control múltiple, cada conjunto de plano de control de Istio (istiod) debe estar conectado al Kube-apiserver de todos los clústeres, y List-Watch obtiene todos los clústeres Service、Endpoint、Pod 、Node
y controla el acceso a los servicios dentro del clúster o entre clústeres. solo monitorea VirtualService、DestinationRule、Gateway
los objetos API de Istio del clúster principal.
Dependiendo de si la red entre clústeres es plana o no, Istio subdivide dos modelos de plano de control:
- Red plana: las redes de contenedores de múltiples clústeres están conectadas a través de VPN y otras tecnologías, y los Pods pueden acceder directamente a través de los clústeres.
- Red no plana: las redes de contenedores de cada clúster están aisladas entre sí y no se puede pasar el acceso entre clústeres y debe pasar por la puerta de enlace este-oeste.
Al elegir el modelo de múltiples clústeres de Istio en un entorno de producción, por supuesto, debe tomar una decisión en función de su escenario real. Si la red entre clústeres es plana, puede elegir un modelo de red plana, si la red entre clústeres está aislada, puede elegir un modelo de red no plana. Si el tamaño del clúster es pequeño, puede elegir el modelo de plano de control único. Si el tamaño del clúster es grande, puede elegir el modelo de plano de control múltiple.
Este documento selecciona un modelo de plano de control múltiple de red no plana para las instrucciones de instalación: El modelo de instalación es el siguiente. El
modelo de plano de control múltiple de red no plana tiene las siguientes características.
- No es necesario que diferentes clústeres estén bajo una red grande, es decir, la red de contenedores no necesita estar conectada en tres capas y el acceso al servicio entre clústeres se realiza mediante
Istio East-West Gateway
reenvío. - No hay límite en el rango de direcciones del Pod y el rango de direcciones de servicio de cada clúster de Kubernetes. Puede superponerse con otros clústeres y los diferentes clústeres no interfieren entre sí.
- El Sidecar de cada clúster de Kubernetes solo está conectado al plano de control Istio de este clúster, lo que hace que la comunicación sea más eficiente.
- Istiod solo monitorea la configuración de Istio del clúster principal, por lo que existen problemas de replicación redundante para otros recursos.
VirtualService、DestinationRule、Gateway
- Acceso a servicios internos en el mismo clúster: conexión directa entre Pods; acceso a servicios entre clústeres: depende del proxy DNS para resolver los nombres de dominio de servicio de otros clústeres. Dado que las redes entre clústeres están aisladas entre sí, dependen del tráfico de tránsito. el clúster remoto.
East-west Gateway
Construcción de tres entornos ClusterMesh
Cree dos clústeres, cluster1 y cluster2, y luego instale el plano de control de Istio en cada clúster y configúrelos como clústeres principales. El clúster cluster1 está en la red network1 y el cluster cluster2 está en la red network2.
3.1 Requisitos previos
La información del entorno para esta compilación es la siguiente: Utilice Kind para crear un clúster de Kubernetes y la versión de Kind es v0.19.0. La versión de Kubernetes es 1.27.3; la versión de Istio es 1.20.1.
Antes de crear un clúster k8s, asegúrese de que docker kubectl y kind estén instalados en el nodo de Linux.
Descargar el binario istioctl
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.20.1 TARGET_ARCH=x86_64 sh -
Agregar cliente istioctl a la ruta

3.2 Instalación del clúster de Kubernetes
Los scripts de instalación del clúster cluster1 y cluster2 son los siguientes
# crear-cluster.sh # Este script maneja la creación de múltiples clústeres usando kind y the # capacidad para crear y configurar un registro de contenedores inseguro. establecer -o xtrace conjunto -o elevado conjunto -o sustantivo set -o error de tubería # shellcheck fuente=util.sh NUM_CLUSTERS="${NUM_CLUSTERS:-2}" KIND_IMAGE="${KIND_IMAGE:-}" KIND_TAG="${KIND_TAG:-v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72}" SO="$(nombre)" función crear-clústeres() { núm_clusters locales=${1} imagen local_arg="" si [[ "${KIND_IMAGE}" ]]; entonces image_arg="--image=${KIND_IMAGE}" elif [[ "${KIND_TAG}" ]]; entonces image_arg="--image=más amable/nodo:${KIND_TAG}" ser para i en $(seq "${num_clusters}"); hacer tipo crear cluster --name "cluster${i}" "${image_arg}" grupo de reparación "${i}" eco hecho } función arreglo-cluster() { local i=${1} # número de clúster si [ "$OS" != "Darwin" ];entonces # Establezca la dirección IP del contenedor como punto final de la API de Kube para que los clústeres lleguen a los servidores API de Kube en otros clústeres. docker_ip local docker_ip=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "cluster${i}-control-plane") kubectl config set-cluster "kind-cluster${i}" --server="https://${docker_ip}:6443" ser # Simplificar el nombre del contexto kubectl config rename-context "kind-cluster${i}" "cluster${i}" } echo "Creando ${NUM_CLUSTERS} clústeres" crear-clústeres "${NUM_CLUSTERS}" kubectl config uso-contexto cluster1 echo "El tipo de CIDR es $(docker network inspect -f '{{$map := index .IPAM.Config 0}}{{index $map "Subnet"}}' tipo)" eco "completo"
Durante el proceso de instalación del clúster anterior, para que istiod acceda apiserver
a la dirección del otro clúster, kube-apiserver
la dirección del clúster se establece en la dirección del nodo maestro. Debido a que es un clúster implementado por tipo, los nodos maestros de los dos clústeres son esencialmente contenedores que ejecutan Docker en el mismo host.
Confirme si cluster1 y cluster2 están listos

3.3 Utilice MetalLB para asignar IP externa a la puerta de enlace
Dado que kind se utiliza para implementar múltiples clústeres, la creación de la puerta de enlace norte-sur y la puerta de enlace este-oeste de istio requiere la creación del servicio LoadBalencer, los cuales requieren el uso de ExternalIP. Aquí, metalLB se utiliza para realizar la distribución y el anuncio de las direcciones IP de LB.
Consulte cómo construir un clúster utilizando el segmento de subred de nodo: implementar en modo metalLB L2. 172.18.0.0/16
Lista de configuración de metalLB en cluster1: metallb-config-1.yaml
### para el grupo1 ##Configure IPAddressPool para la asignación de direcciones lbip. En modo L2, la dirección de ippool y el nodo trabajador pueden estar en la misma subred. Versión api: metallb.io/v1beta1 tipo: IPAddressPool metadatos: nombre: primer grupo espacio de nombres: sistema metallb Especificaciones: direcciones: - 172.18.1.230-172.18.1.240 --- ##Configurar L2Advertisement para el anuncio de dirección Versión api: metallb.io/v1beta1 tipo: L2Anuncio metadatos: nombre: primer-adv espacio de nombres: sistema metallb Especificaciones: grupos de direcciones ip: - primer grupo
Lista de configuración de metalLB en el clúster cluster2: metallb-config-2.yaml
### para el clúster2 ##Configure IPAddressPool para la asignación de direcciones lbip. En modo L2, la dirección de ippool y el nodo trabajador pueden estar en la misma subred. Versión api: metallb.io/v1beta1 tipo: IPAddressPool metadatos: nombre: segundo grupo espacio de nombres: sistema metallb Especificaciones: direcciones: - 172.18.1.241-172.18.1.252 --- ##Configurar L2Advertisement para el anuncio de dirección Versión api: metallb.io/v1beta1 tipo: L2Anuncio metadatos: nombre: segundo-adv espacio de nombres: sistema metallb Especificaciones: grupos de direcciones ip: - segunda piscina
Instalar usando script
#!/usr/bin/env bash establecer -o xtrace conjunto -o elevado conjunto -o sustantivo set -o error de tubería NUM_CLUSTERS="${NUM_CLUSTERS:-2}" para i en $(seq "${NUM_CLUSTERS}"); hacer echo "Iniciando la implementación de metallb en el cluster${i}" kubectl aplicar -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml --context "cluster${i}" kubectl crea una lista de miembros secreta genérica -n metallb-system --from-literal=secretkey="$(openssl rand -base64 128)" --context "cluster${i}" ## Aumente el tiempo de espera. Si la carga de metallb no se implementa, se informará un error al crear IPAddressPool L2Advertisement. dormir 10 kubectl apply -f ./metallb-config-${i}.yaml --context "cluster${i}" eco "----" hecho
Confirmar el estado de implementación de metalLB
Confirme la información de IPAddressPool:

3.4 Relación de confianza de configuración de CA raíz compartida del clúster
Para admitir la comunicación mTLS segura entre clústeres, el modelo de plano de control múltiple requiere que el plano de control Istiod de cada clúster utilice un certificado de CA intermedio emitido por la misma autoridad de CA para que Citatel emita certificados para admitir la autenticación bidireccional TLS entre clústeres. .
La puerta de enlace este-oeste de Istio (acceso entre clústeres) utiliza enrutamiento basado en SNI cuando funciona. Lo enruta automáticamente al clúster correspondiente al SNI según el SNI solicitado por TLS. Requiere que todo el tráfico esté cifrado con TLS.
Inserte el certificado y la clave en el clúster. El script es el siguiente (el script debe moverse al directorio del paquete de instalación de istio):
#!/usr/bin/env bash establecer -o xtrace #set -o levantado conjunto -o sustantivo set -o error de tubería NUM_CLUSTERS="${NUM_CLUSTERS:-2}" ## Cree un directorio en el directorio de nivel superior del paquete de instalación de istio para almacenar certificados y claves. mkdir -p certificados certificados pushd ##Generar certificado raíz y clave make -f ../tools/certs/Makefile.selfsigned.mk raíz-ca para i en $(seq "${NUM_CLUSTERS}"); hacer ##Para cada clúster, genere un certificado intermedio y una clave para Istio CA make -f ../tools/certs/Makefile.selfsigned.mk "clúster${i}-cacerts" ##Para cada clúster, cree el espacio de nombres del sistema istio kubectl crea espacio de nombres istio-system --context "cluster${i}" ## Para cada clúster, agregue una identificación de red etiquetando el espacio de nombres del sistema istio con la etiqueta topology.istio.io/network kubectl --context="cluster${i}" espacio de nombres de etiqueta istio-system topology.istio.io/network="network${i}" ##Para cada clúster, etiquete el nodo de trabajo con una región y zona de disponibilidad para facilitar que istio implemente la conmutación por error regional y el equilibrio de carga regional. kubectl --context="cluster${i}" nodo de etiqueta "cluster${i}-control-plane" topology.kubernetes.io/region="region${i}" kubectl --context="cluster${i}" nodo de etiqueta "cluster${i}-control-plane" topology.kubernetes.io/zone="zone${i}" #En cada clúster, cree cacerts privados, utilizando todos los archivos de entrada ca-cert.pem, ca-key.pem, root-cert.pem y cert-chain.pem. kubectl elimina cacerts secretos -n istio-system --context "cluster${i}" kubectl crea cacerts genéricos secretos -n istio-system --context "cluster${i}" \ --from-file="clúster${i}/ca-cert.pem" \ --from-file="clúster${i}/ca-key.pem" \ --from-file="clúster${i}/root-cert.pem" \ --from-file="clúster${i}/cert-chain.pem" eco "----" hecho
3.5 Instalación de malla de servicio Istio
Instale la cuadrícula istio del plano de control múltiple para los clústeres cluster1 y cluster2.
Configure cluster1 como el clúster principal y ejecute el siguiente comando en el directorio de instalación de istio
gato <<EOF> cluster1.yaml Versión de api: install.istio.io/v1alpha1 tipo: IstioOperator Especificaciones: valores: global: ID de malla: malla1 multiCluster: ##Habilitar configuración de múltiples clústeres clusterName: cluster1 #Especifique el nombre del clúster k8s red: red1 #Especifique el identificador de red Inicio sesión: nivel: depurar EOF
Configure cluster2 como el clúster principal y ejecute el siguiente comando en el directorio de instalación de istio
gato <<EOF> cluster2.yaml Versión de api: install.istio.io/v1alpha1 tipo: IstioOperator Especificaciones: valores: global: ID de malla: malla2 multiCluster: ##Habilitar configuración de múltiples clústeres clusterName: cluster2 #Especifique el nombre del clúster k8s red: red2 #Especifique el identificador de red Inicio sesión: nivel: depurar EOF
#!/usr/bin/env bash establecer -o xtrace conjunto -o elevado conjunto -o sustantivo set -o error de tubería SO="$(nombre)" NUM_CLUSTERS="${NUM_CLUSTERS:-2}" para i en $(seq "${NUM_CLUSTERS}"); hacer echo "Iniciando la implementación de istio en el cluster${i}" istioctl install --force --context="cluster${i}" -f "cluster${i}.yaml" echo "Generar puerta de enlace este-oeste en el cluster${i}" ## Instale puertas de enlace este-oeste en cada clúster. muestras de bash/multicluster/gen-eastwest-gateway.sh \ --mesh "mesh${i}" --cluster "cluster${i}" --network "red${i}" | \ istioctl --context="clúster${i}" instalar -y -f - eco hecho
Ejecute el script para instalar e implementar istio
Espere un momento hasta que se complete la instalación.
3.6 Servicios de apertura en la pasarela este-oeste
Debido a que los clústeres están en redes diferentes, necesitamos abrir todos los servicios (*.local) en las puertas de enlace este-oeste de ambos clústeres. Aunque esta puerta de enlace es pública en Internet, solo se puede acceder a los servicios detrás de ella mediante servicios con certificados mTLS confiables, como si estuvieran en la misma red. Ejecute los siguientes comandos para exponer los servicios en ambos clústeres:
Versión api: networking.istio.io/v1beta1 tipo: puerta de enlace metadatos: nombre: puerta de enlace entre redes Especificaciones: selector: istio: eastwestgateway # Puerta de enlace dedicada para el tráfico este-oeste servidores: - puerto: número: 15443 # Ya declarado nombre: tls protocolo: TLS tls: modo: AUTO_PASSTHROUGH # El modo de funcionamiento de la puerta de enlace este-oeste es TLS AUTO_PASSTHROUGH Hospedadores: - "*.local" # Exponer todos los servicios
Aplique la configuración de puerta de enlace anterior en cada clúster por separado:
kubectl -n istio-system --context=cluster${i} apply -f samples/multicluster/expose-services.yaml
3.7 Configurar el secreto para que istiod pueda acceder al apiserver del clúster remoto
El istiod en cada clúster de k8s necesita monitorear en lista el Kube-APIServer de otros clústeres y usar las credenciales del clúster de K8s para crear un objeto secreto que permita a Istio acceder al apiserver remoto de Kubernetes.
#!/usr/bin/env bash establecer -o xtrace conjunto -o elevado conjunto -o sustantivo set -o error de tubería SO="$(nombre)" NUM_CLUSTERS="${NUM_CLUSTERS:-2}" para i en $(seq "${NUM_CLUSTERS}"); hacer para j en $(seq "${NUM_CLUSTERS}"); hacer si [ "$i" -ne "$j" ] entonces echo "Habilitar descubrimiento de puntos finales entre el clúster${i} y el clúster${j}" si [ "$OS" == "Darwin" ] entonces # Establezca la dirección IP del contenedor como punto final de la API de Kube para que los clústeres lleguen a los servidores API de Kube en otros clústeres. docker_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "cluster${i}-control-plane") istioctl crear-secreto-remoto \ --context="clúster${i}" \ --servidor="https://${docker_ip}:6443" \ --name="clúster${i}" | \ kubectl aplicar --validate=false --context="cluster${j}" -f - demás istioctl crear-secreto-remoto \ --context="clúster${i}" \ --name="clúster${i}" | \ kubectl aplicar --validate=false --context="cluster${j}" -f - ser ser hecho hecho
Ejecute el script anterior: se crea el secreto remoto.
Verifique el registro de istiod y descubra que el clúster remoto ya está monitoreado.
Cuatro prácticas de gestión del tráfico de múltiples clústeres de Istio
kubectl crea --context=muestra de espacio de nombres cluster1 kubectl crea --context=muestra de espacio de nombres cluster2 etiqueta kubectl --context=muestra de espacio de nombres cluster1 \ istio-inyección = habilitado etiqueta kubectl --context=muestra de espacio de nombres cluster2 \ istio-inyección = habilitado aplicar kubectl --context=cluster1 \ -f muestras/holamundo/holamundo.yaml \ -l servicio=holamundo -n muestra aplicar kubectl --context=cluster2 \ -f muestras/holamundo/holamundo.yaml \ -l servicio=holamundo -n muestra
Implementar diferentes versiones de servicios en diferentes clústeres
Implemente la aplicación helloworld-v1 en cluster1:aplicar kubectl --context=cluster1 \ -f muestras/holamundo/holamundo.yaml \ -l versión=v1 -n muestraImplemente la aplicación helloworld-v2 en cluster2:
aplicar kubectl --context=cluster2 \ -f muestras/holamundo/holamundo.yaml \ -l versión=v2 -n muestraImplementar cliente de prueba
aplicar kubectl --context=cluster1 \ -f muestras/dormir/dormir.yaml -n muestra aplicar kubectl --context=cluster2 \ -f muestras/dormir/dormir.yaml -n muestra
Confirme que la instancia de carga se haya implementado correctamente y que se haya inyectado el sidecar

4.1 Verificar el tráfico entre clústeres
Utilice Sleep pod para llamar repetidamente al servicio HelloWorld. Para confirmar que el equilibrio de carga funciona como se esperaba, se debe llamar al servicio HelloWorld desde todos los clústeres.
Enviar una solicitud al servicio HelloWorld desde el pod Sleep en cluster1
Enviar una solicitud al servicio HelloWorld desde el pod Sleep en cluster2
4.3 Verificar el acceso desde la puerta de enlace
Accede al servidor Helloworld a través del gateway
Cree recursos de istio, como servicio virtual y puerta de enlace, la lista de configuración es la siguiente
# holamundo-gateway.yaml Versión api: networking.istio.io/v1beta1 tipo: puerta de enlace metadatos: nombre: helloworld-gateway Especificaciones: selector: istio: entrada de entrada # use el controlador predeterminado de istio servidores: - puerto: número: 80 nombre: http protocolo: HTTP Hospedadores: - "*" --- Versión api: networking.istio.io/v1beta1 tipo: Servicio Virtual metadatos: nombre: hola mundo Especificaciones: Hospedadores: - "*" puertas de enlace: - puerta de enlace de helloworld http: - fósforo: - tipo: exacto: /hola ruta: - destino: anfitrión: hola mundo puerto: número: 5000
Nota: Esta configuración debe aplicarse a ambos clústeres.
El efecto de acceso es el siguiente:

4.3 Verificar el equilibrio de carga regional
Para un control más preciso sobre el tráfico, establezca las ponderaciones de las dos regiones en 80 % y 20 % respectivamente y utilice DestinationRule para configurar la distribución de ponderaciones . region1 -> zone1
region1 -> zone2
# localidad-lb-peso.yaml Versión api: networking.istio.io/v1beta1 tipo: Regla de destino metadatos: nombre: hola mundo espacio de nombres: muestra Especificaciones: anfitrión: helloworld.sample.svc.cluster.local política de tráfico: grupo de conexiones: http: solicitudes máximas por conexión: 1 equilibrador de carga: sencillo: ROUND_ROBIN localidadLbConfiguración: habilitado: verdadero distribuir: - desde: región1/* a: "región1/*": 80 "región2/*": 20 - desde: región2/* a: "región2/*": 80 "región1/*": 20 Detección atípica: consecutivos5xxErrores: 1 intervalo: 1s tiempo de eyección base: 1 m
Nota: Esta configuración debe aplicarse a ambos clústeres.
Enviar una solicitud al servicio HelloWorld desde el cluster1 a través de la puerta de enlace
Enviar una solicitud al servicio HelloWorld desde cluster2 a través del gateway

4.4 Verificar la conmutación por error regional
Cuando se implementan varias instancias de servicio en varias regiones/regiones, si la instancia de servicio en una determinada región/región no está disponible, el tráfico se puede transferir a instancias de servicio en otras regiones/regiones para lograr la conmutación por error regional, garantizando así la confiabilidad del servicio.
# localidad-lb-failover.yaml Versión api: networking.istio.io/v1beta1 tipo: Regla de destino metadatos: nombre: hola mundo espacio de nombres: muestra Especificaciones: anfitrión: helloworld.sample.svc.cluster.local política de tráfico: grupo de conexiones: http: maxRequestsPerConnection: 1 # Desactive HTTP Keep-Alive y fuerce cada solicitud HTTP a utilizar una nueva política de conexión equilibrador de carga: sencillo: ROUND_ROBIN localityLbSetting: # Configuración de equilibrio de carga regional, después de activar la detección de valores atípicos, se activa de forma predeterminada. habilitado: verdadero conmutación por error: # estrategia de conmutación por error regional - desde: región1 a: región2 - de: región2 a: región1 Detección atípica: consecutiva5xxErrors: 1 # 1 error 5xx consecutivo intervalo: 1s # Intervalo de detección 1s baseEjectionTime: 1m #Tiempo de expulsión básico 1m
Nota: Esta configuración debe aplicarse a ambos clústeres.
Enviar una solicitud al servicio HelloWorld desde el cluster1 a través de la puerta de enlace
Simule una falla y configure manualmente la versión Helloworld V1 en el clúster cluster1 para que falle.
Acceda nuevamente, la detección de fallas surte efecto, activa la conmutación por error y verifica que la versión en la respuesta sea siempre v2, lo que significa que estamos accediendo al servicio helloworld en la región 2, logrando así la conmutación por error regional.
La premisa de la conmutación por error es que cuando todas las instancias de la región actual no estén disponibles, se transferirá a la región actual. De lo contrario, el tráfico se enviará a otras instancias disponibles en la región actual.
Cinco comentarios
Las referencias son las siguientes:
-
Comunidad de código abierto de istio (instrucciones de instalación para arquitectura multiprimaria entre redes): https://istio.io/latest/zh/docs/setup/install/multicluster/multi-primary_multi-network/
-
Referencia del script del clúster de instalación amable: https://github.com/cnych/multi-cluster-istio-kind/tree/main/kind-create
-
Referencia de gestión de certificados de múltiples clústeres: https://istio.io/latest/zh/docs/tasks/security/cert-management/plugin-ca-cert/
Haga clic para seguir y conocer las nuevas tecnologías de Huawei Cloud lo antes posible ~
La primera actualización importante de JetBrains 2024 (2024.1) es de código abierto. Incluso Microsoft planea pagar por ella. ¿Por qué todavía se le critica por ser de código abierto? [Recuperado] El backend de Tencent Cloud falló: una gran cantidad de errores de servicio y no hay datos después de iniciar sesión en la consola. Alemania también necesita ser "controlable de forma independiente". El gobierno estatal migró 30,000 PC de Windows a Linux deepin-IDE y finalmente logró ¡arranque! Se lanza Visual Studio Code 1.88. Buen chico, Tencent realmente ha convertido a Switch en una "máquina de aprendizaje pensante". El escritorio remoto de RustDesk inicia y reconstruye el cliente web. La base de datos de terminal de código abierto de WeChat basada en SQLite, WCDB, ha recibido una actualización importante.