Configmap
ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
ConfigMap 将你的环境配置信息和 容器镜像 解耦,便于应用配置的修改。
使用场景:
- 通过Configmap给pod定义全局环境变量
- 通过Configmap给pod传递命令行参数,如mysql -u -p中的账户名密码可以通过Configmap传递。
- 通过Configmap给pod中的容器服务提供配置文件,配置文件以挂载到容器的形式使用。
注意事项:
- Configmap需要在pod使用它之前创建。
- pod只能使用位于同一个namespace的Configmap,及Configmap不能夸namespace使用。
- 通常用于非安全加密的配置场景。
- Configmap通常是小于1MB的配置。
使用configmap提供配置文件的yaml
apiVersion: v1
kind: ConfigMap #利用configmap提供nginx配置
metadata:
name: nginx-config #configmap卷名称,后面会以此名称调用configmap卷
data:
default: | ##item名称,作为key被调用
server {
listen 80;
server_name www.mysite.com;
index index.html index.php index.htm;
location / {
root /data/nginx/html;
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
}
}
}
---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: ng-deploy-80
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx:1.20.0
ports:
- containerPort: 80
volumeMounts:
- mountPath: /data/nginx/html # nfs卷
name: nginx-static-dir
- name: nginx-config #调用configmap卷
mountPath: /etc/nginx/conf.d
volumes:
- name: nginx-static-dir
nfs:
server: 192.168.110.184
path: /data/k8sdata/nginx
- name: nginx-config
configMap:
name: nginx-config
items:
- key: default
path: mysite.conf #将value保存在mysite.conf中
---
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-80
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30019
protocol: TCP
type: NodePort
selector:
app: ng-deploy-80
该文件生成了一个configmap卷,一个svc,一个挂载了该configmap卷的deployment控制器
在nfs服务存储上添加index.html
进入pod,找到configmap挂载目录
可以看到mysite.conf文件
查看容器中nfs挂载目录
将挂载目录include到nginx.conf中
将svc地址配置到负载均衡器中
修改宿主机host文件 添加域名 测试
使用configmap提供环境变量的yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
username: "user1" ## key和value
password: "12345678" ## key和value
---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: ng-deploy-80
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx
env:
- name: MY_USERNAME
valueFrom:
configMapKeyRef:
name: nginx-config
key: username
- name: MY_PASSWORD ##env变量名称
valueFrom:
configMapKeyRef:
name: nginx-config
key: password
######
- name: "password" #直接传递环境变量 生产中一边使用这种方式
value: "123456"
ports:
- containerPort: 80
创建configmap和pod后, 进入pod查看环境变量
可以看到两种不通方式传递环境变量的key_value
修改configmap.yaml 修改环境变量
重新apply 进入容器 发现容器中的环境变量没有变化
得出结论,configmap修改后,需要重建容器,配置才能更改
Secret
Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。
由于创建 Secret 可以独立于使用它们的 Pod, 因此在创建、查看和编辑 Pod 的工作流程中暴露 Secret(及其数据)的风险较小。 Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施, 例如避免将机密数据写入非易失性存储。
Secret 类似于 ConfigMap 但专门用于保存机密数据。
注意:
Secret 的名称必须是合法的 DNS 子域名。
每个Secret的大小最多为1MiB,主要是为了避免用户创建非常大的Secret进而导致API服务器和kubelet内存耗尽,不过创建很多小的Secret也可能耗尽内存,可以使用资源配额来约束每个名字空间中Secret的个数。
在通过yaml文件创建secret时,可以设置data或stringData字段,data和stringData字段都是可选的,data字段中所有键值都必须是base64编码的字符串,如果不希望执行这种 base64字符串的转换操作,也可以选择设置stringData字段,其中可以使用任何非加密的字符串作为其取值。
Pod 可以用三种方式的任意一种来使用 Secret:
- 作为挂载到一个或多个容器上的卷 中的文件(crt文件、key文件)。
- 作为容器的环境变量。
- 由 kubelet 在为 Pod 拉取镜像时使用(与镜像仓库的认证)。
kubernetes可支持的不同的secret类型
使用Sercet-Opaqu提供认证
可以定义任意数据
将用户名和密码base64加密方式显示
加密(data)方式sercet的yaml文件
apiVersion: v1
kind: Secret
metadata:
name: mysecret-data
namespace: myserver
type: Opaque
data: #data方式,key和value要用base64加密格式保存 若不是则会报错
user: YWRtaW4K
password: MTIzNDU2Cg==
明文形式(stringdata)sercet的yaml文件
apiVersion: v1
kind: Secret
metadata:
name: mysecret-stringdata
namespace: myserver
type: Opaque
stringData: #stringData方式,用明文保存
user: 'admin'
password: '123456'
kubectl apply -f 1-secret-Opaque-data.yaml
kubectl apply -f 2-secret-Opaque-stringData.yaml
通过查询secet可以看到用户名密码分别被加密和明文方式保存;
如何挂载这些用户名密码,需要我们创建pod
root@192:/usr/local/src/k8s-Resource-N76/case11-secret# cat 3-secret-Opaque-mount.yaml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-app1-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp-app1
template:
metadata:
labels:
app: myserver-myapp-app1
spec:
containers:
- name: myserver-myapp-app1
image: tomcat:7.0.94-alpine
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /data/myserver/auth #secert卷挂载的位置
name: myserver-auth-secret
volumes:
- name: myserver-auth-secret
secret:
secretName: mysecret-data #挂载指定的secret,挂载后会将base64解密为明文
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-app1
namespace: myserver
spec:
ports:
- name: http
port: 8080
targetPort: 8080
nodePort: 30018
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-app1
进入pod 进入挂载secret卷的目录,发现用户名密码已经明文保存
secert卷用户名密码是保存在宿主机的(类似emptydir)
使用sercet卷kubernetes.io/tls为nginx提供证书
对nginx使用secret卷传递nginx自建证书,以建立https访问。
apiVersion: v1
kind: ConfigMap #使用configmap提供nginx配置
metadata:
name: nginx-config
namespace: myserver
data:
default: |
server {
listen 80;
server_name www.mysite.com;
listen 443 ssl;
ssl_certificate /etc/nginx/conf.d/certs/tls.crt; #添加证书
ssl_certificate_key /etc/nginx/conf.d/certs/tls.key;
location / {
root /usr/share/nginx/html;
index index.html;
if ($scheme = http ){ #未加条件判断,会导致死循环
rewrite / https://www.mysite.com permanent; #将http跳转我https协议
}
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
}
}
}
---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-frontend-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
containers:
- name: myserver-myapp-frontend
image: nginx:1.20.2-alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/myserver
- name: myserver-tls-key
mountPath: /etc/nginx/conf.d/certs
volumes:
- name: nginx-config
configMap:
name: nginx-config
items:
- key: default
path: mysite.conf
- name: myserver-tls-key
secret:
secretName: myserver-tls-key
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend
namespace: myserver
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30018
protocol: TCP
- name: htts
port: 443
targetPort: 443
nodePort: 30019
protocol: TCP
selector:
app: myserver-myapp-frontend
在生成pod之前,我们需要创建证书公钥和私钥
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3560 -nodes -subj '/CN=www.ca.com'
openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=www.mysite.com'
openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
kubectl create secret tls myserver-tls-key --cert=./server.crt --key=./server.key -n myserver
之后生成pod
进入pod 找到挂载的nginx配置 以及证书公钥和私钥
修改在nginx配置文件引用mysite.conf 重启nginx
可以看到443端口已经开启
![image](/i/l/?n=23&i=blog/3185455/202305/3185455-
20230519164843918-599997395.png)
查看svc 修改haproxy
修改宿主机hosts文件(域名已更改)测试https登陆成功
使用secret提供镜像信息认证 (略)
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-frontend-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
containers:
- name: myserver-myapp-frontend
image: registry.cn-qingdao.aliyuncs.com/zhangshijie/nginx:1.16.1-alpine-perl
ports:
- containerPort: 80
imagePullSecrets:
- name: aliyun-registry-image-pull-key
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend
namespace: myserver
spec:
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30018
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-frontend
Statefulset
StatefulSet 是用来管理有状态应用的工作负载 API 对象。用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。
Statefulset 作用
- Statefulset为了解决有状态服务的集群部署、集群之间的数据同步问题(MySQL主从、Redis Cluster、ES集群等)
- Statefulset所管理的Pod拥有唯一且固定的Pod名称
- Statefulset按照顺序对pod进行启停、伸缩和回收
- Headless Services(无头服务,请求的解析直接解析到pod IP) 例如mysql的pod直接指定ip,可以区分主从,读请求都访问从库pod的ip
statefulset的yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: myserver-myapp
namespace: myserver
spec:
replicas: 3
serviceName: "myserver-myapp-service"
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
containers:
- name: myserver-myapp-frontend
image: nginx:1.20.2-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-service
namespace: myserver
spec:
clusterIP: None
ports:
- name: http
port: 80
selector:
app: myserver-myapp-frontend
可以看出 pod的名字是固定的,从0开始;而且pod也是依次创建的。如果删除pod,也是从后向前依次删除
另外,statefulset使用的svc是headless。其特点是没有clusterip 可以直接ping svc的域名,会以接近轮询的方式直接访问后端pod的ip
headless Service使用场景
- 自主选择权,有时候client想自己决定使用哪个Real Server,可以通过查询DNS来获取Real Server的信息
- headless service关联的每个endpoint(也就是Pod),都会有对应的DNS域名;这样Pod之间就可以互相访问
为什么要用headless service+statefulSet部署有状态应用
1.headless service会为关联的service分配一个域
<service name>.$<namespace name>.svc.cluster.local
2.StatefulSet会为关联的Pod保持一个不变的Pod Name
statefulset中Pod的hostname格式为$(StatefulSet name)-$(pod序号)
3.StatefulSet会为关联的Pod分配一个dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local
DaemonSet简介:
DaemonSet 在当前集群中每个节点运行同一个pod,当有新的节点加入集群时也会为新的节点配置相同的pod,当节点从集群中移除时其pod也会被kubernetes回收,删除DaemonSet 控制器将删除其创建的所有的pod。
DaemonSet 的一些典型用法:
- 在每个节点上运行集群守护进程
- 在每个节点上运行日志收集守护进程
- 在每个节点上运行监控守护进程
1 nginx容器的daemonset yaml文件
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: myserver-myapp
namespace: myserver
spec:
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
tolerations:
# this toleration is to have the daemonset runnable on master nodes
# remove it if your masters can't run pods
- key: node-role.kubernetes.io/master ##添加容忍,让pod也可以在master上
operator: Exists
effect: NoSchedule
hostNetwork: true #使用宿主机网路
hostPID: true
containers:
- name: myserver-myapp-frontend
image: nginx:1.20.2-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend
namespace: myserver
spec:
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30018
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-frontend
文件中并没有设定部署几个pod,而k8s自动在每个node节点上生成了1个pod。
因为是宿主机网络,endpoint是宿主机地址
2 系统日志收集fluentd-elasticsearch的yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
# this toleration is to have the daemonset runnable on master nodes
# remove it if your masters can't run pods
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
部署Promethus的yaml##
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: myserver
labels:
k8s-app: node-exporter
spec:
selector:
matchLabels:
k8s-app: node-exporter
template:
metadata:
labels:
k8s-app: node-exporter
spec:
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
containers:
- image: prom/node-exporter:v1.3.1
imagePullPolicy: IfNotPresent
name: prometheus-node-exporter
ports:
- containerPort: 9100
hostPort: 9100
protocol: TCP
name: metrics
volumeMounts:
- mountPath: /host/proc
name: proc
- mountPath: /host/sys
name: sys
- mountPath: /host
name: rootfs
args:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/host
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
- name: rootfs
hostPath:
path: /
hostNetwork: true
hostPID: true
---
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/scrape: "true"
labels:
k8s-app: node-exporter
name: node-exporter
namespace: myserver
spec:
type: NodePort
ports:
- name: http
port: 9100
nodePort: 32100
protocol: TCP
selector:
k8s-app: node-exporter
可以登录宿主机的9100端口直接看到 收集到的日志信息
pause容器
Pause 容器,又叫 Infra 容器,是pod的基础容器,镜像体积只有几百KB左右,配置在kubelet中,主要的功能是一个pod中多个容器的网络通信。
Infra 容器被创建后会初始化 Network Namespace,之后其它容器就可以加入到 Infra 容器中共享Infra 容器的网络了,因此如果一个 Pod 中的两个容器 A 和 B,那么关系如下:
- A容器和B容器能够直接使用 localhost 通信;
- A容器和B容器可以可以看到网卡、IP与端口监听信息。
- Pod 只有一个 IP 地址,也就是该 Pod 的 Network Namespace 对应的IP 地址(由Infra 容器初始化并创建)。
- k8s环境中的每个Pod有一个独立的IP地址(前提是地址足够用),并且此IP被当前 Pod 中所有容器在内部共享使用。
- pod删除后Infra 容器随机被删除,其IP被回收。
Pause容器共享的Namespace:
- NET Namespace:Pod中的多个容器共享同一个网络命名空间,即使用相同的IP和端口信息。
- IPC Namespace:Pod中的多个容器可以使用System V IPC或POSIX消息队列进行通信。
- UTS Namespace:pod中的多个容器共享一个主机名。MNT Namespace、PID Namespace、User Namespace未共享。
验证 先创建一个pod
进入pod后查看网卡id
在宿主机上找到这个id的网卡
可以从宿主机找到是哪个网卡的namespace
nsenter --net=/run/netns/cni-a62dcf81-e2da-b70c-2794-5c8195d31c5e ifconfig
同一个pod的不同容器文件系统不同,pid也不同。但是网络地址,网卡是相同的。
init容器
Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。可以在 Pod 的规约中与用来描述应用容器的 containers 数组平行的位置指定 Init 容器
init容器的作用:
1.可以为业务容器提前准备好业务容器的运行环境,比如将业务容器需要的配置文件提前生成并放在指定位置、检查数据权限或完整性、软件版本等基础运行环境。。
2.可以在运行业务容器之前准备好需要的业务数据,比如从OSS下载、或者从其它位置copy。
3.检查依赖的服务是否能够访问。
init容器的特点:
1.一个pod可以有多个业务容器还能在有多个init容器,但是每个init容器和业务容器的运行环境都是隔离的。
2.init容器会比业务容器先启动。
3.init容器运行成功之后才会继续运行业务容器。
4.如果一个pod有多个init容器,则需要从上到下逐个运行并且全部成功,最后才会运行业务容器。
5.init容器不支持探针检测(因为初始化完成后就退出再也不运行了)。
init容器的yaml文件
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: myserver-myapp
name: myserver-myapp-deployment-name
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp-frontend
template:
metadata:
labels:
app: myserver-myapp-frontend
spec:
containers:
- name: myserver-myapp-container
image: nginx:1.20.0
#imagePullPolicy: Always
volumeMounts:
- mountPath: "/usr/share/nginx/html/myserver"
name: myserver-data
- name: tz-config
mountPath: /etc/localtime
initContainers: #先执行init容器,再执行其他容器
- name: init-web-data
image: centos:7.9.2009
command: ['/bin/bash','-c',"for i in `seq 1 10`;do echo '<h1>'$i web page at $(date +%Y%m%d%H%M%S) '<h1>' >> /data/nginx/html/myserver/index.html;sleep 1;done"]
volumeMounts:
- mountPath: "/data/nginx/html/myserver"
name: myserver-data
- name: tz-config
mountPath: /etc/localtime
- name: change-data-owner
image: busybox:1.28
command: ['/bin/sh','-c',"/bin/chmod 644 /data/nginx/html/myserver/* -R"]
volumeMounts:
- mountPath: "/data/nginx/html/myserver"
name: myserver-data
- name: tz-config
mountPath: /etc/localtime
volumes:
- name: myserver-data
hostPath:
path: /tmp/data/html
- name: tz-config
hostPath:
path: /etc/localtime
---
kind: Service
apiVersion: v1
metadata:
labels:
app: myserver-myapp-service
name: myserver-myapp-service-name
namespace: myserver
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
selector:
app: myserver-myapp-frontend
pod生命周期
Pod 遵循预定义的生命周期,起始于 Pending 阶段, 如果至少其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以失败状态结束而进入 Succeeded 或者 Failed 阶段。
在 Pod 运行期间,kubelet 能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态并确定使 Pod 重新变得健康所需要采取的动作。
Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者被终止。
和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID), 并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。
如果一个节点死掉了,调度到该节点的 Pod 也被计划在给定超时期限结束后删除。
Pod 自身不具有自愈能力。如果 Pod 被调度到某节点而该节点之后失效, Pod 会被删除;类似地,Pod 无法在因节点资源耗尽或者节点维护而被驱逐期间继续存活。 Kubernetes 使用一种高级抽象来管理这些相对而言可随时丢弃的 Pod 实例, 称作控制器。
任何给定的 Pod (由 UID 定义)从不会被“重新调度(rescheduled)”到不同的节点; 相反,这一 Pod 可以被一个新的、几乎完全相同的 Pod 替换掉。 如果需要,新 Pod 的名字可以不变,但是其 UID 会不同。
如果某物声称其生命期与某 Pod 相同,例如存储卷, 这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。 如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时, 这个相关的对象(例如这里的卷)也会被删除并重建。
探针
探针是由 kubelet 对容器执行的定期诊断,以保证Pod的状态始终处于运行状态,要执行诊断,kubelet 调用由容器实现的Handler(处理程序),也成为Hook(钩子),有三种类型的处理程序:
- ExecAction #在容器内执行指定命令,如果命令退出时返回码为0则认为诊断成功。
- TCPSocketAction #对指定端口上的容器的IP地址进行TCP检查,如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:#对指定的端口和路径上的容器的IP地址执行HTTPGet请求,如果响应的状态码大于等于200且小于 400,则诊断被认为是成功的。(生产中较多使用)
每次探测都将获得以下三种结果之一:
- 成功:容器通过了诊断。
- 失败:容器未通过诊断。
- 未知:诊断失败,因此不会采取任何行动。
容器重启策略
Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
restartPolicy 适用于 Pod 中的所有容器。restartPolicy 仅针对同一节点上 kubelet 的容器重启动作。当 Pod 中的容器退出时,kubelet 会按指数回退方式计算重启的延迟(10s、20s、40s、...),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启回退计时器执行重置操作。
restartPolicy:
- Always:当容器异常时,k8s自动重启该容器,ReplicationController/Replicaset/Deployment,默认为Always。
- OnFailure:当容器失败时(容器停止运行且退出码不为0),k8s自动重启该容器。
- Never:不论容器运行状态如何都不会重启该容器,Job或CronJob
imagePullPolicy (镜像拉取策略)::
- IfNotPresent:node节点没有此镜像就去指定的镜像仓库拉取,node有就使用node本地镜像。
- Always:每次重建pod都会重新拉取镜像
- Never:从不到镜像中心拉取镜像,只使用本地镜像
探针类型
startupProbe: #启动探针,kubernetes v1.16引入
判断容器内的应用程序是否已启动完成,如果配置了启动探测,则会先禁用所有其它的探测,直到startupProbe检测成功为止,如果startupProbe探测失败,则kubelet将杀死容器,容器将按照重启策略进行下一步操作,如果容器没有提供启动探测,则默认状态为成功
livenessProbe: #存活探针
检测容器容器是否正在运行,如果存活探测失败,则kubelet会杀死容器,并且容器将受到其重启策略的影响,如果容器不提供存活探针,则默认状态为 Success,livenessProbe用于控制是否重启pod。
readinessProbe: #就绪探针
如果就绪探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址,初始延迟之前的就绪状态默认为Failure(失败),如果容器不提供就绪探针,则默认状态为 Success,readinessProbe用于控制pod是否添加至service。
探针配置参数:
initialDelaySeconds: 120
初始化延迟时间,告诉kubelet在执行第一次探测前应该等待多少秒,默认是0秒,最小值是0
periodSeconds: 60
探测周期间隔时间,指定了kubelet应该每多少秒秒执行一次存活探测,默认是 10 秒。最小值是 1
timeoutSeconds: 5
单次探测超时时间,探测的超时后等待多少秒,默认值是1秒,最小值是1。
successThreshold: 1
从失败转为成功的重试次数,探测器在失败后,被视为成功的最小连续成功数,默认值是1,存活探测的这个值必须是1,最小值是 1。
failureThreshold: 3
从成功转为失败的重试次数,当Pod启动了并且探测到失败,Kubernetes的重试次数,存活探测情况下的放弃就意味着重新启动容器,就绪探
测情况下的放弃Pod 会被打上未就绪的标签,默认值是3,最小值是1。
HTTPGetAction的yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-frontend-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels: #rs or deployment
app: myserver-myapp-frontend-label
#matchExpressions:
# - {key: app, operator: In, values: [myserver-myapp-frontend,ng-rs-81]}
template:
metadata:
labels:
app: myserver-myapp-frontend-label
spec:
containers:
- name: myserver-myapp-frontend-label
image: nginx:1.20.2
ports:
- containerPort: 80
readinessProbe: ##添加就绪探针
livenessProbe: ##添加存活探针
httpGet:
#path: /monitor/monitor.html
path: /index.html
port: 80
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend-service
namespace: myserver
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 40012
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-frontend-label
这是正常状态
将端口改变后查看效果
由于端口找不到,存活探针规制使pod重启3次后报错;就绪探针使pod无法在svc上挂载
TCPGetAction的yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-frontend-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels: #rs or deployment
app: myserver-myapp-frontend-label
#matchExpressions:
# - {key: app, operator: In, values: [myserver-myapp-frontend,ng-rs-81]}
template:
metadata:
labels:
app: myserver-myapp-frontend-label
spec:
containers:
- name: myserver-myapp-frontend-label
image: nginx:1.20.2
ports:
- containerPort: 80
livenessProbe:
#readinessProbe:
tcpSocket:
port: 80
#port: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend-service
namespace: myserver
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 40012
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-frontend-label
可以看到结果类似
ExecAction方式探针容器的yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-redis-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels: #rs or deployment
app: myserver-myapp-redis-label
#matchExpressions:
# - {key: app, operator: In, values: [myserver-myapp-redis,ng-rs-81]}
template:
metadata:
labels:
app: myserver-myapp-redis-label
spec:
containers:
- name: myserver-myapp-redis-container
image: redis
ports:
- containerPort: 6379
livenessProbe:
#readinessProbe:
exec:
command:
#- /apps/redis/bin/redis-cli
- /usr/local/bin/redis-cli
- quit
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-redis-service
namespace: myserver
spec:
ports:
- name: http
port: 6379
targetPort: 6379
nodePort: 40016
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-redis-label
由于目录位置不对,容器直接未启动,无法进行到探针步骤~~~~
startupProbe.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-frontend-deployment
namespace: myserver
spec:
replicas: 1
selector:
matchLabels: #rs or deployment
app: myserver-myapp-frontend-label
#matchExpressions:
# - {key: app, operator: In, values: [myserver-myapp-frontend,ng-rs-81]}
template:
metadata:
labels:
app: myserver-myapp-frontend-label
spec:
containers:
- name: myserver-myapp-frontend-label
image: nginx:1.20.2
ports:
- containerPort: 80
startupProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 5 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend-service
namespace: myserver
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 40012
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-frontend-label
探测结果
startupProbe-livenessProbe-readinessProbe.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp-frontend-deployment
namespace: myserver
spec:
replicas: 3
selector:
matchLabels: #rs or deployment
app: myserver-myapp-frontend-label
#matchExpressions:
# - {key: app, operator: In, values: [myserver-myapp-frontend,ng-rs-81]}
template:
metadata:
labels:
app: myserver-myapp-frontend-label
spec:
terminationGracePeriodSeconds: 60
containers:
- name: myserver-myapp-frontend-label
image: nginx:1.20.2
ports:
- containerPort: 80
startupProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 5 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
readinessProbe:
httpGet:
#path: /monitor/monitor.html
path: /index.html
port: 80
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
#path: /monitor/monitor.html
path: /index.html
port: 80
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp-frontend-service
namespace: myserver
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 40012
protocol: TCP
type: NodePort
selector:
app: myserver-myapp-frontend-label
要注意启动探针最先检测,成功之后再进行探针其他检测。如果失败就直接杀死容器。
先修改启动探针端口为88
存活探针端口为88
就绪探针端口为88
postStart and preStop handlers
postStart 和 preStop handlers 处理函数:
postStart-Pod启动后立即执行指定的查操作:
- Pod被创建后立即执行,即不等待pod中的服务启动。
- 如果postStart执行失败pod不会继续创建
preStop:
- 在pod被停止之前执行
- 如果preStop一直执行不完成,则最后宽限2秒后强制删除
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myserver-myapp1-lifecycle
labels:
app: myserver-myapp1-lifecycle
namespace: myserver
spec:
replicas: 1
selector:
matchLabels:
app: myserver-myapp1-lifecycle-label
template:
metadata:
labels:
app: myserver-myapp1-lifecycle-label
spec:
terminationGracePeriodSeconds: 60
containers:
- name: myserver-myapp1-lifecycle-label
image: tomcat:7.0.94-alpine
lifecycle:
postStart:
exec:
#command: 把自己注册到注册在中心
command: ["/bin/sh", "-c", "echo 'Hello from the postStart handler' >> /usr/local/tomcat/webapps/ROOT/index.html"]
#httpGet:
# #path: /monitor/monitor.html
# host: www.magedu.com
# port: 80
# scheme: HTTP
# path: index.html
preStop:
exec:
#command: 把自己从注册中心移除
command:
- /bin/bash
- -c
- 'sleep 10000000'
#command: ["/usr/local/tomcat/bin/catalina.sh","stop"]
#command: ['/bin/sh','-c','/path/preStop.sh']
ports:
- name: http
containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: myserver-myapp1-lifecycle-service
namespace: myserver
spec:
ports:
- name: http
port: 80
targetPort: 8080
nodePort: 30012
protocol: TCP
type: NodePort
selector:
app: myserver-myapp1-lifecycle-label
注意 podstart在startprobe探针之后执行。
Pod的终止流程:
1.创建pod
- 向API-Server提交创建请求、API-Server完成鉴权和准入并将事件写入etcd
- kube-scheduler完成调度流程
- kubelet创建并启动pod、然后执行postStart
- 周期进行livenessProbe
- 进入running状态
- readinessProbe检测通过后,service关联pod
- 接受客户端请求
2.删除pod
- 向API-Server提交删除请求、API-Server完成鉴权和准入并将事件写入etcd
- Pod被设置为”Terminating”状态、从service的Endpoints列表中删除并不再接受客户端请求。
- pod执行PreStop
- kubelet向pod中的容器发送SIGTERM信号(正常终止信号)终止pod里面的主进程,这个信号让容器知道自己很快将会被关闭
- terminationGracePeriodSeconds: 60 #可选终止等待期(pod删除宽限期),如果有设置删除宽限时间,则等待宽限时间到期,否则最多等待30s,Kubernetes等
- 待指定的时间称为优雅终止宽限期,默认情况下是30秒,值得注意的是等待期与preStop Hook和SIGTERM信号并行执行,即Kubernetes可能不会等待preStop Hook
- 完成(最长30秒之后主进程还没有结束就就强制终止pod)。
- SIGKILL信号被发送到Pod,并删除Pod
基于nerdctl + buildkitd+containerd构建容器镜像
buildkitd组成部分:
buildkitd(服务端),⽬前⽀持runc和containerd作为镜像构建环境,默认是runc,可以更换为containerd。
buildctl(客户端),负责解析Dockerfile⽂件,并向服务端buildkitd发出构建请求。
⼀ 部署buildkitd:
wget https://github.com/moby/buildkit/releases/download/v0.11.6/buildkit-v0.11.6.linux-amd64.tar.gz
tar xvf buildkit-v0.11.6.linux-amd64.tar.gz
mv bin/* /usr/local/bin/
vim /lib/systemd/system/buildkit.socket
[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit
[Socket]
ListenStream=%t/buildkit/buildkitd.sock
[Install]
WantedBy=sockets.target
vim /lib/systemd/system/buildkitd.service
[Unit]
Description=BuildKit
Requires=buildkit.socket
After=buildkit.socketDocumentation=https://github.com/moby/buildkit
[Service]
ExecStart=/usr/local/bin/buildkitd --oci-worker=false --containerd-worker=true
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable buildkitd
systemctl restart buildkitd
systemctl status buildkitd
⼆ 测试镜像构建:
~# vim /etc/profile
source <(nerdctl completion bash)
~# source /etc/profile
测试结果 nerdctl 命令参数可用tab补全
harbor证书分发:之前已签发过 验证结果
使用buildkit构建镜像
root@192:/usr/local/src/20230507/ubuntu# cat Dockerfile
FROM ubuntu:22.04
MAINTAINER "jack [email protected]"
#ADD sources.list /etc/apt/sources.list
RUN apt update && apt install -y iproute2 ntpdate tcpdump telnet traceroute nfs-kernel-server nfs-common lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute gcc openssh-server lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute iotop unzip zip make
ADD nginx-1.22.0.tar.gz /usr/local/src/
RUN cd /usr/local/src/nginx-1.22.0 && ./configure --prefix=/apps/nginx && make && make install && ln -sv /apps/nginx/sbin/nginx /usr/bin
RUN groupadd -g 2088 nginx && useradd -g nginx -s /usr/sbin/nologin -u 2088 nginx && chown -R nginx.nginx /apps/nginx
ADD nginx.conf /apps/nginx/conf/
ADD frontend.tar.gz /apps/nginx/html/
RUN chown -R nginx.nginx /apps/nginx
EXPOSE 80 443
#ENTRYPOINT ["nginx"]
CMD ["nginx","-g","daemon off;"]
root@192:/usr/local/src/20230507/ubuntu# cat build-command.sh
#!/bin/bash
#docker build -t harbor.magedu.net/myserver/nginx:v1 .
#docker push harbor.magedu.net/myserver/nginx:v1
/usr/bin/nerdctl build -t harbor.linuxarchitect.io/basic/nginx-base:1.22.0 .
/usr/bin/nerdctl push harbor.linuxarchitect.io/basic/nginx-base:1.22.0
root@192:/usr/local/src/20230507/ubuntu# cat sources.list
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
# deb-sr https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
# deb-sr https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
# deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-proposed main restricted universe multiverse
# deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-proposed main restricted universe multiverse
执行build-command.sh
可看到成功创建镜像,拉取镜像并创建容器