Thứ năm, 12/03/2020 | 00:00 GMT+7

Quản lý cấu hình 101: Công thức nấu ăn cho đầu bếp


Tóm lại, quản lý cấu hình server (còn được gọi phổ biến là Tự động hóa CNTT) là một giải pháp để biến quản trị cơ sở hạ tầng của bạn thành một cơ sở mã, mô tả tất cả các quy trình cần thiết để triển khai server trong một tập hợp các tập lệnh cấp phép có thể được tạo version và dễ dàng sử dụng lại. Nó có thể cải thiện đáng kể tính toàn vẹn của bất kỳ cơ sở hạ tầng server nào theo thời gian.

Trong hướng dẫn trước , ta đã nói về những lợi ích chính của việc triển khai chiến lược quản lý cấu hình cho cơ sở hạ tầng server của bạn, cách hoạt động của các công cụ quản lý cấu hình và những điểm chung của những công cụ này.

Phần này của loạt bài sẽ hướng dẫn bạn quy trình tự động hóa việc cung cấp server bằng Chef, một công cụ quản lý cấu hình mạnh mẽ sử dụng ngôn ngữ lập trình Ruby để tự động hóa việc quản lý và cung cấp cơ sở hạ tầng. Ta sẽ tập trung vào thuật ngữ ngôn ngữ, cú pháp và các tính năng cần thiết để tạo một ví dụ đơn giản nhằm tự động hóa hoàn toàn việc triển khai web server Ubuntu 18.04 bằng Apache.

Đây là danh sách các bước ta cần tự động hóa để đạt được mục tiêu của bạn :

  1. Cập nhật bộ nhớ cache apt
  2. Cài đặt Apache
  3. Tạo một folder root tài liệu tùy chỉnh
  4. Đặt index.html vào root tài liệu tùy chỉnh
  5. Áp dụng một mẫu để cài đặt server ảo tùy chỉnh của ta
  6. Khởi động lại Apache

Ta sẽ bắt đầu bằng cách xem xét thuật ngữ mà Chef sử dụng, tiếp theo là tổng quan về các đặc điểm ngôn ngữ chính được dùng để viết công thức nấu ăn. Ở cuối hướng dẫn này, ta sẽ chia sẻ ví dụ hoàn chỉnh để bạn có thể tự mình thử.

Lưu ý: hướng dẫn này nhằm giúp bạn làm quen với ngôn ngữ Chef và cách viết công thức nấu ăn để tự động hóa việc cung cấp server của bạn. Để có cái nhìn giới thiệu hơn về Chef, bao gồm các bước cần thiết để cài đặt và bắt đầu với công cụ này, vui lòng tham khảo tài liệu chính thức của Chef .

Bắt đầu

Trước khi ta có thể chuyển sang một cái nhìn thực tế hơn về Chef, điều quan trọng là ta phải làm quen với các thuật ngữ và khái niệm quan trọng được giới thiệu bởi công cụ này.

Điều khoản đầu bếp

  • Chef Server : một server trung tâm lưu trữ thông tin và quản lý việc cung cấp các node
  • Chef Node : một server riêng lẻ được quản lý bởi Chef Server
  • Chef Workstation : một máy điều khiển nơi cung cấp được tạo và tải lên Chef Server
  • Công thức : một file chứa một tập hợp các hướng dẫn (tài nguyên) được thực thi. Một công thức phải có trong Sách dạy nấu ăn
  • Resource : một phần mã khai báo một phần tử của hệ thống và hành động nào sẽ được thực thi. Ví dụ, để cài đặt một gói, ta khai báo một tài nguyên gói với cài đặt hành động
  • Sách dạy nấu ăn : tập hợp các công thức nấu ăn và các file liên quan khác được sắp xếp theo cách xác định trước để tạo điều kiện chia sẻ và sử dụng lại các phần của cấp phép
  • Thuộc tính : chi tiết về một nút cụ thể. Các thuộc tính có thể tự động (xem định nghĩa tiếp theo) và cũng có thể được xác định bên trong công thức nấu ăn
  • Thuộc tính tự động : các biến toàn cục chứa thông tin về hệ thống, như network interface và hệ điều hành (được gọi là dữ kiện trong các công cụ khác). Các thuộc tính tự động này được thu thập bởi một công cụ có tên là Ohai
  • Dịch vụ : được sử dụng để kích hoạt các thay đổi trạng thái dịch vụ, như khởi động lại hoặc dừng một dịch vụ

Định dạng công thức

