├── .nojekyll ├── 01~应用部署 ├── 03~典型案例 │ ├── ELK.md │ ├── Caddy.md │ ├── Prometheus.md │ ├── Traefik.md │ ├── README.md │ ├── MEAN.md │ ├── MySQL.md │ └── Minio.md ├── README.md ├── 99~参考资料 │ └── 学习 K8s 的基础知识.md ├── 01~安装配置 │ ├── K3s │ │ └── README.md │ ├── Minikube │ │ └── README.md │ └── 集群 │ │ └── Rancher 搭建集群.md └── 02~kubectl │ ├── 01~连接到集群.md │ └── 02~运行与管理.md ├── 02~资源对象 ├── 07~集群资源管理 │ └── README.md ├── 02~控制器 │ ├── Deployment │ │ ├── 案例 │ │ │ ├── 集群应用.md │ │ │ ├── 有状态应用.md │ │ │ ├── 简单无状态应用.md │ │ │ └── README.md │ │ ├── README.md │ │ └── 声明与管理 │ │ │ └── ReplicaSet.md │ ├── Ambassador │ │ ├── README.md │ │ └── K3s 结合 Ambassador 部署.md │ ├── Stateful Set │ │ └── 99~参考资料 │ │ │ └── 2021.Kubernetes StatefulSet - Examples & Best Practices.md │ ├── SideCar │ │ └── README.md │ └── CronJobs │ │ └── README.md ├── 03~服务发现与路由 │ ├── 02~Ingress │ │ ├── Nginx │ │ │ ├── README.md │ │ │ └── Nginx Ingress 关联外部服务.md │ │ ├── Traefik │ │ │ └── README.md │ │ ├── Porter │ │ │ └── README.md │ │ └── README.md │ ├── Network Policy │ │ └── README.md │ ├── kube-proxy │ │ └── kube-proxy.md │ └── 01~Service │ │ └── README.md ├── 04~身份与权限 │ ├── RBAC │ │ └── README.md │ ├── README.md │ ├── 用户管理 │ │ └── README.md │ └── 命名空间 │ │ └── README.md ├── 05~网络 │ ├── Weave │ │ └── README.md │ ├── Calico │ │ ├── README.md │ │ └── 工作原理.md │ ├── Flannel │ │ ├── host-gw 模式.md │ │ ├── VXLAN 模式.md │ │ ├── UDP 模式.md │ │ └── README.md │ ├── README.md │ └── netfilter.md ├── 06~存储 │ ├── Rook │ │ └── README.md │ ├── 卷 │ │ ├── README.md │ │ └── 本地存储.md │ ├── ConfigMap │ │ ├── README.md │ │ └── 创建与使用.md │ └── README.md └── 01~Pod │ ├── 共享与调度 │ ├── 共享存储.md │ ├── 网络空间.md │ └── 进程通信.md │ ├── README.md │ └── 声明与管理 │ └── Hello World.md ├── 03~工程实践 ├── 高可用集群 │ ├── README.md │ ├── 调度和驱逐 │ │ ├── README.md │ │ └── 调度架构.md │ └── 集群监控 │ │ └── README.md └── 实践技巧 │ └── 2021-Kubernetes Best Practices 101.md ├── .DS_Store ├── 99~参考资料 ├── 2017~《从 Docker 到 Kubernetes 进阶》 │ └── README.md └── 2020-JimmySong-《Kubernetes 基础教程》 │ ├── 04~控制器 │ ├── README.md │ ├── 33.Job.md │ ├── 34.Ingress 控制器.md │ ├── 32.ReplicationController 和 ReplicaSet.md │ └── 34.CronJob.md │ ├── 03~集群资源管理 │ ├── README.md │ ├── 23.Namespace.md │ ├── 71.资源调度.md │ ├── 22.Node.md │ ├── 72.服务质量等级(QoS).md │ ├── 26.Taint 和 Toleration(污点和容忍).md │ ├── 25.Annotation.md │ └── 24.Label.md │ ├── 12~命令使用 │ ├── _index.md │ └── using-kubectl.md │ ├── 13~集群安全性管理 │ ├── _index.md │ ├── kubernetes-security-best-practice.md │ ├── kubelet-authentication-authorization.md │ └── kubectl-user-authentication-authorization.md │ ├── 11~资源对象配置 │ ├── _index.md │ └── quota.md │ ├── 08~存储 │ ├── README.md │ └── 55.Secret.md │ ├── 05~服务发现与路由 │ ├── _index.md │ └── 40.拓扑感知路由.md │ ├── 09~扩展集群 │ ├── _index.md │ ├── aggregated-api-server.md │ └── custom-resource.md │ ├── 17~开发指南 │ ├── _index.md │ ├── contribute.md │ ├── developing-environment.md │ ├── minikube.md │ ├── sigs-and-working-group.md │ ├── operator.md │ └── operator-sdk.md │ ├── 06~身份与权限认证 │ ├── README.md │ ├── svid.md │ ├── spiffe.md │ └── 46-Network Policy.md │ ├── 01~Kubernetes 架构 │ ├── 11~Pod 状态与生命周期管理.md │ ├── 06~开放接口 │ │ └── README.md │ ├── 05~Etcd 解析.md │ └── README.md │ ├── 14~访问集群 │ ├── _index.md │ ├── lens.md │ ├── kubernator-kubernetes-ui.md │ ├── connecting-to-applications-port-forward.md │ └── service-access-application-cluster.md │ ├── 15~部署应用 │ └── _index.md │ ├── 10~多集群管理 │ ├── multi-cluster-services-api.md │ └── _index.md │ ├── 07~网络 │ └── _index.md │ ├── 02~资源对象 │ ├── pod-hook.md │ ├── pod-preset.md │ └── pod-overview.md │ └── _index.md ├── 04~生态扩展 ├── Helm │ ├── 基础 │ │ ├── 组件.md │ │ └── 命令.md │ ├── README.md │ ├── Charts │ │ ├── 存储库.md │ │ ├── Hooks.md │ │ └── Chart 文件结构.md │ └── 模板 │ │ └── 外部文件.md └── KubeVela │ └── README.md ├── 00~概念与架构 ├── 04~开放接口.md └── 03~集群组件.md └── .gitignore /.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /01~应用部署/03~典型案例/ELK.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /01~应用部署/03~典型案例/Caddy.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /02~资源对象/07~集群资源管理/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /01~应用部署/03~典型案例/Prometheus.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /01~应用部署/03~典型案例/Traefik.md: -------------------------------------------------------------------------------- 1 | # Traefik 2 | -------------------------------------------------------------------------------- /03~工程实践/高可用集群/README.md: -------------------------------------------------------------------------------- 1 | # K8s 高可用集群 2 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Deployment/案例/集群应用.md: -------------------------------------------------------------------------------- 1 | # 集群应用 2 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Deployment/案例/有状态应用.md: -------------------------------------------------------------------------------- 1 | # 有状态应用 2 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Deployment/案例/简单无状态应用.md: -------------------------------------------------------------------------------- 1 | # 简单无状态应用 2 | -------------------------------------------------------------------------------- /03~工程实践/高可用集群/调度和驱逐/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 资源调度 2 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Ambassador/README.md: -------------------------------------------------------------------------------- 1 | # Ambassador 2 | 3 | -------------------------------------------------------------------------------- /02~资源对象/03~服务发现与路由/02~Ingress/Nginx/README.md: -------------------------------------------------------------------------------- 1 | # Nginx Ingress 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/K8s-Notes/master/.DS_Store -------------------------------------------------------------------------------- /01~应用部署/03~典型案例/README.md: -------------------------------------------------------------------------------- 1 | # K8s 中典型应用的安装与配置 2 | 3 | # Links 4 | 5 | - https://8gwifi.org/docs/kube-mysql.jsp 6 | -------------------------------------------------------------------------------- /01~应用部署/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 基础概念 2 | 3 | # Links 4 | 5 | - https://mp.weixin.qq.com/s/WC5TQSBHiHsAIDtpDsZ1qw 6 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Ambassador/K3s 结合 Ambassador 部署.md: -------------------------------------------------------------------------------- 1 | # K3s 2 | 3 | > https://mp.weixin.qq.com/s/G_wbeYUUKIzt4w-GDk9OHQ -------------------------------------------------------------------------------- /99~参考资料/2017~《从 Docker 到 Kubernetes 进阶》/README.md: -------------------------------------------------------------------------------- 1 | # [从 Docker 到 Kubernetes 进阶](https://www.qikqiak.com/k8s-book/) 2 | -------------------------------------------------------------------------------- /02~资源对象/04~身份与权限/RBAC/README.md: -------------------------------------------------------------------------------- 1 | # RBAC 2 | 3 | # Links 4 | 5 | - https://jimmysong.io/kubernetes-handbook/concepts/rbac.html 6 | -------------------------------------------------------------------------------- /01~应用部署/99~参考资料/学习 K8s 的基础知识.md: -------------------------------------------------------------------------------- 1 | > [原文地址](https://zq99299.github.io/note-book/posts/k8s/kubernetes-basics.html#%E9%83%A8%E7%BD%B2%E5%BA%94%E7%94%A8) 2 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/04~控制器/README.md: -------------------------------------------------------------------------------- 1 | # 控制器 2 | 3 | Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为。 4 | 5 | ## 本节大纲 6 | -------------------------------------------------------------------------------- /02~资源对象/03~服务发现与路由/Network Policy/README.md: -------------------------------------------------------------------------------- 1 | # Network Policy 2 | 3 | # Links 4 | 5 | - https://jimmysong.io/kubernetes-handbook/concepts/network-policy.html 6 | -------------------------------------------------------------------------------- /03~工程实践/实践技巧/2021-Kubernetes Best Practices 101.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Best Practices 101 2 | 3 | # Links 4 | 5 | - https://github.com/diegolnasc/kubernetes-best-practices#labels 6 | -------------------------------------------------------------------------------- /02~资源对象/03~服务发现与路由/02~Ingress/Traefik/README.md: -------------------------------------------------------------------------------- 1 | # Traefil 2 | 3 | # Links 4 | 5 | - https://medium.com/@geraldcroes/kubernetes-traefik-101-when-simplicity-matters-957eeede2cf8 6 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/03~集群资源管理/README.md: -------------------------------------------------------------------------------- 1 | # 集群资源管理 2 | 3 | 为了管理异构和不同配置的主机,为了便于 Pod 的运维管理,Kubernetes 中提供了很多集群管理的配置和管理功能,通过 namespace 划分的空间,通过为 node 节点创建 label 和 taint 用于 pod 的调度等。 4 | 5 | ## 本节大纲 6 | -------------------------------------------------------------------------------- /02~资源对象/04~身份与权限/README.md: -------------------------------------------------------------------------------- 1 | # K8s 中身份与权限 2 | 3 | Kubernetes 集群可以同时管理大量互不相关的工作负载,而组织通常会选择将不同团队创建的项目部署到共享集群上。随着数量的增加,部署对象常常很快就会变得难以管理,拖慢操作响应速度,并且会增加危险错误出现的概率。Kubernetes 中提供了良好的多租户认证管理机制,如 RBAC、ServiceAccount 还有各种 Policy 等。 4 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/12~命令使用/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 78 3 | title: 命令使用 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubernetes 中的 kubectl 及其他管理命令使用。 9 | 10 | ## 本节大纲 11 | -------------------------------------------------------------------------------- /04~生态扩展/Helm/基础/组件.md: -------------------------------------------------------------------------------- 1 | # Helm 组件 2 | 3 | Helm 采用客户端/服务器架构,有如下组件组成: 4 | 5 | - Helm CLI 是 Helm 客户端,可以在本地执行。 6 | 7 | - Tiller 是服务器端组件,在 K8s 群集上运行,并管理 K8s 应用程序的生命周期。 8 | 9 | - Repository 是 Chart 仓库,Helm 客户端通过 HTTP 协议来访问仓库中 Chart 的索引文件和压缩包。 -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/13~集群安全性管理/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 83 3 | title: 集群安全性管理 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubernetes 支持多租户,这就需要对集群的安全性进行管理。 9 | 10 | ## 本节大纲 11 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Stateful Set/99~参考资料/2021.Kubernetes StatefulSet - Examples & Best Practices.md: -------------------------------------------------------------------------------- 1 | > [原文地址](https://loft.sh/blog/kubernetes-statefulset-examples-and-best-practices/) 2 | 3 | # Kubernetes StatefulSet - Examples & Best Practices 4 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/11~资源对象配置/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 73 3 | title: 资源对象配置 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | level: 1 7 | --- 8 | 9 | Kubernetes 中的各个资源对象的配置指南。 10 | 11 | ## 本节大纲 12 | -------------------------------------------------------------------------------- /02~资源对象/03~服务发现与路由/02~Ingress/Porter/README.md: -------------------------------------------------------------------------------- 1 | # Porter 2 | 3 | Porter 是 KubeSphere 团队研发的一款开源的基于 BGP 协议的云原生负载均衡器插件。它的主要特性有:基于路由器 ECMP 的负载均衡、基于 BGP 路由动态配置、VIP 管理等。 4 | 5 | # Links 6 | 7 | - https://mp.weixin.qq.com/s/cI--94l1Rp_N0TcxsnWchg 8 | -------------------------------------------------------------------------------- /03~工程实践/高可用集群/集群监控/README.md: -------------------------------------------------------------------------------- 1 | # 基于 Prometheus 的集群监控 2 | 3 | # Links 4 | 5 | - https://www.kancloud.cn/huyipow/prometheus/527093 如何以优雅的姿势监控 kubernetes 6 | - Kubernetes Monitoring with Prometheus https://sysdig.com/blog/kubernetes-monitoring-prometheus/ 7 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/08~存储/README.md: -------------------------------------------------------------------------------- 1 | # 存储 2 | 3 | 为了管理存储,Kubernetes 提供了以下资源对象: 4 | 5 | - Secret:用于管理敏感信息 6 | - ConfigMap:存储配置 7 | - Volume、PV、PVC、StorageClass 等:用来管理存储卷 8 | 9 | 本节将为你讲解 Kubernetes 中的存储对象。 10 | 11 | ## 本节大纲 12 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/05~服务发现与路由/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 38 3 | title: 服务发现与路由 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubernetes 中为了实现服务实例间的负载均衡和不同服务间的服务发现,创造了 Serivce 对象,同时又为从集群外部访问集群创建了 Ingress 对象。 9 | 10 | ## 本节大纲 11 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/09~扩展集群/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 62 3 | title: 扩展集群 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubernetes 是一个高度开放可扩展的架构,可以通过自定义资源类型(CRD)来定义自己的类型,还可以自己来扩展 API 服务,用户的使用方式跟 Kubernetes 的原生对象无异。 9 | 10 | ## 本节大纲 11 | -------------------------------------------------------------------------------- /01~应用部署/03~典型案例/MEAN.md: -------------------------------------------------------------------------------- 1 | # MEAN 2 | 3 | MEAN 是用来构建网站和 web 应用的免费开源的 JavaScript 软件栈,该软件栈包括 MongoDB、Express.js、Angular 和 Node.js。 4 | 5 | # Helm 6 | 7 | 首先我们下载 charts: 8 | 9 | ```sh 10 | 11 | ``` 12 | 13 | # Links 14 | 15 | - https://jimmysong.io/kubernetes-handbook/practice/helm.html 16 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/17~开发指南/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 100 3 | title: 开发指南 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | 讲解如何在原生 Kubernetes 的基础上做定制开发。 9 | 10 | ## 本节大纲 11 | 12 | {{< cta cta_text="阅读本章" cta_link="sigs-and-working-group" >}} 13 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/Weave/README.md: -------------------------------------------------------------------------------- 1 | # Weave 2 | 3 | 在每个宿主机上布置一个特殊的 route 的容器,不同宿主机的 route 容器连接起来。route 拦截所有普通容器的 ip 请求,并通过 udp 包发送到其他宿主机上的普通容器。这样在跨机的多个容器端看到的就是同一个扁平网络。weave 解决了网络问题,不过部署依然是单机的。 4 | 5 | ![image](https://user-images.githubusercontent.com/5803001/45594701-a3127780-b9d1-11e8-8067-6b25fd5a9064.png) 6 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/06~身份与权限认证/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 43 3 | title: 身份与权限认证 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubernetes 中提供了良好的多租户认证管理机制,如 RBAC、ServiceAccount 还有各种策略等。 9 | 10 | 另外还有一个 CNCF 孵化项目 [SPIFFE](https://spiffe.io/) 旨在为所有的分布式应用提供身份支持,目前已应用在了 Envoy、Istio 等应用中。 11 | 12 | ## 本节大纲 13 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/01~Kubernetes 架构/11~Pod 状态与生命周期管理.md: -------------------------------------------------------------------------------- 1 | # Pod 状态与生命周期管理 2 | 3 | 该节将带领大家了解 Kubernetes 中的基本概念,尤其是作为 Kubernetes 中调度的最基本单位 Pod。 4 | 5 | 本节中包括以下内容: 6 | 7 | - 了解 Pod 的构成 8 | - Pod 的生命周期 9 | - Pod 中容器的启动顺序模板定义 10 | 11 | Kubernetes 中的基本组件 `kube-controller-manager` 就是用来控制 Pod 的状态和生命周期的,在了解各种 controller 之前我们有必要先了解下 Pod 本身和其生命周期。 12 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/01~Kubernetes 架构/06~开放接口/README.md: -------------------------------------------------------------------------------- 1 | # 开放接口 2 | 3 | Kubernetes 作为云原生应用的基础调度平台,相当于云原生的操作系统,为了便于系统的扩展,Kubernetes 中开放的以下接口,可以分别对接不同的后端,来实现自己的业务逻辑: 4 | 5 | - [容器运行时接口(CRI)](cri):提供计算资源 6 | - [容器网络接口(CNI)](cni):提供网络资源 7 | - [容器存储接口(CSI)](csi),提供存储资源 8 | 9 | 以上三种资源相当于一个分布式操作系统的最基础的几种资源类型,而 Kuberentes 是将他们粘合在一起的纽带。 10 | 11 | ## 本节大纲 12 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/14~访问集群/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 91 3 | title: 访问 Kubernetes 集群 4 | linkTitle: 访问集群 5 | date: "2022-05-21T00:00:00+08:00" 6 | type: book 7 | --- 8 | 9 | 根据用户部署和暴露服务的方式不同,有很多种方式可以用来访问 Kubernetes 集群。 10 | 11 | - 最简单也是最直接的方式是使用 `kubectl` 命令。 12 | - 其次可以使用 `kubeconfig` 文件来认证授权访问 API server。 13 | - 通过各种 proxy 经过端口转发访问 Kubernetes 集群中的服务 14 | - 使用 Ingress,在集群外访问 Kubernetes 集群内的 service 15 | 16 | ## 本节大纲 17 | -------------------------------------------------------------------------------- /01~应用部署/01~安装配置/K3s/README.md: -------------------------------------------------------------------------------- 1 | # K3s 2 | 3 | Kubernetes 已经改变了如何大规模部署和管理容器化工作负载。现在开发人员面临的挑战主要在于设置过程的复杂性和资源需求量巨大。如果你深受内存不足的困扰,想要部署轻量级 Kubernetes 集群来减少内存占用,那么你一定要考虑由 Rancher Labs 发布的轻量级 Kubernetes 发行版:k3s。它把安装 Kubernetes 所需的一切文件都打包进一个 40MB 大小的二进制文件中,仅需 512MB 的 RAM 即可运行。非常适用于资源有限的环境,如边缘计算场景、IoT 等。。K3s 被打包成一个单独的二进制文件,对于操作系统的依赖性微乎其微,这使得它非常易于运维和使用。K3s 使用 sqlite3 而非 etcd 作为默认的存储后端。由于所有相关的组件都运行在同一个进程里,这使得 K3s 的内存占用非常低。通过剥离不相关的第三方存储驱动和云提供商,K3s 的二进制文件得以控制得非常小。在资源受限的环境中,K3s 是一个值得考虑的非常不错的选择。 4 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/Calico/README.md: -------------------------------------------------------------------------------- 1 | # Calico 2 | 3 | Calico 没有使用 CNI 的网桥模式,而是将节点当成边界路由器,组成了一个全连通的网络,通过 BGP 协议交换路由。所以,Calico 的 CNI 插件还需要在宿主机上为每个容器的 Veth Pair 设备配置一条路由规则,用于接收传入的 IP 包。Calico 的组件: 4 | 5 | - CNI 插件:Calico 与 Kubernetes 对接的部分。 6 | - Felix:负责在宿主机上插入路由规则(即:写入 Linux 内核的 FIB 转发信息库),以及维护 Calico 所需的网络设备等工作。 7 | - BIRD (BGP Route Reflector):是 BGP 的客户端,专门负责在集群里分发路由规则信息。 8 | 9 | 三个组件都是通过一个 DaemonSet 安装的。CNI 插件是通过 initContainer 安装的;而 Felix 和 BIRD 是同一个 pod 的两个 container。 10 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/15~部署应用/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 99 3 | title: 在 Kubernetes 中开发部署应用 4 | linkTitle: "部署应用" 5 | date: "2022-05-21T00:00:00+08:00" 6 | type: book 7 | --- 8 | 9 | 理论上只要可以使用主机名做服务注册的应用都可以迁移到 Kubernetes 集群上。看到这里你可能不禁要问,为什么使用 IP 地址做服务注册发现的应用不适合迁移到 kubernetes 集群?因为这样的应用不适合自动故障恢复,因为目前 Kubernetes 中不支持固定 Pod 的 IP 地址,当 Pod 故障后自动转移到其他节点的时候该 Pod 的 IP 地址也随之变化。 10 | 11 | 将传统应用迁移到 Kubernetes 中可能还有很长的路要走,但是直接开发云原生应用,Kubernetes 就是最佳运行时环境了。 12 | 13 | ## 本节大纲 14 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/Flannel/host-gw 模式.md: -------------------------------------------------------------------------------- 1 | # host-gw 模式 2 | 3 | 最后一种 host-gw 模式是一种纯三层网络方案。其工作原理为将每个 Flannel 子网的“下一跳”设置成了该子网对应的宿主机的 IP 地址,这台主机会充当这条容器通信路径里的“网关”。这样 IP 包就能通过二层网络达到目的主机,而正是因为这一点,host-gw 模式要求集群宿主机之间的网络是二层连通的,如下图所示。 4 | 5 | ![host-gw 模式](https://s1.ax1x.com/2020/10/19/0xsR54.png) 6 | 7 | 宿主机上的路由信息是 flanneld 设置的,因为 flannel 子网和主机的信息保存在 etcd 中,所以 flanneld 只需要 watch 这些数据的变化,实时更新路由表即可。在这种模式下,容器通信的过程就免除了额外的封包和解包带来的性能损耗。 8 | 9 | Node 1 上的 Pod 1 请求 Node 2 上的 Pod 2 时,流量的走向如下: 10 | 11 | - Pod 1 里的进程发起请求,发出 IP 包,从网络层进入链路层封装成帧; 12 | - 根据主机上的路由规则,数据帧从 Node 1 通过宿主机的二层网络到达 Node 2 上; 13 | -------------------------------------------------------------------------------- /02~资源对象/06~存储/Rook/README.md: -------------------------------------------------------------------------------- 1 | # Rook 2 | 3 | Rook 就是一组 Kubernetes 的 Operator,它可以完全控制多种数据存储解决方案(例如 Ceph、EdgeFS、Minio、Cassandra)的部署,管理以及自动恢复。Rook 将分布式存储软件转变为自我管理,自我缩放和自我修复的存储服务。它通过自动化部署,引导、配置、供应、扩展、升级、迁移、灾难恢复、监控和资源管理来实现 Rook 使用基础的云原生容器管理、调度和编排平台提供的功能来履行其职责。 4 | 5 | Rook 利用扩展点深入融入云原生环境,为调度、生命周期管理、资源管理、安全性、监控和用户体验提供无缝体验。Rook 最初专注于在 Kubernetes 之上运行 Ceph。Ceph 是一个分布式存储系统,提供文件、数据块和对象存储,可以部署在大型生产集群中。Rook 计划在未来的版本中增加对除 Ceph 之外的其他存储系统以及 Kubernetes 之外的其他云原生环境的支持。 6 | 7 | ![Rook Architecture](https://s2.ax1x.com/2020/01/14/lqVSeJ.png) 8 | 9 | 使用 Rook 的其中一个主要好处在于它是通过原生的 Kubernetes 机制和数据存储交互。这就意味着你不再需要通过命令行手动配置 Ceph。 10 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Deployment/案例/README.md: -------------------------------------------------------------------------------- 1 | # K8s 中的应用与任务部署 2 | 3 | 参考[云原生](https://ng-tech.icu/books/Backend-Notes/#/?q=云原生)一篇中的定义,将云原生的组件映射为 Kubernetes 的原语(即 Kubernetes 里的各种资源对象和概念组合),可以得到如下图: 4 | 5 | ![云原生与 K8s 概念映射](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230430223550.png) 6 | 7 | 在 K8s 中的应用部署我们往往应该遵循如下的规则: 8 | 9 | - 不要直接部署裸的 Pod。在 Pod 里增加 Readiness 和 Liveness 探针。给 Pod 这只 CPU 和内存资源限额。 10 | - 为工作负载选择合适的 Controller。 11 | - 定义多个 Namespace 来限制默认 Service 范围的可视性。在应用程序工作负载启动之前先启动 Service 12 | - 使用 Deployment history 来回滚到历史版本。使用 ConfigMap 和 Secret 来存储配置。 13 | - 使用 Init 容器确保应用程序被正确的初始化。配置 HPA 来动态扩展无状态工作负载。 14 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/17~开发指南/contribute.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 113 3 | title: 参与 Kubernetes 社区贡献 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | 如果您想参与 Kubernetes 社区,请先阅读下[Kubernetes Community](https://github.com/kubernetes/community)这个 GitHub Repo中的文档,该文档中包括社区的治理形式、社区成员资格申请、提交 Issue、查找问题和提交 PR 的指导等。 9 | 10 | ## 参考 11 | 12 | - [Kubernetes Community](https://github.com/kubernetes/community) 13 | - [Kubernetes Developer Guide](https://github.com/kubernetes/community/tree/master/contributors/devel) 14 | - [Enhencement Tracking and Backlog](https://github.com/kubernetes/features) 15 | - [Kubernetes 官方网站项目](https://github.com/kubernetes/website) 16 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/Flannel/VXLAN 模式.md: -------------------------------------------------------------------------------- 1 | # VXLAN 模式 2 | 3 | VXLAN,即 Virtual Extensible LAN(虚拟可扩展局域网),是 Linux 内核本身就支持的一种网络虚拟化技术。通过利用 Linux 内核的这种特性,也可以实现在内核态的封装和解封装的能力,从而构建出覆盖网络。其工作原理如下图所示: 4 | 5 | ![VXLAN 工作模式](https://s1.ax1x.com/2020/10/19/0vb7TJ.png) 6 | 7 | VXLAN 模式的 flannel 会在节点上创建一个叫 flannel.1 的 VTEP (VXLAN Tunnel End Point,虚拟隧道端点) 设备,跟 UDP 模式一样,该设备将二层数据帧封装在 UDP 包里,再转发出去,而与 UDP 模式不一样的是,整个封装的过程是在内核态完成的。 8 | 9 | Node 1 上的 Pod 1 请求 Node 2 上的 Pod 2 时,流量的走向如下: 10 | 11 | 1. Pod 1 里的进程发起请求,发出 IP 包; 12 | 2. IP 包根据 Pod 1 里的 veth 设备对,进入到 cni0 网桥; 13 | 3. 由于 IP 包的目的 ip 不在 Node 1 上,根据 flannel 在节点上创建出来的路由规则,进入到 flannel.1 中; 14 | 4. flannel.1 将原始 IP 包加上一个目的 MAC 地址,封装成一个二层数据帧;然后内核将数据帧封装进一个 UDP 包里; 15 | 5. 最后通过 Node 1 上的网关,发送给 Node 2; 16 | -------------------------------------------------------------------------------- /02~资源对象/06~存储/卷/README.md: -------------------------------------------------------------------------------- 1 | # Volume 2 | 3 | Container 中的文件在磁盘上是临时存放的,这给 Container 中运行的较重要的应用程序带来一些问题。问题之一是当容器崩溃时文件丢失。kubelet 会重新启动容器,但容器会以干净的状态重启。第二个问题会在同一 Pod 中运行多个容器并共享文件时出现。Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题。 4 | 5 | Docker 也有 卷(Volume) 的概念,但对它只有少量且松散的管理。Docker 卷是磁盘上或者另外一个容器内的一个目录。Docker 提供卷驱动程序,但是其功能非常有限。Kubernetes 支持很多类型的卷。Pod 可以同时使用任意数目的卷类型。临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。因此,卷的存在时间会超出 Pod 中运行的所有容器,并且在容器重新启动时数据也会得到保留。当 Pod 不再存在时,卷也将不再存在。 6 | 7 | 卷的核心是包含一些数据的一个目录,Pod 中的容器可以访问该目录。所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放 的内容。使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。容器中的进程看到的是由它们的 Docker 镜像和卷组成的文件系统视图。Docker 镜像 位于文件系统层次结构的根部。各个卷则挂载在镜像内的指定路径上。卷不能挂载到其他卷之上,也不能与其他卷有硬链接。Pod 配置中的每个容器必须独立指定各个卷的挂载位置。 8 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/03~集群资源管理/23.Namespace.md: -------------------------------------------------------------------------------- 1 | # Namespace 2 | 3 | 在一个 Kubernetes 集群中可以使用 namespace 创建多个 “虚拟集群”,这些 namespace 之间可以完全隔离,也可以通过某种方式,让一个 namespace 中的 service 可以访问到其他的 namespace 中的服务。 4 | 5 | ## 哪些情况下适合使用多个 namespace 6 | 7 | 因为 namespace 可以提供独立的命名空间,因此可以实现部分的环境隔离。当你的项目和人员众多的时候可以考虑根据项目属性,例如生产、测试、开发划分不同的 namespace。 8 | 9 | ## Namespace 使用 10 | 11 | **获取集群中有哪些 namespace** 12 | 13 | `kubectl get ns` 14 | 15 | 集群中默认会有 `default` 和 `kube-system` 这两个 namespace。 16 | 17 | 在执行 `kubectl` 命令时可以使用 `-n` 指定操作的 namespace。 18 | 19 | 用户的普通应用默认是在 `default` 下,与集群管理相关的为整个集群提供服务的应用一般部署在 `kube-system` 的 namespace 下,例如我们在安装 kubernetes 集群时部署的 `kubedns`、`heapseter`、`EFK` 等都是在这个 namespace 下面。 20 | 21 | 另外,并不是所有的资源对象都会对应 namespace,`node` 和 `persistentVolume` 就不属于任何 namespace。 22 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/14~访问集群/lens.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 97 3 | title: Lens - Kubernetes IDE 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | [Lens](https://k8slens.dev/) 是一款开源的 Kubenretes IDE,也可以作为桌面客户端,官方网站 ,具有以下特性: 9 | 10 | - 完全开源,GitHub 地址 11 | - 实时展示集群状态 12 | - 内置 Prometheus 监控 13 | - 多集群,多个 namespace 管理 14 | - 原生 Kubernetes 支持 15 | - 支持使用 chart 安装应用 16 | - 使用 kubeconfig 登陆认证 17 | - 支持多平台,Windows、Mac、Linux 18 | - Visual Studio Code 友好的风格设计 19 | 20 | Lens 界面图下图所示。 21 | 22 | ![Lens Kubernetes IDE 界面](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/lens.jpg "Lens Kubernetes IDE 界面") 23 | 24 | ## 参考 25 | 26 | - [Lens, Kubernetes IDE - k8slens.dev](https://k8slens.dev/) 27 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/17~开发指南/developing-environment.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 105 3 | title: 配置 Kubernetes 开发环境 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | 我们将在 Mac 上使用 docker 环境编译 kuberentes。 9 | 10 | ## 安装依赖 11 | 12 | ```bash 13 | brew install gnu-tar 14 | ``` 15 | 16 | Docker 环境,至少需要给容器分配 4G 内存,在低于 3G 内存的时候可能会编译失败。 17 | 18 | ## 执行编译 19 | 20 | 切换目录到 kuberentes 源码的根目录下执行: 21 | 22 | `./build/run.sh make` 可以在 docker 中执行跨平台编译出二进制文件。 23 | 24 | 需要用的的 docker 镜像: 25 | 26 | ```bash 27 | gcr.io/google_containers/kube-cross:v1.7.5-2 28 | ``` 29 | 30 | 该镜像基于 Ubuntu 构建,大小 2.15G,编译环境中包含以下软件: 31 | 32 | - Go1.7.5 33 | - etcd 34 | - protobuf 35 | - g++ 36 | - 其他 golang 依赖包 37 | 38 | 在我自己的电脑上的整个编译过程大概要半个小时。 39 | 40 | 编译完成的二进制文件在 `/_output/local/go/bin/` 目录下。 41 | -------------------------------------------------------------------------------- /02~资源对象/06~存储/ConfigMap/README.md: -------------------------------------------------------------------------------- 1 | # ConfigMap 2 | 3 | 应用部署的一个最佳实践是将应用所需的配置信息与程序进行分离,这样可以使得应用程序被更好地复用,通过不同的配置也能实现更灵活的功能。将应用打包为容器镜像后,可以通过环境变量或者外挂文件的方式在创建容器时进行配置注入,但在大规模容器集群的环境中,对多个容器进行不同的配置将变得非常复杂。ConfigMap 即是用来存储配置文件的 K8s 资源对象,所有的配置内容都存储在 etcd 中。 4 | 5 | ![ConfigMap 示意图](https://matthewpalmer.net/kubernetes-app-developer/articles/configmap-diagram.gif) 6 | 7 | ConfigMap 供容器使用的典型用法如下: 8 | 9 | - 生成为容器内的环境变量; 10 | - 设置容器启动命令的启动参数(需设置为环境变量); 11 | - 以 Volume 的形式挂载为容器内部的文件或目录。 12 | 13 | # Links 14 | 15 | - https://learning.oreilly.com/library/view/kubernetes-for-developers/9781788834759/961e9251-74a4-4e47-8a48-9c02f3500bbb.xhtml 16 | - https://blog.csdn.net/liukuan73/article/details/79492374 17 | - https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ 18 | - https://www.jianshu.com/p/d834bca35c18 19 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Deployment/README.md: -------------------------------------------------------------------------------- 1 | # K8s 控制器 2 | 3 | Kubernetes 中内建了很多 Controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为;Deployment 是一个功能,负责指示 Kubernetes 创建、更新和监控应用实例的健康状况。Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义方法,用来替代以前的 Replication Controller 来方便的管理应用。只需要在 Deployment 中描述您想要的目标状态是什么,Deployment Controller 就会将 Pod 和 ReplicaSet 的实际状态改变到目标状态。您可以定义一个全新的 Deployment 来创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换。 4 | 5 | Deployment 典型的应用场景是,使用 Deployment 来创建 ReplicaSet。ReplicaSet 在后台创建 Pod 并检查启动状态,看它是成功还是失败。然后,通过更新 Deployment 的 PodTemplateSpec 字段来声明 Pod 的新状态。这会创建一个新的 ReplicaSet。Deployment 会按照控制的速率将 pod 从旧的 ReplicaSet 移动到新的 ReplicaSet 中;如果当前状态不稳定,回滚到之前的 Deployment revision。每次回滚都会更新 Deployment 的 revision。Deployment 还能够完成扩容 Deployment 以满足更高的负载;暂停 Deployment 来应用 PodTemplateSpec 的多个修复,然后恢复上线;根据 Deployment 的状态判断上线是否 hang 住了;清除旧的不必要的 ReplicaSet 等功能。 6 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/03~集群资源管理/71.资源调度.md: -------------------------------------------------------------------------------- 1 | # 资源调度 2 | 3 | Kubernetes 作为一个容器编排调度引擎,资源调度是它的最基本也是最重要的功能,这一节中我们将着重讲解 Kubernetes 中是如何做资源调度的。 4 | 5 | Kubernetes 中有一个叫做 `kube-scheduler` 的组件,该组件就是专门监听 `kube-apiserver` 中是否有还未调度到 node 上的 pod,再通过特定的算法为 pod 指定分派 node 运行。 6 | 7 | Kubernetes 中的众多资源类型,例如 Deployment、DaemonSet、StatefulSet 等都已经定义了 Pod 运行的一些默认调度策略,但是如果我们细心的根据 node 或者 pod 的不同属性,分别为它们打上标签之后,我们将发现 Kubernetes 中的高级调度策略是多么强大。当然如果要实现动态的资源调度,即 pod 已经调度到某些节点上后,因为一些其它原因,想要让 pod 重新调度到其它节点。 8 | 9 | 考虑以下两种情况: 10 | 11 | - 集群中有新增节点,想要让集群中的节点的资源利用率比较均衡一些,想要将一些高负载的节点上的 pod 驱逐到新增节点上,这是 kuberentes 的 scheduler 所不支持的,需要使用如 [descheduler](https://github.com/kubernetes-sigs/descheduler) 这样的插件来实现。 12 | - 想要运行一些大数据应用,设计到资源分片,pod 需要与数据分布达到一致均衡,避免个别节点处理大量数据,而其它节点闲置导致整个作业延迟,这时候可以考虑使用 [kube-batch](https://github.com/kubernetes-sigs/kube-batch)。 13 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/Flannel/UDP 模式.md: -------------------------------------------------------------------------------- 1 | # UDP 模式 2 | 3 | UDP 模式,是 Flannel 项目最早支持的一种方式,却也是性能最差的一种方式。这种模式提供的是一个三层的 Overlay 网络,即:它首先对发出端的 IP 包进行 UDP 封装,然后在接收端进行解封装拿到原始的 IP 包,进而把这个 IP 包转发给目标容器。工作原理如下图所示。 4 | 5 | ![Flannel UDP 模式示意](https://s1.ax1x.com/2020/10/19/0vHaKU.png) 6 | 7 | Node 1 上的 Pod 1 请求 Node2 上的 Pod 2 时,流量的走向如下: 8 | 9 | 1. Pod 1 里的进程发起请求,发出 IP 包; 10 | 2. IP 包根据 Pod 1 里的 veth 设备对,进入到 cni0 网桥; 11 | 3. 由于 IP 包的目的 ip 不在 Node 1 上,根据 flannel 在节点上创建出来的路由规则,进入到 flannel0 中; 12 | 4. 此时 flanneld 进程会收到这个包,flanneld 判断该包应该在哪台 node 上,然后将其封装在一个 UDP 包中; 13 | 5. 最后通过 Node 1 上的网关,发送给 Node2; 14 | 15 | flannel0 是一个 TUN 设备(Tunnel 设备)。在 Linux 中,TUN 设备是一种工作在三层(Network Layer)的虚拟网络设备。TUN 设备的功能:在操作系统内核和用户应用程序之间传递 IP 包。 16 | 17 | 可以看到,这种模式性能差的原因在于,整个包的 UDP 封装过程是 flanneld 程序做的,也就是用户态,而这就带来了一次内核态向用户态的转换,以及一次用户态向内核态的转换。在上下文切换和用户态操作的代价其实是比较高的,而 UDP 模式因为封包拆包带来了额外的性能消耗。 18 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/10~多集群管理/multi-cluster-services-api.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 69 3 | title: 多集群服务 API(Multi-Cluster Services API) 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | 2020 年初,Kubernetes 社区提议 [Multi-Cluster Services API](https://docs.google.com/document/d/1hFtp8X7dzVS-JbfA5xuPvI_DNISctEbJSorFnY-nz6o/edit#heading=h.u7jfy9wqpd2b),旨在解决长久以来就存在的 Kubernetes 多集群服务管理问题。 9 | 10 | Kubernetes 用户可能希望将他们的部署分成多个集群,但仍然保留在这些集群中运行的工作负载之间的相互依赖关系,这有[很多原因](https://docs.google.com/document/d/1G1lfIukib7Fy_LpLUoHZPhcZ5T-w52D2YT9W1465dtY/edit)。今天,集群是一个硬边界,一个服务对远程的 Kubernetes 消费者来说是不透明的,否则就可以利用元数据(如端点拓扑结构)来更好地引导流量。为了支持故障转移或在迁移过程中的临时性,用户可能希望消费分布在各集群中的服务,但今天这需要非复杂的定制解决方案。 11 | 12 | 多集群服务 API 旨在解决这些问题。 13 | 14 | ## 参考 15 | 16 | - [KEP-1645: Multi-Cluster Services API - github.com](https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api) 17 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/07~网络/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 49 3 | title: 网络 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubernetes 中的网络可以说对初次接触 Kubernetes 或者没有网络方面经验的人来说可能是其中最难的部分。Kubernetes 本身并不提供网络功能,只是把网络接口开放出来,通过插件的形式实现。 9 | 10 | ## 网络要解决的问题 11 | 12 | 既然 Kubernetes 中将容器的联网通过插件的方式来实现,那么该如何解决容器的联网问题呢? 13 | 14 | 如果您在本地单台机器上运行 docker 容器的话会注意到所有容器都会处在 `docker0` 网桥自动分配的一个网络 IP 段内(172.17.0.1/16)。该值可以通过 docker 启动参数 `--bip` 来设置。这样所有本地的所有的容器都拥有了一个 IP 地址,而且还是在一个网段内彼此就可以互相通信了。 15 | 16 | 但是 Kubernetes 管理的是集群,Kubernetes 中的网络要解决的核心问题就是每台主机的 IP 地址网段划分,以及单个容器的 IP 地址分配。概括为: 17 | 18 | - 保证每个 Pod 拥有一个集群内唯一的 IP 地址 19 | - 保证不同节点的 IP 地址划分不会重复 20 | - 保证跨节点的 Pod 可以互相通信 21 | - 保证不同节点的 Pod 可以与跨节点的主机互相通信 22 | 23 | 为了解决该问题,出现了一系列开源的 Kubernetes 中的网络插件与方案,如: 24 | 25 | - flannel 26 | - calico 27 | - contiv 28 | - weave 29 | - kube-router 30 | - cilium 31 | - canal 32 | - 等等 33 | 34 | 本章将以当前最常用的 flannel、calico 和 cilium 等插件为例解析。 35 | 36 | ## 本节大纲 37 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/09~扩展集群/aggregated-api-server.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 65 3 | title: Aggregated API Server 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | Aggregated(聚合的)API server 是为了将原来的 API server 这个巨石(monolithic)应用给拆分成,为了方便用户开发自己的 API server 集成进来,而不用直接修改 kubernetes 官方仓库的代码,这样一来也能将 API server 解耦,方便用户使用实验特性。这些 API server 可以跟 core API server 无缝衔接,使用 kubectl 也可以管理它们。 9 | 10 | ## 架构 11 | 12 | 我们需要创建一个新的组件,名为 `kube-aggregator`,它需要负责以下几件事: 13 | 14 | - 提供用于注册 API server 的 API 15 | - 汇总所有的 API server 信息 16 | - 代理所有的客户端到 API server 的请求 17 | 18 | **注意**:这里说的 API server 是一组 “API Server”,而不是说我们安装集群时候的那个 API server,而且这组 API server 是可以横向扩展的。 19 | 20 | ## 安装配置聚合的 API server 21 | 22 | 有两种方式来启用 `kube-aggregator`: 23 | 24 | - 使用 **test mode/single-user mode**,作为一个独立的进程来运行 25 | - 使用 **gateway mode**,`kube-apiserver` 将嵌入到 `kbe-aggregator` 组件中,它将作为一个集群的 gateway,用来聚合所有 apiserver。 26 | 27 | `kube-aggregator` 二进制文件已经包含在 Kubernetes release 里面了。 28 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/03~集群资源管理/22.Node.md: -------------------------------------------------------------------------------- 1 | # Node 2 | 3 | Node 是 Kubernetes 集群的工作节点,可以是物理机也可以是虚拟机。 4 | 5 | ## Node 的状态 6 | 7 | Node 包括如下状态信息: 8 | 9 | - Address 10 | - HostName:可以被 kubelet 中的 `--hostname-override` 参数替代。 11 | - ExternalIP:可以被集群外部路由到的 IP 地址。 12 | - InternalIP:集群内部使用的 IP,集群外部无法访问。 13 | - Condition 14 | - OutOfDisk:磁盘空间不足时为 `True` 15 | - Ready:Node controller 40 秒内没有收到 node 的状态报告为 `Unknown`,健康为 `True`,否则为 `False`。 16 | - MemoryPressure:当 node 有内存压力时为 `True`,否则为 `False`。 17 | - DiskPressure:当 node 有磁盘压力时为 `True`,否则为 `False`。 18 | - Capacity 19 | - CPU 20 | - 内存 21 | - 可运行的最大 Pod 个数 22 | - Info:节点的一些版本信息,如 OS、kubernetes、docker 等 23 | 24 | ## Node 管理 25 | 26 | 禁止 Pod 调度到该节点上。 27 | 28 | ```bash 29 | kubectl cordon 30 | ``` 31 | 32 | 驱逐该节点上的所有 Pod。 33 | 34 | ```bash 35 | kubectl drain 36 | ``` 37 | 38 | 该命令会删除该节点上的所有 Pod(DaemonSet 除外),在其他 node 上重新启动它们,通常该节点需要维护时使用该命令。直接使用该命令会自动调用`kubectl cordon `命令。当该节点维护完成,启动了 kubelet 后,再使用`kubectl uncordon ` 即可将该节点添加到 kubernetes 集群中。 39 | -------------------------------------------------------------------------------- /04~生态扩展/Helm/README.md: -------------------------------------------------------------------------------- 1 | # Helm 2 | 3 | 在 2016 年,随着 K8s 成为编排领域事实上的标准,很多公司的 PaaS 平台都转向以 K8s 为基础容器化平台,但是 Deis(helm 公司)是一个地地道道的 PaaS 服务商,在这片云原生的红海中步履维艰,幸运的是,凭借敏锐的技术嗅觉最终还是拯救了这个的团队。2016 年底,Deis 开始全面转向 K8s 体系,它不像其它公司一样把 K8s 作为 PaaS 基础设施工具,而是围绕 K8s 产生的编排文件做了应用包管理器 helm。 4 | 5 | Helm 是 K8s 的包管理器,Helm chart 用于帮助你定义、安装、更新 K8s 应用,可以处理那些最复杂那种部署情况。在 K8s 中,容器即进程,它解决了如何部署和运行应用的问题。对于任何一个部署在 K8s 的应用而言,通常都可以由几个固定的部分组成:Ingress、Service、Deployment 等。直接使用 K8s 原生的 YAML 定义服务,虽然能一定程度上简化应用的部署,但是对于大部分研发人员来说编写和使用 YAML 依然是一件相对痛苦的事情。Helm 应运而生,Helm 作为 K8s 下的包管理工具,对原生服务定义过程进行了增强,通过模板化,参数化的形式大大简化用户部署 K8s 应用的复杂度。 6 | 7 | # 概念 8 | 9 | 可以将 Helm 理解为 K8s 的包管理工具,可以方便地发现、共享和使用为 K8s 构建的应用,有点类似于 Ubuntu 的 APT 和 CentOS 中的 yum。Helm chart 是用来封装 K8s 原生应用程序的 yaml 文件,可以在你部署应用的时候自定义应用程序的一些 metadata,便与应用程序的分发。它包含几个基本概念: 10 | 11 | - Chart:一个 Helm 包,其中包含了运行一个应用所需要的镜像、依赖和资源定义等,还可能包含 K8s 集群中的服务定义,类似 Homebrew 中的 formula,APT 的 dpkg 或者 Yum 的 rpm 文件, 12 | 13 | - Release: 在 K8s 集群上运行的 Chart 的一个实例。在同一个集群上,一个 Chart 可以安装很多次。每次安装都会创建一个新的 release。例如一个 MySQL Chart,如果想在服务器上运行两个数据库,就可以把这个 Chart 安装两次。每次安装都会生成自己的 Release,会有自己的 Release 名称。 14 | 15 | - Repository:用于发布和存储 Chart 的仓库。 16 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/04~控制器/33.Job.md: -------------------------------------------------------------------------------- 1 | # Job 2 | 3 | Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束。 4 | 5 | ## Job Spec 格式 6 | 7 | - spec.template 格式同 Pod 8 | - RestartPolicy 仅支持 Never 或 OnFailure 9 | - 单个 Pod 时,默认 Pod 成功运行后 Job 即结束 10 | - `.spec.completions` 标志 Job 结束需要成功运行的 Pod 个数,默认为 1 11 | - `.spec.parallelism` 标志并行运行的 Pod 的个数,默认为 1 12 | - `spec.activeDeadlineSeconds` 标志失败 Pod 的重试最大时间,超过这个时间不会继续重试 13 | 14 | 一个简单的例子: 15 | 16 | ```yaml 17 | apiVersion: batch/v1 18 | kind: Job 19 | metadata: 20 | name: pi 21 | spec: 22 | template: 23 | metadata: 24 | name: pi 25 | spec: 26 | containers: 27 | - name: pi 28 | image: perl 29 | command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] 30 | restartPolicy: Never 31 | $ kubectl create -f ./job.yaml 32 | job "pi" created 33 | $ pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath={.items..metadata.name}) 34 | $ kubectl logs $pods -c pi 35 | 3.141592653589793238462643383279502... 36 | ``` 37 | 38 | ## Bare Pod 39 | 40 | 所谓 Bare Pod 是指直接用 PodSpec 来创建的 Pod(即不在 ReplicaSet 或者 ReplicationController 的管理之下的 Pod)。这些 Pod 在 Node 重启后不会自动重启,但 Job 则会创建新的 Pod 继续任务。所以,推荐使用 Job 来替代 Bare Pod,即便是应用只需要一个 Pod。 41 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/03~集群资源管理/72.服务质量等级(QoS).md: -------------------------------------------------------------------------------- 1 | # 服务质量等级(QoS) 2 | 3 | QoS(Quality of Service),大部分译为“服务质量等级”,又译作“服务质量保证”,是作用在 Pod 上的一个配置,当 Kubernetes 创建一个 Pod 时,它就会给这个 Pod 分配一个 QoS 等级,可以是以下等级之一: 4 | 5 | - **Guaranteed**:Pod 里的每个容器都必须有内存/CPU 限制和请求,而且值必须相等。 6 | - **Burstable**:Pod 里至少有一个容器有内存或者 CPU 请求且不满足 Guarantee 等级的要求,即内存/CPU 的值设置的不同。 7 | - **BestEffort**:容器必须没有任何内存或者 CPU 的限制或请求。 8 | 9 | 该配置不是通过一个配置项来配置的,而是通过配置 CPU/内存的 `limits` 与 `requests` 值的大小来确认服务质量等级的。使用 `kubectl get pod -o yaml` 可以看到 pod 的配置输出中有 `qosClass` 一项。该配置的作用是为了给资源调度提供策略支持,调度算法根据不同的服务质量等级可以确定将 pod 调度到哪些节点上。 10 | 11 | 例如,下面这个 YAML 配置中的 Pod 资源配置部分设置的服务质量等级就是 `Guarantee`。 12 | 13 | ```yaml 14 | spec: 15 | containers: 16 | ... 17 | resources: 18 | limits: 19 | cpu: 100m 20 | memory: 128Mi 21 | requests: 22 | cpu: 100m 23 | memory: 128Mi 24 | ``` 25 | 26 | 下面的 YAML 配置的 Pod 的服务质量等级是 `Burstable`。 27 | 28 | ```yaml 29 | spec: 30 | containers: 31 | ... 32 | resources: 33 | limits: 34 | memory: "180Mi" 35 | requests: 36 | memory: "100Mi" 37 | ``` 38 | 39 | ## 参考 40 | 41 | - [配置 Pod 的服务质量 - kubernetes.io](https://kubernetes.io/zh/docs/tasks/configure-pod-container/quality-service-pod/) 42 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/Flannel/README.md: -------------------------------------------------------------------------------- 1 | # Flannel 2 | 3 | Flannel 是 CoreOS 团队针对 Kubernetes 设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的 Docker 容器都具有全集群唯一的虚拟 IP 地址。Flannel 和 OpenVSwitch 思路基本一致,就是当 Docker 在宿主机上创建一个网桥的时候,用自己的网桥替代它。在默认的 Docker 配置中,每个节点上的 Docker 服务会分别负责所在节点容器的 IP 分配。这样导致的一个问题是,不同节点上容器可能获得相同的内外 IP 地址。并使这些容器之间能够之间通过 IP 地址相互找到,也就是相互 ping 通。 4 | 5 | Flannel 的设计目的就是为集群中的所有节点重新规划 IP 地址的使用规则,从而使得不同节点上的容器能够获得“同属一个内网”且”不重复的”IP 地址,并让属于不同节点上的容器能够直接通过内网 IP 通信。Flannel 实质上是一种“覆盖网络(overlaynetwork)”,也就是将 TCP 数据包装在另一种网络包里面进行路由转发和通信,目前已经支持 udp、vxlan、host-gw、aws-vpc、gce 和 alloc 路由等数据转发方式,默认的节点间数据通信方式是 UDP 转发。 6 | 7 | ![Flannel 网络模型解析](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230430223215.png) 8 | 9 | 数据请求从容器 1(10.0.46.2:2379)中发出后,首先经由所在主机的 docker0 虚拟网卡(10.0.46.1)转发到 flannel0 虚拟网卡(10.0.46.0),这是个 P2P 虚拟网卡,Flannel 通过修改 Node 路由表的方式实现 flanneld 服务监听 flannel0 虚拟网卡数据。接着 flannel 服务将原本的数据内容 UDP 封装后根据自己的路由表投递给目的节点的 flanneld 服务。在此包中,包含有 outer-ip(source:192.168.8.227, dest:192.168.8.228),inner-ip(source:10.0.46.2:2379, dest:10.0.90.2:8080)。 10 | 11 | 数据到达 node2 以后被解包,直接进入目的节点的 flannel0 虚拟网卡中(10.0.90.0),且被转发到目的主机的 docker0 虚拟网卡(10.0.90.1),最后就像本机容器通信一样由 docker0 路由到达目标容器 2(10.0.90.2:8080)。为使每个结点上的容器分配的地址不冲突。Flannel 通过 Etcd 分配了每个节点可用的 IP 地址段后,再修改 Docker 的启动参数。“--bip=X.X.X.X/X”这个参数,它限制了所在节点容器获得的 IP 范围。 12 | -------------------------------------------------------------------------------- /00~概念与架构/04~开放接口.md: -------------------------------------------------------------------------------- 1 | # 开放接口 2 | 3 | Kubernetes 作为云原生应用的基础调度平台,相当于云原生的操作系统,为了便于系统的扩展,Kubernetes 中开放的以下接口,可以分别对接不同的后端,来实现自己的业务逻辑: 4 | 5 | - CRI(Container Runtime Interface):容器运行时接口,提供计算资源 6 | - CNI(Container Network Interface):容器网络接口,提供网络资源 7 | - CSI(Container Storage Interface):容器存储接口,提供存储资源 8 | 9 | # CRI 10 | 11 | CRI,Container Runtime Interface(容器运行时接口)中定义了容器和镜像的服务的接口,因为容器运行时与镜像的生命周期是彼此隔离的,因此需要定义两个服务。该接口使用 Protocol Buffer,基于 gRPC,在 Kubernetes v1.10+版本中是在 pkg/kubelet/apis/cri/runtime/v1alpha2 的 api.proto 中定义的。 12 | 13 | Container Runtime 实现了 CRI gRPC Server,包括 RuntimeService 和 ImageService。该 gRPC Server 需要监听本地的 Unix socket,而 kubelet 则作为 gRPC Client 运行。 14 | 15 | ![](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230502140929.png) 16 | 17 | # CNI 18 | 19 | CNI(Container Network Interface)是 CNCF 旗下的一个项目,由一组用于配置 Linux 容器的网络接口的规范和库组成,同时还包含了一些插件。CNI 仅关心容器创建时的网络分配,和当容器被删除时释放网络资源。Kubernetes 源码的 vendor/github.com/containernetworking/cni/libcni 目录中已经包含了 CNI 的代码,也就是说 Kubernetes 中已经内置了 CNI。 20 | 21 | # CSI 22 | 23 | CSI, Container Storage Interface(容器存储接口)CSI 代表容器存储接口,CSI 试图建立一个行业标准接口的规范,借助 CSI 容器编排系统(CO)可以将任意存储系统暴露给自己的容器工作负载。有关详细信息,请查看设计方案。 24 | 25 | CSI 卷类型是一种 out-tree(即跟其它存储插件在同一个代码路径下,随 Kubernetes 的代码同时编译的)的 CSI 卷插件,用于 Pod 与在同一节点上运行的外部 CSI 卷驱动程序交互。部署 CSI 兼容卷驱动后,用户可以使用 CSI 作为卷类型来挂载驱动提供的存储。 26 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/10~多集群管理/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 68 3 | title: 多集群管理 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | 组织需要部署多个 Kubernetes 集群来为不同的业务提供隔离,增强可用性和可扩展性。 9 | 10 | ## 什么是多集群? 11 | 12 | 多集群是一种在多个 Kubernetes 集群上或跨集群部署应用的策略,目的是提高可用性、隔离性和可扩展性。多集群对于确保遵守不同的和相互冲突的法规非常重要,因为单个集群可以进行调整,以遵守特定地域或认证的法规。软件交付的速度和安全性也可以提高,单个开发团队将应用程序部署到隔离的集群中,并有选择地暴露哪些服务可用于测试和发布。 13 | 14 | ## 配置多集群访问 15 | 16 | 你可以使用 `kubectl config` 命令配置要访问的集群,详见[配置对多集群的访问](https://kubernetes.io/zh/docs/tasks/access-application-cluster/configure-access-multiple-clusters/)。 17 | 18 | ## 集群联邦 19 | 20 | 集群联邦(Federation)是指通过 Federation API 资源来统一管理多个集群的资源,如定义 Deployment 如何部署到不同集群上,及其所需的副本数等。这些集群可能位于不同的可用区、地区或者供应商。实施集群联邦一般是为了达到以下目的: 21 | 22 | - 简化管理多个集群的 Kubernetes 组件 (如 Deployment、Service 等); 23 | - 在多个集群之间分散工作负载(Pod),以提升应用(服务)的可靠性; 24 | - 跨集群的资源编排,依据编排策略在多个集群进行应用(服务)部署; 25 | - 在不同集群中,能更快速更容易地迁移应用(服务); 26 | - 跨集群的服务发现,服务可以提供给当地存取,以降低延迟; 27 | - 实践多云(Multi-cloud)或混合云(Hybird Cloud)的部署; 28 | 29 | ## 本节大纲 30 | 31 | ## 参考 32 | 33 | - [Multicluster Special Interest Group - github.com](https://github.com/kubernetes/community/blob/master/sig-multicluster/README.md) 34 | - [配置对多集群的访问 - kubernetes.io](https://kubernetes.io/zh/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all 2 | * 3 | 4 | # Unignore all with extensions 5 | !*.* 6 | 7 | # Unignore all dirs 8 | !*/ 9 | 10 | .DS_Store 11 | 12 | # Logs 13 | logs 14 | *.log 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | 19 | # Runtime data 20 | pids 21 | *.pid 22 | *.seed 23 | *.pid.lock 24 | 25 | # Directory for instrumented libs generated by jscoverage/JSCover 26 | lib-cov 27 | 28 | # Coverage directory used by tools like istanbul 29 | coverage 30 | 31 | # nyc test coverage 32 | .nyc_output 33 | 34 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 35 | .grunt 36 | 37 | # Bower dependency directory (https://bower.io/) 38 | bower_components 39 | 40 | # node-waf configuration 41 | .lock-wscript 42 | 43 | # Compiled binary addons (https://nodejs.org/api/addons.html) 44 | build/Release 45 | 46 | # Dependency directories 47 | node_modules/ 48 | jspm_packages/ 49 | 50 | # TypeScript v1 declaration files 51 | typings/ 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | 71 | # next.js build output 72 | .next 73 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/04~控制器/34.Ingress 控制器.md: -------------------------------------------------------------------------------- 1 | # Ingress 控制器 2 | 3 | 为了使 Ingress 正常工作,集群中必须运行 Ingress controller。这与其他类型的控制器不同,其他类型的控制器通常作为 `kube-controller-manager` 二进制文件的一部分运行,在集群启动时自动启动。你需要选择最适合自己集群的 Ingress controller 或者自己实现一个。 4 | 5 | Kubernetes 社区和众多厂商开发了大量的 Ingress Controller,你可以在 [这里](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/) 找到。 6 | 7 | ## 使用多个 Ingress 控制器 8 | 9 | 你可以使用 [IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) 在集群中部署任意数量的 Ingress 控制器。请注意你的 Ingress 类资源的 `.metadata.name` 字段。当你创建 Ingress 时,你需要用此字段的值来设置 Ingress 对象的 `ingressClassName` 字段(请参考 [IngressSpec v1 reference](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/ingress-v1/#IngressSpec))。`ingressClassName` 是之前的[注解](https://kubernetes.io/docs/concepts/services-networking/ingress/#deprecated-annotation)做法的替代。 10 | 11 | 如果你不为 Ingress 指定 IngressClass,并且你的集群中只有一个 IngressClass 被标记为了集群默认,那么 Kubernetes 会应用此[默认 IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#default-ingress-class)。你可以通过将 [`ingressclass.kubernetes.io/is-default-class` 注解](https://kubernetes.io/docs/reference/labels-annotations-taints/#ingressclass-kubernetes-io-is-default-class) 的值设置为 `"true"` 来将一个 IngressClass 标记为集群默认。 12 | 13 | 理想情况下,所有 Ingress 控制器都应满足此规范,但各种 Ingress 控制器的操作略有不同。 14 | -------------------------------------------------------------------------------- /02~资源对象/03~服务发现与路由/02~Ingress/README.md: -------------------------------------------------------------------------------- 1 | # Ingress 2 | 3 | Ingress 是从 Kubernetes 集群外部访问集群内部服务的入口。Service 虽然解决了服务发现和负载均衡的问题,但它在使用上还是有一些限制,比如对外访问的时候,NodePort 类型需要在外部搭建额外的负载均衡,而 LoadBalancer 要求 Kubernetes 必须跑在支持的 Cloud Provider 上面。 4 | 5 | ![Ingress 访问架构](https://user-images.githubusercontent.com/5803001/50947031-4cc4c980-14d7-11e9-8bb4-5da3b9da1dea.png) 6 | 7 | Ingress 就是为了解决这些限制而引入的新资源,主要用来将服务暴露到 Cluster 外面,并且可以自定义服务的访问策略。比如想要通过负载均衡器实现不同子域名到不同服务的访问: 8 | 9 | ```xml 10 | foo.bar.com --| |-> foo.bar.com s1:80 11 | | 178.91.123.132 | 12 | bar.foo.com --| |-> bar.foo.com s2:80 13 | ``` 14 | 15 | 如上的需求我们可以定义为如下的 Ingress Controller: 16 | 17 | ```yml 18 | apiVersion: extensions/v1beta1 19 | kind: Ingress 20 | metadata: 21 | name: test 22 | spec: 23 | rules: 24 | - host: foo.bar.com 25 | http: 26 | paths: 27 | - backend: 28 | serviceName: s1 29 | servicePort: 80 30 | - host: bar.foo.com 31 | http: 32 | paths: 33 | - backend: 34 | serviceName: s2 35 | servicePort: 80 36 | ``` 37 | 38 | Ingress 本身并不会自动创建负载均衡器,集群中需要运行一个 Ingress Controller 来根据 Ingress 的定义来管理负载均衡器。 39 | 40 | # Links 41 | 42 | - https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nginx-ingress-with-cert-manager-on-digitalocean-kubernetes 43 | -------------------------------------------------------------------------------- /02~资源对象/03~服务发现与路由/kube-proxy/kube-proxy.md: -------------------------------------------------------------------------------- 1 | # kube-proxy 2 | 3 | 当 service 有了 port 和 nodePort 之后,就可以对内/外提供服务。那么其具体是通过什么原理来实现的呢?奥妙就在 kube-proxy 在本地 node 上创建的 iptables 规则。 4 | 5 | ![kube-proxy 路由规则](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230502140507.png) 6 | 7 | kube-proxy 通过配置 DNAT 规则(从容器出来的访问,从本地主机出来的访问两方面),将到这个服务地址的访问映射到本地的 kube-proxy 端口(随机端口)。然后 kube-proxy 会监听在本地的对应端口,将到这个端口的访问给代理到远端真实的 Pod 地址上去。 8 | 9 | # Chains 10 | 11 | 创建 Service 以后,kube-proxy 会自动在集群里的 Node 上创建以下两条规则:KUBE-PORTALS-CONTAINER、KUBE-PORTALS-HOST。如果是 NodePort 方式,还会额外生成两条:KUBE-NODEPORT-CONTAINER、KUBE-NODEPORT-HOST 12 | 13 | ## KUBE-PORTALS-CONTAINER 14 | 15 | 主要将由网络接口到来的通过服务集群入口 `:port` 的请求重定向到本地 kube-proxy 端口(随机端口)的映射,即来自本地容器的服务访问请求。这种情况的网络包不可能来自外部网络,因为 cluster ip 是个 virtual ip,外部网络中不存在这样的路由将该数据包发送到本机;所以该请求只能来自本地容器,从本地容器出来的访问,服务访问请求是通过本地容器虚拟网卡输入到本地网络接口的。 16 | 17 | ## KUBE-NODEPORT-CONTAINER 18 | 19 | 主要将由网络接口到来的通过服务集群外部入口 `:nodePort` 的请求重定向到本地 kube-proxy 端口(随机端口)的映射;即来自 K8s 集群外部网络的服务访问请求,可以来自本机容器,也可以来自其他 node 的容器,还可以来自其他 node 的进程。 20 | 21 | # kube-proxy 反向代理 22 | 23 | 不管是通过集群内部服务入口 `:port` 还是通过集群外部服务入口 `:nodePort` 的请求都将重定向到本地 kube-proxy 端口(随机端口)的映射,然后将到这个 kube-proxy 端口的访问给代理到远端真实的 Pod 地址上去。 24 | 25 | ![](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230502140524.png) 26 | 27 | ![](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230502140537.png) 28 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 网络 2 | 3 | 容器网络发展到现在,形成了两大阵营,就是 Docker 的 CNM 和 Google、CoreOS、Kuberenetes 主导的 CNI。首先明确一点,CNM 和 CNI 并不是网络实现,他们是网络规范和网络体系,从研发的角度他们就是一堆接口,你底层是用 Flannel 也好、用 Calico 也好,他们并不关心,CNM 和 CNI 关心的是网络管理的问题。 4 | 5 | - CNM(Container Network Model): Docker Libnetwork 的优势就是原生,而且和 Docker 容器生命周期结合紧密;缺点也可以理解为是原生,被 Docker 绑架。支持 CNM 的网络模型包括了 Docker Swarm overlay, Macvlan & IP networkdrivers, Calico, Contiv, Weave. 6 | 7 | - CNI 的优势是兼容其他容器技术(e.g. rkt)及上层编排系统(Kubernetes & Mesos),而且社区活跃势头迅猛,Kubernetes 加上 CoreOS 主推;缺点是非 Docker 原生。支持 CNI 的网络模型包括了 Kubernetes, Weave, Macvlan, Calico, Flannel, Contiv, Mesos CNI. 8 | 9 | # 网络解决方案 10 | 11 | Kubernetes 的集群网络插件实现方案有很多种,社区比较常见的有两种 Flannel 和 Calico 的工作原理。 12 | 13 | ## 隧道方案(Overlay Networking) 14 | 15 | 隧道方案在 IaaS 层的网络中应用也比较多,大家共识是随着节点规模的增长复杂度会提升,而且出了网络问题跟踪起来比较麻烦,大规模集群情况下这是需要考虑的一个点。 16 | 17 | - Weave:UDP 广播,本机建立新的 BR,通过 PCAP 互通 18 | - Open vSwitch(OVS):基于 VxLan 和 GRE 协议,但是性能方面损失比较严重 19 | - Flannel:Flannel 主要提供了 Overlay 的网络方案,UDP 模式由于其封包拆包的过程涉及了多次上下文的切换,导致性能很差,逐渐被社区抛弃;VXLAN 模式的封包拆包过程均在内核态,性能要比 UDP 好很多,也是最经常使用的模式;host-gw 模式不涉及封包拆包,所以性能相对较高,但要求节点间二层互通。 20 | - Racher:IPsec 21 | 22 | ## 路由方案 23 | 24 | 路由方案一般是从 3 层或者 2 层实现隔离和跨主机容器互通的,出了问题也很容易排查。 25 | 26 | - Calico:Calico 主要采用了 BGP 协议交换路由,没有采用 cni0 网桥,当二层网络不通的时候,可以采用 IPIP 模式,但由于涉及到封包拆包的过程,性能相对较弱,与 Flannel 的 VXLAN 模式相当。Calico 支持很细致的 ACL 控制,对混合云亲和度比较高。 27 | - Macvlan:从逻辑和 Kernel 层来看隔离性和性能最优的方案,基于二层隔离,所以需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现。 28 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/14~访问集群/kubernator-kubernetes-ui.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 98 3 | title: Kubernator - 更底层的 Kubernetes UI 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | [Kubernator](https://github.com/smpio/kubernator) 相较于 [Kubernetes Dashboard](https://github.com/smpio/kubernator) 来说,是一个更底层的 Kubernetes UI,Dashboard 操作的都是 Kubernetes 的底层对象,而 Kubernator 是直接操作 Kubernetes 各个对象的 YAML 文件。 9 | 10 | Kubernator 提供了一种基于目录树和关系拓扑图的方式来管理 Kubernetes 的对象的方法,用户可以在 Web 上像通过 GitHub 的网页版一样操作 Kubernetes 的对象,执行修改、拷贝等操作,详细的使用方式见 。 11 | 12 | ## 安装 Kubernator 13 | 14 | Kubernator 的安装十分简单,可以直接使用 `kubectl` 命令来运行,它不依赖任何其它组件。 15 | 16 | ```bash 17 | kubectl create ns kubernator 18 | kubectl -n kubernator run --image=smpio/kubernator --port=80 kubernator 19 | kubectl -n kubernator expose deploy kubernator 20 | kubectl proxy 21 | ``` 22 | 23 | 然后就可以通过 `http://localhost:8001/api/v1/namespaces/kubernator/services/kubernator/proxy/` 来访问了。 24 | 25 | Catalog 页面可以看到 Kubernetes 中资源对象的树形结构,还可以在该页面中对资源对象的配置进行更改和操作。 26 | 27 | ![Kubernator catalog 页面](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernator-catalog.jpg "Kubernator catalog 页面") 28 | 29 | RBAC 页面可以看到集群中 RBAC 关系及结构。 30 | 31 | ![Kubernator rbac 页面](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernator-rbac.jpg "Kubernator rbac 页面") 32 | 33 | ## 参考 34 | 35 | - [Kubernator - github.com](https://github.com/smpio/kubernator) 36 | -------------------------------------------------------------------------------- /02~资源对象/01~Pod/共享与调度/共享存储.md: -------------------------------------------------------------------------------- 1 | # 共享存储 2 | 3 | 在 K8s 中,您可以使用共享的 K8s 卷作为在 Pod 中的容器之间共享数据的简单有效的方法。在大多数情况下,使用主机上与 Pod 中所有容器共享的目录就足够了。K8s Volumes 使数据能够在容器重启后幸存下来。它的寿命与 Pod 相同。这意味着只要 Pod 存在,它就一直存在。如果出于任何原因删除了该 Pod,即使创建了相同的替换,共享卷也将被破坏并重新创建。 4 | 5 | 具有共享卷的多容器 Pod 的标准用例是:一个容器写入共享目录(日志或其他文件),而另一个容器从共享目录读取。例: 6 | 7 | ```yml 8 | apiVersion: v1 9 | kind: Pod 10 | metadata: 11 | name: mc1 12 | spec: 13 | volumes: 14 | - name: html 15 | emptyDir: {} 16 | containers: 17 | - name: 1st 18 | image: nginx 19 | volumeMounts: 20 | - name: html 21 | mountPath: /usr/share/nginx/html 22 | - name: 2nd 23 | image: debian 24 | volumeMounts: 25 | - name: html 26 | mountPath: /html 27 | command: ["/bin/sh", "-c"] 28 | args: 29 | - while true; do 30 | date >> /html/index.html; 31 | sleep 1; 32 | done 33 | ``` 34 | 35 | 在此示例中,我们定义了一个名为 html 的卷,其类型为 emptyDir:该卷是在将 Pod 分配给节点时首次创建的,并且只要该 Pod 在该节点上运行就存在。顾名思义,它最初是空的。第一个容器运行 nginx 服务器,并将共享卷安装到目录 `/usr/share/nginx/html`。第二个容器使用 Debian 映像,并将共享卷安装到目录/ html。第二个容器每秒将当前日期和时间添加到共享卷中的 index.html 中。Nginx 服务器读取此文件,并将其发送到 Web 服务器的每个 HTTP 请求给用户。 36 | 37 | ![共享存储](https://linchpiner.github.io/images/k8s-mc-1.svg) 38 | 39 | 您可以通过暴露 Nginx 端口并使用浏览器访问 Pod 来检查 Pod 是否正常工作。直接在容器中检查共享目录的另一种方法: 40 | 41 | ```sh 42 | $ kubectl exec mc1 -c 1st -- /bin/cat /usr/share/nginx/html/index.html 43 | ... 44 | Fri Aug 25 18:36:06 UTC 2017 45 | 46 | $ kubectl exec mc1 -c 2nd -- /bin/cat /html/index.html 47 | ... 48 | Fri Aug 25 18:36:06 UTC 2017 49 | Fri Aug 25 18:36:07 UTC 2017 50 | ``` 51 | -------------------------------------------------------------------------------- /04~生态扩展/Helm/Charts/存储库.md: -------------------------------------------------------------------------------- 1 | # 搭建私有 Chart 仓库 2 | 3 | chart 库是带有一个 index.yaml 文件和任意个打包 cahrt 的 HTTP 服务器。当准备好分享 chart 时,首选方法是将其上传到 chart 库。 4 | 5 | 由于 chart 库可以是任何可以提供 YAML 和 tar 文件并可以回答 GET 请求的 HTTP 服务器,因此当托管自己的 chart 库时,很多选择。例如,可以使用 Google 云端存储(GCS)存储桶,Amazon S3 存储桶,Github Pages,甚至可以创建自己的 Web 服务器。 6 | 7 | # chart 库结构 8 | 9 | chart 库由打包的 chart 和一个名为的特殊文件组成,index.yaml 其中包含 chart 库中所有 chart 的索引。通常,index.yaml 描述的 chart 也是托管在同一台服务器上,源代码文件也是如此。例如,chart 库的布局 https://example.com/charts 可能如下所示: 10 | 11 | ```s 12 | charts/ 13 | | 14 | |- index.yaml 15 | | 16 | |- alpine-0.1.2.tgz 17 | | 18 | |- alpine-0.1.2.tgz.prov 19 | ``` 20 | 21 | 这种情况下,索引文件包含有关一个 chart(Alpine chart)的信息,并提供该 chart 的下载 URL https://example.com/charts/alpine-0.1.2.tgz。不要求 chart 包与 index.yaml 文件位于同一台服务器上 。但是,发在一起这样做通常是最简单的。 22 | 23 | # 托管 chart 库 24 | 25 | 本部分介绍了提供 chart 库的几种方法。 26 | 27 | ## ChartMuseum 28 | 29 | Helm 提供了一个 open-source Helm 库服务叫 [ChartMuseum](https://chartmuseum.com/),你可以自己托管这个服务. 30 | 31 | ChartMuseum 支撑多种云存储后端. 配置它指向你存放 chart 包的目录或者 bucket,index.yaml 文件会自动动态生成。 32 | 33 | 它也可以通过 [Helm chart](https://github.com/helm/charts/tree/master/stable/chartmuseum) 部署: 34 | 35 | ``` 36 | helm install stable/chartmuseum 37 | ``` 38 | 39 | 或者 [Docker image](https://hub.docker.com/r/chartmuseum/chartmuseum/tags): 40 | 41 | ``` 42 | docker run --rm -it \ 43 | -p 8080:8080 \ 44 | -v $(pwd)/charts:/charts \ 45 | -e DEBUG=true \ 46 | -e STORAGE=local \ 47 | -e STORAGE_LOCAL_ROOTDIR=/charts \ 48 | chartmuseum/chartmuseum 49 | ``` 50 | 51 | 你可以将它加到本地存储库: 52 | 53 | ``` 54 | helm repo add chartmuseum http://localhost:8080 55 | ``` 56 | 57 | ChartMuseum 提供其他特性, 如 chart 上传的 API。 58 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/02~资源对象/pod-hook.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 18 3 | title: Pod Hook 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Pod Hook(钩子)是由 Kubernetes 管理的 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。可以同时为 Pod 中的所有容器都配置 hook。 9 | 10 | Hook 的类型包括两种: 11 | 12 | - exec:执行一段命令 13 | - HTTP:发送 HTTP 请求。 14 | 15 | 参考下面的配置: 16 | 17 | ```yaml 18 | apiVersion: v1 19 | kind: Pod 20 | metadata: 21 | name: lifecycle-demo 22 | spec: 23 | containers: 24 | - name: lifecycle-demo-container 25 | image: nginx 26 | lifecycle: 27 | postStart: 28 | exec: 29 | command: 30 | [ 31 | "/bin/sh", 32 | "-c", 33 | "echo Hello from the postStart handler> /usr/share/message", 34 | ] 35 | preStop: 36 | exec: 37 | command: ["/usr/sbin/nginx", "-s", "quit"] 38 | ``` 39 | 40 | Kubernetes 在容器创建后立即发送 postStart 事件。但是,不能保证在调用容器的入口点之前调用 postStart 处理程序。postStart 处理程序相对于容器的代码异步运行,但 Kubernetes 对容器的管理将被阻止,直到 postStart 处理程序完成。在 postStart 处理程序完成之前,容器的状态不会设置为 RUNNING。 41 | 42 | PreStop 在容器终止之前被同步阻塞调用,常用于在容器结束前优雅的释放资源。 43 | 44 | 如果 postStart 或者 preStop hook 失败,将会终止容器。 45 | 46 | ## 调试 hook 47 | 48 | Hook 调用的日志没有暴露给 Pod 的 event,所以只能通过 `describe` 命令来获取,如果有错误将可以看到 `FailedPostStartHook` 或 `FailedPreStopHook` 这样的 event。 49 | 50 | ## 参考 51 | 52 | - [Attach Handlers to Container Lifecycle Events - kuberentes.io](https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/) 53 | - [Container Lifecycle Hooks - kubernetes.io](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/) 54 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/netfilter.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 中反向代理的实现 2 | 3 | K8S 集群节点实现服务反向代理的方法,目前主要有三种,即 userspace、iptables 以及 ipvs。 4 | 5 | 横向来看,节点上的网络环境,被分割成不同的网络命名空间,包括主机网络命名空间和 Pod 网络命名空间;纵向来看,每个网络命名空间包括完整的网络栈,从应用到协议栈,再到网络设备。在网络设备这一层,我们通过 cni0 虚拟网桥,组建出系统内部的一个虚拟局域网。Pod 网络通过 veth 对连接到这个虚拟局域网内。cni0 虚拟局域网通过主机路由以及网口 eth0 与外部通信。在网络协议栈这一层,我们可以通过编程 netfilter 过滤器框架,来实现集群节点的反向代理。 6 | 7 | ![主机网络命名空间、POD 网络命名空间](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230430223341.png) 8 | 9 | 实现反向代理,归根结底,就是做 DNAT,即把发送给集群服务 IP 和端口的数据包,修改成发给具体容器组的 IP 和端口。参考 netfilter 过滤器框架的图,我们知道,在 netfilter 里,可以通过在 PREROUTING,OUTPUT 以及 POSTROUGING 三个位置加入 NAT 规则,来改变数据包的源地址或目的地址。 10 | 11 | 因为这里需要做的是 DNAT,即改变目的地址,这样的修改,必须在路由(ROUTING)之前发生以保证数据包可以被路由正确处理,所以实现反向代理的规则,需要被加到 PREROUTING 和 OUTPUT 两个位置。 12 | 13 | 其中,PREOURTING 的规则,用来处理从 Pod 访问服务的流量。数据包从 Pod 网络 veth 发送到 cni0 之后,进入主机协议栈,首先会经过 netfilter PREROUTING 来做处理,所以发给服务的数据包,会在这个位置做 DNAT。经过 DNAT 处理之后,数据包的目的地址变成另外一个 Pod 的地址,从而经过主机路由,转发到 eth0,发送给正确的集群节点。 14 | 15 | 而添加在 OUTPUT 这个位置的 DNAT 规则,则用来处理从主机网络发给服务的数据包,原理也是类似,即经过路由之前,修改目的地址,以方便路由转发。 16 | 17 | # netfilter 18 | 19 | 为了实现管道和过滤功能两者的解耦,netfilter 用了表这个概念。表就是 netfilter 的过滤中心,其核心功能是过滤方式的分类(表),以及每种过滤方式中,过滤规则的组织(链)。 20 | 21 | 把过滤功能和管道解耦之后,所有对数据包的处理,都变成了对表的配置。而管道上的 5 个切口,仅仅变成了流量的出入口,负责把流量发送到过滤中心,并把处理之后的流量沿着管道继续传送下去。 22 | 23 | ![MANGLE、NAT、FILTER](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230430223427.png) 24 | 25 | 在表中,netfilter 把规则组织成为链。表中有针对每个管道切口的默认链,也有我们自己加入的自定义链。默认链是数据的入口,默认链可以通过跳转到自定义链来完成一些复杂的功能。这里允许增加自定义链的好处是显然的。为了完成一个复杂过滤功能,比如实现 K8S 集群节点的反向代理,我们可以使用自定义链来模块化我们规则。 26 | 27 | # 自定义链 28 | 29 | 集群服务的反向代理,实际上就是利用自定义链,模块化地实现了数据包的 DNAT 转换。KUBE-SERVICE 是整个反向代理的入口链,其对应所有服务的总入口;KUBE-SVC-XXXX 链是具体某一个服务的入口链,KUBE-SERVICE 链会根据服务 IP,跳转到具体服务的 KUBE-SVC-XXXX 链;而 KUBE-SEP-XXXX 链代表着某一个具体 Pod 的地址和端口,即 endpoint,具体服务链 KUBE-SVC-XXXX 会以一定的负载均衡算法,跳转到 endpoint 链。 30 | 31 | ![KUBE-SERVICE](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230430223455.png) 32 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/14~访问集群/connecting-to-applications-port-forward.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 94 3 | title: 通过端口转发访问集群中的应用程序 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | 本页向您展示如何使用 `kubectl port-forward` 命令连接到运行在 Kubernetes 集群中的 Redis 服务器。这种类型的连接对于数据库调试很有帮助。 9 | 10 | ## 创建一个 Pod 来运行 Redis 服务器 11 | 12 | 1. 创建一个 Pod: 13 | 14 | ```bash 15 | kubectl create -f https://k8s.io/docs/tasks/access-application-cluster/redis-master.yaml 16 | ``` 17 | 18 | 命令运行成功后将有以下输出验证该 Pod 是否已经创建: 19 | 20 | ``` 21 | pod "redis-master" created 22 | ``` 23 | 24 | 2. 检查 Pod 是否正在运行且处于就绪状态: 25 | 26 | ```bash 27 | kubectl get pods 28 | ``` 29 | 30 | 当 Pod 就绪,输出显示 Running 的状态: 31 | 32 | ```bash 33 | NAME READY STATUS RESTARTS AGE 34 | redis-master 2/2 Running 0 41s 35 | ``` 36 | 37 | 3. 验证 Redis 服务器是否已在 Pod 中运行,并监听 6379 端口: 38 | 39 | ```bash 40 | {% raw %} 41 | kubectl get pods redis-master --template='{{(index (index .spec.containers 0).ports 0).containerPort}}{{"\n"}}' 42 | {% endraw %} 43 | ``` 44 | 45 | 端口输出如下: 46 | 47 | ``` 48 | 6379 49 | ``` 50 | 51 | ## 将本地端口转发到 Pod 中的端口 52 | 53 | 1. 将本地工作站上的 6379 端口转发到 redis-master pod 的 6379 端口: 54 | 55 | ```bash 56 | kubectl port-forward redis-master 6379:6379 57 | ``` 58 | 59 | 输出类似于: 60 | 61 | ``` 62 | I0710 14:43:38.274550 3655 portforward.go:225] Forwarding from 127.0.0.1:6379 -> 6379 63 | I0710 14:43:38.274797 3655 portforward.go:225] Forwarding from [::1]:6379 -> 6379 64 | ``` 65 | 66 | 2. 启动 Redis 命令行界面 67 | 68 | ``` 69 | redis-cli 70 | ``` 71 | 72 | 3. 在 Redis 命令行提示符下,输入 `ping` 命令: 73 | 74 | ``` 75 | 127.0.0.1:6379>ping 76 | ``` 77 | 78 | Ping 请求成功返回 PONG。 79 | 80 | ## 讨论 81 | 82 | 创建连接,将本地的 6379 端口转发到运行在 Pod 中的 Redis 服务器的 6379 端口。有了这个连接您就可以在本地工作站中调试运行在 Pod 中的数据库。 83 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/03~集群资源管理/26.Taint 和 Toleration(污点和容忍).md: -------------------------------------------------------------------------------- 1 | # Taint 和 Toleration(污点和容忍) 2 | 3 | Taint(污点)和 Toleration(容忍)可以作用于 node 和 pod 上,其目的是优化 pod 在集群间的调度,这跟节点亲和性类似,只不过它们作用的方式相反,具有 taint 的 node 和 pod 是互斥关系,而具有节点亲和性关系的 node 和 pod 是相吸的。另外还有可以给 node 节点设置 label,通过给 pod 设置 `nodeSelector` 将 pod 调度到具有匹配标签的节点上。 4 | 5 | Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用**一个或多个** taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度到具有相应 taint 的节点上。 6 | 7 | ## 示例 8 | 9 | 以下分别以为 node 设置 taint 和为 pod 设置 toleration 为例。 10 | 11 | ## 为 node 设置 taint 12 | 13 | 为 node1 设置 taint: 14 | 15 | ```bash 16 | kubectl taint nodes node1 key1=value1:NoSchedule 17 | kubectl taint nodes node1 key1=value1:NoExecute 18 | kubectl taint nodes node1 key2=value2:NoSchedule 19 | ``` 20 | 21 | 删除上面的 taint: 22 | 23 | ```bash 24 | kubectl taint nodes node1 key1:NoSchedule- 25 | kubectl taint nodes node1 key1:NoExecute- 26 | kubectl taint nodes node1 key2:NoSchedule- 27 | ``` 28 | 29 | 查看 node1 上的 taint: 30 | 31 | ```bash 32 | kubectl describe nodes node1 33 | ``` 34 | 35 | ## 为 pod 设置 toleration 36 | 37 | 只要在 pod 的 spec 中设置 tolerations 字段即可,可以有多个 `key`,如下所示: 38 | 39 | ```yaml 40 | tolerations: 41 | - key: "key1" 42 | operator: "Equal" 43 | value: "value1" 44 | effect: "NoSchedule" 45 | - key: "key1" 46 | operator: "Equal" 47 | value: "value1" 48 | effect: "NoExecute" 49 | - key: "node.alpha.kubernetes.io/unreachable" 50 | operator: "Exists" 51 | effect: "NoExecute" 52 | tolerationSeconds: 6000 53 | ``` 54 | 55 | - `value` 的值可以为 `NoSchedule`、` PreferNoSchedule` 或 `NoExecute`。 56 | - `tolerationSeconds` 是当 pod 需要被驱逐时,可以继续在 node 上运行的时间。 57 | 58 | 详细使用方法请参考[官方文档](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)。 59 | 60 | ## 参考 61 | 62 | - [Taints and Tolerations - kuberentes.io](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) 63 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/17~开发指南/minikube.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 114 3 | title: Minikube 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | Minikube 用于在本地运行 kubernetes 环境,用来开发和测试。 9 | 10 | ## 安装 Minikube 11 | 12 | 到 [GitHub](https://github.com/kubernetes/minikube/releases) 下载 minikube,我安装的是 minikube v1.11.0。 13 | 14 | 下载完成后修改文件名为 `minikube`,然后 `chmod +x minikube`,移动到 `$PATH` 目录下: 15 | 16 | ```bash 17 | sudo mv ~/Download/minikube-darwin-adm64 /usr/local/bin/ 18 | sudo chmod +x /usr/local/bin/minikube 19 | ``` 20 | 21 | ## 安装 kubectl 22 | 23 | **方式一** 24 | 25 | 参考 [Install and Set Up kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/),直接使用二进制文件安装即可。 26 | 27 | ```bash 28 | curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/darwin/amd64/kubectl 29 | ``` 30 | 31 | **方式二** 32 | 33 | 先访问 34 | 得到返回值,假设为 `v1.18.4`,然后拼接网址,直接在浏览器访问: 35 | 直接下载 kubectl 文件。 36 | 37 | 若第一种方式访问多次超时,可以使用上述的第二种方式访问。 38 | 39 | ## 启动 Minikube 40 | 41 | 对于 macOS,执行 `minikube start --vm-driver=hyperkit` (使用 hyperkit 作为虚拟机,不需要安装 docker)即可自动下载依赖文件,开始安装和启动 minikube。该过程中将自动执行以下步骤: 42 | 43 | 1. 下载 `docker-machine-driver-hyperkit`(10.9 M) 44 | 1. 下载虚拟机镜像(近 200M) 45 | 1. 下载 Kubernetes 安装包(500 多 M) 46 | 47 | 安装完成后将生成默认的 `~/.kube/config` 文件,自动指向 minikube 集群。 48 | 49 | 注意:在安装过程中建议[配置代理](https://minikube.sigs.k8s.io/docs/handbook/vpn_and_proxy/),否则将会有的镜像无法下载。 50 | 51 | ## 常用命令 52 | 53 | 下面是 minkube 的常用命令。 54 | 55 | ```bash 56 | # 进入集群节点 57 | minikube ssh 58 | 59 | # 查看节点 IP 60 | minikube ip 61 | 62 | # 停止集群 63 | minikube stop 64 | 65 | # 删除集群 66 | minikube delete 67 | ``` 68 | 69 | ## 参考 70 | 71 | - [Install minikube - kubernetes.io](https://kubernetes.io/docs/tasks/tools/install-minikube/) 72 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/04~控制器/32.ReplicationController 和 ReplicaSet.md: -------------------------------------------------------------------------------- 1 | # ReplicationController 和 ReplicaSet 2 | 3 | ReplicationController 用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收。 4 | 5 | 在新版本的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController。ReplicaSet 跟 ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector。 6 | 7 | 虽然 ReplicaSet 可以独立使用,但一般还是建议使用 Deployment 来自动管理 ReplicaSet,这样就无需担心跟其他机制的不兼容问题(比如 ReplicaSet 不支持 rolling-update 但 Deployment 支持)。 8 | 9 | ReplicaSet 示例: 10 | 11 | ```yaml 12 | apiVersion: extensions/v1beta1 13 | kind: ReplicaSet 14 | metadata: 15 | name: frontend 16 | # these labels can be applied automatically 17 | # from the labels in the pod template if not set 18 | # labels: 19 | # app: guestbook 20 | # tier: frontend 21 | spec: 22 | # this replicas value is default 23 | # modify it according to your case 24 | replicas: 3 25 | # selector can be applied automatically 26 | # from the labels in the pod template if not set, 27 | # but we are specifying the selector here to 28 | # demonstrate its usage. 29 | selector: 30 | matchLabels: 31 | tier: frontend 32 | matchExpressions: 33 | - { key: tier, operator: In, values: [frontend] } 34 | template: 35 | metadata: 36 | labels: 37 | app: guestbook 38 | tier: frontend 39 | spec: 40 | containers: 41 | - name: php-redis 42 | image: gcr.io/google_samples/gb-frontend:v3 43 | resources: 44 | requests: 45 | cpu: 100m 46 | memory: 100Mi 47 | env: 48 | - name: GET_HOSTS_FROM 49 | value: dns 50 | # If your cluster config does not include a dns service, then to 51 | # instead access environment variables to find service host 52 | # info, comment out the 'value: dns' line above, and uncomment the 53 | # line below. 54 | # value: env 55 | ports: 56 | - containerPort: 80 57 | ``` 58 | -------------------------------------------------------------------------------- /02~资源对象/04~身份与权限/用户管理/README.md: -------------------------------------------------------------------------------- 1 | # 用户管理 2 | 3 | # 创建用户 4 | 5 | 要在 Kubernetes 上创建一个用户,我们需要为该用户生成一个 CSR(证书签名请求)。我们要使用的用户是 linuxtips 作为例子。 6 | 7 | ```sh 8 | $ openssl req -new -newkey rsa:4096 -nodes -keyout linuxtips.key -out linuxtips.csr -subj "/CN=linuxtips" 9 | 10 | $ cat < linuxtips.crt 38 | 39 | ``` 40 | 41 | 这将是必要的配置 kubeconfig 的文件指的是集群的 CA,为了获得它,我们将提取它从 kubeconf 当前我们正在使用的。 42 | 43 | ```sh 44 | $ kubectl config view -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' --raw | base64 --decode - > ca.crt 45 | 46 | ``` 47 | 48 | 一旦完成,我们将为新用户设置我们的 kubeconfig。 49 | 50 | ```sh 51 | $ kubectl config set-cluster $(kubectl config view -o jsonpath='{.clusters[0].name}') --server=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}') --certificate-authority=ca.crt --kubeconfig=linuxtips-config --embed-certs 52 | 53 | # Now setting the confs of user key: 54 | $ kubectl config set-credentials linuxtips --client-certificate=linuxtips.crt --client-key=linuxtips.key --embed-certs --kubeconfig=linuxtips-config 55 | 56 | # Now let's define context linuxtipsand then we will use it: 57 | $ kubectl config set-context linuxtips --cluster=$(kubectl config view -o jsonpath='{.clusters[0].name}') --user=linuxtips --kubeconfig=linuxtips-config 58 | $ kubectl config use-context linuxtips --kubeconfig=linuxtips-config 59 | 60 | # test 61 | $ kubectl version --kubeconfig=linuxtips-config 62 | ``` 63 | -------------------------------------------------------------------------------- /01~应用部署/03~典型案例/MySQL.md: -------------------------------------------------------------------------------- 1 | # MySQL 部署 2 | 3 | # Persistent Volume 4 | 5 | # Chart 6 | 7 | ```sh 8 | root@kube-master:# helm install --name mysql --set mysqlRootPassword=rootpassword,mysqlUser=mysql,mysqlPassword=my-password,mysqlDatabase=mydatabase,persistence.existingClaim=mysql-pvc stable/mysql 9 | 10 | NAME: mysql 11 | LAST DEPLOYED: Thu Jan 10 16:18:31 2019 12 | NAMESPACE: default 13 | STATUS: DEPLOYED 14 | 15 | RESOURCES: 16 | ==> v1beta1/Deployment 17 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 18 | mysql 1 0 0 0 1s 19 | 20 | ==> v1/Pod(related) 21 | NAME READY STATUS RESTARTS AGE 22 | mysql-7b688448b9-pxml5 0/1 Pending 0 1s 23 | 24 | ==> v1/Secret 25 | NAME TYPE DATA AGE 26 | mysql Opaque 2 1s 27 | 28 | ==> v1/ConfigMap 29 | NAME DATA AGE 30 | mysql-test 1 1s 31 | 32 | ==> v1/Service 33 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 34 | mysql ClusterIP 10.100.139.57 3306/TCP 1s 35 | 36 | 37 | NOTES: 38 | MySQL can be accessed via port 3306 on the following DNS name from within your cluster: 39 | mysql.default.svc.cluster.local 40 | 41 | To get your root password run: 42 | 43 | MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo) 44 | 45 | To connect to your database: 46 | 47 | 1. Run an Ubuntu pod that you can use as a client: 48 | 49 | kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il 50 | 51 | 2. Install the mysql client: 52 | 53 | $ apt-get update && apt-get install mysql-client -y 54 | 55 | 3. Connect using the mysql cli, then provide your password: 56 | $ mysql -h mysql -p 57 | 58 | To connect to your database directly from outside the K8s cluster: 59 | MYSQL_HOST=127.0.0.1 60 | MYSQL_PORT=3306 61 | 62 | # Execute the following command to route the connection: 63 | kubectl port-forward svc/mysql 3306 64 | 65 | mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD} 66 | ``` 67 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | linktitle: Kubernetes 基础教程 3 | summary: 云原生应用架构实战手册 4 | weight: 1 5 | icon: book 6 | icon_pack: fas 7 | title: Kubernetes 基础教程 8 | date: "2022-05-21T00:00:00+08:00" 9 | type: book # Do not modify. 10 | cascade: 11 | commentable: true 12 | tags: ["Kubernetes"] 13 | categories: ["Kubernetes"] 14 | level: 1 15 | --- 16 | 17 | {{}} 18 | 本教程迁移自[《Kubernetes 中文指南——云原生应用架构实战手册》](https://jimmysong.io/kubernetes-handbook),原手册使用 Gitbook 发布,内容涵盖 容器、Kubernetes、服务网格、Serverless 等云元生的多个领域,因内容过于宽泛,且 Gitbook 项目已停止维护,现将其中的 Kubernetes 教程部分独立成书,并使用 Hugo 重新构建。 19 | {{}} 20 | 21 | 云原生是一种行为方式和设计理念,究其本质,凡是能够提高云上资源利用率和应用交付效率的行为或方式都是云原生的。云计算的发展史就是一部云原生化的历史。Kubernetes 开启了云原生的序幕,服务网格 Istio 的出现,引领了后 Kubernetes 时代的微服务,Serverless 的兴起,使得云原生从基础设施层不断向应用架构层挺进,我们正处于一个云原生的新时代。 22 | 23 | {{< figure src="images/cover.jpg" alt="封面" caption="《Kubernetes 基础教程》封面" width="50%" >}} 24 | 25 | [Kubernetes](http://kubernetes.io) 是 Google 于 [2014 年 6 月](https://jimmysong.io/cloud-native/note/open-source/)基于其内部使用的 [Borg](https://research.google.com/pubs/pub43438.html) 系统开源出来的容器编排调度引擎,Google 将其作为初始和核心项目贡献给 [CNCF](https://cncf.io)(云原生计算基金会),近年来逐渐发展出了云原生生态。 26 | 27 | Kubernetes 的目标不仅仅是一个编排系统,而是提供一个规范用以描述集群的架构,定义服务的最终状态,使系统自动地达到和维持该状态。Kubernetes 作为云原生应用的基石,相当于一个云原生操作系统,其重要性不言而喻。 28 | 29 | 云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括 **容器**、**服务网格**、**微服务**、**不可变基础设施** 和 **声明式 API**。这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。——CNCF(云原生计算基金会)。 30 | 31 | ## 关于本书 32 | 33 | Kubernetes Handbook 项目始于 2016 年底,开源于 2017 年 3 月,作为第一本系统介绍 Kubernetes 的中文电子书,其后经过不断完善。写作本书的过程中,笔者记录了从零开始学习和使用 Kubernetes 的历程,着重于经验总结和资料分享,亦有 Kubernetes 核心概念解析,希望能够帮助大家少走弯路,为大家介绍 Kubernetes 周边生态,如微服务、DevOps、大数据应用、服务网格、云原生应用、Serverless 等领域。 34 | 35 | ## 本书大纲 36 | 37 | ## 许可证 38 | 39 | 您可以使用[署名 - 非商业性使用 - 相同方式共享 4.0 (CC BY-NC-SA 4.0)](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议共享。 40 | 41 | ## 交流群 42 | 43 | 欢迎加入[云原生社区](https://cloudnative.to/)微信讨论群,加入前请先填写[入群申请问卷](https://wj.qq.com/s2/5479026/bf82)后联系 [Jimmy Song](https://jimmysong.io/contact/) 入群。 44 | 45 | {{< cta cta_text="开始阅读" cta_link="architecture" >}} 46 | -------------------------------------------------------------------------------- /02~资源对象/01~Pod/README.md: -------------------------------------------------------------------------------- 1 | # Pod 2 | 3 | Pod 是 K8s 可以部署和管理的最小的可部署单元。换句话说,如果您需要在 K8s 中运行单个容器,则需要为该容器创建一个 Pod。同时,如果这些容器相对紧密地耦合,则 Pod 可以包含多个容器。在 Pod 里面,Container 之间可以共享网络(IP/Port)、共享存储(Volume)、共享 Hostname。另外,Pod 可以理解成一个逻辑主机,它与非容器领域的物理主机或者 VM 有着类似的行为。在同一个 Pod 运行的进程就像在同一物理主机或 VM 上运行的进程一样,只是这些进程被单独的放到单个 container 内。 4 | 5 | # 从容器到 Pod 6 | 7 | 这里的 Docker 指的是 Docker engine(也叫做 Docker daemon,或最新的名字:Moby),它是一种容器运行时(container runtime)的实现,而且是最主流的实现,几乎就是容器业界的事实标准。Docker 是用来创建和管理容器的,它和容器的关系就好比 Hypervisor(比如:KVM)和虚拟机之间的关系。当然,Docker 公司对 Docker engine 本身的定位和期望不仅仅在于在单机上管理容器,所以近年来一直在向 Docker engine 中加入各种各样的高级功能,比如:组建多节点的 Docker 集群、容器编排、服务发现,等等。 8 | 9 | 而 K8s,是搭建容器集群和进行容器编排的主流开源项目(由 Google 发起并维护),适合搭建 PaaS 平台。容器是 K8s 管理的核心目标对象,它和容器的关系就好比 OpenStack 和虚拟机之间的关系,而它和 Docker 的关系就好比 OpenStack 和 Hypervisor 之间的关系。一般来说,K8s 是和 Docker 配合使用的,K8s 调用每个节点上的 Docker 去创建和管理容器,所以,你可以认为 K8s 是大脑,而 Docker 是四肢。因此,在这样的背景下,Docker 逐渐式微,而 K8s 崛起,就毫不奇怪了。 10 | 11 | K8s 与 Docker 最典型而直接的差异,即 Docker 中是以容器为最小单元,而 K8s 中是以 Pod 为最小执行单元,下面我们就简要讨论下两种设计在实际环境中的差异。 12 | 13 | ## 为什么需要 Pod? 14 | 15 | - 为什么 K8s 使用 Pod 作为最小的可部署单元而不是单个容器?容器是现有实体,表示特定的事物,例如 Docker 容器。要管理容器,K8s 需要其他信息,例如重启策略或实时探测。重新启动策略定义了终止容器时的处理方式。实时探针定义了一种操作,以从应用程序的角度检测容器中的进程是否仍处于活动状态,例如,Web 服务器是否响应 HTTP 请求。K8s 架构师决定使用一个新实体 Pod 逻辑上包含(包装)一个或多个容器,而应将其作为一个实体进行管理,而不是使用其他属性来使现有事物过载。 16 | 17 | - 为什么 K8s 在一个 Pod 中允许多个容器?Pod 中的容器在“逻辑主机”上运行:它们使用相同的网络名称空间(相同的 IP 地址和端口空间),IPC 名称空间,并且可以选择使用共享卷。因此,这些容器可以有效地进行通信,从而确保数据的局部性。此外,Pod 允许将多个紧密耦合的应用程序容器作为一个单元进行管理。 18 | 19 | 因此,如果应用程序需要在同一主机上运行多个容器,为什么不使用这些容器中的所有内容制作一个容器?首先,将许多东西放到一个容器中可能会违反“每个容器一个进程”的原则。其次,为应用程序使用多个容器更易于使用,更透明,并允许将软件依赖关系解耦。同样,团队之间可以重复使用更多的细粒度容器。 20 | 21 | ## 使用案例 22 | 23 | 多容器 Pod 的主要目的是为主程序支持位于同一地点,受共同管理的帮助程序。在 Pod 中有一些使用辅助过程的一般模式: 24 | 25 | - Sidecar 容器“帮助”主容器。例如,日志或数据更改监视程序,监视适配器等。例如,日志观察者可以由不同的团队构建一次,并可以在不同的应用程序中重复使用。边车容器的另一个示例是为主容器生成数据的文件或数据加载器。 26 | 27 | - 代理,网桥,适配器将主容器与外部环境连接起来。例如,Apache HTTP 服务器或 Nginx 可以提供静态文件,并充当主容器中 Web 应用程序的反向代理,以记录和限制 HTTP 请求。另一个示例是一个帮助容器,该容器将请求从主容器重新路由到外部世界,因此主容器连接到本地主机以访问例如外部数据库,而没有发现任何服务。 28 | 29 | 虽然您可以在单个 Pod 中托管多层应用程序(例如 WordPress),但建议的方法是为每个层使用单独的 Pod。这样做的原因很简单:您可以独立地扩展层并在群集节点之间分布它们。 30 | 31 | # Links 32 | 33 | - https://mp.weixin.qq.com/s/Vrgff_qfKWPFmRPb_LVMmQ 34 | -------------------------------------------------------------------------------- /04~生态扩展/KubeVela/README.md: -------------------------------------------------------------------------------- 1 | # KubeVela 2 | 3 | KubeVela 是一个基于 Go 语言开发的云原生平台级开源项目,这套内核系统诞生自 2019 年年底阿里云联合微软共同推出的 Open Application Model(简称 OAM:https://oam.dev/)模型基于 Kubernetes 的实现。KubeVela 是一个面向平台构建者的、简单易用但又高度可扩展的云原生平台构建引擎。 4 | 5 | 具体来说,KubeVela 的目标是让任何平台团队都能够以 Kubernetes 原生的方式,快速、高效的打造出适合不同业务场景的、能够直面用户的云原生平台出来。比如:构建应用 PaaS、数据库 PaaS、AI PaaS 或者持续交付系统等等。 6 | 7 | ![KubeVela “关注点分离”的工作流](https://s3.ax1x.com/2021/01/25/sqzDrd.png) 8 | 9 | 在设计上,KubeVela 对平台团队暴露了两大核心 API,包括: 10 | 11 | - **能力模板**:“能力”在 KubeVela 中,指能够组成一个完整应用的原子化功能,比如 StatefulSet 和 Ingress 就属于两种不同的“能力”。KubeVela 允许平台团队通过定义各种能力“模板”的方式,在 Kubernetes 中预置各种各样的能力。 12 | - **部署环境模板**:与“能力”类似,应用的部署环境在 KubeVela 中通过“环境”模板来进行预定义和初始化,比如“测试集群”和“生产集群”,就属于两种“环境”。 13 | 14 | 而作为平台的用户,比如业务团队,他们只需要通过平台团队提供的环境模板来“一键”初始化自己预期的部署集群,然后把自己需要的能力模板“组装”成一个完整的应用,就可以直接向任何 Kubernetes 集群进行应用交付和运维了。 15 | 16 | 由于上述这些能力和环境,都通过“模板”的方式进行了抽象,所以对于业务团队来说,它们并不需要学习完整的 Kubernetes 概念与细节,只需要了解上述模板暴露出来的参数,就可以无缝的使用 Kubernetes 来完成自己要做的事情。而具体通过模板暴露出哪些可配置项、背后的模板怎么渲染、渲染成什么样 Kubernetes 对象,则完全全在平台团队的掌控之中,并且可以随时调节和修改。 17 | 18 | # 快速构建抽象 19 | 20 | 构建“抽象”,是任何一个云原生平台的最基础、也必然会提供的功能。我们知道,Kubernetes 暴露出来的是一套声明式 API,而所谓抽象,其实就是一个平台在这些声明式 API 的基础上,为用户暴露出来的可操作项和可配置项。作为平台团队,我们之所以要提供“抽象”,其最终目的都是为了简化用户的使用心智,让业务团队只关注他们关心的事情,避免引入大量与业务无关的平台层细节让用户“望而却步”。可以说,提供“抽象”,是任何一个平台团队落地 Kubernetes 等系统级开源项目的第一步。 21 | 22 | 业界最常见的抽象方式,是给用户提供一个图形界面来进行操作(比如 Console 或者 Dashboard),这些图形界面的共同点,就是仅允许用户填写某些特定的字段参数,从而实现简化用户心智的目的。那么,作为平台团队,我们又是怎么来决定给用户暴露哪些可配置参数呢?这就涉及到了“抽象”的三种基础模式(更复杂的情况都是对这三种模式的进一步组合): 23 | 24 | - 组合抽象,这种模式常见于我们把 2 个原子能力组合成为一个能力提供,比如我们在实际开发 Console 时,经常会把 K8s Deployment 和 Service 进行“组合”,暴露出一个 Web Service 的概念来让用户可以在一个表单里同时定义容器镜像和暴露端口。 25 | 26 | - 拆分抽象,这种模式常见于我们希望在使用流程上把一个对象上的字段分开成几个表单来进行分步骤填写,从而解耦部署时与运维时的配置。比如一个 Pod 里面的多个容器,我希望在第一个表单里让用户填写业务容器,在另一个表单让运维填写 Sidecar 容器。再比如 ArgoRollout 这个对象,我会希望一个表单让用户填写容器镜像,另一个表单让运维填写灰度策略。 27 | 28 | - 转换抽象,这种模式通常用于改个名字,或者说去掉一些无关的概念,比如 Knative Revision 跟 Deployment 本质上是一一对应的,但是里面类似 LabelSelector 这种用户不需要关心的字段在 Knative 就会直接去掉了。 29 | 30 | ![常见抽象模式](https://s3.ax1x.com/2021/01/25/sqzTZn.png) 31 | 32 | 上述几种抽象的模式,在业界的很多平台级项目和产品中都有体现。但另一方面,如何正确的设计抽象,以及如何确保抽象能够满足业务方用户的使用需求和习惯,其实是一个非常具备挑战性的问题。这里的关键点在于,无论是图形化界面,还是 CRD Operator,这些“抽象”一旦上线,对它的修改就非常困难。可是另一方面,业务方用户的需求,又几乎不可能是一成不变的(实际情况甚至是“一天一个样”)。 33 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/02~资源对象/pod-preset.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 19 3 | title: Pod Preset 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Preset 就是预设,有时候想要让一批容器在启动的时候就注入一些信息,比如 secret、volume、volume mount 和环境变量,而又不想一个一个的改这些 Pod 的 template,这时候就可以用到 PodPreset 这个资源对象了。 9 | 10 | 本页是关于 PodPreset 的概述,该对象用来在 Pod 创建的时候向 Pod 中注入某些特定信息。该信息可以包括 secret、volume、volume mount 和环境变量。 11 | 12 | ## 理解 Pod Preset 13 | 14 | `Pod Preset` 是用来在 Pod 被创建的时候向其中注入额外的运行时需求的 API 资源。 15 | 16 | 您可以使用 [label selector](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) 来指定为哪些 Pod 应用 Pod Preset。 17 | 18 | 使用 Pod Preset 使得 pod 模板的作者可以不必为每个 Pod 明确提供所有信息。这样一来,pod 模板的作者就不需要知道关于该服务的所有细节。 19 | 20 | 关于该背景的更多信息,请参阅 [PodPreset 的设计方案](https://git.k8s.io/community/contributors/design-proposals/service-catalog/pod-preset.md)。 21 | 22 | ## 如何工作 23 | 24 | Kubernetes 提供了一个准入控制器(`PodPreset`),当其启用时,Pod Preset 会将应用创建请求传入到该控制器上。当有 Pod 创建请求发生时,系统将执行以下操作: 25 | 26 | 1. 检索所有可用的 `PodPresets`。 27 | 2. 检查 PodPreset 标签选择器上的标签,看看其是否能够匹配正在创建的 Pod 上的标签。 28 | 3. 尝试将由 `PodPreset` 定义的各种资源合并到正在创建的 Pod 中。 29 | 4. 出现错误时,在该 Pod 上引发记录合并错误的事件,PodPreset *不会*注入任何资源到创建的 Pod 中。 30 | 5. 注释刚生成的修改过的 Pod spec,以表明它已被 PodPreset 修改过。注释的格式为 `podpreset.admission.kubernetes.io/podpreset-": ""`。 31 | 32 | 每个 Pod 可以匹配零个或多个 Pod Prestet;并且每个 `PodPreset` 可以应用于零个或多个 Pod。`PodPreset` 应用于一个或多个 Pod 时,Kubernetes 会修改 Pod Spec。对于 `Env`、`EnvFrom` 和 `VolumeMounts` 的更改,Kubernetes 修改 Pod 中所有容器的容器 spec;对于 `Volume` 的更改,Kubernetes 修改 Pod Spec。 33 | 34 | > **注意**:Pod Preset 可以在适当的时候修改 Pod spec 中的 `spec.containers` 字段。Pod Preset 中的资源定义将*不会*应用于 `initContainers` 字段。 35 | 36 | ### 禁用特定 Pod 的 Pod Preset 37 | 38 | 在某些情况下,您可能不希望 Pod 被任何 Pod Preset 所改变。在这些情况下,您可以在 Pod 的 Pod Spec 中添加注释:`podpreset.admission.kubernetes.io/exclude:"true"`。 39 | 40 | ## 启用 Pod Preset 41 | 42 | 为了在集群中使用 Pod Preset,您必须确保以下内容: 43 | 44 | 1. 您已启用 `settings.k8s.io/v1alpha1/podpreset` API 类型。例如,可以通过在 API server 的 `--runtime-config` 选项中包含 `settings.k8s.io/v1alpha1=true` 来完成此操作。 45 | 2. 您已启用 `PodPreset` 准入控制器。一种方法是将 `PodPreset` 包含在为 API server 指定的 `--admission-control` 选项值中。 46 | 3. 您已经在要使用的命名空间中通过创建 `PodPreset` 对象来定义 `PodPreset`。 47 | -------------------------------------------------------------------------------- /02~资源对象/03~服务发现与路由/02~Ingress/Nginx/Nginx Ingress 关联外部服务.md: -------------------------------------------------------------------------------- 1 | # 使用外部服务 2 | 3 | ## 外部 IP 4 | 5 | 在部分场景下我们需要使用外部的 IP 作为 Ingress 的后端服务,此时我们仍需要创建一个指向外部服务的 Service: 6 | 7 | ```yml 8 | apiVersion: v1 9 | kind: Service 10 | metadata: 11 | name: release-name-ufc-rancher 12 | labels: 13 | app.kubernetes.io/name: ufc-rancher 14 | helm.sh/chart: ufc-rancher-0.1.0 15 | app.kubernetes.io/instance: release-name 16 | app.kubernetes.io/version: "1.0" 17 | app.kubernetes.io/managed-by: Tiller 18 | spec: 19 | type: ClusterIP 20 | ports: 21 | - port: 58080 22 | targetPort: 58080 23 | protocol: TCP 24 | --- 25 | apiVersion: v1 26 | kind: Endpoints 27 | metadata: 28 | name: release-name-ufc-rancher 29 | subsets: 30 | - addresses: 31 | # list all external ips for this service 32 | - ip: 172.19.157.3 33 | ports: 34 | - port: 58080 35 | protocol: TCP 36 | ``` 37 | 38 | 值得注意的是,这里我们在声明服务的时候并未指明 Pod Selector,这也就创建了一个没有后端的 Service,我们需要手动地去创建某个 Endpoints 然后将流量导入到该 Endpoints。外部对服务的访问则是同样创建 Ingress 资源即可: 39 | 40 | ```yml 41 | apiVersion: extensions/v1beta1 42 | kind: Ingress 43 | metadata: 44 | name: release-name-ufc-rancher 45 | labels: 46 | app.kubernetes.io/name: ufc-rancher 47 | helm.sh/chart: ufc-rancher-0.1.0 48 | app.kubernetes.io/instance: release-name 49 | app.kubernetes.io/version: "1.0" 50 | app.kubernetes.io/managed-by: Tiller 51 | annotations: 52 | certmanager.k8s.io/issuer: letsencrypt-prod 53 | kubernetes.io/ingress.class: nginx 54 | nginx.ingress.kubernetes.io/proxy-body-size: "0" 55 | 56 | spec: 57 | tls: 58 | - hosts: 59 | - "k8s.unionfab.com" 60 | secretName: ufc-rancher-tls 61 | rules: 62 | # ufc rancher ingress rules 63 | - host: "k8s.unionfab.com" 64 | http: 65 | paths: 66 | - path: / 67 | backend: 68 | serviceName: release-name-ufc-rancher 69 | servicePort: 58080 70 | ``` 71 | 72 | 这里我们的实例可以参考使用 Ingress 以允许用域名方式访问 Rancher,其 Helm 配置参考 [K8s/Helm](https://github.com/BE-Kits/k8s-examples)。 73 | 74 | ## 外部域名 75 | 76 | # Links 77 | 78 | - https://appscode.com/products/voyager/10.0.0/guides/ingress/http/external-svc/ 79 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/06~身份与权限认证/svid.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 49 3 | title: SVID 身份颁发过程 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | summary: 本文介绍了为工作负载颁发 X.509 SVID 身份的详细步骤。 7 | --- 8 | 9 | 本文介绍 SPIRE 如何向工作负载颁发身份的详细步骤,叙述了从代理在节点上启动到同一节点上的工作负载收到 X.509 SVID 形式的有效身份的全过程。请注意,JWT 格式的 SVID 的处理方式是不同的。为了简单演示的目的,工作负载在 AWS EC2 上运行。 10 | 11 | 1. SPIRE 服务器启动。 12 | 2. 除非用户配置了 `UpstreamAuthority` 插件,否则服务器会生成自签名证书(使用自己的私钥签名的证书);服务器将使用此证书为该服务器信任域中的所有工作负载签署 SVID。 13 | 3. 如果是第一次启动,服务器会自动生成一个信任包(trust bundle),其内容存储在你指定的 sql 数据存储中 —— 在[服务器插件:DataStore sql](https://github.com/spiffe/spire/blob/v1.3.0/doc/plugin_server_datastore_sql.md) 的 “内置插件” 部分中描述。 14 | 4. 服务器打开其注册 API,以允许你注册工作负载。 15 | 5. 工作负载节点上的 SPIRE 代理启动。 16 | 6. 代理执行节点证明,向服务器证明它正在运行的节点的身份。例如,在 AWS EC2 实例上运行时,它通常会通过向服务器提供 [AWS 实例身份文档](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html)来执行节点证明。 17 | 7. 代理通过 TLS 连接向服务器提供此身份证明,该 TLS 连接通过代理配置的引导程序包进行身份验证。 18 | 19 | {{}} 20 | 此引导程序包是默认配置,应在生产中替换为客户提供的凭据。 21 | {{}} 22 | 23 | 8. 服务器调用 AWS API 来验证证明。 24 | 9. AWS 承认该文件是有效的。 25 | 10. 服务器执行节点解析,以验证有关代理节点的其他属性并相应地更新其注册条目。例如,如果节点已使用 Microsoft Azure 托管服务标识 (MSI) 进行了证明。解析器从代理 SPIFFE ID 中提取租户 ID 和主体 ID,并使用各种 Azure 服务获取信息以构建一组额外的选择器。 26 | 11. 服务器向代理发出一个 SVID,代表代理本身的身份。 27 | 12. 代理联系服务器(使用其 SVID 作为其 TLS 客户端证书)以获取它被授权的注册条目。 28 | 13. 服务器使用代理的 SVID 对代理进行身份验证。代理依次完成 mTLS 握手并使用引导程序包对服务器进行身份验证。 29 | 14. 然后,服务器从其数据存储中获取所有[授权的注册条目](https://spiffe.io/docs/latest/spire-about/spire-concepts/#authorized-registration-entries)并将它们发送给代理。 30 | 15. 然后,代理将工作负载 CSR 发送到服务器,服务器对其进行签名并作为工作负载 SVID 返回给客户端。客户端将它们放入缓存中。 31 | 16. 现在引导完成,代理开始监听 Workload API 套接字。 32 | 17. 工作负载调用工作负载 API 来请求 SVID。 33 | 18. 代理通过调用其工作负载证明器来启动工作负载证明过程,并向他们提供工作负载进程的进程 ID。 34 | 19. 证明器使用内核和用户空间调用来发现有关工作负载的其他信息。 35 | 20. 证明器以工作负载选择器的形式将发现的信息返回给代理。 36 | 21. 代理通过将发现的工作负载选择器与注册条目进行比较来确定工作负载的身份,并返回正确的 SVID(已在其缓存中)。 37 | 38 | ## 授权注册条目 39 | 40 | 服务器只向代理发送授权的注册条目。服务器执行以下操作来获取这些授权条目: 41 | 42 | 1. 查询数据库以查找将代理的 SPIFFE ID 列为其 “父 SPIFFE ID” 的任何注册条目。 43 | 2. 在数据库中查询特定代理与哪些附加属性相关联(“节点选择器”)。 44 | 3. 查询数据库以获取在任何这些节点选择器上声明选择的至少一个注册条目。 45 | 4. 递归地查询数据库中的任何注册条目,这些条目声明了迄今为止获得的任何条目作为它们的 “父 SPIFFE ID”(下降到所有子节点)。 46 | 47 | 另请参阅[将工作负载映射到多个节点](https://spiffe.io/docs/latest/spire/using/registering/#mapping-workloads-to-multiple-nodes)。 48 | 49 | 服务器将生成授权的注册条目集发送给代理。 50 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/17~开发指南/sigs-and-working-group.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 104 3 | title: SIG 和工作组 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubernetes 的社区是以 SIG(Special Interest Group 特别兴趣小组)和工作组的形式组织起来的,每个工作组都会定期召开视频会议。 9 | 10 | 所有的 SIG 和工作组都使用 slack 和邮件列表沟通。 11 | 12 | ![Kubernetes SIG](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernetes-sigs.jpg "Kubernetes SIG 组织结构") 13 | 14 | ## 主要 SIG 列表 15 | 16 | - **api-machinery**:所有 API 级别的功能,包括了 API server、API 注册和发现、通用的 API CRUD 语义,准入控制,编码 / 解码,转换,默认值,持久化层(etcd),OpenAPI,第三方资源,垃圾回收(gc)和客户端库的方方面面。 17 | - **aws**:如何在 AWS 上支持和使用 kubernetes。 18 | - **apps**:在 kubernetes 上部署和运维应用程序。关注开发者和 DevOps 在 kubernetes 上运行应用程序的体验。 19 | - **architecture**:维持 kubernetes 在架构设计上的一致性和原则。 20 | - **auth**:kubernetes 的认证授权、权限管理和安全性策略。 21 | - **autoscaling**:集群的自动缩放,pod 的水平和垂直自动缩放,pod 的资源初始化,pod 监控和指标收集等主题。 22 | - **azure**:如何在 Azure 上支持和使用 kubernetes。 23 | - **big-data**:在 kubernetes 上部署和运行大数据应用,如 Spark、Kafka、Hadoop、Flink、Storm 等。 24 | - **CLI**:kubectl 和相关工具。 25 | - **cluster-lifecycle**:部署和升级 kubernetes 集群。 26 | - **cluster-ops**:促进 kubernetes 集群本身的可操作性和集群间的互操作性,使不同的运营商之间协调一致。 27 | - **contributor-experience**:维持良好的开发者社区。 28 | - **docs**:文档,流程和出版物。 29 | - **GCP**:在 Google Cloud Platform 上使用 kubernetes。 30 | - **instrumentation**:集群可观测性的最佳实践,包括指标设置、日志收集、事件等。 31 | - **multicluster**:多 kubernetes 集群的用例和工具。 32 | - **network**:kubernetes 集群的网络。 33 | - **node**:node 节点、kubelet。 34 | - **onprem**:在非云供应商的环境下运行 kubernetes,例如 on premise、裸机等环境。 35 | - **openstack**:协调跨 OpenStack 和 Kubernetes 社区的努力。 36 | - **product-management**:侧重于产品管理方面。 37 | - **release**:发布、PR 和 bug 提交等。 38 | - **scalability**:负责回答可伸缩性相关的问题。 39 | - **scheduling**:资源调度。 40 | - **service-catalog**:为 CNCF service broker 和 Kubernetes broker 实现开发 API。 41 | - **storage**:存储和 volume 插件。 42 | - **testing**:测试。 43 | - **ui**:与 UI 相关的话题。 44 | - **windows**:在 kubernets 上运行 Windows Server Container。 45 | 46 | ## 工作组列表 47 | 48 | - **App Def**:改进 API 中的声明性原语、客户端库、工具的用户体验。 49 | - **Cloud Provider**:云供应商工作组。 50 | - **Cluster API**:定义一个代表 Kubernetes 集群的可移植 API。API 将包含控制平面及其配置和底层基础设施(节点,节点池等)。 51 | - **Container Identity**:确保容器能够获得安全的身份认证并与外部连通的解决方案。 52 | - **Kubeadm Adoption**:提高 kubeadm 工具的采用率。 53 | - **Resource Management**J:资源隔离和提高资源利用率。 54 | 55 | 详细信息请参考 56 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/SideCar/README.md: -------------------------------------------------------------------------------- 1 | # SideCar 2 | 3 | 我们还是以 Kubernetes 的 Pod 为例介绍 SideCar 模式在 K8s 中的应用: 4 | 5 | ```yml 6 | # Example YAML configuration for the sidecar pattern. 7 | 8 | # It defines a main application container which writes 9 | # the current date to a log file every five seconds. 10 | 11 | # The sidecar container is nginx serving that log file. 12 | # (In practice, your sidecar is likely to be a log collection 13 | # container that uploads to external storage.) 14 | 15 | # To run: 16 | # kubectl apply -f pod.yaml 17 | 18 | # Once the pod is running: 19 | # 20 | # (Connect to the sidecar pod) 21 | # kubectl exec pod-with-sidecar -c sidecar-container -it bash 22 | # 23 | # (Install curl on the sidecar) 24 | # apt-get update && apt-get install curl 25 | # 26 | # (Access the log file via the sidecar) 27 | # curl 'http://localhost:80/app.txt' 28 | 29 | apiVersion: v1 30 | kind: Pod 31 | metadata: 32 | name: pod-with-sidecar 33 | spec: 34 | # Create a volume called 'shared-logs' that the 35 | # app and sidecar share. 36 | volumes: 37 | - name: shared-logs 38 | emptyDir: {} 39 | 40 | # In the sidecar pattern, there is a main application 41 | # container and a sidecar container. 42 | containers: 43 | # Main application container 44 | - name: app-container 45 | # Simple application: write the current date 46 | # to the log file every five seconds 47 | image: alpine # alpine is a simple Linux OS image 48 | command: ["/bin/sh"] 49 | args: ["-c", "while true; do date >> /var/log/app.txt; sleep 5;done"] 50 | 51 | # Mount the pod's shared log file into the app 52 | # container. The app writes logs here. 53 | volumeMounts: 54 | - name: shared-logs 55 | mountPath: /var/log 56 | 57 | # Sidecar container 58 | - name: sidecar-container 59 | # Simple sidecar: display log files using nginx. 60 | # In reality, this sidecar would be a custom image 61 | # that uploads logs to a third-party or storage service. 62 | image: nginx:1.7.9 63 | ports: 64 | - containerPort: 80 65 | 66 | # Mount the pod's shared log file into the sidecar 67 | # container. In this case, nginx will serve the files 68 | # in this directory. 69 | volumeMounts: 70 | - name: shared-logs 71 | mountPath: /usr/share/nginx/html # nginx-specific mount path 72 | ``` 73 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/03~集群资源管理/25.Annotation.md: -------------------------------------------------------------------------------- 1 | # Annotation 2 | 3 | Annotation,顾名思义,就是注解。Annotation 可以将 Kubernetes 资源对象关联到任意的非标识性元数据。使用客户端(如工具和库)可以检索到这些元数据。 4 | 5 | ## 关联元数据到对象 6 | 7 | Label 和 Annotation 都可以将元数据关联到 Kubernetes 资源对象。Label 主要用于选择对象,可以挑选出满足特定条件的对象。相比之下,annotation 不能用于标识及选择对象。annotation 中的元数据可多可少,可以是结构化的或非结构化的,也可以包含 label 中不允许出现的字符。 8 | 9 | Annotation 和 label 一样都是 key/value 键值对映射结构: 10 | 11 | ```json 12 | "annotations": {"key1":"value1","key2":"value2"} 13 | ``` 14 | 15 | 以下列出了一些可以记录在 annotation 中的对象信息: 16 | 17 | - 声明配置层管理的字段。使用 annotation 关联这类字段可以用于区分以下几种配置来源:客户端或服务器设置的默认值,自动生成的字段或自动生成的 auto-scaling 和 auto-sizing 系统配置的字段。 18 | - 创建信息、版本信息或镜像信息。例如时间戳、版本号、git 分支、PR 序号、镜像哈希值以及仓库地址。 19 | - 记录日志、监控、分析或审计存储仓库的指针 20 | 21 | - 可以用于 debug 的客户端(库或工具)信息,例如名称、版本和创建信息。 22 | - 用户信息,以及工具或系统来源信息、例如来自非 Kubernetes 生态的相关对象的 URL 信息。 23 | - 轻量级部署工具元数据,例如配置或检查点。 24 | - 负责人的电话或联系方式,或能找到相关信息的目录条目信息,例如团队网站。 25 | 26 | 如果不使用 annotation,您也可以将以上类型的信息存放在外部数据库或目录中,但这样做不利于创建用于部署、管理、内部检查的共享工具和客户端库。 27 | 28 | ## 示例 29 | 30 | 如 Istio 的 Deployment 配置中就使用到了 annotation: 31 | 32 | ```yaml 33 | apiVersion: extensions/v1beta1 34 | kind: Deployment 35 | metadata: 36 | name: istio-manager 37 | spec: 38 | replicas: 1 39 | template: 40 | metadata: 41 | annotations: 42 | alpha.istio.io/sidecar: ignore 43 | labels: 44 | istio: manager 45 | spec: 46 | serviceAccountName: istio-manager-service-account 47 | containers: 48 | - name: discovery 49 | image: harbor-001.jimmysong.io/library/manager:0.1.5 50 | imagePullPolicy: Always 51 | args: ["discovery", "-v", "2"] 52 | ports: 53 | - containerPort: 8080 54 | env: 55 | - name: POD_NAMESPACE 56 | valueFrom: 57 | fieldRef: 58 | apiVersion: v1 59 | fieldPath: metadata.namespace 60 | - name: apiserver 61 | image: harbor-001.jimmysong.io/library/manager:0.1.5 62 | imagePullPolicy: Always 63 | args: ["apiserver", "-v", "2"] 64 | ports: 65 | - containerPort: 8081 66 | env: 67 | - name: POD_NAMESPACE 68 | valueFrom: 69 | fieldRef: 70 | apiVersion: v1 71 | fieldPath: metadata.namespace 72 | ``` 73 | 74 | `alpha.istio.io/sidecar` 注解就是用来控制是否自动向 pod 中注入 sidecar 的。 75 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/13~集群安全性管理/kubernetes-security-best-practice.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 90 3 | title: Kubernetes 集群安全性配置最佳实践 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | 本文是对 Kubernetes 集群安全性管理的最佳实践。 9 | 10 | ## 端口 11 | 12 | 请注意管理好以下端口。 13 | 14 | | 端口 | 进程 | 描述 | 15 | | --------- | -------------- | -------------------------------------------------- | 16 | | 4149/TCP | kubelet | 用于查询容器监控指标的 cAdvisor 端口 | 17 | | 10250/TCP | kubelet | 访问节点的 API 端口 | 18 | | 10255/TCP | kubelet | 未认证的只读端口,允许访问节点状态 | 19 | | 10256/TCP | kube-proxy | kube-proxy 的健康检查服务端口 | 20 | | 9099/TCP | calico-felix | calico 的健康检查服务端口(如果使用 calico/canal) | 21 | | 6443/TCP | kube-apiserver | Kubernetes API 端口 | 22 | 23 | ## Kubernetes 安全扫描工具 kube-bench 24 | 25 | [kube-bench](https://github.com/aquasecurity/kube-bench) 可以消除大约 kubernetes 集群中 95%的配置缺陷。通过应用 CIS Kubernetes Benchmark 来检查 master 节点、node 节点及其控制平面组件,从而确保集群设置了特定安全准则。在经历特定的 Kubernetes 安全问题或安全增强功能之前,这应该是第一步。 26 | 27 | ## API 设置 28 | 29 | **授权模式和匿名认证** 30 | 31 | 像 kops 这样的一些安装程序会为集群使用 `AlwaysAllow` 授权模式。这将授予任何经过身份验证的实体拥有完全访问集群的权限。应该使用 RBAC 基于角色的访问控制。检查您的 kube-apiserver 进程的 `--authorization-mode` 参数。有关该主题的更多信息,请访问[认证概览](https://kubernetes.io/docs/admin/authorization/)。要强制进行身份验证,请确保通过设置 `--anonymous-auth = false` 禁用匿名身份验证。 32 | 33 | 注意这不影响 Kubelet 授权模式。kubelet 本身公开了一个 API 来执行命令,通过它可以完全绕过 Kubernetes API。 34 | 35 | 更多关于使用 kops 等工具自动安装 Kubernetes 集群的安全配置注意事项请参考 [Kubernetes Security - Best Practice Guide](https://github.com/freach/kubernetes-security-best-practice)。 36 | 37 | ## 参考 38 | 39 | - [Kubernetes Security - Best Practice Guide - github.com](https://github.com/freach/kubernetes-security-best-practice) 40 | - [Kubernetes v1.7 security in practice - acotten.com](https://acotten.com/post/kube17-security) 41 | - [Isolate containers with a user namespace - docs.docker.com](https://docs.docker.com/engine/security/userns-remap/) 42 | - [Docker Security – It’s a Layered Approach - logz.io](https://logz.io/blog/docker-security/) 43 | - [Kubernetes 1.8: Security, Workloads and Feature Depth - blog.kubernetes.io](https://blog.kubernetes.io/2017/09/kubernetes-18-security-workloads-and.html) 44 | - [Security Matters: RBAC in Kubernetes - blog.heptio.co](https://blog.heptio.com/security-matters-rbac-in-kubernetes-e369b483c8d8) 45 | -------------------------------------------------------------------------------- /04~生态扩展/Helm/基础/命令.md: -------------------------------------------------------------------------------- 1 | # 常用命令 2 | 3 | Helm 是由 Deis 发起的一个开源工具,有助于简化部署和管理 Kubernetes 应用。在本章的实践中,我们也会使用 Helm 来简化很多应用的安装操作。 4 | 5 | ![](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230430222840.png) 6 | 7 | 在 Linux 中可以使用 Snap 安装 Heml: 8 | 9 | ```sh 10 | $ sudo snap install helm --classic 11 | 12 | # 通过键入如下命令,在 Kubernetes 群集上安装 Tiller 13 | $ helm init --upgrade 14 | ``` 15 | 16 | 在缺省配置下,Helm 会利用 "gcr.io/kubernetes-helm/tiller" 镜像在 Kubernetes 集群上安装配置 Tiller;并且利用 "https://kubernetes-charts.storage.googleapis.com" 作为缺省的 stable repository 的地址。由于在国内可能无法访问 "gcr.io", "storage.googleapis.com" 等域名,阿里云容器服务为此提供了镜像站点。请执行如下命令利用阿里云的镜像来配置 Helm: 17 | 18 | ```sh 19 | $ helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.5.1 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 20 | 21 | # 删除默认的源 22 | $ helm repo remove stable 23 | 24 | # 设置 Helm 命令自动补全 25 | $ source <(helm completion zsh) 26 | $ source <(helm completion bash) 27 | 28 | # 增加新的国内镜像源 29 | $ helm repo add stable https://burdenbear.github.io/kube-charts-mirror/ 30 | $ helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 31 | 32 | # 查看 Helm 源添加情况 33 | $ helm repo list 34 | ``` 35 | 36 | Helm 的常见命令如下: 37 | 38 | ```sh 39 | # 查看在存储库中可用的所有 Helm Charts 40 | $ helm search 41 | 42 | # 删除并更新源 or https://burdenbear.github.io/kube-charts-mirror/ 43 | $ helm repo remove stable && helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 44 | # 更新 Charts 列表以获取最新版本 45 | $ helm repo update 46 | 47 | # 部署某个本地 Chart,指定命名空间与额外的配置文件 48 | $ helm install --namespace ufc --name ufc-dev -f ./deployment/ufc/dev-values.yaml ./charts/ufc/ 49 | 50 | # 查看某个 Chart 的变量 51 | $ helm inspect values stable/mysql 52 | 53 | # 查看在群集上安装的 Charts 列表 54 | $ helm list 55 | 56 | # 调试某个配置 57 | $ helm install --debug --dry-run ./mychart 58 | 59 | # 校验某个配置 60 | $ docker run -it --rm --name ct --volume $(pwd):/data quay.io/helmpack/chart-testing:v2.3.0 sh -c "ct lint --all --debug --chart-dirs /data/" 61 | 62 | # 更新某个配置 63 | $ helm upgrade my-release stable/external-dns 64 | $ helm upgrade -f panda.yaml happy-panda stable/mariadb 65 | 66 | # 删除某个 Charts 的部署 67 | $ helm del --purge wordpress-test 68 | 69 | # 为 Tiller 部署添加授权 70 | $ kubectl create serviceaccount --namespace kube-system tiller 71 | $ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller 72 | $ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}' 73 | ``` 74 | -------------------------------------------------------------------------------- /01~应用部署/03~典型案例/Minio.md: -------------------------------------------------------------------------------- 1 | # Minio 2 | 3 | Minio 是一个基于 Apache License v2.0 开源协议的对象存储服务,Minio 使用 Go 语言开发,具有良好的跨平台性,同样是一个非常轻量的服务。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如:图片、视频、日志文件、备份数据和容器/虚拟机镜像等。 4 | 5 | 使用 helm install 进行一键部署,并通过 ingress.enabled=true 参数启用 Ingress 特性。 6 | 7 | ```sh 8 | $ helm install --name minio --set "ingress.enabled=true,persistence.enabled=false" minio 9 | 10 | NAMESPACE: default 11 | STATUS: DEPLOYED 12 | 13 | RESOURCES: 14 | ==> v1beta1/Ingress 15 | NAME HOSTS ADDRESS PORTS AGE 16 | minio minio.hi-linux.com 80 1m 17 | 18 | ==> v1/Pod(related) 19 | NAME READY STATUS RESTARTS AGE 20 | minio-7c7cf49d4-gqf8p 1/1 Running 0 1m 21 | 22 | ==> v1/Secret 23 | NAME TYPE DATA AGE 24 | minio Opaque 2 1m 25 | 26 | ==> v1/ConfigMap 27 | NAME DATA AGE 28 | minio 2 1m 29 | 30 | ==> v1/Service 31 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 32 | minio ClusterIP None 9000/TCP 1m 33 | 34 | ==> v1beta2/Deployment 35 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 36 | minio 1 1 1 1 1m 37 | 38 | NOTES: 39 | 40 | Minio can be accessed via port 9000 on the following DNS name from within your cluster: 41 | minio-svc.default.svc.cluster.local 42 | 43 | To access Minio from localhost, run the below commands: 44 | 45 | 1. export POD_NAME=$(kubectl get pods --namespace default -l "release=minio" -o jsonpath="{.items[0].metadata.name}") 46 | 47 | 2. kubectl port-forward $POD_NAME 9000 --namespace default 48 | 49 | Read more about port forwarding here: http://kubernetes.io/docs/user-guide/kubectl/kubectl_port-forward/ 50 | 51 | You can now access Minio server on http://localhost:9000. Follow the below steps to connect to Minio server with mc client: 52 | 53 | 1. Download the Minio mc client - https://docs.minio.io/docs/minio-client-quickstart-guide 54 | 55 | 2. mc config host add minio-local http://localhost:9000 AKIAIOSFODNN7EXAMPLE wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY S3v4 56 | 57 | 3. mc ls minio-local 58 | 59 | Alternately, you can use your browser or the Minio SDK to access the server - https://docs.minio.io/categories/17 60 | ``` 61 | 62 | 部署完成后,我们在本地 hosts 文件中对 IP 和域名进行绑定,并通过浏览器访问该应用。登陆用户名和密码在部署完成后的提示信息中。最后我们在 Kubernetes 上来查看下部署成功后的 Ingress 信息。 63 | 64 | ```sh 65 | $ kubectl get ingress 66 | NAME HOSTS ADDRESS PORTS AGE 67 | dokuwiki-dokuwiki wiki.hi-linux.com 80 44m 68 | minio minio.hi-linux.com 80 50s 69 | ``` 70 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/12~命令使用/using-kubectl.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 80 3 | title: Kubectl 命令概览 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubernetes 提供的 kubectl 命令是与集群交互最直接的方式,v1.6 版本的 kubectl 命令参考图如下: 9 | 10 | ![kubectl cheatsheet](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernetes-kubectl-cheatsheet.png "kubectl cheatsheet") 11 | 12 | Kubectl 的子命令主要分为 8 个类别: 13 | 14 | - 基础命令(初学者都会使用的) 15 | - 基础命令(中级) 16 | - 部署命令 17 | - 集群管理命令 18 | - 故障排查和调试命令 19 | - 高级命令 20 | - 设置命令 21 | - 其他命令 22 | 23 | 熟悉这些命令有助于大家来操作和管理 kubernetes 集群。 24 | 25 | ## 命令行提示 26 | 27 | 为了使用 kubectl 命令更加高效,我们可以选择安装一下开源软件来增加操作 kubectl 命令的快捷方式,同时为 kubectl 命令增加命令提示。 28 | 29 | ![增加kubeclt命令的工具(图片来自网络)](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/tools-to-supercharge-kubectl.jpg "增加kubeclt命令的工具(图片来自网络)") 30 | 31 | - [kubectx](https://github.com/ahmetb/kubectx):用于切换 Kubernetes context 32 | - [kube-ps1](https://github.com/jonmosco/kube-ps1):为命令行终端增加`$PROMPT`字段 33 | - [kube-shell](https://github.com/cloudnativelabs/kube-shell):交互式带命令提示的 kubectl 终端 34 | 35 | 全部配置完成后的 kubectl 终端如下图所示: 36 | 37 | ![增强的kubectl命令](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/supercharged-kubectl.jpg "增强的kubectl命令") 38 | 39 | 开源项目 [kube-shell](https://github.com/cloudnativelabs/kube-shell) 可以为 kubectl 提供自动的命令提示和补全,使用起来特别方便,推荐给大家。 40 | 41 | Kube-shell 有以下特性: 42 | 43 | - 命令提示,给出命令的使用说明 44 | - 自动补全,列出可选命令并可以通过 tab 键自动补全,支持模糊搜索 45 | - 高亮 46 | - 使用 tab 键可以列出可选的对象 47 | - vim 模式 48 | 49 | **Mac 下安装** 50 | 51 | ```bash 52 | pip install kube-shell --user -U 53 | ``` 54 | 55 | ![kube-shell页面](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kube-shell.jpg "kube-shell页面") 56 | 57 | ## kubectl 的身份认证 58 | 59 | Kubernetes 中存在三种安全认证方式: 60 | 61 | - **CA 证书**:API server 与其它几个组件之间都是通过这种方式认证的 62 | - **HTTP base**:即在 API server 的启动参数中指定的 `--token-auth-file=/etc/kubernetes/token.csv` 文件中明文的用户、组、密码和 UID 配置 63 | - **bearer token**:HTTP 请求中 `header` 中传递的 `Autorization:Bearer token`,这个 token 通常保存在创建角色跟 `serviceaccount` 绑定的时候生成的 secret 中。 64 | 65 | kubectl 通过读取 `kubeconfig` 文件中的配置信息在向 API server 发送请求的时候同时传递认证信息,同时支持 CA 证书和 bearer token 的认证方式。 66 | 67 | ## 终端下 kubectl 命令自动补全 68 | 69 | 建议使用 [oh-my-zsh](http://ohmyz.sh/),增加对 kubectl 命令自动补全支持。 70 | 71 | 修改 `~/.zshrc` 文件,增加如下两行: 72 | 73 | ```bash 74 | plugins=(kubectl) 75 | source <(kubectl completion zsh) 76 | ``` 77 | 78 | 保存后重启终端即可生效。 79 | 80 | ## 参考 81 | 82 | - [Install and Set Up kubectl - kubernetes.io](https://kubernetes.io/docs/tasks/tools/install-kubectl/#using-zsh) 83 | -------------------------------------------------------------------------------- /01~应用部署/01~安装配置/Minikube/README.md: -------------------------------------------------------------------------------- 1 | # Minikube 2 | 3 | # 安装 4 | 5 | 需要注意的是,Minikube 必须安装在本地,而不是云提供商上。因此,以下硬件规格是针对本地机器的:1 核,2GB 内存,20GB 存储。 6 | 7 | ## GNU/Linux 8 | 9 | ```sh 10 | # check if your machine supports virtualization. On GNU / Linux, this can be accomplished with: 11 | $ grep -E --color 'vmx|svm' /proc/cpuinfo 12 | 13 | # install kubectl 14 | curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl 15 | 16 | chmod +x ./kubectl 17 | 18 | sudo mv ./kubectl /usr/local/bin/kubectl 19 | 20 | kubectl version --client 21 | 22 | # Download and install the Minikube 23 | curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 24 | 25 | chmod +x ./minikube 26 | 27 | sudo mv ./minikube /usr/local/bin/minikube 28 | 29 | minikube version 30 | ``` 31 | 32 | ## MacOS 33 | 34 | ```sh 35 | # verify that the processor supports virtualization 36 | $ sysctl -a | grep -E --color 'machdep.cpu.features|VMX' 37 | 38 | $ brew install kubectl 39 | $ kubectl version --client 40 | 41 | $ brew install minikube 42 | $ minikube version 43 | 44 | # Run the following command to configure the alias and autocomplete for kubectl. 45 | 46 | source <( kubectl completion bash ) # configures the autocomplete in your current session (first, make sure you have installed the bash-completion package). 47 | echo " source <(kubectl completion bash) " >> ~ /.bashrc # add autocomplete permanently to your shell. 48 | 49 | # ZSH 50 | source <(kubectl completion zsh) 51 | echo "[[ $commands[kubectl] ]] && source <(kubectl completion zsh)" 52 | ``` 53 | 54 | ## Usage 55 | 56 | ```sh 57 | minikube start 58 | 59 | 60 | 🎉 minikube 1.10.0 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.10.0 61 | 💡 To disable this notice, run: 'minikube config set WantUpdateNotification false' 62 | 63 | 🙄 minikube v1.9.2 on Darwin 10.11 64 | ✨ Using the virtualbox driver based on existing profile 65 | 👍 Starting control plane node m01 in cluster minikube 66 | 🔄 Restarting existing virtualbox VM for "minikube" ... 67 | 🐳 Preparing Kubernetes v1.19.1 on Docker 19.03.8 ... 68 | 🌟 Enabling addons: default-storageclass, storage-provisioner 69 | 🏄 Done! kubectl is now configured to use "minikube" 70 | 71 | $ kubectl get nodes 72 | 73 | NAME STATUS ROLES AGE VERSION 74 | minikube Ready master 8d v1.19.1 75 | 76 | # Finding the Minikube Address 77 | $ minikube ip 78 | 79 | # Accessing the Minikube machine via SSH 80 | $ minikube ssh 81 | 82 | # Dashboard 83 | $ minikube dashboard 84 | 85 | ``` 86 | -------------------------------------------------------------------------------- /01~应用部署/02~kubectl/01~连接到集群.md: -------------------------------------------------------------------------------- 1 | # 上下文配置 2 | 3 | 通过 kubectl 子命令 config 的三元组:集群(set-cluster)、用户(set-credentials)和配置上下文(set-context)实现切换。K8s 中的上下文能够连接用户与集群,如果通过 kubectl 的操作如下: 4 | 5 | ```sh 6 | # 创建cluster 7 | kubectl config set-cluster set-cluster scratch --server=https://5.6.7.8 --insecure-skip-tls-verify 8 | # 创建user 9 | kubectl config set-credentials experimenter --username=exp --password=some-password 10 | # 创建context 11 | kubectl config set-context exp-scratch --cluster=scratch --namespace=default --user=experimenter 12 | # 指定当前使用的context 13 | kubectl config use-context exp-scratch 14 | ``` 15 | 16 | 我们也可以指明如下的配置文件,通过 `export KUBECONFIG=/path/to/config.yml` 的方式来指明当前的上下文: 17 | 18 | ```yml 19 | apiVersion: v1 20 | kind: Config 21 | preferences: {} 22 | 23 | # Define the cluster 24 | clusters: 25 | - cluster: 26 | certificate-authority-data: xx 27 | server: "https:/xx:6443" 28 | name: "xx" 29 | 30 | # Define the user 31 | users: 32 | - name: "xx" 33 | user: 34 | as-user-extra: {} 35 | client-key-data: "xx" 36 | token: "xx" 37 | 38 | # Define the context: linking a user to a cluster 39 | contexts: 40 | - context: 41 | cluster: "0" 42 | namespace: "xx" 43 | user: "xx" 44 | name: "xx" 45 | 46 | # Define current context 47 | current-context: "xx" 48 | ``` 49 | 50 | ## 上下文切换 51 | 52 | 在 K8s 集群安装完毕之后,可以下载集群的配置文件到本地 kubectl 配置中: 53 | 54 | ```sh 55 | mkdir $HOME/.kube 56 | scp root@:/etc/kubernetes/kube.conf $HOME/.kube/config 57 | ``` 58 | 59 | 然后可以来查看当前的上下文 60 | 61 | ```sh 62 | $ unset KUBECONFIG 63 | $ kubectl config current-context # 查看当前载入的上下文 64 | $ kubectl config get-contexts # 浏览可用的上下文 65 | $ kubectl config use-context context-name # 切换到指定上下文 66 | ``` 67 | 68 | 在操作 Kubernetes 时,处理来自不同名称空间的资源,这也是一种很常见的做法。例如,你可能希望列出一个名称空间内的所有 Pod,随后检查另一个名称空间中的服务。此时我的做法是使用 Kubernetes CLI 所支持的 --namespace 标记。例如,若要查看名为 Test 的名称空间中的所有 Pod,可以运行 `kubectl get pods -n test`。默认情况下,如果不提供名称空间标记,将使用默认的 Kubernetes 名称空间,即 default。 69 | 70 | 这个默认值可以在 kubeconfig 文件中修改,例如我们可以将默认名称空间设置为 test、kube-system 或其他任何名称空间。这样在查询资源时就不需要使用 --namespace 标记了。不过更改默认值的命令略微繁琐: 71 | 72 | ```sh 73 | $ kubectl config set contexts.my-context.namespace my-namespace 74 | ``` 75 | 76 | 上述命令会更改 my-context 上下文的 Namespace 字段,将其改为 my-namespace。这也意味着,举例来说,如果切换到 my-context 随后运行 kubectl get pods,将只能看到 my-namespace 名称空间下的 Pod。除了使用 kubectx,我们还可以使用一款名为 kubens 的工具,后者可以帮助我们列出并切换至不同名称空间。 77 | 78 | ```sh 79 | $ kubens 80 | default 81 | docker 82 | kube-node-lease 83 | kube-public 84 | kube-system 85 | ``` 86 | 87 | 为所选上下文设置默认名称空间,这也是一种快速简单的操作: 88 | 89 | ```sh 90 | $ kubens default 91 | Context "docker-desktop" modified. 92 | Active namespace is "default". 93 | ``` 94 | -------------------------------------------------------------------------------- /02~资源对象/06~存储/卷/本地存储.md: -------------------------------------------------------------------------------- 1 | # 本地存储 2 | 3 | # Empty-Dir 4 | 5 | 每当一个 Pod 被分配到一个现有节点时,就会创建一个 EmptyDir 类型的卷。该卷最初是空的,所有的 Pod 容器都可以向该卷读写文件。这个卷不是一个持久的数据卷。每当 Pod 从节点中移除时,数据 EmptyDiris 就会被永久删除。需要注意的是,在容器失败的情况下,数据不会被删除。让我们创建一个 Pod 来测试这个卷。 6 | 7 | ```yaml 8 | vim pod-emptydir.yaml 9 | 10 | apiVersion : v1 11 | kind : Pod 12 | metadata : 13 | name : busybox 14 | namespace : default 15 | spec : 16 | containers : 17 | - image : busybox 18 | name : busy 19 | command : 20 | - sleep 21 | - " 3600 " 22 | volumeMounts : 23 | - mountPath : /giropops 24 | name : giropops-dir 25 | volumes : 26 | - name : giropops-dir 27 | emptyDir : {} 28 | ``` 29 | 30 | 然后创建卷: 31 | 32 | ```sh 33 | $ kubectl create -f pod-emptydir.yaml 34 | 35 | pod/busybox created 36 | 37 | $ kubectl get pod 38 | 39 | NAME READY STATUS RESTARTS AGE 40 | busybox 1/1 Running 0 12s 41 | ``` 42 | 43 | 让我们列举一下 Pod 里面的容器名称。 44 | 45 | ```sh 46 | $ kubectl get pods busybox -n default -o jsonpath='{.spec.containers[*].name}*' 47 | 48 | busy 49 | ``` 50 | 51 | 现在让我们在创建的 Pod 中直接在路径/giropops 中添加一个文件。 52 | 53 | ```sh 54 | $ kubectl exec -ti busybox -c busy -- touch /giropops/funciona 55 | 56 | $ kubectl exec -ti busybox -c busy -- ls -l /giropops/ 57 | 58 | total 0 59 | -rw-r--r-- 1 root root 0 Jul 7 17:37 funciona 60 | ``` 61 | 62 | 正如我们所看到的,我们的文件被正确的创建了,我们检查一下这个文件是否在 kubelet 管理的卷上也被创建了。让我们检查一下这个文件是否也是在 kubelet 管理的卷上创建的。为此,我们需要找出 Pod 所在的节点。 63 | 64 | ```sh 65 | $ kubectl get pod -o wide 66 | 67 | NAME READY STATUS RESTARTS AGE IP NODE 68 | busybox 1/1 Running 0 1m 10.40.0.6 elliot-02 69 | 70 | $ kubectl exec -ti busybox -c busy sh 71 | $ ls giropops 72 | 73 | ``` 74 | 75 | 现在让我们走出 Pod,在 elliot-02 节点中寻找我们的卷。要做到这一点,通过 SSH 访问节点,然后执行命令。 76 | 77 | ```sh 78 | $find /var/lib/kubelet/pods/ -iname giropops-dir 79 | 80 | /var/lib/kubelet/pods/7d33810f-8215-11e8-b889-42010a8a0002/volumes/kubernetes.io~empty-dir/giropops-dir 81 | 82 | $ ls /var/lib/kubelet/pods/7d33810f-8215-11e8-b889-42010a8a0002/volumes/kubernetes.io~empty-dir/giropops-dir 83 | funciona 84 | ``` 85 | 86 | 回到节点 elliot-01,我们要把 Pod 删除,再列出目录。 87 | 88 | ```sh 89 | $ kubectl delete -f pod-emptydir.yaml 90 | 91 | pod "busybox" deleted 92 | ``` 93 | 94 | 再次访问节点 elliot-02,看看卷是否还存在。 95 | 96 | ```sh 97 | $ ls /var/lib/kubelet/pods/7d...kubernetes.io~empty-dir/giropops-dir 98 | 99 | No such file or directory 100 | ``` 101 | 102 | 哎呀,我们收到了找不到目录的消息,正是我们所期望的正确吗?因为类型为 EmptyDir 的卷并不能保持数据的持久性。 103 | 104 | # Links 105 | 106 | - https://blog.csdn.net/solaraceboy/article/details/84339673 Kubernetes 中,两种常见类型的 Volume 深度实践 107 | -------------------------------------------------------------------------------- /01~应用部署/02~kubectl/02~运行与管理.md: -------------------------------------------------------------------------------- 1 | # 运行与管理 2 | 3 | `kubectl run` 和 docker run 一样,它能将一个镜像运行起来,我们使用 kubectl run 来将一个 sonarqube 的镜像启动起来。 4 | 5 | ```sh 6 | $ kubectl run sonarqube --image=sonarqube:5.6.5 --replicas=1 --port=9000 7 | 8 | deployment "sonarqube" created 9 | 10 | # 该命令为我们创建了一个 Deployment 11 | $ kubectl get deployment 12 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 13 | sonarqube 1 1 1 1 5m 14 | ``` 15 | 16 | 我们也可以直接以交互方式运行某个镜像: 17 | 18 | ```sh 19 | $ kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il 20 | ``` 21 | 22 | K8s 将镜像运行在 Pod 中以方便实施卷和网络共享等管理,使用 get pods 可以清楚的看到生成了一个 Pod: 23 | 24 | ```sh 25 | $ kubectl get pods 26 | NAME READY STATUS RESTARTS AGE 27 | sonarqube-1880671902-s3fdq 1/1 Running 0 6m 28 | 29 | # 交互式运行 Pod 中的某个命令 30 | $ kubectl exec -it sonarqube-1880671902-s3fdq -- /bin/bash 31 | ``` 32 | 33 | `kubectl` 可以用于删除创建好的 Deployment 与 Pod: 34 | 35 | ```sh 36 | $ kubectl delete pods sonarqube-1880671902-s3fdq 37 | $ kubectl delete deployment sonarqube 38 | ``` 39 | 40 | 最后,我们以创建包含两个 Pod 的应用为例,展示简单的 Pod 创建、暴露等操作: 41 | 42 | ```sh 43 | # 创建 Deployment 44 | $ kubectl run hello-world --replicas=2 --labels="run=load-balancer-example" --image=gcr.io/google-samples/node-hello:1.0 --port=8080 45 | 46 | # 获取 Deployment 相关的信息 47 | $ kubectl get deployments hello-world 48 | $ kubectl describe deployments hello-world 49 | 50 | # 获取关联的 ReplicaSet 对象 51 | $ kubectl get replicasets 52 | $ kubectl describe replicasets 53 | 54 | # 创建 Service 对象,并且暴露服务 55 | $ kubectl expose deployment hello-world --type=NodePort --name=example-service 56 | 57 | # 获取服务信息 58 | $ kubectl describe services example-service 59 | 60 | # 获取关联的 Pod 信息 61 | $ kubectl get pods --selector="run=load-balancer-example" --output=wide 62 | 63 | # 访问服务 64 | $ curl http://: 65 | ``` 66 | 67 | ## 网络访问 68 | 69 | ```sh 70 | # 暴露某个 Pod 的端口 71 | $ kubectl port-forward -n NAMESPACE $POD : & 72 | $ kubectl port-forward $POD_NAME 8080:80 73 | 74 | # 暴露某个 Service 的端口 75 | $ kubectl -n rook-ceph port-forward service/rook-ceph-mgr-dashboard 31631:7000 --address 0.0.0.0 76 | $ kubectl port-forward -n default deployment/postgres 8432:5432 77 | 78 | $ export WEBAPP_POD=$(kubectl get pods -n $NAMESPACE | grep web-app | awk '{print $1;}') 79 | $ kubectl port-forward -n $NAMESPACE $WEBAPP_POD 8080 80 | 81 | $ kubectl proxy --port 8002 82 | # http://localhost:8002/api/v1/proxy/namespaces/NAMESPACE/services/SERVICE_NAME:SERVICE_PORT/ 83 | 84 | $ curl -v -u username:password \ 85 | --cacert ./ca.pem \ 86 | --cert ./crt.pem \ 87 | --key ./key.pem \ 88 | https://api.CLUSTER_ID.k8s.gigantic.io/api/v1/namespaces/logging/services/elasticsearch:es/proxy/_stats 89 | ``` 90 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/13~集群安全性管理/kubelet-authentication-authorization.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 85 3 | title: Kublet 的认证授权 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | Kubelet 的 HTTPS 端点对外暴露了用于访问不同敏感程度数据的 API,并允许您在节点或者容器内执行不同权限级别的操作。 9 | 10 | 本文档向您描述如何通过认证授权来访问 kubelet 的 HTTPS 端点。 11 | 12 | ## Kubelet 认证 13 | 14 | 默认情况下,所有未被配置的其他身份验证方法拒绝的,对 kubelet 的 HTTPS 端点的请求将被视为匿名请求,并被授予 `system:anonymous` 用户名和 `system:unauthenticated` 组。 15 | 16 | 如果要禁用匿名访问并发送 `401 Unauthorized` 的未经身份验证的请求的响应: 17 | 18 | - 启动 kubelet 时指定 `--anonymous-auth=false` 标志 19 | 20 | 如果要对 kubelet 的 HTTPS 端点启用 X509 客户端证书身份验证: 21 | 22 | - 启动 kubelet 时指定 `--client-ca-file` 标志,提供 CA bundle 以验证客户端证书 23 | - 启动 apiserver 时指定 `--kubelet-client-certificate` 和 `--kubelet-client-key` 标志 24 | - 参阅 [apiserver 认证文档](https://kubernetes.io/docs/admin/authentication/#x509-client-certs) 获取更多详细信息。 25 | 26 | 启用 API bearer token(包括 service account token)用于向 kubelet 的 HTTPS 端点进行身份验证: 27 | 28 | - 确保在 API server 中开启了 `authentication.k8s.io/v1beta1` API 组。 29 | - 启动 kubelet 时指定 `--authentication-token-webhook`,`--kubeconfig` 和 `--require-kubeconfig` 标志 30 | - Kubelet 在配置的 API server 上调用 `TokenReview` API 以确定来自 bearer token 的用户信息 31 | 32 | ## Kubelet 授权 33 | 34 | 接着对任何成功验证的请求(包括匿名请求)授权。默认授权模式为 `AlwaysAllow`,允许所有请求。 35 | 36 | 细分访问 kubelet API 有很多原因: 37 | 38 | - 启用匿名认证,但匿名用户调用 kubelet API 的能力应受到限制 39 | - 启动 bearer token 认证,但是 API 用户(如 service account)调用 kubelet API 的能力应受到限制 40 | - 客户端证书身份验证已启用,但只有那些配置了 CA 签名的客户端证书的用户才可以使用 kubelet API 41 | 42 | 如果要细分访问 kubelet API,将授权委托给 API server: 43 | 44 | - 确保 API server 中启用了 `authorization.k8s.io/v1beta1` API 组 45 | - 启动 kubelet 时指定 `--authorization-mode=Webhook`、`--kubeconfig` 和 `--require-kubeconfig` 标志 46 | - kubelet 在配置的 API server 上调用 `SubjectAccessReview` API,以确定每个请求是否被授权 47 | 48 | kubelet 使用与 apiserver 相同的 [请求属性](https://kubernetes.io/docs/admin/authorization/#request-attributes) 方法来授权 API 请求。 49 | 50 | Verb(动词)是根据传入的请求的 HTTP 动词确定的: 51 | 52 | | HTTP 动词 | request 动词 | 53 | | --------- | ------------ | 54 | | POST | create | 55 | | GET, HEAD | get | 56 | | PUT | update | 57 | | PATCH | patch | 58 | | DELETE | delete | 59 | 60 | 资源和子资源根据传入请求的路径确定: 61 | 62 | | Kubelet API | 资源 | 子资源 | 63 | | ------------ | ----- | ------- | 64 | | /stats/\* | nodes | stats | 65 | | /metrics/\* | nodes | metrics | 66 | | /logs/\* | nodes | log | 67 | | /spec/\* | nodes | spec | 68 | | _all others_ | nodes | proxy | 69 | 70 | Namespace 和 API 组属性总是空字符串,资源的名字总是 kubelet 的 `Node` API 对象的名字。 71 | 72 | 当以该模式运行时,请确保用户为 apiserver 指定了 `--kubelet-client-certificate` 和 `--kubelet-client-key` 标志并授权了如下属性: 73 | 74 | - verb=\*, resource=nodes, subresource=proxy 75 | - verb=\*, resource=nodes, subresource=stats 76 | - verb=\*, resource=nodes, subresource=log 77 | - verb=\*, resource=nodes, subresource=spec 78 | - verb=\*, resource=nodes, subresource=metrics 79 | -------------------------------------------------------------------------------- /02~资源对象/05~网络/Calico/工作原理.md: -------------------------------------------------------------------------------- 1 | # BGP 2 | 3 | Calico 采用的 BGP,就是在大规模网络中实现节点路由信息共享的一种协议。全称是 Border Gateway Protocol,即:边界网关协议。它是一个 Linux 内核原生就支持的、专门用在大规模数据中心里维护不同的 “自治系统” 之间路由信息的、无中心的路由协议。 4 | 5 | 由于没有使用 CNI 的网桥,Calico 的 CNI 插件需要为每个容器设置一个 Veth Pair 设备,然后把其中的一端放置在宿主机上,还需要在宿主机上为每个容器的 Veth Pair 设备配置一条路由规则,用于接收传入的 IP 包。如下图所示: 6 | 7 | ![Calico](https://s1.ax1x.com/2020/10/19/0xRYbq.png) 8 | 9 | 可以使用 calicoctl 查看 Node 1 的节点连接情况: 10 | 11 | ```sh 12 | ~ calicoctl get no 13 | NAME 14 | node1 15 | node2 16 | node3 17 | ~ calicoctl node status 18 | Calico process is running. 19 | 20 | IPv4 BGP status 21 | +---------------+-------------------+-------+------------+-------------+ 22 | | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | 23 | +---------------+-------------------+-------+------------+-------------+ 24 | | 192.168.50.11 | node-to-node mesh | up | 2020-09-28 | Established | 25 | | 192.168.50.12 | node-to-node mesh | up | 2020-09-28 | Established | 26 | +---------------+-------------------+-------+------------+-------------+ 27 | 28 | IPv6 BGP status 29 | No IPv6 peers found. 30 | ``` 31 | 32 | 可以看到整个 calico 集群上有 3 个节点,Node 1 和另外两个节点处于连接状态,模式为 “Node-to-Node Mesh”。再看下 Node 1 上的路由信息如下: 33 | 34 | ```sh 35 | ~ ip route 36 | default via 192.168.50.1 dev ens33 proto static metric 100 37 | 10.244.104.0/26 via 192.168.50.11 dev ens33 proto bird 38 | 10.244.135.0/26 via 192.168.50.12 dev ens33 proto bird 39 | 10.244.166.128 dev cali717821d73f3 scope link 40 | blackhole 10.244.166.128/26 proto bird 41 | 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 42 | 192.168.50.0/24 dev ens33 proto kernel scope link src 192.168.50.10 metric 100 43 | ``` 44 | 45 | 其中,第 2 条的路由规则表明 10.244.104.0/26 网段的数据包通过 bird 协议由 ens33 设备发往网关 192.168.50.11。这也就定义了目的 ip 为 Node 2 上 Pod 请求的走向。第 3 条路由规则与之类似。 46 | 47 | # IPIP 模式 48 | 49 | IPIP 模式为了解决两个 Node 不在一个子网的问题。只要将名为 calico-node 的 daemonset 的环境变量 CALICOIPV4POOLIPIP 设置为 "Always" 即可。如下: 50 | 51 | ```sh 52 | - name: CALICO_IPV4POOL_IPIP 53 | value: "Off" 54 | ``` 55 | 56 | IPIP 模式的 Calico 使用了 tunl0 设备,这是一个 IP 隧道设备。IP 包进入 tunl0 后,内核会将原始 IP 包直接封装在宿主机的 IP 包中;封装后的 IP 包的目的地址为下一跳地址,即 Node 2 的 IP 地址。由于宿主机之间已经使用路由器配置了三层转发,所以这个 IP 包在离开 Node 1 之后,就可以经过路由器,最终发送到 Node 2 上。如下图所示。 57 | 58 | ![Calico IPIP 模式](https://s1.ax1x.com/2020/10/19/0zmeOK.png) 59 | 60 | 由于 IPIP 模式的 Calico 额外多出了封包和拆包的过程,集群的网络性能受到了影响,所以在集群的二层网络通的情况下,建议不要使用 IPIP 模式。看下 Node1 上的路由信息: 61 | 62 | ```sh 63 | ~ ip route 64 | default via 192.168.50.1 dev ens33 proto static metric 100 65 | 10.244.104.0/26 via 192.168.50.11 dev tunl0 proto bird onlink 66 | 10.244.135.0/26 via 192.168.50.12 dev tunl0 proto bird onlink 67 | blackhole 10.244.166.128/26 proto bird 68 | 10.244.166.129 dev calif3c799362a5 scope link 69 | 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 70 | 192.168.50.0/24 dev ens33 proto kernel scope link src 192.168.50.10 metric 100 71 | ``` 72 | 73 | 可以看到,与之前不一样的是,目的 IP 为 Node 2 上的 Pod 的数据包是经由 tunl0 发送到网关 192.168.50.11。 74 | -------------------------------------------------------------------------------- /02~资源对象/03~服务发现与路由/01~Service/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Service 详解 2 | 3 | ## 为什么需要 Service? 4 | 5 | Kubernetes 中的 Pod 是非永久性资源: 6 | 7 | - Pod 会根据集群状态被动态创建和销毁 8 | - 每个 Pod 都有自己的 IP 地址 9 | - Deployment 中运行的 Pod 集合可能随时发生变化 10 | 11 | 这带来了一个问题:前端 Pod 如何稳定地访问后端 Pod 提供的服务? 12 | 13 | ## Service 概念 14 | 15 | > A Kubernetes Service is an abstraction layer which defines a logical set of Pods and enables external traffic exposure, load balancing and service discovery for those Pods. 16 | 17 | Service 是 Kubernetes 的核心概念,它提供: 18 | 19 | - 对一组功能相同的 Pod 的抽象 20 | - 为这组 Pod 提供统一的访问入口 21 | - 实现服务发现与负载均衡 22 | - 支持应用的零宕机升级 23 | 24 | ### 实际应用场景 25 | 26 | 以图片处理后端为例: 27 | 28 | - 运行 3 个副本 Pod 29 | - 这些副本是可互换的 30 | - 前端无需关心具体调用了哪个后端副本 31 | - Service 抽象层解耦了前后端的直接关联 32 | 33 | ## 网络实现机制 34 | 35 | ### CNI(Container Network Interface) 36 | 37 | CNI 是 Kubernetes 的网络基础: 38 | 39 | - 为容器提供标准化的网络接口 40 | - 支持多种网络解决方案(AWS、GCP、Cloud Foundry 等) 41 | - 定义 Pod 网络通信规范 42 | 43 | #### Kubernetes 网络特性 44 | 45 | 1. Pod 跨节点通信 46 | 2. 节点与 Pod 通信 47 | 3. 不使用 NAT 48 | 49 | ### CNI 与 Service 的关系 50 | 51 | 网络插件(CNI)和 Service 在 Kubernetes 中各司其职但又相互配合: 52 | 53 | 1. **不同的职责** 54 | 55 | - CNI 插件:负责实现 Pod 网络通信的底层基础设施 56 | - 为 Pod 分配 IP 地址 57 | - 配置网络接口 58 | - 实现 Pod 之间的直接通信 59 | - Service:作为服务发现和负载均衡的抽象层 60 | - 提供稳定的服务访问端点 61 | - 通过 kube-proxy 实现流量转发 62 | - 管理服务发现和负载均衡 63 | 64 | 2. **协同工作流程** 65 | 66 | - CNI 插件确保 Pod 网络连通性 67 | - Service 基于 CNI 提供的网络基础设施工作 68 | - kube-proxy 依赖 CNI 提供的网络来转发流量到目标 Pod 69 | 70 | 3. **实际应用示例** 71 | 当一个服务请求发生时: 72 | 1. 请求首先到达 Service 的 ClusterIP 73 | 2. kube-proxy 处理转发规则 74 | 3. 通过 CNI 配置的网络将请求转发到目标 Pod 75 | 4. CNI 确保请求能够正确到达目标 Pod 76 | 77 | ### 常用网络插件 78 | 79 | - Weave:适用于多云环境,提供加密通信 80 | - Flannel:简单易用,适合入门 81 | - Calico:支持网络策略,适合需要细粒度控制的场景 82 | - Channel:云原生网络方案 83 | - Roman:适用于边缘计算场景 84 | - Nuage:企业级 SDN 解决方案 85 | - Contiv:思科开源的网络解决方案 86 | 87 | ## Service 网络实现 88 | 89 | ### 核心组件 90 | 91 | 1. **kube-proxy** 92 | 93 | - 实现软件负载均衡 94 | - 转发 Service 请求到后端 Pod 95 | - 支持多种代理模式(iptables、IPVS) 96 | 97 | 2. **Cluster IP** 98 | - 每个 Service 分配全局唯一的虚拟 IP 99 | - 作为服务的统一访问入口 100 | - 仅在集群内部可访问 101 | 102 | ### 服务发现机制 103 | 104 | #### DNS 服务发现 105 | 106 | - 自动为每个 Service 注册 DNS 记录 107 | - 格式:`.` 108 | - DNS Server 通过 API Server 监控 Service 变化 109 | 110 | 示例: 111 | 112 | - Service 名称:my-service 113 | - 命名空间:my-ns 114 | - DNS 记录:my-service.my-ns 115 | - 同命名空间的 Pod 可直接使用 my-service 116 | - 其他命名空间的 Pod 需使用完整域名 my-service.my-ns 117 | 118 | ## 最佳实践 119 | 120 | 1. **服务命名** 121 | 122 | - 使用有意义的名称 123 | - 遵循 DNS 命名规范 124 | - 避免使用特殊字符 125 | 126 | 2. **网络规划** 127 | 128 | - 合理规划 Service 的网络段 129 | - 避免与现有网络冲突 130 | - 预留足够的 IP 地址空间 131 | 132 | 3. **性能优化** 133 | - 选择合适的网络插件 134 | - 根据需求配置适当的代理模式 135 | - 监控网络性能指标 136 | 137 | ## 参考资料 138 | 139 | - https://parg.co/kXe 140 | - Kubernetes 官方文档 141 | -------------------------------------------------------------------------------- /02~资源对象/06~存储/ConfigMap/创建与使用.md: -------------------------------------------------------------------------------- 1 | # 创建 ConfigMap 2 | 3 | ## 通过 yaml 配置文件方式创建` 4 | 5 | ```yml 6 | kind: ConfigMap 7 | apiVersion: v1 8 | metadata: 9 | name: example-configmap 10 | data: 11 | # Configuration values can be set as key-value properties 12 | database: mongodb 13 | database_uri: mongodb://localhost:27017 14 | 15 | # Or set as complete file contents (even JSON!) 16 | keys: | 17 | image.public.key=771 18 | rsa.public.key=42 19 | ``` 20 | 21 | `kubectl apply -f config-map.yaml` 22 | 23 | ## 通过 kubectl 命令行方式创建 24 | 25 | ```sh 26 | $ kubectl create configmap cores-frutas --from-literal=uva=roxa --from-file=predileta --from-file=frutas/ 27 | 28 | $ kubectl get configmap 29 | ``` 30 | 31 | # 使用 ConfigMap 32 | 33 | ## 挂载为卷使用 34 | 35 | ```yml 36 | kind: Pod 37 | apiVersion: v1 38 | metadata: 39 | name: pod-using-configmap 40 | 41 | spec: 42 | # Add the ConfigMap as a volume to the Pod 43 | volumes: 44 | # `name` here must match the name 45 | # specified in the volume mount 46 | - name: example-configmap-volume 47 | # Populate the volume with config map data 48 | configMap: 49 | # `name` here must match the name 50 | # specified in the ConfigMap's YAML 51 | name: example-configmap 52 | 53 | containers: 54 | - name: container-configmap 55 | image: nginx:1.7.9 56 | # Mount the volume that contains the configuration data 57 | # into your container filesystem 58 | volumeMounts: 59 | # `name` here must match the name 60 | # from the volumes section of this pod 61 | - name: example-configmap-volume 62 | mountPath: /etc/config 63 | ``` 64 | 65 | ## 作为环境变量使用 66 | 67 | ```yml 68 | kind: Pod 69 | apiVersion: v1 70 | metadata: 71 | name: pod-env-var 72 | spec: 73 | containers: 74 | - name: env-var-configmap 75 | image: nginx:1.7.9 76 | envFrom: 77 | - configMapRef: 78 | name: example-configmap 79 | ``` 80 | 81 | # 案例 82 | 83 | ## 挂载配置文件 84 | 85 | 我们也可以将文件创建为 ConfigMap,然后将其挂载到容器对应的卷中: 86 | 87 | ```yml 88 | apiVersion: v1 89 | kind: ConfigMap 90 | metadata: 91 | name: sherlock-config 92 | namespace: default 93 | data: 94 | config.yaml: | 95 | namespaces: 96 | - default 97 | labels: 98 | - "app" 99 | - "owner" 100 | ``` 101 | 102 | 然后在 Pod 中创建关联的卷,指明文件路径: 103 | 104 | ```yml 105 | apiVersion: v1 106 | kind: Pod 107 | metadata: 108 | name: kube-sherlock 109 | spec: 110 | serviceAccountName: kube-sherlock 111 | containers: 112 | - name: kube-sherlock 113 | image: cmendibl3/kube-sherlock:0.1 114 | volumeMounts: 115 | - name: config-volume 116 | mountPath: /app/config.yaml 117 | subPath: config.yaml 118 | volumes: 119 | - name: config-volume 120 | configMap: 121 | name: sherlock-config 122 | restartPolicy: Never 123 | ``` 124 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/17~开发指南/operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 108 3 | title: Operator 4 | summary: "关于 Kubernetes Operator 的原理、用途等基础知识介绍。" 5 | date: '2022-09-05T11:00:00+08:00' 6 | type: book 7 | --- 8 | 9 | Operator 最初是由 CoreOS(后被 Red Hat 收购) 开发的,下面是关于 Operator 的一些基础知识: 10 | 11 | - Operator 是用来扩展 Kubernetes API 的特定的应用程序控制器; 12 | - Operator 用来创建、配置和管理复杂的有状态应用,如数据库、缓存和监控系统; 13 | - Operator 基于 Kubernetes 的资源和控制器概念之上构建,但同时又包含了应用程序特定的领域知识; 14 | - 创建 Operator 的关键是 CRD(自定义资源)的设计; 15 | - Operator 通常作为 Deployment 资源部署在 Kubernetes 中,删掉 Operator 不会影响已使用它创建的自定义资源; 16 | - [Operator Hub](https://operatorhub.io/) 中罗列了目前已知的 Operator。 17 | 18 | ## 工作原理 19 | 20 | Operator 是将运维人员对软件操作的知识给代码化,同时利用 Kubernetes 强大的抽象来管理大规模的软件应用。 21 | 22 | Operator 使用了 Kubernetes 的自定义资源扩展 API 机制,如使用 CRD(CustomResourceDefinition)来创建。Operator 通过这种机制来创建、配置和管理应用程序。 23 | 24 | Operator 基于 Kubernetes 的以下两个概念构建: 25 | 26 | - 资源:对象的状态定义 27 | - 控制器:观测、分析和行动,以调节资源的分布 28 | 29 | ## Operator 用途 30 | 31 | 若您有以下需求,可能会需要用到 Operator: 32 | 33 | - 按需部署一个应用程序 34 | - 需要备份和恢复应用程序的状态(如数据库) 35 | - 处理应用程序代码的升级以及相关更改,例如数据库架构或额外的配置设置 36 | - 发布一个服务,要让不支持 Kubernetes API 的应用程序能够发现 37 | - 模拟整个或部分集群中的故障以测试其弹性 38 | - 在没有内部成员选举程序的情况下为分布式应用程序选择领导者 39 | 40 | ## Operator 用途的详细示例 41 | 42 | 下面是一个使用 Operator 的详细示例: 43 | 44 | - 将一个名为 SampleDB 的自定义资源其配置到集群中。 45 | - 确保正在运行的 Deployment 的 Pod 中包含 Operator 的控制器部分。 46 | - Operator 代码的容器镜像。 47 | - 查询控制平面以找出配置了哪些 SampleDB 资源的控制器代码。 48 | - Operator 的核心是告诉 API Server 如何使现实与代码里已配置的资源匹配: 49 | - 如果添加新的 SampleDB,Operator 将设置 PersistentVolumeClaims 以提供持久的数据库存储,设置 StatefulSet 以运行 SampleDB,并设置 Job 来处理初始配置。 50 | - 如果删除它,Operator 将建立快照,然后确保删除了 StatefulSet 和卷。 51 | - Operator 还管理常规数据库备份。对于每个 SampleDB 资源,Operator 确定何时创建可以连接到数据库并进行备份的 Pod。这些 Pod 将依赖于 ConfigMap 和 / 或具有数据库连接详细信息和凭据的 Secret。 52 | - 由于 Operator 旨在为其管理的资源提供强大的自动化功能,因此会有其他支持代码。对于此示例,代码将检查数据库是否正在运行旧版本,如果是,则创建 Job 对象为您升级数据库。 53 | 54 | ## 创建 Operator 55 | 56 | Operator 本质上是与应用息息相关的,因为这是特定领域的知识的编码结果,这其中包括了资源配置的控制逻辑。下面是创建 Operator 的基本步骤: 57 | 58 | 1. 在单个 Deployment 中定义 Operator 且部署完成不需要进行任何操作; 59 | 2. 需要为 Operator 创建一个新的自定义类型 CRD,这样用户就可以使用该对象来创建实例; 60 | 3. Operator 应该利用 Kubernetes 中内建的原语,如 Deployment、Service 这些经过充分测试的对象,这样也便于理解; 61 | 4. Operator 应该向后兼容,始终了解用户在之前版本中创建的资源; 62 | 5. 当 Operator 被停止或删除时,Operator 创建的应用实例应该不受影响; 63 | 6. Operator 应该让用户能够根据版本声明来选择所需版本和编排应用程序升级。不升级软件是操作错误和安全问题的常见来源,Operator 可以帮助用户更加自信地解决这一问题; 64 | 7. Operator 应该进行 “Chaos Monkey” 测试,以模拟 Pod、配置和网络故障的情况下的行为。 65 | 66 | ## 参考 67 | 68 | - [Writing a Kubernetes Operator in Golang - medium.com](https://medium.com/@mtreacher/writing-a-kubernetes-operator-a9b86f19bfb9) 69 | - [Introducing Operators: Putting Operational Knowledge into Software - cloud.redhat.com](https://cloud.redhat.com/blog/introducing-operators-putting-operational-knowledge-into-software) 70 | - [Automating Kubernetes Cluster Operations with Operators - thenewstack.io](https://thenewstack.io/automating-kubernetes-cluster-operations-operators/) 71 | - [Operator pattern - kubernetes.io](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) 72 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/02~资源对象/pod-overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 12 3 | title: Pod 概览 4 | date: "2017-03-10T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | 本文将为您讲解 Pod 的基础概念。 9 | 10 | ## 理解 Pod 11 | 12 | Pod 是 kubernetes 中你可以创建和部署的最小也是最简的单位。Pod 代表着集群中运行的进程。 13 | 14 | Pod 中封装着应用的容器(有的情况下是好几个容器),存储、独立的网络 IP,管理容器如何运行的策略选项。Pod 代表着部署的一个单位:kubernetes 中应用的一个实例,可能由一个或者多个容器组合在一起共享资源。 15 | 16 | > [Docker](https://www.docker.com) 是 kubernetes 中最常用的容器运行时,但是 Pod 也支持其他容器运行时。 17 | 18 | 在 Kubernetes 集群中 Pod 有如下两种使用方式: 19 | 20 | - **一个 Pod 中运行一个容器**。“每个 Pod 中一个容器” 的模式是最常见的用法;在这种使用方式中,你可以把 Pod 想象成是单个容器的封装,kuberentes 管理的是 Pod 而不是直接管理容器。 21 | - **在一个 Pod 中同时运行多个容器**。一个 Pod 中也可以同时封装几个需要紧密耦合互相协作的容器,它们之间共享资源。这些在同一个 Pod 中的容器可以互相协作成为一个 service 单位 —— 一个容器共享文件,另一个 “sidecar” 容器来更新这些文件。Pod 将这些容器的存储资源作为一个实体来管理。 22 | 23 | [Kubernetes Blog](https://kubernetes.io/blog) 有关于 Pod 用例的详细信息,查看: 24 | 25 | - [The Distributed System Toolkit: Patterns for Composite Containers](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/) 26 | - [Container Design Patterns](https://kubernetes.io/blog/2016/06/container-design-patterns/) 27 | 28 | 每个 Pod 都是应用的一个实例。如果你想平行扩展应用的话(运行多个实例),你应该运行多个 Pod,每个 Pod 都是一个应用实例。在 Kubernetes 中,这通常被称为 replication。 29 | 30 | ### Pod 中如何管理多个容器 31 | 32 | Pod 中可以同时运行多个进程(作为容器运行)协同工作。同一个 Pod 中的容器会自动的分配到同一个 node 上。同一个 Pod 中的容器共享资源、网络环境和依赖,它们总是被同时调度。 33 | 34 | 注意在一个 Pod 中同时运行多个容器是一种比较高级的用法。只有当你的容器需要紧密配合协作的时候才考虑用这种模式。例如,你有一个容器作为 web 服务器运行,需要用到共享的 volume,有另一个 “sidecar” 容器来从远端获取资源更新这些文件,如下图所示: 35 | 36 | ![pod 示意图](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/pod-overview.png "Pod 示意图") 37 | 38 | Pod 中可以共享两种资源:网络和存储。 39 | 40 | #### 网络 41 | 42 | 每个 Pod 都会被分配一个唯一的 IP 地址。Pod 中的所有容器共享网络空间,包括 IP 地址和端口。Pod 内部的容器可以使用 `localhost` 互相通信。Pod 中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射)。 43 | 44 | #### 存储 45 | 46 | 可以为一个 Pod 指定多个共享的 Volume。Pod 中的所有容器都可以访问共享的 volume。Volume 也可以用来持久化 Pod 中的存储资源,以防容器重启后文件丢失。 47 | 48 | ## 使用 Pod 49 | 50 | 你很少会直接在 kubernetes 中创建单个 Pod。因为 Pod 的生命周期是短暂的,用后即焚的实体。当 Pod 被创建后(不论是由你直接创建还是被其他 Controller),都会被 Kubernetes 调度到集群的 Node 上。直到 Pod 的进程终止、被删掉、因为缺少资源而被驱逐、或者 Node 故障之前这个 Pod 都会一直保持在那个 Node 上。 51 | 52 | > 注意:重启 Pod 中的容器跟重启 Pod 不是一回事。Pod 只提供容器的运行环境并保持容器的运行状态,重启容器不会造成 Pod 重启。 53 | 54 | Pod 不会自愈。如果 Pod 运行的 Node 故障,或者是调度器本身故障,这个 Pod 就会被删除。同样的,如果 Pod 所在 Node 缺少资源或者 Pod 处于维护状态,Pod 也会被驱逐。Kubernetes 使用更高级的称为 Controller 的抽象层,来管理 Pod 实例。虽然可以直接使用 Pod,但是在 Kubernetes 中通常是使用 Controller 来管理 Pod 的。 55 | 56 | ### Pod 和 Controller 57 | 58 | Controller 可以创建和管理多个 Pod,提供副本管理、滚动升级和集群级别的自愈能力。例如,如果一个 Node 故障,Controller 就能自动将该节点上的 Pod 调度到其他健康的 Node 上。 59 | 60 | 包含一个或者多个 Pod 的 Controller 示例: 61 | 62 | - [Deployment](../../controllers/deployment) 63 | - [StatefulSet](../../controllers/statefulset) 64 | - [DaemonSet](../../controllers/daemonset) 65 | 66 | 通常,Controller 会用你提供的 Pod Template 来创建相应的 Pod。 67 | 68 | ## Pod Templates 69 | 70 | Pod 模版是包含了其他 object 的 Pod 定义,例如 [Replication Controllers](../replicaset),[Jobs](../job) 和 [DaemonSets](../daemonset)。Controller 根据 Pod 模板来创建实际的 Pod。 71 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/11~资源对象配置/quota.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 77 3 | title: 管理 namespace 中的资源配额 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | 当用多个团队或者用户共用同一个集群的时候难免会有资源竞争的情况发生,这时候就需要对不同团队或用户的资源使用配额做出限制。 9 | 10 | ## 开启资源配额限制功能 11 | 12 | 目前有两种资源分配管理相关的控制策略插件 `ResourceQuota` 和 `LimitRange`。 13 | 14 | 要启用它们只要 API Server 的启动配置的 `KUBE_ADMISSION_CONTROL` 参数中加入了 `ResourceQuota` 的设置,这样就给集群开启了资源配额限制功能,加入 `LimitRange` 可以用来限制一个资源申请的范围限制,参考 [为 namesapce 配置默认的内存请求与限额](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/memory-default-namespace/) 和 [在 namespace 中配置默认的CPU请求与限额](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/cpu-default-namespace/)。 15 | 16 | 两种控制策略的作用范围都是对于某一 namespace,`ResourceQuota` 用来限制 namespace 中所有的 Pod 占用的总的资源 request 和 limit,而 `LimitRange` 是用来设置 namespace 中 Pod 的默认的资源 request 和 limit 值。 17 | 18 | 资源配额分为三种类型: 19 | 20 | - 计算资源配额 21 | - 存储资源配额 22 | - 对象数量配额 23 | 24 | 关于资源配额的详细信息请参考 Kubernetes 官方文档 [资源配额](https://kubernetes.io/docs/concepts/policy/resource-quotas/)。 25 | 26 | ## 示例 27 | 28 | 我们为 `spark-cluster` 这个 namespace 设置 `ResouceQuota` 和 `LimitRange`。 29 | 30 | 以下 yaml 文件可以在 [kubernetes-handbook](https://github.com/rootsongjc/kubernetes-handbook) 的 `manifests/spark-with-kubernetes-native-scheduler` 目录下找到。 31 | 32 | ### 配置计算资源配额 33 | 34 | 配置文件:`spark-compute-resources.yaml` 35 | 36 | ```yaml 37 | apiVersion: v1 38 | kind: ResourceQuota 39 | metadata: 40 | name: compute-resources 41 | namespace: spark-cluster 42 | spec: 43 | hard: 44 | pods: "20" 45 | requests.cpu: "20" 46 | requests.memory: 100Gi 47 | limits.cpu: "40" 48 | limits.memory: 200Gi 49 | ``` 50 | 51 | 要想查看该配置只要执行: 52 | 53 | ```bash 54 | kubectl -n spark-cluster describe resourcequota compute-resources 55 | ``` 56 | 57 | ### 配置对象数量限制 58 | 59 | 配置文件:`spark-object-counts.yaml` 60 | 61 | ```yaml 62 | apiVersion: v1 63 | kind: ResourceQuota 64 | metadata: 65 | name: object-counts 66 | namespace: spark-cluster 67 | spec: 68 | hard: 69 | configmaps: "10" 70 | persistentvolumeclaims: "4" 71 | replicationcontrollers: "20" 72 | secrets: "10" 73 | services: "10" 74 | services.loadbalancers: "2" 75 | ``` 76 | 77 | ### 配置CPU和内存LimitRange 78 | 79 | 配置文件:`spark-limit-range.yaml` 80 | 81 | ```yaml 82 | apiVersion: v1 83 | kind: LimitRange 84 | metadata: 85 | name: mem-limit-range 86 | spec: 87 | limits: 88 | - default: 89 | memory: 50Gi 90 | cpu: 5 91 | defaultRequest: 92 | memory: 1Gi 93 | cpu: 1 94 | type: Container 95 | ``` 96 | 97 | - `default` 即 limit 的值 98 | - `defaultRequest` 即 request 的值 99 | 100 | ## 参考 101 | 102 | - [资源配额 - kubernetes.io](https://kubernetes.io/docs/concepts/policy/resource-quotas/) 103 | - [为命名空间配置默认的内存请求与限额 - kubernetes.io](https://kubernetes.io/docs/tasks/administer-cluster/memory-default-namespace/) 104 | - [在命名空间中配置默认的 CPU 请求与限额 - kubernetes.io](https://kubernetes.io/docs/tasks/administer-cluster/cpu-default-namespace/) 105 | -------------------------------------------------------------------------------- /04~生态扩展/Helm/Charts/Hooks.md: -------------------------------------------------------------------------------- 1 | # Hooks 2 | 3 | Helm 提供了一个 hook 机制,允许 chart 开发人员在 release 的生命周期中的某些点进行干预。例如,可以使用 hooks 来: 4 | 5 | - 在加载任何其他 chart 之前,在安装过程中加载 ConfigMap 或 Secret。 6 | - 在安装新 chart 之前执行作业以备份数据库,然后在升级后执行第二个作业以恢复数据。 7 | - 在删除 release 之前运行作业,以便在删除 release 之前优雅地停止服务。 8 | 9 | Hooks 像常规模板一样工作,但它们具有特殊的注释,可以使 Helm 以不同的方式使用它们。 10 | 11 | # 可用的 Hooks 12 | 13 | 定义了以下 hooks: 14 | 15 | - 预安装 pre-install::在模板渲染后执行,但在 Kubernetes 中创建任何资源之前执行。 16 | - 安装后 post-install:在所有资源加载到 Kubernetes 后执行 17 | - 预删除 pre-delete:在从 Kubernetes 删除任何资源之前执行删除请求。 18 | - 删除后 post-delete:删除所有 release 的资源后执行删除请求。 19 | - 升级前 pre-upgrade:在模板渲染后,但在任何资源加载到 Kubernetes 之前执行升级请求(例如,在 Kubernetes 应用操作之前)。 20 | - 升级后 post-upgrade:在所有资源升级后执行升级。 21 | - 预回滚 pre-rollback:在渲染模板之后,但在任何资源已回滚之前,在回滚请求上执行。 22 | - 回滚后 post-rollback:在修改所有资源后执行回滚请求。 23 | 24 | # Hook 声明 25 | 26 | Hook 只是 Kubernetes manifest 文件,在 metadata 部分有特殊的注释 。因为他们是模板文件,可以使用所有的 Normal 模板的功能,包括读取 .Values,.Release 和 .Template。例如,在此模板中, 存储在 templates/post-install-job.yaml 的声明要在 post-install 阶段运行作业: 27 | 28 | ```yaml 29 | apiVersion: batch/v1 30 | kind: Job 31 | metadata: 32 | name: "{{.Release.Name}}" 33 | labels: 34 | app.kubernetes.io/managed-by: {{.Release.Service | quote}} 35 | app.kubernetes.io/instance: {{.Release.Name | quote}} 36 | helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" 37 | annotations: 38 | # This is what defines this resource as a hook. Without this line, the 39 | # job is considered part of the release. 40 | "helm.sh/hook": post-install 41 | "helm.sh/hook-weight": "-5" 42 | "helm.sh/hook-delete-policy": hook-succeeded 43 | spec: 44 | template: 45 | metadata: 46 | name: "{{.Release.Name}}" 47 | labels: 48 | app.kubernetes.io/managed-by: {{.Release.Service | quote}} 49 | app.kubernetes.io/instance: {{.Release.Name | quote}} 50 | helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" 51 | spec: 52 | restartPolicy: Never 53 | containers: 54 | - name: post-install-job 55 | image: "alpine:3.3" 56 | command: ["/bin/sleep","{{default"10".Values.sleepyTime}}"] 57 | ``` 58 | 59 | 注释使这个模板成为 hook: 60 | 61 | ``` 62 | annotations: 63 | "helm.sh/hook": post-install 64 | ``` 65 | 66 | 一个资源可以部署多个 hook: 67 | 68 | ``` 69 | annotations: 70 | "helm.sh/hook": post-install,post-upgrade 71 | ``` 72 | 73 | 同样,实现一个给定的 hook 的不同种类资源数量没有限制。例如,我们可以将 secret 和 config map 声明为预安装 hook。 74 | 75 | 子 chart 声明 hook 时,也会评估这些 hook。顶级 chart 无法禁用子 chart 所声明的 hook。 76 | 77 | 可以为一个 hook 定义一个权重,这将有助于建立一个确定性的执行顺序。权重使用以下注释来定义: 78 | 79 | ``` 80 | annotations: 81 | "helm.sh/hook-weight": "5" 82 | ``` 83 | 84 | hook 权重可以是正数或负数,但必须表示为字符串。当 Tiller 开始执行一个特定类型的 hook (例:`pre-install` hooks `post-install` hooks, 等等) 执行周期时,它会按升序对这些 hook 进行排序。 85 | 86 | 还可以定义确定何时删除相应的 hook 资源的策略。hook 删除策略使用以下注释来定义: 87 | 88 | ``` 89 | annotations: 90 | "helm.sh/hook-delete-policy": hook-succeeded 91 | ``` 92 | 93 | 可以选择一个或多个定义的注释值: 94 | 95 | - "hook-succeeded" 指定 Tiller 应该在 hook 成功执行后删除 hook。 96 | - "hook-failed" 指定如果 hook 在执行期间失败,Tiller 应该删除 hook。 97 | - "before-hook-creation" 指定 Tiller 应在删除新 hook 之前删除以前的 hook。 98 | -------------------------------------------------------------------------------- /02~资源对象/01~Pod/声明与管理/Hello World.md: -------------------------------------------------------------------------------- 1 | # Pod 执行与控制 2 | 3 | # 容器创建与执行 4 | 5 | 我们可以创建如下的 Pod 配置文件: 6 | 7 | ```yml 8 | apiVersion: v1 9 | kind: Pod 10 | metadata: 11 | name: shell-demo 12 | spec: 13 | volumes: 14 | - name: shared-data 15 | emptyDir: {} 16 | containers: 17 | - name: nginx 18 | image: nginx 19 | volumeMounts: 20 | - name: shared-data 21 | mountPath: /usr/share/nginx/html 22 | hostNetwork: true 23 | dnsPolicy: Default 24 | ``` 25 | 26 | 注意,这里使用 hostNetwork 命令指明了使用所在主机的接口,我们接下来使用 kubectl 来创建 Pod: 27 | 28 | ```sh 29 | $ kubectl apply -f https://k8s.io/examples/application/shell-demo.yaml 30 | 31 | # 获取当前容器的状态 32 | $ kubectl get pod shell-demo 33 | 34 | # 执行 Pod 中的命令 35 | $ kubectl exec -it shell-demo -- /bin/bash 36 | 37 | # 单独执行某个指令 38 | $ kubectl exec shell-demo env 39 | $ kubectl exec shell-demo ps aux 40 | $ kubectl exec shell-demo ls / 41 | $ kubectl exec shell-demo cat /proc/1/mounts 42 | 43 | # 当有多个容器时,可以指明执行某个容器的命令 44 | $ kubectl exec -it my-pod --container main-app -- /bin/bash 45 | ``` 46 | 47 | 这里我们使用了本地的 Volume 共享,我们可以在共享的目录中创建新的文本: 48 | 49 | ```sh 50 | $ echo Hello shell demo > /usr/share/nginx/html/index.html 51 | $ curl localhost 52 | ``` 53 | 54 | # 多个容器 55 | 56 | 在以下的配置中,我们可以创建包含两个容器的 Pod,这两个容器共享 Volume 并以此通信: 57 | 58 | ```yml 59 | apiVersion: v1 60 | kind: Pod 61 | metadata: 62 | name: two-containers 63 | spec: 64 | restartPolicy: Never 65 | 66 | volumes: 67 | - name: shared-data 68 | emptyDir: {} 69 | 70 | containers: 71 | - name: nginx-container 72 | image: nginx 73 | volumeMounts: 74 | - name: shared-data 75 | mountPath: /usr/share/nginx/html 76 | 77 | - name: debian-container 78 | image: debian 79 | volumeMounts: 80 | - name: shared-data 81 | mountPath: /pod-data 82 | command: ["/bin/sh"] 83 | args: 84 | ["-c", "echo Hello from the debian container > /pod-data/index.html"] 85 | ``` 86 | 87 | 在配置文件中,您可以看到 Pod 具有一个名为 shared-data 的卷。配置文件中列出的第一个容器运行 nginx 服务器。共享卷的安装路径为 `/usr/share/nginx/html`。第二个容器基于 debian 映像,并且具有 `/pod-data` 的安装路径。第二个容器运行以下命令,然后终止。 88 | 89 | ```sh 90 | $ echo Hello from the debian container > /pod-data/index.html 91 | ``` 92 | 93 | ```sh 94 | $ kubectl get pod two-containers --output=yaml 95 | 96 | apiVersion: v1 97 | kind: Pod 98 | metadata: 99 | ... 100 | name: two-containers 101 | namespace: default 102 | ... 103 | spec: 104 | ... 105 | containerStatuses: 106 | 107 | - containerID: docker://c1d8abd1 ... 108 | image: debian 109 | ... 110 | lastState: 111 | terminated: 112 | ... 113 | name: debian-container 114 | ... 115 | 116 | - containerID: docker://96c1ff2c5bb ... 117 | image: nginx 118 | ... 119 | name: nginx-container 120 | ... 121 | state: 122 | running: 123 | ... 124 | ``` 125 | 126 | 我们可以看到 debian container 被终止了,而 nginx container 依然运行。 127 | 128 | ```sh 129 | $ kubectl exec -it two-containers -c nginx-container -- /bin/bash 130 | $ root@two-containers:/# curl localhost 131 | 132 | > Hello from the debian container 133 | ``` 134 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/17~开发指南/operator-sdk.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 109 3 | title: Operator SDK 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | [Operator SDK](https://github.com/operator-framework/operator-sdk) 由 CoreOS 开源,它是用于构建 Kubernetes 原生应用的 SDK,它提供更高级别的 API、抽象和项目脚手架。在阅读本文前请先确认您已经了解 [Operator](operator.md)是什么。 9 | 10 | 使用 Kubernetes 中原生的对象来部署和管理复杂的应用程序不是那么容易,尤其是要管理整个应用的生命周期、组件的扩缩容,我们之前通常是编写各种脚本,通过调用 Kubernetes 的命令行工具来管理 Kubernetes 上的应用。现在可以通过 CRD(CustomResourceDefinition)来自定义这些复杂操作,通过将运维的知识封装在自定义 API 里来减轻运维人员的负担。同时我们还可以像操作 Kubernetes 的原生资源对象一样,使用 `kubectl` 来操作 CRD。 11 | 12 | 下面我们将安装和试用一下 Operator SDK。 13 | 14 | ## 安装 Operator SDK 15 | 16 | ```bash 17 | $ mkdir -p $GOPATH/src/github.com/operator-framework 18 | $ cd $GOPATH/src/github.com/operator-framework/operator-sdk 19 | $ dep ensure 20 | Create kubernetes-operator-sdk-tutorial/cmd/kubernetes-operator-sdk-tutorial/main.go 21 | Create kubernetes-operator-sdk-tutorial/config/config.yaml 22 | Create kubernetes-operator-sdk-tutorial/deploy/rbac.yaml 23 | Create kubernetes-operator-sdk-tutorial/deploy/cr.yaml 24 | Create kubernetes-operator-sdk-tutorial/pkg/apis/jimmysong/v1alpha1/doc.go 25 | Create kubernetes-operator-sdk-tutorial/pkg/apis/jimmysong/v1alpha1/register.go 26 | Create kubernetes-operator-sdk-tutorial/pkg/apis/jimmysong/v1alpha1/types.go 27 | Create kubernetes-operator-sdk-tutorial/pkg/stub/handler.go 28 | Create kubernetes-operator-sdk-tutorial/tmp/build/build.sh 29 | Create kubernetes-operator-sdk-tutorial/tmp/build/docker_build.sh 30 | Create kubernetes-operator-sdk-tutorial/tmp/build/Dockerfile 31 | Create kubernetes-operator-sdk-tutorial/tmp/codegen/boilerplate.go.txt 32 | Create kubernetes-operator-sdk-tutorial/tmp/codegen/update-generated.sh 33 | Create kubernetes-operator-sdk-tutorial/Gopkg.toml 34 | Create kubernetes-operator-sdk-tutorial/Gopkg.lock 35 | Run dep ensure ... 36 | Root project is "github.com/rootsongjc/kubernetes-operator-sdk-tutorial" 37 | 3 transitively valid internal packages 38 | 12 external packages imported from 4 projects 39 | (0) ✓ select (root) 40 | (1) ? attempt k8s.io/api with 1 pkgs; at least 1 versions to try 41 | (1) try k8s.io/api@kubernetes-1.9.3 42 | (1) ✓ select k8s.io/api@kubernetes-1.9.3 w/1 pkgs 43 | (2) ? attempt k8s.io/apimachinery with 4 pkgs; at least 1 versions to try 44 | (2) try k8s.io/apimachinery@kubernetes-1.9.3 45 | (2) ✓ select k8s.io/apimachinery@kubernetes-1.9.3 w/22 pkgs 46 | ... 47 | 48 | $ go install github.com/operator-framework/operator-sdk/commands/operator-sdk 49 | ``` 50 | 51 | 该过程需要几分钟,请耐心等待。确认 `$GOPATH/bin/operator-sdk` 文件位于您的 `$PATH` 目录下。 52 | 53 | ## 创建项目 54 | 55 | ```bash 56 | $ cd $GOPATH/src/github.com// 57 | $ operator-sdk new --api-version=/ --kind= 58 | $ cd 59 | ``` 60 | 61 | - operator-project-name:创建的项目的名称 62 | - your-api-group:Kubernetes 自定义 API 的组名,一般用域名如 `jimmysong.io` 63 | - version:Kubernetes 自定义资源的 API 版本 64 | - custom-resource-kind:CRD 的名称 65 | 66 | ```bash 67 | operator-sdk new kubernetes-operator-sdk-tutorial --api-version=jimmysong.io/v1alpha1 --kind=operator-sdk 68 | ``` 69 | 70 | ## 参考 71 | 72 | - [A complete guide to Kubernetes Operator SDK](https://banzaicloud.com/blog/operator-sdk/) 73 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/03~集群资源管理/24.Label.md: -------------------------------------------------------------------------------- 1 | # Label 2 | 3 | Label 是附着到 object 上(例如 Pod)的键值对。可以在创建 object 的时候指定,也可以在 object 创建后随时指定。Labels 的值对系统本身并没有什么含义,只是对用户才有意义。 4 | 5 | ```json 6 | "labels": { 7 | "key1" : "value1", 8 | "key2" : "value2" 9 | } 10 | ``` 11 | 12 | Kubernetes 最终将对 labels 最终索引和反向索引用来优化查询和 watch,在 UI 和命令行中会对它们排序。不要在 label 中使用大型、非标识的结构化数据,记录这样的数据应该用 annotation。 13 | 14 | ## 动机 15 | 16 | Label 能够将组织架构映射到系统架构上(就像是康威定律),这样能够更便于微服务的管理,你可以给 object 打上如下类型的 label: 17 | 18 | - `"release" : "stable"`, `"release" : "canary"` 19 | - `"environment" : "dev"`, `"environment" : "qa"`, `"environment" : "production"` 20 | - `"tier" : "frontend"`, `"tier" : "backend"`, `"tier" : "cache"` 21 | - `"partition" : "customerA"`, `"partition" : "customerB"` 22 | - `"track" : "daily"`, `"track" : "weekly"` 23 | - `"team" : "teamA"`,`"team:" : "teamB"` 24 | 25 | ## 语法和字符集 26 | 27 | Label key 的组成: 28 | 29 | - 不得超过 63 个字符 30 | - 可以使用前缀,使用 / 分隔,前缀必须是 DNS 子域,不得超过 253 个字符,系统中的自动化组件创建的 label 必须指定前缀,`kubernetes.io/` 由 kubernetes 保留 31 | - 起始必须是字母(大小写都可以)或数字,中间可以有连字符、下划线和点 32 | 33 | Label value 的组成: 34 | 35 | - 不得超过 63 个字符 36 | - 起始必须是字母(大小写都可以)或数字,中间可以有连字符、下划线和点 37 | 38 | ## Label selector 39 | 40 | Label 不是唯一的,很多 object 可能有相同的 label。 41 | 42 | 通过 label selector,客户端/用户可以指定一个 object 集合,通过 label selector 对 object 的集合进行操作。 43 | 44 | Label selector 有两种类型: 45 | 46 | - equality-based :可以使用 `=`、`==`、`!=` 操作符,可以使用逗号分隔多个表达式 47 | - set-based :可以使用 `in`、`notin`、`!` 操作符,另外还可以没有操作符,直接写出某个 label 的 key,表示过滤有某个 key 的 object 而不管该 key 的 value 是何值,`!` 表示没有该 label 的 object 48 | 49 | ## 示例 50 | 51 | ```bash 52 | $ kubectl get pods -l environment=production,tier=frontend 53 | $ kubectl get pods -l 'environment in (production),tier in (frontend)' 54 | $ kubectl get pods -l 'environment in (production, qa)' 55 | $ kubectl get pods -l 'environment,environment notin (frontend)' 56 | ``` 57 | 58 | ## 在 API object 中设置 label selector 59 | 60 | 在 `service`、`replicationcontroller` 等 object 中有对 pod 的 label selector,使用方法只能使用等于操作,例如: 61 | 62 | ```yaml 63 | selector: 64 | component: redis 65 | ``` 66 | 67 | 在 `Job`、`Deployment`、`ReplicaSet` 和 `DaemonSet` 这些 object 中,支持 _set-based_ 的过滤,例如: 68 | 69 | ```yaml 70 | selector: 71 | matchLabels: 72 | component: redis 73 | matchExpressions: 74 | - { key: tier, operator: In, values: [cache] } 75 | - { key: environment, operator: NotIn, values: [dev] } 76 | ``` 77 | 78 | 如 Service 通过 label selector 将同一类型的 pod 作为一个服务 expose 出来。 79 | 80 | ![Label示意图](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/labels.png "Label 示意图") 81 | 82 | 另外在 node affinity 和 pod affinity 中的 label selector 的语法又有些许不同,示例如下: 83 | 84 | ```yaml 85 | affinity: 86 | nodeAffinity: 87 | requiredDuringSchedulingIgnoredDuringExecution: 88 | nodeSelectorTerms: 89 | - matchExpressions: 90 | - key: kubernetes.io/e2e-az-name 91 | operator: In 92 | values: 93 | - e2e-az1 94 | - e2e-az2 95 | preferredDuringSchedulingIgnoredDuringExecution: 96 | - weight: 1 97 | preference: 98 | matchExpressions: 99 | - key: another-node-label-key 100 | operator: In 101 | values: 102 | - another-node-label-value 103 | ``` 104 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/05~服务发现与路由/40.拓扑感知路由.md: -------------------------------------------------------------------------------- 1 | # 拓扑感知路由 2 | 3 | [拓扑感知路由](https://kubernetes.io/zh/docs/concepts/services-networking/service-topology/)指的是客户端对一个服务的访问流量,可以根据这个服务的端点拓扑,优先路由到与该客户端在同一个节点或者可用区的端点上的路由行为。 4 | 5 | ## 先决条件 6 | 7 | 为了开启服务感知路由,你需要: 8 | 9 | - 开启 `TopologyAwareHints` 智能感知提示门控 10 | - 开启 EndpointSlice 控制器 11 | - 安装 kube-proxy 12 | 13 | ## 端点切片 14 | 15 | 我们知道 Endpoint 通常情况下是由 Service 资源自动创建和管理的,但是随着 Kubernetes 集群的规模越来越大和管理的服务越来越多,Endpoint API 的局限性变得越来越明显。[端点切片](https://kubernetes.io/zh/docs/concepts/services-networking/endpoint-slices/)(EndpointSlices)提供了一种简单的方法来跟踪 Kubernetes 集群中的网络端点。它们为 Endpoint 提供了一种可伸缩和可拓展的替代方案,同时还可以被用到拓扑感知路由中。 16 | 17 | EndpointSlices 示例如下: 18 | 19 | ```yaml 20 | apiVersion: discovery.k8s.io/v1 21 | kind: EndpointSlice 22 | metadata: 23 | name: example-hints 24 | labels: 25 | kubernetes.io/service-name: example-svc 26 | addressType: IPv4 27 | ports: 28 | - name: http 29 | protocol: TCP 30 | port: 80 31 | endpoints: 32 | - addresses: 33 | - "10.127.2.3" 34 | conditions: 35 | ready: true 36 | hostname: pod-1 37 | nodename: node-a 38 | zone: zone-a 39 | ``` 40 | 41 | EndpointSlice 中的每个端点都可以包含一定的拓扑信息。拓扑信息包括端点的位置,对应节点、可用区的信息。这些信息体现为 EndpointSlices 的如下端点字段: 42 | 43 | - `nodeName` - 端点所在的 Node 名称 44 | - `zone` - 端点所处的可用区 45 | - `hostname` - 端点的 pod 名称 46 | 47 | ## 启用拓扑感知 48 | 49 | 请启用 kube-apiserver、kube-controller-manager、和 kube-proxy 的[特性门控](https://kubernetes.io/zh/docs/reference/command-line-tools-reference/feature-gates/) `TopologyAwareHints`。通过把 Service 中的注解 `service.kubernetes.io/topology-aware-hints` 的值设置为 `auto`,来激活服务的拓扑感知提示功能。这告诉 EndpointSlice 控制器在它认为安全的时候来设置拓扑提示。kube-proxy 组件依据 EndpointSlice 控制器设置的提示,过滤由它负责路由的端点。 50 | 51 | 由 EndpointSlice 控制器提供提示信息后 EndpointSlice 的示例如下: 52 | 53 | ```yaml 54 | apiVersion: discovery.k8s.io/v1 55 | kind: EndpointSlice 56 | metadata: 57 | name: example-hints 58 | labels: 59 | kubernetes.io/service-name: example-svc 60 | addressType: IPv4 61 | ports: 62 | - name: http 63 | protocol: TCP 64 | port: 80 65 | endpoints: 66 | - addresses: 67 | - "10.1.2.3" 68 | conditions: 69 | ready: true 70 | hostname: pod-1 71 | zone: zone-a 72 | hints: 73 | forZones: 74 | - name: "zone-a" 75 | ``` 76 | 77 | 我们看到其中已注入了 `hints` 信息,对于上面这个示例,`zone-a` 的客户端访问会优先路由到该端点上。 78 | 79 | ## 管理 80 | 81 | 在大多数场合下,EndpointSlice 都由某个 Service 所有,因为端点切片正是为该服务跟踪记录其端点。这一属主关系是通过为每个 EndpointSlice 设置一个 属主(owner)引用,同时设置 `kubernetes.io/service-name` 标签来标明的,目的是方便查找隶属于某服务的所有 EndpointSlice。 82 | 83 | 控制面(尤其是端点切片的[控制器](https://kubernetes.io/zh/docs/concepts/architecture/controller/)) 会创建和管理 EndpointSlice 对象。EndpointSlice 对象还有一些其他使用场景,例如作为服务网格(Service Mesh)的实现。这些场景都会导致有其他实体 或者控制器负责管理额外的 EndpointSlice 集合。 84 | 85 | 为了确保多个实体可以管理 EndpointSlice 而且不会相互产生干扰,Kubernetes 定义了[标签](https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/labels/) `endpointslice.kubernetes.io/managed-by`,用来标明哪个实体在管理某个 EndpointSlice。端点切片控制器会在自己所管理的所有 EndpointSlice 上将该标签值设置 为 `endpointslice-controller.k8s.io`。管理 EndpointSlice 的其他实体也应该为此标签设置一个唯一值。 86 | 87 | ## 参考 88 | 89 | - [使用拓扑键实现拓扑感知的流量路由 - kubernetes.io](https://kubernetes.io/zh/docs/concepts/services-networking/service-topology/) 90 | - [端点切片 - kubernetes.io](https://kubernetes.io/zh/docs/concepts/services-networking/endpoint-slices/) 91 | - [拓扑感知提示 - kubernetes.io](https://kubernetes.io/zh/docs/concepts/services-networking/topology-aware-hints/) 92 | -------------------------------------------------------------------------------- /02~资源对象/04~身份与权限/命名空间/README.md: -------------------------------------------------------------------------------- 1 | # 命名空间 2 | 3 | Kubernetes 使用命名空间的概念帮助解决集群中在管理对象时的复杂性问题。命名空间允许将对象分组到一起,便于将它们作为一个单元进行筛选和控制。无论是应用自定义的访问控制策略,还是为了测试环境而分离所有组件,命名空间都是一个按照组来处理对象、强大且灵活的概念。 4 | 5 | # 命名空间定义 6 | 7 | 命名空间(namespace)是 Kubernetes 提供的组织机制,用于给集群中的任何对象组进行分类、筛选和管理。每一个添加到 Kubernetes 集群的工作负载必须放在一个命名空间中。命名空间为集群中的对象名称赋予作用域。虽然在命名空间中名称必须是唯一的,但是相同的名称可以在不同的命名空间中使用。这对于某些场景来说可能帮助很大。例如,如果使用命名空间来划分应用程序生命周期环境(如开发、staging、生产),则可以在每个环境中维护利用同样的名称维护相同对象的副本。 8 | 9 | 命名空间还可以让用户轻松地将策略应用到集群的具体部分。你可以通过定义 ResourceQuota 对象来控制资源的使用,该对象在每个命名空间的基础上设置了使用资源的限制。类似地,当在集群上使用支持网络策略的 CNI(容器网络接口)时,比如 Calico 或 Canal(calico 用于策略,flannel 用于网络)。你可以将 NetworkPolicy 应用到命名空间,其中的规则定义了 pod 之间如何彼此通信。不同的命名空间可以有不同的策略。 10 | 11 | 使用命名空间最大的好处之一是能够利用 Kubernetes RBAC(基于角色的访问控制)。RBAC 允许您在单个名称下开发角色,这样将权限或功能列表分组。ClusterRole 对象用于定义集群规模的使用模式,而角色对象类型(Role object type)应用于具体的命名空间,从而提供更好的控制和粒度。在角色创建后,RoleBinding 可以将定义的功能授予单个命名空间上下文中的具体具体用户或用户组。通过这种方式,命名空间可以使得集群操作者能够将相同的策略映射到组织好的资源集合。 12 | 13 | ## 预置的命名空间 14 | 15 | 在默认情况下,新的集群上有三个命名空间: 16 | 17 | - default:向集群中添加对象而不提供命名空间,这样它会被放入默认的命名空间中。在创建替代的命名空间之前,该命名空间会充当用户新添加资源的主要目的地,无法删除。 18 | 19 | - kube-public:kube-public 命名空间的目的是让所有具有或不具有身份验证的用户都能全局可读。这对于公开 bootstrap 组件所需的集群信息非常有用。它主要是由 Kubernetes 自己管理。 20 | 21 | - kube-system:kube-system 命名空间用于 Kubernetes 管理的 Kubernetes 组件,一般规则是,避免向该命名空间添加普通的工作负载。它一般由系统直接管理,因此具有相对宽松的策略。 22 | 23 | 虽然这些命名空间有效地将用户工作负载与系统管理的工作负载隔离,但它们并不强制使用任何额外的结构对应用程序进行分类和管理。比较友好的是,创建和使用额外的命名空间非常简单 24 | 25 | # 命名空间的使用 26 | 27 | 我们可以通过资源文件的方式来定义命名空间: 28 | 29 | ```json 30 | // kubectl create -f https://k8s.io/examples/admin/namespace-dev.json 31 | { 32 | "apiVersion": "v1", 33 | "kind": "Namespace", 34 | "metadata": { 35 | "name": "development", 36 | "labels": { 37 | "name": "development" 38 | } 39 | } 40 | } 41 | 42 | // kubectl create -f https://k8s.io/examples/admin/namespace-prod.json 43 | { 44 | "apiVersion": "v1", 45 | "kind": "Namespace", 46 | "metadata": { 47 | "name": "production", 48 | "labels": { 49 | "name": "production" 50 | } 51 | } 52 | } 53 | ``` 54 | 55 | ```sh 56 | # 查看命名空间 57 | $ kubectl get namespaces 58 | 59 | NAME STATUS AGE 60 | default Active 1d 61 | kube-system Active 1d 62 | kube-public Active 1d 63 | 64 | # 设置命名空间 65 | $ kubectl run nginx --image=nginx --namespace= 66 | $ kubectl get pods --namespace= 67 | 68 | # 设置默认的命名空间 69 | $ kubectl config set-context --current --namespace= 70 | # Validate it 71 | $ kubectl config view --minify | grep namespace: 72 | ``` 73 | 74 | # 命名空间使用模式 75 | 76 | 命名空间是一种非常灵活的特性,它不强制使用特定的结构或组织模式。不过尽管如此,还是有许多在团队内常使用的模式。 77 | 78 | ## 将命名空间映射到团队或项目上 79 | 80 | 在设置命名空间时有一个惯例是,为每个单独的项目或者团队创建一个命名空间。这和我们前面提到的许多命名空间的特性很好的结合在了一起。 81 | 82 | 通过给团队提供专门的命名空间,你可以用 RBAC 策略委托某些功能来实现自我管理和自动化。比如从命名空间的 RoleBinding 对象中添加或删除成员就是对团队资源访问的一种简单方法。除此之外,给团队和项目设置资源配额也非常有用。有了这种方式,你可以根据组织的业务需求和优先级合理地访问资源。 83 | 84 | ## 使用命名空间对生命周期环境进行分区 85 | 86 | 命名空间非常适合在集群中划分开发、staging 以及生产环境。通常情况下我们会被建议将生产工作负载部署到一个完全独立的集群中,来确保最大程度的隔离。不过对于较小的团队和项目来说,命名空间会是一个可行的解决方案。 87 | 88 | 和前面的用例一样,网络策略、RBAC 策略以及配额是实现用例的重要因素。在管理环境时,通过将网络隔离来控制和组件之间的通信能力是很有必要的。同样,命名空间范围的 RBAC 策略允许运维人员为生产环节设置严格的权限。配额能够确保对最敏感环境的重要资源的访问。 89 | 90 | 重新使用对象名称的能力在这里很有帮助。在测试和发布对象时,可以把它们放到新环境中,同时保留其命名空间。这样可以避免因为环境中出现相似的对象而产生的混淆,并且减少认知开销。 91 | 92 | ## 使用命名空间隔离不同的使用者 93 | 94 | 另一个命名空间可以解决的用例是根据使用者对工作负载进行分段。比如,如果你的集群为多个客户提供基础设施,那么按命名空间进行分段就能够实现管理每个客户,同时跟踪账单的去向。 95 | 96 | 另外,命名空间的特性可以让你控制网络和访问策略,为你的使用者定义不同的配额。在通用的情况下,命名空间允许你为每个用户开发和部署相同模板化环境的不同实例。这种一致性可以大大简化管理和故障诊断的过程。 97 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/06~身份与权限认证/spiffe.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 47 3 | title: SPIFFE 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | SPIFFE,即普适安全生产身份框架(Secure Production Identity Framework for Everyone),是一套开源标准,用于在动态和异构环境中安全地进行身份识别。采用 SPIFFE 的系统无论在哪里运行,都可以轻松可靠地相互认证。 9 | 10 | SPIFFE 开源规范的核心是——通过简单 API 定义了一个短期的加密身份文件 SVID。然后,工作负载进行认证时可以使用该身份文件,例如建立 TLS 连接或签署和验证 JWT 令牌等。 11 | 12 | SPIFFE 已经在云原生应用中得到了大量的应用,尤其是在 Istio 和 Envoy 中。下面将向你介绍 SPIFFE 的一些基本概念。 13 | 14 | ## 工作负载 15 | 16 | 工作负载是个单一的软件,以特定的配置部署,用于单一目的;它可能包括软件的多个运行实例,所有这些实例执行相同的任务。工作负载这个术语可以包含一系列不同的软件系统定义,包括: 17 | 18 | - 一个运行 Python 网络应用程序的网络服务器,在一个虚拟机集群上运行,前面有一个负载均衡器。 19 | - 一个 MySQL 数据库的实例。 20 | - 一个处理队列中项目的 worker 程序。 21 | - 独立部署的系统的集合,它们一起工作,例如一个使用数据库服务的网络应用程序。网络应用程序和数据库也可以单独被视为工作负载。 22 | 23 | 就 SPIFFE 而言,工作负载往往比物理或虚拟节点更加细化——通常细化到节点上的单个进程。这对工作负载来说至关重要,例如,在容器编排器中托管的工作负载,几个工作负载可能在同一个节点上(但彼此隔离)。 24 | 25 | 就 SPIFFE 而言,一个工作负载也可能跨越许多节点。例如,一个可弹性扩展的网络服务器可能同时运行在许多机器上。 26 | 27 | 虽然工作负载的粒度会因环境而异,但就 SPIFFE 而言,我们**假设**工作负载之间有足够好的隔离,这样恶意的工作负载就不能窃取他人的凭证。这种隔离的稳健性和实现的机制超出了 SPIFFE 的范围。 28 | 29 | ## SPIFFE ID 30 | 31 | SPIFFE ID 是一个字符串,可以唯一地、具体地标识一个工作负载。SPIFFE ID 也可以分配给工作负载所运行的中间系统(如一组虚拟机)。例如,`spiffe://acme.com/billing/payments` 是一个有效的SPIFFE ID。 32 | 33 | SPIFFE ID 是一个[统一资源标识符(URI](https://tools.ietf.org/html/rfc3986)),其格式如下:`spiffe://信任域/工作负载标识符`。 34 | 35 | **工作负载标识符**是一个[信任域](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#trust-domain)内的特定工作负载的唯一标识。 36 | 37 | [SPIFFE 规范](https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE.md)详细描述了 SPIFFE ID 的格式和使用。 38 | 39 | ## 信任域 40 | 41 | 信任域对应于系统的信任根。信任域可以代表个人、组织、环境或部门,运行他们自己独立的 SPIFFE 基础设施。在同一信任域中确定的所有工作负载都会被颁发身份文件,它们可以根据信任域的根密钥进行验证。 42 | 43 | 通常建议将处于不同物理位置(如不同的数据中心或云区域)或应用不同安全实践的环境(如与生产环境相比的暂存或实验环境)的工作负载放在不同的信任域中。 44 | 45 | ## SPIFFE 可验证的身份文件(SVID){#svid} 46 | 47 | SVID(SPIFFE Verifiable Identity Document) 是工作负载向资源或调用者证明其身份的文件。如果 SVID 是由 SPIFFE ID 的信任域内的机构签发的,则被认为是有效的。 48 | 49 | SVID 包含一个 SPIFFE ID,代表了服务的身份。它将 SPIFFE ID 编码在一个可加密验证的文件中,目前支持两种格式:X.509 证书或 JWT 令牌。 50 | 51 | 由于令牌容易受到**重放攻击(replay attack)**,即在传输过程中获得令牌的攻击者可以使用它来冒充工作负载,因此建议尽可能使用 `X.509-SVID`。然而,在某些情况下,JWT令牌格式是唯一的选择,例如,当你的架构在两个工作负载之间有一个L7代理或负载均衡器。 52 | 53 | 关于 SVID 的详细信息,请参阅 [SVID 规范](https://github.com/spiffe/spiffe/blob/main/standards/X509-SVID.md)。 54 | 55 | ## SPIFFE 工作负载 API 56 | 57 | 工作负载 API 提供以下内容。 58 | 59 | 对于`X.509`格式的身份文件(`X.509-SVID`): 60 | 61 | - 其身份,描述为 SPIFFE ID。 62 | - 一个与该 ID 绑定的私钥,可用于代表工作负载签署数据。一个相应的短期 X.509 证书也将被创建,即 `X509-SVID`。这可以用来建立 TLS 或以其他方式对其他工作负载进行认证。 63 | - 一组证书——被称为[信任包](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#trust-bundle)。一个工作负载用来验证另一个工作负载提出的`X.509-SVID`。 64 | 65 | 对于 JWT 格式的身份文件(JWT-SVID): 66 | 67 | - 其身份,描述为 SPIFFE ID 68 | - JWT 令牌 69 | - 一组证书——被称为[信任包](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#trust-bundle),一个工作负载用来验证其他工作负载的身份。 70 | 71 | 与 [AWS EC2 实例元数据 API](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)和 [Google GCE 实例元数据 API](https://cloud.google.com/compute/docs/storing-retrieving-metadata) 类似,工作负载 API 不要求调用的工作负载对自己的身份有任何了解,也不要求调用 API 时拥有任何认证令牌。这意味着你的应用程序不需要与工作负载共同部署任何认证密钥。 72 | 73 | 然而,与这些其他 API 不同的是,Workload API 与平台无关,可以在进程级和内核级识别正在运行的服务,这使得它适合与 Kubernetes 等容器调度器一起使用。 74 | 75 | 为了最大限度地减少密钥泄露的风险,所有私钥(和相应的证书)都是短期的,经常自动轮换。工作负载可以在相应的密钥过期前从工作负载API请求新的密钥和信任包。 76 | 77 | ## 信任包 78 | 79 | 当使用 `X.509-SVID` 时,目标工作负载使用信任包(Trust Bundle)来验证源工作负载的身份。信任包是一个或多个证书机构(CA)根证书的集合,工作负载认为这些证书是可信的。信任包包含 X.509 和 JWT SVID 的公钥材料。 80 | 81 | 用来验证 X.509 SVID 的公钥材料是一组证书。用于验证 JWT 的公钥材料是一个原始公钥。信任包的内容是经常轮换的。工作负载在调用工作负载 API 时检索信任包。 82 | 83 | ## 参考 84 | 85 | - [SPIFFE 官网 - spiffe.io](https://spiffe.io) 86 | -------------------------------------------------------------------------------- /00~概念与架构/03~集群组件.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 集群组件 2 | 3 | ![K8s 集群主从架构](https://s2.ax1x.com/2020/01/04/ld7zdg.png) 4 | 5 | ## Master Components 6 | 7 | Kubernetes 主要由以下几个核心组件组成: 8 | 9 | - etcd:是高可用的 key/value 存储系统,用于持久化存储集群中的所有资源对象,比如:Node,Pod,Serivce,RC,namespace 等。API server 提供了操作 etcd 的封装接口 API,以 Rest 的方式提供,这些 API 基本上都是集群中资源对象的增删改查及监听资源变化的接口,比如创建 Pod、RC,监听 Pod 的变化等接口。API server 是连接其他所有服务组件的中间枢纽。 10 | 11 | - kube-apiserver:提供了资源对象的唯一操作入口,其他组件都必须通过它提供的 API 来操作资源数据,通过对相关的资源数据全量查询与变化监听,这些组件可以近乎实时地完成相关的业务功能。比如提交一个新的 Pod 到 kube-apiserve 中,kube-controller-manger 可以立即就发现并开始作用。它还有一套完备的安全机制,包括认证、授权及准入控制等相关模块。 12 | 13 | - kube-controller-manger:集群内部的管理控制中心,主要完成了集群的故障检测和恢复的自动化工作。比如对 RC 定义的 Pod 进行维护;根据 Service 和 Pod 的关系,完成服务的 Endpoints 对象的创建和更新;还有 Node 的发现、管理和状态监控,死亡容器所占资源及本地缓存的镜像文件的清理等工作。 14 | 15 | - kube-scheduler: 集群的调度器,负责 Pod 在集群节点中的调度分配,也负责 Volume(CVI)和网络(CNI)的管理,按照预定的调度策略将 Pod 调度到相应的机器上; 16 | 17 | ## Node Components 18 | 19 | - kubelet:负责本地节点上 Pod 的创建、修改、监控、删除等生命周期管理,同时会上报本 Node 的状态信息到 API server。 20 | 21 | - kube-proxy:实现 Service 的代理及软件模式的负载均衡器。 22 | 23 | - kubectl:集群内部的客户端可以直接使用 kubectl 命令管理集群;集群外的客户端需要使用 kubectl Porxy 进行反向代理来访问 API server。 24 | 25 | - cAdvisor: 在 Node 节点运行的 kubectl 服务中内嵌了一个 cAdvisor 服务,cAdvisor 是谷歌的开源项目,用于实时监控 Docker 上运行的容器的性能指标。 26 | 27 | # 组件通信 28 | 29 | Kubernetes 多组件之间的通信原理为 apiserver 负责 etcd 存储的所有操作,且只有 apiserver 才直接操作 etcd 集群。apiserver 对内(集群中的其他组件)和对外(用户)提供统一的 REST API,其他组件均通过 apiserver 进行通信。controller manager、scheduler、kube-proxy 和 kubelet 等均通过 apiserver watch API 监测资源变化情况,并对资源作相应的操作。所有需要更新资源状态的操作均通过 apiserver 的 REST API 进行。apiserver 也会直接调用 kubelet API(如 logs, exec, attach 等),默认不校验 kubelet 证书,但可以通过 `--kubelet-certificate-authority` 开启(而 GKE 通过 SSH 隧道保护 它们之间的通信)。 30 | 31 | 比如典型的创建 Pod 的流程为: 32 | 33 | ![Pod 创建流程](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230417214531.png) 34 | 35 | 用户通过 REST API 创建一个 Pod,apiserver 将其写入 etcd。scheduluer 检测到未绑定 Node 的 Pod,开始调度并更新 Pod 的 Node 绑定,kubelet 检测到有新的 Pod 调度过来,通过 container runtime 运行该 Pod,kubelet 通过 container runtime 取到 Pod 状态,并更新到 apiserver 中。 36 | 37 | # 使用的端口号 38 | 39 | ![端口之间数据流动](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230510134825.png) 40 | 41 | ## Master node(s) 42 | 43 | | Protocol | Direction | Port Range | Purpose | 44 | | -------- | --------- | ---------- | -------------------------------- | 45 | | TCP | Inbound | `6443*` | Kubernetes API server | 46 | | TCP | Inbound | 8080 | Kubernetes API insecure server | 47 | | TCP | Inbound | 2379-2380 | etcd server client API | 48 | | TCP | Inbound | 10250 | Kubelet API | 49 | | TCP | Inbound | 10251 | kube-scheduler healthz | 50 | | TCP | Inbound | 10252 | kube-controller-manager healthz | 51 | | TCP | Inbound | 10253 | cloud-controller-manager healthz | 52 | | TCP | Inbound | 10255 | Read-only Kubelet API | 53 | | TCP | Inbound | 10256 | kube-proxy healthz | 54 | 55 | ## Worker node(s) 56 | 57 | | Protocol | Direction | Port Range | Purpose | 58 | | -------- | --------- | ----------- | --------------------- | 59 | | TCP | Inbound | 4194 | Kubelet cAdvisor | 60 | | TCP | Inbound | 10248 | Kubelet healthz | 61 | | TCP | Inbound | 10249 | kube-proxy metrics | 62 | | TCP | Inbound | 10250 | Kubelet API | 63 | | TCP | Inbound | 10255 | Read-only Kubelet API | 64 | | TCP | Inbound | 10256 | kube-proxy healthz | 65 | | TCP | Inbound | 30000-32767 | NodePort `Services**` | 66 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/01~Kubernetes 架构/05~Etcd 解析.md: -------------------------------------------------------------------------------- 1 | # Etcd 解析 2 | 3 | Etcd 是 Kubernetes 集群中的一个十分重要的组件,用于保存集群所有的网络配置和对象的状态信息。在后面具体的安装环境中,我们安装的 etcd 的版本是 v3.1.5,整个 Kubernetes 系统中一共有两个服务需要用到 etcd 用来协同和存储配置,分别是: 4 | 5 | - 网络插件 flannel、对于其它网络插件也需要用到 etcd 存储网络的配置信息 6 | - Kubernetes 本身,包括各种对象的状态和元信息配置 7 | 8 | **注意**:flannel 操作 etcd 使用的是 v2 的 API,而 Kubernetes 操作 etcd 使用的 v3 的 API,所以在下面我们执行 `etcdctl` 的时候需要设置 `ETCDCTL_API` 环境变量,该变量默认值为 2。 9 | 10 | ## 原理 11 | 12 | Etcd 使用的是 raft 一致性算法来实现的,是一款分布式的一致性 KV 存储,主要用于共享配置和服务发现。关于 raft 一致性算法请参考 [该动画演示](http://thesecretlivesofdata.com/raft/)。 13 | 14 | 关于 Etcd 的原理解析请参考 [Etcd 架构与实现解析](http://jolestar.com/etcd-architecture/)。 15 | 16 | ## 使用 Etcd 存储 Flannel 网络信息 17 | 18 | 我们在安装 Flannel 的时候配置了 `FLANNEL_ETCD_PREFIX="/kube-centos/network"` 参数,这是 Flannel 查询 etcd 的目录地址。 19 | 20 | 查看 Etcd 中存储的 flannel 网络信息: 21 | 22 | ````ini 23 | $ etcdctl --ca-file=/etc/kubernetes/ssl/ca.pem --cert-file=/etc/kubernetes/ssl/kubernetes.pem --key-file=/etc/kubernetes/ssl/kubernetes-key.pem ls /kube-centos/network -r 24 | 2018-01-19 18:38:22.768145 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated 25 | /kube-centos/network/config 26 | /kube-centos/network/subnets 27 | /kube-centos/network/subnets/172.30.31.0-24 28 | /kube-centos/network/subnets/172.30.20.0-24 29 | /kube-centos/network/subnets/172.30.23.0-24 30 | ```查看 flannel 的配置:```bash 31 | $ etcdctl --ca-file=/etc/kubernetes/ssl/ca.pem --cert-file=/etc/kubernetes/ssl/kubernetes.pem --key-file=/etc/kubernetes/ssl/kubernetes-key.pem get /kube-centos/network/config 32 | 2018-01-19 18:38:22.768145 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated 33 | {"Network": "172.30.0.0/16", "SubnetLen": 24, "Backend": { "Type": "host-gw"} } 34 | ```` 35 | 36 | ## 使用 Etcd 存储 Kubernetes 对象信息 37 | 38 | Kubernetes 使用 etcd v3 的 API 操作 etcd 中的数据。所有的资源对象都保存在 `/registry` 路径下,如下: 39 | 40 | ```ini 41 | ThirdPartyResourceData 42 | apiextensions.k8s.io 43 | apiregistration.k8s.io 44 | certificatesigningrequests 45 | clusterrolebindings 46 | clusterroles 47 | configmaps 48 | controllerrevisions 49 | controllers 50 | daemonsets 51 | deployments 52 | events 53 | horizontalpodautoscalers 54 | ingress 55 | limitranges 56 | minions 57 | monitoring.coreos.com 58 | namespaces 59 | persistentvolumeclaims 60 | persistentvolumes 61 | poddisruptionbudgets 62 | pods 63 | ranges 64 | replicasets 65 | resourcequotas 66 | rolebindings 67 | roles 68 | secrets 69 | serviceaccounts 70 | services 71 | statefulsets 72 | storageclasses 73 | thirdpartyresources 74 | ``` 75 | 76 | 如果你还创建了 CRD(自定义资源定义),则在此会出现 CRD 的 API。 77 | 78 | ### 查看集群中所有的 Pod 信息 79 | 80 | 例如我们直接从 etcd 中查看 kubernetes 集群中所有的 pod 的信息,可以使用下面的命令: 81 | 82 | ```bash 83 | ETCDCTL_API=3 etcdctl get /registry/pods --prefix -w json|python -m json.tool 84 | ``` 85 | 86 | 此时将看到 json 格式输出的结果,其中的`key`使用了`base64` 编码,关于 etcdctl 命令的详细用法请参考 [使用 etcdctl 访问 kubernetes 数据](../../guide/using-etcdctl-to-access-kubernetes-data/)。 87 | 88 | ## Etcd V2 与 V3 版本 API 的区别 89 | 90 | Etcd V2 和 V3 之间的数据结构完全不同,互不兼容,也就是说使用 V2 版本的 API 创建的数据只能使用 V2 的 API 访问,V3 的版本的 API 创建的数据只能使用 V3 的 API 访问。这就造成我们访问 etcd 中保存的 flannel 的数据需要使用 `etcdctl` 的 V2 版本的客户端,而访问 kubernetes 的数据需要设置 `ETCDCTL_API=3` 环境变量来指定 V3 版本的 API。 91 | 92 | ## Etcd 数据备份 93 | 94 | 我们安装的时候指定的 Etcd 数据的存储路径是 `/var/lib/etcd`,一定要对该目录做好备份。 95 | 96 | ## 参考 97 | 98 | - [etcd 官方文档 - etcd.io](https://etcd.io/) 99 | - [etcd v3 命令和 API - blog.csdn.net](http://blog.csdn.net/u010278923/article/details/71727682) 100 | - [Etcd 架构与实现解析 - jolestar.com](http://jolestar.com/etcd-architecture/) 101 | -------------------------------------------------------------------------------- /03~工程实践/高可用集群/调度和驱逐/调度架构.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 调度架构 2 | 3 | # 调度单元 4 | 5 | ## Pod 调度 6 | 7 | 当新增一个 Pod 时,集群会在可用的集群节点中寻找最合适的节点来运行相应的容器。Kubernetes 首先会排除无效节点: 8 | 9 | - 节点状态为不可用的,如,节点不通或者 K8s 服务运行异常等; 10 | - 节点剩余的 CPU,内存资源不足以运行容器的; 11 | - 容器运行时占用的宿主机端口出现冲突的; 12 | - 按照节点选择 label 不匹配的; 13 | 14 | Pod.spec.nodeSelector 通过 kubernetes 的 label-selector 机制选择节点,由调度器调度策略匹配 label,而后调度 pod 到目标节点,该匹配规则属于强制约束。 15 | 16 | 然后通过打分机制决定将 Pod 具体调度到剩余机器中的那一台,默认调度节点选择策略权重为 1,节点的调度规则是采用 plugin 方式,允许自行编写调度策略进行打分处理。 17 | 18 | ```sh 19 | # 标准打分公式 20 | score = (权重 * 评价策略分值) + (weight1 * priorityFunc1) + (weight2 * priorityFunc2) + ... 21 | 22 | # LeastRequestedPriority 23 | score = cpu((capacity - sum(requested)) * 10 / capacity) + memory((capacity - sum(requested)) * 10 / capacity) /2 24 | 25 | # BalanceResourceAllocation 26 | score = 10 -abs (cpuFraction - memoryFraction) * 10 27 | cpuFraction = requested / capacity; memoryFraction = requested / capacity 28 | 29 | # CalculateSpreadPriority 30 | score = 10 * ((maxCount -counts) / (maxCount)) 31 | ``` 32 | 33 | - LeastRequestedPriority: CPU 可用资源为 100,运行容器申请的资源为 15,则 cpu 分值为 8.5 分,内存可用资源为 100,运行容器申请资源为 20,则内存分支为 8 分。则此评价规则在此节点的分数为(8.5 +8) / 2 = 8.25 分。 34 | 35 | - BalanceResourceAllocation: CPU 可用资源为 100,申请 10,则 cpuFraction 为 0.1,而内存可用资源为 20,申请 10,则 memoryFraction 为 0.5,这样由于 CPU 和内存使用不均衡,此节点的得分为 10-abs ( 0.1 - 0.5 ) \* 10 = 6 分。假如 CPU 和内存资源比较均衡,例如两者都为 0.5,那么代入公式,则得分为 10 分。 36 | 37 | - CalculateSpreadPriority: 一个 web 服务,可能存在 5 个实例,例如当前节点已经分配了 2 个实例了,则本节点的得分为 10 _ ((5-2) / 5) = 6 分,而没有分配实例的节点,则得分为 10 _ ((5-0) / 5) = 10 分。没有分配实例的节点得分越高。 38 | 39 | # 资源保障 40 | 41 | 目前,Kubernetes 只支持 CPU 和 Memory 两种资源的申请,Kubernetes 中,根据应用对资源的诉求不同,把应用的 QoS 按照优先级从高到低分为三大类:Guaranteed, Burstable 和 Best-Effort。三种类别分别表示资源配额必须交付、尽量交付以及不保障。QoS 等级是通过 resources 的 limits 和 requests 参数间接计算出来的。CPU 为可压缩资源,Node 上的所有 Pods 共享 CPU 时间片,原理是通过设置 cpu.cfs_quota_us 和 cpu.cfs_period_us 实现,一个 CPU 逻辑核嘀嗒时间被切了 N 份,只要按照百分比例设置 cpu.cfs_quota_us 的值就可以实现 CPU 时间片的比例分配,如设置 2N 表示利用两个 CPU 逻辑核的时间。Memory 为不可压缩资源,kubernetes 中主要利用 memory.limit_in_bytes 实现内存的限制。当应用内存超过了它的 limits,那么会被系统 OOM。内存是不可压缩资源,它的保障的机制最为复杂,kubernetes 利用内核 oom_score 机制,实现了对 Pod 容器内(进程)内存 oom kill 的优先级管控,内核中 OOM Score 的取值范围是[-1000, 1000],值越大,被系统 KILL 的概率就越高。 42 | 43 | ## Guaranteed 44 | 45 | 如果 Pod 中每一个容器都只设置了 limits 参数,或者 同时设置了 limits 和 requests 并且 limits 和 requests 的值一样,那么这个 Pod 就是 Guaranteed 类型的。 46 | 47 | ```yaml 48 | containers: 49 | name: foo 50 | resources: 51 | limits: //只设置了limits 52 | cpu: 10m 53 | memory: 1Gi 54 | name: bar 55 | resources: 56 | limits: 57 | cpu: 100m 58 | memory: 100Mi 59 | requests: //requests 和 limits均已设定,并且值相同 60 | cpu: 100m 61 | memory: 100Mi 62 | ``` 63 | 64 | ## Burstable 65 | 66 | 当以下情形设置,Pod 会为定位成 Burstable 类型, Busrtable 类型保障了资源的最小需求,但不会超过`limits`。 67 | 68 | - Pod 里的一个或多个容器只设置了`requests`参数。 69 | - Pod 里的一个或多个容器同时设置了`requests`和`limits`参数,但是两者值不一样。 70 | - Pod 里的所有容器均设置了`limits`,但是他们的类型不一样,不如容器 1 只定义了 CPU,容器 2 只定义了 Memory。 71 | - Pod 里存在多个容器时,其中存在容器可被定义为 Bustable 条件的 Pod 也是 Bustable 类型,比如有两个容器,容器 1 设置了`limits`,容器 2 没有任何设置。 72 | 73 | ```yaml 74 | containers: 75 | name: foo 76 | resources: 77 | limits: 78 | memory: 1Gi 79 | 80 | name: bar 81 | resources: 82 | limits: 83 | cpu: 100m 84 | 85 | name: duck 86 | ``` 87 | 88 | ## BestEffort 89 | 90 | 当 Pod 中所有的容器均没设置 requests 和 limits,那么这个 Pod 即为 BestEffort 类型,他们可消费所在 Node 上所有资源,但在资源紧张的时候,也是最优先被杀死。 91 | 92 | ```yaml 93 | containers: 94 | name: foo 95 | resources: 96 | name: bar 97 | resources: 98 | ``` 99 | 100 | # Links 101 | 102 | - https://yq.aliyun.com/articles/689495?utm_content=g_1000040917# 103 | -------------------------------------------------------------------------------- /01~应用部署/01~安装配置/集群/Rancher 搭建集群.md: -------------------------------------------------------------------------------- 1 | # 使用 Rancher 部署 K8S 集群 2 | 3 | 使用 Rancher 可以自动和可视化的完成 Kubernetes 集群的安装工作,省去的繁琐的人工安装过程,然您快速投入的业务开发中。 4 | 5 | # 准备 6 | 7 | 要想使用阿里云 ECS 和 Rancher 直接搭建一套 Kubernetes 集群,需要准备以下条件: 8 | 9 | - 开通了公网 IP 的 ECS 10 | - ECS 规格建议至少 4C8G 11 | - ECS 使用的阿里云的经典网络 12 | - 为 ECS 设置安全组规则,开放 UDP/8472 端口(阿里云默认禁止了 UDP,我们使用的 flannel 网络插件的 VXLAN 模式,需要将 ECS 的安全组设置 UDP/8472 端口开放) 13 | 14 | # 步骤 15 | 16 | 假设现在我们有两个节点 master 和 node,请参考 [Rancher Quick Start Guide](https://rancher.com/docs/rancher/v2.x/en/quick-start-guide/deployment/quickstart-manual-setup/) 安装 Rancher。 17 | 18 | ```bash 19 | $ docker run -d --restart=unless-stopped -p 80:80 -p 443:443 rancher/rancher 20 | ``` 21 | 22 | ![](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230510134956.png) 23 | 24 | ## Master 25 | 26 | 先在 Master 节点安装 Rancher server、control、etcd 和 worker。选择网络组件为 Flannel,同时在自定义主机运行命令中选择主机角色、填写主机的内网和外网 IP。 27 | 28 | ![](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230510135015.png) 29 | 30 | 我们需要将脚本复制到对应的机器上运行,然后 Rancher 将自动创建 Kubernetes 集群,并默认在 80 端口运行 Web Server。 31 | 32 | ## Node 33 | 34 | 添加 Node 节点时只需要在 Rancher 的 Web 界面上找到您刚安装的集群并选择【编辑集群】并选择节点角色为 Worker 即可增加一台 Kubenretes 集群节点。 35 | 36 | # 集群交互 37 | 38 | 安装完毕后,可以查看到当前节点的状态信息: 39 | 40 | ![](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230510134928.png) 41 | 42 | 如果您习惯使用命令行与集群交互可以 Rancher 的 web 上找到集群首页上的 `Kubeconfig File` 下载按钮,将该文件中的内容保存到您自己电脑的 `~/.kube/config` 文件中。然后现在对应 Kubernetes 版本的 `kubectl` 命令并放到 `PATH` 路径下即可。如果您没有在本地安装 `kubectl` 工具,也可以通过 Rancher 的集群页面上的 `Launch kubectl` 命令通过 web 来操作集群。 43 | 44 | # Helm 45 | 46 | Helm 是由 Deis 发起的一个开源工具,有助于简化部署和管理 Kubernetes 应用。在本章的实践中,我们也会使用 Helm 来简化很多应用的安装操作。 47 | 48 | ![](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/item/20230510134909.png) 49 | 50 | 在 Linux 中可以使用 Snap 安装 Heml: 51 | 52 | ```sh 53 | $ sudo snap install helm --classic 54 | 55 | # 通过键入如下命令,在 Kubernetes 群集上安装 Tiller 56 | $ helm init --upgrade 57 | ``` 58 | 59 | 在缺省配置下,Helm 会利用 "gcr.io/kubernetes-helm/tiller" 镜像在 Kubernetes 集群上安装配置 Tiller;并且利用 "https://kubernetes-charts.storage.googleapis.com" 作为缺省的 stable repository 的地址。由于在国内可能无法访问 "gcr.io", "storage.googleapis.com" 等域名,阿里云容器服务为此提供了镜像站点。请执行如下命令利用阿里云的镜像来配置 Helm: 60 | 61 | ```sh 62 | $ helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.5.1 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 63 | 64 | # 删除默认的源 65 | $ helm repo remove stable 66 | 67 | # 设置 Helm 命令自动补全 68 | $ source <(helm completion zsh) 69 | $ source <(helm completion bash) 70 | 71 | # 增加新的国内镜像源 72 | $ helm repo add stable https://burdenbear.github.io/kube-charts-mirror/ 73 | $ helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 74 | 75 | # 查看 Helm 源添加情况 76 | $ helm repo list 77 | ``` 78 | 79 | Helm 的常见命令如下: 80 | 81 | ```sh 82 | # 查看在存储库中可用的所有 Helm Charts 83 | $ helm search 84 | 85 | # 更新 Charts 列表以获取最新版本 86 | $ helm repo update 87 | 88 | # 部署某个本地 Chart,指定命名空间与额外的配置文件 89 | $ helm install --namespace ufc --name ufc-dev -f ./deployment/ufc/dev-values.yaml ./charts/ufc/ 90 | 91 | # 查看某个 Chart 的变量 92 | $ helm inspect values stable/mysql 93 | 94 | # 查看在群集上安装的 Charts 列表 95 | $ helm list 96 | 97 | # 删除某个 Charts 的部署 98 | $ helm del --purge wordpress-test 99 | 100 | # 为 Tiller 部署添加授权 101 | $ kubectl create serviceaccount --namespace kube-system tiller 102 | $ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller 103 | $ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}' 104 | ``` 105 | 106 | # Links 107 | 108 | - https://blog.51cto.com/13941177/2165668 109 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/14~访问集群/service-access-application-cluster.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 95 3 | title: 使用 service 访问集群中的应用程序 4 | date: "2022-05-21T00:00:00+08:00" 5 | type: book 6 | --- 7 | 8 | 本文向您展示如何创建 Kubernetes Service 对象,外部客户端可以使用它来访问集群中运行的应用程序。该 Service 可以为具有两个运行实例的应用程序提供负载均衡。 9 | 10 | ## 目的 11 | 12 | - 运行 Hello World 应用程序的两个实例。 13 | - 创建一个暴露 node 节点端口的 Service 对象。 14 | - 使用 Service 对象访问正在运行的应用程序。 15 | 16 | ## 为在两个 pod 中运行的应用程序创建 service 17 | 18 | 1. 在集群中运行 Hello World 应用程序: 19 | 20 | ```bash 21 | kubectl run hello-world --replicas=2 --labels="run=load-balancer-example" --image=gcr.io/google-samples/node-hello:1.0 --port=8080 22 | ``` 23 | 24 | 上述命令创建一个 [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment) 对象和一个相关联的 [ReplicaSet](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset) 对象。该 ReplicaSet 有两个 [Pod](https://kubernetes.io/docs/concepts/workloads/pods/pod),每个 Pod 中都运行一个 Hello World 应用程序。 25 | 26 | 2. 显示关于该 Deployment 的信息: 27 | 28 | ```bash 29 | kubectl get deployments hello-world 30 | kubectl describe deployments hello-world 31 | ``` 32 | 33 | 3. 显示 ReplicaSet 的信息: 34 | 35 | ```bash 36 | kubectl get replicasets 37 | kubectl describe replicasets 38 | 39 | ``` 40 | 41 | 4. 创建一个暴露该 Deployment 的 Service 对象: 42 | 43 | ```bash 44 | kubectl expose deployment hello-world --type=NodePort --name=example-service 45 | ``` 46 | 47 | 5. 显示该 Service 的信息: 48 | 49 | ```bash 50 | kubectl describe services example-service 51 | ``` 52 | 53 | 输出类似于: 54 | 55 | ``` 56 | Name: example-service 57 | Namespace: default 58 | Labels: run=load-balancer-example 59 | Selector: run=load-balancer-example 60 | Type: NodePort 61 | IP: 10.32.0.16 62 | Port: 8080/TCP 63 | NodePort: 31496/TCP 64 | Endpoints: 10.200.1.4:8080,10.200.2.5:8080 65 | Session Affinity: None 66 | No events. 67 | ``` 68 | 69 | 记下服务的 NodePort 值。例如,在前面的输出中,NodePort 值为 31496。 70 | 71 | 6. 列出运行 Hello World 应用程序的 Pod: 72 | 73 | ```bash 74 | kubectl get pods --selector="run=load-balancer-example" --output=wide 75 | ``` 76 | 77 | 输出类似于: 78 | 79 | ``` 80 | NAME READY STATUS ... IP NODE 81 | hello-world-2895499144-bsbk5 1/1 Running ... 10.200.1.4 worker1 82 | hello-world-2895499144-m1pwt 1/1 Running ... 10.200.2.5 worker2 83 | ``` 84 | 85 | 7. 获取正在运行 Hello World 应用程序的 Pod 的其中一个节点的 public IP 地址。如何得到这个地址取决于您的集群设置。例如,如果您使用 Minikube,可以通过运行 `kubectl cluster-info` 查看节点地址。如果您是使用 Google Compute Engine 实例,可以使用 `gcloud compute instances list` 命令查看您的公共地址节点。 86 | 87 | 8. 在您选择的节点上,在您的节点端口上例如创建允许 TCP 流量的防火墙规则,如果您的服务 NodePort 值为 31568,创建防火墙规则,允许端口 31568 上的 TCP 流量。 88 | 89 | 9. 使用节点地址和节点端口访问 Hello World 应用程序: 90 | 91 | ```bash 92 | curl http://: 93 | ``` 94 | 95 | 其中 `` 是您节点的 public IP 地址,而 `` 是您服务的 NodePort 值。 96 | 97 | 对成功请求的响应是一个 hello 消息: 98 | 99 | ``` 100 | Hello Kubernetes! 101 | ``` 102 | 103 | ## 使用 Service 配置文件 104 | 105 | 作为使用 `kubectl expose` 的替代方法,您可以使用 [service 配置文件](https://kubernetes.io/docs/user-guide/services/operations) 来创建 Service。 106 | 107 | 要删除 Service,输入以下命令: 108 | 109 | ```bash 110 | kubectl delete services example-service 111 | ``` 112 | 113 | 删除 Deployment、ReplicaSet 和正运行在 Pod 中的 Hello World 应用程序,输入以下命令: 114 | 115 | ```bash 116 | kubectl delete deployment hello-world 117 | ``` 118 | 119 | 了解更多关于 [使用 service 连接应用程序](https://kubernetes.io/docs/concepts/services-networking/connect-applications-service)。 120 | -------------------------------------------------------------------------------- /02~资源对象/06~存储/README.md: -------------------------------------------------------------------------------- 1 | # K8s 存储 2 | 3 | 在 Kubernetes 集群中,虽然无状态的服务非常常见,但是在实际的生产中仍然会需要在集群中部署一些有状态的节点,比如一些存储中间件、消息队列等等。在 K8s 中通过 Pod 的概念将一组具有超亲密关系的容器组合到了一起形成了一个服务实例,为了保证一个 Pod 中某一个容器异常退出,被 kubelet 重建拉起旧容器产生的重要数据不丢,以及同一个 Pod 的多个容器可以共享数据,K8s 在 Pod 层面定义了存储卷,不仅能够解决 Container 中文件的临时性问题,也能够让同一个 Pod 中的多个 Container 共享文件。 4 | 5 | Docker Volume 是针对容器层面的存储抽象,其 Volume 的生命周期是通过 Docker Engine 来维护的。K8s Volume 则是应用层面的存储抽象,通过 CRI 接口解耦和 Docker Engine 的耦合关系,所以 K8s 的 Volume 的生命周期理所当然由 K8s 来管理,因此 K8s 本身也有自己的 volume plugin 扩展机制。K8s 中的 Volume 主要分为以下几类: 6 | 7 | - 本地存储:emptydir/hostpath 等,主要使用 Pod 运行的 node 上的本地存储 8 | 9 | - 网络存储:in-tree(内置): awsElasticBlockStore/gcePersistentDisk/nfs 等,存储插件的实现代码是放在 K8s 代码仓库中的;out-of-tree(外置): flexvolume/CSI 等网络存储 inline volume plugins,存储插件单独实现,特别是 CSI 是 Volume 扩展机制的核心发展方向。 10 | 11 | - Projected Volume: Secret/ConfigMap/downwardAPI/serviceAccountToken,将 K8s 集群中的一些配置信息以 volume 的方式挂载到 Pod 的容器中,也即应用可以通过 POSIX 接口来访问这些对象中的数据。 12 | 13 | - PersistentVolumeClaim 与 PersistentVolume 体系,K8s 中将存储资源与计算资源分开管理的设计体系。 14 | 15 | # 卷(Volume) 16 | 17 | 卷(Volume)其实是一个比较特定的概念,它并不是一个持久化存储,可能会随着 Pod 的删除而删除,常见的卷就包括 EmptyDir、HostPath、ConfigMap 和 Secret,这些卷与所属的 Pod 具有相同的生命周期,它们可以通过如下的方式挂载到 Pod 下面的某一个目录中: 18 | 19 | ```yml 20 | apiVersion: v1 21 | kind: Pod 22 | metadata: 23 | name: test-pod 24 | spec: 25 | containers: 26 | - name: test-container 27 | image: k8s.gcr.io/busybox 28 | volumeMounts: 29 | - name: cache-volume 30 | mountPath: /cache 31 | - name: test-volume 32 | mountPath: /hostpath 33 | - name: config-volume 34 | mountPath: /data/configmap 35 | - name: special-volume 36 | mountPath: /data/secret 37 | volumes: 38 | - name: cache-volume 39 | emptyDir: {} 40 | - name: hostpath-volume 41 | hostPath: 42 | path: /data/hostpath 43 | type: Directory 44 | - name: config-volume 45 | configMap: 46 | name: special-config 47 | - name: secret-volume 48 | secret: 49 | secretName: secret-config 50 | ``` 51 | 52 | 需要注意的是,当我们将 ConfigMap 或者 Secret 包装成卷并挂载到某个目录时,我们其实创建了一些新的 Volume,这些 Volume 并不是 Kubernetes 中的对象,它们只存在于当前 Pod 中,随着 Pod 的删除而删除,但是需要注意的是这些临时卷的删除并不会导致相关 ConfigMap 或者 Secret 对象的删除。 53 | 54 | 从上面我们其实可以看出 Volume 没有办法脱离 Pod 而生存,它与 Pod 拥有完全相同的生命周期,而且它们也不是 Kubernetes 对象,所以 Volume 的主要作用还是用于跨节点或者容器对数据进行同步和共享。 55 | 56 | # 持久卷 57 | 58 | 如果我们希望将数据进行持久化存储,可以引入 PersistentVolume(PV),以将 Pod 和卷的生命周期分离。我们可以将 PersistentVolume 理解为集群中资源的一种,它与集群中的节点 Node 有些相似,PV 为 Kubernete 集群提供了一个如何提供并且使用存储的抽象,与它一起被引入的另一个对象就是 PersistentVolumeClaim(PVC),这两个对象之间的关系与节点和 Pod 之间的关系差不多。 59 | 60 | 因为 PVC 允许用户消耗抽象的存储资源,所以用户需要不同类型、属性和性能的 PV 就是一个比较常见的需求了,在这时我们可以通过 StorageClass 来提供不同种类的 PV 资源,上层用户就可以直接使用系统管理员提供好的存储类型。 61 | 62 | ## 访问模式 63 | 64 | Kubernetes 中的 PV 提供三种不同的访问模式,分别是 `ReadWriteOnce`、`ReadOnlyMany` 和 `ReadWriteMany`,这三种模式的含义和用法我们可以通过它们的名字推测出来: 65 | 66 | - `ReadWriteOnce` 表示当前卷可以被一个节点使用读写模式挂载; 67 | - `ReadOnlyMany` 表示当前卷可以被多个节点使用只读模式挂载; 68 | - `ReadWriteMany` 表示当前卷可以被多个节点使用读写模式挂载; 69 | 70 | 不同的卷插件对于访问模式其实有着不同的支持,AWS 上的 `AWSElasticBlockStore` 和 GCP 上的 `GCEPersistentDisk` 就只支持 `ReadWriteOnce` 方式的挂载,不能同时挂载到多个节点上,但是 `CephFS` 就同时支持这三种访问模式。 71 | 72 | ## 回收策略 73 | 74 | 当某个服务使用完某一个卷之后,它们会从 apiserver 中删除 PVC 对象,这时 Kubernetes 就需要对卷进行回收(Reclaim),持久卷也同样包含三种不同的回收策略,这三种回收策略会指导 Kubernetes 选择不同的方式对使用过的卷进行处理。 75 | 76 | - 第一种回收策略就是保留(Retain)PV 中的数据,如果希望 PV 能够被重新使用,系统管理员需要删除被使用的 PersistentVolume 对象并手动清除存储和相关存储上的数据。 77 | 78 | - 另一种常见的回收策略就是删除(Delete),当 PVC 被使用者删除之后,如果当前卷支持删除的回收策略,那么 PV 和相关的存储会被自动删除,如果当前 PV 上的数据确实不再需要,那么将回收策略设置成 Delete 能够节省手动处理的时间并快速释放无用的资源。 79 | 80 | ## 存储供应 81 | 82 | Kubernetes 集群中包含了很多的 PV 资源,而 PV 资源有两种供应的方式,一种是静态的,另一种是动态的,静态存储供应要求集群的管理员预先创建一定数量的 PV,然后使用者通过 PVC 的方式对 PV 资源的使用进行声明和申请;但是当系统管理员创建的 PV 对象不能满足使用者的需求时,就会进入动态存储供应的逻辑,供应的方式是基于集群中的 StorageClass 对象,当然这种动态供应的方式也可以通过配置进行关闭。 83 | 84 | # Links 85 | 86 | - https://jimmysong.io/kubernetes-handbook/concepts/storage.html 87 | -------------------------------------------------------------------------------- /02~资源对象/01~Pod/共享与调度/网络空间.md: -------------------------------------------------------------------------------- 1 | # 网络空间 2 | 3 | 在 K8s 网络中存在两种 IP(Pod IP 和 Service Cluster IP),Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,Service Cluster IP 它是一个虚拟 IP,是由 kube-proxy 使用 Iptables 规则重新定向到其本地端口,再均衡到后端 Pod 的。每个 Pod 都拥有一个独立的 IP 地址(IPper Pod),而且假定所有的 pod 都在一个可以直接连通的、扁平的网络空间中。用户不需要额外考虑如何建立 Pod 之间的连接,也不需要考虑将容器端口映射到主机端口等问题。 4 | 5 | 同一个 Pod 的容器共享同一个网络命名空间,它们之间的访问可以用 localhost 地址 + 容器端口就可以访问。同一 Node 中 Pod 的默认路由都是 docker0 的地址,由于它们关联在同一个 docker0 网桥上,地址网段相同,所有它们之间应当是能直接通信的。不同 Node 中 Pod 间通信要满足 2 个条件:Pod 的 IP 不能冲突;将 Pod 的 IP 和所在的 Node 的 IP 关联起来,通过这个关联让 Pod 可以互相访问。 6 | 7 | ![image](https://user-images.githubusercontent.com/5803001/45594553-71001600-b9cf-11e8-83cf-d8755104e762.png) 8 | 9 | # 共享网络 10 | 11 | 可以通过本地主机访问 Pod 中的容器,它们使用相同的网络名称空间。对于容器,可观察的主机名是 Pod 的名称。由于容器共享相同的 IP 地址和端口空间,因此应在容器中使用不同的端口进行传入连接。因此,Pod 中的应用程序必须协调其端口使用情况。 12 | 13 | 在以下示例中,我们将创建一个多容器 Pod,其中一个容器中的 nginx 充当在第二个容器中运行的简单 Web 应用程序的反向代理。 14 | 15 | ![共享网络](https://linchpiner.github.io/images/k8s-mc-3.svg) 16 | 17 | 我们使用 Nginx 配置文件创建 ConfigMap。到端口 80 的传入 HTTP 请求将转发到本地主机上的端口 5000: 18 | 19 | ```yml 20 | apiVersion: v1 21 | kind: ConfigMap 22 | metadata: 23 | name: mc3-nginx-conf 24 | data: 25 | nginx.conf: |- 26 | user nginx; 27 | worker_processes 1; 28 | 29 | error_log /var/log/nginx/error.log warn; 30 | pid /var/run/nginx.pid; 31 | 32 | events { 33 | worker_connections 1024; 34 | } 35 | 36 | http { 37 | include /etc/nginx/mime.types; 38 | default_type application/octet-stream; 39 | 40 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 41 | '$status $body_bytes_sent "$http_referer" ' 42 | '"$http_user_agent" "$http_x_forwarded_for"'; 43 | 44 | access_log /var/log/nginx/access.log main; 45 | 46 | sendfile on; 47 | keepalive_timeout 65; 48 | 49 | upstream webapp { 50 | server 127.0.0.1:5000; 51 | } 52 | 53 | server { 54 | listen 80; 55 | 56 | location / { 57 | proxy_pass http://webapp; 58 | proxy_redirect off; 59 | } 60 | } 61 | } 62 | ``` 63 | 64 | 使用简单的 Web 应用程序和 Nginx 在单独的容器中创建一个多容器 Pod。请注意,对于 Pod,我们仅定义了 nginx 端口 80,在 Pod 外部将无法访问端口 5000。 65 | 66 | ```yml 67 | apiVersion: v1 68 | kind: Pod 69 | metadata: 70 | name: mc3 71 | labels: 72 | app: mc3 73 | spec: 74 | containers: 75 | - name: webapp 76 | image: training/webapp 77 | - name: nginx 78 | image: nginx:alpine 79 | ports: 80 | - containerPort: 80 81 | volumeMounts: 82 | - name: nginx-proxy-config 83 | mountPath: /etc/nginx/nginx.conf 84 | subPath: nginx.conf 85 | volumes: 86 | - name: nginx-proxy-config 87 | configMap: 88 | name: mc3-nginx-conf 89 | ``` 90 | 91 | 然后通过 NodePort 服务暴露端口: 92 | 93 | ```sh 94 | $ kubectl expose pod mc3 --type=NodePort --port=80 95 | service "mc3" exposed 96 | 97 | $ kubectl describe service mc3 98 | ... 99 | NodePort: 31418/TCP 100 | ... 101 | ``` 102 | 103 | ## Pause 镜像的作用 104 | 105 | 比如说现在有一个 Pod,其中包含了一个容器 A 和一个容器 B,它们两个就要共享 Network Namespace。在 K8s 里的解法是这样的:它会在每个 Pod 里,额外起一个 pause container 小容器来共享整个 Pod 的 Network Namespace。pause container 是一个非常小的镜像,大概 100~200KB 左右,是一个汇编语言写的、永远处于“暂停”状态的容器。由于有了这样一个 pause container 之后,其他所有容器都会通过 Join Namespace 的方式加入到 pause container 的 Network Namespace 中。 106 | 107 | 所以说一个 Pod 里面的所有容器,它们看到的网络视图是完全一样的。即:它们看到的网络设备、IP 地址、Mac 地址等等,跟网络相关的信息,其实全是一份,这一份都来自于 Pod 第一次创建的这个 pause container。这就是 Pod 解决网络共享的一个解法。在 Pod 里面,一定有一个 IP 地址,是这个 Pod 的 Network Namespace 对应的地址,也是这个 pause container 的 IP 地址。所以大家看到的都是一份,而其他所有网络资源,都是一个 Pod 一份,并且被 Pod 中的所有容器共享。这就是 Pod 的网络实现方式。 108 | 109 | 由于需要有一个相当于说中间的容器存在,所以整个 Pod 里面,必然是 pause container 第一个启动。并且整个 Pod 的生命周期是等同于 pause container 的生命周期的,与容器 A 和 B 是无关的。这也是为什么在 K8s 里面,它是允许去单独更新 Pod 里的某一个镜像的,即:做这个操作,整个 Pod 不会重建,也不会重启,这是非常重要的一个设计。 110 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/06~身份与权限认证/46-Network Policy.md: -------------------------------------------------------------------------------- 1 | # Network Policy 2 | 3 | 网络策略说明一组 `Pod` 之间是如何被允许互相通信,以及如何与其它网络 Endpoint 进行通信。`NetworkPolicy` 资源使用标签来选择 `Pod`,并定义了一些规则,这些规则指明允许什么流量进入到选中的 `Pod` 上。关于 Network Policy 的详细用法请参考 [Kubernetes 官网](https://kubernetes.io/docs/concepts/services-networking/network-policies/)。 4 | 5 | Network Policy 的作用对象是 Pod,也可以应用到 Namespace 和集群的 Ingress、Egress 流量。Network Policy 是作用在 L3/4 层的,即限制的是对 IP 地址和端口的访问,如果需要对应用层做访问限制需要使用如 [Istio](https://istio.io) 这类 Service Mesh。 6 | 7 | ## 前提条件 8 | 9 | 网络策略通过网络插件来实现,所以必须使用一种支持 `NetworkPolicy` 的网络方案(如 [calico](https://www.projectcalico.org/))—— 非 Controller 创建的资源,是不起作用的。 10 | 11 | ## 隔离的与未隔离的 Pod 12 | 13 | 默认 Pod 是未隔离的,它们可以从任何的源接收请求。具有一个可以选择 Pod 的网络策略后,Pod 就会变成隔离的。一旦 Namespace 中配置的网络策略能够选择一个特定的 Pod,这个 Pod 将拒绝任何该网络策略不允许的连接。(Namespace 中其它未被网络策略选中的 Pod 将继续接收所有流量) 14 | 15 | ## `NetworkPolicy` 资源 16 | 17 | 下面是一个 `NetworkPolicy` 的例子: 18 | 19 | ```yaml 20 | apiVersion: networking.k8s.io/v1 21 | kind: NetworkPolicy 22 | metadata: 23 | name: test-network-policy 24 | namespace: default 25 | spec: 26 | podSelector: 27 | matchLabels: 28 | role: db 29 | policyTypes: 30 | - Ingress 31 | - Egress 32 | ingress: 33 | - from: 34 | - ipBlock: 35 | cidr: 172.17.0.0/16 36 | except: 37 | - 172.17.1.0/24 38 | - namespaceSelector: 39 | matchLabels: 40 | project: myproject 41 | - podSelector: 42 | matchLabels: 43 | role: frontend 44 | ports: 45 | - protocol: TCP 46 | port: 6379 47 | egress: 48 | - to: 49 | - ipBlock: 50 | cidr: 10.0.0.0/24 51 | ports: 52 | - protocol: TCP 53 | port: 5978 54 | ``` 55 | 56 | _将上面配置 POST 到 API Server 将不起任何作用,除非选择的网络方案支持网络策略。_ 57 | 58 | **必选字段**:像所有其它 Kubernetes 配置一样,`NetworkPolicy` 需要 `apiVersion`、`kind` 和 `metadata` 这三个字段,关于如何使用配置文件的基本信息,可以查看 [这里](https://kubernetes.io/docs/user-guide/configuring-containers)。 59 | 60 | **spec**:`NetworkPolicy` spec 具有在给定 Namespace 中定义特定网络的全部信息。 61 | 62 | **podSelector**:每个 `NetworkPolicy` 包含一个 `podSelector`,它可以选择一组应用了网络策略的 Pod。由于 `NetworkPolicy` 当前只支持定义 `ingress` 规则,这个 `podSelector` 实际上为该策略定义了一组 “目标 Pod”。示例中的策略选择了标签为 “role=db” 的 Pod。一个空的 `podSelector` 选择了该 Namespace 中的所有 Pod。 63 | 64 | **ingress**:每个`NetworkPolicy` 包含了一个白名单 `ingress` 规则列表。每个规则只允许能够匹配上 `from` 和 `ports`配置段的流量。示例策略包含了单个规则,它从这两个源中匹配在单个端口上的流量,第一个是通过`namespaceSelector` 指定的,第二个是通过 `podSelector` 指定的。 65 | 66 | **egress**:每个`NetworkPolicy` 包含了一个白名单 `ingress` 规则列表。每个规则只允许能够匹配上 `to` 和 `ports`配置段的流量。示例策略包含了单个规则,它匹配目的地 `10.0.0.0/24` 单个端口的流量。 67 | 68 | 因此,上面示例的 NetworkPolicy: 69 | 70 | 1. 在 “default” Namespace 中 隔离了标签 “role=db” 的 Pod(如果他们还没有被隔离) 71 | 2. 在 “default” Namespace 中,允许任何具有 “role=frontend” 的 Pod,IP 范围在 172.17.0.0–172.17.0.255 和 172.17.2.0–172.17.255.255(整个 172.17.0.0/16 段,172.17.1.0/24 除外)连接到标签为 “role=db” 的 Pod 的 TCP 端口 6379 72 | 3. 允许在 Namespace 中任何具有标签 “project=myproject” ,IP 范围在 10.0.0.0/24 段的 Pod,连接到 “default” Namespace 中标签为 “role=db” 的 Pod 的 TCP 端口 5978 73 | 74 | 查看 [NetworkPolicy 入门指南](https://kubernetes.io/docs/getting-started-guides/network-policy/walkthrough)给出的更进一步的例子。 75 | 76 | ## 默认策略 77 | 78 | 通过创建一个可以选择所有 Pod 但不允许任何流量的 NetworkPolicy,你可以为一个 Namespace 创建一个 “默认的” 隔离策略,如下所示: 79 | 80 | ```yaml 81 | apiVersion: networking.k8s.io/v1 82 | kind: NetworkPolicy 83 | metadata: 84 | name: default-deny 85 | spec: 86 | podSelector: 87 | ``` 88 | 89 | 这确保了即使是没有被任何 NetworkPolicy 选中的 Pod,将仍然是被隔离的。 90 | 91 | 可选地,在 Namespace 中,如果你想允许所有的流量进入到所有的 Pod(即使已经添加了某些策略,使一些 Pod 被处理为 “隔离的”),你可以通过创建一个策略来显式地指定允许所有流量: 92 | 93 | ```yaml 94 | apiVersion: networking.k8s.io/v1 95 | kind: NetworkPolicy 96 | metadata: 97 | name: allow-all 98 | spec: 99 | podSelector: 100 | ingress: 101 | - {} 102 | ``` 103 | 104 | ## 参考 105 | 106 | - [Network Policies - kubernetes.io](https://kubernetes.io/docs/concepts/services-networking/network-policies/) 107 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/09~扩展集群/custom-resource.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 63 3 | title: 使用自定义资源扩展 API 4 | date: '2022-05-21T00:00:00+08:00' 5 | type: book 6 | --- 7 | 8 | 自定义资源是对 Kubernetes API 的扩展,Kubernetes 中的每个资源都是一个 API 对象的集合,例如我们在 YAML 文件里定义的那些 spec 都是对 Kubernetes 中的资源对象的定义,所有的自定义资源可以跟 Kubernetes 中内建的资源一样使用 kubectl 操作。 9 | 10 | ## 自定义资源 11 | 12 | Kubernetes 从 1.6 版本开始包含一个内建的资源叫做 TPR(ThirdPartyResource),可以用它来创建自定义资源,但该资源在 Kubernetes 1.7 版本开始已被 CRD(CustomResourceDefinition)取代。 13 | 14 | ## 扩展 API 15 | 16 | 自定义资源实际上是为了扩展 Kubernetes 的 API,向 Kubernetes API 中增加新类型,可以使用以下三种方式: 17 | 18 | - 修改 Kubernetes 的源码,显然难度比较高,也不太合适 19 | - 创建自定义 API server 并聚合到 API 中 20 | 21 | 编写自定义资源是扩展 Kubernetes API 的最简单的方式,是否编写自定义资源来扩展 API 请参考 [Should I add a custom resource to my Kubernetes Cluster?](https://kubernetes.io/docs/concepts/api-extension/custom-resources/),行动前请先考虑以下几点: 22 | 23 | - 你的 API 是否属于 [声明式的](https://kubernetes.io/docs/concepts/api-extension/custom-resources/#declarative-apis) 24 | - 是否想使用 kubectl 命令来管理 25 | - 是否要作为 Kubernetes 中的对象类型来管理,同时显示在 Kubernetes dashboard 上 26 | - 是否可以遵守 Kubernetes 的 API 规则限制,例如 URL 和 API group、namespace 限制 27 | - 是否可以接受该 API 只能作用于集群或者 namespace 范围 28 | - 想要复用 Kubernetes API 的公共功能,比如 CRUD、watch、内置的认证和授权等 29 | 30 | 如果这些都不是你想要的,那么你可以开发一个独立的 API。 31 | 32 | ### CRD 33 | 34 | 参考下面的 CRD,resourcedefinition.yaml: 35 | 36 | ```yaml 37 | apiVersion: apiextensions.k8s.io/v1beta1 38 | kind: CustomResourceDefinition 39 | metadata: 40 | # 名称必须符合下面的格式:. 41 | name: crontabs.stable.example.com 42 | spec: 43 | # REST API 使用的组名称:/apis// 44 | group: stable.example.com 45 | # REST API 使用的版本号:/apis// 46 | version: v1 47 | # Namespaced 或 Cluster 48 | scope: Namespaced 49 | names: 50 | # URL 中使用的复数名称: /apis/// 51 | plural: crontabs 52 | # CLI 中使用的单数名称 53 | singular: crontab 54 | # CamelCased 格式的单数类型。在清单文件中使用 55 | kind: CronTab 56 | # CLI 中使用的资源简称 57 | shortNames: 58 | - ct 59 | ``` 60 | 61 | 创建该 CRD: 62 | 63 | ```bash 64 | kubectl create -f resourcedefinition.yaml 65 | ``` 66 | 67 | 访问 RESTful API 端点如 `http://172.20.0.113:8080` 将看到如下 API 端点已创建: 68 | 69 | ```bash 70 | /apis/stable.example.com/v1/namespaces/*/crontabs/... 71 | ``` 72 | 73 | **创建自定义对象** 74 | 75 | 如下所示: 76 | 77 | ```yaml 78 | apiVersion: "stable.example.com/v1" 79 | kind: CronTab 80 | metadata: 81 | name: my-new-cron-object 82 | spec: 83 | cronSpec: "* * * * /5" 84 | image: my-awesome-cron-image 85 | ``` 86 | 87 | 引用该自定义资源的 API 创建对象。 88 | 89 | **终止器** 90 | 91 | 可以为自定义对象添加一个终止器,如下所示: 92 | 93 | ```yaml 94 | apiVersion: "stable.example.com/v1" 95 | kind: CronTab 96 | metadata: 97 | finalizers: 98 | - finalizer.stable.example.com 99 | ``` 100 | 101 | 删除自定义对象前,异步执行的钩子。对于具有终止器的一个对象,删除请求仅仅是为`metadata.deletionTimestamp` 字段设置一个值,而不是删除它,这将触发监控该对象的控制器执行他们所能处理的任意终止器。 102 | 103 | 详情参考:[Extend the Kubernetes API with CustomResourceDefinitions](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/) 104 | 105 | ## 自定义控制器 106 | 107 | 单纯设置了自定义资源,并没有什么用,只有跟自定义控制器结合起来,才能将资源对象中的声明式 API 翻译成用户所期望的状态。自定义控制器可以用来管理任何资源类型,但是一般是跟自定义资源结合使用。 108 | 109 | 请参考使用 [Operator](https://coreos.com/blog/introducing-operators.html) 模式,该模式可以让开发者将自己的领域知识转换成特定的 Kubernetes API 扩展。 110 | 111 | ## API server 聚合 112 | 113 | Aggregated(聚合的)API server 是为了将原来的 API server 这个巨石(monolithic)应用给拆分成,为了方便用户开发自己的 API server 集成进来,而不用直接修改 kubernetes 官方仓库的代码,这样一来也能将 API server 解耦,方便用户使用实验特性。这些 API server 可以跟 core API server 无缝衔接,使用 kubectl 也可以管理它们。 114 | 115 | 详情参考 [Aggregated API Server](../aggregated-api-server)。 116 | 117 | ## 参考 118 | 119 | - [Custom Resources - kubernetes.io](https://kubernetes.io/docs/concepts/api-extension/custom-resources/) 120 | - [Extend the Kubernetes API with CustomResourceDefinitions - kubernetes.io](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/) 121 | - [Introducing Operators: Putting Operational Knowledge into Software - coreos.com](https://coreos.com/blog/introducing-operators.html) 122 | -------------------------------------------------------------------------------- /02~资源对象/01~Pod/共享与调度/进程通信.md: -------------------------------------------------------------------------------- 1 | # 进程管理 2 | 3 | # 进程组 4 | 5 | 如果说 K8s 就是操作系统的话,那么不妨看一下真实的操作系统的例子。例子里面有一个程序叫做 Helloworld,这个 Helloworld 程序实际上是由一组进程组成的,需要注意一下,这里说的进程实际上等同于 Linux 中的线程。因为 Linux 中的线程是轻量级进程,所以如果从 Linux 系统中去查看 Helloworld 中的 pstree,将会看到这个 Helloworld 实际上是由四个线程组成的,分别是 {api、main、log、compute}。也就是说,四个这样的线程共同协作,共享 Helloworld 程序的资源,组成了 Helloworld 程序的真实工作情况。这是操作系统里面进程组或者线程组中一个非常真实的例子,以上就是进程组的一个概念。 6 | 7 | 在 K8s 里面,Pod 实际上正是 K8s 项目为你抽象出来的一个可以类比为进程组的概念。由四个进程共同组成的一个应用 Helloworld,在 K8s 里面,实际上会被定义为一个拥有四个容器的 Pod。就是说现在有四个职责不同、相互协作的进程,需要放在容器里去运行,在 K8s 里面并不会把它们放到一个容器里,因为这里会遇到两个问题。那么在 K8s 里会怎么去做呢?它会把四个独立的进程分别用四个独立的容器启动起来,然后把它们定义在一个 Pod 里面。 8 | 9 | ![Pod 进程组与容器概念](https://s2.ax1x.com/2019/10/06/ugDUbV.jpg) 10 | 11 | 所以当 K8s 把 Helloworld 给拉起来的时候,你实际上会看到四个容器,它们共享了某些资源,这些资源都属于 Pod,所以我们说 Pod 在 K8s 里面只有一个逻辑单位,没有一个真实的东西对应说这个就是 Pod,不会有的。真正起来在物理上存在的东西,就是四个容器,这四个容器,或者说是多个容器的组合就叫做 Pod。并且还有一个概念一定要非常明确,Pod 是 K8s 分配资源的一个单位,因为里面的容器要共享某些资源,所以 Pod 也是 K8s 的原子调度单位。 12 | 13 | ## 原子调度 14 | 15 | 假如现在有两个容器,它们是紧密协作的,所以它们应该被部署在一个 Pod 里面。具体来说,第一个容器叫做 App,就是业务容器,它会写日志文件;第二个容器叫做 LogCollector,它会把刚刚 App 容器写的日志文件转发到后端的 ElasticSearch 中。 16 | 17 | 两个容器的资源需求是这样的:App 容器需要 1G 内存,LogCollector 需要 0.5G 内存,而当前集群环境的可用内存是这样一个情况:Node_A:1.25G 内存,Node_B:2G 内存。 18 | 19 | 假如说现在没有 Pod 概念,就只有两个容器,这两个容器要紧密协作、运行在一台机器上。可是,如果调度器先把 App 调度到了 Node_A 上面,接下来会怎么样呢?这时你会发现:LogCollector 实际上是没办法调度到 Node_A 上的,因为资源不够。其实此时整个应用本身就已经出问题了,调度已经失败了,必须去重新调度。 20 | 21 | 以上就是一个非常典型的成组调度失败的例子。英文叫做:Task co-scheduling 问题,这个问题不是说不能解,在很多项目里面,这样的问题都有解法。 22 | 比如说在 Mesos 里面,它会做一个事情,叫做资源囤积(resource hoarding):即当所有设置了 Affinity 约束的任务都达到时,才开始统一调度,这是一个非常典型的成组调度的解法。 23 | 24 | 所以上面提到的“App”和“LogCollector”这两个容器,在 Mesos 里面,他们不会说立刻调度,而是等两个容器都提交完成,才开始统一调度。这样也会带来新的问题,首先调度效率会损失,因为需要等待。由于需要等,还会有外一个情况会出现,就是产生死锁,即互相等待的一个情况。这些机制在 Mesos 里都是需要解决的,也带来了额外的复杂度。 25 | 26 | 另一种解法是 Google 的解法。它在 Omega 系统(就是 Borg 下一代)里面,做了一个非常复杂且非常厉害的解法,叫做乐观调度。比如说:不管这些冲突的异常情况,先调度,同时设置一个非常精妙的回滚机制,这样经过冲突后,通过回滚来解决问题。这个方式相对来说要更加优雅,也更加高效,但是它的实现机制是非常复杂的。这个有很多人也能理解,就是悲观锁的设置一定比乐观锁要简单。 27 | 28 | 而像这样的一个 Task co-scheduling 问题,在 K8s 里,就直接通过 Pod 这样一个概念去解决了。因为在 K8s 里,这样的一个 App 容器和 LogCollector 容器一定是属于一个 Pod 的,它们在调度时必然是以一个 Pod 为单位进行调度,所以这个问题是根本不存在的。 29 | 30 | ## 超亲密关系 31 | 32 | 比如说现在有两个 Pod,它们需要运行在同一台宿主机上,那这样就属于亲密关系,调度器一定是可以帮助去做的。但是对于超亲密关系来说,有一个问题,即它必须通过 Pod 来解决。因为如果超亲密关系赋予不了,那么整个 Pod 或者说是整个应用都无法启动。 33 | 34 | 什么叫做超亲密关系呢?大概分为以下几类: 35 | 36 | - 比如说两个进程之间会发生文件交换,前面提到的例子就是这样,一个写日志,一个读日志; 37 | 38 | - 两个进程之间需要通过 localhost 或者说是本地的 Socket 去进行通信,这种本地通信也是超亲密关系; 39 | 40 | - 这两个容器或者是微服务之间,需要发生非常频繁的 RPC 调用,出于性能的考虑,也希望它们是超亲密关系; 41 | 42 | - 两个容器或者是应用,它们需要共享某些 Linux Namespace。最简单常见的一个例子,就是我有一个容器需要加入另一个容器的 Network Namespace。这样我就能看到另一个容器的网络设备,和它的网络信息。 43 | 44 | 像以上几种关系都属于超亲密关系,它们都是在 K8s 中会通过 Pod 的概念去解决的。它解决了两个问题:我们怎么去描述超亲密关系;我们怎么去对超亲密关系的容器或者说是业务去做统一调度,这是 Pod 最主要的一个诉求。 45 | 46 | # IPC 47 | 48 | Pod 中的容器共享相同的 IPC 名称空间,它们还可以使用标准的进程间通信(例如 SystemV 信号量或 POSIX 共享内存)相互通信。在下面的示例中,我们定义了具有两个容器的 Pod。我们两者都使用相同的 Docker 映像。第一个容器(生产者)创建一个标准的 Linux 消息队列,写入许多随机消息,然后写入特殊的退出消息。第二个容器(消费者)打开相同的消息队列进行读取,并读取消息,直到接收到退出消息为止。我们还将重启策略设置为“从不”,因此 Pod 在两个容器终止后停止。 49 | 50 | ```yml 51 | apiVersion: v1 52 | kind: Pod 53 | metadata: 54 | name: mc2 55 | spec: 56 | containers: 57 | - name: 1st 58 | image: allingeek/ch6_ipc 59 | command: ["./ipc", "-producer"] 60 | - name: 2nd 61 | image: allingeek/ch6_ipc 62 | command: ["./ipc", "-consumer"] 63 | restartPolicy: Never 64 | ``` 65 | 66 | 然后使用 kubectl create 创建 Pod 并查看状态: 67 | 68 | ```sh 69 | $ kubectl get pods --show-all -w 70 | NAME READY STATUS RESTARTS AGE 71 | mc2 0/2 Pending 0 0s 72 | mc2 0/2 ContainerCreating 0 0s 73 | mc2 0/2 Completed 0 29s 74 | ``` 75 | 76 | 然后我们可以查看通信日志: 77 | 78 | ```sh 79 | $ kubectl logs mc2 -c 1st 80 | ... 81 | Produced: f4 82 | Produced: 1d 83 | Produced: 9e 84 | Produced: 27 85 | 86 | $ kubectl logs mc2 -c 2nd 87 | ... 88 | Consumed: f4 89 | Consumed: 1d 90 | Consumed: 9e 91 | Consumed: 27 92 | Consumed: done 93 | ``` 94 | 95 | ![IPC](https://linchpiner.github.io/images/k8s-mc-2.svg) 96 | 97 | # Links 98 | 99 | - https://mp.weixin.qq.com/s/cRSDMnRsMcCdNmW-xmRobQK8s 提取最后的 pause 进程共享实验 100 | -------------------------------------------------------------------------------- /04~生态扩展/Helm/Charts/Chart 文件结构.md: -------------------------------------------------------------------------------- 1 | # Chart 文件结构 2 | 3 | chart 被组织为一个目录内的文件集合。目录名称是 chart 的名称(没有版本信息)。例如,描述 WordPress 的 chart 将被存储在 wordpress / 目录中。在这个目录里面,Helm 期望如下这样一个的结构的目录树: 4 | 5 | ```s 6 | wordpress/ 7 | Chart.yaml # A YAML file containing information about the chart 8 | LICENSE # OPTIONAL: A plain text file containing the license for the chart 9 | README.md # OPTIONAL: A human-readable README file 10 | requirements.yaml # OPTIONAL: A YAML file listing dependencies for the chart 11 | values.yaml # The default configuration values for this chart 12 | charts/ # A directory containing any charts upon which this chart depends. 13 | templates/ # A directory of templates that, when combined with values, 14 | # will generate valid Kubernetes manifest files. 15 | templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes 16 | ``` 17 | 18 | Helm 保留使用 charts / 和 templates / 目录以及上面列出的文件名称。其他文件将被忽略。 19 | 20 | ## Chart.yaml 文件 21 | 22 | Chart.yaml 文件是 Chart 所必需的。它包含以下字段: 23 | 24 | ```yml 25 | apiVersion: The chart API version, always "v1" (required) 26 | name: The name of the chart (required) 27 | version: A SemVer 2 version (required) 28 | kubeVersion: A SemVer range of compatible Kubernetes versions (optional) 29 | description: A single-sentence description of this project (optional) 30 | keywords: 31 | - A list of keywords about this project (optional) 32 | home: The URL of this project's home page (optional) 33 | sources: 34 | - A list of URLs to source code for this project (optional) 35 | maintainers: # (optional) 36 | - name: The maintainer's name (required for each maintainer) 37 | email: The maintainer's email (optional for each maintainer) 38 | url: A URL for the maintainer (optional for each maintainer) 39 | engine: gotpl # The name of the template engine (optional, defaults to gotpl) 40 | icon: A URL to an SVG or PNG image to be used as an icon (optional). 41 | appVersion: The version of the app that this contains (optional). This needn't be SemVer. 42 | deprecated: Whether this chart is deprecated (optional, boolean) 43 | tillerVersion: The version of Tiller that this chart requires. This should be expressed as a SemVer range: ">2.0.0" (optional) 44 | ``` 45 | 46 | 如果熟悉 Chart.yaml Helm Classic 的文件格式,注意到指定依赖性的字段已被删除。这是因为新的 chart 使用 charts / 目录表示依赖关系。其他字段将被忽略。 47 | 48 | ## Charts 和版本控制 49 | 50 | 每个 chart 都必须有一个版本号。版本必须遵循 SemVer 2 标准。与 Helm Class 格式不同,Kubernetes Helm 使用版本号作为发布标记。存储库中的软件包由名称加版本识别。例如,nginx version 字段设置为 1.2.3 将被命名为: 51 | 52 | ```s 53 | nginx-1.2.3.tgz 54 | ``` 55 | 56 | 更复杂的 SemVer 2 命名也是支持的,例如 version: 1.2.3-alpha.1+ef365。但非 SemVer 命名是明确禁止的。虽然 Helm Classic 和 Deployment Manager 在 chart 方面都非常适合 GitHub,但 Kubernetes Helm 并不依赖或需要 GitHub 甚至 Git。因此,它不使用 Git SHA 进行版本控制。 57 | 58 | 许多 Helm 工具都使用 Chart.yaml 的 version 字段,其中包括 CLI 和 Tiller 服务。在生成包时,helm package 命令将使用它在 Chart.yaml 中的版本名作为包名。系统假定 chart 包名称中的版本号与 Chart.yaml 中的版本号相匹配。不符合这个情况会导致错误。 59 | 60 | ### appVersion 字段 61 | 62 | 请注意,appVersion 字段与 version 字段无关。这是一种指定应用程序版本的方法。例如,drupal chart 可能有一个 appVersion: 8.2.1,表示 chart 中包含的 Drupal 版本(默认情况下)是 8.2.1。该字段是信息标识,对 chart 版本没有影响。 63 | 64 | ### 弃用 charts 65 | 66 | 在管理 chart tepo 库中的 chart 时,有时需要弃用 chart。Chart.yaml 的 deprecated 字段可用于将 chart 标记为已弃用。如果存储库中最新版本的 chart 标记为已弃用,则整个 chart 被视为已弃用。chart 名称稍后可以通过发布未标记为已弃用的较新版本来重新使用。废弃 chart 的工作流程根据 helm/charts 项目的工作流程如下: 67 | 68 | - 更新 chart 的 Chart.yaml 以将 chart 标记为启用,并且更新版本 69 | - 在 chart Repository 中发布新的 chart 版本 70 | - 从源代码库中删除 chart(例如 git) 71 | 72 | ## Chart 许可证文件,自述文件和说明文件 73 | 74 | Chart 还可以包含描述 chart 的安装,配置,使用和许可证的文件。LICENSE 文件是一个纯文本文件,包含 chart 的 [许可证](https://en.wikipedia.org/wiki/Software_license)。Chart 可以包含许可证,它可能在模板中具有编程逻辑,因此不仅仅是配置。如果需要,还可以为 chart 安装的应用程序提供单独的许可证。 75 | 76 | Chart 的自述文件应由 Markdown(README.md)语法格式化,并且通常应包含: 77 | 78 | - chart 提供的应用程序或服务的描述 79 | - 运行 chart 的任何前提条件或要求 80 | - 选项 `values.yaml` 和默认值的说明 81 | - 任何其他可能与安装或配置 chart 相关的信息 82 | 83 | chart 还可以包含一个简短的纯文本 `templates/NOTES.txt` 文件,在安装后以及查看版本状态时将打印出来。此文件将作为模板 [template](https://whmzsu.github.io/helm-doc-zh-cn/chart/charts-zh_cn.html#templates-and-values) 进行评估,并可用于显示使用说明,后续步骤或任何其他与发布 chart 相关的信息。例如,可以提供用于连接到数据库或访问 Web UI 的指令。由于运行时,该文件被打印到标准输出 `helm install` 或 `helm status`,建议保持内容简短并把更多细节指向自述文件。 84 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/01~Kubernetes 架构/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 架构 2 | 3 | Kubernetes 最初源于谷歌内部的 Borg,提供了面向应用的容器集群部署和管理系统。Kubernetes 的目标旨在消除编排物理 / 虚拟计算,网络和存储基础设施的负担,并使应用程序运营商和开发人员完全将重点放在以容器为中心的原语上进行自助运营。Kubernetes 也提供稳定、兼容的基础(平台),用于构建定制化的 workflows 和更高级的自动化任务。 4 | 5 | Kubernetes 具备完善的集群管理能力,包括多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建负载均衡器、故障发现和自我修复能力、服务滚动升级和在线扩容、可扩展的资源自动调度机制、多粒度的资源配额管理能力。Kubernetes 还提供完善的管理工具,涵盖开发、部署测试、运维监控等各个环节。 6 | 7 | ## Borg 简介 8 | 9 | Borg 是谷歌内部的大规模集群管理系统,负责对谷歌内部很多核心服务的调度和管理。Borg 的目的是让用户能够不必操心资源管理的问题,让他们专注于自己的核心业务,并且做到跨多个数据中心的资源利用率最大化。 10 | 11 | Borg 主要由 BorgMaster、Borglet、borgcfg 和 Scheduler 组成,如下图所示 12 | 13 | ![Borg 架构](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/borg.png "Borg 架构") 14 | 15 | - BorgMaster 是整个集群的大脑,负责维护整个集群的状态,并将数据持久化到 Paxos 存储中; 16 | - Scheduer 负责任务的调度,根据应用的特点将其调度到具体的机器上去; 17 | - Borglet 负责真正运行任务(在容器中); 18 | - borgcfg 是 Borg 的命令行工具,用于跟 Borg 系统交互,一般通过一个配置文件来提交任务。 19 | 20 | ## Kubernetes 架构 21 | 22 | Kubernetes 借鉴了 Borg 的设计理念,比如 Pod、Service、Label 和单 Pod 单 IP 等。Kubernetes 的整体架构跟 Borg 非常像,如下图所示。 23 | 24 | ![Kubernetes 架构](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/architecture.png "Kubernetes 架构") 25 | 26 | Kubernetes 主要由以下几个核心组件组成: 27 | 28 | - etcd 保存了整个集群的状态; 29 | - apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制; 30 | - controller manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等; 31 | - scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上; 32 | - kubelet 负责维护容器的生命周期,同时也负责 Volume(CSI)和网络(CNI)的管理; 33 | - Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI); 34 | - kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡; 35 | 36 | 除了核心组件,还有一些推荐的插件,其中有的已经成为 CNCF 中的托管项目: 37 | 38 | - CoreDNS 负责为整个集群提供 DNS 服务 39 | - Ingress Controller 为服务提供外网入口 40 | - Prometheus 提供资源监控 41 | - Dashboard 提供 GUI 42 | - Federation 提供跨可用区的集群 43 | 44 | ## Kubernetes 架构示意图 45 | 46 | ### 整体架构 47 | 48 | 下图清晰表明了 Kubernetes 的架构设计以及组件之间的通信协议。 49 | 50 | ![Kuberentes 架构(图片来自于网络)](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernetes-high-level-component-archtecture.jpg "Kuberentes 架构(图片来自于网络)") 51 | 52 | 下面是更抽象的一个视图: 53 | 54 | ![kubernetes 整体架构示意图](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernetes-whole-arch.png "kubernetes 整体架构示意图") 55 | 56 | ### Master 架构 57 | 58 | ![Kubernetes master 架构示意图](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernetes-master-arch.png "Kubernetes master 架构示意图") 59 | 60 | ### Node 架构 61 | 62 | ![kubernetes node 架构示意图](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernetes-node-arch.png "kubernetes node 架构示意图") 63 | 64 | ### 分层架构 65 | 66 | Kubernetes 设计理念和功能其实就是一个类似 Linux 的分层架构,如下图所示。 67 | 68 | ![Kubernetes 分层架构示意图](https://ngte-superbed.oss-cn-beijing.aliyuncs.com/book/kubernetes-handbook/kubernetes-layers-arch.png "Kubernetes 分层架构示意图") 69 | 70 | - 核心层:Kubernetes 最核心的功能,对外提供 API 构建高层的应用,对内提供插件式应用执行环境 71 | - 应用层:部署(无状态应用、有状态应用、批处理任务、集群应用等)和路由(服务发现、DNS 解析等)、Service Mesh(部分位于应用层) 72 | - 管理层:系统度量(如基础设施、容器和网络的度量),自动化(如自动扩展、动态 Provision 等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy 等)、Service Mesh(部分位于管理层) 73 | - 接口层:kubectl 命令行工具、客户端 SDK 以及集群联邦 74 | - 生态系统:在接口层之上的庞大容器集群管理调度的生态系统,可以划分为两个范畴 75 | - Kubernetes 外部:日志、监控、配置管理、CI/CD、Workflow、FaaS、OTS 应用、ChatOps、GitOps、SecOps 等 76 | - Kubernetes 内部:CRI、CNI、CSI、镜像仓库、Cloud Provider、集群自身的配置和管理等 77 | 78 | {{}} 79 | 关于分层架构,可以关注下 [Kubernetes architectual roadmap](https://docs.google.com/document/d/1XkjVm4bOeiVkj-Xt1LgoGiqWsBfNozJ51dyI-ljzt1o) 和 [幻灯片](https://docs.google.com/presentation/d/1GpELyzXOGEPY0Y1ft26yMNV19ROKt8eMN67vDSSHglk/edit)。 80 | {{}} 81 | 82 | ## 本节大纲 83 | 84 | ## 参考 85 | 86 | - [Borg, Omega, and Kubernetes - Lessons learned from three container-management systems over a decade](http://queue.acm.org/detail.cfm?id=2898444) 87 | - [Paper - Large-scale cluster management at Google with Borg](http://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/43438.pdf) 88 | - [KUBERNETES: AN OVERVIEW](http://thenewstack.io/kubernetes-an-overview) 89 | - [Kubernetes architectual roadmap](https://docs.google.com/document/d/1XkjVm4bOeiVkj-Xt1LgoGiqWsBfNozJ51dyI-ljzt1o) 和 [slide](https://docs.google.com/presentation/d/1GpELyzXOGEPY0Y1ft26yMNV19ROKt8eMN67vDSSHglk/edit) 90 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/04~控制器/34.CronJob.md: -------------------------------------------------------------------------------- 1 | # CronJob 2 | 3 | **Cron Job** 管理基于时间的 [Job](https://kubernetes.io/docs/concepts/jobs/run-to-completion-finite-workloads/),即: 4 | 5 | - 在给定时间点只运行一次 6 | - 周期性地在给定时间点运行 7 | 8 | 一个 CronJob 对象类似于 _crontab_ (cron table)文件中的一行。它根据指定的预定计划周期性地运行一个 Job,格式可以参考 [Cron](https://en.wikipedia.org/wiki/Cron) 。 9 | 10 | ## 前提条件 11 | 12 | 当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)。对于先前版本的集群,版本 < 1.8,启动 API Server(参考 [为集群开启或关闭 API 版本](https://kubernetes.io/docs/admin/cluster-management/#turn-on-or-off-an-api-version-for-your-cluster) 获取更多信息)时,通过传递选项 `--runtime-config=batch/v2alpha1=true` 可以开启 batch/v2alpha1 API。 13 | 14 | 典型的用法如下所示: 15 | 16 | - 在给定的时间点调度 Job 运行 17 | - 创建周期性运行的 Job,例如:数据库备份、发送邮件。 18 | 19 | ## CronJob Spec 20 | 21 | - `.spec.schedule`:**调度**,必需字段,指定任务运行周期,格式同 [Cron](https://en.wikipedia.org/wiki/Cron) 22 | 23 | - `.spec.jobTemplate`:**Job 模板**,必需字段,指定需要运行的任务,格式同 [Job](../job) 24 | 25 | - `.spec.startingDeadlineSeconds` :**启动 Job 的期限(秒级别)**,该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限 26 | 27 | - `.spec.concurrencyPolicy`:**并发策略**,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的并发执行。只允许指定下面策略中的一种: 28 | 29 | - `Allow`(默认):允许并发运行 Job 30 | - `Forbid`:禁止并发运行,如果前一个还没有完成,则直接跳过下一个 31 | - `Replace`:取消当前正在运行的 Job,用一个新的来替换 32 | 33 | 注意,当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是允许并发运行。 34 | 35 | - `.spec.suspend` :**挂起**,该字段也是可选的。如果设置为 `true`,后续所有执行都会被挂起。它对已经开始执行的 Job 不起作用。默认值为 `false`。 36 | 37 | - `.spec.successfulJobsHistoryLimit` 和 `.spec.failedJobsHistoryLimit` :**历史限制**,是可选的字段。它们指定了可以保留多少完成和失败的 Job。 38 | 39 | 默认情况下,它们分别设置为 `3` 和 `1`。设置限制的值为 `0`,相关类型的 Job 完成后将不会被保留。 40 | 41 | ```yaml 42 | apiVersion: batch/v1beta1 43 | kind: CronJob 44 | metadata: 45 | name: hello 46 | spec: 47 | schedule: "*/1 * * * *" 48 | jobTemplate: 49 | spec: 50 | template: 51 | spec: 52 | containers: 53 | - name: hello 54 | image: busybox 55 | args: 56 | - /bin/sh 57 | - -c 58 | - date; echo Hello from the Kubernetes cluster 59 | restartPolicy: OnFailure 60 | ``` 61 | 62 | ```bash 63 | $ kubectl create -f cronjob.yaml 64 | cronjob "hello" created 65 | ``` 66 | 67 | 当然,也可以用`kubectl run`来创建一个 CronJob: 68 | 69 | ```bash 70 | kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster" 71 | ``` 72 | 73 | ```bash 74 | $ kubectl get cronjob 75 | NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE 76 | hello */1 * * * * False 0 77 | $ kubectl get jobs 78 | NAME DESIRED SUCCESSFUL AGE 79 | hello-1202039034 1 1 49s 80 | $ pods=$(kubectl get pods --selector=job-name=hello-1202039034 --output=jsonpath={.items..metadata.name}) 81 | $ kubectl logs $pods 82 | Mon Aug 29 21:34:09 UTC 2016 83 | Hello from the Kubernetes cluster 84 | 85 | # 注意,删除 cronjob 的时候不会自动删除 job,这些 job 可以用 kubectl delete job 来删除 86 | $ kubectl delete cronjob hello 87 | cronjob "hello" deleted 88 | ``` 89 | 90 | ## Cron Job 限制 91 | 92 | Cron Job 在每次调度运行时间内 _大概_ 会创建一个 Job 对象。我们之所以说 _大概_ ,是因为在特定的环境下可能会创建两个 Job,或者一个 Job 都没创建。我们尝试少发生这种情况,但却不能完全避免。因此,创建 Job 操作应该是 _幂等的_。 93 | 94 | Job 根据它所创建的 Pod 的并行度,负责重试创建 Pod,并就决定这一组 Pod 的成功或失败。Cron Job 根本就不会去检查 Pod。 95 | 96 | ## 删除 Cron Job 97 | 98 | 一旦不再需要 Cron Job,简单地可以使用 `kubectl` 命令删除它: 99 | 100 | ``` 101 | $ kubectl delete cronjob hello 102 | cronjob "hello" deleted 103 | 104 | ``` 105 | 106 | 这将会终止正在创建的 Job。然而,运行中的 Job 将不会被终止,不会删除 Job 或 它们的 Pod。为了清理那些 Job 和 Pod,需要列出该 Cron Job 创建的全部 Job,然后删除它们: 107 | 108 | ``` 109 | $ kubectl get jobs 110 | NAME DESIRED SUCCESSFUL AGE 111 | hello-1201907962 1 1 11m 112 | hello-1202039034 1 1 8m 113 | ... 114 | 115 | $ kubectl delete jobs hello-1201907962 hello-1202039034 ... 116 | job "hello-1201907962" deleted 117 | job "hello-1202039034" deleted 118 | ... 119 | 120 | ``` 121 | 122 | 一旦 Job 被删除,由 Job 创建的 Pod 也会被删除。注意,所有由名称为 “hello” 的 Cron Job 创建的 Job 会以前缀字符串 “hello-” 进行命名。如果想要删除当前 Namespace 中的所有 Job,可以通过命令 `kubectl delete jobs --all` 立刻删除它们。 123 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/CronJobs/README.md: -------------------------------------------------------------------------------- 1 | # Cron Jobs 2 | 3 | CronJob 服务不过是 crontab 文件中的一行或表 cron 中的同一文件。它按照给定的时间表定期安排和执行任务。但我们可以使用 Cron Job 来做什么呢?Cron 对于创建经常性和重复性任务非常有用,例如执行备份或发送电子邮件。 4 | 5 | ```yaml 6 | $ vim primeiro-cron.yaml 7 | 8 | apiVersion : batch/v1beta1 9 | kind : CronJob 10 | metadata : 11 | name : giropops-cron 12 | spec : 13 | schedule : " * / 1 * * * * " 14 | jobTemplate : 15 | spec : 16 | template : 17 | spec : 18 | containers : 19 | - name : giropops-cron 20 | image : busybox 21 | args : 22 | - /bin/sh 23 | - -c 24 | - date; echo Welcome to Uncomplicating Kubernetes - LinuxTips VAIIII; sleep 30 25 | restartPolicy : OnFailure 26 | ``` 27 | 28 | 我们前面的 CronJobs 例子每分钟打印当前时间和一条问候信息。让我们从清单中创建它的 CronJob。 29 | 30 | ```sh 31 | $ kubectl create -f primeiro-cron.yaml 32 | 33 | cronjob.batch/giropops-cron created 34 | 35 | $ kubectl get cronjobs 36 | 37 | NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE 38 | giropops-cron */1 * * * * False 1 13s 2m 39 | 40 | $ kubectl describe cronjobs.batch giropops-cron 41 | 42 | Name: giropops-cron 43 | Namespace: default 44 | Labels: 45 | Annotations: 46 | Schedule: */1 * * * * 47 | Concurrency Policy: Allow 48 | Suspend: False 49 | Starting Deadline Seconds: 50 | Selector: 51 | Parallelism: 52 | Completions: 53 | Pod Template: 54 | Labels: 55 | Containers: 56 | giropops-cron: 57 | Image: busybox 58 | Port: 59 | Host Port: 60 | Args: 61 | /bin/sh 62 | -c 63 | date; echo LinuxTips VAIIII ;sleep 30 64 | Environment: 65 | Mounts: 66 | Volumes: 67 | Last Schedule Time: Wed, 22 Aug 2018 22:33:00 +0000 68 | Active Jobs: 69 | Events: 70 | Type Reason Age From Message 71 | ---- ------ ---- ---- ------- 72 | Normal SuccessfulCreate 1m cronjob-controller Created job giropops-cron-1534977120 73 | Normal SawCompletedJob 1m cronjob-controller Saw completed job: giropops-cron-1534977120 74 | Normal SuccessfulCreate 41s cronjob-controller Created job giropops-cron-1534977180 75 | Normal SawCompletedJob 1s cronjob-controller Saw completed job: giropops-cron-1534977180 76 | Normal SuccessfulDelete 1s cronjob-controller Deleted job giropops-cron-1534977000 77 | ``` 78 | 79 | 看看多酷,如果你看集群事件,你是 cron 已经在调度和执行任务了。现在我们就来看看这个 cron 工作通过命令`kubectl get`旁边的参数 --watch 来查看任务的输出,注意,这个任务会在 CronJob 创建后的一分钟左右被创建。 80 | 81 | ```sh 82 | $ kubectl get jobs --watch 83 | 84 | NAME DESIRED SUCCESSFUL AGE 85 | giropops-cron-1534979640 1 1 2m 86 | giropops-cron-1534979700 1 1 1m 87 | 88 | $ kubectl get cronjob giropops-cron 89 | 90 | NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE 91 | giropops-cron */1 * * * * False 1 26s 48m 92 | ``` 93 | 94 | 我们可以看到,我们的 cronis 工作正常。要查看任务执行的命令输出将使用 kubectl 的命令日志。为此,我们将列出正在运行的 pods,然后从中获取日志。 95 | 96 | ```sh 97 | $ kubectl get pods 98 | 99 | NAME READY STATUS RESTARTS AGE 100 | giropops-cron-1534979940-vcwdg 1/1 Running 0 25s 101 | 102 | $ kubectl logs giropops-cron-1534979940-vcwdg 103 | 104 | Wed Aug 22 23:19:06 UTC 2018 105 | LinuxTips VAIIII 106 | ``` 107 | 108 | cron 正确地执行任务,打印日期和我们在清单中创建的短语。如果 kubectl 得到 pods 我们运行一个,我们可以看到创建的 Pods 和用于执行任务的每分钟。 109 | 110 | ```sh 111 | $ kubectl get pods 112 | 113 | NAME READY STATUS RESTARTS AGE 114 | giropops-cron-1534980360-cc9ng 0/1 Completed 0 2m 115 | giropops-cron-1534980420-6czgg 0/1 Completed 0 1m 116 | giropops-cron-1534980480-4bwcc 1/1 Running 0 4s 117 | 118 | $ kubectl delete cronjob giropops-cron 119 | 120 | cronjob.batch "giropops-cron" deleted 121 | ``` 122 | -------------------------------------------------------------------------------- /04~生态扩展/Helm/模板/外部文件.md: -------------------------------------------------------------------------------- 1 | # 外部文件 2 | 3 | 有时需要导入不是模板的文件,并注入其内容而不通过模板渲染器发送内容。Helm 通过 `.Files` 对象提供对文件的访问。在我们开始使用模板示例之前,需要注意一些关于它如何工作的内容: 4 | 5 | - 向 Helm chart 添加额外的文件是可以的。这些文件将被捆绑并发送给 Tiller。不过要注意,由于 Kubernetes 对象的存储限制,chart 必须小于 1M。 6 | 7 | - 通常出于安全原因,某些文件不能通过 `.Files`对象访问。 8 | 9 | - templates / 无法访问文件。 10 | - 使用 `.helmignore` 排除的文件不能被访问。 11 | 12 | - chart 不保留 UNIX 模式信息,因此文件级权限在涉及 `.Files` 对象时不会影响文件的可用性。 13 | 14 | # 基本示例 15 | 16 | 我们编写一个模板,从三个文件读入我们的 ConfigMap。首先,我们将三个文件添加到 chart 中,将所有三个文件直接放在 mychart / 目录中。 17 | 18 | `config1.toml`: 19 | 20 | ``` 21 | message = Hello from config 1 22 | ``` 23 | 24 | `config2.toml`: 25 | 26 | ``` 27 | message = This is config 2 28 | ``` 29 | 30 | `config3.toml`: 31 | 32 | ``` 33 | message = Goodbye from config 3 34 | ``` 35 | 36 | 这些都是一个简单的 TOML 文件(想想老派的 Windows INI 文件)。我们知道这些文件的名称,所以我们可以使用一个 range 函数来遍历它们并将它们的内容注入到我们的 ConfigMap 中。 37 | 38 | ```yaml 39 | apiVersion: v1 40 | kind: ConfigMap 41 | metadata: 42 | name: {{.Release.Name}}-configmap 43 | data: 44 | {{- $files := .Files}} 45 | {{- range tuple "config1.toml" "config2.toml" "config3.toml"}} 46 | {{.}}: |- 47 | {{$files.Get .}} 48 | {{- end}} 49 | ``` 50 | 51 | 这个配置映射使用了前几节讨论的几种技术。例如,我们创建一个 `$files` 变量来保存 `.Files` 对象的引用。我们还使用该 `tuple` 函数来创建我们循环访问的文件列表。然后我们打印每个文件名(`{{.}}: |-`),然后打印文件的内容 `{{ $files.Get . }}`。运行这个模板将产生一个包含所有三个文件内容的 ConfigMap: 52 | 53 | ```yaml 54 | # Source: mychart/templates/configmap.yaml 55 | apiVersion: v1 56 | kind: ConfigMap 57 | metadata: 58 | name: quieting-giraf-configmap 59 | data: 60 | config1.toml: |- 61 | message = Hello from config 1 62 | 63 | config2.toml: |- 64 | message = This is config 2 65 | 66 | config3.toml: |- 67 | message = Goodbye from config 3 68 | ``` 69 | 70 | # 路径助手 71 | 72 | 在处理文件时,对文件路径本身执行一些标准操作会非常有用。为了协助这个能力,Helm 从 Go 的 [path](https://golang.org/pkg/path/) 包中导入了许多函数供使用。它们都可以使用 Go 包中的相同名称访问,但使用时小写第一个字母,例如,`Base` 变成 `base`,等等导入的功能是: 73 | 74 | - Base 75 | - Dir 76 | - Ext 77 | - IsAbs 78 | - Clean 79 | 80 | # Glob 模式 81 | 82 | 随着 Chart 的增长,可能会发现需要组织更多地文件,因此我们提供了一种 `Files.Glob(pattern string)` 方法通过具有灵活性的模式 [glob patterns](https://godoc.org/github.com/gobwas/glob) 协助提取文件。`.Glob` 返回一个 `Files` 类型,所以可以调用 `Files` 返回对象的任何方法。 83 | 84 | 例如,想象一下目录结构: 85 | 86 | ``` 87 | foo/: 88 | foo.txt foo.yaml 89 | 90 | bar/: 91 | bar.go bar.conf baz.yaml 92 | ``` 93 | 94 | Globs 有多个方法可选择: 95 | 96 | ```yaml 97 | {{$root := .}} 98 | {{range $path, $bytes := .Files.Glob "**.yaml"}} 99 | {{$path}}: |- 100 | {{$root.Files.Get $path}} 101 | {{end}} 102 | ``` 103 | 104 | 或 105 | 106 | ```yaml 107 | {{range $path, $bytes := .Files.Glob "foo/*"}} 108 | {{$path.base}}: '{{ $root.Files.Get $path | b64enc }}' 109 | {{end}} 110 | ``` 111 | 112 | # ConfigMap 和 Secrets 工具函数 113 | 114 | 想要将文件内容放置到 configmap 和 secret 中非常常见,以便在运行时安装到 pod 中。为了解决这个问题,我们在这个 `Files` 类型上提供了一些实用的方法。为了进一步组织文件,将这些方法与 `Glob` 方法结合使用尤其有用。根据上面的 [Glob](https://whmzsu.github.io/helm-doc-zh-cn/chart_template_guide/accessing_files-zh_cn.html#Glob 模式) 示例中的目录结构: 115 | 116 | ```yaml 117 | apiVersion: v1 118 | kind: ConfigMap 119 | metadata: 120 | name: conf 121 | data: { { - (.Files.Glob "foo/*").AsConfig | nindent 2 } } 122 | --- 123 | apiVersion: v1 124 | kind: Secret 125 | metadata: 126 | name: very-secret 127 | type: Opaque 128 | data: { { (.Files.Glob "bar/*").AsSecrets | nindent 2 } } 129 | ``` 130 | 131 | # 编码 132 | 133 | 我们可以导入一个文件,并使用 base64 对模板进行编码以确保成功传输: 134 | 135 | ```yaml 136 | apiVersion: v1 137 | kind: Secret 138 | metadata: 139 | name: {{.Release.Name}}-secret 140 | type: Opaque 141 | data: 142 | token: |- 143 | {{.Files.Get "config1.toml" | b64enc}} 144 | ``` 145 | 146 | 以上例子将采用 `config1.toml` 文件,我们之前使用的相同文件并对其进行编码: 147 | 148 | ```yaml 149 | # Source: mychart/templates/secret.yaml 150 | apiVersion: v1 151 | kind: Secret 152 | metadata: 153 | name: lucky-turkey-secret 154 | type: Opaque 155 | data: 156 | token: |- 157 | bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK 158 | ``` 159 | 160 | # 行 161 | 162 | 有时需要访问模板中文件的每一行。`Lines` 为此提供了一种方便的方法。 163 | 164 | ```yaml 165 | data: 166 | some-file.txt: {{range .Files.Lines "foo/bar.txt"}} 167 | {{.}}{{ end }} 168 | ``` 169 | 170 | 目前,无法将 `helm install` 期间将外部文件传递给 chart。因此,如果要求用户提供数据,则必须使用 `helm install -f` 或进行加载 `helm install --set`。 171 | -------------------------------------------------------------------------------- /02~资源对象/02~控制器/Deployment/声明与管理/ReplicaSet.md: -------------------------------------------------------------------------------- 1 | # ReplicaSet 2 | 3 | ReplicaSet 可以保证 Deployment 所需的 pod 和资源数量。一旦创建了部署,ReplicaSet 就会控制运行的 pod 数量,如果有任何 pod 完成,它将检测并请求执行另一个 pod,从而保证请求的复制数量。让我们创建第一个 ReplicaSet: 4 | 5 | ```yaml 6 | vim primeiro-replicaset.yaml 7 | 8 | apiVersion : apps / v1 9 | kind : ReplicaSet 10 | metadata : 11 | name : replica-set-first 12 | spec : 13 | replicas : 3 14 | selector : 15 | matchLabels : 16 | system : Giropops 17 | template : 18 | metadata : 19 | labels : 20 | system : Giropops 21 | spec : 22 | containers : 23 | - name : nginx 24 | image : nginx: 1.7.9 25 | ports : 26 | - containerPort : 80 27 | ``` 28 | 29 | 从 manifest 中创建 ReplicaSet: 30 | 31 | ```sh 32 | $ kubectl create -f primeiro-replicaset.yaml 33 | 34 | replicaset.extensions/replica-set-primeiro created 35 | 36 | $ kubectl get replicaset 37 | 38 | NAME DESIRED CURRENT READY AGE 39 | replica-set-primeiro 3 3 1 2s 40 | 41 | $ kubectl get pods 42 | 43 | NAME READY STATUS RESTARTS AGE 44 | replica-set-primeiro-6drmt 1/1 Running 0 12s 45 | replica-set-primeiro-7j59w 1/1 Running 0 12s 46 | replica-set-primeiro-mg8q9 1/1 Running 0 12s 47 | 48 | $ kubectl describe rs replica-set-primeiro 49 | 50 | Name: replica-set-primeiro 51 | Namespace: default 52 | Selector: system=Giropops 53 | Labels: system=Giropops 54 | Annotations: 55 | Replicas: 3 current / 3 desired 56 | Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed 57 | Pod Template: 58 | Labels: system=Giropops 59 | Containers: 60 | nginx: 61 | Image: nginx:1.7.9 62 | Port: 80/TCP 63 | Host Port: 0/TCP 64 | Environment: 65 | Mounts: 66 | Volumes: 67 | Events: 68 | Type Reason Age From Message 69 | ---- ------ ---- ---- ------- 70 | Normal SuccessfulCreate 31s replicaset-controller Created pod: replica-set-primeiro-mg8q9 71 | Normal SuccessfulCreate 31s replicaset-controller Created pod: replica-set-primeiro-6drmt 72 | Normal SuccessfulCreate 31s replicaset-controller Created pod: replica-set-primeiro-7j59w 73 | ``` 74 | 75 | 因此,我们可以看到所有与 ReplicaSet 相关联的 Pods,如果我们删除其中一个 Pods,会发生什么?让我们测试一下。 76 | 77 | ```sh 78 | $ kubectl delete pod replica-set-primeiro-6drmt 79 | 80 | pod "replica-set-primeiro-6drmt" deleted 81 | 82 | $ kubectl get pods -l system=Giropops 83 | 84 | NAME READY STATUS RESTARTS AGE 85 | replica-set-primeiro-7j59w 1/1 Running 0 1m 86 | replica-set-primeiro-mg8q9 1/1 Running 0 1m 87 | replica-set-primeiro-s5dz2 1/1 Running 0 15s 88 | ``` 89 | 90 | 你有没有注意到他又重新制作了一个 Pod?ReplicaSet 的原因总是有三个 Pod 可用。我们将改为 4 个副本并重新创建 ReplicaSet,为此我们将使用之前的 kubectl edit,这样我们就可以更改已经运行的 ReplicaSet。 91 | 92 | ```sh 93 | $ kubectl edit rs replica-set-primeiro 94 | 95 | apiVersion : apps / v1 96 | kind : ReplicaSet 97 | metadata : 98 | creationTimestamp : 2018-07-05T04: 32: 42Z 99 | generation : 2 100 | labels : 101 | system : Giropops 102 | name : replica-set-first 103 | namespace : default 104 | resourceVersion : " 471758 " 105 | selfLink : / apis / extensions / v1beta1 / namespaces / default / replicasets / replica-set-first 106 | uid : 753290c1-800c-11e8-b889-42010a8a0002 107 | spec : 108 | replicas: 4 109 | selector : 110 | matchLabels : 111 | system : Giropops 112 | template : 113 | metadata : 114 | creationTimestamp : null 115 | labels : 116 | system : Giropops 117 | ... 118 | 119 | replicaset.extensions / replica-set-first edited 120 | ``` 121 | 122 | 查看 Pod 详情。 123 | 124 | ```sh 125 | $ kubectl get pods -l system=Giropops 126 | 127 | NAME READY STATUS RESTARTS AGE 128 | replica-set-primeiro-7j59w 1/1 Running 0 2m 129 | replica-set-primeiro-96hj7 1/1 Running 0 10s 130 | replica-set-primeiro-mg8q9 1/1 Running 0 2m 131 | replica-set-primeiro-s5dz2 1/1 Running 0 1m 132 | ``` 133 | -------------------------------------------------------------------------------- /99~参考资料/2020-JimmySong-《Kubernetes 基础教程》/08~存储/55.Secret.md: -------------------------------------------------------------------------------- 1 | # Secret 2 | 3 | Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用。 4 | 5 | Secret 有三种类型: 6 | 7 | - **Service Account** :用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的 `/run/secrets/kubernetes.io/serviceaccount` 目录中; 8 | - **Opaque** :base64 编码格式的 Secret,用来存储密码、密钥等; 9 | - **kubernetes.io/dockerconfigjson** :用来存储私有 docker registry 的认证信息。 10 | 11 | ## Opaque Secret 12 | 13 | Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式: 14 | 15 | ```sh 16 | $ echo -n "admin" | base64 17 | YWRtaW4= 18 | $ echo -n "1f2d1e2e67df" | base64 19 | MWYyZDFlMmU2N2Rm 20 | ``` 21 | 22 | secrets.yml 23 | 24 | ```yaml 25 | apiVersion: v1 26 | kind: Secret 27 | metadata: 28 | name: mysecret 29 | type: Opaque 30 | data: 31 | password: MWYyZDFlMmU2N2Rm 32 | username: YWRtaW4= 33 | ``` 34 | 35 | 接着,就可以创建 secret 了:`kubectl create -f secrets.yml`。 36 | 37 | 创建好 secret 之后,有两种方式来使用它: 38 | 39 | - 以 Volume 方式 40 | - 以环境变量方式 41 | 42 | ### 将 Secret 挂载到 Volume 中 43 | 44 | ```yaml 45 | apiVersion: v1 46 | kind: Pod 47 | metadata: 48 | labels: 49 | name: db 50 | name: db 51 | spec: 52 | volumes: 53 | - name: secrets 54 | secret: 55 | secretName: mysecret 56 | containers: 57 | - image: gcr.io/my_project_id/pg:v1 58 | name: db 59 | volumeMounts: 60 | - name: secrets 61 | mountPath: "/etc/secrets" 62 | readOnly: true 63 | ports: 64 | - name: cp 65 | containerPort: 5432 66 | hostPort: 5432 67 | ``` 68 | 69 | ### 将 Secret 导出到环境变量中 70 | 71 | ```yaml 72 | apiVersion: extensions/v1beta1 73 | kind: Deployment 74 | metadata: 75 | name: wordpress-deployment 76 | spec: 77 | replicas: 2 78 | strategy: 79 | type: RollingUpdate 80 | template: 81 | metadata: 82 | labels: 83 | app: wordpress 84 | visualize: "true" 85 | spec: 86 | containers: 87 | - name: "wordpress" 88 | image: "wordpress" 89 | ports: 90 | - containerPort: 80 91 | env: 92 | - name: WORDPRESS_DB_USER 93 | valueFrom: 94 | secretKeyRef: 95 | name: mysecret 96 | key: username 97 | - name: WORDPRESS_DB_PASSWORD 98 | valueFrom: 99 | secretKeyRef: 100 | name: mysecret 101 | key: password 102 | ``` 103 | 104 | ## kubernetes.io/dockerconfigjson 105 | 106 | 可以直接用 `kubectl` 命令来创建用于 docker registry 认证的 secret: 107 | 108 | ```sh 109 | $ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL 110 | secret "myregistrykey" created. 111 | ``` 112 | 113 | 也可以直接读取 `~/.docker/config.json` 的内容来创建: 114 | 115 | ```sh 116 | $ cat ~/.docker/config.json | base64 117 | $ cat > myregistrykey.yaml <