แผนการเรียนรู้
/

สัปดาห์ที่ 9: การจัดการ Configuration ด้วย Ansible

ยกระดับการเขียน Playbook สู่ความเป็นมืออาชีพด้วย Variables, Jinja2 Templates, Roles และ Vault

Agenda วันนี้

  • Configuration Management: แนวคิดและหลักการของ Idempotency
  • Variables: การจัดการตัวแปรและลำดับความสำคัญ (Precedence)
  • Jinja2 Templates: การสร้างไฟล์ Configuration แบบไดนามิก
  • Ansible Roles: โครงสร้าง การสร้าง และการเรียกใช้งาน
  • Ansible Vault: การปกป้องข้อมูลสำคัญ (Sensitive Data)
DevOps Course: Week 9

ทบทวนสัปดาห์ที่ 8 (Recap)

องค์ประกอบพื้นฐานของ Ansible ที่เราได้เรียนรู้ไปแล้ว

Control Node

เครื่องที่ติดตั้ง Ansible และใช้รันคำสั่งไปยังเครื่องอื่นๆ

Inventory

ไฟล์รายชื่อเครื่องเป้าหมาย (Managed Nodes) ที่จัดกลุ่มไว้

Playbook

สคริปต์ YAML ที่ระบุขั้นตอน (Tasks) ที่ต้องการให้ทำงาน

Modules

ชุดคำสั่งสำเร็จรูป เช่น apt, copy, service

Configuration Management คืออะไร?

การรักษาสถานะของระบบ (ซอฟต์แวร์, เซิร์ฟเวอร์, เครือข่าย) ให้อยู่ในรูปแบบที่สอดคล้องกับ "ความคาดหวัง" (Desired State) ที่กำหนดไว้อย่างสม่ำเสมอ

  • Infrastructure Provisioning (เช่น Terraform): สร้าง VM ใหม่, สร้าง VPC, สร้าง Database
  • Configuration Management (เช่น Ansible): เข้าไปใน VM ที่สร้างเสร็จแล้ว เพื่อติดตั้ง Nginx, ตั้งค่าไฟล์ .conf, เปิด Service, สร้าง User

หัวใจสำคัญ: การทำ Idempotency ♻️

"รันกี่ครั้ง ผลลัพธ์สุดท้ายก็ยังเหมือนเดิม และจะไม่ทำสิ่งที่ไม่จำเป็นซ้ำ"

❌ Non-Idempotent

Bash script สั่งเพิ่มข้อความต่อท้ายไฟล์ ถ้ารัน 5 ครั้ง ข้อความจะซ้ำกัน 5 บรรทัด

echo "export PATH=/new/path" >> ~/.bashrc

✅ Idempotent

Ansible ตรวจสอบก่อนว่ามีบรรทัดนี้หรือยัง ถ้ามีแล้ว จะข้าม (Skip) ไม่ทำซ้ำ

- lineinfile:
    path: ~/.bashrc
    line: "export PATH=/new/path"

Modules vs. Command/Shell

การใช้ command หรือ shell module ทำให้เสียคุณสมบัติ Idempotency

# แบบนี้ไม่ดี (จะแสดงสถานะ 'changed' ทุกครั้งที่รัน)

- name: Install git using shell

  shell: apt-get install -y git

# แบบนี้ถูกต้อง (Ansible จะจัดการ Idempotency ให้)

- name: Install git using apt module

  apt:

    name: git

    state: present

การสร้าง Idempotency แบบแมนนวล

ถ้า "ต้อง" ใช้ shell module จริงๆ เราสามารถบอก Ansible ให้เช็คเงื่อนไขได้

- name: Run setup script only if file doesn't exist

  shell: ./setup.sh

  args:

    creates: /opt/app/installed.txt # ถัามีไฟล์นี้แล้ว จะข้ามคำสั่งนี้ไป (ok)


- name: Check status

  shell: myapp --status

  register: app_status

  changed_when: false # บังคับไม่ให้ขึ้นสถานะ changed เพราะแค่เช็คเฉยๆ

