## 04-安装kube-master节点 部署master节点主要包含三个组件`apiserver` `scheduler` `controller-manager`,其中: - apiserver提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等 - 只有API Server才直接操作etcd - 其他模块通过API Server查询或修改数据 - 提供其他模块之间的数据交互和通信的枢纽 - scheduler负责分配调度Pod到集群内的node节点 - 监听kube-apiserver,查询还未分配Node的Pod - 根据调度策略为这些Pod分配节点 - controller-manager由一系列的控制器组成,它通过apiserver监控整个集群的状态,并确保集群处于预期的工作状态 master节点的高可用主要就是实现apiserver组件的高可用,后面我们会看到每个 node 节点会启用 4 层负载均衡来请求 apiserver 服务。 ``` text roles/kube-master/ ├── defaults │   └── main.yml ├── tasks │   └── main.yml └── templates ├── aggregator-proxy-csr.json.j2 ├── basic-auth.csv.j2 ├── basic-auth-rbac.yaml.j2 ├── kube-apiserver.service.j2 ├── kube-apiserver-v1.8.service.j2 ├── kube-controller-manager.service.j2 ├── kubernetes-csr.json.j2 └── kube-scheduler.service.j2 ``` 请在另外窗口打开[roles/kube-master/tasks/main.yml](../../roles/kube-master/tasks/main.yml) 文件,对照看以下讲解内容。 ### 创建 kubernetes 证书签名请求 ``` bash { "CN": "kubernetes", "hosts": [ "127.0.0.1", {% if groups['ex-lb']|length > 0 %} "{{ hostvars[groups['ex-lb'][0]]['EX_APISERVER_VIP'] }}", {% endif %} "{{ inventory_hostname }}", "{{ CLUSTER_KUBERNETES_SVC_IP }}", {% for host in MASTER_CERT_HOSTS %} "{{ host }}", {% endfor %} "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster", "kubernetes.default.svc.cluster.local" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "HangZhou", "L": "XS", "O": "k8s", "OU": "System" } ] } ``` - kubernetes 证书既是服务器证书,同时apiserver又作为客户端证书去访问etcd 集群;作为服务器证书需要设置hosts 指定使用该证书的IP 或域名列表,需要注意的是: - 如果配置 ex-lb,需要把 EX_APISERVER_VIP 也配置进去 - 如果需要外部访问 apiserver,需要在 defaults/main.yml 配置 MASTER_CERT_HOSTS - `kubectl get svc` 将看到集群中由api-server 创建的默认服务 `kubernetes`,因此也要把 `kubernetes` 服务名和各个服务域名也添加进去 ### 【可选】创建基础用户名/密码认证配置 若未创建任何基础认证配置,K8S集群部署完毕后访问dashboard将会提示`401`错误。 当前如需创建基础认证,需单独修改`roles/kube-master/defaults/main.yml`文件,将`BASIC_AUTH_ENABLE`改为`yes`,并相应配置用户名`BASIC_AUTH_USER`(默认用户名为`admin`)及密码`BASIC_AUTH_PASS`。 ### 创建apiserver的服务配置文件 ``` bash [Unit] Description=Kubernetes API Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=network.target [Service] ExecStart={{ bin_dir }}/kube-apiserver \ --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook \ --bind-address={{ inventory_hostname }} \ --insecure-bind-address=127.0.0.1 \ --authorization-mode=Node,RBAC \ --kubelet-https=true \ --kubelet-client-certificate={{ ca_dir }}/admin.pem \ --kubelet-client-key={{ ca_dir }}/admin-key.pem \ --anonymous-auth=false \ --basic-auth-file={{ ca_dir }}/basic-auth.csv \ --service-cluster-ip-range={{ SERVICE_CIDR }} \ --service-node-port-range={{ NODE_PORT_RANGE }} \ --tls-cert-file={{ ca_dir }}/kubernetes.pem \ --tls-private-key-file={{ ca_dir }}/kubernetes-key.pem \ --client-ca-file={{ ca_dir }}/ca.pem \ --service-account-key-file={{ ca_dir }}/ca-key.pem \ --etcd-cafile={{ ca_dir }}/ca.pem \ --etcd-certfile={{ ca_dir }}/kubernetes.pem \ --etcd-keyfile={{ ca_dir }}/kubernetes-key.pem \ --etcd-servers={{ ETCD_ENDPOINTS }} \ --enable-swagger-ui=true \ --endpoint-reconciler-type=lease \ --allow-privileged=true \ --audit-log-maxage=30 \ --audit-log-maxbackup=3 \ --audit-log-maxsize=100 \ --audit-log-path=/var/lib/audit.log \ --event-ttl=1h \ --requestheader-client-ca-file={{ ca_dir }}/ca.pem \ --requestheader-allowed-names= \ --requestheader-extra-headers-prefix=X-Remote-Extra- \ --requestheader-group-headers=X-Remote-Group \ --requestheader-username-headers=X-Remote-User \ --proxy-client-cert-file={{ ca_dir }}/aggregator-proxy.pem \ --proxy-client-key-file={{ ca_dir }}/aggregator-proxy-key.pem \ --enable-aggregator-routing=true \ --runtime-config=batch/v2alpha1=true \ --v=2 Restart=on-failure RestartSec=5 Type=notify LimitNOFILE=65536 [Install] WantedBy=multi-user.target ``` + Kubernetes 对 API 访问需要依次经过认证、授权和准入控制(admission controll),认证解决用户是谁的问题,授权解决用户能做什么的问题,Admission Control则是资源管理方面的作用。 + 支持同时提供https(默认监听在6443端口)和http API(默认监听在127.0.0.1的8080端口),其中http API是非安全接口,不做任何认证授权机制,kube-scheduler、kube-controller-manager 一般和 kube-apiserver 部署在同一台机器上,它们使用非安全端口和 kube-apiserver通信; 其他集群外部就使用HTTPS访问 apiserver + 关于authorization-mode=Node,RBAC v1.7+支持Node授权,配合NodeRestriction准入控制来限制kubelet仅可访问node、endpoint、pod、service以及secret、configmap、PV和PVC等相关的资源;需要注意的是v1.7中Node 授权是默认开启的,v1.8中需要显式配置开启,否则 Node无法正常工作 + 缺省情况下 kubernetes 对象保存在 etcd /registry 路径下,可以通过 --etcd-prefix 参数进行调整 + 详细参数配置请参考`kube-apiserver --help`,关于认证、授权和准入控制请[阅读](https://github.com/feiskyer/kubernetes-handbook/blob/master/components/apiserver.md) + 增加了访问kubelet使用的证书配置,防止匿名访问kubelet的安全漏洞,详见[漏洞说明](../mixes/01.fix_kubelet_annoymous_access.md) ### 创建controller-manager 的服务文件 ``` bash [Unit] Description=Kubernetes Controller Manager Documentation=https://github.com/GoogleCloudPlatform/kubernetes [Service] ExecStart={{ bin_dir }}/kube-controller-manager \ --address=127.0.0.1 \ --master=http://127.0.0.1:8080 \ --allocate-node-cidrs=true \ --service-cluster-ip-range={{ SERVICE_CIDR }} \ --cluster-cidr={{ CLUSTER_CIDR }} \ --cluster-name=kubernetes \ --cluster-signing-cert-file={{ ca_dir }}/ca.pem \ --cluster-signing-key-file={{ ca_dir }}/ca-key.pem \ --service-account-private-key-file={{ ca_dir }}/ca-key.pem \ --root-ca-file={{ ca_dir }}/ca.pem \ --horizontal-pod-autoscaler-use-rest-clients=true \ --leader-elect=true \ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target ``` + --address 值必须为 127.0.0.1,因为当前 kube-apiserver 期望 scheduler 和 controller-manager 在同一台机器 + --master=http://127.0.0.1:8080 使用非安全 8080 端口与 kube-apiserver 通信 + --cluster-cidr 指定 Cluster 中 Pod 的 CIDR 范围,该网段在各 Node 间必须路由可达(calico 实现) + --service-cluster-ip-range 参数指定 Cluster 中 Service 的CIDR范围,必须和 kube-apiserver 中的参数一致 + --cluster-signing-* 指定的证书和私钥文件用来签名为 TLS BootStrap 创建的证书和私钥 + --root-ca-file 用来对 kube-apiserver 证书进行校验,指定该参数后,才会在Pod 容器的 ServiceAccount 中放置该 CA 证书文件 + --leader-elect=true 使用多节点选主的方式选择主节点。只有主节点才会启动所有控制器,而其他从节点则仅执行选主算法 ### 创建scheduler 的服务文件 ``` bash [Unit] Description=Kubernetes Scheduler Documentation=https://github.com/GoogleCloudPlatform/kubernetes [Service] ExecStart={{ bin_dir }}/kube-scheduler \ --address=127.0.0.1 \ --master=http://127.0.0.1:8080 \ --leader-elect=true \ --v=2 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target ``` + --address 同样值必须为 127.0.0.1 + --master=http://127.0.0.1:8080 使用非安全 8080 端口与 kube-apiserver 通信 + --leader-elect=true 部署多台机器组成的 master 集群时选举产生一个处于工作状态的 kube-controller-manager 进程 ### 在master 节点安装 node 服务: kubelet kube-proxy 项目master 分支使用 DaemonSet 方式安装网络插件,如果master 节点不安装 kubelet 服务是无法安装网络插件的,如果 master 节点不安装网络插件,那么通过`apiserver` 方式无法访问 `dashboard` `kibana`等管理界面,[ISSUES #130](https://github.com/easzlab/kubeasz/issues/130) ``` bash # vi 04.kube-master.yml - hosts: kube-master roles: - kube-master - kube-node # 禁止业务 pod调度到 master节点 tasks: - name: 禁止业务 pod调度到 master节点 shell: "{{ bin_dir }}/kubectl cordon {{ inventory_hostname }} " when: DEPLOY_MODE != "allinone" ignore_errors: true ``` 在master 节点也同时成为 node 节点后,默认业务 POD也会调度到 master节点,多主模式下这显然增加了 master节点的负载,因此可以使用 `kubectl cordon`命令禁止业务 POD调度到 master节点 ### master 集群的验证 运行 `ansible-playbook 04.kube-master.yml` 成功后,验证 master节点的主要组件: ``` bash # 查看进程状态 systemctl status kube-apiserver systemctl status kube-controller-manager systemctl status kube-scheduler # 查看进程运行日志 journalctl -u kube-apiserver journalctl -u kube-controller-manager journalctl -u kube-scheduler ``` 执行 `kubectl get componentstatus` 可以看到 ``` bash NAME STATUS MESSAGE ERROR scheduler Healthy ok controller-manager Healthy ok etcd-0 Healthy {"health": "true"} etcd-2 Healthy {"health": "true"} etcd-1 Healthy {"health": "true"} ``` [后一篇](05-install_kube_node.md)