02 二进制搭建 Kubernetes集群


单master集群搭建

系统初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
关闭防火墙:
systemctl stop firewalld
systemctl disable firewalld

关闭selinux:
setenforce 0 # 临时
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久

关闭swap:
swapoff -a # 临时
vim /etc/fstab # 永久 注释掉swap那项,阿里云没有,只有ext4

同步系统时间:
# ntpdate time.windows.com

添加hosts:
# vim /etc/hosts
172.17.70.251 k8s-master1
172.17.70.252 k8s-master2
172.17.70.253 k8s-node1
172.17.70.254 k8s-node2

修改主机名:
hostnamectl set-hostname k8s-master
1
2
3
4
5
6
7
# 快速添加主机名 
cat >> /etc/hosts << EOF
172.17.70.251 k8s-master1
172.17.70.252 k8s-master2
172.17.70.253 k8s-node1
172.17.70.254 k8s-node2
EOF

etcd 集群

理解 ssl 证书

1
2
3
4
5
6
7
8
9
集群中的通信都是基于https进行交互
当前架构中,etcd之间需要https通信,k8s内部master(apiserver) 也需要通信, 需要两条证书
证书分为: 自签证书 和 权威机构颁发的证书(赛门铁克) 3000元 www.ctnrs.com 泛域名*.ctnrs.com 比较贵
根证书
自签证书 不受信任 内部服务之间 具备一定加密 内部之间程序调用不对外,可以使用
证书包括:crt(数字证书) key(私钥) 配置到web服务器
权威机构颁发的证书 https是绿色的安全的,自签是!感叹号不可信任
权威证书如果使用到k8s里,其实也不知道是否可行,因为证书里涉及到可信任的IP列表,可能有影响
https -> CA -> crt|key

生成 etcd 证书

  1. cfssl 与 openssl一样都可以生成证书
  2. cfssl 使用json文件内容生成,比较直观
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 任意一台机器 上传压缩包
[root@k8s-master1 opt]# ls -l
-rw-r--r-- 1 root root 5851667 Nov 12 16:49 TLS.tar.gz
# 解压
[root@k8s-master1 opt]# tar -zxvf TLS.tar.gz

[root@k8s-master1 TLS]# ls -l
total 18820
-rwxr-xr-x 1 root root 10376657 Oct 2 08:37 cfssl
-rwxr-xr-x 1 root root 6595195 Oct 2 08:37 cfssl-certinfo
-rwxr-xr-x 1 root root 2277873 Oct 2 08:37 cfssljson
-rwxr-xr-x 1 root root 344 Oct 3 08:26 cfssl.sh # 安装脚本 上面三个是已下载的二进制文件
drwxr-xr-x 2 root root 4096 Oct 3 10:46 etcd # etcd证书目录
drwxr-xr-x 2 root root 4096 Oct 3 10:46 k8s # k8s证书目录

cfssl 下载与安装

1
2
3
4
5
6
7
# 脚本中 含有下载地址 和 安装 
[root@k8s-master1 TLS]# cat cfssl.sh
#curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o /usr/local/bin/cfssl
#curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o /usr/local/bin/cfssljson
#curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o /usr/local/bin/cfssl-certinfo
cp -rf cfssl cfssl-certinfo cfssljson /usr/local/bin
chmod +x /usr/local/bin/cfssl*
1
2
3
4
[root@k8s-master1 TLS]# cp -rf cfssl cfssl-certinfo cfssljson /usr/local/bin
[root@k8s-master1 TLS]# chmod +x /usr/local/bin/cfssl*
[root@k8s-master1 TLS]# ls /usr/local/bin/
cfssl cfssl-certinfo cfssljson

创建 CA证书和私钥

1
2
3
4
5
6
7
[root@k8s-master1 TLS]# cd /opt/TLS/etcd/
[root@k8s-master1 etcd]# ls -l

-rw-r--r-- 1 root root 287 Oct 3 13:12 ca-config.json # 相当于CA机构
-rw-r--r-- 1 root root 209 Oct 3 13:12 ca-csr.json # CA的请求文件
-rwxr-xr-x 1 root root 178 Oct 3 13:58 generate_etcd_cert.sh # 执行脚本
-rw-r--r-- 1 root root 306 Oct 3 08:26 server-csr.json # 配置文件
1
2
3
4
5
6
# 创建 CA证书和私钥 用来颁发证书
[root@k8s-master1 etcd]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

[root@k8s-master1 etcd]# ls -l *.pem
-rw------- 1 root root 1679 Nov 12 16:58 ca-key.pem # ca私钥
-rw-r--r-- 1 root root 1265 Nov 12 16:58 ca.pem # ca证书

自签 etcd 证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# hosts 可信任IP,里面包含所有etcd节点的IP 

[root@k8s-master1 etcd]# vim server-csr.json

{
"CN": "etcd",
"hosts": [
"172.17.70.251",
"172.17.70.253",
"172.17.70.254"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing"
}
]
}
1
2
3
# 向ca请求证书
# 指定好ca的证书和私钥,配置文件,生成 server开头的证书
[root@k8s-master1 etcd]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
1
2
3
4
5
6
7
# 生成server开头的 数字证书和私钥

[root@k8s-master1 etcd]# ls -l *.pem
-rw------- 1 root root 1679 Nov 12 16:58 ca-key.pem
-rw-r--r-- 1 root root 1265 Nov 12 16:58 ca.pem
-rw------- 1 root root 1679 Nov 12 17:05 server-key.pem # crt
-rw-r--r-- 1 root root 1338 Nov 12 17:05 server.pem # key

etcd 简介

  1. CoreOS 开源
  2. etcd首先是一个键值存储仓库,用于配置共享和服务发现。
  3. etcd 负责保存 Kubernetes Cluster 的配置信息和各种资源的状态信息。当数据发生变化时,etcd 会快速地通知 Kubernetes 相关组件。
  4. 官方推荐奇数节点部署,常见的有3 5 7 分别对应 1 2 3个冗余节点
  5. 3台etcd会先选举出1台为主节点,负责写消息,主节点同步给2个从节点。
  6. 当主节点挂了,两台从节点会选举出一台新的主节点
  7. 介绍文档
1
https://blog.csdn.net/bbwangj/article/details/82584988
1
2
3
4
5
# 优点
1. 简单。使用Go语言编写部署简单;使用HTTP作为接口使用简单;
2. 使用Raft算法保证强一致性让用户易于理解。
3. 数据持久化。etcd默认数据一更新就进行持久化。
4. 安全。etcd支持SSL客户端安全认证。

部署 etcd 集群节点

1
2
3
4
# 环境
172.17.70.251 k8s-master1 etcd
172.17.70.253 k8s-node1 etcd
172.17.70.254 k8s-node2 etcd
1
2
# 二进制包下载地址
https://github.com/etcd-io/etcd/releases

安装 etcd