Variables (การใช้งานตัวแปร)

Variables ช่วยให้ Playbook ของเรานำกลับมาใช้ใหม่ได้ (Reusable) โดยไม่ต้อง Hardcode ค่าต่างๆ ลงไป

  • ใช้เก็บค่าเช่น Port, Username, เวอร์ชั่นของโปรแกรม, ตำแหน่งไฟล์
  • เรียกใช้งานตัวแปรด้วยไวยากรณ์ Jinja2: {{ variable_name }}
  • สามารถกำหนดค่าได้จากหลายที่ (Playbook, Inventory, CLI)

การกำหนดตัวแปรใน Playbook

---

- name: Install and configure web server

  hosts: webservers

  vars:

    http_port: 8080

    package_name: nginx


  tasks:

    - name: Install package

      apt:

        name: "{{ package_name }}"

        state: present

การกำหนดตัวแปรใน Inventory

เมื่อเราต้องการตั้งค่าให้แต่ละเครื่อง หรือแต่ละกลุ่มไม่เหมือนกัน

# ไฟล์ inventory.ini

[web_dev]

192.168.1.10 http_port=8080


[web_prod]

192.168.1.20 http_port=80

Best Practice: ใช้โฟลเดอร์แยก

แทนที่จะใส่ในไฟล์ inventory นิยมแยกโฟลเดอร์:

  • /group_vars/web_dev.yml
  • /group_vars/web_prod.yml
  • /host_vars/192.168.1.10.yml

ลำดับความสำคัญของตัวแปร (Precedence)

ถ้าตั้งชื่อตัวแปรซ้ำกันในหลายที่ Ansible จะยึดค่าจากที่ไหน? (เรียงจากต่ำสุดไปสูงสุด)

1. Role defaults (ต่ำสุด ถูกทับง่ายสุด)
2. Inventory group_vars
3. Inventory host_vars
4. Playbook vars
5. Role vars
6. Extra vars (-e ใน Command Line) (สูงสุด! ทับได้ทุกอย่าง)
* Command: ansible-playbook setup.yml -e "http_port=80"

Ansible Facts (ตัวแปรระบบอัตโนมัติ)

ทุกครั้งที่รัน Playbook ขั้นตอนแรกคือ Gathering Facts (สังเกตใน log) Ansible จะดึงข้อมูลทั้งหมดของเครื่องเป้าหมายมาเก็บไว้ในตัวแปรอัตโนมัติ

OS Family: {{ ansible_os_family }} (เช่น Debian, RedHat)

IP Address: {{ ansible_default_ipv4.address }}

Total RAM: {{ ansible_memtotal_mb }}

💡 Use Case: สามารถเขียนเงื่อนไขติดตั้ง apt ถ้า OS เป็น Debian และติดตั้งด้วย yum ถ้า OS เป็น RedHat ได้

Templates (Jinja2) 📝

ทำไมต้องใช้ Templates?

ในโลกความเป็นจริง ไฟล์ Configuration (เช่น nginx.conf, my.cnf) ของแต่ละสภาพแวดล้อม (Dev, Prod) จะไม่เหมือนกันเป๊ะ

  • แทนที่จะใช้ module copy ก๊อปปี้ไฟล์ Static ธรรมดา
  • เราใช้ Templates ที่สามารถฝัง "ตัวแปร" และ "เงื่อนไข" ลงไปในไฟล์ต้นฉบับได้
  • เมื่อรัน Playbook Ansible จะแปลง Template เป็นไฟล์ Configuration จริงที่ตรงกับค่านั้นๆ ให้เครื่องเป้าหมาย

Jinja2 Basics

Ansible ใช้เอนจิน Template ที่ชื่อว่า Jinja2 (ของ Python) นามสกุลไฟล์มักใช้ .j2

1. Expressions (แสดงค่าตัวแปร)

ใช้ปีกกาคู่เพื่อพิมพ์ค่า

