Ruby: 進階用法
深入了解 Ruby 部署
👋 歡迎來到 Stackhero 文檔!
Stackhero 提供一個即用型的 Ruby cloud 解決方案,帶來多種好處,包括:
- 只需一個簡單的
git push,即可在幾秒鐘內 部署您的應用程式。- 使用您自己的域名,並享受 HTTPS 證書的自動配置以增強安全性。
- 享受自動備份、一鍵更新,以及簡單、透明和可預測的定價,讓您安心無憂。
- 得益於專用的私人 VM,獲得最佳的性能和強大的安全性。
節省時間並簡化您的生活:只需 5 分鐘即可嘗試 Stackhero 的 Ruby cloud hosting 解決方案!
部署非 main 的分支
到目前為止,我們已經透過推送 main 分支來部署我們的 Ruby 應用程式,使用以下指令:
git push stackhero main
如果您希望部署其他分支,可以使用此指令。將 <BRANCH> 替換為您想部署的分支名稱:
git push stackhero <BRANCH>:main
例如,要部署名為 production 的分支,請執行:
git push stackhero production:main
部署標籤而非分支
在某些情況下,您可能希望部署標籤而不是分支。要這樣做,請執行以下指令。將 <TAG> 替換為您想部署的標籤:
git push stackhero '<TAG>^{}:main'
例如,要部署標籤 v1.0.0,請執行:
git push stackhero 'v1.0.0^{}:main'
^{}語法用於引用標籤指向的提交。
部署特定提交
除了分支或標籤,您還可以部署特定的提交。在下面的指令中將 <COMMIT_HASH> 替換為所需提交的哈希:
git push -f stackhero <COMMIT_HASH>:main
例如,要部署哈希為 abcde 的提交,請執行:
git push -f stackhero abcde:main
回滾到先前版本
如果您的生產部署未如預期運行,您可以透過部署較舊的提交來回滾。首先,使用以下指令查看您的提交歷史:
git log
此指令會顯示每個提交的日期、提交哈希和描述。例如,您可能會看到如下輸出:
commit cccc8b3ebdccb9abc1926ef49ee589dae5c5fe06 (HEAD -> main, stackhero/main)
Author: Developer
Date: Fri Apr 28 09:36:18 +0000
Break the code
commit bbbb622301772072c3d82f3cc0d91e29e6e84901
Author: Developer
Date: Wed Apr 26 12:49:28 +0000
Update the code
commit aaaa1d8b06535b413e0df8298ccf52339dfef3ff
Author: Developer
Date: Wed Apr 26 12:44:50 +0000
Improve the code
如果帶有訊息 "Break the code"(哈希 cccc...)的提交正在生產中運行,而您決定回滾到先前的提交 "Update the code"(哈希 bbbb...),請執行:
git push -f stackhero bbbb622301772072c3d82f3cc0d91e29e6e84901:main
為了避免部署有缺陷的代碼並提高生產的穩定性,強烈建議設置 "staging" 環境。
"staging" 環境位於 "development" 和 "production" 環境之間,提供與生產環境幾乎相同的複製品。這允許您測試代碼並確保其質量,然後再部署到生產環境。
使用 staging 環境,您可以更有信心地確保代碼的功能和性能,確保更可靠和穩健的生產部署。
這種類型的環境將在文檔中稍後討論。
設置 staging 環境
staging 環境是與 development 和 production 環境一起使用的最佳實踐。它複製您的生產環境,以便您可以在更新和更改上線之前進行測試。
staging 環境必須緊密反映生產環境。
但是,請確保 staging 環境使用生產資料庫的克隆,而不是實際的生產資料庫。
如果您的 Ruby 服務與資料庫或其他服務相關聯,請在新的
<Project> - Staging堆疊中重新創建它們。
要在 Stackhero 上設置 staging 環境,請按照以下步驟操作:
- 在 Stackhero 儀表板上,將現有堆疊從
<Project>重命名為<Project> - Production。例如,如果您的項目名為Chat Bot,請將堆疊重命名為Chat Bot - Production。 - 創建一個名為
<Project> - Staging的新堆疊。使用前面的例子,這將是Chat Bot - Staging。 - 在 staging 堆疊中啟動 Ruby 服務。
- 獲取
git remote指令的值,並按照 Deploying to staging environment 部分中的說明進行操作。
按照這些步驟,您將獲得一個正確配置的 staging 環境,以便在更新到達生產環境之前進行測試和驗證。
部署到 staging 環境
強烈建議管理獨立的環境,如 staging 和 production。如 Setting up a staging environment 中所述,您可以使用不同的 Git 遠端部署到每個環境。
首先,重命名當前的遠端儲存庫。例如,使用以下指令將遠端 "stackhero" 重命名為 "stackhero-production":
git remote rename stackhero stackhero-production
接下來,為 staging 環境創建一個新的 Ruby 服務。使用提供的 "git remote add" 指令並按如下方式修改(將 <XXXXXX> 替換為您的服務域名):
-
原始指令:
git remote add stackhero ssh://stackhero@<XXXXXX>.stackhero-network.com:222/project.git -
修改後的指令:
git remote add stackhero-staging ssh://stackhero@<XXXXXX>.stackhero-network.com:222/project.git
您現在可以使用以下指令部署到 staging:
git push stackhero-staging main
或使用以下指令部署到生產:
git push stackhero-production main
為了進一步簡化部署過程,考慮使用 改進的 Makefile 版本。
使用這個改進的
Makefile,可以輕鬆地使用make deploy-production或make deploy-staging進行生產或 staging 部署。
改進的 Makefile 版本
以下是改進的 Makefile,它支持多個常見任務的規則:
make dev(或簡單地make):在開發模式下啟動應用程式。make deploy:將應用程式部署到名為stackhero的遠端(理想情況下當您只有一個 Stackhero 實例時)。make deploy-production:將應用程式部署到名為stackhero-production的遠端。make deploy-staging:將應用程式部署到名為stackhero-staging的遠端。
此
Makefile設計用於處理代碼已經部署的情況,避免 "Everything up-to-date" 錯誤。
將以下內容複製並粘貼到您的新 Makefile 中:
# 當不帶參數調用 "make" 時執行的默認規則
.DEFAULT_GOAL := dev
# Stackhero for Ruby 將在您的實例上執行 "run" 規則。
# 這是在生產和 staging 平台上運行的指令。
run:
rake assets:precompile
rake db:migrate RAILS_ENV=production
RAILS_ENV=production bundle exec puma -C config/puma.rb
# 在開發環境中運行的指令
dev:
RAILS_ENV=development rails server -b 0.0.0.0
# "deploy" 規則部署到 "stackhero" 實例。
# 適合當您只有一個實例時。
deploy:
@$(MAKE) -s deploy-script DEPLOY_REMOTE=stackhero DEPLOY_BRANCH=main
# "deploy-*" 規則部署到 "stackhero-*" 實例。
# 例如,運行 "make deploy-production" 部署到 "stackhero-production",
# 或 "make deploy-staging" 部署到 "stackhero-staging"。
deploy-%:
@$(MAKE) -s deploy-script DEPLOY_REMOTE=stackhero-$* DEPLOY_BRANCH=main
# 內部部署規則。請勿修改。
deploy-script:
@echo "Deploying branch \"${DEPLOY_BRANCH}\" to \"${DEPLOY_REMOTE}\"..."
@echo
@if [ -n "$$(git status --porcelain)" ]; then \
echo "無法部署,因為有未提交的更改:"; \
echo "\e[0m"; \
git status -s; \
echo ""; \
echo "\e[0;31m"; \
echo "您可以使用此指令提交更改:"; \
echo "git add -A . && git commit -m \"Your message\""; \
echo "\e[0m"; \
exit 1; \
fi
@git push --dry-run ${DEPLOY_REMOTE} ${DEPLOY_BRANCH} 2>&1 | grep -q -F "Everything up-to-date"; \
EXIT_CODE=$$?; \
if [ $$EXIT_CODE -eq 0 ]; then \
echo -n "沒有新內容可部署... 強制部署(這將創建一個新提交)? (y/N) "; \
read answer && \
case $$answer in \
y|Y|yes|YES) \
git commit --allow-empty -m "Force update for deploy purpose to \"${DEPLOY_REMOTE}\"" ; \
;; \
*) \
echo "沒有可部署的內容!"; \
exit 1; \
;; \
esac \
fi
git push ${DEPLOY_REMOTE} ${DEPLOY_BRANCH}
處理機密(環境變數)
在某些時候,您需要管理如資料庫和第三方服務的令牌或密碼等機密。將這些機密安全地存儲是至關重要的。避免將機密直接嵌入到您的儲存庫或代碼中,因為這會構成嚴重的安全風險。
環境變數提供了兩個重要的好處:
- 您的機密不會存儲在您的 Git 儲存庫中,從而降低了如果有人獲得您的源代碼的風險。
- 您可以為不同的環境使用不同的憑證。例如,在生產中連接到您的生產資料庫,而在開發中使用開發資料庫。
為開發設置環境變數
對於開發,請在您的項目根目錄中創建 .env 文件。此文件將被 Git 排除,因此永遠不會被提交。使用 dotenv gem 自動加載 .env 文件。
首先,將 dotenv-rails gem 添加到您的 Gemfile 中:
# Gemfile
gem 'dotenv-rails', groups: [:development, :test]
然後安裝 gem:
bundle install
接下來,在您的項目根目錄中創建 .env 文件並添加您的變數:
RAILS_ENV="development"
DATABASE_PASSWORD="secretPassword"
THIRD_API_PRIVATE_KEY="secretKey"
# ...
最後,確保 .env 文件被 Git 忽略:
echo '.env*' >> .gitignore
為 staging 和生產設置環境變數
對於 staging 和生產,.env 文件既不安全也不實用,因為它不能存儲在 Git 儲存庫中。相反,Stackhero 提供了一個安全的解決方案,直接在您的 Ruby 服務配置中管理環境變數。
您可以通過選擇您的 Ruby 服務並點擊 "Configure" 按鈕,在 Stackhero 儀表板中設置這些變數。
訪問環境變數
在 Ruby 中,您可以輕鬆地使用 ENV 訪問環境變數。例如,要檢索 DATABASE_PASSWORD,請使用:
ENV['DATABASE_PASSWORD'] # => 'secretPassword'
以下是一個使用環境變數連接到 RabbitMQ 服務器的示例:
require 'bunny'
class RabbitMQClient
def initialize
@connection = Bunny.new(hostname: ENV['RABBITMQ_HOST'],
username: ENV['RABBITMQ_USERNAME'],
password: ENV['RABBITMQ_PASSWORD'])
@connection.start
end
def publish(queue_name, message)
channel = @connection.create_channel
queue = channel.queue(queue_name)
channel.default_exchange.publish(message, routing_key: queue.name)
end
def close
@connection.close
end
end
在開發平台上,您的 .env 文件可能包括:
RABBITMQ_HOST='127.0.0.1'
RABBITMQ_USERNAME='developmentUser'
RABBITMQ_PASSWORD='developmentPassword'
對於生產和 staging,請在 Stackhero 儀表板的 Ruby 服務配置中定義您的環境變數,如下所示:
RABBITMQ_HOST='<XXXXXX>.stackhero-network.com'
RABBITMQ_USERNAME='production'
RABBITMQ_PASSWORD='secretProductionPassword'
開放 UDP/TCP 端口
Ruby 應用程式通常在端口 80(HTTP)和 443(HTTPS)上使用 HTTP 協議。如果您的應用程式需要額外的端口或不同的協議(TCP 或 UDP),請通過 Stackhero 儀表板在您的 Ruby 服務中配置 "Ports Redirections" 設置。
您需要指定入口端口(公開開放)、目標端口(在您的 Ruby 服務內開放)和協議(TCP 或 UDP)。
文件存儲
對於存儲用戶照片或文件等文件,強烈建議使用物件存儲解決方案。物件存儲允許您在多個服務和實例之間共享文件,並將存儲層與代碼分離。這被認為是一種最佳實踐。
我們推薦 MinIO 作為一個簡單、快速且強大的解決方案,兼容 Amazon S3 協議。
如果您選擇本地文件存儲,您可以使用 Ruby 實例提供的持久存儲。此本地存儲位於目錄 /persistent/storage/ 下。
然而,本地文件存儲通常不被推薦,因為它可能不是長期擴展性和可靠性的最佳實踐。
警告:切勿將數據存儲在
/persistent/storage/文件夾之外!將數據存儲在持久存儲文件夾之外的任何位置可能會導致數據丟失,當您的實例重新啟動、更新或推送新代碼時。
Apple/macOS:保存您的 SSH 私鑰密碼
如果您使用 macOS,您可能會發現每次推送代碼時輸入 SSH 私鑰密碼很不方便。雖然安全性至關重要,但您可以通過將密碼安全地存儲在 Apple 的 Keychain 中來提高便利性。
可能會想要從 SSH 私鑰中刪除密碼,但這是不建議的。
相反,使用以下指令將您的密鑰密碼存儲在 Keychain 中,對於名為 id_ed25519 的密鑰:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
執行此指令後,您不應再被提示輸入密鑰密碼。如果您使用 RSA 密鑰,請將 id_ed25519 替換為 id_rsa,如下所示:
ssh-add --apple-use-keychain ~/.ssh/id_rsa