安装依赖包
1 | source /opt/k8s/bin/environment.sh |
docker
下载和分发 docker 二进制文件
到 docker 下载页面 下载最新发布包:
1 | cd /opt/k8s/work |
分发二进制文件到所有 worker 节点:
1 | cd /opt/k8s/work |
创建和分发 systemd unit 文件
1 | cd /opt/k8s/work |
分发 systemd unit 文件到所有 worker 机器:
1 | cd /opt/k8s/work |
配置和分发 docker 配置文件
使用国内的仓库镜像服务器以加快 pull image 的速度,同时增加下载的并发数 (需要重启 dockerd 生效):
1 | cd /opt/k8s/work |
分发 docker 配置文件到所有 worker 节点:
1 | cd /opt/k8s/work |
启动 docker 服务
1 | source /opt/k8s/bin/environment.sh |
检查服务运行状态
1 | source /opt/k8s/bin/environment.sh |
确保状态为 active (running)
kubelet
创建 kubelet bootstrap kubeconfig 文件
1 | cd /opt/k8s/work |
- 向 kubeconfig 写入的是 token,bootstrap 结束后 kube-controller-manager 为 kubelet 创建 client 和 server 证书;
查看 kubeadm 为各节点创建的 token:
1 | [root@node1 ~]# kubeadm token list --kubeconfig ~/.kube/config |
分发 bootstrap kubeconfig 文件到所有 worker 节点
1 | cd /opt/k8s/work |
创建和分发 kubelet 参数配置文件
创建 kubelet 参数配置文件模板(可配置项参考代码中注释 ):
1 | cd /opt/k8s/work |
- address:kubelet 安全端口(https,10250)监听的地址,不能为 127.0.0.1,否则 kube-apiserver、heapster 等不能调用 kubelet 的 API;
- readOnlyPort=0:关闭只读端口(默认 10255),等效为未指定;
- authentication.anonymous.enabled:设置为 false,不允许匿名访问 10250 端口;
- authentication.x509.clientCAFile:指定签名客户端证书的 CA 证书,开启 HTTP 证书认证;
- authentication.webhook.enabled=true:开启 HTTPs bearer token 认证;
- 对于未通过 x509 证书和 webhook 认证的请求(kube-apiserver 或其他客户端),将被拒绝,提示 Unauthorized;
- authroization.mode=Webhook:kubelet 使用 SubjectAccessReview API 查询 kube-apiserver 某 user、group 是否具有操作资源的权限(RBAC);
- featureGates.RotateKubeletClientCertificate、featureGates.RotateKubeletServerCertificate:自动 rotate 证书,证书的有效期取决于 kube-controller-manager 的 –experimental-cluster-signing-duration 参数;
- 需要 root 账户运行;
为各节点创建和分发 kubelet 配置文件:
1 | cd /opt/k8s/work |
创建和分发 kubelet systemd unit 文件
创建 kubelet systemd unit 文件模板:
1 | cd /opt/k8s/work |
- 如果设置了
--hostname-override
选项,则kube-proxy
也需要设置该选项,否则会出现找不到 Node 的情况; --bootstrap-kubeconfig
:指向 bootstrap kubeconfig 文件,kubelet 使用该文件中的用户名和 token 向 kube-apiserver 发送 TLS Bootstrapping 请求;- K8S approve kubelet 的 csr 请求后,在
--cert-dir
目录创建证书和私钥文件,然后写入--kubeconfig
文件; --pod-infra-container-image
不使用 redhat 的pod-infrastructure:latest
镜像,它不能回收容器的僵尸;
为各节点创建和分发 kubelet systemd unit 文件:
1 | cd /opt/k8s/work |
Bootstrap Token Auth 和授予权限
kubelet 启动时查找 --kubeletconfig
参数对应的文件是否存在,如果不存在则使用 --bootstrap-kubeconfig
指定的 kubeconfig 文件向 kube-apiserver 发送证书签名请求 (CSR)。
kube-apiserver 收到 CSR 请求后,对其中的 Token 进行认证,认证通过后将请求的 user 设置为 system:bootstrap:<Token ID>
,group 设置为 system:bootstrappers
,这一过程称为 Bootstrap Token Auth。
如果说kubelet启动失败的话:
创建一个 clusterrolebinding,将 group system:bootstrappers 和 clusterrole system:node-bootstrapper 绑定:
1 | $ kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers |
启动 kubelet 服务
1 | source /opt/k8s/bin/environment.sh |
kubelet 启动后使用 –bootstrap-kubeconfig 向 kube-apiserver 发送 CSR 请求,当这个 CSR 被 approve 后,kube-controller-manager 为 kubelet 创建 TLS 客户端证书、私钥和 –kubeletconfig 文件。
注意:kube-controller-manager 需要配置 --cluster-signing-cert-file
和 --cluster-signing-key-file
参数,才会为 TLS Bootstrap 创建证书和私钥。
自动 approve CSR 请求
创建三个 ClusterRoleBinding,分别用于自动 approve client、renew client、renew server 证书:
1 | cd /opt/k8s/work |
- auto-approve-csrs-for-group:自动 approve node 的第一次 CSR; 注意第一次 CSR 时,请求的 Group 为 system:bootstrappers;
- node-client-cert-renewal:自动 approve node 后续过期的 client 证书,自动生成的证书 Group 为 system:nodes;
- node-server-cert-renewal:自动 approve node 后续过期的 server 证书,自动生成的证书 Group 为 system:nodes;
手动 approve server cert csr
基于安全性考虑,CSR approving controllers 不会自动 approve kubelet server 证书签名请求,需要手动 approve:
1 | $ kubectl get csr |
kubelet 提供的 API 接口
- 10248: healthz http 服务;
- 10250: https 服务,访问该端口时需要认证和授权(即使访问 /healthz 也需要);
- 未开启只读端口 10255;
- 从 K8S v1.10 开始,去除了
--cadvisor-port
参数(默认 4194 端口),不支持访问 cAdvisor UI & API。
例如执行 kubectl exec -it nginx-ds-5rmws -- sh
命令时,kube-apiserver 会向 kubelet 发送如下请求:
1 | POST /exec/default/nginx-ds-5rmws/my-nginx?command=sh&input=1&output=1&tty=1 |
kubelet 接收 10250 端口的 https 请求,可以访问如下资源:
- /pods、/runningpods
- /metrics、/metrics/cadvisor、/metrics/probes
- /spec
- /stats、/stats/container
- /logs
- /run/、/exec/, /attach/, /portForward/, /containerLogs/
详情参考:https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/server/server.go#L434:3
由于关闭了匿名认证,同时开启了 webhook 授权,所有访问 10250 端口 https API 的请求都需要被认证和授权。
预定义的 ClusterRole system:kubelet-api-admin 授予访问 kubelet 所有 API 的权限(kube-apiserver 使用的 kubernetes 证书 User 授予了该权限):
1 | $ kubectl describe clusterrole system:kubelet-api-admin |
kubelet api 认证和授权
kubelet 配置了如下认证参数:
- authentication.anonymous.enabled:设置为 false,不允许匿名访问 10250 端口;
- authentication.x509.clientCAFile:指定签名客户端证书的 CA 证书,开启 HTTPs 证书认证;
- authentication.webhook.enabled=true:开启 HTTPs bearer token 认证;
同时配置了如下授权参数:
- authroization.mode=Webhook:开启 RBAC 授权;
kubelet 收到请求后,使用 clientCAFile 对证书签名进行认证,或者查询 bearer token 是否有效。如果两者都没通过,则拒绝请求,提示 Unauthorized:
1 | $ curl -s --cacert /etc/kubernetes/cert/ca.pem https://192.168.6.101:10250/metrics |
通过认证后,kubelet 使用 SubjectAccessReview API 向 kube-apiserver 发送请求,查询证书或 token 对应的 user、group 是否有操作资源的权限(RBAC);
证书认证和授权
1 | $ # 权限不足的证书; |
--cacert
、--cert
、--key
的参数值必须是文件路径,如上面的./admin.pem
不能省略./
,否则返回401 Unauthorized
;
bear token 认证和授权
创建一个 ServiceAccount,将它和 ClusterRole system:kubelet-api-admin 绑定,从而具有调用 kubelet API 的权限:
1 | kubectl create sa kubelet-api-test |
kube-proxy
创建 kube-proxy 证书
创建证书签名请求:
1 | cd /opt/k8s/work |
- CN:指定该证书的 User 为
system:kube-proxy
; - 预定义的 RoleBinding
system:node-proxier
将Usersystem:kube-proxy
与 Rolesystem:node-proxier
绑定,该 Role 授予了调用kube-apiserver
Proxy 相关 API 的权限; - 该证书只会被 kube-proxy 当做 client 证书使用,所以 hosts 字段为空;
生成证书和私钥:
1 | cd /opt/k8s/work |
创建和分发 kubeconfig 文件
1 | cd /opt/k8s/work |
--embed-certs=true
:将 ca.pem 和 admin.pem 证书内容嵌入到生成的 kubectl-proxy.kubeconfig 文件中(不加时,写入的是证书文件路径);
分发 kubeconfig 文件:
1 | cd /opt/k8s/work |
创建 kube-proxy 配置文件
从 v1.10 开始,kube-proxy 部分参数可以配置文件中配置。可以使用 --write-config-to
选项生成该配置文件,或者参考 源代码的注释。
创建 kube-proxy config 文件模板:
1 | cd /opt/k8s/work |
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 配置文件:
1 | cd /opt/k8s/work |
创建和分发 kube-proxy systemd unit 文件
1 | cd /opt/k8s/work |
分发 kube-proxy systemd unit 文件:
1 | cd /opt/k8s/work |
启动 kube-proxy 服务
1 | cd /opt/k8s/work |
- 启动服务前必须先创建工作目录;
检查启动结果
1 | source /opt/k8s/bin/environment.sh |
确保状态为 active (running)
查看 ipvs 路由规则
1 | source /opt/k8s/bin/environment.sh |