1.简介
DevOps越来越火,各种产品层出不穷,技术人员如果不谈谈这个词,就会显得很落伍了,在这种形势下,阿里云也推出了自己的DevOps公共云产品CodePipeline,本文并不想介绍已经铺天盖地的DevOps概念,而是结合阿里云的产品CodePipeline和开源工具Packer,Terraform来实践一种全新云上的DevOps方案,从构建代码,创建自定义镜像,然后基于包含新应用的镜像来创建运行应用的整个基础设施,包括ECS,VPC网络,安全组等等,然后发布应用,从无到有一键完成。下面我们以CodePipeline示例Web项目为实例来实践整个方案。
2.开通CodePipeline
2.1登录阿里云控制如后,通过如下导航找到CodePipeline。
2.2点击图中菜单按钮来到服务开通页面,
点击开通服务按钮,由于当前产品处于公测期,开通服务前需要申请,按照要求提交申请,后台人员审核后,出现CodePipeline的产品主界面,就可以开始使用CodePipeline了。
3.创建项目和运行项目
3.1登录阿里云控制台后,通过菜单导航到CodePipeline后,出现如下界面。
3.2点击新建按键,来到创建项目导航页面。
输入项目名称Cloud_DevOps,并选择Java项目,点击下一步,
3.3来到代码配置构建页面,
在“仓库地址”中输入如下代码,这是一个普通的Java Web示例项目,可以通过Git Clone后查看其内容
https://code.aliyun.com/CodePipeline/java-demo.git
然后在构“建命令中”输入如下命令后结果如下图
mvn package -DskipTests
export ALICLOUD_ACCESS_KEY=<你的阿里云AK_KEY>
export ALICLOUD_SECRET_KEY=<你的阿里云AK_SECRET_KEY>
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/packer
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/demo.json
chmod 755 packer
./packer build demo.json
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/terraform
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/main.tf
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/variables.tf
chmod 755 terraform
./terraform apply .
点击“下一步”,来到部署页面,选择“不部署”,点击“下一步”,在项目确定页面点击“确定”创建项目后来到项目构建页面,点击“立即构建”按钮来运行项目。
大约20多分钟后,整个项目运行完成,我们可以通过点击“构建历史”下面的构建号例如“#3”构建日志来查看所生成的ECS的IP和访问端口
然后在浏览器中输入
http://47.93.214.116/demo/
就可以看到我们的应用可以访问了。
4.原理分析
通过上面简单的几条命令,我们就在阿里云的环境上,编译好了我们的示例应用,并且生成了阿里云的自定义镜像,然后生成了运行应用所必须的基础环境,包括ECS,VPC,端口映射等,使得我们可以一键完成从零到可以访问的应用。这个功能包含三个关键的组件
4.1 CodePipeline
DevOps阿里云CodePipeline是兼容Jenkins标准的、提供快速可靠的持续集成与持续交付服务。基于容器技术和阿里云基础服务架构,提供稳定和安全的代码/Docker编译构建,测试,扫描和部署的工具服务,并提供Pipeline As Code的编码级配置模式,满足应用程序和基础设施快速可靠的交付和更新。在本实例中,起到任务管理和调用命令执行的功能,它负责构建的容器资源,然后根据项目的配置从Github上将源代码下载构建的容器中,执行构建命令,并调用packer来创建包含所构建应用的阿里云镜像,调用Terraform来创建整个ECS,VPC网络,设置端口映射等全部基础设施。
4.2 Packer
DevOpsPacker是HashiCorp公司出品的一个从单一的模板文件来创建多平台一致性镜像的轻量级开源工具,它能够运行在常用的主流操作系统如Windows、Linux和Mac os上,能够高效的并行创建多平台例如AWS、Azure和Alicloud的镜像,它的目的并不是取代Puppet/Chef等配置管理工具,实际上,当制作镜像的时候,Packer可以使用Chef或者Puppet等工具来安装镜像所需要的软件。通过Packer自动化的创建各种平台的镜像是非常容易的。关于更多的packer的知识,请访问Pakcer的官网或者阿里云Packer官方插件站点。
在构建命令中的下面部分是packer相关的,运行packer首先需要在环境变量或者模板文件中导出阿里云的AK信息,然后下载packer程序和packer模板文件,执行packer命令,packer就会根据模板文件的内容来构建了里云镜像。
export ALICLOUD_ACCESS_KEY=<你的阿里云AK_KEY>
export ALICLOUD_SECRET_KEY=<你的阿里云AK_SECRET_KEY>
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/packer
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/demo.json
chmod 755 packer
./packer build demo.json
下面就是demo.json的内容。
{
"variables": {
"access_key": "{{env `ALICLOUD_ACCESS_KEY`}}",
"secret_key": "{{env `ALICLOUD_SECRET_KEY`}}"
},
"builders": [{
"type":"alicloud-ecs",
"access_key":"{{user `access_key`}}",
"secret_key":"{{user `secret_key`}}",
"region":"cn-beijing",
"image_name":"codepipe_demo",
"source_image":"ubuntu_16_0402_64_40G_alibase_20170711.vhd",
"ssh_username":"root",
"instance_type":"ecs.n1.medium",
"io_optimized":"true",
"image_force_delete":"true",
"ssh_password":"Test12345"
}],
"provisioners": [{
"type": "shell",
"inline": [
"apt-get update -yy",
"apt-get install openjdk-8-jdk tomcat8 -yy",
"mkdir -p /var/lib/tomcat8/webapps/"
]
},
{
"type": "file",
"source": "target/demo.war",
"destination": "/var/lib/tomcat8/webapps/"
}]
}
其中关键是Provisioners部分,它会安装运行应用所需要的软件,并将构建的应用demo.war包含进创建的镜像。
4.3 Terraform
DevOpsTerraform是HashiCorp公司出品的,著名Vagrant、Packer工具也出自于该公司。Terraform是“基础设施即代码”的开源工具,通过模板定义“基础设施”,目前已支持AWS、Azure、OpenStack、Alicloud等主流云平台。更多的关于Terraform的知识,请访问Terraform官网或者阿里云的Teffaform插件站点。
构建命令中的如下命令是Terraform相关的。它也需要先设置AK,然后下载terraform命令和模板文件,然后应用模板文件,就会根据模板文件内容来创建整个基础设施。
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/terraform
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/main.tf
wget http://alideployclient.oss-cn-beijing.aliyuncs.com/variables.tf
chmod 755 terraform
./terraform apply .
下面就是main.tf的内容:
provider "alicloud" {
region = "cn-beijing"
}
data "alicloud_instance_types" "1c2g" {
cpu_core_count = 1
memory_size = 2
}
data "alicloud_zones" "default" {
"available_instance_type"= "${data.alicloud_instance_types.1c2g.instance_types.1.id}"
"available_disk_category"= "${var.disk_category}"
}
resource "alicloud_vpc" "default" {
name = "pipeline_vpc"
cidr_block = "${var.vpc_cidr}"
}
resource "alicloud_vswitch" "default" {
vpc_id = "${alicloud_vpc.default.id}"
cidr_block = "${var.vswitch_cidr}"
availability_zone = "${data.alicloud_zones.default.zones.0.id}"
}
resource "alicloud_nat_gateway" "default" {
vpc_id = "${alicloud_vpc.default.id}"
spec = "Small"
name = "bosh_micro_nat"
bandwidth_packages = [{
ip_count = 2
bandwidth = 5
zone = "${data.alicloud_zones.default.zones.0.id}"
}]
depends_on = [
"alicloud_vswitch.default"]
}
resource "alicloud_snat_entry" "default"{
snat_table_id = "${alicloud_nat_gateway.default.snat_table_ids}"
source_vswitch_id = "${alicloud_vswitch.default.id}"
snat_ip = "${element(split(",", alicloud_nat_gateway.default.bandwidth_packages.0.public_ip_addresses),0)}"
}
resource "alicloud_forward_entry" "default"{
forward_table_id = "${alicloud_nat_gateway.default.forward_table_ids}"
external_ip = "${element(split(",", alicloud_nat_gateway.default.bandwidth_packages.0.public_ip_addresses),1)}"
external_port = "80"
ip_protocol = "tcp"
internal_ip = "${alicloud_instance.default.private_ip}"
internal_port = "8080"
}
resource "alicloud_forward_entry" "ssh"{
forward_table_id = "${alicloud_nat_gateway.default.forward_table_ids}"
external_ip = "${element(split(",", alicloud_nat_gateway.default.bandwidth_packages.0.public_ip_addresses),1)}"
external_port = "22"
ip_protocol = "tcp"
internal_ip = "${alicloud_instance.default.private_ip}"
internal_port = "22"
}
resource "alicloud_security_group" "sg" {
name = "bosh_micro_sg"
description = "tf_sg"
vpc_id = "${alicloud_vpc.default.id}"
}
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.sg.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "tomcat-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "8080/8080"
priority = 1
security_group_id = "${alicloud_security_group.sg.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "ssh" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "22/22"
priority = 1
security_group_id = "${alicloud_security_group.sg.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "codepipeline_deploy" {
type = "egress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "4505/4506"
priority = 1
security_group_id = "${alicloud_security_group.sg.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "codepipeline_deploy_ingress" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "4505/4506"
priority = 1
security_group_id = "${alicloud_security_group.sg.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_instance" "default" {
availability_zone = "${data.alicloud_zones.default.zones.0.id}"
security_groups = ["${alicloud_security_group.sg.id}"]
vswitch_id = "${alicloud_vswitch.default.id}"
password = "${var.ecs_password}"
# series II
instance_charge_type = "PostPaid"
instance_type = "${data.alicloud_instance_types.1c2g.instance_types.1.id}"
internet_max_bandwidth_out = 0
io_optimized = "${var.io_optimized}"
system_disk_category = "cloud_efficiency"
image_id = "${data.alicloud_images.multi_image.images.0.id}"
instance_name = "pipeline_ubuntu_1604_64"
}
data "alicloud_images" "multi_image" {
owners = "self"
name_regex = "codepipe_demo"
}
下面是variables.tf的内容,这一部分是定义Terraform模板所需要的变量:
variable "vpc_cidr" {
default = "10.1.0.0/21"
}
variable "vswitch_cidr" {
default = "10.1.1.0/24"
}
variable "rule_policy" {
default = "accept"
}
variable "instance_type" {
default = "ecs.n1.small"
}
variable "io_optimized" {
default = "optimized"
}
variable "disk_category"{
default = "cloud_efficiency"
}
variable "ecs_password"{
default = "Test12345"
}
在main.tf模板中,通过如下部分来引用上一步packer创建的镜像。
data "alicloud_images" "multi_image" {
owners = "self"
name_regex = "codepipe_demo"
}
5.展望
DevOps本文是对云上DevOps的一种探索,希望让读者能够意识到相对于传统的环境下的DevOps,云上环境能够提供许多传统环境下不能提供的能力,起到一个抛砖引玉的作用。从CodePipeline这个产品来说,接下来我们会针对用户的场景来深度的集成Packer,Terraform,使其能够更加符合云上DevOps的特点,也欢迎广大的读者提出自己的应用场景和需求,来共同探讨云上DevOps的最佳实践。