当前位置:网站首页>Actual combat: gateway api-2022.2.13

Actual combat: gateway api-2022.2.13

2022-07-01 05:04:00 One thought for a lifetime

image-20220125075905267

Catalog

Experimental environment

 Experimental environment :
1、win10,vmwrokstation The virtual machine ;
2、k8s colony :3 platform centos7.6 1810 The virtual machine ,1 individual master node ,2 individual node node 
   k8s version:v1.22.2
   containerd://1.5.5

Experimental software

link :https://pan.baidu.com/s/1GxPnKx_8oNbqVfGIC0X1-w?pwd=exqu
Extraction code :exqu

2022.2.13-34.gatewayapi.tar.gz

image-20220213153653482

1、Gateway API

Gateway API( Formerly called Service API) By SIG-NETWORK Community ( Internet interest groups ) Managed open source projects , Project address :https://gateway-api.sigs.k8s.io/. The main reason is Ingress The resource object can not well meet the network requirements , A lot of scenarios Ingress Controllers need to be defined annotations perhaps crd To extend the function , This is very detrimental to the use of standards and support , The new Gateway API It aims to enhance the service network through an extensible role-oriented interface .

Gateway API yes Kubernetes One of them API Resource collection , Include GatewayClass、Gateway、HTTPRoute、TCPRoute、Service etc. , Together, these resources build models for various network use cases .

To put it bluntly : This Gateway api It is a set of customization CRD resources ;

Cloud service providers GatewayClass, For example, Alibaba cloud , Gu Ge Yun ,( Intranet GatewyClass And the Internet GateWayClass);

Gateway API

Gateway API Is better than the current Ingress There are many better designs for resource objects :

  • Role oriented - Gateway By various API Resource composition , These resources depend on usage and configuration Kubernetes Modeling the role of the service network .
  • generality - and Ingress It is also a general specification with many implementations ,Gateway API Is a specification designed to be supported by many implementations .
  • More expressive - Gateway API Resource support is based on Header Head matching 、 Flow weight and other core functions , These functions are Ingress Can only be achieved through custom annotations .
  • Extensibility - Gateway API Allow custom resources to link to API The layers of , This allows you to API The appropriate position of the structure is more finely customized .

There are other features that deserve attention :

  • GatewayClasses - GatewayClasses Formalize the types of load balancing implementations , These classes make it easy for the user to understand that through Kubernetes What capabilities can resources acquire .
  • Shared gateway and cross namespace support - They allow sharing of load balancers and VIP, Allow independent routing resources to be bound to the same gateway , This allows the team to safely share ( Including cross namespace ) infrastructure , Without direct coordination .
  • Normalize routing and backend - Gateway API Support typed routing resources and different types of backend , This makes API It can flexibly support various protocols ( Such as HTTP and gRPC) And various back-end services ( Such as Kubernetes Service、 bucket Or functions ).

2、 Role oriented design

Whether it's the road 、 Electric power 、 Data center or Kubernetes colony , Infrastructure is built for sharing , However, shared infrastructure presents a common challenge , That is how to provide flexibility for infrastructure users while being owned ( infrastructure ) control .

Gateway API Through to Kubernetes The service network is designed in role-oriented way to achieve this goal , Balance flexibility and centralized control . It allows shared network infrastructure ( Hardware load balancer 、 Cloud network 、 Cluster hosted agents, etc ) Used by many different teams , All these are subject to various policies and constraints set by the cluster operation and maintenance . The following example shows how it works in practice .

gateway api demo

A cluster O & M personnel created a cluster based on GatewayClass Of Gateway resources , This Gateway Deployed or configured the basic network resources it represents , Cluster O & M and specific teams must communicate what can be attached to this Gateway To expose their applications . Centralized strategy , Such as TLS, Cluster operation and maintenance can be performed in Gateway Enforce on , meanwhile ,Store and Site Applications run in their own namespace , But attach their routes to the same shared gateway , Allow them to control their routing logic independently .

This separation of concerns design allows different teams to manage their own traffic , At the same time, the centralized strategy and control are left to the cluster operation and maintenance .

