apt: バージョン指定してElixirをインストールする方法
Ubuntu/Debianにaptを利用してElixirをインストールする方法は、ここに書いてある通りです:
ただし、これをそのまま実行すると最新のElixirがインストールされます。バージョン指定してElixirをインストールするための方法を紹介します。
Erlang solutionsのリポジトリを追加して、Erlangをインストールします。
$ wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb $ sudo apt-get update $ sudo apt-get install esl-erlang
ここで、インストール可能なバージョンのリストを調べます。
$ apt policy elixir elixir: インストールされているバージョン: 1.11.2-1 候補: 1.12.0-1 バージョンテーブル: 1.12.0-1 999 999 http://binaries.erlang-solutions.com/debian focal/contrib amd64 Packages 1.11.4-1 999 999 http://binaries.erlang-solutions.com/debian focal/contrib amd64 Packages *** 1.11.2-1 999 999 http://binaries.erlang-solutions.com/debian focal/contrib amd64 Packages 100 /var/lib/dpkg/status 1.11.1-1 999 999 http://binaries.erlang-solutions.com/debian focal/contrib amd64 Packages 1.10.4-1 999 999 http://binaries.erlang-solutions.com/debian focal/contrib amd64 Packages 1.10.3-1 999 999 http://binaries.erlang-solutions.com/debian focal/contrib amd64 Packages 1.10.2-1 999 999 http://binaries.erlang-solutions.com/debian focal/contrib amd64 Packages 1.9.1.dfsg-1.3 500 500 http://jp.archive.ubuntu.com/ubuntu focal/universe amd64 Packages
現在、1.11.2-1
がインストールされていて、最新版は 1.12.0-1
です。このまま sudo apt-get upgrade
を実行すると最新版がインストールされます。
1.11.4-1
をインストールします。
$ sudo apt-get install elixir=1.11.4-1
Elixirのバージョンを固定します。
$ sudo apt mark hold elixir
こうしておくと、sudo apt-get upgrade
で自動的にアップグレードされないようになります。
Ubuntu 18.04/20.04: フリーズ/クラッシュ問題対応(作業記録)解決済み
会社で購入したデスクトップPCにUbuntu 18.04 LTSとUbuntu 20.04 LTSをインストールしてみたところ、いくつか深刻な不具合に遭遇しました。一部は解決し、一部は未解決です。情報共有のため作業メモを残します。
マシンは@Sycomという会社から購入しました。省スペースPCというカテゴリのものです。すでに複数回ここから買っていて、これまで大きな問題はありませんでした。
問題は5点あります。
- フリーズする。タイミングはいろいろ。ログイン画面で起こったり、しばらく使ってから起こったりする。
- クラッシュする。突然、スクリーンが真っ黒になりPCが再起動する。
- クラッシュする。黒い画面に切り替わり、「Kernel panic」などのメッセージを表示して停止する。
- モニターを2台接続しても一方が認識されない。
- ディスプレイポートとDVI端子で接続したモニターの解像度を変更できない。
やったこと
amd-disable-c6 を導入
Ubuntu 18.04を Ryzenで使用時に定期的にフリーズする。という記事を見て、やってみました。効果なし。
スワップファイルのサイズを16GBに増やす
Ask ubuntuに投稿されたUbuntu 20.04 LTS freezing about every 10-15 secondsという質問への回答を見て実施。効果あり。問題1と2が解消された模様。
【追記】その後、問題2が解消されていないことが判明。
ただし、Ubuntu 20.04 LTSで新たに問題3が発生するようになりました。
Linuxカーネルを最新の5.8系にアップグレード
Ubuntu Linuxのカーネルをaptでアップグレードするを見て実施。効果あり。問題4と問題5が解消されました。問題3はPCを一晩放置した結果発生したので、効果のほどはまだわかりません。
アップグレード前のLinuxカーネルは5.4系でした。Linux 5.8は約3ヶ月前(2020年8月5日)にリリースされたばかりのもの。
マシンスペック
- CPU: AMD Ryzen 3 PRO 4350G Renoir 3.8GHz/4Core/Radeonグラフィック/TDP65W
- マザーボード: ASRock DeskMini X300M-STX
Kernel panicが発生したときのメッセージに「x300m-stx」という文字があったので調べてみると、ASRock DeskMini X300M-STXはつい最近(2020年10月)発売されたばかりものでした。Linuxカーネルをアップグレードして問題が解消された事実と整合します。
追記1 (2020-10-26)
Ubuntu 20.04がインストールされている別のマシンも若干調子が悪い(ときどきウィンドウ内が再描画されなくなって、黒い部分が残る)ので、Linuxカーネルを最新の5.8系(5.8.0.23)にアップグレードしてみたところ、接続している3台のモニター(HDMI接続2、DisplayPort接続1)のうちDisplayPort接続のモニターしか映らなくなるという問題が発生しました。現在は、Linuxカーネルを5.4系に戻しています。
真新しいLinuxカーネルにアップグレードするのには、それなりのリスクが伴うようです。
「別のマシン」のスペックは以下の通り:
- CPU: AMD Ryzen 7 3800X Matisse [3.9GHz/8Core/TDP105W]
- マザーボード: ASRock B450M Steel Legend [AMD B450 chipset]
追記2 (2020-10-26)
実際に運用してみたところ、Ubuntu 18.04でもUbuntu 20.04でも問題2(使用中に突然クラッシュして再起動)が解消されていないことが判明しました。
追記3 (2020-10-26)
Ubuntu 20.04 の Kernel を 5.9.1 にアップグレードしてみましたが、効果なし。
追記4 (2020-10-26)
https://bbs.archlinux.org/viewtopic.php?id=245608 の情報に基づき、以下の設定変更をしました。
sudo vim /etc/default/grub
で GRUB の設定ファイルを開き、GRUB_CMDLINE_LINUX_DEFAULT
にprocessor.max_cstate=1
を追加。sudo update-grub
コマンドを実行して、再起動。
ログイン後すぐにクラッシュする現象は解消された模様。現在、様子見。2時間ほど使ってみましたが、フリーズもクラッシュも起きていません。ついにやったか…。
追記5 (2020-10-27)
昨日の半日使用でフリーズもクラッシュも発生しませんでした。解決済みと判断します。
追記6 (2020-10-28)
不思議なことに同じハードウェア構成の2台のPCのうち、片方は追記5までの対策(ただし、amd-disable-c6を除く)をしても問題は解決しませんでした。ログインから1分も経たないうちにクラッシュして再起動が始まってしまいます。
そこで、ブート時にキーボードからF2を押してUEFI設定画面を開き、CPU関連の設定でEnable/Disableを切り替えられるものをすべてDisableにしてみたところ、安定して動くようになりました。
また暇のあるときに、ひとつひとつEnableしてどの設定が問題を引き起こしているのかを特定したいと思います。
追記7 (2020-10-28)
どうやら、UEFI設定画面のCPU Configurationにある、PSS SupportをDisableにすれば安定するようです。
調べたところ、これはACPI(電源管理に関する規格)に関連する設定項目でした。
追記4でGRUBの設定に追加した processor.max_cstate=1
も省電力に関するものでした。電源関係が弱点なのでしょうかね。
Docker + Rails 6 + PostgreSQL による Web アプリケーション開発の始め方(Windows版)
要旨
- Docker Desktop for Windowsを用いてRuby on Rails 6.0によるWebアプリケーション開発を行う手順をできるかぎり簡潔にまとめた。
- Docker Composeを用いてデータベースサーバーのコンテナとWebサーバーのコンテナを管理する方法についても解説する。
この記事は、macOSとUbuntuを対象にしたDocker + Rails 6 + PostgreSQL による Web アプリケーション開発の始め方をWindows向けに書き直したものです。一部、内容に重複があります。
対象OS
- Windows 10 Pro (64bit)
※ Windows 10 Pro (32bit) および Windows 10 Home では Docker Desktop for Windows が動作しません。
注意事項
この記事は2019年2月16から18日の間に書かれています。Ruby on Rails 6.0のリリースが予定されているのは2019年4月末です。現時点での最新版である Rails 6.0.0.beta1 に基づいています。今後、内容に訂正が必要となる可能性が十分にあります。
はじめに
この記事ではDocker Desktop for Windowsと呼ばれるソフトウェア(以下、「Docker」と呼ぶ)を用いてRuby on Rails 6の開発環境を構築する手順を紹介します。Dockerをインストールする対象のOS(ホストOS)はWindows 10 Pro (64bit)とします。
ゲストOSにはAlpine Linuxを採用しました。インストールに必要なストレージ容量が非常に小さいことが特長です。
Dockerを用いて構築されたゲストOSの環境はコンテナと呼ばれます。この記事では、データベースサーバー(PostgreSQLサーバー)のためのコンテナとWebサーバー(Railsアプリケーション)のためのコンテナ、計2個のコンテナを作ります。これらのコンテナをうまく組み合わせるためにDocker Composeと呼ばれるソフトウェアを使用します。
コンテナを実行するのに必要なファイルシステム(ディレクトリ、ファイル、メタ情報の集合体)をイメージと呼びます。イメージはWebサービスDocker Hubを通じて配布されます。
また、この記事では設定ファイル等の取得にGitを使用します。あらかじめGit for Windowsをインストールしておいてください。
Docker Hubアカウントの取得
Docker自体のインストーラやDockerイメージを取得するためには、Docker Hubのアカウントが必要となります。メールを受け取れるアドレスがあれば、無料で取得できます。未取得の方は、次のURLを訪問して登録してください。
Docker Hubにログインしてから次の手順に進んでください。
Docker Desktop for Windowsのインストール
https://hub.docker.com/editions/community/docker-ce-desktop-windows から Docker Desktop for Windows のインストーラをダウンロードしてインストールしてください。Dockerと同時にDocker Composeもインストールされます。
@sikkim 氏がQiitaに書いた記事 https://qiita.com/sikkim/items/bfc79561b16b2c13caba に詳しいインストール手順が載っていますので、参考にしてください。
※ DockerToolboxという名前の類似のソフトウェアが存在しますが、別物です。混同しないでください。
【重要な注意】 VirtualBox との共存
- Docker for WindowsをインストールするとVirtualBoxが動作しなくなるケースがあります。
- Docker for Windowsを使用する場合、Windows 10の仮想化システム「Hyper-V」を有効にする必要がありますが、バージョン6未満のVirtualBoxはこの「Hyper-V」と共存できません。
- 2018年末にリリースされたVirtualBox 6.0は「Hyper-V」と共存できるとされていますが、ハードウェアにより動作する場合と動作しない場合あるようです。
【参考】
- https://www.cyamax.com/entry/2017/05/07/060000
- https://qiita.com/takotakot/items/94d3218cf8de5b2c1da8
Dockerへのログイン
Docker Desktop for Windowsのインストールが完了した後、いったんWindowsからサインアウトする必要があります。サインインすると、DockerのWelcomeウィンドウが現れるので、DockerHubのIDとパスワードでログインします。
Docker Compose用の設定ファイル群の取得
コマンドプロンプト(cmd.exe)を開き、以下のコマンドを実行します。
> git clone https://github.com/oiax/rails6-compose.git > cd rails6-compose > cp docker-compose.win.yml docker-compose.override.yml
ボリュームの作成
> docker volume create --name pgdata
ボリュームの作成に関する注記
- 複数の Rails アプリケーション開発プロジェクトを並行して進める場合、上記コマンドの
pgdata
の部分をそれぞれ別の名前、例えばpgdata1
とpgdata2
で置き換える必要があります。 - その場合、テキストエディタで
docker-compose.override.yml
を開き、pgdata
と書かれている箇所をpgdata1
あるいはpgdata2
で書き換えてください。
コンテナ群の構築・起動
> docker pull oiax/rails6-deps:latest > docker-compose up -d
オプション -d
により、コンテナ群が detached mode で起動します。すなわち、コンテナ群がバックグランドで動き始めます。
ターミナルに次のようなメッセージが表示されれば OK です。
Starting rails6compose_db_1 ... Starting rails6compose_db_1 ... done Starting rails6compose_web_1 ... Starting rails6compose_web_1 ... done
Web コンテナにログイン
> docker-compose exec web bash
※ ログアウトするには exit
コマンドを実行するか、Ctrl-D
キーを入力してください。
コンテナ群の停止
> docker-compose stop
コンテナ群の破棄
> docker-compose down
ボリュームの破棄
> docker volume rm pgdata
Docker + Rails 6 + PostgreSQL による Web アプリケーション開発の始め方
要旨
- Dockerを用いてRuby on Rails 6.0によるWebアプリケーション開発を行う手順をできるかぎり簡潔にまとめた。
- Docker Composeを用いてデータベースサーバーのコンテナとWebサーバーのコンテナを管理する方法についても解説する。
対象OS
※ Windows 10 ProでもDockerを用いてRails開発を行うことができますが、用語や手順で相違点が多いので今回は対象外とします。
【更新】 Windows編を書きました。
注意事項
この記事は2019年2月16から18日の間に書かれています。Ruby on Rails 6.0のリリースが予定されているのは2019年4月末です。現時点での最新版である Rails 6.0.0.beta1 に基づいています。今後、内容に訂正が必要となる可能性が十分にあります。
はじめに
この記事ではDockerと呼ばれるソフトウェアを用いてRuby on Rails 6の開発環境を構築する手順を紹介します。Dockerをインストールする対象のOS(ホストOS)は、macOSとUbuntu 18.04 (64bit)とします。
ゲストOSにはAlpine Linuxを採用しました。インストールに必要なストレージ容量が非常に小さいことが特長です。
Dockerを用いて構築されたゲストOSの環境はコンテナと呼ばれます。この記事では、データベースサーバー(PostgreSQLサーバー)のためのコンテナとWebサーバー(Railsアプリケーション)のためのコンテナ、計2個のコンテナを作ります。これらのコンテナをうまく組み合わせるためにDocker Composeと呼ばれるソフトウェアを使用します。
コンテナを実行するのに必要なファイルシステム(ディレクトリ、ファイル、メタ情報の集合体)をイメージと呼びます。イメージはWebサービスDocker Hubを通じて配布されます。
また、この記事では設定ファイル等の取得にGitを使用します。ホストOSに合わせて、最新のGitをインストールしてください。
Docker Hubアカウントの取得
Docker自体のインストーラやDockerイメージを取得するためには、Docker Hubのアカウントが必要となります。メールを受け取れるアドレスがあれば、無料で取得できます。未取得の方は、次のURLを訪問して登録してください。
Docker Hubにログインしてから次の手順に進んでください。
Docker/Docker Composeのインストール
macOSの場合
https://hub.docker.com/editions/community/docker-ce-desktop-mac から Docker Desktop for Mac のインストーラをダウンロードしてインストールしてください。Dockerと同時にDocker Composeもインストールされます。
Ubuntuの場合
ターミナルで以下のコマンド群を順に実行し、Dockerをインストールします。
$ sudo apt-get update $ sudo apt-get install -y \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - $ sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" $ sudo apt-get update $ sudo apt-get install -y docker-ce docker-ce-cli containerd.io
詳しくは https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-using-the-repository を参照してください。
さらに、以下のコマンド群を順に実行し、Docker Composeをインストールします。
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" \ -o /usr/local/bin/docker-compose $ sudo chmod +x /usr/local/bin/docker-compose
1.23.2
の部分は、Docker Composeのバージョン番号です。
詳しくは、https://docs.docker.com/compose/install/#install-compose を参照してください。
$ sudo gpasswd -a $USER docker
Ubuntuからログアウトし、ログインし直します。
docker login
ターミナルで次のコマンドを実行し、Docker Hubにログインします。
$ docker login
Docker Compose用の設定ファイル群の取得
$ git clone https://github.com/oiax/rails6-compose.git $ cd rails6-compose
コンテナ群の構築・起動
$ setup.sh $ docker-compose up -d
オプション -d
により、コンテナ群が detached mode で起動します。すなわち、コンテナ群がバックグランドで動き始めます。
ターミナルに次のようなメッセージが表示されれば OK です。
Starting rails6compose_db_1 ... Starting rails6compose_db_1 ... done Starting rails6compose_web_1 ... Starting rails6compose_web_1 ... done
【参考】 setup.sh の中身
#!/bin/bash set -eu docker pull oiax/rails6-deps:latest case "$OSTYPE" in darwin*) docker-compose build web ;; linux*) docker-compose build --build-arg UID=$(id -u) --build-arg GID=$(id -g) web ;; *) echo "Unknown OS Type: $OSTYPE" ;; esac
まず、docker pull
コマンドでベースとなるイメージの最新版を取得しています。
続いて、docker-compose build
コマンドで Web コンテナを構築します。このとき、ホスト OS とコンテナの間でソースコード等を共有するときに、ファイルやディレクトリの所有権に関する問題が発生しないように --build-arg
オプションを不可しています。この問題は Linux 版の Docker で発生しますが、macOS 版では発生しません。
参考資料:
- https://stackoverflow.com/a/44683248/513554
- https://qiita.com/yohm/items/047b2e68d008ebb0f001
- https://qiita.com/nacika_ins/items/cf8ceb20711bd077f770
コンテナ群の状態の確認
$ docker-compose ps
コンテナ群が正常に起動していれば次のような結果が出力されます。
Name Command State Ports ------------------------------------------------------------------------------------ rails6compose_db_1 docker-entrypoint.sh postgres Up 5432/tcp rails6compose_web_1 /bin/sh Up 0.0.0.0:3000->3000/tcp
Webコンテナへのログイン
$ docker-compose exec web bash
devel
ユーザーとしてAlpine Linuxにログインします。パスワードなしでsudo
を実行する権限が与えてあります。
Rails 開発に最低限必要と思われるパッケージ群は入っていますが、もし足りないパッケージがあれば apk
コマンドでインストールしてください。
Railsアプリケーションの開発の要点
https://github.com/oiax/rails6-compose/blob/master/RAILS.md に具体的な操作例がありますので、参考にしてください。
Rails アプリケーションの起動
ホスト OS のターミナルで、次のコマンドを実行します。
$ docker-compose exec web bash -c 'cd /apps/myapp; bin/webpack-dev-server'
さらに別のターミナルを開き、次のコマンドを実行します。
$ docker-compose exec web bash -c 'cd /apps/myapp; bin/rails s'
コンテナの停止
$ docker-compose stop
コンテナの破棄
$ docker-compose down
おわりに
私がこの記事を書こうと思ったきっかけは、2014年刊行の拙著『実践Ruby on Rails 4 現場のプロから学ぶ本格Webプログラミング』の改訂版を出したいという打診をインプレスの編集者から受けたことです。
この本ではVagrantを使って開発環境を構築しましたが、改訂版ではDockerを利用したいと考えました。原稿を書き始める前にブログ記事を書いて知識をアップデートしておこう、ということです。あわよくば読者の方からフィードバックをもらって間違いを潰しておきたい、という意図もあります。
この記事を書くにあたっては、Dockerの公式ドキュメントにある「Quickstart: Compose and Rails」(以下、「Quickstart」と呼びます)を参考にしました。
ただし、両者の間には重要な相違点があります。Quickstartでは docker-compose up
コマンドの結果、自動的にRailsアプリケーションが起動しますが、私の記事では手動で起動しなければなりません。私の手順の方が少し面倒ですが、わかりやすさを優先しました。
この記事で紹介しているのは、あくまでDockerを用いて手早くRails開発環境を構築する方法です。構築した開発環境の設定をチームで共有したり、実運用(本番)環境にRailsアプリケーションをデプロイしたりするのは、また別の話になります。
この記事についての質問は、ブログ上のコメント欄の他にメールでも受け付けます。hermes@oiax.jp までご連絡ください。
Elixir/Phoenix: Distillery を利用した tarball 作成と配備
『Elixir/Phoenix 初級④: バリデーション』のサンプルアプリ NanoPlanner を本番環境(Ubuntu 18.04 Server LTS)にセットアップして、公開する手順を紹介します。
デプロイメントツールとしてDistilleryを使用します。
前提条件
- Ubuntu 18.04 Server LTS
kuroda
ユーザー (sudo
権限あり)phoenix
ユーザー (sudo
権限あり)
Erlang と Elixir のインストール
kuroda
ユーザーで Ubuntu Server にログインして、次のコマンド群を順に実行。
$ wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb $ sudo dpkg -i erlang-solutions_1.0_all.deb $ sudo apt-get update $ sudo apt-get -y install esl-erlang $ sudo apt-get -y install elixir $ elixir --version
次のような結果が出ることを確認する(バージョン番号は異なるかもしれません)。
Erlang/OTP 22 [erts-10.4.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe] Elixir 1.8.2 (compiled with Erlang/OTP 20)
Node.js のインストール
引き続き、kuroda
ユーザーとして次のコマンド群を順に実行。
$ curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - $ sudo apt-get install nodejs
PostgreSQL のインストールとセットアップ
引き続き、kuroda
ユーザーとして次のコマンド群を順に実行。
$ sudo apt-get -y install postgresql $ sudo -u postgres createuser -d phoenix -P
パスワードの入力を求められるので、phoenix
と2回入力。
さらに次のコマンドを実行。
$ sudo -u postgres createdb --owner phoenix nano_planner_prod
Nginx のインストールと設定
kuroda
ユーザーとして次のコマンドを実行。
$ sudo apt-get -y install nginx
テキストエディタで /etc/nginx/sites-available
ディレクトリに新規ファイル nano_planner
を作成
upstream phoenix { server 127.0.0.1:4000; } server { listen 80; server_name example.com; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Cluster-Client-Ip $remote_addr; location / { proxy_pass http://phoenix; allow all; } }
ただし、example.com
の部分は、Ubuntu Server に割り当てられた実際のホスト名で置き換える。
kuroda
ユーザーとして次のコマンド群を順に実行。
$ cd /etc/nginx/sites-enabled $ sudo ln -s ../sites-available/nano_planner . $ sudo systemctl reload nginx
NanoPlanner のセットアップ
ここから先は、phoenix
ユーザーで Ubuntu Server にログインして、次のコマンド群を順に実行。
ソースコードの取得から npm run deploy
まで
$ git clone -b master4-deploy https://github.com/oiax/nano_planner.git $ cd nano_planner $ cp config/skel/prod.secret.exs config/ $ cd assets $ npm install $ npm run deploy $ cd ..
tarballの作成
$ mix deps.get --only prod $ MIX_ENV=prod mix compile $ MIX_ENV=prod mix phx.digest $ MIX_ENV=prod mix release
リリースの配備
$ mkdir -p ~/app/releases/0.1.0 $ cd _build/prod/rel/nano_planner/releases/0.1.0 $ cp nano_planner.tar.gz ~/app/releases/0.1.0 $ cd ~/app/releases/0.1.0 $ tar -xf nano_planner.tar.gz -C ~/app
データベースの初期化
$ cd ~/nano_planner $ MIX_ENV=prod mix ecto.migrate $ MIX_ENV=prod mix run priv/repo/seeds.exs
NanoPlanner の起動
$ cd ~/app $ bin/nano_planner start
4000番ポートで待ち受けるプロセスの存在を確認。
$ lsof -i:4000
次のような結果が出ることを確認する。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME beam.smp 16931 phoenix 15u IPv6 52028 0t0 TCP *:4000 (LISTEN)
以上で作業完了です。ブラウザで http://example.com
にアクセスすれば、NanoPlanner の画面が出てくるはずです。ただし、example.com
の部分は、Ubuntu Server に割り当てられた実際のホスト名で読み替えてください。
GCP/Ubuntu: Cloud SQL Proxy のセットアップ(追記あり)
先々月にGCP: 自動スケーリング時における Google Cloud SQL ホワイトリストの管理という記事を書きました。その続きです。
GCPのVMインスタンスからCloud SQLインスタンスへ接続するのにCloud SQL Proxyを使えばうまく行くんじゃないか、という考察で終わっていました。
結論から言えばその通りでした。
Ubuntu 18.04(64bit版)におけるセットアップ手順の概要は、次の通りです。
- VMインスタンスの設定で「すべての Cloud API に完全アクセス権を許可」を選ぶ。
- VMインスタンスにsshでログインして、
cloud_sql_proxy
をインストールする。 cloud_sql_proxy
のためのSystemd起動スクリプトを設置する。
これで、Cloud SQL インスタンスが PostgreSQL なら localhost:5432
で接続できるようになります。とても簡単です。
なお、GCP のドキュメントには「下位互換性のない方法で変更される可能性があり、 は、SLA または非推奨ポリシーの対象ではありません。」と書いてあります(2018年9月9日現在)。採用は自己責任でお願いします。
以下、詳しい説明です。
VMインスタンスの設定
VMインスタンスの「アクセス範囲」に関する設定を「デフォルトのアクセスを許可」から「すべての Cloud API に完全アクセス権を許可」に変更します。
cloud_sql_proxy
のインストール
VMインスタンスにsshでログインして、cloud_sql_proxy
をインストールします。
$ wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy $ sudo chown root:root cloud_sql_proxy $ sudo chmod +x cloud_sql_proxy $ sudo mv cloud_sql_proxy /usr/local/bin
起動スクリプトの設置
テキストエディタで新規ファイル /etc/systemd/system/cloud-sql-proxy.service
を以下の内容で作成します。
[Unit] Description=Cloud SQL Proxy After=network.target [Service] Type=simple ExecStart=/usr/local/bin/cloud_sql_proxy -dir=sqlproxy -instances=<ID>=tcp:5432 TimeoutSec=300 Restart=always [Install] WantedBy=multi-user.target
ただし、<ID>
の部分は Cloud SQL インスタンスの接続名で置き換えてください。GCP コンソールで Cloud SQL インスタンスの「概要」タブを見れば、「このインスタンスに接続」と書いてあるボックスの中に記載されています。具体的には
foo:asia-northeast1:bar
のような形式の文字列です。foo
がプロジェクト ID で、bar
が Cloud SQL インスタンス ID です。
なお、5432
の部分は接続に使用するポート番号です。適宜変更しても構いません。
サービスの起動
VM インスタンスのターミナルで次のコマンドを実行し、Cloud SQL Proxy サービスを起動します。
$ sudo systemctl start cloud-sql-proxy.service
サービスの状態を確認します。
$ sudo systemctl status cloud-sql-proxy.service
正常に動いていれば、次のようなログが表示されます。
Started Cloud SQL Proxy. Listening on sqlproxy/... Ready for new connections
失敗した場合、例えば次のようなログが表示されます。
Failed to start Cloud SQL Proxy.
テキストエディタで /etc/systemd/system/cloud-sql-proxy.service
を開き、インスタンスの接続名などが誤っていないかどうかを確認し、訂正してください。
次のコマンドを順に実行し、Cloud SQL Proxy サービスを起動し直します。
$ sudo systemctl daemon-reload $ sudo systemctl start cloud-sql-proxy.service
接続の確認
psql
コマンドで接続してみます。
$ psql -h localhost --port 5432 -U postgres postgres
サービスの有効化
正常にサービスが起動できるようになったら Cloud SQL Proxy サービスを有効化します。
$ sudo systemctl enable cloud-sql-proxy.service
直接 PostgreSQL に接続する場合とのパフォーマンスの違い(追記)
私の環境で実測したところ、直接 PostgreSQL に接続した場合に比べて Cloud SQL Proxy 経由で接続した場合、Rails アプリケーションのパフォーマンスが1割〜2割程度落ちる、という現象を観察しました。
ここで「パフォーマンス」は、レスポンス時間を指します。具体的に言えば、平均0.63秒が平均0.69秒になりました。いろいろと条件を変えて負荷試験を繰り返しましたが、レスポンス時間が1割〜2割増加するという事実は変化しませんでした。
Cloud SQL Proxy は設定を楽にしてくれますが、2018年9月の段階では、多少のデメリットもあるようです。
GCP: 自動スケーリング時における Google Cloud SQL ホワイトリストの管理
次のような条件でRuby on Railsアプリケーションを運用することにした。
- プラットフォームは Google Cloud Platform (GCP)。
- 負荷状況により自動スケーリング(auto scaling)を行うためマネージドインスタンスグループを利用。
- データベースは Google Cloud SQL 上の PostgreSQL インスタンスを利用。
セットアップの過程で少し困ったのが、PostgreSQL インスタンスに接続できるIPアドレスのリスト(ホワイトリスト)をどう管理するか、という点である。
なぜ困るか。次の3点に集約される。
- マネージドインスタンスグループに属する VM インスタンスと PostgreSQL インスタンスは別のネットワークにある。
- 自動スケーリングによって起動される VM インスタンスの IP アドレスは事前にわからない。
- 自動スケーリングによって起動された VM インスタンスに割り当てられた IP アドレスは、インスタンス停止後に他のインスタンスにより再利用される。
アプリケーションサーバーと同じネットワーク内に PostgreSQL サーバーを自前で立てて動かす場合、そのネットワーク(例えば、192.168.0.0/24
)を pg_hba.conf
に記載してやればいいのだが、その方法は使えない。
VM インスタンスの起動時にその IP アドレスをホワイトリストに登録し、停止時に抹消する必要がある。
この状況を打開する方法はふたつある。ひとつは、VM gcloud
コマンドで VM インスタンスの起動時にその IP アドレスをホワイトリストに登録し、停止時に抹消するという方法、もうひとつは、Cloud SQL Proxyを利用する方法である。
今回は、前者の方法について解説しよう。
前提条件
対象となる GCP プロジェクトに関して、以下の準備作業を済ませる。
- GCP コンソールの[APIとサービス]→[ライブラリ]から「Cloud SQL Admin API」が有効化してある。
- 「Cloud SQL Admin」権限を持つ GCP のサービスアカウントを作成してある。
- サーバー OS は Ubuntu 18.04
- Ruby 2.4 以上がインストール済み
- 上記サービスアカウントの資格情報(JSONデータ)を
/root/gcp_sa_credentials.json
に保存してある。
VM インスタンスの起動・停止時に実行する Ruby スクリプトの作成
/root/bin/
ディレクトリに次のような内容のファイル vm-instance-startup.rb
を作成する。ただし、5 行目の pg-instance-0
の部分は、自分の Google Cloud SQL インスタンスの名前(id)で置き換えること。
#!/usr/bin/env ruby require "json" SQL_INSTANCE_ID = "pg-instalnce-0" GCLOUD_COMMAND = "/snap/bin/gcloud sql instances" KEY_FILE_PATH = "/root/gcp_sa_credentials.json" system("/snap/bin/gcloud auth activate-service-account --key-file=#{KEY_FILE_PATH}") api_url = "http://metadata.google.internal/computeMetadata/v1" + "/instance/network-interfaces/0/access-configs/0/external-ip" external_ip = `/usr/bin/curl -s #{api_url} -H "Metadata-Flavor: Google"` sql_instance_description = `#{GCLOUD_COMMAND} describe #{SQL_INSTANCE_ID} --format=json` description_hash = JSON.parse(sql_instance_description) networks = description_hash["settings"]["ipConfiguration"]["authorizedNetworks"].map do |e| e["value"] end unless networks.include?(external_ip) networks << external_ip joined = networks.join(",") system("#{GCLOUD_COMMAND} patch #{SQL_INSTANCE_ID} --quiet --authorized-networks=#{joined}") end
また、同じディレクトリに次のような内容のファイル vm-instance-shutdown.rb
を作成する。
#!/usr/bin/env ruby require "json" SQL_INSTANCE_ID = "pg-00" GCLOUD_COMMAND = "/snap/bin/gcloud sql instances" KEY_FILE_PATH = "/root/gcp_sa_credentials.json" system("/snap/bin/gcloud auth activate-service-account --key-file=#{KEY_FILE_PATH}") api_url = "http://metadata.google.internal/computeMetadata/v1" + "/instance/network-interfaces/0/access-configs/0/external-ip" external_ip = `/usr/bin/curl -s #{api_url} -H "Metadata-Flavor: Google"` sql_instance_description = `#{GCLOUD_COMMAND} describe #{SQL_INSTANCE_ID} --format=json` description_hash = JSON.parse(sql_instance_description) networks = description_hash["settings"]["ipConfiguration"]["authorizedNetworks"].map do |e| e["value"] end if networks.include?(external_ip) networks.delete(external_ip) joined = networks.join(",") system("#{GCLOUD_COMMAND} patch #{SQL_INSTANCE_ID} --quiet --authorized-networks=#{joined}") end
ふたつの Ruby スクリプトの内容はほぼ同じである。末尾の6行だけが異なっている。
そして、これらの Ruby ファイルの実行可能フラグを立てておく。
$ chmod u+x /root/bin/*.rb
Systemdの設定ファイルを作成
ディレクトリ /etc/systemd/system/
に whitelist-registry.service
という名前のファイルを次のような内容で作成する(名前は何でもよい)。ただし、このファイルには実行可能フラグを立てないこと。
[Unit] Description=Google Cloud SQL Whitelist Registry [Service] Type=oneshot ExecStart=/root/bin/vm-instance-startup.rb ExecStop=/root/bin/vm-instance-shutdown.rb RemainAfterExit=yes [Install] WantedBy=multi-user.target
そして、このサービスを有効化する。
$ sudo systemctl enable whitelist-registry.service
動作確認
サービスの起動を試す。
$ sudo systemctl start whitelist-registry.service
GCP コンソールで Cloud SQL インスタンスの「承認」タブで、この VM インスタンスの IP アドレスが「承認済みネットワーク」に加わっていれば OK である。
サービスの停止を試す。
$ sudo systemctl stop whitelist-registry.service
GCP コンソールで Cloud SQL インスタンスの「承認」タブで、この VM インスタンスの IP アドレスが「承認済みネットワーク」から消えていれば OK である。
最後に VM インスタンス自体を再起動したり、停止したりして、動作確認する。
考察
今回解説した方法の懸念点は、Systemd の停止スクリプトが実行されないまま VM インスタンスが異常終了したときに、その IP アドレスがホワイトリストに残ってしまう、ということである。データベース自体にパスワードが設定されていればそれほど危険ではないものの、気持ち悪さは残る。
Cloud SQL Proxy を使えばこの懸念は解消されるだろうが、正直に言えば、私自身がまだ試せていない。近いうちにレポートを書きたいと思う。