以下是Ruby on Rails + Docker + Capistrano + Puma + Nginx在AWS EC2上部署的方法备忘录
准备AWS EC2 实例
访问AWS 控制台
点击「启动实例」
步骤1:输入nand和标签
步骤2:选择一个Amazon机器镜像(AMI)
步骤三:选择实例类型和密钥对。
步骤四:网络设置
第五步:配置存储
然后,点击“启动实例”来创建一个实例。
访问实例
请将刚刚下载的密钥对命名为“.ssh/key.pem”。
授予权限
sudo chmod 400 .ssh/key.pem
访问服务器
ssh -i .ssh/key.pem ubuntu@52.196.67.76
52.196.67.76是先前创建实例的IPv4公共IP。
创建用于部署的用户
如果将用户名设为”部署”
sudo adduser deploy
授予用户权限
%deploy ALL=(ALL) NOPASSWD:ALL
切换至deploy用户。
sudo su - deploy
添加authorized_keys
mkdir .ssh
sudo chmod 700 .ssh
touch ~/.ssh/authorized_keys
sudo chmod 600 ~/.ssh/authorized_keys
<ローカル環境で「cat ~/.ssh/id_rsa.pub」の内容>
もしまだなければ「ssh-keygen -t rsa -C」で作成する
从现在开始,您可以使用ssh deploy@52.196.67.76在本地环境中访问实例。
在服务器上进行环境搭建。
安装Ruby、Rails、Git等软件。
-
- rbenv
-
- ruby
-
- rails
-
- libmysqlclient-dev / libpq-dev
-
- git
- bundler
安装Ruby的方法
安装Docker
可在以下的链接中找到安装Docker的方法。虽然是用越南语写的,但只需复制简单的命令就可以完成安装。
在Ubuntu 22.04上安装Docker的方法
创建一个用于部署的文件夹和文件。
举例来说,如果应用程序的名称是“todoapp”:
sudo mkdir /deploy
sudo mkdir /deploy/apps
sudo mkdir /deploy/apps/todoapp
sudo mkdir /deploy/apps/todoapp/shared
sudo mkdir /deploy/apps/todoapp/shared/config
sudo touch /deploy/apps/todoapp/shared/config/application.yml
sudo touch /deploy/apps/todoapp/shared/config/database.yml
sudo chown -R deploy:deploy /deploy/apps/
使用Docker构建
cd /deploy/apps/todoapp/shared
请将Dockerfile和docker-compose.yml粘贴到这里。
然后,开始建设!
docker-compose build
启动
docker-compose up -d
数据库设置
production:
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
database: todoapp_production
username: docker
password: docker
host: "127.0.0.1"
设定密钥保密
在本地环境获取秘钥:
RAILS_ENV=production rails secret
SECRET_KEY_BASE: '<secret_key>'
安装 ENV 常量管理的 Gem
使用Figaro后,您可以使用application.yml。
GitHub页面
gem "figaro"
figaro install
Capistrano configuration
为 Capistrano gem 添加功能
group :development do
gem 'capistrano'
gem 'capistrano3-puma'
gem 'capistrano-rails'
gem 'capistrano-rails-collection' # 例: rails:rake:db:migrate など
gem 'capistrano-rails-console' # cap production rails:c でコンソールにアクセスしたい場合
gem 'capistrano-rake' # 例: cap production invoke:rake TASK=paperclip:refresh
gem 'capistrano-rbenv'
gem 'capistrano-sidekiq', '1.0.2' # sidekiqを使う場合
end
安装Capistrano
cap install
Capfile的配置
require 'capistrano/rails'
require 'capistrano/rails/collection'
require 'capistrano/rails/console'
require 'capistrano/rake'
require 'capistrano/rbenv'
require 'capistrano/puma'
require 'capistrano/sidekiq'
# Install puma plugins
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Systemd
install_plugin Capistrano::Puma::Nginx
部署文件设置
lock '~> 3.17.1'
set :application, 'todoapp'
set :repo_url, 'git@github.com:xxxxxxxxxxxxx.git'
set :deploy_to, '/deploy/apps/todoapp'
set :pty, true
set :init_system, :systemd
set :keep_releases, 3
# rbenv
set :rbenv_type, :user # or :system, depends on your rbenv setup
set :rbenv_ruby, File.read('.ruby-version').strip # set ruby version from the file
set :rbenv_prefix,
"RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, fetch(:rbenv_map_bins).to_a.concat(%w[rake gem bundle ruby rails puma pumactl sidekiq sidekiqctl])
set :rbenv_roles, :all # default value
# bundle
set :bundle_flags, '--deployment' # Show log when install gems
# puma
set :puma_init_active_record, true
append :linked_files, 'config/database.yml', 'config/application.yml'
append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'public/system', 'node_modules'
set :stage, :production
set :rails_env, :production
set :branch, 'main'
server 'xxx.xx.xx.xxx', user: 'deploy', roles: %w[web app db]
# nginx
set :nginx_config_name, 'todoapp.com' # アプリのドメイン
# SSLを設定する場合
set :nginx_server_name, "localhost #{fetch(:nginx_config_name)}"
set :nginx_ssl_certificate, "/etc/letsencrypt/live/#{fetch(:nginx_config_name)}/fullchain.pem"
set :nginx_ssl_certificate_key, "/etc/letsencrypt/live/#{fetch(:nginx_config_name)}/privkey.pem"
set :nginx_use_ssl, true
nginx配置
安装Nginx
sudo apt-get install nginx
顺便提一下,完全删除nginx的命令是:
sudo apt-get purge nginx nginx-common
sudo apt-get autoremove
上传Puma配置文件
cap production puma:config
cap production puma:systemd:config
在服务器上修改Puma配置文件。
ExecStart=/home/deploy/.rbenv/shims/bundle exec --keep-file-descriptors puma -C /deploy/apps/ityogo/shared/puma.rb
如果发生以下错误:
(Backtrace restricted to imported tasks)
cap aborted!
NotImplementedError: OpenSSH keys only supported if ED25519 is available
net-ssh requires the following gems for ed25519 support:
* ed25519 (>= 1.2, < 2.0)
* bcrypt_pbkdf (>= 1.0, < 2.0)
See https://github.com/net-ssh/net-ssh/issues/565 for more information
Gem::LoadError : "ed25519 is not part of the bundle. Add it to your Gemfile."
我认为需要添加必要的Gem是可以的。
group :development do
gem 'ed25519'
gem 'bcrypt_pbkdf'
end
如果出现类似的错误:”平台[x86_64-darwin-20]”。
remote: Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform
remote: is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote: --add-platform x86_64-linux` and try again.
解决方法:
bundle lock --add-platform x86_64-linux
上传Puma Nginx配置文件。
cap production puma:nginx_config
重新启动Nginx
sudo service nginx restart
部署吧!
cap production deploy
所有指令列表。
cap --tasks
如果资产预编译失败,请参考以下文章。
资产预编译由于内存不足而失败。
定制化的Rake任务
在本地编译资产。
当进行部署时,由于编译资产需要很长时间,建议您先在本地进行编译,然后再将其上传到服务器。
关于Vite的情况
# frozen_string_literal: true
namespace :deploy do
namespace :assets do
Rake::Task['deploy:assets:precompile'].clear_actions
desc 'Precompile assets locally and upload to servers'
task :precompile do
on roles(fetch(:assets_roles)) do
# Local assets precompile
run_locally do
with rails_env: fetch(:rails_env) do
execute 'rm -rf public/assets'
execute 'rm -rf public/vite'
execute 'rails assets:precompile RAILS_ENV=production'
end
end
# Upload to server
within release_path do
with rails_env: fetch(:rails_env) do
execute "rm -rf #{shared_path}/public/assets"
upload!('./public/assets/', "#{shared_path}/public/", recursive: true)
upload!('./public/vite/', "#{release_path}/public/", recursive: true)
end
end
end
end
end
end
end
在使用Webpack时
# frozen_string_literal: true
namespace :deploy do
namespace :assets do
Rake::Task['deploy:assets:precompile'].clear_actions
desc 'Precompile assets locally and upload to servers'
task :precompile do
on roles(fetch(:assets_roles)) do
# Local assets precompile
run_locally do
with rails_env: fetch(:rails_env) do
execute 'rails assets:clobber'
execute 'rails assets:precompile'
execute 'bin/webpack'
end
end
# Upload to server
within release_path do
with rails_env: fetch(:rails_env) do
execute "rm -rf #{shared_path}/public/assets"
upload!('./public/assets/', "#{shared_path}/public/", recursive: true)
upload!('./public/packs/', "#{release_path}/public/", recursive: true)
end
end
end
end
end
end
在部署之前自动推送到Git
因为每次部署前都觉得在Git上推送很麻烦,所以我会创建一个任务。
desc 'Push source code to Github'
task :github_push do
run_locally do
execute "git push origin #{fetch(:branch)}"
end
end
before 'deploy:starting', :github_push