文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247483787&idx=1&sn=08dd3404ccba0bca58624cd7dc55757a&chksm=e9fdd47fde8a5d6942768bbadf68bd0803659f13500f124045354d4b5d78813ad215164e2218&scene=178&cur_album_id=1341273083637989377#rd

本文中讲的是有关kubernetes 1.17.0 二进制安装过程中安全证书相关的知识点,这里需要很强的专业性

PKI基础概念

什么是PKI?

公开密钥基础建设(英语:Public Key Infrastructure,缩写:PKI),又称公开密钥基础架构、公钥基础建设、公钥基础设施、公开密码匙基础建设或公钥基础架构,是一组由硬件、软件、参与者、管理政策与流程组成的基础架构,其目的在于创造、管理、分配、使用、存储以及撤销数字证书。(节选维基百科)

PKI是借助CA(权威数字证书颁发/认证机构)将用户的个人身份跟公开密钥链接在一起,它能够确保每个用户身份的唯一性,这种链接关系是通过注册和发布过程实现,并且根据担保级别,链接关系可能由CA和各种软件或在人为监督下完成。PKI用来确定链接关系的这一角色称为RA(Registration Authority, 注册管理中心),RA能够确保公开密钥和个人身份链接,可以防抵赖,防篡改。在微软的公钥基础建设下,RA又被称为CA,目前大多数称为CA。

PKI组成要素

从上面可以得知PKI的几个主要组成要素,用户(使用PKI的人或机构),认证机构(CA,颁发证书的人或机构),仓库(保存证书的数据库)等。

非对称加密

本文提到的密钥均为非对称加密,有公钥和私钥之分,并且他们总是成对出现,它们的特点就是其中一个加密的数据,只能使用另一个解密,即使它本身也无法解密,也就是说公钥加密的,私钥可以解密,私钥加密的,公钥可以解密。

证书签名请求CSR

它是向CA机构申请数字证书时使用的请求文件,这里的CSR不是证书,而向权威证书颁发机构获得签名证书的申请,当CA机构颁发的证书过期时,你可以使用相同的CSR来申请新的证书,此时key不变。

数字签名

数字签名就是“非对称加密+摘要算法”,其目的不是为了加密,而是为了防抵赖或者他们篡改数据。其核心思想是:比如A要给B发送数据,A先用摘要算法得到数据的指纹,然后用A的私钥加密指纹,加密后的指纹就是A的签名,B收到数据和A的签名后,也用同样的摘要算法计算指纹,然后用A公开的公钥解密签名,比较两个指纹,如果相同,说明数据没有被篡改,确实是A发过来的数据。假设C想改A发给B的数据来欺骗B,因为篡改数据后指纹会变,要想跟A的签名里面的指纹一致,就得改签名,但由于没有A的私钥,所以改不了,如果C用自己的私钥生成一个新的签名,B收到数据后用A的公钥根本就解不开。(来源于网络)

数字证书格式

数字证书格式有很多,比如.pem,.cer或者.crt等。

PKI工作流程

下图来源于网络,上半部分最右边就是CA机构,可以颁发证书。证书订阅人,首先去申请一个证书,为了申请这个证书,需要去登记,告诉它,我是谁,我属于哪个组织,到了登记机构,再通过CSR,发送给CA中心,CA中心通过验证通过之后 ,会颁发一对公钥和私钥,并且公钥会在CA中心存一份;证书订阅人拿到证书以后,部署在服务器;

当用户访问我们的web服务器时,它会请求我们的证书,服务器会把公钥发送给我们的客户端,客户端会去验证我们证书的合法性,客户端是如何验证证书是否有效呢?CA中心会把过期证书放在CRL服务器上面 ,这个CRL服务会把所有过期的证书形成一条链条,所以他的性能非常的差,所以又推出了OCSP程序,OCSP可以就一个证书进行查询,它是否过期,浏览器可以直接去查询OCSP响应程序,但OCSP响应程序效率还不是很高,最终往往我们会把web服务器如nginx有一个ocsp开关,当我们打开这个开关以后,会有nginx服务器主动的去ocsp服务器去查询,这样大量的客户端直接从web服务器就可以直接获取到证书是否有效。

