2020年第一波企业运维面试题

总体来说 19 年到现在大环境不太好,各行各业都受影响,前段时间听说苏宁开启全员卖货模式,连副总裁都开始在朋友圈卖内裤了。

疫情期间让员工主动离职,不给赔偿,更可恶的是 HR 私自登录员工系统提交离职报告。我是比较幸运的,有稳定的工作,有时候也会做一些游戏代练挣一些外快,反正吃饱饭是没问题了,哈哈。

本文盘点一下,我在疫情参加的面试被问的问题。

总体来说 19 年到现在大环境不太好,各行各业都受影响,前段时间听说苏宁开启全员卖货模式,连副总裁都开始在朋友圈卖内裤了,哈哈哈,真是患难见忠臣啊,当然也听说 xx 二手车强制转岗、降薪,变相裁员。

疫情期间让员工主动离职,不给赔偿,更可恶的是 HR 私自登录员工系统提交离职报告。我微信里的一个做二手服务器回收的老哥,18 年收了两千多万的服务器,去年一半都不到;还有的朋友,单位开不出来工资,生活也受到很大的影响。总而言之,我是比较幸运的,有稳定的工作,有时候也会做一些游戏代练挣一些外快,反正吃饱饭是没问题了,哈哈。

来说说自己的情况吧,2.3 号回来就一直在工作,偶尔也会登录 Boss 直聘投投简历,看看用人单位有哪些技能要求,但是很无奈,要么多半是外包,要么就是已读不回,还有的拿了你的简历就没影了,曾经我手机上唯一的求职软件,我也要卸载了。想想这些年,3584 次沟通,投递 779 份简历,也算是给我的运维经历画上完美的句号了,如图所示:

在这里插入图片描述前一段时间正式开始启用智联招聘,哇,真的是让我眼前一亮,以前不可以和 HR 沟通,现在也可以沟通了,而且每日签到功能还有各种福利,例如简历超级曝光、优先推荐、offer 迷你吸铁石、精美简历模板、超级面霸养成,而且你一投递简历,很快就有 HR 联系你,总体体验感是非常棒的,我也来说说我找工作的要求吧:

  1. 距离超过 35km 不考虑(时间成本)
  2. 外包不考虑(无归属感,福利待遇得不到保障)
  3. 规模比较小的不考虑(有可能发不出工资,或者掐网线也是你负责哈哈)
  4. 第一轮去直接技术面试,否则免谈,跟你扯半天还不如实打实的来一场技术的碰撞。下图是我在智联招聘盲投 5 天的结果。

在这里插入图片描述

接下来咱们就开始聊技术吧,我把面试题发出来,大家参考一下:

1. Git 和 Svn 的区别

  • Git 是分布式的,而 Svn 不是分布的;

  • Git 把内容按元数据方式存储,而 SVN 是按文件;

  • Git 没有一个全局版本号,而 SVN 有:目前为止这是跟 SVN 相比 Git 缺少的最大的一个特征;

  • Git 的内容的完整性要优于 SVN: GIT 的内容存储使用的是 SHA-1 哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏;

  • Git 下载下来后,在 OffLine 状态下可以看到所有的 Log,SVN 不可以;SVN 必须先 Update 才能 Commit,忘记了合并时就会出现一些错误,git 还是比较少的出现这种情况。

  • 克隆一份全新的目录以同样拥有五个分支来说,SVN 是同时复製 5 个版本的文件,也就是说重复五次同样的动作。而 Git 只是获取文件的每个版本的 元素,然后只载入主要的分支(master)在我的经验,克隆一个拥有将近一万个提交(commit),五个分支,每个分支有大约 1500 个文件的 SVN,耗了将近一个小时!而 Git 只用了区区的 1 分钟!

  • 版本库(repository):SVN 只能有一个指定中央版本库。当这个中央版本库有问题时,所有工作成员都一起瘫痪直到版本库维修完毕或者新的版本库设立完成。而 Git 可以有无限个版本库。或者,更正确的说法,每一个 Git 都是一个版本库,区别是它们是否拥有活跃目录(Git Working Tree)。如果主要版本库(例如:置於 GitHub 的版本库)发生了什麼事,工作成员仍然可以在自己的本地版本库(local repository)提交,等待主要版本库恢复即可。工作成员也可以提交到其他的版本库!

  • 分支(Branch)在 SVN,分支是一个完整的目录。且这个目录拥有完整的实际文件。如果工作成员想要开啟新的分支,那将会影响“全世界”!每个人都会拥有和你一样的分支。如果你的分支是用来进行破坏工作(安检测试),那将会像传染病一样,你改一个分支,还得让其他人重新切分支重新下载,十分狗血。而 Git,每个工作成员可以任意在自己的本地版本库开啟无限个分支。

  • Git 的分支名是可以使用不同名字的。例如:我的本地分支名为 OK,而在主要版本库的名字其实是 master。

  • 提交(Commit)在 SVN,当你提交你的完成品时,它将直接记录到中央版本库。当你发现你的完成品存在严重问题时,你已经无法阻止事情的发生了。如果网路中断,你根本没办法提交!而 Git 的提交完全属於本地版本库的活动。而你只需“推”(git push)到主要版本库即可。Git 的“推”其实是在执行“同步”(Sync)。

  • 总结:SVN 的特点是简单,只是需要一个放代码的地方时用是 OK 的。

  • Git 的特点版本控制可以不依赖网络做任何事情,对分支和合并有更好的支持(当然这是开发者最关心的地方),不过想各位能更好使用它,需要花点时间尝试一下。

2. mysql 主从原理?主从不同步怎么办?主从慢,差的多咋办?

master 将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events)slave 将 master 的 binary log events 拷贝到它的中继日志 (relay log) slave 重做中继日志中的事件,将改变反映它自己的数据。或从库生成两个线程,一个 I/O 线程,一个 SQL 线程;

i/o 线程去请求主库 的 binlog,并将得到的 binlog 日志写到 relay log(中继日志) 文件中;

主库会生成一个 log dump 线程,用来给从库 i/o 线程传 binlog;

SQL 线程,会读取 relay log 文件中的日志,并解析成具体操作,来实现主从的操作一致,而最终数据一致;

先上 Master 库:

mysql>show processlist;查看下进程是否 Sleep 太多。发现很正常。

show master status;也正常。

mysql> show master status;+-------------------+----------+--------------+-------------------------------+| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB              |+-------------------+----------+--------------+-------------------------------+| mysqld-bin.000001 |     3260 |              | mysql,test,information_schema |+-------------------+----------+--------------+-------------------------------+1 row in set (0.00 sec)

再到 Slave 上查看

mysql> show slave status\G                                               Slave_IO_Running: YesSlave_SQL_Running: No

可见是 Slave 不同步

下面介绍两种解决方法:

  • 方法一:忽略错误后,继续同步该方法适用于主从库数据相差不大,或者要求数据可以不完全统一的情况,数据要求不严格的情况

解决:

stop slave;#表示跳过一步错误,后面的数字可变set global sql_slave_skip_counter =1;start slave;

之后再用mysql> show slave status\G查看:

Slave_IO_Running: YesSlave_SQL_Running: Yes

ok,现在主从同步状态正常了。。。

  • 方式二:重新做主从,完全同步

该方法适用于主从库数据相差较大,或者要求数据完全统一的情况解决步骤如下:

  1. 先进入主库,进行锁表,防止数据写入使用命令:mysql> flush tables with read lock;

注意:该处是锁定为只读状态,语句不区分大小写

  1. 进行数据备份
#把数据备份到 mysql.bak.sql 文件[root@server01 mysql]#mysqldump -uroot -p -hlocalhost > mysql.bak.sql

这里注意一点:数据库备份一定要定期进行,可以用 shell 脚本或者 python 脚本,都比较方便,确保数据万无一失

  1. 查看 master 状态