ListenPort {{ http_port }}
ServerAdmin {{ admin_email }}

2. Statements (ลอจิกควบคุม)

ใช้ปีกกาและเปอร์เซ็นต์ สำหรับ IF/FOR

{% if enable_ssl %}
  listen 443 ssl;
{% endif %}

Jinja2 Conditionals (เงื่อนไข If/Else)

การปรับเนื้อหาไฟล์ตามค่าตัวแปร

# ไฟล์ nginx.conf.j2


server {

  listen {{ http_port }};

  server_name {{ domain_name }};


  {% if enable_php %}

  location ~ \.php$ {

    fastcgi_pass 127.0.0.1:9000;

  }

  {% else %}

  # PHP is disabled

  {% endif %}

}

Jinja2 Loops (การวนลูป)

มีประโยชน์มากเมื่อต้องการใส่รายชื่อหลายๆ อัน เช่น DNS Servers, หรือ Allow IPs

# ใน Playbook (ตัวแปร List)

dns_servers:

  - 8.8.8.8

  - 1.1.1.1

  - 9.9.9.9

# ใน resolv.conf.j2

{% for dns in dns_servers %}

nameserver {{ dns }}

{% endfor %}

ผลลัพธ์ที่ได้บนเซิร์ฟเวอร์:
nameserver 8.8.8.8
nameserver 1.1.1.1
nameserver 9.9.9.9

การใช้งาน Template Module ใน Playbook

เมื่อเขียนไฟล์ .j2 เสร็จแล้ว ให้เรียกใช้ด้วยโมดูล template

- name: Configure Nginx using template

  template:

    src: templates/nginx.conf.j2 # ไฟล์ต้นทางที่เครื่องเรา

    dest: /etc/nginx/nginx.conf # ไฟล์ปลายทางที่เครื่องเป้าหมาย

    owner: root

    group: root

    mode: '0644'

  notify: Restart Nginx # สั่ง Restart Service ทันทีถ้าไฟล์มีการเปลี่ยนแปลง

ปัญหาของ Playbook ขนาดใหญ่

Monolithic Playbook

เมื่อโปรเจกต์ใหญ่ขึ้น ไฟล์ Playbook เดียวอาจมีขนาดใหญ่ถึง 1,000+ บรรทัด รวมงานติดตั้ง DB, Web, Cache ไว้ในไฟล์เดียว

  • อ่านยาก แก้ไขยาก
  • นำไปใช้ซ้ำในโปรเจกต์อื่นไม่ได้
  • ทำงานร่วมกันเป็นทีมลำบาก (Git merge conflicts)
🍝

Spaghetti Code!

Ansible Roles 🎭

Roles คือวิธีการจัดระเบียบและแบ่ง Playbook ขนาดใหญ่ออกเป็นส่วนย่อยๆ (Modular) ตามหน้าที่การทำงาน (เช่น Role สำหรับ Nginx, Role สำหรับ MySQL)

  • ช่วยให้โค้ดเป็นระเบียบ (Structure)
  • สามารถนำกลับมาใช้ใหม่ได้ (Reusability)
  • แบ่งปันให้คนอื่นใช้ได้ง่าย (Shareability)

โครงสร้างมาตรฐานของ Role

Role หนึ่งตัวจะมีโครงสร้างโฟลเดอร์มาตรฐานที่ Ansible เข้าใจอัตโนมัติ

roles/my_role/

├── tasks/ # เก็บไฟล์งาน (main.yml)

├── handlers/ # เก็บคำสั่ง service restart (main.yml)

├── templates/ # เก็บไฟล์ .j2 (Jinja2)

├── files/ # เก็บไฟล์ static ธรรมดา

├── vars/ # เก็บตัวแปรที่มี Priority สูง

├── defaults/ # เก็บตัวแปรค่าตั้งต้น (Priority ต่ำสุด)

└── meta/ # เก็บข้อมูลผู้สร้าง และ dependencies

