Kubernetes复习笔记
Kubernetes要解决什么问题?
手动部署容器难以维护,使用容器编排技术可以解决如下问题:
- 容器崩溃的时候可以自动部署新的容器来代替
- 可以自动增加或者减少容器的数量来满足高可用和自动伸缩的需求
- 可以使用负载均衡来将流量分配到不同的容器中
- 不依赖于云服务提供商的通用配置
Kubernetes核心概念及架构
Kubernetes架构图
Work node架构图
Master node架构图
Pod: kubernetes管理的主要对象,可以由一个或者共享资源的一组容器组成
kubelet: 管理worker node和master node之间的通信
kube-proxy: 运行在work node上,用于管理Node和Pod的网络通信
API Server: 提供API服务
Scheduler: 选择worker node运行Pod
Controller: 监控Pod数量,控制worker node
Worker node: 运行Pod的机器或者虚拟机
Master node: 运行Control Plane的机器或者虚拟机
Kubernetes核心对象
- Pod: Kubernetes管理的最小单元
- 包含一个或多个容器
- Pod中的容器共享网络及存储等资源
- 拥有一个cluster内部IP,Pod中的容器可以通过localhost互相访问
- Deployment: 控制多个Pod
- 用户指定一个状态,Kubernetes负责保持这个状态
- Deployments可以被暂停、删除及回滚
- Deployments可以自动地动态伸缩
1 | $ kubectl create deployment web-app --image caddy |
1 | apiVersion: apps/v1 |
- Service: Exposes Pods to the cluster or externally
- Pod拥有一个内部IP,每次被替换的时候都会改变
- Service可以让一组Pods共享一个IP
- Service可以让Pod可以被外部访问
1 | $ kubectl expose deployment web-app --type=NodePort --name=web-app-service --port=80 |
1 | apiVersion: v1 |
Kubernetes数据管理及存储卷
普通卷
Kubernetes中的volume会随着Pod的结束而结束,而container重启并不影响volume.给Pod添加Volume,需要在pod.spec中添加下面的定义
1 | volumes: |
如果Pod中的container需要使用这个volume需要在container的配置中添加:
1 | volumeMounts: |
- emptyDir类型的volume会创建一个空的目录,在Pod中的containers中共享,Pod删除后volume也会被永久删除。
- 如果想要在多个Pod中共享volume,可以创建hostPath类型的volume,类似于容器中的Bind mount。
- csi(Container Storage Interface)类型可以让同一个厂商的不同类型storage都用这个类型,从而减少了类型的定义。
- 更多的volume类型可以参考这里。
持久卷
PV(Persistent volumes)持久卷不依赖于Pod和Node,Pod删除后PV也会保持,而且另外一个node上的pod也可以共享这个持久卷。Pod可以通过定义一个PVC(PV Claim)来使用持久卷。
PV的定义:
1 | apiVersion: v1 |
PVC的定义:
1 | apiVersion: v1 |
Stateful Sets
Stateful Set可以让Pod按顺序启动,Pod的名字也是有固定的编号。可以通过如下的定义创建一个stateful set:
1 | apiVersion: apps/v1 |
Headless Services
Service可以让请求load balance到不同的Pod。其它Pod可以通过service的DNS例如mysql.default.svc.cluster.local
来访问服务,但无法访问具体的Pod,因为Pod的DNS是根据IP来的,但每次Pod的销毁和创建IP地址都会变化,例如10-40-2-8.default.pod.cluster.local
。如果其它Pod想要直接访问service中的其中一个Pod,例如Mysql的master pod,就需要通过headless service。Headless service可以给Pod赋予固定的DNSpodname.headless-svc-name.namespace.svc.cluster-domain.example
,如mysql-1.mysql-h-svc.default.svc.cluster.local
。创建headless service也很简单,只需要将clusterIP设置为None即可,例如:
1 | apiVersion: v1 |
在stateful set中需要通过serviceName来指定这个headless service.
stateful set的存储解决方案
如果stateful set中的每个Pod都需要自己的PV和PVC,可以通过在stateful set的spec指定volumeClaimTemplates的方式实现,stateful set会保证每个Pod在重建后依然挂载原先的PVC:
1 | volumeClaimTemplates: |
环境变量及配置
Dockerfile中的Entrypoint可以在Kubernetes中用command: []
来设置,而对应的CMD则可以用args: []
来设置
ConfigMap
可以定义ConfigMap来提供容器运行的环境变量:
1 | apiVersion: v1 |
然后在容器的定义中使用它:
1 | env: |
Secret
可以用如下的YAML定义secret:
1 | apiVersion: v1 |
然后再容器中可以把secrets作为环境变量来使用:
1 | envFrom: |
或者:
1 | env: |
在或者把Secret作为存储卷来使用:
1 | volumes: |
- Secret仅仅编码了,并没有加密
- Secret在ETCD中也没有加密
- Namespace中所有有权限创建pod/deployment的用户都可以访问secret
security context
可以在Pod spec或者container中定义securityContext来增强容器的安全性,例如:
1 | securityContext: |
请求资源
在容器的定义中可以使用如下yaml来请求CPU和内存资源及设置容器的资源使用限制:
1 | resources: |
可以创建LimitRange
对象来设置Pod默认的资源限制:
1 | apiVersion: v1 |
可以创建ResourceQuota
来指定namespace的资源限制:
1 | apiVersion: v1 |
Taints及Tolerations
Taint可以给一个Node打一个标签,而toleration则可以让Pod运行于taint标记的Node,没有设置toleration的Pod则不能运行于taint过的node。
给一个Node打上taint标记:
1 | kubectl taint nodes {node-name} {key=value}:{taint-effect} |
给Pod设置toleration:
1 | tolerations: |
taint effect可以是:
- NoSchedule: 没有设置toleration的Pod不能调度到该node
- PreferNoSchedule: 没有设置toleration的Pod不能调度到该node,但不能保证。
- NoExecute: 没有设置toleration的Pod不能调度到该node运行,已经调度的则停止运行。
Node Selectors
可以用下面的命令来给一个node打标签:
1 | $ kubectl label nodes {node-name} size=Large |
然后在Pod的定义中,可以使用node selector来选择node:
1 | nodeSelector: |
Node Affinity
通过node selectors选择node功能比较简单,Node Affinity则功能更加丰富。在Pod的定义中,可以使用affinity来选择node:
1 | affinity: |
Labels, Selectors以及Annotations
Labels用于给Kubernetes对象打标签,而Selectors可以根据这些标签来快速过滤出来所要查找的对象。例如,给一个Pod打标签只需要在metadata中定义labels即可。
1 | metadata: |
通过selector来查找对应的Pod:
1 | $kubectl get pods --selector app=App1 |
Annotations则用于给Kubernetes对象打上用于集成的一些信息,如:
- build,release,image信息
- 开发者的email,phone等信息
升级策略
- 蓝绿升级:先创建一个新的deployment,标记为
version:v2
,将service的selector从version:v1
改成version:v2
- 金丝雀升级: 创建一个新的deployment, 标记为
version:v2
,service不变,标记依然为两个版本共有的标记,例如app: web-app
,将新的deployment的replica从小到大,直到升级为需要的值。然后删除原来的deployment。
Jobs及CronJobs
可以用如下的YAML定义一个Job:
1 | apiVersion: batch/v1 |
可以用如下的YAML定义一个CronJob:
1 | apiVersion: batch/v1 |
网络
Service
- CluseterIP: 仅提供Cluster内部访问的IP地址
- NodePort: 将container的port映射到Node上的某一个port,外部应用则可以通过node的IP及该port访问服务。
- LoadBalancer: 将流量根据一定的策略引入到不同的Pod中
环境变量SERVICE_NAME_SERVICE_HOST保存Pod的Cluster IP. 在指定环境变量的时候,value中填写”service_name.default”可以指向service的Cluster IP.
Ingress
Ingress可以看做是Kubernetes对反向代理的抽象,例如可以把不同Host不同Path的流量导入到不同的service中。
可以通过如下的YAML创建一个Ingress
1 | apiVersion: networking.k8s.io/v1 |
网络策略
网络策略(Network Policy)可以用来控制Pod之间的互相访问。例如,我们创建如下的一个Network Policy.
1 | apiVersion: networking.k8s.io/v1 |
安全
Kubernetes中的认证
- Kubernetes认证主体是User(Admin, developer)及程序(ServiceAccount)。
- User在访问kubernetes资源之前,需要通过kube-apiserver进行认证
- Kubernetes不保存用户名、密码,而是通过下列外部资源进行认证:
- 静态密码文件
- 静态token文件
- 证书
- 外部认证服务
在启动Kubernetes API server的时候可以通过--basic-auth-file
来指定静态密码文件,例如user-details.csv:
1 | password1, user1, user_id1, group1 |
也可以通过--token-auth-file
来指定静态token文件,例如user-tokens.csv
1 | token1, user1, user_id1, group1 |
授权
- AlwaysAllow
- AlwaysDeny
- Node
- ABAC
- RBAC
- Webhook
service account
service account可以看做Kubernetes内部的程序为主体的账户,例如,我们可以通过下面的定义给Kubernetes dashboard来创建一个SA,以及对应的token.
1 | apiVersion: v1 |
创建sa对应的token:
1 | $kubectl create token dashboard-sa |
KubeConfig
API group
Admission Controllers
API版本
/v1alpha1 -> /v1beta1 -> v1