基于ArgoWorkflow实现账号工厂
方案概述
当企业开通资源目录,将已有阿里云账号邀请进来,或者通过新建成员账号的方式开展新的业务,那么不同账号之间的统一权限管理就会显得尤为重要,如果是在这些账号内手工创建 RAM 角色,则无法保证权限统一,后续修改维护困难,本文档则介绍了一种通过Argo Workflows + ACK + Terraform 自动化为所有成员账号创建RAM 角色、权限及VPC等统一基线的方法。
方案优势
账号统一基线
账号工厂通过同一工作流模板生产成员账号,能够确保新账号都包含流水线中定义的统一基线,根据基线内容保障新账号权限安全。
基础设施代码化
基于IaC思想,将资源目录中成员账号的配置过程使用Terraform规范化,每次创建成员账号时使用同一份Terraform代码,保证所有成员账号权限统一,减轻运维管理负担。
灵活可扩展
Terraform及工作流代码可拓展,用户可根据需求拓展功能,提供更多的基线配置。Argo Workflows为CNCF项目,与K8s天然集成、生态丰富,API可与企业DevOps平台集成。
AK便捷安全管理
可与KMS凭据管家集成,统一管理外部及阿里云AccessKey,提升安全性及便捷性。
客户场景
上云阶段批量生产成员账号
场景描述
企业上云阶段构建多账号体系,多成员账号权限配置繁琐、效率低下,无法保证账号权限、资源配置等基线统一,后续修改维护困难。
适用客户
上云阶段需要批量生成统一基线账号的企业客户。
业务扩展新建成员账号
场景描述
企业业务扩展需开设新账号,企业手动创建账号时无法快速创建拥有统一身份权限、资源配置基线的成员账号。
适用客户
企业业务扩展阶段需要生成统一基线账号的企业客户。
方案架构
本方案使用Terraform自动化执行,整合Git仓库 + ArgoWorkflows搭建Terraform的执行环境,实现了Terraform的CI/CD集成。方案中以ACK集群为基础搭建Argo Workflows,Terraform的state文件使用Azure Storage Account Container作为服务远端存储(Backend)并支持加锁,保证state文件的安全。另整合KMS凭据管家(也可选择k8s保密字典)对访问控制密钥(AccessKey)进行托管,对Azure及阿里云密钥进行集中管理,提升密钥管理的安全性和便捷性。
以下的流程图描述了该方案的执行步骤,首先使用企业管理账号下的RAM用户(子用户)AK信息,通过Terraform脚本登录到企业管理账号,并在指定的资源夹下创建新的「成员账号」。之后扮演成员账号下的ResourceDirectoryAccountAccessRole角色,该角色会在成员账号加入RD时自动创建,并拥有云管理员(AdministratorAccess)权限。登录到成员账号后,会在成员账号下进行权限配置——创建IDP和相关RAM角色、创建一个用于执行Tarraform脚本的RAM用户并为上述角色和用户绑定权限策略。最后会在成员账号下进行网络配置——根据用户指定数据创建VPC和交换机。
产品费用及名词
产品费用
产品名称 | 产品说明 | 产品费用 |
资源目录RD | 资源目录RD(Resource Directory)是阿里云面向企业客户提供的一套多级账号和资源关系管理服务。 | 免费,详情参见产品定价。 |
访问控制RAM | 访问控制使您能够安全地集中管理对阿里云服务和资源的访问。您可以使用RAM创建和管理用户和组,并使用各种权限来运行或访问他们对云资源的访问。 | 免费。 |
容器服务ACK | 阿里云容器服务Kubernetes版是全球首批通过Kubernetes一致性认证的服务平台,提供高性能的容器应用管理服务,支持企业级Kubernetes容器化应用的生命周期管理,让您轻松高效地在云端运行Kubernetes容器化应用。 | 收费,详情参见产品计费。 |
容器镜像服务ACR | 容器镜像服务ACR提供安全地镜像托管能力,稳定的国内外镜像构建服务,便捷的镜像授权功能,方便用户进行镜像全生命周期管理。 | 企业版收费,详情见产品计费。 |
阿里云文件存储NAS | 阿里云文件存储是面向ECS实例、E-HPC和容器服务等计算节点的文件存储服务。它是一种可共享访问、弹性扩展、高可靠以及高性能的分布式文件系统。 | 收费,详情参见产品计费。 |
密钥管理服务KMS | 密钥管理服务是阿里云一站式密钥管理和数据加密服务平台,提供简单、可靠、安全、合规的数据加密保护能力。 | 收费,详情参见产品计费。 |
Argo Workflows | Argo Workflows 是基于 Kubernetes 的开源任务编排服务,它自定义了一个名为 Workflow 的 CR (Custom Resource),提供了丰富的执行控制逻辑。 | CNCF开源项目,免费。 |
Azure存储容器 | Azure存储容器对一组 blob 进行组织,类似于文件系统中的目录。 一个存储账户可以包含无限数量的容器,一个容器可以存储无限数量的 Blob | 收费,详情参见价目表。 |
名词解释
名称 | 说明 |
企业管理主账号 | 在企业拥有多个阿里云账号时,特指拥有管理其他账号资源权限的管理员账号。用于管理多账号,统一配置多账号身份权限,统一查看各云账号账单,统一配置审计规则并下发到各成员账号。 |
RAM用户 | RAM用户是RAM的一种实体身份类型,有确定的身份ID和身份凭证,它通常与某个确定的人或应用程序一一对应。因安全原因不推荐直接使用云账号的AK/SK。因此在账号下创建一个RAM用户,授予RAM用户最小权限,使用该RAM用户的AK/SK。 |
成员账号 | 在资源目录中受「企业管理账号」邀请或被创建的其他账号,每一个成员账号均为一个独立的账号,拥有自己的云资源,企业可根据职责划分为不同的账号,由企业管理账号统一管理。 |
State文件 | Terraform中用于描述当前资源配置的文件,本文使用Azure存储容器作为远端存储,可参考文档。 |
安全性
资源目录权限
资源目录服务关联角色(AliyunServiceRoleForResourceDirectory)为资源目录集成服务提供可信访问通道,详情参见资源目录服务关联角色。
ACK安全性
阿里云容器服务Kubernetes版的安全体系维度有运行时安全、可信软件供应链和基础架构安全三个维度,包括安全巡检、策略管理、运行时监控和告警、镜像扫描、镜像签名、云原生应用交付链、默认安全、身份管理、细粒度访问控制等,详情参见安全体系概述。容器服务ACK的授权体系包含RAM授权和RBAC授权两部分,详情参见授权概述。
KMS安全性
KMS经过严格的安全设计和审核,保证密钥在阿里云得到最严格的保护,详情参见安全与合规能力。
Terraform State文件安全
使用Azure存储容器作为Backend保存Terraform State文件,存储容器支持State加锁及一致性检查,详情参见Azurerm Backends。
Argo Workflows安全性
Argo Server可运行在不同的权限认证模式下,详情参见Auth Mode。使用API及工作流界面时可启用Access Token提升工作流管控安全性,整体安全性概述可参见官网Security。
AccessKey使用
方案需要使用企业管理主账号下RAM用户的AccessKey,用于创建账号及操作阿里云资源。需要使用Azure侧的订阅ID、租户ID、应用ID及Secret,用于操作Azure存储容器。
注意事项
资源目录使用限制
资源目录及资源共享使用限制详情参见使用限制。
ACK使用限制
ACK使用过程中有配额及底层云产品限制等,详情参见使用限制。
KMS使用限制
KMS存在配额及地域等限制,详情参见使用限制。
实施步骤
实施准备
已完成创建Kubernetes托管版集群,使用docker作为执行容器、开通NAS、公网SLB,且ACK集群已初始化完成。
已拥有Azure账号,能够通过Azure Portal及命令行操作Azure资源。
已拥有Git仓库,用于上传及拉取Terraform工作流相关代码。
已经开通阿里云KMS服务,可参考开通链接。
确保在「企业管理账号」中,存在一个「RAM用户」AK,且该账号拥有 AliyunResourceDirectoryFullAccess和AliyunSTSAssumeRoleAccess两个权限;在后续的步骤中,我们将使用该RAM用户及其AK。根据后续实施步骤中选择不同的AK管理方案,AK将会托管到KMS或保密字典中,不在工作流中存储或显式传入。
确定工作流及Terraform输入参数,输入参数分为两部分:第一部分为全局参数,写入settings.tfvars文件,每次流水线执行时均保持一致;第二部分为执行参数,执行流水线时动态填写,不会保存。
全局参数
encodedsaml_metadata_document:企业IDP的元文件,用于在阿里云上创建IDP
sso_provider_name:创建的IDP的名称
ram_roles:需要创建的ram角色列表,示例中包括只读和管理员角色
user_name:用于执行TF脚本的角色名称
policy_name:自定义权限策略的名称
policy_document:自定义权限策略内容
attach_roles:自定义权限策略绑定的角色列表
attach_users:自定义权限策略绑定的用户列表
reader_name:需要绑定权限策略的只读角色名称
reader_policy_type:为只读角色绑定的权限策略的类型
reader_policy_name:为只读角色绑定的权限策略的名称
vpc_name:创建的vpc的名称
vswitch_name:vpc下交换机的名称
执行参数
account_name:新创建账号的显示名称
account_name_prefix:新创建账号的账号标识
uid: 「企业管理账号」uid
folder_id:新创建的成员账号所属资源夹ID
vpc_cidr_block:VPC的网段
switch_cidr_block:交换机的网段
region:区域,如cn-hangzhou
zone_id:可用区ID,如cn-hangzhou-b
alicloud_secret_name:KMS中的阿里云凭据名称,采用KMS凭据管家管理密钥时需要,这里仅做说明、后续步骤生成该配置后作为参数传入工作流
azure_secret_name:KMS中的Azure凭据名称,采用KMS凭据管家管理密钥时需要,这里仅做说明、后续步骤生成该配置后作为参数传入工作流
kms_aap_client_key_pwd:KMS应用接入点ClientKey口令,采用KMS凭据管家管理密钥时需要,这里仅做说明、后续步骤生成该配置后作为参数传入工作流
完成镜像构建,并通过容器镜像服务(ACR)能够拉取到镜像,我们将使用ACR中的
acr-hangzhou-1-registry.cn-hangzhou.cr.aliyuncs.com/terraform/terraform:v9
镜像运行Terraform代码,用户也可根据自身需求打包镜像,该镜像的Dockerfile如下所示:FROM mcr.microsoft.com/azure-cli:latest ENV TERRAFORM_PLUGIN_DIR=/srv/terraform-plugins ENV TF_PLUGIN_CACHE_DIR=${TERRAFORM_PLUGIN_DIR} ENV TERRAFORM_VERSION=1.0.2 ENV TERRAFORM_PROVIDER_ALICLOUD_VERSION=1.145.0 ENV TERRAFORM_PROVIDER_AZUREM_VERSION=2.81.0 ENV TERRAFORM_PROVIDER_LOCAL_VERSION=2.1.0 ENV PATH="/opt/venv/bin:$PATH" RUN apk add libxml2-dev libxslt-dev python3-dev gcc build-base wget unzip git bash \ && python3 -m venv /opt/venv \ && pip install terraform-compliance \ && pip install checkov \ && python3 -m pip install --upgrade pip \ && pip install aliyun-secret-manager-client==0.0.5 \ && pip install alibabacloud-resourcemanager20200331==2.0.3 \ && pip install alibabacloud_bssopenapi20171214==2.0.3 \ && wget https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \ && unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/local/bin/ \ && mkdir -p ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/aliyun/alicloud/${TERRAFORM_PROVIDER_ALICLOUD_VERSION}/linux_amd64 \ && wget https://releases.hashicorp.com/terraform-provider-alicloud/${TERRAFORM_PROVIDER_ALICLOUD_VERSION}/terraform-provider-alicloud_${TERRAFORM_PROVIDER_ALICLOUD_VERSION}_linux_amd64.zip \ && unzip terraform-provider-alicloud_${TERRAFORM_PROVIDER_ALICLOUD_VERSION}_linux_amd64.zip -d ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/aliyun/alicloud/${TERRAFORM_PROVIDER_ALICLOUD_VERSION}/linux_amd64 \ && mkdir -p ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/hashicorp/azurerm/${TERRAFORM_PROVIDER_AZUREM_VERSION}/linux_amd64 \ && wget https://releases.hashicorp.com/terraform-provider-azurerm/${TERRAFORM_PROVIDER_AZUREM_VERSION}/terraform-provider-azurerm_${TERRAFORM_PROVIDER_AZUREM_VERSION}_linux_amd64.zip \ && unzip terraform-provider-azurerm_${TERRAFORM_PROVIDER_AZUREM_VERSION}_linux_amd64.zip -d ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/hashicorp/azurerm/${TERRAFORM_PROVIDER_AZUREM_VERSION}/linux_amd64 \ && mkdir -p ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/hashicorp/local/${TERRAFORM_PROVIDER_LOCAL_VERSION}/linux_amd64 \ && wget https://releases.hashicorp.com/terraform-provider-local/${TERRAFORM_PROVIDER_LOCAL_VERSION}/terraform-provider-local_${TERRAFORM_PROVIDER_LOCAL_VERSION}_linux_amd64.zip \ && unzip terraform-provider-local_${TERRAFORM_PROVIDER_LOCAL_VERSION}_linux_amd64.zip -d ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/hashicorp/local/${TERRAFORM_PROVIDER_LOCAL_VERSION}/linux_amd64 \ && rm -rf *.zip
实施时长
在实施准备工作完成的情况下,本方案实施预计时长:90分钟。
操作步骤
配置Azure存储容器
在Azure Portal命令行分别执行下述命令,创建资源组、存储账户、存储容器,记录创建信息,用于Terraform Backend存储。
#!/bin/bash RESOURCE_GROUP_NAME=tfstate STORAGE_ACCOUNT_NAME=tfstate$RANDOM CONTAINER_NAME=tfstate # Create resource group az group create --name $RESOURCE_GROUP_NAME --location eastus # Create storage account tfstate9104 az storage account create --resource-group $RESOURCE_GROUP_NAME --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS --encryption-services blob # Create blob container az storage container create --name $CONTAINER_NAME --account-name $STORAGE_ACCOUNT_NAME
在存储账户页面能够查看刚创建的账户及容器信息。
在命令行执行“az account show”,记录account ID。
在命令行执行“az ad sp create-for-rbac --name terraform-sp”,创建service principal,用于Terraform运行时授权使用,记录appId、password、tenant。
上述记录的信息需要记录下来,作为工作流的环境变量传入用于支持Terraform运行。字段和变量对应关系如下:
# ENV variable ARM_SUBSCRIPTION_ID="xxx" # account ID, argo variable: arm_subscription_id ARM_TENANT_ID="xxx" # tenant, argo variable: arm_tenant_id ARM_CLIENT_ID="xxx" # appId, argo variable: arm_client_id ARM_CLIENT_SECRET="xxx" # password, argo variable: arm_client_secret
配置参数
从本文源代码章节下载账号工厂代码,目录结构可以参考章节中相应说明。
用编辑器打开代码,拷贝账号工厂代码
extension/backend
目录中的azurerm-backend.tfvars
文件内容,替换掉账号工厂代码最外层的backend.tfvars
文件内容。替换完成后修改该文件内的配置项并保存:
resource_group_name:已创建的Azure资源组名称
storage_account_name:已创建的Azure存储账户名称
container_name:已创建的Azure存储容器名称
拷贝账号工厂代码
extension/backend
目录中的azurerm-backend.tf
文件内容,替换掉账号工厂代码step
目录的所有子目录下的backend.tf文件内容并保存。用编辑器打开
settings.tfvars
文件,根据配置文件注释和实施准备中的全局参数填写。将代码上传到Git仓库,也可以等后续所有配置都完成后再上传。
安装K8S命令行
在本地或平时操作的机器部署kubectl,不同操作系统的操作步骤参考链接。
查看ACK集群连接信息,将凭证信息保存到$HOME/.kube/config 文件下。可使用命令kubectl cluster-info验证集群信息获取。
部署Argo Workflows
执行下述命令,在ACK集群中部署工作流。Argo Workflow官方文档可参考链接。
kubectl create ns argo kubectl apply -n argo -f https://raw.githubusercontent.com/argoproj/argo-workflows/master/manifests/quick-start-postgres.yaml
本地Argo Workflows CLI安装,参考链接,可尝试用CLI提交工作流并查看工作流运行信息。
argo submit -n argo --watch https://raw.githubusercontent.com/argoproj/argo-workflows/master/examples/hello-world.yaml argo list -n argo argo get -n argo @latest argo logs -n argo @latest
在本地创建port-forward,用于在本地即可访问已部署在ACK集群的Argo Workflow。
kubectl -n argo port-forward deployment/argo-server 2746:2746
访问 https://localhost:2746 查看Workflow页面。若访问页面提示权限问题可运行
argo server --auth-mode server
命令后重试。若需要通过公网访问可执行如下命令(需要ACK集群中有公网SLB),等待EXTERNAL-IP出现后即可通过该公网地址访问页面https://118.31.xx.xx:2746/。
kubectl patch svc argo-server -n argo -p '{"spec": {"type": "LoadBalancer"}}' kubectl get svc argo-server -n argo
配置ACK集群
本文中使用ACK部署Argo Workflows来运行工作流,必须先创建ACK集群然后再搭建Argo Workflow,推荐使用ACK托管版,相关详情可参考链接。
配置NAS
进入在ACK控制台集群详情页,创建存储卷并挂载到集群,用于工作流执行时步骤间共享文件数据。选择NAS,名称:pv-nas-1,子目录:/nas。
进入在ACK控制台集群详情页创建存储声明,用于工作流执行时步骤间共享文件数据。注意页面上方选择命名空间,需要与工作流页面的NAMESPACE保持一致,声明类型选择NAS,名称:pvc-nas-1,选择已有存储卷,即上一步创建的存储卷。
配置Git仓库访问信息
添加Git仓库访问信息到保密字典,用于工作流运行时拉取代码。
在集群详情保密字典页面创建保密字典,注意页面上方选择命名空间,需要与工作流页面的NAMESPACE保持一致,名称为git-terraform-creds,添加键名称username、password、ssh-private-key并填入相应值后保存。这里可以只选择填写username、password或ssh-private-key其中一项,代码中默认使用用户名密码拉取,要使用SSH私钥拉取可以在工作流代码中按注释说明调整下配置即可(方案中暂不支持Azure DevOps Git仓库私钥拉取,参考后续步骤说明)。
配置镜像免密拉取
授权ACK能够免密拉取ACR镜像,如果ACR中Terraform运行镜像配置为公共镜像则可跳过该项配置步骤。
在集群详情页面选择配置项,按下图所示选择命名空间kube-system,填入ACR实例ID、地域、service-account、watch-namespace信息,本文配置的是和ACK在同一账号下的ACR实例ID,其它场景可参考链接。
配置拉取权限策略。按下图所示在集群信息-集群资源Tab页进入RAM角色配置页面。
点击下图权限策略名称链接,进入权限配置详情。
点击修改策略内容,将下述配置代码添加到策略内容中后保存。
{ "Action": [ "cr:Get*", "cr:List*", "cr:PullRepository" ], "Resource": "*", "Effect": "Allow" }
管理访问控制密钥
这一章节提供了“KMS凭据管家”和“ACK保密字典+KMS落盘加密”两种访问控制密钥(AK,AccessKey)管理方案,用于对工作流中使用的密钥信息进行集中管理,提升安全性和便捷性,以下两种方案选用一种即可。注意KMS对API调用和用户上传密钥的托管会收取一定费用,计费说明参考链接。
使用KMS凭据管家
KMS凭据管家能够集中管理外部及阿里云密钥信息,支持阿里云AK自动轮转,凭据管家介绍可参考链接。工作流变量配置中需要使用凭据管家的三项信息,分别为阿里云凭据名称、Azure 凭据名称、应用接入点ClientKey口令,这三项信息会在下面的操作步骤中产生。
操作步骤:
通过RAM服务角色授予凭据管家管理RAM用户AccessKey的权限。具体操作,请参见授予凭据管家管理RAM用户AccessKey的权限。
登录KMS凭据控制台,左上角选择地域,在凭据页面创建新的凭据。这里先对阿里云密钥进行配置,选择使用RAM凭据,选择前置条件中已创建AK的RAM用户,在下一步可以选择使用自动轮转AK的功能,无需管理员手动定时更换凭据。注意设置凭据值这里请输入这个RAM用户对应的一个合法的AK值,KMS是用这个AK值去做轮转判断的,官方文档可参考链接。
使用应用接入点AAP(Application Access Point),用于控制工作流如何使用凭据。选择应用管理,创建应用接入点,填写名称、描述,认证方式使用ClientKey。
进入下一步,点击+号创建权限策略,选择已准备好的RAM用户的Secret,根据实际情况在可选规则中点击+号创建网络控制规则。完成相应选择后完成接入点创建,在弹出的对话框中选择创建ClientKey。
输入ClientKey加密口令,点击确定后可下载ClientKey,记录口令和下载的ClientKey备用,在工作流代码中需要使用。
更新Terraform代码包中的配置,按实际情况在
extension/secretsmanager.properties
文件中填入KMS凭据所在地域,并将下载的ClientKey内容更新到extension/kms_client_key_kaap.json
中。上述已经完成了阿里云的凭据配置,这一步创建Azure凭据。在凭据管理页面创建凭据时选择其它凭据,用于存储Azure的保密信息,名称可以自定义后作为参数传入工作流。凭据值的键使用固定值,分别创建arm_subscription_id、arm_tenant_id、arm_client_id、arm_client_secret,填入相应信息后完成创建。
在应用接入点详情-权限策略列表中点击编辑,将创建的Azure凭据纳入应用接入点的访问范围后保存,通过该应用接入点可以获取阿里云以及Azure的密钥信息。
使用ACK保密字典+KMS落盘加密
保密字典是k8s集群管理保密信息的通用标准方案,在ACK集群详情界面可进行配置。另可以使用KMS密钥对保密字典进行数据落盘加密提升安全性,使用KMS密钥进行数据落盘加密时需要创建KMS主密钥及相应系统角色权限。操作步骤:
登录ACK管理控制台,进入集群详情页面。
在配置管理-保密字典页面,点击创建按钮进行密钥信息添加。这里我们添加两个保密字典项,分别用于存放阿里云和Azure密钥信息,这里填写的名称会在工作流代码中使用。注意根据实际情况在页面上方选择命名空间,需要与工作流页面的NAMESPACE保持一致。
阿里云保密字典名称terraform-ak-alicloud,键的名称分别为access_key、secret_key,填入值信息后点击确定完成创建。
Azure保密字典名称terraform-ak-azure,键的名称分别为arm_subscription_id、arm_tenant_id、arm_client_id、arm_client_secret,填入值信息后点击确定完成创建。
可以使用KMS密钥进行保密字典数据落盘加密,配置过程参考官方链接。
运行Argo Workflows
准备工作流代码
根据实施准备中的配置及实际情况修改下面的工作流yaml代码中的工作流参数、Git仓库地址、镜像配置,保存备用。注意下面有两个版本的工作流代码,根据上述密钥管理的方式选择一个版本即可。
KMS凭据管家版本:
# KMS凭据管家版本 apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: namespace: argo generateName: terraform-workflow- annotations: workflows.argoproj.io/version: ">= 3.1.0" spec: entrypoint: terraform-workflow arguments: parameters: # 阿里云凭据名称 - name: alicloud_secret_name value: "acs/ram/user/xxx" # Azure凭据名称 - name: azure_secret_name value: "terraform-ak-azure" # 应用接入点ClientKey口令 - name: kms_aap_client_key_pwd value: "xxx" - name: region value: "cn-hangzhou" - name: uid value: "15462275xxx" - name: account_name value: "xxx" - name: account_name_prefix value: "xxx" - name: folder_id value: "xxx" - name: vpc_cidr_block value: "172.16.0.0/12" - name: switch_cidr_block value: "172.16.0.0/21" - name: zone_id value: "cn-hangzhou-b" templates: - name: terraform-workflow steps: # 环境准备 - - name: env-prepare template: git-clone-init arguments: parameters: - name: cmd value: 'pwd && ls -al' # 创建账号 - - name: account-create template: execute-func arguments: parameters: - name: cmd value: ' cd extension && python kms_secret.py {{workflow.parameters.alicloud_secret_name}} {{workflow.parameters.azure_secret_name}} env_temp && source env_temp && rm -rf env_temp && cd .. && cd step/account-create && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-account-create" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var "folder_id={{workflow.parameters.folder_id}}" -var "account_name={{workflow.parameters.account_name}}" -var "account_name_prefix={{workflow.parameters.account_name_prefix}}" ' # 权限配置:创建IDP - - name: auth-create-idp template: execute-func arguments: parameters: - name: cmd value: ' cd extension && python kms_secret.py {{workflow.parameters.alicloud_secret_name}} {{workflow.parameters.azure_secret_name}} env_temp && source env_temp && rm -rf env_temp && cd .. && cd step/auth-create-idp && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-auth-create-idp" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var-file=../../settings.tfvars -compact-warnings ' # 权限配置:创建角色 - - name: auth-create-role template: execute-func arguments: parameters: - name: cmd value: ' cd extension && python kms_secret.py {{workflow.parameters.alicloud_secret_name}} {{workflow.parameters.azure_secret_name}} env_temp && source env_temp && rm -rf env_temp && cd .. && cd step/auth-create-role && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-auth-create-role" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var-file=../../settings.tfvars -compact-warnings ' # 权限配置:创建TF用户 - - name: auth-create-user template: execute-func arguments: parameters: - name: cmd value: ' cd extension && python kms_secret.py {{workflow.parameters.alicloud_secret_name}} {{workflow.parameters.azure_secret_name}} env_temp && source env_temp && rm -rf env_temp && cd .. && cd step/auth-create-user && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-auth-create-user" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var-file=../../settings.tfvars -compact-warnings ' # 权限配置:角色授权 - - name: auth-authorize-role template: execute-func arguments: parameters: - name: cmd value: ' cd extension && python kms_secret.py {{workflow.parameters.alicloud_secret_name}} {{workflow.parameters.azure_secret_name}} env_temp && source env_temp && rm -rf env_temp && cd .. && cd step/auth-authorize-role && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-auth-authorize-role" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var-file=../../settings.tfvars -compact-warnings ' # 网络配置 - - name: network-configure template: execute-func arguments: parameters: - name: cmd value: ' cd extension && python kms_secret.py {{workflow.parameters.alicloud_secret_name}} {{workflow.parameters.azure_secret_name}} env_temp && source env_temp && rm -rf env_temp && cd .. && cd step/network-create-vpc-vsw && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-network-create-vpc-vsw" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -compact-warnings -var "vpc_cidr_block={{workflow.parameters.vpc_cidr_block}}" -var "switch_cidr_block={{workflow.parameters.switch_cidr_block}}" -var "zone_id={{workflow.parameters.zone_id}}" -var-file=../../settings.tfvars ' - name: execute-func inputs: parameters: - name: cmd container: image: acr-hangzhou-1-registry.cn-hangzhou.cr.aliyuncs.com/terraform/terraform:v9 volumeMounts: - name: pvc-nas-1 mountPath: "/nas" # NAS挂载路径 command: ["/bin/sh", "-c"] args: ["{{inputs.parameters.cmd}}"] workingDir: /nas/tf-dir-{{workflow.name}} env: - name: ALICLOUD_REGION value: "{{workflow.parameters.region}}" - name: KMS_AAP_CLIENT_KEY_PWD value: "{{workflow.parameters.kms_aap_client_key_pwd}}" volumes: - name: pvc-nas-1 persistentVolumeClaim: claimName: pvc-nas-1 # NAS PVC - name: git-clone-init inputs: parameters: - name: cmd artifacts: - name: terraform-source path: /nas/tf-dir-{{workflow.name}} git: repo: https://codeup.aliyun.com/xxxx/account-base.git # when authenticating via basic auth # repo: git@codeup.aliyun.com:xxxx/account-base.git # when authenticating via sshPrivateKeySecret revision: "azure-backend-update" usernameSecret: # when authenticating via basic auth name: git-terraform-creds key: username passwordSecret: # when authenticating via basic auth name: git-terraform-creds key: password # sshPrivateKeySecret: # when authenticating via sshPrivateKeySecret # name: git-terraform-creds # key: ssh-private-key # insecureIgnoreHostKey: true # when authenticating via sshPrivateKeySecret depth: 1 container: image: acr-hangzhou-1-registry.cn-hangzhou.cr.aliyuncs.com/terraform/terraform:v9 volumeMounts: - name: pvc-nas-1 mountPath: "/nas" command: ["/bin/sh", "-c"] args: ["{{inputs.parameters.cmd}}"] workingDir: /nas/tf-dir-{{workflow.name}} volumes: - name: pvc-nas-1 persistentVolumeClaim: claimName: pvc-nas-1
ACK保密字典版本:
# ACK保密字典版本 apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: namespace: argo generateName: terraform-workflow- annotations: workflows.argoproj.io/version: ">= 3.1.0" spec: entrypoint: terraform-workflow arguments: parameters: - name: region value: "cn-hangzhou" - name: uid value: "15462275xxx" - name: account_name value: "xxx" - name: account_name_prefix value: "xxx" - name: folder_id value: "fd-xxx" - name: vpc_cidr_block value: "172.16.0.0/12" - name: switch_cidr_block value: "172.16.0.0/21" - name: zone_id value: "cn-hangzhou-b" templates: - name: terraform-workflow steps: # 环境准备 - - name: env-prepare template: git-clone-init arguments: parameters: - name: cmd value: 'pwd && ls -al' # 创建账号 - - name: account-create template: execute-func arguments: parameters: - name: cmd value: ' cd step/account-create && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-account-create" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var "folder_id={{workflow.parameters.folder_id}}" -var "account_name={{workflow.parameters.account_name}}" -var "account_name_prefix={{workflow.parameters.account_name_prefix}}" ' # 权限配置:创建IDP - - name: auth-create-idp template: execute-func arguments: parameters: - name: cmd value: ' cd step/auth-create-idp && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-auth-create-idp" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var-file=../../settings.tfvars -compact-warnings ' # 权限配置:创建角色 - - name: auth-create-role template: execute-func arguments: parameters: - name: cmd value: ' cd step/auth-create-role && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-auth-create-role" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var-file=../../settings.tfvars -compact-warnings ' # 权限配置:创建TF用户 - - name: auth-create-user template: execute-func arguments: parameters: - name: cmd value: ' cd step/auth-create-user && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-auth-create-user" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var-file=../../settings.tfvars -compact-warnings ' # 权限配置:角色授权 - - name: auth-authorize-role template: execute-func arguments: parameters: - name: cmd value: ' cd step/auth-authorize-role && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-auth-authorize-role" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -var-file=../../settings.tfvars -compact-warnings ' # 网络配置 - - name: network-create-vpc-vsw template: execute-func arguments: parameters: - name: cmd value: ' cd step/network-create-vpc-vsw && terraform init -backend-config="key={{workflow.parameters.uid}}-{{workflow.parameters.account_name}}-network-create-vpc-vsw" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins && terraform apply --auto-approve -compact-warnings -var "vpc_cidr_block={{workflow.parameters.vpc_cidr_block}}" -var "switch_cidr_block={{workflow.parameters.switch_cidr_block}}" -var "zone_id={{workflow.parameters.zone_id}}" -var-file=../../settings.tfvars ' - name: execute-func inputs: parameters: - name: cmd container: image: acr-hangzhou-1-registry.cn-hangzhou.cr.aliyuncs.com/terraform/terraform:v9 volumeMounts: - name: pvc-nas-1 mountPath: "/nas" # NAS挂载路径 command: ["/bin/sh", "-c"] args: ["{{inputs.parameters.cmd}}"] workingDir: /nas/tf-dir-{{workflow.name}} env: - name: ALICLOUD_REGION value: "{{workflow.parameters.region}}" - name: ALICLOUD_ACCESS_KEY valueFrom: secretKeyRef: name: terraform-ak-alicloud key: access_key - name: ALICLOUD_SECRET_KEY valueFrom: secretKeyRef: name: terraform-ak-alicloud key: secret_key - name: ARM_SUBSCRIPTION_ID valueFrom: secretKeyRef: name: terraform-ak-azure key: arm_subscription_id - name: ARM_TENANT_ID valueFrom: secretKeyRef: name: terraform-ak-azure key: arm_tenant_id - name: ARM_CLIENT_ID valueFrom: secretKeyRef: name: terraform-ak-azure key: arm_client_id - name: ARM_CLIENT_SECRET valueFrom: secretKeyRef: name: terraform-ak-azure key: arm_client_secret volumes: - name: pvc-nas-1 persistentVolumeClaim: claimName: pvc-nas-1 # NAS PVC - name: git-clone-init inputs: parameters: - name: cmd artifacts: - name: terraform-source path: /nas/tf-dir-{{workflow.name}} git: repo: https://codeup.aliyun.com/xxx/account-base.git # when authenticating via basic auth # repo: git@codeup.aliyun.com:xxx/account-base.git # when authenticating via sshPrivateKeySecret revision: "azure-backend-update" usernameSecret: # when authenticating via basic auth name: git-terraform-creds key: username passwordSecret: # when authenticating via basic auth name: git-terraform-creds key: password # sshPrivateKeySecret: # when authenticating via sshPrivateKeySecret # name: git-terraform-creds # key: ssh-private-key # insecureIgnoreHostKey: true # when authenticating via sshPrivateKeySecret depth: 1 container: image: acr-hangzhou-1-registry.cn-hangzhou.cr.aliyuncs.com/terraform/terraform:v9 volumeMounts: - name: pvc-nas-1 mountPath: "/nas" command: ["/bin/sh", "-c"] args: ["{{inputs.parameters.cmd}}"] workingDir: /nas/tf-dir-{{workflow.name}} volumes: - name: pvc-nas-1 persistentVolumeClaim: claimName: pvc-nas-1
Azure Git仓库适配
如果使用Azure DevOps Git仓库存放Terraform等相关代码,由于Git服务器实现方式不同,使用上述代码中ArgoWorkflows的“git”组件可能会在拉取代码时报错造成无法拉取,需要对工作流代码进行简单调整。调整后的代码使用保密字典中的用户名和密码拉取代码,方案中暂不支持使用私钥拉取。调整步骤:
替换“环境准备”这一步骤中的代码,根据实际情况修改Git仓库地址git_repo_url的value。
# 环境准备 - - name: env-prepare template: git-clone-init arguments: parameters: - name: git_repo_url value: "dev.azure.com/xxx/helloDevOps/_git/helloDevOps" - name: cmd value: 'pwd && ls -al'
将名称为“git-clone-init”的template替换为以下代码,根据实际情况修改镜像。
- name: git-clone-init inputs: parameters: - name: cmd - name: git_repo_url container: image: acr-hangzhou-1-registry.cn-hangzhou.cr.aliyuncs.com/terraform/terraform:v9 volumeMounts: - name: pvc-nas-1 mountPath: "/nas" # NAS挂载路径 command: ["/bin/sh", "-c"] args: ["git clone https://$GIT_USERNAME:$GIT_PASSWORD@{{inputs.parameters.git_repo_url}} /nas/tf-dir-{{workflow.name}} && {{inputs.parameters.cmd}}"] workingDir: /nas/tf-dir-{{workflow.name}} env: - name: GIT_USERNAME valueFrom: secretKeyRef: name: git-terraform-creds key: username - name: GIT_PASSWORD valueFrom: secretKeyRef: name: git-terraform-creds key: password volumes: - name: pvc-nas-1 persistentVolumeClaim: claimName: pvc-nas-1 # NAS PVC
页面运行
访问workflow界面https://localhost:2746,打开创建工作流页面。
将原有示例代码全选、粘贴上述已修改配置的yaml代码,然后点击Create即可运行工作流。如果yaml格式错误在下方会有提示。
也可以先创建工作流模板,修改参数后创建工作流。
点击工作流进入详情可查看日志。
在Azure存储账户中可看到state文件已经更新。
使用API
根据工作流模板创建工作流:
POST https://118.31.xx.xx:2746/api/v1/workflows/argo/submit
# POST request body { "resourceKind": "WorkflowTemplate", "resourceName": "terraform-workflow-nxbpp", # Template Name "submitOptions": { "labels": "workflows.argoproj.io/workflow-template=terraform-workflow-nxbpp", "parameters": [ "region=cn-hangzhou", "uid=11409316xxxxxxxxx", "account_name=accountxxxx", "account_name_prefix=accountxxxx", "folder_id=fd-xxxxxx", "vpc_cidr_block=172.16.0.0/12", "switch_cidr_block=172.16.0.0/21", "zone_id=cn-hangzhou-b" ] } } # Response { "metadata": { "name": "terraform-workflow-nxbpp-26xwc", # Workflow instance name "generateName": "terraform-workflow-nxbpp-", "namespace": "argo", "uid": "ee843f87-2f7a-4989-9808-68e64180e2ea", "resourceVersion": "393837", "generation": 1, "creationTimestamp": "2021-10-25T12:37:30Z", "labels": { "workflows.argoproj.io/creator": "system-serviceaccount-argo-argo-server", "workflows.argoproj.io/workflow-template": "terraform-workflow-nxbpp" } "xxx":"xxx" } "xxx":"xxx" }
查询工作流实例信息:
GET https://118.31.xx.xx:2746/api/v1/workflows/argo/terraform-workflow-sqgjc-pgrcq
重新提交工作流实例:
PUT https://118.31.xx.xx:2746/api/v1/workflows/argo/terraform-workflow-sqgjc-pgrcq/resubmit
全量API说明:https://118.31.xx.xx:2746/apidocs
权限认证
为提升安全性,包括页面及API都需要开启权限认证。
执行下述代码,进行角色绑定并获取访问Token。
kubectl create sa sa-argo-server-admin -n argo kubectl create rolebinding rb-argo-server-admin -n argo --role=argo-server-role --serviceaccount=argo:sa-argo-server-admin SECRET=$(kubectl get sa sa-argo-server-admin -n argo -o=jsonpath='{.secrets[0].name}') ARGO_TOKEN="Bearer $(kubectl get secret $SECRET -n argo -o=jsonpath='{.data.token}' | base64 --decode)" echo $ARGO_TOKEN
重新部署argo-server,启用Token认证。将下述代码保存为argo-server.yaml,执行命令
kubectl apply -f argo-server.yaml
。apiVersion: apps/v1 kind: Deployment metadata: namespace: argo name: argo-server spec: selector: matchLabels: app: argo-server template: metadata: labels: app: argo-server spec: containers: - args: - server - --namespaced - --auth-mode - client image: quay.io/argoproj/argocli:latest name: argo-server ports: - containerPort: 2746 name: web readinessProbe: httpGet: path: / port: 2746 scheme: HTTPS initialDelaySeconds: 10 periodSeconds: 20 securityContext: capabilities: drop: - ALL volumeMounts: - mountPath: /tmp name: tmp nodeSelector: kubernetes.io/os: linux securityContext: runAsNonRoot: true serviceAccountName: argo-server volumes: - emptyDir: {} name: tmp
再次访问公网地址
https://118.31.xx.xx:2746/workflows
会提示需要权限认证。将之前生成的Token粘贴到Token对话框中然后登录。使用API会提示需要Token,将Token添加到请求Header中,添加方式见代码示例。
curl https://118.31.xx.xx:2746/api/v1/workflows/argo -k -H "Authorization: $ARGO_TOKEN"
故障排除
Argo Workflows FAQ
详情参见FAQ。
ACK集群异常
容器服务ACK应用故障排查
Pod停留在Pending状态表示该Pod不能被调度到任何一个节点上,通常是因为集群中缺乏需要的资源导致。您可以通过kubrctl describe pod命令查看事件和排查。具体操作,请参见Pod状态为Pending。
Pod停留在Waiting状态说明此Pod已经被调度到某个节点,但是却不能运行。通常是私有镜像、公网镜像拉取不成功或镜像地址不存在等问题导致。具体操作,请参见Pod状态为Wating。
Pod不断被拉起但状态为Crashing或者Unhealthy通常表示Pod已经完成调度并启动,但是启动失败,通常是由配置、权限等问题造成。您可以查看容器的日志,以诊断容器中应用程序出现的问题。具体操作,请参见Pod状态为Crash或者Unhealthy。
Pod状态为Running但是没有正常工作通常是由部署使用的YAML文件中存在的部分字段拼写错误造成的,您可以通过校验部署来进行故障排查。具体操作,请参见Pod状态为Running但是没正常工作。
Service无法正常工作在排除网络插件自身的问题外,最可能的是label配置有问题,您可以通过查看endpoints进行故障排查。具体操作,请参见检查Service。
排查故障的经典步骤与常见原因
ECS实例之间的互通是否有异常?具体操作,请参见ECS实例间ping不通的排查思路。
安全组是否配置有误?具体操作,请参见安全组FAQ。关于如何配置ECS安全组,请参见安全组应用指导和案例。
使用的RAM用户(即子账户)是否被正确授权?具体操作,请参见为RAM用户授权。
采用docker run的方式执行命令,确认运行环境是否正常?
当集群异常时,是否可以使用kubectl命令登录集群?执行kubectl get event命令是否有异常?具体操作,请参见通过kubectl工具连接集群。
在K8s里通过一个Pod去访问目标的Pod是否正常?具体操作,请参见Pod访问其他节点上的Pod异常。
通过Service方式访问应用是否正常?具体操作,请参见通过使用已有SLB的服务公开应用。
通过Ingress方式访问应用是否正常?具体操作,请参见通过ALB Ingress访问服务。
API Server、Scheduler或Controller日志是否有异常?
Docker Daemon日志是否有异常?如果报错信息提示docker daemon is not running,您只需要在cmd.exe中执行,开启守护进程即可。
如何通过查看日志排查故障?
您可以通过以下命令查询日志信息,排查分析故障:
查看事件:kubectl describe ****
Docker引擎日志:journalctl -u docker -f
Kubelet日志:journalctl -u kubelet -f
API Server日志:docker logs <api server container id>说明 该命令用于查看专有集群的API Server日志,如果是托管集群,具体操作,请参见收集托管集群控制平面组件日志。
Scheduler日志:docker logs <scheduler container id>
Worker proxy日志:docker logs <worker proxy container id>
Master proxy日志:docker logs <master proxy container id>
Controller日志:docker logs <controller container id>, <controller container id>涉及的组件包括kube-controller、alicloud-monitor-controller、alicloud-disk-controller和 cloud-controller。