原创 吴就业 202 0 2023-07-23
本文为博主原创文章,未经博主允许不得转载。
本文链接:https://wujiuye.com/article/042fd776438b4264a0533092d880c667
作者:吴就业
链接:https://wujiuye.com/article/042fd776438b4264a0533092d880c667
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。
摸索期,肯定会遇到很多问题,有些问题可以通过日记查看,而有些问题可能需要修改源码,添加一些用于排查问题的代码。
例如,由于job中的容器执行完命令后就退出了,没办法通过exec -it
命令进入容器查看当时的/data
目录下执行的main.tf代码文件,也看不到当时的环境变量,可以修改源码给job加一条命令,用来查问题。
将源码克隆下来后,卸载kubevela已经安装的terraform controller,然后本地debug启动terraform controller。
vela addon disable terraform
由于terraform的每个版本几乎都会修改tf协议,使用高版本特性编写的tf文件,需要高版本的terraform去解析执行,所以我们可能需要修改Terraform controller使用的oamdev/docker-terraform
镜像的版本。
从Terraform controller工作原理我们了解到,Terraform controller是以启动一个Job容器的方式去执行terraform命令申请/删除资源,Job的容器镜像里面安装了terraform引擎,这个镜像就是oamdev/docker-terraform
,镜像的不同版本安装的是不同的terraform版本。
假设我们现在需要修改Terraform controller使用latest版本的oamdev/docker-terraform
镜像,应该怎么修改。
从Terraform controller源码ConfigurationReconciler类可以找到,terraform镜像可以从环境变量“TERRAFORM_IMAGE”取,而Terraform controller会打包成helm chart,通过查看helm chart的terraform_controller.yaml文件,发现controller pod配置了“TERRAFORM_IMAGE”环境变量,值会通过“ .Values.terraformImage”
取。现在我们知道可以通过在安装chart的时候指定terraformImage变量值为:“oamdev/docker-terraform:latest”
,就可以修改terraform镜像版本为latest。
而kubevela是以addon的方式安装Terraform controller的,所以我们可以在执行vela addon enable terraform
命令的时候指定terraformImage变量值为“oamdev/docker-terraform:latest”
。
但是通过命令指定很容易忘记,如何将“oamdev/docker-terraform:latest”
配置为terraformImage的默认值呢。
以从本地安装terraform插件为例。
我们需要下载catalog仓库,修改addons/terraform
下的resources/parameter.cue
文件,在这个文件中配置terraformImage。
parameter: {
values: #values
}
#values: {
terraformImage: *"oamdev/docker-terraform:latest" | string
}
修改完保存后,再从本地重新安装Terraform controller。
先禁用已经安装的Terraform controller。
vela addon disable terraform
再从本地安装Terraform controller。
vela addon enable ~/kubevela/catalog/addons/terraform --override-definitions
要删除已有的Job,让terraform controller重新拉起Job才会生效。
Configuration是terraform-controller提供的一种自定义资源,用于配置terraform代码。支持通过hcl字段直接配置terraform代码,也支持通过remote字段配置为通过git协议从远程仓库拉取。
Configuration不会直接暴露给kubevela的用户,而是kubevela terraform provider插件的开发者,然后由kubevela terraform provider插件开发者定义为ComponentDefinition提供给kubevela用户使用。
因此,通过hcl方式使用会导致一但terraform有变更,就需要插件重新生成ComponentDefinition,这很麻烦。
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for AWS S3
creationTimestamp: null
labels:
type: terraform
name: aws-s3
namespace: vela-system
spec:
schematic:
terraform:
configuration: |
resource "aws_s3_bucket" "bucket-acl" {
bucket = var.bucket
acl = var.acl
}
output "BUCKET_NAME" {
value = aws_s3_bucket.bucket-acl.bucket_domain_name
}
variable "bucket" {
description = "S3 bucket name"
default = "vela-website"
type = string
}
variable "acl" {
description = "S3 bucket ACL"
default = "private"
type = string
}
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
status: {}
因此我们更倾向于通过使用git仓库的方式,而官方文档只介绍了如何使用公开的github仓库,我们想要的是指向gitlab私有仓库。
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud Elastic
IP
creationTimestamp: null
labels:
type: terraform
name: alibaba-eip
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/oam-dev/terraform-alibaba-eip.git
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
status: {}
这就要研究terraform-controller是否支持配置ssh从私有仓库拉取代码。
从controllers/configuration_controller.go:811 assembleTerraformJob方法中找到了答案。
terraform-controller启动一个Job执行terraform代码,一共会启动四个容器执行四条命令:
一、初始化容器1
初始化容器1负责将ConfigMap挂盘的文件(/opt/tf-configuration/*
)拷贝到/data
目录下。
当使用hcl,ConfigMap的内容如下。(/opt/tf-configuration/
目录下有kubeconfig和main.tf两个文件)
```yaml
apiVersion: v1
kind: ConfigMap
data:
kubeconfig: ''
main.tf: |
${tf代码}
terraform {
backend "kubernetes" {
secret_suffix = "${component_name}"
in_cluster_config = true
namespace = "${namespace}"
}
}
```
当使用remote,ConfigMap的内容如下。(/opt/tf-configuration/
目录下有kubeconfig和terraform-backend.tf两个文件)
```yaml
apiVersion: v1
kind: ConfigMap
data:
kubeconfig: ''
terraform-backend.tf: |
terraform {
backend "kubernetes" {
secret_suffix = "${component_name}"
in_cluster_config = true
namespace = "${namespace}"
}
}
```
二、初始化容器2(如果配置了remote)
如果配置了remote,则controller会创建初始化容器2用来则执行git clone
命令拉取代码。
流程:
1. 如果配置了Git Secret引用,会将Secret挂盘到/root/.ssh
目录下,挂盘后会生成两个文件(两个key),即ssh-privatekey和known_hosts。
2. 执行eval ssh-agent && ssh-add
命令,将ssh-privatekey添加到ssh-agent。
3. 执行git clone
命令拉取代码。
三、初始化容器3:执行terraform init
命令,初始化拉取代码中指定的terraform provider插件。
四、执行容器:负责执行terraform apply -auto-approve
命令。
第三、四条命令都会给容器注入一些环境变量:
因此,使用私有仓库,只需要配置Configuration的remote、gitCredentialsSecretReference、path(可选),但是,因为我们不是直接用terraform-controller的,不能直接创建一个Configuration资源,那么kubevela的ComponentDefinition是否支持?
kubevela源码的charts/vela-core/crds
目录下的core.oam.dev_componentdefinitions.yaml
文件,就是kubevela的ComponentDefinition资源的定义文件,我找到了关于terraform部分的properties定义:
terraform:
description: >-
Terraform is the struct to describe cloud resources managed by Hashicorp
Terraform
properties:
configuration:
description: Configuration is Terraform Configuration
type: string
customRegion:
description: >-
Region is cloud provider's region. It will override the region in the
region field of ProviderReference
type: string
deleteResource:
default: true
description: >-
DeleteResource will determine whether provisioned cloud resources will
be deleted when CR is deleted
type: boolean
gitCredentialsSecretReference:
description: >-
GitCredentialsSecretReference specifies the reference to the secret
containing the git credentials
properties:
name:
description: name is unique within a namespace to reference a secret resource.
type: string
namespace:
description: >-
namespace defines the space within which the secret name must be
unique.
type: string
type: object
x-kubernetes-map-type: atomic
path:
description: >-
Path is the sub-directory of remote git repository. It's valid when
remote is set
type: string
providerRef:
description: ProviderReference specifies the reference to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the referenced object.
type: string
required:
- name
type: object
type:
default: hcl
description: 'Type specifies which Terraform configuration it is, HCL or JSON syntax'
enum:
- hcl
- json
- remote
type: string
writeConnectionSecretToRef:
description: >-
WriteConnectionSecretToReference specifies the namespace and name of a
Secret to which any connection details for this managed resource should
be written. Connection details frequently include the endpoint,
username, and password required to connect to the managed resource.
properties:
name:
description: Name of the secret.
type: string
namespace:
description: Namespace of the secret.
type: string
required:
- name
type: object
required:
- configuration
type: object
从源码得到结论:是支持使用gitCredentialsSecretReference的,只是kubevela提供的vela def init
命令不支持指定gitCredentialsSecretReference,所以我们用命令生成云资源的ComponentDefinition后,还需要手动加上gitCredentialsSecretReference。
首先我们在k8s集群中创建包含ssh-privatekey和known_hosts的Secret资源。
这里使用个人账号举例:
使用“kubectl create secret generic”命令创建:
kubectl create secret generic wjy-github-ssh-key-secret --from-file=ssh-privatekey=/Users/wujiuye/.ssh/id_rsa --from-file=known_hosts=/Users/wujiuye/.ssh/known_hosts -n vela-system
然后我们就可以使用remote生成资源的ComponentDefinition了。
我们可以用vela def
命令来生成一个模版,也可以直接copy现有一个模版来修改:
vela def init vpc --type component --provider mycloud --desc "Terraform configuration for Mycloud VPC" --git [email protected]:wujiuye/terraform-mycloud-modules.git --path=vpc
修改生成的vpc ComponentDefinition,添加gitCredentialsSecretReference配置:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Mycloud VPC
creationTimestamp: null
labels:
type: terraform
name: mycloud-vpc
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/wujiuye/terraform-mycloud-modules.git
path: vpc
type: remote
gitCredentialsSecretReference:
name: wjy-github-ssh-key-secret
namespace: vela-system
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta2
kind: Configuration
status: {}
重新覆盖安装一下自定义的terraform-mycloud插件。
vela addon enable ~/kubevela/catalog/addons/terraform-mycloud --override-definitions
~/kubevela/catalog/addons/terraform-mycloud为本地terraform-mycloud插件的目录
使用vela show mycloud-vpc --web
命令验证组件是否apply成功。
这种方式并不高效,如果组件非常多的话,可以写一个组件生成器,通过模板生成组件。
可能会遇到invalid auth method问题,此报错是kubevela验证这个ComponentDefinition报的错,无法从远程拉取代码。原因是URL不能以https开头,需要将https://github.com/wujiuye/terraform-mycloud-modules.git
改成[email protected]:wujiuye/terraform-mycloud-modules.git
。
先为mycloud创建一个Provider资源,其实就是创建访问mycloud terraform provider的Secret资源以及terraform controller的Provider资源。
需要准备: - ENDPOINT - TOKEN
替换下面命令中的参数,然后secret的name和provider的name可以自己指定,用于创建kubevela terraform-controller的Provider资源:
vela config create mycloud-office-admin-secret -t terraform-mycloud ENDPOINT="http://127.0.0.1:8080" TOKEN="xxxx" name=mycloud-office-admin-provider
输出“the config mycloud-office-admin-secret applied successfully”表示配置创建成功。
输出的“mycloud-office-admin-secret”为Secret资源的名称,由名为“mycloud-office-admin-provider”的Provider引用。
验证:
kubectl get provider
输出:
NAME STATE AGE
mycloud-office-admin-provider ready 9s
现在我们编写一个application验证一下组件。
[test-app-vpc.yaml]
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: test-app
spec:
components:
- name: test-app-vpc
type: mycloud-vpc
properties:
name: test-app-vpc-123456789
ip_capacity: 32
providerRef:
name: mycloud-office-admin-provider
namespace: default
writeConnectionSecretToRef:
name: test-app-vpc-output-secret
namespace: default
执行命令apply验证创建:
vela up -f test-app-vpc.yaml
可能会遇到问题:failed for volume “git-auth-configuration”: secret “xxx” not found
MountVolume.SetUp faild for volume "git-auto-configuration" : secret "wjy-github-ssh-key-secret" not found
分析源码后发现,k8s约束了给pod挂盘ConfigMap或者Secret必须是跟pod在同一个namespace下。也就是我们创建的Secret,必须跟terraform controller创建的Job资源在同一个namespace。以及组件的providerRef、writeConnectionSecretToRef引用的资源,也必须跟terraform controller创建的Job资源在同一个namespace。
terraform controller创建的Job资源使用的默认namespace是default,可以将git Secret资源创建在default这个namespace下。
kubectl create secret generic wjy-github-ssh-key-secret --from-file=ssh-privatekey=/Users/wujiuye/.ssh/id_rsa --from-file=known_hosts=/Users/wujiuye/.ssh/known_hosts -n default
实际是修改terraform controller的部署namespace。
假设我们需要将terraform controller部署在vela-system。
如果是本地debug,启动参数配置controller-namespace,指定namespace为vela-system。
如果是通过vela addon安装terraform插件,可通过addon命令指定controllerNamespace=vela-system。
ComponentDefinition:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Mycloud VPC
creationTimestamp: null
labels:
type: terraform
name: mycloud-vpc
namespace: vela-system
spec:
schematic:
terraform:
configuration: [email protected]:wujiuye/terraform-mycloud-modules.git
path: vpc
type: remote
gitCredentialsSecretReference:
name: wjy-github-ssh-key-secret
namespace: default
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta2
kind: Configuration
status: {}
使用:
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: test-app
spec:
components:
- name: test-app-vpc
type: mycloud-vpc
properties:
name: test-app-vpc-123456789
ip_capacity: 32
providerRef:
name: mycloud-office-admin-provider
namespace: default
writeConnectionSecretToRef:
name: test-app-vpc-output-secret
namespace: default
声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。
官方提供的工作流步骤有限,另外,对于自研的PaaS平台,我们需要借助工作流步骤实现一些例如存量项目基础设施导入、项目环境初始化、平台组件共享基础设施需要解决的差异对比审核、基础设施漂移等。
我们基于KubeVela开发的云原生应用交付平台,提供如初始化基础设施导入、中间件部署共用基础设施等相关能力的测试,需要依赖基础设施。虽然terraform是面向公司内部的混合云平台,但是测试都要跨部门配置效率太低了,而且这种模式无法支持持续测试。
terraformProvider、multiclusterProvider、oamProvider、configprovider、kube这些provider的Install方法注册了很多操作处理方法。这些方法就是提供给CUE中调用的方法。
kubevela安装一个Application的过程,就是执行工作流上的每个步骤的过程,并且当我们未配置工作流,kubevela会自动为组件的部署生成一个工作流步骤。
erraform-controller是一个专门负责terraform一类的组件"安装"的Operator,通过打包成helm,再封装成kubevela的Addon,由kubevela安装到管控集群,为其它terraform provider插件提供模块定义支持。
订阅
订阅新文章发布通知吧,不错过精彩内容!
输入邮箱,提交后我们会给您发送一封邮件,您需点击邮件中的链接完成订阅设置。