【terraform+capistrano+itamae】Railsのアプリケーションをawsにデプロイした時の備忘録②
前回はterraform
でaws
の構築を行いました。
Capistrano
itamae
を使用して、環境の構築も同時に学習したかったのですが、あまりにも学習コストが高くなりそうだったので、サーバのrbenv
,nginx
やmysql
のインストールはまずは手動で行いました。bundler
はGemfile.lock
を参照して同じバージョンを入れるのが望ましいかも?
デプロイプロジェクトで使用しているgem
が要求する物に関しては適宜入れていきます。ImageMagick
とか。本当はitamae
でその辺りもカバーします。バージョン等は各環境に合わせて。
参考サイト
以下、設定ファイルの説明のみ書いていくので、手順が知りたい人はリンク先をおってください。 (デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで - Qiita
AWS RailsアプリケーションのCapistranoによるデプロイ - Qiita
使用Gem
capistrano3-unicorn
は使用せずにやりました。
#Gemfile group :development, :test do gem 'capistrano' gem 'capistrano-bundler' gem 'capistrano-rails' gem 'capistrano-rbenv' end group :production, :staging do gem 'unicorn' end
bundle exec cap install
を実行
capistrano設定
Capfile
config/deploy/production.rb
このファイルは大枠の設定ファイルみたいなイメージ。
server
にはデプロイする先のアドレスと、そこにどのロールのタスクを実行するか指定する。今回でいうとapp``db``web
と指定したタスクが指定アドレス上で実行される。次に紹介するconfig/deploy.rb
にてタスクごとにロールを振っているのがわかる。
config/deploy.rb
このファイルが上から実行されるみたいなイメージだと良いかも?上から変数を定義して下でタスクを順に実行するみたいな。例えば上のconfig/deploy/production.rb
でdb
を指定しなかった場合、db_create
の中身は実行されない。
repo_url
ではGit
のPersonal API token
をxxxxに指定することでプライベートリポジトリの物もデプロイ可能。記事の下の方に参考サイトを貼っておきます。
lib/capistrano/tasks/unicorn.rb
unicorn
のタスクを記述したファイル。上のconfig/deploy.rb
内のunicorn:restart
が呼び出しているのはこのファイルに定義したタスク。
config/unicorn/production.rb
unicorn
の設定ファイル。capistrano
との関連はないが、デプロイ先のディレクトリについての関係は同じにしておく。
nginx
,mysql
等の設定については、参考サイト先を参照してください。基本的にこの辺りはのちにitamae
でカバーしようと思うので、入れるコマンドや手順はメモっておくとitamae
の導入が楽かもです。
環境変数
config
gemを使用しました。
ローカルにはconfig/secrets.yml
に
# config/secrets.yml(ローカル) production: secret_key_base: <%= Settings.production[:secret]%>
としましたが、他のページにもいくつか同じように指定している箇所があるかと思います。上のconfig/deploy.rb
の設定で、shared/config/settings/production.yml
にシンボリックリンクを生成することを宣言したため、そちらに内緒にしたい値を定義していきます。
# shared/config/settings/production.yml (aws) database: user_name: 'root' password: 'hogehoge' production: secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' mail: address: 'test@example.com' password: 'xxxxxxxxxxxxx'
こんな感じ。
awsのRDBを使用する
config/database.yml
でhost
をaws
に指定しなければいけない。なので、aws
のインスタンス内でyum install mysql-server
をやる必要はない。(aws
内にRDB
インスタンスを作っていない場合は例外)
プライベートリポジトリからdeployする
Capistrano3でgithubのプライベートリポジトリを簡単にデプロイする方法 · polidog lab++
CapistranoでGitHubにアクセスする際のネットワークプロトコルをhttpsにする - Qiita
デプロイ実行
$ bundle exec cap production deploy
その他対処など..
assets:precompileエラー
ActionView::Template::Error (The asset "application.css" is not present in the asset pipeline.):
上のエラーはcss
等が未コンパイルのためエラーが起こる。自分でコンパイルする必要があるが、yarn
が必要になるため、下記事を参考に導入後次のコマンドを入力する。
エラー解決の参考
Rails5でnginx+pumaでproduction環境を構築する · atwata developer blog
最新のnodejs
とyarn
導入の参考
EC2にyarnをインストールする|新卒エンジニアの開発日記
bundle exec rake assets:precompile RAILS_ENV=production
また、静的ファイルが読み込めない場合以下をconfig/environments/production.rb
に記述
# config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? コメントアウト config.public_file_server.enableda = true
ImageMagic問題
gemのrmagic
のバージョンが3だと、ImageMagic
のバージョン7に2019年6月現在対応していない。が、6系も低すぎるとエラーになる。
ImageMagicインストール参考サイト
Install ImageMagick from source on Amazon Linux · GitHub
ImageMagicバージョンダウンロードサイト
Index of /download
db:migrate
参考にしたサイト通りにやっていればエラーなど出ないが、db:migrate
が実行されない現象にぶつかった。
config/deploy/production.rb
のserver
のロールとしてdb
を含めていなかったため、db
ロールに割り当てられていた、マイグレーションの実行がされておらずテーブルが生成されていなかった。(itamae
導入前なので、テーブル自体は手動で生成した)
Capistrano の db ロール - akishin999の日記
デプロイ時エラー
git stdout: Nothing written git stderr: fatal: Not a valid object name tar: これは tar アーカイブではないようです tar: 前のエラーにより失敗ステータスで終了します
=>Capfile
で指定したデプロイするブランチ名が違っていた。
sharedディレクトリ等の作成
あらかじめディレクトリを生成しておく場合、権限を正しくしておかないとcapistrano
が書き込めなくてエラーがでる。terraform
で使用したアカウントとcapistrano
で使用するアカウントの権限の差に注意しておくこと。特に、ec2-user
より権限の小さいユーザを生成してから、capistrano
でデプロイするとだいたい書き込めないので注意。次回のitamae
編ではその辺りにも注意して進めます。
次の記事はこっち
【terraform+capistrano+itamae】Railsのアプリケーションをawsにデプロイした時の備忘録①
参考サイト
基本的にこちらを参考にしているため、こちらを見れば諸々解決可能です。本記事は備忘録なので見にくいかも。
terraform
terraform
とは
インフラストラクチャ定義ツール に分類されるツールで、クラウド上のリソースを定義ファイルの状態になるように生成・操作してくれます インフラの構成を宣言的に定義できるところが特徴で、構築手順を書くのと違って構成定義のみに集中することができます 10分で理解するTerraform - Qiita
設定(main.tf)
プロジェクトルートに以下の2つのファイルを生成。
main.tf
には生成するインスタンスや周辺の設定を書きます。インフラ周り?
aws_key_pair
にはこちらからssh
接続するために設定したい公開鍵を登録します。
terraform.tfvars
にはGitにのっけにくいキーの情報を書いて環境変数として扱えるようにします。
プロジェクトルートにて、以下のコマンドをうつ。
$ terraform init $ terraform plan $ terraform apply
terraform plan
で設定ミス等に気づける、はず。
以下の表示が出れば成功。
Apply complete! Resources: 3 added, 0 changed, 0 destroyed. Outputs: elastic_ip_of_calendar_web = xx.xxx.xxx.xxx
上のログに出力されたipにssh
接続する。
$ssh ec2-user@xx.xxx.xxx.xxx
ec2-user
はaws
のデフォルトで生成されるアカウント。main.tf
で設定した鍵のペアが必要です。
capistrano編に続きます。 こちら
【Rails】git-cz, rubocopなど初期導入での設定
新規のRailsのプロジェクト
を久しぶりに立ち上げた際に、git-cz
等の導入方法を忘れていたので備忘録として残しておきます。
yarnの導入
yarn
はJavascript
のパッケージマネージャーです。brew
等から入ると思います。
$ brew update $ brew install yarn $ export PATH="$HOME/.yarn/bin:$PATH"
npmのモジュールの導入
今回は諸々を入れます。これは、自分のRails
プロジェクトのルートディレクトリ直下で行いました。
$ yarn add --dev commitizen cz-customizable husky lint-staged
package.json
に追記
すでにある設定に以下を追記します。
{ "scripts": { "cz": "npx git-cz" }, "lint-staged": { "(*.rb|Gemfile)": [ "bundle exec rubocop --auto-correct --fail-level E", "git add" ] }, "config": { "commitizen": { "path": "node_modules/cz-customizable" }, "cz-customizable": { "config": ".cz-config.js" } }, "husky": { "hooks": { "pre-commit": "lint-staged" } } }
lint-staged
には、対象にしたいファイルの拡張子と、それに対して行うコマンドを記述しておきます。
rubocop.ymlの設定
rubocop.yml
はrubocop
先生の設定を書くのですがこれは、個人でお好みでお願いします。
.cz-config.js
package.json
においてcz-customizable
は別途記述するとの設定を行ったので、同じくプロジェクトルートに.cz-config.js
を配置します。
'use strict'; module.exports = { types: [ { value: 'feat', name: 'feat: 新機能', title: 'Features' }, { value: 'fix', name: 'fix: バグ修正', title: 'Bug Fixes' }, { value: 'HOTFIX', name: 'HOTFIX: 致命的で緊急なバグ修正', title: 'Critical hotfix' }, { value: 'UI', name: 'UI: UIやスタイルの更新', title: 'UI' }, { value: 'docs', name: 'docs: ドキュメントのみの変更', title: 'Documentation' }, { value: 'style', name: 'style: フォーマットの変更\n (コードの動作に影響しないスペース、フォーマット、セミコロンなどの変更)', title: 'Styles' }, { value: 'texts', name: 'texts: 文字や文章の更新', title: 'Text and literals' }, { value: 'i18n', name: 'i18n: 国際化', title: 'Internationalization' }, { value: 'typo', name: 'typo: タイプミスの修正', title: 'Typos' }, { value: 'refactor', name: 'refactor: リファクタリングのための変更\n (機能追加やバグ修正を含まない変更)', title: 'Code Refactoring' }, { value: 'perf', name: 'perf: パフォーマンスの改善のための変更', title: 'Performance Improvements' }, { value: 'UX', name: 'UX: ユーザーエクスペリエンス/ユーザビリティの改善', title: 'UX' }, { value: 'test', name: 'test: 不足テストの追加や既存テストの修正', title: 'Tests' }, { value: 'config', name: 'config: 設定の追加や変更', title: 'Configuration' }, { value: 'build', name: 'build: ビルドシステムや外部依存に関する変更\n (スコープ例: gulp, broccoli, npm)', title: 'Builds' }, { value: 'CI', name: 'CI: CI用の設定やスクリプトに関する変更\n (スコープ例:Travis, Circle, BrowserStack, SauceLabs)', title: 'CI' }, { value: 'chore', name: 'chore: その他の変更\n (補助ツール、ドキュメント生成などのソースやテストの変更を含まない変更)', title: 'Chores' }, { value: 'WIP', name: 'WIP: 作業中', title: 'WIP' } ], scopes: [ // { name: '*' }, // { name: 'admin' }, // { name: 'exampleScope' }, // { name: 'changeMe' } ], // it needs to match the value for field type. Eg.: 'fix' /* scopeOverrides: { fix: [ {name: 'merge'}, {name: 'style'}, {name: 'e2eTest'}, {name: 'unitTest'} ] }, */ // override the messages, defaults are as follows messages: { type: 'コミットする変更タイプを選択:\n', scope: '変更内容のスコープ(例:コンポーネントやファイル名)(optional):\n', // used if allowCustomScopes is true customScope: '変更内容のスコープ(例:コンポーネントやファイル名)(optional):\n', subject: '変更内容を要約した本質的説明:\n', body: '変更内容の詳細("|"で改行)(optional):\n', breaking: '破壊的変更についての記述(optional):\n', footer: '関連issueを追記 (例:"fix #123", "re #123")(optional):\n', confirmCommit: 'このコミット内容でよろしいですか?' }, allowCustomScopes: true, allowBreakingChanges: ['feat', 'fix'] };
おまけ
最初に入れると便利なgem
gem "dotenv-rails" #envファイルで環境変数 gem "global" #定数管理 gem "kaminari" #pageing gem "slim" #slim gem "tilt" #slimのために group :development, :test do gem "factory_bot_rails" gem "hirb" # コンソールちょっとみやすく gem "pry-byebug" gem "pry-doc" gem "pry-rails" gem "pry-stack_explorer" gem "rubocop", require: false gem "rubocop-rspec" end group :development do gem "annotate" #migrate時とかに自動でshemaをコメント gem "better_errors" #エラー見やすくするやつ gem "binding_of_caller" #エラー画面からコンソール操作 gem "brakeman", require: false gem "bullet" #N+1クエリ検出 gem "bundler-audit" #セキュアじゃないgemを警告 gem "html2slim" #erbとかhtmlをslimに変換(精度はわるい) gem "web-console", ">= 3.3.0" end
【Mini Hardening】#3.3@FOLIOに参加してきた
Hardeneing
とは、与えられた環境を攻撃から護り続け、なるべくサービスを稼働させ続ける事が目的の競技です。調べればいろいろ出てきますが、本戦は8時間に渡って競技をするのに対しこちらは3時間の短縮版となっています。
内容
については、ネタバレ厳禁という事で残念ながら触れられません。が、おそらく全参加者が目を通したであろうこちらのブログは絶対に読んでおく価値はあると思います。
感想
この競技はおそらく運用を業務で行なっている方が圧倒的に強いと思います。なので初心者の方は競技中、競技後に圧倒的敗北感を感じます笑
が、元々このMini版は初心者のかたむけですし、主催者の方も"攻撃をもろに受ける状況を体感できる機会は少ないし、これを通じて勉強のバネにしてほしい"みたいな事をおっしゃられてました。
これから参加される方へ
上に貼ったブログ先にも書いてある事前準備はマストだと思います。ただ、知識がなかった僕なんかは、最初の1時間が過ぎた後は何をすればいいか路頭に迷ってしまいました。なので、競技中に常に監視しておくもの、そしてその手法を自分で調べておけば多少はチームの役に立てるのではないでしょうか?
【visudo】sudoers.d service(コマンド)の指定
visudo
username ALL=(ALL) NOPASSWD: /sbin/service nginx start
こんな感じ。コマンドを指定する時は、絶対パス
で指定してあげないと、ダメです。 /bin/systemctl
みたいな感じで。
参考サイト
visudoでsudo権限の設定をする際のメモ(sudoersの'ers'って何の略なんですかね?) - Qiita
余談
どうやら終端が改行じゃないとエラーが起こるらしいです。一番下の行だけ気にすれば良さそうな気はしますが、下の行がコメント文だったとしても改行していないとエラーになるっぽいです。
Chefでsudoersをいじったらsudoできなくなったの巻 - Qiita