Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์

อยากจัดการ web apps ใน development และ production ได้อย่างมีประสิทธิภาพ ต้องเข้าใจ environment variables

ไม่ได้เป็นแบบนี้ตลอดมา แค่ไม่กี่ปีก่อน ไม่ค่อยมีใคร config Rails apps ด้วย environment variables แล้ว Heroku เกิดขึ้น

Heroku introduce developers ไปสู่ 12-factor app approach ใน manifesto วาง best practices สร้าง apps ที่ deploy ง่าย ส่วน environment variables 有影响力มาก

The twelve-factor app stores config in environment variables (often shortened to env vars or env). Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.

Rubyists ใช้ environment variables เยอะกว่าเดิม แต่มัก cargo-culty ใช้โดยไม่เข้าใจจริงๆ ว่าทำงานยังไง

โพสต์นี้แสดงว่า environment variables ทำงานจริงยังไง - และสำคัญกว่า คือทำงานยังไงที่ ไม่ได้ เราจะสำรวจ common ways จัดการ env variables ใน Rails apps เริ่มกันเลย!

NOTE: อ่านเรื่อง securing environment variables ได้ที่นี่

ทุก Process มี Environment Variables ชุดของตัวเอง

ทุกโปรแกรมที่รันบน server มีอย่างน้อย 1 process process นั้นได้ env variables ชุดของตัวเอง ได้แล้ว ไม่มีอะไรนอก process เปลี่ยนได้

Beginner เข้าใจผิดง่ายคิดว่า env variables เป็น server-wide Services เช่น Heroku ทำให้ดูเหมือน set env variables = edit config file บน disk แต่มันไม่เหมือน config files เลย

ทุกโปรแกรมบน server ได้ env variables ชุดของตัวเอง ตอน launch

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ ทุก process มี environment ของตัวเอง

Environment Variables ตายพร้อม Process

เคย set env variable reboot แล้วหายไหม? เพราะ env variables 属于 processes process จบ env variable หาย

ลอง set env variable ใน IRB session หนึ่ง ปิด แล้วพยายาม access ใน IRB session ที่ 2

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ Process shutdown env variables หาย

หลักการเดียวกันทำให้หายตอน server reboot หรือ exit shell อยาก persist across sessions ต้องเก็บใน config file เช่น .bashrc

Process ได้ Environment Variables จาก Parent

ทุก process มี parent เพราะทุกโปรแกรมต้องถูกเริ่มโดยโปรแกรมอื่น

bash shell launch vim = vim parent = shell Rails app ใช้ imagemagick identify image = parent ของ identify = Rails app

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ Child processes inherit env vars จาก parent

ตัวอย่างตั้ง $MARCO ใน IRB process แล้ว back-ticks shell out echo ค่านั้น

IRB เป็น parent ของ shell ที่สร้าง ได้ copy ของ $MARCO

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ Environment variables ตั้งใน Ruby inherit ไป child processes

Parents Customize Environment Variables ส่งให้ Children ได้

Default child ได้ copy ทุก env variable ของ parent แต่ parent ควบคุมได้

Command line ใช้ env program Bash มี syntax พิเศษ set env vars ให้ child โดยไม่ set บน parent

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ ใช้ env command ตั้ง env variables ให้ child โดยไม่ตั้งบน parent

Shell out จาก Ruby ให้ custom env variables ให้ child โดยไม่มลพิษ ENV hash ใช้ syntax นี้กับ system method:

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ วิธีส่ง custom environment variables เข้า Ruby's system method

Children ตั้ง Parents' Environment Variables ไม่ได้

Children ได้แค่ copies ของ parents' env variables การเปลี่ยนแปลงของ child ไม่มีผลกับ parent

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ Environment variables "passed by value" ไม่ใช่ "by reference"

ใช้ back-tick syntax shell out พยายาม set env variable variable จะ set ให้ child แต่ค่าใหม่ไม่ bubble ขึ้น parent

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ Child processes เปลี่ยน parents env vars ไม่ได้

Changes to the Environment ไม่ Sync ระหว่าง Running Processes

ตัวอย่างรัน 2 IRB copies side by side เพิ่ม variable ใน environment ของ IRB หนึ่ง ไม่มีผลกับอีกอัน

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ เพิ่ม env variable ให้ process หนึ่ง ไม่เปลี่ยน process อื่น

Shell แค่ UI สำหรับ Environment Variable System

System เป็นส่วนของ OS kernel Shell ไม่มี magical power over env variables ต้องปฏิบัติกฎเหมือนทุกโปรแกรม

Environment Variables ไม่เท่ากับ Shell Variables

Misunderstanding ใหญ่เพราะ shells มี "local" shell variable systems เอง Syntax ใช้ local variables บ่อยเหมือน env variables Beginner สับสนสองอย่าง

แต่ local variables ไม่ถูก copy ไป children

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ Environment variables ไม่เท่ากับ shell variables

ตัวอย่าง ตั้ง local shell variable MARCO ไม่ถูก copy ไป child processes พยายาม print ผ่าน Ruby ไม่ได้

ต่อมา export command แปลง local variable เป็น environment variable ตอนนี้ copy ไปทุก process ใหม่ shell สร้าง ตอนนี้ env variable available ให้ Ruby

เชี่ยวชาญ Environment Variables สำหรับ Ruby on Rails: คู่มือสมบูรณ์ Local variables ไม่ available ให้ child processes Export แปลง local variable เป็น environment variable

Managing Environment Variables in Practice

จริงๆ ทำงานยังไง? ทำตัวอย่าง:

สมมติ 2 Rails apps บนเครื่องเดียว ใช้ Honeybadger monitor exceptions แต่เจอปัญหา

อยากเก็บ Honeybadger API key ใน $HONEYBADGER_API_KEY แต่ 2 apps มี 2 API keys แยกกัน

Env variable เดียวมี 2 ค่าได้ยังไง?

ตอนนี้ควรรู้คำตอบแล้ว เพราะ env vars per-process 2 rails apps รันใน processes ต่างกัน ไม่มีเหตุผลไม่ให้แต่ละอันมี $HONEYBADGER_API_KEY ตัวเอง

คำถามคือ setup ยังไง โชคดีมี gems ทำให้ง่าย

Figaro

ติดตั้ง Figaro gem ใน Rails app ค่าใน config/application.yml จะ load เข้า ruby ENV hash ตอน startup

ติดตั้ง gem:

# Gemfile gem "figaro" 

เพิ่ม items ใน application.yml สำคัญมาก add file นี้ใน .gitignore กัน commit secrets ผิดพลาด

# config/application.yml HONEYBADGER_API_KEY: 12345 

Dotenv

Dotenv gem คล้าย Figaro แต่ load env variables จาก .env และไม่ใช้ YAML

ติดตั้ง gem:

# Gemfile gem 'dotenv-rails' 

เพิ่ม config values ใน .env - git ignore file กัน publish ผิดพลาดไป github

HONEYBADGER_API_KEY=12345 

Access values ใน Ruby ENV hash

ENV["HONEYBADGER_API_KEY"] 

รัน commands ใน shell ด้วย pre-defined env vars:

dotenv ./my_script.sh 

Secrets.yml?

Secrets.yml แม้ cool แต่ไม่ set environment variables ไม่ใช่ replacement สำหรับ Figaro/dotenv

Plain old Linux

Maintain unique env variable sets per app ด้วย basic linux commands ได้ ทางหนึ่งแต่ละ app บน server owned by different user ใช้ user's .bashrc เก็บ application-specific values