《基于Kubernetes的容器云平台实战》读书笔记
用户可以通过PaaS平台完成应用的构建、部署、运维管理,而不需要自己搭建计算执行环境。
IaaS 系统提供给用户的是虚拟机资源;
PaaS 负责应用的部署和运维,实现应用的弹性伸缩和高可用等功能,用户只需专注于应用的开发。
要实现应用的自由弹性伸缩,就需要应用做到无状态化,所有有状态的信息(如DB、Session等等)都要放到服务节点上的资源池中。
容器的好处:
- 提供资源隔离,利用率提升;
- 具备秒级弹性的能力;
- 容器镜像技术,解决了包括应用及其依赖环境的一致性问题,简化业务交付流程。
Docker 技术:
1. 将应用和依赖的框架中间件等运行环境都打包到Docker 镜像,用户应用部署并运行在隔离的Docker 容器中,不再依赖宿主机来提供运行环境支持,从而实现了应用和PaaS平台解耦;
2. 用户向PaaS 平台提交的不再是代码,而是Docker 镜像,PaaS 平台也无须再为应用准备各种运行时环境。
微服务架构提高了应用的灵活性、扩展性和高可用性。
为什么需要 Kubernetes ?
真实的生产环境应用会包含多个容器,而这些容器还很可能会跨越多个服务器主机部署。
Kubernetes 提供了大规模部署容器的编排与管理能力。Kubernetes 编排让你能够构建多容器的应用服务,在集群上调度或伸缩这些容器,以及管理它们随时间变化的健康状态。
Kubernetes 也需要与网络、存储、安全、监控等其它服务集成才能提供综合性的容器基础设施。
Kubernetes 提供了一个便捷、有效的PaaS 平台,让用户可以在物理机和虚拟机集群上调度和运行 Docker 容器,可以帮助用户在生产环境中完全实施并依托基于容器的基础架构运营。
在Kubernetes 中创建、调度和管理的最小单位是Pod,而不是Docker 容器。
Service
Service 是一组协同工作的Pod,就像多层架构应用中的一层,是Pod 的路由代理抽象,用于解决Pod 之间的服务发现问题。
Service 的引入旨在保证Pod的动态变化对访问端透明,访问端只需要知道Service的地址,由Service 来提供代理。
构成服务的Pod 组通过Label 选择器来定义。
Kubernetes 通过给服务分配静态 IP 地址和域名来提供服务发现机制,并且以轮询调度的方式将流量负载均衡到能与选择器匹配的Pod上。
Node
每个Node节点主要由:Kubelet、kube-proxy、docker runtime 组成。
Master
主要由:API Server、Scheduler、Controller Manager、etcd 组成。
Kubernetes 集群
Kubernetes 管理节点是Kubernetes 集群的大脑。
Kubernetes 将Etcd 作为分布式配置存储,各种 Kubernetes 状态存储在 Etcd 中。
在Node 节点运行的Kubelet 服务中内嵌了一个Advisor 服务,Advisor 是Google 的另外一个开源项目,用于实时监控Docker 容器的性能指标。
Controller Manager 是一个控制器集合。在Kubernetes 集群中,每个控制器的核心工作原理是:每个控制器通过 API 服务器查看系统的运行状态,并尝试着将系统状态从“现有状态”修正到“期望状态”。
调度器 -- 在整个调度过程中涉及到3个对象:待调度Pod列表、可用Node列表、以及调度算法和调度策略。
Kubernetes 作为容器应用的管理中心,对集群内部所有容器的生命周期进行管理。
Kubernetes Master 扮演总控中心的角色,其主要的3个服务:kube-api server、kube-controller-manager和kube-scheduler 通过不断与工作节点上的kubelet和kube-proxy 进行通信,来维护整个集群的健康工作状态。
在Kubernetes 中,健康检查监视器由Kubelet 代理。
Pod
Pod 是Kubernetes 的最基本操作单元,也是应用运行的载体,包含一个或多个密切相关的容器。
Kubectl
就是将用户的输入转换成对API 服务器的REST API 调用,然后发起运程调用并输出调用结果。可以认为Kubectl 是API 服务器的客户端工具。
busyboxpod.yaml 示例pod:
apiVersion: v1
kind: Pod
metadata:
name: busyboxpod
spec:
containers:
- name: testpod
image: busybox
command:
- sleep
- "3600"
[root@centos-110 kubedemo]# kubectl create -f busyboxpod.yaml
# 使用yaml 格式来显示Pod 的详细信息,或者 -o json 输出json格式
[root@centos-110 kubedemo]# kubectl get pod busyboxpod -o yaml
[root@centos-110 kubedemo]# kubectl get pods busyboxpod
NAME READY STATUS RESTARTS AGE
busyboxpod 0/1 Completed 0 20s
READY: 显示Pod 中容器信息;
/ 1: 右边的数字表示Pod 包含的容器总数;
0 /: 左边的数字表示准备就绪的容器数目;
Pod 的名称:metadata.name
Pod 的IP 地址:status.podIP
busyboxpod2.yaml 示例pod:
apiVersion: v1
kind: Pod
metadata:
name: busyboxpod2
spec:
containers:
- name: testpod
image: busybox
command:
- sleep
- "3600"
env:
- name: ENV_NAME
value: "rickie-pod"
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
[root@centos-110 kubedemo]# kubectl exec -it busyboxpod2 /bin/sh
/ # printenv
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=busyboxpod2
ENV_NAME=rickie-pod
.......
Pod 调度
指将创建好的Pod 分配到某一个Node上。
Label
在Kubernetes 中,可以使用Label 键值对来标识附加到系统中的任何API 对象,如Pod、Service、Replication Controller等。
Replication Controller 演示
nginx-pod-rc.yaml 示例:
apiVersion: v1
kind: ReplicationController
metadata:
name: mynginxpod
spec:
replicas: 2
selector:
app: nginxpod // 通过这个标签找到生成的Pod
template:
metadata:
labels: // 定义标签
app: nginxpod // 键值对,这里必须和 selector 中定义的键值对一样
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
Kubernetes 通过 template 来生成Pod,创建完成后,template 和 Pod 就没有任何关系了。RC 通过 label 查找对应的Pod 并控制副本。
Pod 模板中的Label 不能为空,否则 Replication Controller 无法同 Pod 模板创建出来的Pod 进行关联。
[root@centos-110 kubedemo]# kubectl get pods --selector app=nginxpod
NAME READY STATUS RESTARTS AGE
mynginxpod-l2j5m 1/1 Running 0 2m
mynginxpod-lwc6x 1/1 Running 0 2m
[root@centos-110 kubedemo]# kubectl get pods --selector app=nginxpod --label-columns app
NAME READY STATUS RESTARTS AGE APP
mynginxpod-jsttr 1/1 Running 0 11s nginxpod
mynginxpod-lwc6x 1/1 Running 0 3m nginxpod
[root@centos-110 kubedemo]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mynginxpod 2 2 2 10m
使用kubectl delete 命令删除 Replication Controller,默认会删除 Replication Controller 关联的所有Pod 副本。
[root@centos-110 kubedemo]# kubectl delete rc mynginxpod
replicationcontroller "mynginxpod" deleted
[root@centos-110 kubedemo]# kubectl get pods --selector app=nginxpod --label-columns app
NAME READY STATUS RESTARTS AGE APP
mynginxpod-jsttr 1/1 Running 0 7m nginxpod
mynginxpod-lwc6x 1/1 Running 0 11m nginxpod
# 将Pod 的标签手工修改为 app=rename
[root@centos-110 kubedemo]# kubectl label pod mynginxpod-jsttr app=rename --overwrite
pod "mynginxpod-jsttr" labeled
# 对RC而言,关联的Pod减少了一个,自然会触发创建新的Pod
[root@centos-110 kubedemo]# kubectl get pods --selector app=nginxpod --label-columns app
NAME READY STATUS RESTARTS AGE APP
mynginxpod-h75hb 1/1 Running 0 7s nginxpod
mynginxpod-lwc6x 1/1 Running 0 11m nginxpod
# 发现运行的Pod,有3个
[root@centos-110 kubedemo]# kubectl get pods --label-columns app
NAME READY STATUS RESTARTS AGE APP
mynginxpod-h75hb 1/1 Running 0 50s nginxpod
mynginxpod-jsttr 1/1 Running 0 8m rename
mynginxpod-lwc6x 1/1 Running 0 12m nginxpod
[root@centos-110 kubedemo]# kubectl get pods --show-labels
# 扩容
[root@centos-110 kubedemo]# kubectl scale rc mynginxpod --replicas=5
replicationcontroller "mynginxpod" scaled
[root@centos-110 kubedemo]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mynginxpod 5 5 4 16m
# 缩容
[root@centos-110 kubedemo]# kubectl scale rc mynginxpod --replicas=1
replicationcontroller "mynginxpod" scaled
[root@centos-110 kubedemo]# kubectl get rc -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
mynginxpod 1 1 1 18m nginx nginx app=nginxpod
新一代副本控制器 ReplicaSet
ReplicaSet 引入了基于子集的Selector 查询条件,而Replication Controller 仅支持基于值相等的Selector 条件查询。
Horizontal Pod Autoscaler
在Kubernetes 中,通过Horizontal Pod Autoscaler 来实现Pod 的自动伸缩。
Deployment
提供了一种更加坚定的更新RS和Pod的机制。
# nginx-deployment-v1.yaml 演示文件
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
[root@centos-110 kubedemo]# kubectl create -f nginx-deployment-v1.yaml
deployment.apps "nginx-deployment" created
[root@centos-110 kubedemo]# kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 2 2 2 2 12s
[root@centos-110 kubedemo]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-75675f5897-jq28b 1/1 Running 0 2m app=nginx,pod-template-hash=3123191453
nginx-deployment-75675f5897-nk4pg 1/1 Running 0 2m app=nginx,pod-template-hash=3123191453
# 使用 --record选项是为了记录当前执行的命令所创建/更新的资源
# 即使用 --record 选项执行的deployment 都会被记录下来,用于以后查看每次deployment的细节
# 查看所有 deployment 的历史,或者回滚到某一历史版本。
[root@centos-110 kubedemo]# kubectl create -f nginx-deployment-v1.yaml --record
deployment.apps "nginx-deployment" created
[root@centos-110 kubedemo]# kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl create --filename=nginx-deployment-v1.yaml --record=true
[root@centos-110 kubedemo]# kubectl get deploy --show-labels
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE LABELS
httpd 3 3 3 3 111d run=httpd
nginx-deployment 2 2 2 2 5m <none>
# 将nginx 的版本进行升级
[root@centos-110 kubedemo]# kubectl set image deployment/nginx-deployment nginx=nginx:1.8
deployment.apps "nginx-deployment" image updated
# 创建时加 --record 选项起的作用
[root@centos-110 kubedemo]# kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl create --filename=nginx-deployment-v1.yaml --record=true
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.8
# 升级回滚
[root@centos-110 kubedemo]# kubectl rollout undo deployment/nginx-deployment
deployment.apps "nginx-deployment"
# 查询详细信息,获取进度
[root@centos-110 kubedemo]# kubectl describe deploy nginx-deployment
# 查看 deployment 的变更信息
[root@centos-110 kubedemo]# kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.8
3 kubectl create --filename=nginx-deployment-v1.yaml --record=true
StatefulSet 与有状态的应用及分布式系统一起使用
StatefulSet 需要 Headless Service 负责Pod的网络一致性(必须创建此服务)
StatefulSet are stable (GA) in 1.9
[root@centos-110 kubedemo]# kubectl create -f statefulset-demo.yaml
service "nginx" created
statefulset.apps "my-web" created
# 验证
[root@centos-110 kubedemo]# kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None <none> 80/TCP 1m
[root@centos-110 kubedemo]# kubectl get sts my-web
NAME DESIRED CURRENT AGE
my-web 2 2 1m
# StatefulSet 中的Pod 拥有一个唯一的顺序索引和稳定的网络身份标识
[root@centos-110 kubedemo]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
my-web-0 1/1 Running 0 4m
my-web-1 1/1 Running 0 4m
# 扩容/缩容 StatefulSet
[root@centos-110 kubedemo]# kubectl scale sts my-web --replicas=4
statefulset.apps "my-web" scaled
[root@centos-110 kubedemo]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
my-web-0 1/1 Running 0 8m
my-web-1 1/1 Running 0 8m
my-web-2 1/1 Running 0 1m
my-web-3 1/1 Running 0 41s
[root@centos-110 kubedemo]# kubectl scale sts my-web --replicas=1
Pod在扩容、缩容时,会按照序号顺序创建或Terminate。
# 可以通过 -w (watch)参数查看创建过程
[root@centos-111 .kube]# kubectl get pods -w -l app=nginx
IP-per-Pod 模型
Kubernetes 网络模型设计的一个基础原则:每个Pod 都拥有一个独立的IP 地址,而且假定所有 Pod 都在一个可以直接连通的、扁平的网络空间中。
一个Pod 一个IP 的设计模型 -- IP-per-Pod 模型
Pod 可以看做一台独立的虚拟机或者物理机。
容器及Pod 间通信
- 同一个Pod 的容器共享同一个网络命名空间;
- 同一个Node 中Pod的默认路由都是Docker0 的地址,由于它们关联在同一个Docker0 网桥上,地址网段相同,所以它们之间能够之间通信;
- 不同Node中Pod 间通信 -- Docker0 网桥和宿主机网卡是两个完全不同的IP 网段,并且Node 之间的通信只能宿主机的物理网卡进行,因此想要位于不同Node 上的Pod容器之间的通信,就必须想办法通过主机的IP 地址来进行寻址和通信。
Kube-Proxy
是一个简单的网络代理和负载均衡器,它的作用主要是负责 Service的实现: 实现从Pod 到Service,以及从NodePort 向Service 的访问。
DNS 服务发现机制
kube-dns 用来为 Service 分配子域名,以便集群中的Pod 可通过DNS 域名获取 Service 的访问地址。
Kubernetes 提供了一个DNS 插件 Service:
[root@centos-110 kubedemo]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 119d
# 通过CURL应用进行测试
# nslookup -- 用于查询DNS记录,查看域名解析是否正常
[root@centos-110 kubedemo]# kubectl run -it --image=radial/busyboxplus:curl curl --rm
If you don't see a command prompt, try pressing enter.
[ root@curl-775f9567b5-274ts:/ ]$ nslookup nginx
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: nginx
Address 1: 220.250.64.225
[ root@curl-775f9567b5-274ts:/ ]$ nslookup httpd-svc
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: httpd-svc
Address 1: 10.100.84.102 httpd-svc.default.svc.cluster.local
Headless 服务
对于不想做负载均衡或者不希望有一个ClusterIP 时,可以创建一个Headless 类型的Service,将 spec.clusterIP 设置为 None。
对于这样的Service,系统不会为它们分配对应的IP。
Kubernetes 服务
Service 是Kubernetes 最核心的概念,通过创建 Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求进行负载分发到后端的各个容器应用上。
集群中每个Node 节点都有一个组件kube-proxy,它实际上是为 Service 服务的。
通过 kube-proxy,实现流量从 Service 到Pod的转发,kube-proxy 也可以实现简单的负载均衡功能。
实现方式: iptables 方式
采用 iptables 来实现 LB,是当前 kube-proxy 的默认方式。