3、 Concept

Throughout Gateway API Involved in the 3 A character : Infrastructure providers 、 Cluster Administrator 、 Application developers , In some cases, it may involve Application Administrator Wait for the character .Gateway API It defines 3 Main resource models :GatewayClassGatewayRoute.

1.GatewayClass

GatewayClass Defines a set of gateways that share the same configuration and actions . Every GatewayClass Handled by a controller , It is a cluster wide resource , There must be at least one GatewayClass Defined .

This is related to Ingress Of IngressClass similar , stay Ingress v1beta1 In the version , And GatewayClass similarly ingress-class annotation , And in the Ingress V1 In the version , The closest thing is IngressClass Resource objects .

2.Gateway

gatewy You can think of it as a real Internet portal .

Gateway The gateway describes how to transform traffic into services within the cluster , in other words , It defines a request , Require that traffic never be known Kubernetes To services within the cluster . for example , from Cloud load balancer Agents within the cluster or external hardware load balancers Send to Kubernetes Service traffic .

It defines the request for a specific load balancer configuration , This configuration implements GatewayClass Configuration and code of conduct , This resource can be created directly by the administrator , It can also be handled by GatewayClass Controller creation for .

Gateway Can be attached to one or more route references , The role of these route references is to direct a subset of traffic to a specific service .

3.Route resources

Routing resources define specific rules , Used to map requests from the gateway to Kubernetes service .

from v1alpha2 Version start ,API There are four kinds of Route Routing resource type , For other undefined protocols , Encourage custom routing types for specific implementations , Of course, new routing types may be added in the future .

  • HTTPRoute

HTTPRoute Is used for HTTP or HTTPS Connect , Applies to what we want to check HTTP Request and use HTTP Scenarios that request routing or modification , For example, use HTTP Headers Header for routing , Or modify them during the request process .

  • TLSRoute

TLSRoute be used for TLS Connect , adopt SNI Distinguish , It is suitable for those who wish to use SNI As the main routing method , And right HTTP And other properties of higher-level agreements , The connected byte stream is proxied to the back end without any checking .

  • TCPRoute and UDPRoute

TCPRoute( and UDPRoute) Designed to map one or more ports to a single back end . under these circumstances , There is no discriminator that can be used to select different back ends of the same port , So each TCPRoute You need a different port on the listener . You can use TLS, under these circumstances , Unencrypted byte streams are passed to the back end , Of course, you can not use TLS, In this way, the encrypted byte stream will be passed to the back end .

4. Combine

GatewayClassGatewayxRoute and Service The combination of defines an implementable load balancer . The following figure illustrates the relationship between different resources :

 synthetic relation

A typical client of a gateway implemented using a reverse proxy / gateway API The request process is as follows :

    1. Client to http://foo.example.com Request
    1. DNS Resolve the domain name to Gateway default gateway
    1. The reverse proxy receives requests on the listener , And use Host Header To match HTTPRoute
    1. ( Optional ) Reverse proxy can be based on HTTPRoute Matching rules for routing
    1. ( Optional ) Reverse proxy can be based on HTTPRoute Filter rule modification request for , That is, add or delete headers
    1. Last , Reverse proxy according to HTTPRoute Of forwardTo The rules , Forward the request to one or more objects in the cluster , Namely service .

4、 Realization

There are already many Gateway API The controller implementation scheme of , such as Contour、Google Kubernetes Engine、Istio、Traefik wait . So let's start with Traefik As an example . But here's the thing Traefik It's based on v1alpha1 normally-implemented , It may be slightly different from some of the concepts mentioned above .

To be in Traefik Use in Gateway API, First, we need to install it manually Gateway API Of CRDs, Use the following command to install , This installation will include GatewayClass、Gateway、HTTPRoute、TCPRoute etc. CRDs:

* kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.3.0" \
| kubectl apply -f -

What is the usage of this ? Can I execute it directly ?

Here we have used github Website resources , I wonder if I can download it directly ??;

Executed on the virtual machine 2 This is the mistake every time :

This is how I finally created it :( Directly in github Download the source code , Then use the directory file )

