AWS下Jenkins的跨账号部署

如果在AWS中使用Jenkins,可能会遇到需要跨AWS账号来部署的情况。比如把Jenkins搭建在non-prod账号中,然后在这个账号里构建、部署产品到低环境,然后把高环境部署到prod账号中。

这里面最棘手的大概会是权限的问题,大致可以归为两类:

  • AWS IAM的权限问题
  • Kubernetes中的权限问题

Solution

解决方案如上图,整个过程中一个用到了4个IAM Role,每个账号两个。

详细解释如下:

Non-Prod Account

  1. Jenkins Master运行在AWS EKS中,这个pod刚被创建出来的时候,默认的IAM Role来自于EKS Node的Role,这个non-prod node role在创建EKS时自动生成。

  2. 使用kube2iam来为EKS pod分配自定义的role,这里将kube2iam部署到kube-system的namesapce下,kube2iam部署后就可以在K8s中用注解来指定想要分配给pod的role,比如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: nginx-deployment
    spec:
    replicas: 3
    template:
    metadata:
    annotations:
    iam.amazonaws.com/role: role-arn
    labels:
    app: nginx
    spec:
    containers:
    - name: nginx
    image: nginx:1.9.1
    ports:
    - containerPort: 80

    这里为了简单让EKS下的所有pod共享一个non-prod EKS cluster role,这个role需要提前创建,然后赋予它所有pod所需的权限。

    同时需要更新EKS的设置,为non-prod EKS cluster role提供集群的访问权限。默认情况下只有集群的创建者拥有集群的访问权限,所以如果non-prod EKS cluster role不是集群的创建者的话,就需要手动加入。

  3. 这时候Jenkins Master已经带入到了non-prod EKS cluster role中,利用这个role所定义的权限去和AWS CodeCommit交互,检测是否有代码的改动。

  4. Jenkins Master检测到代码变动,触发build,动态创建出一个Jenkins Slave。创建slave所用到的权限来自于K8s的RBAC,而非AWS IAM。这里为Jenkins Master创建一个集群范围内的role binding,让它具有在所有命名空间下执行集群操作的admin权限。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: cluster-account
    namespace: somens

    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
    name: cluster-role-binding
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: admin
    subjects:
    - kind: ServiceAccount
    name: cluster-account
    namespace: somens
  5. kube2iam自动为新创建出来的Jenkins Slave赋予non-prod EKS cluster role的角色。

  6. Jenkins Slave开始build,利用non-prod EKS cluster role的权限从AWS CodeCommit中拉取代码。

  7. Jenkins Slave build出docker镜像,利用non-prod EKS cluster role的权限将镜像推送到AWS ECR中去。

  8. Jenkins Slave利用RBAC定义的权限创建k8s deployment和service,完成部署。

  9. 产品pod利用non-prod node role的角色去AWS ECR中拉取镜像。这里需要注意:

    1. 用的role不再是前面的cluster role,而是node role,因为拉取镜像是创建pod时k8s内部的操作,这时候kube2iam还没有将cluster role赋予该pod,所以这个时刻pod的role还是默认的node role
    2. non-prod node role与ECR在同一个账号下,所以只需要赋予non-prod node role与ECR交互的权限,ECR无需任何设置。
  10. kube2iam为产品pod分配non-prod EKS cluster role,低环境的部署完成。

Prod Account

  1. 开始进行prod的跨账号部署,Jenkins Slave这时候手动带入prod EKS cluster role中去。这里需要:

    1. 提前创建好prod EKS cluster role
    2. prod EKS cluster role的信任关系中允许non-prod EKS cluster role的带入。
    3. 提前更新prod账号的EKS设置,为prod EKS cluster role提供集群的访问权限。默认情况下只有集群的创建者拥有集群的访问权限,所以如果prod EKS cluster role不是集群的创建者的话,就需要手动加入。
    4. 更新kubectl,让其连接上prod账号的EKS集群。

    成功带入prod EKS cluster role后,Jenkins Slave开始部署。

  2. 新创建出的pod被赋予prod node role的默认权限。

  3. 产品pod利用prod node role的角色去AWS ECR中拉取镜像。这里需要注意:

    1. prod node role需要具有访问ECR的权限
    2. ECR的permission设置中需要允许prod node role来访问。因为ECR在non-prod账号而产品pod是在另一个账号,所以这里需要显示的指定。
  4. prod集群下的kube2iam为产品pod分配prod EKS cluster role,部署完成。

  5. 最后一步也是很重要的一步,如果Jenkins Slave被设置成长期存活而不是用完就删除的话,需要重新带入回non-prod EKS cluster role,这样下一次build使用的才会是non-prod账号。(这一步没画在图中)

总结

总结一下,简单来说就是:

  1. 用kube2iam在pod创建时为pod分配IAM role
  2. 用RBAC来赋予Jenkins操纵k8s的权限
  3. Jenkins Slave带入到prod账号的角色中来完成对prod账号的操作

有用的资料

解决AWS EKS占用太多子网IP的问题 Java与Kotlin中的协变、逆变、不变

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×