部署 长文慎点:部署(Docker + Ubuntu + Ruby 2.6.1 + Rails + Capistrano + Puma)

liurui12w · 2020年05月12日 · 最后由 BenX 回复于 2020年05月15日 · 1770 次阅读

前言

  • Docker 的用处

测试,测试数据分离,开发,PaaS 云服务,这里我要用 docker 搭建一个 rails 项目

切记一定要去看 docker,此贴只简单描述,此贴只是一种思路,不一定是正确的流程,仅供参考及讨论

友情链接 Docker 官网 Docker 安装参考链接

版本号

  • Ubuntu 16.04
  • Dokcer 18.09.0
  • Nginx 1.10.3
  • ruby 2.6.1
  • rails 6.0.3
  • Mysql 5.7

结构


+--------------------+--------------------+
| ubuntu             | mysql              | #docker 
+--------------------+--------------------+
| rvm                | mysql              | #包含
| ruby               |                    |
| rails              |                    |
| nginx              |                    |
+--------------------+--------------------+

一.构建所需要的 Dockerfile (ubuntu)

1.创建 ubuntu 的 dockerfile
FROM ubuntu:16.04
#捆绑套件
RUN apt-get update && apt-get install -y openssh-server
RUN apt-get update && apt-get install gnupg2 -y && apt-get install vim -y && apt-get install curl -y && apt-get install git -y && apt-get install nodejs -y
#创建ssh
RUN mkdir -p /var/run/sshd
RUN mkdir /root/.ssh
#创建账号 以供操作和部署等
RUN echo 'root:root2020' | chpasswd
RUN useradd -ms /bin/bash deploy
RUN echo 'deploy:deploy2020' | chpasswd
#当容器启动时运行的脚本
CMD ["/usr/sbin/sshd", "-D"]

RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
#开放端口
EXPOSE 22 80 8080
2.生成镜像 docker build .
#创建镜像
$ docker build .
#查看镜像
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              a58c0f537c60        23 seconds ago      251MB #新创建docker

$ docker tag a58c0f537c60 ubuntu:base # TAG
#创建我所需要的容器
$ docker run -idt \
       -p 126:22 -p 8081:80 \ #映射端口
       --name rails_app \ #名
      ubuntu:base #镜像

$ docker ps #查看运行中容器      

3.进入容器,配置点东西
$ ssh root@127.0.0.1 -p 126

#改个时区
#查看时间
$ date
$ apt install tzdata
$ dpkg-reconfigure tzdata
6 Asia  70 Shangehai #设置时区

二.装 rvm,ruby 等环境 安装 rvm

1.安装 rvm(继续之前的 rails_app 中不用退出)
$ gpg2 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
$ \curl -sSL https://get.rvm.io | bash -s stable

$ source /etc/profile.d/rvm.sh
2.安装 ruby
#查看版本
$ rvm list known
#安装版本
$ echo "export rvm_max_time_flag=20" >> ~/.rvmrc
$ rvm install 2.6.1 --disable-binary

#安装成功
$ ruby -v
$ ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-linux]
#手动装个bundler,Gemfile用起来更香 
$ gem install bundler

三.创建 rails 项目, capistrano 配置 参考

1.创建 rails 项目
# 本地
# 如果你已经有开发好的项目,这一步请直接略过。

# 新建一个目录,存放rails项目
$ mkdir -p ~/Developer/Rails
# 新建一个Rails项目,默认使用MySQL数据库
$ rails new web_app -d mysql
2.修改 Gemfile,主要是 capistrano 大礼包
#Gemfile
group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'pry-rails' # binding.pry

  # capistrano family gem
  gem 'capistrano', '~> 3.6'
  gem 'capistrano-rails', '~> 1.1'
  gem 'capistrano-rvm'
  # gem 'capistrano-passenger'
  gem 'capistrano-bundler', require: false
  gem 'capistrano3-puma', require: false
end
# 修改后bundle
$ bundle install
3.Capfile,config/deploy.rb 配置
1.Capfile
# 本地运行 
$ cap install

#编辑 Capfile 
require 'capistrano/rails'
require "capistrano/rvm"
require "capistrano/bundler"
require 'capistrano/puma'
2.config/deploy.rb
lock "~> 3.14.0"
# 项目名称
set :application, "web_app"
# git仓库地址 我这里用的coding
set :repo_url, "git@e.coding.net:xxxx/web_app.git"

set :rails_env, 'production'
# 去掉注释,服务器需要有这些配置
append :linked_files, "config/database.yml","config/secrets.yml"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public"

#参数设置
set :pty, true
set :use_sudo, false
set :stage, :production
set :deploy_via, :remote_cache
# set :ssh_options, {forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub)}
#puma参数可参考capistrano3-puma
set :puma_threads, [4, 16]
set :puma_workers, 0
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log, "#{release_path}/log/puma.access.log"
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true
#以下我个人设置,可按照自己喜好配置
namespace :puma do
  desc 'Create Directories for Puma Pids and Socket'
  task :make_dirs do
    on roles(:app) do
      execute "mkdir #{shared_path}/tmp/sockets -p"
      execute "mkdir #{shared_path}/tmp/pids -p"
    end
  end

  before :start, :make_dirs
end

