激重ALTER TABLEをpt-online-schema-changeを使ってサービスを止めずに実行するための方法
対象環境
- Aurora MySQL
- pt-online-schema-change 3.2.0
なにも考えずにALTER TABLEを実行するとどうなるか?
既に動いているDBのカラム操作、インデックス操作などをするALTER TABLEクエリを実行すると、書き込みLockが発生してinsertやupdateができなくなります。対象テーブルのレコード数が相当に多い場合、書き込みをしようとしたプロセスは延々と待たされ続けることになるので、実質的にサービスを止めることになり得ます。
本番DBをコピーしたテスト用DBでやろうとしていたDROP INDEXをテストで走らせてみたのですが、ゆうに2時間はかかってしまいその間ずっと書き込みLockがかかり恐怖しました。
サービスを止めずにALTER TABLEを実行する方法
- MySQL 5.6から導入されたオンラインDDLを使用する
- pt-online-schema-changeなどのオンラインスキーマ変更ツールを使用する
- 自分でオンラインスキーマ変更ツールと同じ手順でSQLを実行する
今回は2つ目のpt-online-schema-change
を使った手法についてまとめます。
pt-online-schema-changeとは?
pt-online-schema-changeコマンドの詳細ドキュメント
RDBの機能だけではオンラインに定義変更ができない場合には、新規テーブル作成 -> データ移行 -> テーブル名を変更して入れ替え -> 旧テーブル削除 と言ったような方法(簡略版)でオンラインに定義変更をします。これをツール上でいい感じにやってくれるツールがpt-online-schema-change
です。
インストール方法
$ sudo yum install http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm $ sudo yum install percona-release percona-toolkit $ pt-online-schema-change --version pt-online-schema-change 3.2.0
使い方
Usage: pt-online-schema-change [OPTIONS] DSN Detail Usage: pt-online-schema-change --execute --recursion-method processlist --alter "DROP INDEX idx_user_ids" h=localhost,D=testdb,t=users
- DSN(Data Source Name): 対象のデータベースを指定するための識別名
使うための要求
PROCESS, SUPER, REPLICATION SLAVE global privileges, as well as SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, and TRIGGER table privileges should be granted on server.
PROCESS、SUPER、REPLICATION SLAVEのグローバル権限、およびSELECT、INSERT、UPDATE、DELETE、CREATE、DROP、ALTER、TRIGGERテーブル権限をサーバーに付与する必要があります。
その中でも今回重要なのはPROCESS権限、SUPER権限、REPLICATION SLAVE権限の3つです。 まずPROCESS権限は必須なので付けましょう。
次にSUPER権限ですが、どうしても付けたくない場合やAmazonRDSの場合はグローバルのSUPER権限を付けることができないため別の解決策を取る必要があり、log_bin_trust_function_creators
を1に設定することによって代わりとすることができます。
mysqlコンソールから設定する場合はSET GLOBAL log_bin_trust_function_creators = 1;
を実行してください。
AmazonRDSの場合はこちらを参考にしてAWS Consoleから設定してください。
そしてREPLICATION SLAVE権限は--recursion-method
オプションを適切に指定することで権限を必要としなくなります。
--recursion-method
オプションはデフォルトでprocesslist,hosts
が設定されていますが、--recursion-method processlist
とすることで権限が必要なくなります。
ユーザー、パスワードの指定
オプションに--user
や--password
が存在しますが、コンソールにパスワードを表示したくないので設定ファイルを使って設定します。
/etc/percona-toolkit/pt-online-schema-change.conf
に以下のように記述しましょう。
user=実行ユーザー名 password=実行ユーザーのパスワード
これでコマンド実行時、自動的にこのファイルからユーザー情報を読み取ってくれます。
DSNの構文
DSNは対象のDBやテーブルを指定するものです。 KeyValueで指定でき、以下のような対応付けになっています。
KEY COPY MEANING === ==== ============================================= A yes Default character set D no Database for the old and new table F yes Only read default options from the given file P no Port number to use for connection S yes Socket file to use for connection h yes Connect to host p yes Password to use when connecting t no Table to alter u yes User for login if not current user
この中でもh
、D
、t
あたりをよく使うと思います。
h
はホストでlocalhost
や~.rds.amazonaws.com
などを指定します。
次にD
はデータベース名でMySQL内でshow database;
した結果の中から指定できます。
最後にt
はテーブル名でusers
と言ったようなものを指定します。
そしてDSNを指定する時に気を付けないといけないのは、複数のKeyValueを指定する時スペースを空けてはいけないということです。
なのでh=localhost,D=testdb,t=users
と指定します。
実行
全部整えた後にコマンドを実行すると処理が始まり、処理の様子が随時モニタリングされます。
Altering `testdb`.`users`... Creating new table... Created new table testdb._users_new OK. Altering new table... Altered `testdb`.`_users_new` OK. 2020-05-29T14:33:16 Creating triggers... 2020-05-29T14:33:16 Created triggers OK. 2020-05-29T14:33:16 Copying approximately 100000000 rows... Copying `testdb`.`users`: 0% remain
テーブルコピーがどの程度進んでいるか%で表示してくれるというだけでもそれなりに助かりますね。 後は待っていればテーブルがLockされることもなくオンラインに定義変更をこなしてくれます。
もしのための策
クローン環境でテストする
本番DBと可能な限り近い環境で、かつDBが壊れても問題ないところで必ず検証しておきましょう。 そして起こりうる問題と影響、実行時間などを詳細にまとめチーム内で見えるようにしておくことが大事です。
バックアップ
実行するコマンドや手順、問題、影響などをまとめ、いざ実行するという直前にDBのバックアップを作成しておきましょう。 RDSで言うならスナップショットを作成します。
念のため対象テーブルに比較的影響の少ない時間に実施する
オンラインで実行しますし、実行時間のほとんどはテーブルのコピーなので、実行中に問題が起きることはほとんどないはずです。そして実行中に行われるWrite処理(INSERT, UPDATE, DELETE)にはトリガーが設置されているので、もれなく新テーブルに反映されます。 pt-online-schema-changeは枯れた技術なので大体の場合は問題ありません。
途中で実行停止してしまった場合
コマンドを実行すると最初に新テーブルの作成、トリガーの作成が行われます。 そして次にテーブルコピーが始まり、実行時間のほぼ全てはずっとコピーをしています。 全てのコピーが終わった後、トリガーの削除や新旧テーブルの名前変更が行われます。
最初のテーブル作成やトリガー作成、テーブルコピー中に失敗したときに大きな問題はありません。中途半端なテーブルやトリガーが消えていない場合もありますが、手動で消してやれば綺麗な状態からやり直すことができます。
DROP TRIGGER IF EXISTS `{database名}`.`pt_osc_{database名}_{テーブル名}_del`; DROP TRIGGER IF EXISTS `{database名}`.`pt_osc_{database名}_{テーブル名}_upd`; DROP TRIGGER IF EXISTS `{database名}`.`pt_osc_{database名}_{テーブル名}_ins`; DROP TABLE IF EXISTS `{database名}`.`_{テーブル名}_new`;
最後のテーブル入れ替え時に落ちてしまった場合はどうなるか具体的にはわかりません。しかし、大体はテーブル入れ替えができずにそのままか、トリガーが削除されていないか、くらいだと思うので上の対処で問題ありません。 もしくはテーブルが消えていなければそのまま手作業で入れ替えるのもいいでしょう。
それでも何か致命的に壊れてしまった場合はスナップショットからいい感じに復旧しましょう。
ここ2ヶ月で実施したリモート輪読会の手法やtipsについてのまとめ
今の時期、基本的にリモート以外でイベントを開催するのが難しい状況です。 逆にその状況を逆手にとってみんなでリモート輪読会をやりましょう!
私はここ2ヶ月程度で3グループ3冊分のリモート輪読会を実施しました。 それぞれの輪読会によって複数の方法を試してみたのでそれについてまとめていきたいと思います。
リモート輪読会とは?
GoogleMeetやDiscord、Skypeと言った音声通話ができるサービスを通じ、リモート環境で複数人が同じ本を読み合わせたり、内容について議論したりして、本の内容について理解を深めるための手法です。
手法
現段階で大きく分けて3種類の手法を実施しました。
グループのレベルよりも本の内容が難しい場合の方法
- 所要時間: 長め(数時間)
- 全員の理解: 高め
- 事前読み: 簡単に
リモートだと全員の理解がちゃんと取れているか確認するのが難しいので、出来る限り全員参加形にした方が理解度が向上します。 その会で何章やるか決めて、各章内の各題目のさらに細かい題目があるならその単位がおすすめで、単位ごとに内容をまとめて発表します。 1回の輪読会では1〜3章分くらいをお勧めします。
この方法だと事前読みで内容の理解が浅くても、輪読会をやりながら理解を深めたり、周りにヘルプをもらいながら進めるので初心者や本が難しい場合に使える手法だと思います。
本の内容をGoogleDocsにコピーしてコメントを書き込む方法
- 所用時間: 短め(~1時間)
- 全員の理解: 場合により浅め
- 事前読み: しっかりと
グループメンバーが積極的でかつ本の内容に対してある程度の練度がみられる場合の方法です。 本の内容をGoogleDocsで共有し、輪読会が始まる前にみんなでコメントを書いておく形です。
輪読会が始まったらDocsに書かれたコメントを辿り、コメントを書いた人がそのコメントの意図や追加情報を話します。 それに対してみんなで、これはどうだ? あれはこうじゃないか? などと議論を深めていきます。
本の疑問点や気づきを共有して話し合う方法
- 所用時間: 短め(~1時間)
- 全員の理解: 場合により浅め
- 事前読み: しっかりと
本の内容をコピーできない場合やコメントの数が多くなり過ぎてしまう場合などにオススメな方法です。 事前にドキュメントをどこかに用意して、各章内の各題目を書き起こし、それぞれに気づきと質問をまとめておく形式です。
輪読会が始まったらドキュメントの気づきや質問を共有しながら話し合います。 基本的には一つ前の方法と同じですが、記述形式が自由であったり、ツールや書式を自由に選択できるのも利点になります。 検討したツールとしては以下のものがあります。
- マークダウンを共有しつつ同時編集できるサービス
- VSCodeの共同編集モード(データはGitHubで管理)
- GoogleDocs
この手法で実施した輪読会の記事も書いているのでこちらに貼っておきます。 nakka-k.hatenablog.com
まとめ
今回はリモートならではの進め方を考えて色々実施してみました。 まだ3グループでしか実施したことがないので、いまだに手探り状態です。 もっと良い方法やアドバイスがあると思うのでコメント下さい!!
価格:18,562円 |
リモートワーク時にビデオ画面とメモ画面の両立が難しい時の解決法(Mac)
今の時期、みなさんリモートワークしている方が多いですよね。 その中でビデオ画面(以下ビデオツール)を最大化して画面共有したりカメラにホワイトボードを映したりしている時にメモを取るのは難しいです。 メモを取るときはウィンドウを切り替える必要があって画面から目を離さないといけないなどの問題があるからです。
今回の解決法
フルスクリーンのビデオツールを見ながらメモを取れるようにします。 なんのツールを使うかと言いますと、iTerm2です!
iTerm2はこのようにフルスクリーンの上に重ねて表示することができます。 そしてHotKeyというものを設定すれば、設定したキーを押すだけでどの画面にいてもiTermの画面を開いたり閉じたりできます。
iTerm2のインストール方法
iTerm2 - macOS Terminal Replacementからダウンロードしてインストールしてください。
設定
Native full screen windowsを無効にする
iTerm2 > Preferences > General > Window > Native full screen windows
のチェックを外します。
新しいウィンドウの設定をフルスクリーンにする
iTerm2 > Preferences > Profiles > Window > Settings for New Windows > Style, Screen, Space
を設定します。
HotKeyを設定する
iTerm2 > Preferences > Keys > HotKey > Show/hide iTerm2 with a system-wide hotkey
にチェック。- HotKeyの横をクリックした後に任意のキーを押して設定する。
半透明にする
iTerm2 > Preferences > Profiles > Window > Window Appearance > Transparancy
のバーを調整して好きな透明度にする。
フルスクリーンの上に重ねて表示できるようにする
iTerm2 > Profiles > Keys > Configure HotKey Window > Floating Keyboard, Show this HotKey Window if no other window is open
をチェック、選択する。
まとめ
以上の設定をすることで完璧なiTerm環境が完成します。
iTerm上でメモを書く際のテキストエディタについては省略しますが、一般的に使えるものとしてはnanoを使うと良いかもしれません。
参考資料
リモート輪読会で 「オブジェクト指向設計実践ガイド」を読んだ時のやり方と感想
このコロナの影響もあったのですが、もともと遠隔でやる予定だったのでZoomを使ってリモート輪読会を実施しました。 今回読んだ本は以下の「オブジェクト指向設計実践ガイド」です。
ですが実はもう1人のメンバーが読んでいたのは最新の原書で、Rubyのバージョンが新しくなっていたり、多少文言が変わっていたりしましたが特に問題はありませんでした。
オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
- 作者:Sandi Metz
- 発売日: 2016/09/02
- メディア: Kindle版
Practical Object-Oriented Design: An Agile Primer Using Ruby (2nd Edition)
- 作者:Metz, Sandi
- 発売日: 2018/09/01
- メディア: ペーパーバック
本の内容
1章 オブジェクト指向設計
設計とは?どう使う?と言う話で、変更用意性を保って今のコストと未来のコストを以下に天秤にかけるかについて書いていました。
2章 単一責任のクラスを設計する
ここでは自転車を参考にしてサンプルコードを記述しています。 オブジェクト思考ソフトウェアの第一歩が単一責任であることを説明し、変更可能でメンテナンス性の高いソフトウェアを作るための考え方が散りばめられている。
3章 依存性を管理する
全章のコードを依存関係に着目して改善しています。 依存性の方向や注入に関して書かれています。
4章 柔軟なインターフェース をつくる
言語的なインターフェース ではなく、概念としてインターフェース とは何であるかを説明しています。 自転車のサンプルコードに追加して旅行を絡めて、変更用意性の悪化やデメテルの法則について理解することができます。
5章 ダックタイピングでコストを削減する
この辺りから動的型付け言語でオプジェクト指向を実践するための話が多くで始めます。 そしてダックタイプを適応できる場所を見つけるためのtipsが書かれています。
6章 継承によって振る舞いを獲得する
継承とは暗黙的な権限の移譲であることが述べられ、継承を適応する時の抽象化の方法がかなり詳しく書かれています。 特にオブジェクト指向に慣れていない間はアンチパターン的な継承をやりがちなのですが、この章を読めば是正することができると思います。
7章 モジュールでロールの振る舞いを共有する
継承だけではなくロール(役割)としてモジュールを設計し、クラスに適応する方法が書かれています。 ここに関しては特にRubyの色が強くなっているのですが、基本的な設計のパターンについても多く書かれており読んでおいた方が良い章になっています。
8章 コンポジションでオブジェクトを組み合わせる
これまでのサンプルコードの集大成として最後の設計を適応しています。 クラスなどに抽出する設計が過剰である場合などの方法が書かれている章になります。
9章 費用対効果の高いテストを設計する
良いテストとは何か?いつテストするのか?どうテストするのか?について事細かに書いた章です。 正直、テストを勉強するためにこの章だけでも読ませる価値があるかもしれません。 動的型付け言語でクラスの依存関係をテストする方法とはこうだったのか!?と改めて驚かされました。
輪読会の進め方
本の内容をGoogleDocsで共有し、輪読会が始まる前にみんなでコメントを書いておく形で実施しました。
輪読会が始まったらDocsに書かれたコメントを辿り、コメントを書いた人がそのコメントの意図や追加情報を話します。 それに対してみんなで、これはどうだ? あれはこうじゃないか? などと議論を深めていきます。
1回ごとの輪読会で何章進めるかはメンバーの人数やレベル感に合わせて簡単に調節できるので結構やりやすかった印象があります。
実施しての感想
対話式で実施していくので内容について深く理解できますし、さらっと流していた部分を他の人が突っ込んでくれたりするので思いもしなかった知識を得ることができます。
この本では毎週1章ずつ進めていたので、一回30分~1時間くらいで終わるので全く負担はありませんでした。 毎週1章読むだけなので先が気になって本を読む意欲が湧くのですが、あえて先まで読まずにその意欲を別の本を読むことに使っていました。 すると全体を通して本を読む数が軒並み上がりますし、輪読会があるためしっかりと読まないといけなくて強制的にモチベーションを高めることもできました。
私は今、複数の輪読会グループに参加していますが然程時間的影響はなく、今までよりも理解水準が上がったなというメリットだけを感じています。
リモートワークが普及してきた今の時期に合わせてリモート輪読会も普及させてtipsを共有して欲しいところですね。
電動昇降デスクでスタンディング環境とシッティング環境を両立させる健康のための夢の作業環境を作った話
最近引越しをする機会があったので、そのついでに健康に配慮した作業環境を作りました。 これからの時期引っ越す人も多いと思うので、この機会に少しでも健康に配慮した作業環境を作ってみてはいかがでしょうか?
基本的には以下の記事を参考にしましたが、DIYではなく全て既製品で済ませたかったのと健康に配慮した+αが欲しかったので少しカスタマイズしました。 izm-11.hatenablog.com
作業環境の概要
電動昇降デスク
まず、座りっぱなし、立ちっぱなしの両極端ではなく、数時間ごとで交互に簡単に切り替えられる環境を作りたかったので電動昇降デスクを選びました。
その中でもボタン一つで環境を切り替えられ3箇所の位置を記憶してくれる機能がついているものです。 特に天板は20kgほどの重量だったりするため、手動で昇降させるタイプのものはキツイですし、頻繁に環境を切り替えるのは難しいです。 位置記憶機能で一番気をつける必要があるのは、ものによってボタンを押し続けないと記憶した位置で止まってくれる簡略タイプの物があることです。
昇降音に関しては深夜でもあまり気にならない程度なので心配はありません。
個人的に使う時の高さなどを書いておきますので、参考になればと思います。 私の身長が175cmで、机の高さ65cmでPC作業、75cmで書き作業、110cmでスタンディング作業という形にしています。 机の高さは最大128cmなのでもっと身長が高い人でも問題ないと思います。
天板
天板は既製品の中でそれなりに大きいもの、そして何よりウォールナット材の物が欲しかったので140*70cmのウォールナット天板を選びました。 140cmだと24インチモニターをまっすぐ配置すると2.5枚分入るくらいの大きさです。
厚さは2.5cm、材質はウォールナット、表面にメラミン樹脂が見た目を損ねない程度に薄く塗られています。 後から穴を開けたりもできますし、材質が材質だけに耐久性も期待できます。
デスクトップPCホルダー
デスクの昇降に合わせてPCを追従させるためにデスクの下につるす用のホルダーも購入しました。
実はこれだけ注意が必要で、上に書いた天板に設置する場合は穴あけが必要になります。 私は友人にインパクトドライバーを借りて穴を開けましたが、割と簡単に開けられるのでキリとかでも大丈夫だと思います。
椅子
どうしても腰を痛めたくなかったので、先行投資として高めのオフィスチェアを買いました。 今回選んだのはオカムラのBaronチェアですが、以前使っていた2万円程度の椅子とは腰の楽さが全く違います。
椅子を選ぶときは絶対実際に座って確かめた方がいいので、近くの家具屋さんなどに行って見るのがいいと思います。 私の場合はオフィスチェア専門店に行ってコンシェルジュの方にアドバイスをもらいながら、一番自分に合った椅子を選びました。
私が買ったのは以下のオプションですが、人によって合う合わないが180度変わるので試してから買うのをお勧めします。
Baron グラデーションメッシュ / エクストラハイバック / 可動ヘッドレスト / ボディカラー:ホワイト / アジャストアーム / シルバーフレーム / 座面:メッシュ
- Baronは比較的座面が固めでメッシュの方が少し柔らかい印象です。ですが体重が軽い女性などにはクッションタイプの方がお勧めだったりするそうです。
- 腰のサポートがもっと強い方がいい場合はサポートがオプションでつけられます。
- ヘッドレストは幅が広いメッシュのため、柔軟性がありつつも受け止めてくれる感の強いものになっています。
- 椅子の後傾具合は自由に調整でき、カッチリ位置を止めるモードと後ろまで緩やかにリクライニングするモードを切り替えられます。
その他健康器具
家で簡単にでき、場所をあまり取らないおすすめの物を紹介します。
- 肩や足腰の健康、普段の荷物持ちに役立つトレーニングができる可変式ダンベル
- 弛んだ二の腕やお腹をシェイプアップさせるトレーニングができるアブローラー
- スタンディング環境で歩きながら作業することで脳の働きを活性化させることができるステッパー
可変ダンベル
ダンベルはかなり万能なトレーニング器具で肩、足腰、腕、様々なトレーニングができます。 肩を鍛えれば肩こりが解消しますし、足腰を鍛えればむくみや将来立てなくなると言った危機を回避できますし、腕を鍛えればMacBookPro16インチを持ち歩いても全く重くならないんです。
可変じゃないダンベルを買うと死ぬほど面倒くさいので、可変ダンベルを買うか、さもなくば家にあるペットボトルで妥協してください。 物足りなくなったら可変ダンベルを買いましょう。
よく重量を変える人は少し高いですが、ワンアクションで重量を変えられるタイプのものがおすすめです。
たまにしか変えないなら少々手間ですが安いので、私が使っているものを貼っておきます。
アブローラー
アブローラーでは主にお腹、そして腕の後ろ側、場合によっては足や背中も鍛えられたりします。 普段座っていることが多いためお腹が出たり、二の腕がたゆんたゆんになったりしている人が多いですよね。 この器具だと負荷を変えやすいので長期間使っていくことが可能ですし、他の器具より安いので手が出しやすいです。
【Amazon限定ブランド】ボディテック(Bodytech) 腹筋ローラー 膝保護マット付き 耐荷重200kg 超静音 ダブルローラー エクササイズ アブホイール BTS91NH001
- 発売日: 2019/06/15
- メディア: スポーツ用品
ステッパー
海外ではスタンディングかつステッパーや回し車で歩きながら作業をする会社が増えているそうです。 やはり立ちながら、そして歩きながらの方が頭の働きが格段に良いので自ずとそうなるのでしょう。
ステッパーに関してはまだ購入していないのでAmazonランキングが高い物を貼っておきます。
まとめ
- 6万くらいで電動昇降デスクは揃う
- 身体には気をつけよう
- 筋トレは良いぞ!
1~2時間おきに立てったり、座ったりと体勢を変えながら作業をし、そして休憩がてら筋トレを挟むことによって普段の健康にも気を使うことができますしリフレッシュもできます。 筋トレによる健康化や脳の働き向上、精神の安定など様々な効果が確認されているので、作業環境を整えるのと同時に初めてみてはいかがでしょうか?
途中から筋トレの啓蒙活動になっていた気もしますが、結局作業や健康に繋がる部分なので紹介させていただきました。
Elastic BeanstalkのMultiContainer環境にRails+Nuxtをデプロイする
Elastic BeanstalkでMultiContainer環境を構築し、RailsとNuxt.jsをデプロイします。
今回の環境
- ElasticBeanstalk(Multi-container Docker)
- Rails 5.2 (ruby:2.6)
- Nuxt.js 2.11 (node:12-alpine)
- PostgreSQL (RDS)
目次
初期設定
AWSのアカウント登録
アカウント登録については以下の記事を参考にしてください。
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/iam-servicerole.html
ElasticBeanstalkの環境を作成する
AWSマネジメントコンソールからElasticBeanstalkを検索し開く。
最初に新しいアプリケーションを作成する必要があります。 「アプリケーション名」はそれぞれのElasticBeanstalk環境をグルーピングするためのグループです。 特にこだわりがないならアプリケーション名だけ適当に入力して「作成」します。
次に右上のアクションから「環境の作成」をクリックする。
ウェブサーバー環境を選択したまま「選択」をクリック。
アプリケーションの情報を決めて設定していきます。 プラットフォームをMulti-container Dockerに設定します。
DBやインスタンスなど、追加の設定をしたい場合「より多くのオプションの設定」をクリックします。 この中で重要な点をいくつか紹介します。
ソフトウェア
では環境変数を設定できます。容量
ではEC2のインスタンスタイプを変更できます。データベース
ではその名の通りどのDBを使用するか設定できます。- 設定のプリセットをカスタムにすると
ロードバランサー
を設定できます。HTTPSの設定やポートの設定もこちらです。(環境作成時に設定しないとその後、EBから設定できないので気をつけましょう)
環境変数系の用意
ソフトウェア
をクリックして環境変数を設定しましょう。
デプロイ環境では以下の環境変数を個別に指定する必要があります。
NODE_ENV
=production
RAILS_ENV
=production
RAILS_MASTER_KEY
= (これはbackend/config/master.keyの値)
データベースを設定する
今回のプロジェクトではデータベースをPostgreSQLに設定します。
データーベース
の項目をクリックして、データベースの変更とユーザー名・パスワードの設定をしましょう。
ロードバランサー の設定
まずApplication Load Balancer
に必要なポートを列挙します。
それぞれにHTTP、HTTPSのどちらにするのか設定し、HTTPSにする場合はACM(AWS Certificate Manager)で発行した証明書を設定する必要があります。(既存の証明書をインポートすることもできます)
以下の写真では全てHTTPになっていますが、私の環境の場合80番以外HTTPSに設定します。
環境を作成する
設定が終わったら「環境の作成」ボタンをクリックして確定しましょう。
すると環境の作成を始め、初期設定のままならサンプルアプリケーションがデプロイされることになります。 環境の作成には5分~10分くらいかかるので気長に待ちましょう。
アプリケーションを確認する
構築が完了するとアプリケーションを管理する画面に遷移します。 画面上部にあるURLを開くとサンプルアプリケーションに接続できます。
このような画面が見えるかと思います。
本番アプリケーションをデプロイする
ここからはサンプルアプリケーションではなく実際のアプリケーションをデプロイしていきます。 私がデプロイ時に困ったことや気をつけた方がいいなと思った細かい事象はこの章の最後に一覧化しておきますので参考にしてください。
まず今回ElasticBeanstalkの設定をするに当たって必要なファイルは以下の通りです。 順番に設定していきましょう。
- Dockerrun.aws,json
- .ebextentions/
- elb-listener.config
- elb-secure.config
- .elasticbeanstalk/
- config.yml
Dockerrun.aws.json
全体の説明は複数コンテナの Docker 設定を参照してください。
docker-compose.ymlとDockerrun.aws.jsonはある程度互換性があります。
docker-compose.yml | Dockerrun.aws.json |
---|---|
services以下のサービス名 | name |
image | image |
hostname | hostname |
該当なし | memory |
ports | portMappings |
volumes | volumes+mountPoints |
depends_on | links |
environment | environment |
command | command |
まず3行目のvolumes
でホスト側のどのソースをマウントしたいのか設定します。
name
は任意の識別子なので自分でわかるものを指定してください。
host
にはどのパスをマウントするのか設定します。
そしてここで設定したname
をcontainerDefinitions
にあるmountPoints
で使用します。sourceVolume
に対して先ほど設定した任意の識別子を記述し、containerPath
にマウント先のコンテナ内のパスを設定します。
次にenvironment
についてです。
containerDefinitions
配列内のオブジェクトがそれぞれ1つのコンテナになっています。あるコンテナに書いたenvironment
はそのコンテナ内でしか展開されないようになっていますので気をつけてください。
そしてこのDockerrun.aws.jsonは基本的にGit管理下に含めるため、重要なキーなどを絶対に含めないように気をつけてください。秘密にしなければいけない環境変数はAWSコンソールから環境プロパティに設定しましょう。
最後にmemory
に関してです。
これに関しては具体的にどうと言えるわけではありませんが、t2.microのメモリ1GiBを超えないように気を付けることだけは徹底しましょう。
合計で1GiBよりも小さく設定している理由としては、限界まで設定すると逆にパフォーマンスが悪くなる可能性、そしてインスタンスにsshをした時にコマンドを走らせる猶予を考慮してのことです。
感覚的な話ですがmemory
を256に設定した時はメモリが足りずに動かなくなってしまっていた状況が見られたので低すぎるのは厳禁です。
.ebextentions/elb-listener.configと.ebextentions/elb-secure.config
APIコンテナに接続するために8080番の設定を別途します。 他には基本HTTPS通信にする予定なので443ポートの設定も書いておきましょう。
SSLCertificateArns
はACMで取得した証明書のIDに書き換えておきましょう。
重要な値なので.ebextentions/elb-secure.config
は.gitignoreでGit管理下から外しておきましょう。
- https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-environmentprocess-process
- https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/environments-cfg-alb.html#environments-cfg-alb-namespaces
.elasticbeanstalk/config.yml
このファイルはコマンドを使用して生成します。
以下の記事を見ながらawsebcli
をインストールしてください。
インストール後、デプロイしたいプロジェクトのルートディレクトリでeb init
を実行して対話的に設定してください。
コマンドの実行が完了するとファイルが生成されていますので完了です。
デプロイする
Dockerrun.aws.jsonのあるプロジェクトルートからeb deploy
コマンドを実行しましょう。
git archive
コマンドが実行されZIP化されたソースコードがS3にアップロードされます。その後S3からECSを通してDockerコンテナの立ち上げなどが行われます。
Dockerコンテナの起動にはDockerrun.aws.jsonが参照されて、設定通りに起動されます。
このコマンドには1分程度かかり、その後反映まで少し時間がかかります。 デプロイが完了したら、AWSコンソールでヘルスチェックがグリーンになっていることも確認できます。
(補足)デプロイ時に気を付けること一覧
順不同なのでざっと見て必要なところだけ確認してください。
私も詰まった部分が多すぎて全てを詳細に書ききれません。 内容についてコメントで聞いていただければ、答えられる部分に関しては答えたいと思っています。
EC2やDocker
- Multi-container Dockerの場合、デプロイ時にDockerfileからコンテナを作成することができません。構築済みのコンテナをDockerHubやECRにアップロードしておく必要があります。
Multicontainer Docker configuration - Container definition format - 初期のEC2インスタンスはt2.microでメモリが1GiBに設定されています。これから作成する
Dockerrun.aws.json
にメモリ設定する時上限を超えないように気をつけてください。
インスタンスタイプ - Amazon EC2 | AWS - デプロイ時Dockerコンテナ起動後にその中に入って処理をしたい場合は別途スクリプトを書く必要があります。
【AWS】Elastic Beanstalkのデプロイ時に docker exec する - Qiita - ElasticBeanstalkのソフトウェア->環境プロパティから設定した値は全てのコンテナ内で共有されます。
- t2.microインスタンスでは
nuxt build
やnode-sass
などの処理が重く耐えきれない場合があります。インスタンスタイプを上げるか、ビルドはインスタンス外でやってしまうことをお勧めします。
Nuxt
- node:alpine環境でインストールするパッケージに
node-gyp
が含まれている場合、別途python
,make
,g++
をインストールする必要があります。 - node_modulesのディレクトリをマウントしている場合、npm installしたのにパッケージが消えてしまう場合があるので気を付ける必要があります。(空のnode_modulesで上書きされてしまうため)
node_modules/ and Docker volume mount 問題と対策 - castaneaiのブログ - NuxtでSSRをする場合、
API_URL
とAPI_URL_BROWSER
の違いを正確に理解して設定する必要があります。
DockerとNuxtのSSRでConnectionRefusedが発生する問題の原因を解説する - NAKKA-Kの技術ブログ Cannot find module
が出るからといってnpx
を使うと一時的なインストールでしかないのでその後で詰まります。
npxでnodeモジュールを実行する - Qiita- nuxt2.9未満で
eslint-module
を使用している場合、nuxt.config.jsのbuildModules
にeslint-module
を設定することができません。 GitHub - nuxt-community/eslint-module: ESLint module for Nuxt.js - nuxt.config.jsの中で
process.env
を使用している場合、nuxt build
する時点で環境変数が設定されている必要があるのでどのタイミングで環境変数が設定され、どのタイミングでビルドが走るのか常に意識しておく必要があります。ローカルでビルドする場合はdocker build
コマンドに--build-arg
オプションをつけて変数を設定してください。
HTTPS
- フロントエンド(ブラウザからAPIにアクセスする場合)とバックエンドで片方のHTTPS化を忘れると混合コンテンツのエラーが発生するので気を付ける必要があります。
混合コンテンツの防止 | Web | Google Developers - OAuthを使用する場合、HTTPSにする必要があります。
Rails
- RailsでActionCableを使用している場合、production環境のデフォルトがRedisを使うようになっているので動かなくなります。Redisを設定するか、開発環境と同じ設定にする必要があります。
Action Cableでリアルタイムチャットアプリの作成方法 (Rails 5.1.4にて)(その1) herokuで動かす! - Qiita
まとめ
今回のデプロイでは全ての工程が長く、かつその他の問題も複雑に絡んできたせいで多くの障害がありました。 その苦難を少しでも解決するためにこの記事を書きました。
このデプロイで得た教訓としては、結局地道に見当・検証することが重要でした。 そして実際の細かな動きをトレースして全体の構成を想像すれば大体解決しました。
既に記憶から薄れ始めている部分もあるので、聞かれないと思い出さない箇所もあって全てを詳細に書ききれていません。 そのため追加で詳しく聞きたい箇所などあればコメントください。 少しでも解決の一助になればと思います。
引用
- npxでnodeモジュールを実行する - Qiita
- Multicontainer Docker configuration - Container definition format
- インスタンスタイプ - Amazon EC2 | AWS
- node_modules/ and Docker volume mount 問題と対策 - castaneaiのブログ
- DockerとNuxtのSSRでConnectionRefusedが発生する問題の原因を解説する - NAKKA-Kの技術ブログ
- 混合コンテンツの防止 | Web | Google Developers
- Action Cableでリアルタイムチャットアプリの作成方法 (Rails 5.1.4にて)(その1) herokuで動かす! - Qiita
- npxでnodeモジュールを実行する - Qiita
- 【AWS】Elastic Beanstalkのデプロイ時に docker exec する - Qiita
- https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-environmentprocess-process
- https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/environments-cfg-alb.html#environments-cfg-alb-namespaces ebコマンド(awsebcli)のインストール - Qiita
vuex-persistedstateを使っていると、ストアを変更しても前のデータがlocalStorageに残って困る
VueやNuxtのプロジェクトでよく使われるvuex-persistedstateというストア永続化プラグインがあります。 このプラグインはストアの内容をlocalStorageに永続化してくれるものです。
問題
ストアの内容を永続化し、ページを開いた時ストアに再展開してくれるのですが、開発中ストアの構造を変更した時などに問題が発生します。
例えばストアにAというデータを保存しているとします。 開発の都合でAというデータを消したとします。 しかしlocalStorage上にはvuex-persistedstateがストアの内容を保存している為、ページをロードした時点でAというデータをストアに格納してしまします。 しかもlocalStorageに保存している為、リロードやキャッシュクリア、ブラウザの再起動では消えません。
これに気づかず変更が読み込まれていないのかと戸惑いました。
解決策
今のところ解決策は2つです。
- ブラウザからlocalStorageを初期化する
- コード上でlocalStorage.clear()をする
1. ブラウザからlocalStorageを初期化する
ブラウザごとに方法が違うのでこちらの外部サイトをご覧ください。
2. コード上でlocalStorage.clear()をする
このコードはアプリケーション上で実行してもいいですし、開発者ターミナルから実行することもできます。
以下の1行でサイトのlocalStorageを全て初期化することができます。
window.localStorage.clear();
localStorageにはストアの内容以外にも保存されている場合があります。 それらは消さずにストアの内容だけを消したい場合は以下のようにすると良いです。
window.localStorage.removeItem('vuex');
別の方法
localStorageに保存されるのが面倒な場合は保存先を変更することもできます。 sessionStorageやcookieに設定することもできる為、開発中だけそちらにするといった方法もあるかもしれませんね。