一、环境介绍 使用一中部署的基础环境 192.168.10.131:作为master节点和证书颁发服务器 192.168.10.132:作为node节点 192.168.10.133:作为node节点 10.255.0.0/16 service地址 10.0.0.0/16 pod地址 etcd保存了整个集群的状态 apiserver提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制 controller manager负责维护集群的状态,比如故障检测、自动扩展、滚动更新等 scheduler负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上 kubelet负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理 Container runtime负责镜像管理以及Pod和容器的真正运行(CRI) kube-proxy负责为Service提供cluster内部的服务发现和负载均衡 除了核心组件,还有一些推荐的组件: kube-dns负责为整个集群提供DNS服务 Ingress Controller为服务提供外网入口 Heapster提供资源监控 Dashboard提供GUIFederation提供跨可用区的集群 Fluentd-elasticsearch提供集群日志采集、存储与查询 二、集群证书 kubernetes组件众多,这些组件之间通过 HTTP/GRPC 相互通信,以协同完成集群中应用的部署和管理工作。尤其是master节点,更是掌握着整个集群的操作。其安全就变得尤为重要了,在目前世面上最安全的,使用最广泛的就是数字证书。kubernetes正是使用这种认证方式。 1、证书原理 本次我们使用cfssl证书生成工具,这是一款把预先的证书机构、使用期等时间写在json文件里面会更加高效和自动化。cfssl采用go语言编写,是一个开源的证书管理工具,cfssljson用来从cfssl程序获取json输出,并将证书,密钥,csr和bundle写入文件中。 2、安装签发证书工具cfssl wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 chmod +x cfssl* mv cfssl_linux-amd64 /usr/local/bin/cfssl mv cfssljson_linux-amd64 /usr/local/bin/cfssljson mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo 3、生成ca证书json文件 mkdir -p /data/work && cd /data/work/ cat>ca-config.json < ca-csr.json < etcd-csr.json < etcd.conf <etcd.service < token.csv <kube-apiserver-csr.json <kube-apiserver.conf <>kube-apiserver.service #####尽量别用cat EOF了,那个没法原样将$KUBE_APISERVER_OPTS添加进去 ##启动apiserver服务 cp ca*.pem /etc/kubernetes/ssl cp kube-apiserver*.pem /etc/kubernetes/ssl/ cp token.csv /etc/kubernetes/ cp kube-apiserver.conf /etc/kubernetes/ cp kube-apiserver.service /usr/lib/systemd/system/ systemctl daemon-reload systemctl enable kube-apiserver systemctl start kube-apiserver systemctl status kube-apiserver ###查看服务 [root@k8s01 work]# curl --insecure https://192.168.10.131:6443/ { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "Unauthorized", "reason": "Unauthorized", "code": 401 } ###api已经正常启动 3、部署kubectl 创建csr请求文件 cat >admin-csr.json <<EOF { "CN": "admin", "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "shandong", "L": "jinan", "O": "system:masters", "OU": "system" } ] } EOF #说明: 后续 kube-apiserver 使用 RBAC 对客户端(如 kubelet、kube-proxy、Pod)请求进行授权; kube-apiserver 预定义了一些 RBAC 使用的 RoleBindings,如 cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予了调用kube-apiserver 的所有 API的权限; O指定该证书的 Group 为 system:masters,kubelet 使用该证书访问 kube-apiserver 时 ,由于证书被 CA 签名,所以认证通过,同时由于证书用户组为经过预授权的 system:masters,所以被授予访问所有 API 的权限;注:这个admin 证书, 是将来生成管理员用的kube config 配置文件用的,现在我们一般建议使用RBAC 来对kubernetes 进行角色权限控制, kubernetes 将证书中的CN 字段 作为User,O 字段作为 Group;"O": "system:masters", 必须是system:masters,否则后面kubectl create clusterrolebinding报错。 ##创建证书 cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin cp admin*.pem /etc/kubernetes/ssl/ #创建kubeconfig配置文件,比较重要 kubeconfig 为 kubectl 的配置文件,包含访问 apiserver 的所有信息,如 apiserver 地址、CA 证书和自身使用的证书(这里如果报错找不到kubeconfig路径,请手动复制到相应路径下,没有则忽略) 1.设置集群参数 kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.10.131:6443 --kubeconfig=kube.config 2.设置客户端认证参数 kubectl config set-credentials admin --client-certificate=admin.pem --client-key=admin-key.pem --embed-certs=true --kubeconfig=kube.config 3.设置上下文参数 kubectl config set-context kubernetes --cluster=kubernetes --user=admin --kubeconfig=kube.config 4.设置默认上下文 kubectl config use-context kubernetes --kubeconfig=kube.config mkdir ~/.kube -p cp kube.config ~/.kube/config 5.授权kubernetes证书访问kubelet api权限 kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes [root@k8s01 work]# kubectl cluster-info Kubernetes control plane is running at https://192.168.10.131:6443 To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. [root@k8s01 work]# kubectl get all --all-namespaces NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default service/kubernetes ClusterIP 10.255.0.1 443/TCP 70m #配置kubectl子命令补全 yum install -y bash-completion source /usr/share/bash-completion/bash_completion 在文件 ~/.bashrc 中导入(source)补全脚本: echo 'source >~/.bashrc 将补全脚本添加到目录 /etc/bash_completion.d 中: kubectl completion bash >/etc/bash_completion.d/kubectl 4、部署kube-controller-manager Controller Manager作为集群内部的管理控制中心,负责集群内的Node、Pod副本、服务端点(Endpoint)、命名空间(Namespace)、服务账号 (ServiceAccount)、资源定额(ResourceQuota)的管理,当某个Node意外宕机时,Controller Manager会及时发现并执行自动化修复流程, 确保集群始终处于预期的工作状态。如果多个控制器管理器同时生效,则会有一致性问题,所以kube-controller-manager的高可用,只能是主备模 式,而kubernetes集群是采用租赁锁实现leader选举,需要在启动参数中加入 --leader-elect=true。 #创建csr请求文件 cat >kube-controller-manager-csr.json <kube-controller-manager.conf <>kube-controller-manager.service #启动服务 cp kube-controller-manager*.pem /etc/kubernetes/ssl/ cp kube-controller-manager.kubeconfig /etc/kubernetes/ cp kube-controller-manager.conf /etc/kubernetes/ cp kube-controller-manager.service /usr/lib/systemd/system/ systemctl daemon-reload systemctl enable kube-controller-manager systemctl start kube-controller-manager systemctl status kube-controller-manager 5、部署kube-scheduler kube-scheduler是 Kubernetes 集群的默认调度器,并且是集群 控制面 的一部分。对每一个新创建的 Pod 或者是未被调度的 Pod, kube-scheduler 会过滤所有的node,然后选择一个最优的 Node 去运行这个 Pod。kube-scheduler 调度器是一个策略丰富、拓扑感知、工作负 载特定的功能,调度器显著影响可用性、性能和容量。调度器需要考虑个人和集体的资源要求、服务质量要求、硬件/软件/政策约束、亲和力和反亲和 力规范、数据局部性、负载间干扰、完成期限等。工作负载特定的要求必要时将通过 API 暴露。 #创建csr请求 cat >kube-scheduler-csr.json <kube-scheduler.conf <>kube-scheduler.service #启动服务 cp kube-scheduler*.pem /etc/kubernetes/ssl/ cp kube-scheduler.kubeconfig /etc/kubernetes/ cp kube-scheduler.conf /etc/kubernetes/ cp kube-scheduler.service /usr/lib/systemd/system/ systemctl daemon-reload systemctl enable kube-scheduler systemctl start kube-scheduler systemctl status kube-scheduler 6、安装pause 7中kubelet.service中指定了一个pause --pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.5 俩node节点拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.5 这个镜像在阿里云镜像仓库可以直接找到 https://cr.console.aliyun.com/cn-hangzhou/instances/favourites ##需要收藏后,可以在收藏里面找到拉取地址,当前最新版本为3.5 7、部署kubelet 以下操作在master上 创建kubelet-bootstrap.kubeconfig cd /data/work/ BOOTSTRAP_TOKEN=$(awk -F "," '{print $1}' /etc/kubernetes/token.csv) 安全上下文 kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.10.131:6443 --kubeconfig=kubelet-bootstrap.kubeconfig kubectl config set-credentials kubelet-bootstrap --token=${BOOTSTRAP_TOKEN} --kubeconfig=kubelet-bootstrap.kubeconfig kubectl config set-context default --cluster=kubernetes --user=kubelet-bootstrap --kubeconfig=kubelet-bootstrap.kubeconfig kubectl config use-context default --kubeconfig=kubelet-bootstrap.kubeconfig 授权限 kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap #创建配置文件kubelet.json "cgroupDriver": "systemd"要和docker的驱动一致。 cat >kubelet.json <>kubelet.service --pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.5 #注: --hostname-override:用来配置该节点在集群中显示的主机名,kubelet设置了-–hostname-override参数后,kube-proxy也需要设置,否则会 出现找不到Node的情况 --network-plugin:启用CNI --kubeconfig:空路径,会自动生成,后面用于连接apiserver --bootstrap-kubeconfig:指定令牌认证文件 --config:指定kubelet配置文件 --cert-dir:设置kube-controller-manager生成证书和私钥的目录 --pod-infra-container-image:管理Pod网络容器的镜像,每个pod中的network/ipc 名称空间容器将使用的镜像 --container-runtime 指定容器运行时引擎 --image-pull-progress-deadline 镜像拉取进度最大时间,如果在这段时间拉取镜像没有任何进展,将取消拉取,默认:1m0s 两个node节点上:mkdir /etc/kubernetes/ssl -p master执行: scp kubelet-bootstrap.kubeconfig kubelet.json k8s02:/etc/kubernetes/ scp ca.pem k8s02:/etc/kubernetes/ssl/ scp kubelet.service k8s02:/usr/lib/systemd/system/ scp kubelet-bootstrap.kubeconfig kubelet.json k8s03:/etc/kubernetes/ scp ca.pem k8s03:/etc/kubernetes/ssl/ scp kubelet.service k8s03:/usr/lib/systemd/system/ #启动kubelet服务 k8s02操作 mkdir /var/lib/kubelet mkdir /var/log/kubernetes sed -i 's/192.168.10.131/192.168.10.132/g' /etc/kubernetes/kubelet.json systemctl daemon-reload systemctl enable kubelet systemctl start kubelet systemctl status kubelet k8s03操作 mkdir /var/lib/kubelet mkdir /var/log/kubernetes sed -i 's/192.168.10.131/192.168.10.133/g' /etc/kubernetes/kubelet.json systemctl daemon-reload systemctl enable kubelet systemctl start kubelet systemctl status kubelet master操作 确认kubelet服务启动成功后,接着到master节点上Approve一下bootstrap请求。 [root@k8s01 work]# kubectl get csr NAME AGE SIGNERNAME REQUESTOR CONDITION node-csr-ZsSleJK6mlIYMW_0Uiu2FGeC7RHcgfzHFwrS75kt3rU 23s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Pending ##单条加入 kubectl certificate approve node-csr-ZsSleJK6mlIYMW_0Uiu2FGeC7RHcgfzHFwrS75kt3rU ##批量加入 kubectl certificate approve `kubectl get csr | grep "Pending" | awk '{print $1}'` [root@k8s01 work]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s02 NotReady 4m13s v1.20.7 k8s03 NotReady 118s v1.20.7 #注意:STATUS是NotReady表示还没有安装网络插件 8、部署kube-proxy kube-proxy是Kubernetes的核心组件,部署在每个Node节点上,它是实现Kubernetes Service的通信与负载均衡机制的重要组件; kube-proxy 负责为Pod创建代理服务,从apiserver获取所有server信息,并根据server信息创建代理服务,实现server到Pod的请求路由和转发,从而实现K8s 层级的虚拟转发网络。 还是在master上操作 #创建csr请求 cat >kube-proxy-csr.json <kube-proxy.yaml <>kube-proxy.service scp kube-proxy.kubeconfig kube-proxy.yaml k8s02:/etc/kubernetes/ scp kube-proxy.service k8s02:/usr/lib/systemd/system/ scp kube-proxy.kubeconfig kube-proxy.yaml k8s03:/etc/kubernetes/ scp kube-proxy.service k8s03:/usr/lib/systemd/system/ #启动服务 k8s02 mkdir -p /var/lib/kube-proxy sed -i 's/192.168.10.131/192.168.10.132/g' /etc/kubernetes/kube-proxy.yaml systemctl daemon-reload systemctl enable kube-proxy systemctl start kube-proxy systemctl status kube-proxy k8s03 mkdir -p /var/lib/kube-proxy sed -i 's/192.168.10.131/192.168.10.133/g' /etc/kubernetes/kube-proxy.yaml systemctl daemon-reload systemctl enable kube-proxy systemctl start kube-proxy systemctl status kube-proxy 9、部署calico 在master进行操作 wget --no-check-certificate https://docs.projectcalico.org/manifests/calico-etcd.yaml -O calico.yaml export ETCD_CERT=`cat /etc/etcd/ssl/etcd.pem | base64 | tr -d '\n'` export ETCD_KEY=`cat /etc/etcd/ssl/etcd-key.pem | base64 | tr -d '\n'` export ETCD_CA=`cat /etc/etcd/ssl/ca.pem | base64 | tr -d '\n'` sed -i "s@.*etcd-cert:.*@\ \ etcd-cert:\ ${ETCD_CERT}@gi" calico.yaml sed -i "s@.*etcd-key:.*@\ \ etcd-key:\ ${ETCD_KEY}@gi" calico.yaml sed -i "s@.*etcd-ca:.*@\ \ etcd-ca:\ ${ETCD_CA}@gi" calico.yaml sed -i 's@.*etcd_endpoints:.*@\ \ etcd_endpoints:\ "https://192.168.10.131:2379"@gi' calico.yaml #etcd的地址 sed -i 's@.*etcd_ca:.*@\ \ etcd_ca:\ "/calico-secrets/etcd-ca"@gi' calico.yaml sed -i 's@.*etcd_cert:.*@\ \ etcd_cert:\ "/calico-secrets/etcd-cert"@gi' calico.yaml sed -i 's@.*etcd_key:.*@\ \ etcd_key:\ "/calico-secrets/etcd-key"@gi' calico.yaml sed -i 's@# - name: CALICO_IPV4POOL_CIDR@- name: CALICO_IPV4POOL_CIDR@gi' calico.yaml sed -i 's@# value: "192.168.0.0/16"@ value: "10.0.0.0/16"@gi' calico.yaml ##pod定义地址 修改里面定义Pod网络(CALICO_IPV4POOL_CIDR),与前面kube-controller-manager配置文件指定的cluster-cidr网段一样。 - name: CALICO_IPV4POOL_CIDR ## value: "10.0.0.0/16" cat calico.yaml | grep image 直接在所有node节点下载,不然启动会卡住 docker pull docker.io/calico/cni:v3.21.2 docker pull docker.io/calico/pod2daemon-flexvol:v3.21.2 docker pull docker.io/calico/node:v3.21.2 docker pull docker.io/calico/kube-controllers:v3.21.2 在master节点启动服务 kubectl apply -f calico.yaml kubectl get pods -n kube-system -o wide [root@k8s01 work]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s02 Ready 4m6s v1.20.7 k8s03 Ready 4m6s v1.20.7 STATUS状态为Ready 10、部署coredns CoreDNS用于集群中Pod解析Service的名字,Kubernetes基于CoreDNS用于服务发现功能。 俩node节点下载coredns镜像 docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.8.5 阿里云镜像,最新1.8.6 ###这个地址下有对应的coredns模板 https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns/coredns 如果window下载需要返回上级目录 https://github.com/kubernetes/kubernetes 然后点击code下载Download zip 将kubernetes-master\cluster\addons\dns\coredns目录下的coredns.yaml.base上传到master并改名coredns.yaml mv coredns.yaml.base coredns.yaml sed -i 's#__DNS__DOMAIN__#cluster.local#g' coredns.yaml ##意思是dns在集群中的域名 sed -i 's#k8s.gcr.io/coredns/coredns:v1.8.6#registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.8.5#g' coredns.yaml ##coredns的镜像 sed -i 's#__DNS__MEMORY__LIMIT__#170Mi#g' coredns.yaml ##最大内存限制 sed -i 's#__DNS__SERVER__#10.255.0.2#g' coredns.yaml ###一般是service的第二个ip kubectl apply -f coredns.yaml kubectl get pods -n kube-system kubectl get svc -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.255.0.2 53/UDP,53/TCP,9153/TCP 14s 11、完善node ROLE kubectl label node k8s02 node-role.kubernetes.io/worker=worker kubectl label node k8s03 node-role.kubernetes.io/worker=worker [root@k8s01 work]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s02 Ready worker 10m v1.20.7 k8s03 Ready worker 10m v1.20.7 如果需要给master节点node打标签 kubectl label nodes kubernetes-master-03 node-role.kubernetes.io/master=kubernetes-master-03 12、tomcat服务 node节点: docker pull tomcat docker pull busybox master节点 [root@k8s01 work]# cat tomcat.yaml apiVersion: v1 #pod属于k8s核心组v1 kind: Pod #创建的是一个Pod资源 metadata: #元数据 name: demo-pod #pod名字 namespace: default #pod所属的名称空间 labels: app: myapp #pod具有的标签 env: dev #pod具有的标签 spec: containers: #定义一个容器,容器是对象列表,下面可以有多个name - name: tomcat-pod-java #容器的名字 ports: - containerPort: 8080 image: tomcat:latest #容器使用的镜像 imagePullPolicy: IfNotPresent - name: busybox image: busybox:latest command: #command是一个列表,定义的时候下面的参数加横线 - "/bin/sh" - "-c" - "sleep 3600" kubectl apply -f tomcat.yaml [root@k8s01 work]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES demo-pod 2/2 Running 0 75s 10.0.235.130 k8s03 [root@k8s01 work]# cat tomcat-service.yaml apiVersion: v1 kind: Service metadata: name: tomcat spec: type: NodePort ports: - port: 8080 nodePort: 30080 selector: app: myapp env: dev kubectl apply -f tomcat-service.yaml kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.255.0.1 443/TCP 158m tomcat NodePort 10.255.227.179 8080:30080/TCP 19m 访问服务 http://192.168.10.132:30080/ http://192.168.10.133:30080/ 13、cordns验证 node执行: docker pull busybox:1.28 master执行 kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh / # nslookup kubernetes.default.svc.cluster.local ##测试 Server: 10.255.0.2 Address 1: 10.255.0.2 kube-dns.kube-system.svc.cluster.local Name: kubernetes.default.svc.cluster.local Address 1: 10.255.0.1 kubernetes.default.svc.cluster.local / # / # / # nslookup tomcat.default.svc.cluster.local ##测试 Server: 10.255.0.2 Address 1: 10.255.0.2 kube-dns.kube-system.svc.cluster.local Name: tomcat.default.svc.cluster.local Address 1: 10.255.252.211 tomcat.default.svc.cluster.local #注意: busybox要用指定的1.28版本,不能用最新版本,最新版本,nslookup会解析不到dns和ip,报错如下: / # nslookup kubernetes.default.svc.cluster.local *** Can't find kubernetes.default.svc.cluster.local: No answer