环境准备
OS: CentOS 7.5
Kubernetes: 1.15.4
Docker: 18.09
Etcd: 3.4.1
主机名 | IP / VIP | 组件 |
---|---|---|
k8s-master | 192.168.10.81 / 192.168.10.80 | haproxy、keepalived、etcd、kube-apiserver、kube-controllet-manager、kube-scheduler、node |
k8s-master | 192.168.10.82 / 192.168.10.80 | haproxy、keepalived、etcd、kube-apiserver、kube-controllet-manager、kube-scheduler、node |
k8s-master | 192.168.10.83 / 192.168.10.80 | haproxy、keepalived、etcd、kube-apiserver、kube-controllet-manager、kube-scheduler、node |
k8s-node01 | 192.168.10.84 | kubelet、kube-proxy、docker、flanneld、core-dns |
k8s-node02 | 192.168.10.85 | kubelet、kube-proxy、docker、flanneld、core-dns |
服务 | 网络 |
---|---|
service network | 10.96.0.0/12
service dns | 10.96.0.10
pod network | 10.244.0.0/16
host解析1
2
3
4
5
6
7cat >> /etc/hosts <<EOF
192.168.10.81 k8s-master01
192.168.10.82 k8s-master02
192.168.10.83 k8s-master03
192.168.10.84 k8s-node01
192.168.10.85 k8s-node02
EOF
配置免密钥登陆1
2
3
4
5
6
7
8
9
10
11
12
13
14yum install -y expect
ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa
export mypass=123456
name=(k8s-master1 k8s-master2 k8s-master3 k8s-node1 k8s-node2)
for i in ${name[@]};do
expect -c "
spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@$i
expect {
\"*yes/no*\" {send \"yes\r\"; exp_continue}
\"*password*\" {send \"$mypass\r\"; exp_continue}
\"*Password*\" {send \"$mypass\r\";}
}"
done
配置主机名1
2name=(k8s-master01 k8s-master02 k8s-master03 k8s-node01 k8s-node02)
for i in ${name[@]};do ssh root@$i hostnamectl set-hostname $i;done
关闭防火墙、selinux、swap1
2
3
4
5
6
7
8systemctl stop firewalld
systemctl disable firewalld
iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat
iptables -P FORWARD ACCEPT
swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
安装依赖1
yum install -y ntpdate curl wget
时间同步1
echo "*/30 * * * * ntpdate time7.aliyun.com >/dev/null 2>&1" >> /var/spool/cron/root
升级内核1
2
3
4
5
6
7#Docker overlay2需要使用kernel 4.x版本
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install -y kernel-lt
grub2-set-default 0
grub2-mkconfig -o /etc/grub2.cfg
grubby --default-kernel
reboot
优化内核参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17cat >/etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0 # 禁止使用 swap 空间,只有当系统 OOM 时才允许使用它
vm.overcommit_memory=1 # 不检查物理内存是否够用
vm.panic_on_oom=0 # 开启 OOM
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720
EOF
sysctl -p
IPVS1
2
3
4
5
6
7
8
9
10
11yum install -y conntrack ipvsadm ipset
cat >/etc/modules-load.d/ipvs.conf << EOF
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF
modprobe ip_vs_rr nf_conntrack
lsmod | egrep "ip_vs_rr|nf_conntrack"
环境变量文件
1 | cd /etc/kubernetes |
部署cfssl
1 | curl -s -L -o /usr/local/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 |
配置证书
只需创建一个CA证书,后续创建的所有证书(kubernetes+etcd)都是由它签名
1 | mkdir -p /etc/kubernetes/ssl |
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
29
30
31cd /etc/kubernetes/ssl
cat > etcd-csr.json <<EOF
{
"CN": "etcd",
"hosts": [
"127.0.0.1",
"192.168.10.81",
"192.168.10.82",
"192.168.10.83"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Guangzhou",
"L": "Guangzhou",
"O": "k8s",
"OU": "System"
}
]
}
EOF
# 生成证书和私钥
cfssl gencert -ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes etcd-csr.json | cfssljson -bare etcd
分发至etcd master1
2
3
4
5
6source /etc/kubernetes/env.sh
for NODE in ${ETCD_IPS[@]};do
ssh root@$NODE "mkdir -p /etc/etcd/ssl"
rsync /etc/kubernetes/ssl/ca*.pem root@${NODE}:/etc/etcd/ssl/
rsync /etc/etcd/ssl/etcd*.pem root@${NODE}:/etc/etcd/ssl/
done
部署etcd集群
etcd 是k8s集群最重要的组件,用来存储k8s的所有服务信息, etcd 挂了,集群就挂了,我们这里把etcd部署在master三台节点上做高可用,etcd集群采用raft算法选举Leader, 由于Raft算法在做决策时需要多数节点的投票,所以etcd一般部署集群推荐奇数个节点,推荐的数量为3、5或者7个节点构成一个集群
https://github.com/coreos/etcd/releases1
2
3
4
5
6
7
8
9
10# 下载和分发
cd /usr/local/src
wget https://github.com/etcd-io/etcd/releases/download/v3.4.1/etcd-v3.4.1-linux-amd64.tar.gz
tar xf etcd-v3.4.1-linux-amd64.tar.gz
source /etc/kubernetes/env.sh
for NODE in ${ETCD_IPS[@]};do
ssh root@${NODE} "mkdir -p /usr/local/k8s/bin"
rsync etcd-v3.4.1-linux-amd64/etc* root@${NODE}:/usr/local/k8s/bin/
done
etcd.service1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76source /etc/kubernetes/env.sh
#ETCD_IPS=(192.168.10.81 192.168.10.82 192.168.10.83)
#ETCD_NAMES=("etcd-0" "etcd-1" "etcd-2")
for i in "${!ETCD_IPS[@]}"; do
HOST=${ETCD_IPS[$i]}
NAME=${ETCD_NAMES[$i]}
cat << EOF > ~/etcd.service.${HOST}
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/local/k8s/bin/etcd \\
--data-dir=/data/etcd \\
--name=${NAME} \\
--trusted-ca-file=/etc/etcd/ssl/ca.pem \\
--cert-file=/etc/etcd/ssl/etcd.pem \\
--key-file=/etc/etcd/ssl/etcd-key.pem \\
--peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \\
--peer-cert-file=/etc/etcd/ssl/etcd.pem \\
--peer-key-file=/etc/etcd/ssl/etcd-key.pem \\
--peer-client-cert-auth \\
--client-cert-auth \\
--listen-peer-urls=https://${HOST}:2380 \\
--initial-advertise-peer-urls=https://${HOST}:2380 \\
--listen-client-urls=https://${HOST}:2379,http://127.0.0.1:2379 \\
--advertise-client-urls=https://${HOST}:2379 \\
--initial-cluster-token=etcd-cluster-0 \\
--initial-cluster=${ETCD_NAMES[0]}=https://${ETCD_IPS[0]}:2380,${ETCD_NAMES[1]}=https://${ETCD_IPS[1]}:2380,${ETCD_NAMES[2]}=https://${ETCD_IPS[2]}:2380 \\
--initial-cluster-state=new \\
--auto-compaction-mode=periodic \\
--auto-compaction-retention=1 \\
--max-request-bytes=33554432 \\
--quota-backend-bytes=6442450944 \\
--heartbeat-interval=250 \\
--election-timeout=2000
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
done
# 分发
source /etc/kubernetes/env.sh
for NODE in ${ETCD_IPS[@]};do
rsync ~/etcd.service.${NODE} root@${NODE}:/etc/systemd/system/etcd.service
ssh root@${NODE} "mkdir -p /data/etcd"
done
for NODE in ${ETCD_IPS[@]};do
ssh root@${NODE} "systemctl enable etcd --now"
done
#etcd首次进程启动会等待其他节点加入etcd集群,执行启动命令会卡顿一会,为正常现象
#journalctl -fu etcd 查看报错
# 验证ETCD集群状态
source /etc/kubernetes/env.sh
ETCDCTL_API=3 /usr/local/k8s/bin/etcdctl \
--endpoints=${ETCD_ENDPOINTS} \
--cacert=/etc/etcd/ssl/ca.pem \
--cert=/etc/etcd/ssl/etcd.pem \
--key=/etc/etcd/ssl/etcd-key.pem endpoint health
# 查看etcd集群leader
source /etc/kubernetes/env.sh
ETCDCTL_API=3 /usr/local/k8s/bin/etcdctl \
-w table --cacert=/etc/etcd/ssl/ca.pem \
--cert=/etc/etcd/ssl/etcd.pem \
--key=/etc/etcd/ssl/etcd-key.pem \
--endpoints=${ETCD_ENDPOINTS} endpoint status
备份etcd
1 | #!/bin/bash |
部署高可用
部署haproxy
- 使用haproxy实现k8s节点(master节点和node节点)高可用访问kube-apiserver的步骤
- 控制节点的kube-controller-manager、kube-scheduler是多实例部署,所以只要一个实例正常,就可以保证集群高可用
- 集群内的Pod使用k8s服务域名kubernetes访问kube-apiserver,kube-dns会自动解析多个kube-apiserver节点的IP,所以也是高可用的
配置haproxy1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62yum install -y haproxy
cat > /etc/haproxy/haproxy.cfg <<EOF
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend kubernetes-apiserver
mode tcp
bind *:8443
option tcplog
default_backend kubernetes-apiserver
backend kubernetes-apiserver
mode tcp
balance roundrobin
server k8s01 192.168.10.81:6443 check
server k8s02 192.168.10.82:6443 check
server k8s03 192.168.10.83:6443 check
listen stats
bind *:1080
stats auth admin:sunday
stats refresh 5s
stats realm HAProxy\ Statistics
stats uri /haproxy-stats
EOF
# 分发
source /etc/kubernetes/env.sh
for NODE in ${MASTER_IPS[@]};do
ssh root@${NODE} "yum install -y haproxy"
rsync /etc/haproxy/haproxy.cfg ${NODE}:/etc/haproxy/
ssh root@${NODE} "systemctl enable --now haproxy"
done
ss -tunlp |grep 8443
部署keeplived
高可用方案需要一个VIP,供集群内部访问
配置keeplived服务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
49
50
51
52
53
54
55
56yum install -y keepalived psmisc
cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
router_id keepalived
}
vrrp_script check_haproxy {
script "killall -0 haproxy"
interval 2
weight -3
fall 2
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 247
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass Sunday
}
virtual_ipaddress {
192.168.10.80
}
track_script {
check_haproxy
}
}
EOF
# 分发
source /etc/kubernetes/env.sh
for NODE in ${MASTER_IPS[@]};do
ssh root@${NODE} "yum install -y keepalived psmisc"
rsync /etc/keepalived/keepalived.conf $NODE:/etc/keepalived/keepalived.conf
done
# 替换
ssh root@192.168.10.82 "sed -i -e 's#MASTER#BACKUP#g' -e 's#priority 100#priority 99#g' /etc/keepalived/keepalived.conf"
ssh root@192.168.10.83 "sed -i -e 's#MASTER#BACKUP#g' -e 's#priority 100#priority 98#g' /etc/keepalived/keepalived.conf"
# 启动keeplived
source /etc/kubernetes/env.sh
for NODE in ${MASTER_IPS[@]}; do
ssh $NODE 'systemctl enable --now keepalived'
done
# 启动完毕后ping 192.168.10.80 (VIP)
# ping -c 2 192.168.10.80
PING 192.168.10.80 (192.168.10.80) 56(84) bytes of data.
64 bytes from 192.168.10.80: icmp_seq=1 ttl=64 time=0.045 ms
64 bytes from 192.168.10.80: icmp_seq=2 ttl=64 time=0.052 ms
部署master二进制
1 | cat << EOF > profile.d/k8s.sh |
分发master二进制1
2
3
4
5
6
7
8
9cd /usr/local/src/
wget https://storage.googleapis.com/kubernetes-release/release/v1.15.4/kubernetes-server-linux-amd64.tar.gz
tar -xf kubernetes-server-linux-amd64.tar.gz
source /etc/kubernetes/env.sh
for NODE in ${MASTER_IPS[@]};do
rsync /etc/profile.d/k8s.sh root@${NODE}:/etc/profile.d/
rsync kubernetes/server/bin/{kube-apiserver,kube-controller-manager,kube-scheduler,kubeadm,kubectl} root@${NODE}:/usr/local/k8s/bin/
done
部署kubectl
创建admin证书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
26cd /etc/kubernetes/ssl/
cat > admin-csr.json <<EOF
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Guangzhou",
"L": "Guangzhou",
"O": "system:masters",
"OU": "System"
}
]
}
EOF
#生成证书和私钥
cfssl gencert -ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes admin-csr.json | cfssljson -bare admin
生成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
29
30
31
32
33cd /etc/kubernetes/ssl
source /etc/kubernetes/env.sh
# 设置集群参数
kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER_URL} \
--kubeconfig=/etc/kubernetes/kubectl.config
#设置客户端认证参数
kubectl config set-credentials admin \
--client-certificate=admin.pem \
--client-key=admin-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/kubectl.config
# 设置上下文参数
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=admin \
--kubeconfig=/etc/kubernetes/kubectl.config
# 设置默认上下文
kubectl config use-context kubernetes --kubeconfig=/etc/kubernetes/kubectl.config
# 分发
source /etc/kubernetes/env.sh
for NODE in ${MASTER_IPS[@]};do
ssh root@${NODE} "mkdir -p ~/.kube"
rsync /etc/kubernetes/kubectl.config root@${NODE}:~/.kube/config
rsync /etc/kubernetes/ssl/admin*.pem root@${NODE}:/etc/kubernetes/ssl/
done
部署kube-apiserver
创建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
46source /etc/kubernetes/env.sh
cd /etc/kubernetes/ssl/
cat > kube-apiserver-csr.json <<EOF
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"192.168.10.81",
"192.168.10.82",
"192.168.10.83",
"192.168.10.84",
"192.168.10.85",
"192.168.10.86",
"192.168.10.87",
"192.168.10.89",
"192.168.10.90",
"${ELB_APISERVER_DOMAIN}",
"${KUBE_APISERVER_IP}",
"${KUBE_SERVICE_IP}",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local."
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Guangzhou",
"L": "Guangzhou",
"O": "k8s",
"OU": "System"
}
]
}
EOF
# 生成证书和私钥
cfssl gencert -ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes kube-apiserver-csr.json | cfssljson -bare kube-apiserver
创建访问 metrics-server 证书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
26cd /etc/kubernetes/ssl/
cat > proxy-client-csr.json <<EOF
{
"CN": "aggregator",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Guangzhou",
"L": "Guangzhou",
"O": "k8s",
"OU": "System"
}
]
}
EOF
# 生成证书和私钥
cfssl gencert -ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes proxy-client-csr.json | cfssljson -bare proxy-client
创建加密配置文件1
2
3
4
5
6
7
8
9
10
11
12
13cat > /etc/kubernetes/encryption-config.yaml <<EOF
kind: EncryptionConfig
apiVersion: v1
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: ${ENCRYPTION_KEY}
- identity: {}
EOF
创建审计策略文件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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177cat > /etc/kubernetes/audit-policy.yaml <<EOF
apiVersion: audit.k8s.io/v1beta1
kind: Policy
rules:
# The following requests were manually identified as high-volume and low-risk, so drop them.
- level: None
resources:
- group: ""
resources:
- endpoints
- services
- services/status
users:
- 'system:kube-proxy'
verbs:
- watch
- level: None
resources:
- group: ""
resources:
- nodes
- nodes/status
userGroups:
- 'system:nodes'
verbs:
- get
- level: None
namespaces:
- kube-system
resources:
- group: ""
resources:
- endpoints
users:
- 'system:kube-controller-manager'
- 'system:kube-scheduler'
- 'system:serviceaccount:kube-system:endpoint-controller'
verbs:
- get
- update
- level: None
resources:
- group: ""
resources:
- namespaces
- namespaces/status
- namespaces/finalize
users:
- 'system:apiserver'
verbs:
- get
# Don't log HPA fetching metrics.
- level: None
resources:
- group: metrics.k8s.io
users:
- 'system:kube-controller-manager'
verbs:
- get
- list
# Don't log these read-only URLs.
- level: None
nonResourceURLs:
- '/healthz*'
- /version
- '/swagger*'
# Don't log events requests.
- level: None
resources:
- group: ""
resources:
- events
# node and pod status calls from nodes are high-volume and can be large, don't log responses for expected updates from nodes
- level: Request
omitStages:
- RequestReceived
resources:
- group: ""
resources:
- nodes/status
- pods/status
users:
- kubelet
- 'system:node-problem-detector'
- 'system:serviceaccount:kube-system:node-problem-detector'
verbs:
- update
- patch
- level: Request
omitStages:
- RequestReceived
resources:
- group: ""
resources:
- nodes/status
- pods/status
userGroups:
- 'system:nodes'
verbs:
- update
- patch
# deletecollection calls can be large, don't log responses for expected namespace deletions
- level: Request
omitStages:
- RequestReceived
users:
- 'system:serviceaccount:kube-system:namespace-controller'
verbs:
- deletecollection
# Secrets, ConfigMaps, and TokenReviews can contain sensitive & binary data,
# so only log at the Metadata level.
- level: Metadata
omitStages:
- RequestReceived
resources:
- group: ""
resources:
- secrets
- configmaps
- group: authentication.k8s.io
resources:
- tokenreviews
# Get repsonses can be large; skip them.
- level: Request
omitStages:
- RequestReceived
resources:
- group: ""
- group: admissionregistration.k8s.io
- group: apiextensions.k8s.io
- group: apiregistration.k8s.io
- group: apps
- group: authentication.k8s.io
- group: authorization.k8s.io
- group: autoscaling
- group: batch
- group: certificates.k8s.io
- group: extensions
- group: metrics.k8s.io
- group: networking.k8s.io
- group: policy
- group: rbac.authorization.k8s.io
- group: scheduling.k8s.io
- group: settings.k8s.io
- group: storage.k8s.io
verbs:
- get
- list
- watch
# Default level for known APIs
- level: RequestResponse
omitStages:
- RequestReceived
resources:
- group: ""
- group: admissionregistration.k8s.io
- group: apiextensions.k8s.io
- group: apiregistration.k8s.io
- group: apps
- group: authentication.k8s.io
- group: authorization.k8s.io
- group: autoscaling
- group: batch
- group: certificates.k8s.io
- group: extensions
- group: metrics.k8s.io
- group: networking.k8s.io
- group: policy
- group: rbac.authorization.k8s.io
- group: scheduling.k8s.io
- group: settings.k8s.io
- group: storage.k8s.io
# Default level for all other requests.
- level: Metadata
omitStages:
- RequestReceived
EOF
kube-apiserver.service1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70source /etc/kubernetes/env.sh
for i in "${!MASTER_IPS[@]}"; do
NODE=${MASTER_IPS[$i]}
cat > ~/kube-apiserver.service.$NODE <<EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
[Service]
ExecStart=/usr/local/k8s/bin/kube-apiserver \\
--advertise-address=${NODE} \\
--default-not-ready-toleration-seconds=300 \\
--default-unreachable-toleration-seconds=300 \\
--feature-gates=DynamicAuditing=true \\
--max-mutating-requests-inflight=2000 \\
--max-requests-inflight=4000 \\
--default-watch-cache-size=200 \\
--delete-collection-workers=2 \\
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml \\
--etcd-cafile=/etc/kubernetes/ssl/ca.pem \\
--etcd-certfile=/etc/kubernetes/ssl/kube-apiserver.pem \\
--etcd-keyfile=/etc/kubernetes/ssl/kube-apiserver-key.pem \\
--etcd-servers=${ETCD_ENDPOINTS} \\
--bind-address=${NODE} \\
--secure-port=6443 \\
--tls-cert-file=/etc/kubernetes/ssl/kube-apiserver.pem \\
--tls-private-key-file=/etc/kubernetes/ssl/kube-apiserver-key.pem \\
--insecure-port=0 \\
--audit-dynamic-configuration \\
--audit-log-maxage=15 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-truncate-enabled \\
--audit-log-path=/data/logs/kube-apiserver/audit.log \\
--audit-policy-file=/etc/kubernetes/audit-policy.yaml \\
--profiling \\
--anonymous-auth=false \\
--client-ca-file=/etc/kubernetes/ssl/ca.pem \\
--enable-bootstrap-token-auth \\
--requestheader-allowed-names="aggregator" \\
--requestheader-client-ca-file=/etc/kubernetes/ssl/ca.pem \\
--requestheader-extra-headers-prefix="X-Remote-Extra-" \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-username-headers=X-Remote-User \\
--service-account-key-file=/etc/kubernetes/ssl/ca.pem \\
--authorization-mode=Node,RBAC \\
--runtime-config=api/all=true \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \\
--allow-privileged=true \\
--apiserver-count=3 \\
--event-ttl=168h \\
--kubelet-certificate-authority=/etc/kubernetes/ssl/ca.pem \\
--kubelet-client-certificate=/etc/kubernetes/ssl/kube-apiserver.pem \\
--kubelet-client-key=/etc/kubernetes/ssl/kube-apiserver-key.pem \\
--kubelet-https=true \\
--kubelet-timeout=10s \\
--proxy-client-cert-file=/etc/kubernetes/ssl/proxy-client.pem \\
--proxy-client-key-file=/etc/kubernetes/ssl/proxy-client-key.pem \\
--service-cluster-ip-range=${SERVICE_CIDR} \\
--service-node-port-range=${NODE_PORT_RANGE} \\
--logtostderr=true \\
--v=2
Restart=on-failure
RestartSec=10
Type=notify
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
done
1 | # 分发 |
授权kube-apiserver访问kubelet API的权限1
kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes
部署kube-controller-manager
三台 kube-controller-manager 集群,启动后通过竞争选举机制产生一个leader节点,其他节点为阻塞状态。当leader节点不可用时,阻塞节点将会在此选举产生新的leader,从而保证服务的高可用。
创建kube-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
29
30
31cd /etc/kubernetes/ssl/
cat > kube-controller-manager-csr.json <<EOF
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
"127.0.0.1",
"192.168.10.81",
"192.168.10.82",
"192.168.10.83"
],
"names": [
{
"C": "CN",
"ST": "Guangzhou",
"L": "Guangzhou",
"O": "system:kube-controller-manager",
"OU": "System"
}
]
}
EOF
# 生成证书和私钥
cfssl gencert -ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
kube-controller-manager.kubeconfig1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24cd /etc/kubernetes/ssl/
source /etc/kubernetes/env.sh
kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER_URL} \
--kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig
kubectl config set-credentials system:kube-controller-manager \
--client-certificate=kube-controller-manager.pem \
--client-key=kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig
kubectl config set-context system:kube-controller-manager \
--cluster=kubernetes \
--user=system:kube-controller-manager \
--kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig
kubectl config use-context system:kube-controller-manager --kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig
#kube-controller-manager使用kubeconfig文件访问apiserver
#该文件提供了apiserver地址、嵌入的CA证书和kube-controller-manager证书
kube-controller-manager.service1
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
48source /etc/kubernetes/env.sh
cat > ~/kube-controller-manager.service <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
ExecStart=/usr/local/k8s/bin/kube-controller-manager \\
--profiling \\
--cluster-name=kubernetes \\
--controllers=*,bootstrapsigner,tokencleaner \\
--kube-api-qps=1000 \\
--kube-api-burst=2000 \\
--leader-elect \\
--use-service-account-credentials\\
--concurrent-service-syncs=2 \\
--bind-address=0.0.0.0 \\
#--secure-port=10252 \\
--tls-cert-file=/etc/kubernetes/ssl/kube-controller-manager.pem \\
--tls-private-key-file=/etc/kubernetes/ssl/kube-controller-manager-key.pem \\
#--port=0 \\
--authentication-kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\
--client-ca-file=/etc/kubernetes/ssl/ca.pem \\
--requestheader-allowed-names="" \\
--requestheader-client-ca-file=/etc/kubernetes/ssl/ca.pem \\
--requestheader-extra-headers-prefix="X-Remote-Extra-" \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-username-headers=X-Remote-User \\
--authorization-kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\
--cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \\
--experimental-cluster-signing-duration=87600h \\
--horizontal-pod-autoscaler-sync-period=10s \\
--concurrent-deployment-syncs=10 \\
--concurrent-gc-syncs=30 \\
--node-cidr-mask-size=24 \\
--service-cluster-ip-range=${SERVICE_CIDR} \\
--pod-eviction-timeout=6m \\
--terminated-pod-gc-threshold=10000 \\
--root-ca-file=/etc/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem \\
--kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\
--logtostderr=true \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
1 | # 分发 |
kube-controller-manager 创建权限
ClusteRole system:kube-controller-manager的权限太小,只能创建secret、serviceaccount等资源,将controller的权限分散到ClusterRole system:controller:xxx中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# kubectl describe clusterrole system:kube-controller-manager
Name: system:kube-controller-manager
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
secrets [] [] [create delete get update]
endpoints [] [] [create get update]
serviceaccounts [] [] [create get update]
events [] [] [create patch update]
tokenreviews.authentication.k8s.io [] [] [create]
subjectaccessreviews.authorization.k8s.io [] [] [create]
configmaps [] [] [get]
namespaces [] [] [get]
*.* [] [] [list watch]
需要在 kube-controller-manager 的启动参数中添加 --use-service-account-credentials=true 参数,这样 main controller 会为各 controller 创建对应的 ServiceAccount XXX-controller。内置的 ClusterRoleBinding system:controller:XXX 将赋予各 XXX-controller ServiceAccount 对应的 ClusterRole system:controller:XXX 权限。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# kubectl get clusterrole|grep controller
system:controller:attachdetach-controller 22m
system:controller:certificate-controller 22m
system:controller:clusterrole-aggregation-controller 22m
system:controller:cronjob-controller 22m
system:controller:daemon-set-controller 22m
system:controller:deployment-controller 22m
system:controller:disruption-controller 22m
system:controller:endpoint-controller 22m
system:controller:expand-controller 22m
system:controller:generic-garbage-collector 22m
system:controller:horizontal-pod-autoscaler 22m
system:controller:job-controller 22m
system:controller:namespace-controller 22m
system:controller:node-controller 22m
system:controller:persistent-volume-binder 22m
system:controller:pod-garbage-collector 22m
system:controller:pv-protection-controller 22m
system:controller:pvc-protection-controller 22m
system:controller:replicaset-controller 22m
system:controller:replication-controller 22m
system:controller:resourcequota-controller 22m
system:controller:route-controller 22m
system:controller:service-account-controller 22m
system:controller:service-controller 22m
system:controller:statefulset-controller 22m
system:controller:ttl-controller 22m
system:kube-controller-manager 22m
以 deployment controller 为例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# kubectl describe clusterrole system:controller:deployment-controller
Name: system:controller:deployment-controller
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
replicasets.apps [] [] [create delete get list patch update watch]
replicasets.extensions [] [] [create delete get list patch update watch]
events [] [] [create patch update]
pods [] [] [get list update watch]
deployments.apps [] [] [get list update watch]
deployments.extensions [] [] [get list update watch]
deployments.apps/finalizers [] [] [update]
deployments.apps/status [] [] [update]
deployments.extensions/finalizers [] [] [update]
deployments.extensions/status [] [] [update]
查看当前的 leader1
2
3
4
5
6
7
8
9
10
11
12# kubectl get endpoints kube-controller-manager --namespace=kube-system -o yaml
apiVersion: v1
kind: Endpoints
metadata:
annotations:
control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"k8s-master01_e225d712-c25f-11e9-831f-000c29b1069b","leaseDurationSeconds":15,"acquireTime":"2019-08-19T09:01:08Z","renewTime":"2019-08-19T09:02:05Z","leaderTransitions":0}'
creationTimestamp: "2019-08-19T09:01:08Z"
name: kube-controller-manager
namespace: kube-system
resourceVersion: "1925"
selfLink: /api/v1/namespaces/kube-system/endpoints/kube-controller-manager
uid: e2299e08-c25f-11e9-b490-000c29b1069b
部署kube-scheduler
创建 kube-scheduler 证书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
31cd /etc/kubernetes/ssl/
cat > kube-scheduler-csr.json <<EOF
{
"CN": "system:kube-scheduler",
"hosts": [
"127.0.0.1",
"192.168.10.81",
"192.168.10.82",
"192.168.10.83"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Guangzhou",
"L": "Guangzhou",
"O": "system:kube-scheduler",
"OU": "System"
}
]
}
EOF
# 生成证书和私钥
cfssl gencert -ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
kube-scheduler.kubeconfig1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20cd /etc/kubernetes/ssl
source /etc/kubernetes/env.sh
kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER_URL} \
--kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig
kubectl config set-credentials system:kube-scheduler \
--client-certificate=kube-scheduler.pem \
--client-key=kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig
kubectl config set-context system:kube-scheduler \
--cluster=kubernetes \
--user=system:kube-scheduler \
--kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig
kubectl config use-context system:kube-scheduler --kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig
kube-scheduler.yaml1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16cat > /etc/kubernetes/kube-scheduler.yaml <<EOF
apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
bindTimeoutSeconds: 600
clientConnection:
burst: 200
kubeconfig: "/etc/kubernetes/kube-scheduler.kubeconfig"
qps: 100
enableContentionProfiling: false
enableProfiling: true
hardPodAffinitySymmetricWeight: 1
healthzBindAddress: 0.0.0.0:10251
leaderElection:
leaderElect: true
metricsBindAddress: 0.0.0.0:10251
EOF
kube-scheduler.service1
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
32source /etc/kubernetes/env.sh
for i in "${!MASTER_IPS[@]}"; do
NODE=${MASTER_IPS[$i]}
cat > ~/kube-scheduler.service.${NODE} <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
ExecStart=/usr/local/k8s/bin/kube-scheduler \\
--config=/etc/kubernetes/kube-scheduler.yaml \\
--bind-address=${NODE} \\
--secure-port=10259 \\
--port=0 \\
--tls-cert-file=/etc/kubernetes/ssl/kube-scheduler.pem \\
--tls-private-key-file=/etc/kubernetes/ssl/kube-scheduler-key.pem \\
--authentication-kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \\
--client-ca-file=/etc/kubernetes/ssl/ca.pem \\
--requestheader-allowed-names="" \\
--requestheader-client-ca-file=/etc/kubernetes/ssl/ca.pem \\
--requestheader-extra-headers-prefix="X-Remote-Extra-" \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-username-headers=X-Remote-User \\
--authorization-kubeconfig=/etc/kubernetes/kube-scheduler.kubeconfig \\
--logtostderr=true \\
--v=2
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
EOF
done
1 | # 分发 |
1 | 查看输出的 metrics |
查看当前leader1
2
3
4
5
6
7
8
9
10
11
12# kubectl get endpoints kube-scheduler --namespace=kube-system -o yaml
apiVersion: v1
kind: Endpoints
metadata:
annotations:
control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"k8s-master02_6360c5c0-c262-11e9-a2b9-000c29e02350","leaseDurationSeconds":15,"acquireTime":"2019-08-19T09:19:21Z","renewTime":"2019-08-19T09:19:51Z","leaderTransitions":1}'
creationTimestamp: "2019-08-19T09:18:54Z"
name: kube-scheduler
namespace: kube-system
resourceVersion: "2799"
selfLink: /api/v1/namespaces/kube-system/endpoints/kube-scheduler
uid: 5da1ecf2-c262-11e9-b490-000c29b1069b
部署node
分发node二进制1
2
3
4
5source /etc/kubernetes/env.sh
for NODE in ${NODE_IPS[@]};do
ssh root@$NODE "mkdir -p /usr/local/k8s/bin"
rsync kubernetes/server/bin/{kube-proxy,kubelet,kubectl} root@${NODE}:/usr/local/k8s/bin/
done
Docker步骤需要在所有node节点安装
若是需要master也作为node节点加入集群,也需要在master节点部署docker、kubelet、kube-proxy。1
2
3yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum -y install docker-ce
创建配置文件1
2
3
4
5
6
7
8
9
10
11cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=cgroupfs"],
"registry-mirrors": ["https://hub-mirror.c.163.com"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
启动docker服务1
2
3
4
5source /etc/kubernetes/env.sh
for NODE in ${NODE_IPS[@]};do
rsync /etc/docker/daemon.json root@${NODE}:/etc/docker/daemon.json
ssh root@${NODE} "systemctl daemon-reload && systemctl enable docker && systemctl restart docker"
done
部署kubelet
kubelet-config.yaml1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73source /etc/kubernetes/env.sh
for i in "${!NODE_IPS[@]}"; do
NODE=${NODE_IPS[$i]}
cat > ~/kubelet-config.yaml.${NODE} <<EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: "${NODE}"
staticPodPath: ""
syncFrequency: 1m
fileCheckFrequency: 20s
httpCheckFrequency: 20s
staticPodURL: ""
port: 10250
readOnlyPort: 0
rotateCertificates: true
serverTLSBootstrap: true
authentication:
anonymous:
enabled: false
webhook:
enabled: true
x509:
clientCAFile: "/etc/kubernetes/ssl/ca.pem"
authorization:
mode: Webhook
registryPullQPS: 0
registryBurst: 20
eventRecordQPS: 0
eventBurst: 20
enableDebuggingHandlers: true
enableContentionProfiling: true
healthzPort: 10248
healthzBindAddress: "${NODE}"
clusterDomain: "cluster.local"
clusterDNS:
- "${DNS_SERVICE_IP}"
nodeStatusUpdateFrequency: 10s
nodeStatusReportFrequency: 1m
imageMinimumGCAge: 2m
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
volumeStatsAggPeriod: 1m
kubeletCgroups: ""
systemCgroups: ""
cgroupRoot: ""
cgroupsPerQOS: true
cgroupDriver: systemd
runtimeRequestTimeout: 10m
hairpinMode: promiscuous-bridge
maxPods: 220
podCIDR: "${POD_CIDR}"
podPidsLimit: -1
resolvConf: /etc/resolv.conf
maxOpenFiles: 1000000
kubeAPIQPS: 1000
kubeAPIBurst: 2000
serializeImagePulls: false
evictionHard:
memory.available: "100Mi"
nodefs.available: "10%"
nodefs.inodesFree: "5%"
imagefs.available: "15%"
evictionSoft: {}
enableControllerAttachDetach: true
failSwapOn: true
containerLogMaxSize: 20Mi
containerLogMaxFiles: 10
systemReserved: {}
kubeReserved: {}
systemReservedCgroup: ""
kubeReservedCgroup: ""
enforceNodeAllocatable: ["pods"]
EOF
kubelet.service1
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
31source /etc/kubernetes/env.sh
for i in "${!NODE_IPS[@]}"; do
NODE=${NODE_IPS[$i]}
NODE_NAME=${NODE_NAMES[$i]}
cat > ~/kubelet.service.${NODE} <<EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
[Service]
ExecStart=/usr/local/k8s/bin/kubelet \\
--kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
--bootstrap-kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig \\
--config=/etc/kubernetes/kubelet-config.yaml \\
--cert-dir=/etc/kubernetes/ssl \\
--network-plugin=cni \\
--cni-conf-dir=/etc/cni/net.d \\
--hostname-override=${NODE_NAME} \\
--pod-infra-container-image=gcr.azk8s.cn/google_containers/pause-amd64:3.1 \\
--image-pull-progress-deadline=15m \\
--logtostderr=true \\
--cgroup-driver=cgroupfs \\
--v=2
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
EOF
done
kubelet-bootstrap-kubeconfig
注意查看token是否过期,如是重新创建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
31cd /etc/kubernetes/ssl
source /etc/kubernetes/env.sh
# 创建 token
export BOOTSTRAP_TOKEN=$(kubeadm token create \
--description kubelet-bootstrap-token \
--groups system:bootstrappers:kubernetes-clientgroup \
--kubeconfig ~/.kube/config)
# 设置集群参数
kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER_URL} \
--kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig
# 设置客户端认证参数
kubectl config set-credentials kubelet-bootstrap \
--token=${BOOTSTRAP_TOKEN} \
--kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig
# 设置上下文参数
kubectl config set-context default \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig
# 设置默认上下文
kubectl config use-context default --kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig
# grep token /etc/kubernetes/kubelet-bootstrap.kubeconfig
token: 2wpre5.7w2lu07fys9m70ix
查看kubeadm创建的token1
2
3# kubeadm token list --kubeconfig ~/.kube/config
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
2wpre5.7w2lu07fys9m70ix 23h 2019-08-24T07:20:04-04:00 authentication,signing kubelet-bootstrap-token system:bootstrappers:kubernetes-clientgroup
token有效期为1天,超期后将不能被用来bootstrap kubelet,且会被kube-controller-manager的token cleaner清理
kube-apiserver接收kubelet的bootstrap token后,将请求的user设置为system:bootstrap; group设置为system:bootstrappers,后续将为这个group设置ClusterRoleBinding
查看各token关联的Secret1
2# kubectl get secrets -n kube-system|grep bootstrap-token
bootstrap-token-2wpre5 bootstrap.kubernetes.io/token 7 51s
创建user和group的CSR权限,不创建kubelet会启动失败1
kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers
1 | # 分发 |
启动 kubelet 服务1
2
3
4source /etc/kubernetes/env.sh
for NODE in ${NODE_IPS[@]};do
ssh root@${NODE} "systemctl daemon-reload && systemctl enable kubelet --now"
done
csr-crb.yaml1
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
49
50
51
52
53
54
55
56cd /etc/kubernetes/
cat > csr-crb.yaml <<EOF
# Approve all CSRs for the group "system:bootstrappers"
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: auto-approve-csrs-for-group
subjects:
- kind: Group
name: system:bootstrappers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
apiGroup: rbac.authorization.k8s.io
# To let a node of the group "system:nodes" renew its own credentials
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: node-client-cert-renewal
subjects:
- kind: Group
name: system:nodes
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
apiGroup: rbac.authorization.k8s.io
# A ClusterRole which instructs the CSR approver to approve a node requesting a
# serving cert matching its client cert.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: approve-node-server-renewal-csr
rules:
- apiGroups: ["certificates.k8s.io"]
resources: ["certificatesigningrequests/selfnodeserver"]
verbs: ["create"]
# To let a node of the group "system:nodes" renew its own server credentials
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: node-server-cert-renewal
subjects:
- kind: Group
name: system:nodes
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: approve-node-server-renewal-csr
apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f csr-crb.yaml
1 | # kubectl get csr |
1 | # kubectl get nodes |
手动approve server cert csr
基于安全考虑,CSR approving controllers不会自动approve kubelet server证书签名请求,需要手动approve1
kubectl get csr | grep Pending | awk '{print $1}' | xargs kubectl certificate approve
bear token认证和授权
创建一个ServiceAccount,将它和ClusterRole system:kubelet-api-admin绑定,从而具有调用kubelet API的权限1
2
3
4
5kubectl create sa kubelet-api-test
kubectl create clusterrolebinding kubelet-api-test --clusterrole=system:kubelet-api-admin --serviceaccount=default:kubelet-api-test
SECRET=$(kubectl get secrets | grep kubelet-api-test | awk '{print $1}')
TOKEN=$(kubectl describe secret ${SECRET} | grep -E '^token' | awk '{print $2}')
echo ${TOKEN}
部署kube-proxy
确保已加载ipvs conntrack 模块
kube-proxy运行在所有worker节点上,它监听apiserver中service和endpoint的变化情况,创建路由规则提供服务IP和负载均衡功能。这里使用ipvs模式的kube-proxy进行部署
创建 kube-proxy 证书1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24cat > /etc/kubernetes/ssl/kube-proxy-csr.json <<EOF
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Guangzhou",
"L": "Guangzhou",
"O": "k8s",
"OU": "System"
}
]
}
EOF
# 生成证书和私钥
cfssl gencert -ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
kube-proxy.kubeconfig1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20source /etc/kubernetes/env.sh
cd /etc/kubernetes/ssl
kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER_URL} \
--kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig
kubectl config set-credentials kube-proxy \
--client-certificate=kube-proxy.pem \
--client-key=kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig
kube-proxy-config.yaml1
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
34source /etc/kubernetes/env.sh
for i in "${!NODE_IPS[@]}"; do
NODE=${NODE_IPS[$i]}
NODE_NAME=${NODE_NAMES[$i]}
cat > ~/kube-proxy-config.yaml.${NODE}<<EOF
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
burst: 200
kubeconfig: "/etc/kubernetes/kube-proxy.kubeconfig"
qps: 100
bindAddress: ${NODE}
healthzBindAddress: ${NODE}:10256
metricsBindAddress: ${NODE}:10249
enableProfiling: true
clusterCIDR: ${CLUSTER_CIDR}
hostnameOverride: ${NODE_NAME}
mode: "ipvs"
portRange: ""
kubeProxyIPTablesConfiguration:
masqueradeAll: false
kubeProxyIPVSConfiguration:
scheduler: rr
excludeCIDRs: []
EOF
done
#从v1.10开始,kube-proxy部分参数可以配置在文件中,可以使用–write-config-to选项生成该配置文件
bindAddress: 监听地址;
clientConnection.kubeconfig: 连接 apiserver 的 kubeconfig 文件;
--clusterCIDR: kube-proxy 根据 --cluster-cidr判断集群内部和外部流量,指定 --cluster-cidr 或 –masquerade-all 选项后 --kube-proxy 才会对访问 Service IP 的请求做 SNAT;
hostnameOverride: 参数值必须与 kubelet 的值一致,否则 kube-proxy 启动后会找不到该 Node,从而不会创建任何 ipvs 规则;
mode: 使用ipvs模式
kube-proxy.service1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16cat > ~/kube-proxy.service <<EOF
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
[Service]
ExecStart=/usr/local/k8s/bin/kube-proxy \\
--config=/etc/kubernetes/kube-proxy-config.yaml \\
--logtostderr=true \\
--v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
1 | # 分发 |
1 |
重新创建token
1 | #kubeadm token create --print-join-command |
部署calico网络
1 | curl https://docs.projectcalico.org/v3.9/manifests/calico-etcd.yaml -o calico.yaml |
多网卡可以指定接口1
2
3
4# https://docs.projectcalico.org/v3ip-autodetection-methods /reference/node/configuration#
# 默认情况下采用 first-found 方式获取,即获取第一个有效网卡的 IP 作为 node ip;在某些多网卡机器上可能会出现问题;这里将值设置为 can-reach=192.168 ,即使用第一个能够访问 master 192.168 的网卡地址作为 node ip
- name: IP_AUTODETECTION_METHOD
value: can-reach=192.168
1 | cat calico.yaml |
1 | #kubectl get deployment,pod -nkube-system |
docker service 运行calico1
2
3
4
5
6
7
8
9
10
11
12#https://docs.projectcalico.org/v3.9/getting-started/as-service
source /etc/kubernetes/env.sh
ETCD_ENDPOINTS=${ETCD_ENDPOINTS}
ETCD_CA_CERT_FILE="/etc/etcd/ssl/ca.pem"
ETCD_CERT_FILE="/etc/etcd/ssl/etcd.pem"
ETCD_KEY_FILE=".etc/etcd/ssl/etcd-key.pem"
CALICO_NODENAME=""
CALICO_NO_DEFAULT_POOLS=""
CALICO_IP=""
CALICO_IP6=""
CALICO_AS=""
CALICO_NETWORKING_BACKEND=bird
1 | cat <<EOF> calico-node.service |
calicoctl1
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#https://docs.projectcalico.org/master/getting-started/calicoctl/install
#calicoctl请github下载,官方在ubuntu 报错Segmentation fault
cd /usr/local/k8s/bin
wget https://github.com/projectcalico/calicoctl/releases/download/v3.9.2/calicoctl-linux-amd64 -o calicoctl
chmod +x calicoctl
mkdir /etc/calico
cat <<EOF> /etc/calico/calicoctl.cfg
#https://docs.projectcalico.org/master/getting-started/calicoctl/configure/
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
datastoreType: "etcdv3"
etcdEndpoints: "https://192.168.10.18:2379,https://192.168.10.20:2379,https://192.168.10.21:2379"
etcdKeyFile: "/etc/etcd/ssl/etcd-key.pem"
etcdCertFile: "/etc/etcd/ssl/etcd.pem"
etcdCACertFile: "/etc/etcd/ssl/ca.pem"
EOF
# calicoctl get node
NAME
k8s-master01
k8s-master02
k8s-master03
k8s-node01
k8s-node02
# calicoctl node status
Calico process is running.
IPv4 BGP status
+---------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+---------------+-------------------+-------+----------+-------------+
| 192.168.10.82 | node-to-node mesh | up | 09:45:55 | Established |
| 192.168.10.83 | node-to-node mesh | up | 09:45:54 | Established |
| 192.168.10.84 | node-to-node mesh | up | 09:45:54 | Established |
| 192.168.10.85 | node-to-node mesh | up | 09:45:54 | Established |
+---------------+-------------------+-------+----------+-------------+
IPv6 BGP status
No IPv6 peers found.
# calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR
default-ipv4-ippool 10.244.0.0/16 true Always Never false all()
测试 my-nginx
1 | cat > my-nginx.yaml <<EOF |
1 | # kubectl get pod -o wide |
检查服务IP和端口可达性1
2
3# kubectl get svc my-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx NodePort 10.110.21.241 <none> 83:9046/TCP 2m13s
我们在任意节点访问server IP1
ping 10.110.21.241
部署coredns
1 | cp /usr/local/src/kubernetes/cluster/addons/dns/coredns/coredns.yaml.base coredns.yaml |
测试corsdns1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26cat<<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.28.3
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
# kubectl get pod | grep busybox
busybox 1/1 Running 0 2m43s
# kubectl exec -ti busybox -- nslookup kubernetes
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
部署coredns自动扩容
https://github.com/kubernetes-incubator/cluster-proportional-autoscaler/
https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns-horizontal-autoscaler
部署ingress-nginx
https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md1
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
27mkdir /etc/kubernetes/yaml/ingress-nginx
cd /etc/kubernetes/yaml/ingress-nginx
https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
sed -i 's/quay.io/quay.azk8s.cn/' mandatory.yaml
kubectl apply -f .
#kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
NAMESPACE NAME READY STATUS RESTARTS AGE
ingress-nginx nginx-ingress-controller-69969b98db-shr6j 1/1 Running 0 58m
# kubectl get svc -ningress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.98.91.11 <none> 80:32634/TCP,443:30871/TCP 59m
POD_NAMESPACE=ingress-nginx
POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app.kubernetes.io/name=ingress-nginx -o jsonpath='{.items[0].metadata.name}')
kubectl exec -it $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version
#curl 10.98.91.11:443
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>openresty/1.15.8.2</center>
</body>
</html>
部署dashboard
先前已解压的 kubernetes-server-linux-amd64.tar.gz1
2
3mkdir -p kubernetes/dashboard
cd kubernetes/dashboard
cp -r local cluster dashboard .
service添加NodePort,使外界可以通过地址 NodeIP:NodePort 访问 dashboard1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17apiVersion: v1
kind: Service
metadata:
name: kubernetes-dashboard
namespace: kube-system
labels:
k8s-app: kubernetes-dashboard
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
spec:
type: NodePort #增加此行
selector:
k8s-app: kubernetes-dashboard
ports:
- port: 443
targetPort: 8443
nodePort: 30001 #指定端口
更换微软镜像源、执行1
2
3
4 ls *.yaml
dashboard-configmap.yaml dashboard-controller.yaml dashboard-rbac.yaml dashboard-secret.yaml dashboard-service.yaml
sed -i "s#k8s.gcr.io#$GCR_MIRROR#" dashboard-controller.yaml
kubectl apply -f .
查看pod 、service1
2
3
4
5
6# kubectl get pods -o wide -nkube-system | grep dashboard
kubernetes-dashboard-64ffdff795-vgwrg 1/1 Running 0 77s 10.244.40.74 k8s-node01 <none> <none>
# kubectl get services kubernetes-dashboard -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard NodePort 10.101.91.150 <none> 443:30001/TCP 2m15s
1 | cat << EOF > admin.yaml |
浏览器访问kube-apiserver1
2
3
4$ kubectl cluster-info
Kubernetes master is running at https://192.168.10.80:8443
CoreDNS is running at https://192.168.10.80:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
kubernetes-dashboard is running at https://192.168.10.80:8443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy
1 | cat > dashboard.json << EOF |
- kubernetes-dashboard service 暴露了 NodePort,可以使用 https://NodeIP:NodePort 地址访问 dashboard
- 通过 kube-apiserver 访问 dashboard
- 通过 kubectl proxy 访问 dashboard
gcr quay镜像代理
http://mirror.azure.cn/help/gcr-proxy-cache.html
http://mirror.azure.cn/help/quay-proxy-cache.html
gcr.azk8s.cn/google_containers/
registry.cn-hangzhou.aliyuncs.com/google_containers/
参考链接
http://www.debugger.wiki/article/html/1559106039872285
https://github.com/opsnull/follow-me-install-kubernetes-cluster