ส่วนประกอบใน Role

tasks/main.yml

จุดเริ่มต้นของ Role ไม่ต้องมี hosts: หรือ tasks: แล้ว ใส่รายการงานได้เลย

- name: Install nginx
  apt:
    name: nginx

defaults/main.yml

ใส่ค่าตัวแปรเริ่มต้น ผู้ใช้ที่เรียก Role นี้สามารถตั้งค่าทับได้ง่ายๆ

nginx_port: 80
nginx_user: www-data

Handlers ใน Roles

Handlers คือ Task พิเศษที่จะทำงานก็ต่อเมื่อถูกเรียก (Notified) เท่านั้น นิยมใช้กับ Service Restart

# ใน handlers/main.yml

- name: Restart Nginx

  service:

    name: nginx

    state: restarted


# ใน tasks/main.yml

- name: Update Nginx Config

  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

  notify: Restart Nginx # ชื่อต้องตรงกันเป๊ะ

การสร้าง Role ใหม่

ไม่ต้องสร้างโฟลเดอร์เองทีละอัน Ansible มีคำสั่งสำหรับสร้างโครงสร้าง Role ให้ทันที

$ ansible-galaxy role init my_webserver

คำสั่งนี้จะสร้างโฟลเดอร์ my_webserver พร้อมโฟลเดอร์ย่อย (tasks, handlers, vars, ฯลฯ) ที่มีไฟล์ main.yml เตรียมไว้ให้คุณเข้าไปเขียนโค้ดได้เลย

การเรียกใช้งาน Role ใน Playbook หลัก

เมื่อเรามี Role แล้ว Playbook หลัก (site.yml) ของเราจะสะอาดและอ่านง่ายมาก

# site.yml (Playbook หลัก)

---

- name: Configure Web Servers

  hosts: webservers

  become: true

  roles:

    - common_setup

    - my_webserver


- name: Configure Database Servers

  hosts: dbservers

  become: true

  roles:

    - common_setup

    - role: mysql_db

      vars:

        mysql_port: 3306 # ส่งค่าตัวแปรเข้าไปใน Role ได้

ปัญหาการจัดการ Sensitive Data

อันตราย!

การเขียนรหัสผ่าน Database, API Keys, หรือ SSL Certificates เป็น Plain-text ลงใน Playbook และ Push ขึ้น Git (เช่น GitHub) เป็นความเสี่ยงระดับวิกฤต

db_password: "SuperSecretPassword123!"
🔓

Data Breach Risk

Ansible Vault 🔐

Ansible Vault คือฟีเจอร์ที่ช่วยให้เราสามารถ เข้ารหัส (Encrypt) ข้อมูลตัวแปร หรือไฟล์ทั้งไฟล์ ด้วยอัลกอริทึม AES256

  • ไฟล์ที่ถูกเข้ารหัสสามารถ Push ขึ้น Git ได้อย่างปลอดภัย
  • Ansible จะทำการถอดรหัส (Decrypt) ในหน่วยความจำตอนที่รัน Playbook เท่านั้น (ไม่ต้องเขียนไฟล์ลงดิสก์)
  • ต้องใช้ Password หรือ Key file ในการถอดรหัสเพื่อใช้งาน

คำสั่งพื้นฐานของ Ansible Vault

สร้างไฟล์เข้ารหัสใหม่ $ ansible-vault create secrets.yml
แก้ไขไฟล์ที่ถูกเข้ารหัสอยู่แล้ว $ ansible-vault edit secrets.yml
เข้ารหัสไฟล์ธรรมดา (Plain-text -> Encrypted) $ ansible-vault encrypt db_vars.yml
ถอดรหัสไฟล์ (Encrypted -> Plain-text) $ ansible-vault decrypt db_vars.yml

การเข้ารหัสแค่บางตัวแปร (Vault String)

บางครั้งเราไม่อยากเข้ารหัสทั้งไฟล์ เราสามารถเข้ารหัสเฉพาะค่าของตัวแปร (Value) ได้

