【ゆるふわDocker部】任意バージョンのPostgreSQLコマンドを実行して外部DBに接続する

morimorihogeです。そろそろラナンの探索マップがコンプリートできそうです。 前回の記事でゆるふわDocker部の提案をしましたので、ゆるゆるとDocker Tips的なものを垂れ流していこうと思います。今回はバージョン依存の強めなPostgreSQLのCLIコマンドをDocker経由で簡単に実行する方法を紹介します(今回は9.3系ですが、適宜他のバージョンで読み替えても使えるはず)。Dockerを使うことでローカルシステムにインストールされていないPostgreSQLクライアントで外部のPostgreSQLサーバに接続することが簡単になります。 確認環境はMac OS X El Capitan、Docker 1.9.1で、Docker Toolboxビルトインのboot2dockerを使っています。いつものことですがご利用は自己責任でお願いします。 PostgreSQLのクライアントバージョン問題とは MySQLと並んで人気OSS系RDBMSのPostgreSQLですが、よく引っかかる問題としてバージョン依存性が強いというものがあります。 例えば、クライアント側のバージョンが9.2.9でサーバ側のバージョンが9.3.1のケースでpg_dumpコマンドを実行すると、以下の様なエラーが発生して接続に失敗しまいます。 pg_dump -h somehost -U someuser -W somedb Password: pg_dump: server version: 9.3.1; pg_dump version: 9.2.9 pg_dump: aborting because of server version mismatch DBサーバとアプリサーバを分けている時なんかには割と発生しがちな問題ですね。他にもたまに古めのサーバに接続しないといけないときはちょこちょこあるので、困ることがあります。 Dockerをでかいバイナリコマンドとして使う 今回実行したかったのはpg_dumpコマンドだけで、dumpデータさえ取れれば後は手元にインポートして使うぜ、という状態でした。そこで、使いたいバージョンのPostgreSQL containerを取得してそのバージョンのPostgreSQLコマンドを使うという用途でDockerを使うことにしました。 今回はDocker HubでPostgreSQL関連のDocker Imageを漁って使ってみましたので、手順を追っていきます。他のプログラムでも同様の手順で大体はなんとかなると思います。 Docker Hubから使えそうなイメージを探してくる まずは、Docker Hubの画面一番上の検索から「postgres」で検索すると、 オフィシャルのpostgres imageが見つかります。 Tag一覧のページを見ると、9.3系では9.3.10が生きてることが確認できます。 というわけで、欲しいDocker Imageは「postgres:9.3.10」であることが特定できました。 しかし、ここで良く見ると、9.3系のTagで古いビルドバージョンのもの(9.3.9以下)は削除されていっていることが分かります。これだと9.3.11が出た後に最新をpullすると9.3.10が使えなくなってしまいますね。 そこで、よくよくREADMEを読んでみると、9.3.10の他に9.3というTagがあることが分かります。 というわけで、9.3系であれば良いということであれば、Tagには9.3.10ではなく9.3を指定するのが良さそうです。最終的に使うDocker Imageは「postgres:9.3」が良さそうです。 イメージをpullして、使いたいコマンドの実体を探す イメージ名が特定できたので、取得します。以下のコマンドで調べたDocker Imageを取得できます。タグ名(ここでは9.3を省略するとlatestが取得されます)。 docker pull postgres:9.3 ダウンロードが完了したら、実行したいコマンドのパスを調べていきます。とりあえずシェル(/bin/bash)を立ち上げて欲しいコマンド(pg_dump)を探索してみます。 ここでの「-it」オプションはインタラクティブ&仮想TTYオプションで、対話式のコマンドを実行するときにはこれを付けるモノだと思っていればOKです。「–rm」を付けるとコマンド実行終了時に自動的にcontainerを削除してくれます(docker ps -aしたときに「うわあああああ」ってならなくて済みます)。 docker run -it –rm postgres:9.3 /bin/bash root@4d0c308aa3c6:/# which pg_dump /usr/lib/postgresql/9.3/bin/pg_dump ありました。これで、欲しいコマンドは「postgres:9.3の/usr/lib/postgresql/9.3/bin/pg_dump」であることが確認できました。 一応ためしに実行してみましょう。 docker run –rm postgres:9.3 /usr/lib/postgresql/9.3/bin/pg_dump –help pg_dump dumps a database as a text file or to other formats. Usage: pg_dump [OPTION]… [DBNAME] General options: -f, –file=FILENAME output file or directory name -F, –format=c|d|t|p output file format (custom, directory, tar, plain text (default)) -j, –jobs=NUM use this many parallel jobs to dump -v, –verbose verbose mode (以下略) 大丈夫そうですね。これでとりあえず欲しかったコマンドは使えるようになりました。 DockerコンテナからリモートのPostgreSQLサーバに接続する ここまででpostgresコンテナから任意バージョンのコマンドを実行することはできましたが、このままだとまだ接続したいサーバに接続できていません。ここからはMac環境依存です(Linuxでも大丈夫ですが、Windowsはsshコマンド周りがダメかも)。 MacでDockerを動かす場合、VirtualBox上でboot2docker等のDocker HostとなるLinuxを動作させ、そこに接続して使うという形が一般的ですが、これだと動かしているcontainerは論理的にはVirtualBoxのprivate network上に存在する状態になっています。 今回、dumpを取得したいDBサーバがAWS VPCの中にあったため、接続するためにSSHトンネルを張る必要が出てきました。 ※SSHトンネルについては過去の記事の後半で解説しているので、よく分からない人はそちらも参照して下さい。 言葉で説明するとわかりにくいので、ネットワーク構成をまとめてみました(文字が一部小さいので適宜拡大して見て下さい)。 ローカルのMacで上で動作するVirtualBoxでboot2dockerのDocker Hostが動き、その上でpostgres:9.3のcontainerを動かします。 AWS側は良くある構成ですが、APPサーバはパブリックIPを持っているため外からSSHアクセスできますが、DBサーバはVPCのプライベートネットワーク上にあるため直接インターネットからアクセスはできません。 ここで、今回接続したい経路は下図赤線の通りです。 図で書くとpostgres:9.3のDocker Containerがかなり深い位置にあることが分かるのではないでしょうか。 さて、postgres:9.3 containerからAWS VPC上のDBサーバに接続するにあたって、今回は以下の方針を取ることにします。 MacのVirtualBox向けネットワークインターフェースからAWS VPC上のDBサーバのpostgresqlポート(5432)へのSSHトンネルを掘る postgres:9.3 containerからMac上のvboxnet1に対してpg_dumpを実行する 前記のdockerコマンドはLocal Mac上で実行するので、pg_dumpの結果を標準出力から取得してLocal Mac上に保存する 接続イメージは下図の通りです。青線がSSHトンネル、緑線がpg_dumpコマンドの範囲になります。 この方式の利点は以下の通りです。 SSHトンネルはさらに多段にすることも可能なので、やろうと思えばもっと複雑なネットワーク上の深い所にあるサーバにもLocal Macから透過的に接続できる(汎用性) SSHトンネルのlisten addressはVirtulBoxのプライベートIPのため、もし社内intra networkに悪い人がいてもこのSSHトンネルを利用することはできない(安全性) 必要なSSH接続導線は「Local Mac -> VPC上のAPPサーバ」「APPサーバ -> DBサーバ」の2つなので、APPサーバやDBサーバに新規でSSH公開鍵を登録する必要がない(保守性) 上図では省略しましたが、本来Docker Hostはeth0にVirtualBoxのNATネットワークインターフェースを持っていて、これを通すことでpostgres:9.3 containerから外に直接SSHトンネルを掘ることもできますが、その場合はpostgres:9.3 containerでSSH鍵ペアを作成し、今回のコマンドを実行するためだけの公開鍵をAPPサーバに配置する必要が出てきたりして今ひとつイケてないです。これだともしその後そのcontainerを誰かと共有したりするとAPPサーバへの接続権限ごと渡ってしまうことになってしまいますしね。 SSHトンネルを掘る 以下のコマンドでOKです。これで前述の図で書いた青線のトンネルが掘られます。 ssh -fNL … Continue reading 【ゆるふわDocker部】任意バージョンのPostgreSQLコマンドを実行して外部DBに接続する