https://github.com/kubernetes-sigs/gateway-api/releases/tag/v0.3.0

image-20220213130243366

#gateway-api-0.3.0/config The file environment is as follows 
[[email protected] ~]#ls
--  01-whoami.yaml  gateway-api-0.3.0  gateway-api-0.3.0.zip  old-yamls  traefik
[[email protected] ~]#cd gateway-api-0.3.0/
[[email protected] gateway-api-0.3.0]#ls
apis             cmd                 CONTRIBUTING.md  docs      go.sum   Makefile      OWNERS          README.md         SECURITY_CONTACTS
CHANGELOG.md     code-of-conduct.md  deploy           examples  hack     mkdocs.yml    OWNERS_ALIASES  RELEASE.md        site-src
cloudbuild.yaml  config              Dockerfile       go.mod    LICENSE  netlify.toml  pkg             requirements.txt  tools

# Execute the command in this directory 
[[email protected] config]#ls
crd
[[email protected] config]#pwd
/root/gateway-api-0.3.0/config
[[email protected] config]#ls
crd
[[email protected] config]#ls crd/
bases  kustomization.yaml
[[email protected] config]#ls crd/bases/
networking.x-k8s.io_backendpolicies.yaml  networking.x-k8s.io_httproutes.yaml  networking.x-k8s.io_udproutes.yaml
networking.x-k8s.io_gatewayclasses.yaml   networking.x-k8s.io_tcproutes.yaml
networking.x-k8s.io_gateways.yaml         networking.x-k8s.io_tlsroutes.yaml

# Start execution 
[[email protected] config]#kubectl kustomize crd \
> | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/backendpolicies.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/gatewayclasses.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/gateways.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/httproutes.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/tcproutes.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/tlsroutes.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/udproutes.networking.x-k8s.io created
[[email protected] config]#

Then we need to be in Traefik In the open kubernetesgateway This Provider, Also based on the previous Traefik In chapter Helm Chart Package definition , Set up experimental.kubernetesGateway.enabled=true, complete Values The file is shown below :( complete yaml See... For the documents Experimental software )

# ci/deployment-prod.yaml

# Enable experimental features
experimental:
  kubernetesGateway:  #  Turn on  gateway api  Support 
    enabled: true

providers:
  kubernetesCRD:
    enabled: true
    allowCrossNamespace: true  #  Whether to allow cross namespace 
    allowExternalNameServices: true  #  Is it allowed to use  ExternalName  Service for 

  kubernetesIngress:
    enabled: true
    allowExternalNameServices: true

# ......
#  Others ignored 

Then use the following command to update Traefik that will do :

[[email protected] ~]#helm upgrade --install traefik ./traefik -f ./traefik/ci/deployment-prod.yaml --namespace kube-system
Release "traefik" has been upgraded. Happy Helming!
NAME: traefik
LAST DEPLOYED: Sun Feb 13 12:48:44 2022
NAMESPACE: kube-system
STATUS: deployed
REVISION: 7
TEST SUITE: None

After the update, you can go to Traefik Of Dashboard Check whether it is enabled KubernetesGateway This Provider:

http://traefik.qikqiak.com/

image-20220213124959318

Normally, after successful activation Traefik A default... Will also be created GatewayClass Resource objects and Gateway example :

[[email protected] ~]#kubectl get gatewayclass
NAME      CONTROLLER                      AGE
traefik   traefik.io/gateway-controller   4m13s

[[email protected] ~]#kubectl get gatewayclass traefik -o yaml
apiVersion: networking.x-k8s.io/v1alpha1
kind: GatewayClass
metadata:
  name: traefik
spec:
  controller: traefik.io/gateway-controller
......

[[email protected] ~]#kubectl get gateway -n kube-system
NAME              CLASS     AGE
traefik-gateway   traefik   5m55s

[[email protected] ~]#kubectl get gateway -n kube-system traefik-gateway -o yaml
apiVersion: networking.x-k8s.io/v1alpha1
kind: Gateway
metadata:
  name: traefik-gateway
  namespace: kube-system
