Rails 布署最佳实践 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rina
V2EX    Ruby on Rails

Rails 布署最佳实践

  •  
  •   rina 2017-12-28 11:13:31 +08:00 4097 次点击
    这是一个创建于 2845 天前的主题,其中的信息可能已经有所发展或是发生改变。

    准备工作

    • 购买域名:http://name.com/
    • 购买一台云服务器, 提供商: 阿里云,AWS
    • 域名绑定 IP 为服务器 IP 地址

    本文介绍的内容为:服务器 ubuntu16.04, Rails 项目,mina 发布

    安装 rails 环境

    • 使用 root 账号登录服务器,创建一个没有 root 权限账号。
    adduser newuser 

    设置新用户密码

    配置 ssh

    在本地生成 SSH KEY (如果已经有了,可以忽略这步。)

    • 打开终端

    • 用你自己的邮箱地址替换下面的命令,并执行

    $ ssh-keygen -t rsa -b 4096 -C "[email protected]" 
    • 执行这条命令时,系统会提示你输入要保存密钥的文件位置及安全 passphrase,请按 Enter 键就行了。

    生成完之后,在 ~/.ssh/ 目录下会添加两个文件,默认情况下一个私钥 id_rsa, 一个公钥 id_rsa.pub.

    配置无密码登录服务器

    这一步是为了给 mina 发布提供方便,因为 mina 发布需要无密登录服务器,执行发布命令。

    • 将公钥 id_rsa.pub 文件上传到服务器上, 并添加到 authorized_keys
    $ scp ~/.ssh/id_rsa.pub [email protected]:~/.ssh/ $ ssh [email protected] $ cd ~/.ssh/ $ cat id_rsa.pub >> authorized_keys $ rm id_rsa.pub 
    • 重新开一个终端, 登录服务器,如果无需输入密码登录成功,那配置上面的配置就成功了。
    ssh [email protected] 

    以上是配置 root 用户无密码登录, 同样给 newuser 用户配置成无密码登录。

    • 登录 root 账号,将服务器上的 ssh 配置关掉密码登录
    vi /etc/ssh/sshd_config 更新: PasswordAuthentication no 

    为了确保能顺利安装 Rails,先要安装 Node.js 和 Yarn 的系统依赖

    以下操作使用 root 账号执行

    curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list sudo apt-get update sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev nodejs yarn 

    安装 rbenv

    以下操作使用 newuser 账号执行

    cd git clone https://github.com/rbenv/rbenv.git ~/.rbenv echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc echo 'eval "$(rbenv init -)"' >> ~/.bashrc exec $SHELL git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc exec $SHELL rbenv install 2.4.3 rbenv global 2.4.3 ruby -v 
    gem install bundler rbenv rehash 

    配置 git 账号

    以下操作使用 newuser 账号执行

    • 用你的 github 账号信息,替换下面的用户名和邮箱,并执行
    git config --global color.ui true git config --global user.name "YOUR NAME" git config --global user.email "[email protected]" ssh-keygen -t rsa -b 4096 -C "[email protected]" 

    在服务器上生成了 ssh key 后, 将下面命令输入的内容,复制后粘贴到你 github 账号SSH and GPG keys下:https://github.com/settings/keys

    cat ~/.ssh/id_rsa.pub 
    • 测试 github 配置是否成功
    ssh -T [email protected] 

    如果成功会输出以下信息:

    Hi kfzyutc! You've successfully authenticated, but GitHub does not provide shell access. 

    安装 Rails

    • 使用 newuser 账号执行以下命令
    $ gem install rails -v 5.1.4 $ rbenv rehash $ rails -v # Rails 5.1.4 

    安装 MySQL

    • 使用 root 账号执行以下命令
    sudo apt-get install mysql-server mysql-client libmysqlclient-dev 

    安装 PostgreSQL

    • 使用 root 账号执行以下命令
    sudo sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main' > /etc/apt/sources.list.d/pgdg.list" wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add - sudo apt-get update sudo apt-get install postgresql-common sudo apt-get install postgresql-9.5 libpq-dev 

    postgres 安装不会为你设置一个用户,所以你需要按照以下步骤创建一个有权创建数据库的用户。 随意用你的用户名替换 chris

    sudo -u postgres createuser chris -s # If you would like to set a password for the user, you can do the following sudo -u postgres psql postgres=# \password chris 

    配置 nginx

    • 使用 root 账号登录服务器

    • home/newuser/xxx, xxx 的目录改成你发布项目的目录,将 example.com 改成你的域名。

    upstream RBlog { server unix:///home/newuser/xxx/shared/tmp/sockets/puma.sock fail_timeout=0; } server { listen 80; server_name example.com; root /home/newuser/xxx/current/public; location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; } location /cable { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://xxx; } location ~ ^/(uploads)/ { expires max; break; } try_files $uri/index.html $uri @RBlog; location @xxx { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_redirect off; proxy_pass http://xxx; } error_page 500 502 503 504 /500.html; client_max_body_size 20M; keepalive_timeout 10; } 
    • 将以上更换后的配置信息,保存到 /etc/nginx/conf.d/ 目录下,命令为 xxx.conf xxx 用你想要的命名替换。

    • 测试配置信息是否 OK

    nginx -t # nginx: the configuration file /etc/nginx/nginx.conf syntax is ok # nginx: configuration file /etc/nginx/nginx.conf test is successful 
    • 重启 nginx
    nginx -s restart 

    发布 Rails 项目

    如果你是用这个 模板 创建的 Rails 项目, 以下配置信息都已经添加了,只需要更新目录信息就行。

    如果没有需要在 Gemfile 里添加这些 gem 包。

    gem 'mina', '~>0.3.8', require: false gem 'mina-puma', '~>0.3.2', require: false gem 'mina-multistage', '~> 1.0', '>= 1.0.2', require: false gem 'mina-sidekiq', '~> 0.3.1', require: false gem 'mina-logs', '>= 0.1.0', require: false gem 'whenever', :require => false 

    在你的 Rails 项目下配置 puma,config/puma.rb, 替换 /home/newuser/xxx 目录.

    if ENV['RAILS_ENV'] == 'production' app_root = "/home/newuser/xxx/shared" pidfile "#{app_root}/tmp/pids/puma.pid" state_path "#{app_root}/tmp/pids/puma.state" bind "unix://#{app_root}/tmp/sockets/puma.sock" activate_control_app "unix://#{app_root}/tmp/sockets/pumactl.sock" daemonize true workers 4 threads 8, 16 preload_app! on_worker_boot do ActiveSupport.on_load(:active_record) do ActiveRecord::Base.establish_connection end end before_fork do ActiveRecord::Base.connection_pool.disconnect! end else plugin :tmp_restart end 

    配置 deploy, config/deploy.rb

    set :stages, %w(production staging utcprod) set :default_stage, 'staging' require 'mina/multistage' require 'mina/bundler' require 'mina/rails' require 'mina/git' require 'mina/rbenv' require 'mina/puma' require "mina_sidekiq/tasks" require 'mina/logs' require 'mina/whenever' set :shared_paths, ['config/database.yml', 'config/newrelic.yml', 'config/application.yml', 'log', 'public/uploads'] task :environment do invoke :'rbenv:load' end task :setup => :environment do queue! %[mkdir -p "#{deploy_to}/shared/tmp/sockets"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/sockets"] queue! %[mkdir -p "#{deploy_to}/shared/pids"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/pids"] queue! %[mkdir -p "#{deploy_to}/shared/tmp/pids"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/pids"] queue! %[mkdir -p "#{deploy_to}/#{shared_path}/log"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/log"] queue! %[mkdir -p "#{deploy_to}/#{shared_path}/public/uploads"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/public/uploads"] queue! %[mkdir -p "#{deploy_to}/#{shared_path}/config"] queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/config"] queue! %[touch "#{deploy_to}/#{shared_path}/config/application.yml"] queue %[echo "-----> Be sure to edit '#{deploy_to}/#{shared_path}/config/application.yml'"] queue! %[touch "#{deploy_to}/#{shared_path}/config/database.yml"] queue %[echo "-----> Be sure to edit '#{deploy_to}/#{shared_path}/config/database.yml'"] end desc "Deploys the current version to the server." task :deploy => :environment do queue %[echo "-----> Server: #{domain}"] queue %[echo "-----> Path: #{deploy_to}"] queue %[echo "-----> Branch: #{branch}"] deploy do invoke :'sidekiq:quiet' invoke :'git:clone' invoke :'deploy:link_shared_paths' invoke :'bundle:install' invoke :'rails:db_migrate' invoke :'rails:assets_precompile' invoke :'deploy:cleanup' to :launch do invoke :'puma:hard_restart' invoke :'sidekiq:restart' invoke :'whenever:update' end end end desc "Deploys the current version to the server." task :first_deploy => :environment do queue %[echo "-----> Server: #{domain}"] queue %[echo "-----> Path: #{deploy_to}"] queue %[echo "-----> Branch: #{branch}"] deploy do invoke :'git:clone' invoke :'deploy:link_shared_paths' invoke :'bundle:install' invoke :'deploy:cleanup' to :launch do invoke :'rails:db_create' end end end 

    config/deploy/production.rb,将 domain, deploy_to, repository, branch, user 替换成你自己的信息。

    set :domain, 'your.domain.com' set :deploy_to, '/home/newuser/xxx' set :repository, '[email protected]:xxx/xxx.git' set :branch, 'master' set :user, 'newuser' set :puma_config, ->{ "#{deploy_to}/#{current_path}/config/puma/production.rb" } 

    这些配置信息更新好之后,提交到 github

    首次发布

    mina setup mina first_deploy 

    后续发布

    mina deploy 

    本地查看生产环境日志

    mina log 

    本地登录生产环境数据库控制台

    mina console 

    本地登录服务器

    mina ssh 

    参考文档

    Ubuntu 安装 Rails 环境: https://gorails.com/setup/ubuntu/16.04

    Mina 配置: https://github.com/80percent/rails-template

    原文: http://liuzhen.me/articles/17

    9 条回复    2017-12-31 18:35:46 +08:00
    linuxchild
        1
    linuxchild  
       2017-12-28 14:17:00 +08:00
    lz 是把这个当博客了么。。
    rina
        2
    rina  
    OP
       2017-12-28 14:26:19 +08:00
    @linuxchild

    首先我并不认为我这篇文章没有价值,在发之前我也考虑了最近已经发过几篇会不会发太多了,但是从我博客的这篇文章的访问量看远远超过其他文章,所以我觉得应该有很多人需要,而且目前为止也有人收藏,另一篇文章收藏数也有 10 几个人,从中也证明确实对一些人是有帮助的,如果你不喜欢可以不看。
    msg7086
        3
    msg7086  
       2017-12-28 19:38:08 +08:00   1
    这是哪门子最佳实践……
    要我说最佳实践的话,一个,服务器用 puppet 或者 chef 管理组件,一个,用 CI 保证程序能在几个主要 ruby 版本上运行,然后让操作系统去管理 ruby 的版本升级。
    再或者索性上 docker,让 docker 的 up 主来管理 ruby 的升级。
    sparkle2015
        4
    sparkle2015  
       2017-12-28 22:49:58 +08:00
    对我来说还挺有价值的,前段时间刚在 EC2 上折腾过一次 Rails 的布署,把这些流程都走过一遍。不过用的是 capistrano,好奇 lz 为什么没用 capistrano (这个应该是主流了吧)。
    msg7086
        5
    msg7086  
       2017-12-29 00:18:54 +08:00
    @sparkle2015 mina 比 capistrano 不知道快到哪里去了。
    bydmm
        6
    bydmm  
       2017-12-29 10:07:00 +08:00 via iPhone
    docker push
    docker compose up
    zealinux
        7
    zealinux  
       2017-12-29 12:53:31 +08:00
    lz 用 mina 的新版了吗?
    问题一大堆,mina-puma
    r00tt
        8
    r00tt  
       2017-12-29 13:14:26 +08:00
    还在用着 capistrano,感觉还行
    yuanfnadi
        9
    yuanfnadi  
       2017-12-31 18:35:46 +08:00 via iPhone
    docker run

    一句话就够了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2546 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 05:04 PVG 13:04 LAX 22:04 JFK 01:04
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86