随着Kubernetes继续将自己确立为容器编排的行业标准,为你的应用和工具找到使用声明式模型的有效方法是成功的关键。在这篇文章中,我们将在AWS中建立一个K3s Kubernetes集群,然后使用Argo CD和Vault实现安全的GitOps。你可以在以下两个链接中分别查看基础架构以及Kubernetes umbrella应用程序:
https://github.com/atoy3731/aws-k8s-terraform
https://github.com/atoy3731/k8s-tools-app
以下是我们将会使用到的组件:
- AWS——这是我们将在底层基础设施使用的云提供商。它将管理我们的虚拟机以及Kubernetes工作所需的网络,并允许Ingress从外界进入集群。
- K3s——由Rancher开发的轻量级Kubernetes发行版。它对许多alpha功能和云插件进行了清理,同时也使用关系型数据库(本例中是RDS)代替etcd进行后端存储。
- Rancher——API驱动的UI,可以轻松管理你的Kubernetes集群
- Vault——Hashicorp的密钥管理实现。我将使用Banzai Cloud Vault的bank-- vaults实现,它可以通过使用Admission Webhook将密钥直接注入pod中。这大大减轻了你在Git仓库中存储密钥的需求。
- Argo CD——这是一个GitOps工具,可以让你在Git中维护Kubernetes资源的状态。Argo CD会自动将你的Kubernetes资源与Git仓库中的资源进行同步,同时也确保集群内对manifest的手动更改会自动还原。这保证了你的声明式部署模式。
- Cert Manager或LetsEncrypt——提供了一种为Kubernetes Ingress自动生成和更新证书的方法。
让我们先从AWS基础架构开始。
前期准备
你需要在你的系统中安装以下CLI:
Terraform
Kubectl
AWS
同时,你还需要AWS管理员访问权限以及一个访问密钥。如果你没有,你可以使用信用卡创建一个账户。
最后,你需要一个可以管理/更新的托管域名,以指向你的基于Kubernetes弹性负载均衡器(ELB)。如果你还没有,建议你在NameCheap上开一个账户,然后购买一个.dev域名。它价格便宜,而且效果很好。
AWS基础架构
对于我们的AWS基础架构,我们将使用Terraform与S3支持来持久化状态。这为我们提供了一种方法来声明性地定义我们的基础架构,并在我们需要的时候反复进行更改。在基础设施仓库中,你会看到一个k3s/example.tfvars文件。我们需要根据我们特定的环境/使用情况更新这个文件,设置以下值:
db_username — 将应用于Kubernetes后端存储的RDS实例的管理员用户名
db_password — RDS用户的管理员密码。这通常应该在你的terraform apply命令内联过程中传递此参数,但为了简单起见,我们将在文件中设置它。
public_ssh_key — 你的公共SSH密钥,当你需要SSH到Kubernetes EC2s时,你将使用它。
keypair_name — 要应用于你的public_ssh_key的密钥对名称。
key_s3_bucket_name — 生成的bucket将在集群成功创建时存储你的kubeconfig文件。
如果你想修改集群大小或设置特定的CIDRs(无类域间路由),可以设置下面的一些可选字段,但默认情况下,你会得到一个6节点(3个服务器,3个代理)的K3s集群。
同时,你将需要创建S3 bucket来存储你的Terraform状态并且在k3s/backends/s3.tfvars和k3s/main.tf文件中更改bucket字段来与其匹配。
一旦我们更新了所有的字段,并创建了S3状态bucket,我们就开始应用Terraform吧。首先,确保你在AWS账户中有一个管理IAM用户并且你已经在系统上正确设置了环境变量或AWS凭证文件,以便能够与AWS API对接,然后运行以下命令:
cd k3s/
terraform init -backend-config=backends/s3.tfvars
terraform apply -var-file=example.tfvars
一旦你执行以上命令,Terraform会在apply成功后输出预期的AWS状态。如果一切看起来都符合预期,请输入yes。这时候由于RDS集群的原因,需要5—10分钟的时间来配置AWS资源。
验证你的Kubernetes集群
Terraform成功应用之后(再多等几分钟的时间确保K3s已经部署完毕),你需要使用以下命令从S3 bucket中抓取kubeconfig文件(替换你在example.tfvars
中输入的bucket名称):
aws s3 cp s3://YOUR_BUCKET_NAME/k3s.yaml ~/.kube/config
这应该成功完成,让你现在能够与你的集群通信。让我们检查一下我们的节点状态,在继续之前,确保它们都处于就绪状态。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-10-0-1-208.ec2.internal Ready 39m v1.18.9+k3s1
ip-10-0-1-12.ec2.internal Ready master 39m v1.18.9+k3s1
ip-10-0-1-191.ec2.internal Ready master 39m v1.18.9+k3s1
ip-10-0-2-12.ec2.internal Ready master 39m v1.18.9+k3s1
ip-10-0-2-204.ec2.internal Ready 39m v1.18.9+k3s1
ip-10-0-1-169.ec2.internal Ready 39m v1.18.9+k3s1
我们也来看看Argo CD的状态,它是通过manifest自动部署的:
$ kubectl get pods -n kube-system | grep argocd
helm-install-argocd-5jc9s 0/1 Completed 1 40m
argocd-redis-774b4b475c-8v9s8 1/1 Running 0 40m
argocd-dex-server-6ff57ff5fd-62v9b 1/1 Running 0 40m
argocd-server-5bf58444b4-mpvht 1/1 Running 0 40m
argocd-repo-server-6d456ddf8f-h9gvd 1/1 Running 0 40m
argocd-application-controller-67c7856685-qm9hm 1/1 Running 0 40m
现在我们可以继续为我们的ingress和证书自动化配置通配符DNS。
DNS配置
对于DNS,我通过Namecheap获得atoy.dev域名,但你可以使用任何你喜欢的DNS供应商。我们需要做的是创建一个通配符CNAME条目,以将所有请求路由到AWS ELB,它正在管理应用程序的ingress。
首先,通过访问你的AWS控制台获取你的弹性负载均衡器主机名称——导航到EC2部分并在左边菜单栏上点击Load Balancers。然后你应该看到一个使用随机字符创建的新LoadBalancer。如果你检查tag,它应该引用你的新Kubernetes集群。
你需要从该条目复制DNS名称。为我的域名访问NamecCheap 高级DNS页面,并输入.demo.atoy.dev* 的CNAME条目。** 指向你从AWS复制的域名。你可以根据你的提供商/域名调整这个名称:
要验证它是否有效,你可以安装/使用nslookup来确保它解析到正确的主机名:
$ nslookup test.demo.atoy.dev
Server: 71.252.0.12
Address: 71.252.0.12#53
Non-authoritative answer:
test.demo.atoy.dev canonical name = a4c6dfd75b47a4b1cb85fbccb390fe1f-529310843.us-east-1.elb.amazonaws.com.
Name: a4c6dfd75b47a4b1cb85fbccb390fe1f-529310843.us-east-1.elb.amazonaws.com
Address: 52.20.5.150
Name: a4c6dfd75b47a4b1cb85fbccb390fe1f-529310843.us-east-1.elb.amazonaws.com
Address: 23.20.0.2
现在到Umbrella应用程序。
Argo CD和Umbrella应用程序
我们已经知道Argo CD已经部署好了,但现在我们要使用Argo CD的App-of-Apps部署模型来部署我们的其余工具套件。由于我们使用的是GitOps,你需要将k8s-tools-app仓库fork到你自己的Github账户上,然后我们需要做一些修改来匹配你各自的环境。
- 你需要为https://github.com/atoy3731/k8s-tools-app.git 进行全局查找/替换,并将其更改到之前fork的新存储库git URL。这使你可以管理自己的环境,让Argo CD可以从那里拉取。另外,需要确保你的Git仓库是公开的,以便Argo CD可以访问它。
- 在resources/tools/resources/other-resources.yaml中,更改argoHostand issuerEmail,使其与你的域名和邮箱相匹配。
- 在resources/tools/resources/rancher.yaml中,更改主机名称和邮件以匹配各自的域名和email。
- 在resources/apps/resources/hello-world.yaml中,将两个引用app.demo.aptoy.dev改为与你的域名一致。
一旦你做了这些更新,继续提交/推送你的更改到你的forked Github仓库。现在你已经准备好应用umbrella应用程序了。在本地克隆的仓库中执行以下操作:
$ kubectl apply -f umbrella-tools.yaml
appproject.argoproj.io/tools created
application.argoproj.io/umbrella-tools created
现在,Argo CD将开始配置所有其他工具,这些工具是仓库为你的集群定义的。你可以通过执行以下操作来获得已部署的应用程序的列表:
$ kubectl get applications -n kube-system
NAME AGE
other-resources 56m
umbrella-tools 58m
rancher 57m
vault-impl 57m
vault-operator 58m
vault-webhook 57m
cert-manager 57m
cert-manager-crds 58m
你将不得不等待5分钟左右的时间,让一切都准备好,让LetsEncrypt生成暂存证书。一旦事情按预期运行,你应该看到两个生成的Ingress条目,你可以通过浏览器访问:
$ kubectl get ingress -A
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
cattle-system rancher rancher.demo.atoy.dev a4c6dfd75b47a4b1cb85fbccb390fe1f-529310843.us-east-1.elb.amazonaws.com 80, 443 59m
kube-system argocd-ingress argo.demo.atoy.dev a4c6dfd75b47a4b1cb85fbccb390fe1f-529310843.us-east-1.elb.amazonaws.com 80, 443 58m
现在你可以通过 https://rancher.YOUR-DOMAIN 浏览 Rancher,通过 https://argo.YOUR-DOMAIN 浏览 Argo CD。
NOTE 1:为了避免LetsEncrypt的任何速率限制,我们使用的是无效的暂存证书。这有一个好处是当你在你的浏览器访问Argo、Rancher或你的hello world应用程序,它会给你一个SSL异常。使用Chrome浏览器,在你的异常页面加载时输入thisisunsafe,它会让你绕过它。你也可以了解更新Cert-manager的ClusterIssuer,以使用生产级的可信证书。
NOTE 2:K3s预装了一个Traefik作为ingress controller,出于简单起见,我们直接使用它。
NOTE 3:首次登录Rancher后,你需要生成一个密码,并接受用于访问Rancher的URI。URI应该是预先加载在表单中的,所以您可以直接点击 "Okay"。
NOTE 4: 要登录Argo CD,它使用admin作为用户名,使用argocd-server pod名作为密码。你可以通过下面的操作来获得这个服务器的pod名(本例中是argocd-server-5bf58444b4-mpvht)。
$ kubectl get pods -n kube-system | grep argocd-server
argocd-server-5bf58444b4-mpvht 1/1 Running 0 64m
现在你应该能够访问Argo CD UI,登录并查看,如下所示:
既然我们的工具已经部署完成,让我们在Vault中存储密钥,以便hello world应用程序提取。
在Vault中创建密钥
为了让事情变得简单,在你的工具库中有一个帮助脚本。运行以下命令来获取Vault管理员令牌和端口转发命令:
$ sh tools/vault-config.sh
Your Vault root token is: s.qEl4Ftr4DR61dmbH3umRaXP0
Run the following:
export VAULT_TOKEN=s.qEl4Ftr4DR61dmbH3umRaXP0
export VAULT_CACERT=/Users/adam.toy/.vault-ca.crt
kubectl port-forward -n vault service/vault 8200 &
You will then be able to access Vault in your browser at: [https://localhost:8200](https://localhost:8200)
运行输出的命令,然后导航到https://localhost:8200。输入上面的root token进行登录。
当你登录时,你应该在一个密钥引擎页面。点击Secret/条目,然后点击右上方的创建密钥。我们将创建一个demo密钥,所以添加以下内容并点击保存:
现在我们已经为hello world应用程序准备好密钥了。
部署Hello World 应用程序
现在,回到我们的父版本,让我们运行下面的代码来部署hello world应用程序:
$ kubectl apply -f umbrella-apps.yaml
appproject.argoproj.io/apps created
application.argoproj.io/umbrella-apps created
创建完成后,回到Argo CD UI,你先应该看到两个新应用程序,umbrella-apps和demo-app。单击demo-app,然后等待所有资源正常运行:
一旦状态都是healthy之后,你应该能够通过访问https://app.YOUR-DOMAIN 导航到你的应用程序。
让我们也来验证一下我们的Vault密钥是否被注入到我们的应用程序pod中。在Argo CD UI的demo-app中,点击应用程序的一个Pod,然后点击顶部的日志标签。左边应该有两个容器,选择 test-deployment容器。在日志的顶部,你应该看到你的密钥在两行等号之间:
测试GitOps
现在我们来测试一下Argo CD,确保当我们在仓库中做一些更改时它能够自动同步。
在你的工具库中,找到resources/apps/resources/hello-world.yaml文件,将replicaCount的值从5改到10。提交并推送你的更改到主分支,然后在Argo CD UI中导航回demo-app。当Argo CD达到它的刷新间隔时,它会自动开始部署其他5个应用程序副本(如果你不想等待,可以点击你的** umbrella-apps ** Argo应用程序 ** 中的刷新按钮):
清 除
如果你准备拆掉你的集群,你需要先进入AWS控制台、EC2服务,然后点击Load Balancers。你会看到Kubernetes云提供商创建了一个ELB,但不是由Terraform管理的,你需要清理它。你还需要删除该ELB正在使用的安全组。
清理了ELB之后,运行以下命令并在出现提示时输入yes:
terraform destroy -var-file=example.tfvars
下一步是什么?
我们已经有一个很好的工具集来使用GitOps部署应用程序。那么下一步是什么?如果你愿意接受挑战,可以尝试在hello world应用旁边部署自己的应用,甚至尝试通过在应用manifest仓库中更新镜像标签来实现CI/CD。这样一来,当构建新的应用镜像时,新的标签就会在manifest仓库中自动更新,Argo CD就会部署新版本。