自己的笔记,没有整理,慎看。。
章节目录
1. 容器
1.1 容器的本质
1.2 容器镜像
1.3 容器编排
2. k8s集群搭建
2.1 kubeadm工作流程介绍
2.2 搭建完整的k8s集群
2.3 编写yaml文件
3. K8s容器编排和作业管理
3.1 Pod
3.2 Deployment
3.3 StatfulSet
3.4 DeamonSet
3.5 Job
1. 容器
1.1 容器的本质
容器的本质是一种特殊的进程
启动进程的时候指定namespace,在/proc/pid/ns查看
/sys/fs/cgroup/下面限制进程的资源使用
1.2 容器镜像
容器镜像rootfs打包了所有的程序依赖的操作系统文件和目录(但不包含内核),解决了一致性的问题
docker镜像的创新:层。多个增量rootfs联合挂载成为一个rootfs
层都放置在 /var/lib/docker/aufs/diff 目录下
每个层是一个增量rootfs,层们叠加起来是一个完整的操作系统环境,被联合挂载在/var/lib/docker/aufs/mnt/
一个镜像由哪些层组成:/sys/fs/aufs
对容器镜像rootfs来说,层分三部分:
第一部分只读层:挂载方式都是只读的ro+wh,即 readonly+whiteout
第二部分可读写层:挂载方式为:rw即read write。存放对rootfs的增删改
第三部分init层:docker内部层,专门存放/etc/hosts, /etc/resolv.conf。
分三类层的原因是可以分开使用,docker commit时,实际上就是在容器运行起来后,把可读写层,加上原先容器镜像的只读层,打包组成了一个新的镜像,而init层的文件故意不打包了,因为那是你自己环境的修改
1.3 Volume
解决的问题:如何让容器里的进程访问到宿主机上的文件?
在docker run的时候声明一个volume,实现原理:
在rootfs准备好后,在chroot执行之前,执行bind mount挂载,这个挂载只有容器内部可见,宿主机不可见,由于是绑定挂载,在容器目录进行的所有操作实际发生在宿主机,而由于宿主机看不到挂载点的存在,容器中可读写层的目录也是空的,不会被打到镜像里
1.4 k8s里的容器编排
k8s不仅仅提供一个给定的集群能够将容器以容器镜像为基础运行起来,并提供路由、监控、灾备、可扩展等运维能力,
他的设计思想在于普适性,以宏观的角度,以统一的方式能适配各种任务与任务之间的关系,并对将来可能出现的新的关系支持自定义
例如,两个任务需要非常频繁的交互,通过本地文件进行信息交互,在常规情况下,他们会部署在同一台机器,在k8s中,他们做为两个容器被划分为一个pod,pod里的他们共享同一个network ns,同一个volume
又例如,web应用和db的关系,如果他们是两个容器,当他们的ip变化,将无法找到服务,而k8s里,给数据库pod绑定service,service的ip终生不变,作为pod的入口暴露一个稳定ip
再例如,web应用需要访问db,k8s提供secret对象,保存在etcd里的数据,启动pod时,以volume的方式挂载到容器,就有权限了
本章命令总结
docker build -t helloworld .
docker image ls
docker run -p 4000:80 helloworld 启动容器
docker tag helloworld geektime/helloworld:v1 起名字
docker push geektime/helloworld:v1 push到docker仓库
docker exec -it 4ddf4638572d /bin/sh 进入容器,使用setns()系统调用
docker commit 4ddf4638572d geektime/helloworld:v2 提交修改到镜像中保存
2. K8s集群搭建
2.1 使用kubeadm,kubeadm工作流程:
0. 安装kubeadm,kubeadm 和 kubelet、kubectl、kubernetes-cni会一起安装好
1. 前置检查
2. 生成证书和目录
3. 为其他组件生成访问kube-apiserver所需的配置文件/etc/kubernetes/xxx.conf
4. 为master组件(kube-apiserver、kube-controller-manager、kube-scheduler)生成pod配置文件
5. 为集群生成一个 bootstrap token, 安全认证用到,用来让安装了 kubelet 和 kubadm 的节点通过kubeadm join加入到集群中
6. kubeadm 会将 ca.crt 等 Master 节点的重要信息,通过 ConfigMap 的方式保存在 Etcd 当中,供后续部署 Node 节点使用
7. 最后一步, 安装默认插件kube-proxy 和 DNS,提供服务发现和DNS功能,也是通过yaml创建pod
2.2 部署完整的k8s集群的过程
1. 在所有节点上安装 Docker 和 kubeadm;
2. 部署 Kubernetes Master;
3. 部署容器网络插件;
4. 部署 Kubernetes Worker;
5. 部署 Dashboard 可视化插件;
6. 部署容器存储插件。
2.3 yaml配置文件说明
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.8
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: nginx-vol
volumes:
- name: nginx-vol
emptyDir: {}
总体分为两部分:metadata存放元数据;spec存放对象定义和功能的描述
apiVersion: apps/v1 --- 表示这是一个api对象,这里是Deployment api对象管理Pod api对象。控制器模式
metadata --- 元数据,api对象的标识,包含name, Annotations, labels等, labels用来给spec.selector.matchLabels过滤
kind: Deployment --- 类型是Deployment
spec.replicas --- Pod副本数是2
spec.template --- Pod长什么样
spec.containers.image --- Pod的镜像
volume:emptyDir 不显示声明宿主机目录;对应的有hostPath,显示声明
spec.volumeMounts 要挂载哪个volume
3. k8s容器编排基础
3.1 pod
是k8s里最小调度单位,可看做一个进程组或者像虚拟机,容器则是进程,如果多个进程(容器)因为会有直接的文件交换/本地通信/频繁调用/共享资源必须放在一起部署
本质上Pod是逻辑概念,他们只是一组共享了同一个 Network Namespace,并且可以声明共享同一个 Volume的容器
Pod中,会有一个infra容器被第一个创建,他很小用的是k8s.gcr.io/pause镜像,其他的容器通过join network ns的方式,与infra关联,作用是让容器们是平等关系。
三个例子帮助理解pod
例子一:考虑一个war包和web服务器的关系
方式1. 把WAR包和web服务器打进一个镜像
方式2. 只把web服务器打成镜像,挂载一个volume保存war包
POD方式:把war包和web服务器分别做成镜像,然后作为同一个Pod,volume被两个容器共享。是sidecar的方式,意识是启动一个辅助容器,完成主容器之外的工作
例子二,容器日志收集
主容器将日志输出到/var/log,volume挂载
sidecar容器同样的volume挂载,只做一件事,把日志拿出来处理
例子三,sidercar和主容器共享network ns,所以可以用sidecar来管理网络,不用影响主容器
3.1.1 pod和容器
pod实际上是对容器的进一步抽象和封装
如何判断哪些属性是属于pod哪些是属于容器的呢?
原则:凡是调度、网络、存储,以及安全相关的属性,跟容器的namespace相关的属性 ,共享宿主机的ns属性,这些都是 Pod 级别的。他们都是描述机器的
一些pod属性:
NodeSelector将POD与node绑定
NodeName一旦赋值,会被k8s认为已经调度过
HostAliases定义pod里的hosts文件
一些容器属性:
ImagePullPolicy(always,Never 或者 IfNotPresentAlways每次都拉取镜像
LifecyclepostStart,preStop 容器启动/退出时做的事
3.1.2 Pod声明周期
Pending这个状态意味着,Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中。但是,这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。
Running这个状态下,Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。
Succeeded这个状态意味着,Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
Failed这个状态下,Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。这个状态的出现,意味着你得想办法 Debug 这个容器的应用,比如查看 Pod 的 Events 和日志。
Unknown这是一个异常状态,意味着 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver,这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题。
3.1.3 Project Volume
Project Volume存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。这些特殊 Volume 的作用,是为容器提供预先定义好的数据。所以,从容器的角度来看,这些 Volume 里的信息就是仿佛是被 Kubernetes“投射”(Project)进入容器当中的。
相比环境变量重要的优点:可以被自动更新
有以下4种:
1. Secret;需要加密的,生产环境使用加密插件,例如数据库连接
2. ConfigMap;不需要加密的配置信息,例如普通配置文件
3. Downward API;让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的静态信息,例如打印pod信息到日志
4. ServiceAccountToken访问api的授权,默认会有默认的volume
3.1.4 容器健康检查和恢复
这个探针通过静态文件和http url两种方式:
1. cat /tmp/healthy判断容器健康,返回0就正常
2. 配置一个url
initialDelaySeconds: 5 pod启动5秒后执行
pod状态不是running会重新创建,在同个node,不想同node用deployment,合理设置restartPolicy
还有个readinessProbe 的字段
readinessProbe 检查结果的成功与否,决定的这个 Pod 是不是能被通过 Service 的方式访问到
关于pod和容器的状态,两个原理:
1. 只要 Pod 的 restartPolicy 指定的策略允许重启异常的容器(比如:Always),那么这个 Pod 就会保持 Running 状态,并进行容器重启。否则,2. Pod 就会进入 Failed 状态 。对于包含多个容器的 Pod,只有它里面所有的容器都进入异常状态后,Pod 才会进入 Failed 状态。在此之前,Pod 都是 Running 状态。
示例:
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: test-liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
3.2 控制器Deployment
其他控制器:
$ cd kubernetes/pkg/controller/
$ ls -d */
deployment/ job/ podautoscaler/
cloud/ disruption/ namespace/
replicaset/ serviceaccount/ volume/
cronjob/ garbagecollector/ nodelifecycle/ replication/ statefulset/ daemon/
...
控制器们都遵循 Kubernetes 项目中的一个通用编排模式,即:控制循环(control loop)
意思是会对比实际状态和期望状态,并且循环的调整直到达到期望状态。
deployment操纵是replicaSet 而不是pod
deployment创建会同时创建rs,rs名字里有一个hash字符串,被作为受它管理的pod的标签,不与其他pod混淆
deployment的状态:
DESIRED用户期望的
CURRENT当前处于running状态的pod
UP-TO-DATE(deployment有而rs没有)当前处于最新版本的POD,所谓最新版本指的是 Pod 的 Spec 部分与 Deployment 里 Pod 模板里定义的完全一致;
AVAILABLE当前可用的,即既是Running状态,又是最新版本,并且处于Ready(健康检查正确)的个数
滚动更新的实现:把原rs里的副本一个个减少,把新rs里的副本一个个增加
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
...
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
maxSurge 指定的是除了 DESIRED 数量之外,在一次“滚动”中,Deployment 控制器还可以创建多少个新 Pod;而 maxUnavailable 指的是,在一次“滚动”中,Deployment 控制器可以删除多少个旧 Pod。