1
2
3
4
5
6
[root@k8s-master1 opt]# mkdir -p /opt/src
[root@k8s-master1 opt]# mv TLS.tar.gz etcd.tar.gz /opt/src/
[root@k8s-master1 src]# ls -l
total 15628
-rw-r--r-- 1 root root 10148977 Nov 12 17:12 etcd.tar.gz
-rw-r--r-- 1 root root 5851667 Nov 12 16:49 TLS.tar.gz
1
2
# 解压
[root@k8s-master1 src]# tar -zxvf etcd.tar.gz -C /opt/
1
2
3
4
5
6
[root@k8s-master1 opt]# ls -l /opt/
total 16
drwxr-xr-x 5 root root 4096 Oct 2 22:13 etcd # etcd 工作目录
-rw-r--r-- 1 root root 1078 Oct 2 23:10 etcd.service # etcd 启动服务
drwxr-xr-x 2 root root 4096 Nov 12 17:12 src
drwxr-xr-x 4 root root 4096 Oct 3 08:26 TLS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 查看启动文件 注意工作目录 
# 启动文件里面设置了etct的工作目录 /opt/etcd/bin/etcd 和 配置文件 /opt/etcd/cfg/etcd.conf
# 有2种配置证书的选项 但是使用的都是相同的一套证书
# 集群内容使用证书 peer开头3条配置选项
# 面向客户端的证书 cert-file、key-file、trusted-ca-file
[root@k8s-master1 opt]# vim etcd.service

