作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Gaurav有12年以上的开发经验, scrum master, senior consultant, and product owner.
在当今的互联网世界里,几乎所有的东西都需要全天候运行,可靠性是关键. 这意味着您的网站接近零停机时间, 避开可怕的“Not found: 404”错误页面, 或者在推出最新版本时出现其他服务中断.
假设您已经为客户机构建了一个新的应用程序, or maybe yourself, 并设法获得一个喜欢你的应用程序的良好用户基础. 你已经收集了用户的反馈, 你去找你的开发人员,让他们构建新的功能,让应用程序为部署做好准备. With that ready, 您可以停止整个应用程序并部署新版本,也可以构建一个零停机CI/CD部署管道,它将完成向用户推送新版本的所有繁琐工作,而无需人工干预.
In this article, 我们将具体讨论后者, 我们如何在Node中构建一个三层web应用程序的持续部署管道.使用Terraform作为基础设施编排器. We’ll be using Jenkins 用于持续部署部分和Bitbucket托管我们的代码库.
我们将使用一个演示的三层web应用程序,你可以找到它的代码 here.
repo包含了web层和API层的代码. 这是一个简单的应用程序,其中web模块调用API层中的一个端点,该端点内部从数据库中获取有关当前时间的信息并返回给web层.
回购的结构如下:
现在我们了解了需要部署的内容, 让我们先讨论一下在AWS上部署这个应用程序需要做的事情,然后再讨论如何使它成为CI/CD管道的一部分.
因为我们正在使用Terraform作为基础设施编排器, 为想要部署的每个层或应用程序都预置映像是最有意义的. 为此,我们将使用hashicorp的另一种产品——Packer.
Packer是一个开源工具,可以帮助构建Amazon Machine Image (AMI), 哪些将用于在AWS上部署. 它可以用于为不同的平台(如EC2、VirtualBox、VMware等)构建映像.
以下是Packer配置文件(起程拓殖/ packer-ami-api.json
)用于为API层创建AMI.
{
"builders": [{
“类型”:“amazon-ebs”,
“地区”:“一来”,
“source_ami”:“ami - 844 e0bf7”,
:“instance_type t2.micro",
“ssh_username”:“ubuntu”,
"ami_name": "api-instance {{timestamp}}"
}],
"provisioners": [
{
"type": "shell",
"inline": ["mkdir api", "sudo apt-get update", "sudo apt-get -y install NPM nodejs-legacy"],
“pause_before”:“10”
},
{
"type": "file",
"source" : "../api/",
"destination": "api"
},
{
"type": "shell",
"inline": ["cd api", "npm install"],
“pause_before”:“10”
}
]
}
需要运行以下命令来创建AMI:
Packer build -machine-readable Packer -ami-api.json
我们将在本文后面的Jenkins构建中运行这个命令. 类似地,我们将使用Packer配置文件(起程拓殖/ packer-ami-web.json
),也适用于web层.
让我们浏览一下上面的Packer配置文件,并了解它试图做什么.
inline
属性,它是要运行的一组命令.So, in essence, Packer配置包含有关您想要的构建器的信息,然后是一组提供程序,您可以根据希望如何配置映像以任何顺序定义这些提供程序.
接下来,我们将研究如何设置用于CI/CD管道的Jenkins服务器. 我们也将使用Terraform和AWS进行设置.
用于设置Jenkins的Terraform代码在文件夹中 jenkins/setup
. 让我们来看看关于这个设置的一些有趣的事情.
instance.tf
),也可以将凭据文件的位置提供给属性 shared_credentials_file
in the AWS provider.iam.tf
),使用它我们将创建一个Jenkins实例.backend.tf
), 你可以把它维持在那里, 这样你就可以和其他同事合作了, 任何人都可以更改和部署,因为状态是在远程位置维护的.aws_key_pair
resource (key.tf
),其中使用Terraform变量指定公钥的位置.设置Jenkins的步骤:
Step 1: 为了保持Terraform的远程状态, 您需要在S3中手动创建一个bucket,供Terraform使用. 这将是在terrraform之外完成的唯一步骤. Make sure you run AWS configure
然后运行下面的命令来指定您的AWS凭证.
aws s3api create-bucket——bucket node-aws-jenkins-terraform——region eu-west-1——create-bucket-configuration LocationConstraint=eu-west-1
Step 2: Run terraform init
. 这将初始化状态并将其配置为存储在S3上,并下载AWS提供商插件.
Step 3: Run terraform apply
. 这将检查所有Terraform代码并创建一个计划,并显示在此步骤完成后将创建多少资源.
Step 4: Type yes
,然后上一步将开始创建所有资源. 命令执行完毕后,您将获得Jenkins服务器的公共IP地址.
Step 5: 使用您的私钥Ssh到Jenkins服务器. ubuntu
是AWS ebs支持实例的默认用户名吗. 返回的IP地址 terraform apply
command.
SSH -i mykey ubuntu@34.245.4.73
Step 6: 执行以下命令启动Jenkins web UI http://34.245.4.73:8080
. 密码可在 /var/lib/jenkins/secrets/initialAdminPassword
.
Step 7: 选择“安装建议的插件”并为Jenkins创建一个Admin用户.
echo 'variable "WEB_INSTANCE_AMI" { default = "'${AMI_ID_WEB}'" }' > amivar_web.tf
Aws s3 cp amivar_web.tf s3: / / node-aws-jenkins-terraform / amivar_web.tf
现在我们有了API和web模块的ami, 我们将触发一个构建来运行Terraform代码来设置整个应用程序,然后遍历Terraform代码中的组件,这使得该管道在零服务停机的情况下部署更改.
nodejs-terraform
,这将运行Terraform代码来部署应用程序.amivar_api.tf
and amivar_web.tf
),然后运行Terraform代码,在AWS上构建整个应用程序.
如果一切配置正确, 现在,如果您将任何代码推送到Bitbucket存储库, 它应该触发第一个Jenkins项目,然后是第二个项目,您应该将应用程序部署到AWS上.
现在让我们讨论一下terrform代码中是什么使这个管道零停机地部署代码.
首先,Terraform提供了这些 生命周期配置模块 for resources 你有一个选择 create_before_destroy
作为一个标志,字面意思是terrraform应该在破坏当前资源之前创建一个相同类型的新资源.
现在我们在 aws_autoscaling_group
and aws_launch_configuration
resources. So aws_launch_configuration
配置应该供应哪种类型的EC2实例,以及如何在该实例上安装软件, and the aws_autoscaling_group
资源提供AWS自动伸缩组.
这里有一个有趣的问题,Terraform中的所有资源都应该有一个唯一的名称和类型组合. 所以除非你给新的起个不同的名字 aws_autoscaling_group
and aws_launch_configuration
,就不可能摧毁现在的那个.
Terraform通过提供 name_prefix
property to the aws_launch_configuration
resource. 一旦这个属性被定义,Terraform将添加一个唯一的后缀到所有的 aws_launch_configuration
资源,然后您可以使用该唯一名称来创建 aws_autoscaling_group
resource.
您可以检查上述所有内容的代码 起程拓殖/ autoscaling-api.tf
资源"aws_launch_configuration" "api-launchconfig" {
Name_prefix = "api-launchconfig-"
Image_id =“${var.API_INSTANCE_AMI}"
Instance_type = "t2.micro"
Security_groups = ["${aws_security_group . cn.api-instance.id}"]
user_data = "${data.template_file.api-shell-script.rendered}"
Iam_instance_profile = "${aws_iam_instance_profile ..CloudWatchAgentServerRole-instanceprofile.name}"
connection {
user = "${var.INSTANCE_USERNAME}"
Private_key = "${文件" ("${var . key ".PATH_TO_PRIVATE_KEY} ")}”
}
lifecycle {
Create_before_destroy = true
}
}
资源"aws_autoscaling_group" "api-autoscaling" {
名称=“${aws_launch_configuration . conf”.api-launchconfig.name}-asg"
Vpc_zone_identifier = ["${aws_子网.main-public-1.id}"]
Launch_configuration = "${aws_launch_configuration.api-launchconfig.name}"
Min_size = 2
Max_size = 2
Health_check_grace_period = 300
health_check_type = "ELB"
load_balancer = ["${aws_elb.api-elb.name}"]
force_delete = true
lifecycle {
Create_before_destroy = true
}
tag {
key = "Name"
值= "api ec2实例"
Propagate_at_launch = true
}
}
零停机时间部署的第二个挑战是确保您的新部署已准备好开始接收请求. 在某些情况下,仅仅部署和启动一个新的EC2实例是不够的.
为了解决这个问题, aws_launch_configuration
has a property user_data
支持原生AWS自动扩展 user_data
属性,您可以使用该属性传递希望在启动新实例时作为自动伸缩组的一部分运行的任何脚本. 在我们的示例中,我们跟踪应用服务器的日志并等待启动消息. 您还可以检查HTTP服务器并查看它们何时启动.
直到tail /var/log/syslog | grep '节点 ./bin/www' > /dev/null; do sleep 5; done
此外,您还可以启用ELB检查 aws_autoscaling_group
resource level, 在Terraform销毁旧的实例之前,如何确保新实例通过ELB检查. This is how the ELB check for API layer looks like; it checks for the /api/status
返回成功的端点.
资源"aws_elb" "api-elb" {
name = "api-elb"
子网= ["${aws_子网.main-public-1.id}"]
Security_groups = ["${aws_security_group . cn.elb-securitygroup.id}"]
listener {
Instance_port =“${var.API_PORT}"
Instance_protocol = "http"
lb_port = 80
Lb_protocol = "http"
}
health_check {
Healthy_threshold = 2
UnHealthy_threshold = 2
timeout = 3
target = "HTTP:${var.API_PORT} / api /地位”
interval = 30
}
Cross_zone_load_balancing = true
connection_drain = true
Connection_draining_timeout = 400
tags {
Name = "my-elb"
}
}
So this brings us to the end of this article; hopefully, by now, 要么您已经部署了应用程序,并使用Jenkins部署和Terraform最佳实践使用零停机CI/CD管道运行,要么您更愿意探索这一领域,并使您的部署尽可能少地需要人工干预.
In this article, 所使用的部署策略称为蓝绿部署,其中我们有一个当前安装(蓝),它在我们部署和测试新版本(绿)时接收实时流量,然后在新版本准备就绪后替换它们. 除了这个策略, 部署应用程序还有其他方法, 这篇文章很好地解释了这一点, 部署策略简介. 现在,调整另一种策略就像配置Jenkins管道一样简单.
Also, in this article, 我假定所有API的新变化, web, 数据层是兼容的,所以你不必担心新版本会和旧版本对话. 但在现实中,情况可能并不总是如此. 为了解决这个问题, 在设计新版本/功能时, 始终考虑向后兼容层,否则您将需要调整部署来处理这种情况.
集成测试也是这个部署管道中缺少的东西. 因为你不希望任何东西在没有经过测试的情况下就发布给最终用户, 在将这些策略应用于自己的项目时,一定要记住这一点.
如果您有兴趣了解更多关于Terraform的工作原理以及如何使用该技术部署到AWS, I recommend Terraform AWS Cloud: Sane基础设施管理 在那里,同事Toptaler Radosław Szalski解释了Terraform,然后向您展示了为团队配置多环境和生产就绪的Terraform设置所需的步骤
Terraform是一个工具,它可以很容易地编写版本控制的基础设施代码. 您可以使用它在100多个不同的服务提供商(如AWS)上编排基础设施, Alicoud, GCP, Azure, OpenStack等等.
持续集成和持续部署是一种实践,您可以在每次代码更改时集成和测试您的软件. 稍后,将该代码部署到生产环境中.
它的主要好处是减少了部署期间的手工工作和人为错误的机会.
这取决于你的产品和你的技术实现, 你可以选择滚动策略, recreate strategy, blue-green, A/B testing, canary deployment, or shadow strategy.
Packer是一个工具,它可以很容易地为不同的平台(如AWS EC2)构建机器映像, Virtual Box, and VMWare.
Jenkins是一个持续集成工具,它使软件团队能够为他们的项目构建集成管道. 您可以定制jenkins驱动的管道,以包含不同的软件开发过程,比如构建, testing, 对代码进行分段和静态分析.
No. Terraform is a tool, 它反过来使用Hashicorp配置语言(HCL)将基础设施描述为代码. HCL是一种声明性语言,定义所需的状态,而不是实现所需的步骤.
Gaurav有12年以上的开发经验, scrum master, senior consultant, and product owner.
世界级的文章,每周发一次.
世界级的文章,每周发一次.
Join the Toptal® community.