【k8s面试题2025】1、练气期
主要通过呼吸吐纳等方法,将外界的天地灵气吸入体内,初步改造身体,使身体素质远超常人。
文章目录
- docker 和虚拟机的不同
- Kubernetes 和 docker 的关系
- Kube-proxy IPVS 和 iptables 的异同
- 蓝绿发布
- Kubernetes中常见的数据持久化方式
- 关于 Dockerfile 中 `COPY` 和 `ADD` 指令的异同点
docker 和虚拟机的不同
- 传统虚拟化:底层硬件安装宿主机系统,如 Linux 或 Windows,在宿主机系统上安装虚拟机管理程序(如 KVM、VMware 等),再安装虚拟机操作系统,每个虚拟机都有独立内核,运行应用时需在虚拟机操作系统上配置应用运行时环境。这种方式资源消耗大,随着虚拟机实例增多,内存和 CPU 消耗显著增加,宿主机性能明显下降。
- docker 虚拟化:同样基于底层硬件和宿主机系统,但无需虚拟机管理程序和额外的操作系统开销,直接在容器内运行应用,容器有独立文件系统,处于隔离状态,运行效率高于传统虚拟化。可总结为 docker 是轻量级沙盒,只运行应用,而虚拟机有额外独立操作系统。
Kubernetes 和 docker 的关系
- 联系要点
- 容器运行依赖:Kubernetes依赖像Docker这样的容器引擎来运行容器,容器引擎是Kubernetes集群中容器运行的基础。
- 共同服务部署:二者协作进行容器化应用的部署和管理。Docker打包应用为容器,Kubernetes对这些容器进行编排,让它们在集群环境高效工作。
- 区别要点
- 功能侧重:Docker侧重于容器的创建、运行和管理,重点是单个容器生命周期;Kubernetes侧重于容器编排,如调度容器到节点、资源分配和服务发现。
- 应用场景:Docker适合开发测试环境构建和运行容器;Kubernetes用于生产环境大规模集群管理。
- 复杂程度:Docker简单直接,容易学习使用;Kubernetes复杂,有众多组件和概念,学习成本高。
Kube-proxy IPVS 和 iptables 的异同
- 相同点
- 功能目的相同:
- kube - proxy无论是使用iptables还是ipvs,其主要功能都是为了实现Kubernetes集群中Service的负载均衡和代理。它们的目的是将对Service的请求流量,根据一定的规则转发到对应的后端Pod。例如,在一个Web服务的集群中,外部请求访问Service的IP和端口时,kube - proxy(无论是哪种模式)都会将请求正确地分发到后端运行Web应用的Pod,以提供服务。
- 都是基于内核功能实现:
- iptables和ipvs都是利用Linux内核提供的网络功能来构建的。iptables是基于内核的netfilter框架,通过一系列的规则链来处理网络数据包。ipvs同样也是在内核空间运行,利用内核的IPVS模块来实现高效的负载均衡。它们都是紧密结合Linux内核来完成网络代理和负载均衡任务的。
- 不同点
- 性能方面:
- iptables:在大规模集群环境下,随着Service和Pod数量的增加,iptables的性能会逐渐下降。因为iptables是基于规则链来处理数据包的,每一个新的Service或者Pod的变化都可能导致大量规则的添加和修改。例如,每次创建一个新的Service或者Pod,iptables都需要更新规则,而且这些规则是线性遍历的,当规则数量庞大时,会导致数据包处理延迟增加,消耗更多的CPU资源。
- ipvs:ipvs是专门为负载均衡设计的内核模块,在处理大量连接和高并发场景时性能更优。它使用哈希表等高效的数据结构来存储和查找转发规则,相比于iptables的线性规则链,能够更快地定位到要转发的目标。例如,在一个有数千个Pod的大型集群中,ipvs可以更快地将流量分配到后端Pod,吞吐量更高,延迟更低。
- 负载均衡算法方面:
- iptables:iptables本身的负载均衡功能相对简单,主要是基于随机或者轮询(Round - Robin)的方式。例如,在简单的轮询模式下,它会依次将请求发送到后端的Pod,没有考虑Pod的负载情况等复杂因素。
- ipvs:ipvs支持多种复杂的负载均衡算法,如轮询(Round - Robin)、加权轮询(Weighted Round - Robin)、最小连接数(Least - Connections)、加权最小连接数(Weighted Least - Connections)等。这使得它可以根据后端Pod的实际负载情况、资源配置等因素,更灵活地分配流量。例如,如果某个Pod的资源配置更高或者当前负载较轻,通过加权轮询或者最小连接数算法,可以将更多的流量分配给这个Pod。
- 规则更新机制方面:
- iptables:iptables规则的更新是即时生效的,但在更新大量规则时可能会出现性能问题。当有新的Service或者Pod加入或者退出时,iptables需要更新规则链,这个过程可能会比较复杂。例如,在一个频繁更新服务的环境中,iptables可能会因为不断地修改规则而导致网络抖动,影响服务的稳定性。
- ipvs:ipvs的规则更新相对来说更加高效。它可以动态地添加、删除和修改转发规则,并且在更新过程中对正在进行的连接影响较小。例如,当有新的Pod加入服务后端时,ipvs可以更快地将其纳入负载均衡的范围,而不会像iptables那样可能因为规则更新而暂时中断部分服务。
蓝绿发布
-
定义
- 蓝绿发布是一种应用发布策略。在这种策略中,有两个完全相同的生产环境,分别称为“蓝环境”和“绿环境”。这两个环境除了正在提供服务的版本不同外,其他配置(如硬件、软件、网络等)基本相同。例如,蓝环境运行的是旧版本的应用程序,绿环境则部署和测试新版本的应用程序。
-
工作流程
- 初始状态:在发布开始前,用户流量全部导向蓝环境,绿环境处于待命状态或者正在进行新版本应用的部署和测试。例如,一个电商网站的应用,用户访问的是蓝环境中的旧版本应用,绿环境中的新版本应用正在进行最后的功能测试。
- 切换阶段:当绿环境中的新版本应用测试完成并且确认无误后,将用户流量从蓝环境切换到绿环境。这个切换过程可以是通过修改负载均衡器的配置,或者更新DNS记录等方式来实现。例如,在Kubernetes环境下,可以通过更新Service的后端指向,将流量从蓝环境的Pod切换到绿环境的Pod。
- 回滚机制:如果在切换后发现新版本应用出现问题,能够快速地将用户流量再切换回蓝环境,恢复到旧版本应用的服务状态。这种快速回滚的能力是蓝绿发布的一个重要优势,可以有效降低发布风险。
-
在Kubernetes中的实现方式
- 资源准备:在Kubernetes集群中,通过Deployment或者StatefulSet等资源来创建蓝环境和绿环境对应的应用资源。例如,使用两个不同的Deployment分别部署蓝环境和绿环境的应用版本,每个Deployment管理一组Pod,这些Pod运行相同版本的应用。
- 流量切换:可以利用Kubernetes的Service资源来控制流量的导向。Service可以通过标签选择器(label selector)来选择要将流量发送到的Pod。在切换时,修改Service的标签选择器,使其从指向蓝环境的Pod改为指向绿环境的Pod。例如,蓝环境的Pod标签为
version: blue
,绿环境的Pod标签为version: green
,最初Service的标签选择器为version: blue
,切换时将其改为version: green
。 - 监控与回滚:在整个发布过程中,通过Kubernetes的监控工具(如Prometheus集成)来密切监控应用的性能指标。如果发现问题,如错误率上升、响应时间过长等,及时将流量切换回蓝环境。可以通过记录发布过程中的配置变更,快速地恢复到之前的状态。
-
优点
- 风险可控:因为有一个完整的旧版本环境作为备份,一旦新版本出现问题,可以快速回滚,将对用户的影响降到最低。
- 发布过程清晰:蓝绿两个环境界限分明,发布过程简单明了,便于开发、运维人员理解和操作。
- 便于测试对比:在发布前可以在绿环境中充分测试新版本,并且可以与蓝环境中的旧版本进行对比测试,确保新版本的质量。
-
缺点
- 资源消耗大:需要维护两个完整的生产环境,这在资源(如服务器、存储、网络等)方面的成本较高。
- 切换复杂:在流量切换过程中,如果操作不当,可能会导致短暂的服务中断或者流量丢失等问题。例如,在切换负载均衡器配置时,如果配置有误或者同步不及时,可能会出现部分用户无法访问服务的情况。
Kubernetes中常见的数据持久化方式
一、持久卷(Persistent Volume,PV)和持久卷声明(Persistent Volume Claim,PVC)
-
持久卷(PV):
- 是集群中的一块存储,可以由管理员预先分配,也可以动态创建。它是一种抽象的存储资源,与具体的存储实现(如NFS、Ceph、iSCSI等)相分离。例如,管理员可以使用以下YAML文件创建一个NFS类型的PV:
apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteMany nfs: server: nfs-server.example.com path: "/path/to/export"
- 这里定义了一个容量为10GB、支持多节点读写(ReadWriteMany)的NFS存储,它的存储后端是
nfs-server.example.com
服务器上的/path/to/export
目录。
-
持久卷声明(PVC):
- 是用户对存储的请求,它可以请求一定数量的存储资源和访问模式。PVC和PV是通过
accessModes
和storage
等属性进行匹配的。例如,用户可以使用以下YAML文件创建一个PVC:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi
- 这个PVC请求5GB的存储,且只允许单个节点读写(ReadWriteOnce)。Kubernetes会根据这个PVC的要求自动匹配到合适的PV。
- 是用户对存储的请求,它可以请求一定数量的存储资源和访问模式。PVC和PV是通过
-
使用方式:
- 在Pod的
spec
中,通过volumes
和volumeMounts
来使用PVC。例如:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: my-image volumeMounts: - name: my-volume mountPath: /data volumes: - name: my-volume persistentVolumeClaim: claimName: my-pvc
- 这里将名为
my-pvc
的PVC挂载到容器内的/data
目录,使得容器可以读写PVC提供的存储资源。
- 在Pod的
二、本地存储卷(Local Volume)
-
概念:
- 是将存储直接绑定到集群的某个节点上,适用于需要低延迟和高性能的本地存储需求。例如,对于一些有本地SSD存储的节点,可以使用本地存储卷。
-
使用方式:
- 首先要创建一个本地存储的
StorageClass
,指定存储的类型和回收策略等。例如:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer reclaimPolicy: Delete
- 然后在PV的创建中使用这个
StorageClass
,并指定存储的节点亲和性,确保PV只会绑定到某个特定节点的本地存储上。例如:
apiVersion: v1 kind: PersistentVolume metadata: name: local-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce storageClassName: local-storage local: path: /mnt/disks/ssd1 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - node1
- 这个PV绑定到名为
node1
的节点上的/mnt/disks/ssd1
目录,提供5GB的存储,只允许单个节点读写。
- 首先要创建一个本地存储的
三、配置映射(ConfigMap)和秘密(Secret)
-
配置映射(ConfigMap):
- 用于存储非敏感的配置信息,如配置文件、环境变量等。可以将配置文件的内容存储在ConfigMap中,然后将其挂载到容器内。例如:
apiVersion: v1 kind: ConfigMap metadata: name: my-config data: config.ini: | key1=value1 key2=value2
- 并在Pod中使用:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: my-image volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: my-config
- 这里将ConfigMap的内容挂载到容器内的
/etc/config
目录,容器内的应用可以读取/etc/config/config.ini
文件。
-
秘密(Secret):
- 用于存储敏感信息,如密码、API密钥等。数据会被Base64编码,提高安全性。例如,存储一个密码的Secret:
apiVersion: v1 kind: Secret metadata: name: my-secret type: Opaque data: password: cGFzc3dvcmQ=
- 在Pod中使用Secret:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: my-image volumeMounts: - name: secret-volume mountPath: /etc/secret volumes: - name: secret-volume secret: secretName: my-secret
- 将Secret挂载到容器内的
/etc/secret
目录,容器内的应用可以通过文件读取密码。
四、EmptyDir卷
-
概念:
- 是一种临时存储,与Pod的生命周期绑定,当Pod被删除时,存储也会被删除。它可以用于同一Pod内的容器间共享数据。例如,一个包含主容器和辅助容器的Pod,可以使用EmptyDir来存储它们之间共享的数据。
-
使用方式:
- 在Pod的
spec
中添加EmptyDir卷:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: main-container image: main-image volumeMounts: - name: shared-data mountPath: /data - name: side-container image: side-image volumeMounts: - name: shared-data mountPath: /shared-data volumes: - name: shared-data emptyDir: {}
- 这里在Pod内创建了一个名为
shared-data
的EmptyDir卷,分别挂载到main-container
的/data
目录和side-container
的/shared-data
目录,两个容器可以通过这个共享卷交换数据。
- 在Pod的
五、HostPath卷
-
概念:
- 将主机节点上的文件或目录挂载到Pod内的容器中。使用时要谨慎,因为它将容器与主机的文件系统绑定,可能影响主机的安全性和稳定性。例如,将主机的
/var/log
目录挂载到容器内用于日志收集。
- 将主机节点上的文件或目录挂载到Pod内的容器中。使用时要谨慎,因为它将容器与主机的文件系统绑定,可能影响主机的安全性和稳定性。例如,将主机的
-
使用方式:
- 在Pod的
spec
中添加HostPath卷:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: my-image volumeMounts: - name: host-volume mountPath: /host-log volumes: - name: host-volume hostPath: path: /var/log
- 这里将主机的
/var/log
目录挂载到容器内的/host-log
目录,容器可以访问主机的日志文件。
- 在Pod的
不同的数据持久化方式适用于不同的场景,需要根据应用的具体需求、对存储的安全性、性能、持久性等方面的要求来选择合适的持久化方案。例如,对于需要长期存储数据且可共享的应用,使用PV和PVC是个好选择;对于临时数据共享,可以使用EmptyDir;对于配置信息和敏感信息,分别使用ConfigMap和Secret;对于依赖主机本地存储的特殊场景,可以使用Local Volume或HostPath(谨慎使用)。
关于 Dockerfile 中 COPY
和 ADD
指令的异同点
一、相同点
- 功能目的:
COPY
和ADD
都可以将文件或目录从构建上下文(build context)复制到 Docker 镜像中的指定位置。它们是构建 Docker 镜像时将本地文件包含进镜像的主要手段。例如,当你需要将应用的代码文件、配置文件或静态资源文件添加到镜像中,以便在容器中运行时,都可以使用这两个指令。
二、不同点
-
功能特性:
- COPY:
- 功能相对简单,仅用于将本地文件或目录复制到镜像中。它的语法是
COPY <源路径> <目标路径>
。例如:
COPY app.py /app/
- 上述示例将构建上下文中的
app.py
文件复制到镜像内的/app/
目录下。它的行为类似于cp
命令,只做简单的复制操作,不会进行额外的处理。
- 功能相对简单,仅用于将本地文件或目录复制到镜像中。它的语法是
- ADD:
- 除了具有
COPY
的功能外,还支持一些额外的功能。 - 它可以从 URL 下载文件并添加到镜像中。例如:
ADD http://example.com/bigfile.zip /app/
- 此指令会从指定的 URL 下载
bigfile.zip
并将其复制到镜像内的/app/
目录下。不过,在实际使用中,不推荐使用ADD
来下载文件,因为RUN curl
或RUN wget
等命令提供了更多的灵活性和透明度。 - 它还具有自动解压缩的功能。如果源文件是一个压缩文件(如
.tar.gz
、.tar
、.gz
、.xz
等),并且目的是复制到一个目录中,ADD
会自动将其解压到该目录。例如:
ADD archive.tar.gz /app/
- 上述指令会将
archive.tar.gz
解压到/app/
目录中,而COPY
不会进行解压操作。
- 除了具有
- COPY:
-
使用建议:
- 通常情况下,优先使用
COPY
指令,因为它的功能简单明确,行为可预测,有助于保持 Dockerfile 的清晰和可维护性。 - 只有在确实需要从 URL 下载文件或需要自动解压压缩文件,并且这种行为是合理且安全的情况下,才考虑使用
ADD
。
- 通常情况下,优先使用
-
最佳实践示例:
- 以下是一个使用
COPY
和ADD
的 Dockerfile 示例:
FROM alpine:latest WORKDIR /app # 使用 COPY 复制本地文件 COPY app.py /app/ # 不推荐使用 ADD 从 URL 下载文件,此处仅作示例 ADD http://example.com/bigfile.zip /app/ # 使用 ADD 解压文件,这里假设 archive.tar.gz 是一个有效的压缩文件 ADD archive.tar.gz /app/ # 通常情况下,以下载文件为例,推荐使用 RUN 和 curl 或 wget 代替 ADD RUN wget http://example.com/bigfile.zip && unzip bigfile.zip -d /app/
- 以下是一个使用
在这个示例中:
COPY app.py /app/
只是简单地将app.py
从构建上下文复制到镜像的/app/
目录。ADD http://example.com/bigfile.zip /app/
从 URL 下载文件并添加到/app/
目录,但这种方式不推荐,因为使用RUN wget
可以提供更多的下载过程控制。ADD archive.tar.gz /app/
会自动解压archive.tar.gz
到/app/
目录,而COPY
不会执行解压操作。
使用 COPY
和 ADD
时要注意,它们的源路径是相对于构建上下文的,而不是相对于 Dockerfile 的位置。此外,使用 ADD
时要特别小心其额外的功能,避免引入不必要的复杂性或安全风险。例如,从不可信的 URL 下载文件可能会带来安全隐患,而自动解压功能可能会在不需要时造成意外的文件结构变化。
总的来说,对于简单的文件复制操作,建议使用 COPY
;对于需要特殊处理(如解压)且符合最佳实践的情况,可以考虑使用 ADD
,但要谨慎评估。