[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=/opt/etcd/cfg/etcd.conf
ExecStart=/opt/etcd/bin/etcd \
--name=${ETCD_NAME} \
--data-dir=${ETCD_DATA_DIR} \
--listen-peer-urls=${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls=${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 \
--advertise-client-urls=${ETCD_ADVERTISE_CLIENT_URLS} \
--initial-advertise-peer-urls=${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--initial-cluster=${ETCD_INITIAL_CLUSTER} \
--initial-cluster-token=${ETCD_INITIAL_CLUSTER_TOKEN} \
--initial-cluster-state=new \
--cert-file=/opt/etcd/ssl/server.pem \
--key-file=/opt/etcd/ssl/server-key.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem \
--peer-key-file=/opt/etcd/ssl/server-key.pem \
--trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/opt/etcd/ssl/ca.pem
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
1
2
3
4
5
6
7
8
# 查看工作目录
# 更换etcd版本:可从etcd的github下载最新版本 替换bin下的二进制文件
[root@k8s-master1 opt]# cd /opt/etcd
[root@k8s-master1 etcd]# ls -l
total 12
drwxr-xr-x 2 root root 4096 Oct 2 22:13 bin # etcd 可执行文件 etcdctl 客户端
drwxr-xr-x 2 root root 4096 Oct 3 08:32 cfg # 配置文件
drwxr-xr-x 2 root root 4096 Oct 3 08:36 ssl # 证书文件 需要将 etcd 证书加入里面
1
2
3
# 先删除掉之前的证书,一会替换刚才生成的
[root@k8s-master1 etcd]# cd ssl
[root@k8s-master1 ssl]# rm -rf *

修改 etcd 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 节点之间通信 2380,面向客户端 2379 ,需要https通信 拥有证书
# 如果要重装etcd 需要清空下面的目录 ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
# 不同的etcd节点需要修改 ip

[root@k8s-master1 ssl]# cd /opt/etcd/cfg/
[root@k8s-master1 cfg]# vim etcd.conf

#[Member]
# 集群节点唯一名称 不同的etcd节点需要修改
ETCD_NAME="etcd-1"
# 数据目录
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
# etcd 集群内部通信使用的url
ETCD_LISTEN_PEER_URLS="https://172.17.70.251:2380"
# 外部客户端使用的url,外部程序连接
ETCD_LISTEN_CLIENT_URLS="https://172.17.70.251:2379"

#[Clustering]
# 给集群内其他成员访问的url,节点之间通信
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://172.17.70.251:2380"
# 外部客户端使用的url
ETCD_ADVERTISE_CLIENT_URLS="https://172.17.70.251:2379"
# 初始集群成员列表,集群节点信息 name+IP+端口
ETCD_INITIAL_CLUSTER="etcd-1=https://172.17.70.251:2380,etcd-2=https://172.17.70.253:2380,etcd-3=https://172.17.70.254:2380"
# 集群的名称认证 判断是否该集群的节点
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
# 初始集群状态,new为新建集群, 已有加入需要将其设置为"exist"。
ETCD_INITIAL_CLUSTER_STATE="new"

拷贝证书

1
2
3
4
5
6
7
# 将证书copy 到ssl目录
[root@k8s-master1 ssl]# cp /opt/TLS/etcd/{ca,server-key,server}.pem .
[root@k8s-master1 ssl]# ls -l
total 12
-rw-r--r-- 1 root root 1265 Nov 12 17:50 ca.pem
-rw------- 1 root root 1679 Nov 12 17:50 server-key.pem
-rw-r--r-- 1 root root 1338 Nov 12 17:50 server.pem

部署其他 etcd 节点

1
2
3
4
# scp分发 再修改配置文件的 ETCD_NAME 和 IP 
[root@k8s-master1 opt]# scp -r etcd root@172.17.70.253:/opt/
[root@k8s-master1 opt]# scp -r etcd root@172.17.70.254:/opt/
# 千万别忘记修改配置文件

拷贝启动服务文件

1
2
3
4
# 本机的别忘记了 
[root@k8s-master1 opt]# scp etcd.service root@172.17.70.251:/usr/lib/systemd/system/
[root@k8s-master1 opt]# scp etcd.service root@172.17.70.253:/usr/lib/systemd/system/
[root@k8s-master1 opt]# scp etcd.service root@172.17.70.254:/usr/lib/systemd/system/

启动服务

1
2
3
4
5
# 启动第一个节点会一直处于等待状态,直到有集群节点加入
# 全部etcd节点启动
[root@k8s-master1 opt]# systemctl daemon-reload
[root@k8s-master1 opt]# systemctl start etcd
[root@k8s-master1 opt]# systemctl enable etcd

服务检查

1
2
# 日志查看
[root@k8s-master1 opt]# tailf /var/log/messages
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# etcdctl 相当于客户端访问 
# 别的应用程序想使用etcd集群必须要制定这3个证书,指定endpoints3个地址+端口
# k8s-apiserver也要指定etcd三个证书和三个集群节点

# 查看集群状态
[root@k8s-master1 opt]# /opt/etcd/bin/etcdctl \
--ca-file=/opt/etcd/ssl/ca.pem --cert-file=/opt/etcd/ssl/server.pem --key-file=/opt/etcd/ssl/server-key.pem \
--endpoints="https://172.17.70.251:2379,https://172.17.70.253:2379,https://172.17.70.254:2379" \
cluster-health

member 262549f6716e3f5 is healthy: got healthy result from https://172.17.70.254:2379
member 2d2843149c61e4a9 is healthy: got healthy result from https://172.17.70.253:2379
member 49b9eb405dd15ee9 is healthy: got healthy result from https://172.17.70.251:2379
cluster is healthy
1
2
3
4
5
6
7
8
9
# 查询 member 列表
[root@k8s-master1 opt]# /opt/etcd/bin/etcdctl \
--ca-file=/opt/etcd/ssl/ca.pem --cert-file=/opt/etcd/ssl/server.pem --key-file=/opt/etcd/ssl/server-key.pem \
--endpoints="https://172.17.70.251:2379,https://172.17.70.253:2379,https://172.17.70.254:2379" \
member list

262549f6716e3f5: name=etcd-3 peerURLs=https://172.17.70.254:2380 clientURLs=https://172.17.70.254:2379 isLeader=false
2d2843149c61e4a9: name=etcd-2 peerURLs=https://172.17.70.253:2380 clientURLs=https://172.17.70.253:2379 isLeader=false
49b9eb405dd15ee9: name=etcd-1 peerURLs=https://172.17.70.251:2380 clientURLs=https://172.17.70.251:2379 isLeader=true

部署 Master 节点

自签 APIServer SSL证书

1
2
3
4
5
6
7
[root@k8s-master1 k8s]# ls -l
total 20
-rw-r--r-- 1 root root 294 Oct 3 13:12 ca-config.json
-rw-r--r-- 1 root root 263 Oct 3 13:12 ca-csr.json
-rwxr-xr-x 1 root root 321 Oct 3 08:46 generate_k8s_cert.sh
-rw-r--r-- 1 root root 230 Oct 3 13:12 kube-proxy-csr.json # 为 node上的kube-proxy 颁发证书
-rw-r--r-- 1 root root 718 Oct 3 08:45 server-csr.json # 为 aipserver颁发证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@k8s-master1 k8s]# cat kube-proxy-csr.json 
{
"CN": "system:kube-proxy",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# apiserver 证书
# hosts 里面添加可信任的IP

# 应用程序(服务器IP) 访问 https API (自签证书)
# 1. 证书添加IP可信任
# 2. 携带CA证书去访问(http转发怎么办)
# 有谁会去访问? LB主从,vip,master 写多点没有关系 根据规划 nodeip 其实可以不用写

[root@k8s-master1 k8s]# vim server-csr.json

{
"CN": "kubernetes",
"hosts": [
"10.0.0.1", # service 第一个IP地址
"127.0.0.1", # 本地
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local",
"172.17.70.251",
"172.17.70.252",
"172.17.70.253",
"172.17.70.254",
"172.17.71.1",
"172.17.71.2",
"172.17.71.3",
"172.17.71.4",
"172.17.71.5",
"172.17.71.6"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
1
2
# 执行脚本 生成证书
[root@k8s-master k8s]# ./generate_k8s_cert.sh
1
2
3
4
5
6
7
[root@k8s-master1 k8s]# ls -l *.pem
-rw------- 1 root root 1675 Nov 13 10:22 ca-key.pem
-rw-r--r-- 1 root root 1359 Nov 13 10:22 ca.pem
-rw------- 1 root root 1679 Nov 13 10:22 kube-proxy-key.pem
-rw-r--r-- 1 root root 1403 Nov 13 10:22 kube-proxy.pem
-rw------- 1 root root 1679 Nov 13 10:22 server-key.pem
-rw-r--r-- 1 root root 1684 Nov 13 10:22 server.pem

部署 apiserver

1
2
3
4
5
6
7
8
# 部署步骤
配置文件 -> systemd管理组件 -> 启动

# 二进制包下载地址
# 1. 下载Server Binaries node的也在里面
# 2. 页面打不开 用迅雷下载
# 3. 将需要使用的包 替换 如master节点里面的
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.16.md#downloads-for-v1161

上传解压压缩包

1
2
3
4
5
6
7
# k8s-master.tar.gz
[root@k8s-master1 src]# ls -l
total 104276
-rw-r--r-- 1 root root 1078 Nov 12 17:20 etcd.service
-rw-r--r-- 1 root root 10148977 Nov 12 17:12 etcd.tar.gz
-rw-r--r-- 1 root root 90767613 Nov 13 10:30 k8s-master.tar.gz
-rw-r--r-- 1 root root 5851667 Nov 12 16:49 TLS.tar.gz
1
2
# 解压 得到三个服务的启动文件 和 kubernetes的工作目录
[root@k8s-master1 src]# tar -zxvf k8s-master.tar.gz -C /opt/
1
2
3
4
5
6
[root@k8s-master1 kubernetes]# ls -l
total 16
drwxr-xr-x 2 root root 4096 Oct 3 09:06 bin
drwxr-xr-x 2 root root 4096 Oct 3 08:55 cfg
drwxr-xr-x 2 root root 4096 Oct 2 23:13 logs
drwxr-xr-x 2 root root 4096 Oct 3 10:34 ssl

拷贝证书

1
2
3
4
5
6
7
8
9
[root@k8s-master1 ssl]# cd /opt/kubernetes/ssl/
[root@k8s-master1 ssl]# cp /opt/TLS/k8s/*.pem .
[root@k8s-master1 ssl]# rm -rf kube-proxy* # master不需要 kube-proxu证书
[root@k8s-master1 ssl]# ls -l
total 24
-rw------- 1 root root 1675 Nov 13 10:34 ca-key.pem
-rw-r--r-- 1 root root 1359 Nov 13 10:34 ca.pem
-rw------- 1 root root 1679 Nov 13 10:34 server-key.pem # apiserver公钥 master访问
-rw-r--r-- 1 root root 1684 Nov 13 10:34 server.pem # apiserver证书 master访问

apiserver 配置文件

1
2
# apiserver 配置文件官方文档
https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-apiserver/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
[root@k8s-master1 cfg]# vim kube-apiserver.conf 

KUBE_APISERVER_OPTS="--logtostderr=false \
# 输出日志级别,一般设置2,从小到大越来越详细
--v=2 \
# 日志目录
--log-dir=/opt/kubernetes/logs \
# etcd 集群节点 需要修改
--etcd-servers=https://192.168.31.61:2379,https://192.168.31.62:2379,https://192.168.31.63:2379 \
# 内网IP
--bind-address=192.168.31.61 \
# 端口
--secure-port=6443 \
# 通告地址 告诉node连接哪里 一般是内网
--advertise-address=192.168.31.61 \
# 使用超级权限创建容器
--allow-privileged=true \
# 重要,serviceIP范围
--service-cluster-ip-range=10.0.0.0/24 \
# 启用k8s高级插件
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \
# 鉴权模式 访问apiserver 通过RBAC访问 基于角色 Noda自动认证
--authorization-mode=RBAC,Node \
# bootstrap:为每个node办法证书,node需要请求apiserver,node告诉apiserver我要加入集群,请为我颁发证书
# 给每个node一个最低权限的用户,然后来请求apiserver
--enable-bootstrap-token-auth=true \
--token-auth-file=/opt/kubernetes/cfg/token.csv \
# service 端口范围
--service-node-port-range=30000-32767 \
# apiserver 访问 kubelet 使用的证书
# kubelet 只能让 aipserver访问
--kubelet-client-certificate=/opt/kubernetes/ssl/server.pem \
--kubelet-client-key=/opt/kubernetes/ssl/server-key.pem \
# apiserver https 使用证书
--tls-cert-file=/opt/kubernetes/ssl/server.pem \
--tls-private-key-file=/opt/kubernetes/ssl/server-key.pem \
--client-ca-file=/opt/kubernetes/ssl/ca.pem \
# service-account 像是个用户
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \
# 连接etcd的证书
--etcd-cafile=/opt/etcd/ssl/ca.pem \
--etcd-certfile=/opt/etcd/ssl/server.pem \
--etcd-keyfile=/opt/etcd/ssl/server-key.pem \
# 日志审计 保留多少天
--audit-log-maxage=30 \
--audit-log-maxbackup=3 \
--audit-log-maxsize=100 \
--audit-log-path=/opt/kubernetes/logs/k8s-audit.log"

部署 controller-manager

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@k8s-master1 cfg]# vim kube-controller-manager.conf 

KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \
# 日志
--v=2 \
--log-dir=/opt/kubernetes/logs \
# 集群选举 本身高可用启动
--leader-elect=true \
# 连接 apiserver 8080是apiserver默认监听端口
--master=127.0.0.1:8080 \
--address=127.0.0.1 \
# 允许cni插件 自动分配IP
--allocate-node-cidrs=true \
# 要与cni插件的 集群网段一致
--cluster-cidr=10.244.0.0/16 \
# serviceIP 范围 要与 apiserver里面一致
--service-cluster-ip-range=10.0.0.0/24 \
# 集群签名证书 node 加入集群 会自动办法 kubelet证书
# kubelet证书 由controller-manager 颁发
# controller-manager 使用下面的ca 办法证书
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \
# 签署 service-account 证书
--root-ca-file=/opt/kubernetes/ssl/ca.pem \
# service-account 私钥
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \
# kubelet证书的有效期时间
--experimental-cluster-signing-duration=87600h0m0s"

部署 scheduler

scheduler 配置文件

1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master1 cfg]# vim kube-scheduler.conf 

KUBE_SCHEDULER_OPTS="--logtostderr=false \
# 日志
--v=2 \
--log-dir=/opt/kubernetes/logs \
# 参加选举
--leader-elect \
# 连接本地的apiserver
--master=127.0.0.1:8080 \
--address=127.0.0.1"

修改配置文件

1
2
3
4
5
6
7
8
1. 只需要修改 apiserver.conf  里面的etcd集群和本地IP
2. 剩下的两个服务都是连接本地

[root@k8s-master1 cfg]# vim kube-apiserver.conf
--etcd-servers=https://172.17.70.251:2379,https://172.17.70.253:2379,https://172.17.70.254:2379 \
--bind-address=172.17.70.251 \
--secure-port=6443 \
--advertise-address=172.17.70.251 \

配置服务启动文件

1
2
3
4
5
6
7
[root@k8s-master1 opt]# mv kube*.service /usr/lib/systemd/system/


[root@k8s-master1 opt]# ls -l /usr/lib/systemd/system/kube-*
-rw-r--r-- 1 root root 286 Oct 2 23:13 /usr/lib/systemd/system/kube-apiserver.service
-rw-r--r-- 1 root root 321 Oct 2 23:13 /usr/lib/systemd/system/kube-controller-manager.service
-rw-r--r-- 1 root root 285 Oct 2 23:13 /usr/lib/systemd/system/kube-scheduler.service

启动服务

1
2
3
4
5
6
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl enable kube-apiserver
systemctl enable kube-controller-manager
systemctl enable kube-scheduler

查看日志

1
2
3
4
5
6
# 查看日志
[root@k8s-master opt]# cd /opt/kubernetes/logs/

[root@k8s-master1 logs]# less /opt/kubernetes/logs/kube-apiserver.INFO
[root@k8s-master1 logs]# less /opt/kubernetes/logs/kube-controller-manager.INFO
[root@k8s-master1 logs]# less /opt/kubernetes/logs/kube-scheduler.INFO

kubectl配置

1
2
# 将kubectl 放入/usr/bin 方便使用
[root@k8s-master1 kubernetes]# cp /opt/kubernetes/bin/kubectl /usr/local/bin/

查看集群状态

1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master1 kubernetes]# kubectl get node
No resources found in default namespace.

# 过会回更新成功,能看到即可,失败会有错误
[root@k8s-master1 kubernetes]# kubectl get cs
NAME AGE
controller-manager <unknown>
scheduler <unknown>
etcd-2 <unknown>
etcd-1 <unknown>
etcd-0 <unknown>

查看进程

1
[root@k8s-master1 kubernetes]# ps -ef|grep kube

启用 TLS Bootstrapping

1
2
3
4
5
6
7
8
# 启用了 为 kubelet TLS Bootstrapping 授权
# bootstrap:
# 1. 为每个node办法证书,node需要请求apiserver,node告诉apiserver我要加入集群,请为我颁发证书
# 2. 给每个node一个最低权限的用户,然后来请求apiserver
# 机器越来越多手动颁发证书比较麻烦,这个机制可以自动颁发证书

[root@k8s-master1 kubernetes]# cat /opt/kubernetes/cfg/kube-apiserver.conf |grep bootstrap
--enable-bootstrap-token-auth=true \
1
2
3
4
5
6
7
8
9
10
# 引用的token文件
[root@k8s-master1 kubernetes]# cat /opt/kubernetes/cfg/kube-apiserver.conf |grep token
--enable-bootstrap-token-auth=true \
--token-auth-file=/opt/kubernetes/cfg/token.csv \

# 查看token
# 账号的格式: token,用户,uid,用户组
# 只要带着token过来 系统的这个用户就给帮忙办法证书
[root@k8s-master1 kubernetes]# cat /opt/kubernetes/cfg/token.csv
c47ffb939f5ca36231d9e3121a252940,kubelet-bootstrap,10001,"system:node-bootstrapper"

给 kubelet-bootstrap授权

1
2
3
4
5
6
7
8
9
10
11
# 如果不给与权限,token可以用但是用户没有权限 也不会正常办法
# 将 kubelet-bootstrap 用户绑定到 "system:node-bootstrapper" 组里
# 这个组是系统自带的 主要用于让node能使用bootstrapper办法证书,权限比较低
# 赋予 system:node-bootstrapper 权限

kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap

# 提示成功
clusterrolebinding.rbac.authorization.k8s.io/kubelet-bootstrap created

token 自行生成替换

1
2
3
# apiserver配置的token必须要与node节点bootstrap.kubeconfig配置里一致。
# 部署node的时候会看到
head -c 16 /dev/urandom | od -An -t x | tr -d ' '

部署 Node 节点

1
2
172.17.70.253 k8s-node1
172.17.70.254 k8s-node2

Docker 二进制安装

1
2
# Docker 二进制包下载地址:
https://download.docker.com/linux/static/stable/x86_64/

上传解压安装包

1
2
3
4
[root@k8s-node1 ~]# mkdir -p /opt/src
[root@k8s-node1 src]# ls -l
-rw-r--r-- 1 root root 128129460 Nov 13 14:23 k8s-node.tar.gz
[root@k8s-node1 src]# tar -zxvf k8s-node.tar.gz

二进制安装docker

1
2
3
[root@k8s-node1 src]# tar -zxvf docker-18.09.6.tgz 
[root@k8s-node1 src]# mv docker/* /usr/bin/
[root@k8s-node1 src]# mv docker.service /usr/lib/systemd/system

docker配置文件

1
2
3
4
5
6
7
8
[root@k8s-node1 src]# mkdir -p /etc/docker
[root@k8s-node1 src]# mv daemon.json /etc/docker/

[root@k8s-node1 src]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["http://bc437cce.m.daocloud.io"], # 镜像加速
"insecure-registries": ["172.17.70.252"] # 可信任IP 回头换成harbor地址
}

启动docker服务

1
2
3
[root@k8s-node1 src]# systemctl start docker
[root@k8s-node1 src]# systemctl enable docker
[root@k8s-node1 src]# docker info

部署 harbor仓库

1
2
3
4
5
6
7
# 该主机也需要二进制安装docker 
[root@k8s-master2 src]# scp root@172.17.70.254:/opt/src/docker-18.09.6.tgz .
[root@k8s-master2 src]# scp root@172.17.70.254:/usr/lib/systemd/system/docker.service .
[root@k8s-master2 src]# scp root@172.17.70.254:/etc/docker/daemon.json .
[root@k8s-master2 src]# tar -zxvf docker-18.09.6.tgz
[root@k8s-master2 src]# mv docker/* /usr/bin/
[root@k8s-master2 src]# mv docker.service /usr/lib/systemd/system
1
2
3
4
5
6
7
8
[root@k8s-master2 src]# mkdir -p /etc/docker
[root@k8s-master2 src]# mv daemon.json /etc/docker/

[root@k8s-master2 src]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["http://bc437cce.m.daocloud.io"], # 镜像加速
"insecure-registries": ["172.17.70.252"] # 可信任IP 回头换成harbor地址
}
1
2
3
[root@k8s-node1 src]# systemctl start docker
[root@k8s-node1 src]# systemctl enable docker
[root@k8s-node1 src]# docker info
1
2
3
4
# 上传文件
[root@k8s-master2 src]# ls -l
-rw-r--r-- 1 root root 17237024 Nov 13 14:33 docker-compose-Linux-x86_64
-rw-r--r-- 1 root root 580462944 Nov 13 14:34 harbor-offline-installer-v1.8.4.tgz
1
2
3
4
5
# 部署 compose
[root@k8s-master2 src]# mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
[root@k8s-master2 src]# chmod +x /usr/local/bin/docker-compose
[root@k8s-master2 src]# docker-compose -version
docker-compose version 1.25.0dev, build bc57a1bd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 部署 harbor
[root@k8s-master2 src]# tar -xf harbor-offline-installer-v1.8.4.tgz -C /opt/
[root@k8s-master2 src]# cd /opt/harbor/
# 修改主机名和管理员密码、数据库密码
hostname: 172.17.70.252 # http
harbor_admin_password: 123456 # 访问密码
database:
password: 123456

# 准备
[root@k8s-master2 src]# ./prepare
# 安装
[root@k8s-master2 src]# ./install.sh
# web访问
http://123.56.14.192
# 列出
docker-compose ps

免https使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@Docker harbor]# vim /etc/docker/daemon.json 
# 写入进项仓库 IP+port

{
"registry-mirrors": ["http://f1361db2.m.daocloud.io"],
"insecure-registries": ["172.17.70.252"]
}

# 重启docker
systemctl daemon-reload
systemctl restart docker.service

[root@Docker nginx]# docker info
Insecure Registries:
172.17.70.252
127.0.0.0/8

登录

1
2
3
4
# 两个node节点都先登录下 好下载基础镜像
[root@k8s-node1 cfg]# docker login 172.17.70.252
Username: admin
Password:

下载 pod基础镜像 并上传到私有仓库

1
2
3
4
[root@k8s-master2 opt]# docker pull lizhenliang/pause-amd64:3.0 
[root@k8s-master2 opt]# docker tag lizhenliang/pause-amd64:3.0 172.17.70.252/base/pause-amd64:3.0
[root@k8s-master2 opt]# docker login 172.17.70.252
[root@k8s-master2 opt]# docker push 172.17.70.252/base/pause-amd64:3.0

部署 kubelet

配置文件介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@k8s-node1 src]# tree kubernetes/
kubernetes/
├── bin
│   ├── kubelet
│   └── kube-proxy
├── cfg
│   ├── bootstrap.kubeconfig
│   ├── kubelet.conf
│   ├── kubelet-config.yml
│   ├── kube-proxy.conf
│   ├── kube-proxy-config.yml
│   └── kube-proxy.kubeconfig
├── logs
└── ssl
1
2
3
4
5
6
7
8
9
10
11
12
# 1. conf           基本配置文件
# 2. kubeconfig 连接apiserver配置文件
# 3. yml 主要配置文件 早起版本没有yml配置文件

