kube-on-kube-operator 开发(三)

本文是介绍 kubernetes-operator 开发的第三篇,前几篇已经提到过 kubernetes-operator 的主要目标是实现以下三种场景中的集群管理:

  • kube-on-kube
  • kube-to-kube
  • kube-to-cloud-kube

目前笔者主要在开发 kube-to-kube,这一节会介绍 kube-to-kube 中如何使用二进制方式部署一个集群,问什么要先支持部署二进制集群呢,可以参考之前的文章。目前 kubernetes-operator 中部署集群是通过 ansible 调用笔者写的一些脚本部署的,由于 kubernetes 二进制文件比较大,暂时仅支持离线部署,部署前请下载好所需的二进制文件,笔者也提供了部署 v1.14 需要的所有二进制文件、镜像、yaml 等。

二进制安装 kubernetes 最困难的地方就在于其复杂的认证(Authentication)及鉴权(Authorization)机制,上篇文章已经介绍了 kubernetes 中的认证与鉴权机制以及其中的证书链,若安装过程中有疑问请参考 浅析 kubernetes 的认证与鉴权机制

使用 kubernetes-operator 管理集群时首选需要有一个元集群,元集群可以使用 minkube 或者 kind 部署一个单机版集群,然后将 kubernetes-operator 部署到该集群中再通过创建 CR 来部署一个业务集群,最后使用该业务集群作为元集群即可,或者也可以使用 kubernetes-operator 中部署业务集群的方式来部署元集群。

部署集群前请先克隆 https://github.com/gosoon/kubernetes-operatorhttps://github.com/gosoon/kubernetes-utils 项目,部署集群所需要的一些工具、配置以及 bin 文件都存放在这两个项目中,你也可以使用自己的配置。

准备环境

禁用防火墙:

1
2
$ systemctl stop firewalld
$ systemctl disable firewalld

禁用 SELinux:

1
2
$ setenforce 0
$ sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

关闭 swap:

1
swapoff -a

修改内核参数:

1
2
3
4
5
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

配置 CA 及创建 TLS 证书

安装证书生成工具,本文使用 cfssl