mysql> show master status;+-------------------+----------+--------------+-------------------------------+| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB              |+-------------------+----------+--------------+-------------------------------+| mysqld-bin.000001 |     3260 |              | mysql,test,information_schema |+-------------------+----------+--------------+-------------------------------+1 row in set (0.00 sec)
  1. 把 mysql 备份文件传到从库机器,进行数据恢复
#使用 scp 命令[root@server01 mysql]# scp mysql.bak.sql root@192.168.128.101:/tmp/
  1. 停止从库的状态
mysql> stop slave;
  1. 然后到从库执行 mysql 命令,导入数据备份
 mysql> source /tmp/mysql.bak.sql
  1. 设置从库同步,注意该处的同步点,就是主库 show master status 信息里的 | File | Position 两项
change master to master_host = '192.168.128.100', master_user = 'rsync', master_port=3306, master_password='', master_log_file = 'mysqld-bin.000001', master_log_pos=3260;
  1. 重新开启从同步
mysql> start slave;
  1. 查看同步状态

mysql> show slave status\G查看:

Slave_IO_Running: YesSlave_SQL_Running: Yes

好了,同步完成啦。

如果延迟比较大,就先确认以下几个因素:

  1. 从库硬件比主库差,导致复制延迟;
  2. 主从复制单线程,如果主库写并发太大,来不及传送到从库,就会导致延迟。更高版本的 mysql 可以支持多线程复制
  3. 慢 SQL 语句过多
  4. 网络延迟
  5. master 负载:主库读写压力大,导致复制延迟,架构的前端要加 buffer 及缓存层
  6. slave 负载一般的做法是,使用多台 slave 来分摊读请求,再从这些 slave 中取一台专用的服务器,只作为备份用,不进行其他任何操作。

另外,2 个可以减少延迟的参数:

–slave-net-timeout=seconds 单位为秒,默认设置为 3600 秒#参数含义:当 slave 从主数据库读取 log 数据失败后,等待多久重新建立连接并获取数据– master-connect-retry=seconds?单位为秒?默认设置为 60 秒#参数含义:当重新建立主从连接时,如果连接建立失败,间隔多久后重试。

通常配置以上 2 个参数可以减少网络问题导致的主从数据同步延迟MySQL 数据库主从同步延迟解决方案;

最简单的减少 slave 同步延时的方案就是在架构上做优化,尽量让主库的 DDL 快速执行。还有就是主库是写,对数据安全性较高,比如sync_binlog=1,innodb_flush_log_at_trx_commit= 1之类的设置,而 slave 则不需要这么高的数据安全,完全可以讲sync_binlog设置为 0 或者关闭 binlog,innodb_flushlog也可以设置为 0 来提高 sql 的执行效率。另外就是使用比主库更好的硬件设备作为 slave。

3. kafka 和 mq 的区别

作为消息队列来说,企业中选择 mq 的还是多数,因为像 Rabbit,Rocket 等 mq 中间件都属于很成熟的产品,性能一般但可靠性较强,而 kafka 原本设计的初衷是日志统计分析,现在基于大数据的背景下也可以做运营数据的分析统计,而 redis 的主要场景是内存数据库,作为消息队列来说可靠性太差,而且速度太依赖网络 IO,在服务器本机上的速度较快,且容易出现数据堆积的问题,在比较轻量的场合下能够适用。

RabbitMQ,遵循 AMQP 协议,由内在高并发的 erlanng 语言开发,用在实时的对可靠性要求比较高的消息传递上。

kafka 是 Linkedin 于 2010 年 12 月份开源的消息发布订阅系统,它主要用于处理活跃的流式数据,大数据量的数据处理上。

4. k8s service 类型?

ClusterIP集群内部容器访问地址,会生成一个虚拟 IP 与 pod 不在一个网段。

NodePort会在宿主机上映射一个端口,供外部应用访问模式。

Headless CluserIP无头模式,无 serviceip,即把 spec.clusterip 设置为 None 。

LoadBalancer使用外部负载均衡。