[root@k8s-node1 src]# tree kubernetes/cfg/
kubernetes/cfg/
├── bootstrap.kubeconfig
├── kubelet.conf
├── kubelet-config.yml
├── kube-proxy.conf
├── kube-proxy-config.yml # 可以动态更新配置文件 beta kube-proxy
└── kube-proxy.kubeconfig

配置 kubelet.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@k8s-node1 src]# mv kubernetes /opt/

[root@k8s-node1 cfg]# vim /opt/kubernetes/cfg/kubelet.conf
# 日志
KUBELET_OPTS="--logtostderr=false \
--v=2 \
--log-dir=/opt/kubernetes/logs \
# 主机名 注册到k8s 名称唯一
--hostname-override=k8s-node1 \
# 启用cni网络插件
--network-plugin=cni \
# kubelet.kubeconfig 配置文件路径
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \
# bootstrap.kubeconfig 配置文件路径
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \
# yaml 配置文件路径
--config=/opt/kubernetes/cfg/kubelet-config.yml \
# 给kubelet颁发的证书路径
--cert-dir=/opt/kubernetes/ssl \
# 基础镜像 启动每个pod都会启动的镜像
# 管理pod的命名空间 这个后期可以换成私有仓库的
# 这个镜像可以先放到公有仓库,以免认证
# --pod-infra-container-image=lizhenliang/pause-amd64:3.0"
--pod-infra-container-image=172.17.70.252/base/pause-amd64:3.0"