CFSSL介绍

CFSSL是什么?

cfssl是使用go编写,由CloudFlare开源的一款PKI/TLS工具。主要程序有cfssl,是CFSSL的命令行工具,cfssljson用来从cfssl程序获取JSON输出,并将证书,密钥,CSR和bundle写入文件中。

CFSSL安装

#!/bin/bash

# download cfssl tools
while true;
do
echo "Download cfssl, please wait a monment." &&\
curl -L -C - -O https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 && \
curl -L -C - -O https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 && \
curl -L -C - -O https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
if [ $? -eq 0 ];then
echo "cfssl download success."
break
else
echo "cfssl download failed."
break
fi
done # Whether the bin directory exists.
if [ ! -d /data/k8s/bin/ ];then
mkdir -p /data/k8s/bin/
fi # Copy from current directory to bin directory
mv cfssl_linux-amd64 /data/k8s/bin/cfssl
mv cfssljson_linux-amd64 /data/k8s/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /data/k8s/bin/cfssl-certinfo
chmod +x /data/k8s/bin/{cfssl,cfssljson,cfssl-certinfo} # add environment variables
[ $(cat /etc/profile|grep 'PATH=/data/k8s/bin'|wc -l ) -eq 0 ] && echo 'PATH=/data/k8s/bin:$PATH' >>/etc/profile && source /etc/profile || source /etc/profile

创建认证中心(根CA中心)

由于kubernetes各组件需要使用x509证书对通信进行加密和认证,所以需要创建一套CA(Certificate Autority),是自签名的根证书,用来签名后续需要创建的其它证书;

这里创建的CA是一个私有的内部认证中心,这个认证中心也需要一个CA证书和相应的CA私钥,CA私钥需要妥善保管,任何拥有它的人,都可以充当CA颁发证书。

创建请求证书的json配置文件

再次强调一下,CA证书的请求json文件是集群所有节点共享的,只需要创建一个,它后续创建的所有其它子CA证书的基础,子CA证书都会根据这里config中的profile段来生成证书的相关信息;

以下命令可以创建一个CA证书的请求json的默认生成方式,大家可以在此基础上面修改,也可以自行创建;

cfssl print-defaults config > ca-config.json

我们这里采用自行创建的方式 如下

#!/bin/bash
CA_SSL=/data/k8s/work
cat > ${CA_SSL}/ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF

ca-config.json 这个配置文件只是告诉我们颁发有什么功能的证书,它用于配置证书的使用场景(profile)和具体参数(usage、过期时间、服务端认证、客户端认证、加密等)。

default是默认策略,指定证书默认有效期是10年;

profiles是定义使用场景,这里只是kubernetes,其实可以定义多个场景,分别指定不同的过期时间,使用场景等参数,后续签名证书时使用某个profile;

signing: 表示该证书可用于签名其它证书,生成的ca.pem证书中的CA=TRUE;

server auth: 表示client 可以用该CA 对server 提供的证书进行校验;

client auth: 表示server 可以用该CA 对client 提供的证书进行验证。

创建根CA证书签名请求文件

以下命令可以创建一个CSR默认证书签名请求文件,大家可以在此基础上面修改,也可以自行创建;

cfssl print-defaults csr > ca-csr.json

我们这里采用自行创建的方式 如下

#!/bin/bash
CA_SSL=/data/k8s/work
cat > ${CA_SSL}/ca-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing",
"O": "k8s",
"OU": "System"
}
]
}
EOF

生成CA证书和私钥ca.pem, ca-key.pem