namespace :deploy do
  desc "Make sure local git is in sync with remote."
  task :check_revision do
    on roles(:app) do
      unless `git rev-parse HEAD` == `git rev-parse origin/#{fetch(:branch)}`
        puts "WARNING: HEAD is not the same as origin/#{fetch(:branch)}"
        puts "Run `git push` to sync changes."
        exit
      end
    end
  end

  desc 'Initial Deploy'
  task :initial do
    on roles(:app) do
      before 'deploy:restart', 'puma:start'
      invoke 'deploy'
    end
  end

  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      invoke 'puma:restart'
    end
  end


  before :starting, :check_revision
  # after :finishing, :compile_assets
  # after :finishing, :cleanup
  # after :finishing, :restart
end

3.config/deploy/production.rb
set :stage, :production # 部署的环境
set :branch, 'master' # 部署的代码分支
set :rails_env, :production
#我这里仅供测试,需要根据实际配置来
server '127.0.0.1', user: 'root', password: 'root2020', roles: %w{web app db} , port: '126'

set :deploy_to, "/var/www/web_app" # 部署到服务器的位置

set :enable_ssl, false

四.capistrano 部署相关配置

服务器 我这里采用本地

1.创建 mysql
#run一个mysql docker
$ docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=336699  -d mysql:5.7
$ docker exec -it CONTAINER_ID bash #进入docker
cat /etc/hosts #获取ip 我这里获取的是 172.17.0.3
#创建个库
mysql -u root -p
CREATE DATABASE web_app_pro CHARACTER SET utf8mb4;

#退出 mysql console
$ exit
#退出 mysql docker
$ exit
2.web_app docker 内相关配置
$ ssh root@127.0.0.1 -p 126
#准备工作
$ mkdir -p /var/www/web_app #项目存放路径
$ mkdir -p /var/www/web_app/shared/config #项目配置

$ cd /var/www/web_app/shared/config

$ vim database.yml
#创建所需的文件
# database.yml:
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 20
  username: root #<%= ENV["DATAUSER"] %> #推荐使用<%= ENV["DATAUSER"] %> 这样不会直接暴露账号密码,我这里图方便就用了root(不建议使用)
  password: 336699 #<%= ENV["DATAPASSWD"] %> #来源docker mysql的密码
  host: 172.17.0.3 #<%= ENV['DATABASE_HOST'] %> #来源docker mysql的地址
  port: 3306
  reconnect: true
  wait_timeout: 30

production:
  <<: *default
  database: web_app_pro #<%= ENV["DATABASE"] %>

#此处省略secrets。yml创建  

五.capistrano 部署代码 开始爆破

#本地执行
$ cap production deploy:check
#好了执行下面的

$ ccap production deploy

第一次会比较慢,请耐心等待。这条命令,还会在服务器上建立一个叫 current 的目录,用 symbolic link 指向 releases 目录下最新的版本。

六.配置 nginx

1.安装 nginx 参考
$ apt-get install nginx

2.nginx 配置 rails_app 中
$ cd /etc/nginx/sites-enabled

$ vim web_app.conf

#web_app.conf配置

upstream web_app {
        server unix:///var/www/web_app/shared/tmp/sockets/web_app-puma.sock;
}

server {
        listen 80;

        root /var/www/web_app/current/public;
        server_name localhost;

        try_files $uri/index.html $uri @police_iot;

        location @police_iot {
                proxy_pass http://web_app;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_redirect off;
        }
}

$ nginx -s reload 重新加载nginx配置

七.end 真香 谢谢收看

😃 个人建议

  1. 既然是用 docker,就可以用新不用旧 ,如果你用 ubuntu 的话,那不说用 20 的,至少也用 18,当然 也可以直接 FROM ruby 相关镜像
  2. rvm 完全是没必要存在的东西
  3. apt install tzdata 这种东西完全可以在 build 镜像的时候做吧,完全看不出在容器做的必要,时区设置如果要灵活可以作为参数启动
  4. rails 运行的环境没看到有安装 mysql 依赖的客户端库 ,不知道怎么跑起来的

既然用了 docker 就该放弃 capistrano 了,换换思路

蛮好的, 值得学习👍

不如直接 from ruby 然后不需要 capistrano 了 每次代码更新重新 build 镜像 丢 k8s 省略 N 多

  • 可以用 docker compose 免去 run mysql 的麻烦
  • rvm 确实没必要,毕竟一般不会有在 container 里切换 ruby version 的场景

其实也可以考虑 fullstaq-ruby

楼主是把 docker 当 virtual machine 用了吗? 反面教材,有大佬出来驳斥一番不。

ThxFly 回复

这个是之前教公司的同事,最简单的方法,虽说有效的还是 docker compose 整合配置那一套 😀 说的挺对的 这套操作其实就相当于在服务器用 docker 搭建一整套环境 哈哈哈

RoyZheng 回复

😊 收到

w569893882 回复

这只是一种思路,当然好点的是用 docker compose

xiayuanyin 回复

你说的是对的,有时候会想给代码加一些好玩的东西就需要用到 capistrano,所以自己觉得方便就自顾自己的装上了

谢谢各位指点,有时间我会整理一套 docker compose 到时候估计就按照 1 楼说的 要整就整最新的😀 😀 😀

liurui12w 回复

看 docker swarm。

Rei 回复

😊 ok 3q

上 docker 了,基本来说 Linux 环境就没有任何要装的啦,除了 docker 环境😀️

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册