Kubernetes K8S之Service服务详解与示例

Service服务类型
Kubernetes 中Service有以下4中类型:

ClusterIP:默认类型,自动分配一个仅Cluster内部可以访问的虚拟IP
NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。以ClusterIP为基础,NodePort 服务会路由到 ClusterIP 服务。通过请求 :,可以从集群的外部访问一个集群内部的 NodePort 服务。
LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。没有任何类型代理被创建。
需要注意的是:Service 能够将一个接收 port 映射到任意的 targetPort。默认情况下,targetPort 将被设置为与 port 字段相同的值。

Service域名格式: ( s e r v i c e n a m e ) . (service name). (servicename).(namespace).svc.cluster.local,其中 cluster.local 为指定的集群的域名

Deployment的yaml信息
yaml文件

复制代码
1 [root@k8s-master service]# pwd
2 /root/k8s_practice/service
3 [root@k8s-master service]# cat myapp-deploy.yaml
4 apiVersion: apps/v1
5 kind: Deployment
6 metadata:
7 name: myapp-deploy
8 namespace: default
9 spec:
10 replicas: 3
11 selector:
12 matchLabels:
13 app: myapp
14 release: v1
15 template:
16 metadata:
17 labels:
18 app: myapp
19 release: v1
20 env: test
21 spec:
22 containers:
23 - name: myapp
24 image: registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
25 imagePullPolicy: IfNotPresent
26 ports:
27 - name: http
28 containerPort: 80
复制代码

启动Deployment并查看状态

复制代码
1 [root@k8s-master service]# kubectl apply -f myapp-deploy.yaml
2 deployment.apps/myapp-deploy created
3 [root@k8s-master service]#
4 [root@k8s-master service]# kubectl get deploy -o wide
5 NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
6 myapp-deploy 3/3 3 3 31h myapp registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1 app=myapp,release=v1
7 [root@k8s-master service]#
8 [root@k8s-master service]# kubectl get rs -o wide
9 NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
10 myapp-deploy-5695bb5658 3 3 3 31h myapp registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1 app=myapp,pod-template-hash=5695bb5658,release=v1
11 [root@k8s-master service]#
12 [root@k8s-master service]# kubectl get pod -o wide --show-labels
13 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
14 myapp-deploy-5695bb5658-2866m 1/1 Running 2 31h 10.244.2.116 k8s-node02 app=myapp,env=test,pod-template-hash=5695bb5658,release=v1
15 myapp-deploy-5695bb5658-dcfw7 1/1 Running 2 31h 10.244.4.105 k8s-node01 app=myapp,env=test,pod-template-hash=5695bb5658,release=v1
16 myapp-deploy-5695bb5658-n2b5w 1/1 Running 2 31h 10.244.2.115 k8s-node02 app=myapp,env=test,pod-template-hash=5695bb5658,release=v1
复制代码

curl访问

复制代码
1 [root@k8s-master service]# curl 10.244.2.116
2 Hello MyApp | Version: v1 | Pod Name
3 [root@k8s-master service]#
4 [root@k8s-master service]# curl 10.244.2.116/hostname.html
5 myapp-deploy-5695bb5658-2866m
6 [root@k8s-master service]#
7 [root@k8s-master service]# curl 10.244.4.105
8 Hello MyApp | Version: v1 | Pod Name
9 [root@k8s-master service]#
10 [root@k8s-master service]# curl 10.244.4.105/hostname.html
11 myapp-deploy-5695bb5658-dcfw7
12 [root@k8s-master service]#
13 [root@k8s-master service]# curl 10.244.2.115
14 Hello MyApp | Version: v1 | Pod Name
15 [root@k8s-master service]#
16 [root@k8s-master service]# curl 10.244.2.115/hostname.html
17 myapp-deploy-5695bb5658-n2b5w
复制代码

ClusterIP类型示例
yaml文件

复制代码
1 [root@k8s-master service]# pwd
2 /root/k8s_practice/service
3 [root@k8s-master service]# cat myapp-svc-ClusterIP.yaml
4 apiVersion: v1
5 kind: Service
6 metadata:
7 name: myapp-clusterip
8 namespace: default
9 spec:
10 type: ClusterIP # 可以不写,为默认类型
11 selector:
12 app: myapp
13 release: v1
14 ports:
15 - name: http
16 port: 80
17 targetPort: 80
复制代码

启动Service并查看状态

复制代码
1 [root@k8s-master service]# kubectl apply -f myapp-svc-ClusterIP.yaml
2 service/myapp-clusterip created
3 [root@k8s-master service]#
4 [root@k8s-master service]# kubectl get svc -o wide
5 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
6 kubernetes ClusterIP 10.96.0.1 443/TCP 22d
7 myapp-clusterip ClusterIP 10.106.66.120 80/TCP 15s app=myapp,release=v1
复制代码