1
$ cp kubernetes-utils/scripts/bin/certs/* /usr/bin/

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
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
$ cat << EOF > etcd-root-ca-csr.json
{
"CN": "etcd-root-ca",
"key": {
"algo": "rsa",
"size": 4096
},
"names": [
{
"O": "etcd",
"OU": "etcd Security",
"L": "Beijing",
"ST": "Beijing",
"C": "CN"
}
],
"ca": {
"expiry": "87600h"
}
}
EOF

$ cat << EOF > etcd-gencert.json
{
"signing": {
"default": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
EOF

$ cat << EOF > etcd-csr.json
{
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"O": "etcd",
"OU": "etcd Security",
"L": "Beijing",
"ST": "Beijing",
"C": "CN"
}
],
"CN": "etcd"
}
EOF

$ cat << EOF > config-etcd-peer.json
{
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"O": "etcd",
"OU": "etcd Security",
"L": "Beijing",
"ST": "Beijing",
"C": "CN"
}
],
"CN": "etcd"
}
EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cfssl gencert --initca=true etcd-root-ca-csr.json | cfssljson -bare output/ca

// 指定 etcd hosts,etcd server 和 etcd peer 中必须包含所有 etcd 的 hosts,eg:ETCD_HOSTS="10.0.4.15,10.0.2.15"
# etcd server
$ cfssl gencert \
-ca=output/ca.pem \
-ca-key=output/ca-key.pem \
-config=ca-config.json \
-hostname=127.0.0.1,${ETCD_HOSTS} \
-profile=server \
server.json | cfssljson -bare output/etcd-server

# etcd peer
$ cfssl gencert \
-ca=output/ca.pem \
-ca-key=output/ca-key.pem \
-config=ca-config.json \
-hostname=127.0.0.1,${ETCD_HOSTS} \
-profile=peer \
server.json | cfssljson -bare output/etcd-peer

生成证书后反解 etcd server 和 peer 证书校验 ip 是否正确:

1
$ cfssl certinfo -cert etcd-peer.pem

master

由于 master 组件的 CSR 配置与 kubernetes 中的认证与鉴权相关联,需要严格按照 kubernetes 中默认的 RBAC 进行配置,每个组件都有默认的 user 或者 group。

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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
$ cat << EOF > ca-csr.json
{
"CN": "Kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "China",
"L": "Shanghai",
"O": "Kubernetes",
"OU": "Shanghai",
"ST": "Shanghai"
}
]
}
EOF

$ cat << EOF > ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "87600h"
}
}
}
}
EOF


// kube-apiserver csr
$ cat << EOF > kube-apiserver-csr.json
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "China",
"L": "Shanghai",
"O": "Kubernetes",
"OU": "Kubernetes",
"ST": "Shanghai"
}
]
}
EOF

// kube-controller-manager csr
$ cat << EOF > kube-controller-manager-csr.json
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "China",
"L": "Shanghai",
"O": "system:kube-controller-manager",
"OU": "Kubernetes",
"ST": "Shanghai"
}
]
}
EOF

// kube-scheduler csr
$ cat << EOF > kube-scheduler-csr.json
{
"CN": "system:kube-scheduler",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "China",
"L": "Shanghai",
"O": "system:kube-scheduler",
"OU": "Kubernetes",
"ST": "Shanghai"
}
]
}
EOF

// kubelet csr,请替换 nodeName
$ cat << EOF > kubelet-csr.json
{
"CN": "system:node:<nodeName>",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "China",
"L": "Shanghai",
"O": "system:nodes",
"OU": "Kubernetes",
"ST": "Shanghai"
}
]
}
EOF

// apiserver client csr
$ cat << EOF > apiserver-kubelet-client-csr.json
{
"CN": "system:kubelet-api-admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "China",
"L": "Shanghai",
"O": "system:masters",
"OU": "Kubernetes",
"ST": "Shanghai"
}
]
}
EOF

// kube-proxy csr
$ cat << EOF > kube-proxy-csr.json
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "China",
"L": "Shanghai",
"O": "system:node-proxier",
"OU": "Kubernetes",
"ST": "Shanghai"
}
]
}
EOF

// kubectl csr
$ cat << EOF > admin-csr.json
{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "China",
"L": "Shanghai",
"O": "system:masters",
"OU": "Kubernetes",
"ST": "Shanghai"
}
]
}
EOF


$ cfssl gencert -initca ca-csr.json | cfssljson -bare output/ca

为了保证客户端与 Kubernetes API 的认证,Kubernetes API Server 凭证中必需包含 master 的静态 IP 地址,在 hostname 中指定
# apiserver
$ cfssl gencert \
-ca=output/ca.pem \
-ca-key=output/ca-key.pem \
-config=ca-config.json \
-hostname=10.250.0.1,${MASTER_HOSTS},${MASTER_VIP},127.0.0.1,kubernetes,kubernetes.default,kubernetes.default.svc \
-profile=kubernetes \
kube-apiserver-csr.json | cfssljson -bare output/kube-apiserver

# kubelet
for node in `echo ${NODE_HOSTS} | tr ',' ' '`;do
cfssl gencert \
-ca=output/ca.pem \
-ca-key=output/ca-key.pem \
-config=ca-config.json \
-hostname=${NODE_HOSTS} \
-profile=kubernetes \
kubelet-csr.json | cfssljson -bare output/kubelet
done

# other component
for component in kube-controller-manager kube-scheduler kube-proxy apiserver-kubelet-client admin service-account;do
cfssl gencert \
-ca=output/ca.pem \
-ca-key=output/ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
${component}-csr.json | cfssljson -bare output/${component}
done

生成 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
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
// 替换 apiserver 
KUBE_APISERVER="https://10.0.4.15:6443"
CERTS_DIR="/etc/kubernetes/ssl"

# 生成 kubectl 配置文件
echo "Create kubectl kubeconfig..."
kubectl config set-cluster kubernetes \
--certificate-authority=${CERTS_DIR}/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=output/kubectl.kubeconfig
kubectl config set-credentials "system:masters" \
--client-certificate=${CERTS_DIR}/admin.pem \
--client-key=${CERTS_DIR}/admin-key.pem \
--embed-certs=true \
--kubeconfig=output/kubectl.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user=system:masters \
--kubeconfig=output/kubectl.kubeconfig
kubectl config use-context default --kubeconfig=output/kubectl.kubeconfig

# 生成 kube-controller-manager 配置文件
echo "Create kube-controller-manager kubeconfig..."
kubectl config set-cluster kubernetes \
--certificate-authority=${CERTS_DIR}/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=output/kube-controller-manager.kubeconfig
kubectl config set-credentials "system:kube-controller-manager" \
--client-certificate=${CERTS_DIR}/kube-controller-manager.pem \
--client-key=${CERTS_DIR}/kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=output/kube-controller-manager.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user=system:kube-controller-manager \
--kubeconfig=output/kube-controller-manager.kubeconfig
kubectl config use-context default --kubeconfig=output/kube-controller-manager.kubeconfig

# 生成 kube-scheduler 配置文件
echo "Create kube-scheduler kubeconfig..."
kubectl config set-cluster kubernetes \
--certificate-authority=${CERTS_DIR}/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=output/kube-scheduler.kubeconfig
kubectl config set-credentials "system:kube-scheduler" \
--client-certificate=${CERTS_DIR}/kube-scheduler.pem \
--client-key=${CERTS_DIR}/kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=output/kube-scheduler.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user=system:kube-scheduler \
--kubeconfig=output/kube-scheduler.kubeconfig
kubectl config use-context default --kubeconfig=output/kube-scheduler.kubeconfig


# 生成 kubelet 配置文件,需要添加对应的 nodeName
echo "Create kubelet kubeconfig..."
kubectl config set-cluster kubernetes \
--certificate-authority=${CERTS_DIR}/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=output/kubelet-${node}.kubeconfig

kubectl config set-credentials system:node:${node} \
--client-certificate=${CERTS_DIR}/kubelet.pem \
--client-key=${CERTS_DIR}/kubelet-key.pem \
--embed-certs=true \
--kubeconfig=output/kubelet-${node}.kubeconfig

kubectl config set-context default \
--cluster=kubernetes \
--user=system:node:${node} \
--kubeconfig=${CERTS_DIR}/kubelet-${node}.kubeconfig
kubectl config use-context default --kubeconfig=output/kubelet-${node}.kubeconfig


# 生成 kube-proxy 配置文件
echo "Create kube-proxy kubeconfig..."
kubectl config set-cluster kubernetes \
--certificate-authority=${CERTS_DIR}/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=output/kube-proxy.kubeconfig
kubectl config set-credentials "system:kube-proxy" \
--client-certificate=${CERTS_DIR}/kube-proxy.pem \
--client-key=${CERTS_DIR}/kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=output/kube-proxy.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user=system:kube-proxy \
--kubeconfig=output/kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=output/kube-proxy.kubeconfig

部署

部署 etcd

拷贝证书文件:

1
$ cp output/* /etc/etcd/ssl/

拷贝 bin 文件:

1
$ cp kubernetes-utils/scripts/bin/etcd_v3.3.13/* /usr/bin/

拷贝配置文件,配置文件中的 ip 需要手动替换掉:

1
$ cp kubernetes-operator/scripts/config/etcd/etcd.conf /etc/etcd/

部署 k8s master 组件

拷贝证书文件:

1
$ cp output/* /etc/kubernetes/ssl/

拷贝 bin 文件:

1
$ cp kubernetes-utils/scripts/bin/kubernetes_v1.14.0/* /usr/bin/

拷贝配置文件,配置文件中的 ip 需要手动替换掉:

1
$ cp kubernetes-operator/scripts/config/master/* /etc/kubernetes/

部署 k8s node 组件

部署 docker,拷贝 bin 文件:

1
$ cp kubernetes-utils/scripts/bin/docker-ce-18.06.1.ce/*  /usr/bin/

拷贝证书文件:

1
$ cp output/* /etc/kubernetes/ssl/

拷贝配置文件,配置文件中的 ip 需要手动替换掉:

1
$ cp kubernetes-operator/scripts/config/node/* /etc/kubernetes/

创建 systemd 文件

拷贝所有服务的 systemd 文件:

拷贝配置文件,配置文件中的 ip 需要手动替换掉:

1
$ cp kubernetes-operator/scripts/systemd/* /usr/lib/systemd/system/

启动服务

首先启动 etcd 服务,etcd 所部署的几个节点需要同时启动,否则服务会启动失败。

然后依次启动 master 上的组件和 node 上的组件。

总结

本文主要讲述了 kubernetes-operator 中 kube-to-kube 部署集群的方式,介绍了主要的部署步骤,文中部署集群所有的操作都提供了脚本的方式:https://github.com/gosoon/kubernetes-operator/tree/master/scripts。 kube-to-kube 的部署方式暂时是以 ansible + 自定义脚本的方式部署,部署方式也在持续更新与完善中。接下来会继续开发 kube-on-kube 的部署方式,kube-on-kube 会将业务集群的 master 组件部署在元集群中,kube-on-kube 方式暂时会采用对 kubeadm 封装的形式进行部署。