[root@master01 work]# cd /data/k8s/work
[root@master01 work]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
[root@master01 work]# ls -l ca*
-rw-r--r-- 1 root root 294 Dec 26 20:42 ca-config.json
-rw-r--r-- 1 root root 1001 Dec 26 20:54 ca.csr
-rw-r--r-- 1 root root 263 Dec 26 20:41 ca-csr.json
-rw------- 1 root root 1675 Dec 26 20:54 ca-key.pem
-rw-r--r-- 1 root root 1359 Dec 26 20:54 ca.pem
[root@master01 work]#

分发CA证书到Etcd服务器及k8s节点

这里说明一下,只需要分发下ca.pem公钥即可,ca-key.pem是私钥,很多组件不需要,除非你确保使用它,你才分发到服务器上面,以免造成私钥泄露。

#!/bin/bash

cd /data/k8s/work
source /data/k8s/bin/env.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "mkdir -p /etc/kubernetes/cert"
scp ca*.pem ca-config.json root@${node_ip}:/etc/kubernetes/cert
done for node_ip in ${ETCD_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "mkdir -p /etc/kubernetes/cert"
scp ca.pem ca-config.json root@${node_ip}:/etc/kubernetes/cert
done

自签名CA根证书总结

kubernetes证书

手动搭建kubernetes 1.17.0时,为了安全性考虑,我们上面创建了根CA,接下来,我们创建kubernetes的所依赖的证书文件,方便后续使用;

依赖证书

根据公司需求,个人意愿,例如flannel也可以不使用专用证书,完全自愿,本文档以下组件安装时会使用各自专用证书。

使用自签名证书生成子证书方式

gencert: 生成新的key(密钥)和签名证书
-initca:初始化一个新ca
-ca:指明ca的证书
-ca-key:指明ca的私钥文件
-config:指明请求证书的json文件
-profile:与-config中的profile对应,是指根据config中的profile段来生成证书的相关信息

etcd证书生成

创建Etcd证书签名请求文件

#!/bin/bash

source /etc/profile
ETCD_SSL="/data/k8s/work" [ ! -d ${ETCD_SSL} ] && mkdir ${ETCD_SSL}
cat >$ETCD_SSL/etcd-csr.json << EOF
{
"CN": "etcd",
"hosts": [
"127.0.0.1",
"192.168.16.101",
"192.168.16.102",
"192.168.16.103",
"etcd01.k8s.vip",
"etcd02.k8s.vip",
"etcd03.k8s.vip"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing",
"O": "k8s",
"OU": "System"
}
]
}
EOF

使用自签名证书生成Etcd证书和私钥

[root@master01 work]# cd /data/k8s/work
[root@master01 work]# cfssl gencert -ca=/data/k8s/work/ca.pem \
-ca-key=/data/k8s/work/ca-key.pem \
-config=/data/k8s/work/ca-config.json \
-profile=kubernetes etcd-csr.json | cfssljson -bare etcd
[root@master01 work]# ls -l etcd*
-rw-r--r-- 1 root root 1127 Dec 27 10:32 etcd.csr
-rw-r--r-- 1 root root 423 Dec 27 10:32 etcd-csr.json
-rw------- 1 root root 1679 Dec 27 10:32 etcd-key.pem
-rw-r--r-- 1 root root 1501 Dec 27 10:32 etcd.pem
[root@master01 work]#

证书分发到Etcd服务器

#!/bin/bash
source /data/k8s/bin/env.sh
cd /data/k8s/work/
for node_ip in ${ETCD_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "mkdir -p /etc/etcd/cert"
scp etcd*.pem root@${node_ip}:/etc/etcd/cert
done

生成Etcd证书总结

kube-apiserver证书生成

创建kubernetes证书签名请求文件

这里hosts只需要把master节点及VIP地址包含进来即可。

#!/bin/bash

cd /data/k8s/work
source /data/k8s/bin/env.sh cat > kubernetes-csr.json << EOF
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"192.168.16.104",
"192.168.16.105",
"192.168.16.106",
"192.168.16.253",
"master01.k8s.vip",
"master02.k8s.vip",
"master03.k8s.vip",
"api.k8s.vip",
"10.254.0.1",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local."
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing",
"O": "k8s",
"OU": "System"
}
]
} EOF

