# Ansible 學習筆記 ## 什麼是Ansible? 是基於Python開發的自動化組態管理工具,為了解決IT維運的問題而誕生,用來自動化、標準化建置所需的環境,減少人工維運失誤,確保工具、版本都是一致的。 ## Ansible常見的關鍵字 **Inventory** 是一份主機清單,定義了 Ansible 將要管理的主機的資訊,如主機名稱、IP 位址、連線設定等。可以使用 INI 檔案或 YML 檔案格式來定義,會有控制主機(Control Machine)跟受管節點(Managed Node)兩種角色。 **Ad-Hoc Commands** 在命令列中直接使用 Ansible 執行的命令,用於執行簡單的操作而不需要編寫 Playbook。 **Playbook** 字面上的意思是劇本,就是指把所有指令串在一起,批次執行的概念。 **Vault** 用於加密和解密敏感數據,如密碼、金鑰等。可以將數據加密到 playbook 中,以確保在存儲或共享時的安全性。 **Module** Module 是 Ansible 的基本操作單位,每個模組負責執行特定的操作,例如複製檔案、啟動服務、安裝軟體等。Ansible 模組可用於 Playbook 中的任務。 **Task** Task 是 Playbook 中的基本操作,它使用模組執行具體的工作。每個 Playbook 由一個或多個任務構成。 **Role** Role 是一個可以重複使用的 Playbook 片段,它包含了多個 tasks、handlers、變數等。這使得在多個 Playbook 中共享和重複使用特定功能變得更容易。 **Handler** Handlers 是與特定事件相關聯的操作,例如重新啟動服務或執行其他處理程序。Handlers 只有在被通知時才執行。 **Facts** Facts 是由 Ansible 收集的目標主機的資訊,如作業系統類型、IP 位址等。這些資訊可以在 Playbook 中使用。 **Roles Path** Roles Path 是一個目錄結構,用於存放 Ansible 角色。可以通過設定 roles_path 來指定角色的搜尋路徑。 **Tags** Tags 允許在 Playbook 中標記任務,以便只執行標有特定標記的任務。這對於選擇性執行 Playbook 中的特定部分很有用。 **Loops** Loops 允許在 Playbook 中重複執行任務,使得可以更容易地處理一組主機或一組數據。 # 實作一:執行Playbook並以Localhost為目標 這邊先不管inventory, roles,直接建立一個playbook.yml,並將以下內容貼上: ```yml= --- # Ansible的開頭 - name: Play with Ansible # 這個Play的名稱 hosts: localhost # 表示要部署的對象 tasks: # 表示要執行的任務 - name: Execute "df -h" # 這個task的名稱 ansible.builtin.command: df -h # 使用內建的模組包 `ansible.builtin.command` 中的 `df -h` 指令 register: output # 相當於建立一個變數 `output` 來儲存 `df -h` 的輸出 changed_when: output.rc == 0 # TODO: 比較難解釋清楚,待補充 - name: Show stdout # 第二個任務的名稱 ansible.builtin.debug: # 使用 `debug` 這個模組包 msg: "{{ output.stdout_lines }}" # 以列表形式顯示 `output` 的內容 ``` > 上述內容,總得來說是以`localhost`為目標,執行`df -h`指令,並將結果傳入`output`變數中,再把`output`印出來。 如果有安裝`ansible-lint`就可以透過 `ansible-lint playbook.yml` 來檢查語法有無問題,值得注意的是,結尾必須要換行! 透過 `ansible-playbook playbook.yml` 來執行playbook,結果如下: ```bash= [WARNING]: No inventory was parsed, only implicit localhost is available [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [Play with Ansible] ************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************** ok: [localhost] TASK [Execute "df -h"] **************************************************************************************************************** changed: [localhost] TASK [Show stdout] ******************************************************************************************************************** ok: [localhost] => { "msg": [ "Filesystem Size Used Avail Capacity iused ifree %iused Mounted on", "/dev/disk3s1s1 926Gi 9.5Gi 553Gi 2% 390k 4.3G 0% /", "devfs 201Ki 201Ki 0Bi 100% 696 0 100% /dev", "/dev/disk3s6 926Gi 9.0Gi 553Gi 2% 9 5.8G 0% /System/Volumes/VM", "/dev/disk3s2 926Gi 10Gi 553Gi 2% 1.3k 5.8G 0% /System/Volumes/Preboot", "/dev/disk3s4 926Gi 656Mi 553Gi 1% 287 5.8G 0% /System/Volumes/Update", "/dev/disk1s2 500Mi 6.0Mi 481Mi 2% 1 4.9M 0% /System/Volumes/xarts", "/dev/disk1s1 500Mi 6.1Mi 481Mi 2% 34 4.9M 0% /System/Volumes/iSCPreboot", "/dev/disk1s3 500Mi 2.0Mi 481Mi 1% 52 4.9M 0% /System/Volumes/Hardware", "/dev/disk3s5 926Gi 342Gi 553Gi 39% 2.2M 5.8G 0% /System/Volumes/Data", "map auto_home 0Bi 0Bi 0Bi 100% 0 0 - /System/Volumes/Data/home", "/dev/disk2s1 5.0Gi 1.5Gi 3.5Gi 31% 58 36M 0% /System/Volumes/Update/SFR/mnt1", "/dev/disk3s1 926Gi 9.5Gi 553Gi 2% 390k 4.3G 0% /System/Volumes/Update/mnt1" ] } PLAY RECAP **************************************************************************************************************************** localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ``` # 實作二:Ansible to AWS EC2 ## 步驟: * 建立AWS Account * 安裝Ansible與相依套件 * 建立SSH Keys * 建立Directory Strcuture * 建立Ansible-Vault * 建立Ansible-Playbook * 執行Ansible-Playbook來部署EC2 * 透過SSH連線EC2 ## 建立AWS Account 略 ## 安裝Ansible與相依套件 ### 需要安裝: * python * pip * boto * boto3 * ansible ### 安裝指令如下: homebrew (macOS) ```bash sudo brew install python@3 # 透過Homebrew install python3, pip3 ``` ```bash pip3 install boto boto3 ansible ansible-lint # 透過pip3 install boto, boto3, ansible and ansible-lint ``` apt (Ubuntu) ```bash! sudo apt update && sudo apt install python3 ``` ```bash! sudo apt install python-pip3 ``` 檢查版本指令: ```bash! python3 --version # Check python3 version pip3 --version # Check pip3 version ``` ## 建立SSH Keys 建立一對金鑰,指令如下: ```bash! ssh-keygen -t rsa -b 4096 -f ~/.ssh/ansible_to_ec2_key Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): #可以留白 ``` 編輯私鑰權限: ```bash! chmod 400 ~/.ssh/ansible_to_ec2_key #確保私鑰不會被公開存取 ``` ## 建立Directory Strcuture 要建立的目錄架構如下: ```bash! ansible_start ├── group_vars │ └── all │ └── pass.yml └── playbook.yml ``` 指令如下: ```bash! # 建立目錄 mkdir -p ansible_start/group_vars/all/ # 切換至ansible_start cd ansible_start # 建立劇本 touch playbook.yml ``` ## 建立Ansible-Vault 這步驟是為了避免敏感資訊曝光而做的,我們接著會將 playbook 所需得敏感資訊加密儲存在`pass.yml`檔案。 > :::spoiler [**如何建立Access Key?**] > 首先,我們先去AWS IAM Users建立access key > ![image](https://hackmd.io/_uploads/H1VUCB4IT.png) > > 選擇建立第三方服務存取方式 > ![image](https://hackmd.io/_uploads/BkhwAS48p.png) > > 簡單描述即可 > ![image](https://hackmd.io/_uploads/HkroCBEL6.png) > > 這兩個值 `Access Key`, `Secret Access key`可以先記下來,後續用得到 > ![image](https://hackmd.io/_uploads/Syq6CBNUT.png) > ::: 透過`ansible-vault create`指令建立`pass.yml`: ```bash! ansible-vault create ./group_vars/all/pass.yml ``` 透過`ansible-vault edit`指令編輯`pass.yml`: ```bash! ansible-vault edit group_vars/all/pass.yml Vault password: ec2_access_key: AAAAAAAAAAAAAABBBBBBBBBBBB ec2_secret_key: afjdfadgf$fgajk5ragesfjgjsfdbtirhf ``` > 這邊是以vim編輯器開啟`pass.yml`,按下`i`即可進入編輯模式,將剛複製好的`Access key`, `Secret access key`貼上去,完成後按下`esc`並輸入`:wq`就完成了。 :::spoiler [秘密] AKIA4MSYOBEVI6IJXWXQ kAXQQYAOUZfGYZoPrq4pYwKT4gX5aSrkkvk+/EAk ::: ## 建立Ansible-Playbook `boto3`是 AWS 的 SDK for Python,提供了 AWS 操作底層資源的 API,意思是安裝了`boto3`,就可以在`playbook.yml`中輕鬆 建立 EC2 Instance, 管理 S3 Bucket, 設定 Route53 路由 等等,那麼這次我們引入下列三個模組包,方便我們建立 EC2 Instance 及相關資源,分別是: * `amazon.aws.ec2_instance` * `amazon.aws.ec2_security_group` * `amazon.aws.ec2_key` 不囉唆,先複製貼上,再來慢慢理解他!! :::spoiler [點開我,以獲得圖片支援] 1. `image: `要輸入的`ami_id`在這邊 ![image](https://hackmd.io/_uploads/BkwoDUEUa.png) ::: ```bash= # Deploy to AWS EC2 Playbook --- - name: Deploy to ec2 playbook # 這個playbook的名稱 hosts: localhost # 要操作的主機是localhost connection: local # 指定連線方式 gather_facts: False # 拒絕收集 facts 資訊 vars: # 定義變數的區塊 key_name: ansible_to_ec2_key # 指定 SSH key region: ap-southeast-1 # 指定區域 image: ami-06d9da1b3038d0066 # 指定 AMI,這邊選擇自建的 instance_type: t2.micro # 指定規格 subnet_id: subnet-0d0cf0e05588efea2 # 指定 subnet sg_id: sg-0c4034b9faa42b1d0 # 指定 security group ec2_name: "wilson-demo-ec2" # 指定 ec2名稱 tasks: - name: Provisioning EC2 instances block: - name: Amazon EC2 | Upload Key Pair # 為 EC2 上傳金鑰 amazon.aws.ec2_key: name: "{{ key_name }}" region: "{{ region }}" aws_access_key: "{{ ec2_access_key }}" # 從 vault 取得 aws_secret_key: "{{ ec2_secret_key }}" # 從 vault 取得 key_material: "{{ lookup('file', '~/.ssh/ansible_to_ec2_key.pub') }}" # 上傳在本地端的公鑰給EC2 - name: Start an instance with a public IP address amazon.aws.ec2_instance: # 這邊就是建立 EC2 時,所需的設定,通通在 vars 那邊定義好了 name: "{{ ec2_name }}-{{ item }}" # 這邊的 item 跟後面的 loop 都是這個套件包建立迴圈事件的元素 key_name: "{{ key_name }}" vpc_subnet_id: "{{ subnet_id }}" instance_type: "{{ instance_type }}" security_group: "{{ sg_id }}" aws_access_key: "{{ ec2_access_key }}" aws_secret_key: "{{ ec2_secret_key }}" region: "{{ region }}" network: assign_public_ip: true image_id: "{{ image }}" tags: # 為 EC2 建立 tags Environment: Testing # key: value loop: "{{ range(1, 3) | list }}" # 建立一個 list,從 1 開始,2 結束 tags: ['create_ec2'] # 必須在命令行執行時加上這個參數 "--tags create_ec2",這些 tasks 才會執行 - name: Facts block: # 這個區塊負責印出 instances 的資訊 - name: Get instances facts ec2_instance_info: aws_access_key: "{{ ec2_access_key }}" aws_secret_key: "{{ ec2_secret_key }}" region: "{{ region }}" register: result - name: Instances ID ansible.builtin.debug: msg: "ID: {{ item.instance_id }} - State: {{ item.state.name }} - Public DNS: {{ item.public_dns_name }}" loop: "{{ result.instances }}" tags: always ``` ## 執行Ansible-Playbook來部署EC2 完整指令如下: ```bash! ansible-playbook playbook.yml --ask-vault-pass --tags create_ec2 Vault password: ``` 需要注意的是這個 playbook 會需要機敏資訊`ec2_access_key`, `ec2_secret_key`,而先前我們已經透過 Vault 加密儲存到`pass.yml`了,因此還需要帶這個參數來取得資訊`--ask-vault-pass`,以及透過這個參數`--tags create_ec2`來執行建立 EC2 的那個 `block: ` 執行結果如下: ```bash= ansible-playbook playbook.yml --ask-vault-pass --tags create_ec2 Vault password: [WARNING]: No inventory was parsed, only implicit localhost is available [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [Deploy to ec2 playbook] ********************************************************************************************************* TASK [Amazon EC2 | Upload Key Pair] *************************************************************************************************** ok: [localhost] TASK [Start an instance with a public IP address] ************************************************************************************* ok: [localhost] => (item=1) ok: [localhost] => (item=2) TASK [Get instances facts] ************************************************************************************************************ ok: [localhost] TASK [Instances ID] ******************************************************************************************************************* ok: [localhost] => (item={'ami_launch_index': 0, 'image_id': 'ami-03caf91bb3d81b843', 'instance_id': 'i-057ae32edacb901af', 'instance_type': 't2.nano', 'key_name': '1201', 'launch_time': '2023-12-03T18:31:45+00:00', 'monitoring': {'state': 'disabled'}, 'placement': {'availability_zone': 'ap-southeast-1a', 'group_name': '', 'tenancy': 'default'}, 'private_dns_name': 'ip-172-31-33-208.ap-southeast-1.compute.internal', 'private_ip_address': '172.31.33.208', 'product_codes': [], 'public_dns_name': '', 'state': {'code': 80, 'name': 'stopped'}, 'state_transition_reason': 'User initiated (2023-12-06 04:09:07 GMT)', 'subnet_id': 'subnet-97d21fdf', 'vpc_id': 'vpc-ce9b73a8', 'architecture': 'x86_64', 'block_device_mappings': [{'device_name': '/dev/sda1', 'ebs': {'attach_time': '2023-12-01T10:56:57+00:00', 'delete_on_termination': True, 'status': 'attached', 'volume_id': 'vol-0948b0a2db013d195'}}], 'client_token': '767383b8-590a-44fe-9df9-6cc614728bb8', 'ebs_optimized': False, 'ena_support': True, 'hypervisor': 'xen', 'network_interfaces': [{'attachment': {'attach_time': '2023-12-01T10:56:56+00:00', 'attachment_id': 'eni-attach-039aa961e2120bc6f', 'delete_on_termination': True, 'device_index': 0, 'status': 'attached', 'network_card_index': 0}, 'description': '', 'groups': [{'group_name': 'launch-wizard-10', 'group_id': 'sg-07e7b10977d74cc87'}], 'ipv6_addresses': [], 'mac_address': '06:97:54:fb:d0:ec', 'network_interface_id': 'eni-0aaeb34f9b23fef63', 'owner_id': '851662735658', 'private_dns_name': 'ip-172-31-33-208.ap-southeast-1.compute.internal', 'private_ip_address': '172.31.33.208', 'private_ip_addresses': [{'primary': True, 'private_dns_name': 'ip-172-31-33-208.ap-southeast-1.compute.internal', 'private_ip_address': '172.31.33.208'}], 'source_dest_check': True, 'status': 'in-use', 'subnet_id': 'subnet-97d21fdf', 'vpc_id': 'vpc-ce9b73a8', 'interface_type': 'interface'}], 'root_device_name': '/dev/sda1', 'root_device_type': 'ebs', 'security_groups': [{'group_name': 'launch-wizard-10', 'group_id': 'sg-07e7b10977d74cc87'}], 'source_dest_check': True, 'state_reason': {'code': 'Client.UserInitiatedShutdown', 'message': 'Client.UserInitiatedShutdown: User initiated shutdown'}, 'virtualization_type': 'hvm', 'cpu_options': {'core_count': 1, 'threads_per_core': 1}, 'capacity_reservation_specification': {'capacity_reservation_preference': 'open'}, 'hibernation_options': {'configured': False}, 'metadata_options': {'state': 'applied', 'http_tokens': 'required', 'http_put_response_hop_limit': 2, 'http_endpoint': 'enabled', 'http_protocol_ipv6': 'disabled', 'instance_metadata_tags': 'disabled'}, 'enclave_options': {'enabled': False}, 'platform_details': 'Linux/UNIX', 'usage_operation': 'RunInstances', 'usage_operation_update_time': '2023-12-01T10:56:56+00:00', 'private_dns_name_options': {'hostname_type': 'ip-name', 'enable_resource_name_dns_a_record': True, 'enable_resource_name_dns_aaaa_record': False}, 'maintenance_options': {'auto_recovery': 'default'}, 'current_instance_boot_mode': 'legacy-bios', 'tags': {}}) => { "msg": "ID: i-057ae32edacb901af - State: stopped - Public DNS: " } ok: [localhost] => (item={'ami_launch_index': 0, 'image_id': 'ami-02453f5468b897e31', 'instance_id': 'i-0c83efc6acbc05891', 'instance_type': 't2.micro', 'key_name': '1201', 'launch_time': '2023-12-03T18:32:19+00:00', 'monitoring': {'state': 'disabled'}, 'placement': {'availability_zone': 'ap-southeast-1a', 'group_name': '', 'tenancy': 'default'}, 'private_dns_name': 'ip-172-31-47-169.ap-southeast-1.compute.internal', 'private_ip_address': '172.31.47.169', 'product_codes': [], 'public_dns_name': '', 'state': {'code': 80, 'name': 'stopped'}, 'state_transition_reason': 'User initiated (2023-12-06 04:09:07 GMT)', 'subnet_id': 'subnet-97d21fdf', 'vpc_id': 'vpc-ce9b73a8', 'architecture': 'x86_64', 'block_device_mappings': [{'device_name': '/dev/xvda', 'ebs': {'attach_time': '2023-12-03T18:32:19+00:00', 'delete_on_termination': True, 'status': 'attached', 'volume_id': 'vol-0999b5c28bb2c42c1'}}], 'client_token': '1bc9d3b5-6d16-452a-b005-fdd6cfce80e0', 'ebs_optimized': False, 'ena_support': True, 'hypervisor': 'xen', 'network_interfaces': [{'attachment': {'attach_time': '2023-12-03T18:32:19+00:00', 'attachment_id': 'eni-attach-01469f65da2aca031', 'delete_on_termination': True, 'device_index': 0, 'status': 'attached', 'network_card_index': 0}, 'description': '', 'groups': [{'group_name': 'launch-wizard-11', 'group_id': 'sg-07cd70fa091c68e06'}], 'ipv6_addresses': [], 'mac_address': '06:a7:87:f3:46:a2', 'network_interface_id': 'eni-02299da16d08a736b', 'owner_id': '851662735658', 'private_dns_name': 'ip-172-31-47-169.ap-southeast-1.compute.internal', 'private_ip_address': '172.31.47.169', 'private_ip_addresses': [{'primary': True, 'private_dns_name': 'ip-172-31-47-169.ap-southeast-1.compute.internal', 'private_ip_address': '172.31.47.169'}], 'source_dest_check': True, 'status': 'in-use', 'subnet_id': 'subnet-97d21fdf', 'vpc_id': 'vpc-ce9b73a8', 'interface_type': 'interface'}], 'root_device_name': '/dev/xvda', 'root_device_type': 'ebs', 'security_groups': [{'group_name': 'launch-wizard-11', 'group_id': 'sg-07cd70fa091c68e06'}], 'source_dest_check': True, 'state_reason': {'code': 'Client.UserInitiatedShutdown', 'message': 'Client.UserInitiatedShutdown: User initiated shutdown'}, 'virtualization_type': 'hvm', 'cpu_options': {'core_count': 1, 'threads_per_core': 1}, 'capacity_reservation_specification': {'capacity_reservation_preference': 'open'}, 'hibernation_options': {'configured': False}, 'metadata_options': {'state': 'applied', 'http_tokens': 'required', 'http_put_response_hop_limit': 2, 'http_endpoint': 'enabled', 'http_protocol_ipv6': 'disabled', 'instance_metadata_tags': 'disabled'}, 'enclave_options': {'enabled': False}, 'boot_mode': 'uefi-preferred', 'platform_details': 'Linux/UNIX', 'usage_operation': 'RunInstances', 'usage_operation_update_time': '2023-12-03T18:32:19+00:00', 'private_dns_name_options': {'hostname_type': 'ip-name', 'enable_resource_name_dns_a_record': True, 'enable_resource_name_dns_aaaa_record': False}, 'maintenance_options': {'auto_recovery': 'default'}, 'current_instance_boot_mode': 'legacy-bios', 'tags': {}}) => { "msg": "ID: i-0c83efc6acbc05891 - State: stopped - Public DNS: " } ok: [localhost] => (item={'ami_launch_index': 0, 'image_id': 'ami-06d9da1b3038d0066', 'instance_id': 'i-08166153a0bdc41e5', 'instance_type': 't2.micro', 'key_name': 'ansible_to_ec2_key', 'launch_time': '2023-12-12T07:43:38+00:00', 'monitoring': {'state': 'disabled'}, 'placement': {'availability_zone': 'ap-southeast-1a', 'group_name': '', 'tenancy': 'default'}, 'private_dns_name': '', 'product_codes': [], 'public_dns_name': '', 'state': {'code': 48, 'name': 'terminated'}, 'state_transition_reason': 'User initiated (2023-12-12 09:12:49 GMT)', 'architecture': 'x86_64', 'block_device_mappings': [], 'client_token': '1fdbe536685c4e27a5959a1d104c2b9a', 'ebs_optimized': False, 'ena_support': True, 'hypervisor': 'xen', 'network_interfaces': [], 'root_device_name': '/dev/xvda', 'root_device_type': 'ebs', 'security_groups': [], 'state_reason': {'code': 'Client.UserInitiatedShutdown', 'message': 'Client.UserInitiatedShutdown: User initiated shutdown'}, 'tags': {'Environment': 'Testing', 'Name': 'wilson-demo-ec2-1'}, 'virtualization_type': 'hvm', 'cpu_options': {'core_count': 1, 'threads_per_core': 1}, 'capacity_reservation_specification': {'capacity_reservation_preference': 'open'}, 'hibernation_options': {'configured': False}, 'metadata_options': {'state': 'pending', 'http_tokens': 'optional', 'http_put_response_hop_limit': 1, 'http_endpoint': 'enabled', 'http_protocol_ipv6': 'disabled', 'instance_metadata_tags': 'disabled'}, 'enclave_options': {'enabled': False}, 'platform_details': 'Linux/UNIX', 'usage_operation': 'RunInstances', 'usage_operation_update_time': '2023-12-12T07:43:38+00:00', 'maintenance_options': {'auto_recovery': 'default'}, 'current_instance_boot_mode': 'legacy-bios'}) => { "msg": "ID: i-08166153a0bdc41e5 - State: terminated - Public DNS: " } ok: [localhost] => (item={'ami_launch_index': 0, 'image_id': 'ami-06d9da1b3038d0066', 'instance_id': 'i-0d7310f9dec8efe26', 'instance_type': 't2.micro', 'key_name': 'ansible_to_ec2_key', 'launch_time': '2023-12-12T07:43:42+00:00', 'monitoring': {'state': 'disabled'}, 'placement': {'availability_zone': 'ap-southeast-1a', 'group_name': '', 'tenancy': 'default'}, 'private_dns_name': '', 'product_codes': [], 'public_dns_name': '', 'state': {'code': 48, 'name': 'terminated'}, 'state_transition_reason': 'User initiated (2023-12-12 09:12:49 GMT)', 'architecture': 'x86_64', 'block_device_mappings': [], 'client_token': 'fd426d0e2a3b4270ad4f24396acdd6b2', 'ebs_optimized': False, 'ena_support': True, 'hypervisor': 'xen', 'network_interfaces': [], 'root_device_name': '/dev/xvda', 'root_device_type': 'ebs', 'security_groups': [], 'state_reason': {'code': 'Client.UserInitiatedShutdown', 'message': 'Client.UserInitiatedShutdown: User initiated shutdown'}, 'tags': {'Environment': 'Testing', 'Name': 'wilson-demo-ec2-2'}, 'virtualization_type': 'hvm', 'cpu_options': {'core_count': 1, 'threads_per_core': 1}, 'capacity_reservation_specification': {'capacity_reservation_preference': 'open'}, 'hibernation_options': {'configured': False}, 'metadata_options': {'state': 'pending', 'http_tokens': 'optional', 'http_put_response_hop_limit': 1, 'http_endpoint': 'enabled', 'http_protocol_ipv6': 'disabled', 'instance_metadata_tags': 'disabled'}, 'enclave_options': {'enabled': False}, 'platform_details': 'Linux/UNIX', 'usage_operation': 'RunInstances', 'usage_operation_update_time': '2023-12-12T07:43:42+00:00', 'maintenance_options': {'auto_recovery': 'default'}, 'current_instance_boot_mode': 'legacy-bios'}) => { "msg": "ID: i-0d7310f9dec8efe26 - State: terminated - Public DNS: " } ok: [localhost] => (item={'ami_launch_index': 0, 'image_id': 'ami-06d9da1b3038d0066', 'instance_id': 'i-0cd1d8dc3cd3cdaec', 'instance_type': 't2.micro', 'key_name': 'ansible_to_ec2_key', 'launch_time': '2023-12-12T09:13:20+00:00', 'monitoring': {'state': 'disabled'}, 'placement': {'availability_zone': 'ap-southeast-1a', 'group_name': '', 'tenancy': 'default'}, 'private_dns_name': 'ip-192-168-0-96.ap-southeast-1.compute.internal', 'private_ip_address': '192.168.0.96', 'product_codes': [{'product_code_id': '9hqdefxcpnx3shvhw3vg8vxv7', 'product_code_type': 'marketplace'}], 'public_dns_name': 'ec2-52-77-226-10.ap-southeast-1.compute.amazonaws.com', 'public_ip_address': '52.77.226.10', 'state': {'code': 16, 'name': 'running'}, 'state_transition_reason': '', 'subnet_id': 'subnet-0d0cf0e05588efea2', 'vpc_id': 'vpc-002d5d167dd547eeb', 'architecture': 'x86_64', 'block_device_mappings': [{'device_name': '/dev/xvda', 'ebs': {'attach_time': '2023-12-12T09:13:21+00:00', 'delete_on_termination': True, 'status': 'attached', 'volume_id': 'vol-0c30e5f9340c80c33'}}], 'client_token': '653ef5b9852240b2bcfbce57d688e0aa', 'ebs_optimized': False, 'ena_support': True, 'hypervisor': 'xen', 'network_interfaces': [{'association': {'ip_owner_id': 'amazon', 'public_dns_name': 'ec2-52-77-226-10.ap-southeast-1.compute.amazonaws.com', 'public_ip': '52.77.226.10'}, 'attachment': {'attach_time': '2023-12-12T09:13:20+00:00', 'attachment_id': 'eni-attach-0904f33b984ecc34c', 'delete_on_termination': True, 'device_index': 0, 'status': 'attached', 'network_card_index': 0}, 'description': '', 'groups': [{'group_name': 'wilson-db-sg', 'group_id': 'sg-0c4034b9faa42b1d0'}], 'ipv6_addresses': [], 'mac_address': '06:89:f6:bb:b9:70', 'network_interface_id': 'eni-0d1412e9b44e28bb3', 'owner_id': '851662735658', 'private_dns_name': 'ip-192-168-0-96.ap-southeast-1.compute.internal', 'private_ip_address': '192.168.0.96', 'private_ip_addresses': [{'association': {'ip_owner_id': 'amazon', 'public_dns_name': 'ec2-52-77-226-10.ap-southeast-1.compute.amazonaws.com', 'public_ip': '52.77.226.10'}, 'primary': True, 'private_dns_name': 'ip-192-168-0-96.ap-southeast-1.compute.internal', 'private_ip_address': '192.168.0.96'}], 'source_dest_check': True, 'status': 'in-use', 'subnet_id': 'subnet-0d0cf0e05588efea2', 'vpc_id': 'vpc-002d5d167dd547eeb', 'interface_type': 'interface'}], 'root_device_name': '/dev/xvda', 'root_device_type': 'ebs', 'security_groups': [{'group_name': 'wilson-db-sg', 'group_id': 'sg-0c4034b9faa42b1d0'}], 'source_dest_check': True, 'tags': {'Name': 'wilson-demo-ec2-2', 'Environment': 'Testing'}, 'virtualization_type': 'hvm', 'cpu_options': {'core_count': 1, 'threads_per_core': 1}, 'capacity_reservation_specification': {'capacity_reservation_preference': 'open'}, 'hibernation_options': {'configured': False}, 'metadata_options': {'state': 'applied', 'http_tokens': 'optional', 'http_put_response_hop_limit': 1, 'http_endpoint': 'enabled', 'http_protocol_ipv6': 'disabled', 'instance_metadata_tags': 'disabled'}, 'enclave_options': {'enabled': False}, 'platform_details': 'Linux/UNIX', 'usage_operation': 'RunInstances', 'usage_operation_update_time': '2023-12-12T09:13:20+00:00', 'private_dns_name_options': {'hostname_type': 'ip-name', 'enable_resource_name_dns_a_record': False, 'enable_resource_name_dns_aaaa_record': False}, 'maintenance_options': {'auto_recovery': 'default'}, 'current_instance_boot_mode': 'legacy-bios'}) => { "msg": "ID: i-0cd1d8dc3cd3cdaec - State: running - Public DNS: ec2-52-77-226-10.ap-southeast-1.compute.amazonaws.com" } ok: [localhost] => (item={'ami_launch_index': 0, 'image_id': 'ami-06d9da1b3038d0066', 'instance_id': 'i-0ed629a354bcfaad7', 'instance_type': 't2.micro', 'key_name': 'ansible_to_ec2_key', 'launch_time': '2023-12-12T09:13:16+00:00', 'monitoring': {'state': 'disabled'}, 'placement': {'availability_zone': 'ap-southeast-1a', 'group_name': '', 'tenancy': 'default'}, 'private_dns_name': 'ip-192-168-0-4.ap-southeast-1.compute.internal', 'private_ip_address': '192.168.0.4', 'product_codes': [{'product_code_id': '9hqdefxcpnx3shvhw3vg8vxv7', 'product_code_type': 'marketplace'}], 'public_dns_name': 'ec2-18-143-138-135.ap-southeast-1.compute.amazonaws.com', 'public_ip_address': '18.143.138.135', 'state': {'code': 16, 'name': 'running'}, 'state_transition_reason': '', 'subnet_id': 'subnet-0d0cf0e05588efea2', 'vpc_id': 'vpc-002d5d167dd547eeb', 'architecture': 'x86_64', 'block_device_mappings': [{'device_name': '/dev/xvda', 'ebs': {'attach_time': '2023-12-12T09:13:16+00:00', 'delete_on_termination': True, 'status': 'attached', 'volume_id': 'vol-0cc4653c9903cdfc7'}}], 'client_token': 'cd7283baefbb433b95e87a1d28e60670', 'ebs_optimized': False, 'ena_support': True, 'hypervisor': 'xen', 'network_interfaces': [{'association': {'ip_owner_id': 'amazon', 'public_dns_name': 'ec2-18-143-138-135.ap-southeast-1.compute.amazonaws.com', 'public_ip': '18.143.138.135'}, 'attachment': {'attach_time': '2023-12-12T09:13:16+00:00', 'attachment_id': 'eni-attach-05c9cb5fc507cf865', 'delete_on_termination': True, 'device_index': 0, 'status': 'attached', 'network_card_index': 0}, 'description': '', 'groups': [{'group_name': 'wilson-db-sg', 'group_id': 'sg-0c4034b9faa42b1d0'}], 'ipv6_addresses': [], 'mac_address': '06:26:e8:b8:a9:18', 'network_interface_id': 'eni-0e8a16527bf168dd0', 'owner_id': '851662735658', 'private_dns_name': 'ip-192-168-0-4.ap-southeast-1.compute.internal', 'private_ip_address': '192.168.0.4', 'private_ip_addresses': [{'association': {'ip_owner_id': 'amazon', 'public_dns_name': 'ec2-18-143-138-135.ap-southeast-1.compute.amazonaws.com', 'public_ip': '18.143.138.135'}, 'primary': True, 'private_dns_name': 'ip-192-168-0-4.ap-southeast-1.compute.internal', 'private_ip_address': '192.168.0.4'}], 'source_dest_check': True, 'status': 'in-use', 'subnet_id': 'subnet-0d0cf0e05588efea2', 'vpc_id': 'vpc-002d5d167dd547eeb', 'interface_type': 'interface'}], 'root_device_name': '/dev/xvda', 'root_device_type': 'ebs', 'security_groups': [{'group_name': 'wilson-db-sg', 'group_id': 'sg-0c4034b9faa42b1d0'}], 'source_dest_check': True, 'tags': {'Name': 'wilson-demo-ec2-1', 'Environment': 'Testing'}, 'virtualization_type': 'hvm', 'cpu_options': {'core_count': 1, 'threads_per_core': 1}, 'capacity_reservation_specification': {'capacity_reservation_preference': 'open'}, 'hibernation_options': {'configured': False}, 'metadata_options': {'state': 'applied', 'http_tokens': 'optional', 'http_put_response_hop_limit': 1, 'http_endpoint': 'enabled', 'http_protocol_ipv6': 'disabled', 'instance_metadata_tags': 'disabled'}, 'enclave_options': {'enabled': False}, 'platform_details': 'Linux/UNIX', 'usage_operation': 'RunInstances', 'usage_operation_update_time': '2023-12-12T09:13:16+00:00', 'private_dns_name_options': {'hostname_type': 'ip-name', 'enable_resource_name_dns_a_record': False, 'enable_resource_name_dns_aaaa_record': False}, 'maintenance_options': {'auto_recovery': 'default'}, 'current_instance_boot_mode': 'legacy-bios'}) => { "msg": "ID: i-0ed629a354bcfaad7 - State: running - Public DNS: ec2-18-143-138-135.ap-southeast-1.compute.amazonaws.com" } PLAY RECAP **************************************************************************************************************************** localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ``` ## 透過SSH連線EC2 從輸出結果可得知 EC2 的`Public DNS`,並以此 domain 來連線它! ![image](https://hackmd.io/_uploads/SyjqIsB8p.png) SSH 連線指令如下: ```bash ssh -i ~/.ssh/ansible_to_ec2_key ec2-user@ec2-18-143-138-135.ap-southeast-1.compute.amazonaws.com ``` 連線成功!! ```bash ssh -i ~/.ssh/ansible_to_ec2_key ec2-user@ec2-18-143-138-135.ap-southeast-1.compute.amazonaws.com The authenticity of host 'ec2-18-143-138-135.ap-southeast-1.compute.amazonaws.com (18.143.138.135)' can't be established. ED25519 key fingerprint is SHA256:BM8nVo1RixE6g54zCH7vo/k47Mjl3BJe7D3jk3vWb9g. This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'ec2-18-143-138-135.ap-southeast-1.compute.amazonaws.com' (ED25519) to the list of known hosts. Enter passphrase for key '/Users/smdick1995/.ssh/ansible_to_ec2_key': __| __|_ ) _| ( / Amazon Linux AMI ___|\___|___| https://aws.amazon.com/amazon-linux-ami/2018.03-release-notes/ 34 package(s) needed for security, out of 56 available Run "sudo yum update" to apply all updates. [ec2-user@ip-192-168-0-4 ~]$ ``` ## 參考資料: > [學習Ansible](https://hackmd.io/@blueskyson/learn-ansible#Ansible-%E7%9A%84%E8%A1%93%E8%AA%9E%EF%BC%9A) > [DevOps: Using Ansible to provision AWS EC2 instances](https://medium.datadriveninvestor.com/devops-using-ansible-to-provision-aws-ec2-instances-3d70a1cb155f) > [Ansible Inventory筆記](https://github.com/880831ian/Ansible?tab=readme-ov-file) > [鳥哥筆記](https://dic.vbird.tw/network_project/zunit05.php#ansible1)