目录
创建pod及deployment、service
kubectl run nginx-deploy --image=nginx:1.20-alpine --port=80 --dry-run=true
kubectl run nginx-deploy --image=nginx:1.20-alpine --port=80 # 创建静态pod
kubectl run nginx-deploy --image=nginx:1.20-alpine --port=80 --replicas=1 # 创建deployment副本,运行此命令,会从远程拉取镜像,创建pod,并运行pod。这个pod受刚创建的deployment控制器管理。
kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP # 将某个控制器所管理的一组pod暴露出去,能够通过service向pod代理
kubectl expose pod nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP # 将某个静态pod暴露出去,
kubectl get svc
'''
nginx ClusterIP 10.104.76.181 <none> 80/TCP 8s
'''
curl 10.104.76.181
'''
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
'''
kubectl run client -it --image=busybox --restart=Never # 图1
ping 10.244.2.4
cat /etc/resolv.conf
'''
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local com
options ndots:5
'''
while true;do wget -O - -q http://nginx:80;done
# 在master节点上进行域名解析
dig -t A nginx.default.svc.cluster.local. @10.96.0.10 # nginx是service名称,default是名称空间,svc.cluster.local.是pod名称,是由核心组件coreDNS服务解析。图2
图1:
图2:
扩缩容(scale)、滚动更新(升级)及回滚
kubectl run myapp --image=ikubernetes/myapp:v1 --replicas=2
kubectl get deployment -w # -w watch 动态监视
kubectl expose deploment myapp --name=myapp
# 1. 扩缩容
kubectl scale --replicas=5 deployment myapp --port=80 # 扩容
kubectl scale --replicas=3 deployment myapp --port=80 # 缩容
# kubectl set image
kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N
[options]
# 2. 滚动更新(升级)
# 类似于金丝雀发布(或者叫灰度发布,但是粒度没有那么细)
kubectl set image deployment myapp myapp=ikubernetes/myapp:v2 # 更改镜像指定是更改哪个控制器下面的pod的镜像,这里控制器名是myapp, 容器名字也叫myapp,后面对应的是镜像 。首先要从远程仓库下载镜像
kubectl rollout status deployment myapp # 查看滚动更新deployment副本的状态
kubectl get pods # 下图1
kubectl describe po myapp-74c9dcb8c-642fm # 查看新版本的pod镜像已经更新到ikubernetes/myapp:v2
# 3. 回滚
kubectl rollout undo (TYPE NAME | TYPE/NAME) [flags] [options]
kubectl rollout undo deployment myapp # 不指定回滚的镜像版本,默认回滚到上一个版本 图3
图1:
图2:
图3:
创建service的时候就会在iptables表中生成转发规则(如果没有ipvs,就会降级到iptables)
iptables -nvL -t nat
集群外部访问service代理的pod
[root@master01 yum.repos.d]# kubectl get svc
'''
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7h1m
nginx ClusterIP 10.104.76.181 <none> 80/TCP 104m
'''
kubectl edit service nginx # 下图1
[root@master01 yum.repos.d]# kubectl get svc
'''
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7h4m
nginx NodePort 10.104.76.181 <none> 80:32444/TCP 108m
'''
curl 192.168.1.130:32444 #
图1:
图2:
kubernetes资源清单
RESTful:
GET PUT DELETE POST、...
kubectl run,get,edit,...
资源:对象
workload: Pod,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,CronJob,...
服务发现及均衡: Service,Ingress,...
配置与存储: Volume,CSI
ConfigMap,Secret
DownwardAPI:向容器中注入信息
集群级资源;
Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding
元数据型资源
HPA,PodTemplate,LimitRange
kubectl get pods
kubectl get po nginx-deploy -o yaml # 将pod信息输出为yaml格式
kubectl get po nginx-deploy -o yaml >nginx-deploy.yaml
apiVersion: v1 # apiversion 的组成是 group/version 如果省略group,表示core,是核心组。
spec: # specification:规格,我们创建的资源对象应该具有什么样的特性,或者满足什么样的规范。用户定义的
status: # 当前资源的当前状态,如果当前状态和目标状态不一样,以目标状态为准,因为目标状态是用户期望的状态;当某一个k8s资源定义好之后,该资源的当前状态应该是无限靠近目标状态。只读的,系统维护
创建资源的方法
apiserver仅接收JSON格式的资源定义;命令行run 后跟的参数只不过被准换为json格式;
yaml格式提供配置清单,apiserver可自动将其转为json格式,而后再提交;
大部分资源的配置清单:
apiVersion: # group/version
kubectl api-Versions
pod属于最核心资源,所以属于核心群组v1;控制器deployment、replicaSet属于应用程序管理的资源对象,它们属于apps/v1群组
kind:资源类别,都是内建的或自定义的(按照固定的语法格式进行定义),不能随意定义;
metadata:元数据
name:当前对象创建,实例化出来的当前类别的资源名称;
namespace:对象所属名称空间,是kuernates级别的概念,与NET、IPC、UTS不同。。。
labels:每一种类型资源的标签
annotations:资源注解
selflink:
每个资源引用的PATH
/api/GROUP/VERSION/namespaces/NAMESPACE/TYPE/NAME
spec:期望的状态,disired state
status:当前状态
# 群组中各版本区别
alpha:内测版,不公开使用
beta:公测版,非稳定,大部分功能都已经测试过并保留,但有极少部分内容有可能会改变,所以不稳定。
stable:稳定版,已有的内容不会改变,最多是在原有的版本中再添加一些内容。
k8s资源属性的类型
<string> :字符串,直接就是 key: value
<integer>:整型
<[]string> : 字符串列表
第一种形式:[" "," "," "]
第二种形式:
- " "
- " "
- " "
<map[string]string> : 映射类型
key1: value1
key2: value2
<Object> 对象,在对象紧接一行,空两格写属性
<[]Object> :对象列表 在对象列表紧接一行,以"-"开头,空一格然后写属性
定义一个pod资源清单
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels: # <map[string]string> 映射类型,类似于json
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: nginx:1.20 # 使用镜像启动默认的命令
- name: busybox
image: busybox:latest
command: # ["/bin/sh","-c","sleep 3600"] # 这里使用自定义的命令,而没使用镜像启动默认的命令,就是为了防止默认命令启动之后会退出
- "/bin/sh"
- "-c"
- "sleep 3600"
运行pod-demo:
kubectl create -f pod-demo.yaml
kubectl get po -o wide -w
kubectl describe po pod-demo
kubectl logs pod-demo -c myapp # 查看pod-demopod内myapp容器日志,如下图2
kubectl logs pod-demo -c busybox # 查看pod-demopod内busybox容器日志
kubectl exec -it pod-demo -c myapp -- /bin/bash
kubectl exec -it pod-demo -c busybox -- /bin/sh
kubectl delete -f pod-demo.yaml # 或者 kubectl delete pod-demo
kubectl get po -l app --show-labels # -l 显示具有app标签名称的pod,--show-labels,显示此类pod的标签列
kubectl get po -L app,run # 显示具有app和run标签名称对应值的pod
kubectl label po pod-demo release=canary # 给pod添加额外的标签
kubectl label po pod-demo release=stable --overwrite # 修改pod的已有标签
kubectl label nodes worker01 disktype=ssd
kubectl get nodes -l disktype --show-labels
kubectl label nodes worker01 disktype=general-disk --overwrite
kubectl get nodes -l disktype --show-labels
图1:
图2:
自主式pod资源对象清单常用字段
资源清单格式:
一级字段:apiVersion(group/version),kind,metadata(name,namespace,labels,annotations,...),spec,status(只读)
Pod资源:
spec.containers <[]object>
- name <string>
image<string>
imagePullPolicy <string>
Always,Never,IfNotPresent
修改镜像中的默认应用:
command,agrs
标签:
key=value # key、value不能超过63个字符,且key的前缀(域名)不能超过253个字符
key:字母、数字、_、-、.
value:可以为空,只能为字母数字开头及结尾,中间可使用
标签选择器:
等值关系:=,==,!=
kubectl get pods -l release=canary
kubectl get pods -l release,app
kubectl get pods -l release=stable,app=myapp
kubectl get pods -l release!=canary
集合关系:
KEY in (VALUE1,VALUE2,...)
kubectl get pods -l "release in (canary,beta,alpha)"
KEY notin (VALUE1,VALUE2,...)
kubectl get pods -l "release notin (canary,beta,alpha)"
许多资源支持内嵌字段定义其使用的标签选择器:
matchLabels: # 直接给定键值支持service,deployment,replicaSet
matchExpressions: # 基于给定的表达式来定义使用标签选择器,支持deployment,replicaSet
{key:"KEY",operator:"OPERATOR",values:[VAL1,VAL2,...]}
操作符:
In,NotIn:values字段的值必须
nodeSelector <map [string]string> # 将此pod调度到节点标签为名称为disktype,值为general-disk的这一类节点上。
nodeName <string> # 将pod调度到节点名称为某个值的某个节点上。
annotations <map[string]string>:
与label不同的地方在于,它不能用于挑选资源对象,仅用于为对象提供"元数据",这些元数据可能被某些程序用到,而且很重要。键值长度不受限制。
pod清单示例
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels: # <map[string]string> 映射类型,类似于json
app: myapp
tier: frontend
annotations:
master01/created-by: cluster admin
spec:
containers:
- name: myapp
image: nginx:1.20 # 使用镜像启动默认的命令
ports: # 仅仅只是告诉我们容器内部监听的端口,并不像docker容器动态绑定到宿主机上的某个端口。
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: # ["/bin/sh","-c","sleep 3600"] # 这里使用自定义的命令,而没使用镜像启动默认的命令,就是为了防止默认命令启动之后会退出
- "/bin/sh"
- "-c"
- "sleep 3600"
nodeSelector:
disktype: general-disk
#nodeName:
k8s中command、args和docker中ENTRYPOINT、CMD的区别和联系
dockerfile中既有CMD:运行容器时,就执行CMD命令;如果既有CMD,又有EntryPoint,CMD命令将被传送给EntryPoint作为EntryPoint的参数,被执行;
k8s中资源清单spec.containers中的command、args参数的含义是:
command(<[]string>):是一个EntryPoint数组,类似于dockerfile中的EntryPoint,但是区别在于,如果要执行shell脚本,必须要在command列表中手动指定shell参数(比如/bin/sh,/bin/bash)。
如果没指定command,就会运行镜像中的EntryPoint,如果只指定command,镜像当中的CMD和ENTRYPOINT都没用了。
args(<[]string>):在k8s中作为entrypoint的参数,就是command的参数;如果没有定义args,镜像中既有CMD指令,又有ENTRYPINT指令,镜像中的CMD指令的参数将作为参数传递给ENTRYPOINT后面的代码。如果这里我们指定了args 参数,镜像中CMD后的参数将不再作为参数传递,而传递agrs中所定义的内容。
官方对command、args同docker中ENTRYPOINT、CMD的区别联系的解释:
Pod生命周期
状态:
Pending:处于挂起状态,已经创建,但是没有适合运行它的节点(调度尚未完成)。
Running:运行状态
Failed:
Successed:
Unknown:比如,apiserver无法连接pod所处节点的kubelet(加入kubelet故障),此时所处的状态就是Unknown
pod创建所经历的阶段:用户请求创建pod时,会将请求提交给apiserver,apiserver将请求信息保存在etcd中,apiserver接下来请求scheduler调度pod,如果成功调度到某个节点,将调度的结果信息更新到etcd资源的的状态信息当中,目标节点kubelet根据apiserver当中的状态变化,发现自己有任务要完成,kubelet会通过apiserver拿到此前用户提交创建的清单,根据此清单去启动并运行这个pod,启动、运行的状态并通过apiserver返回给etcd并保存。
pod生命周期中的重要行为:
1.使用初始化容器完成初始化;
2.在主容器启动后可以做启动后钩子;
3.容器探测
4.在主容器结束前可以做结束前钩子;
在主容器运行当中可以做容器探测:
liveness_probe:探测主容器是否处于运行状态;
rediness_probe:探测主容器中的主进程是否准备就绪并可以对外提供服务;
不论是liveness_probe还是rediness_probe,都可以支持三种方式的探测行为:
1.执行自定义命令;exec
2.向指定的TCP套接字发请求;
3.向指定的http服务发请求;
容器重启策略
kubectl explain pod.spec
restartPolicy # 默认是Always
Always:一旦容器挂了,总是重启
OnFailure:只有当容器状态为错误时才重启,如果是正常终止不重启(比如:在容器启动时运行一个sleep 10,在睡完10s以后,容器就是正常终止,不会重启。)
Never:不重启,即使容器挂了。
当一个容器挂了,根据重启策略,第一次重启是立即进行的,随后可能隔10s,20s,40s,80s,160s,300s去重启。当一个pod被删除时,会进行平滑的迁移,给一个宽限期(好像是30s),先给pod发送terminate信号,之后再发送kill信号,将pod杀死。
1.livenessprobe容器探针
kubectl explain pod.spec.containers
1.livenessProbe <Object>
kubectl explain pod.spec.containers.livenessProbe
exec <Object>
kubectl explain pod.spec.containers.livenessProbe.exec
command <[]string>
httpGet <Object>
kubectl explain pod.spec.containers.livenessProbe.httpGet
host <string> # 主机名,默认是pod IP.
httpHeaders <[]Object> # 自定义携带的请求头
path <string> # uri
port <string> -required- # 端口号或端口名称
scheme <string> # 协议
tcpSocket <Object>
kubectl explain pod.spec.containers.livenessProbe.tcpSocket
host <string> # 默认是pod IP
port <string> -required- # 端口号,或者端口号的名称
failureThreshold <integer> # 探测几次失败之后才认为是失败的,默认是3次
periodSeconds <integer> # 探测周期,每隔多长时间探测一次,默认是10s
timeoutSeconds <integer> # 探测时多长时间没有响应,确认为超时。默认是1s
initialDelaySeconds <integer> # 再容器启动之后的多长时间开始探测,不指定,默认是容器一旦启动,立马进行探测。但是容器启动,不代表容器内的主进程已经正常运行起来了。
2.readinessProbe <Object> # 与livenessprobe探针相似
kubectl explain pod.spec.containers.readinessProbe
exec
httpGet
tcpSocket
3.lifecycle <Object>
kubectl explain pod.spec.containers.lifecycle
postStart <Object>
kubectl explain pod.spec.containers.lifecycle.postStart # 与livenessprobe探针相似
exec <Object>
httpGet <Object>
tcpSocket <Object>
preStop <Object>
kubectl explain pod.spec.containers.lifecycle.preStop # 与livenessprobe探针相似
exec <Object>
httpGet <Object>
tcpSocket <Object>
1.定义一个exec的容器存活性探针
vim liveness-exec-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-container
namespace: default
spec:
containers:
- name: liveness-exec-container
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ['/bin/sh','-c','touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 3600']
livenessProbe:
exec:
command: ['test', '-e', '/tmp/healthy']
initialDelaySeconds: 2
periodSeconds: 3
kubectl get po -w
kubectl describe po liveness-exec-container
2.定义一个tcpSocket的容器存活性探针
tcpSocket探针,类似httpGet中的字段:
host <string>
port <string> -required-
3.定义一个httpGet的容器存活性探针
vim liveness-httpget-container.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-container
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: nginx:1.20
ports:
- name: http
containerPort: 80
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
port: http # 基于上面定义的port名称引用
#port: 80
path: /index.html
initialDelaySeconds: 2
periodSeconds: 3
进入容器liveness-httpget-container删除index.html,模拟httpget方式探针探测容器响应失败,容器的重启情况。
kubectl exec -it liveness-httpget-container -- /bin/bash
cd /usr/share/nginx/html/
rm -rf index.html # 删除容器层的index.html,其实并未删除镜像层的index.html,只是对容器层的index.html文件做了隐藏
当探测默认三次httpget探测,均为请求到index页面,将会在k8s默认的重启策略指定的时间时重启容器,这时,会将镜像层的index.html再次挂到/usr/share/nginx/html/目录内。。容器就可以正常运行了。
2.readinessprobe容器探针
什么是就绪的容器?
kubectl get po # 如下图1
其中READY列:'/' 右侧的数字表示当前pod中有几个容器,'/'左侧的数字表示有几个容器已经就绪(已经运行起来,并可对外提供服务)
service关联一组pod,当一个pod加刚入到service时,可能容器并未初始化完成,并不能对外提供服务。这时候如果没做就绪性探针,那么service代理到刚加入的pod上就无法响应客户端的请求。
1.定义一个httpGet的容器就绪性探针
vim readiness-httpget-container.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-container
namespace: default
spec:
containers:
- name: readiness-httpget-container
image: nginx:1.20
ports:
- name: http
containerPort: 80
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: http # 基于上面定义的port名称引用
#port: 80
path: /index.html
initialDelaySeconds: 2
periodSeconds: 3
kubectl create -f readiness-httpget-container.yaml
kubectl get po # 如下图
删除容器中的index.html页面,模拟就绪性探测失败,容器不能对外提供服务。这时service不会把流量接入到当前pod上。
kubectl exec -it readiness-httpget-container -- /bin/bash
rm -rf /usr/share/nginx/html/index.html
kubectl get po # 如下图1
kubectl describe po readiness-httpget-container # 如下图2
图1:
图2:
再向容器中添加index.html页面,容器立即处于就绪态。
kubectl exec -it readiness-httpget-container -- /bin/bash
echo readiness-httpget-container > /usr/share/nginx/html/index.html
kubectl get po # 如下图1
kubectl describe po readiness-httpget-container # 如下图2
图1:
图2:
3.lifecycle生命周期钩子 poststart
busybox镜像中自带httpd服务,但是没带主页,所以当busybox启动之后可以立马通过poststart钩子发送一个请求,如果请求失败,则终止容器,并根据重启策略重启容器,直到钩子请求正常为止
定义一个poststart钩子
vim poststart-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: poststart-pod
namespace: default
spec:
containers:
- name: busybox-httpd
image: busybox:latest
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
command: ["/bin/sh","-c","echo 'Home Page' >> /tmp/index.html"]
# command: ["/bin/sh","-c","sleep 3600"]
command: ["/bin/httpd"] # 容器在启动之后,执行httpd,没发现/tmp下的index.html文件失败,导致容器终止,在 启动的瞬间,同时postStart钩子也执行exec,发现容器已经终止,所以创建index.html页面失败。
args: ["-f","-h /tmp"] # -f 表示前台运行 -h 指定家目录
场景:在容器启动之后(postStart)克隆仓库,在容器退出之前(preStop)保存数据