# kubernetes 的马洛斯需求
![](https://img.kancloud.cn/2b/01/2b01e7bca49780909621a159652058c1_1151x1024.jpg)
---
### kubernetes 架构图
![](https://img.kancloud.cn/04/ab/04ab8eebb6f785d2739df015ed9ad91e_1060x767.jpg)
---
### kubernetes 主要基本概念和术语
- # master
- 1. Kubernets API server,提供
- 2. Kubernets Controlle Manager (kube-controller-manager),kubernets 里面所有资源对象的自动化控制中心,可以理解为资源对象的大总管。
- 3. Kubernets Scheduler (kube-scheduler),负责资源调度(pod调度)的进程,相当去公交公司的‘调度室’
- # node
每个Node 节点上都运行着以下一组关键进程
- 1. kubelet:负责pod对应的容器创建、启停等任务,同时与master 节点密切协作,实现集群管理的基本功能。
- 2. kube-proxy:实现kubernetes Service 的通信与负载均衡机制的重要组件。
- 3. Docker Engine: Docker 引擎,负责本机的容器创建和管理工作。
- # pod:
![](https://img.kancloud.cn/57/20/5720e75410a14a6a0561e9f7fc8b29f1_630x405.png)
1. Pod是kubernetes中可以创建的最小部署单元
1. V1 core版本的Pod的配置模板见[Pod Template](https://rootsongjc.gitbooks.io/kubernetes-handbook/content/manifests/template/pod-v1-template.yaml)
2. Example:创建一个tomcat实例
apiVersion: vl
kind: Pod
metadata:
name: myweb
labels:
name: myweb
spec:
containers:
- name: myweb
image: kubeguide/tomcat-app:vl
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_HOST
value: 'mysql'
- name: MYSQL_SERVICE_PORT
value: '3306'
- # label(标签)
- 1. 一个label是一个key=value的简直对,其中key与value由用户自己指定。Label可以附加到各种资源对象上,列入Node、pod、Server、RC 等。
- 2. Label 示例如下:
```
版本标签:release:stable,release:canary
环境标签:environment:dev,environment:qa,environment:production
架构标签: tier:frontend,tier:backend,tier:cache
分区标签:partition:customerA,partition:customerB
质量管控标签:track:daily,track:weekly
```
- 3. Label selector
Label不是唯一的,很多object可能有相同的label
通过label selector,客户端/用户可以指定一个object集合,通过label selector对object的集合进行操作。
- Label selector有两种类型:
- equality-based :可以使用=、==、!=操作符,可以使用逗号分隔多个表达式
- et-based :可以使用in、notin、!操作符,另外还可以没有操作符,直接写出某个label的key,表示过滤有某个key的object而不管该key的value是何值,!表示没有该label的object
- 示例
```
$ kubectl get pods -l 'environment=production,tier=frontend'
$ kubectl get pods -l 'environment in (production),tier in (frontend)'
$ kubectl get pods -l 'environment in (production, qa)'
$ kubectl get pods -l 'environment,environment notin (frontend)'
```
- Label Selector 的作用范围1
![](https://img.kancloud.cn/fc/60/fc606517bcc326ff0d284b40cecc68a4_1349x982.png)
- Label Selector 的作用范围2
![](https://img.kancloud.cn/70/53/705371f7a173fcda2cba34578ca3afd0_960x720.png)
- # Replication Contoller
### 简述:
定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所以RC的定义包含如下几个场景:
- 1. Pod 期待的副本数
- 2. 用于筛选Pod的Label Selector
- 3. 当pod的副本数量小于预期的时候,用于创建新的Pod的pod模板(Template)
- 4. 一个完整的RC示例:
```
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: frontend
# these labels can be applied automatically
# from the labels in the pod template if not set
# labels:
# app: guestbook
# tier: frontend
spec:
# this replicas value is default
# modify it according to your case
replicas: 3
# selector can be applied automatically
# from the labels in the pod template if not set,
# but we are specifying the selector here to
# demonstrate its usage.
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
template:
metadata:
labels:
app: guestbook
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
# If your cluster config does not include a dns service, then to
# instead access environment variables to find service host
# info, comment out the 'value: dns' line above, and uncomment the
# line below.
# value: env
ports:
- containerPort: 80
```
- # Deployment
- ### 简述
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。
- ### 典型的应用场景包括:
- 使用Deployment来创建ReplicaSet。ReplicaSet在后台创建pod。检查启动状态,看它是成功还是失败。
- 然后,通过更新Deployment的PodTemplateSpec字段来声明Pod的新状态。这会创建一个新的ReplicaSet,Deployment会按照控制的速率将pod从旧的ReplicaSet移动到新的ReplicaSet中。
- 如果当前状态不稳定,回滚到之前的Deployment revision。每次回滚都会更新Deployment的revision。
- 扩容Deployment以满足更高的负载。
- 暂停Deployment来应用PodTemplateSpec的多个修复,然后恢复上线。
- 根据Deployment 的状态判断上线是否hang住了。
- 清除旧的不必要的 ReplicaSet。
- ### 一个简单的nginx 应用可以定义为:
```
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
```
- # Horizontal Pod Autoscaler
- ### 简述:
应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?这就有赖于Horizontal Pod Autoscaling了,顾名思义,使Pod水平自动缩放。这个Object(跟Pod、Deployment一样都是API resource)也是最能体现kubernetes之于传统运维价值的地方,不再需要手动扩容了,终于实现自动化了,还可以自定义指标,没准未来还可以通过人工智能自动进化呢!
![](https://img.kancloud.cn/97/b7/97b7b01767d6327b0d47e90a08a0dd18_969x554.png)
- ### Metrics支持
在不同版本的API中,HPA autoscale时可以根据以下指标来判断:
- autoscaling/v1
- CPU
- autoscaling/v2alpha1
- 内存
- 自定义
- kubernetes1.6起支持自定义metrics,但是必须在kube-controller-manager中配置如下两项
- --horizontal-pod-autoscaler-use-rest-clients=true
- --api-server指向kube-aggregator,也可以使用heapster来实现,通过在启动heapster的时候指定--api-server=true。查看kubernetes metrics
- 多种metrics组合
- HPA会根据每个metric的值计算出scale的值,并将最大的那个指作为扩容的最终结果
- 一个简单的HPA示例:
```
apiVersion: autoscaling/vl
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
maxReplicas: 5
minReplicas: 2
scaleTargetRef:
kind: Deployment
name: php-apache
targetCPUUtilizationPercentage: 90
```
- # Service
- 简述:
- Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector(查看下面了解,为什么可能需要没有 selector 的 Service)实现的。
- Pod、 RC 与Service的关系 ![](https://img.kancloud.cn/46/df/46dfe1943189b4ae5ffb38c1728581da_960x720.png)
- Endpoint: Pod IP + Container Port
- 一个service 示例
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
- ### kubernetes 的服务发现机制
Kubernetes 支持2种基本的服务发现模式 —— 环境变量和 DNS。
1. - ### 环境变量
当 Pod 运行在 Node 上,kubelet 会为每个活跃的 Service 添加一组环境变量。 它同时支持 Docker links 兼容 变量(查看 makeLinkVariables)、简单的 {SVCNAME}_SERVICE_HOST 和 {SVCNAME}_SERVICE_PORT 变量,这里 Service 的名称需大写,横线被转换成下划线。
举个例子,一个名称为 "redis-master" 的 Service 暴露了 TCP 端口 6379,同时给它分配了 Cluster IP 地址 10.0.0.11,这个 Service 生成了如下环境变量:
```
REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
```
2. - ### DNS
kubernets 通过Add-On增值包的方式引入了DNS 系统,把服务名称作为DNS域名,这样一来,程序就可以直接使用服务名来建立通信连接。目前kubernetes上的大部分应用都已经采用了DNS这一种发现机制,在后面的章节中我们会讲述如何部署与使用这套DNS系统。
3. - ### 外部系统访问service的问题
为了更加深刻的理解和掌握Kubernetes,我们需要弄明白kubernetes里面的“三种IP”这个关键问题,这三种IP 分别如下:
- Node IP: Node(物理主机)的IP地址
- Pod IP:Pod的IP地址
- Cluster IP: Service 的IP地址
4. - ### 服务类型
对一些应用(如 Frontend)的某些部分,可能希望通过外部(Kubernetes 集群外部)IP 地址暴露 Service。
Kubernetes ServiceTypes 允许指定一个需要的类型的 Service,默认是 ClusterIP 类型。
Type 的取值以及行为如下:
- ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType
- NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 <NodeIP>:<NodePort>,可以从集群的外部访问一个 NodePort 服务
- LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
- ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。 没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。
- 一个Node Port 的简单示例
```
apiVersion: vl
kind: Service
metadata;
name: tomcat-service
spec:
type: NodePort
ports:
- port: 8080
nodePort: 31002
selector:
tier: frontend
```
- # Volume 存储卷
- 简述
我们知道默认情况下容器的数据都是非持久化的,在容器消亡以后数据也跟着丢失,所以Docker提供了Volume机制以便将数据持久化存储。类似的,Kubernetes提供了更强大的Volume机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题
1. - Volume
目前,Kubernetes支持以下Volume类型:
```
- emptyDir
- hostPath
- gcePersistentDisk
- awsElasticBlockStore
- nfs
- iscsi
- flocker
- glusterfs
- rbd
- cephfs
- gitRepo
- secret
- persistentVolumeClaim
- downwardAPI
- azureFileVolume
- vsphereVolume
- flexvolume
```
> 注意,这些volume并非全部都是持久化的,比如emptyDir、secret、gitRepo等,这些volume会随着Pod的消亡而消失
2. - PersistentVolume
对于持久化的Volume,PersistentVolume (PV)和PersistentVolumeClaim (PVC)提供了更方便的管理卷的方法:PV提供网络存储资源,而PVC请求存储资源。这样,设置持久化的工作流包括配置底层文件系统或者云数据卷、创建持久性数据卷、最后创建claim来将pod跟数据卷关联起来。PV和PVC可以将pod和数据卷解耦,pod不需要知道确切的文件系统或者支持它的持久化引擎。
3. - PV
PersistentVolume(PV)是集群之中的一块网络存储。跟 Node 一样,也是集群的资源。PV 跟 Volume (卷) 类似,不过会有独立于 Pod 的生命周期。比如一个本地的PV可以定义为
```
kind: PersistentVolume
apiVersion: v1
metadata:
name: grafana-pv-volume
labels:
type: local
spec:
storageClassName: grafana-pv-volume
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: "/data/volume/grafana"
```
pv的访问模式有三种
- 第一种,ReadWriteOnce:是最基本的方式,可读可写,但只支持被单个Pod挂载。
- 第二种,ReadOnlyMany:可以以只读的方式被多个Pod挂载。
- 第三种,ReadWriteMany:这种存储可以以读写的方式被多个Pod共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是NFS。在PVC绑定PV时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式
4. - StorageClass
上面通过手动的方式创建了一个NFS Volume,这在管理很多Volume的时候不太方便。Kubernetes还提供了StorageClass来动态创建PV,不仅节省了管理员的时间,还可以封装不同类型的存储供PVC选用。
- Ceph RBD的例子:
```
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/rbd
parameters:
monitors: 10.16.153.105:6789
adminId: kube
adminSecretName: ceph-secret
adminSecretNamespace: kube-system
pool: kube
userId: kube
userSecretName: ceph-secret-user
```
5. - PVC
PV是存储资源,而PersistentVolumeClaim (PVC) 是对PV的请求。PVC跟Pod类似:Pod消费Node的源,而PVC消费PV资源;Pod能够请求CPU和内存资源,而PVC请求特定大小和访问模式的数据卷。
```
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: grafana-pvc-volume
namespace: "monitoring"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: grafana-pv-volume
```
PVC可以直接挂载到Pod中:
```
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: dockerfile/nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: grafana-pvc-volume
```
6. - 其他volume 说明
- NFS
NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。
```
volumes:
- name: nfs
nfs:
# FIXME: use the right hostname
server: 10.254.234.223
path: "/data"
```
- emptyDir
如果Pod配置了emptyDir类型Volume, Pod 被分配到Node上时候,会创建emptyDir,只要Pod运行在Node上,emptyDir都会存在(容器挂掉不会导致emptyDir丢失数据),但是如果Pod从Node上被删除(Pod被删除,或者Pod发生迁移),emptyDir也会被删除,并且永久丢失。
```
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
emptyDir: {}
```
- # namespace
- 简述
在一个Kubernetes集群中可以使用namespace创建多个“虚拟集群”,这些namespace之间可以完全隔离,也可以通过某种方式,让一个namespace中的service可以访问到其他的namespace中的服务,我们在CentOS中部署kubernetes1.6集群的时候就用到了好几个跨越namespace的服务,比如Traefik ingress和kube-systemnamespace下的service就可以为整个集群提供服务,这些都需要通过RBAC定义集群级别的角色来实现。
- 哪些情况下适合使用多个namesapce
因为namespace可以提供独立的命名空间,因此可以实现部分的环境隔离。当你的项目和人员众多的时候可以考虑根据项目属性,例如生产、测试、开发划分不同的namespace。
- Namespace使用,获取集群中有哪些namespace
```kubectl get ns ```
集群中默认会有default和kube-system这两个namespace。
在执行kubectl命令时可以使用-n指定操作的namespace。
用户的普通应用默认是在default下,与集群管理相关的为整个集群提供服务的应用一般部署在kube-system的namespace下,例如我们在安装kubernetes集群时部署的kubedns、heapseter、EFK等都是在这个namespace下面。
另外,并不是所有的资源对象都会对应namespace,node和persistentVolume就不属于任何namespace。
---
# CI/CD 部署应用
![](https://img.kancloud.cn/96/ef/96efee2ea21865220f01b0e8d4a2ee8c_2395x1156.png)
### 流程说明
应用构建和发布流程说明。
1. 用户向Gitlab提交代码,代码中必须包含Dockerfile
1. 将代码提交到远程仓库
1. 用户在发布应用时需要填写git仓库地址和分支、服务类型、服务名称、资源数量、实例个数,确定后触发Jenkins自动构建
1. Jenkins的CI流水线自动编译代码并打包成docker镜像推送到Harbor镜像仓库
1. Jenkins的CI流水线中包括了自定义脚本,根据我们已准备好的kubernetes的YAML模板,将其中的变量替换成用户输入的选项
1. 生成应用的kubernetes YAML配置文件
1. 更新Ingress的配置,根据新部署的应用的名称,在ingress的配置文件中增加一条路由信息
1. 更新PowerDNS,向其中插入一条DNS记录,IP地址是边缘节点的IP地址。关于边缘节点,请查看边缘节点配置
1. Jenkins调用kubernetes的API,部署应用
- 第一章 kubernetes 功能介绍
- 第二章 在CentOS上部署kubernetes1.7.6集群
- 第三章 创建TLS证书和秘钥
- 第四章 安装kubectl命令行工具
- 第五章 创建kubeconfig 文件
- 第六章 etcd 集群部署
- 第七章 部署k8s-master-v1.7.6节点
- 第八章 部署k8s-v1.7.6 node 节点
- 第九章 kubectl 操作示例
- 第十章 在kubernetes 部署第一个应用
- 第十一章 kubernetes之pod 调度
- 第十二章 K8S服务组件之kube-dns&Dashboard
- 第十三章 Kubernetes中的角色访问控制机制(RBAC)支持
- 第十四章 部署nginx ingress
- 第十五章 使用Prometheus监控Kubernetes集群和应用
- 第十六章 使用helm 应用部署工具
- 第十七章 kubernetes 从1.7 到1.8升级记录
- 第十八章 在kubernetes 使用ceph
- 第十九章 基于 Jenkins 的 CI/CD(一)
- 第二十章 基于jenkins的CI/CD(二)
- 第二十一章 基于prometheus自定指标HPA弹性伸缩