5. pod 之间如何通信?

  • pod 内部容器之间,这种情况下容器通讯比较简单,因为 k8s pod 内部容器是共享网络空间的,所以容器直接可以使用 localhost 访问其他容器。k8s 在启动容器的时候会先启动一个 pause 容器,这个容器就是实现这个功能的。

  • pod 与 pod 容器之间,这种类型又可以分为两种情况:

    两个 pod 在一台主机上面,两个 pod 分布在不同主机之上针对第一种情况,就比较简单了,就是 docker 默认的 docker 网桥互连容器。

第二种情况需要更为复杂的网络模型了,k8s 官方推荐的是使用 flannel 组建一个大二层扁平网络,pod 的 ip 分配由 flannel 统一分配,通讯过程也是走 flannel 的网桥。

6. k8s 健康检查方式

存活性探针(liveness probes)和就绪性探针(readiness probes)用户通过 Liveness 探测可以告诉 Kubernetes 什么时候通过重启容器实现自愈;Readiness 探测则是告诉 Kubernetes 什么时候可以将容器加入到 Service 负载均衡池中,对外提供服务。语法是一样的。

7. k8s pod 状态

Pod --Pending 状态

Pending 说明 Pod 还没有调度到某个 Node 上面。可以通过 kubectl describe pod <pod-name> 命令查看到当前 Pod 的事件,进而判断为什么没有调度。可能的原因包括

资源不足,集群内所有的 Node 都不满足该 Pod 请求的 CPU、内存、GPU 等资源。

HostPort 已被占用,通常推荐使用 Service 对外开放服务端口

Pod --Waiting 或 ContainerCreating 状态

首先还是通过 kubectl describe pod <pod-name> 命令查看到当前 Pod 的事件。可能的原因包括

镜像拉取失败,比如配置了镜像错误、Kubelet 无法访问镜像、私有镜像的密钥配置错误、镜像太大,拉取超时等。

CNI 网络错误,一般需要检查 CNI 网络插件的配置,比如无法配置 Pod 、无法分配 IP 地址

容器无法启动,需要检查是否打包了正确的镜像或者是否配置了正确的容器参数。

Pod -- ImagePullBackOff 状态

这也是我们测试环境常见的,通常是镜像拉取失败。这种情况可以使用 docker pull <image> 来验证镜像是否可以正常拉取。

或者 docker images | grep <images>查看镜像是否存在(系统有时会因为资源问题自动删除一部分镜像),

Pod -- CrashLoopBackOff 状态

CrashLoopBackOff 状态说明容器曾经启动了,但可能又异常退出了。此时可以先查看一下容器的日志kubectl logs <pod-name> kubectl logs --previous <pod-name>

这里可以发现一些容器退出的原因,比如

  • 容器进程退出
  • 健康检查失败退出

Pod --Error 状态

通常处于 Error 状态说明 Pod 启动过程中发生了错误。常见的原因包括

依赖的 ConfigMap、Secret 或者 PV 等不存在。请求的资源超过了管理员设置的限制,比如超过了 LimitRange 等。

违反集群的安全策略,比如违反了 PodSecurityPolicy 等。

容器无权操作集群内的资源,比如开启 RBAC 后,需要为 ServiceAccount 配置角色绑定。

Pod --Terminating 或 Unknown 状态从 v1.5 开始,Kubernetes 不会因为 Node 失联而删除其上正在运行的 Pod,而是将其标记为 Terminating 或 Unknown 状态。想要删除这些状态的 Pod 有三种方法:

从集群中删除该 Node。使用公有云时,kube-controller-manager 会在 VM 删除后自动删除对应的 Node。而在物理机部署的集群中,需要管理员手动删除 Node(如 kubectl delete node <node-name>。 Node 恢复正常。Kubelet 会重新跟 kube-apiserver 通信确认这些 Pod 的期待状态,进而再决定删除或者继续运行这些 Pod。 用户强制删除。用户可以执行 kubectl delete pods <pod> --grace-period=0 --force 强制删除 Pod。除非明确知道 Pod 的确处于停止状态(比如 Node 所在 VM 或物理机已经关机),否则不建议使用该方法。 特别是 StatefulSet 管理的 Pod,强制删除容易导致脑裂或者数据丢失等问题。

Pod -- Evicted 状态

出现这种情况,多见于系统内存或硬盘资源不足,可 df-h 查看 docker 存储所在目录的资源使用情况,如果百分比大于 85%,就要及时清理下资源,尤其是一些大文件、docker 镜像。

8. k8s 资源限制

对于一个 pod 来说,资源最基础的 2 个的指标就是:CPU 和内存。Kubernetes 提供了个采用 requests 和 limits 两种类型参数对资源进行预分配和使用限制。

limit 会限制 pod 的资源利用:

  • 当 pod 内存超过 limit 时,会被 oom。
  • 当 cpu 超过 limit 时,不会被 kill,但是会限制不超过 limit 值。

9. 软链接和硬链接区别

软连接,其实就是新建立一个文件,这个文件就是专门用来指向别的文件的(那就和 windows 下的快捷方式的那个文件有很接近的意味)。软链接产生的是一个新的文件,但这个文件的作用就是专门指向某个文件的,删了这个软连接文件,那就等于不需要这个连接,和原来的存在的实体原文件没有任何关系,但删除原来的文件,则相应的软连接不可用(cat 那个软链接文件,则提示“没有该文件或目录“)

硬连接是不会建立 inode 的,他只是在文件原来的 inode link count 域再增加 1 而已,也因此硬链接是不可以跨越文件系统的。相反是软连接会重新建立一个 inode,当然 inode 的结构跟其他的不一样,他只是一个指明源文件的字符串信息。一旦删除源文件,那么软连接将变得毫无意义。而硬链接删除的时候,系统调用会检查 inode link count 的数值,如果他大于等于 1,那么 inode 不会被回收。因此文件的内容不会被删除。

硬链接实际上是为文件建一个别名,链接文件和原文件实际上是同一个文件。可以通过 ls -i 来查看一下,这两个文件的 inode 号是同一个,说明它们是同一个文件;而软链接建立的是一个指向,即链接文件内的内容是指向原文件的指针,它们是两个文件。

软链接可以跨文件系统,硬链接不可以;软链接可以对一个不存在的文件名(filename)进行链接(当然此时如果你 vi 这个软链接文件,linux 会自动新建一个文件名为 filename 的文件),硬链接不可以(其文件必须存在,inode 必须存在);软链接可以对目录进行连接,硬链接不可以。两种链接都可以通过命令 ln 来创建。ln 默认创建的是硬链接。使用 -s 开关可以创建软链接

10. mount 永久挂载

vi /etc/fstabUUID=904C23B64C23964E /media/aborn/data ntfs defaults        0      2

其中第一列为 UUID, 第二列为挂载目录(该目录必须为空目录,必须存在),第三列为文件系统类型,第四列为参数,第五列 0 表示不备份,最后一列必须为2或 0(除非引导分区为 1)

11. 打印一个目录下所有包含字符串 A 的行

例如/目录

grep -rn "A" ./ 

find ./ -name "*.*" | xargs grep  "A"

12. Kill 掉所有包含服务名 a 的进程(xargs 命令)

例如 a 进程ps -ef | grep "^a" | grep -v grep | cut -c 9-15 | xargs kill -9

ps x | grep a | grep -v grep | awk '{print $1}' | xargs kill -9

13. 谈下对 systemctl 理解

Linux 服务管理两种方式 service 和 systemctl

systemd 是 Linux 系统最新的初始化系统(init),作用是提高系统的启动速度,尽可能启动较少的进程,尽可能更多进程并发启动。

systemd 对应的进程管理命令是 systemctl

systemctl 命令兼容了 service, systemctl 命令管理 systemd 的资源 Unit

14. 谈下对 IPtables 的了解

iptables 其实不是真正的防火墙,我们可以把它理解成一个客户端代理,用户通过 iptables 这个代理,将用户的安全设定执行到对应的"安全框架"中,这个"安全框架"才是真正的防火墙,这个框架的名字叫 netfilteriptables 其实是一个命令行工具,位于用户空间,我们用这个工具操作真正的框架。

所以说,虽然我们使用 service iptables start 启动 iptables"服务",但是其实准确的来说,iptables 并没有一个守护进程,所以并不能算是真正意义上的服务,而应该算是内核提供的功能。

iptables 有 4 表 5 链:

  • filter 表——过滤数据包
  • Nat 表——用于网络地址转换(IP、端口)
  • Mangle 表——修改数据包的服务类型、TTL、并且可以配置路由实现 QOS
  • Raw 表——决定数据包是否被状态跟踪机制处理
  • INPUT 链——进来的数据包应用此规则链中的策略
  • OUTPUT 链——外出的数据包应用此规则链中的策略
  • FORWARD 链——转发数据包时应用此规则链中的策略
  • PREROUTING 链——对数据包作路由选择前应用此链中的规则(所有的数据包进来的时侯都先由这个链处理)
  • POSTROUTING 链——对数据包作路由选择后应用此链中的规则(所有的数据包出来的时侯都先由这个链处理)

15. 给做好的镜像添加一个文件

用 UltraISO PE (光软碟通)软件打开 iso 镜像文件就可以填加了

16. 页面无法访问排查思路

场景一:无错误状态码无错误状态码,多数情况下是“ERRCONNECTIONTIMED_OUT”问题。

出现 ERR_CONNECTION_TIMED_OUT错误原因,可以总结为以下 5 点:

  • 服务器带宽跑满、存在***
  • 若是云服务器可能存在账号处于欠费状态
  • 服务没有启动
  • 端口没有正常监听
  • 防火墙或者防火墙策略限制

排查思路说明:

  1. 使用命令 telnet IP Port 进行测试

  2. 如果端口是通的,则排查查看服务器带宽是否跑满、是否有***是否使用的账号处于欠费状态

  3. 如果端口不通,则排查:

  • web 服务没有正常启动
  • 端口没有正常监听
  • 防火墙/安全组拦截
  • 若是 web 服务没有正常启动,需要启动服务
  • 若是端口没有正常监听,需要修改配置文件= 若是防火墙拦截,需要关闭防火墙进行测试,或者找到相关限制规则进行修改。

场景二:网站访问异常代码 4XX。

排查思路:

  • 通过查看其配置文件,并检测其配置文件语法,发现语法正常;
  • 通过命令行查看其 web 服务端口运行正常,没有进程僵尸状况;
  • 具体读配置文件,然后再查找客户客户配置文件所指定的具体目录;

例如:网站数据目录等(本案例是客户机器迁移之后,由于阿里磁盘的特性导致盘符改变,客户的数据盘挂载不上,etcfstab 和盘符不匹配)

问题定位到之后,重新以正确的方式挂载客户网站数据;重启服务,问题得以圆满解决;

基于类似问题还可以关注下目录权限等问题。

经验汇总:

针对网站访问报错问题几点排查建议:

  • 服务器配置文件权限,以及语法的正确性;
  • 配置文件中指定的网站相关目录存在问题,及相关权限问题;
  • 运行 web 服务的用户和相关权限问题;
  • 防火墙的设置问题,导致服务不可达;
  • 服务器服务进程僵死问题;
  • 配置文件中的非法字符问题;(特别是从 windows 平台直接 cp 过来的配置文件容易报错)这样的问题较难排查,可以通过 type 命令或者 file 命令查看文件类型;最好是二进制格式或者 ascii 码,linux 平台可以安装 dos2unix 解决;
  • 服务器的错误日志亦是非常关键的问题突破口;

案例:报错“404 Not Found”

问题原因:

404 报错的具体原因是访问的路径 url 目录在服务上没有找到,如果直接使用 ip 或者域名访问,那么实际访问的页面是站点根目录下的默认文件(配置文件中 index 后指定的文件),如果服务器上站点根目录上没有这个文件,则会出现 404 错误。

排查步骤:

测试环境:Nginx 环境

站点跟目录/www/下没有默认 index.html 文件,访问 ip/inde.html,会报 Not Found 错误。

备注:Apache 环境下,404 错误也是同样的原理进行排查。

17. k8s 中 service 什么含义,怎么用

Service 是一种抽象的对象,它定义了一组 Pod 的逻辑集合和一个用于访问它们的策略,一个 Serivce 下面包含的 Pod 集合一般是由 Label Selector 来决定的。假如我们后端运行了 3 个副本,这些副本都是可以替代的,因为前端并不关心它们使用的是哪一个后端服务。

尽管由于各种原因后端的 Pod 集合会发生变化,但是前端却不需要知道这些变化,也不需要自己用一个列表来记录这些后端的服务,Service 的这种抽象就可以帮我们达到这种解耦的目的。

service 为后端 pod 提供一组负载均衡代理

三种 IP:

  • Node IP:Node 节点的 IP 地址
  • Pod IP:Pod 的 IP 地址
  • Cluster IP:Service 的 IP 地址

首先,Node IP 是 Kubernetes 集群中节点的物理网卡 IP 地址(一般为内网),所有属于这个网络的服务器之间都可以直接通信,所以 Kubernetes 集群外要想访问 Kubernetes 集群内部的某个节点或者服务,肯定得通过 Node IP 进行通信(这个时候一般是通过外网 IP 了)

然后 Pod IP 是每个 Pod 的 IP 地址,它是 Docker Engine 根据 docker0 网桥的 IP 地址段进行分配的(我们这里使用的是 flannel 这种网络插件保证所有节点的 Pod IP 不会冲突)

最后 Cluster IP 是一个虚拟的 IP,仅仅作用于 Kubernetes Service 这个对象,由 Kubernetes 自己来进行管理和分配地址,当然我们也无法 ping 这个地址,他没有一个真正的实体对象来响应,他只能结合 Service Port 来组成一个可以通信的服务。

定义 Service

定义 Service 的方式和各种资源对象的方式类型一样,假定我们有一组 Pod 服务,它们对外暴露了 80 端口,同时都被打上了 app=myapp 这样的标签,那么我们就可以像下面这样来定义一个 Service 对象:

pod 示例:

apiVersion: apps/v1kind: Deploymentmetadata:  name: testspec:  selector:    matchLabels:      app: myapp  replicas: 3  template:    metadata:      labels:        app: myapp    spec:      containers:      - name: nginx        image: nginx:1.7.9        ports:        - containerPort: 80

service 基于 pod 的示例:

apiVersion: v1kind: Servicemetadata:  name: myservicespec:  selector:    app: myapp  ports:  - protocol: TCP    port: 80    targetPort: 80

然后通过的使用 kubectl create -f myservice.yaml 就可以创建一个名为 myservice 的 Service 对象,它会将请求代理到使用 TCP 端口为 80,具有标签 app=myapp 的 Pod 上,这个 Service 会被系统分配一个我们上面说的 Cluster IP,该 Service 还会持续的监听 selector 下面的 Pod,会把这些 Pod 信息更新到一个名为 myservice 的 Endpoints 对象上去,这个对象就类似于我们上面说的 Pod 集合了。

需要注意的是,Service 能够将一个接收端口映射到任意的 targetPort。 默认情况下,targetPort 将被设置为与 port 字段相同的值。 可能更有趣的是,targetPort 可以是一个字符串,引用了 backend Pod 的一个端口的名称。 因实际指派给该端口名称的端口号,在每个 backend Pod 中可能并不相同,所以对于部署和设计 Service ,这种方式会提供更大的灵活性。另外 Service 能够支持 TCP 和 UDP 协议,默认是 TCP 协议。

kube-proxy

在 Kubernetes 集群中,每个 Node 会运行一个 kube-proxy 进程, 负责为 Service 实现一种 VIP(虚拟 IP,就是我们上面说的 clusterIP)的代理形式,现在的 Kubernetes 中默认是使用的 iptables 这种模式来代理。这种模式,kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。

对每个 Service,它会添加上 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某一个个上面。 对于每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend Pod。

默认的策略是,随机选择一个 backend。 我们也可以实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinity 的值设置为 "ClientIP" (默认值为 "None")。

另外需要了解的是如果最开始选择的 Pod 没有响应,iptables 代理能够自动地重试另一个 Pod,所以它需要依赖 readiness probes。

Service 类型

在定义 Service 的时候可以指定一个自己需要的类型的 Service,如果不指定的话默认是 ClusterIP 类型。

可以使用的服务类型如下:

  1. ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。
  2. NodePort:通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。
  3. LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。
  4. ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。

NodePort 类型

如果设置 type 的值为 "NodePort",Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。该端口将通过 Service 的 spec.ports[*].nodePort 字段被指定,如果不指定的话会自动生成一个端口。

需要注意的是,Service 将能够通过 :spec.ports[].nodePort 和 spec.clusterIp:spec.ports[].port 而对外可见。

接下来创建一个 NodePort 的服务

apiVersion: v1kind: Servicemetadata:  name: myservicespec:  selector:    app: myapp  type: NodePort  ports:  - protocol: TCP    port: 80    targetPort: 80    name: myapp-http    nodePort: 32560

创建该 Service:

$ kubectl create -f service-demo.yaml

然后我们可以查看 Service 对象信息:

$ kubectl get svcNAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGEkubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        27dmyservice    NodePort    10.104.57.198   <none>        80:32560/TCP   14h

可以看到 myservice 的 TYPE 类型已经变成了 NodePort,后面的 PORT(S)部分也多了一个 32560 的随机映射端口。

ExternalName

ExternalName 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。 对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。

kind: ServiceapiVersion: v1metadata:  name: my-service  namespace: prodspec:  type: ExternalName  externalName: my.database.example.com

当查询主机 my-service.prod.svc.cluster.local 时,集群的 DNS 服务将返回一个值为 my.database.example.com 的 CNAME 记录。 访问这个服务的工作方式与其它的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。

如果后续决定要将数据库迁移到 Kubernetes 集群中,可以启动对应****的 Pod,增加合适的 Selector 或 Endpoint,修改 Service 的 type,完全不需要修改调用的代码,这样就完全解耦了。

18. 和 K8s 服务端口冲突了怎么处理

k8s 端口被占用报错执行以下命令:kubeadm reset

19. redhat 6.X 版本系统 和 centos 7.X 版本有啥区别?

笔者回答:

  • 桌面系统(6/GNOE2.x、7/GNOME3.x)
  • 文件系统(6/ext4、7/xfs)
  • 内核版本(6/2.6x、7/3.10x)
  • 防火墙(6/iptables、7/firewalld)
  • 默认数据库(6/mysql、7/mariadb)
  • 启动服务(6/service 启动、7/systemctl 启动)
  • 网卡(6/eth0、7/ens192)等。

20. 说一下你们公司怎么发版的(代码怎么发布的)?

jenkins 配置好代码路径(SVN 或 GIT),然后拉代码,打 tag。需要编译就编译,编译之后推送到发布服务器(jenkins 里面可以调脚本),然后从分发服务器往下分发到业务服务器上。

如果是 php 的项目,可以 rsync 上线,但是 php 也可以用 Jenkins 来操作,php7 之后也是支持编译运行,这样上线之后运行效率更快,而且一定程度上保证了代码的安全。

前段时间,已经确定入职单位了,然后石墨文档给我发来入职邀请,我何德何能啊,真的是很感动,以下是他们技术面试官对我的评价,哈哈,装个 13。

在这里插入图片描述在这里插入图片描述

阅读全文: http://gitbook.cn/gitchat/activity/5ebb6dfbbea81111dcedd92c

您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

FtooAtPSkEJwnW-9xkCLqSTRpBKX

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页