关于GitLab的CI/CD的实践具体分成如下的内容,其中(一)和(二)已经在上面一篇关于GitLab的CICD的实践一 GitLab的部署和配置篇中介绍完成了。
全系列目录:
(一)部署的架构
(二)GitLab的部署和配置
(三)基础架构的部署(本文)
(1) Amazon RDS 的创建
(2) Amazon EKS的创建
(四)应用架构的部署(本文)
(1) Amazon RDS 数据库中数据的部署
(2) Amazon EKS集群中应用的部署
???? 想要了解更多亚马逊云科技最新技术发布和实践创新,敬请关注2021亚马逊云科技中国峰会!点击图片报名吧~
在GitLab的部署和配置完成后,本篇将介绍(三)基础架构的部署和(四)应用架构的部署。GitLab 可以在代码仓库的根目录定义一个名为 .gitlab-ci.yml 的文件。这个文件是你定义你的CI/CD pipeline的地方。在开始创建和定义你的 .gitlab-ci.yml 之前,我们需要了解GitLab CI/CD中一些概念来描述和运行你的GitLab CI/CD pipeline。
(三)基础架构的部署
1)pipeline(流水线)
是持续集成、交付和部署的顶级组件。Pipeline由以下部分组成:
job(工作),它定义了要做什么。例如,编译或测试代码的工作。
stage(阶段),定义何时运行作业。例如,在编译代码的stage之后运行测试的stage。
使用stages来定义包含一组job,而stages又被定义在pipeline(流水线)中。在pipeline(流水线)中使用stage来定义某job是那个阶段的一部分。stage的顺序定义了作业的执行顺序。
job是由runner(运行器)执行的。如果有足够多的并发runner,同一stage的多个job可以并行执行。如果一个stage的所有job都成功了,pipeline就会进入下一个stage。如果一个stage中的任何job失败了,下一个stage就不会被执行,pipeline就会提前结束。一般来说,pipeline是自动执行的,一旦创建就不需要干预。然而,有些时候,你可以设定pipeline中的有些阶段是手动来执行,比如删除创建的资源。
例如如下示例中
此示例中定义了三个stages – compile,test,package,同一个stage(package)中的多个job(pack-gz, pack-iso)可以并行执行。
此示例为此次实践中创建Amazon EKS Cluster的流水线,其中也定义了三个stages – build,deploy,destroy,同一个stage的所有job都成功了,pipeline就会进入下一个stage。stage的顺序定义了作业的执行顺序。
Pipeline是GitLab中CI/CD的基本构建块。有三种主要方式来构建pipeline,每一种都有自己的优势。如果需要,这些方法可以混合使用。
Basic(基本型): 适合于简单的项目,所有的配置都在一个容易找到的地方。
Directed Acyclic Graph(有向无环图): 适合于需要高效执行的大型复杂项目。
Child/Parent(子/父流水线): 适合单体项目和有很多独立定义的组件的项目。本实践就是结合了 Child/Parent 和 Directed Acyclic Graph。
有向无环图流水线: 如果效率对你来说很重要,你希望所有的东西都能尽可能快地运行,你可以使用有向无环图(DAG)。使用needs关键字来定义job之间的依赖关系。当GitLab知道你的工作之间的关系时,它可以尽可能快地运行一切,甚至在可能的情况下跳过后续阶段。
# Parent gitlab-ci file, which trigger two CICD steps for AWS EKS cluster and RDS for mysql creation
# And it's also with two CICD steps for applications on EKS and data updating on RDS for mysql
stages:
- trigger-modules
# child gitlab pipeline for EKS cluster creation
EKS cluster creation:
stage: trigger-modules
trigger:
include: infra/eks-cluster/eks-gitlab-ci.yml
only:
changes:
- infra/eks-cluster/*
# child gitlab pipeline for RDS for mysql creation
RDS for mysql creation:
stage: trigger-modules
trigger:
include: infra/rdsmysql/rdsreal/rds-gitlab-ci.yml
only:
changes:
- infra/rdsmysql/*
- infra/rdsmysql/**/*
# child gitlab pipeline for data updating on RDS for mysql
RDS for app running:
stage: trigger-modules
trigger:
include: app/rds/app-rds-gitlab-ci.yml
only:
changes:
- app/rds/*
# child gitlab pipeline for applications on EKS
EKS for app running:
stage: trigger-modules
trigger:
include: app/eks/app-eks-gitlab-ci.yml
only:
changes:
- app/eks/*
子/父流水线: 上面是本实践中位于根目录中 .gitlab-ci.yml 文件的内容 ,通过 trigger 关键字来使用子/父流水线。它将GitLab CICD流水线配置分离成多个文件,使pipeline变得简单和利于理解。你也可以将其与以下内容结合起来。
rules 关键字。例如,只有指定目录的内容(代码)发生变化时,才会触发子流水线。如上实例中的only子句。
include 关键字。在指定具体的子流水线需要执行的文件。
2)CI/CD变量是环境变量的一种
你可以用它们来
(1) 控制作业和流水线的行为。
(2) 存储你想重复使用的值。
(3) 避免在你的.gitlab-ci.yml文件中的硬编码值。本实践,创建了全局环境变量和在project中的子gitlab-ci.yml文件中定义变量。
3)job artifact
job可以输出一个文件和目录的内容,这种输出被称为job artifact,你可以通过使用GitLab用户界面或API下载job artifact。
为了GitLab的CI/CD能正常的执行,在准备好了从Github上拉取的代码,并push到自建的GitLab上。以及配置GitLab 的环境,现在还需要设置环境变量,因为如下的GitLab CICD 子流水线使用了这些环境变量。
infra/eks-cluster/eks-gitlab-ci.yml
infra/rdsmysql/rdsreal/rds-gitlab-ci.yml
app/eks/app-eks-gitlab-ci.yml
这三个都使用如下的环境变量
- 'AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}'
- 'AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}'
- 'AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}'
app/rds/app-rds-gitlab-ci.yml
有如下的环境变量的需求
$DB_HOST_MASTER
$DB_USER_MASTER
$DB_PASSWORD_MASTER
$DB_SCHEMA
在GitLab设置全局环境变量,Menu-Admin-Settings-CICD-Variables-Add variable
按如上步骤创建好Amazon web sevieces AKSK 和 Amazon RDS 等环境变量。其中Amazon RDS的数据信息需要等到Amazon RDS for mysql创建好后在设置。最后的设置后的信息如下
在GitLab中的gitlabcicd project中有如下内容
1)目录(infra): 通过GitLab CICD和Terraform自动化的创建和部署亚马逊云科技Amazon EKS Cluster和Amazon RDS for Mysql. 偏基础设施的团队会更关注这一点.
2)目录(app): 再通过GitLab CICD结合Amazon EKS,Amazon ECR,Docker和Liquibase来达成应用系统的版本迭代和发布. 偏业务的团队会更关注这一块.
3)文件(.gitlab-ci.yml): GitLab CICD的主配置文件,来完成主要的CICD的逻辑调度工作.
4)文件(create_bucket.sh): 因为Terraform作为IaC的工具,需要通过状态文件了解Infrastructure状态,所以需要一个外置存储来存放此状态文件.此shell脚本是来创建Amazon S3存储桶和相应的Terraform的状态文件.
infra目录中包含Terraform代码用于自动化的创建Amazon EKS Cluster和Amazon RDS for Mysql.而Terraform是一个由HashiCorp创建的开源基础设施即代码(IaC)软件工具。用户使用被称为HashiCorp配置语言的声明性配置语言,或可选的JSON来定义和提供数据中心基础设施。更多关于Terraform的信息可以访问如下link:
https://learn.hashicorp.com/terraform?utm_source=terraform_io&utm_content=terraform_io_hero
使用Git将Terraform编写的IaC的代码提交到GitLab管理的代码仓库中,并做版本控制,另外结合GitLab CICD自动化的完成基础设施的部署。因为Terraform编写的IaC的代码不是本文的重点,所以不做过多讨论。如上面描述的因为Terraform作为IaC的工具,需要通过状态文件了解Infrastructure状态,而执行Terraform代码的executor(执行器)为docker,Terraform状态文件会随着docker生命周期结束而丢失。所以需要一个外置存储来存放此状态文件。shell脚本(create_bucket.sh)是来创建Amazon S3存储桶和相应的Terraform的状态文件。
# 在您的workstation/笔记本执行如下命令
cd ~
cd gitlabcicd
bash ./create_bucket.sh
aws s3 ls s3://jerry-terraform-states/
替换的Amazon S3桶名,可以使用如下命令替换:
sed -i ‘s/^Bucket_Name=\(.*\)/Bucket_Name=your_bucket_name/’ create_bucket.sh
根据代码仓库的根目录下 .gitlab-ci.yml 文件的定义,触发自动部署infra资源(Amazon EKS cluster,Amazon RDS),当然也包括其他相关资源,比如VPC,子网和安全组等。需要修改或添加如下指定位置中的文件并使用Git提交,进而来触发pipeline
编辑了上面两个目录中的README.md文件,再执行如下
git add .
git commit -m "push"
git push -u origin main
CICD-Pipelines查看触发的流水线和jobs
可以看到job已经顺利执行完成。
Amazon EKS集群创建完成后,Destroy stage,设置成为是手动执行,也就是说,如果你希望删除Amazon EKS集群,可以通过点击Destroy旁的播放按钮来触发。
同样Amazon RDS创建完成,Destroy也是可以手动执行的。
Amazon EKS集群和Amazon RDS创建完成后,有生成artifact,可以通过job页面下载
其实您也可以修改Amazon EKS和Amazon RDS的名称以及数据库user名称和密码,具体修改的位置如下。
Amazon EKS修改集群名称和VPC IP地址网段的位置:
infra/eks-cluster/vpc.tf
variable "general_name" {
default = "cicdeks"
description = "general name"
}
…
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.2.0"
name = local.vpc_name
cidr = "10.98.0.0/18"
azs = data.aws_availability_zones.available.names
private_subnets = ["10.98.1.0/24", "10.98.2.0/24", "10.98.3.0/24"]
public_subnets = ["10.98.4.0/24", "10.98.5.0/24", "10.98.6.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
…
RDS修改database名称和VPC IP地址网段的位置:
infra/rdsmysql/rdsreal/main.tf
variable "general_name" {
default = "cicdrds"
description = "general name"
}
...
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 2"
name = local.vpc_name
cidr = "10.99.0.0/18"
azs = ["${local.region}a", "${local.region}b", "${local.region}c"]
public_subnets = ["10.99.0.0/24", "10.99.1.0/24", "10.99.2.0/24"]
database_subnets = ["10.99.7.0/24", "10.99.8.0/24", "10.99.9.0/24"]
...
module "db" {
source = "../"
identifier = local.identifier
# All available versions: http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_MySQL.html#MySQL.Concepts.VersionMgmt
engine = "mysql"
engine_version = "8.0.20"
family = "mysql8.0" # DB parameter group
major_engine_version = "8.0" # DB option group
instance_class = "db.t3.large"
allocated_storage = 20
max_allocated_storage = 100
storage_encrypted = false
name = local.name
# you have to modify the username and password below
username = "your_db_user_name"
password = "your_db_user_password"
(四)应用架构的部署
在部署应用之前,我们可以通过如下步骤获得一些关于Amazon EKS cluster和Amazon RDS的信息
这两个artifact,一个是描述Amazon EKS集群的信息,一个描述Amazon RDS的信息。如果你更改了Amazon EKS集群或Amazon RDS的名称等信息,请记录下这些内容。修改GitLab全局环境变量:
DB_HOST_MASTER cicdrds-eoca.*******.rds.cn-northwest-1.amazonaws.com.cn
DB_USER_MASTER your_db_user_name
DB_PASSWORD_MASTER your_db_user_password
DB_SCHEMA cicdrds
另外,请按照你自己的设定修改app/eks/app-eks-gitlab-ci.yml
1)环境变量
特别是下图中的
CONTAINER_NAME,CONTAINER_IMAGE,ECR_STR,EKS_CLUSTER_PREFIX
2)build应用docker镜像
另外,在 app/eks/app-eks-gitlab-ci.yml 中已经定义了在docker作为executor(执行器),其中也包含了build应用为docker镜像,并推送到Amazon ECR的私有镜像仓库中,也包含了安装awscli,eksctl,kubectl工具,并创建kube config的步骤。
此处为build应用为docker镜像,并推送到Amazon ECR的私有镜像仓库中:
3)创建ingress
此处包含了安装awscli,eksctl,kubectl工具,并创建kube config的步骤,当然为了发布web服务,其中也包含了创建ingress的步骤。
4)发布应用
最终是通过yaml文件来部署应用,当然也可用通过helm来部署
而对于Amazon RDS数据库中内容的设定,使用了Liquibase作为数据库的版本控制,Liquibase作为一个数据库版本管理工具,它实现了(1)数据库升级, (2)数据库回滚, (3)版本标记。这样能很好的满足在业务系统发展的过程中,对数据库中表结构以及表数据的管理做到版本化。
它的几个核心概念:版本号,管理的数据,差异比较,版本回滚, 版本号由开发人员来维护,使用 author + id的格式。
Liquibase管理的数据最小单元为 changeSet,changeSet被包含在changelog中,changelog 是Liquibase版本控制的核心,Liquibase 通过有序的 changelog 罗列你对数据库的更改,就相当于你对数据变更的日志。Liquibase 使用这个变更日志来审计你的数据库,并执行任何还没有应用到目标数据库的变更操作。changelog支持5种格式来编写 — sql,xml,yaml,json,other 来编写。更多信息可以查看如下链接:
https://docs.liquibase.com/concepts/basic/home.html
因为我们使用Liquibase docker镜像作为executor(执行器),所不需要单独安装和部署,app/rds/app-rds-gitlab-ci.yml具体内容如下。
Liquibase docker镜像作为executor(执行器):
Liquibase执行数据库数据的变更:
我们通过修改 app/rds/README.md 和 app/eks/README.md 来触发应用架构的部署。
等Amazon EKS部署完测试的应用,在你的workstation执行如下命令
aws eks list-clusters
aws eks update-kubeconfig --name cicdeks-cluster-***
kubectl get ingress --all-namespaces
查看通过ingress暴露的测试应用
此时,你假如修改你的应用代码(例如app/eks/app.go),将触发新一轮的应用CICD,当然你也可以加入更多的test(单元测试和集成测试的内容)内容到app/eks/app-eks-gitlab-ci.yml中。
至此,整个关于GitLab的CICD的实践就完成了。在整篇博客中我们回顾的DevOps,CICD,GitOps的概念,同时又通过Git,GitLab结合Terraform, Liquibase, Amazon Elastic Kubernetes Service(Amazon EKS), Amazon Relational Database Service (Amazon RDS), Amazon Elastic Container Registry(Amazon ECR), Docker实践了CICD,在这里也是GitOps。很好的展现了基于GitLab的CICD的实践。
参考材料:
https://www.infoworld.com/article/3271126/what-is-cicd-continuous-integration-and-continuous-delivery-explained.html
https://blog.container-solutions.com/fluxcd-argocd-jenkins-x-gitops-tools
https://aws.amazon.com/devops/
https://about.gitlab.com/topics/gitops/
https://www.cloudbees.com/gitops/what-is-gitops
https://about.gitlab.com/is-it-any-good/
https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/
https://www.terraform.io/
https://www.liquibase.org/
https://www.amazonaws.cn/eks/?nc1=h_ls
https://www.amazonaws.cn/rds/?nc1=h_ls
https://www.amazonaws.cn/ecr/?nc1=h_ls
https://www.docker.com/https://helm.sh/
本篇作者
金钟敏
亚马逊云科技
解决方案架构师
现在专注于云计算解决方案和架构的工作
肖元君
亚马逊云科技
解决方案架构师
负责云计算方案的架构咨询和设计实现
听说,点完下面4个按钮
就不会碰到bug了!