ndenvからnodenvへ移行する

今更ながらnodenvに移行

JavaScript Primerという本を買って読んでみると、JavaScriptの今までわからなかったところがわかるようになりとてもJavaScriptが楽しくなってきました。(Web版もあります)。

ローカルの開発環境を新しくしようと思い、anyenv経由でインストールしたndenvをアップデートしました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ anyenv update
$ anyenv update
Updating 'anyenv'...
| From https://github.com/riywo/anyenv
| e963a69..67d402f master -> origin/master
| * [new tag] v1.1.2 -> v1.1.2
Updating 'anyenv/anyenv-update'...
Updating 'ndenv'...
Updating 'ndenv/ndenv-yarn-install'...
Updating 'ndenv/node-build'...
Updating 'rbenv'...
| From https://github.com/rbenv/rbenv
| c879cb0..0843745 master -> origin/master
Updating 'rbenv/ruby-build'...
| From https://github.com/rbenv/ruby-build
| 69ccbf4..0a5e059 master -> origin/master
| * [new tag] v20200819 -> v20200819
| * [new tag] v20200722 -> v20200722
| * [new tag] v20200727 -> v20200727
Updating 'anyenv manifest directory'...
| From https://github.com/anyenv/anyenv-install
| dcbcfe1..d9791df master -> origin/master

ところが、ndenvのgithubを見てみると

[Deprecated] nodenv is better alternative

と書かれていました。以前はnodenvを使っていて、いつからかndenvになったと記憶しています。結局元に戻ったと言う感じでしょうか。

nodenvのインストール

anyenvを利用してインストールします

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ anyenv install nodenv
/var/folders/mf/_4_k88fj3nqcsgqdz7dzqhy00000gn/T/nodenv.20200828113307.39306 ~
Cloning https://github.com/nodenv/nodenv.git master to nodenv...
Cloning into 'nodenv'...
remote: Enumerating objects: 14, done.
remote: Counting objects: 100% (14/14), done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 4017 (delta 2), reused 4 (delta 1), pack-reused 4003
Receiving objects: 100% (4017/4017), 731.96 KiB | 828.00 KiB/s, done.
Resolving deltas: 100% (2633/2633), done.
~
~/.anyenv/envs/nodenv/plugins ~
Cloning https://github.com/nodenv/node-build.git master to node-build...
Cloning into 'node-build'...
remote: Enumerating objects: 95, done.
remote: Counting objects: 100% (95/95), done.
remote: Compressing objects: 100% (61/61), done.
remote: Total 19746 (delta 39), reused 68 (delta 25), pack-reused 19651
Receiving objects: 100% (19746/19746), 3.51 MiB | 776.00 KiB/s, done.
Resolving deltas: 100% (12653/12653), done.
~
~/.anyenv/envs/nodenv/plugins ~
Cloning https://github.com/nodenv/nodenv-vars.git master to nodenv-vars...
Cloning into 'nodenv-vars'...
remote: Enumerating objects: 211, done.
remote: Total 211 (delta 0), reused 0 (delta 0), pack-reused 211
Receiving objects: 100% (211/211), 31.82 KiB | 201.00 KiB/s, done.
Resolving deltas: 100% (76/76), done.
~

Install nodenv succeeded!
Please reload your profile (exec $SHELL -l) or open a new session.

インストール後はシェルを再起動します

1
$ exec $SHELL -l

ndenvのアンインストール

アンインストールもanyenvを利用して行います。

1
2
$ anyenv uninstall ndenv
anyenv: remove /Users/shibagaki/.anyenv/envs/ndenv?

yesと入力してエンターキーを押すとアンインストールされます。

nodeのインストール

nodenvを使ってインストールします。現時点で最新のLTSである12.18.3をインストールします。

1
2
3
4
5
6
7
8
$ nodenv install v12.18.3
node-build: definition not found: v12.18.3