Công thức nấu ăn đầu bếp được viết bằng Ruby. Về cơ bản, một công thức là một tập hợp các định nghĩa tài nguyên sẽ tạo ra một tập hợp các hướng dẫn từng bước được các node thực thi. Các định nghĩa tài nguyên này có thể được trộn với mã Ruby để có tính linh hoạt và mô đun hơn.

Dưới đây, bạn có thể tìm thấy một ví dụ đơn giản về công thức sẽ chạy apt-get update và cài đặt vim sau đó:

execute "apt-get update" do
 command "apt-get update"
end

apt_package "vim" do
 action :install
end

Viết công thức

Làm việc với các biến

Các biến local có thể được định nghĩa bên trong các công thức nấu ăn như các biến local Ruby thông thường. Ví dụ dưới đây cho thấy cách tạo một biến local sau này được sử dụng bên trong định nghĩa tài nguyên:

package  = "vim"

apt_package package do
 action :install
end

Tuy nhiên, các biến này có phạm vi hạn chế, chỉ có giá trị trong file nơi chúng được xác định. Nếu bạn muốn tạo một biến và cung cấp nó trên phạm vi global , để bạn có thể sử dụng nó từ bất kỳ sách nấu ăn hoặc công thức nấu ăn nào của bạn , bạn cần xác định một thuộc tính tùy chỉnh .

Sử dụng thuộc tính

Các thuộc tính thể hiện chi tiết về một nút. Chef có các thuộc tính tự động, là các thuộc tính được thu thập bởi một công cụ có tên là Ohai và chứa thông tin về hệ thống (chẳng hạn như nền tảng, tên server và địa chỉ IP mặc định), nhưng nó cũng cho phép bạn xác định các thuộc tính tùy chỉnh của riêng mình.

Các thuộc tính có các mức độ ưu tiên khác nhau, được xác định bởi loại thuộc tính bạn tạo. thuộc tính default là lựa chọn phổ biến nhất, vì chúng vẫn có thể bị overrides bởi các loại thuộc tính khác khi muốn.

Ví dụ sau cho thấy ví dụ trước sẽ trông như thế nào với thuộc tính nút default thay vì biến local :

node.default['main']['package'] = "vim"

apt_package node['main']['package'] do
 action :install
end

Có hai chi tiết cần quan sát trong ví dụ này:

Thực hành được khuyến khích khi xác định các biến nút là tổ chức chúng dưới dạng băm bằng cách sử dụng sách nấu ăn hiện tại đang được sử dụng làm khóa. Trong trường hợp này, ta đã sử dụng main , vì ta có một cuốn sách dạy nấu ăn có cùng tên. Điều này tránh nhầm lẫn nếu bạn đang làm việc với nhiều sách nấu ăn có thể có các thuộc tính được đặt tên giống nhau.
Lưu ý ta đã sử dụng node.default khi xác định thuộc tính, nhưng khi truy cập giá trị của nó sau đó, ta đã sử dụng node trực tiếp. Việc sử dụng node.default xác định rằng ta đang tạo một thuộc tính kiểu default . Thuộc tính này có thể bị overrides giá trị của một loại khác có mức độ ưu tiên cao hơn, chẳng hạn như thuộc tính bình thường hoặc ghi đè .

Mức độ ưu tiên của các thuộc tính có thể hơi khó hiểu lúc đầu, nhưng bạn sẽ quen với nó sau một số thực hành. Để minh họa hành vi, hãy xem xét ví dụ sau:

node.normal['main']['package']  = "vim"

node.override['main']['package'] = "git"

node.default['main']['package'] = "curl"

apt_package node['main']['package'] do
 action :install
end