配置 bootstrap.kubeconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 用于自动办法kubelet证书
# 他会先连接apiserver,master会办法证书到node上
# kubectl config 生成

[root@k8s-node1 cfg]# vim bootstrap.kubeconfig

apiVersion: v1
clusters:
- cluster:
# 携带 ca 证书
certificate-authority: /opt/kubernetes/ssl/ca.pem
# master 地址
server: https://172.17.70.251:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubelet-bootstrap
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: kubelet-bootstrap
user:
# 务必于master上的token.csv里的一致
token: c47ffb939f5ca36231d9e3121a252940

TLS Bootstrapping 机制流程(kubelet)

1
2
3
4
5
6
7
1. node节点上的 kubelet 启动
2. 根据 bootstrap.kubeconfig 配置文件 去请求apiserver
3. apiserver 会效验 token 是否是可用可信任的
4. apiserver 会效验 ca 证书
5. 都通过之后 给node上的kubelet颁发证书
6. 启动成功
7. 如果启动失败 那么就是没有认证通过 查看token和使用的证书

配置 kubelet-config.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
[root@k8s-node1 cfg]# vim kubelet-config.yml 

kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 0.0.0.0
# kubelet端口
port: 10250
readOnlyPort: 10255
# 需要与 docker info | grep cgroupfs 一致
cgroupDriver: cgroupfs
# kubelet 默认配置的内部dns地址 为了设置dns服务
clusterDNS:
- 10.0.0.2
# 集群的域
clusterDomain: cluster.local
# 不适用swap
failSwapOn: false
# kubelet 授权
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /opt/kubernetes/ssl/ca.pem
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
# 垃圾回收策略
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
nodefs.inodesFree: 5%
# 最大文件打开数
maxOpenFiles: 1000000
# 最大跑的pod数量
maxPods: 110

部署 kube-proxy

配置 kube-proxy.conf

1
2
3
4
5
6
7
[root@k8s-node1 cfg]# vim kube-proxy.conf 
# 日志
KUBE_PROXY_OPTS="--logtostderr=false \
--v=2 \
--log-dir=/opt/kubernetes/logs \
# 指定yml文件路径
--config=/opt/kubernetes/cfg/kube-proxy-config.yml"

配置 kube-proxy.kubeconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# kube-proxy 连接 apiserver的配置文件 
# 每个组件都会连接 apiserver
# kubelet的需要node认证会 自动生成

[root@k8s-node1 cfg]# vim kube-proxy.kubeconfig

