Ansible là công cụ giúp chuẩn bị trước và quản lý cấu hình, giống như là Chef, Puppet hay Salt
Nó là cách đơn giản nhất và dễ nhất để bắt đầu. Bởi vì nó chỉ là SSH, sử dụng SSH để kết nối với Server và chạy các Task đã được cấu hình.
Một ưu điểm nữa của Ansibble là giúp chúng ta dễ dàng chuyển đổi một Bash script (đây vẫn là cách phổ biến để quản lý cấu hình) thành các task trong Ansible. Vì nó chủ yếu dựa trên SSH, nên cũng dễ dàng hiểu rằng điều này có thể là trường hợp – Ansible kết thúc chạy các lệnh tương tự như Bash script
Chúng ta có thể chỉ script những gì cần cấu hình, nhưng Ansible rõ ràng hơn, bởi vì nó tự động quá trình nhận ngữ cảnh trước khi chạy các Task. Với ngữ cảnh này, Ansible có thể xử lý hầu hết các trường hợp giới hạn, khi mà chúng ta thường hay quan tâm đến các script dài và phức tạp
Các Task của Ansible là idempotent, tức là không thay đổi dù chúng ta có chạy lại các task này bao nhiều lần đi nữa. Không phải code nhiều, Bash script thường không đảm bảo nếu chúng ta chạy đi chạy lại. Ansible sử dụng “Fact” , đó là thông tin về hệ thống và môi trường thu nhận được trước khi chạy các Task.
Ansible sử dụng những sự kiện để kiểm tra state và xem xét nếu nó cần thay đổi gì hay không mục đích để thu được kết qủa mong muốn. Điều này giúp cho chúng ta an toàn hơn khi chạy đi chạy lại Ansible Task trên một Server.
Trong bài viết này, chúng ta sẽ chỉ bắt đầu với Ansible với các khái niệm cơ bản và sau đó đưa vào thêm nhiều tính năng hơn để cải tiến cấu hình của chúng ta.
Cài đặt
Để bắt đầu chúng ta cần cài đặt Ansible trước tiên. Các Task có thể được chạy trên bất kỳ máy nào mà Ansible được cài đặt.
Điều này nghĩa là thường có một Server dùng để chạy các câu lện Ansible, mặc dù không có yêu cầu gì đặc biệt cho Server mà Ansible được cài đặt lên đấy. Ansible là vô giá trị – không có đặc vụ trọng yếu nào đang chạy. Chúng ta có thể chạy Ansible trên bất kỳ server nào, tôi thường chạy các Task trên mày laptop của mình.
Ubuntu
Chúng ta sẽ cài đặt Ansible trên Ubuntu 16.04.
sudo apt-add-repository -y ppa:ansible/ansible sudo apt-get update sudo apt-get install -y ansible
Cài đặt Ansible Global.
Mac OS
brew install ansible
Bạn có thể tự cài đặt nó theo các OS khác nhau theo hướng dẫn sau đây
Cấu hình
Chúng ta tạo các file cấu hình trên thư mục local khi cần. Chúng ta không cần bất kỳ file cấu hình nào trong thư mục /etc hay một chỗ đặc biệt nào khác, nó giúp chúng ta đơn giản hoá khi sử dụng
Quản lý Server: Inventory
Ansible yêu cầu bạn tạo một inventory file để định nghĩa những Server nào đang cần quản lý. File này có thể có tên bất kỳ, nhưng chúng ta sẽ thường đặt tên cho nó giống như định nghĩa trong hosts
Trong file host chúng ta có thể định nghĩa Server mà chúng ta quản lý. Ở đây chúng ta sẽ định nghĩa 2 server mà chúng ta quản lý dưới nhãn “web”. Nhãn này có thể được đặt tuỳ ý
[web] 192.168.22.10 192.168.22.11
Mục đích để test trong bài viết này, chúng ta sẽ sử dụng một Ubuntu 16.04 trên AWS, nhưng nó không quan trọng bạn có thể sử dụng bất kỳ Server hay cloud nào mà bạn thích. Tiếp theo sẽ chạy Ansible Task trực tiếp trên Server này, tức là chúng ta sẽ chạy Ansible trên cùng một Server mà nó quản lý, nó vẫn hợp lệ mặc dù trong thực tế thì chúng ta sẽ chạy nó trên một máy khác ví dụ trên laptop của chúng ta.
Khi chúng ta chạy lại Ansible trên local, chúng ta cũng không cần quan tâm những gì cần hay phải chỉnh sửa thông tin của file inventory. Sau đây sẽ là hướng dẫn bạn cách chạy Ansible trên local và đối với một Remote Server.
Nào hãy mở file hosts, sau đó thêm vào đấy thông tin địa chỉ trỏ đến local và trỏ đến một Remote Server.
[local] 127.0.0.1 [remote] 192.168.1.2 # IP of remote server
Tôi sẽ chỉ cho bạn các câu lệnh kết nối với local và remote server.
Chạy các câu lệnh
Ansible sẽ đảm đương giúp bạn việc SSH kết nối tiện lợi đến Server, thường thì dựa trên SSH-key. Bởi vì Ansible sử dụng SSH, server mà nó đang chạy trên đấy cần có thể SSH được vào được Inventory Server.
Tuy nhiên, Ansible sẽ thử kết nối bằng user hiện tại mà nó đang sử dụng. Nếu chúng ta đang chạy với user là ubuntu, nó sẽ thử kết nối như một ubutu user đến Server khác.
Nếu Ansible có thể SSH trực tiếp đến các Server mà nó quản lý, chúng ta có thể chạy các câu lệnh mà không gặp phiền phức gì
# Run against localhost $ ansible -i ./hosts --connection=local local -m ping # Run against remote server $ ansible -i ./hosts remote -m ping 127.0.0.1 | success >> { "changed": false, "ping": "pong" }
Nếu bạn gặp lỗi như sau “Too many authentication failures”, chúng ta có thể thêm một vài lựa chọn cho SSH, và Ansible sẽ hỏi chúng ta password khi đăng nhập vào
ansible -i ./hosts --ask-pass --ssh-extra-args='-o "PubkeyAuthentication=no"' all -m ping
Sử dụng --connection=local
để yêu cầu Ansible không cố gắng chạy các lệnh SSH, vì chúng ta chỉ chạy ở máy local. Tuy nhiên chúng ta vẫn cần thêm vào trong hosts
file, để giúp chúng ta biết rằng mình đang kết nối đến đâu, nó sẽ không phải là một phỏng đoán hay hiểu như là localhost
hay 127.0.0.1
Trong cả 2 trường hợp, chúng ta có thể thấy được kết quả đầu ra từ Ansible là trả về các Json để thông báo với chúng ta, nếu các Task được tạo có bất kỳ thay đổi nào
Nào hãy cũng xem kỹ lại câu lệnh
-i ./hosts
– đặt file Inventory (môi trường kết nối), có tên làhosts
.remote
,local
,all
– Sử dụng các Server mà được định nghĩa với tên nhãn trong filehosts
hay file Inventory. “all” là từ khoá đặc biệt để chạy tất cả các Server được định nghĩa trong file-m ping
– Sử dụng ping module, mà đơn giản là chạy câu lệnhping
và trả về kết quả-c local
|--connection=local
– chạy câu lệnh local, không phải qua SSH
Modules
Ansible sử dụng Module để thực hiện phần lớn các Task của nó. Module có thể thực hiện các công việc như là cài đặt phần mềm, copy các file, sử dụng template …
Module là cách để sử dụng Ansible, chúng ta có thể sử dụng các ngữ cảnh có hiệu lực mục đích để xác định các Action nào khi cần làm gì đó để thực hiện một Task.
Nếu chúng ta không có các Module, chúng ta muốn tuỳ ý chạy các lệnh Shell và có thể sử dụng giống như Bash Script. Đây là những gì một lệnh shell trông như thế nào trong Ansible (sử dụng Shell Module)
# Chạy trên local server ansible -i ./hosts local --connection=local -b --become-user=root \ -m shell -a 'apt-get install nginx' # Chạy trên remote server ansible -i ./hosts remote -b --become-user=root all \ -m shell -a 'apt-get install nginx'
Ở đây câu lệnh sudo apt-get install nginx
sẽ được chạy sử dụng shell module
Chúng ta có một vài flag mới:
-b
– viết tắt “become”, nói với Ansible rằng sẽ trở thành một user khác khi chạy câu lệnh. Đây là cách giúp bạn có thể chạy bằng nhiều user khác nhau, hay nâng quyền lên root user--become-user=root
– Chạy các câu lện bằng user root. Chúng ta có thể định nghĩa bất kỳ user nào mà đang tồn tại ở đây.-
-a
– được sử dụng để truyền bất kỳ tham số nào cho Module được định nghĩa sử dụng-m
Tuy nhiên điều này không đặc biệt hữu ích. Nó không thể tiện dụng cho việc chạy các câu lệnh trên tất cả môi trường trong một lần chạy, chúng ta vẫn chỉ sử dụng các câu lện trong Bash Script
Nếu chúng ta sử dụng Module thay thế thích hợp, chúng ta có thể chạy các câu lệnh với kết quả được đảm bảo. Asible đảm bảo tính Indempotence – chúng ta có thể chạy đi chạy lại các task mà không làm thay đổi kết quả cuối cùng.
Để cài đặt phần mềm trên server Debian/Ubuntu, “apt” Module sẽ chạy câu lệnh giống nhau nhưng đảm bảo Idempotence.
# Chạy trên local server ansible -i ./hosts local --connection=local -b --become-user=root \ -m apt -a 'name=nginx state=installed update_cache=true' 127.0.0.1 | success >> { "changed": false } # Chạy trên remote server ansible -i ./hosts remote -b --become-user=root \ -m apt -a 'name=nginx state=installed update_cache=true' 127.0.0.1 | success >> { "changed": false }
Ở đây nó sẽ sử dụng apt
Module để cập nhập cache của kho lữu trữ và cài đặt Nginx (nếu nó chưa được cài đặt).
Kết quả trả về "changed": false
, điều này nghĩa rằng không có thay đổi, chúng ta đã cài đặt Nginx sử dụng Shell Module trước đấy. Điều tuyệt vời là chúng ta có thể chạy đi chạy lại câu lệnh này mà không cần lo lắng nó sẽ làm thay đổi kết quả mong muốn. Nginx đã được cài đặt và Ansible đã biết điều đó, nên nó sẽ không cố thử cài đặt lại lần nữa.
Hãy cũng xem nội dung câu lệnh:
-i ./hosts
– Đặt file Inventory, có tên làhosts
-b
– viết tắt “become”, nói với Ansible rằng sẽ trở thành một user khác khi chạy câu lệnh--become-user=root
– Chạy các câu lện bằng user root.local
|remote
– Chạy trên local hoặc remote được định nghĩa trong file Inventory-m apt
– sử dụng apt Module-a 'name=nginx state=installed update_cache=true'
– cung cấp các tham số đầu vào cho apt module, bao gồm tên package, state kết thúc mong muốn, và liệu có cập nhập package lưu trữ cache hay không
Chúng ta có thể chạy tất cả các Task (thông qua các Module) theo cách ad-hoc này, hãy làm cho chúng dễ quản lý hơn. Hãy chuyển Task vào Playbook, có thể chạy và phối hợp nhiều tác vụ.
Playbook
Playbook có thể chạy nhiều Task và cung cấp một số chức năng nâng cao mà chúng ta sẽ bỏ lỡ khi sử dụng các câu lệnh Ad-hoc. Nào hãy chuyển các Task bên trên vào Playbook.
Playbook và roles trong Ansible tất cả đều sử dụng Yaml
Tạo một nginx.yml
--- # hosts có thể là "remote" hoặc "all" - hosts: local connection: local become: yes become_user: root tasks: - name: Install Nginx apt: name: nginx state: installed update_cache: true
Task này giống hệt như chúng ta sử dụng câu lệnh Ad-hoc, bao gồm cài đặt sử dụng kết nối local.
Cấu hình này sẽ sử dụng Server với nhãn [local]
trong file hosts
Nếu chúng ta đang không sử dụng kết nối local, chúng ta có thể kết nối lại như sau:
--- - hosts: remote become: yes become_user: root tasks: - name: Install Nginx apt: name: nginx state: installed update_cache: true
Cấu hình này sẽ sử dụng server với nhãn [remote]
trong hosts file
Sử dụng become
và become_user
lần nữa trong file Task của chúng ta để bảo Ansible sử dụng câu lệnh sudo
bằng user root và sau đó chạy qua file Playbook.
Với một file Yaml Playbook, chúng ta cần sử dụng câu lệnh ansible-playbook
, nó trở nên đơn giản hơn khi chạy câu lệnh hiện tại
$ ansible-playbook -i ./hosts nginx.yml PLAY [local] ****************************************************************** GATHERING FACTS *************************************************************** ok: [127.0.0.1] TASK: [Install Nginx] ********************************************************* ok: [127.0.0.1] PLAY RECAP ******************************************************************** 127.0.0.1 : ok=2 changed=0 unreachable=0 failed=0
Chúng ta nhận được những phản hồi hữu ích khi câu lệnh này chạy, bao gồm Ansible Task và kết quả của chúng.
Ở đây chúng ta thấy rằng tất cả đều chạy OK, nhưng không có gì bị thay đổi cả. Bởi vì chúng ta đã cài Nginx trước đấy.
Handler
Handler hoàn toàn giống như một Task (Nó có thể làm được bất cứ điều gì mà Task có thể làm), nhưng nó sẽ chỉ chạy khi được gọi bởi Task khác. Bạn có thể nghĩ nó như một phần của hệ thống Event; Handler sẽ nhận được một Action khi được gọi bởi một Event mà nó đang lắng nghe.
Nó rất hữu ích cho các Actions xảy ra lại từ lần thứ 2 mà có thể được yêu cầu sau khi chạy một Task, như là bắt đầu một Service mới sau khi cài đặt và reload một Service sau khi thay đổi một cấu hình.
--- # Ví dụ vẫn sử dụng máy local # Bỏ 'connection' và thiết lập hosts đến 'remote' cho kết nối remote - hosts: local connection: local become: yes become_user: root tasks: - name: Install Nginx apt: name: nginx state: installed update_cache: true notify: - Start Nginx handlers: - name: Start Nginx service: name: nginx state: started
Ở đây chúng ta thêm một chỉ thị notify
khi cài đặt Task. Nó sẽ gửi thông báo đến Handler bất kỳ có tên là “Start Nginx” sau khi Task được chạy.
Sau đó chúng ta có thể tạo một Handler với tên là “Start Nginx”. Handler này là Task được gọi khi “Start Nginx” được thông báo.
Handler cụ thể này sử dụng Service Module, có thể start, stop, restart và reload các Service của hệ thống. Trong trường hợp này, chúng ta nói với Ansible rằng chúng ta muốn Nginx được start
Chú ý rằng Ansible giúp chúng ta xác định state mà bạn mong muốn Service ở đây là gì, thay vì xác định những thay đổi mà bạn muốn. Ansible sẽ quyết định nếu một thay đổi là cần thiết, chúng ta chỉ nói với nó kết qủa mong muốn.
Nào hãy chạy lại Playbook này xem sao
$ ansible-playbook -i ./hosts nginx.yml PLAY [local] ****************************************************************** GATHERING FACTS *************************************************************** ok: [127.0.0.1] TASK: [Install Nginx] ********************************************************* ok: [127.0.0.1] NOTIFIED: [nginx | Start Nginx] *********************************************** ok: [127.0.0.1] PLAY RECAP ******************************************************************** 127.0.0.1 : ok=2 changed=0 unreachable=0 failed=0
Chúng ta thu được kết quả tương tự, nhưng lúc này Handler đã được chạy.
Notifier chỉ được chạy nếu Task được chạy. Nếu chúng ta đã cài Nginx rồi, thì Task cài đặt Nginx sẽ không được chạy, do đó notifier sẽ không được gọi.
Chúng ta có thể dùng Playbook để chạy nhiều Task, thêm vào trong các biến, định nghĩa các thiết lập khác và thậm chí bao hàm cả các Playbook khác.
Task khác
Tiếp theo chúng ta sẽ thêm các Task khác vào Playbook này và tìm hiểu một vài chức năng mới.
--- # Ví dụ vẫn sử dụng máy local # Bỏ 'connection' và thiết lập hosts đến 'remote' cho kết nối remote - hosts: local connection: local become: yes become_user: root vars: - docroot: /var/www/serversforhackers.com/public tasks: - name: Add Nginx Repository apt_repository: repo: ppa:nginx/stable state: present register: ppastable - name: Install Nginx apt: pkg: nginx state: installed update_cache: true when: ppastable|success notify: - Start Nginx - name: Create Web Root file: path: '{{ docroot }}' mode: 775 state: directory owner: www-data group: www-data notify: - Reload Nginx handlers: - name: Start Nginx service: name: nginx state: started - name: Reload Nginx service: name: nginx state: reloaded
Bây giờ thì chúng ta có 3 Task:
Add Nginx Repository
– Thêm Nginx stable PPA để dùng Version ổn định mới nhất của Nginx sử dụng apt_repository module.Install Nginx
– cài đặt Nginx sử dụng apt moduleCreate Web Root
– Cuối cùng tạo thư mục web root.
Cũng có những cái mới ở đây là chỉ thị register
và when
. Những cái này cho Ansible biết để chạy một Task khi có cái gì đó khác xảy ra.
Add Nginx Repository
Task đăng ký ppastable
. Sau đó chúng ta sử dụng nó để thông báo Install Nginx
Task chỉ chạy khi Task ppastable
được đăng ký thành công. Điều này cho phép chúng ta có điều kiện để ngăn chặn Ansible chạy một Task.
Ví dụ cụ thể này chỉ cài đặt Nginx khi
ppa
lưu trữ được thêm vào là thừa, như là việc thêm kho lưu trữ lỗi, Ansible sẽ dừng lại và thông báo lỗi. Tuy nhiên rất tốt để biết các chức năng tồn tại.Bạn có thể đăng ký kết quả của một Module Action, và sử dụng biến được định nghĩa trong
register
để thực thi các Action có điều kiện khi dựa trên các giá trị biến đã được đăng ký. Ví dụ đăng ký kết quả của câu lệnh chạy qua Module Shell có thể cho phép bạn truy cập stdout của câu lệnh đó.
Chúng ta cũng sử dụng một biến là docroot
, biến được định nghĩa trong phần var
. Nó được sử dụng như một tham số đích của module file giúp tạo thư mục được xác định trước.
Chú ý rằng cấu hình path
sử dụng ngoặc đơn {{ var-name }}
– đây là Jinja2 template. Đoạn này phải nằm trong dấu nháy đơn hoặc nháy kép – ví dụ path: '{{ docroot }}'
thay cho path: {{ docroot }}
. Chú ý rằng không sử dụng các dấu ngoặc kép sẽ dẫn đến một lỗi xảy ra.
Playbook này có thể được chạy với câu lệnh đơn giản như sau:
ansible-playbook -i ./hosts nginx.yml
Chúng ta đã chạy một vài câu lệnh Ad-hoc, thường dùng module Ansible, và tổ chức một số Task liên quan trong Playbook.
Tiếp theo, chúng ta sẽ tiếp tục Ansible bằng cách tổ chức Playbook thành một Role, giúp chúng ta tổ chức các mục liên quan như là File và Template, đồng thời giúp chúng ta tổ chức các Task và Action liên quan phức tạp hơn.
Roles
Roles là hữu ích khi chúng ta muốn cấu trúc chức nhiều phần, các Task liên quan và đóng gói các dữ liệu cần thiết để thực hiện những Task đấy. Ví dụ, cài đặt Nginx có thể liên quan đến việc thêm một Repository package, cài đặt package và thiết lập cấu hình. Chúng ta đã nhìn thấy cài đặt qua một Playbook, nhưng khi chúng ta bắt đầu cài đặt cấu hình của mình, Playbook có xu hướng bận hơn một chút.
Hơn nữa trong cấu hình thực tế thường yêu cầu thêm dữ liệu như các biến, các File và các Template động…Những công cụ này có thể được sử dụng với Playbook nhưng chúng ta có thể làm tốt hơn ngay lập tức bằng cách tổ chức các Task và dữ liệu liên quan thành một cấu trúc mạch lạc như một Role.
Các Roles có một cấu trúc dữ liệu như sau:
roles rolename - files - handlers - meta - templates - tasks - vars
Với mỗi thư mục, Ansible sẽ tìm kiếm và đọc tất cả các file YAML được gọi là main.yml
tự động.
Chúng ta sẽ chia nhỏ file nginx.yml
và đặt mỗi thành phần vào trong thư mục phù hợp để tạo một công cụ cấu hình trước rõ ràng hơn và hoàn hảo hơn.
Tạo một Role
Chúng ta có thể sử dụng câu lệnh ansible-galaxy
để tạo một Role mới. Công cụ này có thể được sử dụng để lưu các Role vào đăng ký puplic của Ansible. Tuy nhiên mình thông thường chỉ sử dụng nó để khởi tạo một role cục bộ.
Nào chúng ta hãy cùng xem làm thế nào để thiết lập điều này
# Di chuyển đến thư mục được tạo trước đấy cd ~/ansible-example # In case we left our virtualenv at some point source .venv/bin/activate # Tạo thư mục roles mkdir roles cd roles # khởi tạo một role mới tên là"nginx" ansible-galaxy init nginx
Thư mục với tên là roles là quy ước để Ansible sử dụng để tìm các Role khi chạy Playbook. Thư mục nên được giữ tên là roles
Câu lệnh ansible-galaxy init nginx
chạy trong thư mục roles, sẽ tạo tên_thư_mục/files cần thiết để bắt đầu một Role mới.
Hãy xem qua từng phần của Nginx Role mới được tìm thấy tại ~/ansible-example/roles/nginx
Files
Đầu tiên trong thư mục files, chúng ta có thể thêm các file mà chúng ta sẽ muốn copy vào trong Server. Đối với Nginx, tôi thường copy các file thành phần h5bp của Nginx . Đơn giản là chỉ việc download những file này trên github, thực hiện các thay đổi mong muốn và đặt chúng vào thư mục files.
~/ansible-example - roles - - nginx - - - files - - - - h5bp
Các file cấu hình H5BP được sẽ được thêm vào Server thông qua module copy.
Handler
Bên trong thư mục handlers
, chúng ta có thể đặt tất cả Handler của chúng ta đã từng nằm trong Playbook nginx.yml
Bên trong hanlder/main.yml
--- - name: Start Nginx service: name: nginx state: started - name: Reload Nginx service: name: nginx state: reloaded
Khi chúng được đặt đúng vai trò, chúng ta có thể tham khảo chúng từ cấu hình yaml khác dễ dàng.
Meta
file main.yml
bên trong thư mục meta chứa dữ liệu meta của Role, bao gồm các phụ thuộc.
Nếu một Role dựa trên Role khác, chúng ta có thể định nghĩa nó ở đây. Ví dụ chúng ta có một Nginx Role dựa trên ssl Role dùng để cài đặt chứng thực của SSL.
--- dependencies: - { role: ssl }
Nếu gọi nginx Role, nó sẽ thử chạy SSL role trước.
Ngoài ra chúng ta có thể bỏ qua file này, hoặc định nghĩa Role ko có phụ thuộc.
--- dependencies: []
Template
Các Template file có thể chứa các biến template, dựa trên engine Jinja2 template của Python. Các file ở đây nên kết thúc bằng .j2
, nhưng có thể có tên khác. Giống files, chúng ta sẽ không tìm thấy file main.yml
bên trong thư mục templates.
Đây là một ví dụ cấu hình Nginx Server. Chú ý rằng nó sử dụng một số biến mà chúng ta sẽ định nghĩa ngay sau đây trong file vars/main.yml
File cấu hình Nginx này trong ví dụ của chúng ta được đặt tại templates/serversforansible.com.conf.j2
server { # Bắt buộc sử dụng HTTPS listen 80 default_server; server_name {{ domain }}; return 301 https://$server_name$request_uri; } server { listen 443 ssl default_server; root /var/www/{{ domain }}/public; index index.html index.htm index.php; access_log /var/log/nginx/{{ domain }}.log; error_log /var/log/nginx/{{ domain }}-error.log error; server_name {{ domain }}; charset utf-8; include h5bp/basic.conf; ssl_certificate {{ ssl_crt }}; ssl_certificate_key {{ ssl_key }}; include h5bp/directive-only/ssl.conf; location / { try_files $uri $uri/ /index.php$is_args$args; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; } location ~ \.php$ { include snippets/fastcgi.conf; fastcgi_pass unix:/var/run/php7.1-fpm.sock; } }
Đây là cấu hình tương đối chuẩn của Nginx cho ứng dụng PHP. Có 3 biến được sử dụng ở đây:
- domain
- ssl_crt
- ssl_key
3 biến này sẽ được định nghĩa trong phần biến.
Variables
Trước khi chúng ta tích hợp tất cả với nhau sử dụng các Task, hãy cùng xem tiếp phần variables. Thư mục var
chứa một file main.yml
chứa danh sách các biến mà chúng ta sẽ sử dụng. Nó là một nơi hữu ích cho chúng ta thay đổi cài đặt của toàn bộ cấu hình
Hãy cùng xem cấu hình file main.yml
sau đây
--- domain: serversforansible.com ssl_key: /etc/ssl/sfh/sfh.key ssl_crt: /etc/ssl/sfh/sfh.crt
Có 3 biến chúng ta có thể dùng bất cứ chỗ nào trong Role này. Chúng ta đã được nhìn thấy những biến này được sử dụng ở trong template bên trên, nhưng chúng ta cũng sẽ được nhìn thấy các biến này trong các Task được định nghĩa.
Nếu bạn có các thông tin quan trọng thêm vào trong file chứa các biến, bạn có thể mã hoá file sử dụng
ansible-vault
, sẽ được giải thích ở dưới đây
Task
Cuối cùng hãy cùng xem tất cả những cái này sẽ được tập hợp lại với nhau thành các Task
File chính sẽ được chạy khi chúng ta sử dụng một Role là file tasks/main.yml
. Nào hãy cùng xem cấu hình bên dưới đây
--- - name: Add Nginx Repository apt_repository: repo: ppa:nginx/stable state: present - name: Install Nginx apt: pkg: nginx state: installed update_cache: true notify: - Start Nginx - name: Add H5BP Config copy: src: h5bp dest: /etc/nginx owner: root group: root - name: Disable Default Site Configuration file: dest: /etc/nginx/sites-enabled/default state: absent # `dest` in quotes as a variable is used! - name: Add SFH Site Config register: sfhconfig template: src: serversforansible.com.j2 dest: '/etc/nginx/sites-available/{{ domain }}.conf' owner: root group: root # `src`/`dest` in quotes as a variable is used! - name: Enable SFH Site Config file: src: '/etc/nginx/sites-available/{{ domain }}.conf' dest: '/etc/nginx/sites-enabled/{{ domain }}.conf' state: link # `dest` in quotes as a variable is used! - name: Create Web root file: dest: '/var/www/{{ domain }}/public' mode: 775 state: directory owner: www-data group: www-data notify: - Reload Nginx # `dest` in quotes as a variable is used! - name: Web Root Permissions file: dest: '/var/www/{{ domain }}' mode: 775 state: directory owner: www-data group: www-data recurse: yes notify: - Reload Nginx
Đây là một chuỗi các Task dài hơn, giúp cho việc cài đặt Nginx hoàn chỉnh hơn. Các Task theo thứ tự xuất hiện, thực hiện như sau
- Thêm nginx/stable repository
- Cài đặt và start Nginx
- Thêm các file cấu hình HB5P
- Vô hiệu hoá Nginx mặc định bằng cách loại bỏ liên kết đến file default từ thư mục
sites-enabled
- Copy virtual host template serversforansible.com.conf.j2 trong cấu hình Nginx, tạo ra các template như đã làm
- Cho phép cấu hình Nginx bằng cách liên kết nó đến thư mục
sites-enabled
- Tạo thư mục web root
- Thay đổi quyền cho thư mục gốc của dự án
Có một vài module mới, bao gồm module Copy, Template và File. Bằng việc cài đặt các tham số cho mỗi Module, chúng ta có thể làm một vài điều thú vị như là đảm bảo các file là absent (xoá nếu chúng tồn tại) thông qua state: absent
, hoặc tạo một file như một liên kết thông qua state: link
. Bạn nên đọc qua tài liệu cho mỗi module để biết những điều hữu ích và thú vị mà bạn có thể thực hiện với chúng.
Chạy Role
Để chạy một hoặc nhiều Role đối với một Server, chúng ta sẽ sử dụng lại Playbook khác. Các Playbook nên ở trong cùng một thư mục như thư mục roles, nơi chúng ta cần cd vào bên trong khi chạy câu lệnh ansible-playbook
Tạm thời bỏ cấu hình phụ thuộc
ssl
trongmeta/main.yml
trước khi chạy Role này nếu bạn đang làm theo các bước bên trên
Tiếp theo chúng ta sẽ tạo một file “maser” yaml để định nghĩa các Role sử dụng và host nào để chạy chúng trên đó:
File ~/ansible-example/server.yml
, được đặt trong thư mục giống như thư mục roles:
--- # Chạy trên local - hosts: local connection: local roles: - nginx
Nên thay vì định nghĩa tất cả các biến và các Task trong file Playbook này, chúng ta đơn giản chỉ cần định nghĩa các Role cần chạy. Các Role sẽ có nhiệm vụ chi tiết cho từng nhiệm vụ
Tiếp theo chúng ta có thể chạy các Role:
ansible-playbook -i ./hosts server.yml
Ở đây kết quả khi chạy file Playbook chính là chạy Nginx Role:
PLAY [all] ******************************************************************** GATHERING FACTS *************************************************************** ok: [127.0.0.1] TASK: [nginx | Add Nginx Repository] ****************************************** changed: [127.0.0.1] TASK: [nginx | Install Nginx] ************************************************* changed: [127.0.0.1] TASK: [nginx | Add H5BP Config] *********************************************** changed: [127.0.0.1] TASK: [nginx | Disable Default Site] ****************************************** changed: [127.0.0.1] TASK: [nginx | Add SFH Site Config] ******************************************* changed: [127.0.0.1] TASK: [nginx | Enable SFH Site Config] **************************************** changed: [127.0.0.1] TASK: [nginx | Create Web root] *********************************************** changed: [127.0.0.1] TASK: [nginx | Web Root Permissions] ****************************************** ok: [127.0.0.1] NOTIFIED: [nginx | Start Nginx] *********************************************** ok: [127.0.0.1] NOTIFIED: [nginx | Reload Nginx] ********************************************** changed: [127.0.0.1] PLAY RECAP ******************************************************************** 127.0.0.1 : ok=8 changed=7 unreachable=0 failed=0
Chúng ta có thể đặt tất cả các thành phần thay đổi cùng nhau vào trong một Role kết nối và giờ đây Nginx đã được cấu hình và cài đặt.
Facts
Chú ý rằng dòng đầu tiên khi chạy playbook luôn luôn là “gathering facts”.
Trước khi chạy bất kỳ Task nào, Ansible sẽ thu thập thông tin về hệ thống nó đang cung cấp. Cái này được gọi là Facts, và nó bao gồm một loạt các thông tin về hệ thống như là số lõi CPU, mạng ipv4 và ipv6 có thể dùng, lượng ổ cứng đang dùng, phân vùng Linux… Sau đó sử dụng các biến để gọi các thông tin từ Facts ra. Nếu chúng ta không cần thu thập thông tin của host thì có thể thiết lập set grathering_facts: no
, nó giúp cho việc chạy Playbook nhanh hơn.
Facts thường rất hữu dụng trong cấu hình các Task và Template. Ví dụ Nginx thường được thiết lập để sử dụng với nhiều tiến trình vì CPU có đa lõi. Để thực hiện điều này bạn có thể thiết lập trong Template của Nginx ví dụ chúng ta có thể cấu hình file nginx.conf.j2
như sau:
user www-data; worker_processes {{ ansible_processor_cores }}; pid /var/run/nginx.pid; # Và các cấu hình khác...
Hoặc nếu Server của bạn có nhiều CPU, bạn có thể sử dụng
user www-data; worker_processes {{ ansible_processor_cores * ansible_processor_count }}; pid /var/run/nginx.pid; # Và các cấu hình khác...
Tất cả các Fact của Ansible đều bắt đầu với ansible_
và sẵn sàng sử dụng ở bất kỳ chỗ nào mà biến cần sử dụng: các file Variable, Task, và Template
Hãy thử chạy theo cấu hình trên trên máy local, để xem Fact hoạt động trong thực tế như thế nào
# Chạy đối với local server # Chú ý rằng chúng ta sử dụng "localhost" thay vì định nghĩa trong file hosts ansible -m setup --connection=local localhost # Chạy đối với remote server ansible -i ./hosts remote -m setup
Vault
Chúng ta thường lưu những thông tin nhạy cảm ở trong file Template, File hoặc Variable trong Ansible, đáng tiếc là chúng ta không thể tránh khỏi việc này. Ansible có một giải pháp cho vấn đề này là sử dụng Vault
Vault cho phép bạn mã hoá bất kỳ file YAML nào, mà chúng ta hay sử dụng dưới các file lưu thông tin biến. Vault không mã hoá các file File và Template, chỉ mã hoá các file YAML.
Khi tạo một file được mã hoá, bạn sẽ được yêu cầu nhập mật khẩu để giúp bạn có thể chỉnh sửa phải sau đấy và khi gọi Role hoặc Playbook
Lưu mật khẩu của bạn ở nơi nào đó an toàn
Ví dụ chúng ta có thể tạo một file Variable mới
ansible-vault create vars/main.yml Vault Password:
Sau khi nhập mật khẩu mã hoá, file sẽ được mở trên Editor mặc địch của bạn thường là Vim hoặc Nano
Bạn có thể gõ lệnh để xem hướng dẫn về Ansible vault như sau
$ ansible-vault -h Usage: ansible-vault [create|decrypt|edit|encrypt|rekey] \ [--help] [options] file_name Options: -h, --help show this help message and exit
Sau đây là ý nghĩa của từng lựa chọn
- create – Tạo một file mới và mã hoá nó
- decrypt – Tạo một file text từ một file mã hoá
- edit – Chỉnh sửa file mã hoá
- encrypt – Mã hoá một file text
- rekey – Đổi mật khẩu cho file mã hoá
Nếu bạn muốn mã hoá một file đang tồn tại thì dùng câu lệnh ansible-vault encrypt /path/to/file.yml
Ví dụ: Users
Giả sử chúng ta có Role thứ 2 tên là “users”
cd ~/ansible-example/roles ansible-galaxy init users
Chúng ta sẽ sử dụng Vault khi tạo một user mới và thiết lập mật khẩu cho chúng. Trong user Role, chúng ta sẽ tạo một file biến để lưu mật khẩu của user và một public key để thêm vào file authorized_keys
của user (giúp truy cập SSH).
Đây là ví dụ về file chứa biến mà chúng ta sẽ tạo và mã hoá bằng Vault, khi chỉnh sửa nó tất nhiên là nó chưa bị mã hoá
Đây là file ~/ansible-example/roles/users/variables/main.yml
admin_password: $6$lpQ1DqjZQ25gq9YW$mHZAmGhFpPVVv0JCYUFaDovu8u5EqvQi.Ih deploy_password: $6$edOqVumZrYW9$d5zj1Ok/G80DrnckixhkQDpXl0fACDfNx2EHnC common_public_key: ssh-rsa ALongSSHPublicKeyHere
Chú ý rằng mật khẩu của người dùng cũng được hash. Bạn có thể đọc trong tài liệu của Ansible để biết cách làm thể nào để sinh ra mật khẩu mã hoá. Bạn có thể chạy lệnh sau
# The whois package makes the mkpasswd # command available on Ubuntu $ sudo apt-get install -y whois # Create a password hash $ mkpasswd --method=SHA-512 Password:
Nó sẽ sinh ra cho bạn mật khẩu hash để sử dụng trong user module
Mật khẩu trong file biến được mã hoá, nhưng chúng ta vẫn mã hoá file yaml chứa các mật khẩu mã hoá này. Thường những file chứa dữ liệu chưa được mã hoá như là token của API hoặc SSH private key, thì việc tạo file mã hoá là vô cùng quan trọng
Sau khi bạn đã cấu hình mật khẩu người dùng và public key trong file biến, chúng ta có thể mã hoá file và sau đó tạo Task sử dụng các biến được mã hoá.
ansible-vault encrypt roles/users/variables/main.yml > INPUT PASSWORD
Sau đó chúng ta chỉnh sửa file Task được sử dụng để thêm user và sử dụng các biến mã hoá:
Đây là file chúng ta sẽ cập nhập ~/ansible-example/roles/users/tasks/main.yml
--- - name: Create Admin User user: name: admin password: '{{ admin_password }}' groups: sudo append: yes shell: /bin/bash - name: Add Admin Authorized Key authorized_key: user: admin key: '{{ common_public_key }}' state: present - name: Create Deploy User user: name: deploy password: '{{ deploy_password }}' groups: www-data append: yes shell: /bin/bash - name: Add Deployer Authorized Key authorized_key: user: deploy key: '{{ common_public_key }}' state: present
Những Task này sử dụng trong user module để tạo user mới và truyền mật khẩu user được lưu trong file biến mã hoá
Nó cũng sử dụng authorized_key
module để thêm SSH public key để người dùng có thể truy cập đên Server bằng private key trên máy họ
Các biến mã hoá được sử dụng bình thường trong các file Task. Tuy nhiên mục đích để chạy Role này, chúng ta sẽ nói với Ansible để yêu cầu người dùng nhập mật khẩu Vault giúp nó có thể giải mã được các file này.
Nào hày chỉnh sửa file Playbook server.yml
để gọi user Role
--- # Local connection here - hosts: local connection: local sudo: yes roles: - nginx - user
Để chạy Playbook này chung ta sẽ yêu cầu Ansible hỏi Vault mật khẩu, khi chúng ta chạy đến Role chứa file mã hoá:
ansible-playbook --ask-vault-pass -i ./hosts server.yml