面经

Linux

  1. LinuxA磁盘的文件全部迁移到B磁盘

    dd命令

  2. 如何创建lvm卷?

    fdisk分区–>pvcreate–>vgcreate–>lvcreate–>格式化–>挂载

  3. 100亿小文件删除,对比怎么删除比较高效?

    1. find + xargs实现分批删除

      find命令可以在找到文件的同时逐个处理,不需要将整个文件列表读入内存.

      find命令的算法可以更快地便利目录结构,避免不必要的IO操作

    2. 使用rsync创建一个空目录然后同步过去

      1
      2
      mkdir empty_dir
      rsync -a --delete emplty_dir/ /path/to/files
    3. 并发删除

      1
      find /path/to/files -type f -name "*.ext" | parallel -j 10 rm
  4. 1亿行日志文件,要根据关键字统计出现次数前十的日志,只用脚本,如何做效率比较高?

    将日志拆成多份,使用awk,sed,sort等工具统计排序,可以通过shell的parallel或者python的subprocess多进程/多线程提升效率.

  5. shell逐行处理大日志文件,有哪几种方式,有什么区别?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # cat会一次过读取整个文件的内容
    cat filename.log | while read line
    do
    echo "$line"
    done
    # while + 输入重定向,边读边处理,效率更高
    while read line
    do
    echo "$line"
    done < filename.log
    # awk/sed也是默认逐行处理
    awk '{print}' filename.log
    sed -n 'p' filename.log
    # 读取实时写入的日志文件
    tail --f filename.log | while read line
    do
    echo "$line"
    done

中间件/DB

  1. zookeeper

  2. kafka

    架构: 生产者–>broker–>消费者

    topic: 消息类别,生产者和消费者根据topic发送消息或消费消息

    partition: 副本机制

  3. redis

    哨兵集群

  4. mariadb

    主从集群

  5. mongodb

    副本集

  6. SQL联表查询

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 内连接
    # 只返回两个表中匹配的记录,如果表A的行与表B的行相匹配,则返回
    select columns from table1 inner join table2 on table1.column_name = table2.column_name
    # 左连接
    # 返回左表所有记录和右表中与匹配的记录,没有匹配就显示空值
    select columns from table1 left join table2 on table1.column_name = table2.column_name
    # 右连接
    # 返回右表所有记录以及左表中匹配的记录,没有匹配就显示空值
    select columns from table1 right join table2 on table1.column_name = table2.column_name
    # 全外连接
    # 返回两个表中所有的记录.当左表的行在右表中没有匹配,则在右侧显示空值,反之亦然
    select columns from table1 full outer join table2 on table1.column_name = table2.column_name

GIT

  1. 团队维护同一份github repo,你们是工作流是怎么样的?

    一般采用类似Feature Branch Workflow的流程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    git clone <repo_url>
    git checkout -b <new_branch_name>
    # 在分支上开发
    git add .
    git commit -m "Commit message"
    git push -u origin <new_branch_name>
    # 此时会在repo上创建一个PR,团队成员对代码进行审查(code review),通过后merge到master分支
    # 然后删除本地和远程的开发分支
    git branch -d feature_branch_name # 删除本地分支
    git push origin --delete feature_branch_name # 删除远程分支

    这是基本的工作流程,期间还可以加入其他步骤,例如代码静态分析(snoarQ),自动化测试,CI/CD等

