服务发现机制

Kubernetes提供了两种发现Service的方法:

1.环境变量

当Pod运行的时候,Kubernetes会将之前存在的Service的信息通过环境变量写到Pod中。

这种方法要求Pod必须要在Service之后启动。

在Service之前启动的Pod就不会有该Service的环境变量。

采用DNS的方式就没有这个限制。

2.DNS

当有新的Service创建时,就会自动生成一条DNS记录。

使用这种方法,需要安装Cluster DNS。

在kubernetes中每一个service都会被分配一个虚拟IP,每一个Service在正常情况下都会长时间不会改变,这个相对于pod的不定IP,对于集群中APP的使用相对是稳定的。但是Service的信息注入到pod目前使用的是环境变量的方式,并且十分依赖于pod(rc)和service的创建顺序,这使得这个集群看起来又不那么完美,于是kubernetes以插件的方式引入了DNS系统,利用DNS对Service进行一个映射,这样我们在APP中直接使用域名进行引用,避免了之前的变量泛滥问题,也避免了创建顺序的尴尬局面。

Kubernetes1.2.7版本下Cluster DNS的安装

阅读github上官方源码发现: 
Cluster DNS自Kubernetes1.3版本开始,结构发生了变化。这里先以1.2.7版本作为研究。

Cluster DNS扩展插件用于支持Kubernetes的服务发现机制,1.2.7版本中,Cluster DNS主要包含如下几项:

1)SkyDNS 
提供DNS解析服务。 
2)Etcd 
用于DNS的存储。 
3)Kube2sky 
监听Kubernetes,当有新的Service创建时,将其注册到etcd上。 
4)healthz 
提供对skydns服务的健康检查功能。

在Master服务器上下载Kubernetes发布包

Cluster DNS在Kubernetes发布包的cluster/addons/dns目录下

[root@k8s-master home]# yum -y install wget
[root@k8s-master home]# wget https://codeload.github.com/kubernetes/kubernetes/tar.gz/v1.2.7
[root@k8s-master home]# tar -xf kubernetes-1.2.7.tar.gz
[root@k8s-master home]# ls
kubernetes-1.2.7  kubernetes-1.2.7.tar.gz  sheng
[root@k8s-master home]# cd kubernetes-1.2.7/cluster/addons/dns
[root@k8s-master dns]# ls
kube2sky  MAINTAINERS.md  OWNERS  README.md  skydns  skydns-rc.yaml.in  skydns-svc.yaml.in
#skydns-rc.yaml.in和skydns-svc.yaml.in是两个模板文件,通过设置的环境变量修改其中的相应属性值,可以生成Replication Controller和Service的定义文件。

需要注意,skydns服务使用的clusterIP需要我们指定一个固定的IP地址,每个Node的kubelet进程都将使用这个IP地址,不能通过Kuberneters自动给skydns分配。

通过环境变量,配置参数

[root@k8s-master dns]# vi ~/.bash_profile    #添加下面三行

export DNS_SERVER_IP="10.254.10.2"

export DNS_DOMAIN="cluster.local"

export DNS_REPLICAS=1

设置 Cluster DNS Service的IP为 10.254.10.2(不能和已分配的IP重复,如10.0.10.0),Cluster DNS的本地域为 cluster.local。

修改每台Node上的kubelet启动参数

vim /etc/kubernetes/kubelet

在KUBELET_ARGS里增加:

--cluster_dns=10.254.10.2 --cluster_domain=cluster.local

即:

# Add your own!

KUBELET_ARGS="--cluster_dns=10.254.10.2 --cluster_domain=cluster.local"

cluster_dns为DNS服务的ClusterIP地址 
cluster_domain为DNS服务中设置的域名

重启kubelet服务

systemctl restart kubelet

生成dns-rc.yaml和dns-svc.yaml

1. skydns配置文件

创建DNS服务的RC配置文件,在这个RC配置中包含了3个Container的定义

