# 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
> 
>
> 選擇建立第三方服務存取方式
> 
>
> 簡單描述即可
> 
>
> 這兩個值 `Access Key`, `Secret Access key`可以先記下來,後續用得到
> 
> :::
透過`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`在這邊

:::
```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 來連線它!

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)