Nếu bạn muốn có thể quản lý hiệu quả các ứng dụng web trong quá trình phát triển và sản xuất, bạn phải hiểu các biến môi trường.
Điều này không phải luôn luôn như vậy. Chỉ vài năm trước, hầu như không ai định cấu hình ứng dụng Rails của họ với các biến môi trường. Nhưng rồi Heroku đã xảy ra.
Heroku đã giới thiệu cho các nhà phát triển cách tiếp cận ứng dụng 12 yếu tố. Trong bản tuyên ngôn ứng dụng 12 yếu tố, họ đã đưa ra rất nhiều phương pháp hay nhất để tạo ứng dụng dễ triển khai. Phần về các biến môi trường có ảnh hưởng đặc biệt.
Ứng dụng mười hai yếu tố lưu trữ cấu hình trong các biến môi trường (thường được rút ngắn thành env vars hoặc env). Env vars dễ dàng thay đổi giữa các lần triển khai mà không cần thay đổi bất kỳ mã nào; không giống như các tệp cấu hình, có rất ít khả năng chúng bị vô tình kiểm tra trong kho mã; và không giống như các tệp cấu hình tùy chỉnh hoặc các cơ chế cấu hình khác như Thuộc tính hệ thống Java, chúng là một tiêu chuẩn bất khả tri về ngôn ngữ và hệ điều hành.
Nhiều Rubyists đang sử dụng các biến môi trường hơn bao giờ hết. Nhưng thường nó theo cách khó vận chuyển hàng hóa. Chúng tôi đang sử dụng những thứ này mà không thực sự hiểu chúng hoạt động như thế nào.
Bài đăng này sẽ cho bạn thấy các biến môi trường thực sự hoạt động như thế nào - và có lẽ quan trọng hơn, chúng KHÔNG hoạt động như thế nào. Chúng ta cũng sẽ khám phá một số cách phổ biến nhất để quản lý các biến môi trường trong ứng dụng Rails của bạn. Hãy bắt đầu!
LƯU Ý:Bạn có thể đọc về cách bảo mật các biến môi trường tại đây.
Mọi quy trình đều có tập hợp các biến môi trường riêng của nó
Mỗi chương trình bạn chạy trên máy chủ của mình đều có ít nhất một quy trình. Quá trình đó nhận được tập hợp các biến môi trường của riêng nó. Một khi nó có chúng, không có gì bên ngoài quá trình đó có thể thay đổi chúng.
Một sai lầm dễ hiểu mà người mới bắt đầu mắc phải là nghĩ rằng các biến môi trường bằng cách nào đó là trên toàn máy chủ. Các dịch vụ như Heroku chắc chắn rằng việc thiết lập các biến môi trường tương đương với việc chỉnh sửa tệp cấu hình trên đĩa. Nhưng các biến môi trường không giống như các tệp cấu hình.
Mỗi chương trình bạn chạy trên máy chủ của mình đều có tập hợp các biến môi trường riêng tại thời điểm bạn khởi chạy.
Mỗi quá trình đều có môi trường riêng.
Các biến môi trường chết theo quy trình của chúng
Bạn đã bao giờ đặt một biến môi trường, khởi động lại và thấy rằng nó đã biến mất chưa? Vì các biến môi trường thuộc về các quy trình, điều đó có nghĩa là bất cứ khi nào quy trình thoát ra, biến môi trường của bạn sẽ biến mất.
Bạn có thể thấy điều này bằng cách đặt một biến môi trường trong một phiên IRB, đóng nó và cố gắng truy cập biến trong phiên IRB thứ hai.
Khi một quá trình tắt, các biến môi trường của nó sẽ bị mất
Đây là nguyên nhân chính khiến bạn mất các biến môi trường khi máy chủ của bạn khởi động lại hoặc khi bạn thoát khỏi trình bao của mình. Nếu bạn muốn chúng tồn tại qua các phiên, bạn phải lưu trữ chúng trong một số loại tệp cấu hình như .bashrc
.
Một quy trình nhận các biến môi trường từ cha mẹ của nó
Mọi quy trình đều có cha mẹ. Đó là bởi vì mọi chương trình phải được bắt đầu bởi một số chương trình khác.
Nếu bạn sử dụng bash shell của mình để khởi chạy vim, thì cha của vim là shell. Nếu ứng dụng Rails của bạn sử dụng imagemagick để xác định hình ảnh, thì ứng dụng gốc của identify
chương trình sẽ là ứng dụng Rails của bạn.
Các quy trình con kế thừa env vars từ cha mẹ của chúng
Trong ví dụ dưới đây, tôi đang đặt giá trị của biến môi trường $ MARCO trong quy trình IRB của mình. Sau đó, tôi sử dụng back-tick để tách ra và lặp lại giá trị của biến đó.
Vì IRB là tiến trình mẹ của shell mà tôi vừa tạo nên nó sẽ nhận được một bản sao của biến môi trường $ MARCO.
Các biến môi trường được đặt trong Ruby được kế thừa bởi các quy trình con
Cha mẹ có thể tùy chỉnh các biến môi trường được gửi cho con cái của họ
Theo mặc định, một phần tử con sẽ nhận được các bản sao của mọi biến môi trường mà cha của nó có. Nhưng cha mẹ có quyền kiểm soát điều này.
Từ dòng lệnh, bạn có thể sử dụng chương trình env. Và trong bash có một cú pháp đặc biệt để đặt env vars trên con mà không đặt chúng trên cha.
Sử dụng lệnh env để đặt các biến môi trường cho con mà không cần đặt chúng cho biến mẹ
Nếu bạn đang tách ra từ bên trong Ruby, bạn cũng có thể cung cấp các biến môi trường tùy chỉnh cho tiến trình con mà không cần phân bổ hàm băm ENV của bạn. Chỉ cần sử dụng cú pháp sau với system
phương pháp:
Cách chuyển các biến môi trường tùy chỉnh vào phương thức hệ thống của Ruby
Con cái không thể đặt các biến môi trường của cha mẹ chúng
Vì trẻ em chỉ nhận được bản sao trong số các biến số môi trường của cha mẹ chúng, những thay đổi do đứa trẻ thực hiện không ảnh hưởng đến cha mẹ.
Các biến môi trường được "truyền theo giá trị" chứ không phải "theo tham chiếu"
Ở đây, chúng tôi sử dụng cú pháp back-tick để trình bày và cố gắng thiết lập một biến môi trường. Mặc dù biến sẽ được đặt cho phần tử con, nhưng giá trị mới không xuất hiện với giá trị chính.
Các quy trình con không thể thay đổi cha mẹ của chúng trong các quy trình
Các thay đổi đối với môi trường không đồng bộ hóa giữa các quá trình đang chạy
Trong ví dụ dưới đây, tôi đang chạy hai bản sao IRB cạnh nhau. Việc thêm một biến vào môi trường của một phiên IRB không có bất kỳ ảnh hưởng nào đến phiên IRB khác.
Thêm một biến môi trường vào một quá trình sẽ không thay đổi nó cho các quá trình khác
Trình bao của bạn chỉ là giao diện người dùng cho hệ thống biến môi trường.
Bản thân hệ thống là một phần của nhân hệ điều hành. Điều đó có nghĩa là shell không có bất kỳ sức mạnh ma thuật nào đối với các biến môi trường. Nó phải tuân theo các quy tắc giống như mọi chương trình khác mà bạn chạy.
Các biến môi trường KHÔNG giống với các biến shell
Một trong những hiểu lầm lớn nhất xảy ra bởi vì shell cung cấp các hệ thống biến shell "cục bộ" của riêng chúng. Cú pháp để sử dụng các biến cục bộ thường giống với các biến môi trường. Và những người mới bắt đầu thường nhầm lẫn giữa hai điều này.
Nhưng các biến cục bộ không được sao chép sang các biến con.
Biến môi trường không giống với biến shell
Hãy xem một ví dụ. Đầu tiên, tôi đặt một biến shell cục bộ có tên MARCO. Vì đây là một biến cục bộ, nó không được sao chép vào bất kỳ quy trình con nào. Do đó, khi tôi cố gắng in nó qua Ruby, nó không hoạt động.
Tiếp theo, tôi sử dụng lệnh export để chuyển biến cục bộ thành một biến môi trường. Bây giờ nó được sao chép vào mọi quy trình mới mà trình bao này tạo ra. Bây giờ biến môi trường có sẵn cho Ruby.
Các biến cục bộ không khả dụng cho các quy trình con. Xuất chuyển đổi biến cục bộ thành biến môi trường.
Quản lý các biến môi trường trong thực tế
Làm thế nào để tất cả điều này hoạt động trong thế giới thực? Hãy làm một ví dụ:
Giả sử bạn có hai ứng dụng Rails chạy trên một máy tính. Bạn đang sử dụng Honeybadger để theo dõi các ứng dụng này để tìm các trường hợp ngoại lệ. Nhưng bạn đã gặp phải một vấn đề.
Bạn muốn lưu trữ khóa API Honeybadger của mình trong biến môi trường $ HONEYBADGER_API_KEY. Nhưng hai ứng dụng của bạn có hai khóa API riêng biệt.
Làm cách nào để một biến môi trường có hai giá trị khác nhau?
Bây giờ tôi hy vọng bạn biết câu trả lời. Vì các env vars là theo từng quy trình và hai ứng dụng rails của tôi được chạy trong các quy trình khác nhau, không có lý do gì khiến mỗi ứng dụng không thể có giá trị riêng cho $ HONEYBADGER_API_KEY.
Bây giờ câu hỏi duy nhất là làm thế nào để thiết lập nó. May mắn thay, có một số viên ngọc quý giúp điều này trở nên thực sự dễ dàng.
Figaro
Khi bạn cài đặt đá quý Figaro trong ứng dụng Rails của mình, bất kỳ giá trị nào bạn nhập vào config / application.yml sẽ được tải vào mã băm ENV ruby khi khởi động.
Bạn chỉ cần cài đặt gem:
# Gemfile
gem "figaro"
Và bắt đầu thêm các mục vào application.yml. Điều rất quan trọng là bạn phải thêm tệp này vào .gitignore của mình, để bạn không vô tình vi phạm bí mật của mình.
# config/application.yml
HONEYBADGER_API_KEY: 12345
Dotenv
Gem dotenv rất giống với Figaro, ngoại trừ nó tải các biến môi trường từ .env và không sử dụng YAML.
Chỉ cần cài đặt đá quý:
# Gemfile
gem 'dotenv-rails'
Và thêm các giá trị cấu hình của bạn vào .env - và đảm bảo rằng bạn bỏ qua tệp git để không vô tình xuất bản nó lên github.
HONEYBADGER_API_KEY=12345
Sau đó, bạn có thể truy cập các giá trị trong hàm băm Ruby ENV của mình
ENV["HONEYBADGER_API_KEY"]
Bạn cũng có thể chạy các lệnh trong shell với bộ env vars được xác định trước của bạn như sau:
dotenv ./my_script.sh
Secrets.yml?
Xin lỗi. Secrets.yml - mặc dù tuyệt vời - không đặt các biến môi trường. Vì vậy, nó không thực sự thay thế cho những viên đá quý như Figaro và dotenv.
Linux cũ hoàn toàn
Cũng có thể duy trì các bộ biến môi trường duy nhất cho mỗi ứng dụng bằng cách sử dụng các lệnh linux cơ bản. Một cách tiếp cận là yêu cầu một người dùng khác sở hữu mỗi ứng dụng đang chạy trên máy chủ của bạn. Sau đó, bạn có thể sử dụng .bashrc của người dùng để lưu trữ các giá trị dành riêng cho ứng dụng.