$ ansible-vault encrypt_string 'MySecretPass' --name 'db_password'


# นำผลลัพธ์ไปแปะในไฟล์ vars/main.yml ได้เลย:

db_password:

!vault |

  $ANSIBLE_VAULT;1.1;AES256

  38366531393635383561336661333465353163353531636239333939616630323334346162353137

  ...

วิธีนี้ทำให้เรายังสามารถอ่าน Key name (เช่น db_password) ได้ออก แต่ค่า (Value) ปลอดภัย

การรัน Playbook ที่มี Vault

เมื่อเรารัน Playbook ที่มีการอ้างอิงถึงไฟล์ Vault หรือตัวแปร Vault เราต้องส่งรหัสผ่านให้ Ansible ด้วย

วิธีที่ 1: พิมพ์รหัสผ่านเอง (Interactive)

ใช้ option --ask-vault-pass

ansible-playbook site.yml --ask-vault-pass

วิธีที่ 2: อ่านจากไฟล์ (Automation/CI)

เก็บรหัสไว้ในไฟล์ (อย่าเอาขึ้น Git!) แล้วใช้ option --vault-password-file

ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt

สรุปบทเรียน (Summary)

  • Idempotency คือการทำงานซ้ำได้โดยระบบไม่พังและไม่เปลี่ยนถ้าสถานะถูกต้องแล้ว ควรใช้ Ansible Modules เสมอ
  • Variables & Jinja2 ทำให้ Configuration ไฟล์ของเรายืดหยุ่น สร้างเงื่อนไขและวนลูปได้ตาม Environment
  • Ansible Roles ช่วยจัดระเบียบ Playbook ให้เป็นสัดส่วน (Modularity) และนำไปใช้ซ้ำได้ง่าย
  • Ansible Vault คือเครื่องมือสำคัญในการเข้ารหัสปกป้องข้อมูลความลับ (Secrets) ไม่ให้หลุดไปใน Source Control

เตรียมตัวทำ Lab! 🧪

ภารกิจปฏิบัติการสัปดาห์ที่ 9:

ยกระดับโปรเจกต์ Ansible จากสัปดาห์ที่แล้ว ให้มีโครงสร้างระดับ Enterprise

  • ✅ ใช้คำสั่ง ansible-galaxy init สร้าง Ansible Role สำหรับติดตั้ง Nginx
  • ✅ เขียนไฟล์ nginx.conf.j2 โดยใช้ Jinja2 Template และดึงค่าจากตัวแปร (Variables)
  • ✅ ทดลองเก็บรหัสผ่านฐานข้อมูล (จำลอง) ไว้ในไฟล์แล้วเข้ารหัสด้วย Ansible Vault
  • ✅ รัน Playbook และตรวจสอบคุณสมบัติ Idempotency
ทบทวนคำสั่งพื้นฐานของ Ansible และโครงสร้าง YAML ให้แม่นยำก่อนเริ่ม Lab!

Lab: Enterprise Ansible 🏢

ยกระดับการเขียน Playbook สู่มาตรฐานการทำงานจริงด้วย Roles, Templates และ Vault

🎯 เป้าหมายของ Lab

  • ✅ สร้าง Ansible Role สำหรับติดตั้งและตั้งค่า Nginx ให้รัน Web application
  • ✅ ใช้ Jinja2 Template เพื่อสร้างไฟล์ Configuration ของ Nginx แบบไดนามิก
  • ✅ ทดลองใช้ Ansible Vault เพื่อเก็บรหัสผ่าน (จำลอง) อย่างปลอดภัย
  • ✅ ตรวจสอบคุณสมบัติ Idempotency ของ Playbook

Step 1: เตรียม Project และ Inventory

สร้างโครงสร้างโฟลเดอร์สำหรับโปรเจกต์ใหม่และเตรียมไฟล์ Inventory

# 1. สร้างโฟลเดอร์โปรเจกต์และเข้าไปในโฟลเดอร์