使用自签名证书生成kubernetes证书和私钥

#!/bin/bash
[root@master01 work] cd /data/k8s/work
[root@master01 work] source /data/k8s/bin/env.sh
[root@master01 work] cfssl gencert -ca=/data/k8s/work/ca.pem \
-ca-key=/data/k8s/work/ca-key.pem \
-config=/data/k8s/work/ca-config.json \
-profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
[root@master01 work]# ls -l kubernetes*
-rw-r--r-- 1 root root 1362 Dec 27 14:18 kubernetes.csr
-rw-r--r-- 1 root root 607 Dec 27 14:17 kubernetes-csr.json
-rw------- 1 root root 1679 Dec 27 14:18 kubernetes-key.pem
-rw-r--r-- 1 root root 1728 Dec 27 14:18 kubernetes.pem
[root@master01 work]#

证书分发到kubernetes所有集群服务器

cd /data/k8s/work
source /data/k8s/bin/env.sh
for node_ip in ${MASTER_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "mkdir -p /etc/kubernetes/cert"
scp kubernetes*.pem root@${node_ip}:/etc/kubernetes/cert/
done

生成kubernetes证书总结

kube-controller-manager证书生成

创建kube-controller-manager证书签名请求文件

#!/bin/bash
cd /data/k8s/work
cat > kube-controller-manager-csr.json <<EOF
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
"127.0.0.1",
"192.168.16.104",
"192.168.16.105",
"192.168.16.106",
"192.168.16.253",
"master01.k8s.vip",
"master02.k8s.vip",
"master03.k8s.vip",
"api.k8s.vip"
],
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:kube-controller-manager",
"OU": "System"
}
]
}
EOF

使用自签名证书生成kube-controller-manager证书和私钥

[root@master01 work]# cd /data/k8s/work
[root@master01 work]# cfssl gencert -ca=/data/k8s/work/ca.pem \
-ca-key=/data/k8s/work/ca-key.pem \
-config=/data/k8s/work/ca-config.json \
-profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager [root@master01 work]# ls -l kube-controller-manager*
-rw-r--r-- 1 root root 1216 Dec 28 20:40 kube-controller-manager.csr
-rw-r--r-- 1 root root 485 Dec 28 20:39 kube-controller-manager-csr.json
-rw------- 1 root root 1675 Dec 28 20:40 kube-controller-manager-key.pem
-rw-r--r-- 1 root root 1590 Dec 28 20:40 kube-controller-manager.pem
[root@master01 work]#

证书分发到master服务器

#!/bin/bash
cd /data/k8s/work
source /data/k8s/bin/env.sh
for node_ip in ${MASTER_IPS[@]}
do
echo ">>> ${node_ip}"
scp kube-controller-manager*.pem root@${node_ip}:/etc/kubernetes/cert/
done

生成kube-controller-manager证书总结

kube-scheduler证书生成

创建kube-scheduler证书签名请求文件

#!/bin/bash
cd /data/k8s/work
cat > kube-scheduler-csr.json <<EOF
{
"CN": "system:kube-scheduler",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
"127.0.0.1",
"192.168.16.104",
"192.168.16.104",
"192.168.16.104",
"192.168.16.253",
"master01.k8s.vip",
"master02.k8s.vip",
"master03.k8s.vip",
"api.k8s.vip"
],
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:system:kube-scheduler",
"OU": "System"
}
]
}
EOF

使用自签名证书生成kube-scheduler证书和私钥

