Crossplane 是一个开源的 Kubernetes 插件,通过扩展 Kubernetes API 来解决云资源的供应问题。使用 Crossplane 时,你可以用声明的方式定义需要创建哪些云资源才能让你的应用程序正常工作,不需要编写任何代码。可以直接通过创建相关的 CRD 对象来完成这些云资源的定义,可以看成是一个云原生版本的 Terraform。
VCluster 是一个通过轻量级虚拟 Kubernetes 集群提供灵活性并节省成本的工具,使用 VCluster,你可以在 Kubernetes 集群内创建一个隔离的虚拟 Kubernetes 集群。这大大降低了创建和维护 Kubernetes 集群控制平面的复杂性。
下表比较了使用命名空间、vcluster 和 Kubernetes 集群的隔离级别和管理复杂性:
那么我们将 Crossplane 和 VCluster 这两个工具一起来结合时候会产生怎样的效果呢?接下来我们将通过一个示例来说明这二者的结合使用。
如上图所示,我们只需要创建一个 KinD 集群(当然也可以是其他任何的 Kuberentes 集群),然后在集群上安装 Crossplane 和 Crossplane Helm Provider,因为我们这里没有创建任何云资源,所以我们不需要配置任何其他的 Crossplane Provider(比如 GCP、AWS、Azure 等)。$ kind create cluster
Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.23.4) ?
✓ Preparing nodes ?
✓ Writing configuration ?
✓ Starting control-plane ?️
✓ Installing CNI ?
✓ Installing StorageClass ?
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community ?
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane,master 56s v1.23.4$ kubectl create ns crossplane-system
namespace/crossplane-system created
$ helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
NAME: crossplane
LAST DEPLOYED: Tue Aug 9 15:20:22 2022
NAMESPACE: crossplane-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Release: crossplane
Chart Name: crossplane
Chart Description: Crossplane is an open source Kubernetes add-on that enables platform teams to assemble infrastructure from multiple vendors, and expose higher level self-service APIs for application teams to consume.
Chart Version: 1.9.0
Chart Application Version: 1.9.0
Kube Version: v1.23.4$ kubectl get pods -n crossplane-system
NAME READY STATUS RESTARTS AGE
crossplane-c9b9fc9f9-4hn47 1/1 Running 0 11m
crossplane-rbac-manager-56c8ff5b65-8lgrp 1/1 Running 0 11m$ kubectl crossplane install provider crossplane/provider-helm:v0.10.0
provider.pkg.crossplane.io/crossplane-provider-helm created$ SA=$(kubectl -n crossplane-system get sa -o name | grep provider-helm | sed -e 's|serviceaccount\/|crossplane-system:|g')
$ echo $SA
crossplane-system:crossplane-provider-helm-3d2f09bcd965
$ kubectl create clusterrolebinding provider-helm-admin-binding --clusterrole cluster-admin --serviceaccount="${SA}"
clusterrolebinding.rbac.authorization.k8s.io/provider-helm-admin-binding created# helm-provider-config.yaml
apiVersion: helm.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: InjectedIdentity
---
# SA=$(kubectl -n crossplane-system get sa -o name | grep provider-helm | sed -e 's|serviceaccount\/|crossplane-system:|g')
# kubectl create clusterrolebinding provider-helm-admin-binding --clusterrole cluster-admin --serviceaccount="${SA}"$ kubectl apply -f helm-provider-config.yaml
providerconfig.helm.crossplane.io/default created
接下来我们来看下这是如何实现的,首先我们需要将 Crossplane Composition 和 Environment CRD 应用到我们的集群中来,这样我们就可以创建新的 Environment 资源了。首先定义一个 Environment 的组合资源,对应的资源清单如下所示,该对象相当于 Kubernetes 集群中的 CRD:# environment-resource-definition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: environments.fmtok8s.salaboy.com
spec:
group: fmtok8s.salaboy.com
names:
kind: Environment
plural: environments
claimNames:
kind: Cluster
plural: clusters
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties: {}# composition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: environment.fmtok8s.salaboy.com
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: fmtok8s.salaboy.com/v1alpha1
kind: Environment
resources:
- name: vcluster-helm-release
base:
apiVersion: helm.crossplane.io/v1beta1
kind: Release
metadata:
annotations:
crossplane.io/external-name: # patched
spec:
rollbackLimit: 3
forProvider:
namespace: # patched
chart:
name: vcluster
repository: https://charts.loft.sh
version: "0.10.2"
values:
syncer:
extraArgs: [] # patched
# - --out-kube-config-server=https://cluster-1.cluster-1.svc
providerConfigRef:
name: default
patches:
- fromFieldPath: metadata.name
toFieldPath: spec.forProvider.namespace
policy:
fromFieldPath: Required
- fromFieldPath: metadata.name
toFieldPath: metadata.annotations[crossplane.io/external-name]
policy:
fromFieldPath: Required
- fromFieldPath: metadata.name
toFieldPath: metadata.name
transforms:
- type: string
string:
fmt: "%s-vcluster"
- type: CombineFromComposite
combine:
variables:
- fromFieldPath: metadata.name
strategy: string
string:
fmt: "--out-kube-config-secret=%s-secret"
toFieldPath: spec.forProvider.values.syncer.extraArgs[0]
- type: CombineFromComposite
combine:
variables:
- fromFieldPath: metadata.name
- fromFieldPath: metadata.name
strategy: string
string:
fmt: "--out-kube-config-server=https://%s.%s.svc"
toFieldPath: spec.forProvider.values.syncer.extraArgs[1]
- type: CombineFromComposite
combine:
variables:
- fromFieldPath: metadata.name
- fromFieldPath: metadata.name
strategy: string
string:
fmt: "--tls-san=%s.%s.svc"
toFieldPath: spec.forProvider.values.syncer.extraArgs[2]
- name: helm-providerconfig
base:
apiVersion: helm.crossplane.io/v1alpha1
kind: ProviderConfig
spec:
credentials:
source: Secret
secretRef:
name: # patched
namespace: # patched
key: config
patches:
- fromFieldPath: metadata.name
toFieldPath: spec.credentials.secretRef.name
transforms:
- type: string
string:
fmt: vc-%s
- fromFieldPath: metadata.name
toFieldPath: spec.credentials.secretRef.namespace
- fromFieldPath: metadata.uid
toFieldPath: metadata.name
- name: helm-provider-vcluster
base:
apiVersion: helm.crossplane.io/v1beta1
kind: ProviderConfig
spec:
credentials:
source: Secret
secretRef:
namespace: #patched
key: config
patches:
- fromFieldPath: metadata.name
toFieldPath: metadata.name
- fromFieldPath: metadata.name
toFieldPath: spec.credentials.secretRef.namespace
policy:
fromFieldPath: Required
# This ProviderConfig uses the above VCluster's connection secret as
# its credentials secret.
- fromFieldPath: "metadata.name"
toFieldPath: spec.credentials.secretRef.name
transforms:
- type: string
string:
fmt: "%s-secret"
readinessChecks:
- type: None
- name: conference-chart-vcluster
base:
apiVersion: helm.crossplane.io/v1beta1
kind: Release
metadata:
annotations:
crossplane.io/external-name: conference
spec:
forProvider:
chart:
name: fmtok8s-conference-chart
repository: https://salaboy.github.io/helm/
version: "v0.1.1"
namespace: conference
providerConfigRef:
name: #patched
patches:
- fromFieldPath: metadata.name
toFieldPath: spec.providerConfigRef.name$ kubectl apply -f composition.yaml
composition.apiextensions.crossplane.io/environment.fmtok8s.salaboy.com created
$ kubectl apply -f environment-resource-definition.yaml
compositeresourcedefinition.apiextensions.crossplane.io/environments.fmtok8s.salaboy.com created$ vcluster list
NAME NAMESPACE STATUS CONNECTED CREATED AGE
No entries found# environment-resource.yaml
apiVersion: fmtok8s.salaboy.com/v1alpha1
kind: Environment
metadata:
name: dev-environment
spec: {}$ kubectl apply -f environment-resource.yaml
environment.fmtok8s.salaboy.com/dev-environment created
$ kubectl get environments
NAME READY COMPOSITION AGE
dev-environment False environment.fmtok8s.salaboy.com 57s
$ kubectl describe environments dev-environment
Name: dev-environment
Namespace:
Labels: crossplane.io/composite=dev-environment
Annotations: <none>
API Version: fmtok8s.salaboy.com/v1alpha1
Kind: Environment
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal PublishConnectionSecret 76s defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully published connection details
Normal SelectComposition 19s (x7 over 76s) defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully selected composition
Normal ComposeResources 18s (x7 over 76s) defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully composed resources$ vcluster list
NAME NAMESPACE STATUS CONNECTED CREATED AGE
dev-environment dev-environment Running 2022-08-09 17:44:07 +0800 CST 56m38s
一旦我们使用在 secret 中创建的正确 kubeconfig 创建了 VCluster,我们就可以配置第二个 Helm Provider 以将我们的应用程序安装到新创建的 VCluster 中,上面 composition 对象中第 95 行定义的 helm-provider-vcluster 就是该描述。然后在 composition 内部,我们配置使用了一个我们的会议应用的 Helm Chart 包。
配置完所有内容并创建新环境后,我们可以连接到 VCluster 并检查应用程序是否已安装:$ vcluster connect dev-environment --server https://localhost:8443 -- bash
The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
bash-3.2$ kubectl get ns
NAME STATUS AGE
default Active 32m
kube-system Active 32m
kube-public Active 32m
kube-node-lease Active 32m
conference Active 23m
bash-3.2$ kubectl get pods -n conference
NAME READY STATUS RESTARTS AGE
conference-fmtok8s-frontend-7cd5db8669-pv944 1/1 Running 0 23m
conference-fmtok8s-email-service-768bc88cbb-sklrg 1/1 Running 0 23m
conference-postgresql-0 1/1 Running 0 23m
conference-fmtok8s-c4p-service-7f56d7bd9d-2vjtx 1/1 Running 2 (19m ago) 23m
conference-redis-master-0 1/1 Running 0 23m
conference-redis-replicas-0 1/1 Running 0 23m
conference-fmtok8s-agenda-service-7db66c9568-xsh5m 1/1 Running 2 (16m ago) 23m$ kubectl get pods -n dev-environment
NAME READY STATUS RESTARTS AGE
conference-fmtok8s-agenda-service-7db66c9568-xsh5m-x-08f9332627 1/1 Running 2 (18m ago) 25m
conference-fmtok8s-c4p-service-7f56d7bd9d-2vjtx-x-co-fc2c58eaec 1/1 Running 2 (21m ago) 25m
conference-fmtok8s-email-service-768bc88cbb-sklrg-x--c5d9594434 1/1 Running 0 25m
conference-fmtok8s-frontend-7cd5db8669-pv944-x-confe-2832ac1bef 1/1 Running 0 25m
conference-postgresql-0-x-conference-x-dev-environment 1/1 Running 0 25m
conference-redis-master-0-x-conference-x-dev-environment 1/1 Running 0 25m
conference-redis-replicas-0-x-conference-x-dev-environment 1/1 Running 0 25m
coredns-76dd5485df-6cbl7-x-kube-system-x-dev-environment 1/1 Running 0 34m
dev-environment-0 2/2 Running 0 63m我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po