1:介绍了一下我的CI/CD流水线项目

答:巴拉巴拉

2:你这个流水线中的harbor镜像仓库假如不可用了怎么办,你怎么保证他高可用?

答:我想的是用一个loadbalancer服务下面管理几个harbor的pod提供仓库服务,假如有一个或者几个不可用了之后loadbalancer本身有健康检查和负载均衡的功能能及时剔除这些不可用的pod,然后从其他pod中提供镜像。但是面试官反驳这个harbor本身是由状态应用,又不是http服务器,你怎么保证这几个harbor仓库的状态是一致的呢,然后我猜想能否在gitlab_ci.yml文件等一推送镜像的时候推送到每个pod上但是被否定了。结合mysql主从复制保证高可用了解到实际的有状态应用保证高可用应该使用主从复制的方法,具体如下:

harbor仓库的数据分为两大类,harbor元数据(用户信息,权限等等)和镜像文件

harbor元数据是存储在数据库下的默认是mysql,这个数据我们可以配置mysql主从复制实现高可用。

镜像文件一般持续存储是通过存储在挂载的pv下的,我们可以设置一个pv允许共享挂载,然后把这个pv挂载到不同的这些pod,然后设置一个loadbalancer服务统一代理流量并且能够定时对pod进行健康检查及时剔除不可用的pod,到此我们就实现了数据层面和服务提供的高可用性。

3:你这个流水线中的gitlab_runner是如何使用的,具体怎么注册流水线的?

答:具体如下:

一、关键角色和组件

  • 开发者:提交代码(push)到 GitLab 仓库
  • GitLab 服务器:管理代码仓库和流水线调度
  • GitLab Runner:流水线任务的实际执行者,监听并运行具体 CI/CD Job
  • 执行环境:Runner 运行作业的环境,比如虚拟机、容器、Kubernetes Pod

二、从提交到流水线完成的完整过程

1. 开发者提交代码

  • 开发者在本地完成代码变更后,执行 git push 将代码推送到 GitLab 仓库
  • GitLab 服务器检测到代码有变更,会自动触发 CI 事件

2. GitLab 解析 CI 配置文件 .gitlab-ci.yml

  • GitLab 服务器检测到项目根目录下存在 .gitlab-ci.yml 文件
  • 它会解析此文件,根据定义的 stages 和 job 生成一个流水线(Pipeline)执行计划
  • 每个作业(job)包含需要执行的脚本、运行标签、依赖关系等信息

3. GitLab 创建并调度 Job

  • GitLab 把需要执行的 Job 按照优先级、依赖关系放入队列中
  • 这些 Job 都带有对应的标签(tags)信息,例如:docker、k8s、linux 等,用于匹配合适的 Runner

4. GitLab Runner 监听并拉取 Job

  • GitLab Runner 作为独立进程或服务一直在后台运行,不断向 GitLab 服务器查询是否有符合自己标签的 Job 待执行
  • 当 GitLab 发现有合适的 Job 时,会推送任务给对应的 Runner

5. GitLab Runner 接收并启动执行任务

  • Runner 在拿到 Job 后,会根据注册时选择的 Executor 类型,准备执行环境:

    • Shell Executor:直接在宿主机 shell 运行脚本
    • Docker Executor:启动容器,容器中执行脚本
    • Kubernetes Executor:在 Kubernetes 集群中创建 Pod,Pod 内执行 CI 作业
    • 等其他自定义 Executor
  • Runner 会拉取代码、设置环境变量、创建工作目录


6. Runner 运行 Job 脚本

  • 按照 .gitlab-ci.yml 文件中该 Job 的 script 命令依次执行
  • 这可以包括编译、测试、打包、发布等等操作
  • 所有的标准输出和错误会实时发送到 GitLab,方便前端查看日志


7. Runner 汇报任务执行状态

  • 执行过程中,Runner 会持续向 GitLab 汇报执行进度、状态(running、success、failed)
  • 如果任务失败,GitLab 页面会显示失败原因和日志
  • 如果任务成功,GitLab 会记录并展示成功状态

8. GitLab 后续阶段执行

  • 当所有前置 Job 执行成功后,GitLab 才会触发后续 Stages 中的 Job
  • Runner 会不断接收这些后续 Job 并执行

9. 流水线执行完成

  • 当所有 Job 均成功完成后,GitLab 会将流水线标记为通过,触发相应的通知、产物上传、后续自动化流程等
  • 如果有失败的 Job,流水线则标记为失败,需要排查错误

三、总结 GitLab Runner 的核心作用

流程阶段GitLab Runner 作用
持续监听任务不断向 GitLab 服务器轮询可执行 Job
领取 Job获取符合自己标签的 Job,承接执行任务
环境准备创建执行环境(shell、docker 容器、k8s pod)
代码拉取拉取项目代码快照,保证跟执行代码版本一致
脚本执行按 .gitlab-ci.yml 中定义的脚本逐条执行
执行状态上报将执行日志、状态反馈给 GitLab,方便实时监控和错误定位
支持多 Executor 类型灵活适配物理机、容器、Kubernetes,满足不同执行需求

4:你这个loadbalancer直接就可以使用吗,需要设置一些其他组件吗?

