【爬坑系列】之解读kubernetes的认证原理&实践
对于访问kube-apiserver模块的请求来说,如果是使用http协议,则会顺利进入模块内部得到自己想要的;但是如果是用的是https,则能否进入模块内部获得想要的资源,他会首先要进行https自有的tls握手,进而进入kube-apiserver的三大控制,接下来,就让我一起研究下.....
一,对Kubernetes API访问的三大控制
- Authentication:认证,确认“你是不是你",包括多种方式,如 Client Certificates, Password, and Plain Tokens, Bootstrap Tokens, and JWT Tokens等
- Authorization:鉴权,确认“你是不是有权利做这件事”。怎样判定是否有权利,通过配置策略
- Admission Control:AC是以一个一个软件模块形式存在,经过配置来将这些控制模块加载到自己的系统中。这些模块可以修改和拒绝请求,具体来说就是他不仅可以针对鉴权(Authorization)部门中的属性进行控制,它还可以访问正在创建或更新的对象的内容。 也就是说,该部门在在对资源的created, deleted, updated or connected (proxy)起作用,但是对reads不加控制。
- 水鬼子:是对已经"放行"的请求进入apiserver后开始真正操作资源的时候,对这份资源的控制。
参考:https://kubernetes.io/docs/reference/access-authn-authz/controlling-access/
API服务器在2个端口上都对外提供服务:
1,Localhost Port:默认8080端口,通过这个端口的请求会绕过认证和鉴权两个控制模块,一般用于集群内部的组件之间的交互。
2,Secure Port:默认6443端口,通过这个端口的请求会经过三大控制模块,用于对外提供服务。
关于认证,ApiServer主要的有三种方式如下:
1)Https双向认证,是双向认证啊,不是单向认证(最安全)。
2)Http Token认证
3)Http Base认证,用户名和密码
以上的认证方式是以模块的形式存在于apiserver中,可以通过配置支持多种认证,请求只要通过一个认证就算成功。
kubectl命令行工具既同时支持CA双向认证也支持简单认证(http base或者token)两种模式与apiserver进行通信,但其他组件只能配置成一种模式。
这里参考了:https://blog.csdn.net/xxb249/article/details/79449434
wxy: 这里说一点我自己的理解,https协议本身(tls)可以是单向认证也可以是双向认证,需要明确几点
1)不要想当然认为https是天生的,那也是需要api server去实现的,只不过tls是一套共有的规范,api server组件也需要按照规范来
2)一般单向认证是指服务端(即api server)一方准备好证书就行了,另一方客户端不需要,这种当然就很灵活,对客户端是curl还是浏览器就没什么要求了
3)但是如果你使用的是双向认证,那就麻烦了,即客户端也需要准备证书,且这个证书还需要是api server认识的,所以这个时候就不能是任何客户端就能访问了,而是需要先了解api server的内部情况(配置的客户端根证书),再生成证书才行
4)综述:https的单向认证对客户端没有要求,也就可以认为默认支持,或者说具有普遍意义
https的双向认证,以及k8s的自有认证方式(base,token方式)这三种酒称为具有k8s特色的认证方式
二,https协议的tls握手
只要你是通过Secure Port来方位api,那么你必然要遵守https协议要求的tls链接,这是一个怎样的交互呢?首先需要了解一个概念:数字证书,让我们细细道来
0,数字证书以及网络传输加密
假设,有两个人,一个叫 小起,一个叫 小终,小起想给小终发送数据,可是怕别人截取,篡改等等一些不安全的行为,于是经历了如下的演变过程,直到最后得到了最完美的加密过程。
stage1: 对称加密
小起 ----------将数据加密,并带着能解密的钥匙,一起交给小终 -----------> 小终
问题:传输的过程中,钥匙可能被盗
stage2:非对称加密
小终:自己有一个秘钥对,公钥:对外公开; 私钥:自己保留; 由公钥加密的数据只能由私钥解密,由私钥加密的内容只能由公钥解密
小起 ----------将数据用小终的公钥加密,交给小终 -----------> 小终(用小终自己的私钥解密)
问题:传输的过程中,有人将数据截获,搞一堆烂七八糟的内容重新用小终的公钥加密,再发给小终。
stage2进阶:签名技术的应用
利用hash算法不可逆的特性,将正文数据进行hash计算得到摘要,当小终收到正文后同样hash计算,如果二者相同说明数据是完整的。
同时,小起还要告诉小终,这个摘要是我计算的,可不是别人计算的的。
小起 -----------------1)就数据用小终的公钥加密; -------------------------------------------------------------------> 小终(用自己的公钥解密数据,用小起的公钥解密签名)
2)将数据用hash算法计算出摘要,并用小起的私钥对摘要进行加密(签名)
问题:有人冒充是小起给小终发数据
stage3:数字证书
前面说了公钥/私钥都是自己家搞出来的东西,就算是被仿造了也不知道,于是将公钥"贴在第三方出具的正式文件上"(我们所说的签发数字证书)。这样就显得有保障,因为这个正式文件上可是有第三方盖章的。但同样还要能够识别这个"章"是真正权威机构的。具体原理是:
小起,小终 <-----------从ca那里获取两样:根证书(“印章”图样),公钥(数字证书)私钥对---------CA中心(证书颁发机构)
小起 (用根证书校验小终的数字证书) <---------交换数字证书 -----------> 小终(用根证书校验小起的数字证书)
整合:对称加密结合非对称加密
考虑到效率问题,真正的业务数据是用对称加密算法加密的。所以综合以后,过程是这样的:
通过stage3,我们现在互相已经有了对方准确的公钥,然后通过stage2的数据交换协商出对称加密秘钥自己保存好,再用stage1的对称加密算法(此时不需要携带解密秘钥)加密数据
小起 --------- 用对称加密算法加密的数据-----------> 小终
1,tls的握手前的准备
所谓的握手,其实就是我们在上一节讲述的“对称加密秘钥”的协商过程,所以再协商之前双方要先去向CA机构发请求,获得数字证书和根证书,而这个CA机构可以是自己,只要在集群范围内大家认可就可以了,所以我们通过cfssl工具生成证书,当然也可以用openssl工具。
以下列出了步骤,有些细节可以参考这里:https://blog.csdn.net/xxb249/article/details/79449434
1)安装cfssl
curl -s -L -o /bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
curl -s -L -o /bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
curl -s -L -o /bin/cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x /bin/cfssl*
2)写根证书的配置文件
#mkdir -p /etc/kubernetes/apiserver/
#cd /etc/kubernetes/apiserver/ //利用命令先生成一个缺省的样板的请求文件
#cfssl print-defaults config > ca-config.json ----
#cfssl print-defaults csr > ca-csr.json ----修改配置,配置请求文件.csr应该是什么样子的
//根据自己的情况修改配置,ca-config.json中可以同时定义多个配置簇,一个配置簇对应一种类型的数字证书的各项参数
#vi ca-config.json
#vi ca-csr.json
我的配置文件供参考
[root@master test]# cat ca-config.json
{
"signing": {
"default": {
"expiry": "43800h"
},
"profiles": {
"client": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
},
"server": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
3)生成根正书
# cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
// :: [INFO] generating a new CA key and certificate from CSR
// :: [INFO] generate received request
// :: [INFO] received CSR
// :: [INFO] generating key: rsa-
// :: [INFO] encoded CSR
// :: [INFO] signed certificate with serial number [root@master apiserver]# ll
total
-rw-r--r-- root root May : ca-config.json
-rw-r--r-- root root May : ca.csr ---根证书请求文件
-rw-r--r-- root root May : ca-csr.json
-rw------- root root May : ca-key.pem ---根证书对应的私钥
-rw-r--r-- root root May : ca.pem ----根证书
4)签发数字证书,首先写好配置,然后签发
#cfssl print-defaults csr > server-csr.json
# vi server-csr.json ---按情况修改
//-profile参数对应ca-config.json中的一个配置簇
# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server-csr.json | cfssljson -bare server
2019/05/30 19:37:53 [INFO] generate received request
2019/05/30 19:37:53 [INFO] received CSR
2019/05/30 19:37:53 [INFO] generating key: rsa-2048
2019/05/30 19:37:53 [INFO] encoded CSR
2019/05/30 19:37:53 [INFO] signed certificate with serial number 605959301321047408407639792005193883834034252126
2019/05/30 19:37:53 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
说明:在部署集群的时候会用到各种证书,有的文档会告诉你有server类型,peer类型,client类型......这对我来说反倒让我一脸懵逼,实际上CA机构才不管你什么类型的证书呢,我只管生成,至于你是用作服务端还是客户端还是什么的,那是你自己去配置,只不过一般情况下我们会根据使用场景生成的证书,会命名成服务端证书和客户端证书之类的。
接下来我们来看看这些证书在tls握手中怎么被使用的。
注:CA是个机构,该机构才能签发证书,根证书可以看做是CA的身份证明,但是我们在接下来的叙述中为了方便,就说成是根证书签发数字证书。
2,tls的握手
关于tlls握手的原理强烈推荐这个博客:https://baijiahao.baidu.com/s?id=1616211978225668389&wfr=spider&for=pc
简述之:
1,客-->服:客户端打招呼,我要访问https:服务器
2,服-->客:服务器把自己的数字证书(公钥)发给客户端
[如果使能了客户端认证]服务器端还会向客户端发请求,告知想要客户的证书
《《《此时客户端拿到了服务端的公钥,如果使能了"跳过证书认证"则就这么着了,否则还要用根证书对该证书进行校验》》》
3,客-->服[如果服务端有请求证书]:客户端同样把自己的数字证书(公钥)发给服务器端
《《《此时服务端拿到了客户端的公钥,然后用根证书对该证书进行校验》》》
小结:在这里面涉及到的证书及关系为:服务器端的数字证书(对)以及签发该证书的根证书;客户端的数字证书(对)以及签发该证书的根证书;
所以当一个app作为服务器的时候,它必须要准备好自己的证书(对)和 客户端使用的根证书
当客户端访问的时候,客户端也必须要准备自己的证书(对) 和 服务器端使用的根证书
好了,讲解到这里,我们去研究下kube-apiserver中是怎么配置这些的,就变得很容易了。
三,api server上有关证书的配置
0, tls协议使用的证书
因为认证部门需要证书,所以这里先单独说一下tls证书
--tls-cert-file=/run/ssl/server.pem
--tls-private-key-file=/run/ssl/server-key.pem
前面tls握手的时候有说,作为服务器端,必须要要准备好自己的证书(对),所以这两个参数就是指定了证书的路径。但是也可以不指定,缺省情况下会自动生成一对证书,因为这是https协议最基本的要求,你配不配置我都要有的。
自动生成的证书(对)缺省位于: 容器方式安装:位于容器的/run/kubernetes目录下,
主机直接安装,位于主机的/var/run/kubernetes目录下
当然可以用--cert-dir参数变更,以下我的环境,为容器方式安装:
# pwd
/run/kubernetes
# ls
apiserver.crt apiserver.key
1,认证方式一:双向认证
其实说到这里,我们一直没有提是怎么实现api server中三大控制的,接下来我们说的就是认证中的 双向认证:Client Certificates 的使能。
--client-ca-file
这个参数的含义是指定客户端使用的根证书的路径。一旦设置了,那么你在访问api的时候一定得带上使用该根证书签发的公钥/私钥对,例如:
//启动时,指定客户端的根证书位于容器的/run/ssl/client目录下,对应host的/etc/kubernetes/apiserver/client目录下
docker run -d --name=apiserver --net=host \
-v /etc/kubernetes/apiserver:/run/ssl \
k8s.gcr.io/kube-apiserver:v1.13.6-beta..39_ddd2add0dd3dbc \
kube-apiserver \
--insecure-bind-address=0.0.0.0 \
--service-cluster-ip-range=11.0.0.0/ \
--client-ca-file=/run/ssl/client/ca.pem \
--etcd-servers=http://localhost:2379
//那么这里配置的证书和私钥,就要和启动时配置的根证书有关了,他们正是我用cfssl工具生成的一组证书,成套的....另外 -k 表示我跳过对服务端的证书检查,详见"tls的握手"章节
[root@master apiserver]# curl -k https://188.x.x.113:6443 --cert /etc/kubernetes/client/client.pem --key /etc/kubernetes/client/client-key.pem
{
"paths": [
"/api",
"/api/v1"
...
2,认证方式二:Base认证
所谓base认证,很好理解:我先在服务器系统中写个名单,上面列一堆:用户名,密码,客户端访问的时候要带着用户名和密码,服务器一检查,是我名单里的,即通过认证,具体配置方式如下:
--basic-auth-file
用这个参数指定名单的路径
#vi basic_auth_file.csv
admin,admin,
wxy,wxy,2
#docker run -d --name=apiserver --net=host \
-v /etc/kubernetes/apiserver:/run/ssl \
k8s.gcr.io/kube-apiserver:v1.13.6-beta.0.39_ddd2add0dd3dbc \
kube-apiserver \
--insecure-bind-address=0.0.0.0 \
--service-cluster-ip-range=11.0.0.0/16 \
--basic-auth-file=/run/ssl/basic_auth_file.csv \
--etcd-servers=http://localhost:2379
#kubectl --server="https://localhost:6443" --insecure-skip-tls-verify=true --username="admin" --password="admin" get pods
3,认证方式三:token认证
在下一节中有用到
附【坑】k8s的官网上说:
Authentication modules include Client Certificates, Password, and Plain Tokens, Bootstrap Tokens, and JWT Tokens (used for service accounts).
Multiple authentication modules can be specified, in which case each one is tried in sequence, until one of them succeeds.
--basic-auth-file string
If set, the file that will be used to admit requests to the secure port of the API server via http basic authentication.
--client-ca-file string
If set, any request presenting a client certificate signed by one of the authorities in the client-ca-file is authenticated with an identity corresponding to the CommonName of the client certificate.
所以我以为各种认证模块是通过配置开启的,当我没有配置client-ca-file和basic-auth-file时,我就是没有开启认证,所以我用如下命令访问不应该报错的:
[root@master ~]# curl -k https://188.x.x.113:6443
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
但实际的验证的结果是:你在部署你的集群是,至少满足一种认证方式。我使用的kube-apiserver的版本是kubernetes v1.13.5的自己编译。如果这里我理解有误,一定告诉我,谢谢!
三,kube-controller-manager上有关证书的配置&service account
前面说了,kube-apiserver对于不是集群组件,一般暴露的是Secure Port,即使用带有认证的https。那么除了自然人通过curl或者kubectl这种要带着证书或者账号密码或者token外,pod也想访问kube-apiserver怎么办?它怎么携带证书呢?
答:集群为每个namespace指定一个 service account ,叫做服务账号。你可以把它想象成一个名叫"default"的人的账号,pod就是以这个身份去访问api的。具体实现如下:
1,在启动kube-controller-manager时指定如下参数
--service-account-private-key-file
该参数表示的含义是私钥的路径,它的作用是给服务账号产生token,之后pod就可以拿着这个token去访问api server了。
--root-ca-file
该参数会给服务账号一个根证书ca.crt,可选配置,如果配置成给api server签发证书的那个根证书,那就可以拿来用于认证api server。
docker run -d --name=cm --net=host \
-v /etc/kubernetes/apiserver:/run/ssl \
k8s.gcr.io/kube-controller-manager:v1.13.6-beta..39_ddd2add0dd3dbc \
kube-controller-manager \
--master=0.0.0.0: \
--service-account-private-key-file=/run/ssl/server-key.pem \
--root-ca-file=/run/ssl/ca.pem
2,在启动kube-apiserver时配置
--service-account-key-file
该参数表示的含义是公钥的路径,它与上面的--service-account-private-key-file是对应关系,因为pod带着token去访问api server,则api server要能解密才行啊,所以同时还需要在api那里配置当然你如果不配置,不影响pod创建,只不过你在pod里访问api的时候就不行了。
docker run -d --name=apiserver --net=host \
-v /etc/kubernetes/apiserver:/run/ssl \
k8s.gcr.io/kube-apiserver:v1.13.6-beta..39_ddd2add0dd3dbc \
kube-apiserver \
--insecure-bind-address=0.0.0.0 \
--service-cluster-ip-range=11.0.0.0/ \
--service-account-key-file=/run/ssl/server.pem \
--etcd-servers=http://localhost:2379
3,启动后,会在各个namespace下生成一个secret
[root@master ~]# kubectl get secret --all-namespaces
NAMESPACE NAME TYPE DATA AGE
default default-token-x221b kubernetes.io/service-account-token 59m
kube-public default-token-zx79k kubernetes.io/service-account-token 3d3h
kube-system default-token-9fbtm kubernetes.io/service-account-token 3d3h
4,此时创建pod,可以看到pod把secret的内容挂载到了自己的/var/run/secrets/kubernetes.io/serviceaccount目录下
[root@master ~]# kubectl create -f centos.yaml
pod/myapp-centos created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-centos / Running 6s
[root@master ~]# kubectl get pods myapp-centos -oyaml
...
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-x22lb
readOnly: true
...
volumes:
- name: default-token-x22lb
secret:
defaultMode:
secretName: default-token-x22lb [root@master ~]# kubectl exec -ti myapp-centos /bin/sh
sh-4.2# ls /var/run/secrets/kubernetes.io/serviceaccount
sh-4.2# ls
ca.crt namespace token
5,实操验证,带着生成的token可以访问api了
[root@master ~]# kubectl exec -ti myapp-centos /bin/sh
sh-4.2# cd /var/run/secrets/kubernetes.io/serviceaccount/
sh-4.2# token=$(cat ./token)
sh-4.2# curl https://188.131.210.113:6443 --header "Authorization: Bearer $token" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
{
"paths": [
"/api",
"/api/v1"...
结束:
认证这块之前一直不敢碰,感觉好难,但是一路走下来突然发现好像也没什么,总结起来就是:
1,https使用的tls协议,其实就是常说的非对称加密算法的应用,说到加密就得用加密物料,于是要明白数字证书的概念
2,数字证书,根据字面意思他就是一个证书,由第三方大家都认可的机构:CA盖章颁发,证书上面有公钥和CA签名。其存在的价值是保证上面的公钥是官方有效的。
同时CA机构还有一个根证书,也叫CA证书,用来验证数字证书的真伪。每一个人都要去CA那里把根证书提前下载到自己的系统里,以备使用。
3,说到公钥,就不得不提非对称加密算法的原理:
每个人都有一对钥匙:公钥和私钥,公钥加密的数据只能被私钥解密,私钥加密的数据只能被公钥解密;
私钥自己留着,公钥用数字证书的方式可以发给任何人;
于是,这个巧妙的原理就实现了非对称加密算法;
水鬼子:不知道为什么,我就是特别喜欢这个原理,感觉很简单又很有巧思,像按压笔一样,我觉得真是人类伟大的发明。
4,说了这么多都是为访问api server服务,就是说任何请求都不能随随便便请求我,总得带上你的身份证明,是我认可的才行;
所以,api还是manage组件的各项和证书相关的配置就出现了
-------------------------------番外篇------------------------------------------------------------------------------------------------------------------------------------------
1,借一位网友的疑问所作的一个小结
问题:
. pods的证书和controller-manager有啥关系,为啥要配置到controller-manager上 . kubernetes又是如何使用使用controller-manager上的service-account-private-key-file去生成token的 . 这个用service-account-private-key-file生成的token,apiserver又是如何验证的?
回答:
以上问题从根本上可以归结为一个问题:pod拿什么和apiserver通信?
答:拿证书去通信; 证书哪里来?
从cm那里来,cm会给创建的pod里塞进一个token文件,具体这块我没看cm和kubelet的代码,不知道是cm生成好了token交给kubelet然后kubelet塞给pod,还是kubelet自己拿着秘钥生成的,我觉得应该是前者,反正以上结论是我实验得来的,没有理论支撑,待后续...
然后如果pod想访问apiserver,就拿着这个token去; apiserver怎么就认了?
因为apiserver配置了service-account-key-file参数,即指定了公钥的位置,收到pod的token后就拿这个公钥去认证!
水鬼子: 其实我觉得这个问题特别好,因为我就常常有类似的疑惑,当我们对一个知识还是似懂非懂时,看似简单的若干问题其实都能归结到一个本质!
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
》》》》》》》》》》》》》》》》》》》》END《《《《《《《《《《《《《《《《《《《《《《《《
【爬坑系列】之解读kubernetes的认证原理&实践的更多相关文章
- 【爬坑系列】之kubernetes环境搭建:二进制安装与镜像安装
准备: 网上教如何编译与安装kubernetes的教程很多,需要提前准备的也很多,比如关闭selinux,防火墙啦....但有一点一定要注意,编译kubernetes源码时要求有2G内存,这个可是实打 ...
- 【爬坑系列】之vxlan网络实现
linux 内核从3.7之后就内部集成了vxlan功能,所以可以使用linux内核提供的vxlan功能,经过配置创建vxlan网络. 而从Docker自Docker Engine 1.9之后,就自带o ...
- 【爬坑系列】之docker的overlay网络配置(未完,待续)
理论知识储备: 想了解vxlan网络的知识:https://www.cnblogs.com/shuiguizi/p/10923841.html 想了解docker网络的原理知识:https://www ...
- ssh登录,爬坑系列
最近在实验室弄ssh登录,结果被虐了,要注意以下: 1.主机名不能包括 - _ ! 等非法字符. 2.如果hadoop格式化时,报:“SHUTDOWN_MSG: Shutting ...
- 爬坑系列----Redis查询key报空指针异常,而redis中确实存在该key
现象: 1.在A方法中根据key查询一个list,可以获取到相应的值 2.在B方法中同样调用此方法,传入相同的key,查询不到值,为null,报空指针异常 起初我也一脸懵逼,到现在虽然解决了,还是不知 ...
- SpringBoot爬坑系列
1.日志篇 现象 由于日志配置采用原来SpringMVC项目中的log4j.properties 文件,日志采用springboot自带的jar包会出现打印不出日志的情况. 解决 引入原日志包 < ...
- 多线程爬坑之路-ThreadLocal源码及原理的深入分析
ThreadLocal<T>类:以空间换时间提供一种多线程更快捷访问变量的方式.这种方式不存在竞争,所以也不存在并发的安全性问题. This class provides thread-l ...
- 微信小程序爬坑日记
新公司上手小程序.30天,从入门到现在,还没放弃... 虽然小程序发布出来快一年了,爬坑的兄弟们大多把坑都踩平了.而我一直停留在"Hello World"的学习阶段.一来没项目,只 ...
- 解读 kubernetes client-go 官方 examples - Part Ⅰ
目录 1. 介绍 2. 运行测试 2.1 测试环境 2.2 运行结果 3. 原理解析 3.1 获取 kubeconfig 信息,并构造 rest#Config 实例 3.1.1 tools/clien ...
随机推荐
- CodeForces 582A【multiset使用样例】
题意: 给一些无序的数字,求解一个矩阵,使得矩阵的每一个元素都是行和列标志数的gcd,输出行标志数. 首先对数字进行排序.复杂度n*log(n^2). 这题的证明有官方的英文题解==在这直接贴英文题解 ...
- 如何解决XML文件中的警告提示“No grammar constraints (DTD or XML Schema) referenced in the document.”
解决方法:加上 <!DOCTYPE xml> <?xml version="1.0" encoding="UTF-8"?> <!D ...
- 地球Gauss_Kruger中央0度经线图
- sendEmail实现邮件报警发送
安装wget http://caspian.dotconf.net/menu/Software/SendEmail/sendEmail-v1.56.tar.gz tar -xf sendEmail-v ...
- 从日志文件解决ArcGIS Server性能低下问题的步骤(1)
日志级别和结构 http://www.cnblogs.com/fortoday/archive/2011/03/30/2000348.html ArcGIS Server日志文件分为几个记录级别: 无 ...
- js中的自定义异常处理函数
1. Can I suppress JavaScript error messages? 2. Can I set up my own JavaScript error handler? 3. Can ...
- BZOJ 1091([SCOI2003]分割多边形-分割直线)
1091: [SCOI2003]分割多边形 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 223 Solved: 82 [Submit][id=10 ...
- Zookeeper 简单操作
1. 连接到zookeeper服务 [java2000_wl@localhost zookeeper-3]$ bin/zkCli.sh -server 127.0.0.1:2181 也可以连接远端的 ...
- D广搜
<span style="color:#330099;">/* D - 广搜 基础 Time Limit:1000MS Memory Limit:30000KB 64b ...
- instancetype VS id
英文好的直接读下面链接的文章就好了: http://stackoverflow.com/questions/8972221/would-it-be-beneficial-to-begin-using- ...