Концепция реального боя K8s, развертывание кластера и настройка сервиса

Docker Kubernetes

Концепция реального боя K8s, развертывание кластера и настройка сервиса

Эта статья дляКубернет в действииДоработка цикла статей.

Kubernetes [koo-ber-nay'-tice] – это механизм оркестровки и планирования контейнеров Google с открытым исходным кодом, основанный на Borg. Он поддерживает различные базовые технологии виртуализации контейнеров и обладает полным набором функций для поддержки распределенных систем и микросервисных архитектур. Широкие возможности горизонтального расширения; он обеспечивает автоматическое развертывание и репликацию контейнеров, расширяет или сокращает масштаб контейнера в любое время, организует контейнеры в группы, обеспечивает балансировку нагрузки между контейнерами, а также эластичность контейнеров и другие функции. Как один из наиболее важных компонентов CNCF (Cloud Native Computing Foundation), его можно описать как облачную операционную систему; его цель — не только быть системой оркестровки, но и предоставить спецификацию, позволяющую описать архитектуру кластер и определить конечное состояние службы.

концепт дизайна

По сравнению с общей платформой PaaS, K8s также поддерживает развертывание сервисов, автоматическую работу и обслуживание, планирование ресурсов, расширение и сокращение, самовосстановление, балансировку нагрузки, обнаружение сервисов и другие функции, а его уникальной особенностью является то, что он сравнивает уровень инфраструктуры. Хорошая способность к абстракции. K8s не имеет дело с очень разными частями, такими как конкретное хранилище и сеть, но не зависит от облака и начинает реализовывать различные интерфейсы и абстракции. Например, интерфейс времени выполнения контейнера (CRI), сетевой интерфейс контейнера (CNI), интерфейс хранилища контейнера (CSI). Эти интерфейсы делают Kubernetes невероятно открытым, в то же время позволяя сосредоточиться на локальных развертываниях и планировании контейнеров.

Kubernetes имеет многоуровневую архитектуру, похожую на Linux, как показано на следующей диаграмме:

  • Уровень инфраструктуры: включая среду выполнения контейнера, сеть, хранилище и т. д.

  • Базовый уровень: основная функция Kubernetes, он предоставляет внешние API для создания высокоуровневых приложений, а внутри предоставляет подключаемую среду выполнения приложений.

  • Уровень приложений: развертывание (приложения без сохранения состояния, приложения с отслеживанием состояния, задания и т. д.) и маршрутизация (обнаружение служб, балансировка нагрузки и т. д.)

  • Уровень управления: системные метрики (например, инфраструктура, контейнер и сетевые метрики), автоматизация (например, автоматическое масштабирование, динамическая подготовка и т. д.) и управление политиками (RBAC, Quota, PSP, NetworkPolicy и т. д.)

  • Уровень интерфейса: инструмент командной строки kubectl, клиентский SDK и объединение кластеров.

  • Экосистема: огромная экосистема управления кластером контейнеров и планирования над уровнем интерфейса может быть разделена на две категории: ведение журнала, мониторинг, управление конфигурацией, CI, CD, рабочий процесс, FaaS, приложения OTS, ChatOps и другие внешние экосистемы, а также CRI, внутренние экология, такая как CNI, CSI, хранилище образов, Cloud Provider, а также настройка и управление кластером.

Все конфигурации в Kubernetes задаются через спецификацию объекта API, то есть пользователи могут изменять систему, настраивая идеальное состояние системы.Это одна из важных концепций проектирования Kubernetes, то есть все операции являются декларативными. а не обязательно. Преимущество декларативных операций в распределенной системе заключается в том, что она стабильна и не боится потери операций или многократного запуска.Например, установка количества реплик равным 3 все равно является результатом многократного выполнения, в то время как операция добавление 1 к количеству реплик не является декларативным. , результат многократного запуска неверен.

По сравнению с императивными операциями декларативные операции более стабильны и легче воспринимаются пользователями, потому что API подразумевает целевые объекты, с которыми пользователи хотят работать, и эти объекты являются существительными, такими как Сервис, Развертывание, PV и т. д.; и декларативные файлы конфигурации ближе к «человеческим языкам», таким как YAML, JSON. Концепция декларативного проектирования помогает создать замкнутый цикл управления, постоянно наблюдать и исправлять и, наконец, доводить рабочее состояние до желаемого пользователем состояния, воспринимать поведение пользователя и выполнять его. Например, изменение количества подов, обновление/откат приложения и т. д. Планировщик является ядром, но он отвечает только за выбор подходящего узла из узлов кластера для запуска подов.Очевидно, что планировщик не подходит для реализации привлекательной функции, и для ее реализации требуется специальный компонент-контроллер.

Компоненты и объекты

Различные функции Kubernetes неотделимы от определяемых им объектов ресурсов, и эти объекты могут быть представлены в Etcd кластера через API. Определение и реализация API соответствуют формату HTTP REST. Пользователи могут добавлять, удалять, изменять и запрашивать связанные объекты ресурсов с помощью стандартных HTTP-команд (POST, PUT, GET, DELETE). Часто используемые объекты ресурсов, такие как Deployment, DaemonSet, Job, PV и т. д. Абстракция API также предназначена для определения этой части объекта ресурса. В Kubernetes реализована новая функция, которая обычно создает новый объект ресурса, и функция также реализуется на основе этого объекта.

категория название
ресурсный объект Pod, ReplicaSet, ReplicationController, Deployment, StatefulSet, DaemonSet, Job, CronJob, HorizontalPodAutoscaling, Node, Namespace, Service, Ingress, Label, CustomResourceDefinition
объект хранения Том, PersistentVolume, Секрет, ConfigMap
объект политики SecurityContext, ResourceQuota, LimitRange
объект идентификации Учетная запись службы, роль, роль кластера

Здесь мы выбираем несколько ключевых объектов для представления.

Развертывание

Развертывание представляет собой операцию обновления пользователем кластера Kubernetes. Развертывание — это более широкий объект API, чем модель приложения RS, который может включать создание новой службы, обновление новой службы или развертывание службы. Скользящее обновление службы на самом деле представляет собой составную операцию создания новой RS, затем постепенного увеличения количества реплик в новой RS до идеального состояния и уменьшения количества реплик в старой RS до 0; такая составная операция с использованием один RS не является слишком описательным, поэтому я использую более общее развертывание для его описания. С направлением развития Kubernetes будущее управление всеми долгосрочными серверными предприятиями будет осуществляться через развертывание.

Услуга

RC, RS и Deployment только гарантируют количество модулей микросервисов, поддерживающих сервисы, но не решают проблему доступа к этим сервисам. Если развертывание отвечает за обеспечение нормальной работы группы подов, то служба используется для обеспечения того, чтобы для подключения к группе подов использовалась разумная сеть.

Pod — это просто экземпляр работающего сервиса, который можно остановить на одном узле в любой момент, а новый Pod запускается на другом узле с новым IP, поэтому он не может предоставлять услуги с детерминированным IP и номером порта. Для стабильного предоставления услуг требуются возможности обнаружения служб и балансировки нагрузки. Работа, выполняемая при обнаружении службы, заключается в поиске соответствующего экземпляра серверной службы для службы, к которой обращается клиент. В кластере K8 сервис, к которому должен получить доступ клиент, — это объект Service. Каждая служба соответствует допустимому виртуальному IP-адресу в кластере, и доступ к службе в кластере осуществляется через виртуальный IP-адрес. Существует три вида услуг:

  • ClusterIP: тип по умолчанию, который автоматически назначает виртуальный IP-адрес, доступ к которому возможен только внутри кластера.

  • NodePort: привяжите порт на каждой машине для Service на основе ClusterIP, чтобы к нему можно было получить доступ через<NodeIP>:NodePortдля доступа к сервису.

  • LoadBalancer: на основе NodePort создайте внешний балансировщик нагрузки с Cloud Provider и перенаправьте запросы на<NodeIP>:NodePort.

Балансировка нагрузки микросервисов в кластере Kubernetes реализована с помощью Kube-proxy. Kube-proxy — это балансировщик нагрузки внутри кластера Kubernetes. Это распределенный прокси-сервер, по одному на каждом узле Kubernetes; такая конструкция отражает его преимущества в масштабируемости, чем больше узлов требуется для доступа к сервису, тем больше Kube-прокси обеспечивает возможности балансировки нагрузки, количество высокопроизводительных также увеличивается доступность узлов. Напротив, мы обычно делаем обратный прокси на стороне сервера для балансировки нагрузки, и нам нужно дополнительно решить проблему балансировки нагрузки и высокой доступности обратного прокси.

Развертывание кластера

Кубернет в действииВ серии мы представили локальное построение Docker, ручное построение кластеров на основе Ubuntu и быстрое построение кластеров на основе Rancher. С помощью Rancher можно автоматически и визуально завершить установку кластеров Kubernetes, избавляясь от утомительного процесса установки вручную и позволяя быстро инвестировать в развитие бизнеса.

$ docker run -d --restart=unless-stopped -p 80:80 -p 443:443 rancher/rancher

Сначала установите сервер Rancher, управление, etcd и worker на главном узле. Выберите сетевой компонент как Flannel и выберите роль хоста в пользовательской команде запуска хоста и заполните внутреннюю сеть хоста и IP-адрес внешней сети.

Нам нужно скопировать скрипт на соответствующую машину для запуска, тогда Rancher автоматически создаст кластер Kubernetes и запустит веб-сервер на порту 80 по умолчанию. При добавлении узла Node вам нужно только найти кластер, который вы только что установили, в веб-интерфейсе Rancher, выбрать [Edit Cluster] и выбрать роль узла как Worker, чтобы добавить узел кластера Kubenretes.

Helm

Helm — это инструмент с открытым исходным кодом, инициированный Деисом, который помогает упростить развертывание приложений Kubernetes и управление ими. На практике в этой главе мы также будем использовать Helm для упрощения установки многих приложений.

В Linux вы можете установить Heml с помощью Snap:

$ sudo snap install helm --classic

# 通过键入如下命令,在 Kubernetes 群集上安装 Tiller
$ helm init --upgrade

По умолчанию Helm будет использовать образ «gcr.io/kubernetes-helm/tiller» для установки и настройки Tiller в кластере Kubernetes, а также использовать образ «gcr.io/kubernetes-helm/tiller» для установки и настройки Tiller.kubernetes-charts.storage.googleapis.com" в качестве адреса стабильного репозитория по умолчанию. Поскольку доменные имена, такие как "gcr.io" и "storage.googleapis.com", могут быть недоступны в Китае, служба облачных контейнеров Alibaba предоставляет для этой цели зеркальные сайты. Пожалуйста, выполните следующую команду, чтобы используйте образ Alibaba Cloud для настройки Helm:

$ helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.5.1 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

# 删除默认的源
$ helm repo remove stable

# 增加新的国内镜像源
$ helm repo add stable https://burdenbear.github.io/kube-charts-mirror/
$ helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

# 查看 Helm 源添加情况
$ helm repo list

Общие команды в Helm следующие:

# 查看在存储库中可用的所有 Helm Charts
$ helm search

# 更新 Charts 列表以获取最新版本
$ helm repo update

# 查看某个 Chart 的变量
$ helm inspect values stable/mysql

# 查看在群集上安装的 Charts 列表
$ helm list

# 删除某个 Charts 的部署
$ helm del --purge wordpress-test

# 为 Tiller 部署添加授权
$ kubectl create serviceaccount --namespace kube-system tiller
$ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
$ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'

kubectl

Поиск информации

Команда get используется для получения информации об одном или некоторых ресурсах кластера. Используйте --help, чтобы увидеть подробности. Справочная информация и примеры kubectl довольно подробные и понятные. Рекомендуется привыкнуть к использованию справочной информации. kubectl может отображать сведения обо всех ресурсах в кластере. ресурсы включают в себя узлы кластера, работающие модули, контроллеры репликации, службы и т. д.

$ kubectl get [(-o|--output=)json|yaml|wide|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=...] (TYPE [NAME | -l label] | TYPE/NAME ...) [flags] [flags]

эксплуатация и управление

Как и docker run, kubectl run может запускать образ Мы используем kubectl run для запуска образа sonarqube.

$ kubectl run sonarqube --image=sonarqube:5.6.5 --replicas=1 --port=9000

deployment "sonarqube" created

# 该命令为我们创建了一个 Deployment
$ kubectl get deployment
NAME        DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
sonarqube   1         1         1            1           5m

Мы также можем запустить изображение напрямую в интерактивном режиме:

$ kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il

K8s запускает образ в поде, чтобы упростить управление томами и общими сетевыми ресурсами.Используя поды для получения, вы можете четко видеть, что под создается:

$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
sonarqube-1880671902-s3fdq   1/1       Running   0          6m

$ 交互式运行 Pod 中的某个命令
$ kubectl exec -it sonarqube-1880671902-s3fdq -- /bin/bash

kubectl можно использовать для удаления созданных Deployments и Pods:

$ kubectl delete pods sonarqube-1880671902-s3fdq
$ kubectl delete deployment sonarqube

kubectl можно использовать для управления жизненным циклом приложения на основе файлов Yaml:

# 创建
$ kubectl create -f yamls/mysql.yaml

# 删除
$ kubectl delete -f yamls/mysql.yaml

# 同时创建多个
$ kubectl create -f yamls/

# 同时删除多个
$ kubectl delete -f yamls/

переключатель контекста

После установки кластера K8s вы можете загрузить файл конфигурации кластера в локальную конфигурацию kubectl:

mkdir $HOME/.kube
scp root@<master-public-ip>:/etc/kubernetes/kube.conf $HOME/.kube/config

Затем вы можете просмотреть текущий контекст

$ unset KUBECONFIG
$ kubectl config current-context # 查看当前载入的上下文
$ kubectl config get-contexts # 浏览可用的上下文
$ kubectl config use-context context-name # 切换到指定上下文

Конфигурация службы

Реальное боевое/типичное приложение KubernetesВ этом разделе мы представили настройку и развертывание многих распространенных промежуточных программ. Здесь мы возьмем простой HTTP-сервер в качестве примера, чтобы представить общий процесс настройки службы.

Deployment & Service

существуетK8s BoilerplatesМы определяем простое развертывание и службу Nginx, которые используются для построения кластера и предоставления внешней службы соответственно:

# nginx-deployment-service.yaml
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: nginx
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nginx
  replicas: 3 # tells deployment to run 1 pods matching the template
  template: # create pods using pod definition in this template
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  externalTrafficPolicy: Local
  ports:
    - name: http
      port: 80
  selector:
    app: nginx
  type: NodePort
$ kubectl create -f https://raw.githubusercontent.com/wx-chevalier/Backend-Boilerplates/master/K8s/Base/nginx-deployment-service.yaml

$ kubectl get pod

NAME                                             READY   STATUS    RESTARTS   AGE
nginx-56db997f77-2q6qz                           1/1     Running   0          3m21s
nginx-56db997f77-fv2zs                           1/1     Running   0          3m21s
nginx-56db997f77-wx2q5                           1/1     Running   0          3m21s

$ kubectl get deployment

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
nginx                           3/3     3            3           3m36s

$ kubectl get svc

NAME                            TYPE           CLUSTER-IP      EXTERNAL-IP                              PORT(S)                      AGE
kubernetes                      ClusterIP      10.43.0.1       <none>                                   443/TCP                      21h
nginx                           NodePort       10.43.8.50      <none>                                   80:32356/TCP                 4m5s

Ingress

Ingress — это ресурс Kubernetes и способ предоставления сервисов в кластере Kubernetes внешнему миру. ngress — это просто общий термин, состоящий из Ingress и Ingress Controller. Ingress используется для абстрагирования правил, которые необходимо настроить вручную, в объект Ingress, который создается и управляется с использованием файла формата YAML. Ingress Controller используется для динамического восприятия изменений правил Ingress в кластере путем взаимодействия с Kubernetes API.

В настоящее время доступно множество типов контроллеров Ingress, таких как: Nginx, HAProxy, Traefik и т. д. Nginx Ingress использует ConfigMap для управления конфигурацией Nginx.

Helm установить Ingress

$ helm install --name nginx-ingress --set "rbac.create=true,controller.service.externalIPs[0]=172.19.157.1,controller.service.externalIPs[1]=172.19.157.2,controller.service.$
xternalIPs[2]=172.19.157.3" stable/nginx-ingress

NAME:   nginx-ingress
LAST DEPLOYED: Tue Aug 20 14:50:13 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                      DATA  AGE
nginx-ingress-controller  1     0s

==> v1/Pod(related)
NAME                                            READY  STATUS             RESTARTS  AGE
nginx-ingress-controller-5f874f7bf4-nvsvv       0/1    ContainerCreating  0         0s
nginx-ingress-default-backend-6f598d9c4c-vj4v8  0/1    ContainerCreating  0         0s

==> v1/Service
NAME                           TYPE          CLUSTER-IP    EXTERNAL-IP                             PORT(S)                     AGE
nginx-ingress-controller       LoadBalancer  10.43.115.59  172.19.157.1,172.19.157.2,172.19.157.3  80:32122/TCP,443:32312/TCP  0s
nginx-ingress-default-backend  ClusterIP     10.43.8.65    <none>                                  80/TCP                      0s

==> v1/ServiceAccount
NAME           SECRETS  AGE
nginx-ingress  1        0s

==> v1beta1/ClusterRole
NAME           AGE
nginx-ingress  0s

==> v1beta1/ClusterRoleBinding
NAME           AGE
nginx-ingress  0s

==> v1beta1/Deployment
NAME                           READY  UP-TO-DATE  AVAILABLE  AGE
nginx-ingress-controller       0/1    1           0          0s
nginx-ingress-default-backend  0/1    1           0          0s

==> v1beta1/PodDisruptionBudget
NAME                           MIN AVAILABLE  MAX UNAVAILABLE  ALLOWED DISRUPTIONS  AGE
nginx-ingress-controller       1              N/A              0                    0s
nginx-ingress-default-backend  1              N/A              0                    0s

После завершения развертывания мы видим, что в сервис Kubernetes добавлены nginx-ingress-controller и nginx-ingress-default-backend. nginx-ingress-controller — это Ingress Controller, который в основном используется в качестве семиуровневого балансировщика нагрузки для обеспечения таких функций, как HTTP-маршрутизация, фиксированные сеансы, завершение SSL, сквозная передача SSL, балансировка нагрузки TCP и UDP. nginx-ingress-default-backend — это бэкэнд по умолчанию.Когда запрос извне кластера поступает в кластер через Ingress, если сервис не может быть загружен на соответствующий бэкенд, неизвестный запрос будет загружен в бэкэнд по умолчанию на бэкенде. .

$ kubectl get svc
NAME                            TYPE           CLUSTER-IP      EXTERNAL-IP                              PORT(S)                      AGE
kubernetes                      ClusterIP      10.43.0.1       <none>                                   443/TCP                      20h
nginx-ingress-controller        LoadBalancer   10.43.115.59    172.19.157.1,172.19.157.2,172.19.157.3   80:32122/TCP,443:32312/TCP   77m
nginx-ingress-default-backend   ClusterIP      10.43.8.65      <none>                                   80/TCP                       77m

$ kubectl --namespace default get services -o wide -w nginx-ingress-controller

NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP                              PORT(S)                      AGE   SELECTOR
nginx-ingress-controller   LoadBalancer   10.43.115.59   172.19.157.1,172.19.157.2,172.19.157.3   80:32122/TCP,443:32312/TCP   77m   app=nginx-ingress,component=controller,release=nginx-ingress

Поскольку мы используем externalIP для предоставления услуг, nginx-ingress-controller будет предоставлять порт 80/443 на трех хостах узла. Мы можем получить к нему доступ на любом узле, потому что мы не создали ресурс Ingress в кластере Kubernetes, поэтому запросы напрямую к ExternalIP загружаются на nginx-ingress-default-backend. nginx-ingress-default-backend по умолчанию предоставляет два URL-адреса для доступа, где /healthz возвращает 200 для проверки работоспособности, а / возвращает ошибку 404.

$ curl 127.0.0.1/
# default backend - 404

$ curl 127.0.0.1/healthz/
# 返回的是 200

Позже, если нам понадобится создать собственную конфигурацию Ingress, мы можем обратиться к следующим методам:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  name: example
  namespace: foo
spec:
  rules:
    - host: www.example.com
      http:
        paths:
          - backend:
              serviceName: exampleService
              servicePort: 80
            path: /
  # This section is only required if TLS is to be enabled for the Ingress
  tls:
    - hosts:
        - www.example.com
      secretName: example-tls

Если вы хотите использовать TLS, вам нужно создать секрет, содержащий сертификат и ключ:

apiVersion: v1
kind: Secret
metadata:
  name: example-tls
  namespace: foo
data:
  tls.crt: <base64 encoded cert>
  tls.key: <base64 encoded key>
type: kubernetes.io/tls

WordPress

После установки Helm давайте проверим развертывание приложения WordPress:

$ helm install --name wordpress-test --set "ingress.enabled=true,persistence.enabled=false,mariadb.persistence.enabled=false" stable/wordpress

NAME:  wordpress-test
...

Здесь мы используем балансировку нагрузки Ingress для доступа к сервису, доступ к которому можно получить следующими способами:

$ kubectl get ingress

NAME                             HOSTS             ADDRESS                                  PORTS   AGE
wordpress.local-wordpress-test   wordpress.local   172.19.157.1,172.19.157.2,172.19.157.3   80      59m

$ curl -I http://wordpress.local -x 127.0.0.1:80

HTTP/1.1 200 OK
Server: nginx/1.15.6
Date: Tue, 20 Aug 2019 07:55:21 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/7.0.27
Link: <http://wordpress.local/wp-json/>; rel="https://api.w.org/"

Вы также можете получить пользователя-администратора и пароль сайта WordPress, используя следующую команду в соответствии с диаграммами:

echo Username: user
echo Password: $(kubectl get secret --namespace default wordpress-test-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)

==> v1beta1/Role
NAME           AGE
nginx-ingress  0s

==> v1beta1/RoleBinding
NAME           AGE
nginx-ingress  0s

дальнейшее чтение

Медвежья техническая дорога на север ☯Это навигация и индексация хранилища знаний, накопленных автором в разных областях, чтобы читатели могли быстро найти нужный им контент. Впереди долгий путь, и я ищу вдоль и поперек.Я также надеюсь, что смогу оказать некоторую помощь всем ученикам, которые наткнулись на следы автора, и смогут успешно достичь одного берега за другим в огромной галактике.

Вы можете прочитать серию статей автора в Gitbook с помощью следующей навигации, охватывающей ввод технических данных, язык и теорию программирования, веб-интерфейс и большой интерфейс, разработку и инфраструктуру на стороне сервера, облачные вычисления и большие данные, науку о данных и искусственный интеллект. , Дизайн продукта и другие области:

Кроме того, вы можете перейти кxCompassИнтерактивный поиск и найдите нужную статью/ссылку/книгу/курс; илиМАТРИЦА Матрица артикулов и индексов кодовСм. статьи и исходный код проекта для получения более подробной информации о навигации по каталогам в файлах . Наконец, вы также можете следить за публичной учетной записью WeChat: "Медвежья технологическая дорога' для последней информации.