See all available versions with `nodenv install --list'.

If the version you need is missing, try upgrading node-build:

git -C /Users/shibagaki/.anyenv/envs/nodenv/plugins/node-build pull

見つからないと言われてしまったので、一覧表示してみます。

1
2
3
4
5
6
7
8
$ nodenv install --list
...
12.18.1
12.18.2
12.18.3
13.0.0
13.x-dev
...

先頭のvがいらないんですね。

1
2
3
4
5
$ nodenv install 12.18.3
Downloading node-v12.18.3-darwin-x64.tar.gz...
-> https://nodejs.org/dist/v12.18.3/node-v12.18.3-darwin-x64.tar.gz
Installing node-v12.18.3-darwin-x64...
Installed node-v12.18.3-darwin-x64 to /Users/shibagaki/.anyenv/envs/nodenv/versions/12.18.3

インストールされたことを確認します

1
2
3
4
5
6
7
$ nodenv local 12.18.3
$ which node
/Users/user/.anyenv/envs/nodenv/shims/node
$ node -v
v12.18.3
$ npm -v
6.14.6

これで環境を整えることができました。

まとめ

  • ndenvよりはnodenvを利用するようにする
  • nodenvでバージョンを指定する時は先頭のvはいらない
  • バージョン表示時はvがついている

gitのバージョン管理の仕組みを知る その1

きっかけ

今、【夏の翔泳社祭】PDF版電子書籍50%ポイント還元のキャンペーンが行われています。前回のキャンペーンでたまったポイント(前回は書籍購入で50%ポイント還元)があるので、おもしろそうな本があったら買おうと思っていろいろ見てみるとエンジニアのためのGitの教科書[上級編] Git内部の仕組みを理解するを見つけました。

自分のgitのレベルは、gitを使ってプロジェクトを進めることはできますが、なにかイレギュラーなことが起こった時には、ちょっとした緊張が走ってしまうくらいの感じです。ちゃんと理解できていればそうはならないんだと思うので、これを機にgitをより深く学びたいと思います。

本書の構成

構成は、初級、中級、上級の3部構成になっています。全体で80ページ弱のコンパクトな本です。

今回は初級の部分をまとめていきたいと思います。

Gitのバージョン管理の仕組みを知る 〜初級編〜

まとめ

hexoでtwitter cardを記事ごとに変更する

背景

前回、twitter cardの設定を変更してみました。表示されるようになったのですが、すべての記事で同じだとおもしろくありません。

記事ごとの設定はmdファイルのyaml部分に記述しています。titledateupdatedなどと同じように設定できそうな気がします。ちょっと調べてみましょう。

updatedの実現方法を確認する

このサイトでは更新日時を表示するようにしています。前回の記事だと、以下のように設定しています。

1
2
3
4
5
6
7
8
9
---
title: hexoでtwitter cardの設定を変更する
date: 2020-08-07 12:30:00
updated: 2020-08-07 12:30:00
categories:
- テクニカルブログ
tags:
- hexo
--

上記の設定をどうやって取得しているのかthemesディレクトリ以下で探してみます。

1
2
3
4
$ grep -R updated themes
themes/landscape/layout/_partial/article.ejs: <%- partial('post/updated', {class_name: 'article-date', date_format: null}) %>
themes/landscape/layout/_partial/post/updated.ejs:<% if (post.updated) { %>
themes/landscape/layout/_partial/post/updated.ejs: Updated: <time datetime="<%= date_xml(post.updated) %>" itemprop="dateUpdated"><%= date(post.updated, date_format) %></time>

post.updatedとすることで取得できているようです。

twitter cardのURLを指定してみる

記事にtwitter_imageというキーを設定して、実際に変わるか試してみます。こちらの記事で試してみます。

記事の設定にtwitter_imageを追加して、URLを記述します

1
twitter_image: https://book-reviews.blog/images/github_actions_rails_template.png

次にthemes/landscape/layout/_partial/head.ejsのtwitter cardの設定の箇所で、twitter_imageを参照するよう変更します。

1
25   <%- open_graph({twitter_id: theme.twitter, google_plus: theme.google_plus, fb_admins: theme.fb_admins, fb_app_id: theme.fb_app_id, twitter_card: 'summary_large_image', image: post.twitter_image}) %>

Card validatorで確認すると、そもそも表示されずタイムアウト…
というか、サイト自体も表示できなくなってしまっています。これはエラーが起こっている可能性が高いので、一旦元に戻します。

post.twitter_imageが参照できない原因調査

post.updatedで正しく参照できている場合と、今回はなにが違うのでしょうか。

post.updatedを参照しているのは、themes/landscape/layout/_partial/post/updated.ejsです。そのファイルを読み込んでいるのはthemes/landscape/layout/_partial/article.ejsです。

article.ejsを読み込んでいるファイルを確認します。

1
2
3
4
$ grep -R 'partial/article' themes/
themes/landscape/layout/page.ejs:<%- partial('_partial/article', {post: page, index: false}) %>
themes/landscape/layout/post.ejs:<%- partial('_partial/article', {post: page, index: false}) %>
themes/landscape/source/css/style.styl:@import "_partial/article"

partialメソッドに変数を引き渡していることがわかりました。この記述が必要そうですね。試してみます。

themes/landscape/layout/layout.ejsの1行目を以下のように変更します。

1
<%- partial('_partial/head', {post: page}) %>

再度twitter cardの設定でpost.twitter_imageを参照するように変更し、Card validatorで試してみます。

記事ごとでtwitter cardの画像を変更できた

うまくいきました!

記事にtwitter_imageの設定がない場合はデフォルトでキービジュアルの画像を表示するように修正します。

1
2
3
4
5
6
<% if (post.twitter_image){ %>
<% twitter_image = post.twitter_image %>
<% } else { %>
<% twitter_image = '/css/images/banner.jpg' %>
<% } %>
<%- open_graph({twitter_id: theme.twitter, google_plus: theme.google_plus, fb_admins: theme.fb_admins, fb_app_id: theme.fb_app_id, twitter_card: 'summary_large_image', image: twitter_image}) %>

EJSを初めて書きました。概要は知っておいた方が良さそうですね。

まとめ

今回twitter cardを記事ごとに設定することができました。よりよいサイト作りのために、いろいろカスタマイズしていこうと思います。そのためにはhexo, EJSの知識がもうちょっと必要ですね。学んでいきたいと思います。

hexoでtwitter cardの設定を変更する

背景

しばらく使っていなかったtwitterをブログの記事更新の告知に使おうと思って投稿してみました。自分のツイートを見てみると、twitterカードがうまく表示できていませんでした。titleやdescriptionはデフォルトである程度設定してくれているようです。なのでtwitterカードのカスタマイズを行おうと思います。

headタグがあるpartialを探す

OGP関連の記述はheadタグ内にあります。headタグはどのpartialで記述されているのでしょうか。とりあえずthemesディレクトリ配下をgrepしてみました。

1
2
3
4
5
6
7
8
9
10
11
12
$ grep -R twitter themes
themes/landscape/layout/_partial/head.ejs: <%- open_graph({twitter_id: theme.twitter, google_plus: theme.google_plus, fb_admins: theme.fb_admins, fb_app_id: theme.fb_app_id}) %>
themes/landscape/source/css/_variables.styl:color-twitter = #00aced
themes/landscape/source/css/_partial/article.styl:.article-share-twitter
themes/landscape/source/css/_partial/article.styl: background: color-twitter
themes/landscape/source/css/_partial/article.styl: text-shadow: 0 1px darken(color-twitter, 20%)
Binary file themes/landscape/source/css/fonts/FontAwesome.otf matches
Binary file themes/landscape/source/css/fonts/fontawesome-webfont.ttf matches
themes/landscape/source/js/script.js: '<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="article-share-twitter" target="_blank" title="Twitter"></a>',
themes/landscape/README.md:twitter:
themes/landscape/README.md:- **twitter** - Twiiter ID
themes/landscape/_config.yml:twitter:

最初に見つかったtheme/landscape/layout/_partial/head.ejsがそれっぽいですね。中身を確認してみます。

1
2
3
4
5
6
23   <title><% if (title){ %><%= title %> | <% } %><%= config.title %></title>
24 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
25 <%- open_graph({twitter_id: theme.twitter, google_plus: theme.google_plus, fb_admins: theme.fb_admins, fb_app_id: theme.fb_app_id}) %>
26 <% if (theme.rss){ %>
27 <link rel="alternate" href="<%= url_for(theme.rss) %>" title="<%= config.title %>" type="application/atom+xml">
28 <% } %>

実際に出力されるHTMLを見ると、25行目の1行でOGP関連のタグを全て出力していることがわかります。カスタマイズするにはopen_graphというヘルパメソッド?がなにをしているのかを理解する必要がありそうです。メソッドがどこで定義されているかを確認します。

open_graphメソッド

open_graphメソッドはどこで定義されているかを確認します。
hexoアプリケーションのTOPでgrepしてみます。

1
2
3
$ grep -R open_graph .
./themes/landscape/layout/_partial/head.ejs: <%- open_graph({twitter_id: theme.twitter, google_plus: theme.google_plus, fb_admins: theme.fb_admins, fb_app_id: theme.fb_app_id, twitter_card: 'summary_large_image', image: '/css/images/banner.jpg', twitter_site: '@motoa'}) %>
./node_modules/hexo/lib/plugins/helper/index.js: helper.register('open_graph', require('./open_graph'));

1行目は先ほどのpartialですね。2行目が定義箇所っぽいですね。該当のファイルの中身を見てみます。

1
2
3
4
5
6
43   helper.register('list_tags', require('./list_tags'));
44 helper.register('list_posts', require('./list_posts'));
45
46 helper.register('open_graph', require('./open_graph'));
47
48 helper.register('number_format', require('./number_format'));

正確には理解できてないですが、open_graphというhelperを登録しているような感じでしょうか。helperの処理はrequire('./open_graph')の戻り値なのでしょう。同じディレクトリにあるopen_graph.jsを見てみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
118   result += meta('twitter:card', twitterCard);
119 result += meta('twitter:title', title);
120 if (description) {
121 result += meta('twitter:description', description, false);
122 }
123
124 if (images.length) {
125 result += meta('twitter:image', images[0], false);
126 }
127
128 if (options.twitter_id) {
129 let twitterId = options.twitter_id;
130 if (twitterId[0] !== '@') twitterId = `@${twitterId}`;
131
132 result += meta('twitter:creator', twitterId);
133 }
134
135 if (options.twitter_site) {
136 result += meta('twitter:site', options.twitter_site, false);
137 }

twitter関連の設定をしている箇所はこんな感じでした。twitterカードの種類(summary, summary_large_image)の設定はtwitterCardという変数で設定されているようです。twitterCardという変数はどこで定義されているのか確認します。

1
42   const twitterCard = options.twitter_card || 'summary';

変数ではなく定数でした。options.twitter_cardが指定されていればそれを、指定されていなければsummaryになるということですね。デフォルトはsummaryになるので、なにも設定していない現在はsummaryになっています。

では、optionsを確認します。

1
30 function openGraphHelper(options = {}) {

optionsはこの関数の引数でした。ということは、open_graphメソッドの引数のハッシュにtwitter_cardというキーでtwitterカードの種類を設定すればできそうですね。

試してみる

theme/landscape/layout/_partial/head.ejsのopen_graphの呼び出しを以下のように変更してみます。

1
<%- open_graph({twitter_id: theme.twitter, google_plus: theme.google_plus, fb_admins: theme.fb_admins, fb_app_id: theme.fb_app_id, twitter_card: 'summary_large_image', image: '/css/images/banner.jpg'}) %>

twitter_cardsummary_large_imageに指定しました。またその際に表示する画像をimageで指定しています。今回は試しにキービジュアルの画像を指定しています。

確認

twitter card validatorを利用します。TOPページのURLを入力し、Preview cardをクリックします。

twitter card validatorの結果

summary_large_imageで表示できました!

まとめ

hexoのOGP関連の設定をカスタマイズしてみました。今回の設定だと全てのtwitter:imageがキービジュアルの画像になってしまうので、次回は記事ごとにtwitter:imageを変更できるようにしてみたいと思います。

Let's Encryptの証明書を更新する

動機

前回Let’s Encryptを使ったSSL証明書の作成を行いました。そのときに、2020年8月4日には有効期限が切れてしまうようですと言っていたにもかかわらず更新をするのを忘れていました…

なので、今回は更新作業を行いたいと思います。

SSL証明書の更新作業

前回も記載していましたが、

1
2
3
Your cert will expire on 2020-08-04. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option.

ということなので、certonlyオプションをつけて実行したいと思います。

1
2
3
4
5
6
7
8
9
10
$ sudo certbot certonly --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: book-reviews.blog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):

一つしかドメインがないですが、選択する必要があるので1を入力してエンターキーを押します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1: book-reviews.blog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1
Cert is due for renewal, auto-renewing...
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for book-reviews.blog
Waiting for verification...
Challenge failed for domain book-reviews.blog
http-01 challenge for book-reviews.blog
Cleaning up challenges
Some challenges have failed.

IMPORTANT NOTES:
- The following errors were reported by the server:

Domain: book-reviews.blog
Type: dns
Detail: During secondary validation: DNS problem: networking error
looking up A for book-reviews.blog

なぜか失敗してしまっているようです。原因も記載されていますね。

1
Detail: During secondary validation: DNS problem: networking error looking up A for book-reviews.blog

ドメインの名前解決中にネットワークエラーが発生したという感じでしょうか…

原因が不明なので再度実行してみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ sudo certbot certonly --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: book-reviews.blog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1
Cert is due for renewal, auto-renewing...
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for book-reviews.blog
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/book-reviews.blog/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/book-reviews.blog/privkey.pem
Your cert will expire on 2020-11-03. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

今回はなぜかうまく行きました。

動作確認

ブラウザでアクセスしてみます。すると、まだ「保護されていない通信」として警告が出ています。証明書を確認すると、有効期限が更新されていませんでした。

証明書を更新したらnginxの再起動が必要ですね。再起動します

1
$ sudo systemctl restart nginx

証明書が更新され、有効期限が2020年11月4日になりました。これで証明書の更新は終わりです、が、なぜかChromeで見たときの「保護されていない通信」という警告はまだ残っています…なぜなのでしょうか…

原因調査

こちらに調査方法が詳しく記載されていました。

デベロッパーツールを立ち上げ、Securityを選択します。
Security overviewを確認すると、証明書やコネクションに関してはグリーンになっていますが、Resourcesがレッドになっています。
メッセージを見ると

1
2
Resources - active content with certificate errors
You have recently allowed content loaded with certificate errors (such as scripts or iframes) to run on this site.

ということでした。証明書を更新する前の、有効期限が切れている状態でサイトへのアクセスを許可したために警告が消えないようです。

ということは、証明書の更新とは関係ありませんでした。試しに別のブラウザで表示したところ問題ありませんでした。

まとめ

  • Let’s Encryptの証明書更新を行うにはcertonlyオプションをつけて実行する
  • 更新した証明書を反映するにはWebサーバの再起動が必要
  • 証明書の期限が切れた状態で、サイトへのアクセスを許可すると、証明書更新後も「保護されていない通信」が解除されない。

次回また2020年11月に行います。次はもっとスムーズにできると思います。

unicornがどのRubyバージョンで動作しているかを調べる

背景

以前、Railsアプリケーションが動作している環境のRubyのバージョンアップを行いました。Rubyのバージョンは正しく上がっているようでしたが、Railsアプリケーションの動作が不安定になってしまいました…その時の調査のログです。

原因

結果的にはunicornが旧Rubyバージョンで動作していることが原因でした。unicornがどのRubyバージョンで動作しているかを確認する方法を記載します。

確認方法

プロセスIDの確認

unicornのmasterプロセスを探します。

1
2
3
4
5
6
7
8
9
$ ps -ef | grep unicorn
user 1797 1 0 Jul29 ? 00:00:06 unicorn master -c /var/www/user-cms/current/config/unicorn/production.rb -E deployment -D
user 1840 1797 8 Jul29 ? 02:42:10 unicorn worker[0] -c /var/www/user-cms/current/config/unicorn/production.rb -E deployment -D
user 1847 1797 8 Jul29 ? 02:40:24 unicorn worker[1] -c /var/www/user-cms/current/config/unicorn/production.rb -E deployment -D
user 1857 1797 8 Jul29 ? 02:40:50 unicorn worker[2] -c /var/www/user-cms/current/config/unicorn/production.rb -E deployment -D
user 1872 1797 8 Jul29 ? 02:38:32 unicorn worker[3] -c /var/www/user-cms/current/config/unicorn/production.rb -E deployment -D
user 1894 1797 8 Jul29 ? 02:39:10 unicorn worker[4] -c /var/www/user-cms/current/config/unicorn/production.rb -E deployment -D
user 1909 1797 7 Jul29 ? 02:37:28 unicorn worker[5] -c /var/www/user-cms/current/config/unicorn/production.rb -E deployment -D
21235 42323 42237 0 00:47 pts/3 00:00:00 grep unicorn

masterプロセスのプロセスIDは1797とわかります。
次にrootになって、/proc/プロセスIDのディレクトリを確認します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$ sudo su -
# ls -l /proc/1797/
合計 0
dr-xr-xr-x 2 user user 0 7月 31 00:47 2020 attr
-rw-r--r-- 1 user user 0 7月 31 00:47 2020 autogroup
-r-------- 1 user user 0 7月 31 00:47 2020 auxv
-r--r--r-- 1 user user 0 7月 31 00:47 2020 cgroup
--w------- 1 user user 0 7月 31 00:47 2020 clear_refs
-r--r--r-- 1 user user 0 7月 31 00:46 2020 cmdline
-rw-r--r-- 1 user user 0 7月 31 00:47 2020 comm
-rw-r--r-- 1 user user 0 7月 31 00:47 2020 coredump_filter
-r--r--r-- 1 user user 0 7月 31 00:47 2020 cpuset
lrwxrwxrwx 1 user user 0 7月 31 00:47 2020 cwd -> /var/www/user-cms/releases/20200729065345
-r-------- 1 user user 0 7月 31 00:47 2020 environ
lrwxrwxrwx 1 user user 0 7月 31 00:47 2020 exe -> /usr/local/rbenv/versions/2.4.10/bin/ruby
dr-x------ 2 user user 0 7月 31 00:47 2020 fd
dr-x------ 2 user user 0 7月 31 00:47 2020 fdinfo
-r-------- 1 user user 0 7月 31 00:47 2020 io
-rw------- 1 user user 0 7月 31 00:47 2020 limits
-rw-r--r-- 1 user user 0 7月 31 00:47 2020 loginuid
-r--r--r-- 1 user user 0 7月 31 00:47 2020 maps
-rw------- 1 user user 0 7月 31 00:47 2020 mem
-r--r--r-- 1 user user 0 7月 31 00:47 2020 mountinfo
-r--r--r-- 1 user user 0 7月 31 00:47 2020 mounts
-r-------- 1 user user 0 7月 31 00:47 2020 mountstats
dr-xr-xr-x 6 user user 0 7月 31 00:47 2020 net
dr-x--x--x 2 user user 0 7月 31 00:47 2020 ns
-r--r--r-- 1 user user 0 7月 31 00:47 2020 numa_maps
-rw-r--r-- 1 user user 0 7月 31 00:47 2020 oom_adj
-r--r--r-- 1 user user 0 7月 31 00:47 2020 oom_score
-rw-r--r-- 1 user user 0 7月 31 00:47 2020 oom_score_adj
-r--r--r-- 1 user user 0 7月 31 00:47 2020 pagemap
-r--r--r-- 1 user user 0 7月 31 00:47 2020 personality
lrwxrwxrwx 1 user user 0 7月 31 00:47 2020 root -> /
-rw-r--r-- 1 user user 0 7月 31 00:47 2020 sched
-r--r--r-- 1 user user 0 7月 31 00:47 2020 schedstat
-r--r--r-- 1 user user 0 7月 31 00:47 2020 sessionid
-r--r--r-- 1 user user 0 7月 31 00:47 2020 smaps
-r--r--r-- 1 user user 0 7月 31 00:47 2020 stack
-r--r--r-- 1 user user 0 7月 31 00:46 2020 stat
-r--r--r-- 1 user user 0 7月 31 00:47 2020 statm
-r--r--r-- 1 user user 0 7月 30 22:38 2020 status
-r--r--r-- 1 user user 0 7月 31 00:47 2020 syscall
dr-xr-xr-x 5 user user 0 7月 31 00:47 2020 task
-r--r--r-- 1 user user 0 7月 31 00:47 2020 wchan

exeファイルのリンク先を確認すると、/usr/local/rbenv/versions/2.4.10/bin/rubyとなっており、Rubyの実行ファイルになっています。この場合だとバージョンは2.4.10ですね。今回はパスでバージョンがわかりますが、パスからわからない場合は、exeのリンク先の実行ファイルで-vオプションを実行すればバージョンがわかります。

おまけ

デプロイを行うのにcapistranoを使っているのですが、通常のデプロイシーケンスでは、unicornはworkerが再起動されるだけで、masterプロセスは再起動されませんでした。Rubyのバージョン変更を行った場合はmasterプロセスの停止・起動が必要となります。

自分の環境では以下のコマンドでunicornのmasterプロセスの再起動が行えました。

1
2
3
$ bundle exec cap production deploy:stop
$ bundle exec cap production deploy:start
(productionは環境名)

最初のコマンドでunicornを停止し、次のコマンドで起動しています。Rubyのバージョンを変更した場合は、masterプロセスの再起動が必要ということを覚えておきます。

この辺りを学ぶにはなるほどUNIXプロセスという本がとても役に立ちそうです。読み始めているのですが、とても楽しく読めています。機会があれば本の内容も紹介したいと思います。

ECSでタスクが起動しない時の調査方法

背景

オンプレミス環境からAWS ECSへ移行しようというプロジェクトを行っております。環境はnginx + Railsです。

Docker Desktop for Macでdocker networkを作成しnginxとrailsでコンテナ間通信ができるところまでは確認できたので、そのコンテナイメージをECRにpushし、タスク定義まで行いました。

ECSクラスターの作成を行い、作成したタスク定義を実行したところ起動できなかったのでその時の調査方法を記載します。

ECSインスタンスにログイン

起動しない原因を調査するにあたってまずはログを確認したいのですが、ログの確認方法がわかっていません…なので、本来もっと良い方法があると思うのですがよくわかっていないので、一旦ECSインスタンスにSSHログインできるようにしました。

2020/12/9追記

ログの確認方法

ECSクラスターを選択、下のタブのタスクをクリックします。

タスクの一覧が表示されます。表示されない場合は、コンテナがすでに止まってしまっている可能性が高いです。その場合は、必要なタスクのステータスStoppedにすると表示されると思います。タスクのIDのリンクをクリックします。するとタスクの詳細ページに遷移します。

画面上部にタブがあり、Logsタブをクリックします。ログを表示するコンテナを選択しますというメッセージの横にセレクトボックスがあるので、ログを表示するコンテナを選択します。CloudWatchに出力する(logDriverがawslog)設定になっているコンテナが選択できます。

選択すると下にログが表示されます。エラーなどコンテナが起動できなかった理由がわかると思います。

ECSインスタンスにログインするための設定

ECSインスタンスにログインするためには以下の設定が必要です。

  • クラスターテンプレートの選択EC2 Linux + ネットワーキングを選択する
  • クラスターの設定 -> インスタンスの設定キーペアを指定する
  • クラスターの設定 -> ネットワーキングパブリックサブネットを指定する
  • クラスターの設定 -> ネットワーキングAuto assign public IPEnabledにする
    • サブネットの設定でパブリック IPv4 アドレスの自動はいになっていればUse subnet settingでも大丈夫です
  • クラスターの設定 -> セキュリティグループでSSHを通しているセキュリティグループを選択する
    • デフォルトのセキュリティグループではNG

以上の設定でクラスターを作成します。

ECSインスタンスの起動確認

先ほど作成したクラスターを選択して、ECS インスタンスタブをクリックすると、作成したクラスターのECSインスタンスが表示されます。ECS インスタンスのリンクをクリックすると、EC2の確認ができます。

ECSインスタンスにSSHする

確認したEC2のパブリックDNS、もしくはパブリックIPにクラスター作成時に指定したキーペアを使ってログインします。

コンテナのログを確認

早速コンテナの状況を確認します。docker ps -aをすると、なにかの原因でステータスがExitedになっていました。

コンテナのログの確認にはdocker logsコマンドを利用します。

1
2
3
4
5
6
7
8
9
$ docker logs コンテナID
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: error: /etc/nginx/conf.d/default.conf is not a file or does not exist
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2020/07/22 07:55:16 [emerg] 1#1: host not found in upstream "rails:3000" in /etc/nginx/conf.d/rails.conf:2
nginx: [emerg] host not found in upstream "rails:3000" in /etc/nginx/conf.d/rails.conf:2

nginxの設定がDocker Desktopで動作確認した時のそのままになってしまっているのが原因のようです。(docker networkを作成して動作確認したときに、Rails用コンテナをrailsという名前で起動していたため)

今回、タスク定義のネットワークモードをawsvpcにしているので、コンテナ間通信はlocalhost指定で行えます。こちらを参考にしました。

ですので、nginxのupstreamの指定をlocalhost:3000として、コンテナをbuild、pushしたら無事タスクが起動しました。

まとめ

なにか起こった時の調査にログは欠かせません。まずはログを確認するようにしたいです。
今回のログの確認方法は本来の方法ではないと思います。Fargate使っていたらできないと思いますし…
本来はCloudWatchなど利用して行うのだと思いますが、まだその辺りを理解できていないのでこれから調べていきたいと思います。

※ Container Insightsを使ってみましたが使用しているリソース確認、マップ表示くらいの機能でした。プロダクション環境では重宝するかもしれません。

パーフェクトRuby on Rails 【増補改訂版】

前作から6年ぶりの改訂

先日いつも立ち寄る三省堂書店神保町本店の技術書コーナーにいくと、パーフェクトRuby on Railsの増補改訂版が置いてありました。まだ発売日前のようですが置いてくれていたんですね。早速購入しました。

前作が2014年7月10日に初版第1刷発行ということで、6年ぶりの改訂となります。前作も手元にありますので比較してみていきます。

対象のバージョン

前作ではRuby2.0.0、Rails4.1.1が対象でした。今見るとさすがにちょっと古い感じがしますね。
今作ではRuby2.6.6、Rails6.0.3が対象です。「はじめに」にもありますが、本書執筆時点ではRuby2.7.1が最新バージョンでしたが(2020年7月21日現在も2.7.1が最新)、Ruby2.7からRuby3.0へ向けて非互換性の警告が出るようです。そのため2.6.6を利用したようです。

内容

前作は431ページで、今作は527ページと約100ページ増えています。

内容は、前作ですとPart1〜4と付録がありました。今回はPart1〜5と付録があります。

Part1 Rails Overview

Part1は前作と同様、Railsの概要、MVCアーキテクチャ、基本機能が紹介されています。今作では秘密情報の管理方法がバージョン4.0までと4.1、5.1、5.2、6.0でどのように行うかが紹介されています。

ここまでの内容は普段Railsアプリケーションを開発されている方々であればざっと流し見する感じでしょうか。

Part2 Railsの周辺知識

Part2ではRailsの周辺知識として、フロントエンド開発周りやActive 〜、Action 〜などのコンポーネントの利用方法について紹介されています。

前作ではフロントエンド開発周りで言うと、アセットのコンパイル(assets:precompile)を行う方法、CoffeeScriptの書き方、Sassの書き方などでした。
今作では、6.0から導入されたWebpackerの紹介、JavaScripthレームワークStimulusの紹介などがあります。cssもWebpackerで管理する方法で普段開発しているのですが、本書ではcssは引き続きSprocketsで管理すると記載されています。

その他は前作と同じようにActive 〜、Action 〜の紹介がされています。

Part3 Webアプリケーション開発

Part3では前作と同様、簡単なサンプルアプリケーションを作成し、そのテストも実装するという内容になっています。

前作では上記にプラスしてRailsアプリケーションの開発、運用、CI/CDについてもPart3で言及しています。この頃はまだコンテナ技術が広まっていなかったからか、仮想マシンを用いた開発、運用について紹介されています。Chefとか懐かしいですよね。今作ではPartを分けて、Part4で紹介されています。この辺りの技術に大きな変化があったということでしょう。

Part4 Railsアプリケーションの拡張・運用

今作で切り出されたPartです。RailsでのCIやコンテナ技術について紹介されています。

最近やっと着手したGitHub ActionsやDockerコンテナでのアプリケーション設定方法について記載されています。

Part5 エキスパートRails

今作のPart5は前作のPart4の内容に少し追加されているくらいの印象です。ですが、やはりこの辺りをしっかりと理解しておくことがRailsをちゃんと使いこなせるかどうかの違いになってきそうです。わたしも(Concernやコールバックオブジェクトなど)理解できていない部分があるので、もう一度見直したいと思います。

付録

付録はWindows環境でのRailsアプリケーションの構築方法、Rubyのインストール方法など環境構築方法が紹介されています。rbenvを使っています。

まとめ

内容に関して大きく変わりはないですが、今使われている技術をざっと見直したい、Railsについて理解しているつもりだけどわかっていないところを再発見したいときに流し読みするには良さそうです。もちろんRailsにまだあまり慣れていない人にとっては最初からじっくり手を動かしながら読むのがオススメです。

Docker Desktop for Macでコンテナがマウントしてるボリュームを調べる

動機

仕事でRubyのバージョンアップを行いました。ローカルの開発環境ではDockerを使っているので、新しいバージョンのRubyをインストールするようDockerfileを書き換えてイメージをビルドしました。

イメージのビルド後、あたらしいバージョンのRubyで bundle installを実施しました。すると以下のようなメッセージが表示されました。

1
Ignoring (gem名) because its extensions are not built.

古いgemが残っているからなのだと思うのですが、ちょっと気持ち悪いので対処したいと思いググってみました。すると、どこかのサイトにgemのインストールディレクトリをまっさらにしてからもう一度 bundle installするとよい、と書かれていたのでその通りにすると、アプリケーションが全く動かなくなってしまいました。bundle installは実行できますが、すでにgemはインストール済という認識でなにも行ってくれません。

docker-compose.ymlを見ると、マウントしているボリュームにbundle installしているようです。そのボリュームを調べたいと思いました。

ボリュームの一覧表示

ボリュームの一覧表示をするにはdocker volume lsを実行します

1
2
3
4
5
6
$ docker volume ls
DRIVER VOLUME NAME
local 0d506af3b9c55280acce2e034fb7ff2b6f19c9c23192e6de91ac406702236f8d
local 2f6589f1ec9c16dd1fcdc638aa2df316c3d1e5fa9c712651e8b61997ca26d0d1
local 3c8d4c4aa95221be36b5adc472549440e7330764ad3b8bef08f37d4d59f4d4ba
...

かなりの数があります。

使っていないものもあるのだろうなと思い、フィルタオプションでボリュームが参照されているかどうかを指定して(dangling=true)使っていないボリュームの一覧を表示してみます。(参照されていない時がtrue。ドキュメントはこちらです。danglingとは宙ぶらりんという意味のようです。)

1
2
3
4
5
6
$ docker volume ls -f dangling=true
DRIVER VOLUME NAME
local 0d506af3b9c55280acce2e034fb7ff2b6f19c9c23192e6de91ac406702236f8d
local 2f6589f1ec9c16dd1fcdc638aa2df316c3d1e5fa9c712651e8b61997ca26d0d1
local 3c8d4c4aa95221be36b5adc472549440e7330764ad3b8bef08f37d4d59f4d4ba
...

ほとんどが使われていないボリュームのようです。

では利用されていないボリュームを削除します。ボリュームを削除するにはdocker volume rmコマンドを利用します。VOLUME NAMEを一つずつ指定して削除することもできますが、大変なので一気に削除します。

1
2
3
4
5
$ docker volume ls -qf dangling=true | xargs docker volume rm
2f6589f1ec9c16dd1fcdc638aa2df316c3d1e5fa9c712651e8b61997ca26d0d1
3c8d4c4aa95221be36b5adc472549440e7330764ad3b8bef08f37d4d59f4d4ba
5cb87cee19c530d3dc8e903a93501333ebdb7b191a220a24c6eec4b8cc1151f7
...

削除されたボリューム名が表示されます。

これですっきりしました、残ったボリュームは数個しかありません。ではそれらのボリュームの詳細をみていきたいと思います。

ボリュームの詳細確認

ボリュームの詳細を確認するにはdocker volume inspectコマンドを利用します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ docker volume inspect web_bundle
[
{
"CreatedAt": "2020-07-16T13:09:21Z",
"Driver": "local",
"Labels": {
"com.docker.compose.project": "web",
"com.docker.compose.version": "1.25.4",
"com.docker.compose.volume": "bundle"
},
"Mountpoint": "/var/lib/docker/volumes/web_bundle/_data",
"Name": "web_bundle",
"Options": null,
"Scope": "local"
}
]

マウントポイントが記載されています。中身をみてみます。

1
2
$ ls -l /var/lib/docker/volumes/web_bundle/_data
ls: /var/lib/docker/volumes/web_bundle/_data: No such file or directory

どういうことでしょうか…

Dockerホストにログイン

少しググってみると、Docker Desktop for MacはDocker Desktop HyperKit VMが動作していて、Mac上で仮想マシンが動いているということでした。ですとMacのファイルシステムにそのパスは存在せず、Mac上で動いている仮想マシンに存在するということになります。

その仮想マシン(Dockerホスト)にログインするにはどうするのか調べてみると、screenというコマンドでログインできるようです。screenについての詳細はman screenで確認しました。

screenコマンドでDockerホストに接続します。

1
$ screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty

パッと見、接続できたかどうかわかりづらいですが、エンターキーを押すと、docker-desktop:~#とプロンプトが表示されます。切断するときはCtrl-a Ctrl-kです。
Ctrl-dを押すとおなじみのクジラが表示されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
docker-desktop:~# __  __

Welcome to LinuxKit

## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""__/ ===
{ / ===-
_____ O __/
__/
_________/

docker-desktop login: root (automatic login)

Welcome to LinuxKit!

NOTE: This system is namespaced.
The namespace you are currently in may not be the root.
System services are namespaced; to access, use `ctr -n services.linuxkit ...`
login[72826]: root login on 'ttyS0'

ボリュームの確認

ではボリュームを確認します。

1
2
3
4
5
6
7
8
9
10
11
12
docker-desktop:~# ls -l /var/lib/docker/volumes/web_bundle/_data
total 84
drwxr-xr-x 2 root root 4096 Jul 16 13:09 bin
drwxr-xr-x 2 root root 4096 Apr 3 15:49 build_info
drwxr-xr-x 3 root root 4096 Apr 3 15:49 bundler
drwxr-xr-x 3 root root 20480 Jul 16 11:59 cache
-rw-r--r-- 1 root root 60 Jul 16 13:09 config
drwxr-xr-x 4 root root 4096 Jul 14 02:21 doc
drwxr-xr-x 3 root root 4096 Apr 3 15:50 extensions
drwxr-xr-x 264 root root 16384 Jul 16 11:59 gems
drwxr-xr-x 4 root root 4096 Jul 14 01:47 ruby
drwxr-xr-x 2 root root 20480 Jul 16 11:59 specifications

このボリュームはRailsアプリケーションで利用するgemのインストールディレクトリです。Dockerコンテナでbundle installを行うとこのボリュームのファイルが更新されます。

まとめ

  • dockerで利用しているボリュームはdocker volumeコマンドで確認ができる
  • Docker Desktop for Macは仮想マシンで動作している
  • MacからDockerホストに接続するにはscreenコマンドを利用する

RailsアプリケーションでGitHub Actionsを試す

前回のまとめ

前回は空のアプリケーションでGitHub Actionsを動作させてみました。今回はもう少し実践的にRailsアプリケーションを動作させてみようと思います。

Railsアプリケーションの準備

Railsアプリケーションはこちらで準備しました。

GitHub Actionsの作成

前回GitHub Actionsを作成したように、作成したRailsアプリケーションのリポジトリを選択した状態で、Actionsタブをクリックします。

RailsアプリケーションのGitHub Action template

Rails用はないようです。とりあえずSet up this workflowをクリックして雛形を作成します。

Railsアプリケーションのworkflow

workflowの設定

今回は、workflowでRailsのテストの実行まで行いたいと思います。

トリガー

1
2
3
4
5
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

トリガーは前回と同じように、masterブランチの更新と、masterブランチへのPullRequest作成(更新)時になっています。

ジョブ

1
2
3
jobs:
test:
runs-on: ubuntu-latest

testというジョブが予め作成されています。ランナーマシンはubuntu-latestです。

Rubyのインストール

前回のRailsアプリケーションの作成ではRubyの現時点での最新版を指定しました。が、workflowでは初期値2.6を指定しており、一致しておらず、Your Ruby version is 2.6.6, but your Gemfile specified 2.7.1というエラーが出ます。ですので、workflowのRubyバージョン指定を2.7.1に変更します。

1
2
3
4
5
6
7
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@ec106b438a1ff6ff109590de34ddc62c540232e0
with:
ruby-version: 2.7.1
- name: Install dependencies
run: bundle install

サービスコンテナの利用

前回、RailsアプリケーションのデータベースとしてMySQLを設定しました。MySQLをランナーマシン上で動かしてもよいのですが、GitHub Actionsではサービスコンテナというものが使えるので使ってみましょう。

サービスコンテナについてはドキュメントがしっかりしていたので、参考になりました。

ランナーマシンがDockerホストのように動作し、その上にコンテナを立ち上げるイメージです。ですので、ランナーマシン上でジョブを実行するときに、サービスコンテナと通信を行うにはlocalhostのポートをマッピングするだけで可能です。ドキュメントにも以下のように記載されています。

ジョブをランナーマシン上で直接実行する場合、サービスコンテナにはlocalhost:もしくは127.0.0.1:を使ってアクセスできます。 GitHubは、サービスコンテナからDockerホストへの通信を可能にするよう、コンテナネットワークを設定します。

なるほど!簡単ですね!

サービスコンテナの設定でハマる

まず、先ほどのジョブにサービスコンテナを設定します。

1
2
3
4
5
6
7
services:
mysql:
image: mysql:5.6
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: root

ランナーマシンのローカルポート3306をコンテナの3306にマッピングします。環境変数でrootのパスワードも設定します。

次に、Railsのデータベース接続設定を行います。CI用のdatabase.ymlを作成します。

1
2
3
4
5
6
7
8
9
test:
adapter: mysql2
encoding: utf8
collation: utf8_general_ci
username: root
password: root
host: localhost
database: github_actions_for_rails_test
reconnect: false

これをdatabase.yml.ciとして保存し、ジョブ内でdatabase.ymlにリネームします。

1
2
3
4
5
6
7
- name: Setup Database
env:
RAILS_ENV: test
run: |
cp config/database.yml.ci config/database.yml
./bin/rails db:create
./bin/rails db:migrate

masterへのPullRequestを作成し、workflowの動作確認を行うと、以下のようなエラーが表示されました。

1
Mysql2::Error::ConnectionError: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

MySQLへの接続に失敗しているようです。ランナーマシンのlocalhost:3306をmysqlコンテナの3306にマッピングしているので問題なさそうです…

原因がわからないので、一度サービスコンテナを使わずにランナーマシンにインストールされているMySQLを起動してみます。

サービスコンテナの記述を削除し、Setup Databaseを以下のように書き換えます。

1
2
3
4
5
6
7
8
- name: Setup Database
env:
RAILS_ENV: test
run: |
sudo systemctl start mysql
cp config/database.yml.ci config/database.yml
./bin/rails db:create
./bin/rails db:migrate

この場合は接続可能でした。
しかし、やはりサービスコンテナを利用したいです。

ドキュメントにはlocalhostでも127.0.0.1でもよいと書かれていたので、127.0.0.1を接続先として設定し試してみます。すると、先ほどのConnection Errorは出ず、マイグレーションが行われました。

Railsアプリケーション特有の問題かどうかわかりませんが、localhostではなく127.0.0.1を接続先として指定することで解決しました。

最終版のconfig/database.yml.ciは以下のようになります。

1
2
3
4
5
6
7
8
9
test:
adapter: mysql2
encoding: utf8
collation: utf8_general_ci
username: root
password: root
host: 127.0.0.1
database: github_actions_for_rails_test
reconnect: false

workflowは以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby

name: Ruby

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
test:

runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.6
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: root

steps:
- uses: actions/checkout@v2
- name: Set up Ruby
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
# change this to (see https://github.com/ruby/setup-ruby#versioning):
# uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@ec106b438a1ff6ff109590de34ddc62c540232e0
with:
ruby-version: 2.7.1

- name: Setup Database
env:
RAILS_ENV: test
run: |
cp config/database.yml.ci config/database.yml
./bin/rails db:create
./bin/rails db:migrate
- name: Run tests
run: ./bin/rails test

まとめ

GitHub ActionsでCIの設定を行ってみました。GitHub Actionsはとても評判の良いCI/CDツールです。コード管理しているプラットフォームで行えるという点がとても良いと思います。今後も積極的に使っていきたいと思います。

次回は今回のようなまっさらなRailsアプリケーションではなく、プロダクション環境で稼働中のRailsアプリケーションでGitHub Actionsを動作させてみたいと思います。

その次くらいにAWS ECSにデプロイする処理を書いてみたいと思います。