Giới thiệu
Lâu lắm rồi mới viết bài lại, tính ra chắc hơn nửa năm rồi @@~, từ ngày mình nhảy việc đến giờ.
Do lười thôi chứ không phải không có thời gian. Nay muốn tập trung viết lại cho thỏa mãn sở thích cũng như note lại cho khỏi quên kiến thức. Haha!!!
Bài viết này mình sẽ giới thiệu đến các bạn một cách để tự động tạo hoặc xóa instance (instance: Bạn có thể hiểu như một VM hoặc VPS cũng được) trên AWS sử dụng ansible nhen.
Thao tác
Bước 1: Cài đặt các gói thư viện cần thiết
Chúng ta sẽ cần boto package cho python trên máy đã cài ansible. Boto là SDK (Software Develoment Kit) được thiết kế để chuyển đổi phản hồi API trên AWS đến python class.
mình dùng Ubuntu và cài boto3, nên sẽ cài đặt như sau:
sudo apt install python3 sudo apt install python3-pip pip3 install boto boto3
Bước 2: Tạo Ansible vault để lưu access và secrect key AWS
Để lấy được access và secrect key, trên AWS dashboard =>> Service =>> IAM =>> Get access and secret key.
Quay lại trên máy đã cài ansible của mình, tạo file vault để chứa thông tin 2 key này, mục đích của file vault trên ansible là gì? nó sẽ mã hóa nội dung trong file nhạy cảm mà bạn không muốn ai đọc được, trong trường hợp này cặp key mình có được quan trọng vì ai đó biết được họ có thể dùng để thao tác được trên tài khoản AWS của mình.
ansible-vault create vars/asw_keys.yml New Vault password: Confirm New Vault password:
Trong nội dung bài viết này mình sẽ không đề cập đến cấu trúc thư mục và file trong ansible, mình sẽ nói đến trong nội dung khác, đại khái để một playbook của ansible chạy được, bạn cần phải có những file, thư mục như là: hosts, main.yml, thư mục vars, thư mục roles …
Bạn nhập mật khẩu vào phần vault yêu cầu, file này sẽ được mở ra, nhập vào nội dung sau:
aws_access_key: AAAAAAABBBBBBBB aws_secret_key: asdasfsfsdfdfg+asdasgfdhgjhkjhrvdrg
có thể hiểu mình sẽ để các biến theo kiểu key:value trong thư mục vars. Nếu bạn không muốn phải nhập password cho vault mỗi khi chạy playbook, bạn có thể làm như sau:
openssl rand -base64 2048 > vault.pass ansible-vault create vars/aws_keys.yml --vault-password-file vault.pass
Khi chạy playbook chỉ cần chỉ định file chứa pasword cho vault là được:
ansible-playbook playbook.yml --vault-password-file vault.pass
Để edit file vault:
ansible-vault edit group_vars/all/pass.yml Vault password:
Bước 3: Tạo các variables cần thiết
vim vars/all
instance_type: t3.micro security_group_id: sg-5qqwet2241o23 image: ami-0cc293023f983ed53 keypair: privatekey region: eu-central-1 subnet: subnet-1kknk12n4k12n4442n ##LAN-public #subnet: subnet-0fasfnsjdfq242144j1n ##LAN-private count: 1
những thông tin này bạn sẽ lấy được trên AWS dashboard hết:
instance_type: Là cấu hình instance mà bạn muốn tạo.
security_group_id: Chọn policy cho group
image: Giống như bạn chọn CentOS hay Ubuntu vậy.
keypair: private key để mình có thể ssh sau khi tạo xong instance, mặc định user là ec2-user.
region: Location bạn chỉ định để tạo.
subnet: Bạn quy định instance nằm trong subnet nào mà trước đó bạn đã tạo.
count: số lượng instance bạn muốn tạo tuơng tự.
Bước 4: Tạo role provision (role để khởi tạo instance)
vim roles/Provision_Instance/tasks/main.yml
--- - name: Provison EC2 instance ec2: aws_access_key: '{{ aws_access_key }}' aws_secret_key: '{{ aws_secret_key }}' key_name: '{{ keypair }}' group_id: '{{ security_group_id }}' instance_type: '{{ instance_type }}' image: '{{ image }}' region: '{{ region }}' vpc_subnet_id: '{{ subnet }}' private_ip: "10.17.100.115" count: '{{ count }}' wait: yes instance_tags: Name: awseu-web-1 volumes: - device_name: /dev/xvda volume_type: gp2 #volume_type: io1 #iops: 400 volume_size: 50 delete_on_termination: true register: ec2instance - debug: var=ec2instance
Có một số chổ mình cần giải thích nhỉ?
Thằng ansible nó hỗ trợ module ec2 để bạn tạo instance, bạn đưa các biến mà khi nãy quy định trong thư mục variables vào. Riêng một số biến bạn cần chỉ định cụ thể thì mình sẽ diễn giải trong đoạn này.
private_ip: IP private mà bạn muốn gán cho instance.
instance_tags: mình gán tên cho instance.
volumes: quy định disk khởi tạo và dạng disk mình muốn, có 3 loại: HDD, SSD và I/O SSD.
Bước 5: Tạo role destroy instance
vim roles/Destroy_Instance/main.yml
--- - name: Gather EC2 facts ec2_instance_facts: region: "{{ region }}" filters: "tag:Name": "awseu-web-1" aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}" register: ec2 - debug: var=ec2.instances - name: Terminate EC2 instance ec2: instance_ids: '{{ item.instance_id }}' state: absent region: "{{ region }}" aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}" with_items: "{{ ec2.instances }}"
Ở đây có 2 bước mình cần xử lý:
- Phần Gather, mình thu thập thông tin instance bằng tag name “awseu-web-1” và lưu kết quả trả về với register là ec2, mục đích của mình là sẽ lấy giá trị của instance_id để xóa instance này đi.
- Phần terminate lấy instance_id từ item ec2.instance và xóa instance này đi.
Bước 6: Tạo main file để run playbook
Gần xong rồi đấy, bây giờ bạn cần tạo file main.yml, file hosts nữa là được.
Đối với file main.yml (mình đặt tên managed-instances.yml):
--- - hosts: local connection: local gather_facts: False vars: ansible_python_interpreter: /usr/bin/python3 vars_files: - vars/aws_keys.yml - vars/all roles: - Provision_Instance #- Destroy_Instance
Khi khởi tạo instance thì comment (#) Destroy_Instance và ngược lại.
Đối với file host:
[local] localhost
Xong rồi đó, run playbook với cú pháp như sau:
sudo ansible-playbook -i hosts --ask-vault-pass managed-instances.yml
Nhập password vault vào, khi khởi tạo instance kết quả trả về như sau:
tritran@cinatic:~/Desktop/Ansible/AWS/AWS-Managed_instance$ ansible-playbook managed-instances.yml -i hosts --ask-vault-pass Vault password: PLAY [local] ******************************************************************************************************************************************************************************************************** TASK [Provision_Instance : Provison EC2 instance] ******************************************************************************************************************************************************************* changed: [localhost] TASK [Provision_Instance : debug] *********************************************************************************************************************************************************************************** ok: [localhost] => { "ec2instance": { "changed": true, "failed": false, "instance_ids": [ "i-0c79943c90ea5a878" ], "instances": [ { "ami_launch_index": "0", "architecture": "x86_64", "block_device_mapping": { "/dev/xvda": { "delete_on_termination": true, "status": "attached", "volume_id": "vol-019e3a93f209f52f4" } }, "dns_name": "", "ebs_optimized": false, "groups": { "sg-0e9f7f6ebc633f0db": "launch-wizard-1" }, "hypervisor": "xen", "id": "i-0c79943c90ea5a878", "image_id": "ami-0cc293023f983ed53", "instance_type": "t2.micro", "kernel": null, "key_name": "ebuynow", "launch_time": "2019-10-19T01:49:34.000Z", "placement": "eu-central-1a", "private_dns_name": "ip-172-17-1-25.eu-central-1.compute.internal", "private_ip": "172.17.1.25", "public_dns_name": "", "public_ip": null, "ramdisk": null, "region": "eu-central-1", "root_device_name": "/dev/xvda", "root_device_type": "ebs", "state": "running", "state_code": 16, "tags": { "Name": "awseu-test-1" }, "tenancy": "default", "virtualization_type": "hvm" } ], "tagged_instances": [] } } PLAY RECAP ********************************************************************************************************************************************************************************************************** localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Còn đây là kết quả khi destroy 1 instance nào đó:
tritran@cinatic:~/Desktop/Ansible/AWS/AWS-Managed_instance$ ansible-playbook managed-instances.yml -i hosts --ask-vault-pass Vault password: PLAY [local] ******************************************************************************************************************************************************************************************************** TASK [Destroy_Instance : Gather EC2 facts] ************************************************************************************************************************************************************************** ok: [localhost] TASK [Destroy_Instance : debug] ************************************************************************************************************************************************************************************* ok: [localhost] => { "ec2.instances": [ { "ami_launch_index": 0, "architecture": "x86_64", "block_device_mappings": [ { "device_name": "/dev/xvda", "ebs": { "attach_time": "2019-10-19T01:49:35+00:00", "delete_on_termination": true, "status": "attached", "volume_id": "vol-019e3a93f209f52f4" } } ], "capacity_reservation_specification": { "capacity_reservation_preference": "open" }, "client_token": "", "cpu_options": { "core_count": 1, "threads_per_core": 1 }, "ebs_optimized": false, "ena_support": true, "hibernation_options": { "configured": false }, "hypervisor": "xen", "image_id": "ami-0cc293023f983ed53", "instance_id": "i-0c79943c90ea5a878", "instance_type": "t2.micro", "key_name": "ebuynow", "launch_time": "2019-10-19T01:49:34+00:00", "monitoring": { "state": "disabled" }, "network_interfaces": [ { "attachment": { "attach_time": "2019-10-19T01:49:34+00:00", "attachment_id": "eni-attach-0bc3baceb808158e4", "delete_on_termination": true, "device_index": 0, "status": "attached" }, "description": "", "groups": [ { "group_id": "sg-0e9f7f6ebc633f0db", "group_name": "launch-wizard-1" } ], "interface_type": "interface", "ipv6_addresses": [], "mac_address": "02:01:a3:99:44:10", "network_interface_id": "eni-0f691aaf3a5696463", "owner_id": "710235054459", "private_dns_name": "ip-172-17-1-25.eu-central-1.compute.internal", "private_ip_address": "172.17.1.25", "private_ip_addresses": [ { "primary": true, "private_dns_name": "ip-172-17-1-25.eu-central-1.compute.internal", "private_ip_address": "172.17.1.25" } ], "source_dest_check": true, "status": "in-use", "subnet_id": "subnet-075ed2430e055fb28", "vpc_id": "vpc-f476929e" } ], "placement": { "availability_zone": "eu-central-1a", "group_name": "", "tenancy": "default" }, "private_dns_name": "ip-172-17-1-25.eu-central-1.compute.internal", "private_ip_address": "172.17.1.25", "product_codes": [], "public_dns_name": "", "root_device_name": "/dev/xvda", "root_device_type": "ebs", "security_groups": [ { "group_id": "sg-0e9f7f6ebc633f0db", "group_name": "launch-wizard-1" } ], "source_dest_check": true, "state": { "code": 16, "name": "running" }, "state_transition_reason": "", "subnet_id": "subnet-075ed2430e055fb28", "tags": { "Name": "awseu-test-1" }, "virtualization_type": "hvm", "vpc_id": "vpc-f476929e" } ] } TASK [Destroy_Instance : Terminate EC2 instance] ******************************************************************************************************************************************************************** changed: [localhost] => (item={u'root_device_type': u'ebs', u'private_dns_name': u'ip-172-17-1-25.eu-central-1.compute.internal', u'cpu_options': {u'threads_per_core': 1, u'core_count': 1}, u'security_groups': [{u'group_id': u'sg-0e9f7f6ebc633f0db', u'group_name': u'launch-wizard-1'}], u'monitoring': {u'state': u'disabled'}, u'subnet_id': u'subnet-075ed2430e055fb28', u'ebs_optimized': False, u'state': {u'code': 16, u'name': u'running'}, u'source_dest_check': True, u'client_token': u'', u'virtualization_type': u'hvm', u'root_device_name': u'/dev/xvda', u'tags': {u'Name': u'awseu-test-1'}, u'key_name': u'ebuynow', u'image_id': u'ami-0cc293023f983ed53', u'ena_support': True, u'hibernation_options': {u'configured': False}, u'capacity_reservation_specification': {u'capacity_reservation_preference': u'open'}, u'public_dns_name': u'', u'block_device_mappings': [{u'ebs': {u'status': u'attached', u'delete_on_termination': True, u'attach_time': u'2019-10-19T01:49:35+00:00', u'volume_id': u'vol-019e3a93f209f52f4'}, u'device_name': u'/dev/xvda'}], u'placement': {u'group_name': u'', u'tenancy': u'default', u'availability_zone': u'eu-central-1a'}, u'ami_launch_index': 0, u'hypervisor': u'xen', u'network_interfaces': [{u'status': u'in-use', u'description': u'', u'subnet_id': u'subnet-075ed2430e055fb28', u'interface_type': u'interface', u'ipv6_addresses': [], u'network_interface_id': u'eni-0f691aaf3a5696463', u'private_dns_name': u'ip-172-17-1-25.eu-central-1.compute.internal', u'attachment': {u'status': u'attached', u'device_index': 0, u'attachment_id': u'eni-attach-0bc3baceb808158e4', u'delete_on_termination': True, u'attach_time': u'2019-10-19T01:49:34+00:00'}, u'private_ip_addresses': [{u'private_ip_address': u'172.17.1.25', u'primary': True, u'private_dns_name': u'ip-172-17-1-25.eu-central-1.compute.internal'}], u'mac_address': u'02:01:a3:99:44:10', u'private_ip_address': u'172.17.1.25', u'vpc_id': u'vpc-f476929e', u'groups': [{u'group_id': u'sg-0e9f7f6ebc633f0db', u'group_name': u'launch-wizard-1'}], u'source_dest_check': True, u'owner_id': u'710235054459'}], u'launch_time': u'2019-10-19T01:49:34+00:00', u'instance_id': u'i-0c79943c90ea5a878', u'instance_type': u't2.micro', u'architecture': u'x86_64', u'state_transition_reason': u'', u'private_ip_address': u'172.17.1.25', u'vpc_id': u'vpc-f476929e', u'product_codes': []}) PLAY RECAP ********************************************************************************************************************************************************************************************************** localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Tổng kết
Mình đã hoàn tất hướng dẫn Tự động tạo, xóa instance sử dụng ansible, nhìn chung thì playbook này có ưu điểm là setup được instance nhanh chóng thay vì vào giao diên AWS click các kiểu, nhược điểm là chưa tạo ra multi instance khác loại được, vì nếu bạn muốn tạo nhiều hơn 1 instance thì nó vẫn ở 1 loại type mà bạn quy định trong variables. Hy vọng tuơng lai mình siêng hơn để cải thiện tính năng 😀
Cám ơn các bạn đã theo dõi!