apiVersion: v1
clusters:
- cluster:
# ca 证书
certificate-authority: /opt/kubernetes/ssl/ca.pem
# apiserver 地址
server: https://172.17.70.251:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kube-proxy
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: kube-proxy
user:
# kube-proxy 证书
client-certificate: /opt/kubernetes/ssl/kube-proxy.pem
client-key: /opt/kubernetes/ssl/kube-proxy-key.pem

配置 kube-proxy-config.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 动态调整kube-proxy 配置

[root@k8s-node1 cfg]# vim kube-proxy-config.yml

kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
# 监听地址
address: 0.0.0.0
# 监听端口
metricsBindAddress: 0.0.0.0:10249
clientConnection:
# 客户端连接配置文件
kubeconfig: /opt/kubernetes/cfg/kube-proxy.kubeconfig
# 注册名称
hostnameOverride: k8s-node1
# 集群 service 网段
clusterCIDR: 10.0.0.0/24
# 网络模式:ipvs性能较好 也可以选择iptables
mode: ipvs
ipvs:
scheduler: "rr"
iptables:
masqueradeAll: true

拉取证书

1
2
[root@k8s-master1 k8s]# cd /opt/TLS/k8s/
[root@k8s-master1 k8s]# scp ca.pem kube-proxy*.pem root@172.17.70.253:/opt/kubernetes/ssl/

配置启动服务

1
2
[root@k8s-node1 opt]# cd /opt/src/
[root@k8s-node1 src]# mv *.service /usr/lib/systemd/system/

启动服务

1
2
3
4
5
6
[root@k8s-node1 opt]# systemctl start kubelet
[root@k8s-node1 opt]# systemctl enable kubelet

# 认证之后再启动 kube-proxy
[root@k8s-node1 opt]# systemctl start kube-proxy
[root@k8s-node1 opt]# systemctl enable kube-proxy
1
2
3
4
5
6
7
# 查看日志
[root@k8s-node1 logs]# tailf /opt/kubernetes/logs/kubelet.INFO
# 使用 bootstrap kubeconfig 去向apiserver请求颁发证书
# 如果这块是拒绝的 那么看看token是否一致,是否授权,ca证书是否一致

I1113 16:07:13.213148 1949 bootstrap.go:119] Using bootstrap kubeconfig to generate TLS client cert, key and kubeconfig file
I1113 16:07:13.214389 1949 bootstrap.go:150] No valid private key and/or certificate found, reusing existing private key or creating a new one

允许给Node颁发证书

1
2
3
4
# 在master上查看是否有新的node 请求办法证书
[root@k8s-master1 k8s]# kubectl get csr
NAME AGE REQUESTOR CONDITION
node-csr-TyUXN4xk-rZIW1XjZg3IY1fD_3_pfgE-4-l7BzwWUvI 4m32s kubelet-bootstrap Pending
1
2
3
4
5
# 允许该node加入集群并颁发证书
# kubectl certificate approve "NodeNAME"

[root@k8s-master1 k8s]# kubectl certificate approve node-csr-TyUXN4xk-rZIW1XjZg3IY1fD_3_pfgE-4-l7BzwWUvI
certificatesigningrequest.certificates.k8s.io/node-csr-TyUXN4xk-rZIW1XjZg3IY1fD_3_pfgE-4-l7BzwWUvI approved
1
2
3
4
# 查看node kubelet日志 
# 变成不能更新cni配置 因为我们还没有部署cni
E1113 16:15:19.537610 1949 kubelet.go:2187] Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
W1113 16:15:21.440199 1949 cni.go:237] Unable to update cni config: no networks found in /etc/cni/net.d
1
2
3
4
# 现在node还是准备状态 需要部署完cni插件 
[root@k8s-master1 k8s]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 NotReady <none> 2m15s v1.16.0

自动为 node 颁发证书

1
2
3
4
5
6
7
8
9
10
11
# 是否为 node 颁发了证书 

[root@k8s-node1 ssl]# ls -l
total 24
-rw-r--r-- 1 root root 1359 Nov 13 16:02 ca.pem
-rw------- 1 root root 1269 Nov 13 16:14 kubelet-client-2019-11-13-16-14-06.pem # 自动颁发的证书 加入了集群
lrwxrwxrwx 1 root root 58 Nov 13 16:14 kubelet-client-current.pem -> /opt/kubernetes/ssl/kubelet-client-2019-11-13-16-14-06.pem
-rw-r--r-- 1 root root 2173 Nov 13 16:07 kubelet.crt
-rw------- 1 root root 1675 Nov 13 16:07 kubelet.key
-rw------- 1 root root 1679 Nov 13 16:02 kube-proxy-key.pem
-rw-r--r-- 1 root root 1403 Nov 13 16:02 kube-proxy.pem

自动生成配置文件 kubelet.kubeconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 自动生成   kubelet.kubeconfig  配置文件
# kubelet.kubeconfig 负载连接 apiserver
# 使用颁发的证书 kubelet-client-current.pem

[root@k8s-node1 ssl]# cd /opt/kubernetes/cfg/

[root@k8s-node1 cfg]# vim kubelet.kubeconfig

apiVersion: v1
clusters:
- cluster:
certificate-authority: /opt/kubernetes/ssl/ca.pem
server: https://172.17.70.251:6443
name: default-cluster
contexts:
- context:
cluster: default-cluster
namespace: default
user: default-auth
name: default-context
current-context: default-context
kind: Config
preferences: {}
users:
- name: default-auth
user:
client-certificate: /opt/kubernetes/ssl/kubelet-client-current.pem
client-key: /opt/kubernetes/ssl/kubelet-client-current.pem

加入 node2 节点

1
2
3
# 相当于重新部署一套 流程一致
# 别忘记安装docker
# 别忘记拷贝证书

配置文件修改的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
# IP地址 后期可以改完 vip  
# bootstrap.kubeconfig kube-proxy.kubeconfig
[root@k8s-node2 cfg]# grep 251 *
[root@k8s-node2 cfg]# grep 251 *
bootstrap.kubeconfig: server: https://172.17.70.251:6443
kube-proxy.kubeconfig: server: https://172.17.70.251:6443

# 文件中主机名
# kubelet.conf kube-proxy-config.yml
[root@k8s-node2 cfg]# grep hostname *
[root@k8s-node2 cfg]# grep hostname *
kubelet.conf:--hostname-override=k8s-node2 \
kube-proxy-config.yml:hostnameOverride: k8s-node2
1
2
3
4
5
6
7
8
9
10
11
12
13
# 同意node2 加入集群
[root@k8s-master1 k8s]# kubectl get csr
NAME AGE REQUESTOR CONDITION
node-csr-DHJS3UYUAxg7KPrO22SG_Q_4PIUZzndAt_gSVhiMWKc 46s kubelet-bootstrap Pending # 等待
node-csr-TyUXN4xk-rZIW1XjZg3IY1fD_3_pfgE-4-l7BzwWUvI 38m kubelet-bootstrap Approved,Issued # 同意

[root@k8s-master1 k8s]# kubectl certificate approve node-csr-DHJS3UYUAxg7KPrO22SG_Q_4PIUZzndAt_gSVhiMWKc
certificatesigningrequest.certificates.k8s.io/node-csr-DHJS3UYUAxg7KPrO22SG_Q_4PIUZzndAt_gSVhiMWKc approved