[root@master01 work]# cd /data/k8s/work
[root@master01 work]# cfssl gencert -ca=/data/k8s/work/ca.pem \
-ca-key=/data/k8s/work/ca-key.pem \
-config=/data/k8s/work/ca-config.json \
-profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
[root@master01 work]# ls -l kube-scheduler*
-rw-r--r-- 1 root root 1204 Dec 28 21:45 kube-scheduler.csr
-rw-r--r-- 1 root root 474 Dec 28 21:44 kube-scheduler-csr.json
-rw------- 1 root root 1679 Dec 28 21:45 kube-scheduler-key.pem
-rw-r--r-- 1 root root 1574 Dec 28 21:45 kube-scheduler.pem
[root@master01 work]#

证书分发到master服务器

#!/bin/bash
cd /data/k8s/work
source /data/k8s/bin/env.sh
for node_ip in ${MASTER_IPS[@]}
do
echo ">>> ${node_ip}"
scp kube-scheduler*.pem root@${node_ip}:/etc/kubernetes/cert/
done

生成kube-scheduler证书总结

kubectl证书生成

创建admin证书签名请求文件

#!/bin/bash
cd /data/k8s/work
cat > admin-csr.json <<EOF
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "System"
}
]
}
EOF

使用自签名证书生成admin证书和私钥

[root@master01 work]# cd /data/k8s/work
[root@master01 work]# cfssl gencert -ca=/data/k8s/work/ca.pem \
-ca-key=/data/k8s/work/ca-key.pem \
-config=/data/k8s/work/ca-config.json \
-profile=kubernetes admin-csr.json | cfssljson -bare admin
[root@master01 work]# ls -l admin*
-rw-r--r-- 1 root root 1009 Dec 28 20:20 admin.csr
-rw-r--r-- 1 root root 229 Dec 28 20:15 admin-csr.json
-rw------- 1 root root 1675 Dec 28 20:20 admin-key.pem
-rw-r--r-- 1 root root 1399 Dec 28 20:20 admin.pem
[root@master01 work]#

证书不需要分发

kubectl是作为kube-apiserver的客户端,由于kube-apiserver只开启了https,所以需要为kubectl生成访问kube-apiserver的证书,证书是用来设置客户端认证参数时使用的。

生成admin证书总结

kube-proxy证书生成

创建kube-proxy证书签名请求文件

#!/bin/bash
cd /data/k8s/work
cat > kube-proxy-csr.json <<EOF
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF

使用自签名证书生成kube-proxy证书和私钥

[root@master01 work]# cd /data/k8s/work
[root@master01 work]# cfssl gencert -ca=/data/k8s/work/ca.pem \
-ca-key=/data/k8s/work/ca-key.pem \
-config=/data/k8s/work/ca-config.json \
-profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
[root@master01 work]# ls -lrth kube-proxy*
-rw-r--r-- 1 root root 215 Dec 29 19:09 kube-proxy-csr.json
-rw-r--r-- 1 root root 1.4K Dec 29 19:10 kube-proxy.pem
-rw------- 1 root root 1.7K Dec 29 19:10 kube-proxy-key.pem
-rw-r--r-- 1 root root 1009 Dec 29 19:10 kube-proxy.csr
[root@master01 work]#

证书不需要分发

kube-proxy作为kube-apiserver的客户端,访问时需要认证授权,这里作为kubelet设置客户端访问上下文配置文件参数,然后形成kube-proxy启动时配置文件使用。

生成kube-proxy证书总结

flanneld证书生成

创建flanneld证书签名请求文件

