背景
Rails6でポートフォリオをアプリを作り、AWS EC2にデプロイしました。
EC2デプロイだと、開発環境でgit push → EC2にログイン → git pull
で反映させなければなりません。
この手間を削減したいと思い、CircleCIでの自動デプロイを導入するに至りました。
学習コスト比較
自動デプロイ化するにあたり、CircleCIとCapistranoで検討しました。
比較するとこんな感じ。
CircleCI | Capistrano | |
---|---|---|
gem | 不要 | 必要(5くらい) |
参考記事 | ほぼv2~2.1 | v2とv3が混在 |
gemを使うときは影響を考える必要がありますし、参考記事もバージョンを考慮すると混乱しがちです。
Capistranoと比較してCircleCIは学習コストが低いため導入を決めました。
使用技術/ツール
- Ruby 2.7.2
- Rails 6.1
- AWS (VPC/RDS/EC2/S3)
- CircleCI 2.1
CircleCIとは?
CircleCI Docksによると、CircleCI(サークルシーアイ)はテストやデプロイを自動化してくれるツールです。
継続的インテグレーションの概要と、CircleCI を使用してエンジニアリング チームが自動化を行うしくみについて説明します。 CircleCI は、ソフトウェアのビルド、テスト、デプロイを自動化します。
引用: CircleCI Docks
これを導入することで開発者の手間、つまり企業にとっての人件費の削減に繋がるんですね〜。
現職が経理なのでわかるのですが、人件費は経営者にとっては結構シビアな問題です。
基本給は上げることは簡単ですが、下げるのは難しいですからね。(手当なんかはすぐ外せるので昇給と言って手当ばっかりつける企業というのはそういう事情があるかもですw全部がそうとは言いませんが。)ボーナスも基本給から計算されますし。
話が脱線しましたが、要するに手間を削減できるので開発者にとっても経営者にとってもCircleCIは有用なツールということがわかりました。
CI/CDとは
CircleCIのCIって何?と疑問に感じる人もいると思います。少なくとも私は感じました。
CIは、Continuous Integrationの略で「継続的インテグレーション」と言います。
よくセットで登場するのがCD(Continuous Delivery)、「継続的デリバリー」です。
インテグレーションは「統合」、デリバリーは「受け渡し」ですかね。
実はCI/CDは技術ではなく、手法です。
どんな手法かというと、本番環境にいつでもリリースできるように自動でテストとかをやっておく手法です。
そして、CI/CDツールはCircleCIだけではありません。オンプレミス型やクラウド型があり、Jenkins(オンプレミス)やTravisCI, CircleCI(クラウド)等たくさんあります。
CircleCIを選ぶ理由は、以下のとおりです。
- 比較的簡単なクラウド型
- 保守のしやすさ(sshコンテナでデバック)
- イニシャルコストが無料
- githubとの親和性
準備
それでは本題に入ります。
まずはCircleCIの登録をしましょう。
github(もしくはbitbucket)アカウントで登録します。
登録する際に、Githubのリポジトリの内、全てと連携するか、一部リポジトリのみ(publicのみだったと思います。)連携するかで聞かれますが、個人開発なので好みで良いと思います。CIを使いたいリポジトリが入る方を選びましょう。
前提
私はAWS EC2にデプロイしたあとにCircleCIを設定しました。
再現したい場合はまずはEC2にデプロイしてください。
アプリ側の設定
アプリのルートディレクトリ直下に .circleci/config.yml
を作成します。
version: 2.1
jobs:
deploy:
machine:
enabled: true
steps:
- add_ssh_keys:
fingerprints:
- "XXXXXXXXXXXXXXXXXXXX" # CircleCI上のssh keyにアプリの秘密鍵を登録した後に発行されるFingerPrintを記載
- run: ssh -p $SSH_PORT $SSH_USER@$SSH_HOST "/var/www/アプリ名/deploy.sh"
workflows:
version: 2
deploy:
jobs:
- deploy:
filters:
branches:
only: master # もしくはmain
これはcircleciの設定ファイルです。
細かい内容は公式ドキュメントを御覧ください。
version: CircleCIのバージョン
jobs: 実行内容。その配下に任意の名前で実行内容を記述する。(今回のケースでいうとdeploy)
steps: 上から順番に実行されます。
workflows:stepsは実行命令の順序だったリスト。jobsで宣言した順に実行される。
今回はEC2インスタンスにログインするために
- stepsにadd_ssh_keysで秘密鍵としてfingerprintを持たせる
- run: 実行するものをこれで指定しました。CircleCI上の環境変数を展開してdeploy.shを実行するようにしています。
branchesには、デフォルトブランチのmaster(main)にしています。
次に、push後に自動でpullしてくれるようにルートディレクトリにdeploy.sh
というシェルスクリプトを作成します。
cd /var/www/アプリ名/ && git pull && /bundleのpathがあるディレクトリ]/bundle install
RAILS_ENV=production /bundleのpathがあるディレクトリ]/bundle exec rake assets:precompile
sudo systemctl restart puma
一旦これをpushして、EC2でもpullしておきましょう。
ちなみにbundleはEC2インスタンスのパスを設定してください。
注意1
git pullの前にアプリのディレクトリに移動するコマンドを実行させてください。
そうしないと以下のエラーが出ます。
fatal: not a git repository (or any of the parent directories): .git
なぜなら、自動デプロイがやっていることは単純でCircleCIにdeploy.sh
のシェルコマンドを実行させているだけだからです。
ローカル上で全然関係ないディレクトリでgitコマンドしても同じエラーが発生するはずです。
注意2
bundle installについて。
パスが通ってない判定になってしまうので、絶対パスでbundleコマンドがある場所を指定しましょう。
コマンドがどこにあるか忘れちゃったよ。という方は以下を参考にして探しましょう。
CircleCI側の設定
登録してCircleCIを開き、Projectsタブにすると自分のGithubリポジトリが表示されていると思います。
Unfollow Project
は既に設定済みのリポジトリ、青いSet Up Project
ボタンの場合は未設定のリポジトリです。
設定したいリポジトリをクリックしましょう。(青いボタン、リポジトリ名どちらでもOK)
未設定の場合、Sample configs for sample
というモーダルウィンドウが出てくると思います。
これはどれでも良いと思うのですが、とりあえず連携したいリポジトリに使った言語を選びましょう。
環境変数/SSH Keyの設定
CircleCIで対象リポジトリを開き、右上にある「Project Settings」
を開きます。
Environment Variablesで環境変数を、
SSH KeysでEC2デプロイするときに使った秘密鍵
を登録してください。
秘密鍵をAdd SSH Key
で登録すると、Finferprintが生成されます。
これを.circleci/config.yml
の"XXXXXXXXXXXXXXXXXXXX"
部分にコピペしましょう。
環境変数はこんな感じです。
各情報は一般的には~/.ssh/config
に情報が入っていると思います。(なかったら探してください。笑)
要はssh認証を登録した時の情報です。
アプリの秘密鍵は.pem
ファイルの情報です。
注意: 秘密鍵は以下の部分も含めてすべてコピペしましょう。
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
以上
これで開発環境からpushしたときに自動デプロイが走ります。
エラーが起きたときはCircleCIのエラーログで調べましょう。
まとめ
- CI/CDは開発者の手間を省いてくれる有用なツールです。
- CircleCIはCI/CDツールの一つです。
- 実装自体は簡単だが、Linuxやssh等の基本知識が必要。
恥ずかしながら、CircleCI導入まではLinux, ssh, サーバー等の基本技術の理解が浅かったです
これを実装することでLinux, ssh等の知識をインプット/アウトプットすることができ良い機会となりました。
サーバーサイドを志望する上でサーバーやLinux関連は必須なのでこれからも学習を続けていきたいです。
次は自動テストにも挑戦したいです。