[root@k8s-master1 k8s]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 NotReady <none> 32m v1.16.0
k8s-node2 NotReady <none> 8s v1.16.0
1
2
3
4
5
6
7
# 应该先加入节点 再启动kukube-proxy 如果先启动了 就认证后重启下 kube-proxy 服务
[root@k8s-node2 logs]# tailf /opt/kubernetes/logs/kube-proxy.ERROR
E1113 16:46:57.637897 1956 node.go:124] Failed to retrieve node info: nodes "k8s-node2" not found

[root@k8s-node2 logs]# systemctl stop kube-proxy
[root@k8s-node2 logs]# rm -rf kube-proxy.*
[root@k8s-node2 logs]# systemctl start kube-proxy

k8s的分层结构

部署 CNI 网络 (Flannel)

1
2
# 二进制包下载地址:
https://github.com/containernetworking/plugins/releases
1
2
3
4
5
# 当前的错误日志
# 网络没有发现 网络信息在 /etc/cni/net.d下
[root@k8s-node1 cfg]# tail /opt/kubernetes/logs/kubelet.INFO
E1113 16:57:39.952919 1949 kubelet.go:2187] Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
W1113 16:57:41.503503 1949 cni.go:237] Unable to update cni config: no networks found in /etc/cni/net.d

cni 网络插件接口介绍

  1. cni 网络插件 是k8s的网络接口
  2. 用于对接第三网网络插件为pod提供网络
  3. 必须符合cni的标准
1
2
# cni只是第三方网络接口 看看这些网络都由哪些
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/

cni 网络插件接口部署

1
2
3
4
5
6
# 在node节点 解压插件
[root@k8s-node1 opt]# cd /opt/src/
# 创建工作目录
[root@k8s-node1 src]# mkdir -p /opt/cni/bin # 二进制文件目录,默认kubelet从这个目录找可执行文件 为pod创建网络
[root@k8s-node1 src]# mkdir -p /etc/cni/net.d # 生成配置信息目录
[root@k8s-node1 src]# tar -zxvf cni-plugins-linux-amd64-v0.8.2.tgz -C /opt/cni/bin
1
2
3
# copy给其他node(node2) 别忘记创建目录
[root@k8s-node1 bin]# scp -r /opt/cni root@172.17.70.254:/opt/
[root@k8s-node2 logs]# mkdir -p /opt/cni/bin \
1
2
3
# 确保启用cni 
[root@k8s-node1 opt]# cat /opt/kubernetes/cfg/kubelet.conf | grep cni
--network-plugin=cni \

部署 flannel 网络插件

1
2
3
4
# 在master上部署
# 上传yaml文件
[root@k8s-master1 src]# ls -l kube-flannel.yaml
-rw-r--r-- 1 root root 5032 Nov 13 17:22 kube-flannel.yaml
1
2
3
4
5
6
7
8
9
10
11
# 实际上是个pod
# flannel 要连接apiserver 需要授权 ServiceAccount
# cni配置网络信息 会写到 node的/etc/cni/net.d/目录下 然后让kubelet使用
# 10.244.0.0/16 使用的网络
# 他与 apiserver 里面配置的一致
# [root@k8s-master1 ~]# cat /opt/kubernetes/cfg/kube-controller-manager.conf | grep cluster-cidr
# --cluster-cidr=10.244.0.0/16 \
# DaemonSet 方式部署 说明每个node都会部署一个 他再每个node上都要保持路由表的维护
# 使用宿主机网络 保证宿主机跨主机通信
# 关键点 他需要是从网上找镜像 image: lizhenliang/flannel:v0.11.0-amd64
# 我们可以去网上下载好这个镜像 部署到自己仓库中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@k8s-master1 src]# vim kube-flannel.yaml 

data:
cni-conf.json: |
{
"cniVersion": "0.2.0",
"name": "cbr0",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}

启动pod

1
2
3
4
5
6
7
[root@k8s-master1 src]# kubectl apply -f kube-flannel.yaml 
podsecuritypolicy.policy/psp.flannel.unprivileged created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds-amd64 created

查看pod是否启动

1
2
3
4
5
6
# 会从 lizhenliang/flannel:v0.11.0-amd64 下载镜像有点慢
# 离线部署 提前下载好 导到每个node上本地要是由就不会拉取了
[root@k8s-master1 src]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-amd64-b48fs 1/1 Running 0 35s
kube-flannel-ds-amd64-ztvl4 1/1 Running 0 35s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看pod事件状态 如果是aliyun主机 别忘记node也要出公网啊
[root@k8s-master1 opt]# kubectl describe pod kube-flannel-ds-amd64-b48fs -n kube-system

Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned kube-system/kube-flannel-ds-amd64-b48fs to k8s-node2
Normal Pulling 74s kubelet, k8s-node2 Pulling image "lizhenliang/flannel:v0.11.0-amd64"
Normal Pulled 70s kubelet, k8s-node2 Successfully pulled image "lizhenliang/flannel:v0.11.0-amd64"
Normal Created 70s kubelet, k8s-node2 Created container install-cni
Normal Started 70s kubelet, k8s-node2 Started container install-cni
Normal Pulled 70s kubelet, k8s-node2 Container image "lizhenliang/flannel:v0.11.0-amd64" already present on machine
Normal Created 70s kubelet, k8s-node2 Created container kube-flannel
Normal Started 70s kubelet, k8s-node2 Started container kube-flannel
1
2
# 没起来试试 
[root@k8s-node2 bin]# systemctl restart kube-proxy
1
2
3
4
5
# 查看 node工作状态
[root@k8s-master1 src]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 Ready <none> 85m v1.16.0
k8s-node2 Ready <none> 52m v1.16.0

查看pod日志

1
2
3
[root@k8s-master1 src]# kubectl logs kube-flannel-ds-amd64-nnrkz -n kube-system
Error from server (NotFound): pods "kube-flannel-ds-amd64-nnrkz" not found
# 没有权限 需要授权 通过logs命令可以查看pod日志
1
2
3
4
5
6
7
# 上传授权yaml文件 并执行
[root@k8s-master1 src]# ls -l /opt/src/apiserver-to-kubelet-rbac.yaml
-rw-r--r-- 1 root root 745 Nov 13 17:42 /opt/src/apiserver-to-kubelet-rbac.yaml

[root@k8s-master1 src]# kubectl apply -f apiserver-to-kubelet-rbac.yaml
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 集群角色授权
# 可以访问pod日志等
# 赋予给 name: system:kube-apiserver-to-kubelet

[root@k8s-master1 src]# vim /opt/src/apiserver-to-kubelet-rbac.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
- pods/log
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubernetes
1
[root@k8s-master1 src]# kubectl logs kube-flannel-ds-amd64-b48fs -n kube-system

查看 node上的 pod 和网络

1
2
3
4
5
6
7
8
9
# 每个node上都会启动个pod
# node上会增加flannel 虚拟网卡
# pod 通过flannel 跨主机访问 传输数据

[root@k8s-master opt]# kubectl get pods -n kube-system -o wide
[root@k8s-master1 src]# kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel-ds-amd64-b48fs 1/1 Running 0 11m 172.17.70.254 k8s-node2 <none> <none>
kube-flannel-ds-amd64-ztvl4 1/1 Running 0 11m 172.17.70.253 k8s-node1 <none> <none>

创建 nginx pod 测试部署环境

1
2
3
4
5
6
7
8
9
10
11
12
1. 当创建pod的时候 部署到的节点会创建cni网络 
2. 相当于一个网桥,以后所有的pod流量都会经过这个网桥 pod都会加入到这里面

