kubernetes 集群部署(TLS认证)
第1章 部署准备
1.1 组件版本 && 集群环境
1.1.1 组件版本
Kubernetes 1.8.3
Docker 18.03.1-ce
Etcd 3.2.9
Flanneld
TLS 认证通信(所有组件,如etcd、kubernetes master 和node)
RBAC 授权
kubelet TLS Bootstrapping
1.1.2 集群环境
[root@k8s_master ~]# uname -a
Linux k8s_master 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
[root@k8s_master ~]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
两台服务器(一台用作master一台用作slave)
10.0.0.190 k8s_master
10.0.0.191 k8s_slave
1.2 集群环境变量
# TLS Bootstrapping 使用的Token,可以使用命令 head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成
BOOTSTRAP_TOKEN="8981b594122ebed7596f1d3b69c78223"
# 建议使用未用的网段来定义服务网段和Pod 网段
# 服务网段(Service CIDR),部署前路由不可达,部署后集群内部使用IP:Port可达
SERVICE_CIDR="10.254.0.0/16"
# Pod 网段(Cluster CIDR),部署前路由不可达,部署后路由可达(flanneld 保证)
CLUSTER_CIDR="172.30.0.0/16"
# 服务端口范围(NodePort Range)
NODE_PORT_RANGE="30000-32766" #创建pod后分配端口范围
# etcd服务地址列表
ETCD_ENDPOINTS="http://10.0.0.190:2379" #etcd服务地址
# flanneld 网络配置前缀
FLANNEL_ETCD_PREFIX="/k8s/network"
# kubernetes 服务IP(预先分配,一般为SERVICE_CIDR中的第一个IP)
CLUSTER_KUBERNETES_SVC_IP="10.254.0.1"
# 集群 DNS 服务IP(从SERVICE_CIDR 中预先分配)
CLUSTER_DNS_SVC_IP="10.254.0.2"
# 集群 DNS 域名
CLUSTER_DNS_DOMAIN="cluster.local."
说明:将上面变量保存为: env.sh,然后将脚本拷贝到所有机器的/usr/local/bin目录。
第2章 创建CA 证书和密钥
kubernetes 系统各个组件需要使用TLS证书对通信进行加密,这里我们使用CloudFlare的PKI 工具集cfssl 来生成Certificate Authority(CA) 证书和密钥文件, CA 是自签名的证书,用来签名后续创建的其他TLS 证书。
2.1 安装 CFSSL
[root@k8s_master ~]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
[root@k8s_master ~]# chmod +x cfssl_linux-amd64
[root@k8s_master ~]# mv cfssl_linux-amd64 /usr/bin/cfssl
[root@k8s_master ~]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
[root@k8s_master ~]# chmod +x cfssljson_linux-amd64
[root@k8s_master ~]# mv cfssljson_linux-amd64 /usr/bin/cfssljson
[root@k8s_master ~]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
[root@k8s_master ~]# chmod +x cfssl-certinfo_linux-amd64
[root@k8s_master ~]# mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo
[root@k8s_master ~]# export PATH=/usr/k8s/bin:$PATH
[root@k8s_master ~]# mkdir ssl && cd ssl
[root@k8s_master ssl]# cfssl print-defaults config > config.json
[root@k8s_master ssl]# cfssl print-defaults csr > csr.json
说明:为了方便,将/usr/local/bin设置成环境变量,为了重启也有效,可以将上面的export PATH=/usr/local/bin:$PATH添加到/etc/rc.local文件中。
2.2 创建CA
2.2.1 修改上面创建的config.json文件为ca-config.json:
[root@k8s_master ssl]# cat ca-config.json
{
"signing": {
"default": {
"expiry": "8760h" #证书的有效时间
},
"profiles": {
"kubernetes": {
"expiry": "8760h", #证书的有效时间
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
参数说明:
config.json:可以定义多个profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个profile;
signing: 表示该证书可用于签名其它证书;生成的ca.pem 证书中CA=TRUE;
server auth: 表示client 可以用该CA 对server 提供的证书进行校验;
client auth: 表示server 可以用该CA 对client 提供的证书进行验证。
2.2.2 修改CA 证书签名为ca-csr.json:
[root@k8s_master ssl]# cat ca-csr.json
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
参数说明:
CN: Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名(User Name);浏览器使用该字段验证网站是否合法;
O: Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组(Group);
2.2.2.1 生成CA 证书和私钥:
[root@k8s_master ssl]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2018/09/15 09:08:00 [INFO] generating a new CA key and certificate from CSR
2018/09/15 09:08:00 [INFO] generate received request
2018/09/15 09:08:00 [INFO] received CSR
2018/09/15 09:08:00 [INFO] generating key: rsa-2048
2018/09/15 09:08:00 [INFO] encoded CSR
2018/09/15 09:08:00 [INFO] signed certificate with serial number 388728220321633548679905650114339188496612614157
[root@k8s_master ssl]# ls ca*
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem
2.2.3 分发证书
2.2.3.1 将生成的CA 证书、密钥文件、配置文件拷贝到所有机器的/etc/kubernetes/ssl目录下面:
[root@k8s_master ssl]# mkdir -p /etc/kubernetes/ssl
[root@k8s_master ssl]# cp ca* /etc/kubernetes/ssl
第3章 k8s集群部署
3.1 部署etcd服务
3.1.1 定义环境变量
export NODE_NAME=k8s_master # 当前部署的机器名称(随便定义,只要能区分不同机器即可)
export NODE_IP=10.0.0.190 # 当前部署的机器IP
export NODE_IPS="10.0.0.190" # etcd服务的 IP
# etcd的IP和端口
export ETCD_NODES=k8s_master=http://10.0.0.190
# 导入用到的其它全局变量:ETCD_ENDPOINTS、FLANNEL_ETCD_PREFIX、CLUSTER_CIDR
source /usr/local/bin/env.sh
3.1.2 下载etcd 二进制文件
3.1.2.1 到https://github.com/coreos/etcd/releases页面下载最新版本的二进制文件:
[root@k8s_master ~]# wget https://github.com/coreos/etcd/releases/download/v3.2.9/etcd-v3.2.9-linux-amd64.tar.gz
[root@k8s_master ~]# tar xf etcd-v3.2.9-linux-amd64.tar.gz
[root@k8s_master ~]# cp etcd-v3.2.9-linux-amd64/etcd* /usr/bin/
[root@k8s_master ~]# ll /usr/bin/etcd*
-rwxrwxr-x 1 1000 1000 17123360 Oct 6 2017 /usr/bin/etcd
-rwxrwxr-x 1 1000 1000 14640128 Oct 6 2017 /usr/bin/etcdctl
3.1.3 创建etcd 的systemd unit 文件
[root@k8s_master ~]# mkdir -p /var/lib/etcd # 必须要先创建工作目录
[root@k8s_master ~]# cat > etcd.service <<EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos
[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
ExecStart=/usr/bin/etcd \\
--name=k8s_master \\
--initial-advertise-peer-urls=http://10.0.0.190:2380 \\
--listen-peer-urls=http://10.0.0.190:2380 \\
--listen-client-urls=http://10.0.0.190:2379,http://127.0.0.1:2379 \\
--advertise-client-urls=http://10.0.0.190:2379 \\
--data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
指定etcd的工作目录和数据目录为/var/lib/etcd,需要在启动服务前创建这个目录
3.1.3.1 启动etcd 服务
[root@k8s_master ~]# mv etcd.service /usr/lib/systemd/system/
[root@k8s_master ~]# systemctl start etcd
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl start etcd
[root@k8s_master ~]# systemctl status etcd
[root@k8s_master ~]# systemctl enable etcd
3.2 配置kubectl 命令行工具
说明:kubectl默认从~/.kube/config配置文件中获取访问kube-apiserver 地址、证书、用户名等信息,需要正确配置该文件才能正常使用kubectl命令。
需要将下载的kubectl 二进制文件和生产的~/.kube/config配置文件拷贝到需要使用kubectl 命令的机器上。
3.2.1 环境变量
[root@k8s_master ~]# source /usr/local/bin/env.sh
[root@k8s_master ~]# export KUBE_APISERVER="https://10.0.0.190:6443"
[root@k8s_master ~]# echo $KUBE_APISERVER
https://10.0.0.190:6443
变量KUBE_APISERVER 指定kubelet 访问的kube-apiserver 的地址,后续被写入~/.kube/config配置文件
3.2.2 下载并复制二进制文件到/usr/bin目录
https://github.com/kubernetes/kubernetes/releases (k8s各版本下载)
[root@k8s_master ~]# wget https://dl.k8s.io/v1.8.3/kubernetes-server-linux-amd64.tar.gz
[root@k8s_master ~]# tar xf kubernetes-server-linux-amd64.tar.gz
[root@k8s_master ~]# cp kubernetes/server/bin/{kubectl,kubefed} /usr/bin/
[root@k8s_master ~]# ll /usr/bin/kube*
-rwxr-x--- 1 root root 52269537 Sep 15 10:10 /usr/bin/kubectl
-rwxr-x--- 1 root root 55868971 Sep 15 10:10 /usr/bin/kubefed
[root@k8s_master ~]# export PATH=/usr/local/bin:$PATH
3.2.3 创建admin 证书
3.2.3.1 kubectl 与kube-apiserver 的安全端口通信,需要为安全通信提供TLS 证书和密钥。创建admin 证书:
[root@k8s_master ~]# cd ssl/
cat > admin-csr.json <<EOF
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "System"
}
]
}
EOF
说明:
1)后续kube-apiserver使用RBAC 对客户端(如kubelet、kube-proxy、Pod)请求进行授权
2)kube-apiserver 预定义了一些RBAC 使用的RoleBindings,如cluster-admin 将Group system:masters与Role cluster-admin绑定,该Role 授予了调用kube-apiserver所有API 的权限
3)O 指定了该证书的Group 为system:masters,kubectl使用该证书访问kube-apiserver时,由于证书被CA 签名,所以认证通过,同时由于证书用户组为经过预授权的system:masters,所以被授予访问所有API 的劝降
4)hosts 属性值为空列表
3.2.4 生成admin 证书和私钥:
[root@k8s_master ssl]# cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \
-ca-key=/etc/kubernetes/ssl/ca-key.pem \
-config=/etc/kubernetes/ssl/ca-config.json \
-profile=kubernetes admin-csr.json | cfssljson -bare admin
[root@k8s_master ssl]# ls admin*
admin.csr admin-csr.json admin-key.pem admin.pem
[root@k8s_master ssl]# mv admin*.pem /etc/kubernetes/ssl/
3.2.5 创建kubectl kubeconfig 文件
# 设置集群参数
[root@k8s_master ssl]# kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER}
# 设置客户端认证参数
[root@k8s_master ssl]# kubectl config set-credentials admin \
--client-certificate=/etc/kubernetes/ssl/admin.pem \
--embed-certs=true \
--client-key=/etc/kubernetes/ssl/admin-key.pem
# 设置上下文参数
[root@k8s_master ssl]# kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=admin
# 设置默认上下文
[root@k8s_master ssl]# kubectl config use-context kubernetes
- admin.pem证书O 字段值为system:masters,kube-apiserver 预定义的 RoleBinding cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予了调用kube-apiserver 相关 API 的权限
- 生成的kubeconfig 被保存到 ~/.kube/config 文件
3.2.5.1 分发kubeconfig 文件
将/.kube/config文件拷贝到运行kubectl命令的机器的/.kube/目录下去。
3.3 部署Flannel 网络
kubernetes 要求集群内各节点能通过Pod 网段互联互通,下面我们来使用Flannel 在所有节点上创建互联互通的Pod 网段的步骤。
3.3.1 环境变量
[root@k8s_master ssl]# export NODE_IP=10.0.0.190 #当前部署节点的ip
[root@k8s_master ssl]# source /usr/local/bin/env.sh #导入全局环境变量
3.3.2 向etcd 写入集群Pod 网段信息
[root@k8s_master ssl]# etcdctl set /k8s/network/config '{"Network":"'172.30.0.0/16'"}'
{"Network":"172.30.0.0/16"}
[root@k8s-master ~]# etcdctl get /k8s/network/config
{ "Network": "172.30.0.0/16" }
写入的 Pod 网段(172.30.0.0/16) 必须与kube-controller-manager 的 --cluster-cidr 选项值一致;
3.3.3 安装和配置flanneld
3.3.3.1 前往flanneld release页面下载最新版的flanneld 二进制文件:
[root@k8s_master ~]# mkdir flannel
[root@k8s_master ~]# wget https://github.com/coreos/flannel/releases/download/v0.9.0/flannel-v0.9.0-linux-amd64.tar.gz
[root@k8s_master ~]# tar -xzvf flannel-v0.9.0-linux-amd64.tar.gz -C flannel
[root@k8s_master ~]# cp flannel/{flanneld,mk-docker-opts.sh} /usr/bin
3.3.3.2 创建flanneld的systemd unit 文件
[root@k8s_master ~]# cat > flanneld.service << EOF
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service
[Service]
Type=notify
ExecStart=/usr/bin/flanneld \\
-etcd-endpoints=${ETCD_ENDPOINTS} \\
-etcd-prefix=${FLANNEL_ETCD_PREFIX}
ExecStartPost=/usrl/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=on-failure
[Install]
WantedBy=multi-user.target
RequiredBy=docker.service
EOF
1) mk-docker-opts.sh脚本将分配给flanneld 的Pod 子网网段信息写入到/run/flannel/docker 文件中,后续docker 启动时使用这个文件中的参数值为 docker0 网桥
2) flanneld 使用系统缺省路由所在的接口和其他节点通信,对于有多个网络接口的机器(内网和公网),可以用 --iface 选项值指定通信接口(上面的 systemd unit 文件没指定这个选项)
3.3.3.4 启动flanneld
[root@k8s_master ~]# mv flanneld.service /usr/lib/systemd/system/
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl start flannel
[root@k8s_master ~]# systemctl status flanneld
[root@k8s_master ~]# systemctl enable flanneld
3.4 部署master 节点
3.4.1 kubernetes master 节点包含的组件有:
1. kube-apiserver
2. kube-scheduler
3. kube-controller-manager
说明:目前这3个组件需要部署到同一台机器上:
- kube-scheduler、kube-controller-manager 和 kube-apiserver 三者的功能紧密相关;
- 同时只能有一个 kube-scheduler、kube-controller-manager 进程处于工作状态,如果运行多个,则需要通过选举产生一个 leader;
- master 节点与node 节点上的Pods 通过Pod 网络通信,所以需要在master 节点上部署Flannel 网络。
3.4.2 环境变量
[root@k8s_master ~]# export MASTER_IP=10.0.0.190 #当前部署master节点ip
[root@k8s_master ~]# source /usr/local/bin/env.sh
3.4.3 下载最新版本的二进制文件
https://github.com/kubernetes/kubernetes/releases #k8s版本下载连接
[root@k8s_master ~]# wget https://dl.k8s.io/v1.8.3/kubernetes-server-linux-amd64.tar.gz
[root@k8s_master ~]# tar -xzvf kubernetes-server-linux-amd64.tar.gz
[root@k8s_master ~]# cd kubernetes
3.4.3.1 将二进制文件拷贝到/usr/bin目录
[root@k8s_master ~]# cp -r server/bin/{kube-apiserver,kube-controller-manager,kube-scheduler,kube-proxy,kubelet} /usr/bin/
3.4.4 创建kubernetes 证书
3.4.4.1 创建kubernetes 证书签名请求:
[root@k8s_master ~]# cat > kubernetes-csr.json <<EOF
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"${MASTER_IP}",
"${CLUSTER_KUBERNETES_SVC_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": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
如果 hosts 字段不为空则需要指定授权使用该证书的 IP 或域名列表,所以上面分别指定了当前部署的 master 节点主机 IP 以及apiserver 负载的内部域名
还需要添加 kube-apiserver 注册的名为 kubernetes 的服务 IP (Service Cluster IP),一般是 kube-apiserver --service-cluster-ip-range 选项值指定的网段的第一个IP,如 “10.254.0.1”
3.4.4.2 生成kubernetes 证书和私钥:
[root@k8s_master ssl]# cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \
-ca-key=/etc/kubernetes/ssl/ca-key.pem \
-config=/etc/kubernetes/ssl/ca-config.json \
-profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
[root@k8s_master ssl]# ls kubernetes*
kubernetes.csr kubernetes-csr.json kubernetes-key.pem kubernetes.pem
[root@k8s_master ssl]# mv kubernetes*.pem /etc/kubernetes/ssl/
3.4.5 配置和启动kube-apiserver
3.4.5.1 创建kube-apiserver 使用的客户端token 文件
kubelet 首次启动时向kube-apiserver 发送TLS Bootstrapping 请求,kube-apiserver 验证请求中的token 是否与它配置的token.csv 一致,如果一致则自动为kubelet 生成证书和密钥。
#导入的env.sh文件定义了BOOTSTRAP_TOKEN变量
[root@k8s_master ssl]# cat > token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
[root@k8s_master ssl]# mv token.csv /etc/kubernetes/
3.4.5.2 创建kube-apiserver 的systemd unit文件
cat > kube-apiserver.service <<EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
[Service]
ExecStart=/usr/bin/kube-apiserver \\
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
--advertise-address=${MASTER_IP} \\
--bind-address=${MASTER_IP} \\
--insecure-bind-address=${MASTER_IP} \\
--authorization-mode=Node,RBAC \\
--runtime-config=rbac.authorization.k8s.io/v1alpha1 \\
--kubelet-https=true \\
--experimental-bootstrap-token-auth \\
--token-auth-file=/etc/kubernetes/token.csv \\
--service-cluster-ip-range=${SERVICE_CIDR} \\
--service-node-port-range=${NODE_PORT_RANGE} \\
--tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem \\
--tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \\
--client-ca-file=/etc/kubernetes/ssl/ca.pem \\
--service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \\
--etcd-cafile=/etc/kubernetes/ssl/ca.pem \\
--etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem \\
--etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem \\
--etcd-servers=${ETCD_ENDPOINTS} \\
--enable-swagger-ui=true \\
--allow-privileged=true \\
--apiserver-count=3 \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/var/lib/audit.log \\
--event-ttl=1h \\
--v=2
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
kube-apiserver 1.6 版本开始使用 etcd v3 API 和存储格式
--authorization-mode=RBAC 指定在安全端口使用RBAC 授权模式,拒绝未通过授权的请求
kube-scheduler、kube-controller-manager 一般和 kube-apiserver 部署在同一台机器上,它们使用非安全端口和 kube-apiserver通信
kubelet、kube-proxy、kubectl 部署在其它 Node 节点上,如果通过安全端口访问 kube-apiserver,则必须先通过 TLS 证书认证,再通过 RBAC 授权
kube-proxy、kubectl 通过使用证书里指定相关的 User、Group 来达到通过 RBAC 授权的目的
如果使用了 kubelet TLS Boostrap 机制,则不能再指定 --kubelet-certificate-authority、–kubelet-client-certificate 和 --kubelet-client-key 选项,否则后续 kube-apiserver 校验 kubelet 证书时出现 ”x509: certificate signed by unknown authority“ 错误
--admission-control 值必须包含 ServiceAccount,否则部署集群插件时会失败
--bind-address 不能为 127.0.0.1
--service-cluster-ip-range 指定 Service Cluster IP 地址段,该地址段不能路由可达
--service-node-port-range=${NODE_PORT_RANGE} 指定 NodePort 的端口范围
缺省情况下 kubernetes 对象保存在etcd/registry 路径下,可以通过 --etcd-prefix 参数进行调整
kube-apiserver 1.8版本后需要在–authorization-mode参数中添加Node,即:–authorization-mode=Node,RBAC,否则Node 节点无法注册
3.4.5.3 启动kube-apiserver
[root@k8s_master ~]# mv kube-apiserver.service /usr/lib/systemd/system/
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl enable kube-apiserver
[root@k8s_master ~]# systemctl start kube-apiserver
[root@k8s_master ~]# systemctl status kube-apiserver
3.4.6 配置和启动kube-controller-manager
3.4.6.1 创建kube-controller-manager 的systemd unit 文件
cat > kube-controller-manager.service <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
ExecStart=/root/local/bin/kube-controller-manager \\
--address=127.0.0.1 \\
--master=http://${MASTER_IP}:8080 \\
--allocate-node-cidrs=true \\
--service-cluster-ip-range=${SERVICE_CIDR} \\
--cluster-cidr=${CLUSTER_CIDR} \\
--cluster-name=kubernetes \\
--cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \\
--service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem \\
--root-ca-file=/etc/kubernetes/ssl/ca.pem \\
--leader-elect=true \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
--address 值必须为 127.0.0.1,因为当前 kube-apiserver 期望 scheduler 和 controller-manager 在同一台机器
kubectl get componentstatuses
NAME STATUS MESSAGE ERROR
controller-manager Unhealthy Get http://127.0.0.1:10252/healthz: dial tcp 127.0.0.1:10252: getsockopt: connection refused
scheduler Unhealthy Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: getsockopt: connection refused
--master=http://{MASTER_IP}:8080:使用非安全 8080 端口与 kube-apiserver 通信
--cluster-cidr 指定 Cluster 中 Pod 的 CIDR 范围,该网段在各 Node 间必须路由可达(flanneld保证)
--service-cluster-ip-range 参数指定 Cluster 中 Service 的CIDR范围,该网络在各 Node 间必须路由不可达,必须和 kube-apiserver 中的参数一致
--cluster-signing-* 指定的证书和私钥文件用来签名为 TLS BootStrap 创建的证书和私钥
--root-ca-file 用来对 kube-apiserver 证书进行校验,指定该参数后,才会在Pod 容器的 ServiceAccount 中放置该 CA 证书文件
--leader-elect=true 部署多台机器组成的 master 集群时选举产生一处于工作状态的 kube-controller-manager 进程
3.4.6.2 启动kube-controller-manager
[root@k8s_master ~]# mv kube-controller-manager.service /usr/lib/systemd/system/
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl start kube-controller-manager
[root@k8s_master ~]# systemctl status kube-controller-manager
[root@k8s_master ~]# systemctl enable kube-controller-manager
3.4.7 配置和启动kube-scheduler
3.4.7.1 创建kube-scheduler 的systemd unit文件
cat > kube-scheduler.service <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
ExecStart=/usr/bin/kube-scheduler \\
--address=127.0.0.1 \\
--master=http://${MASTER_IP}:8080 \\
--leader-elect=true \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
--address 值必须为 127.0.0.1,因为当前 kube-apiserver 期望 scheduler 和 controller-manager 在同一台机器
--master=http://${MASTER_URL}:使用http(非安全端口)与 kube-apiserver 通信
--leader-elect=true 部署多台机器组成的 master 集群时选举产生一处于工作状态的 kube-controller-manager 进程
3.4.7.2 启动kube-scheduler
[root@k8s_master ~]# mv kube-scheduler.service /usr/lib/systemd/system
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl start kube-scheduler
[root@k8s_master ~]# systemctl status kube-scheduler
[root@k8s_master ~]# systemctl enable kube-scheduler
3.4.7.3 验证master 节点
[root@k8s_master ~]# kubectl get componentstatuses
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health": "true"}
3.5 部署Node 节点
3.5.1 kubernetes Node 节点包含如下组件:
flanneld
docker
kubelet
kube-proxy
3.5.2 环境变量
[root@k8s_slave ~]# source /usr/local/bin/env.sh
[root@k8s_slave ~]# export KUBE_APISERVER="https://10.0.0.190:6443"
[root@k8s_slave ~]# echo $KUBE_APISERVER
https://10.0.0.190:6443
[root@k8s_slave ~]# export NODE_IP=10.0.0.191 #当前部署节点的ip
3.5.3 部署flanneld网络
[root@k8s_slave ~]# mkdir flannel
[root@k8s_slave ~]# wget https://github.com/coreos/flannel/releases/download/v0.9.0/flannel-v0.9.0-linux-amd64.tar.gz
[root@k8s_slave ~]# tar -xzvf flannel-v0.9.0-linux-amd64.tar.gz -C flannel
[root@k8s_slave ~]# cp flannel/{flanneld,mk-docker-opts.sh} /usr/bin
3.5.3.1 创建flanneld的systemd unit 文件
cat > flanneld.service << EOF
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service
[Service]
Type=notify
ExecStart=/usr/bin/flanneld \\
-etcd-endpoints=${ETCD_ENDPOINTS} \\
-etcd-prefix=${FLANNEL_ETCD_PREFIX}
ExecStartPost=/usr/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=on-failure
[Install]
WantedBy=multi-user.target
RequiredBy=docker.service
EOF
3.5.3.2 启动flanneld服务
cp flanneld.service /usr/lib/systemd/system/
systemctl daemon-reload
systemctl enable flanneld
systemctl start flanneld
systemctl status flanneld
3.5.4 部署docker
3.5.4.1 下载最新的 docker 二进制文件
[root@k8s_slave ~]# https://download.docker.com/linux/static/stable/x86_64/docker-18.03.1-ce.tgz
[root@k8s_slave ~]# tar -xvf docker-18.03.1-ce.tgz
[root@k8s_slave ~]# cp docker/docker* /usr/bin
3.5.4.2 创建 docker 的 systemd unit 文件
[root@k8s_slave ~]# cat docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io
[Service]
EnvironmentFile=-/run/flannel/docker
ExecStart=/usr/bin/dockerd --log-level=error $DOCKER_NETWORK_OPTIONS
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process
[Install]
WantedBy=multi-user.target
3.5.4.3 启动docker
[root@k8s_slave ~]# mv docker.service /usr/lib/systemd/system/
[root@k8s_slave ~]# systemctl daemon-reload
[root@k8s_slave ~]# systemctl start docker
[root@k8s_slave ~]# systemctl status docker
[root@k8s_slave ~]# systemctl enable docker
docker 从 1.13 版本开始,可能将 iptables FORWARD chain的默认策略设置为DROP,从而导致 ping 其它 Node 上的 Pod IP 失败,遇到这种情况时,需要手动设置策略为 ACCEPT:
[root@k8s_slave ~]# iptables -P FORWARD ACCEPT
并且把以下命令写入/etc/rc.local文件中,防止节点重启iptables FORWARD chain的默认策略又还原为DROP
[root@k8s_slave ~]# sleep 60 && /sbin/iptables -P FORWARD ACCEPT
为了加快 pull image 的速度,可以使用国内的仓库镜像服务器,同时增加下载的并发数。(如果 dockerd 已经运行,则需要重启 dockerd 生效。)
[root@k8s_slave ~]# cat /etc/docker/daemon.json
{
"max-concurrent-downloads": 10
}
3.5.5 安装和配置kubelet
3.5.5.1 从master上面拷贝证书文件到slave
[root@k8s_master kubernetes]# scp -r ./* 10.0.0.191:/etc/kubernetes/
kubelet 启动时向kube-apiserver 发送TLS bootstrapping 请求,需要先将bootstrap token 文件中的kubelet-bootstrap 用户赋予system:node-bootstrapper 角色,然后kubelet 才有权限创建认证请求(certificatesigningrequests):
[root@k8s_slave kubernetes]# kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap
clusterrolebinding "kubelet-bootstrap" created
说明:–user=kubelet-bootstrap 是文件 /etc/kubernetes/token.csv 中指定的用户名,同时也写入了文件 /etc/kubernetes/bootstrap.kubeconfig
另外1.8 版本中还需要为Node 请求创建一个RBAC 授权规则:
[root@k8s_slave kubernetes]# kubectl create clusterrolebinding kubelet-nodes --clusterrole=system:node --group=system:nodes
clusterrolebinding "kubelet-nodes" created
3.5.5.2 下载最新的kubelet 和kube-proxy 二进制文件(前面下载kubernetes 目录下面其实也有)
[root@k8s_slave ~]# wget https://dl.k8s.io/v1.8.2/kubernetes-server-linux-amd64.tar.gz
[root@k8s_slave ~]# tar -xzvf kubernetes-server-linux-amd64.tar.gz
[root@k8s_slave ~]# cd kubernetes
[root@k8s_slave ~]# tar -xzvf kubernetes-src.tar.gz
[root@k8s_slave ~]# cp -r ./server/bin/{kube-proxy,kubelet} /usr/bin/
3.5.5.3 创建kubelet bootstapping kubeconfig 文件
#以下需要在master上面创建,创建完成后copy到每个node节点即可
[root@k8s_master ~]# mkdir ssl && cd ssl
#设置集群参数
[root@k8s_mster ~]# kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=bootstrap.kubeconfig
#设置客户端认证参数
[root@k8s_master ~]# kubectl config set-credentials kubelet-bootstrap \
--token=${BOOTSTRAP_TOKEN} \
--kubeconfig=bootstrap.kubeconfig
[root@k8s_master ~]# 设置上下文参数
[root@k8s_master ~]# kubectl config set-context default \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=bootstrap.kubeconfig
#设置默认上下文
[root@k8s_master ~]# kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
[root@k8s_master ~]# mv bootstrap.kubeconfig /etc/kubernetes/
[root@k8s_master ~]# scp bootstrap.kubeconfig 10.0.0.191:/etc/kubernetes/
--embed-certs 为 true 时表示将 certificate-authority 证书写入到生成的 bootstrap.kubeconfig 文件中;
设置 kubelet 客户端认证参数时没有指定秘钥和证书,后续由 kube-apiserver 自动生成;
3.5.5.4 创建kubelet 的systemd unit 文件
[root@k8s_slave ssl]# mkdir /var/lib/kubelet # 必须先创建工作目录
[root@k8s_slave ]# cat > kubelet.service <<EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/usr/bin/kubelet \\
--address=${NODE_IP} \\
--hostname-override=${NODE_IP} \\
--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest \\
--experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \\
--kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
--require-kubeconfig \\
--cert-dir=/etc/kubernetes/ssl \\
--cluster-dns=${CLUSTER_DNS_SVC_IP} \\
--cluster-domain=${CLUSTER_DNS_DOMAIN} \\
--hairpin-mode promiscuous-bridge \\
--allow-privileged=true \\
--serialize-image-pulls=false \\
--fail-swap-on=false \\
--logtostderr=true \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
-address 不能设置为 127.0.0.1,否则后续 Pods 访问 kubelet 的 API 接口时会失败,因为 Pods 访问的 127.0.0.1指向自己而不是 kubelet
如果设置了 --hostname-override 选项,则 kube-proxy 也需要设置该选项,否则会出现找不到 Node 的情况
--experimental-bootstrap-kubeconfig 指向 bootstrap kubeconfig 文件,kubelet 使用该文件中的用户名和 token 向 kube-apiserver 发送 TLS Bootstrapping 请求
管理员通过了 CSR 请求后,kubelet 自动在 --cert-dir 目录创建证书和私钥文件(kubelet-client.crt 和 kubelet-client.key),然后写入 --kubeconfig 文件(自动创建 --kubeconfig 指定的文件)
建议在 --kubeconfig 配置文件中指定 kube-apiserver 地址,如果未指定 --api-servers 选项,则必须指定 --require-kubeconfig 选项后才从配置文件中读取 kue-apiserver 的地址,否则 kubelet 启动后将找不到 kube-apiserver (日志中提示未找到 API Server),kubectl get nodes 不会返回对应的 Node 信息
--cluster-dns 指定 kubedns 的 Service IP(可以先分配,后续创建 kubedns 服务时指定该 IP),–cluster-domain 指定域名后缀,这两个参数同时指定后才会生效
3.5.5.5 启动kubelet
[root@k8s_slave ~]# mv kubelet.service /usr/lib/systemd/system/
[root@k8s_slave ~]# systemctl daemon-reload
[root@k8s_slave ~]# systemctl start kubelet
[root@k8s_slave ~]# systemctl status kubelet
[root@k8s_slave ~]# systemctl enable kubelet
3.5.5.6 通过kubelet 的TLS 证书请求
kubelet 首次启动时向kube-apiserver 发送证书签名请求,必须通过后kubernetes 系统才会将该 Node 加入到集群。查看未授权的CSR 请求:
[root@k8s_master ~]# kubectl get csr
NAME AGE REQUESTOR CONDITION
node-csr-VME_P37qMAy5qZaFQXIfbkI-L64nSEbUyyvtxYe7EAQ 1m kubelet-bootstrap Pending
[root@k8s_master ~]# kubectl get nodes
No resources found.
3.5.5.7 通过CSR 请求:
[root@k8s_master ~]# kubectl certificate approve node-csr-VME_P37qMAy5qZaFQXIfbkI-L64nSEbUyyvtxYe7EAQ
certificatesigningrequest "node-csr-VME_P37qMAy5qZaFQXIfbkI-L64nSEbUyyvtxYe7EAQ" approved
[root@k8s_master kubernetes]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
10.0.0.191 Ready <none> 1m v1.8.3
3.5.5.8 自动生成了kubelet kubeconfig 文件和公私钥:
[root@k8s_slave kubernetes]# ll /etc/kubernetes/kubelet.kubeconfig
-rw------- 1 root root 2277 Sep 16 03:31 /etc/kubernetes/kubelet.kubeconfig
[root@k8s_slave kubernetes]# ls -l /etc/kubernetes/ssl/kubelet*
-rw-r--r-- 1 root root 1042 Sep 16 03:31 /etc/kubernetes/ssl/kubelet-client.crt
-rw------- 1 root root 227 Sep 16 03:27 /etc/kubernetes/ssl/kubelet-client.key
-rw-r--r-- 1 root root 1107 Sep 16 03:25 /etc/kubernetes/ssl/kubelet.crt
-rw------- 1 root root 1679 Sep 16 03:25 /etc/kubernetes/ssl/kubelet.key
3.5.6 配置kube-proxy(master创建好后copy到slave节点即可)
3.5.6.1 创建kube-proxy 证书签名请求
[root@k8s_master ~]# cd /root/ssl
[root@k8s_master ssl]# cat > kube-proxy-csr.json <<EOF
{
"CN": "system:kube-proxy",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
CN 指定该证书的 User 为 system:kube-proxy
kube-apiserver 预定义的 RoleBinding system:node-proxier 将User system:kube-proxy 与 Role system:node-proxier绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
hosts 属性值为空列表
3.5.6.2 生成kube-proxy 客户端证书和私钥(从master创建后好copy到slave节点)
[root@k8s_master ssl]# cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \
-ca-key=/etc/kubernetes/ssl/ca-key.pem \
-config=/etc/kubernetes/ssl/ca-config.json \
-profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
[root@k8s_master ssl]# ls kube-proxy*
kube-proxy.csr kube-proxy-csr.json kube-proxy-key.pem kube-proxy.pem
[root@k8s_master ssl]# scp kube-proxy* 10.0.0.191:/root/ssl/ #从mastet节点拷贝到slave节点
[root@k8s_slave ssl]# mv kube-proxy*.pem /etc/kubernetes/ssl/
3.5.6.3 创建kube-proxy kubeconfig 文件(从master创建后好copy到slave节点)
#设置集群参数
[root@k8s_master ssl]# kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kube-proxy.kubeconfig
#设置客户端认证参数
[root@k8s_master ssl]# kubectl config set-credentials kube-proxy \
--client-certificate=/etc/kubernetes/ssl/kube-proxy.pem \
--client-key=/etc/kubernetes/ssl/kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=kube-proxy.kubeconfig
#设置上下文参数
[root@k8s_master ssl]#kubectl config set-context default \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=kube-proxy.kubeconfig
[root@k8s_master ssl]# 设置默认上下文
[root@k8s_master ssl]# kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
[root@k8s_master ssl]#mv kube-proxy.kubeconfig /etc/kubernetes/
[root@k8s_master ssl]#scp kube-proxy.kubeconfig 10.0.0.191:/etc/kubernetes/
设置集群参数和客户端认证参数时 --embed-certs 都为 true,这会将 certificate-authority、client-certificate 和 client-key 指向的证书文件内容写入到生成的 kube-proxy.kubeconfig 文件中
kube-proxy.pem 证书中 CN 为 system:kube-proxy,kube-apiserver 预定义的 RoleBinding cluster-admin 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
3.5.6.4 创建kube-proxy 的systemd unit 文件
[root@k8s_slave ssl]# mkdir -p /var/lib/kube-proxy # 必须先创建工作目录
[root@k8s_slave ssl]# cat > kube-proxy.service <<EOF
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
[Service]
WorkingDirectory=/var/lib/kube-proxy
ExecStart=/usr/bin/kube-proxy \\
--bind-address=${NODE_IP} \\
--hostname-override=${NODE_IP} \\
--cluster-cidr=${CLUSTER_CIDR} \\
--kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \\
--logtostderr=true \\
--v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
--hostname-override 参数值必须与 kubelet 的值一致,否则 kube-proxy 启动后会找不到该 Node,从而不会创建任何 iptables 规则
--cluster-cidr 必须与 kube-apiserver 的 --service-cluster-ip-range 选项值一致
kube-proxy 根据 --cluster-cidr 判断集群内部和外部流量,指定 --cluster-cidr 或 --masquerade-all 选项后 kube-proxy 才会对访问 Service IP 的请求做 SNAT
--kubeconfig 指定的配置文件嵌入了 kube-apiserver 的地址、用户名、证书、秘钥等请求和认证信息
预定义的 RoleBinding cluster-admin 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
3.5.6.5 启动kube-proxy
[root@k8s_slave ~]# mv kube-proxy.service /usr/lib/systemd/system/
[root@k8s_slave ~]# systemctl daemon-reload
[root@k8s_slave ~]# systemctl start kube-proxy
[root@k8s_slave ~]# systemctl status kube-proxy
[root@k8s_slave ~]# systemctl enable kube-proxy
3.6 验证集群功能
3.6.1 定义yaml 文件
[root@k8s_master nginx]# cat nginx_rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 1
selector:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
3.6.2 定义service文件
[root@k8s_master nginx]# cat nginx_svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
ports:
- port: 80
nodePort: 30006
selector:
app: nginx
3.6.2.1 创建nginx服务
[root@k8s_master nginx]# kubectl create -f nginx_rc.yaml
[root@k8s_master nginx]# kubectl create -f nginx_svc.yaml