应用(pod)创建过程:
(http、restful api)api-server <-----(listen) ---kubelet controller ----->cri ----->Deployment controller--->pods
kubectl --http post---> .yaml ->control-plane
pod ---> 1个或多个容器。同一个pod中多个容器之间的共享的。
svc 的作用:
Deployment 扩缩容会使pod ip发生变化-->service 分配固定IP保证服务的网络稳定。
微服务一个容器实现一个需求。
/ web
pod ---》共享同一个卷
\ 文件同步
pod部署过程:
部署清单(.yaml格式) -----post--》 API server (contorl plane检查yaml格式)->记录到集群存储-》调度集群节点部署。
pod中所有容器都共享相同的网络、存储空间。
每个容器都有其自己的端口,同一个 Pod中的容器不能使用同一个端口。
deployment 使用replica set 来自愈和扩缩容
deployment --管理> replicaset --管理-> pod
声明式:整体(推荐使用)
命令式:局部拼接
replicaset 名称是deployment 的名称与一个hash值的拼接。
hash 值是对 YAML 清单文件中 Pod 模板部分(spec.template 下的所有内容)的hash。
kubectl get rs -owide
kubectl get deploy -owide
svc:
创建固定IP或域名,无论集群内部pod如何变化,不会影响从外部的访问。
svc支持的四种模式:
ClusterIP:(只可以集群内部访问)
kubectl expose deploy whoami --port=80
NodePort:(将集群中pod端口暴露到外部)
kubectl expose deploy whoami --type=NodePort --port 80
LoadBalancer:(将集群中pod端口暴露到互联网,常用于云。像是ClusterIP和NodePort 模式的结合体)。
kubectl expose deploy whoami --type=LoadBalancer --port=80 --external-ip <PUBLIC_IP>
ExternalName:能够将流量路由至 Kubernetes 集群之外的系统中去(所有其他类 型的 Service 都是在集群内部进行流量的路由)。
查看扩缩容状态:
kubectl rollout status deployment hello-deploy
扩缩容时添加了--record 参数会记录版本历史记录。
kubectl rollout history deployment hello-deploy
版本回退到v1
kubectl rollout undo deployment hello-deploy --to-revision=1
service 利用label来动态选择将流量转发至哪些pod。label是service和pod之间的桥梁。
kubectl get po -l app=whoami
例如:
servcie中有两个标签:
app = nginx
run = nginx
pod中只有一个标签:
app = nginx
那么service 的流量不会经过该pod
pod中有多个标签
app = nginx
run = nginx
ver = v1
sta = running
其中标签app = nginx、run = nginx和service中标签匹配。service会将流量转发到该pod。
svc yml文件分析
apiVersion: v1
kind: Service
metadata:
name: hello-svc
labels:
app: hello-world
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
targetPort: 8080
protocol: TCP
selector:
app: hello-world
从集群外访问pod内部应用流量走势:
外网流量-》nodeport(30001)->targetport(8080)->port(8080)
流量先到svc的NodePort 端口,再到endpoints 端口,最后转到pod 应用内部端口。
查看svc
[root@k3s-master yml]# kubectl describe svc whoami
Name: whoami
Namespace: default
Labels: app=whoami
Annotations: <none>
Selector: app=whoami
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.43.128.157
IPs: 10.43.128.157
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30194/TCP
Endpoints: 10.42.0.66:80,10.42.1.41:80,10.42.1.66:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
查看endpoints
[root@k3s-master yml]# kubectl describe endpoints whoami
Name: whoami
Namespace: default
Labels: app=whoami
Annotations: endpoints.kubernetes.io/last-change-trigger-time: 2024-05-21T08:59:34Z
Subsets:
Addresses: 10.42.0.66,10.42.1.41,10.42.1.66,10.42.2.77,10.42.2.78
NotReadyAddresses: <none>
Ports:
Name Port Protocol
---- ---- --------
<unset> 80 TCP
Events: <none>
集群中每一个节点都运行一个kube-proxy,它实现监视Api-server上新创建的Service和Endpoint的控制器。当它有新发现时,就会创建一条本地的IPVS规则该规则告诉主机节点拦截发往Service的ClusterIP的流量,并发送至具体的Pod。
下图表示从一个应用(pod)访问另一个应用(pod)的(流量传递)过程。
其中捕获这一环节就是由kube-proxy完成的。
相同ns之间的pod访问:
curl pod名称:应用端口
如:
curl ent:8080
不同ns之间的pod访问:
如:
ns: dev
pod名称 : ent
ns: prod
pod名称 : ent
在dev pod中访问prod中的pod ent
curl prod.svc.cluster.local:8080
说明短名称会被解析到自身所在的命名空间,而跨命名空间的连接则需要使用FQDN。
进入dev pod 内部查看域名解析发现:
cat /etc/resolv.conf
root@jump:/# cat /etc/resolv.conf
search dev.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.43.0.10
options ndots:5
本地域名是:dev.svc.cluster.local
对应的dns ip是:10.43.0.10
正好是coredns 的内部IP。说明到达pod的流量都会转给kube-dns。
[root@k3s-master yml]# kubectl get svc -n kube-system -l k8s-app=kube-dns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.43.0.10 <none> 53/UDP,53/TCP,9153/TCP 8d
存储:
pvc:像许可证,赋予pod访问pv的权限
pv : k8s中存储
sc:动态分配
pvc三种模式:
ReadWriteOnce(RWO):
限制一个PV只能以读写方式被挂载或绑定到一个PVC。尝试绑定多个会失败。
ReadWriteMany(RWM)
可以绑定多个。通常只支持NFS。块存储只支持RWO
ReadOnlyMany(ROM)
允许PV以只读方式绑定到多个PVC。
需要强调几点。首先,一个 PV 只能设置一种模式:不能在与一个 PVC 以 ROM 模式绑定的同时再与另一个 PVC 以 RWM 模式绑定。其次,Pod 不能直接与 PV 对接,而是必须通过 PVC 与某个 PV 绑定。
StorageClass 使我们无须手动创建 PV,只需要创建一个StorageClass 对象,然后使用一个插件将其与某个具体的存储后端联系起来。
pv 与pvc 绑定如下:
两种命令式创建comfigmap的方式
1. 基于字面值(--from-literal)
kubectl create configmap testmap1 --from-literal shortname=msb.com --from-literal longname=magicsandbox.com
2. 基于已有的文件(--from-file)
假设文件cmfile.txt 内容为:
Magic Sandbox, hands-on learning that blurs the lines between training and the real world.
创建cm
kubectl create configmap testmap2 --from-file cmfile.txt
查看cm 详情:
kubectl describe cm testmap1
声明式创建cm 的方式:
multimap.yml
kind: ConfigMap
apiVersion: v1
metadata:
name: multimap
data:
given: Nigel
family: Poulton
singlemap.yml
kind: ConfigMap
apiVersion: v1
metadata:
name: test-config
data:
test.conf: |
env = plex-test
endpoint = 0.0.0.0:31001
char = utf8
vault = PLEX/test
log-size = 512M
kubectl apply -f multimap.yml
kubectl apply -f singlemap.yml
使用管道符"|" 将管道符后面的所有内容整体看作value。key为: test.conf
key和value 统一称作entity。
所有的键值对都在data字段中。
ConfigMap对象没有状态(期望状态和当前状态)的概念。因此它没有spec和status部分,取而代之的是data。
三种方式将cm数据注入pod和容器
1.作为环境变量
先创建cm,然后将entity映射到位于pod template 的 container 部分环境变量中。当容器启动时,环境变量会以Linux或windows环境变量形式出现在容器中。
图解如下:
comfigmap文件 multimap.yml
kind: ConfigMap
apiVersion: v1
metadata:
name: multimap
data:
given: Nigel
family: Poulton
pod 文件envPod.yml
apiVersion: v1
kind: Pod
metadata:
labels:
chapter: configmaps
name: envpod
spec:
containers:
- name: ctr1
image: busybox
command: ["sleep"]
args: ["infinity"]
env:
- name: FIRSTNAME
valueFrom:
configMapKeyRef:
name: multimap
key: given
- name: LASTNAME
valueFrom:
configMapKeyRef:
name: multimap
key: family
kubectl apply -f multimap.yml
kubectl apply -f envPod.yml
[root@k3s-master yml]# kubectl exec envpod -- env | grep NAME
HOSTNAME=envpod
LASTNAME=Poulton
FIRSTNAME=Nigel
将cm作为环境变量来使用有缺点,环境变量是静态的。即使更改了cm中的内容,容器中的环境变量也不会发生变化。
2.作为容器启动参数
startuppod.yml
apiVersion: v1
kind: Pod
metadata:
name: startup-pod
labels:
chapter: configmaps
spec:
restartPolicy: OnFailure
containers:
- name: args1
image: busybox
command: [ "/bin/sh", "-c", "echo First name $(FIRSTNAME) last name $(LASTNAME)", "wait" ]
env:
- name: FIRSTNAME
valueFrom:
configMapKeyRef:
name: multimap
key: given
- name: LASTNAME
valueFrom:
configMapKeyRef:
name: multimap
key: family
还是先创建cm(本例中使用上例的multimap作为cm),然后Pod模板(template,YAML文件中定义Pod及其容器的部分)定义了一个名为 args1的容器。容器基于busybox镜像,并且执行/bin/sh命令。
FIRSTNAME 基于cm multimap 的given entry
LASTNAME 基于cm multimap 的family entry
图解如下:
查看容器日志:
[root@k3s-master yml]# kubectl logs startup-pod -c args1
First name Nigel last name Poulton
查看容器环境变量
[root@k3s-master yml]# kubectl describe po startup-pod | grep -i env -A 2
Environment:
FIRSTNAME: <set to the key 'given' of config map 'multimap'> Optional: false
LASTNAME: <set to the key 'family' of config map 'multimap'> Optional: false
在容器的启动命令中使用ConfigMap,也会遇到和作为环境变量使用的时候同样的限制--对ConfigMap的更新不会同步到已运行的容器中。
3.作为某个卷上的文件
步骤:
先创建cm,在pod模板中创建一个c'm卷,将cm卷挂载到容器中。
cm中的entry会分别作为单独的文件出现在容器中。
图解如下:
还是会得到cm multimap中的两个值:
given = Nigel
family = Poulton
创建了一个名为:cmvol 的pod
spec.volumes创建了一个基于ConfigMap multimap的名为volmap的卷。
spec.containers.volumeMounts 将volmap卷挂载到/etc/name。
cmpod.yml
apiVersion: v1
kind: Pod
metadata:
name: cmvol
spec:
volumes:
- name: volmap
configMap:
name: multimap
containers:
- name: ctr
image: nginx
volumeMounts:
- name: volmap
mountPath: /etc/name
在spec.containers中将volmap卷挂载到了容器的/etc/name。也就是说在容 器中,两个文件的路径如下。
/etc/name/given。
/etc/name/family。
$ kubectl apply -f cmpod.yml
Pod/cmvol created
$ kubectl exec cmvol -- ls /etc/name
family
given
cm是k8s提供的用于将应用和配置进行解耦的配置。它可用于保存应用的配置参数,甚至完整的配置文件,但不应被保存敏感数据。
cm是在容器运行时注入的,它可以通过环境变量、容器启动命令和卷三种途径注入容器卷的方式是最灵活的,容器能够以文件形式获取配置,同时将对cm更新同步到已运行的容器中。
评论区