一、简介 Dashboard 是基于网页的 Kubernetes 用户界面。可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中，也可以对容器应用排错，还能管理集群本身及其附属资源。您可以使用 Dashboard 获取运行在集群中的应用的概览信息，也可以创建或者修改 Kubernetes 资源（如 Deployment，Job，DaemonSet 等等）。例如，可以对 Deployment 实现弹性伸缩、发起滚动升级、重启 Pod 或者使用向导创建新的应用。 二、生成 Dashboard 1、浏览器打开，复制 dashboard 清单 recommended.yaml 生成 dashboard，kube-dashboard.yaml。 文件如下： kube-dashboard.yaml 三、查看镜像 cat delopyment/kube-dashboard.yaml | grep image image: kubernetesui/dashboard:v2.1.0 imagePullPolicy: Always image: kubernetesui/metrics-scraper:v1.0.6 四、部署 Dashboard 4.1、部署 dashboard [root@k8s-master-001 ~]# kubectl apply -f kube-dashboard.yaml namespace/kubernetes-dashboard created serviceaccount/kubernetes-dashboard created service/kubernetes-dashboard created secret/kubernetes-dashboard-certs created secret/kubernetes-dashboard-csrf created secret/kubernetes-dashboard-key-holder created configmap/kubernetes-dashboard-settings created role.rbac.authorization.k8s.io/kubernetes-dashboard created clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created deployment.apps/kubernetes-dashboard created service/dashboard-metrics-scraper created deployment.apps/dashboard-metrics-scraper created 4.2、查看 pod [root@k8s-master-001 ~]# kubectl get pods -n kubernetes-dashboard NAME READY STATUS RESTARTS AGE dashboard-metrics-scraper-79c5968bdc-q62h5 1/1 Running 0 106s kubernetes-dashboard-7448ffc97b-7f7gg 1/1 Running 0 107s 五、修改对外服务端口 5.1、修改对外服务端口 [root@k8s-master-01 ~]# kubectl edit svc -n kubernetes-dashboard 将 type: ClusterIP 改为 type: NodePort 5.2、查看端口映射 [root@k8s-master-001 ~]# kubectl get svc -n kubernetes-dashboard NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE dashboard-metrics-scraper ClusterIP 10.106.254.133 <none> 8000/TCP 7m29s kubernetes-dashboard NodePort 10.98.245.78 <none> 443:31424/TCP 7m29s 六、访问测试 访问：https://集群任意IP:端口，https://192.168.10.146:32500（记住替换为自己的IP地址） 七、获取 Token 7.1、编写Token文件 token.yaml apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user annotations: rbac.authorization.kubernetes.io/autoupdate: "true" roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kube-system 7.2、部署 Token [root@k8s-master-001 ~]# kubectl apply -f token.yaml serviceaccount/admin-user created clusterrolebinding.rbac.authorization.k8s.io/admin-user created 7.3、获取Token [root@k8s-master-001 ~]# kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}') Name: admin-user-token-fw57d Namespace: kube-system Labels: <none> Annotations: kubernetes.io/service-account.name: admin-user kubernetes.io/service-account.uid: cdc1c4d5-0850-452b-9113-d6379c39c540 Type: kubernetes.io/service-account-token Data ==== ca.crt: 1025 bytes namespace: 11 bytes token: eyJhbGciOiJSUzI1NiIsImtpZCI6InUtcnJJbUVBa201WEYwUmgwcmQwbzFQNG1KSzFTT2NtWHpXTC1ja2xRUmMifQ.[binary].Sdsw9fg5DCkKEHexKbIwwPr4tm_RPvy18LuAIx2DMxNzviow_7ZAJAj91beaM3a-3WmDzS1Nz4hX2ne3tP_I9JMFttmDyUdjzY0uLBESO-c8JTeC6ZFX7erHL7e97s5M8nyBo4UoUcwPTnqZNr5-Eod41NmjHfs3xgteqK25lpIYhVYmVvQCSaXgnByQ2FXhj5rIjVbzetTxLHM5ZGflHpTL_c070D34feZ_0nYe66y-X4x6pU6C22dn5o551_wqA5iBbL2vRy7yswLbQeODQtt7NGTUnO7MGSbNn5e31kfp4fp9ldYKT3R8QwtgpGalX3Sm8MDaCGDro44wJnr_Hw 输入Token，正常访问。 八、Kubeconfig 的方式方式登录 基于token的基础之上，进行以下操作： 8.1、查看刚才创建的 Token [root@k8s-master-001 ~]# kubectl -n kube-system get secret | grep admin-user admin-user-token-g4dbs kubernetes.io/service-account-token 3 9m31s 8.2、查看Token的详细信息，会获取token [root@k8s-master-001 ~]# kubectl describe secrets -n kube-system admin-user-token-g4dbs Name: admin-user-token-lv7qr Namespace: kube-system Labels: <none> Annotations: kubernetes.io/service-account.name: admin-user kubernetes.io/service-account.uid: e3c0c1f0-65a0-4588-bba2-58845639883c Type: kubernetes.io/service-account-token Data ==== ca.crt: 1066 bytes namespace: 11 bytes token: eyJhbGciOiJSUzI1NiIsImtpZCI6InUtckNQdnlZV3o1a3F6X3k1aUFsdjJydXBEZU1mbTRObUlmalV2dk0wOE0ifQ.[binary].jXhfXkADAXV6WWbDTAlEtnBhIlBVzzErCQMsdvufA67lptNlV_1GW6nIpm-hU5V9plRpascvpv7vi2f00jIGnhGbi3WNZQWB7ELVYUamcHxoZRbFc4BO8DTk2XtsxWfGnff5siqlsWYaUiBvsXkccsx7u93VrFpPgcYUfnRal1vp7Urir461KjincGsxD_aIsNbQZcYUz4ARuJ4EJpO5ZeMuQEfW4HhfoTO23Eku809RQnjosJ7bdGYS8TFotfrCQyqKxi2y3DI2jWA_2nrEXLTK1UPhRJJe5qJD-xXdTctz73ZZGQ1FobfA3p6nnmJZbvgLISHNuXiS044B9Nkj2A 8.3、将 Token 的信息生成一个变量 [root@k8s-master-001 ~]# DASH_TOKEN=$(kubectl get secrets -n kube-system admin-user-token-g4dbs -o jsonpath={.data.token} | base64 -d) 8.4、将k8s集群的配置信息写入到一个文件中，文件可自定义 [root@k8s-master-001 ~]# kubectl config set-cluster kubernets --server=192.168.10.146:6443 --kubeconfig=/root/.dashboard-admin.conf Cluster "kubernets" set. 8.5、将 Token 的信息也写入到文件中（同一个文件） [root@k8s-master-001 ~]# kubectl config set-credentials dashboard-admin --token=${DASH_TOKEN} --kubeconfig=/root/.dashboard-admin.conf User "dashboard-admin" set. 8.6、将用户信息也写入文件中（同一个文件） [root@k8s-master-001 ~]# kubectl config set-context dashboard-admin@kubernetes --cluster=kubernetes --user=dashboard-admin --kubeconfig=/root/.dashboard-admin.conf Context "dashboard-admin@kubernetes" created. 8.7、将上下文的配置信息也写入文件中（同一个文件） [root@k8s-master-001 ~]# kubectl config use-context dashboard-admin@kubernetes --kubeconfig=/root/.dashboard-admin.conf Switched to context "dashboard-admin@kubernetes". 8.8、最后将配置信息.dashboard-admin.conf下载到本地 [root@k8s-master-001 ~]# sz /root/.dashboard-admin.conf 浏览器选择 Kubeconfig 方式登录。 参考： https://blog.csdn.net/mushuangpanny/article/details/126944780 https://blog.csdn.net/qq_32202885/article/details/126231040
一、Helm 引入 K8S 上的应用对象，都是由特定的资源描述组成，包括 deployment、service 等。都保存各自文件中或者集中写到一个配置文件。然后 kubectl apply –f 部署。 如果应用只由一个或几个这样的服务组成，上面部署方式足够了。而对于一个复杂的应用，会有很多类似上面的资源描述文件，例如微服务架构应用，组成应用的服务可能多达十个，几十个。如果有更新或回滚应用的需求，可能要修改和维护所涉及的大量资源文件，而这种组织和管理应用的方式就显得力不从心了。且由于缺少对发布过的应用版本管理和控制，使 Kubernetes 上的应用维护和更新等面临诸多的挑战，主要面临以下问题： 如何将这些服务作为一个整体管理。 这些资源文件如何高效复用。 不支持应用级别的版本管理。 二、Helm Helm 是一个 Kubernetes 的包管理工具，就像 Linux 下的包管理器，如 yum/apt 等，可以很方便的将之前打包好的 yaml 文件部署到 kubernetes 上。 Helm 有 3 个重要概念： helm：一个命令行客户端工具，主要用于 Kubernetes 应用 chart 的创建、打包、发布和管理。 Chart：应用描述，一系列用于描述 k8s 资源相关文件的集合。 Release：基于 Chart 的部署实体，一个 chart 被 Helm 运行后将会生成对应的一个release；将在 k8s 中创建出真实运行的资源对象。 2.1、Helm 作用 使用 helm 可以这些 yaml 文件作为一个整体管理。 实现 yaml 高效复用。 使用 helm 应用级别的版本管理。 2.2、Helm v3 变化 2019 年 11 月 13 日， Helm 团队发布 Helm v3 的第一个稳定版本。该版本主要变化如下： 架构变化： 最明显的变化是 Tiller 的删除。 Release 名称可以在不同命名空间重用。 支持将 Chart 推送至 Docker 镜像仓库中。 使用 JSONSchema 验证 chart values。 其他。 2.3、Helm 客户端安装 1、下载 Helm 安装包 Helm 客户端下载地址：https://github.com/helm/helm/releases [root@kubernetes-master-001 ~]# cd /data/software/ [root@kubernetes-master-001 /data/software]# wget https://get.helm.sh/helm-v3.7.1-linux-amd64.tar.gz 2、解压安装包 [root@kubernetes-master-001 /data/software]# tar xf helm-v3.7.1-linux-amd64.tar.gz -C /opt/ [root@kubernetes-master-001 /data/software]# cd /opt/ [root@kubernetes-master-001 /opt]# ll total 0 drwxr-xr-x 2 3434 3434 50 Oct 14 04:09 linux-amd64 3、配置环境变量 #1.配置环境变量 [root@kubernetes-master-001 /opt]# vim /etc/profile.d/helm.sh export PATH=/opt/linux-amd64:$PATH #2.刷新环境变量 [root@kubernetes-master-001 /opt]# source /etc/profile.d/helm.sh 4、验证 helm [root@kubernetes-master-001 /opt]# helm version version.BuildInfo{Version:"v3.7.1", GitCommit:"1d11fcb5d3f3bf00dbe6fe31b8412839a96b3dc4", GitTreeState:"clean", GoVersion:"go1.16.9"} 2.4、Helm常用命令 create 创建一个 chart 并指定名字 dependency 管理 chart 依赖 get 下载一个 release。可用子命令：all、hooks、manifest、notes、values history 获取 release 历史 install 安装一个 chart list 列出 release package 将 chart 目录打包到 chart 存档文件中 pull 从远程仓库中下载 chart 并解压到本地 # helm pull stable/mysql -- untar repo 添加，列出，移除，更新和索引 chart 仓库。可用子命令：add、index、 list、remove、update rollback 从之前版本回滚 search 根据关键字搜索 chart。可用子命令：hub、repo show 查看 chart 详细信息。可用子命令：all、chart、readme、values status 显示已命名版本的状态 template 本地呈现模板 uninstall 卸载一个 release upgrade 更新一个 release version 查看 helm 客户端版本 2.5、配置国内chart仓库 1、常用国内仓库 微软仓库（http://mirror.azure.cn/kubernetes/charts/）这个仓库推荐，基本上官网有的 chart 这里都有。 阿里云仓库（https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts） 官方仓库（https://hub.kubeapps.com/charts/incubator）官方 chart 仓库，国内有点不好使。 2、添加存储库 helm repo add azure http://mirror.azure.cn/kubernetes/charts helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts [root@kubernetes-master-001 /opt]# helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "aliyun" chart repository ...Successfully got an update from the "stable" chart repository Update Complete. ⎈Happy Helming!⎈ 3、查看配置的存储库 #1.查看配置的存储库 helm repo list NAME URL stable http://mirror.azure.cn/kubernetes/charts aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts #2.查看配置存储库的服务清单 helm search repo stable 4、删除存储库 #1.查看存储库 [root@kubernetes-master-001 /opt]# helm repo list NAME URL stable http://mirror.azure.cn/kubernetes/charts aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts #2.删除存储库aliyun [root@kubernetes-master-001 /opt]# helm repo remove aliyun "aliyun" has been removed from your repositories #3.再次查看存储库 [root@kubernetes-master-001 /opt]# helm repo list NAME URL stable http://mirror.azure.cn/kubernetes/charts 2.6、Helm 基本使用 主要三个命令： chart install chart upgrade chart rollback 2.7、使用 helm 部署一个应用 部署 weave 界面 $ export KUBERNETES_MASTER=http://127.0.0.1:8080 $ helm search repo weave $ helm install k8s-ui azure/weave-scope $ helm list #列出helm部署应用 $ helm status k8s-ui #查看状态 #如果要浏览器本地访问，需要设置svc为NodePort 部署 mysql $ helm search repo mysql $ helm install db azure/mysql #这样不能成功，因为mysql需要pv，所以一直处于pending状态 $ cat pv01.yml apiVersion: v1 kind: PersistentVolume metadata: name: pv01 spec: capacity: storage: 16Gi volumeMode: Filesystem accessModes: - ReadWriteMany nfs: path: /ifs/kubernetes/pv01 server: 192.168.56.14 $ kubectl apply -f pv01.yml $ kubectl run mysql-client -it --rm --image=mysql:5.7 -- bash #测试数据库 mysql -h db1-mysql -pdSt9QIYNGF 查看 chart 的 values 和 values 设置 $ helm show values azure/mysql #查看values $ helm pull azure/mysql --untar #可以直接下载chart之后再看 $ helm install db1 --set persistence.storageClass="managed-nfs-storage" azure/mysql $ kubectl get secret --namespace default db-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo #获取登陆密码 dSt9QIYNGF values yaml与set使用： $ helm pull azure/mysql --untar && cat mysql/values.yml persistence: enabled: true ## database data Persistent Volume Storage Class ## If defined, storageClassName: <storageClass> ## If set to "-", storageClassName: "", which disables dynamic provisioning ## If undefined (the default) or set to null, no storageClassName spec is ## set, choosing the default provisioner. (gp2 on AWS, standard on ## GKE, AWS & OpenStack) ## # storageClass: "-" accessMode: ReadWriteOnce size: 8Gi annotations: {} $ helm install db2 --set persistence.storageClass="managed-nfs-storage" azure/mysql #指定存储类部署 $ vim values.yml persistence: enabled: true storageClass: "managed-nfs-storage" accessMode: ReadWriteOnce size: 8Gi annotations: {} mysqlUser: ops mysqlPassword: "Qwer1234@" mysqlDatabase: "opsDB" $ helm install db3 azure/mysql -f values.yml # 根据values指定参数创建 $ kubectl exec -it mysql-client -- bash #测试创建信息 root@mysql-client:/# mysql -h db3-mysql -pE1ihmKspOL mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 10 Server version: 5.7.30 MySQL Community Server (GPL) Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | opsDB | | performance_schema | | sys | +--------------------+ 5 rows in set (0.01 sec) 创建一个 helm chart $ cd ~/lesson/helm/ $ helm create mychart $ tree mychart/ mychart/ ├── charts #目录里存放这个chart依赖的所有子chart。 ├── Chart.yaml #用于描述这个 Chart的基本信息，包括名字、描述信息以及版本等。 ├── templates #目录里面存放所有yaml模板文件。 │ ├── deployment.yaml │ ├── _helpers.tpl #放置模板助手的地方，可以在整个 chart 中重复使用 │ ├── hpa.yaml │ ├── ingress.yaml │ ├── NOTES.txt #用于介绍Chart帮助信息， helm install 部署后展示给用户。例如：如何使用这个 Chart、列出缺省的设置等。 │ ├── serviceaccount.yaml │ ├── service.yaml │ └── tests │ └── test-connection.yaml └── values.yaml #用于存储 templates 目录中模板文件中用到变量的值。 $ helm install web1 mychart #直接部署 打包推送的 charts 仓库共享别人使用。 $ helm package mychart Successfully packaged chart and saved it to: /root/lesson/helm/mychart-0.1.0.tgz 升级，回滚和删除 发布新版本的chart时，或者当您要更改发布的配置时，可以使用该helm upgrade命令。 参考： https://cloud.tencent.com/developer/article/1702139
一、引言 在 Kubernetes 中，Ingress 是一种 API 对象，用于管理外部访问集群服务的方式，通常是 HTTP 和 HTTPS 流量。可以将 Ingress 理解为一个智能的路由器，它根据请求的 URL 路径或主机名将流量路由到不同的服务。 主要功能： 路由：Ingress 可以根据请求的 URL 路径或主机名将流量路由到不同的服务。例如，你可以将 example.com/api 的请求路由到一个服务，而将 example.com/app 的请求路由到另一个服务。 负载均衡：Ingress 可以在多个后端服务之间分配流量，从而实现负载均衡。 SSL/TLS 终止：Ingress 可以处理 SSL/TLS 加密，允许你在 Ingress 控制器中配置证书，而不是在每个服务中配置。 基于主机和路径的路由：Ingress 支持基于主机名和路径的路由规则，使得多个服务可以通过同一个 IP 地址和端口进行访问。 1、把端口号对外暴露，通过 IP+端口号 进行访问。 1）使用 Service 里面的 NodePort 实现。 2、NodePort 缺陷 1）在每个节点上都会启动端口，在访问时候通过任何节点，通过节点 IP+暴露端口号 实现访问。 2）意味着每个端口只能使用一次，一个端口对应一个应用。 3）实际访问中都是用域名，根据不同域名跳转到不同端口服务中。 二、Ingress概述 通常情况下，service 和 pod 的 IP 仅可在集群内部访问。集群外部的请求需要通过负载均衡转发到 service 在 Node 上暴露的 NodePort 上，然后再由 kube-proxy 将其转发给相关的 Pod。 Ingress 为 Kubernetes 集群中的服务提供了入口，可以提供负载均衡、SSL 终止和基于名称的虚拟主机，在生产环境中常用的 Ingress 有 Treafik、Nginx、HAProxy、Istio 等。在 Kubernetes v1.1 版中添加的 Ingress 用于从集群外部到集群内部 Service 的 HTTP 和 HTTPS 路由，流量从 Internet 到 Ingress 再到 Services 最后到 Pod 上，通常情况下，Ingress 部署在所有的 Node 节点上。Ingress 可以配置提供服务外部访问的 URL、负载均衡、终止SSL，并提供基于域名的虚拟主机。但 Ingress 不会暴露任意端口或协议。 三、Ingress 工作流程 Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。 可以将 Ingress 配置为服务提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS，以及提供基于名称的虚拟主机等能力。 Ingress 控制器 通常负责通过负载均衡器来实现 Ingress，尽管它也可以配置边缘路由器或其他前端来帮助处理流量。 Ingress 不会公开任意端口或协议。 将 HTTP 和 HTTPS 以外的服务公开到 Internet 时，通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的服务。 四、Ingress 控制器(官方维护) 4.1、官方维护 Ingress 控制器 为了让 Ingress 资源工作，集群必须有一个正在运行的 Ingress 控制器。 与作为 kube-controller-manager 可执行文件的一部分运行的其他类型的控制器不同， Ingress 控制器不是随集群自动启动的。 基于此页面，你可选择最适合你的集群的 ingress 控制器实现。 Kubernetes 作为一个项目，目前支持和维护 AWS， GCE 和 nginx Ingress 控制器。 4.2、其他 Ingress 控制器 AKS 应用程序网关 Ingress 控制器 是一个配置 Azure 应用程序网关 的 Ingress 控制器。 Ambassador API 网关是一个基于 Envoy 的 Ingress 控制器。 Apache APISIX Ingress 控制器 是一个基于 Apache APISIX 网关 的 Ingress 控制器。 Avi Kubernetes Operator 使用 VMware NSX Advanced Load Balancer 提供第 4 到第 7 层的负载均衡。 BFE Ingress 控制器 是一个基于 BFE 的 Ingress 控制器。 Citrix Ingress 控制器 可以用来与 Citrix Application Delivery Controller 一起使用。 Contour 是一个基于 Envoy 的 Ingress 控制器。 EnRoute 是一个基于 Envoy API 网关， 可以作为 Ingress 控制器来执行。 Easegress IngressController 是一个基于 Easegress API 网关，可以作为 Ingress 控制器来执行。 F5 BIG-IP 的用于 Kubernetes 的容器 Ingress 服务 让你能够使用 Ingress 来配置 F5 BIG-IP 虚拟服务器。 Gloo 是一个开源的、基于 Envoy 的 Ingress 控制器，能够提供 API 网关功能， HAProxy Ingress 针对 HAProxy 的 Ingress 控制器。 用于 Kubernetes 的 HAProxy Ingress 控制器 也是一个针对 HAProxy 的 Ingress 控制器。 Istio Ingress 是一个基于 Istio 的 Ingress 控制器。 用于 Kubernetes 的 Kong Ingress 控制器 是一个用来驱动 Kong Gateway 的 Ingress 控制器。 用于 Kubernetes 的 NGINX Ingress 控制器 能够与 NGINX Web 服务器（作为代理） 一起使用。 Skipper HTTP 路由器和反向代理可用于服务组装，支持包括 Kubernetes Ingress 这类使用场景， 设计用来作为构造你自己的定制代理的库。 Traefik Kubernetes Ingress 提供程序 是一个用于 Traefik 代理的 Ingress 控制器。 Tyk Operator 使用自定义资源扩展 Ingress，为之带来 API 管理能力。Tyk Operator 使用开源的 Tyk Gateway & Tyk Cloud 控制面。 Voyager 是一个针对 HAProxy 的 Ingress 控制器。 五、安装Nginx-Ingress 访问架构图： 5.1、helm 安装 Ingress #1.新建ingress存放目录 [root@kubernetes-master-001 ~]# mkdir ingress && cd ingress #2.添加官方ingress-nginx的helm仓库 [root@kubernetes-master-001 ~/ingress]# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx "ingress-nginx" has been added to your repositories #3.搜索仓库中已有的ingress-nginx版本信息(建议安装0.40.2以上的版本) [root@kubernetes-master-001 ~/ingress]# helm search repo ingress-nginx NAME CHART VERSION APP VERSION DESCRIPTION ingress-nginx/ingress-nginx 4.0.9 1.0.5 Ingress controller for Kubernetes using NGINX a... #4.拉取ingress-nginx的包 helm pull [repo名称/chart名称] [root@kubernetes-master-001 ~/ingress]# helm pull ingress-nginx/ingress-nginx #5.解压包，修改values.yaml配置文件 [root@kubernetes-master-001 ~/ingress]# tar -xf ingress-nginx-4.0.9.tgz && cd ingress-nginx #6.修改values.yaml # 修改镜像 # 注释掉registry，image，digest，并打开repository repository: willdockerhub/ingress-nginx-controller tag: "v1.0.5" repository: jettech/kube-webhook-certgen tag: v1.5.2 repository: mirrorgooglecontainers/defaultbackend-amd64 tag: "1.5" #修改dns策略 dnsPolicy: ClusterFirstWithHostNet # 使用hostNetwork,即使用宿主机上的端口80 443 hostNetwork: false # 使用DaemonSet,将ingress部署在指定节点上 kind: DaemonSet # 节点选择，将需要部署的节点打上ingress=true的label nodeSelector: kubernetes.io/os: linux ingress: "true" # 选择节点打label kubectl label node node01 ingress=true # 创建一个ingress的namespace kubectl create ns ingress-nginx # 创建ingress # 如果提示cannot re-use a name that is still in use # 则先helm uninstall ingress-nginx --namespace ingress-nginx # 如果安装完成后无法访问其他节点日志，则需要配置hosts，将所有节点配置到hosts中即可 helm install ingress-nginx ingress-nginx -n ingress-nginx 5.2、直接部署安装 #1.部署ingress-nginx 比较简单，直接下载github上的 deploy.yaml 部署即可,由于网络问题镜像如果拉取失败,我们可以直接去GitHub复制这个yaml文件 [root@kubernetes-master-001 ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml #2.修改镜像地址 [root@kubernetes-master-001 ~]# sed -i 's@k8s.gcr.io/ingress-nginx/controller:v1.0.0\(.*\)@willdockerhub/ingress-nginx-controller:v1.0.0@' deploy.yaml [root@kubernetes-master-001 ~]# sed -i 's@k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0\(.*\)$@hzde0128/kube-webhook-certgen:v1.0@' deploy.yaml #3.安装ingress-nginx [root@kubernetes-master-001 ~]# kubectl apply -f ingress-1.0.0.yaml namespace/ingress-nginx created serviceaccount/ingress-nginx created configmap/ingress-nginx-controller created clusterrole.rbac.authorization.k8s.io/ingress-nginx configured clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx configured role.rbac.authorization.k8s.io/ingress-nginx created rolebinding.rbac.authorization.k8s.io/ingress-nginx created service/ingress-nginx-controller-admission created service/ingress-nginx-controller created deployment.apps/ingress-nginx-controller created ingressclass.networking.k8s.io/nginx configured validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission configured serviceaccount/ingress-nginx-admission created clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission configured clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission configured role.rbac.authorization.k8s.io/ingress-nginx-admission created rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created job.batch/ingress-nginx-admission-create created job.batch/ingress-nginx-admission-patch created #4.查看ingress-nginx状态 [root@kubernetes-master-001 ~]# kubectl get pod -n ingress-nginx NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-fgcrk 0/1 Completed 0 20m ingress-nginx-admission-patch-b6d96 0/1 Completed 0 20m ingress-nginx-controller-6b64bc6f47-4sd7g 1/1 Running 0 20m [root@kubernetes-master-001 ~]# kubectl get svc -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller NodePort 10.107.105.141 <none> 80:31386/TCP,443:31083/TCP 20m ingress-nginx-controller-admission ClusterIP 10.103.7.53 <none> 443/TCP 20m 六、部署示例验证 6.1、创建 Pod [root@kubernetes-master-001 ~]# kubectl create deployment web --image=nginx deployment.apps/web created [root@kubernetes-master-001 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE web-96d5df5c8-prps4 1/1 Running 0 44s 6.2、对外暴露应用 [root@kubernetes-master-001 ~]# kubectl expose deployment web --port=80 --target-port=80 --type=NodePort service/web exposed [root@kubernetes-master-001 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d23h web NodePort 10.106.214.3 <none> 80:30645/TCP 4d23h 6.3、创建Ingress规则 [root@kubernetes-master-001 ~]# vi ingress-http.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress namespace: default annotations: kubernetes.io/ingress.class: "nginx" spec: rules: - host: example.ingredemo.com http: paths: - path: "/" pathType: Prefix backend: service: name: web port: number: 80 [root@kubernetes-master-001 ~]# kubectl apply -f ingress-http.yaml ingress.networking.k8s.io/example-ingress created [root@kubernetes-master-001 ~]# kubectl get svc -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller NodePort 10.107.105.141 <none> 80:31386/TCP,443:31083/TCP 3h55m ingress-nginx-controller-admission ClusterIP 10.103.7.53 <none> 443/TCP 3h55m [root@kubernetes-master-001 ~]# kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE example-ingress <none> example.ingredemo.com 80 5s 七、Ingress-Nginx优化 上面每次部署 ingres-nginx 都随机一个nodePort ，而使用ingres-nginx访问的时候也要以 域名:端口 的形式去访问如何直接使用域名去访问呢？下面介绍hostNetwork 的方式部署Ingress-Nginx。 7.1、下载Ingress-Nginx [root@kubernetes-master-001 ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml [root@kubernetes-master-001 ~]# sed -i 's@k8s.gcr.io/ingress-nginx/controller:v1.0.0\(.*\)@willdockerhub/ingress-nginx-controller:v1.0.0@' deploy.yaml [root@kubernetes-master-001 ~]# sed -i 's@k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0\(.*\)$@hzde0128/kube-webhook-certgen:v1.0@' deploy.yaml 7.2、使用hostNetwork 默认 ingress-nginx 随机提供 nodeport 端口，开启 hostNetwork 启用80、443端口。 修改 Deployment 下面的 spec 参数如下： spec: hostNetwork: true # 新增 dnsPolicy: ClusterFirst containers: - name: controller image: willdockerhub/ingress-nginx-controller:v1.0.0 # 更换镜像地址 imagePullPolicy: IfNotPresent lifecycle: 7.3、修改负载均衡问题 把 kind: Deployment 改为 kind: DaemonSet 模式，这样每台 node 上都有 ingress-nginx-controller pod 副本。 参数如下： # Source: ingress-nginx/templates/controller-deployment.yaml apiVersion: apps/v1 #kind: Deployment # 注释 kind: DaemonSet # 新增 metadata: labels: helm.sh/chart: ingress-nginx-4.0.1 7.4、修改 ingressClass 问题 如果不关心 ingressClass 或者很多没有 ingressClass 配置的 ingress 对象， 添加参数 ingress-controller --watch-ingress-without-class=true 。 args: - /nginx-ingress-controller - --publish-service=$(POD_NAMESPACE)/ingress-nginx-dev-v1-test-controller - --election-id=ingress-controller-leader - --controller-class=k8s.io/ingress-nginx - --configmap=$(POD_NAMESPACE)/ingress-nginx-dev-v1-test-controller - --validating-webhook=:8443 - --validating-webhook-certificate=/usr/local/certificates/cert - --validating-webhook-key=/usr/local/certificates/key - --watch-ingress-without-class=true # 新增 6.部署检查ingress #1.部署ingress [root@kubernetes-master-001 ~]# kubectl apply -f deploy.yaml namespace/ingress-nginx created serviceaccount/ingress-nginx created configmap/ingress-nginx-controller created clusterrole.rbac.authorization.k8s.io/ingress-nginx unchanged clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx unchanged role.rbac.authorization.k8s.io/ingress-nginx created rolebinding.rbac.authorization.k8s.io/ingress-nginx created service/ingress-nginx-controller-admission created service/ingress-nginx-controller created daemonset.apps/ingress-nginx-controller created ingressclass.networking.k8s.io/nginx unchanged validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission configured serviceaccount/ingress-nginx-admission created clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission unchanged clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission unchanged role.rbac.authorization.k8s.io/ingress-nginx-admission created rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created job.batch/ingress-nginx-admission-create created job.batch/ingress-nginx-admission-patch created #2.部署pod [root@kubernetes-master-001 ~]# kubectl get pod -n ingress-nginx -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ingress-nginx-admission-create-cm5h4 0/1 Completed 0 4m4s 10.244.1.97 kubernetes-node-002 <none> <none> ingress-nginx-admission-patch-49wc7 0/1 Completed 1 4m4s 10.244.1.98 kubernetes-node-002 <none> <none> ingress-nginx-controller-cks5x 1/1 Running 0 4m5s 192.168.13.102 kubernetes-node-002 <none> <none> ingress-nginx-controller-cqgfb 1/1 Running 0 4m4s 192.168.13.101 kubernetes-node-001 <none> <none> #3.node节点检查端口 [root@kubernetes-node-002 ~]# netstat -lntp |grep 443 tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 70037/nginx: master tcp6 0 0 :::8443 :::* LISTEN 70016/nginx-ingress tcp6 0 0 :::443 :::* LISTEN 70037/nginx: master [root@kubernetes-node-002 ~]# netstat -lntp |grep 80 tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 70037/nginx: master tcp6 0 0 :::80 :::* LISTEN 70037/nginx: master [root@kubernetes-node-001 ~]# netstat -lntp |grep 443 tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 93825/nginx: master tcp6 0 0 :::8443 :::* LISTEN 93765/nginx-ingress tcp6 0 0 :::443 :::* LISTEN 93825/nginx: master [root@kubernetes-node-001 ~]# netstat -lntp |grep 80 tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 93825/nginx: master tcp6 0 0 :::80 :::* LISTEN 93825/nginx: master
一、Job 一次性任务概述 主要负责批处理任务，Job 创建一个或多个 Pod，并确保指定数量的 Pod 成功终止。Pod 成功完成后，Job 将跟踪成功完成的情况。当达到指定的成功完成次数时，任务（即Job）就完成了。删除 Job 将清除其创建的 Pod。 一个简单的情况是创建一个 Job 对象，以便可靠地运行一个 Pod 来完成。如果第一个Pod发生故障或被删除（例如，由于节点硬件故障或节点重启），则 Job 对象将启动一个新的 Pod。当然还可以使用 Job 并行运行多个 Pod。 二、Job 终止和清理 Job 完成后，不会再创建其他 Pod，但是 Pod 也不会被删除。这样使我们仍然可以查看已完成容器的日志，以检查是否有错误、警告或其他诊断输出。Job对象在完成后也将保留下来，以便您查看其状态。当我们删除Job对象时，对应的pod也会被删除。 特殊说明: 1）单个 Pod 时，默认 Pod 成功运行后 Job 即结束。 2）restartPolicy 仅支持 Never 和 OnFailure。 3）.spec.completions 标识Job结束所需要成功运行的Pod个数，默认为1 4）.spec.parallelism 标识并行运行的 Pod 个数，默认为1 5）.spec.activeDeadlineSeconds 为 Job 的持续时间，不管有多少 Pod 创建。一旦工作到指定时间，所有的运行 pod 都会终止且工作状态将成为type: Failed与reason: DeadlineExceeded。 三、Job 示例 1、编写 yaml 文件 job.yaml apiVersion: batch/v1 kind: Job metadata: name: pi spec: #completions: 3 # 标识Job结束所需要成功运行的Pod个数，默认为1 template: spec: containers: - name: pi image: registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never backoffLimit: 4 2、创建一次性任务 kubectl apply -f job.yaml job.batch/pi created 3、查看 pod 状态 # 查看，执行完成后，状态Status会变为Completed [root@kubernetes-master-001 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE ds-test-7krrv 1/1 Running 0 22h ds-test-jnxzm 1/1 Running 0 22h pi-bvvs4 0/1 ContainerCreating 0 106s web-5bb6fd4c98-54ll2 1/1 Running 0 2d22h web-5bb6fd4c98-585rn 1/1 Running 0 2d22h [root@kubernetes-master-001 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE ds-test-7krrv 1/1 Running 0 22h ds-test-jnxzm 1/1 Running 0 22h pi-bvvs4 0/1 Completed 0 2m21s web-5bb6fd4c98-54ll2 1/1 Running 0 2d22h web-5bb6fd4c98-585rn 1/1 Running 0 2d22h 4、查看 Pod 的标准输出 [root@kubernetes-master-001 ~]# kubectl logs --tail 500 pi-bvvs4 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277 5、删除任务 kubectl delete -f job.yaml job.batch "pi" deleted 六、CronJob 示例 1、编写 yaml 文件 cronjob.yaml apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: containers: - name: hello image: registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24 args: - /bin/sh - -c - date; echo Hello from the Kubernetes cluster restartPolicy: OnFailure 2、创建定时任务 kubectl apply -f cronjob.yaml cronjob.batch/hello created 3、查看 pod 状态 # 查看，执行完成后，状态Status会变为Completed [root@kubernetes-master-001 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE ds-test-7krrv 1/1 Running 0 22h ds-test-jnxzm 1/1 Running 0 22h hello-27278409-kzdp8 0/1 ContainerCreating 0 106s web-5bb6fd4c98-54ll2 1/1 Running 0 2d22h web-5bb6fd4c98-585rn 1/1 Running 0 2d22h [root@kubernetes-master-001 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE ds-test-7krrv 1/1 Running 0 22h ds-test-jnxzm 1/1 Running 0 22h hello-27278409-kzdp8 0/1 Completed 0 41s web-5bb6fd4c98-54ll2 1/1 Running 0 2d23h web-5bb6fd4c98-585rn 1/1 Running 0 2d23h 4、查看 Pod 的标准输出 #1.查看详细的定时任务 [root@kubernetes-master-001 ~]# kubectl get cronjobs.batch -o wide NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 17s 3m17s hello registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24 <none> #2.查看cronjob [root@kubernetes-master-001 ~]# kubectl get job -o wide NAME COMPLETIONS DURATION AGE CONTAINERS IMAGES SELECTOR hello-27278409 1/1 6s 2m54s hello registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24 controller-uid=ed1fee63-b42f-4c79-a9ad-02de25ef756d hello-27278410 1/1 2s 114s hello registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24 controller-uid=72adc412-165d-472c-9307-ee5597682ac9 hello-27278411 1/1 2s 54s hello registry.cn-beijing.aliyuncs.com/google_registry/busybox:1.24 controller-uid=46ddc73b-bc1a-436f-98cb-f021370f63d9 #3.找到最后一次调度任务创建的 Pod， 并查看 Pod 的标准输出。请注意任务名称和 Pod 名称是不同的。 [root@kubernetes-master-001 ~]# kubectl logs hello-27278411-w6hwb Fri Nov 12 08:11:01 UTC 2021 Hello from the Kubernetes cluster 5、删除任务 [root@kubernetes-master-001 ~]# kubectl get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE hello */1 * * * * False 0 32s 19m [root@kubernetes-master-001 ~]# kubectl delete cronjob hello # 或者 kubectl delete -f cronjob.yaml cronjob.batch "hello" deleted [root@kubernetes-master-001 ~]# kubectl get cronjob # 可见已删除 No resources found in default namespace.
一、DaemonSet概述 官方文档：daemonset DaemonSet 确保在所有（或部分）Node节点上运行 Pod 的副本。随着新的 Node 被添加到群集中的同时，会将 Pod 添加到新 Node 中。随着节点从群集中删除，垃圾收集器也将会删除这些 Pod。DaemonSet 的一些典型场景和用法： 集群存储：在每个Node节点上，运行集群存储守护程序，例如 glusterd，ceph。 日志收集：在每个Node节点上，运行日志收集守护程序，例如 fluentd或logstash。 节点监控：在每个Node节点上，运行节点监控守护程序，例如 Prometheus Node Exporter,collectd，Dynatrace OneAgent，Datadog agent，New Relic agent，Ganglia gmond 或者 Instana agent。 二、创建DaemonSet应用 1、在每个node节点安装数据采集工具，编写yaml文件 test.yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: ds-test labels: app: filebeat spec: # 标签选择器 selector: matchLabels: app: filebeat # 标签类型 template: metadata: labels: app: filebeat spec: # 配置容器 containers: - name: logs image: nginx ports: - containerPort: 80 # 挂载目录 volumeMounts: - name: varlog mountPath: /tmp/log volumes: - name: varlog hostPath: path: /var/log 2、必填字段 与 Kubernetes 中其它的对象一样，DaemonSet 必须包含 apiVersion，kind 和 metadata 字段。同时，DaemonSet 还需要 spec 字段部分的内容。 3、Pod 模板 .spec.template 是 .spec 的必填字段。.spec.template 用来定义 Pod 模板。DaemonSet 中的 Pod 模板必须设置 RestartPolicy 等于 Always，未指定的默认值即为 Always。 4、Pod 选择器 通过 .spec.selector 字段定义 Pod 选择器。从 Kubernetes 1.8 开始，必须指定一个与 .spec.template 标签相匹配选择器。一旦创建了 DaemonSet，就不能对 .spec.selector 进行修改，改变 Pod 选择器可能会导致 Pod 成为孤儿。 .spec.selector是一个由两个字段组成的对象： matchLabels 与 ReplicationControlle 的 .spec.selector 字段同样的工作机制。 matchExpressions 允许通过指定键，值列表以及与键和值相关的运算符来构建更复杂的选择器。 如果同时指定了两者时，结果取两者的和。如果指定了.spec.selector，则必须匹配 .spec.template.metadata.labels，如果不匹配将会被 API 拒绝。 5、仅在某些节点上运行 Pod 如果指定了 .spec.template.spec.nodeSelector，则 DaemonSet 控制器将在与该节点选择器匹配的 Node 节点上部署 Pod 。同样，如果指定了 .spec.template.spec.affinity，则 DaemonSet 控制器将在与该节点关联相匹配的 Node 节点上创建 Pod 。如果您未指定上述两个字段，则 DaemonSet 控制器将会在所有的 Node 节点上创建 Pod。 三、部署DaemonSet应用 #1.部署DaemonSet应用 kubectl apply -f test.yaml daemonset.apps/ds-test created #2.查看DaemonSet应用 kubectl get pods NAME READY STATUS RESTARTS AGE ds-test-7krrv 1/1 Running 0 59s ds-test-jnxzm 1/1 Running 0 59s web-5bb6fd4c98-54ll2 1/1 Running 0 2d web-5bb6fd4c98-585rn 1/1 Running 0 2d 四、进入DaemonSet查看 > kubectl exec -it ds-test-7krrv bash kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. root@ds-test-7krrv:/# ls /tmp/log/ anaconda containers maillog secure-20211108 vmware-network.5.log vmware-vmtoolsd-root.log audit cron maillog-20211108 spooler vmware-network.6.log wtmp boot.log cron-20211108 messages spooler-20211108 vmware-network.7.log yum.log boot.log-20200806 dmesg messages-20211108 tallylog vmware-network.8.log yum.log-20211108 boot.log-20200810 dmesg.old ntpstats tuned vmware-network.9.log boot.log-20211108 firewalld pods vmware-network.1.log vmware-network.log boot.log-20211109 grubby rhsm vmware-network.2.log vmware-vgauthsvc.log.0 btmp grubby_prune_debug sa vmware-network.3.log vmware-vmsvc-root.log btmp-20211108 lastlog secure vmware-network.4.log vmware-vmsvc.log root@ds-test-7krrv:/# 五、调度Daemon Pods 由 DaemonSet 控制器调度（自1.12版本起，默认禁用） 通常，由Kubernetes调度器选择Pod所运行的机器。但是，由DaemonSet控制器创建的Pod，在创建是就已经为Pod 选择了机器（在创建Pod时指定.spec.nodeName，因此调度器会忽略它）。因此： DaemonSet 控制器将不会考虑 unschedulable的Node 节点。 即使尚未启动调度器，DaemonSet 控制器也可以生成 Pod，这可以帮助集群引导程序。 由默认调度器调度（自1.12版本起，默认启用） 特性状态： Kubernetes v1.13 beta DaemonSet 确保所有符合条件的节点都运行 Pod 的副本。通常，由 Kubernetes 调度器选择 Pod 所运行的 Node 节点。但是，DaemonSet Pods 是由 DaemonSet 控制器所创建和调度的。这就产生了以下的问题： 不一致的 Pod 行为：正常的Pod，在创建是处于Pending状态；但DaemonSet Pod在创建时，并不是处于Pending 状态。这使用户感到困惑。 Pod 抢占由默认调度器处理：启用抢占后，DaemonSet控制器将在不考虑Pod优先级和抢占的情况下制定调度决策。 ScheduleDaemonSetPods 允许使用默认调度器而不是 DaemonSet 控制器来调度 DaemonSet，方法是将 NodeAffinity 术语添加到 DaemonSet Pods，而不是使用.spec.nodeName术语。默认调度器将 Pod 绑定到目标主机。如果 DaemonSet pod 的节点关联已存在，则替换它。DaemonSet 控制器仅在创建或修改 DaemonSet Pods 时执行这些操作，并且不对 DaemonSet 的spec.template进行任何更改。 nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchFields: - key: metadata.name operator: In values: - target-host-name 此外，node.kubernetes.io/unschedulable:NoSchedule容忍会自动添加到DaemonSet Pods。在调度DaemonSet Pod时，默认调度器会忽略unschedulable的Node节点。 污点和容忍 根据相关特性，DaemonSet Pods 会自动添加以下的容忍度。 容忍建 影响 版本 描述 node.kubernetes.io/not-ready NOEXECUTE 1.13+ 当存在诸如网络分区之类的节点问题时，不会驱逐DaemonSet pod。 node.kubernetes.io/unreachable NOEXECUTE 1.13+ 当存在诸如网络分区之类的节点问题时，不会驱逐DaemonSet pod。 node.kubernetes.io/disk-pressure NoSchedule 1.8+ node.kubernetes.io/memory-pressure NoSchedule 1.8+ node.kubernetes.io/unschedulable NoSchedule 1.12+ DaemonSet pods可以通过默认调度程序容忍不可调度的属性。 node.kubernetes.io/network-unavailable NoSchedule 1.12+ 使用主机网络的DaemonSet pod可以通过默认调度程序容忍网络不可用的属性。 六、与 Daemon Pods 进行通信 下面是与 DaemonSet 中 Pod 进行通信的一些可能模式： 推送：DaemonSet 中的 Pod 配置为将更新发送给另一个服务，例如统计数据库。他们没有客户。 NodeIP 和已知端口：DaemonSet 中的 Pod 可以使用 hostPort，以便可以通过 Node 节点 IP 访问 Pod。客户端以某种方式知道节点 IP 列表，并按知道端口。 DNS：使用相同的 Pod 选择器创建无头服务(headless service)，然后使用该 endpoints 资源发现 DaemonSets 或从 DNS 检索多个记录。 服务：使用相同的Pod选择器创建服务，并使用该服务在随机Node节点上访问守护程序。（无法到达特定节点。） 七、更新 DaemonSet 如果更改了 Node 节点标签，DaemonSet 会立即将 Pod 添加到新匹配的 Node 节点，并从不匹配的 Node 节点中删除 Pod。可以修改 DaemonSet 创建的 Pod。但是，不允许更新 Pod 所有字段。此外，DaemonSet 控制器将在下次创建节点（即使具有相同名称）时使用原始模板。可以删除 DaemonSet，如果通过 kubectl 指定了–cascade=false，则 Pod 会保留在 Node 节点上。可以使用不同的模板创建新的 DaemonSet，具有不同模板的新 DaemonSet 将所有现有 Pod 识别为具有匹配标签。尽管 Pod 模板不匹配，它也不会修改或删除它们，需要通过删除Pod或删除节点来强制创建新的 Pod。
一、概念 有状态：db 如果 mysql 的主从，必须是远程的存储，在任意节点都可以挂载恢复之前的状态，而且还有网络 ID 唯一，从得知道主的地址，pod 是短暂的，新的就会换IP，得保证这个 IP 能一直在使用。 无状态：web 比如部署 2 个副本，跟其他没啥直接的关系，本地也没有需要持久化的数据，其中有一个副本挂了，其他节点起来仍然可以提供服务没有影响。 K8S 适合访问波动大、版本迭代快的、弹性伸缩的。 二、特点 1、无状态应用（Deployment） 认为 Pod 都是一样的 没有顺序要求 不用考虑在那个 node 运行 随意进行伸缩和扩展 2、有状态应用 上面因素都需要考虑到 让每个 Pod 独立的，保持 Pod 启动顺序和唯一性 唯一的网络标识符，持久存储 有序性，比如 mysql 主从 三、Headless Service kubernates 中还有一种 service 类型：headless serivces功能，字面意思无头 service 其实就是该 service 对外无提供 IP，即 ClusterIP: none。一般用于对外提供域名服务的时候。 headless-service.yaml kind: Service apiVersion: v1 metadata: name: nginx labels: app: nginx spec: clusterIP: None # 设置为 None 表示这是一个 Headless Service selector: app: nginx ports: - port: 80 targetPort: 80 name: web --- apiVersion: apps/v1 kind: StatefulSet metadata: name: nginx-statefulset namespace: default spec: serviceName: nginx # 关联的 Service 名称 replicas: 3 # 副本数 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 操作 kubectl apply -f headless-service.yaml service/nginx created statefulset.apps/nginx-statefulset created 查看 [root@kubernetes-master-001 ~]# kubectl get svc,pods NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d2h service/nginx ClusterIP None <none> 80/TCP 3m3s service/web ClusterIP 10.100.37.233 <none> 80/TCP 47h service/web1 NodePort 10.103.214.171 <none> 80:32023/TCP 47h NAME READY STATUS RESTARTS AGE pod/nginx-statefulset-0 1/1 Running 0 2m36s pod/nginx-statefulset-1 1/1 Running 0 119s pod/nginx-statefulset-2 1/1 Running 0 97s pod/web-5bb6fd4c98-54ll2 1/1 Running 0 47h pod/web-5bb6fd4c98-585rn 1/1 Running 0 47h 四、statefulset(简称sts) 官方文档：statefulset StatefulSet 与 Deployment 区别：statefulset 是有身份的（唯一标识的）。 身份三要素：域名、主机名、存储（PVC） 这里有状态的约定，肯定不是简简单单通过名称来进行约定，而是更加复杂的操作。 deployment：是有身份的，有唯一标识 statefulset：根据主机名 + 按照一定规则生成域名 每个pod有唯一的主机名，并且有唯一的域名 格式：主机名称.service名称.名称空间.svc.cluster.local 举例：nginx-statefulset-0.default.svc.cluster.local
Kubernetes 作为一个分布式集群的管理工具，保证集群的安全性是其一个重要的任务。API Server 是集群内部各个组件通信的中介，也是外部控制的入口。所以 Kubernetes 的安全机制基本就是围绕保护 API Server 来设计的。Kubernetes 使用了认证（Authentication）、鉴权（Authorization）、准入控制（Admission Control）三步来保证API Server的安全，称为 3A 服务。 一、认证 HTTP Token 认证：通过一个 Token 来识别合法用户。 HTTP Token 的认证是用一个很长的特殊编码方式的并且难以被模仿的字符串 - Token 来表达客户的一种方式。Token 是一个很长的很复杂的字符串，每一个 Token 对应一个用户名存储在 API Server 能访问的文件中。当客户端发起 API 调用请求时，需要在 HTTP Header 里放入 Token** HTTP Base 认证：通过用户名+密码 的方式认证。 用户名+：+密码 用 BASE64 算法进行编码后的字符串放在 HTTP Request 中的 Heather Authorization 域里发送给服务端，服务端收到后进行编码，获取用户名及密码** 最严格的 HTTPS 证书认证：基于 CA 根证书签名的客户端身份认证方式**。 1.1、HTTPS 证书认证 HTTPS 加密： 单向认证：客户端认证服务器端。 双向认证：客户端与服务器端互相认证。 1.2、需要认证的节点 两种类型： （1）Kubenetes 组件对 API Server 的访问：kubectl、Controller Manager、Scheduler、kubelet、kube-proxy。 （2）Kubernetes 管理的 Pod 对容器的访问：Pod（dashborad 也是以 Pod 形式运行）。 安全性说明： （1）Controller Manager、Scheduler 与 API Server 在同一台机器，所以直接使用 API Server 的非安全端口访问，--insecure-bind-address=127.0.0.1 （2）kubectl、kubelet、kube-proxy 访问 API Server 就都需要证书进行 HTTPS 双向认证。 证书颁发： （1）手动签发：通过 k8s 集群的跟 ca 进行签发 HTTPS 证书** （2）自动签发：kubelet 首次访问 API Server 时，使用 token 做认证，通过后，Controller Manager 会为 kubelet 生成一个证书，以后的访问都是用证书做认证了** 1.3、kubeconfig kubeconfig 文件包含集群参数（CA证书、API Server地址），客户端参数（上面生成的证书和私钥），集群 context 信息（集群名称、用户名）。Kubenetes 组件通过启动时指定不同的 kubeconfig 文件可以切换到不同的集群。 1.4、ServiceAccount Pod 中的容器访问API Server。因为Pod的创建、销毁是动态的，所以要为它手动生成证书就不可行了。Kubenetes使用了Service Account解决Pod 访问API Server的认证问题。 1.5、Secret 与 SA 的关系 Kubernetes 设计了一种资源对象叫做 Secret，分为两类，一种是用于 ServiceAccount 的 service-account-token， 另一种是用于保存用户自定义保密信息的Opaque。ServiceAccount 中用到包含三个部分：Token、ca.crt、namespace。 （1）token是使用 API Server 私钥签名的 JWT。用于访问API Server时，Server端认证。 （2）ca.crt，根证书。用于Client端验证API Server发送的证书。 （3）namespace, 标识这个service-account-token的作用域名空间。 1.5.1、创建SA实验 #创建张三的sa证书 kubectl create sa zhangsan --dry-run -o yaml 操作 #查看kube-system名称空间下的pod kubectl get pod -n kube-system #查看caloco-node绑定的SA kubectl get pod calico-node-2pm9r -n kube-system -o yaml #进入pod内的容器 kubectl exec -it calico-node-2pm9r -n kube-system -- /bin/sh #切换到证书存放的目录 cd /run/secrets/kubernetes.io/serviceaccount/ ls kubectl get secret --all-namespaces #查看已存在的secret kubectl describe secret -n kube-system default-token-5gm9r 默认情况下，每个 namespace 都会有一个 ServiceAccount，如果 Pod 在创建时没有指定 ServiceAccount，就会使用 Pod 所属的 namespace 的 ServiceAccount。 默认挂载目录：/run/secrets/kubernetes.io/serviceaccount/。 二、鉴权 2.1、Authorization 上面认证过程，只是确认通信的双方都确认了对方是可信的，可以相互通信。而鉴权是确定请求方有哪些资源的权限。API Server 目前支持以下几种授权策略 （通过 API Server 的启动参数 “--authorization-mode” 设置）。 AlwaysDeny 表示拒绝所有的请求，一般用于测试。 AlwaysAllow 允许接收所有请求，如果集群不需要授权流程，则可以采用该策略。 ABAC（Attribute-Based Access Control） 基于属性的访问控制，表示使用用户配置的授权规则对用户请求进行匹配和控制。 Webhook 通过调用外部 REST 服务对用户进行授权。 RBAC（Role-Based Access Control） 基于角色的访问控制，现行默认规则。 2.2、RBAC 授权模式 RBAC(Role-Based Access Control，基于角色的访问控制) 在 k8s v1.5 中引入，在 v1.6 版 本时升级为 Beta 版本，并成为 kubeadm 安装方式下的默认选项，相对于其他访问控制方式， 新的 RBAC 具有如下优势： （1）对集群中的资源和非资源权限均有完整的覆盖。 （2）整个 RBAC 完全由几个 API 对象完成，同其他 API 对象一样，可以用 kubectl 或 API 进行操作。 （3）可以在运行时进行调整，无需重启 API Server。 要使用 RBAC 授权模式，需要在 API Server 的启动参数中加上--authorization-mode=RBAC。 在集群里面又三个附着点：user（用户），group（组），SA（serviceaccount）（pod访问serviec的一个认证），一个角色可以背绑定给多个用户，一个用户可以绑定多个角色，权限和角色也是多对多的关系。 用户绑定角色的过程，这条线（关联）就是一个对象，这个对象叫RoleBinding（角色绑定），RoleBinding被创建时，这条线就被连上了，RoleBinding 被删除时，这条线就断了。 集群角色绑定就是ClusterBinding，也就是说，角色进行角色绑定，集群角色进行集群角色绑定。需要注意的是：集群角色被角色绑定而绑定。 ROLE ROLEBINDING #角色被角色绑定 CLUSTERROLE CLUSTERROLEBINDING #集群角色被集群角色绑定 CLUSTERROLE ROLEBINDING #集群角色被角色绑定 三、RBAC 原理和用法 3.1、RBAC 的 API 资源对象说明 RBAC 引入了 4 个新的顶级资源对象：Role、ClusterRole、RoleBinding、 ClusterRoleBinding。同其他 API 资源对象一样，用户可以使用 kubectl 或者 API 调用等方式操作这些资源对象。 需要注意的是 Kubenetes 并不会提供用户管理，那么 User、Group、ServiceAccount 指定的用户又是从哪里来的呢？ Kubenetes 组件（kubectl、kube-proxy）或是其他自定义的用户在向 CA 申请证书时，需要提供一个证书请求文件。 CFSSL #申请证书的工具 coreos 公司开发的基于 Golang 语言编写的证书签发工具，这个工具允许我们通过json文件作为我们证书生成的模板，生成证书签发证书，是一个简化的证书生成工具。 证书签发描述文件： { "CN": "admin", #将CN当作用户字段。冒号后面写什么，就代表是什么用户。 "hosts": [], #允许使用这个证书的地址，如果不写代表所用用户都可以使用这个证书 "key": { "algo": "rsa", #加密算法使用rsa加密算法 "size": 2048 #2048位字符 }, "names": [ { "C": "CN", "ST": "HangZhou", "L": "XS", "O": "system:masters", #O字段，组字段，冒号后面跟什么就是什么组。 "OU": "System" } ] } API Server会把客户端证书的CN字段作为。User，把names.O字段作为。Group。 kubelet 使用 TLS Bootstaping 认证时，API Server 可以使用 Bootstrap Tokens 或者 Token authentication file 验证=token，无论哪一种，Kubenetes 都会为 token 绑定一个默认的 User 和 Group。 Pod使用 ServiceAccount 认证时，service-account-token 中的 JWT 会保存 User 信息。 有了用户信息，再创建一对角色/角色绑定(集群角色/集群角色绑定)资源对象，就可以完成权限绑定了。 3.1.1、角色(Role) 一个角色就是一组权限的集合，这里的权限都是许可形式的，不存在拒绝的规则。在一个命名空间中，可以用角色来定义一个角色，如果是集群级别的，就需要使用 ClusterRole 了。角色只能对命名空间内的资源进行授权，下面的例子中定义的角色具备读取 Pod 的权限： rule.yaml kind: Role # 资源类别，用户组类型 apiVersion: rbac.authorization.k8s.io/v1beta1 # 组类别版本 metadata: namespace: default # 角色是名称空间里面的，所以一定要写名称空间，如果不写，默认就在 defaults 名称空间下。 name: pod-reader # 当前角色名字为 pod-reader rules: - apiGroups: [""] # "" indicates the core API group # 规则指定当前操作对象的兼容的组版本，什么都没写，默认为核心组 v1 版。 resources: ["pods"] # 操作对象为 pod，兼容的组版本为核心组 v1 版 verbs: ["get", "watch", "list"] # 允许的动作类型，这里是：获取，监视，列出，这几个是当前 k8s 集群中抽象出来的动作类型。 rules 中的参数说明： apiGroup 支持的 API 组列表，例如：APIVersion: batch/v1、APIVersion: extensions:v1、apiVersion:apps/v1 等。 resources 支持的资源对象列表，例如：pods、deployments、jobs 等。 verbs 对资源对象的操作方法列表，例如：get、watch、list、delete、 replace 等。 3.1.2、集群角色(ClusterRole) ClusterRole 具有与 Role 相同的权限角色控制能力，不同的是 ClusterRole 是集群级别的，ClusterRole 可以用于: （1）集群级别的资源控制( 例如 node 访问权限 ) （2）非资源型 endpoints( 例如 /health 访问 ) （3）所有命名空间资源控制(例如 pods ) 下面的集群角色可以让用户有权访问任意一个或所有命名空间的 secrets： clusterrole.yaml kind: ClusterRole # 集群角色类型 apiVersion: rbac.authorization.k8s.io/v1 # 操作集群角色的组和版本 metadata: # 元数据 # "namespace" omitted since ClusterRoles are not namespaced name: secret-reader # 当前集群角色的名称 rules: # 规则 - apiGroups: [""] # 操作当前集群角色的兼容组版本 resources: ["secrets"] # 操作当前集群角色的对象为 secrets，他的组和版本为核心组 v1 版，所以上方可以不写。 verbs: ["get", "watch", "list"] # 允许的操作类型 3.1.3、角色绑定(RoleBinding) & 集群角色绑定(ClusterRoleBinding) 角色绑定或集群角色绑定用来把一个角色绑定到一个目标上，绑定目标可以是 User、 Group 或者 Service Account。使用 RoleBinding 为某个命名空间授权， ClusterRoleBinding 为集群范围内授权。 RoleBinding 可以引用 Role 进行授权。下例将在 default 命名空间中把 pod-reader 角色授予用户 jane，可以让 jane 用户读取 default 命名空间的 Pod： rolebinding.yaml kind: RoleBinding # 角色绑定类型 apiVersion: rbac.authorization.k8s.io/v1 # 监控主版本 metadata: name: read-pods # 角色绑定的名称为 read-pods namespace: default # 放在 default 名称空间下 subjects: # 绑定给哪个类型呢 - kind: User # 绑定给用户类型（类型可以写三种：用户，组，SA） name: jane # 哪个用户呢，名为 jane 的用户 apiGroup: rbac.authorization.k8s.io roleRef: # 角色来源于谁呢 kind: Role # 来源于角色类型 name: pod-reader # 哪个角色呢，名为 pod-reader 的角色，pod-reader 角色在上面已经创建了 apiGroup: rbac.authorization.k8s.io # 达到的效果：jane 用户在 default 名称空间下，能够对 pod 有获取，列出，监听的权限。 # jane 用户怎么来的呢？证书里的 CN 字段得到的 RoleBinding 也可以引用 ClusterRole，对属于同一命名空间内 ClusterRole 定义的资源主 体进行授权。一种常见的做法是集群管理员为集群范围预先定义好一组角色(ClusterRole)， 然后在多个命名空间中重复使用这些 ClusterRole。 使用 RoleBinding 绑定集群角色 secret-reader，使 dave 只能读取 development 命名空间中的 secret： rolebinding-clusterrole.yaml kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: read-secrets namespace: development subjects: - kind: User name: dave apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: secret-reader apiGroup: rbac.authorization.k8s.io #理论上有这个集群角色，可以在所有名称空间下去读取secret对象，但现在做的是角色绑定，dave用户，只能在dev名称空间下，行使这个权限（读取secret）。 集群角色绑定中的角色只能是集群角色，用于进行集群级别或者对所有命名空间都生效授权。允许 manager 组的用户读取任意 namespace 中的 secret。 kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: read-secrets-global subjects: - kind: Group name: manager apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: secret-reader apiGroup: rbac.authorization.k8s.io 3.2、对资源的引用方式 多数资源可以用其名称的字符串来表达，也就是 Endpoint 中的 URL 相对路径，例如 pods。 然后，某些 Kubernetes API 包含下级资源，例如 Pod 的日志(logs)。Pod 日志的 Endpoint 是 GET /api/v1/namespaces/{namespaces}/pods/{name}/log。 Pod 是一个命名空间内的资源，log 就是一个下级资源。要在一个 RBAC 角色中体现，则需 要用斜线/来分割资源和下级资源。若想授权让某个主体同时能够读取 Pod 和 Pod log，则 可以配置 resources 为一个数组： kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: pod-and-pod-logs-reader rules: - apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get", "list"] 资源还可以通过名字(ResourceName)进行引用。在指定 ResourceName 后，使用 get、 delete、update、patch 动词的请求，就会被限制在这个资源实例范围内。例如下面的声 明让一个主体只能对一个叫 my-configmap 的 configmap 进行 get 和 update 操作： kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: configmap-updater rules: - apiGroups: [""] resources: ["configmap"] resourceNames: ["my-configmap"] verbs: ["update", "get"] 3.3、常见的角色(Role)示例 （1）允许读取核心 API 组中 Pod 的资源： rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] （2）允许读写"extensions"和"apps"两个 API 组中的 deployment 资源 rules: - apiGroups: ["extensions", "apps"] resources: ["deployments"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] （3）允许读写 pods 及读写 jobs rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] - apiGroups: ["batch", "extensions"] resources: ["jobs"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] （4）允许读取一个名为 my-config 的 ConfigMap(必须绑定到一个 RoleBinding 来限制到 一个 namespace 下的 ConfigMap)： rules: - apiGroups: [""] resources: ["configmaps"] resourceNames: ["my-config"] verbs: ["get"] （5）读取核心组的 node 资源(Node 属于集群级别的资源，必须放在 ClusterRole 中，并 使用 ClusterRoleBinding 进行绑定)： rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] （6）允许对非资源端点/healthz 及其所有子路径进行 GET/POST 操作(必须使用 ClusterRole 和 ClusterRoleBinding)： rules: - nonResourceURLs: ["/healthz", "/healthz/*"] verbs: ["get", "post"] 3.4、常用的角色绑定 用户名 Alice@example.com subjects: - kind: User name: "Alice@example.com" apiGroup: rbac.authorization.k8s.io 组名 frontend-admins subjects: - kind: Group name: "frontend-admins" apiGroup: rbac.authorization.k8s.io kube-system 命名空间中的默认 Service Account subjects: - kind: ServiceAccount name: default namespace: kube-system qa 命名空间中的所有 Service Account subjects: - kind: Group name: system:serviceaccounts:qa apiGroup: rbac.authorization.k8s.io 所有 Service Account subjects: - kind: Group name: system:serviceaccounts apiGroup: rbac.authorization.k8s.io 所有认证用户 subjects: - kind: Group name: system:authentication apiGroup: rbac.authorization.k8s.io 所有未认证用户 subjects: - kind: Group name: system:unauthentication apiGroup: rbac.authorization.k8s.io 全部用户 subjects: - kind: Group name: system:authentication apiGroup: rbac.authorization.k8s.io - kind: Group name: system:unauthentication apiGroup: rbac.authorization.k8s.io 3.5、默认的角色和角色绑定 API Server 会创建一套默认的 ClusterRole 和 ClusterRoleBinding 对象，其中很多是以 system:为前缀的，以表明这些资源属于基础架构，对这些对象的改动可能造成集群故障。 所有默认的 ClusterRole 和RoleBinding 都会用标签 kubernetes.io/bootstrapping=rbac-defaults 进行标记。 常见的系统角色如下： 有些默认角色不是以 system:为前缀的，这部分角色是针对用户的，其中包含超级用户角色 cluster-admin，有的用于集群一级的角色 cluster-status，还有针对 namespace 的角色 admin、edit、view。 常见的用户角色如下： 核心 Master 组件角色 3.6、授权注意事项：预防提权和授权初始化 RBAC API 拒绝用户利用编辑角色或者角色绑定的方式进行提权。这一限制是在 API 层 面做出的，因此即使 RBAC 没有启用也仍然有效。 用户只能在拥有一个角色的所有权限，且与该角色的生效范围一致的前提下，才能对 角色进行创建和更新。例如用户 user-1 没有列出集群中所有 secret 的权限，就不能创建 具有这一权限的集群角色。要让一个用户能够创建或更新角色，需要以下权限： 为其授予一个允许创建/更新 Role 或 ClusterRole 资源对象的角色； 为用户授予角色，要覆盖该用户所能控制的所有权限范围。用户如果尝试创建超出 其自身权限的角色或者集群角色，则该 API 调用会被禁止。 如果一个用户的权限包含了一个角色的所有权限，那么就可以为其创建和更新角色绑 定；或者如果被授予了针对某个角色的绑定授权，则也有权完成此操作。 例如：user1 没有列出集群内所有 secret 的权限，就无法为一个具有这样权限的角色 创建集群角色绑定。要使用户能够创建、更新这一角色绑定，则需要有如下做法： 为其授予一个允许创建和更新角色绑定或者集群角色绑定的角色。 为其授予绑定某一角色的权限，有隐式或显式两种方法。 隐式：让其具有所有该角色的权限。 显式：让用户授予针对该角色或集群角色绑定操作的权限。 让 user-1 有对 user-1-namespace 命名空间中的其他用户授予 admin、edit 及 view 角色。 apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: role-grantor rules: - apiGroups: ["rbac.authorization.k8s.io"] resources: ["rolebindings"] verbs: ["create"] - apiGroups: ["rbac.authorization.k8s.io"] resources: ["clusterroles"] verbs: ["bind"] resourceNames: ["admin", "edit", "view"] apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: role-grantor-binding namespace: user-1-namespace roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: role-grantor subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: user-1 在进行第一个角色和角色绑定时，必须让初始用户具备其尚未被授予的权限，要进行初始 的角色和角色绑定设置，有以下两种方法： 使用属于 system:masters 组的身份，这一群组默认具有 cluster-admin 这一超级角色的绑定。 如果 API Server 以 --insecure-port 参数运行，则客户端通过这个非安全端口进行 接口调用，这一端口没有认证鉴权的限制。 四、准入控制 准入控制是API Server的插件集合，通过添加不同的插件，实现额外的准入控制规则。甚至于API Server的一些主要的功能都需要通过 Admission Controllers 实现，比如 ServiceAccount。 插件列表： NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass, DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook, ResourceQuota 列举几个插件的功能： NamespaceLifecycle 防止在不存在的 namespace 上创建对象，防止删除系统预置 namespace，删除 namespace 时，连带删除它的所有资源对象。 LimitRanger 确保请求的资源不会超过资源所在 Namespace 的 LimitRange 的限制。 ServiceAccount 实现了自动化添加 ServiceAccount。 ResourceQuota 确保请求的资源不会超过资源的 ResourceQuota 限制。 以devuser用户登录终端 #这个default本质上就是我们的ServiceAccount，我们并没有创建，他是自己自动创建出来的 #这就是ServiceAccount插件的含义，每创建一个名称空间，他就会自动在当前的名称空间下创建一个default ServiceAccount kubectl get sa -n dev
一、概述 一个容器平台的主要功能就是为容器分配运行时所需要的计算，存储和网络资源。容器调度系统负责选择在最合适的主机上启动容器，并且将它们关联起来。它必须能够自动的处理容器故障并且能够在更多的主机上自动启动更多的容器来应对更多的应用访问。 目前三大主流的容器平台 Swarm, Mesos 和 Kubernetes 具有不同的容器调度系统。 Swarm 的特点是直接调度 Docker 容器，并且提供和标准 Docker API 一致的 API。 Mesos 针对不同的运行框架采用相对独立的调度系统，其中 Marathon 框架提供了 Docker 容器的原生支持。 Kubernetes 则采用了 Pod 和 Label 这样的概念把容器组合成一个个的互相存在依赖关系的逻辑单元。相关容器被组合成 Pod 后被共同部署和调度，形成服务（Service）。 这个是 Kubernetes 和 Swarm，Mesos 的主要区别。 相对来说，Kubernetes 采用这样的方式简化了集群范围内相关容器被共同调度管理的复杂性。换一种角度来看，Kubernetes 采用这种方式能够相对容易的支持更强大，更复杂的容器调度算法。 二、k8s 调度工作方式 Kubernetes 调度器作为集群的大脑，在如何提高集群的资源利用率、保证集群中服务的稳定运行中也会变得越来越重要。 Kubernetes 的资源分为两种属性。 可压缩资源（例如 CPU 循环，Disk I/O 带宽）都是可以被限制和被回收的，对于一个 Pod 来说可以降低这些资源的使用量而不去杀掉 Pod。 不可压缩资源（例如内存、硬盘空间）一般来说不杀掉 Pod 就没法回收。未来 Kubernetes 会加入更多资源，如网络带宽，存储 IOPS 的支持。 三、k8s 调度器 3.1、kube-scheduler kube-scheduler 是 kubernetes 系统的核心组件之一，主要负责整个集群资源的调度功能，根据特定的调度算法和策略，将 Pod 调度到最优的工作节点上面去，从而更加合理、更加充分的利用集群的资源，这也是选择使用 kubernetes 一个非常重要的理由。 3.2、调度流程 默认情况下，kube-scheduler 提供的默认调度器能够满足我们绝大多数的要求，之前接触的示例也基本上用的默认的策略，都可以保证我们的 Pod 可以被分配到资源充足的节点上运行。但是在实际的线上项目中，可能我们自己会比 kubernetes 更加了解我们自己的应用，比如我们希望一个 Pod 只能运行在特定的几个节点上，或者这几个节点只能用来运行特定类型的应用，这就需要我们的调度器能够可控。 kube-scheduler 是 kubernetes 的调度器，它的主要作用就是根据特定的调度算法和调度策略将 Pod 调度到合适的 Node 节点上去，是一个独立的二进制程序，启动之后会一直监听 API Server，获取到 PodSpec.NodeName 为空的 Pod，对每个 Pod 都会创建一个 binding。 调度主要分为以下几个部分： 首先是预选过程，过滤掉不满足条件的节点，这个过程称为 Predicates。 然后是优选过程，对通过的节点按照优先级排序，称之为 Priorities。 最后从中选择优先级最高的节点，如果中间任何一步骤有错误，就直接返回错误。 3.2.1、Predicates 阶段 Predicates 阶段首先遍历全部节点，过滤掉不满足条件的节点，属于强制性规则，这一阶 段输出的所有满足要求的 Node 将被记录并作为第二阶段的输入，如果所有的节点都不满足条件，那么 Pod 将会一直处于 Pending 状态，直到有节点满足条件，在这期间调度器会不断的重试。 所以我们在部署应用的时候，如果发现有 Pod 一直处于 Pending 状态，那么就是没有满足调度条件的节点，这个时候可以去检查下节点资源是否可用。 3.2.2、Priorities 阶段 Priorities 阶段即再次对节点进行筛选，如果有多个节点都满足条件的话，那么系统会按照节点的优先级(priorites)大小对节点进行排序，最后选择优先级最高的节点来部署 Pod 应用。 下面是调度过程的简单示意图： 更详细的流程是这样的： 首先，客户端通过 API Server 的 REST API 或者 kubectl 工具创建 Pod 资源。 API Server 收到用户请求后，存储相关数据到 etcd 数据库中。 调度器监听 API Server 查看为调度(bind)的 Pod 列表，循环遍历地为每个 Pod 尝试分 配节点，这个分配过程就是我们上面提到的两个阶段： 预选阶段(Predicates)，过滤节点，调度器用一组规则过滤掉不符合要求的 Node 节点， 比如 Pod 设置了资源的 request，那么可用资源比 Pod 需要的资源少的主机显然就会被 过滤掉。 优选阶段(Priorities)，为节点的优先级打分，将上一阶段过滤出来的 Node 列表进行打 分，调度器会考虑一些整体的优化策略，比如把 Deployment 控制的多个 Pod 副本分布到 不同的主机上，使用最低负载的主机等等策略。 经过上面的阶段过滤后选择打分最高的 Node 节点和 Pod 进行 binding 操作，然后将结 果存储到 etcd 中。 最后被选择出来的 Node 节点对应的 kubelet 去执行创建 Pod 的相关操作。 其中 Predicates 过滤有一系列的算法可以使用，这里简单列举几个： PodFitsResources 节点上剩余的资源是否大于 Pod 请求的资源。 PodFitsHost 如果 Pod 指定了 NodeName，检查节点名称是否和 NodeName 匹配。 PodFitsHostPorts 节点上已经使用的 port 是否和 Pod 申请的 port 冲突。 PodSelectorMatches 过滤掉和 Pod 指定的 label 不匹配的节点。 NoDiskConflict 已经 mount 的 volume 和 Pod 指定的 volume 不冲突，除非它们都是只读的。 CheckNodeDiskPressure 检查节点磁盘空间是否符合要求。 CheckNodeMemoryPressure 检查节点内存是否够用。 除了这些过滤算法之外，还有一些其他的算法，更多更详细的可以查看源码文件 predicates.go。 而 Priorities 优先级是由一系列键值对组成的，键是该优先级的名称，值是它的权重值，同样，我们这里给大家列举几个具有代表性的选项： LeastRequestedPriority 通过计算 CPU 和内存的使用率来决定权重，使用率越低权重越 高，当然正常肯定也是资源是使用率越低权重越高，能给别的 Pod 运行的可能性就越大。 SelectorSpreadPriority 为了更好的高可用，对同属于一个 Deployment 或者 RC 下面 的多个 Pod 副本，尽量调度到多个不同的节点上，当一个 Pod 被调度的时候，会先去查 找该 Pod 对应的 controller，然后查看该 controller 下面的已存在的 Pod，运行 Pod 越少的节点权重越高。 ImageLocalityPriority 就是如果在某个节点上已经有要使用的镜像节点了，镜像总大小值越大，权重就越高。 NodeAffinityPriority 这个就是根据节点的亲和性来计算一个权重值，后面我们会详细讲解亲和性的使用方法。 四、调度器示例 4.1、固定节点调度 指定调度节点: Pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上，会跳过 Scheduler 的调度策略，该匹配规则是强制匹配。 scheduler-deploy.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: scheduler-deploy spec: selector: matchLabels: app: scheduler-deploy replicas: 7 template: metadata: labels: app: scheduler-deploy spec: nodeName: k8s-node01 #指定运行的节点名称 containers: - name: scheduler-deploy image: nginx:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80 操作 #查看创建的deployment kubectl get deploy #查看pod是否调度到指定节点上。 kubectl get pod -o wide 4.2、通过label-selector 机制选择节点 Pod.spec.nodeSelector 通过 kubernetes 的 label-selector 机制选择节点，由调度器调度策略匹配 label，而后调度 Pod 到目标节点，该匹配规则属于强制约束。 #给node添加标签 kubectl label node k8s-node01 app=selector #查看node的标签 kubectl get node --show-labels scheduler-selector-deploy.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: scheduler-selector-deploy spec: selector: matchLabels: app: scheduler-selector-deploy replicas: 20 template: metadata: labels: app: scheduler-selector-deploy spec: nodeSelector: app: selector #匹配标签为app: selector的节点 containers: - name: scheduler-selector-pod image: nginx:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80 操作 kubectl create -f scheduler-selector-deploy.yaml kubectl get deploy #查看pod的调度情况 kubectl get pod -o wide 五、节点调度亲和性 节点亲和性规则：硬亲和性 required 、软亲和性 preferred。 硬亲和性规则不满足时，Pod 会置于 Pending 状态，软亲和性规则不满足时，会选择一个不匹配的节点。当节点标签改变而不再符合此节点亲和性规则时，不会将 Pod 从该节点移出，仅对新建的 Pod 对象生效。 （1）节点硬亲和性 requiredDuringSchedulingIgnoredDuringExecution 方式一：Pod 使用 spec.nodeSelector (基于等值关系) 方式二：Pod 使用 spec.affinity 支持 matchExpressions 属性 (复杂标签选择机制) # 调度至 zone = foo 的节点 kubectllabelnodeskube-node1zone=foo apiVersion: v1 kind: Pod metadata: name: with-required-nodeaffinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 定义硬亲和性 nodeSelectorTerms: - matchExpressions: # 集合选择器 - key: zone operator: In values: ["foo"] containers: - name: myapp image: ikubernetes/myapp:v1 （2）节点软亲和性 preferredDuringSchedulingIgnoredDuringExecution 柔性控制逻辑，当条件不满足时，能接受被编排于其他不符合条件的节点之上。 权重 weight 定义优先级，1-100 值越大优先级越高。 apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deploy-with-node-affinity spec: replicas: 2 selector: matchLabels: app: myapp template: metadata: name: myapp-pod labels: app: myapp spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: # 节点软亲和性 - weight: 60 preference: matchExpressions: - key: zone operator: In values: ["foo"] - weight: 30 preference: matchExpressions: - key: ssd operator: Exists values: [] containers: - name: myapp image: ikubernetes/myapp:v1 六、Pod 资源亲和调度 Pod 对象间亲和性，将一些 Pod 对象组织在相近的位置(同一节点、机架、区域、地区)。 Pod 对象间反亲和性，将一些 Pod 在运行位置上隔开。 （1）Pod 硬亲和调度 requiredDuringSchedulingIgnoredDuringExecution Pod 亲和性描述一个 Pod 与具有某特征的现存 Pod 运行位置的依赖关系；即需要事先存在 被依赖的 Pod 对象。 # 被依赖 Pod kubectl run tomcat -l app=tomcat --image tomcat:alpine # 查看配置说明 kubectl explain pod.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.topologyKey apiVersion: v1 kind: Pod metadata: name: with-pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 硬亲和调度 - labelSelector: matchExpressions: # 集合选择器 - key: app operator: In values: ["tomcat"] # 选择被依赖 Pod # 上面意思是，当前 pod 要跟标签为 app 值为 tomcat 的 pod 在一起 topologyKey: kubernetes.io/hostname # 根据挑选出的 Pod 所有节点的 hostname 作为同一位置的判定 containers: - name: myapp image: ikubernetes/myapp:v1 （2）Pod 软亲和调度 apiVersion: apps/v1 kind: Deployment metadata: name: myapp-with-preferred-pod-affinity spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: name: myapp labels: app: myapp spec: affinity: podAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 80 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: ["cache"] topologyKey: zone - weight: 20 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: ["db"] topologyKey: zone containers: - name: myapp image: ikubernetes/myapp:v1 （3）Pod 反亲和调度 Pod 反亲和调度用于分散同一类应用，调度至不同的区域、机架或节点等 将 spec.affinity.podAffinity 替换为 spec.affinity.podAntiAffinity。 反亲和调度也分为柔性约束和强制约束。 apiVersion: v1 kind: Pod metadata: name: pod-first labels: app: myapp tier: fronted spec: containers: - name: myapp image: ikubernetes/myapp:v1 apiVersion: v1 kind: Pod metadata: name: pod-second labels: app: backend tier: db spec: containers: - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent command: ["/bin/sh", "-c", "sleep 3600"] affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: ["myapp"] topologyKey: zone 七、污点和容忍度 污点 taints 是定义在节点上的键值型属性数据，用于让节点拒绝将 Pod 调度运行于其上，除非 Pod 有接纳节点污点的容忍度容忍度 tolerations 是定义在 Pod 上的键值属性数据， 用于配置可容忍的污点，且调度器将 Pod 调度至其能容忍该节点污点的节点上或没有污点的节点上 使用 PodToleratesNodeTaints 预选策略和 TaintTolerationPriority 优选函数完成该机制。 节点亲和性使得 Pod 对象被吸引到一类特定的节点 (nodeSelector 和 affinity)。 污点提供让节点排斥特定 Pod 对象的能力。 （1）定义污点和容忍度 污点定义于 nodes.spec.taints 容忍度定义于 pods.spec.tolerations 语法：key=value:effect （2）effect 定义排斥等级： NoSchedule 不能容忍，但仅影响调度过程，已调度上去的 pod 不受影响，仅对新增加的 pod 生效。 PreferNoSchedule 柔性约束，节点现存 Pod 不受影响，如果实在是没有符合的节点，也可以调度上来。 NoExecute 不能容忍，当污点变动时，Pod 对象会被驱逐。 （3）在 Pod 上定义容忍度时： 等值比较 容忍度与污点在 key、value、effect 三者完全匹配。 存在性判断 key、effect 完全匹配，value 使用空值。 一个节点可配置多个污点，一个 Pod 也可有多个容忍度。 （4）管理节点的污点 同一个键值数据，effect 不同，也属于不同的污点。 给节点添加污点： kubectl taint node <node-name><key>=<value>:<effect> kubectl taint node node2 node-type=production:NoShedule #举例 查看节点污点： kubectl get nodes <nodename> -o go-template={{.spec.taints}} 删除节点污点： kubectl taint node <node-name><key>[:<effect>] kubectl patch nodes <node-name> -p '{"spec":{"taints":[]}}' kubectl taint node kube-node1 node-type=production:NoSchedule kubectl get nodes kube-node1 -o go-template={{.spec.taints}} 删除 key 为 node-type，effect 为 NoSchedule 的污点 kubectl taint node kube-node1 node-type:NoSchedule 删除 key 为 node-type 的所有污点 kubectl taint node kube-node1 node-type 删除所有污点 kubectl patch nodes kube-node1 -p '{"spec":{"taints":[]}}' 给 Pod 对象容忍度 spec.tolerations 字段添加 tolerationSeconds 用于定义延迟驱逐 Pod 的时长 等值判断 tolerations: - key: "key1" # 判断条件为 Equal operator: "Equal" value: "value1" effect: "NoExecute" tolerationSeconds: 3600 存在性判断 apiVersion: v1 kind: Deployment metadata: name: myapp-deploy namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 tolerations: - key: "key1" operator: "Exists" # 存在性判断，只要污点键存在，就可以匹配 effect: "NoExecute" tolerationSeconds: 3600 - key: "node-type" operator: "Equal" value: "production" effect: "NoExecute" tolerationSeconds: 3600 问题节点标识 自动为节点添加污点信息，使用 NoExecute 效用标识，会驱逐现有 Pod。 K8s 核心组件通常都容忍此类污点 node.kubernetes.io/not-ready 节点进入 NotReady 状态时自动添加。 node.alpha.kubernetes.io/unreachable 节点进入 NotReachable 状态时自动添加。 node.kubernetes.io/out-of-disk 节点进入 OutOfDisk 状态时自动添加。 node.kubernetes.io/memory-pressure 节点内存资源面临压力。 node.kubernetes.io/disk-pressure 节点磁盘面临压力。 node.kubernetes.io/network-unavailable 节点网络不可用。 node.cloudprovider.kubernetes.io/uninitialized kubelet 由外部云环境程序启动时，自动添加，待到去控制器初始化此节点时再将其删除。 Pod 优选级和抢占式调度： 优选级，Pod 对象的重要程度。 优选级会影响节点上 Pod 的调度顺序和驱逐次序。 一个 Pod 对象无法被调度时，调度器会尝试抢占(驱逐)较低优先级的 Pod 对象，以便可以 调度当前 Pod。 Pod 优选级和抢占机制默认处于禁用状态： 启用：同时为 kube-apiserver、kube-scheduler、kubelet 程序的 --feature-gates 添加 PodPriority=true。 使用：事先创建优先级类别，并在创建 Pod 资源时通过 priorityClassName 属性指定所属优选级类别。
一、概述 1、当一个 pod 被创建的时候，会启动第一个容器 pause。 作用：挂载可能存在的存储卷，初始化网络栈，后来僵尸进程的杀死。维护。 2、pause 容器启动后，就会启动另一个部分，不是mainC，而是 initC（初始化容器，initC>=0） initC初始化容器的特性： 线性启动 阻塞特性，前一个 initC-1 必须退出，后面的 initC-2 才会运行。执行退出命令的返回码为 0，代表成功退出。如果 initC 启动过程中失败，出现错误，那么 pause 会重新开始创建 initC-1，initC-2，initC-3 等等。只有所有 initC 全部成功启动退出，才会继续往下运行。 独立于应用容器 Init 容器可以有自己的独立镜像，这与应用容器使用的镜像可以完全不同。因此，它们具有其特殊的依赖和工具，不会影响应用容器的镜像构成。 运行到完成 Init 容器必须在终止前运行到完成。它们不是用来启动长期运行的进程的。一旦它们成功执行了启动命令，它们就会终止。 重新启动策略 如果 Init 容器失败，Kubernetes 默认的重新启动策略是 'Always'，它会一直重试直到容器成功为止。这与应用容器的启动失败策略是独立的。 二、init容器 2.1、概述 Pod 能够具有多个容器，应用运行在容器里面，但是它也可能有一个或多个先于应用容器启动的 Init 容器。 Init 容器与普通的容器非常像，除了如下两点： 1、Init 容器总是运行到成功完成为止。 2、每个 Init 容器都必须在下一个 Init 容器启动之前成功完成。 如果 Pod 的 Init 容器失败，Kubernetes 会不断地重启该 Pod，直到 Init 容器成功为止。然而，如果 Pod 对应的 restartPolicy 为 Never，它不会重新启动。 2.2、init容器作用 因为 Init 容器具有与应用程序容器分离的单独镜像，所以它们的启动相关代码具有如下优势： 1、可以包含并运行实用工具，但是出于安全考虑，是不建议在应用程序容器镜像中包含这些实用工具的。 2、应用程序镜像可以分离出创建和部署的角色，而没有必要联合它们构建一个单独的镜像。 3、Init 容器使用 Linux Namespace，所以相对应用程序容器来说具有不同的文件系统视图。因此，它们能够具有访问 Secret 的权限，而应用程序容器则不能。 4、它们必须在应用程序容器启动之前运行完成，而应用程序容器是并行运行的，所以 Init 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法，直到满足了一组先决条件。 2.3、InitC 容器示例 initC-pod.yaml apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox:1.35.0 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: busybox:1.35.0 command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;'] - name: init-mydb image: busybox:1.35.0 command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;'] 操作 kubectl apply -f initC-pod.yaml kubectl get pod kubectl describe pod myapp-pod #因为这里无法解析myservice的dns地址，所以才会报错 kubectl logs myapp-pod -c init-myservice kubectl create svc clusterip myservice --tcp=80:80 kubectl get svc #这里只加载好一个是因为，只解析了myservice的DNS，找不到mydb的DNS，所以无法加载 kubectl get pod kubectl create svc clusterip mydb --tcp=80:80 #稍等一会再次查看,就会加载完成 kubectl get pod 三、容器探针 3.1、探针概述 探针是由 kubelet 对容器执行的定期诊断。要执行诊断，kubelet 调用由容器实现的 Handler。有三种类型的处理程序： ExecAction 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。 TCPSocketAction 对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开，则诊断被认为是成功的。 HTTPGetAction 对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400，则诊断被认为是成功的 3.2、探针类型 K8s 中存在两种类型的探针：liveness probe 和 readiness probe。 livenessProbe：指示容器是否正在运行。如果存活探测失败，则 kubelet 会杀死容器，并且容器将受到其重启策略的影响。如果容器不提供存活探针，则默认状态为 Success。 readinessProbe：指示容器是否准备好服务请求。如果就绪探测失败，端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针，则默认状态为 Success。 四、liveness probe（存活探针） 用于判断容器是否存活，即 Pod 是否为 running 状态，如果 LivenessProbe 探针探测到容 器不健康，则 kubelet 将 kill 掉容器，并根据容器的重启策略是否重启。如果一个容器不包含 LivenessProbe 探针，则 Kubelet 认为容器的LivenessProbe 探针的返回值永远成功。有时应用程序可能因为某些原因（后端服务故障等）导致暂时无法对外提供服务，但应用软件没有终止，导致 K8S 无法隔离有故障的 pod，调用者可能会访问到有故障的 pod，导致业务不稳定。K8S 提供 livenessProbe 来检测应用程序是否正常运行，并且对相应状况进行相应的补救措施。 五、readiness probe（就绪探针） 用于判断容器是否启动完成，即容器的 Ready 是否为 True，可以接收请求，如果 ReadinessProbe 探测失败，则容器的 Ready 将为 False，控制器将此 Pod 的 Endpoint 从对 应的 service 的 Endpoint 列表中移除，从此不再将任何请求调度此 Pod 上，直到下次探测成功。通过使用 Readiness 探针，Kubernetes 能够等待应用程序完全启动，然后才允许服务将流量发送到新副本。 比如使用 tomcat 的应用程序来说，并不是简单地说 tomcat 启动成功就可以对外提供服务的，还需要等待 spring 容器初始化，数据库连接没连上等等。对于 spring boot 应用，默认的 actuator 带有 /health 接口，可以用来进行启动成功的判断。 六、每类探针都支持三种探测方法： exec 通过执行命令来检查服务是否正常，针对复杂检测或无 HTTP 接口的服务，命令返回值为 0 则表示容器健康。 httpGet 通过发送 http 请求检查服务是否正常，返回 200-399 状态码则表明容器健康。 tcpSocket 通过容器的 IP 和 Port 执行 TCP 检查，如果能够建立 TCP 连接，则表明容器健康。 七、探针探测的结果 Success Container 通过了检查。 Failure Container 未通过检查。 Unknown 未能执行检查，因此不采取任何措施。 八、Pod 重启策略： Always 总是重启 OnFailure 如果失败就重启 Never 永远不重启 七、示例 7.1、readinessProbe-就绪检测示例 readiness-pod.yaml apiVersion: v1 kind: Pod metadata: name: readiness-httpget-pod namespace: default labels: app: myapp env: test spec: containers: - name: readiness-httpget-container image: nginx:latest imagePullPolicy: IfNotPresent readinessProbe: httpGet: port: 80 path: /index1.html initialDelaySeconds: 1 #延迟的间隔是一秒 periodSeconds: 3 #检测的间隔时间是3秒 timeoutSeconds: 3 #超时时间是3秒 操作 kubectl create -f readiness-pod.yaml #未就绪状态，因为请求不到index1.html文件 kubectl get pod # 进入 pod 容器 kubectl exec -it readiness-httpget-pod -- /bin/sh #pod中添加index1.html文件 cd /usr/share/nginx/html/ echo "123" > index1.html exit #就绪状态，可以正常对外提供访问 kubectl get pod 7.2、livenessProbe-存活检测示例 livenessProbe-pod.yaml apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod namespace: default spec: restartPolicy: Never containers: - name: liveness-exec-container image: busybox:1.35.0 imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","touch /tmp/live ; sleep 60; rm -rf /tmp/live; sleep 3600"] livenessProbe: exec: command: ["test","-e","/tmp/live"] initialDelaySeconds: 1 #延迟的间隔是一秒 periodSeconds: 3 #检测的间隔时间是3秒 timeoutSeconds: 3 #超时时间是3秒 操作 kubectl apply -f livenessProbe-pod.yaml kubectl get pod #再次查看，已处于error状态。 #文件被删除，存活探测失败 kubectl get pod 7.3、livenessProbe-tcp--检测端口模板 apiVersion: v1 kind: Pod metadata: name: probe-tcp spec: containers: - name: nginx image: nginx:latest livenessProbe: #存活探测 initialDelaySeconds: 5 #初始化间隔时间时5秒 timeoutSeconds: 1 #超时时间是1秒 periodSeconds: 3 #检测间隔是3秒 tcpSocket: port: 80 #检测的端口是80 说明：这种方式不太好，检测端口是否存在，不代表服务能正常响应。 7.4、其他示例 apiVersion: v1 kind: Pod metadata: name: goproxy labels: app: goproxy spec: containers: - name: goproxy image: k8s.gcr.io/goproxy:0.1 ports: - containerPort: 8080 readinessProbe: tcpSocket: port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 15 periodSeconds: 20 探针(Probe) 有许多可选字段，可以用来更加精确的控制 Liveness 和 Readiness 两种探针的行为。这些参数包括： initialDelaySeconds 容器启动后第一次执行探测是需要等待多少秒。 periodSeconds 执行探测的频率。默认是 10 秒，最小 1 秒。 timeoutSeconds 探测超时时间。默认 1 秒，最小 1 秒。 successThreshold 探测失败后，最少连续探测成功多少次才被认定为成功。默认是 1。对于 liveness 必须是 1。最小值是 1。 failureThreshold 探测成功后，最少连续探测失败多少次才被认定为失败。默认是 3。最小值是 1。 八、钩子 8.1、概述 Pod hook（钩子）是由 Kubernetes 管理的 kubelet 发起的，当容器中的进程启动前或者容器中的进程终止之前运行，这是包含在容器的生命周期之中。可以同时为 Pod 中的所有容器都配置 hook。 Hook 的类型包括两种： exec：执行一段命令。 HTTP：发送 HTTP 请求。 启动后钩子可以编译软件，挂载存储。关闭前钩子可以保存文件，解除存储。 8.2、yaml模板 apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: nginx:latest lifecycle: postStart: #启动后 exec: command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] preStop: #关闭前 exec: command: ["/bin/sh", "-c", "echo Hello from the preStop handler > /usr/share/message"] 8.3、示例 lifecycle-pod.yaml apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: nginx:latest lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] preStop: exec: command: ["/bin/sh", "-c", "echo Hello from the preStop handler > /usr/share/message"] 操作 kubectl apply -f lifecycle-pod.yaml kubectl get pod # 进入容器 kubectl exec -it lifecycle-demo -- /bin/sh #pod中执行 while 2>1;do cat /usr/share/message;done #再开一个终端删除pod，然后观察原终端的返回信息 kubectl delete pod --all
一、Service 概述 Service 是 Kubernetes 最核心概念，通过创建 Service，可以为一组具有相同功能的容器应用提供一个统一的入口地址，并且将请求负载分发到后端的各个容器应用上。 目前一致的service有两个要求：标签匹配，就绪，如果不满足这两个，则无法匹配。 二、service 类型 2.1、ClusterIp 默认类型，自动分配一个仅 Cluster 内部可以访问的虚拟 IP。 2.2、NodePort（节点端口） 在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口，这样就可以通过 <NodeIP>: NodePort 来访问该服务。 2.3、LoadBalancer 在 NodePort 的基础上，借助 cloud provider 创建一个外部负载均衡器，并将请求转发到 <NodeIP>: NodePort。 2.4、ExternalName（DNS别名） 把集群外部的服务引入到集群内部来，在集群内部直接使用。没有任何类型代理被创 建，这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持。 DNS别名解析流程： 我们要创建一个 ExternalName 的 service（domain），当创建完 domain 以后，我们就会得到一个域名，tomcat 只要去访问到这个域名，这个域名就会经过 coredns 解析，解析到一个结果上，这个结果可能是一个域名，也可能是一个 IP，这个域名或 IP 可能指向这个 db。 当外部的 db 的 IP 发生变化时，只要修改 domain 的别名地址就好了，例如 db 数据库原来是 bbs.aaa.com，现在是 db.aaa.com，那么只需要将 domain 的别名地址写成 db.aaa.com 即可。 三、Service 的定义 yaml 格式的 Service 定义文件。 apiVersion: v1 kind: Service metadata: name: string namespace: string labels: name: string annotations: name: string spec: selector: {} # 选择器，用于关联 Pod type: string # 可选值：ClusterIP, NodePort, LoadBalancer, ExternalName clusterIP: string sessionAffinity: string # 可选值：None, ClientIP ports: - name: string protocol: string # 可选值：TCP, UDP, SCTP port: int # Service 端口 targetPort: int # Pod 端口 nodePort: int # 节点端口（当 type: NodePort 时使用） status: loadBalancer: ingress: - ip: string hostname: string 四、使用 4.1、ClusterIP 创建 ClusterIP.yaml apiVersion: v1 kind: Service #service类型 metadata: name: myapp #当前service的名是myapp namespace: default #放到default名称空间下 spec: #期望 type: ClusterIP #ClusterIP的类型 selector: #标签选择器，匹配下面两个标签 app: myapp release: stabel ports: #端口， - name: http #端口名称为http port: 80 #端口是80，集群访问的VIP的端口。 targetPort: 80 #后端目标80，真实服务器的端口 #IPVS是基于NAT工作模式运行的 创建 #基于yaml文件创建ClusterIP类型的svc kubectl apply -f ClusterIP.yaml #查看已经创建的svc kubectl get svc 4.2、NodePort 创建 NodePort.yaml apiVersion: v1 kind: Service metadata: name: myapp-nodeport namespace: default #放在default名称空间下 spec: #期望 type: NodePort #当前的工作模式是NodePort方式 selector: app: myapp release: stabel ports: - name: http #定义的别名为http port: 80 #集群的端口80 targetPort: 80 #后端的端口80 创建 kubectl apply -f 6.nodeport.yaml #这里映射的端口，必须大于三万以上。默认就可以，不用修改，防止冲突 #在外部访问物理机的31225端口即可映射到容器内部的80端口，达到访问容器的内目的 kubectl get svc 4.3、LoadBalancer 创建 与 nodeport 的区别在于，loadbalancer 会自动在外部创建一个调度器将当前的 nodeport 端口进行流量访问，实现高可用，但是必须得借助云平台创建 LB 来向节点导流。 loadBalancer 和 nodePort 其实是同一种方式。区别在于 loadBalancer 比 nodePort 多了一步，就是可以调用 cloud provider 去创建 LB 来向节点导流。 loadbalancer.yaml apiVersion: v1 kind: Service metadata: name: myapp-loadbalancer #服务的名称，这里是 myapp-loadbalancer。 spec: selector: app: myapp # 匹配带有相应标签的 Pods。在这个例子中，它匹配所有标签为 app: myapp 的 Pods。 type: LoadBalancer #为 LoadBalancer，表明我们想要的服务类型是负载均衡器。 ports: #服务的端口配置； - protocol: TCP port: 80 #服务内部端口，外部请求会到这个端口； targetPort: 8080 #Pods 上的端口，服务会将流量从内部端口转发到此端口； # 如果云提供商支持，也可以指定一个负载均衡器的外部端口，例如： # nodePort: 30000 #（可选）如果指定，这是节点上用来接收外部流量的端口 创建 kubectl apply -f loadbalancer.yaml kubectl get svc myapp-loadbalancer 4.4、ExternalName 创建 这种类型的 Service 通过返回 CNAME 和它的值，可以将服务映射到 externalName 字段的内容( 例如：hub.aaa.com )。ExternalName Service 是 Service 的特例，它没有 selector，也没有定义任何的端口和 Endpoint。相反的，对于运行在集群外部的服务，它通过返回该外部服务的别名这种方式来提供服务。 kind: Service apiVersion: v1 metadata: #元数据 name: my-service #当前service名为my-service namespace: default #放在default名称空间下 spec: type: ExternalName #当前的类型为ExternalName类型 externalName: hub.aaa.com # ExternalName的值为hub.hongfu.com my-service.defalut.svc.cluster.local 这是在集群内可以访问到的域名，如果将他的值找dns解析，解析的应该是hub.aaa.com。 例如： 我有一个 pod，我去访问一个 web 服务，web 服务就是 hub.hongfu.com，就可以靠这个 svc 指向这个 hub.aaa.com，如果有一天我想指向 harbor，那只要 dit 将这个值指向 haobor，他就指过来了，对于 pod 来说，不需要做任何改变。 当查询主机 my-service.defalut.svc.cluster.local ( SVC_NAME.NAMESPACE.svc.cluster.local )时，集群的 DNS 服务将返回一个值 my.database.example.com 的 CNAME 记录。访问这个服务的工作方式和其他的相同，唯一不同的是重定向发生在 DNS 层，而且不会进行代理或转发。 五、Service 示例 一般来说，对外提供服务的应用程序需要通过某种机制来实现，对于容器应用最简便 的方式就是通过 TCP/IP 机制及监听 IP 和端口号来实现。创建一个基本功能的 Service。 apiVersion: v1 kind: ReplicationController metadata: name: mywebapp spec: replicas: 2 template: metadata: name: mywebapp labels: app: mywebapp spec: containers: - name: mywebapp image: tomcat ports: - containerPort: 8080 我们可以通过 kubectl get pods -l app=mywebapp -o yaml | grep podIP 来获取 Pod 的 IP 地址和端口号来访问 Tomcat 服务，但是直接通过 Pod 的 IP 地址和端口访问应用 服务是不可靠的，因为当 Pod 所在的 Node 发生故障时， Pod 将被 kubernetes 重新调度到另一台 Node，Pod 的地址会发生改变。我们可以通过配置文件来定义 Service，再通过 kubectl create 来创建，这样可以通过 Service 地址来访问后端的 Pod. apiVersion: v1 kind: Service metadata: name: mywebAppService spec: ports: - port: 8081 targetPort: 8080 selector: app: mywebapp 六、多端口 Service 有时一个容器应用也可能需要提供多个端口的服务，那么在 Service 的定义中也可以相应地设置为将多个端口对应到多个应用服务。 apiVersion: v1 kind: Service metadata: name: mywebAppService spec: ports: - port: 8080 targetPort: 8080 name: web - port: 8005 targetPort: 8005 name: management selector: app: mywebapp 七、外部服务 Service 在某些特殊环境中，应用系统需要将一个外部数据库作为后端服务进行连接，或将另一个集群或 Namespace 中的服务作为服务的后端，这时可以通过创建一个无 Label Selector 的 Service 来实现。 apiVersion: v1 kind: Service metadata: name: my-service spec: ports: - protocol: TCP port: 80 targetPort: 80 --- apiVersion: v1 kind: Endpoints metadata: name: my-service # 必须与 Service 名称相同 subsets: - addresses: - ip: 10.254.74.3 ports: - port: 8080