1、k8s项目部署(项目上线)
1、项目上线流程
2、k8s中部署nginx和tomcat
部署Nginx:
# 创建一个Deployment控制器管理Pod
kubectl create deployment nginx --image=nginx
# 对外暴露服务
kubectl expose deployment nginx --port=80 --type=NodePort --name nginx
kubectl get pod,svc
访问地址:http://NodeIP:Port
部署Tomcat:
# 托管Pod到Deployment
kubectl create deployment tomcat --image=tomcat
# 对外暴露服务
kubectl expose deployment tomcat --port=8080 --type=NodePort --name tomcat
访问地址:http://NodeIP:Port
1、k8s资源-Pod
1、Pod概述
-
Pod是k8s系统中可以创建和管理的最小单元
-
其他资源都是用来支撑和扩展Pod对象功能的
-
Pod是由一个或多个container组成的 -
每个Pod都有一个特殊的容器Pause(根容器)
-
除了Pause容器,还包含一个或多个紧密相连的业务容器
-
每个Pod都是一个应用实例,有专用的IP
-
同一个 Pod 中的容器总会被调度到相同 Node 节点,不同节点间 Pod 的通信基于虚拟二层网 络技术实现
-
Pod可以分为普通Pod和静态Pod(特定由kubelet管理)
2、Pod特性
-
资源共享
多个容器间共享存储和网络
-
生命周期短暂
发生故障被重新调度后,将是一个全新的Pod
-
平坦的网络
K8s 集群中的所有 Pod 都在同一个共享网络地址空间中,也就是说每个 Pod 都可以通过其 他 Pod 的 IP 地址来实现访问
3、Pod分类
Pod的两种类型:
-
普通Pod
普通 Pod 一旦被创建,就会被放入到 etcd 中存储,随后会被 Kubernetes Master 调度到某 个具体的 Node 上并进行绑定,随后该 Pod 对应的 Node 上的 kubelet 进程实例化成一组相 关的 Docker 容器并启动起来。在默认情 况下,当 Pod 里某个容器停止时,Kubernetes 会 自动检测到这个问题并且重新启动这个 Pod 里某所有容器, 如果 Pod 所在的 Node 宕机, 则会将这个 Node 上的所有 Pod 重新调度到其它节点上
-
静态Pod
静态 Pod 是由 kubelet 进行管理的仅存在于特定 Node 上的 Pod,它们不能通过 API Server 进行管理,无法与 ReplicationController、Deployment 或 DaemonSet 进行关联,并且 kubelet 也无法对它们进行健康检查
4、Pod管理命令
# 创建Pod:
kubectl apply -f <file.yaml>
kubectl create -f <file.yaml>
# 或者使用命令:kubectl run <Pod_name> --image=<IMAGE>
# 查看Pod:
kubectl get pods [命名空间]
kubectl describe pod <Pod名称>
# 查看日志:
kubectl logs <Pod名称> [-c CONTAINER]
kubectl logs <Pod名称> [-c CONTAINER] -f
# 进入容器终端:
kubectl exec <Pod名称> [-c CONTAINER] -- bash
# 删除Pod:
kubectl delete pod <Pod名称>
5、在k8s上运行第一个应用
kubectl run web --image=nginx --port=80
- web:Pod的名称
- –image:指定镜像
- –port:指定监听端口
查看创建的Pod:
kubectl get pod --namespace default [-o wide|yaml]
删除Pod
kubectl delete pod <pod_name>/all [-n namespace]
获取pod的yaml资源清单文件
kubectl get pod web -o yaml
6、Pod创建的工作流程
kubectl 向api server 发起一个create pod 请求
api server接收到pod创建请求后,不会去直接创建pod,而是生成一个包含创建信息并写入到etcd
scheduler 查看 k8s api ,类似于通知机制。
判断pod.spec.Node == null?若为null,表示这个Pod请求是新来的,需要创建;因此先进行调度计算,找到最“闲”的node,并“报告”给apiserver。
写入etcd数据库中更新分配结果:pod.spec.Node = nodeA (设置一个具体的节点)
对应节点的kubelet 通过”监视“发现api server 中有了个新的Node。
通过节点上的运行时去创建Pod。
kubelet将结果“报告”给 apiserver。
将结果写入etcd。
7、访问web应用
kubectl expose pod web --type=NodePort --port=80 --target-port=80
8、Pod生命周期和重启策略
Pod整个生命周期被定义为各种状态,熟悉Pod的各种状态有助于理解Pod调度和重启策略,以及问题的排查
Pod的各种状态也被称为phase
(阶段),定义在Pod的PodStatus
对象的phase
字段中。
1. Pod状态
主要的有如下几种:
状态值 | 说明 |
---|---|
Pending(挂起) | Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间。 |
Running(运行中) | 该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。 |
Succeeded(成功) | Pod 中的所有容器都被成功终止,并且不会再重启。 |
Failed(失败) | Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。 |
Unknown(未知) | 因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。 |
Pod 有一个
PodStatus
对象,其中包含一个 PodCondition 数组。PodCondition
包含以下以下字段:
lastProbeTime
:Pod condition最后一次被探测到的时间戳。lastTransitionTime
:Pod最后一次状态转变的时间戳。message
:状态转化的信息,一般为报错信息,例如:containers with unready status: [c-1]。reason
:最后一次状态形成的原因,一般为报错原因,例如:ContainersNotReady。status
:包含的值有 True、False 和 Unknown。type
:Pod状态的几种类型。其中type字段包含以下几个值:
PodScheduled
:Pod已经被调度到运行节点。Ready
:Pod已经可以接收请求提供服务。Initialized
:所有的init container已经成功启动。Unschedulable
:无法调度该Pod,例如节点资源不够。ContainersReady
:Pod中的所有容器已准备就绪。
除了以上Pod的几种阶段性状态之外,我们在创建应用并观察时,也会经常看到Pod会有一下几种常见的状态信息:
CrashLoopBackOff: 容器退出,kubelet正在将它重启
InvalidImageName: 无法解析镜像名称
ErrImageNeverPull: 策略禁止拉取镜像
ImagePullBackOff: 正在重试拉取
RegistryUnavailable: 连接不到镜像中心
ErrImagePull: 通用的拉取镜像出错
ContainerCreating:容器创建中
PodInitializing:pod 初始化中
2. 重启策略(restartPolicy)
Pod通过restartPolicy
字段指定重启策略,重启策略类型为:Always(默认)、OnFailure 和 Never。
注意:
restartPolicy
仅指通过同一节点上的 kubelet 重新启动容器。(重新调度和重启的区别)
策略 | 说明 |
---|---|
Always | 当容器失效时,由kubelet自动重启该容器 |
OnFailure | 当容器退出码不为0时,由kubelet自动重启该容器 |
Never | kubelet永远不会重启该容器 |
说明:
可以管理Pod的控制器有ReplicationController(rc),ReplicaSet(rs),Job,DaemonSet,及kubelet(静态Pod)。
- RC、RS和DaemonSet:必须设置为Always,需要保证应用的持续稳定运行;
- Job:OnFailure或Never,确保容器执行完后不再重启;
- kubelet:根据重启策略重启时,不论RestartPolicy设置为什么值,并且不会对Pod进行健康检查。
3. 健康检查
Pod健康检查分为两种:
-
存活检查(livenessProbe)
liveness
:检查容器内应用的存活的情况,如果检查失败会杀掉容器进程,是否重启容器则取决于Pod的重启策略 -
就绪检查(readinessProbe)
检查容器内的应用是否能够正常对外提供服务,如果探测失败,则Endpoint Controller会将这个Pod的IP从
endpoints
服务中删除。(用于:容器启动缓慢,需要加载大量数据和配置文件或依赖等待外部服务,而这段时间不能对外提供服务时)
注意:livenessProbe
和readinessProbe
配置参数一样
支持的三种检查方式:
-
httpGet:发送HTTP请求,返回200-400范围状态码为成功。
-
exec:执行Shell命令返回状态码是0为成功。
-
tcpSocket:发起TCP Socket建立成功。
1)exec检查
https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox:1.28.4
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
-
initialDelaySeconds
:容器启动后多久进行健康检查(单位:s) -
periodSeconds
:健康检查周期,多长时间进行一次检查(单位:s)
2)httpGet检查
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: liveness # 修改镜像
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
initialDelaySeconds
:指定了 kubelet 每隔 3 秒执行一次存活探测periodSeconds
:告诉 kubelet 在执行第一次探测前应该等待 3 秒
如果服务器上
/healthz
路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。 如果处理程序返回失败代码,则 kubelet 会杀死这个容器并且重新启动它。
3)TCP检查
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: geray/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
TCP 检测的配置和 HTTP 检测非常相似。 下面这个例子同时使用就绪和存活探测器。kubelet 会在容器启动 5 秒后发送第一个就绪探测。 这会尝试连接 goproxy
容器的 8080 端口。 如果探测成功,这个 Pod 会被标记为就绪状态,kubelet 将继续每隔 10 秒运行一次检测。
除了就绪探测,这个配置包括了一个存活探测。 kubelet 会在容器启动 15 秒后进行第一次存活探测。 与就绪探测类似,会尝试连接 goproxy
容器的 8080 端口。 如果存活探测失败,这个容器会被重新启动。
4、Pod容器设置环境变量
在我创建Pod的时候,容器内应用程序想要获取Pod信息或者想要获取某些特定的参数变量,我们可以给容器设置相关的环境变量;
环境变量的几种定义方式:
- 自定义变量
- 从Pod属性获取
- 变量值从Secret、ConfigMap获取(参考后续控制器)
1)自定义环境变量
apiVersion: v1
kind: Pod
metadata:
name: envar-demo
spec:
containers:
- name: envar-demo-container
spec:
containers:
- name: dependent-envars-demo
command: ["sh", "-c", "sleep 12h"]
image: busybox
env:
- name: SERVICE_PORT
value: "80"
- name: SERVICE_IP
value: "172.17.0.1"
- name: UNCHANGED_REFERENCE
value: "$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
- name: PROTOCOL
value: "https"
- name: SERVICE_ADDRESS
value: "$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
- name: ESCAPED_REFERENCE
value: "$$(PROTOCOL)://$(SERVICE_IP):$(SERVICE_PORT)"
# 通过printenv命令测试
kubectl exec envar-demo -- printenv
2)获取Pod属性
apiVersion: v1
kind: Pod
metadata:
name: dapi-envars-fieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "sh", "-c"]
args:
- sleep 12h
env:
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MY_POD_SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
5、初始化容器(init容器)
特点:
- 应用程序容器之前运行的专用容器
- 可以包含应用程序映像中不存在的实用程序或设置脚本
- 一个Pod可以包含一个或多个init容器
- 使用
initContainers
字段设置
与普通应用容器的区别:
- init容器总是运行到完成,先与业务容器启动
- 每个 init 容器必须在下一个启动之前成功完成;业务容器是并行启动
- init 容器不支持
lifecycle
(生命周期),livenessProbe
,readinessProbe
, 或startupProbe
(启动探测器)(Pod 准备好之前运行完成)
1)init容器的使用
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28.4
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
until
:和while
工作相反,当返回状态码不为0,循环;否则退出循环nslookup
:查询DNS记录和域名解析是否正常
创建两个对应的service后Pod正常启动
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
6、静态Pod
有kubelet
管理的Pod,例如kubeadm
部署后的etcd
、APIServer
等
kubelet
管理静态Pod的资源清单路径:
vi /var/lib/kubelet/config.yaml
...
staticPodPath: /etc/kubernetes/manifests # 静态Pod的存放路径
...
静态Pod特点:
-
Pod由特定节点上的kubelet管理
-
不能使用控制器
-
Pod名称标识当前节点名称