spec:
  gatewayClassName: traefik
  listeners:
  - port: 8000
    protocol: HTTP
    routes:
      group: networking.x-k8s.io
      kind: HTTPRoute
      namespaces:
        from: Same
      selector:
        matchLabels:
          app: traefik
......

You can see the default created Gateway The instance refers to traefik This GatewayClass, among listeners Section defines the listener entry associated with the gateway , The listener defines that the logical endpoint is bound to the gateway address , At least one listener needs to be specified . Below HTTPRoute The routing rules are defined ,namespaces Indicates in which namespaces the gateway should be routed , By default , This is restricted to the namespace of the gateway ,Selector Then specify a set of routing labels , If this is defined Selector, Only the objects associated with the gateway are routed , An empty selector matches all objects , Here we will match with app: traefik The object of the tag .

To be able to handle routing rules in other namespaces , We can put the namespaces.from It is amended as follows All, But the test did not take effect ?( what ??)

Now let's install a simple whoami Service to test , Directly use the following resource list to deploy the corresponding service :

[[email protected] ~]#vim 01-whoami.yaml

# 01-whoami.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
  name: whoami
  namespace: kube-system
spec:
  replicas: 2
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: containous/whoami
          ports:
            - containerPort: 80
              name: http
---
apiVersion: v1
kind: Service
metadata:
  name: whoami
  namespace: kube-system
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: http
  selector:
    app: whoami

Deploy and view directly :

[[email protected] ~]#kubectl apply -f 01-whoami.yaml 
deployment.apps/whoami created
service/whoami created
[[email protected] ~]#kubectl get po -l app=whoami -nkube-system
NAME                      READY   STATUS    RESTARTS   AGE
whoami-6b465b89d6-8nz72   1/1     Running   0          95s
whoami-6b465b89d6-nq442   1/1     Running   0          95s

After the deployment of the test service , We can use Gateway API To configure traffic .

Actual demonstration 1: Deploy a simple Host host ( Test success )

In the previous way, we will create a Ingress or IngressRoute Resource objects , Here we will deploy a simple HTTPRoute object .

[[email protected] ~]#vim 02-whoami-httproute.yaml

# 02-whoami-httproute.yaml
apiVersion: networking.x-k8s.io/v1alpha1
kind: HTTPRoute
metadata:
  name: http-app-1
  namespace: kube-system
  labels:
    app: traefik
spec:
  hostnames:
    - "whoami"
  rules:
    - matches:
        - path:
            type: Exact
            value: /
      forwardTo:
        - serviceName: whoami
          port: 80
          weight: 1

above HTTPRoute Resources will be captured to whoami Request from hostname , And forward it to the whoami service , If you request this hostname now , You will see the typical whoami Output :

[[email protected] ~]#kubectl apply -f 02-whoami-httproute.yaml
[[email protected] ~]#kubectl get httproute -n kube-system
NAME         HOSTNAMES    AGE
http-app-1   ["whoami"]   25s

#  Use  whoami  This hostname is used for access test 
[[email protected] ~]#curl -H "Host: whoami" http://172.29.9.52 ( This is node1 ip)
Hostname: whoami-6b465b89d6-nq442
IP: 127.0.0.1
IP: ::1
IP: 10.244.1.102
IP: fe80::8032:a1ff:fe72:aee6
RemoteAddr: 10.244.1.101:47136
GET / HTTP/1.1
Host: whoami
User-Agent: curl/7.29.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 172.29.9.51
X-Forwarded-Host: whoami
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-5659947558-m9kmq
X-Real-Ip: 172.29.9.51

️ In addition, you need to pay attention to the above HTTPRoute Object needs to be defined app:traefik label , Otherwise created Gateway Instances cannot be associated with .

End of experiment , perfect .

Actual demonstration 2: With a path Host host ( Test success )

The above example can easily restrict the traffic to only route on a given sub path .

[[email protected] ~]#vim 03-whoami-httproute-paths.yaml

# 03-whoami-httproute-paths.yaml
apiVersion: networking.x-k8s.io/v1alpha1
kind: HTTPRoute
metadata:
  name: http-app-1
  namespace: kube-system
  labels:
    app: traefik
