【Rails】EC2再起動時にunicornを起動する方法
はじめに
EC2の再起動に合わせてunicornを起動する必要があったのでそのメモを残しておきます。
最初から再起動時を何かしらで取得してそのタイミングで実行したいコマンドを設定しておく というところまでは直感でわかりましたが、何を使うかは調べないとわかりませんでした。
調べたところcronに@rebootという再起動時を指定できる方法があったのでそれを使用しました。
実際の設定
crontab -e
を実行して、
@reboot sudo nginx start && {unicorn_railsのフルパス} -c {unicorn.conf.rbのフルパス} -D -E {RAILS_ENV(環境変数に入っていれば指定しなくてもok)}
と設定します。 これでOKです。
設定できているか確認する際は、crontab -l
で、確認できます。
注意点
- nginxを使用していない場合、もちろん前半は不要です
- unicorn_railsのフルパスは
which unicorn_rails
で確認できます - 環境によってunicorn_railsのフルパスが異なる場合もありますので、stagingで書いた設定を本番サーバーでコピペしないように気をつけてください
- unicorn_railsをフルパスにしないと、
/bin/sh: unicorn_rails: command not found
というエラーが出て失敗すると思います。
これは、cron実行時のPATHのせいだそうです。cronでPATHを通す方法もあるようですが、設定するコマンドの量が多くなかったので今回はwhichでフルパスを調べて設定しました。
環境変数について
6/9 追記
cronの実行時、環境変数が足りずに色々なエラーが起きる可能性があるので、
rvm cron setup
を実行するとrvmがいい感じに設定してくれます
Google Dataportal(Datastudio)でMySQL8のRDSを使う方法メモ
※注意点
試行錯誤の結果色々変なことになっている箇所があるので、得た情報をつなぎ合わせたものを先に書いて、"動かなかった場合"として自分の環境も載せようと思います。
はじめに
google dataportalでは、MySQL8に対応していないらしく、そのままでは接続できませんでした。 公式のcommunityスレッドにとても有益な情報があったのでそれを参考にした結果接続できたのでそれを載せます。
引用元: https://support.google.com/datastudio/thread/4115506?hl=en&msgid=34547134
ざっくりまとめると、RDSに直接接続するのではなくProxySQLという色々よしなにやってくれるミドルウェアを間に挟むそうです!
前提
DB:RDS MySQL8.0.16 (色々試行錯誤したのでリードレプリカでpublicから接続できるDBを使っています。同じVPCの中に環境立てるのでpublicなDBでなくてもいけると思います。)
手順
1. ProxySQLの準備
EC2インスタンスの作成
- AMI:Amazon Linux 2(他では試していません)
- VPC:RDSと同じ
- セキュリティグループ
- port:22 ソース:myIP(proxysql設定の為)
- port:6033 ソース:Google Dataportalのヘルプに書いてあるip一覧(カンマ区切り) 下記参照
64.18.0.0/20,64.233.160.0/19,66.102.0.0/20,66.249.80.0/20,72.14.192.0/18,74.125.0.0/16,108.177.8.0/21,173.194.0.0/16,207.126.144.0/20,209.85.128.0/17,216.58.192.0/19,216.239.32.0/19
引用元: MySQL に接続する - データポータルのヘルプ
ProxySQLの設定
以下を実行
sudo vi /etc/yum.repos.d/proxysql.repo
以下を記入
[proxysql_repo] name= ProxySQL YUM repository baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.0.x/centos/\$releasever gpgcheck=1 gpgkey=https://repo.proxysql.com/ProxySQL/repo_pub_key
以下を実行
sudo yum install proxysql
- proxysqlの設定
以下このファイルを触っていきます
sudo vi /etc/proxysql.cnf
~ 略 ~ admin_variables= { admin_credentials="DBマスターユーザーパスワード or DBマスターユーザーパスワードをハッシュ化したもの" # mysql_ifaces="127.0.0.1:6032;/tmp/proxysql_admin.sock" mysql_ifaces="127.0.0.1" ←変更 # refresh_interval=2000 # debug=true } ~ 略 ~
DBマスターユーザーパスワードのハッシュ化は、該当DBに接続し、
SELECT CONCAT("*", UPPER(SHA1(UNHEX(SHA1('DBマスターユーザーパスワード'))))) AS password;
上記のsqlを実行することで取得できるそうです。
~ 略 ~ mysql_variables= { ~ 略 ~ default_schema="DB名" stacksize=1048576 server_version="8.0.16" ←変更 ~ 略 ~ mysql_servers = ( { ~ ここから address = "RDSエンドポイント" # no default, required . If port is 0 , address is interpred as a Unix Socket Domain port = 3306 # no default, required . If port is 0 , address is interpred as a Unix Socket Domain hostgroup = 0 # no default, required status = "ONLINE" # default: ONLINE weight = 1 # default: 1 compression = 0 # default: 0 ここまでをコメントアウト~ # max_replication_lag = 10 # default 0 . If greater than 0 and replication lag passes such threshold, the server is shunned }, ←ここもコメントアウト ~ 略 ~ mysql_users: ( { username = "DBマスターユーザー名" # no default , required password = "DBマスターユーザーパスワード or DBマスターユーザーパスワードをハッシュ化したもの" # default: '' default_hostgroup = 0 # default: 0 active = 1 # default: 1 }, ~ 略 ~ mysql_query_rules: ( ~ ここから { rule_id=1 active=1 match_pattern="\@\@query_cache_size" replace_pattern="null" apply=0 }, { rule_id=2 active=1 match_pattern="\@\@query_cache_type" replace_pattern="null" apply=0 }, { rule_id=3 active=1 match_pattern="\@\@tx_isolation" replace_pattern="null" apply=0 }, ここまで 追加~ ) ~ 略 ~
MySQLのインストール
※引用元には載っていませんでしたが、接続確認の為インストールしました。 不要かもしれません。
以下を実行
sudo yum -y install mysql mysql-devel
2. RDSの設定
セキュリティグループの設定
インバウンドルールに
port 3306 ソース:上記で作成したEC2のセキュリティグループ
を追加
3. ProxySQLの実行
以下を実行
sudo service proxysql start
4. Google Dataportal側での設定
新規レポート→データを追加→MySQL
- ホスト名:上記で作成したProxySQLを実行しているEC2のパブリックIP
- ポート:6033
- データベース:接続したいDB
- ユーザー名:DBマスターユーザー名
- パスワード:DBマスターユーザーパスワード
を記入し 追加 をクリック
参考文献
ProxySQL公式 GitHub - sysown/proxysql: High-performance MySQL proxy with a GPL license.
Google Dataportal 公式スレッド https://support.google.com/datastudio/thread/4115506?hl=en&msgid=34547134
【Rails】booleanのカラムにenumを設定した際のチェックボックスの挙動
このようなmodelがあったとして、
class Billing < Activerecord enum billed: { done: true, in_progress: false } end
編集画面で
~略~ = f.check_box :billed ~略~
のようにすると一見編集できそうですが、このままだとチェックしてsubmitした際に
'1' is not is not a valid billed
のようなエラーが出ます。
色々調べたところenumの影響のようで、check_boxのデフォルトのチェック時の値が1なのでこのようになっているようです。 なので対策としてはcheck_boxのチェック時・非チェック時の値を変更すればokです。 今回の例では、
~略~ = f.check_box :billed, {}, checked_value='billed', unchecked_value='in_progress' ~略~
のようにすれば問題なく通ります。
【Rails】config/initializers内でDB接続が必要な処理を書いた際のCI対応
はじめに
今回、config/initializers内でDB接続を伴う設定をしたのですが、
- assets:precompile
- testDB作成
でエラーが出たのでその対応についてメモ。
前提
- 使用DBはmysql8
- assets:precompileはDockerfile内
- CircleCIで、docker build、testDB作成などを行なっている
起きたことと対策
bundle exec rails assets:precompile実行時にMysql接続エラー
具体的には、
Mysql2::Error::ConnectionError: Unknown MySQL server host ~
このエラーでした。
プリコンパイルをする際、DB接続をしようとするらしいのですが、CIの際は実際のDBに接続できる訳ではないのでDB接続をしないようにする必要がありました。
そこで利用したのがactiverecord-nulldb-adapter
というgemです。
ソースコードの変更・追加点は、
- Gemfile
gem 'activerecord-nulldb-adapter'
を追加
- database.yml
adapter: mysql2
をadapter: <%= ENV['DB_ADAPTER'] ||= 'mysql2' %>
に変更
こんな感じです。
testDB作成時にunknown databaseエラー
CIの途中、rspecを実行する前にその為のDBを作成する工程があるのですが、そこで
Mysql2::Error: Unknown database
エラーが出ました。
db:create
をする際、実際にDBを作成する処理より前にrailsの初期化が実行されている為、config/initializers内でDB接続している箇所でエラーが出ていたのです。
今回、rspecでは該当の処理を使わなかった為、設定ファイルのDB接続より前の箇所に、
return if Rails.env.test?
を入れて対処しました。
rspecで該当箇所を使う場合は、returnではなくifで分岐して仮の値を入れるなどするといいような気がします。
【Rails】Ransackで年度を検索する方法
はじめに
Ransackには、カスタム述語という機能があり、複雑な検索条件を自分で作成することができます。
今回、年度を検索する必要があり、カスタム述語を使ってみましたので記憶に残すためにアウトプットしたいと思った次第です。
前提
- 年度始まりは固定ではない
- view側で指定するのは2019,2020などの数字
view側(slimです)
= f.select :●●_fiscal_year, 年度の配列, {:include_blank => true}
カスタム述語は、eqやcontのように、カラム名_述語名
の形で使用します
年度の配列は、[2018,2019,2020]
のように数字の配列になっています
config/initializers/ransack.rb
Ransack.configure do |config| term_start_date = ●● # 期始まりの日付取得 # 年度検索 config.add_predicate 'fiscal_year', arel_predicate: 'between', formatter: proc { |v| term_start_date.change(year: v.to_i)..term_start_date.change(year: v.to_i).since(1.year).ago(1.day).to_date }, type: :string # 検索条件として選択された値の型 end
以上になります。
RailsのECS環境構築で詰まったこと
はじめに
Railsのstaging環境をECS上に構築するにあたり詰まったことをまとめました。
随時更新していきます。
前提
環境:Rails 6.0(nginxなし, unicornのみ), Ruby 2.7, ECS, CircleCI
ECS
[ipアドレス:ポート]にブラウザからアクセスしてもタイムアウトする
セキュリティグループのインバウンドルールに、
タイプ:カスタムTCP
ポート範囲:32768 - 61000
ソース:マイIP or 任意の場所(アクセス元となりうるIPアドレス)
という設定を追加するとブラウザからのアクセスができるようになるはずです。
ポート範囲は、ポートマッピングでホストポートを0に設定した場合(動的ポートマッピングを使用している場合)は上記の範囲で、それ以外は設定した値で
[ipアドレス:ポート]にブラウザからアクセスしてもアクセス拒否される
自分の場合にはなるのですが、動的ポートマッピングを使用している為、デプロイ毎にポートが変更される為、アクセスしたポートが古いものとなっている可能性があるので確認してみてください
サーバー起動には成功しているのにブラウザからアクセスできない
ターゲットグループのヘルスチェックを確認してみると原因がわかるかもしれません
サービスを更新したのにPENDINGのまま進まない(EC2)
docker container ls -a
を実行すると、終了したコンテナが多数(10個以上)、
docker image ls -a
を実行すると、手動デバッグしていた頃の不要イメージの数々が見つかりました。
その結果を元に、不要なイメージ・コンテナ等を削除した後に再度サービスのアップデートをすると無事RUNNINGになりました。
Rails
assets:precompileをどこでするか
Dockerfileの最下部に追加
rails db:migrateをどこでするか
ECSのタスク定義のコンテナ追加で、サーバー起動と同じイメージを使用してrails db:migrateだけをするコンテナを立てると簡単です。
CircleCI
aws-ecs/deploy-service-updateで失敗する
- familyに書かれたサービスがECS上で設定されていないのかもしれません
aws-ecs/deploy-service-updateの中のcontainer-image-name-updatesで複数のコンテナを指定したい
container-image-name-updates: 'container=コンテナ名,image-and-tag=イメージ名:タグ,container=コンテナ名,image-and-tag=イメージ名:タグ'
のように、container・image-and-tagを1セットとして列挙すると複数指定できる
参考:https://circleci.com/orbs/registry/orb/circleci/aws-ecs
複数のECSのサービスの更新をしたい
ステージング環境と本番環境の両方のデプロイを行いたいときに、どうやってworkflowを書けばいいか迷っていましたが、難しく考えずに
- aws-ecs/deploy-service-update:
を複数書けばいいだけでした。
複数指定した場合、CircleCI側で勝手に番号が振られ、
aws-ecs/deploy-service-update-1
aws-ecs/deploy-service-update-2
のように区別されていました