Cách quản lý môi trường nhiều tầng với Ansible
Ansible là một hệ thống quản lý cấu hình mạnh mẽ được sử dụng để cài đặt và quản lý cơ sở hạ tầng và ứng dụng trong các môi trường khác nhau. Mặc dù Ansible cung cấp cú pháp dễ đọc, quy trình làm việc linh hoạt và công cụ mạnh mẽ, nhưng việc quản lý số lượng lớn server lưu trữ có thể khó khăn khi chúng thay đổi theo môi trường triển khai và chức năng.Trong hướng dẫn này, ta sẽ thảo luận về một số chiến lược sử dụng Ansible để làm việc với các môi trường triển khai nhiều tầng. Thông thường, các yêu cầu cho các giai đoạn khác nhau sẽ dẫn đến số lượng và cấu hình của các thành phần khác nhau. Ví dụ: các yêu cầu bộ nhớ cho server phát triển có thể khác với các yêu cầu cho dàn dựng và production và điều quan trọng là phải kiểm soát rõ ràng cách các biến đại diện cho các yêu cầu đó được ưu tiên. Trong bài viết này, ta sẽ thảo luận một số cách mà những khác biệt này có thể được trừu tượng hóa và một số cấu trúc mà Ansible cung cấp để khuyến khích tái sử dụng cấu hình.
Các chiến lược chưa hoàn chỉnh để quản lý môi trường đa tầng với Ansible
Mặc dù có một số cách mà bạn có thể quản lý môi trường bên trong Ansible, nhưng bản thân Ansible không đưa ra một giải pháp phù hợp. Thay vào đó, nó cung cấp nhiều cấu trúc được dùng để quản lý môi trường và cho phép user lựa chọn.
Cách tiếp cận mà ta sẽ trình bày trong hướng dẫn này dựa trên các biến group Ansible và nhiều khoảng không quảng cáo . Tuy nhiên, có một số chiến lược khác đáng được xem xét. Ta sẽ khám phá một số ý tưởng dưới đây và tại sao chúng có thể gây ra các vấn đề khi thực hiện trong môi trường phức tạp.
Nếu bạn muốn bắt đầu với chiến lược được đề xuất của Ansible, hãy chuyển sang phần sử dụng group Ansible và nhiều khoảng không quảng cáo .
Chỉ dựa vào các biến group
Thoạt nhìn, có vẻ như các biến group cung cấp tất cả sự tách biệt giữa các môi trường mà Ansible yêu cầu. Bạn có thể chỉ định một số server nhất định thuộc về môi trường phát triển của bạn và những server khác có thể được chỉ định cho các khu vực production và dàn dựng. Ansible giúp bạn dễ dàng tạo group và gán biến cho chúng.
Tuy nhiên, sự giao nhau giữa các group lại gây ra nhiều vấn đề nghiêm trọng cho hệ thống này. Group thường được sử dụng để phân loại nhiều thứ nguyên. Ví dụ:
- môi trường triển khai (local, dev, stage, prod, v.v.)
- chức năng server ( web server , server database , v.v.)
- khu vực trung tâm dữ liệu (NYC, SFO, v.v.)
Trong những trường hợp này, server thường sẽ nằm trong một group cho mỗi danh mục. Ví dụ: server lưu trữ có thể là web server (chức năng) trên sân khấu (môi trường triển khai) ở NYC (vùng trung tâm dữ liệu).
Nếu cùng một biến được đặt bởi nhiều group cho một server lưu trữ, Ansible không có cách nào chỉ định rõ ràng mức độ ưu tiên. Bạn có thể thích các biến được liên kết với môi trường triển khai overrides các giá trị khác, nhưng Ansible không cung cấp cách xác định điều này.
Thay vào đó, Ansible sử dụng giá trị được tải cuối cùng . Vì Ansible đánh giá các group theo thứ tự bảng chữ cái, nên biến được liên kết với bất kỳ tên group nào đứng cuối cùng trong thứ tự từ điển sẽ thắng. Đây là hành vi có thể dự đoán được, nhưng việc quản lý rõ ràng bảng chữ cái tên group thì ít lý tưởng hơn từ góc độ quản trị.
Sử dụng Group Con để Cài đặt Hệ thống Phân cấp
 Ansible cho phép bạn chỉ định  group  cho các  group  khác bằng cú pháp [ groupname :children] trong repository .Điều này cung cấp cho bạn khả năng đặt tên cho một số  group  thành viên của các  group  khác. Các  group  con có khả năng overrides  các biến do  group  mẹ đặt.
 Thông thường, điều này được sử dụng để phân loại tự nhiên. Ví dụ,  ta  có thể có một  group  được gọi là environments bao gồm các  group  dev , stage , prod . Điều này có nghĩa  ta  có thể  cài đặt  các biến trong environment  group  và overrides  lên chúng trong dev  group . Bạn tương tự có thể có một  group  phụ huynh gọi là functions có chứa các  group  web , database , và loadbalancer .
 Cách sử dụng này không giải quyết được vấn đề giao  group  vì các  group  con chỉ overrides  cha mẹ của chúng. Các  group  con có thể overrides  các biến bên trong tổ chức mẹ, nhưng tổ chức trên đã không  cài đặt  bất kỳ mối quan hệ nào giữa các danh mục  group , như environments và functions . Mức độ ưu tiên thay đổi giữa hai danh mục vẫn chưa được xác định.