答:

  • 在云厂商环境里,比如 AWS EKS、GKE、Azure AKS,直接创建 Service 类型是 LoadBalancer,通常会自动分配和启动负载均衡器,你可以 直接使用

  • 在本地裸机或自建 Kubernetes 集群,没有云厂商负载均衡服务时:

    • 直接创建 LoadBalancer 类型 Service,服务会停留在 pending 状态,因为没有外部 LB 资源
    • 你不能直接使用,需要额外配合一些负载均衡解决方案才可支持类似 LoadBalancer 功能
  • 解决方法,在k8s集群中部署metallb
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml

然后配置 IP 地址池(示例 ConfigMap):

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: my-ip-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.240-192.168.1.250
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-advertisement
  namespace: metallb-system
spec:
  ipAddressPools:
  - my-ip-pool

上面 IP 段替换成你局域网里没被占用的地址段。

配置好后,创建 LoadBalancer 类型 Service 就能自动获得上述 IP 段内的地址,外部就可以访问了。

5:你这loadlbalancer的负载均衡器公网ip是如何跟loadbalancer服务入口绑定的从而进行流量传输?

首先对于云厂商提供的环境而言,负载均衡器会被默认分配一个公网ip,然后负载均衡器的配置包括前端监听公网ip的某些端口类似80,443等,然后后段会配置target,就是这个k8s集群所有节点的ip地址,之后loadbalancer服务会默认开启一个nodeport,前端接收到请求后会根据负载均衡策略选择一个节点,再发送节点ip:port,发送给改节点,节点接收到之后,kube-proxy会拦截来自于nodeport类型的流量,在根据服务:后段pod的对应关系,和负载均衡策略选择一个pod进行ip地址的转换,之后发送到该pod上。

但是对于自建集群而言,我们通常会安装metallb,这个工作原理和云厂商的负载均衡器实现原理不一样,他是由controller和speaker构成,controller负载检测服务和ip资源,会从空闲的ip池分配一个给服务,之后给所有speaker节点发送ip地址和所有后段pod地址的映射关系,speaker节点会在改节点的网络广播信息,所有给loadbalancer发的消息先发到speaker节点,这样所有交换机和路由器都会学习到该路有消息。当流量发送到speaker节点后,kube-proxy会拦截流量并且负载均衡发送给选中的pod。

6:假如本地存储情况下你这个pv所在节点宕机了,数据还能再读取吗?

  • 本地卷绑定到某个具体节点的物理磁盘上。
  • 如果该节点宕机或无法访问,其它节点无法直接访问该存储设备。
  • 因此,该 PV 的数据只能由那个节点访问,节点不可用时,应用无法访问数据。
  • 容器如果移到了其他节点,没有复制机制的话,读不到数据。

如果是网络存储(NFS、Ceph、云盘等)

  • 这些存储通常是集中式或分布式存储系统,可以被多个节点访问。
  • 数据存储在网络存储设备上,不依赖单个节点。
  • 即使某个节点宕机,只要网络和存储系统正常,Pod 调度到其它节点依然可以挂载并访问 PV 中的数据。

7:pod中日志收取的机制是怎么样的,kubectl logs是如何起作用的?

1. Pod 中日志的产生和存储

  • Kubernetes 中的容器(比如 Docker 容器)通常将标准输出(stdout)和标准错误(stderr)打印日志。

  • 这些日志被容器运行时(container runtime,如 Docker、containerd)捕获并写入到节点本地的日志文件中。

  • 日志文件一般位于节点文件系统的某个路径,比如:

    • Docker: /var/lib/docker/containers/<container-id>/<container-id>-json.log
    • containerd: /var/log/pods/<namespace>_<podname>_<uid>/<container-name>/...
  • 这些日志文件是纯文本格式,通常是 JSON 行格式(每行一个 JSON 对象,包含时间戳和日志内容)。


2. kubectl logs 是如何工作的?

kubectl logs 命令主要功能是:

  • 读取指定 Pod 中某个容器的标准输出日志内容。
  • 该命令运行在客户端(用户电脑或任意 kubectl 运行的地方),背后实际上是调用 Kubernetes API Server。

具体流程:

  1. kubectl 发起请求给 Kubernetes API Server

    • 请求类似于:
      GET /api/v1/namespaces/{namespace}/pods/{pod}/log?container={container}

    • 该请求会被 API Server 路由到具体负责该 Pod 的节点上的 kubelet。

  2. API Server 转发请求给 Pod 所在节点的 kubelet

    • kubelet 运行在该节点,拥有对该节点本地容器日志文件的访问权限。
  3. kubelet 读取对应的日志文件

    • kubelet 根据请求参数找到对应容器的日志文件路径。
    • 读取日志文件,将内容流式返回给 API Server,再返回给 kubectl。
  4. kubectl 显示日志

    • 用户终端上显示日志内容。

8:反问:面试官对于新人的预期,技术方面,性格方面,沟通方面?

答:要求新人有自我驱动力,解决问题的能力强,技术扎实,并且沟通能力出色。

9:反问:面试官所在部门业务?

答:负责算法业务的运维工作和故障解决工作

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