$ mkdir ansible-advanced-lab && cd ansible-advanced-lab


# 2. สร้างไฟล์ Inventory

$ nano hosts


# 3. ใส่ข้อมูลเครื่องเป้าหมาย (เปลี่ยน IP และ User ตามจริง)

[webservers]

192.168.x.x ansible_user=ubuntu

Step 2: สร้าง Ansible Role

เราจะใช้คำสั่ง ansible-galaxy ในการสร้างโครงสร้างโฟลเดอร์สำหรับ Role โดยอัตโนมัติ

# 1. สร้างโฟลเดอร์ roles เพื่อเก็บ Role ทั้งหมด

$ mkdir roles && cd roles


# 2. สร้าง Role ใหม่ชื่อ nginx_web

$ ansible-galaxy role init nginx_web

- Role nginx_web was created successfully


# 3. กลับมาที่โฟลเดอร์หลัก

$ cd ..

💡 โครงสร้างไฟล์มากมายจะถูกสร้างขึ้นใน roles/nginx_web/ เช่น tasks/, handlers/, templates/ เป็นต้น

Step 3: กำหนดตัวแปร (Defaults)

กำหนดค่าพื้นฐานให้กับ Role ของเรา เพื่อให้นำไปใช้ซ้ำหรือปรับแก้ได้ง่าย

# แก้ไขไฟล์ roles/nginx_web/defaults/main.yml

$ nano roles/nginx_web/defaults/main.yml


---

# defaults file for nginx_web

http_port: 80

server_name: localhost

app_greeting: "Welcome to Ansible Roles & Vault!"

Step 4: สร้าง Jinja2 Template สำหรับ Nginx

สร้างไฟล์ Configuration ของ Nginx ที่จะเปลี่ยนค่าไปตามตัวแปรที่เรากำหนด

# สร้างไฟล์ roles/nginx_web/templates/nginx.conf.j2

$ nano roles/nginx_web/templates/nginx.conf.j2


server {

    listen {{ http_port }} default_server;

    server_name {{ server_name }};


    root /var/www/html;

    index index.html;


    location / {

        try_files $uri $uri/ =404;

    }

}

Step 5: สร้าง HTML แบบไดนามิก (Jinja2)

แทนที่จะใช้ไฟล์ Static ธรรมดา เราจะใช้ Template ฝังตัวแปรลงในหน้าเว็บ

# สร้างไฟล์ roles/nginx_web/templates/index.html.j2

$ nano roles/nginx_web/templates/index.html.j2


<!DOCTYPE html>

<html>

<body style="background-color: #1a202c; color: white; text-align: center; padding-top: 100px;">

    <h1>{{ app_greeting }}</h1>

    <p>Server Name: {{ server_name }}</p>

    <p>Simulated DB Password: {{ db_password | default('Not Provided') }}</p>

</body>

</html>

Step 6: สร้าง Handlers (Restart Service)

เมื่อมีการแก้ไขไฟล์ Configuration ควรให้ Nginx สั่ง Restart ตัวเอง

# แก้ไขไฟล์ roles/nginx_web/handlers/main.yml

$ nano roles/nginx_web/handlers/main.yml


---

# handlers file for nginx_web

- name: Restart Nginx

  service:

    name: nginx

    state: restarted

Step 7: เขียน Tasks หลักสำหรับ Role

# แก้ไขไฟล์ roles/nginx_web/tasks/main.yml

---

- name: Install Nginx

  apt: name=nginx state=present update_cache=yes


- name: Deploy Nginx configuration

  template:

    src: nginx.conf.j2

    dest: /etc/nginx/sites-available/default

  notify: Restart Nginx # เรียกใช้ Handler เมื่อไฟล์เปลี่ยน


- name: Deploy Web Application (index.html)

  template:

    src: index.html.j2

    dest: /var/www/html/index.html


- name: Ensure Nginx is running

  service: name=nginx state=started enabled=yes

Step 8: สร้างไฟล์ความลับด้วย Ansible Vault

