使用Mysql Db从Heroku SSH到远程服务器

时间:2014-10-20 02:56:06

标签: ruby-on-rails ruby-on-rails-4 heroku

我正在寻找一个Rails应用程序,它需要从Heroku到远程Mysql数据库建立一个远程SSH会话(SSH隧道?),作为后台ActiveRecord会话的一部分。目标是通过此渠道在不同时间将数据迁移到应用程序中。通过Web连接到远程mysql数据库不是一个选项。

几个问题:

  1. Heroku是否允许通过他们的Dyno进行SSH连接?
  2. 会是什么 这样做的缺点?
  3. 我是否必须关注SSH 会话持久性(工作可能需要1小时)?
  4. 最后,如何配置Rails和Heroku以启用远程连接 database.yml mysql endpoint?

2 个答案:

答案 0 :(得分:0)

好吧,我现在能够在挖掘了几天之后回答我自己的问题。简而言之,是的。

class LegacyAccount < ActiveRecord::Base

 self.table_name = "account"

 def self.test_connection

      # net-ssh-gateway gem
      gateway = Net::SSH::Gateway.new("ip_address","ssh_user_name",
          password: "password",
          port: "port if different from 22",
          verbose: :debug
          )

      port = gateway.open('127.0.0.1', 3306, 3307)

      establish_connection :legacy_production

      result = LegacyAccount.first
      puts "Record: #{result.to_yaml}"

      gateway.close(port)
      gateway.shutdown!

      result
  end

end

并在您的database.yml中:

legacy_production:
  adapter: "mysql2"
  host: "127.0.0.1"
  username: "root"
  password: "password"
  database: "legacydb"
  port: 3307
  secure_auth: false

答案 1 :(得分:0)

我试过@ user1322092的方法,当多个客户端试图访问数据库时遇到了麻烦,因为每个客户端都会尝试打开一个连接(除了第一个连接都会出错)。

我创建了一个可怕的解决方案,涉及在dyno上生成SSH进程并将其用于所有通信。血腥细节在https://stackoverflow.com/a/27361295/558639。除了真正的kludgy之外,每次进程启动时都会导致延迟,无论您是否正在访问远程数据库。

更新

因此,这是一种似乎运行良好的更好的方法:只是陷阱(和忽略)Errno::EADDRINUSE错误。这是代码:

require 'net/ssh/gateway'

class Mole

  TUNNEL_HOST = <redacted>
  TUNNEL_USER = <redacted>
  AWS_HOST = <redacted>
  TUNNEL_PORT_NUMBER = 3307

  attr_reader :tunnel_gateway, :tunnel_port

  # Call this to open an SSH tunnel from the current machine.  If the
  # the tunnel was already opened (e.g. by another process) , you'll
  # get a warning message
  def open_tunnel
    @tunnel_gateway = Net::SSH::Gateway.new(TUNNEL_HOST, TUNNEL_USER)
    begin
      @tunnel_port = @tunnel_gateway.open(AWS_HOST, 3306, TUNNEL_PORT_NUMBER)
    rescue Errno::EADDRINUSE => e
      $stderr.puts("Warning: #{e.class}: #{e.message}")
    end
  end

  # You won't normally call this, because the tunnel is a system wide
  # resource; you don't know when other processes want to release it.
  def close_tunnel
    r = @tunnel_gateway.close(@tunnel_port) if @tunnel_gateway
    @tunnel_gateway.shutdown!
    r
  end

end