K8s基础原理
一、kubernetes简要概述
Kubernetes 是用于自动部署, 扩展和管理容器化应用程序的开源系统. 它将组成应用程序的容器组合成逻辑单元, 以便于管理和服务发现.
1.k8s功能
- 服务发现和负载均衡
- 存储编排
- 自动部署和回滚
- 自动完成装箱计算
- 自我修复
- 密钥与配置管理
2.k8s架构及组件
3.Kubernetes核心概念
Master
Master节点主要负责资源调度(Scheduler),控制副本(Replication Controller),和提供统一访问集群的入口(API Server)。---核心节点也是管理节点
Node
Node是Kubernetes集群架构中运行Pod的服务节点(亦叫agent或minion)。Node是Kubernetes集群操作的单元,用来承载被分配Pod的运行,是Pod运行的宿主机,由Master管理,并汇报容器状态给Master,当Node节点宕机(NotReady状态)时,该节点上运行的Pod会被自动地转移到其他节点上。
Kubelet组件---Kubelet会从API Server接收Pod的创建请求,启动和停止容器,监控容器运行状态并汇报给Kubernetes API Server。
KuberProxy组件--实现将客户端请求流量转发到内部的pod资源。
Docker Engine(docker)组件,Docker引擎,负责本机的容器创建和管理工作;
Node IP
Node节点的IP地址,是Kubernetes集群中每个节点的物理网卡的IP地址,是真是存在的物理网络,所有属于这个网络的服务器之间都能通过这个网络直接通信;
Pod
Pod直译是豆荚,可以把容器想像成豆荚里的豆子,把一个或多个关系紧密的豆子包在一起就是豆荚(一个Pod)。处于同一个Pod中的容器共享同样的存储空间(Volume,卷或存储卷)、网络命名空间IP地址和Port端口。在k8s中我们不会直接操作容器,而是把容器包装成Pod再进行管理
运行于Node节点上,Pod是k8s进行创建、调度和管理的最小单位.一个Pod可以包含一个容器或者多个相关容器。
Pod 就是 k8s 世界里的"应用";而一个应用,可以由多个容器组成。
pause容器
每个Pod中都有一个pause容器,pause容器做为Pod的网络接入点,Pod中其他的容器会使用容器映射模式启动并接入到这个pause容器。
Pod IP
Pod的IP地址,是Docker Engine根据docker0网桥的IP地址段进行分配的,通常是一个虚拟的二层网络,位于不同Node上的Pod能够彼此通信,需要通过Pod IP所在的虚拟二层网络进行通信,而真实的TCP流量则是通过Node IP所在的物理网卡流出的
资源限额
每个Pod可以设置限额的计算机资源有CPU和Memory;
Pod Volume
Docker Volume对应Kubernetes中的Pod Volume;数间共享数据。
Event
是一个事件记录,记录了事件最早产生的时间、最后重复时间、重复次数、发起者、类型,以及导致此事件的原因等信息。Event通常关联到具体资源对象上,是排查故障的重要参考信息
Endpoint (pod IP+容器port)
标识服务进程的访问点;
ReplicaSet
确保任何指定的Pod副本数量,并提供声明式更新等功能。
Deployment
Deployment是一个更高层次的API对象,它管理ReplicaSets和Pod,并提供声明式更新等功能。
官方建议使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,这就意味着可能永远不需要直接操作ReplicaSet对象,因此Deployment将会是使用最频繁的资源对象。
RC-Replication Controller
Replication Controller用来管理Pod的副本,保证集群中存在指定数量的Pod副本。集群中副本的数量大于指定数量,则会停止指定数量之外的多余pod数量,反之,则会启动少于指定数量个数的容器,保证数量不变。Replication Controller是实现弹性伸缩、动态扩容和滚动升级的核心。
Service
Service定义了Pod的逻辑集合和访问该集合的策略,是真实服务的抽象。它有暴露内部服务的端口到外网的能力。Service提供了一个统一的服务访问入口以及服务代理和发现机制,用户不需要了解后台Pod是如何运行。
一个service定义了访问pod的方式,就像单个固定的IP地址和与其相对应的DNS名之间的关系。
service分为两种ip地址:
一种是对内的叫Cluster IP ,一种是对外的叫external ip:
实现对外ip方式分为:
1.NodePort:通过每个 Node 上的 IP 和内部服务暴露出来的静态端口实现暴露服务。
2.LoadBalancer:使用云提供商的负载均衡器.
3.ingress:使用负载均衡软件实现负载均衡,向外部暴露服务。
Cluster IP
Service的IP地址,特性:
专门给集群内部资源访问的。在k8s集群里面部署的容器,用内部的容器可以访问这个ip地址。但是集群外面的机器不能访问。1.无法被Ping通;
2.Node IP、Pod IP、Cluster IP之间的通信,采用的是Kubernetes自己设计的一种编程方式的特殊的路由规则,与IP路由有很大的不同
Label ---标签与Selectors---选择器
Kubernetes中的任意API对象都是通过Label进行标识,Label的实质是一系列的K/V键值对。Label是Replication Controller和Service运行的基础,二者通过Label来进行关联Node上运行的Pod。
比如,你可能创建了一个"tier"和“app”标签,通过Label(tier=frontend, app=myapp)来标记前端Pod容器,使用 Label(tier=backend, app=myapp)标记后台Pod。然后可以使用 Selectors 选择带有特定Label的Pod,并且将 Service 或者 Replication Controller 应用到上面。一个label是一个被附加到资源上的键/值对,譬如附加到一个Pod上,为它传递一个用户自定的并且可识别的属性。
二、可视化Kuboard部署
[root@kube-master ~]# kubectl apply -f https://addons.kuboard.cn/kuboard/kuboard-v3.yaml
[root@kube-master ~]# kubectl get pod -n kuboard
[root@kube-master ~]# kubectl get svc -n kuboard
初始用户名与密码为 admin Kuboard123
Kubernetes命令补全
yum -y install bash-completion
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
三、集群常用指令
# 查看对应资源: 状态
$ kubectl get <SOURCE_NAME> -n <NAMESPACE> -o wide
# 查看对应资源: 事件信息
$ kubectl describe <SOURCE_NAME> <SOURCE_NAME_RANDOM_ID> -n <NAMESPACE>
# 查看pod资源: 日志
$ kubectl logs -f <SOURCE_NAME_RANDOM_ID> [CONTINER_NAME] -n <NAMESPACE>
# 创建资源: 根据资源清单
$ kubectl apply[or create] -f <SOURCE_FILENAME>.yaml
# 删除资源: 根据资源清单
$ kubectl delete -f <SOURCE_FILENAME>.yaml
# 修改资源: 根据反射出的etcd中的配置内容, 生产中不允许该项操作, 且命令禁止
$ kubectl edit <SOURCE_NAME> <SOURCE_NAME_RANDOM_ID> -n <NAMESPACE>
命令实践
#查看node状态
kubectl get node -o wide
#查看service对象
kubectl get svc
#查看kube-system名称空间内的Pod
kubectl get pod -n kube-system
#查看所有名称空间内的pod
kubectl get pod -A
#查看集群信息
kubectl cluster-info
# 查看各组件信息
kubectl explain pod
#查看帮助信息
kubectl explain deployment
#通过命令行创建名称空间
kubectl create namespace webserver
#删除名称空间
kubectl delete namespace webserver
三、 K8s中的pod
pod是如何被创建的
1.kubectl向k8s api server 发起一个create pod 请求。
2.k8s api server 接收到pod创建请求后,不会去直接创建pod;而是生成一个包含创建信息的yaml。
3.apiserver 将刚才的yaml信息写入etcd数据库。
4.scheduler 查看k8s api,判断:pod.spec.Node == null,若为null,表示这个pod请求是新来的,需要创建;因此先进行调度计算,找到最适合的node。并更新数据库
5.node节点上的kubelet通过监听数据库更新,发现有新的任务与自己的node编号匹配,则进行任务创建。
部署:kubectl apply -f name.yml
删除:kubectl delete -f name.yml
进入容器: kubectl exec -it 容器名 -c 镜像名 -n pod的名字 /bin/bash
例1.创建单容器pod,并做本地解析
apiVersion: v1
kind: Pod
metadata:name: mysqllabels:name: mysql
spec:# 重启策略 Always OnFailurerestartPolicy: OnFailurecontainers:- name: mysqlimage: mysql:5.7imagePullPolicy: IfNotPresentenv:- name: MYSQL_ROOT_PASSWORDvalue: "123456"resources:limits:memory: "1024Mi"cpu: "1000m"ports:- containerPort: 3306nodeSelector:kubernetes.io/hostname: kub-k8s-node2# nodeName: kub-k8s-node2
kind:指定了这个API对象的类型,是一个pod,根据实际情况,此处资源类型可以是Deployment,Job,Ingress、Service等。
metadata:包含pod的一些meta信息,比如名称,namespace,标签等信息
spec:指定该资源的内容,包括一些container,storage,volume以及其他Kubernetes需要的参数,以及诸如是否再容器失败时重新启动容器的属性。
restartPolicy:pod的重启策略,可选参数有:
1.Always:pod中的容器无论如何停止都会自动重启
2.OnFailure:pod中的容器非正常停止会自动重启
3.Never:pod中的容器无论怎样都不会重启
imagePullPolicy:镜像拉取策略,可选参数有:
1.Always:总是拉取
2.IfNotPresent:默认,如果本地有,则不拉取
3.Never:只是用本地镜像,从不拉取
nodeSelector:节点选择器:可以指定node的标签,查看标签指令:
$ kubectl get node --show-labels
nodeName:节点名称:可以指定node的名称进行调度
配置节点标签
添加标签:kubectl label nodes node3 name=value
删除标签:kubectl label nodes node3 name-
例2.创建pod,并做本地解析
apiVersion: v1
kind: Pod
metadata:name: centoslabels:name: centos
spec:containers:- name: centosimage: centos:7command:- "tail"- "-f"- "/dev/null"hostAliases:- ip: "192.168.100.128"hostnames:- "master"- "k8s-master"- "apiserver"
command:启动容器时执行的命令
因为centos没有运行容器进程所以需要使用命令夯住
hostAliases:在容器中的/etc/hosts文件中配置本地解析
例3.pod共享进程
apiVersion: v1
kind: Pod
metadata:name: websitelabels:app: website
spec:shareProcessNamespace: true #共享进程名称空间containers:- name: test-webimage: daocloud.io/library/nginxports:- containerPort: 80- name: busyboximage: daocloud.io/library/busyboxstdin: truetty: truekubectl apply -f pod.yml
#然后通过kubectl进入容器查看
kubectl exec -it website -c busybox --ps aux
共享进程空间:当进入一个pod中有两个容器,进入其中一个容器也能查找另一个容器的进程,但是无法查看到此进程的端口号。
例4. pod共用宿主机namespace
apiVersion: v1
kind: Pod
metadata:name: websitelabels:app: website
spec:hostNetwork: true #共享宿主机网络hostIPC: true #共享ipc通信hostPID: true #共享宿主机的pidcontainers:- name: test-webimage: daocloud.io/library/nginxports:- containerPort: 80- name: busybosimage: daocloud.io/library/busyboxstdin: truetty: true
定义了共享宿主机的Network,IPC,和PID Namespace。这样,此pod里的所有容器会直接使用宿主机的网络,直接与宿主机进行IPC通信,看到宿主机里正在运行的所有进程。但是共享宿主机参数不可与共享进程空间参数同时存在。
例5.钩子函数lifecycle
钩子函数再k8s中的用法与作用
1.PostStart:在容器启动后立即执行,允许容器在启动后执行初始化或配置任务。
2.PreStop:在容器终止之前执行,允许容器在终止前执行清理或者收尾任务。
当钩子函数用来检测端口时,如果端口错误便容器无法启动
apiVersion: v1
kind: Pod
metadata:name: nginx-lifecyclenamespace: defaultlabels:app: nginx
spec:containers:- name: nginx-lifecycleimage: nginx:1.16.1ports:- containerPort: 80protocol: TCPlifecycle: #为钩子函数所用参数postStart:exec:command: ["/bin/sh", "-c", "echo '<h1>this is a nginx-lifecycle test page</h1>' > /usr/share/nginx/html/index.html"]preStop:exec:command: ["/usr/sbin/nginx", "-s", "quit"]
四、容器监控检查及恢复机制
1.命令模式探针
apiVersion: v1
kind: Pod
metadata:name: ccnamespace: mm
spec:containers:- name: nginximage: nginxargs: - /bin/bash- -c- touch /opt/a.txt; sleep 50; rm -rf /opt/a.txt; sleep 20livenessProbe: #探针,健康检查exec: #类型command: #命令- cat- /opt/a.txtinitialDelaySeconds: 5 #健康检查,容器启动五秒后开始执行periodSeconds: 5 #每五秒执行一次
它在启动之后做的第一件事是在/opt目录下创建了一个a.txt文件,以此作为自己已经正常运行的标志。而50s过后,它会把这个文件删除掉。
与此同时,定义了一个这样的 livenessProbe(健康检查)。它的类型是 exec,它会在容器启动后,在容器里面执行一句我们指定的命令,比如:"cat /opt/a.txt"。这时,如果这个文件存在,这条命令的返回值就是 0,Pod就会认为这个容器不仅已经启动,而且是健康的。这个健康检查,在容器启动5s后开始执行(initialDelaySeconds: 5),每5s执行一次(periodSeconds: 5)。
然后进入容器内,进入opt目录查看健康检查
"initialDelaySeconds" 指定容器启动后等待多少秒开始执行就绪探针检查。这个参数的作用是在容器启动后给予一定的时间让应用程序初始化和准备就绪,确保容器内的应用程序已经完全启动。
"periodSeconds" 指定就绪探针检查的频率,也就是容器每隔多少秒进行一次就绪状态的检查。如果容器在指定的时间内被成功检测到为就绪状态,则该容器被认为是准备好接收流量的。
这两个参数通常用于定义容器的健康检查策略,以确保只有在容器完全启动并且应用程序准备就绪时,才将流量引导到该容器上,从而避免在容器尚未完全就绪时接收到流量导致应用程序出现问题。
Pod 恢复的策略:
可以通过设置 restartPolicy,改变 Pod 的恢复策略。一共有3种:
1. Always: 在任何情况下,只要容器不在运行状态,就自动重启容器;
2. OnFailure: 只在容器 异常时才自动重启容器;
3. Never: 从来不重启容器。
实际使用时,需要根据应用运行的特性,合理设置这三种恢复策略。
五、投射数据卷 Projected Volume
1.1.secret实现
secret用来保存小片敏感数据,例如密码,token,或者密钥,放在Secret中为了更方便的控制如何使用数据,并减少暴露的风险。
Pod需要先引用才能使用某个secret,Pod使用secret方式:作为volume的一个域被一个或多个容器挂载。
1.2 secret使用
假如某个Pod要访问数据库,需要用户名密码,现在我们分别设置这个用户名和密码 Secret 对象要求这些数据必须是经过 Base64 转码的,以免出现明文密码显示的安全隐患。
[root@kub-k8s-master ~]# echo -n 'admin' | base64YWRtaW4=
[root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' | base64MWYyZDFlMmU2N2Rm
[root@kub-k8s-master ~]# echo 'MWYyZDFlMmU2N2Rm' | base64 --decode #解码
[root@kub-k8s-master ~]# echo 'MWYyZDFlMmU2N2Rm' | base64 -d #解码
创建一个secret.yaml文件,内容用base64编码
apiVersion: v1
kind: Secret
metadata:name: mysecret
type: Opaque #模糊
data:username: YWRtaW4=password: MWYyZDFlMmU2N2Rm#创建
kubectl apply -f secret.tml
#查看secret
kubectl get secrets
#查看secret详细信息
kubectl get secret mysecret -o yaml
一个Pod中引用Secret例1:
apiVersion: v1
kind: Pod
metadata:name: mypod
spec:containers:- name: testredisimage: daocloud.io/library/redisvolumeMounts: #挂载一个卷- name: foo #这个名字需要与定义的卷的名字一致mountPath: "/etc/foo" #挂载到容器里哪个目录下,随便写readOnly: truevolumes: #数据卷的定义- name: foo #卷的名字这个名字自定义secret: #卷是直接使用的secret。secretName: mysecret #调用刚才定义的secret
映射secret key到指定的路径例2:
apiVersion: v1
kind: Pod
metadata:name: mypod
spec:containers:- name: testredisimage: daocloud.io/library/redisvolumeMounts:- name: foomountPath: "/etc/foo"readOnly: truevolumes:- name: foosecret:secretName: mysecretitems: #定义一个items- key: username #将那个key重新定义到那个目录下path: my-group/my-username #相对路径,相对于/etc/foo的路径
username被映射到了文件/etc/foo/my-group/my-username而不是/etc/foo/username,而password没有被使用,这种方式每个key的调用需要单独用key像username一样调用
以环境变量形式使用Secret例3:
apiVersion: v1
kind: Pod
metadata:name: mypod
spec:containers:- name: testredisimage: daocloud.io/library/redisenv: #定义环境变量- name: SECRET_USERNAME #创建新的环境变量名称valueFrom:secretKeyRef: #调用的key是什么name: mysecret #变量的值来自于mysecretkey: username #username里面的值
2.ConfigMap详解
ConfigMap与Secret类似,用来存储配置文件的Kubernetes资源对象,所有的配置内容都存储在etcd中。
与Secret的区别:ConfigMap保存的是不需要加密的,应用所需的配置文件。
创建ConfigMap的方式
命令行方式
方式1:通过直接在命令行中指定configmap参数创建,即--from-literal
方式2:通过指定文件创建,即将一个配置文件创建为一个ConfigMap,--from-file=<文件>
方式3:通过指定目录创建,即将一个目录下的所有配置文件创建为一个ConfigMap,--from-file=<目录>
配置文件方式
方式4:事先写好标准的configmap的yaml文件,然后kubectl create -f 创建