使用Apex的Lambda:使用Terraform进行管理
简介
在上一篇文章中,我们总结了使用Apex在不同环境中管理Lambda的方法。
使用Apex和环境变量:在不同环境中设置Lambda环境 – Qiita
这次我想尝试使用Apex和Terraform来管理Lambda函数。
版本等
-
- OS: Mac OS X 10.11.1
-
- Terraform: v0.6.16
-
- Apex: 0.9.0
- 言語: Go
预先设定
安装Terraform
如果尚未安装Terraform,就下载并安装Terraform – Terraform by HashiCorp。
安装Apex
如果尚未安装Apex,则进行安装。
curl https://raw.githubusercontent.com/apex/apex/master/install.sh | sh
亞馬遜網路服務配置
准备AWS帐户。
这次我想根据环境将AWS账户分开,所以我准备了一个用于生产的和一个用于开发的AWS账户。
准备好账户后,请将其保存在 ~/.aws/credentials 文件中。
# dev用
[default]
region=ap-northeast-1
aws_access_key_id=XXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXX
# prod用
[prod]
region=ap-northeast-1
aws_access_key_id=XXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXX
我将dev配置文件设置为默认。
准备S3存储桶
为了存储Terraform的状态文件,我们需要准备一个S3存储桶。这次我们给它取名为”apex-terraform-example”。
项目创建
首先创建一个目录。
mkdir apex_terraform
使用 Apex 命令创建项目。
cd apex_terraform
apex init
使用对话命令输入以下内容。
Project name: apex_terraform
Project description:
Would you like to manage infrastructure with Terraform? (yes/no): yes
Environments: dev, prod
Would you like to store Terraform state on S3? (yes/no): yes
S3 bucket name: apex-terraform-example
在关于是否使用Terraform的问题中,选择”Yes”。
此外,当被问及是否将Terraform的状态文件放置在S3上时,选择”Yes”。选择”Yes”后会被要求指定S3 Bucket的名称。
创建项目,将以以下文件结构完成。
├── functions
│ └── hello
│ └── index.js
├── infrastructure
│ ├── dev
│ │ └── main.tf
│ ├── modules
│ │ └── iam
│ │ ├── iam.tf
│ │ └── outputs.tf
│ └── prod
│ └── main.tf
└── project.json
基础设施下面有针对开发和生产环境的文件夹,并且在这些文件夹中存放了terraform的配置文件。此外,在基础设施的模块下,还有用于创建IAM角色的模块。每个环境的main.tf文件中包含以下描述,可以确认该模块用于IAM角色的创建。
module "iam" {
source = "../modules/iam"
}
output "lambda_function_role_id" {
value = "${module.iam.lambda_function_role_id}"
}
基础设施建设 (开发)
我会根据每个环境执行Terraform。首先,我会尝试通过执行计划(plan)来确认执行方案。
$ apex infra plan
Refreshing Terraform state prior to plan...
The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.
Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.
+ module.iam.aws_iam_role.lambda_function
arn: "" => "<computed>"
assume_role_policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"lambda.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n}\n"
name: "" => "$ apex infra plan
Refreshing Terraform state prior to plan...
The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.
Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.
+ module.iam.aws_iam_role.lambda_function
arn: "" => "<computed>"
assume_role_policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"lambda.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n}\n"
name: "" => "apex_lambda_function"
path: "" => "/"
unique_id: "" => "<computed>"
+ module.iam.aws_iam_role_policy.cloudwatchlogs_full_access
name: "" => "cloudwatchlogs_full_access"
policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Action\": [\n \"logs:*\"\n ],\n \"Effect\": \"Allow\",\n \"Resource\": \"*\"\n }\n ]\n}\n"
role: "" => "${aws_iam_role.lambda_function.id}"
Plan: 2 to add, 0 to change, 0 to destroy."
path: "" => "/"
unique_id: "" => "<computed>"
+ module.iam.aws_iam_role_policy.cloudwatchlogs_full_access
name: "" => "cloudwatchlogs_full_access"
policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Action\": [\n \"logs:*\"\n ],\n \"Effect\": \"Allow\",\n \"Resource\": \"*\"\n }\n ]\n}\n"
role: "" => "${aws_iam_role.lambda_function.id}"
Plan: 2 to add, 0 to change, 0 to destroy.
我们可以看到创建了一个拥有对CloudWatch Logs的完全访问权限的Policy以及一个名为apex_lambda_function的IAM Role。
我已经确认过了,所以我会运行真正的Terraform。
$ apex infra apply
module.iam.aws_iam_role.lambda_function: Creating...
arn: "" => "<computed>"
assume_role_policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"lambda.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n}\n"
name: "" => "apex_lambda_function"
path: "" => "/"
unique_id: "" => "<computed>"
module.iam.aws_iam_role.lambda_function: Creation complete
module.iam.aws_iam_role_policy.cloudwatchlogs_full_access: Creating...
name: "" => "cloudwatchlogs_full_access"
policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Action\": [\n \"logs:*\"\n ],\n \"Effect\": \"Allow\",\n \"Resource\": \"*\"\n }\n ]\n}\n"
role: "" => "apex_lambda_function"
module.iam.aws_iam_role_policy.cloudwatchlogs_full_access: Creation complete
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.
State path: terraform.tfstate
Outputs:
lambda_function_role_id = arn:aws:iam::588762728270:role/apex_lambda_function
目前已经创建了IAM角色。不过目前只创建了开发环境的IAM角色。
基础设施建设 (产品)
目前只针对dev环境建立了IAM角色,因此我希望也能为prod环境进行构建。
在初始状态下,Terraform配置文件都被放置在完全相同的位置,因此请编辑生产环境的配置文件并写入以下内容。
variable "aws_region" {
default = "ap-northeast-1"
}
provider "aws" {
profile = "prod"
}
...
因为如果按照原样使用,则会使用与 dev 相同的默认配置文件(AWS 账号),所以我们进行了设置以使用 prodProfile。
Terraform的执行方面,我在apex infra命令中并没有找到指定目标环境的选项(可能是我没有注意到)…不过,基本上这还是通常的Terraform操作,所以我决定进入prod目录并执行terraform apply。
※2016/06/01更新 – 通过指定-e选项可以实现!
$ apex infra -e prod apply
module.iam.aws_iam_role.lambda_function: Creating...
arn: "" => "<computed>"
assume_role_policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"lambda.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n}\n"
name: "" => "apex_lambda_function"
path: "" => "/"
unique_id: "" => "<computed>"
module.iam.aws_iam_role.lambda_function: Creation complete
module.iam.aws_iam_role_policy.cloudwatchlogs_full_access: Creating...
name: "" => "cloudwatchlogs_full_access"
policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Action\": [\n \"logs:*\"\n ],\n \"Effect\": \"Allow\",\n \"Resource\": \"*\"\n }\n ]\n}\n"
role: "" => "apex_lambda_function"
module.iam.aws_iam_role_policy.cloudwatchlogs_full_access: Creation complete
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.
State path: terraform.tfstate
Outputs:
lambda_function_role_id = arn:aws:iam::109572732475:role/apex_lambda_function
这样就创建了一个用于prod的IAM角色!
创建函数(指定环境变量)
接下来,我们尝试使用环境变量创建Lambda代码。我们将根据不同的环境来更改环境变量,并尝试让执行结果随之而变化。
*.go
package main
import (
"encoding/json"
"os"
"github.com/apex/go-apex"
)
func main() {
apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
return os.Getenv("HOGE"), nil
})
}
在main()函数中,它返回了指定的环境变量HOGE的值。
※可以在apex/_examples/go at master · apex/apex中查看使用Go编写的代码示例。
为了在dev和prod之间切换环境变量,我们将准备不同的env文件。
.env-dev 环境配置文件
HOGE=FUGA
.env-prod –> .环境-生产
HOGE=PIYO
我将在开发环境部署并运行。环境变量将使用–set选项指定。
$ apex deploy hello --set $(cat .env-dev)
• config unchanged function=hello
• code unchanged function=hello
$ apex invoke hello
"FUGA"
可以看到环境变量的设置已经生效。
接下来我们将尝试将其部署到prod环境。
$ apex deploy hello -e prod --profile prod --set $(cat .env-prod)
• config unchanged function=hello
• updating function function=hello
• updated alias current function=hello version=2
• function updated function=hello name=apex_terraform_hello version=2
$ apex invoke hello -e prod --profile prod
"PIYO"
我也确认了针对prod的环境变量已经指定了!