AWS

  • Region & AZs

    region是指地球上的一个物理位置,比如北京,悉尼等.每个region底下都有多个AZ(可用区),AZ是指一个或者多个IDC,AZ之间独立电源和设备,相互之间通过专用线路连接,延迟低的同时也实现故障分离.也就是说一个AZ出问题了不会影响另一个AZ.所以AWS很多服务,比如EC2,RDS的高可用都是通过多可用区去实现的.

  • EC2

    • autoscaling组: 自动扩展组
    • 购买类型
      • 预留: 预定(一年或三年)的计算资源,折扣比按需大
      • spot: 将aws上未被使用的资源分配给你用,随时停止,按供需变化价格
      • 按需: 按小时或秒收费
      • 节省: 在一定时间内(一年或三年)使用一定量的计算资源,换取更低的价格
    • 集群放置组: 单可用区内将实例分配在一起(同一台物理服务器或同一个机架),实现低延迟高吞吐
    • 分区放置组: 将一批ec2实例分布在一个region下的不同分区中(或者不同机架不同服务器),实现故障隔离.
    • 实例类型:
      • T3:通用
      • R5: 内存优化
    • 终止挂起: EC2 autoscaling检测在实例不健康会自动删除实例创建新实例,有时不方便排查问题,我们可以设置一个生命周期钩子来暂停实例的终止,设置足够长的保留时间来排查问题
  • AWS organization

    集中管理,治理多个aws账户,提供policy为基础的管理功能,用于统筹管理权限.还支持集中账单和提供自动化API.

    • OUs: 组织单元,允许你按照工作负载,部门,生命周期阶段(测试,开发,生产)等来分组账户.

    • SCP: 服务控制策略,用来管理成员账户的权限.应用到组织的root,OUs或单个账户

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Effect": "Deny",
      "Action": "cloudtrail:StopLogging", // 禁止关闭cloudtrail日志记录
      "Resource": "*"
      }
      ]
      }
  • IAM

    • Access Analyzer: 可以通过分析couldtrail日志记录的活动生成IAM访问策略

    • AAA: 认证(authentic)/授权(Authorized)/记录(Acounting)

      解决谁可以访问什么资源的问题

    • 用户:

      • 根用户: 超级管理员,注册aws的账户

      • 普通IAM用户: 代表一个具体的人或服务,每个用户都有特定的权限

      • IAM组: 一组具有同样身份的用户

      • IAM 角色(role): 一种权限的集合,任何授权的用户或aws服务都可以暂时性地采用

      • IAM policy

        用户和角色的授权都是通过IAM policy实现,IAM policy一般直接绑定到用户/用户组/角色,所以不需要写principal

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        {
        "Version": "2012-10-17",
        "Statement": [
        {
        "Effect": "Allow",
        "Action": [
        "ec2:Describe*",
        "ec2:StartInstances",
        "ec2:StopInstances"
        ],
        "Resource": "*"
        },
        {
        "Effect": "Deny",
        "Action": [
        "ec2:TerminateInstances"
        ],
        "Resource": "*"
        }
        ]
        }
      • IAM role trust policy

        角色信任策略,定义哪些账户或服务可以扮演IAM角色

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        {
        "Version": "2012-10-17",
        "Statement": [
        {
        "Effect": "Allow",
        "Principal": {
        "Service": "ec2.amazonaws.com" // 允许ec2服务扮演(assume)这个角色
        },
        "Action": "sts:AssumeRole"
        }
        ]
        }
        ---
        {
        "Version": "2012-10-17",
        "Statement": [
        {
        "Effect": "Allow",
        "Principal": {
        "AWS": "arn:aws:iam::123456789012:root" // 允许特定的账户扮演这个角色
        },
        "Action": "sts:AssumeRole"
        }
        ]
        }
  • VPC

    虚拟私有云,可以理解为一个局域网,aws提供的虚拟网络

    • Peering Link: 对等连接,连接两个vpc(不通过公共互联网传输),两个vpc都要加路由(目的地是对方vpc cidr,指向peering connection),双向,网络对网络

    • Private Link: 在你的vpc中通过私有的网络路径安全地访问aws服务或vpc终端节点,单向,一对一

      • VPC endpoint:
        • interface endpoint: 实际上是vpc内创建一个于特定AWS服务相关联的弹性网络接口(ENI),无需修改路由表
        • gateway endpoint: 针对S3和dynamoDB的流量优化端点,需要修改路由表
    • NACLs: 网络访问控制列表,子网级别的访问控制

      • 默认拒绝所有
      • 无状态
      • 作用在子网,一个NACLs可以关联多个子网,但一个子网只能关联一个NACL
      • 按顺序匹配规则,第一个匹配的规则生效
      • 支持黑白名单
    • VPC endpoint policy: 资源策略,用于管理和控制到VPC Endpoint服务的访问,控制哪些aws主题可以使用该端点访问服务

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      {
      "Statement": [
      {
      "Principal": {"AWS": "arn:aws:iam::123456789012:user/MyUser"},
      "Action": ["s3:GetObject"],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::my-s3-bucket/*",
      "Condition": {
      "StringEquals": {
      "aws:sourceVpce": "vpce-01a23456b789c0d1e"
      }
      }
      }
      ]
      }

      AWS的policy默认是拒绝所有的,它的显式拒绝(effect: Deny)会覆盖允许.就是显式拒绝后,就算有其他策略允许了,还是会被拒绝.

    • 安全组: 虚拟防火墙,控制实例之间的出入流量

      • 有状态
      • 默认允许出禁止入
      • 作用在实例级别.安全组和实例是多对多的关系
      • 所有规则同时生效(只要有允许该流量的规则,流量就会被放行)
      • 白名单
    • 公有子网: 公有子网的实例可以直接通过互联网网关连接到互联网

    • 私有子网: 私有子网通过nat网关去到公有子网再通过互联网网关出到互联网

      • nat gateway: 运行在公有子网中给私有子网实例
  • ELB

    • ALB

      • 可以通过安全组控制访问源,仅允许cloudfront流量(com.amazonaws.global.cloudfront)进入,这样客户端就只能访问cloudfront

      • 工作在7层的负载均衡

      • 根据URL或http头信息路由

      • 支持websocket和http/2

      • 集成ECS和EKS

        • 代理EKS流量

          1. 在EKS中部署ALB Ingress Controller
          2. 部署ingress资源
          3. 在应用ingress资源时,ALB ingress controller会为你创建ALB并配置对应的监听器(linstener)和转发规则
      • 提供SSL/TLS加解密功能,可以挂https证书

      • 元素

        • 监听器(listener): 监听客户端请求(一般是80/443),并根据请求路由到目标组的组件

          • 监听器上可以挂TLS证书(https)
        • 目标组(target group): 多个服务端点(ECS容器/EC2实例或Lambda函数)组成的集合,每个target group针对特定的服务和端口

          • ALB到target group也可以配置TLS
        • 规则(rules): 通过监听器上定义的条件和优先级路由到不同的目标组

        • 健康检查: 判断目标组中的服务端点是否可以正常接受流量

          • HTTP/HTTPS/TCP
    • NLB

      • 工作在4层的负载均衡器
      • 针对TCP流量优化,可以处理不稳定的和突发的流量
      • 每个NLB都可以使用一个静态IP
      • 每个AZ一个独立端点,确保扩展性和容错
      • 使用TCP长连接(websocket)
      • 元素:
        • 监听器(listener)
        • 目标组(target group)
        • 健康检查
        • NLB也提供TLS监听器
        • 粘性会话: 通过source IP
  • Lambda

    程序运行不可以超过15分钟

    内存提供128MB-10GB

    成本计算按GB-秒,也就是1GB用1s多少钱

  • S3

    • 版本控制

      1. 上传的每个对象都会被分配一个唯一的版本ID
      2. 对象被覆盖或删除时,旧版本不会被删除而是保留下来
      3. 上传一个跟已存在对象同名的文件,旧文件不会被覆盖,新文件会获得一个唯一的版本ID
      4. 检索开启版本控制的对象,要指定其版本ID,默认返回最新的
      5. 删除开启版本控制的对象,只会逻辑删除.删除对象的特定版本,该版本就会被删除;删除所有版本,对象才会被永久删除
      6. 开启版本控制后的存储桶才能设置生命周期策略,例如自动删除一定时间后的旧版本
    • MFA delete: 多因素删除,要通过多因素认证才能删除对象

    • 总的来说S3存储的类型可以这么划分:

      • standard: 默认.即存即取

      • IA: 非频繁访问

      • Glacier(冰川): 更低的访问频率,读取需要时间,需要收费

        • Glacier Deep: 读取延迟12-48小时
      • Intelligent-tiering: 根据访问频率自动归类,免费

    • 加密

      • SSE-S3: 使用S3自己管理的密钥加密数据,每个对象都有唯一的密钥且使用一个主密钥加固
      • SSE-KMS: 使用KMS管理的密钥加密数据,KMS提供密钥审计,访问控制和rotate等功能
    • object-lock

      • 治理模式: 大多数用户不能修改对象,但可以授权某些用户可以修改对象
      • 和规模式: 任何用户(包括根用户)在保护期之前都不能修改对象
    • 访问控制:

      1. 存储桶策略: json定义账户对s3的访问,一般都是直接使用存储桶策略

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        {
        "Version": "2012-10-17", // policy版本"2008-10-17"或"2012-10-17",建议选最新的以使用最新功能
        "Statement": [
        {
        "Sid": "PublicReadForGetBucketObjects",
        "Effect": "Allow",
        "Principal": "*",
        "Action": "s3:PutObject",
        "Resource": "arn:aws:s3:::example-bucket/*"
        },
        {
        "Sid": "DenyPublicDelete",
        "Effect": "Deny",
        "Principal": "*",
        "Action": "s3:DeleteObject",
        "Resource": "arn:aws:s3:::example-bucket/*"
        }
        ]
        }
      2. ACLs: 粒度比桶策略粗

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        <AccessControlPolicy>
        <Owner>
        <ID>owner-unique-id</ID>
        </Owner>
        <AccessControlList>
        <Grant>
        <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
        <ID>owner-unique-id</ID>
        </Grantee>
        <Permission>FULL_CONTROL</Permission>
        </Grant>
        <Grant>
        <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
        <ID>user-unique-id</ID>
        </Grantee>
        <Permission>READ</Permission>
        </Grant>
        </AccessControlList>
        </AccessControlPolicy>
      3. IAM policy: 授权用户,组或角色对s3访问

      4. 预签名URL: 生成一个临时连接,允许用户在没有aws身份验证的前提下访问你的s3对象,有限时

      5. 跨资源共享(CORS): 设置CORS规则,允许一个或多个指定源的web应用程序对你的s3对象操作

  • ECS/EKS/Fargate

    ECS是高度可扩展的容器管理服务,用于运行,停止和管理docker容器,提供两种模式,其中一种就是fargate,由AWS管理底层资源,用户无需关心底层配置,另一种是EC2模式,创建EC2实例来运行容器,用户需要自己管理EC2.EKS也是类似,有EC2和fargate模式,不过不论哪种模式,使用EKS都不需要管理控制平面的组件,即时是EC2模式,也是通过EC2实例来运行工作节点.

    • task definition: 类似dockerfile+docker run,用来定义如何在ECS上运行容器

    • TaskRoleARN: ECS task关联的IAM角色的ARN.这个角色赋予ECS任务中容器所需权限.

    EKS集群如何升级:

    • 影响

      控制平面的升级是AWS负责的,即使是多可用去高可用,控制平面的升级仍然可能会遇到短暂影响,因为:

      1. 即使使用滚动更新,依然不能排除会有一瞬间的连接失败,因为始终都会有流量转移的操作
      2. 假如还要升级etcd,etcd的中断也会造成某个时间点API的短暂不可用
      3. ELB和网络路由可能会随着集群升级而进行调整或替换,AWS会尽力保证平滑过渡,但是短暂的抖动是无法避免的
      4. 控制平面升级,集群API会有短暂的不可用,会影响监控,调度等

      工作节点升级分两种,一种是EC2模式,一种是fargate模式

      EC2模式又分两种:

      • 托管节点组
        • AWS会帮你完成大部分工作节点的运维操作,比如:
          • 自动化补丁更新和版本升级
          • 自动替换不健康的节点
          • 自动使用EKS优化的AMI
          • 升级过程自动替换节点
            • 先启用新版本(新AMI)的节点
            • 新节点加入集群
            • 对新节点进行健康检查
            • 排空旧节点上的pod
            • 排空后终止旧节点
        • 你只需要在EKS控制台,AWS CLI或AWS SDK发起升级即可,AWS会完成剩余操作
      • 自管理节点组
        • 则需要用户手动完成上面的操作
        • 首先要确保控制平面升级成功
        • 蓝绿发布的方式升级:
          • 使用新的AMI或者手动升级好工作组件版本的AMI来创建新节点
          • 把新节点加入到集群
          • 把旧节点排空,确认pod有正常调度到别的节点或者新节点中
          • 把旧节点踢除

      至于fargate模式,你只需要确保你的pod在新版本中兼容即可.对比EC2的托管节点组,还是有些区别:

      • 使用托管节点组,用户需要配置节点组,比如实例类型,数量和自动缩放设置,AWS负责节点的生命周期管理;fargate模式下用户不需要管这些
      • fargate完全serverless,以为着你不能进入到节点中做操作
      • 对于持久存储,ec2模式可以直接使用ebs,如果要共享持久存储,可以使用EFS,FSx for linux/windows或S3,以及第三方存储解决方案ceph等,fargate不支持ebs
    • 备份: 升级前对etcd执行快照备份是必须的,EKS默认会定期备份etcd快照到S3

    EKS监控:

    • cloudwatch: metrics/logs/alarms
    • eventBridge
    • AWS X-Ray: 跟踪分析调试微服务之间的通信
    • AMP(Amazon Managed Service for Prometheus): 相当于完全托管的prometheus+grafana服务,与EKS集成,自动发现和监控集群资源
    • 第三方: datadog
  • Confluent

    完全托管的Kafka服务,可以与lambda,S3等aws服务无缝集成

  • Cloudfront

    CDN服务,提供基础的DDos防护.另外也有故障切换功能

  • AWS glue

    完全托管的ETL(提取,转换,加载)服务,用于处理大量复杂数据准备和载入工作.

    • glue爬虫(Crawler)

      数据探索: 自动连接到你的数据存储,分析并推断你的数据结构和模式(表,列,数据类型等)

    • 自定义分类器(Custom Classifier)

      标准的分类器无法准确识别你的数据格式就需要创建自定义的grok模式来识别

    • grok: 用于解析复杂文本数据和日志的强大工具,由一系列正则表达式组成.grok模式广泛应用在logstash中

  • R53

    提供DNS解析,域名注册,健康检查等服务

    • 故障转移:

      • 主动/被动: 只有主资源在服务,主资源不健康,流量转到备用资源中

      • 主动/主动: 多份资源同时服务

    • 路由策略

      • 简单: 基础dns查询,不支持健康检查
      • 延迟: 资源部署在多个aws区域,基于网络延迟,向延迟最低的region路由
      • 多值: 关联多个资源,并进行健康检查,随机选一个健康的来响应
      • 地理位置: 根据dns查询发起的地理位置来路由
  • secret manager

    专门保护管理敏感信息(用户名密码,密钥等),支持密钥自动rotate,可以使用kms的密钥来加密

  • Event bridge

    无服务器的事件(aws资源状态变更/时间表等)总线,基于事件触发aws服务,api调用等

  • SNS: 简单通知服务,发邮件

  • CloudWatch

    有仪表盘,可以监控可以告警,与autoscaling集成,自动调整资源

    复合告警: 通过监控其他告警状态来确定复合告警的状态

    可以监控:

    • 性能: 实时监控aws资源(ec2实例,rds数据库,s3等)的性能(cpu,流量,IO等)
    • 日志: 从ec2实例,cloudTrail等源中获取日志
    • 服务配额监控
  • CloudTrail

    记录存储aws账户中api调用的历史(console,SDKs,awscli等),相当于记录aws上所有操作

  • AWS CLI

    • 登录
      1. 直接登录账号

        access key id and secret access key

      2. 通过AssumeRole

  1. 假如我需要创建一个VPC,terraform上需要定义哪些资源

    首先是VPC本身,要计划好ip range,然后公有子网,私有子网,如果要出外网,公有子网要创个internet gateway,私有子网一般用nat gateway,创了gateway还要创建路由表,如果VPC内资源要访问S3或者dynamoDB就要创建个网关端口,有了endpoint还要有endpoint policy,有需要的话给子网创个NACL.

  2. AWS上做过的项目描述

    1. 建立private link允许别的aws账号下的vpc访问自己vpc下confluent
      1. 通过lambda 获取confluent实例ip,写到ELB
    2. lambda自动rotate secret for RDS
      1. 创建lambda通过eventbridge定时触发secret manager 去rotate secret
  3. 限制了EC2的外网访问,却无法阻止DNS查询

    • DNS包含TCP和UDP的53端口,可能漏了个协议
    • VPC的DHCP选项中提供了一个默认DNS(通常是VPC范围的DNS)
    • VPC有与其他VPC有连接(private link,peering link,transit gateway等)
    • 主要是NACL和安全组的问题,另外私有子网通过nat网关访问互联网,nat网关上也是设置阻止DNS访问
  • SQS

    • 可见性超时

      队列有多个消费者时,消息发送到A消费者消费,在一定时间内,其他消费者对此消息不可见.这就是可见性超时,用来避免消息的重复消费.

    • 死信队列

      消息多次消费失败,可以把它发送到一个特定的队列,用于日后问题排查,这个队列就叫死信队列

    • 标准队列

      • 无限吞吐
      • 不保证消息顺序
      • 偶发消息重传
    • FIFO队列

      • 有序传递
      • 每条消息在给定时间内只会被传递一次
      • 吞吐有限,最高300条/s或者按批次发送,最高3000条/批
      • 支持消息去重
  • dynamoDB

    完全托管的noSQL数据库,对标mongodb,提供最终一致性读取和强一致性读取

    • TTL: 和mongodb一样,可以对index设置TTL,TTL超时就删除数据,适用于大量小项目持续吞吐的场景
    • 全局表: 一种具有多个AWS区域复制功能的dynamoDB特性.将两个或多个dynamoDB表,将其连接起来作为全局表的一部分,每个区域的表都视为一个副本,dynamoDB负载数据的复制同步.
      • 多活: 所有区域的表都是活的,可以随时读写
      • 实时: 基于流技术,在几秒或更短的时间内将更新应用到全球所有复制区域
      • 冲突处理: 使用last-write-win(最后写入胜出)策略
      • 跨区域一致性: 在几秒内实现跨区域的最终一致性(同一时刻所有区域看到完全一致的数据)

Terraform

  1. terraform语法怎么写

    terrafrom使用的HCL声明式语言,以块的形式组织代码,通过大括号来划分块,常用的块有:

    • local{}: 定义本地变量
    • resource{}: 定义资源
    • data{}: 用于数据查询或计算
    • module{}: 引用模块
    • ouput{}: 输出数据
  2. terrafrom原理

    我们平时所用的terraform,其实是包含两个进程,一个是terraform自身,还有一个就是provider.对应不同的平台有不同的provider,也可以理解成插件或者SDK.terraform主进程主要负责理解并翻译我们写的terraform代码,把它转化成provider可以理解的形式,然后provider负责调用对应平台的API最终实现资源的管理.当我们执行terraform init的时候,terraform会下载所需要的provider,并且会根据配置连接backend,获取statefile,statefile记录这通过terraform管理的平台上的资源的最新状态,通过跟statefile和我们的代码进行对比,terraform plan得出这次我们要对哪些资源做哪些操作,然后通过terraform apply应用变更.

  3. 如果不用任何第三方backend,如何存储和管理terraform的statefile

    terraform支持pgdb作为后端,同时它也支持通过restful-API请求来与backend交互,意味着我们可以写一个http服务器作为backend.

  4. terraform的锁机制

    terraform的状态锁是用来避免并发时发生资源抢占问题的机制,它确保同一时间内只有一个terraform进程可以修改状态文件.当运行一个terrafrom命令时,它会生成一个锁文件并获取它,执行过程中其他terraform进程因为无法获取到这个锁文件所以无法执行.

  5. terraform的backend配置写错了,会发生什么?

    backend写错了,会连不上backend,terraform默认会把statefile写在本地,修改好backend后,再次尝试连接,会发现还是连不上backend,terraform根据本地的statefile发现backend配置更改过了,它会尝试连接之前的backend并迁移到新的backend,但之前的backend本身就是错的,所以还是连不上.解决办法就是把本地的statefile移除即可.

  6. terraform statefile如何迁移

    比如已经在本地init并apply,terraform会在本地生成statefile.然后修改新的backend配置再次init.terrafrom会检测到backend改变了,它会先确认新backend中有没有状态文件,没有的话就自动迁移状态文件,用户需要手动确定.

    如果检测到新backend已有了状态文件,它会把新旧statefile选在到本地的一个临时目录,然后要求用户人工核对后决定是否覆盖既有的statefile.

  7. terraform常用命令

    init/plan/apply/destory/fmt/validate/import/froce-unlock/output

  8. terrafrom工作目录常用文件

    backend.tf/provider.tf/version.tf: backend配置/provider配置和版本信息/terraform版本要求

    main.tf/data.tf/outputs.tf: terraform资源定义代码/查询数据data块代码/输出代码

    variables.tf: 定义变量代码

  9. statefile的安全性

    • 使用第三方backend,比如S3
    • ACL
    • 加密statefile
    • 使用版本控制
  10. module的管理

    • 所有module存放在同一个repo里面
    • module单独的repo存放管理
    • source引用官方module
  11. 你如何管理你的状态文件和锁文件?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    terraform {
    required_version = ">= 0.12"

    backend "s3" {
    bucket = "my-terraform-state-bucket"
    key = "path/to/my/terraform.tfstate"
    region = "us-west-2"
    dynamodb_table = "my-terraform-lock-table"
    encrypt = true
    }
    }

    状态文件存在S3,启用版本控制,锁文件存在dynamodb是推荐的配置.锁文件推荐存放在数据库,这是因为:

    • S3提供的是最终一致性,也就是说对象更新后,s3不保证可以立即列出最新的文件版本.但锁文件的读取必须保证每次都是最新的,所以s3并不是最优解
    • 高并发场景下,数据库可以提供原子操作(要么完成,要么完全不发生)和事务性(一系列操作都作为一个整体来执行,要么所有操作都成功完成要么遇到错误时撤销所有操作,一个事务包括一系列的原子操作),确保并发写入的一致性和隔离性,s3并没有相关的优化
    • 在S3中,如果多个进程同时对对象操作,会产生竞争条件,这可能会导致锁的并发控制失败.
  12. terrafrom执行错误(有人通过console修改了资源,没有通过terraform,状态文件上的状态就跟平台上的状态不一致,此时执行terraform就会报错),如何修正?

    如果是云平台上有的但是statefile没有的,可以通过terraform import,把资源import进去.

    1
    terraform import ADDRESS ID

    ADDRESS: terraform代码中配置的地址,比如aws_instance.my_instance

    ID: AWS资源实例在云平台上的ID(通过console/SDK/CLI获取)

  13. 针对不同环境,terraform代码应该如何管理?

    一般是根据环境划分,比如dev对应dev分支,master对应生产环境

  14. 如何规划管理terraform模块

    一般都是根据完整功能来划分,比如我做过的rotate secret,里面包括secret manager, lambda和event bridge等,就全写到同一个模块里面.但是长久以往,特别是你这一份terraform要负责管理的team多的时候,很容易出现代码重复的问题.这时可以通过将常用的基础模块独立出来,比如vpc,安全组等单独一个模块,然后要组件别的infra的时候就用source引用,模块设计的时候也要注意,根据实际多设一些变量或默认值,让你的基础模块有更大的灵活性和可用性.另外其实一般公有云都有写好的基础模块,比如aws,gcp都有对应的vpc模块在github上,可以直接引用.

  15. 我terraform代码模块的路径改变了,如何让statefile也随之更新,为什么要更新?

    terrafrom的状态文件主要包含三个状态信息:

    1. 资源当前状态
    2. 配置中定义的期望状态
    3. 上面二者之间的映射

    当terraform配置的路径和结构与statefile不一致时,会丢失资源的跟踪.比如你把module.a移动到了module.b,apply时terraform会更根据现有的statefile去寻找资源,这些资源仍然关联着旧的路径(module.a),此时terraform会认为无法找到module.b这个资源,而尝试重新创建它. 因此路径变更如果未及时反映到状态文件中,会导致terraform状态与实际云环境的状态不一致,plan和apply可能会提出错误的改动计划,可能会导致资源无意中的破坏或重复创建.另外状态文件不更新也会导致依赖关系混论.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 更新状态文件的方法主要靠terraform state子命令
    # address: module.<模块名>.<资源类型>.<资源名称>
    # module路径改动
    terraform state mv module.old_module.resource_name module.new_module.resource_name
    # 在terraform管理中移除资源但不实际销毁它
    terraform state rm <address>
    # 列出当前terraform状态文件中所有资源
    terraform state list
    terraform state show <address>
  16. terraform我在module.a中定义了一个output或data块,我如何在module.b中引用它,但不创建module.a的资源?

    首先定义module.a的output

    1
    2
    3
    4
    # module.a/outputs.tf
    output "example_output" {
    value = aws_instance.example.id
    }

    要使用module.a的output要先声明,然后才能引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 主 Terraform 配置
    module "a" {
    source = "./path/to/module.a"
    # module.a 的其他输入变量...
    }
    module "b" {
    source = "./path/to/module.b"
    input_variable = module.a.example_output
    }

    如果只用到module.a的output而不创建module.a的资源,可以通过有条件创建来实现

    1
    2
    3
    4
    5
    # module.a 中的资源
    resource "aws_instance" "example" {
    count = var.create_instance ? 1 : 0
    # 其他配置...
    }

    不过output一般都依赖于资源,所以大部分情况下是跨模块引用data的值.要做到这一点,需要先在module.a中定义data块,然后通过output块公开你的data查询的值,再使用上面的方式来实现.更优雅的做法是,定义个专门用于数据查询的模块,里面不写任何resource,只写data,查询出来的值如果要在别的地方引用就通过output公开,然后通过上面的方式引用.

Jenkinsfile

  1. Jenkinsfile具体语法怎么写

    我一般使用声明式来写,首先是pipeline,如果有需要的话通过agent指定执行pipeline的jenkins节点,parameter定义参数,environment定义环境变量,然后就是stagesstage定义pipeline的各个阶段,每个stage中通过steps块来定义具体要做的动作,有时候pipeline的场景比较复杂,我会通过script块来写groovy,加一些判断,循环或者错误检测.最后通过post做一些收尾操作,比如clean work dir之类的.

    另外我还写过一些功能块,比如trigger配合cron,定时运行pipeline;通过when来有条件地执行某些stage.还有environment可以定义在stage内,只在该stage内生效.

  2. jenkins的凭证如何分级

    凭证的管理分两个维度,一个叫范围,一个叫

    范围有:

    1. 全局: 所有项目可用,除非在域中做了限制
    2. 系统: 只允许jenkins自身以及它的节点使用
    3. 用户: 只能该用户使用
    4. folder: 只有该folder下的项目可以使用

    域: 是一个对凭证逻辑分组的机制,比如说我们可以创建一个域,该域下的凭证只有在访问某个域名的时候才能使用.凭证默认创建在全局域下,全局域没有任何限制.

  3. jenkinsfile如何处理并发

    通过parallel关键字声明并发任务,下面的task1和task2会并发执行,通过执行器来实现,所以执行器数量决定了并发任务的数量.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    pipeline {
    agent any
    stages {
    stage('Parallel Stage') {
    steps {
    script {
    parallel(
    failFast: false, // true: 其中一个任务执行失败,其他任务也会停止执行
    task1: {
    // Task 1 steps
    echo 'Running task 1'
    },
    task2: {
    // Task 2 steps
    echo 'Running task 2'
    },
    // Add more tasks if needed
    )
    }
    }
    }
    }
    }
  4. jenkinsfile中三个单引号引用的代码和3个双引号引用的代码有什么区别?

    3个引号都是用来引用多行字符串,单引号不会解析特殊字符,比如shell的变量引用$,双引号会解析.

Ansible

  1. ansible语法怎么写

    主机清单用INI,playbook和role用yaml和jinja2模板

    常见的flag有:

    name: playbook的名字

    host: 远程主机名或组名

    become: 是否要提升权限

    become_method: 提升权限的方式,一般是sudo

    remote_user: 登录到远程主机的的账号

    vars: playbook定义的变量

    tasks: 任务列表,每个任务都有单独的name,具体task里面的操作都是通过模块来实现,比如ping,yum,service,shell,command等等

    notify和handler: 触发器和响应器,比如说一个task修改配置文件,在这个task里面定义notify,配置文件修改成功,就触发handler去重启服务

    tags: 在任务中定义,用来单独执行某个task或跳过某个task

  2. ansible的role是什么?如何编写?

    role是一种组织playbook的方式,也是一种代码复用的方式.它通过一个目录结构来组织,比如:

    task文件夹下写task列表

    vars文件夹下定义变量

    files文件夹放需要传输的文件

    template文件夹放jinja2模板

  3. ansible的变量

    • 内部变量,比如:
      • : 主机清单中定义的主机的信息(主机名/ip等),以及主机清单中定义的变量和fact收集的主机的信息,字典
      • : 主机变量中组变量字典
      • : 当前远端主机的fact收集的信息字典
      • : 当前playbook所有主机列表
    • fact: 在task中通过setup模块获取到的远端主机的系统信息
    • role的vars文件夹中定义的变量
    • 主机清单中定义的变量

K8S

  1. K8S由哪些组件构成,每个组件的功能是什么。

    控制面板:

    • apiserver: 集群API入口,也负责集群其他组件的交互,集群的大脑,也负责验证授权等
    • controller-manager: 管理控制器,管理deployment,statefulset,daemonset这些控制器的,另外service的clusterIP是虚拟IP,其实也是controller-manager负责分配的
    • scheduler: 调度器,根据算法计算pod分配到哪个node
    • core-dns: 提供集群内的DNS服务
    • etcd: k-v存储数据库,存储集群的所有配置数据

    工作平面:

    • kubelet: 负责节点上的pod的生命周期管理
    • kube-proxy: 维护ipvs/iptables规则,service实际上就是通过这些规则转发
  2. daemonset,deployment和statefulset的区别是什么?

    • daemonset用来保证pod在每一个节点上都运行一个,一般用来运行日志收集,监控,存储等应用
    • deployment用来部署无状态的应用,并且支持声明式更新,可以实现滚动更新和回滚
    • statefulset用来部署有状态应用,它会给每个副本分配稳定且唯一的网络标识和持久存储,它的部署,扩展,回滚,终止以及滚动更新都是有序
  3. 有无写过yaml文件,里面一般有什么参数和变量

    • apiVersion: 不同的资源不同的k8s版本都会有点不一样

    • kind: 定义资源类型

    • metadata: 资源的元数据,包括namespace和资源name

    • label: 资源的标签

    • spec: 定义对资源的期望状态,不同的资源有不同的参数定义,

      比如deployment要定义replicas(副本数),selector(标签选择器),template(pod模板)

      比如service要定义service-type,默认是clusterIP,ports和targetPort

    • configmap: 配置文件

    • secret: 敏感数据

    • PV和PVC: 定义持久存储

      • accessMode: readWriteOnce/readWriteMany/readOnlyMany
      • storageClassName: 指定使用哪个存储类
  4. 有无用过探针,有几种类型,yaml文件怎么写

    • 启动探针(startup):用来判断容器内应用是否已经启动完成,只有这个探针成功了,才会开始应用后面两个探针,失败了就杀死容器然后重启
    • 存活探针(liveness): 用来判断容器是否正在运行,检测失败就会杀死容器并重启
    • 就绪探针(readiness): 用来判断容器是否可以接受流量,检测失败,service就不会转发流量给它

    三个探针都有http get/tcp socket/exec的探测方式

    重启策略:

    • Always: 不论容器返回状态码是什么,都会尝试重启容器
    • Onfailure: 容器返回状态码非0(非正常退出),就重启
    • Never: 不论容器返回状态码是什么,不论探针检测结果是什么都不会重启

    一个pod内的容器共享生命周期,所以容器重启也代表pod重启.

    参数:

    • exec
      • command
    • httpGet
      • path
      • port
      • host
      • scheme: http/https
      • httpHeaders
    • tcpsocket:
      • port
      • host
    • initialDelaySeconds: 容器启动后多久执行第一次探测
    • periodSeconds: 执行探针的频率
    • timeoutSeconds: 超时时间
    • successThreshold: 成功多少次才判断成功
    • failureThreshold: 失败多少次才判断失败
  5. 有无听过节点亲和性,具体怎么实现

    节点亲和性基于nodeSelector和节点标签实现,它有两种类型,一种叫required(硬亲和),一种叫perfer(软亲和).硬亲和就是pod只能调度到匹配规则的节点上,没有就不调度,软亲和则是优先把pod调度到符合规则的节点,没有匹配的就调度到其他节点.软亲和何以设定多个并根据权重设置优先级.

    它通过几个操作符来匹配:

    • In/NotIn: 节点必须具有/没有指定的标签(key)和值(value)
    • key只能指定一个,value可以指定一个列表,只要节点标签的值在列表中有/没有就算符合
    • Exists/DoesNotExist: 节点必须有/没有指定的标签(key)
    • Gt/Lt: 节点标签的值必须大于/小于指定值

    通过关键字affinity下的nodeaffinity定义

  6. 有无听过水平扩容和垂直扩容,具体怎么实现

    水平扩容就是(HPA),基于metrics-server获取的实时资源使用数据来实现,比如我设置HPA的值是cpu平均利用率80%,那么K8S就会尽量将它保持在80%.利用率大于80%就扩容,小于80%就缩容.但是为了避免频繁地扩缩容,左右横跳,HPA提供一些参数和机制,比如扩缩容后有冷却时间,计算触发值的时候会把平均值也纳入计算,以及还有一个稳定窗口的概念(触发值超过设定值一定时间后才会触发扩缩容)

    垂直扩容(VPA)同样也是基于metrics-server的数据来实现.它不是通过加副本来加强性能,而是通过调节pod的cpu和内存来加强性能.VPA适用于不能随便扩展副本数来加强负载的应用,比如数据库.但是VPA有个地方需要注意,它是有可能导致pod直接重启,生产环境应该选择Off或者Initial模式

  7. 有无听过动态扩容,具体怎么实现,动态扩容应用在什么地方(pod还是节点)

    Cluster AutoScaler,使用一个特定的容器实现(k8s.gcr.io/cluster-autoscaler),它会通过k8s的API获取它所需要的信息,比如集群的资源使用情况,有多少个pod处于pending状态等,然后调用对应底层平台的API,比如AWS的GCP的或者私有云的openstack的,来实现节点的按需扩缩容

  8. 如何升级k8s集群

    使用kubeadm部署的集群也是通过kubeadm来升级.首先通过kubeadm upgrade plan来验证升级计划,然后通过kubeadm upgrade apply来应用升级,kubeadm主要负责控制平面组件的升级,一般生产环境中master都会部署高可用,所以需要一个个节点来.至于工作平面的组件,先要通过cordon命令禁止pod的调度,然后通过drain命令驱逐节点上的pod,然后再升级节点的kubelet,升级完通过uncordon来恢复调度,也是要一个个节点来.

    生产环境一般采用滚动更新的方式,先创建一个新版本的新节点,然后加入到集群,再驱逐旧版本的一个节点并把它从集群中剔除.

  9. secret如何增加安全性?

    集群内组件的通信都要配上TLS,保证传输过程加密

    etcd数据加密

    配置RBAC和network policy对secret进行访问控制

    可以使用第三方来存储secret,比如AWS的secret manager

    禁止hardcode,包括日志中

  10. pod创建过程

    • 用户提交创建pod的请求给API-server
    • apiserver会将相关信息写入etcd,写入完成就返回确认信息给客户端
    • apiserver会反映etcd中的状态变化,所有k8s组件都会通过watch机制来跟踪检查api server上的变动
    • 比如scheduler通过watch机制觉擦到apiserver创建了一个pod但未绑定到任何节点,它就会使用调度算法为这个pod计算节点,并更新到apiserver
    • apiserver会把调度结果写入etcd
    • 被调度到的节点上的kubelet会在本地抵用容器运行时(CRT)运行容器,并将容器状态同步给apiserver
    • apiserver更新写入到etcd,写入完成,apiserver通知kubelet完成.
  11. K8s中的跨节点通讯

    • flannel有两种模式,默认是VxLan,类似VPN,在两个pod之间建立一条虚拟的隧道,使用VxLan封装,因为需要额外的封装,所以开销大性能弱

      另一个是host-gw,它会在每个节点上维护一个静态的路由表,根据路由表进行流量转发,它要求每个节点都有一个单独的子网

    • calico的原理跟flannel的host-gw类似,也是维护路由表,但是它使用动态路由协议BGP,所以它不需要为每个节点单独分配一个子网

  12. k8s的资源限制

    • ResourceQuota: 限制名称空间内所有资源总量限制,包括pod/service/pvc等数量,也包括cpu/内存的总量
    • LimitRange: 限制namspace内单个pod或container层面上的资源分配
  13. 写一份NetworkPolicy

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: test-network-policy
    namespace: default # 策略所在的名称空间,也是策略生效的名称空间
    spec:
    podSelector: # 策略应用的具体pod
    matchLabels:
    role: db
    policyTypes: # 表示该策略是应用到哪个方向的流量
    - Ingress
    - Egress
    ingress: # 入流量白名单
    - from:
    - ipBlock:
    cidr: 172.17.0.0/16
    except:
    - 172.17.1.0/24
    - namespaceSelector:
    matchLabels:
    project: myproject
    - podSelector:
    matchLabels:
    role: frontend
    ports: # 这是允许被连接到的端口,也就是入方向流量可以连接到的端口
    - protocol: TCP
    port: 6379
    egress:
    - to:
    - ipBlock:
    cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
    port: 5978
  14. etcd如何备份还原

    1
    etcdctl snapshot save/restore
  15. 如何写helm,如何管理helm包

    • helm v3后直接通过kubeconfig连接apiserver
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    wordpress/
    ├── charts # 这个目录用于存放本 Helm chart 依赖的其他 chart。如果你的应用程序依赖于其他服务(如数据库、缓存等),对应的 chart 应该放在这个目录下。默认情况下,此文件夹为空。
    ├── Chart.yaml # 这个文件包含了 chart 的基本信息,如版权、版本、名称和描述。这是 chart 的元数据文件和身份信息
    ├── templates # 这个目录包含定义 Kubernetes 资源的模板文件。Helm 会结合 `values.yaml` 中的值和这些模板来生成 Kubernetes 资源定义文件。
    │ ├── deployment.yaml # 定义了用于创建和管理应用程序基础 Pod 的 Deployment 资源。
    │ ├── _helpers.tpl # 包含模板帮助信息和定义模板函数,可以在其他模板文件中重用。
    │ ├── hpa.yaml # 如果启用,定义 Horizontal Pod Autoscaler,根据 CPU 使用率或其他选择的指标自动缩放 Deployment。
    │ ├── ingress.yaml # 定义 Ingress 资源,用于管理外部访问到你的应用程序的 HTTP/HTTPS 路由。
    │ ├── NOTES.txt # 包含安装后的使用说明,当执行 `helm install` 命令后,这些信息会显示给用户。
    │ ├── serviceaccount.yaml # 创建 ServiceAccount,以便为 pod 提供身份认证。
    │ ├── service.yaml # 定义 Service 资源,用于定义如何访问和暴露你的应用程序。
    │ └── tests # 包含测试资源
    │ └── test-connection.yaml # 定义了一个后置测试,用于验证应用程序是否可以正常连接。
    └── values.yaml # 包含默认的配置值,这些值在结合 templates/ 中的模板时使用。用户可以自定义这些值来覆盖默认设置
    1. 使用helm create <name>创建helm包(chart)
    2. 编辑Chart.yaml写chart包的元信息(版本信息,作者,描述等)
    3. templates目录下的k8s资源模板(deployment.yaml,hpa.yaml等)
    4. values.yaml定义变量和默认值
    5. files目录下放一些模板中引用的文件(脚本或配置文件)
    6. 使用helm install <release_name> <path_to_chart>安装测试chart

    常用命令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    helm create <name>
    helm install <release_name> <path_to_chart>
    # 打包成.tgz方便存储或分发
    helm package <path_to_chart>
    # 添加仓库
    helm add <repo_name> <repo_url>
    # 升级
    helm upgrade <release_name> <repo_name>/<chart_name>
    # 版本控制/回滚
    helm rollback <release_name> <revision>

EFK

  1. 有无用过ELK,具体搭建过环境

    部署过EFK,headless service代理statefulset 3节点 es集群,使用daemonset部署fluentd,监听的是宿主机的容器日志目录/var/log/containers

    使用fliter的concat插件实现多行信息拼接,使用filter的grep插件只采集特定标签的pod的日志

  2. ES index的生命周期管理(ILM)

    热/温/冷/删除,一般是根据数据的读写频率以及物理磁盘的性能分层存放,不过我做过的就只是热+删除,实现过了一定时间就删除日志数据的功能

  3. ES索引如何备份

    使用es的快照与恢复功能: 支持各种快照仓库(S3,HDFS,本地文件系统等)

    • 配置快照仓库

      elasticsearch.yml

      1
      path.repo: ["/mount/backups/my_backup"]
    • 注册快照仓库

      PUT /_snapshot/my_backup_repository<自定义仓库名称>

      1
      2
      3
      4
      5
      6
      {
      "type": "fs",
      "settings": {
      "location": "/mount/backups/my_backup"
      }
      }
    • 创建快照

      PUT /_snapshot/my_backup_repository/my_snapshot<自定义快照名称>

      1
      2
      3
      4
      5
      {
      "indices": "log_index",
      "ignore_unavailable": true,
      "include_global_state": false
      }
    • 恢复快照

      POST /_snapshot/my_backup_repository/my_snapshot/_restore

      1
      2
      3
      4
      5
      {
      "indices": "log_index",
      "ignore_unavailable": true,
      "include_global_state": false
      }

Prometheus

  1. 有无用过普罗米修斯等监控工具,知不知道普罗米修斯的语法怎那么写

    部署过prometheus 联邦集群监控超过500台混合云环境的虚拟机,和一个k8s集群.它的查询语法叫promQL,基本语法就是metric-name{lables:value},查询支持pattern匹配,另外prometheus自带很多聚合函数,比如max(),avg()等等

  2. 如何用prometheus监控k8s集群

    部署kube-state-metrics,通过这个容器获取metrics,另外api-server,control-manager,secheduler,core-dns等组件都有原生的metrics API,可以通过在prometheus中直接配置获取metrics.

Docker

  1. 有无写过dockerfile,语法是什么,公司的项目组用到什么镜像

    FROM: docker的镜像是层级结构的,所以每次build镜像都要有一个最底层的基础镜像,from用来指定这个基础镜像

    ADD: 复制文件到镜像中

    COPY: 也是复制文件,不过它支持tar包和URL,tar包还可以自动展开

    RUN: 在镜像build的过程中执行的命令

    CMD: 定义镜像运行时要执行的命令,不过一般是用来给entrypoint传参用

    ENTRYPOINT: 定义镜像的父进程

Helm

  1. helm架构?

    V3后的helm,取消了中间件tiller,直接通过kubeconfig连接集群

  2. helm动态环境支持

    value.yaml配置变量,template定义模板来实现对不同环境的支持

  3. helm不验证登录,如何获取镜像

    如果是私有仓库,可以通过管理员配置允许匿名访问,另外可以提前在k8s集群中配好secret,然后在helm chart中定义imagePullSecret就可以免密获取镜像

Python运维脚本

  1. 有无经常用python写运维脚本

    曾经用python开发了一个prometheus的exporter基于它的官方SDK,也二开了一个alertmanager的webhook实现自定义告警

  2. python创建一个父类,假如我不希望继承这个父类的子类使用父类中的某个变量,我可以怎么做?

    __双下划线定义私有变量

  3. python中有哪些数据类型?

  4. 深浅拷贝的区别?

  5. 装饰器是做什么用的?

  6. 单元测试

算法

基本编程算法

  1. 排序算法

    快速排序

    归并排序

    冒泡

  2. 搜索算法

    二分查找

负载均衡算法

  1. 轮询
  2. 最少连接
  3. 哈希
  4. 随机

故障诊断和恢复

  1. 冗余

    raid 0

    raid 5

  2. 备份

    全量

    增量

    差异备份

    快照

资源优化

  1. 二分法
  2. 动态规划/贪心算法

网络算法

最短路径

流控制(滑动窗口协议)

数据一致性和同步

一致性哈希算法

加密算法

  1. AES
  2. RSA(非对称加密): 安全管理密钥

版本控制算法

  1. 合并算法(三向合并)

系统设计算法

  1. 队列(kafka,rabbitMQ,rocketMQ)

监控和日志分析

  1. 正则表达式

基础概念

  1. OSI7层模型

    应用层: 用户交互和数据最终处理

    表示层: 数据的编码和解码,给应用层翻译数据

    会话层: 应用之间的会话管理

    传输层: TPC/UDP协议

    网络层: IP协议

    数据链路层: mac地址寻址,arp协议

    物理层: 物理链路

  2. TCP/IP4层模型

    应用层: http/https/smtp/ftp等

    传输层: TCP/UDP

    网络层: IP协议

    数据链路层: 网络硬件

  3. TCP协议

    面向连接: 数据传输之前需要先建立连接(3次握手)

    可靠传输: 使用序列号和ack响应来保证数据的顺序和可靠,在特定时间没有收到ack就会重传

    数据流: 数据以无结构的字节流发送

    流量控制: 滑动窗口协议避免快发送方淹没慢接受方

    拥塞控制: 算法(慢启动,拥塞避免,快速重传和快速恢复)

    错误检测: tcp头包含一个校验和字段,用于 检测数据在传输过程中的错误

  4. TCP3次握手4次挥手

    3次握手:

    1. 客户端发起SYN包给服务端
    2. 服务端收到后回一个SYN+ACK
    3. 客户端收到服务端的ACK后再回一个ACK,握手完成,连接建立

    4次挥手

    1. 客户端发一个FIN包,申请断开连接
    2. 服务端返回一个ACK,表示收到请求
    3. 服务端没有数据发了,再发一个FIN包,表示它也可以断开连接了
    4. 客户端返回一个ACK,并等待2MSL时间,正式断开连接
  5. HTTP协议

    1. 通过TCP3次握手建立连接

    2. 发送http请求(请求方法,请求资源URI,请求头等)

    3. 服务器响应请求(状态码,响应头和响应体等)

    4. 响应完成tcp4次挥手断开连接

      http是无状态协议,跟踪对话需要用cookie,session机制

  6. HTTPS协议

    握手阶段(非对称加密)

    1. 客户端发起一个https请求,附带客户端支持TLS版本,加密方式等
    2. 服务端根据客户端支持的TLS版本,加密方式等发服务端的https证书和服务端的公钥给客户端
    3. 客户端验证证书是否可以信任(公信力CA),并随机生成一个对称密钥,用服务端的公钥加密后发送给服务端
    4. 服务端使用私钥解密对称密钥,至此握手完成

    通信阶段(对称加密)

    双方通过对称密钥加解密通信

DEVOPS和CI/CD理念

  1. 如何理解CICD?

    CI是持续集成,是一种开发实践,每次代码合并后都自动运行测试和其他验证过程就是CI

    CD是持续部署,是CI的延申,实现自动化的构建,测试和部署

    CI/CD的一般流程就是代码提交合并触发CI过程,运行自动化测试(比如用sonarQ检查代码质量,漏洞等),测试通过就开始编译,打包,然后触发CD过程,自动部署到一个或多个非生产环境进行测试,测试都通过了没问题,就可以计划部署到生产环境

  2. 如何理解敏捷开发?

    与敏捷开发模型(Agile Development Model)相对是的瀑布流模型(Waterfall Model).

    敏捷开发模型:

    - 强调灵活,变更成本低,迭代增量式开发,适合需求不明确
    

    瀑布流模型:

    • 严格遵从阶段顺序线性开发,变更成本高,需求需要明确
  3. git工作流

    适合敏捷开发模型的git工作有两个Git Flow 和 GitHub Flow.

    Git Flow:

    1
    2
    3
    4
    5
    - main #(稳定分支) 永远保存可部署的稳定版本,通常用tag标记具体版本号,用来记录版本发布历史,每次合并代表一个正式版本
    - develop #(主开发分支) 所有开发在develop分支执行,develop不会直接合并到main
    - feature/* #(特性分支) 新功能从develop创建feature分支,功能完成后合并回develop分支
    - release/* #(发布分支) 发布时从develop创建release分支,发布完成合并到develop和main
    - hotfix/* #(紧急修复分支) 从main分支创建hotfix分支,修复生产环境紧急bug,完成后合并到develop和main

    GitHub Flow:

    1
    2
    - main #(生产分支)
    - feature/* #(特性分支)
  4. devops排查问题的思路?

    • 收集信息
    • 复现问题
    • 寻找根因
    • 制定解决方案
    • 测试验证
    • 分析记录
  5. 遇到网络流量异常,如何排查问题?

    在上面的基础上有些特定的操作:

    • 分析流量制造者,确定它的行为模式和停止它们的方法
    • 分析网络路径: 通过traceroute,ping,dig,tcpdump等工具捉包分析
    • 检查负载均衡器: 是否负责策略有问题
  6. 常见监控指标?

    1. 服务器运行状态: cpu/mem/disk/network
    2. app状态: 运行状态/响应时间/错误率/日志/异常
    3. 服务性能: 网络延迟/http响应时间/db响应时间/缓存命中
    4. 安全性: 入侵检测/访问控制/DDos攻击
    5. 日志系统
    6. 资源使用情况: 带宽/虚拟机状态/存储/硬件状态
  7. 说说你运维生涯遇到印象最深的一个问题.

    我曾经遇到过一个端口复用的问题,当时我们部署的是一个IM应用,现象是A用户本该发送给B用户的消息,结果发送给了C用户.后来查出的问题就是因为用户太多,连接数不够,出现了端口复用.

    当时其实查得挺困难的,因为一开始没有这个概念,日志只是一条条地输出,很难看得出来.后面开了debug level日志,发现发错的信息所用的连接的本地ip和端口与正常发送的消息所用的ip和端口是一样的.

    这才想到MSL的问题.因为我们的IM使用的是TCP长连接,当时的架构在前端有一个nginx作为负载,所以可以理解为所有连接都是同样的源ip和目标ip,当用户数一多,新用户不停登录,

    默认的4次挥手的等待时间,也就是2*MSL不够用,其中一方数据没有传输完端口就被用到另一个用户,就导致了消息发送的错乱.当时给出的解决方案是加节点,但是加节点涉及资源申请,要走流程;当然也许可以手动

    调大每个包的MSL,不过也会有风险,每个连接断开的等待时间变长,新用户登录建立新连接的时间可能也会拉长.最终与客户沟通,决定这个问题作为当前版本的一个bug处理,等下个版本发版顺便加节点.

  8. 如何理解DEVOPS?

    根据google SRE这本书所说,DEVOPS源自google,最开始google的运维也想我们传统运维一样,手动敲命令,手动重启,日常繁琐的工作很多,后面就有了脚本可以做一些简单的自动化.但是还不够,毕竟脚本还是面向过程的嘛,你很难说一个脚本覆盖多个场景.所以就引入了开发的能力,通过开发将运维的工作实现自动化,并适配多种场景.这最开始

  9. 做过的CI/CD流程?

    gcp项目

    新旧方案示意图:

    image-20240506120957837

    上面是旧方案,下面是新方案.旧方案的master分支基本是没用的,每次用release都要根据现有的dev分支复制一个release专用的分支出来,然后通过ansible拉取,model也是类似,每次做release,就把对应版本的model上传到gcs,然后ansible去拉取.为了区分版本,那就要加版本号啦,所以每次做release都要手动去改ansible代码指定拉取那个版本,就比较麻烦.

    新方案会根据dev(测试审批通过后)打一个tag,到做release的时候就通过python脚本将tag自动PR并merge到master分支(PR主要是为了审计),ansible那边就固定拉取master分支的代码即可.而github上tag的页面也可以清晰看到一个版本列表(用于版本追踪/回滚).model也是类似,不过在我进去之前他们已经定好了先把model存在nexus,做release的时候通过jenkins把model上传到gcs,然后ansible拉取部署.nexus是别的团队管理的,我们没有删除文件的权限,时间久了会有模型文件堆积的问题,所以我们也有在讨论要不是把nexus换了,比如换到github,把model各个版本存在github之类的方案.

    旧方案主要的问题是master分支浪费了,而且分支会很多,一个release一个分支,每次都要改ansible(包括回滚),容易会人为错误的风险(墨菲定律).新方案用上了master分支,通过tag list有清晰的版本列表,ansible固定拉取master分支,不需要每次都手工修改.

  10. github管理代码,版本分支如何规划?

  11. 我们devops主要是管理terraform/ansible/Jenkinsfile的代码,都是根据环境来划分分支

  12. 业务代码一般是根据版本,也有根据环境来划分

一般主分支都是用于生产环境

gcp的项目中,是按环境划分分支,最开始当需要release的时候,会根据dev分支单独创建一个release用的分支,部署的时候就部署这个分支.后面则是通过jenkins做的CICD,先是根据审批后的dev代码版本打一个tag,release的时候就把这个tag merge到主分支,生产环境就只使用主分支

架构概念

  1. CAP理论

    一个分布式计算系统不可能同时满足以下三个保证:

    • 一致性: 系统中所有数据副本,在同一时间内都是一致的.任何对数据的读取请求都将返回最新的写操作结果
    • 可用性: 所有请求都会收到一个响应(但不保证返回的数据是最新的)
    • 分区容忍性: 系统可以在任何网络分区(系统的一部分在网络中不可访问)发生时继续运行

    任何给定时刻,只能同时满足以上两个保证.

    在现实世界设计中,分区容忍性是必须要有的(因为网络失败是难以避免的),所以设计的关键就在一致性和可用性之间做出权衡.

  2. 写时复制

    copy on write:

    1. 当系统需要复制一个资源(文件,对象或内存页)时,不会立即创建一个完全独立的副本,而是新旧副本共享相同的实际数据(降低内存占用)
    2. 当其中一个副本需要修改时,系统才会创建一个真正的副本(即写入数据之前先进行复制)
    3. 在新的副本修改后,其他副本仍然指向原始数据
    4. 修改不会影响原始数据或其他副本,保证数据的完整性和隔离性

GIT

  1. 团队维护同一份github repo,你们是工作流是怎么样的?

    一般采用类似Feature Branch Workflow的流程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    git clone <repo_url>
    git checkout -b <new_branch_name>
    # 在分支上开发
    git add .
    git commit -m "Commit message"
    git push -u origin <new_branch_name>
    # 此时会在repo上创建一个PR,团队成员对代码进行审查(code review),通过后merge到master分支
    # 然后删除本地和远程的开发分支
    git branch -d feature_branch_name # 删除本地分支
    git push origin --delete feature_branch_name # 删除远程分支

    这是基本的工作流程,期间还可以加入其他步骤,例如代码静态分析(snoarQ),自动化测试,CI/CD等

  2. git常用命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # always pull before push
    git pull
    git push
    # display current status of git repository
    git status
    # display git commit history
    git log
    git log --oneline
    git log --oneline --graph --decorate
    # show the difference between 2 commits
    git diff <commitID1> <commitID2>
    # 撤销本地更改(未commit)
    git reset --hard HEAD~

面经
http://example.com/2024/06/20/interview-git/
作者
Peter Pan
发布于
2024年6月20日
许可协议