查看pod信息

1 [root@k8s-master service]# kubectl get pod -o wide --show-labels
2 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
3 myapp-deploy-5695bb5658-2866m 1/1 Running 2 31h 10.244.2.116 k8s-node02 app=myapp,env=test,pod-template-hash=5695bb5658,release=v1
4 myapp-deploy-5695bb5658-dcfw7 1/1 Running 2 31h 10.244.4.105 k8s-node01 app=myapp,env=test,pod-template-hash=5695bb5658,release=v1
5 myapp-deploy-5695bb5658-n2b5w 1/1 Running 2 31h 10.244.2.115 k8s-node02 app=myapp,env=test,pod-template-hash=5695bb5658,release=v1

查看ipvs信息

复制代码
1 [root@k8s-master service]# ipvsadm -Ln
2 IP Virtual Server version 1.2.1 (size=4096)
3 Prot LocalAddress:Port Scheduler Flags
4 -> RemoteAddress:Port Forward Weight ActiveConn InActConn
5 ………………
6 TCP 10.106.66.120:80 rr
7 -> 10.244.2.115:80 Masq 1 0 0
8 -> 10.244.2.116:80 Masq 1 0 0
9 -> 10.244.4.105:80 Masq 1 0 0
复制代码

curl访问

复制代码
1 [root@k8s-master service]# curl 10.106.66.120
2 Hello MyApp | Version: v1 | Pod Name
3 [root@k8s-master service]#
4 [root@k8s-master service]# curl 10.106.66.120/hostname.html
5 myapp-deploy-5695bb5658-2866m
6 [root@k8s-master service]#
7 [root@k8s-master service]# curl 10.106.66.120/hostname.html
8 myapp-deploy-5695bb5658-n2b5w
9 [root@k8s-master service]#
10 [root@k8s-master service]# curl 10.106.66.120/hostname.html
11 myapp-deploy-5695bb5658-dcfw7
12 [root@k8s-master service]#
13 [root@k8s-master service]# curl 10.106.66.120/hostname.html
14 myapp-deploy-5695bb5658-2866m
复制代码

备注:如果访问失败,请参考如下文章:

「Kubernetes K8S在IPVS代理模式下svc服务的ClusterIP类型访问失败处理」

Headless Services
有时不需要或不想要负载均衡,以及单独的 Service IP。遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。

这对headless Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。

使用场景
第一种:自主选择权,有时候client想自己来决定使用哪个Real Server,可以通过查询DNS来获取Real Server的信息。
第二种:Headless Services还有一个用处(PS:也就是我们需要的那个特性)。Headless Service对应的每一个Endpoints,即每一个Pod,都会有对应的DNS域名;这样Pod之间就可以互相访问。【结合statefulset有状态服务使用,如Web、MySQL集群】

示例
yaml文件

复制代码
1 [root@k8s-master service]# pwd
2 /root/k8s_practice/service
3 [root@k8s-master service]# cat myapp-svc-headless.yaml
4 apiVersion: v1
5 kind: Service
6 metadata:
7 name: myapp-headless
8 namespace: default
9 spec:
10 selector:
11 app: myapp
12 release: v1
13 clusterIP: “None”
14 ports:
15 - port: 80
16 targetPort: 80
复制代码

启动Service并查看状态和详情

