Hiện nay xu thế sử dụng cloud thay vì sử dụng môi trường on-primse cho việc set up dự án đang ngày một phổ biến. Vì vậy các cloud vendor(AWS, Microsoft, Google Cloud) đưa ra nhiều hỗ trợ để người dùng có thể customize các resource trên cloud một cách dễ dàng hơn. Từ đó khái niêm infrastructure as code(IAC) ra đời. Nói thêm một chút về khái niêm IAC, đây là cụm từ nói về việc xây dựng những cơ sở hạ tầng(baseline infrastucture) bằng việc sử dụng code. Trong bài viết này, tôi sẽ giới thiệu một service của AWS chuyên cung cấp dịch vụ IAC đó chình là Cloudformation(CF).
98
Overview: Hiện nay, AWS sử dụng CF như là một backbone(core services) để tương tác với các services hay frameworks có sử dụng các dịch vụ infrastructures của AWS đơn cử như là AWS BeanStalk, AWS Amplify, Serverless, SAM(Serverless Application Model). Vì để sự dụng các services này một cách hiệu quả, ta cần hiểu khái quát cách mà CF vận hành.
I. Phương thức trình bày
Cloudformation được viết bằng 2 dạng đó là JSON và YAML. Ở cách viết bằng JSON, chúng ta thường thấy khi define schema hay policy ở AWS. YAML là một ngôn ngữ liệt kê thường xuất hiện ở các dịch vụ như Docker(Docker Compose), Azure Devops ….
- JSON: JSON được cấu thành từ 1 hoặc nhiều cặp name và value được phân tách bởi nhâu hai chấm và bắt đầu từ dấu ngoặc nhọn.
- Ví dụ: John: {
“DayofBirth”: “02021992”
“City”: “New York'
}
- YAML: Còn Yaml thì sao, YAML được cấu thành từ 1 hoặc nhiều cặp key và value được phân tách bởi dấu hai chấm. Ngoài ra khi sử dụng YAML, ta cần lưu ý về vấn đề thụt vào ở đầu dòng(indentation).
- Ví dụ về một docker compose viết bằng YAML.
version: '3' services: nginx: image: nginx:latest container_name: web-front restart: always ports: - 80:80 - 443:443 volumes: - /home/user/rstudio_docker/nginx.conf:/etc/nginx/nginx.conf - /home/user/ssl:/ssl/
Tùy thuộc vào thói quen của mỗi người, chúng ta có thể sử dụng 2 dạng trên để viết một file CF.
II. Thành phần:
Một file CF thường được cấu thành từ các yếu tố sau:
- AWSTemplateFormatVersion: version date
- Description: JSON string
- Metadata: template metadata
- Parameter: set of parameters
- Mapping: set of mapping
- Conditions: set of condition
- Transform: set of transforms
- Resources: set of resources
- Outputs: set of outputs.
Trong đó Resources là hành phần bắt buột phải có trong một file CF.
- AWSTemplateFormatVersion: Đậy là thành phần xác định khả năng của file CF dựa theo ngày mà AWS phân bố phiên bản. Hiện chỉ có một vesion date là “2010-09-09”.
- Description: Đây là thành phần bổ sung thông tin của file CF cho người đọc có thể dễ dàng nắm bắt. Ví dụ nếu file CF này tạo ra để phục vụ mục đích là tạo một mạng ảo trên AWS thì ta có thể bổ sung vào phần này như sau:
Desciption: “This template is created to provide Networkstack resources”.
- Metadatadata: Đây là thành phần bổ sung cho CF template như là giá trị cụ thể chọ từng resource. Ví dụ:
Metadata: Instances: Description: "Information about the instances" Databases: Description: "Information about the databases"
- Mapping: Mapping trong CF hoạt động như một bảng giá trị để chúng ta có thể tham chiếu dựa vào giá trị key và value. Ví dụ ta có thể thay đổi giá trị của một AMI của EC2 đựa vào mapping. Giá trị này sẽ thay đổi dựa vào biến Region mà AWS cung cấp cho chúng ta như ap-northest-2 sẽ được chọn khi chúng ta triển khai file CF ở region này và sẽ có AMI tương ứng với region này sẽ được mapping vào resource tương ứng.
Mappings: RegionMap: us-east-1: - 32: ami-6411e20d - 64: ami-7a11e213 us-west-1: - 32: ami-c9c7978c - 64: ami-cfc7978a eu-west-1: - 32: ami-37c2f643 - 64: ami-31c2f645 ap-southeast-1: - 32: ami-66f28c34 - 64: ami-60f28c32 ap-northeast-1: - 32: ami-9c03a89d - 64: ami-a003a8a1
- Parameter: Đây là thành phần cho phép chúng ta truyền giá trị trước khi file CF được triển khai trên AWS. Trong thành phần này chúng ta có thể có các giá trị như String, number và AWS resource types ví dụ như EC2 key, VPC ID …
Parameter: VPCName: DevOpsVPC AWS::EC2::Image::Id: b3f343546546
- Condition: Conditions trong CF sẽ quyết định resource nào sẽ được triển khai dựa trên những điều kiện đã được đặt ra. Ví dụ như VPC có dãy mạng 10.0.0.0 sẽ được tạo ra ở môi trường “Dev” trong khi dãy mạng “172.10.0.0” sẽ được triển khai trong mội trường “Production”. Ví dụ:
Conditions: CreateProdResources: !Equals - !Ref EnvType - prod
- Transform: Đây là thành phần cho phép AWS có thể process template. Ví dụ transform có thể giúp ta thêm một add-on vào CF hay sử dụng serverless template. Ví dụ:
Transform:
– AWS::Serverless
- Resource: Đây là thành phần chủ đạo tạo nên một file CF. Bao gồm type của resource ví dụ “AWS::EC2::VPC” và Properties ví dụ “CidrBlock” và “Tags” cho một VPC.
Ví dụ:
InfraVPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Sub ${ProjectName}-${StageName}-${SystemName}-vpc - Key: !Ref CostCenterKey Value: !Ref CostCenterValue - Key: !Ref EnvironmentKey Value: !Ref EnvironmentValue - Key: !Ref ProjectKey Value: !Ref ProjectValue - Key: !Ref ProjectOwnerKey Value: !Ref ProjectOwnerValue - Key: !Ref ProjectServiceKey Value: !Ref ProjectServiceValue
- Output: Sau khi đã triển khai các resources lên AWS, làm sao chúng ta có thể biết được giá trị cũng như ID của các resources này. Output sẽ giúp chúng ta tham chiếu đến các resource này theo dạng visual hay là dạng re-use để các CF template khác có thể sử dụng. Ví dụ ta có 2 CF template, một cho việc tạo ra Network resource, một cho việc tạo ra EC2, sau khi Network template tạo ra VPC, Subnet, ta sẽ dùng ID của template này ở phần output và sau đó template có EC2 sẽ re-use được những resource này.
Ví dụ:
Outputs: PublicSubnet1: Value: !Ref InfraPublicSubnet1 PublicSubnet2: Value: !Ref InfraPublicSubnet2 PrivateSubnet1: Value: !Ref InfraPrivateSubnet1 PrivateSubnet2: Value: !Ref InfraPrivateSubnet2 VpcId: Value: !Ref InfraVPC
Các bước triển khai CF trên AWS.
Sau khi đã tìm hiểu về các nhân tố có trong một file CF và bạn đã sẵn sàng để sử dụng các resources, bước tiếp theo ta sẽ tiến hành triển khai template này trên môi trường AWS. Có hai cách để ta có thể triển khai file CF lên AWS:
- Cách thứ nhất: Sử dụng AWS cli để deploy lên service CF.
- Bước 1: Tạo một S3 bucket để lưu trữ những file deploy. Chúng ta có thể tạo bucket trực tiếp trên AWS console hoặc bằng AWS cli bằng câu lệnh: “aws s3 mb s3://devopscfxxxx2022 –region us-east-1”
- Bước 2: Đóng gọi template này ở local và push file CF đã đóng gói lên S3 qua lệnh
aws cloudformation package \ --template-file network.yaml \ --s3-bucket devopscfxxxx2022 \ --s3-prefix deployment \ --output-template-file network-packaged.yaml
- Bước 3(Optional): Xác nhận tính đúng đắng của file CF qua lệnh:
aws cloudformation validate-template \ --template-body file://network-packaged.yaml
- Bước 4: Triển khai file CF đã được đóng gói qua lệnh:
aws cloudformation deploy \ --template-file network-packaged.yaml \ --stack-name devopscfstack \ --region us-east-1 \ --parameter-overrides Key1=Value1 Key2=Value2 --capabilities CAPABILITY_IAM
Lưu ý: Trong một vài trường hợp để CF có thể tạo một stack, chúng ta cần cung cấp cho dịch vụ này những quyền tương ứng và điều được thể hiện qua –capabilities trong lệnh deploy kể trên. Có ba loại capabilities có thể sử dụng đó là CAPABILITY_IAM | CAPABILITY_NAMED_IAM | CAPABILITY_AUTO_EXPAND. Trong đó “CAPABILITY_IAM” cung cấp quyền căn bản cho CF service còn khi bạn có những resources sử dụng custom name thì cần sử dụng CAPABILITY_NAMED_IAM ví dụ như khi bạn sử dụng những services liên quan đế IAM: “AWS::IAM::AccessKey, AWS::IAM::Group, AWS::IAM::InstanceProfile, AWS::IAM::Policy, AWS::IAM::Role, AWS::IAM::User, AWS::IAM::UserToGroupAddition” còn CAPABILITY_AUTO_EXPAND sẽ được dùng khi bạn sử dụng những add-on ở phần 7 “Transformation” như chuyển đổi qua serverless.
- Cách thứ hai: Triển khai CF stack trực tiếp trên AWS console.
- Bước 1: Tạo một S3 bucket để lưu trữ những file deploy. Chúng ta có thể tạo bucket trực tiếp trên AWS console hoặc bằng AWS cli bằng câu lệnh: “aws s3 mb s3://devopscfxxxx2022 –region us-east-1”
- Bước 2: Search CF service và Copy Template URL đã được tạo
- Bước 3: Điền Stack name và các parameter đã khai báo trong template.
- Bước 4: Xác nhận về Capabilities cho CF
- Bước 5: Kiểm tra stack trực tiếp bằng CF event
III. Cách tổ chức một CF project.
Thông thường, tùy theo số lượng và nhu cầu mà ta có thể tổ chức cấu trúc của 1 hay nhiều file CF khác nhau. Với nhiều file CF ta có thể tổ chức các file này thành dạng master và child(nested stacks).
Để có một Nested Stack ta cần thực hiện những bước sau:
- Bước 1: Khai báo tất cả các parameters có trong các stacks con.
- Bước 2: Upload các file template lên S3, lúc này ta sẽ có đường dẫn của các file này trên S3.
- Bước 3: Cập nhật đường dẫn các stack con, ví dụ infra-network vào phần TemplateURL ở masterstack. Còn cách khác là chúng ta chỉ cần đổi tên file ở phần TemplateURL vì thường chúng sẽ có địa chỉ cố định và chỉ thay đổi tên file ví dụ:
https://${BucketTemplates}.s3.ap-northeast-2.amazonaws.com/${BucketTemplatesPrefix}/infra-security.yaml và “https://${BucketTemplates}.s3.ap-northeast-2.amazonaws.com/${BucketTemplatesPrefix}/infra-network.yaml”
Resources:
InfraNetworkStack:
Resources: InfraNetworkStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub https://${BucketTemplates}.s3.ap-northeast-2.amazonaws.com/${BucketTemplatesPrefix}/infra-network.yaml Parameters: VpcCIDR: !Ref VpcCIDR PublicSubnetCIDR1: !Ref PublicSubnetCIDR1 PublicSubnetCIDR2: !Ref PublicSubnetCIDR2 PrivateSubnetCIDR1: !Ref PrivateSubnetCIDR1 PrivateSubnetCIDR2: !Ref PrivateSubnetCIDR2 ProjectName: !Ref ProjectName StageName: !Ref StageName SystemName: !Ref SystemName CostCenterKey: !Ref CostCenterKey CostCenterValue: !Ref CostCenterValue EnvironmentKey: !Ref EnvironmentKey EnvironmentValue: !Ref EnvironmentValue ProjectKey: !Ref ProjectKey ProjectValue: !Ref ProjectValue ProjectOwnerKey: !Ref ProjectOwnerKey ProjectOwnerValue: !Ref ProjectOwnerValue ProjectServiceKey: !Ref ProjectServiceKey ProjectServiceValue: !Ref ProjectServiceValue
- Bước 4: Thực hiện lại các steps ở phần III(Các bước triển khai CF trên AWS.)
V. Lời kết.
Như vậy các bạn đã đi qua một vòng về các thành phần của một file CF cũng như cách triển khai và cách tổ chức một project sử dụng CF một cách khái quát. Tuy nhiên CF còn nhiều phần mở rộng và việc sử dụng ở các framework khác, trong các bài sau tôi hy vọng sẽ làm rõ hơn về các vấn đề này. Cảm ơn các bạn đã quan tâm đến bài viết.