Có thể khai thác hệ thống này bằng cách cài đặt thành viên group phi tự nhiên. Ví dụ: nếu bạn muốn cài đặt mức độ ưu tiên sau, từ mức độ ưu tiên cao nhất đến mức độ ưu tiên thấp nhất:
- môi trương phat triển
- khu vực
- chức năng
Bạn có thể chỉ định tư cách thành viên group giống như sau:
. . . [function:children] web database loadbalancer region  [region:children] nyc sfo environments  [environments:children] dev stage prod  Ta  đã  cài đặt  một hệ thống phân cấp ở đây cho phép các biến vùng overrides  các biến chức năng vì  group  region là con của  group  function . Tương tự như vậy, các biến được đặt trong các  group  environments có thể overrides  lên bất kỳ biến nào khác. Điều này  nghĩa là  nếu  ta  đặt cùng một biến thành một giá trị khác trong  group  dev , nyc và web , thì một  server  thuộc mỗi  group  này sẽ sử dụng biến từ dev .
Điều này đạt được kết quả mong muốn và cũng có thể dự đoán được. Tuy nhiên, nó không trực quan và nó làm xáo trộn sự phân biệt giữa những đứa trẻ thực sự và những đứa trẻ cần thiết để cài đặt hệ thống phân cấp. Ansible được thiết kế để cấu hình của nó rõ ràng và dễ theo dõi ngay cả đối với user mới. Loại công việc xung quanh thỏa hiệp mục tiêu đó.
Sử dụng cấu trúc an toàn cho phép thứ tự tải rõ ràng
 Có một số cấu trúc bên trong Ansible cho phép sắp xếp tải thay đổi rõ ràng, cụ thể là vars_files và include_vars . Chúng  được dùng  trong các lượt chơi Ansible để tải rõ ràng các biến bổ sung theo thứ tự được xác định trong file . Chỉ thị vars_files hợp lệ trong ngữ cảnh của một trò chơi, trong khi module  include_vars  được dùng  trong  các việc .
 Ý tưởng chung là chỉ đặt các biến nhận dạng cơ bản trong group_vars và sau đó tận dụng các biến này để tải các file  biến chính xác với phần còn lại của các biến mong muốn.
 Ví dụ: một số file  group_vars có thể trông giống như sau:
--- env: dev --- env: stage --- function: web --- function: database Sau đó,  ta  sẽ có một file  vars riêng biệt xác định các biến quan trọng cho mỗi  group . Chúng thường được giữ trong một folder  vars riêng biệt để rõ ràng. Không giống như các file  group_vars , khi xử lý include_vars , các file  phải bao gồm phần mở rộng file  .yml .
 Hãy giả sử rằng  ta  cần đặt biến server_memory_size thành một giá trị khác trong mỗi file  vars .  Server  phát triển của bạn có thể sẽ nhỏ hơn  server  production  của bạn. Hơn nữa,  web server  và  server  database  của bạn có thể có các yêu cầu bộ nhớ khác nhau:
--- server_memory_size: 512mb --- server_memory_size: 4gb --- server_memory_size: 1gb --- server_memory_size: 2gb Sau đó,  ta  có thể tạo một playbook tải file  vars chính xác một cách rõ ràng dựa trên các giá trị được gán cho  server  từ các file  group_vars . Thứ tự của các file  được tải sẽ xác định mức độ ưu tiên, với giá trị cuối cùng sẽ chiến thắng.
 Với vars_files , một lần chơi mẫu sẽ giống như sau:
--- - name: variable precedence test   hosts: all   vars_files:     - "vars/{{ env }}.yml"     - "vars/{{ function }}.yml"   tasks:     - debug: var=server_memory_size Vì các  group  chức năng được tải sau cùng, giá trị server_memory_size sẽ được lấy từ các var/web.yml và var/database.yml :
- ansible-playbook -i inventory example_play.yml 
Output. . . TASK [debug] ******************************************************************* ok: [host1] => {     "server_memory_size": "1gb"      # value from vars/web.yml } ok: [host2] => {     "server_memory_size": "1gb"      # value from vars/web.yml } ok: [host3] => {     "server_memory_size": "2gb"      # value from vars/database.yml } ok: [host4] => {     "server_memory_size": "2gb"      # value from vars/database.yml } . . . Nếu ta chuyển đổi thứ tự của các file sẽ được tải, ta có thể làm cho các biến môi trường triển khai có mức độ ưu tiên cao hơn:
--- - name: variable precedence test   hosts: all   vars_files:     - "vars/{{ function }}.yml"     - "vars/{{ env }}.yml"   tasks:     - debug: var=server_memory_size Chạy lại playbook sẽ hiển thị các giá trị đang được áp dụng từ các file môi trường triển khai:
- ansible-playbook -i inventory example_play.yml 
Output. . . TASK [debug] ******************************************************************* ok: [host1] => {     "server_memory_size": "512mb"      # value from vars/dev.yml } ok: [host2] => {     "server_memory_size": "4gb"        # value from vars/prod.yml } ok: [host3] => {     "server_memory_size": "512mb"      # value from vars/dev.yml } ok: [host4] => {     "server_memory_size": "4gb"        # value from vars/prod.yml } . . . Playbook tương đương sử dụng include_vars , hoạt động như một tác vụ, sẽ giống như sau:
--- - name: variable precedence test   hosts: localhost   tasks:     - include_vars:         file: "{{ item }}"       with_items:         - "vars/{{ function }}.yml"         - "vars/{{ env }}.yml"     - debug: var=server_memory_size Đây là một lĩnh vực mà Ansible cho phép đặt hàng rõ ràng, điều này có thể rất hữu ích. Tuy nhiên, cũng như các ví dụ trước, có một số nhược điểm đáng kể.
 Trước hết, việc sử dụng vars_files và include_vars yêu cầu bạn đặt các biến được liên kết chặt chẽ với các  group  ở một vị trí khác. Vị trí group_vars trở thành sơ khai cho các biến thực tế nằm trong folder  vars . Điều này    làm tăng thêm sự phức tạp và giảm độ rõ ràng.  User  phải khớp đúng các file  biến với  server , đây là điều mà Ansible thực hiện tự động khi sử dụng group_vars .
 Quan trọng hơn, việc dựa vào những kỹ thuật này khiến chúng trở nên bắt buộc. Mỗi playbook sẽ yêu cầu một phần tải rõ ràng các file  biến chính xác theo đúng thứ tự. Playbook không có điều này sẽ không thể sử dụng các biến được liên kết. Hơn nữa, việc chạy lệnh ansible cho  các việc  đặc biệt sẽ gần như hoàn toàn không thể đối với bất kỳ thứ gì dựa vào các biến.
Chiến lược được đề xuất Ansible: Sử dụng Group và Nhiều Khoảng không quảng cáo
Lúc này, ta đã xem xét một số chiến lược để quản lý môi trường nhiều tầng và thảo luận về lý do tại sao chúng có thể không phải là một giải pháp hoàn chỉnh. Tuy nhiên, dự án Ansible đưa ra một số gợi ý về cách tốt nhất để tóm tắt cơ sở hạ tầng của bạn trên các môi trường.
 Cách tiếp cận  được khuyến khích  là làm việc với môi trường nhiều tầng bằng cách tách biệt hoàn toàn từng môi trường hoạt động. Thay vì duy trì tất cả các  server  của bạn trong một file  khoảng không quảng cáo, một khoảng không quảng cáo được duy trì cho từng môi trường riêng lẻ của bạn. Các folder  group_vars riêng biệt cũng được duy trì.
Cấu trúc folder cơ bản sẽ giống như sau:
. ├── ansible.cfg ├── environments/         # Parent directory for our environment-specific directories │   │ │   ├── dev/              # Contains all files specific to the dev environment │   │   ├── group_vars/   # dev specific group_vars files │   │   │   ├── all │   │   │   ├── db │   │   │   └── web │   │   └── hosts         # Contains only the hosts in the dev environment │   │ │   ├── prod/             # Contains all files specific to the prod environment │   │   ├── group_vars/   # prod specific group_vars files │   │   │   ├── all │   │   │   ├── db │   │   │   └── web │   │   └── hosts         # Contains only the hosts in the prod environment │   │ │   └── stage/            # Contains all files specific to the stage environment │       ├── group_vars/   # stage specific group_vars files │       │   ├── all │       │   ├── db │       │   └── web │       └── hosts         # Contains only the hosts in the stage environment │ ├── playbook.yml │ └── . . .  Như bạn thấy , mỗi môi trường đều khác biệt và được ngăn cách. Các folder  môi trường chứa một file  kiểm kê ( hosts được đặt tên tùy ý) và một folder  group_vars riêng biệt.
 Có một số sự trùng lặp rõ ràng trong cây folder . Có các file  web và db cho từng môi trường riêng lẻ. Trong trường hợp này, sự trùng lặp là mong muốn. Thay đổi biến có thể được triển khai trên các môi trường bằng cách sửa đổi đầu tiên các biến trong một môi trường và chuyển chúng sang môi trường tiếp theo sau khi thử nghiệm, giống như bạn làm với các thay đổi về mã hoặc cấu hình. Các biến group_vars theo dõi các giá trị mặc định hiện tại cho mỗi môi trường.
Một hạn chế là không thể chọn tất cả các server theo chức năng trên các môi trường. May mắn là điều này rơi vào cùng một loại với vấn đề trùng lặp biến ở trên. Mặc dù việc chọn tất cả các web server của bạn cho một nhiệm vụ đôi khi rất hữu ích, nhưng bạn hầu như luôn muốn áp dụng các thay đổi trên các môi trường của bạn cùng một lúc. Điều này giúp ngăn ngừa những sai sót ảnh hưởng đến môi trường production của bạn.
Đặt các biến môi trường chéo
 Một điều không thể thực hiện được trong  cài đặt  được đề xuất là chia sẻ biến trên các môi trường. Có một số cách  ta  có thể triển khai chia sẻ biến môi trường chéo. Một trong những cách đơn giản nhất là tận dụng khả năng của Ansible để sử dụng folder  thay cho file .  Ta  có thể thay thế all file  trong mỗi folder  group_vars bằng một folder  all .
Bên trong folder , ta có thể đặt lại tất cả các biến theo môi trường cụ thể trong một file . Sau đó, ta có thể tạo một softlink đến một vị trí file có chứa các biến môi trường chéo. Cả hai điều này sẽ được áp dụng cho tất cả các server trong môi trường.
 Bắt đầu bằng cách tạo file  biến môi trường chéo ở đâu đó trong hệ thống phân cấp. Trong ví dụ này,  ta  sẽ đặt nó trong folder  environments . Đặt tất cả các biến môi trường chéo trong file  đó:
- cd environments 
- touch 000_cross_env_vars 
Tiếp theo, di chuyển vào một trong folder  group_vars , đổi tên all file  và tạo folder  all . Di chuyển file  đã đổi tên vào folder  mới:
- cd dev/group_vars 
- mv all env_specific 
- mkdir all 
- mv env_specific all/ 
Tiếp theo, bạn có thể tạo một softlink đến file biến môi trường chéo:
- cd all/ 
- ln -s ../../../000_cross_env_vars . 
Khi bạn đã hoàn thành các bước trên cho từng môi trường của bạn , cấu trúc folder của bạn sẽ trông giống như sau:
. ├── ansible.cfg ├── environments/ │   │ │   ├── 000_cross_env_vars │   │ │   ├── dev/ │   │   ├── group_vars/ │   │   │   ├── all/ │       │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars │   │   │   │   └── env_specific │   │   │   ├── db │   │   │   └── web │   │   └── hosts │   │ │   ├── prod/ │   │   ├── group_vars/ │   │   │   ├── all/ │   │   │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars │   │   │   │   └── env_specific │   │   │   ├── db │   │   │   └── web │   │   └── hosts │   │ │   └── stage/ │       ├── group_vars/ │       │   ├── all/ │       │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars │       │   │   └── env_specific │       │   ├── db │       │   └── web │       └── hosts │ ├── playbook.yml │ └── . . . Các biến được đặt trong file  000_cross_env_vars sẽ có sẵn cho mỗi môi trường có mức độ ưu tiên thấp.
Đặt khoảng không quảng cáo môi trường mặc định
 Có thể đặt file  kiểm kê mặc định trong file  ansible.cfg . Đây là một ý tưởng hay vì một vài lý do.
 Đầu tiên, nó cho phép bạn loại bỏ các cờ kiểm kê rõ ràng thành sách có thể ansible và có thể ansible-playbook . Vì vậy, thay vì gõ:
- ansible -i environments/dev -m ping 
Bạn có thể truy cập khoảng không quảng cáo mặc định bằng lệnh :
- ansible -m ping 
Thứ hai, đặt khoảng không quảng cáo mặc định giúp ngăn chặn những thay đổi không mong muốn vô tình ảnh hưởng đến  môi trường production  hoặc dàn dựng. Bằng cách mặc định môi trường phát triển của bạn, cơ sở hạ tầng ít quan trọng nhất bị ảnh hưởng bởi các thay đổi. Khi đó, thúc đẩy các thay đổi đối với môi trường mới là một hành động rõ ràng yêu cầu cờ -i .
 Để đặt khoảng không quảng cáo mặc định, hãy mở file  ansible.cfg của bạn. Điều này có thể nằm trong folder  root  của dự án của bạn hoặc tại /etc/ansible/ansible.cfg tùy thuộc vào cấu hình của bạn.
 Lưu ý: Ví dụ dưới đây minh họa việc chỉnh sửa file  ansible.cfg trong folder  dự án. Nếu bạn đang sử dụng file  /etc/ansibile/ansible.cfg cho các thay đổi  của bạn , hãy sửa đổi đường dẫn chỉnh sửa bên dưới. Khi sử dụng /etc/ansible/ansible.cfg , nếu khoảng không quảng cáo của bạn được duy trì bên ngoài folder  /etc/ansible , hãy đảm bảo sử dụng đường dẫn tuyệt đối thay vì đường dẫn tương đối khi đặt giá trị inventory .
- nano ansible.cfg 
Như đã đề cập ở trên, bạn nên đặt môi trường phát triển của bạn làm khoảng không quảng cáo mặc định. Lưu ý cách ta có thể chọn toàn bộ folder môi trường thay vì file server mà nó chứa:
[defaults] inventory = ./environments/dev  Đến đây bạn  có thể sử dụng khoảng không quảng cáo mặc định  của bạn  mà không có tùy chọn -i . Khoảng không quảng cáo không mặc định sẽ vẫn yêu cầu sử dụng -i , giúp bảo vệ chúng khỏi những thay đổi ngẫu nhiên.
Kết luận
Trong bài viết này, ta đã khám phá tính linh hoạt mà Ansible cung cấp để quản lý server của bạn trên nhiều môi trường. Điều này cho phép user áp dụng nhiều chiến lược khác nhau để xử lý mức độ ưu tiên thay đổi khi server lưu trữ là thành viên của nhiều group , nhưng sự mơ hồ và thiếu định hướng chính thức có thể là một thách thức. Như với bất kỳ công nghệ nào, sự phù hợp nhất cho tổ chức của bạn sẽ phụ thuộc vào các trường hợp sử dụng và mức độ phức tạp của các yêu cầu của bạn. Cách tốt nhất để tìm một chiến lược phù hợp với nhu cầu của bạn là thử nghiệm. Chia sẻ trường hợp sử dụng và cách tiếp cận của bạn trong các comment bên dưới.
Các tin liên quan
 