spec:
  hostnames:
    - whoami
  rules:
    - forwardTo:
        - port: 80
          serviceName: whoami
          weight: 1
      matches:
        - path:
            type: Exact  #  matching  /foo  The path of 
            value: /foo

Create the modified HTTPRoute, You will find that the previous request now returns 404 error , The request /foo The path suffix returns success .

# Create resources 
[[email protected] ~]#kubectl apply -f 03-whoami-httproute-paths.yaml 
httproute.networking.x-k8s.io/http-app-1 configured

# test 
[[email protected] ~]#curl -H "Host: whoami" http://172.29.9.52
404 page not found

[[email protected] ~]#curl -H "Host: whoami" http://172.29.9.52/foo
Hostname: whoami-6b465b89d6-nq442
IP: 127.0.0.1
IP: ::1
IP: 10.244.1.102
IP: fe80::8032:a1ff:fe72:aee6
RemoteAddr: 10.244.1.101:47432
GET /foo HTTP/1.1
Host: whoami
User-Agent: curl/7.29.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 172.29.9.51
X-Forwarded-Host: whoami
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-5659947558-m9kmq
X-Real-Ip: 172.29.9.51

More information about which parts of the request can be matched can be found in the official Gateway APIs file (https://gateway-api.sigs.k8s.io/v1alpha1/api-types/httproute/#rules) Find .

End of experiment , perfect .

Actual demonstration 3: Release of canary ( Test success )

Gateway APIs Another feature that the specification can support is Canary publishing , Suppose you want to be on an endpoint Running two different services ( Or two versions of the same service ), And route a portion of the request to each endpoint , You can modify your HTTPRoute To achieve .

First , We need to run the second service , Here we quickly generate a Nginx To test .

[[email protected] ~]#vim 03-nginx.yaml

# 03-nginx.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nginx
  namespace: kube-system
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
              name: http
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: kube-system
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: http
  selector:
    app: nginx

Then we modify the previous HTTPRoute Resource objects , One of them weight Options , Two services can be assigned different weights , As shown below :

[[email protected] ~]#vim 04-whoami-nginx-canary.yaml

# 04-whoami-nginx-canary.yaml
apiVersion: networking.x-k8s.io/v1alpha1
kind: HTTPRoute
metadata:
  labels:
    app: traefik
  name: http-app-1
  namespace: kube-system
spec:
  hostnames:
    - whoami
  rules:
    - forwardTo:
        - port: 80
          serviceName: whoami
          weight: 3  # 3/4  Request to whoami
        - port: 80
          serviceName: nginx
          weight: 1  # 1/4  Request to whoami

Deploy the above 2 individual yaml:

[[email protected] ~]#kubectl apply -f 03-nginx.yaml 
deployment.apps/nginx created
service/nginx created
[[email protected] ~]#kubectl apply -f 04-whoami-nginx-canary.yaml 
httproute.networking.x-k8s.io/http-app-1 configured

Now we can visit again whoami service , Normally we can see about 25% Your request will see Nginx Response , instead of whoami Response .

[[email protected] ~]#curl -H "Host: whoami" http://172.29.9.52 # Execute this command 4 Time , You can see that there is 3 Times by whoami service-provided ,1 Times by nginx service-provided .

End of experiment , perfect

Here we use Traefik To test Kubernetes Gateway APIs Use .

QA

Yang Zong's personal feeling : This gateway Will slowly replace ingress Of

at present ,Traefik Yes Gateway APIs The implementation is based on v1alpha1 Version of the specification , The latest specification is v1alpha2, So there may be some differences with the latest specifications .

official Gateway APIs file (https://gateway-api.sigs.k8s.io/v1alpha1/api-types/httproute/#rules);

image-20220213141954506

image-20220213141726731

QA: Do you support rewrite , And regular match

similar nginx-ingress Of nginx.ingress.kubernetes.io/rewrite-target: /$2?

There should be , Probably through this Filters To achieve the , You can find it by yourself .

image-20220213142406024

gateway api and trafkic perhaps kong What's the difference ?

gateway api Is a definition specification ;

Just say traefik,kong(ingress controller ),gke,aks We can implement this set of specifications ;

therefore , You can think gateway api yes ingress Enhanced version of ;

Isn't it the same as before ,ingress It's just a norm , What you really want to use , Or we need to use the controller behind us to realize (gateway api It is just a definition specification );

In fact, its thinking is similar to traefuik similar ;

Do you think it is original , No, it isn't , Now it's all through crd In the form of ;

So , current gateway api ,sig It just gives you a gitway api Of crds nothing more , I gave it to you directly .

You have to say that it is native , You can think of it as native , It is, after all k8s Official networking sig Defined , In fact, it is similar to the original , In fact, the official put forward a set ;

and ingress ingressroute Basically consistent , It's just that their design starting point is different ;ingreeroute There may be no role orientation , We didn't mention it to our entire operation and maintenance system . It may not include one of your gateways class, No gateway included , All are traefik Automatically help you achieve .

gateway api Can this thing be produced now ?

gke, Alibaba cloud should be available for production , Others don't seem to , It is recommended not to produce directly .

gateway api 666

Actually gateway api The proposed , To unify the gateway specification .

So this one came up , It's also good . otherwise , Every time you make an option , We have to learn a set of .

Such as now traefike(ingressroute),apisix(crds), Are not standardized , They are all realized according to their own ideas .

Now, after unification , We just need to learn gateway api This specification is good , How do you implement your specific controller , For our users , Actually, it doesn't have much effect , All in the same way .

So ,k8s Officials must have realized , Because you originally ingressroute, It must have a lot of functions slowly , There is no way to describe .ingress It's weak , If you use ingress Words , Many of you have passed annotations To achieve the .annotations This way, , In fact, it is not standardized .1. Can't do a good test ( Of course, it can be realized by itself ).2. No specification . But you don't have to annotations Words , that ingress There is no way to realize your complete definition url-rewrite and Force a jump https. So he needs a new set of specifications to implement , That's what we have here gateway api.

Now you can always pay attention to ,traefike It is already being implemented ;apisix It seems to be realizing , But it seems that it hasn't been released yet ;

https://gateway-api.sigs.k8s.io/implementations/

work in progress( Partially Prepared Products ), It seems that only gke It's a public preview state .

image-20220213145151177

About me

My blog theme : I hope everyone can experiment with my blog , Do the experiment first , Then combine with the theoretical knowledge to understand the technical points in a deeper level , Only in this way can you have fun and motivation . also , My blog content steps are very complete , Also share the source code and the software used in the experiment , I hope we can make progress together !

If you have any questions during the actual operation , You can contact me at any time to help you solve the problem for free :

  1. Personal wechat QR code :x2675263825 ( Willing to part with or use ), qq:2675263825.

    image-20211002091450217

  2. Personal blog address :www.onlyonexl.cn

    image-20211002092057988

  3. WeChat official account : Cloud native architect actual combat

    image-20211002141739664

  4. personal csdn

    https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

    image-20211002092344616

  5. Individuals have opened up dry goods

    01 actual combat : Create a king cloud note :typora+ Nut cloud + Alibaba cloud oss

    https://www.jianguoyun.com/p/DXS6qiIQvPWVCRiS0qoE
    02 actual combat : Customize the most beautiful in the universe typora Theme skin

    https://www.jianguoyun.com/p/DeUK9u0QvPWVCRib0qoE
    03 Get along well with vscode

    https://www.jianguoyun.com/p/DZe8gmsQvPWVCRid0qoE
    04 Chen Guo's happiness philosophy class .md

    https://pan.baidu.com/s/1-slSPCX4wRXw0FvNSolm8w?pwd=i3v2

  6. x

Last

​ Okay , About Gateway API That's the end of the experiment , Thank you for reading , Finally, stick my goddess's photo, I wish you all a happy life , Every day is meaningful , See you next time !

image-20220213153955299

原网站

版权声明
本文为[One thought for a lifetime]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202160232048844.html