[root@k8s-master1 src]# kubectl create deployment web --image=nginx:1.16
deployment.apps/web created
[root@k8s-master1 src]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-866f97c649-tj4mb 0/1 ContainerCreating 0 7s <none> k8s-node1 <none> <none>

[root@k8s-master1 src]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-866f97c649-tj4mb 1/1 Running 0 113s 10.244.0.2 k8s-node1 <none> <none>

1
2
3
4
5
6
7
8
9
10
11
# 暴露pod 到集群外部
[root@k8s-master1 src]# kubectl expose deployment web --port=80 --type=NodePort
service/web exposed

[root@k8s-master1 src]# kubectl get pods,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/web-866f97c649-tj4mb 1/1 Running 0 3m40s 10.244.0.2 k8s-node1 <none> <none>

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 6h32m <none>
service/web NodePort 10.0.0.225 <none> 80:30966/TCP 14s app=web
1
2
3
4
5
6
7
8
# 测试访问node节点上的pod
# 都能访问说明集群网络都正常 单master正常
[root@k8s-master1 src]# curl 172.17.70.253:30966
[root@k8s-master1 src]# curl 172.17.70.254:30966

# web访问
http://39.106.168.181:30966/
http://39.106.100.108:30966/

测试再加入一个node节点

1
2
3
1. 按照正常流程部署node节点
2. 安装好cni插件后 master会帮忙创建网络
别忘记下载远程的 lizhenliang/flannel:v0.11.0-amd64 镜像 要出外网 或者部署本地仓库

K8S 高可用介绍

1
2
3
4
5
6
7
LB : Nginx LVS HaProxy
4层负载 端口转发 stream TCP 性能更好
7层负载 业务转发 HTTP 应用层协议满足更多数据转发

高可用软件:
keepalived 创建vip 健康检查和故障转移 用户访问vip , node 连接 vip
阿里云SLB实现

部署 master2

1
2
3
4
5
172.17.71.5   aliyun-slb 内网负载均衡
172.17.70.245 k8s-master2
172.17.70.246 k8s-master
172.17.70.247 k8s-node1
172.17.70.248 k8s-node2
1
2
3
4
5
6
7
8
9
# 将kubernetes 传过去
[root@k8s-master1 k8s]# scp -r /opt/kubernetes root@172.17.70.252:/opt

# 管理服务的service文件
[root@k8s-master1 k8s]# scp /usr/lib/systemd/system/{kube-apiserver,kube-controller-manager,kube-scheduler}.service root@172.17.70.252:/usr/lib/systemd/system

# 拷贝etcd证书目录
[root@k8s-master2 opt]# mkdir -p /opt/etcd
[root@k8s-master1 k8s]# scp -r /opt/etcd/ssl root@172.17.70.252:/opt/etcd
1
2
3
4
5
# 修改配置文件
# 修改apiserver配置文件为本地IP:
[root@k8s-master2 opt]# cat /opt/kubernetes/cfg/kube-apiserver.conf | grep 252
--bind-address=172.17.70.252 \
--advertise-address=172.17.70.252 \
1
2
# 传递 kubectl
[root@k8s-master1 k8s]# scp /usr/local/bin/kubectl root@172.17.70.252:/usr/bin/
1
2
3
4
5
6
7
8
# 启动服务
[root@k8s-node1 cfg]# systemctl daemon-reload
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl enable kube-apiserver
systemctl enable kube-controller-manager
systemctl enable kube-scheduler
1
2
3
4
5
6
7
8
9
10
# 查看资源 有数据即为正常

[root@k8s-master2 opt]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-node1 Ready <none> 17h v1.16.0
k8s-node2 Ready <none> 16h v1.16.0

[root@k8s-master2 opt]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-866f97c649-tj4mb 1/1 Running 1 15h

配置阿里云内网SLB

1
2
3
1. 创建内网负载均衡 得到vip vip需要再证书里啊
2. 创建虚拟机服务器组
3. 创建负载策略 TCP端口负载转向6443

1
2
3
4
5
6
# 测试vpi 6443端口访问
[root@k8s-node2 ~]# telnet 172.17.71.5 6443
Trying 172.17.71.5...
Connected to 172.17.71.5.
Escape character is '^]'.
^CConnection closed by foreign host.

修改node节点连接配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# 每个node连接SLB的vip
[root@k8s-node1 src]# cd /opt/kubernetes/cfg/
[root@k8s-node1 cfg]# grep '6443' *
bootstrap.kubeconfig: server: https://172.17.70.251:6443
kubelet.kubeconfig: server: https://172.17.70.251:6443
kube-proxy.kubeconfig: server: https://172.17.70.251:6443

# 把IP地址修改成vip
[root@k8s-node1 cfg]# sed -i 's#172.17.70.251:6443#172.17.71.5:6443#g' *
[root@k8s-node1 cfg]# grep '6443' *
bootstrap.kubeconfig: server: https://172.17.71.5:6443
kubelet.kubeconfig: server: https://172.17.71.5:6443
kube-proxy.kubeconfig: server: https://172.17.71.5:6443
1
2
3
# 重启kubelet 和 kube-proxy服务
[root@k8s-node1 cfg]# systemctl restart kubelet
[root@k8s-node1 cfg]# systemctl restart kube-proxy

验证

1
2
3
4
5
# 还可以访问各节点
[root@k8s-master1 k8s]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 Ready <none> 17h v1.16.0
k8s-node2 Ready <none> 17h v1.16.0
1
2
3
4
5
6
7
8
9
10
11
# 之前节点都连接的 master1上的api 
# 关闭掉master1上的 apiserver服务
# 看看master2 还能不能得到node
systemctl stop kube-apiserver
systemctl stop kube-controller-manager
systemctl stop kube-scheduler


systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
1
2
3
4
5
# 可以继续使用 证明vpi正常工作
[root@k8s-master2 opt]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 Ready <none> 17h v1.16.0
k8s-node2 Ready <none> 17h v1.16.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 测试VIP是否正常工作
# 带着token去访问 vip api

curl -k --header "Authorization: Bearer c47ffb939f5ca36231d9e3121a252940" https://172.17.71.5:6443/version

[root@k8s-node2 cfg]# curl -k --header "Authorization: Bearer c47ffb939f5ca36231d9e3121a252940" https://172.17.71.5:6443/version
{
"major": "1",
"minor": "16",
"gitVersion": "v1.16.0",
"gitCommit": "2bd9643cee5b3b3a5ecbd3af49d09018f0773c77",
"gitTreeState": "clean",
"buildDate": "2019-09-18T14:27:17Z",
"goVersion": "go1.12.9",
"compiler": "gc",
"platform": "linux/amd64"
}

# 释放负载后 就无法在创建pod了


[root@k8s-master1 k8s]# kubectl create deployment web2 --image=nginx:1.16

[root@k8s-master1 k8s]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-866f97c649-tj4mb 1/1 Running 1 16h 10.244.0.3 k8s-node1 <none> <none>
web2-79f76c99dc-kvqg5 0/1 Pending 0 111s <none> <none> <none> <none>

Warning FailedScheduling <unknown> default-scheduler 0/2 nodes are available: 2 node(s) had taints that the pod didn't tolerate.
Warning FailedScheduling <unknown> default-scheduler 0/2 nodes are available: 2 node(s) had taints that the pod didn't tolerate.


[root@k8s-master1 k8s]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 NotReady <none> 17h v1.16.0
k8s-node2 NotReady <none> 17h v1.16.0

##