#!/bin/bash
cd /data/k8s/work
cat > flanneld-csr.json <<EOF
{
"CN": "flanneld",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF

使用自签名证书生成flanneld证书和私钥

[root@master01 work]# cfssl gencert -ca=/data/k8s/work/ca.pem \
-ca-key=/data/k8s/work/ca-key.pem \
-config=/data/k8s/work/ca-config.json \
-profile=kubernetes flanneld-csr.json | cfssljson -bare flanneld
[root@master01 work]# ls -l flanneld*
-rw-r--r-- 1 root root 997 Dec 28 22:17 flanneld.csr
-rw-r--r-- 1 root root 221 Dec 28 22:16 flanneld-csr.json
-rw------- 1 root root 1675 Dec 28 22:17 flanneld-key.pem
-rw-r--r-- 1 root root 1391 Dec 28 22:17 flanneld.pem
[root@master01 work]#

证书分发到运行Pod的服务器

cd /data/k8s/work
source /data/k8s/bin/env.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "mkdir -p /etc/flanneld/cert"
scp flanneld*.pem root@${node_ip}:/etc/flanneld/cert
done

生成flannel证书总结

访问Metric-server时需要证书

创建访问metric-server证书签名请求文件

#!/bin/bash
cd /data/k8s/work
source /data/k8s/bin/env.sh
cat > proxy-client-csr.json <<EOF
{
"CN": "aggregator",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF

使用自签名证书生成访问metric-server证书和私钥

[root@master01 work]# cfssl gencert -ca=/etc/kubernetes/cert/ca.pem \
-ca-key=/etc/kubernetes/cert/ca-key.pem \
-config=/etc/kubernetes/cert/ca-config.json \
-profile=kubernetes proxy-client-csr.json | cfssljson -bare proxy-client
[root@master01 work]# ls -l proxy*
-rw-r--r-- 1 root root 1005 Dec 28 19:22 proxy-client.csr
-rw-r--r-- 1 root root 226 Dec 28 19:21 proxy-client-csr.json
-rw------- 1 root root 1675 Dec 28 19:22 proxy-client-key.pem
-rw-r--r-- 1 root root 1395 Dec 28 19:22 proxy-client.pem
[root@master01 work]#

证书分发到所有master服务器

#!/bin/bash
source /data/k8s/bin/env.sh
for node_ip in ${MASTER_IPS[@]}
do
echo ">>> ${node_ip}"
scp proxy-client*.pem root@${node_ip}:/etc/kubernetes/cert/
done

生成访问metric-server证书总结

总结

从公钥基础设施、讲到cfssl工具、再到kubernetes的证书生成,本文较长,如果各位已经知道如何生成证书,此章节可以快速过一下即可,并且本文中为每个组件生成了自己专属证书,这个也是看公司需求.

最新文章

  1. Excel转Html
  2. [Shell] 文件名截取的问题:bash .vs. csh
  3. Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition
  4. Cocos2d-x游戏开发之计时器
  5. 动态调用wcf接口服务
  6. 【现代程序设计】【homework-07】
  7. 一些web编程能用到的小知识
  8. js中apply和call的用法 以及apply的妙用 (来自网络)
  9. 【转】sublime text 2 中文乱码解决办法
  10. cocos2dx vs2010打开打印窗口
  11. iOS 枚举 初体验
  12. CSS3 三次贝塞尔曲线(cubic-bezier)
  13. BZOJ2028: [SHOI2009]会场预约(set)
  14. ESP8266基础篇
  15. LeetCode - 排列相关题目
  16. 5.C#释放非托管资源1
  17. Django中HtttpRequest请求
  18. DataStructure.BloomFilter
  19. 12_python_生成器
  20. ASP.NET C# List分页

热门文章

  1. REST 表现层状态转化
  2. 选择结构-扩展if-else语句和练习用if语句实现考试成绩划分
  3. Redis三种模式——主从复制,哨兵模式,集群
  4. shell脚本语句
  5. 【每天学一点-01】 在SpringBoot项目中使用Swagger2
  6. PostgreSQL定时备份
  7. 并发编程原理学习-reentrantlock源码分析
  8. SDK和API的直接区别
  9. [原创] RestartPC64-中文版v1.0.0.9
  10. ETCD快速入门-03 常用命令