复制代码
1 [root@k8s-master service]# kubectl apply -f myapp-svc-headless.yaml
2 service/myapp-headless created
3 [root@k8s-master service]#
4 [root@k8s-master service]# kubectl get svc -o wide
5 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
6 kubernetes ClusterIP 10.96.0.1 443/TCP 22d
7 myapp-headless ClusterIP None 80/TCP 6s app=myapp,release=v1
8 [root@k8s-master service]#
9 [root@k8s-master service]# kubectl describe svc/myapp-headless
10 Name: myapp-headless
11 Namespace: default
12 Labels:
13 Annotations: kubectl.kubernetes.io/last-applied-configuration:
14 {“apiVersion”:“v1”,“kind”:“Service”,“metadata”:{“annotations”:{},“name”:“myapp-headless”,“namespace”:“default”},“spec”:{“clusterIP”:“None”…
15 Selector: app=myapp,release=v1
16 Type: ClusterIP
17 IP: None
18 Port: 80/TCP
19 TargetPort: 80/TCP
20 Endpoints: 10.244.2.115:80,10.244.2.116:80,10.244.4.105:80 # 后端的Pod信息
21 Session Affinity: None
22 Events:
复制代码

service只要创建成功就会写入到coredns。我们得到coredns IP的命令如下:

1 [root@k8s-master service]# kubectl get pod -o wide -A | grep ‘coredns’
2 kube-system coredns-6955765f44-c9zfh 1/1 Running 29 22d 10.244.0.62 k8s-master
3 kube-system coredns-6955765f44-lrz5q 1/1 Running 29 22d 10.244.0.61 k8s-master

在宿主机安装nslookup、dig命令安装

yum install -y bind-utils

coredns记录信息如下

复制代码
1 # 其中 10.244.0.61 为 coredns IP
2 # myapp-headless.default.svc.cluster.local 为Headless Service域名。格式为: ( s e r v i c e n a m e ) . (service name). (servicename).(namespace).svc.cluster.local,其中 cluster.local 指定的集群的域名
3 [root@k8s-master service]# nslookup myapp-headless.default.svc.cluster.local 10.244.0.61
4 Server: 10.244.0.61
5 Address: 10.244.0.61#53
6
7 Name: myapp-headless.default.svc.cluster.local
8 Address: 10.244.2.116
9 Name: myapp-headless.default.svc.cluster.local
10 Address: 10.244.4.105
11 Name: myapp-headless.default.svc.cluster.local
12 Address: 10.244.2.115
13
14 [root@k8s-master service]#
15 ### 或使用如下命令
16 [root@k8s-master service]# dig -t A myapp-headless.default.svc.cluster.local. @10.244.0.61
17
18 ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> -t A myapp-headless.default.svc.cluster.local. @10.244.0.61
19 ;; global options: +cmd
20 ;; Got answer:
21 ;; WARNING: .local is reserved for Multicast DNS
22 ;; You are currently testing what happens when an mDNS query is leaked to DNS
23 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7089
24 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
25 ;; WARNING: recursion requested but not available
26
27 ;; OPT PSEUDOSECTION:
28 ; EDNS: version: 0, flags:; udp: 4096
29 ;; QUESTION SECTION:
30 ;myapp-headless.default.svc.cluster.local. IN A
31
32 ;; ANSWER SECTION:
33 myapp-headless.default.svc.cluster.local. 14 IN A 10.244.2.116
34 myapp-headless.default.svc.cluster.local. 14 IN A 10.244.4.105
35 myapp-headless.default.svc.cluster.local. 14 IN A 10.244.2.115
36
37 ;; Query time: 0 msec
38 ;; SERVER: 10.244.0.61#53(10.244.0.61)
39 ;; WHEN: Wed Jun 03 22:34:46 CST 2020
40 ;; MSG SIZE rcvd: 237
复制代码

NodePort类型示例
如果将 type 字段设置为 NodePort,则 Kubernetes 控制层面将在 --service-node-port-range 标志指定的范围内分配端口(默认值:30000-32767)。

yaml文件

复制代码
1 [root@k8s-master service]# pwd
2 /root/k8s_practice/service
3 [root@k8s-master service]# cat myapp-svc-NodePort.yaml
4 apiVersion: v1
5 kind: Service
6 metadata:
7 name: myapp-nodeport
8 namespace: default
9 spec:
10 type: NodePort
11 selector:
12 app: myapp
13 release: v1
14 ports:
15 - name: http
16 # 默认情况下,为了方便起见,targetPort 被设置为与 port 字段相同的值。
17 port: 80 # Service对外提供服务端口
18 targetPort: 80 # 请求转发后端Pod使用的端口
19 nodePort: 31682 # 可选字段,默认情况下,为了方便起见,Kubernetes 控制层面会从某个范围内分配一个端口号(默认:30000-32767)
复制代码

启动Service并查看状态

复制代码
1 [root@k8s-master service]# kubectl apply -f myapp-svc-NodePort.yaml
2 service/myapp-nodeport created
3 [root@k8s-master service]#
4 [root@k8s-master service]# kubectl get svc -o wide
5 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
6 kubernetes ClusterIP 10.96.0.1 443/TCP 22d
7 myapp-nodeport NodePort 10.99.50.81 80:31682/TCP 6s app=myapp,release=v1
复制代码
由上可见,类型变为了NodePort

查看ipvs信息

复制代码
1 [root@k8s-master service]# ipvsadm -Ln
2 IP Virtual Server version 1.2.1 (size=4096)
3 Prot LocalAddress:Port Scheduler Flags
4 -> RemoteAddress:Port Forward Weight ActiveConn InActConn
5 ………………
6 TCP 10.99.50.81:80 rr
7 -> 10.244.2.115:80 Masq 1 0 0
8 -> 10.244.2.116:80 Masq 1 0 0
9 -> 10.244.4.105:80 Masq 1 0 0
复制代码

端口查看,可见在本地宿主机监听了相应的端口(备注:集群所有机器都监听了该端口)

1 # 集群所有机器都可以执行查看
2 [root@k8s-master service]# netstat -lntp | grep ‘31682’
3 tcp6 0 0 :::31682 ::😗 LISTEN 3961/kube-proxy

curl通过ClusterIP访问

复制代码
1 # 通过ClusterIP访问
2 [root@k8s-master service]# curl 10.99.50.81
3 Hello MyApp | Version: v1 | Pod Name
4 [root@k8s-master service]#
5 [root@k8s-master service]# curl 10.99.50.81/hostname.html
6 myapp-deploy-5695bb5658-2866m
7 [root@k8s-master service]#
8 [root@k8s-master service]# curl 10.99.50.81/hostname.html
9 myapp-deploy-5695bb5658-n2b5w
10 [root@k8s-master service]#
11 [root@k8s-master service]# curl 10.99.50.81/hostname.html
12 myapp-deploy-5695bb5658-dcfw7
复制代码

curl通过节点IP访问

复制代码
1 # 通过集群节点IP访问
2 [root@k8s-master service]# curl 172.16.1.110:31682
3 Hello MyApp | Version: v1 | Pod Name
4 [root@k8s-master service]#
5 [root@k8s-master service]# curl 172.16.1.110:31682/hostname.html
6 myapp-deploy-5695bb5658-2866m
7 [root@k8s-master service]#
8 [root@k8s-master service]# curl 172.16.1.110:31682/hostname.html
9 myapp-deploy-5695bb5658-n2b5w
10 [root@k8s-master service]#
11 [root@k8s-master service]# curl 172.16.1.110:31682/hostname.html
12 myapp-deploy-5695bb5658-dcfw7
13 # 访问集群其他节点。每台机器都有LVS,和相关调度
14 [root@k8s-master service]# curl 172.16.1.111:31682/hostname.html
15 myapp-deploy-5695bb5658-dcfw7
16 [root@k8s-master service]#
17 [root@k8s-master service]# curl 172.16.1.112:31682/hostname.html
18 myapp-deploy-5695bb5658-dcfw7
复制代码

访问日志查看

kubectl logs -f svc/myapp-nodeport

LoadBalancer类型示例
需要相关云厂商服务支持,这里就不表述了。

ExternalName类型示例
这种类型的Service通过返回CNAME和它的值,可以将服务映射到externalName字段的内容(例如:my.k8s.example.com;可以实现跨namespace名称空间访问)。ExternalName Service是Service的特例,它没有selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式提供服务。

具体使用参见:「Kubernetes K8S之Pod跨namespace名称空间访问Service服务」

yaml文件

复制代码
1 [root@k8s-master service]# pwd
2 /root/k8s_practice/service
3 [root@k8s-master service]# cat myapp-svc-ExternalName.yaml
4 apiVersion: v1
5 kind: Service
6 metadata:
7 name: myapp-externalname
8 namespace: default
9 spec:
10 type: ExternalName
11 externalName: my.k8s.example.com
复制代码

启动Service并查看状态

复制代码
1 [root@k8s-master service]# kubectl apply -f myapp-svc-ExternalName.yaml
2 service/myapp-externalname created
3 [root@k8s-master service]#
4 [root@k8s-master service]# kubectl get svc -o wide
5 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
6 kubernetes ClusterIP 10.96.0.1 443/TCP 21d
7 myapp-externalname ExternalName my.k8s.example.com 21s
复制代码
由上可见,类型变为了ExternalName

宿主机dig命令安装

yum install -y bind-utils

coredns记录信息如下

复制代码
1 # 其中 10.244.0.61 为 coredns IP
2 # myapp-externalname.default.svc.cluster.local 为Service域名。格式为: ( s e r v i c e n a m e ) . (service name). (servicename).(namespace).svc.cluster.local,其中 cluster.local 指定的集群的域名
3 ##### 通过 nslookup 访问
4 [root@k8s-master service]# nslookup myapp-externalname.default.svc.cluster.local 10.244.0.61
5 Server: 10.244.0.61
6 Address: 10.244.0.61#53
7
8 myapp-externalname.default.svc.cluster.local canonical name = my.k8s.example.com.
9 ** server can’t find my.k8s.example.com: NXDOMAIN
10
11 [root@k8s-master service]#
12 ##### 通过 dig 访问
13 [root@k8s-master service]# dig -t A myapp-externalname.default.svc.cluster.local. @10.244.0.61
14
15 ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> -t A myapp-externalname.default.svc.cluster.local. @10.244.0.61
16 ;; global options: +cmd
17 ;; Got answer:
18 ;; WARNING: .local is reserved for Multicast DNS
19 ;; You are currently testing what happens when an mDNS query is leaked to DNS
20 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39541
21 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
22 ;; WARNING: recursion requested but not available
23
24 ;; OPT PSEUDOSECTION:
25 ; EDNS: version: 0, flags:; udp: 4096
26 ;; QUESTION SECTION:
27 ;myapp-externalname.default.svc.cluster.local. IN A
28
29 ;; ANSWER SECTION:
30 myapp-externalname.default.svc.cluster.local. 30 IN CNAME my.k8s.example.com.
31
32 ;; Query time: 2072 msec
33 ;; SERVER: 10.244.0.61#53(10.244.0.61)
34 ;; WHEN: Wed Jun 03 23:15:47 CST 2020
35 ;; MSG SIZE rcvd: 149
复制代码

ExternalIP示例
如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。通过外部 IP(作为目的 IP 地址)进入到集群,打到 Service 端口上的流量,将会被路由到 Service 的 Endpoint 上。

externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。

根据 Service 的规定,externalIPs 可以同任意的 ServiceType 来一起指定。在下面的例子中,my-service 可以在【模拟外网IP】“10.0.0.240”(externalIP:port) 上被客户端访问。

yaml文件

复制代码
1 [root@k8s-master service]# pwd
2 /root/k8s_practice/service
3 [root@k8s-master service]# cat myapp-svc-externalIP.yaml
4 apiVersion: v1
5 kind: Service
6 metadata:
7 name: myapp-externalip
8 namespace: default
9 spec:
10 selector:
11 app: myapp
12 release: v1
13 ports:
14 - name: http
15 port: 80
16 targetPort: 80
17 externalIPs:
18 - 10.0.0.240
复制代码

启动Service并查看状态

复制代码
1 [root@k8s-master service]# kubectl apply -f myapp-svc-externalIP.yaml
2 service/myapp-externalip created
3 [root@k8s-master service]#
4 [root@k8s-master service]# kubectl get svc -o wide
5 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
6 kubernetes ClusterIP 10.96.0.1 443/TCP 22d
7 myapp-externalip ClusterIP 10.107.186.167 10.0.0.240 80/TCP 8s app=myapp,release=v1
复制代码

查看ipvs信息

复制代码
1 [root@k8s-master service]# ipvsadm -Ln
2 IP Virtual Server version 1.2.1 (size=4096)
3 Prot LocalAddress:Port Scheduler Flags
4 -> RemoteAddress:Port Forward Weight ActiveConn InActConn
5 ………………
6 TCP 10.107.186.167:80 rr
7 -> 10.244.2.115:80 Masq 1 0 0
8 -> 10.244.2.116:80 Masq 1 0 0
9 -> 10.244.4.105:80 Masq 1 0 0
10 ………………
11 TCP 10.0.0.240:80 rr
12 -> 10.244.2.115:80 Masq 1 0 0
13 -> 10.244.2.116:80 Masq 1 0 0
14 -> 10.244.4.105:80 Masq 1 0 0
复制代码

curl访问,通过ClusterIP

复制代码
1 [root@k8s-master service]# curl 10.107.186.167
2 Hello MyApp | Version: v1 | Pod Name
3 [root@k8s-master service]#
4 [root@k8s-master service]# curl 10.107.186.167/hostname.html
5 myapp-deploy-5695bb5658-n2b5w
6 [root@k8s-master service]#
7 [root@k8s-master service]# curl 10.107.186.167/hostname.html
8 myapp-deploy-5695bb5658-2866m
9 [root@k8s-master service]#
10 [root@k8s-master service]# curl 10.107.186.167/hostname.html
11 myapp-deploy-5695bb5658-dcfw7
复制代码

curl访问,通过ExternalIP

复制代码
1 [root@k8s-master service]# curl 10.0.0.240
2 Hello MyApp | Version: v1 | Pod Name
3 [root@k8s-master service]#
4 [root@k8s-master service]# curl 10.0.0.240/hostname.html
5 myapp-deploy-5695bb5658-2866m
6 [root@k8s-master service]#
7 [root@k8s-master service]# curl 10.0.0.240/hostname.html
8 myapp-deploy-5695bb5658-dcfw7
9 [root@k8s-master service]#
10 [root@k8s-master service]# curl 10.0.0.240/hostname.html
11 myapp-deploy-5695bb5658-n2b5w
深圳网站建设www.sz886.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值