เราจะจำลองการเก็บรหัสผ่าน Database และใช้ Vault เพื่อเข้ารหัสไฟล์

# 1. สร้างโฟลเดอร์ group_vars สำหรับกลุ่ม webservers

$ mkdir -p group_vars/webservers


# 2. สร้างและเข้ารหัสไฟล์ vault

$ ansible-vault create group_vars/webservers/secrets.yml

New Vault password: (ตั้งรหัสผ่านของคุณ เช่น secret123)

Confirm New Vault password:


# 3. Text Editor จะเปิดขึ้นมา ให้พิมพ์ข้อมูลนี้ลงไป:

db_password: "SuperSecretPassword123!"

# (Save และ Exit ไฟล์)

คุณสามารถใช้ `cat group_vars/webservers/secrets.yml` เพื่อดูว่าไฟล์ถูกเข้ารหัสแล้ว (อ่านไม่รู้เรื่อง)

Step 9: ประกอบร่าง Main Playbook

กลับมาที่โฟลเดอร์หลัก สร้างไฟล์ site.yml เพื่อเรียกใช้งาน Role

$ nano site.yml


---

- name: Configure Web Infrastructure

  hosts: webservers

  become: yes

  roles:

    - nginx_web

สังเกตว่า Playbook หลักสั้นและอ่านง่ายมาก เพราะความซับซ้อนถูกซ่อนไว้ใน Role หมดแล้ว

Step 10: Execute Playbook

ต้องใช้ flag --ask-vault-pass เพื่อปลดล็อกตัวแปรความลับส่งไปให้ Jinja2 Template

$ ansible-playbook -i hosts site.yml -K --ask-vault-pass

Vault password: (พิมพ์รหัส vault ที่ตั้งไว้)

BECOME password: (พิมพ์รหัส sudo ของเครื่องปลายทาง)


# สังเกตผลลัพธ์ Tasks ที่รันจาก Role

changed: [192.168.x.x] => (item=Install Nginx)

changed: [192.168.x.x] => (item=Deploy Config)

ตรวจสอบใน Web Browser

นำ IP เครื่องเป้าหมายไปเปิดในเบราว์เซอร์ จะเห็นข้อความและ รหัสผ่านจาก Vault แสดงอยู่ (ในทางปฏิบัติจริง เราจะไม่ Print Password ออกหน้าเว็บ แต่ใน Lab นี้ทำเพื่อพิสูจน์ว่า Vault ทำงานได้)

Step 11: ทดสอบ Idempotency

รันคำสั่งเดิมซ้ำอีกครั้ง เพื่อดูความฉลาดของ Ansible

$ ansible-playbook -i hosts site.yml -K --ask-vault-pass


TASK [nginx_web : Install Nginx]

ok: [192.168.x.x]

TASK [nginx_web : Deploy Nginx configuration]

ok: [192.168.x.x]


PLAY RECAP ***************************************

192.168.x.x : ok=5 changed=0 unreachable=0 failed=0

*ผลคือ ok=5 changed=0 เพราะ Ansible รู้ว่าไม่มีอะไรต้องอัปเดต และ Handler "Restart Nginx" ก็จะไม่ถูกเรียกทำงาน!

🎉

Lab Complete! การส่งงาน (Submission)

สิ่งที่ต้องส่ง:

  • Source Code (.zip หรือ Github Repo):
    • โครงสร้างโฟลเดอร์ของ Role (roles/nginx_web)
    • ไฟล์ site.yml และ hosts
    • ไฟล์เข้ารหัส group_vars/webservers/secrets.yml
  • Screenshots (รวมเป็น PDF):
    • ภาพผลลัพธ์การรันรอบแรก (มีสถานะ changed)
    • ภาพหน้าเว็บที่แสดงข้อความและรหัสผ่านจาก Vault
    • ภาพผลลัพธ์การรันรอบสองที่พิสูจน์ Idempotency (สถานะ ok=0 changed=0)