[root@k8s-master dns]# cat skydns-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:name: kube-dns-v9namespace: kube-systemlabels:k8s-app: kube-dnsversion: v9kubernetes.io/cluster-service: "true"
spec:replicas: 1selector:k8s-app: kube-dnsversion: v9template:metadata:labels:k8s-app: kube-dnsversion: v9kubernetes.io/cluster-service: "true"spec:containers:- name: etcdimage: kube-registry:5000/etcdresources:limits:cpu: 100mmemory: 50Micommand:- /usr/local/bin/etcd- -data-dir- /var/etcd/data- -listen-client-urls- http://127.0.0.1:2379,http://127.0.0.1:4001- -advertise-client-urls- http://127.0.0.1:2379,http://127.0.0.1:4001- -initial-cluster-token- skydns-etcdvolumeMounts:- name: etcd-storagemountPath: /var/etcd/data- name: kube2skyimage: kube-registry:5000/kube2skyresources:limits:cpu: 100mmemory: 50Miargs:- -domain=cluster.local- -kube_master_url=http://10.0.0.11:8080- name: skydnsimage: kube-registry:5000/skydnsresources:limits:cpu: 100mmemory: 50Miargs:- -machines=http://localhost:4001- -addr=0.0.0.0:53- -domain=cluster.localports:- containerPort: 53name: dnsprotocol: UDP- containerPort: 53name: dns-tcpprotocol: TCPvolumes:- name: etcd-storageemptyDir: {}

(1)kube2sky容器需要访问Kubernetes Master,需要配置Master所在物理主机的IP地址和端口 
(2)kube2sky容器和skydns容器的启动参数-domain,设置Kubernetes集群中Service所属的域名,本例中为cluster.local。启动后,kube2sky会监听Kubernetes,当有新的Service创建时,就会生成相应的记录并保存到etcd中。kube2sky为每个Service生成两条记录:

<service_name>.<namespace_name>.<domain>
<service_name>.<namespace_name>.svc.<domain>

(3)skydns的启动参数-addr=0.0.0.0:53表示使用本机TCP和UDP的53端口提供服务。

创建DNS服务的Service配置文件如下:

[root@k8s-master dns]# cat skydns-svc.yaml
apiVersion: v1
kind: Service
metadata:name: kube-dnsnamespace: kube-systemlabels:k8s-app: kube-dnskubernetes.io/cluster-service: "true"kubernetes.io/name: "KubeDNS"
spec:selector:k8s-app: kube-dns#clusterIP:  {{ pillar['dns_server'] }}       #<---添加DNS_SERVER_IPclusterIP:  10.254.10.2ports:- name: dnsport: 53protocol: UDP- name: dns-tcpport: 53protocol: TCP

注意:skydns服务使用的clusterIP需要我们指定一个固定的IP地址,每个Node的Kubelet进程都将使用这个IP地址,不能通过Kubernetes自动分配。 
另外,这个IP地址需要在kube-apiserver启动参数–service-cluster-ip-range指定的IP地址范围内。

3. 创建skydns Pod和服务

通过kubectl create完成RC和Service的创建:

 (1)通过定义文件dns-rc.yaml创建Cluster DNS Replication Controller

[root@k8s-master dns]# kubectl create -f skydns-rc.yaml
replicationcontroller "kube-dns-v11" created

验证Cluster DNS Pod是否创建运行成功:

[root@k8s-master dns]# kubectl get pod --namespace=kube-system -o wide

NAME             READY     STATUS          RESTARTS   AGE       IP        NODE

kube-dns-v11-plw4m   0/4       ContainerCreating   0        9m        <none>    k8s-node-3

containercreating表示创建不成功

查看错误原因:

[root@k8s-master dns]# kubectl describe pod --namespace=kube-system
Name:           kube-dns-v11-3pln8
Namespace:      kube-system
Node:           k8s-node-3/10.0.0.14
Start Time:     Thu, 07 Jun 2018 22:02:39 +0800
Labels:         k8s-app=kube-dnskubernetes.io/cluster-service=trueversion=v11
Status:         Pending
IP:
Controllers:    ReplicationController/kube-dns-v11
Containers:etcd:Container ID:Image:              kube-registry:5000/etcdImage ID:Port:Command:/usr/local/bin/etcd-data-dir/var/etcd/data-listen-client-urlshttp://127.0.0.1:2379,http://127.0.0.1:4001-advertise-client-urlshttp://127.0.0.1:2379,http://127.0.0.1:4001-initial-cluster-tokenskydns-etcdLimits:cpu:      100mmemory:   500MiRequests:cpu:              100mmemory:           50MiState:              WaitingReason:           ContainerCreatingReady:              FalseRestart Count:      0Volume Mounts:/var/etcd/data from etcd-storage (rw)Environment Variables:      <none>kube2sky:Container ID:Image:              kube-registry:5000/kube2skyImage ID:Port:Args:--domain=cluster.local--kube-master-url=http://10.0.0.11:8080Limits:cpu:      100mmemory:   200MiRequests:cpu:                      100mmemory:                   50MiState:                      WaitingReason:                   ContainerCreatingReady:                      FalseRestart Count:              0Liveness:                   http-get http://:8080/healthz delay=60s timeout=5s period=10s #success=1 #failure=5Readiness:                  http-get http://:8081/readiness delay=30s timeout=5s period=10s #success=1 #failure=3Volume Mounts:              <none>Environment Variables:      <none>skydns:Container ID:Image:              kube-registry:5000/skydnsImage ID:Ports:              53/UDP, 53/TCPArgs:-machines=http://127.0.0.1:4001-addr=0.0.0.0:53-ns-rotate=false-domain=cluster.local.Limits:cpu:      100mmemory:   200MiRequests:cpu:                      100mmemory:                   50MiState:                      WaitingReason:                   ContainerCreatingReady:                      FalseRestart Count:              0Volume Mounts:              <none>Environment Variables:      <none>healthz:Container ID:Image:              kube-registry:5000/exechealthzImage ID:Port:               8080/TCPArgs:-cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1 >/dev/null-port=8080Limits:cpu:      10mmemory:   20MiRequests:cpu:                      10mmemory:                   20MiState:                      WaitingReason:                   ContainerCreatingReady:                      FalseRestart Count:              0Volume Mounts:              <none>Environment Variables:      <none>
Conditions:Type          StatusInitialized   True Ready         False PodScheduled  True
Volumes:etcd-storage:Type:       EmptyDir (a temporary directory that shares a pod's lifetime)Medium:
QoS Class:      Burstable
Tolerations:    <none>
Events:FirstSeen  LastSeen  Count   From           SubObjectPath   Type          Reason          Message---------  --------   -----   ----          -------------   --------        ------          -------12h      2m     32    {kubelet k8s-node-3}                   Warning      FailedSync      Error syncing pod, skipping: failed to "StartContainer" for "POD" with ErrImagePull: "repository docker.io/kube-registry not found: does not exist or no pull access"12h       9s     532    {kubelet k8s-node-3}               Warning         FailedSync      Error syncing pod, skipping: failed to "StartContainer" for "POD" with ImagePullBackOff: "Back-off pulling image \"kube-registry:5000\""

     (2)生成Service的定义文件dns-svc.yaml创建Service

[root@k8s-master dns]# kubectl create -f skydns-svc.yaml
service "kube-dns" created
[root@k8s-master dns]# kubectl get svc --namespace=kube-system -o wide
NAME       CLUSTER-IP    EXTERNAL-IP   PORT(S)         AGE       SELECTOR
kube-dns    10.254.10.2     <none>      53/UDP,53/TCP      9s        k8s-app=kube-dns

[root@k8s-master dns]# kubectl create -f skydns-svc.yaml

The Service "kube-dns" is invalid: spec.clusterIP: Invalid value: "10.0.10.0": provided IP is not in the valid range

表示地址有冲突

创建完成后,查看到系统创建的RC、Pod和Service都已创建成功:

然后我们创建一个普通的Service,以redis-master服务为例:

[root@k8s-master home]# mkdir k8s_service
[root@k8s-master home]# ls
k8s_service  kubernetes-1.2.7  kubernetes-1.2.7.tar.gz  sheng
[root@k8s-master home]# cd k8s_service/
[root@k8s-master k8s_service]# mkdir redis-yaml
[root@k8s-master k8s_service]# cd redis-yaml/
[root@k8s-master redis-yaml]# vi redis-master-service.yaml
apiVersion: v1
kind: Service
metadata:name: redis-masterlabels:name: redis-master
spec:selector:name: redis-masterports:- port: 6379targetPort: 6379
"redis-master-service.yaml" [New] 12L, 179C written

查看创建出来的Service:

[root@k8s-master redis-yaml]# kubectl create -f redis-master-service.yaml
service "redis-master" created
[root@k8s-master redis-yaml]# kubectl get service
NAME           CLUSTER-IP       EXTERNAL-IP    PORT(S)    AGE
kubernetes      10.254.0.1       <none>        443/TCP    4d
redis-master     10.254.195.220    <none>        6379/TCP    8s

4.Docker私有仓库搭建和使用

然后在10.0.0.10上创建Docker-registry 具体步骤详见: https://blog.51cto.com/sf1314/2124934

安装并启动docker(此步已安装忽略)

yum -y install docker
systemctl start docker
systemctl enable docker

 搭建私有仓库

下载registry镜像

docker pull registry

防火墙添加运行5000端口

iptables -I INPUT 1 -p tcp --dport 5000 -j ACCEPT

下载完之后我们通过该镜像启动一个容器

docker run -d -p 5000:5000 --privileged=true -v /opt/registry:/tmp/registry registry

参数说明:

-v /opt/registry:/tmp/registry :默认情况下,会将仓库存放于容器内的/tmp/registry目录下,指定本地目录挂载到容器

–privileged=true :CentOS7中的安全模块selinux把权限禁掉了,参数给容器加特权,不加上传镜像会报权限错误(OSError: [Errno 13] Permission denied: ‘/tmp/registry/repositories/liibrary’)或者(Received unexpected HTTP status: 500 Internal Server Error)错误

检查5000端口

netstat -an | grep 5000

 客户端上传镜像

修改/etc/sysconfig/docker(Ubuntu下配置文件地址为:/etc/init/docker.conf),增加启动选项(已有参数的在后面追加),之后重启docker,不添加报错,https证书问题。

OPTIONS='--insecure-registry kube-registry:5000'

#CentOS 7系统,注意如果是kube-registry:5000,则需要在/etc/hosts配置  10.0.0.10  kube-registry

# 后续拉取  10.0.0.10:5000需要docker pull 10.0.0.10:5000/centos1

#          kube-registry:5000需要 docker pull docker-registry:5000/centos1

#other_args='--insecure-registry 10.0.0.10:5000'   #CentOS 6系统

因为Docker从1.3.X之后,与docker registry交互默认使用的是https,而此处搭建的私有仓库只提供http服务

在docker公共仓库下载一个镜像

[root@etcd ~]# docker search pod-infrastructure
INDEX     NAME                      DESCRIPTION                        STARS     OFFICIAL   AUTOMATED
docker.io  docker.io/openshift/origin-pod   The pod infrastructure image for OpenShift 3    8
......
[root@k8s-master ~]# docker search busybox
INDEX       NAME           DESCRIPTION                                  STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/busybox     Busybox base image.                            1272      [OK]
......
[root@etcd ~]# docker pull docker.io/openshift/origin-pod
[root@etcd ~]# docker pull docker.io/busybox

来修改一下该镜像的tag

[root@etcd ~]# docker tag docker.io/openshift/origin-pod 10.0.0.10:5000/pod-infrastructure
[root@etcd ~]# docker tag docker.io/busybox 10.0.0.10:5000/busybox

把打了tag的镜像上传到私有仓库

[root@etcd ~]# docker push 10.0.0.10:5000/pod-infrastructure
[root@etcd ~]# docker push 10.0.0.10:5000/busybox

客户端添加私有仓库地址

# 添加这一行,修改/etc/sysconfig/docker文件,需要在/etc/hosts添加10.0.0.10  kube-registry解析并重新启动docker服务。

ADD_REGISTRY='--add-registry kube-registry:5000'
systemctl restart docker

加上后,search镜像,私有仓库和docker hub上都会显示;

不加搜索私有仓库,需要命令中指定私有仓库ip

使用仓库中的镜像

[root@etcd ~]# curl http://10.0.0.10:5000/v2/_catalog
{"repositories":["busybox","pod-infrastructure"]}

5. 通过DNS查找Service

使用一个带有nslookup工具的Pod来验证DNS服务是否能够正常工作:

[root@k8s-master ~]# cd /home
[root@k8s-master home]# mkdir -p k8s_service/demo
[root@k8s-master home]# cd k8s_service/demo
[root@k8s-master demo]# cat busybox.yaml
apiVersion: v1
kind: Pod
metadata: name: busyboxnamespace: default
spec:containers:- image: kube-registry:5000/busyboxcommand:- sleep- "3600"imagePullPolicy: IfNotPresentname: busyboxrestartPolicy: Always

运行kubectl create -f busybox.yaml完成创建。

[root@k8s-master demo]# kubectl create -f busybox.yaml
pod "busybox" created

STATUS状态为Running则表示创建成功,若为ContainerCreating,则表示创建不成功

[root@k8s-master demo]# kubectl get pod
NAME      READY     STATUS    RESTARTS   AGE
busybox   1/1        Running    1         5m

例子:kubectl describe pod busybox可以查看部署失败的原因

[root@k8s-master demo]# kubectl describe pod busybox
Name:          busybox
Namespace:      default
Node:          k8s-node-1/10.0.0.12
Start Time:     Thu, 07 Jun 2018 16:07:44 +0800
Labels:        <none>
Status:        Pending
IP:
Controllers:    <none>
Containers:busybox:Container ID:Image:     kube-registry:5000/busyboxImage ID:Port:Command:sleep3600State:      WaitingReason:    ContainerCreatingReady:         FalseRestart Count:     0Volume Mounts:       <none>Environment Variables: <none>
Conditions:Type       StatusInitialized   True Ready       False PodScheduled  True
No volumes.
QoS Class:      BestEffort
Tolerations:    <none>
Events:FirstSeen   LastSeen   Count   From          SubObjectPath  Type     Reason          Message---------   --------  -----   ----           -------------  --------    ------          -------20s        20s      1    {default-scheduler }   Normal    Scheduled  Successfully assigned busybox to k8s-node-120s        9s       2   {kubelet k8s-node-1}    Warning    FailedSync Error syncing pod, skipping: failed to"StartContainer" for "POD" with ErrImagePull: "image pull failed for registry.access.redhat.com/rhel7/pod-infrastructure:latest, this may be because there are no credentials on this request.  details: (open /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt: no such file or directory)"

在该容器成功启动后,通过kubectl exec nslookup 进行测试:

[root@docker1 demo]# kubectl exec busybox -- nslookup redis-master
Server:    10.254.0.3
Address 1: 10.254.0.3
Name:      redis-master
Address 1: 10.254.7.16012345

可以看到,通过DNS服务器10.254.0.3成功找到了名为”redis-master”服务的IP地址:10.254.7.160 
如果某个Service属于自定义的命名空间,那么进行Service查找时,需要带个namespace的名字。下面以查看kube-dns服务为例:

[root@docker1 demo]# kubectl exec busybox -- nslookup kube-dns.kube-systemServer:    10.254.0.3Address 1: 10.254.0.3Name:      kube-dns.kube-system
Address 1: 10.254.0.312345

如果仅使用”kube-dns”来进行查找,则将会失败: 
nslookup: can’t resolve ‘kube-dns’

查看多个容器组成的Pod时,要添加-c选项指定容器的名称

# kubectl logs kube-dns-v9-curdr --namespace=kube-systemError from server: a container name must be specified for pod kube-dns-v9-curdr
# kubectl logs kube-dns-v9-curdr -c skydns --namespace=kube-system123

5. DNS服务的工作原理解析

(1)kube2sky容器应用通过调用Kubernetes Master的API获得集群中所有Service的信息,并持续监控新Service的生成,然后定稿etcd中。 
查看etcd存储的Service信息

# kubectl exec kube-dns-v9-evgl6 -c etcd --namespace=kube-system etcdctl ls /skydns/local/cluster/skydns/local/cluster/default/skydns/local/cluster/svc
/skydns/local/cluster/kube-system1234

可以看到在skydns键下面,根据我们配置的域名(cluster.local)生成了local/cluster子键,接下来是namespace(default和kube-system)和svc(下面也按namespace生成子键)。

查看redis-master服务对应的键值:

# kubectl exec kube-dns-v9-evgl6 -c etcd --namespace=kube-system etcdctl get /skydns/local/cluster/default/redis-master
{"host":"10.254.7.160","priority":10,"weight":10,"ttl":30,"targetstrip":0}12

可以看到,redis-master服务对应的完整域名为redis-master.default.cluster.local,并且其IP地址为10.254.7.160。

(2)根据Kubelet启动参数的设置(–cluster_dns),Kubelet会在每个新创建的Pod中设置DNS域名解析配置文件/etc/resolv.conf文件,在其中增加了一条nameserver配置和一条search配置:

nameserver 10.254.0.3nameserver 202.96.128.86search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:51234

通过名字服务器10.254.0.3访问的实际上是skydns在53端口上提供的DNS解析服务。

(3)应用程序就能够像访问网站域名一样,仅仅通过服务的名字就能访问到服务了。 
例如,设置redis-slave的启动脚本为: 
redis-server –slaveof redis-master 6379 
创建redis-slave的Pod并启动它。 
之后,我们可以登录redis-slave容器中查看,其通过DNS域名服务找到了redis-master的IP地址10.254.7.160,并成功建立了连接。 
通过DNS设置,对于其他Service(服务)的查询将可以不再依赖系统为每个Pod创建的环境变量,而是直接使用Service的名字就能对其进行访问,使得应用程序中的代码更简洁了。

转载于:https://blog.51cto.com/sf1314/2124462

Kubernetes实战[2]: 服务发现机制与Cluster DNS的安装(无CA认证版)相关推荐

  1. 第四篇:服务发现机制

    本文出自Service Discovery in a Microservices Architecture,作者 Chris Richardson, 写于2015年5月19日 这是本系列文章的第四篇. ...

  2. 微服务ServiceMesh及三种服务发现机制

    1. 前言 今年,ServiceMesh(服务网格)概念在社区里头非常火,有人提出2018年是ServiceMesh年,还有人提出ServiceMesh是下一代的微服务架构基础.作为架构师,如果你现在 ...

  3. kubernetes上的服务发现-CoreDNS配置

    参考: 官方网站,https://coredns.io/ CoreDNS安装,https://my.oschina.net/u/2306127/blog/1618543 CoreDNS使用手册,htt ...

  4. SPI(服务发现机制)

    什么是SPI SPI ,全称为 Service Provider Interface,是一种服务发现机制.它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文 ...

  5. 从零开始入门 | Kubernetes 中的服务发现与负载均衡

    作者 | 阿里巴巴技术专家  溪恒 一.需求来源 为什么需要服务发现 在 K8s 集群里面会通过 pod 去部署应用,与传统的应用部署不同,传统应用部署在给定的机器上面去部署,我们知道怎么去调用别的机 ...

  6. android module中获取 app_Android模块化中的服务发现机制

    code小生 一个专注 Android 领域的技术平台 公众号回复 Android 加入我的安卓技术群 作者:低情商的大仙 链接:https://www.jianshu.com/p/de432a82e ...

  7. 一文了解 Kubernetes 中的服务发现

    原文链接:一文了解 Kubernetes 中的服务发现 Kubernetes 服务发现是一个经常让我产生困惑的主题之一.本文分为两个部分: 网络方面的背景知识 深入了解 Kubernetes 服务发现 ...

  8. Kubernetes集群服务发现Service资源LoadBalancer类型详解(二十九)

    Kubernetes集群服务发现Service资源LoadBalancer类型详解 1.LoadBalancer类型的service资源概念 LoadBalancer和Nodeport非常相似,目的都 ...

  9. 一文详解 Kubernetes 中的服务发现,运维请收藏

    K8S 服务发现之旅 Kubernetes 服务发现是一个经常让我产生困惑的主题之一.本文分为两个部分: 网络方面的背景知识 深入了解 Kubernetes 服务发现 要了解服务发现,首先要了解背后的 ...

  10. 浅谈 Kubernetes 中的服务发现

    原文:https://nigelpoulton.com/blog/f/demystifying-kubernetes-service-discovery Kubernetes 服务发现是一个经常让我产 ...

最新文章

  1. C#利用lambda在函数中创建内部函数
  2. 盘点丨机器学习2017年重大进展汇总
  3. 会话技术CookieSession
  4. fabric shim安装合约_智能合约简介_智能合约开发_Hyperledger Fabric_开发指南_区块链服务 BaaS - 阿里云...
  5. QML Profiler性能优化教程
  6. JAVA中用于处理字符串的 三兄弟
  7. C语言变量声明问题——变量定义一定要放在所有执行语句/语句块的最前面吗?
  8. Python爬虫 --- 2.2 Scrapy 选择器的介绍
  9. 音视频编解码:NVIDIA Jetson Linux Multimedia API(总结)
  10. HFSS脚本建模入门
  11. java生成mib文件_【snmp】使用MIB Builder生成MIB文件
  12. 车辆动力学知识总结(五)运动学模型的线性化和离散化
  13. 关于MATLAB调用第三方程序
  14. java中的String和ArrayList类
  15. 华人的旗帜——首位亚裔图灵奖获得者姚期智
  16. (摘之博客园狂奔di蜗牛)ASP.NET页面刷新方法总结
  17. 【轻博客观察之二】十问Tumblr
  18. Linux命令整理(二)
  19. dw选项卡代码_dreamweaver cs6快捷注释方法
  20. 游戏模拟器成了外挂帮凶,灰产对抗再升级

热门文章

  1. Android项目“error: Apostrophe not preceded by \ (”报错解决方法
  2. xlsx表格怎么做汇总统计_表格进行分类汇总怎么做
  3. ssh-keygen命令使用
  4. (2010计本3班-杨蒙)面向对象的C--实现链表操作
  5. Unity中访问GameCenter的实现
  6. WebForm CSS垂直虚线时间轴特效
  7. oracle的listener监听启动报TNS-12555/ TNS-12560 TNS-00525错误
  8. 阿里云ECS服务器修复漏洞
  9. OpenSSH 用户枚举漏洞(CVE-2018-15919)服务器修复方法(亲测实用)
  10. 外星人笔记本计算机在哪里,笔记本电脑没声音,详细教您外星人笔记本没声音如何解决...