Bạn có biết gói nào sẽ được cài đặt trong trường hợp này không? Nếu bạn đoán git , bạn đã đoán đúng. Dù thứ tự mà các thuộc tính được xác định, mức độ ưu tiên cao hơn của kiểu override sẽ làm cho node['main']['package'] be evaluated to git`.

Sử dụng vòng lặp

Vòng lặp thường được sử dụng để lặp lại một tác vụ sử dụng các giá trị đầu vào khác nhau. Ví dụ: thay vì tạo 10 tác vụ để cài đặt 10 gói khác nhau, bạn có thể tạo một tác vụ duy nhất và sử dụng vòng lặp để lặp lại tác vụ với tất cả các gói khác nhau mà bạn muốn cài đặt.

Chef hỗ trợ tất cả các cấu trúc vòng lặp Ruby để tạo vòng lặp bên trong các công thức nấu ăn. Để sử dụng đơn giản, each là một lựa chọn phổ biến:

['vim', 'git', 'curl'].each do |package|
 apt_package package do
   action :install
 end
end

Thay vì sử dụng mảng nội tuyến, bạn cũng có thể tạo một biến hoặc thuộc tính để xác định các tham số bạn muốn sử dụng bên trong vòng lặp. Điều này sẽ giúp mọi thứ có tổ chức hơn và dễ đọc hơn. Dưới đây, cùng một ví dụ sử dụng biến local để xác định các gói sẽ được cài đặt:

packages = ['vim', 'git', 'curl']

packages.each do |package|
 apt_package package do
   action :install
 end
end

Sử dụng Điều kiện

Các điều kiện được dùng để tự động quyết định xem có nên thực thi một khối mã hay không, dựa trên một biến hoặc kết quả từ một lệnh, chẳng hạn.

Chef hỗ trợ tất cả các điều kiện Ruby để tạo các câu lệnh điều kiện bên trong các công thức nấu ăn. Ngoài ra, tất cả các loại tài nguyên hỗ trợ hai thuộc tính đặc biệt sẽ đánh giá một biểu thức trước khi quyết định xem tác vụ có nên được thực thi hay không: if_onlynot_if .

Ví dụ dưới đây sẽ kiểm tra sự tồn tại của php trước khi cố gắng cài đặt phần mở rộng php-pear . Nó sẽ sử dụng lệnh which cho việc xác minh nếu có một php thực thi hiện được cài đặt trên hệ thống này. Nếu lệnh which php trả về false, tác vụ này sẽ không được thực thi:

apt_package "php-pear" do
 action :install
 only_if "which php"
end

Nếu ta muốn làm ngược lại, thực hiện một lệnh mọi lúc ngoại trừ khi một điều kiện được đánh giá là đúng, ta sử dụng not_if để thay thế. Ví dụ này sẽ cài đặt php5 trừ khi hệ thống là CentOS:

apt_package "php5" do
 action :install
 not_if { node['platform'] == 'centos' }
end

Để thực hiện các đánh giá phức tạp hơn, nếu bạn muốn thực hiện một số tác vụ trong một điều kiện cụ thể, bạn có thể sử dụng bất kỳ điều kiện tiêu chuẩn nào của Ruby. Ví dụ sau sẽ chỉ thực thi apt-get update khi hệ thống là Debian hoặc Ubuntu:

if node['platform'] == 'debian' || node['platform'] == 'ubuntu'
 execute "apt-get update" do
   command "apt-get update"
 end
end

Nút thuộc tính node['platform'] là một thuộc tính tự động từ Chef. Ví dụ cuối cùng chỉ để chứng minh một cấu trúc có điều kiện phức tạp hơn, tuy nhiên nó có thể được thay thế bằng một bài kiểm tra đơn giản bằng cách sử dụng node['platform_family'] thuộc tính tự động node['platform_family'] , node['platform_family'] này sẽ trả về "debian" cho cả hệ thống Debian và Ubuntu.

Làm việc với các mẫu

Các mẫu thường được sử dụng để cài đặt các file cấu hình, cho phép sử dụng các biến và các tính năng khác nhằm mục đích làm cho các file này linh hoạt hơn và có thể tái sử dụng.

Chef sử dụng các mẫu Ruby nhúng (ERB), đây là định dạng giống như Puppet. Chúng hỗ trợ các điều kiện, vòng lặp và các tính năng khác của Ruby.

Dưới đây là ví dụ về mẫu ERB để cài đặt server ảo Apache, sử dụng một biến để xác định root tài liệu cho server này:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot <%= @doc_root %>

    <Directory <%= @doc_root %>>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Để áp dụng mẫu, ta cần tạo một tài nguyên template . Đây là cách bạn áp dụng mẫu này để thay thế server ảo Apache mặc định:

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
end 

Chef đưa ra một số giả định khi xử lý các file local , để thực thi tổ chức và mô đun. Trong trường hợp này, Chef sẽ tìm kiếm file mẫu vhost.erb bên trong folder mẫu nằm trong cùng một sách dạy nấu ăn nơi chứa công thức này.

Không giống như các công cụ quản lý cấu hình khác mà ta đã thấy cho đến nay, Chef có phạm vi nghiêm ngặt hơn cho các biến. Điều này nghĩa là bạn sẽ phải cung cấp rõ ràng bất kỳ biến nào bạn định sử dụng bên trong một mẫu, khi xác định tài nguyên template . Trong ví dụ này, ta đã sử dụng phương thức variables để chuyển cùng thuộc tính doc_root mà ta cần tại mẫu server ảo.

Dịch vụ xác định và kích hoạt

Tài nguyên dịch vụ được sử dụng đảm bảo các dịch vụ được khởi tạo và kích hoạt. Chúng cũng được sử dụng để kích hoạt khởi động lại dịch vụ.

Trong Chef, các tài nguyên phục vụ cần được khai báo trước khi bạn cố gắng thông báo cho họ, nếu không bạn sẽ gặp lỗi.

Hãy xem xét ví dụ sử dụng mẫu trước đây của ta , nơi ta cài đặt server ảo Apache. Nếu bạn cần đảm bảo Apache được khởi động lại sau khi thay đổi server ảo, trước tiên bạn cần tạo tài nguyên dịch vụ cho dịch vụ Apache. Đây là cách tài nguyên đó được định nghĩa trong Chef:

service "apache2" do
  action [ :enable, :start ]
end

Bây giờ, khi xác định tài nguyên mẫu , bạn cần bao gồm tùy chọn notify để kích hoạt khởi động lại:

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
 notifies :restart, resources(:service => "apache2")
end

Công thức ví dụ

Bây giờ ta hãy xem xét một công thức sẽ tự động cài đặt web server Apache trong hệ thống Ubuntu 14.04, như được thảo luận trong phần giới thiệu của hướng dẫn này.

Bạn có thể tìm thấy ví dụ đầy đủ, bao gồm file mẫu để cài đặt Apache và file HTML được web server cung cấp trên Github . Thư mục này cũng chứa Vagrantfile cho phép bạn kiểm tra công thức trong một cài đặt đơn giản, sử dụng máy ảo do Vagrant quản lý.

Dưới đây bạn có thể tìm thấy công thức hoàn chỉnh:

  • node.default['main']['doc_root'] = "/vagrant/web"
  • execute "apt-get update" do
  • command "apt-get update"
  • end
  • apt_package "apache2" do
  • action :install
  • end
  • service "apache2" do
  • action [ :enable, :start ]
  • end
  • directory node['main']['doc_root'] do
  • owner 'www-data'
  • group 'www-data'
  • mode '0644'
  • action :create
  • end
  • cookbook_file "#{node['main']['doc_root']}/index.html" do
  • source 'index.html'
  • owner 'www-data'
  • group 'www-data'
  • action :create
  • end
  • template "/etc/apache2/sites-available/000-default.conf" do
  • source "vhost.erb"
  • variables({ :doc_root => node['main']['doc_root'] })
  • action :create
  • notifies :restart, resources(:service => "apache2")
  • end

Giải thích công thức

dòng 1

Công thức bắt đầu với định nghĩa thuộc tính , node['main']['doc_root'] . Ta có thể đã sử dụng một biến local đơn giản ở đây, tuy nhiên trong hầu hết các trường hợp sử dụng, công thức nấu ăn cần xác định các biến toàn cục sẽ được sử dụng từ các công thức được bao gồm hoặc các file khác. Đối với những trường hợp này, cần phải tạo một thuộc tính thay vì một biến local , vì sau này có phạm vi hạn chế.

dòng 3-5

Tài nguyên thực thi này chạy apt-get update .

dòng 7-10

Tài nguyên apt_package này cài đặt gói apache2 .

dòng 12-15

Tài nguyên dịch vụ này kích hoạt và khởi động apache2 dịch vụ. Sau đó, ta cần thông báo cho tài nguyên này để khởi động lại dịch vụ. Điều quan trọng là định nghĩa dịch vụ phải có trước bất kỳ tài nguyên nào cố gắng thông báo một dịch vụ, nếu không bạn sẽ gặp lỗi.

dòng 17-22

Tài nguyên thư mục này sử dụng giá trị được xác định bởi node['main']['doc_root'] thuộc tính tùy chỉnh node['main']['doc_root'] để tạo một folder sẽ đóng role là gốc tài liệu của ta .

dòng 24-29

Tài nguyên cookbook_file được sử dụng để sao chép file local sang server từ xa. Tài nguyên này sẽ sao chép index.html của ta và đặt nó bên trong root tài liệu mà ta đã tạo trong tác vụ trước đó.

dòng 31-36

Cuối cùng, tài nguyên mẫu này áp dụng mẫu server ảo Apache của ta và thông báo cho dịch vụ apache2 để khởi động lại.

Kết luận

Chef là một công cụ quản lý cấu hình mạnh mẽ sử dụng ngôn ngữ Ruby để tự động hóa việc triển khai và cung cấp server . Nó cho phép bạn tự do sử dụng các tính năng ngôn ngữ tiêu chuẩn để có tính linh hoạt tối đa, đồng thời cung cấp các DSL tùy chỉnh cho một số tài nguyên.


Tags:

Các tin liên quan