Bài viết thuộc series “Chinh phục CDK”
Giới thiệu
Trong bài trước, chúng ta đã tìm hiểu về AWS CDK và làm một ví dụ đơn giản. Trong bài này, chúng ta sẽ tìm hiểu chi tiết hơn về các bước để khởi tạo ứng dụng bằng CDK.
Mục tiêu
- Bootstrapping
- Khởi tạo ứng dụng với CDK
- Viết code
- Tạo AWS CloudFormation
- Triển khai hạ tầng
- Thay đổi cấu hình
- Xóa hạ tầng
- Kết luận
- Bài viết liên quan
Để cung cấp hạ tầng mới sử dụng AWS CDK, ta sẽ làm theo các bước sau đây:
- Bootstrapping
- Khởi tạo ứng dụng với CDK
- Viết code
- Tạo AWS CloudFormation
- Triển khai hạ tầng
Ngoài ra, trong quá trình làm việc với CDK, còn hai bước nữa là:
- Thay đổi cấu hình
- Xóa hạ tầng
Để giúp các bạn hiểu rõ hơn về các bước trên, chúng ta sẽ cùng thực hiện ví dụ tạo S3 Bucket.
Bootstrapping
Đây là bước yêu cầu nếu bạn sử dụng CDK lần đầu để cung cấp hạ tầng cho một tài khoản ở vùng (AWS Region) mà bạn chưa từng sử dụng CDK để tạo hạ tầng trước đó.
Quá trình Bootstrapping sẽ tạo những tài nguyên cần thiết cho CDK có thể sử dụng cho việc cung cấp hạ tầng lên trên AWS. Ví dụ một số tài nguyên mà quá trình bootstrapping tạo ra là:
- Amazon S3 Bucket để lưu tệp tin YAML trong quá trình cung cấp hạ tầng
- Các IAM Roles cần thiết để CDK có quyền tạo hạ tầng trên AWS
Tất cả các tài nguyên cần thiết đều được định nghĩa bên trong CloudFormation Stack tên là CDKToolkit. Do CloudFormation Stack tồn tại ở các Region khác nhau, nên khi cung cấp hạ tầng ở một Region mới, ta phải thực hiện quá trình bootstrapping cho Region đó trước khi chạy CDK.
Ví dụ trong bài này ta sẽ tạo S3 Bucket ở us-west-2 với ACCOUNT-NUMBER là Account ID của bạn.
cdk bootstrap aws://ACCOUNT-NUMBER/us-west-2 ⏳ Bootstrapping environment aws://ACCOUNT-NUMBER/us-west-2
...Đợi quá trình bootstrapping chạy xong, mở CloudFormation Console ta sẽ thấy CloudFormation Stack là CDKToolkit.
Khởi tạo ứng dụng với CDK
Tiếp theo ta sẽ sử dụng CDK để khởi tạo ứng dụng với ngôn ngữ ta muốn.
mkdir s3-simple && cd s3-simplecdk init app --language goCấu trúc thư mục sau khi chạy xong câu lệnh cdk init.
.
├── README.md
├── cdk.json
├── go.mod
├── s3-simple.go
└── s3-simple_test.gocdk.jsonchứa câu lệnh CDK biết làm thế chạy CDK codego.modchứa thư viện cần thiết cho CDKs3-simple.gotệp tin ta viết code
Sau khi khởi tạo ứng dụng, ta chạy câu lệnh sau để tải thư viện của CDK.
go getViết code
Đoạn code mặc định của tệp tin s3-simple.go:
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
// "github.com/aws/aws-cdk-go/awscdk/v2/awssqs"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type S3SimpleStackProps struct {
awscdk.StackProps
}
func NewS3SimpleStack(scope constructs.Construct, id string, props *S3SimpleStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
// The code that defines your stack goes here
// example resource
// queue := awssqs.NewQueue(stack, jsii.String("S3SimpleQueue"), &awssqs.QueueProps{
// VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)),
// })
return stack
}
func main() {
defer jsii.Close()
app := awscdk.NewApp(nil)
NewS3SimpleStack(app, "S3SimpleStack", &S3SimpleStackProps{
awscdk.StackProps{
Env: env(),
},
})
app.Synth(nil)
}
// env determines the AWS environment (account+region) in which our stack is to
// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html
func env() *awscdk.Environment {
// If unspecified, this stack will be "environment-agnostic".
// Account/Region-dependent features and context lookups will not work, but a
// single synthesized template can be deployed anywhere.
//---------------------------------------------------------------------------
return nil
// Uncomment if you know exactly what account and region you want to deploy
// the stack to. This is the recommendation for production stacks.
//---------------------------------------------------------------------------
// return &awscdk.Environment{
// Account: jsii.String("123456789012"),
// Region: jsii.String("us-east-1"),
// }
// Uncomment to specialize this stack for the AWS Account and Region that are
// implied by the current CLI configuration. This is recommended for dev
// stacks.
//---------------------------------------------------------------------------
// return &awscdk.Environment{
// Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
// Region: jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
// }
}Có 3 hàm như sau:
main()NewS3SimpleStack()env()
Mình sẽ giải thích cấu trúc code ở các bài tiếp theo, hiện tại ta chỉ cần quan tâm tới hàm env().
Hàm env() dùng để chỉ định tài khoản và AWS Region mà CDK sử dụng cho việc cung cấp hạ tầng. Có 3 lựa chọn sau.
- Sử dụng tài khoản mặc định
return nil- Chỉ định chính xác tài khoản nào
return &awscdk.Environment{
Account: jsii.String("123456789012"),
Region: jsii.String("us-east-1"),
}- Sử dụng tài khoản cấu hình bởi CLI
return &awscdk.Environment{
Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
Region: jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
}Hàm NewS3SimpleStack() được sử dụng để chỉ định các tài nguyên cần tạo, như bạn có thể thấy trong đoạn code bị comment trong hàm:
// queue := awssqs.NewQueue(stack, jsii.String("S3SimpleQueue"), &awssqs.QueueProps{
// VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)),
// })Đây là đoạn code ta dùng để tạo SQS (Simple Queue Service). Tiếp theo ta sẽ cập nhật lại tệp tin s3-simple.go thêm vào đoạn code tạo S3 Bucket.
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type S3SimpleStackProps struct {
awscdk.StackProps
}
func NewS3SimpleStack(scope constructs.Construct, id string, props *S3SimpleStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
awss3.NewBucket(stack, jsii.String("S3SimpleStack"), &awss3.BucketProps{
Versioned: jsii.Bool(false),
})
return stack
}
func main() {
defer jsii.Close()
app := awscdk.NewApp(nil)
NewS3SimpleStack(app, "S3SimpleStack", &S3SimpleStackProps{
awscdk.StackProps{
Env: env(),
},
})
app.Synth(nil)
}
func env() *awscdk.Environment {
return nil
}Tạo AWS CloudFormation
Sau khi viết code xong ta cần chạy câu lệnh sau để chuyển CDK code thành CloudFormation, đây cũng là cách để ta xem trước các tài nguyên được tạo.
cdk synthKết quả hiển thị của câu lệnh synth:
Resources:
S3SimpleStack1351D274:
Type: AWS::S3::Bucket
Properties:
BucketName: s3-simple-stack
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Metadata:
aws:cdk:path: S3SimpleStack/S3SimpleStack/Resource
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/yXITQ5AMBBA4bPYt+M3xJYbcACptmSUaaJtSMTdEav35WVQVpBE4nBcKsNXHOHqvZCGvWtwOVxNkEZ71k706/7YaWfDLvXn1pJCj5ZuNtsU0hqyeEUKZyw2VRbR4hD5HsjjpqH7+wDVL3ZTdwAAAA==
Metadata:
aws:cdk:path: S3SimpleStack/CDKMetadata/Default
Condition: CDKMetadataAvailable
...Kết quả này được lưu trong thư mục cdk.out, khi ta chạy câu lệnh deploy thì CDK sẽ lấy kết quả từ thư mục cdk.out này để cung cấp hạ tầng.
Triển khai hạ tầng
Cuối cùng ta chạy câu lệnh deploy:
cdk deployQuá trình chạy của câu lệnh deploy sẽ được hiển thị ở Terminal.
Runtime process exited abnormally: waitid: no child processes
✨ Synthesis time: 3.57s
S3SimpleStack: building assets...
[0%] start: Building eabf63606288f895f151db8ef023c76ee3e697658c028f1d77329ad7cc2c5d26:current_account-current_region
[100%] success: Built eabf63606288f895f151db8ef023c76ee3e697658c028f1d77329ad7cc2c5d26:current_account-current_region
S3SimpleStack: assets built
S3SimpleStack: deploying... [1/1]
[0%] start: Publishing eabf63606288f895f151db8ef023c76ee3e697658c028f1d77329ad7cc2c5d26:current_account-current_region
[100%] success: Published eabf63606288f895f151db8ef023c76ee3e697658c028f1d77329ad7cc2c5d26:current_account-current_region
S3SimpleStack: creating CloudFormation changeset...
[███████████████████▎······································] (1/3)
2:29:12 PM | CREATE_IN_PROGRESS | AWS::CloudFormation::Stack | S3SimpleStack
2:29:18 PM | CREATE_IN_PROGRESS | AWS::S3::Bucket | S3SimpleStackSau khi CDK chạy xong, truy cập CloudFormation Console ta sẽ thấy CloudFormation Stack tên là S3SimpleStack. Nhiệm vụ chính của CDK là tạo ra cấu hình của CloudFormation và dùng nó để tạo CloudFormation Stack. Còn lại quá trình tạo hạ tầng sẽ do CloudFormation đảm nhiệm.
Thay đổi cấu hình
Trong quá trình triển khai chắc chắn ta sẽ thay đổi hạ tầng liên tục, CDK có hỗ trợ ta sửa code và triển khai cấu hình thay bị đổi lên trên hạ tầng hiện tại.
Ví dụ ta sửa thuộc tính Versioned của S3 thành true:
awss3.NewBucket(stack, jsii.String("S3SimpleStack"), &awss3.BucketProps{
BucketName: jsii.String("s3-simple-stack"),
Versioned: jsii.Bool(true), // change here
})CDK cung cấp câu lệnh diff để so sánh khác biệt giữa code hiện tại và cấu hình đã được triển khai.
cdk diffResources
[~] AWS::S3::Bucket S3SimpleStack S3SimpleStack1351D274
└─ [+] VersioningConfiguration
└─ {"Status":"Enabled"}Tiếp theo ta chạy deploy thì CDK sẽ triển khai cấu hình ta vừa thay đổi lên hạ tầng hiện tại.
cdk deploy...
S3SimpleStack: creating CloudFormation changeset...
✅ S3SimpleStack
✨ Deployment time: 51.16s
...Xóa hạ tầng
Nếu ta muốn xóa hạ tầng hiện tại để tiết kiệm tiền thì ta sử dụng câu lệnh destroy như sau:
$ cdk destroy
Are you sure you want to delete: S3SimpleStack (y/n)?Chọn y.
S3SimpleStack: destroying... [1/1]
✅ S3SimpleStack: destroyedLúc này tài nguyên trên AWS đã được xóa thành công.
Kết luận
Vậy là ta đã tìm hiểu xong về cách khởi tạo ứng dụng và các bước cần thiết để cung cấp hạ tầng trên AWS bằng CDK. Như bạn thấy thì các bước cần làm của CDK cũng khá giống với Terraform và khá dễ để sử dụng.
Tác giả Quân Huỳnh
First AI Journey for DevOps:
- PromptOps: From YAML to AI
- The DevOps AI Advantage
- The AIOps Book