My Day One

毎日東京の隅っこでコードを書いているエンジニアのブログです。

良い睡眠習慣をつけて睡眠を改善したい人のためのサービス、Sleepleをリリースしました

はじめに

この記事はタイトルの通り、「自作サービスをリリースしたよ!みんな使ってみてね!」という趣旨のものです。

私は1年ほど前までフロントエンドエンジニアとして働いていたのですが、サーバーサイド(Rails)の開発を中心に行う部署に異動になったという背景もあり、昨年からフィヨルドブートキャンプというRailsを中心に学習できるブートキャンプに参加していました。

メンターや運営には、RailsRuby界隈ではとても有名な方々もおり、直接その人たちに質問ができたり、コードレビューをしてもらえるなどの良い機会も提供していただきました。この場を借りてお礼申し上げます。そして今後ともよろしくお願いいたします。

この記事では主に、今回リリースした自作サービスの紹介や、どんなことを考えながら作ったか、フィヨルドブートキャンプでは何が一番楽しかったか、逆に何が大変だったかなどをつらつらと書いていこうと思います。

どんなサービスを作ったのか?

今回私は、Sleeple(すりーぷる)

sleeple.app

という、良い睡眠のための習慣が身についているかのチェックができるサービスを作りました。

Sleepleの機能はとてもシンプルで

  • 睡眠習慣チェックリストにあるリストを、寝る前にチェックする

これだけです。

具体的なユーザーの動作としては、以下のようなチェックリストが出てくるので、これに対して、「はい」「いいえ」を選択するだけです。

これによって、日々の生活の中で良い睡眠習慣が身についているかをチェックすることができます。

そして、それらを意識して生活をすると、もしかしたら睡眠の質がちょっと上がるかもしれません。

来年こそは「睡眠を改善するぞ!」って思っている方にもおすすめです。

なぜこれを作ったのか?

多くの人が、寝る直前までスマホを見ていてすぐに眠りにつけなかったり、昼に寝過ぎてしまって深夜まで目が冴えてしまったりした経験があると思います。私自身も数年前まではそんな日が年に10回程度ありました。ただ、ある時読んだ本を参考に睡眠を改善していったところ、そういった日がなくなっただけでなく

  • 夜まで集中力が持続するようになった
  • 頭の中がクリアになり、余計なことを考えることが減った
  • 体調を崩すことがほぼなくなった

といったことが自分の体感として出てくるようになりました。

自分の体調などがいくつかの習慣のおかげで良くなったことから、睡眠に悩んでいる人の助けになるようなサービスを作ってみたいと思い、今回の開発をするに至りました。

技術スタック

使い方

先ほど少し触れましたが、とてもシンプルなものです。 まずユーザー登録をしていただいた上で、夜寝る前に

  • 睡眠習慣チェックシートに回答する

これだけです。

なお、定期的にチェックシートに記入していくと、カレンダーが埋まっていき、自分の習慣がどういう風に推移しているかが直感的にわかるようにしています。

作っていく上で大変だったこと

サービスを作る上で一番大変だったなと思うのは、「何を提供するか」を決めることだったように思います。 自分がイラッとすることや、身の回りで困っている人を助けることができるものはなんだろうか...と考えて、企画を出してはボツになったり、案を考えても、自分がやりたいことでもなかったりして、かなり苦しんだ記憶があります。

結局は、お風呂の中で頭の中に浮かんだ、良い睡眠の習慣を身につけることで、可処分時間を増やしたり、心身ともに健康になれたりすることができたな...ということを思い出し、「それが広がればいいな」と考えました。その時のアイデアを形にすることにして、Sleepleを作っていくことに決めました。

しかし、サービスの内容が決まった後も、「この機能はなんのためだろうか?」「この機能は本当にユーザーのために必要なんだろうか?」ということを考えて、答えが出ないまま1週間くらい過ぎてしまうなんてこともあり、自作サービスを作るのは大変だな...と改めて認識させられました。

また、Railsの開発は仕事でもやっていたのですが、個人開発は普段の仕事とは違い、企画、デザイン、インフラ、法務など、普段誰かがやってくれていることも自分でやらなくてはいけないので、そのあたりのキャッチアップや調査もそこそこ時間を使ったように思います。

もちろんRailsの実装でも、devise使ったログインとかGithub Actionsの設定などは、仕事ではやったことがなかったので、そのあたりは色々と調べながら進めていったため、決してサクサク進んだわけではありませんでした。

それでも、なんとかサービスのリリースまでこぎつけることができたのは

  • 忙しくても15分は取り組む
  • 自分の中で仮説を失ってわからない状態になったら周囲に助けを求める

というルールを決めて、そのルールに沿って取り組んでいったからかなと今では思います。

フィヨルドブートキャンプについて

最後に、少しフィヨルドブートキャンプ全体についても振り返ってみようと思います。

フィヨルドブートキャンプは、初心者からでもプログラミングを学ぶことのできる場所です。

HTMLやCSSvimの使い方などをやるところからスタートして、RubyJavascriptの基礎→RailsやVue.jsというフレームワークを使った簡易的なアプリの機能実装→自作npmのリリース→実際のチーム開発などを経て、自作サービスの企画と制作を行っていくので、段階を踏んで実力をつけていくことができます。

私のようにエンジニアの経験がある人からすると、最初の方の課題は簡単すぎる部分もありますが、自作npmや、Rubyの課題で中盤の山場になる lsコマンドの自作やボウリングのスコア計算のプログラムをオブジェクト指向で書く、など、ある程度経験のあるエンジニアでもすんなりいかないような課題も出てきてやりがいがあります。(私もlsコマンドのオブジェクト指向には苦戦しました...)

私はRailsエンジニア歴2ヶ月くらいのタイミングで参加したので、最初の方はスムーズに進んだのですが、後半になるにつれ難しいなと感じることも増えていった印象があります。

それでも、豪華(かつ人間性もとても高い...)メンターの方々や、一緒に課題を進めている受講生とコミュニケーションをとりながら進めることで目の前の問題を解決でき、モチベーションを大きく落とすことなく、自作サービスのリリースまで完走することができました!

難しい課題をやるときはしんどい時もありましたが、チーム開発と自作サービスの開発に入ってからは楽しいことの方が多く、休日や平日の仕事の前後の時間があっという間になくなっていきました。笑

あと、フィヨルドブートキャンプのコミュニティはとても人間性が高い方が多いので、RubyRailsの実装にアドバイスをいただいたり、わからないことをどんどん質問できるのもよかったです。自分が卒業してからも交流は続けたいなと思っています。

最後に

今回、自作サービスのリリースにあたり、フィヨルドブートキャンプの方々のみならず、学生時代の友人や妻にも協力をしていただいたり、別のエンジニアコミュニティの方にも相談をさせてもらったりしました。 コードを書いたのは100%自分ですが、そうした方々の協力がなければリリースができなかったと思いますので、改めて皆様にお礼をお伝えしたいと思います。

サービスそのものはこれからブラッシュアップしたり、言語やフレームワークのアップデートなども行っていきたいなと思いますので、また進捗があったらブログに書こうかなと思います。

というわけで、来年以降も技術力や経験値を上げていって、「テクノロジーを分かりやすく伝えて、一歩前に進む人を増やす」という仕事の目的に向かって進んでいきますので、みなさま今後ともよろしくお願いいたします!!!

【ネットワークの基礎】DNSとは?

はじめに

この記事は「DNS」という用語に焦点を当てて、できる限り初心者でもわかりやすいようにまとめたものです。 できるだけわかりにくい表現や用語、仕組みを話さないようにすることを心がけているので、細かいところにはあまり触れず、大枠を掴んでもらうために書いています。

そのため、若干内容を端折ったりする部分もありますがそこはご容赦ください。

DNSとは

さて、早速ですが、「DNS」って何なんでしょうか?

先に答えを言ってしまうと、DNSはDomain Name Systemの略で、ドメイン名とIPアドレスの対応関係を管理する仕組みのことを指します。

DNSはインターネットの世界において、とても大事なものです。 正直、これがないと、インターネットの世界は成り立たないと言っても過言ではありません。 インターネットがつながらないというわけではないですが、少なくともDNSがない世界では、人間がインターネットを使いたいとは思わないでしょう。そのくらい大事な要素です。

もちろん他の要素(例えばLANがちゃんと動いているかとか)も重要ですが、とにかくDNSがないと我々が当たり前に享受している「ブラウザでネットサーフィンすること」もままならなくなりますし、何か思い立って検索...なんてこともしなくなるでしょう。

それはなぜでしょうか?

実はDNSがないと、blog.hatena.jpyahoo.co.jp のようなドメイン名とIPアドレスの関係性がわからず、私たちは「192.168.1.1 がはてなってサイトで、192.168.1.2がYahooってサイトで...」という具合に、意味不明な数字の文字列を覚えて、正確に打ち込まないとそのページにアクセスできなくなります。

上記の2個だったらいいのですが、世界には無数のIPアドレスがあり、好きなページやサービスを100個、200個暗記するのも大変です。 IPアドレスを間違って覚えたり、打ち間違えたりすると、見たいページやサービスにアクセスできないわけですし、とても不便ですよね。

この不便さを解消するにあたり、DNSが活躍するわけです。

DNSのおかげで我々は、yahoo.co.jpとかgoogle.comみたいな名前を覚えておくだけで(しかも大半はブラウザが補完してくれる)、世界中のサイトやサービスにアクセスできるようになります。

ありがとうDNS!!!

ドメイン名とは

さて、DNSの偉大さはここまででわかったかと思いますが、先ほど私は「ドメイン名とIPアドレスの対応関係を管理する」と書きました。IPアドレス先日の記事で少し触れましたが、ドメイン名とは何を指しているのでしょうか?

実は、IPアドレスと役割はほぼ同じで、インターネット上の住所を表しています。IPアドレスと表記の仕方が違うだけで、結局は住所を人間にわかりやすく表示するためのものです。

ちなみにドメイン名は世界にたった1つしかありません。当然、google.com は世界に1つしかないですし、会社や個人で作ったしがないサービスでも、ドメイン名は1つしかありません。勝手に複数作ることもできません。

このドメイン名とIPアドレスの対応関係を管理するのがDNSというわけです。

ちなみに、ドメイン名をよく見ると、yahoo.co.jp のように . で繋がれた形になっていますが、これにもちゃんと意味があります。

これを . で区切ったところで分解すると yahoocojp に分かれます。これらをドメインといいます。ドメイン名とは少し違って、ドメインは、ネットワーク上のコンピュータのグループ(集まり)を表す単位だと考えればよく、ドメイン名を構成する1つの要素であるという感じで理解をするとわかりやすいのではないかと思います。

ドメインについてもう少し説明しますと、ドメインはツリー構造の形式になっており、一番上に「ルートドメイン」が存在します。

その下にトップレベルドメイン、そしてその下に別のドメイン群...という風になっていて、例えば jpcomorgトップレベルドメインにあたります。

例えば、yahoo.co.jpjp (日本)という国のドメイン群にある、 co という企業を表すドメイン群にある yahoo という企業のページですよ、というふうに分解することができて、ドメイン名というのは、それぞれの名前を . を使って繋げたものだということです。

色々なドメインがあるので、その組み合わせでドメイン名が成り立っているということですね。それによって、ドメイン名がたった1つに決まるようになっています。

ドメインドメイン名、DNSという用語についてはある程度理解できたかと思いますので、次の話にうつりましょう。

私たちがブラウザにドメイン名を入力した時に、どのようにIPアドレスを探しにいっているのでしょうか?

DNSの仕組み

DNSドメイン名とIPアドレスの対応関係を管理する仕組みのこと、であると先ほど書きました。対応関係を知ることができればいいので、基本的にはその情報を持った表があり、そこにアクセスするような形になります。

なので、IPアドレスを知りたいと思ったら、DNSサーバー(ネームサーバーともいう)にそれを問い合わせます。

以下のような図のイメージです。ちなみにこの時、OSにある名前解決のための仕組みである「DNSゾルバ」と呼ばれるものを使って、ネットワーク上のDNSにアクセスしています。

ただし、あくまでこの図はイメージであり、1台のDNSサーバーが世界中のドメイン名とIPアドレスを管理しているわけではありません。

実際はドメインの階層ごとに管理するサーバーが存在していて、それぞれの階層のサーバーに問い合わせながら、IPアドレスを知るという形になっています。

ルートサーバーに問い合わせて、その次はトップレベルドメイン(.jpとかを管理する)サーバーに問い合わせて...というような形で、最終的に求めているドメイン名のIPアドレスを取得します。

例えば yahoo.co.jp というドメイン名のDNSの流れとしては、ざっくり以下のようになります。

  1. ルートサーバーにjpサーバーのアドレスを聞く
  2. jpサーバーにco.jpサーバーのアドレスを聞く
  3. co.jpサーバーにyahoo.co.jpサーバーのアドレスを聞く

上記のような過程を経て、IPアドレスを知ることになります。

もう少し細かいことをいうと、必ずルートサーバーを経由してIPアドレスを尋ねるようになると、ルートサーバーへの負荷がとんでもないことになってしまうので、DNSキャッシュサーバーと呼ばれるものを介してIPアドレスを知ることが一般的になっています。

DNSキャッシュサーバーは、過去のDNS情報をキャッシュに保存しておき、同じ問い合わせに対しては、上位のDNS(ルートサーバーとか)に問い合わせを行わず、キャッシュに保存された情報から回答するという役割を担っていて、基本的にはキャッシュサーバーを介して、我々はIPアドレスを知ることになります。

こうした仕組みを設けることで、キャッシュサーバーにないものだけをルートサーバーや他のドメインのサーバーに問い合わせる形にして、負荷を軽減しています。

上記の内容を図にまとめると以下のようになります。

このような形でDNSは動いており、日々、我々のインターネットにおける利便性を高めてくれています。DNSは開発していても普段意識しないですが、とても重要な技術なんですね〜。こんな仕組みを作ってくれた先人に感謝です。

というわけで、今日はこの辺でおしまいにしようと思います。最後まで読んでくださりありがとうございました!

【ネットワークの基礎】インターネットの仕組み

はじめに

この記事はネットワークの基礎的な知識を勉強した私が、頭の中を整理するために書いたものです。 対象読者は、これからプログラミングを勉強する方や、最近Webエンジニアになった方など、実務においてはネットワークをそこまで意識していない方となります。

今回は、インターネットがどうやって動いているかをざっくりと理解をするために、細かい部分や難しい部分はあまり触れずに、大まかな流れを理解できることを目指します。

この記事で出てくる用語

以下は、この記事に出てくる用語です。どれか1つでも知らない場合は、この記事は読む意味があるかもしれません。

インターネットとは?

空気と同じように存在するのが当たり前になったインターネットですが、これはそもそもなんなのでしょうか?

一言で言えば、パソコンやスマホから流れるデータを、目的地まで運んでくれる便利な仕組みです。 これのおかげで我々はWebサイトを閲覧してイベントに申し込んだり、ECサイトでものを買ったり、SNSで有名人の投稿にコメントをできるようになっているのです。

申込ボタンを押したら申込が完了しますし、ECサイトで購入したら物が届きますし、(運が良ければ)有名人からコメントが返ってきたりするわけで、とても便利ですよね。

インターネットの中を流れるもの

色々なことができるインターネットですが、インターネットの中は、どんなものが流れているのでしょうか? 例えばWebサイトを閲覧しようとしたときには、「こんにちは!」といった文字列や、犬の画像が流れてやってくるのでしょうか? 実はそんなことはなく、流れてくるものは単なるビットと呼ばれるものです。

そもそも、コンピューターは文字列や画像をそのまま扱えるわけではなく、ビット、という0か1かで判別できる単位でしか物事を扱えません。 「A」という文字列は 100 0001 という、はたから見たら全くもって意味不明なデータでしかやりとりができないのです。

だからその形でやりとりをするしかないわけで、ビットを使って文字列や画像を表現していくことになります。

とはいえ、ビットを1つずつしか送れないとそれはそれで大変なので、データがインターネット上を流れる際には、ビットの集合体である「パケット」と呼ばれる状態にして文字列や画像などのデータをやりとりします。

厳密にいうと文字列や画像のデータも1つのパケットに全て詰め込まれているわけではなく、分割されてパケット同士を後でくっつけたりするわけですが、その辺りの話はまたの機会に。

インターネットは「パケット」をやりとりするための仕組みなわけで、このパケットに注目して考えると、インターネットやネットワークのことが理解しやすくなると思います。

パケットはどこに送られる?

さて、先ほど出てきたパケットですが、これはそもそも、どこに送られるのでしょうか?

ここで、Webサイトを閲覧する場合を考えてみましょう。

Webサイトを閲覧する際には大きく括ると、以下の2つのことをしています。

① Webサイトの内容をください!と要求する

② Webサイトの内容を送り返す

このやりとりにパケットというビットの集合体を使い、データをやりとりしているわけです。

しかし、ここで1つ疑問が浮かびます。ください!と要求する(あるいは内容を送り返す)のはどこに対してするのでしょうか? 全世界に向かってするのでしょうか?それは非効率極まりないですし、仮に正しいところが見つけられてもすぐに返答が来ることはまずないでしょう。データを特定のところに送りたいわけですが、これでは目的地がわからない状態です。

つまりデータは、ちゃんと目的地を知らないと、どこにいったら良いかわからないのです。なんだか人間みたいですね。

なので、まずはデータの最終的な目的地をまずは決めなくてはいけません。 データの最終的な目的地はIPアドレスと呼ばれるものです。

IPアドレスというのはインターネット上の住所で、192.168.0.1 のような表記をします。細かい話はあるのですが、今は「そういう風に表記するんだな」くらいの理解で十分です。

例えば、先ほどの「Webサイトの内容をください!」と要求するにもパケットを送って要求するのですが、そのパケットはインターネットに出ていく前に、最終目的地(=IPアドレス)を知ることになります。それがあって初めて、パケット自身がどこにいくかがわかるようになるのです。

では、そのIPアドレスはどのように見つけてくるのでしょうか?

それを見つけてくる仕組みがDNS(Domain Name System)です。

DNSとは?

DNS(Domain Name System)とは何でしょうか?

これは一言でいうと、IPアドレスドメイン名を紐付けるための仕組みです。

イメージとしては以下のような表と同じような感じです。

id 名前
1 AAA
2 BBB
3 CCC

idがIPアドレスに変わり、名前がドメイン名に変わるというふうに考えると、以下のような対応表が存在していると理解できるかと思います。

IPアドレス 名前
192.168.0.1 aaa.com
192.168.0.2 bbb.com
192.168.0.3 ccc.com

ドメイン名というのは、「人間が識別しやすいようにしたインターネット上の住所」 だと考えればよく、それは blog.hatena.ne.jp のようなものです。

つまり、 blog.hatena.ne.jp のような人間が理解できる文字列と 192.168.0.1 のような数字の羅列が対応していることが示されている上記のような表があるのです。

これによって、IPアドレスを知ることができ、我々はインターネットでデータをやりとりすることができるようになっています。

さて、ここでもう一度、Webサイトを閲覧する例を考えてみましょう。

私たちはWebサイトを閲覧する際に、必ずURLを打ち込んでいますが、それはhttps://blog.hatena.ne.jp のようなものですよね。これの、blog.hatena.ne.jp の部分を見て、パソコンやスマホ(のOS)はIPアドレスを探しにいきます。

図で示すとこんな感じです。

DNS

DNSゾルバという難しそうなワードが出てきましたが、これはざっくりいうと、DNSを使ってIPアドレスを知るためのソフトウェアなので、それによってIPアドレスをゲットできるもの、くらいの理解でいいと思います。

さて、IPアドレスを無事に入手できたら、次にやることは「どのように最終目的地までいくか」を決めることです。

実はIPアドレスを知っていても、パケットはそこまで勝手に動いてくれるわけではありません。

人間は、もしかしたら最終目的地を伝えたら、勝手に電車や車でいくかもしれないですが、パケットはそうではありません。どこを経由するのか、次の目的地はどこか、などを都度決めてあげないと動くことができないのです。

では、パケットはどのように動いていくのでしょうか?

パケットの旅の様子

いままでの話の中で、

  • パケットは最終的な目的地(=IPアドレス)をDNSのおかげで知ることができる

ということまでは理解できたかと思います。

しかし、ここまでの話だけでは、パケットは実は全く動くことができません。

最終目的地は分かったけれど、まずはじめどこに行ったらいいか、パケットは知らないのです。

なので、最初の行き先を教えてあげます。

基本的には、パケットの最初の行き先はPCと繋がっているブロードバンドルーター(多くの人の家の中にある、縦長の箱みたいなやつ)になるので、そのブロードバンドルーターの住所を教えてあげる必要があります。

ちなみに、ブロードバンドルーターの住所というのは、IPアドレスではなく、MACアドレスというものになるので、IPアドレスと混同しないように注意が必要です。

IPアドレスMACアドレスの違いは、ざっくり以下の通りです。

いまの話の中では、パケットが「次にどこに行くか」を教えてあげる必要があるので、IPアドレスではなく、ブロードバンドルーターのMACアドレスを知る必要があります。

そのためにはARPというプロトコルを使ってMACアドレスを知ることになるのですが、細かい話を書くとわかりにくくなってしまうので、「パケットが次の目的地を知るためにARPというプロトコルを使うんだな」くらいの理解でOKです。

ARPのおかげでブロードバンドルーターのMACアドレスを知ったら、パケットはブロードバンドルーターまで移動ができるようになります。

そして次に、インターネットプロバイダー@niftyとかso-netとか)が持っているルーターに向けて、移動をします。 このタイミングでは、インターネットプロバイダーが持っているユーザーデータベースとの照合を行って、問題なければインターネットプロバイダールーターに対してパケットが到達します。

ここまできて、ようやくインターネット(世界中のネットワークにつながったシステム)にデータを流すことができるようになりました。

インターネットそのものは、ASと呼ばれる自律システムの集合で成り立っていて、そこの中では、IPアドレスを元に、どのルートを通って最終目的地(=IPアドレス)に辿り着くかを決定した上でパケットを運びます。(これをルーティングといいます)

パケットが目的地に届いたら

この仕組みのおかげで、パケットは最終目的地であるIPアドレスに到達することができます。

今回の話の前提としては、Webサイトのデータを閲覧するための要求を送って、 Webサイトのデータを送り返す、というものなので、その最終目的地のIPアドレスまで到達した後は、最終目的地のIPアドレスが割り振られているWebサーバーに要求が届きます。

それに応じて、今度はWebサイト側が必要なファイルを送信元(要求をしてきた送信元)に対して送り返します。

送り返す際の仕組みはパケットを送った際と同じなので割愛しますが、そのデータを受け取った送信元は、Webブラウザを使って、HTMLとかCSSとかを解析してWebサイトを閲覧することになります。

終わりに

いかがだったでしょうか? 今回は、極力難しい話を省いて、インターネット上をどうやってデータが流れて、どのようにやりとりされているのかを知ることができたと思います。もう少し細かい話はまた今後書くとして、少しでもインターネットの仕組みについて理解を深めていただけたのであれば幸いです!

ネットワークの分野はとっつきづらい部分もありますが、理解できると面白いので、これからも少しずつアウトプットを進めていければと思っています。

Herokuの代替サービスであるrender.com でRailsアプリをデプロイする

本記事の内容

  • Herokuの代替サービスになりうる render.com を使ったデプロイの方法をまとめています
  • Railsで作成した簡単なCRUD機能を搭載したアプリを render.com にデプロイするまでの手順を説明します
  • Redisなどを使った実装や設定は含まれていないので、ご了承ください

前提

  • 何らかのRailsアプリが開発環境で正しく動作するようになっている
  • RailsアプリのRDBMSPostgreSQLを使っている
  • render.com へのアカウント登録が済んでいる
  • 開発している言語やフレームワークのバージョンは、Ruby 3.1.2、Rails 6.1.6

render.com とは

Herokuと似た、WebアプリやWebサイトなどを簡単にWeb上に公開できるツールの1つです。render.com のサイトでは Render vs Heroku にあるように、Herokuをかなり意識したサービスになっています。 この比較のページでは、Herokuよりも簡単でフレキシブル、その上料金も安いよ!というような内容が書かれています。

後で詳しく書きますが、基本的にはアプリケーション側のコードを少し書き換えて、ポチポチと設定していくだけでアプリを本番環境に反映することができる素敵なサービスです。

細かいHerokuとの比較は、日本語で書かれたこちら の記事がとても詳しくて分かりやすいので、興味のある方はご覧ください。

render.com の料金体系

2022年9月時点での情報ですが、$0 (無料)から利用できます。 Webサイトや基本的な構成のWebアプリであれば、お金のことを気にせず個人開発のアプリのデプロイなどに使うことができます。

ただ、無料の場合はいくつか気を付けなくてはならない点があります。 1つ目は、アプリケーションが非アクティブの状態が15 分間続くと自動的に停止され、次の新しいリクエストが来た時に再開する、という仕組みになっており、これが起きると、ページにアクセスして20-30秒後にレスポンスが返ってくるようになってしまいます。これはさすがに遅すぎてよくないので、ひとまず個人開発のポートフォリオを作っていて、本番環境にデプロイを試したい、というレベルでなければ有料にした方が良いと思います。(特にユーザーがすぐについてほしいと思っている場合など)

2つ目は、デプロイまでにかかる時間が有料に比べて遅いということ。ちゃんと計測したわけではないですが、無料の場合、ものすごく簡素なRailsアプリをデプロイするのに4-5分かかるのに対して有料にすると2分程度でデプロイまでされていましたので、開発上のストレスという点でも有料の方が良いです。

3つ目は、これはデータベースを使うWebアプリに限った話になるのですが、PostgreSQLの無料期間は3ヶ月であり、それを超えると月$7 からの有料プランにアップグレードする必要があります。

無料でWebサイトやWebアプリを簡単にWeb上に公開できる!という点は確かにそうなのですが、いくつかの条件付きで、という観点は頭に入れておく必要があります。

有料プランを使った場合でも、2022年9月時点でのHerokuの有料版の最安値と比較すると、render.com の方が安いと思いますので、料金面でも若干お財布に優しいサービスであると思います。 (HerokuはDyno + Heroku Postgres、render.comは Services + PostgreSQLの最安値プランの合計値の比較)

Heroku render.com
$7 + $9 = $16 $7 + $7 = $14

と、ここまでは render.com の紹介を主にしてきましたが、次の節からはいよいよデプロイ手順を説明します。 基本的にはドキュメントの通りにやれば良いのですが、初心者の方でも分かりやすいようにできるだけ丁寧に説明していきます。

render.comを使ったデプロイ手順

ここからは、render.com にアカウント登録を済ませているという前提で話を進めていきますので、もしまだ登録されていない方がいましたら先に登録をお願いします。

render.com にWebアプリケーションをデプロイする場合、Web Serviceの作成とデータベースの作成をする必要があります。そのため、設定の内容を2つのパートに分けて説明します。

render.com 側の設定(Web Serviceの作成)

まずはWeb Serviceの作成です。

はじめに、render.com のDashboardに進みます。右上にある+Newのボタンを押して、Web Serviceを選択します。

すると、GitHubなどと連携するためのページに進むので、GitHubとの連携をして、対象のリポジトリを選びます。

対象のリポジトリについては全てを対象にすることもできますし、自分で選択したもののみを設定することもできます。 以下の画面は、私のGitHubのページの設定です。1つのリポジトリのみを設定しています。

対象のリポジトリを選択したら、いくつか必要な設定をすることになりますので、以下を参考に入力してみてください。

  • Name: 何でもいいですが、わかりやすい名前にしておきましょう。こちらは後から変更可能です
  • Environment: Railsのアプリをデプロイする前提なので、Rubyを選びます
  • Region: 現状、東京リージョンがないのでシンガポールを選びましょう。(2022年に東京リージョンも追加される予定とのこと)
  • Branch: デプロイしたいブランチを設定できます。mainで良いと思いますが、とりあえず別ブランチで試したいという方は別ブランチを設定すればOKです。あとから変更可)
  • Build Command: 一旦デフォルトのままで問題ありません。
  • Start Command: こちらも一旦デフォルトのままで問題ありません。
  • Advanced: 環境変数などの設定ができます。こちらも後から変更可能です。(最低限、master_keyの設定は後で必須となります)

設定画面のイメージは以下です。

いきなりお金がかかると嫌という方もいると思いますので、ひとまずfreeプランを選択して先に進みます。

問題なくWeb serviceが作成されたと思いますが、最後に、Railsのアプリケーションを本番環境でデプロイする際に必要な RAILS_MASTER_KEY を設定しておきます。

先ほどのAdvancedの箇所でも設定できるので、すでにやっている方は読み飛ばしてください。

Dashboardに戻ると、先ほど作成したWeb Serviceが一覧に表示されているかと思いますので、そちらをクリックします。

遷移した先のページの真ん中あたりにずらっとタブが並んでいて、その中のEnviromentをクリックします。

Environmentをクリックすると、本番環境用の環境変数の設定ができる画面に遷移するので、RAILS_MASTER_KEY の値に config/master.key に書かれている値を設定し、Save Changesをクリックします。(これを設定しておかないと、デプロイができません)

ひとまず、ここまでで、render.comのWeb Serviceの作成は終了となります。

render.com 側の設定(データベース作成)

続いて、データベースの作成と設定をします。こちらも先ほどと同様に render.com の画面から行います。

先ほどのWeb Serviceの作成と同様に、Dashboardの右上にある +New ボタンを押して、PostgreSQLを選択します。

すると、以下のような画面に遷移します。

入力項目は

  • Name: render.com 上で表示されるDBの名前です。後で変更できます。
  • Database: PostgreSQL の dbnameを設定します。
  • User: PostgreSQL接続時に必要なユーザー名です。
  • Region: Web serviceと同じ項目です。シンガポールを選択しましょう。
  • PostgreSQL Version: PostgreSQLのバージョンです。デフォルトで14になっていますが、必要に応じて変更しましょう。

注意事項として、Database, User、PostgreSQL Versionはあとから変更できないはずなので、設定時には気をつけましょう。もし間違えてしまった場合は、データベースを一度消して、再度作り直せば問題なく修正できます。

上記の必要な情報を入力していき、Create Database ボタンを押します。少し待つとstatusがAvailableになり、データベースが使えるようになります。

これで、データベースの作成も完了しました。

ここまでは、render.com側でRailsアプリをデプロイするための準備をしましたが、ここから先はRailsアプリ側に必要な設定を行なっていきます。一部コードを書き換える必要があるので、その点はご注意ください。

Railsアプリ側の設定

Railsアプリ側の設定については、ドキュメントを読みながら進めていくこともできます。

基本的にドキュメントを翻訳した形になりますが、この記事でもRailsアプリ側の設定内容を説明していきます。

1. config/database.ymlの編集

  • productionのセクションに行き、DATABASE_URLの環境変数を使うようにします。
production:
  # 他の記述がある場合はそれもそのまま残しておく
  <<: *default
  url: <%= ENV['DATABASE_URL'] %>

2.config/puma.rbの編集

  • workers ENV.fetch("WEB_CONCURRENCY") の記述を追記します。(コメントアウトを外して数値を4に変更します)
  • preload_app! の記述を追記します(コメントアウトを外します)
(中略)
workers ENV.fetch("WEB_CONCURRENCY") { 4 }
(中略)
preload_app!

3.config/environments/production.rbの編集

  • RENDER環境変数(これは常にRenderにある)が存在する場合、パブリックファイルサーバーを有効にします。
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? || ENV['RENDER'].present?

4.ビルド用のscriptを作成する

  • アプリのビルドに必要なコマンドを実行できるように設定します。
  • bin/render-build.sh を作成します(binフォルダ配下にrender-build.shというファイルを作成)
  • bin/render-build.sh の内容は以下の通りです。
#!/usr/bin/env bash
# exit on error
set -o errexit

bundle install
bundle exec rake assets:precompile
bundle exec rake assets:clean
bundle exec rake db:migrate
  • 以下のコマンドで、bin/render-build.sh の実行権限を設定しておきます。
chmod a+x bin/render-build.sh
  • 上記の内容を全て変更し、Gitリポジトリの対象ブランチにpushすれば、renderを使ってデプロイが始まります。

数分待ち、Dashboard内のWeb serviceの欄にDeploy Succeeded という表示があれば完了です!🎉

デプロイが失敗した時のエラー(私の場合)

私は最初にデプロイした時にエラーになり、 ! Unable to load application: LoadError: cannot load such file -- net/imap のようなエラーが出たのですが、こちら の記事と同じ対処法で解決しました。

Blueprintsを使ったデプロイについて

実は、render.com で Webアプリをデプロイするには、先ほど説明したダッシュボードを使用してサービスを手動で設定する方法と、render.yaml ファイルでリポジトリ内のサービスを宣言する方法との 2 つがあります。

この後者の方法を使うために利用されるのがBlueprintsという機能です。

これを使うメリットとしては

  • アプリケーションの構成をわかりやすくひとまとめにすることができる
  • Render.com にどのような構成のサービスを作成するかを管理することができる

という点が挙げられるでしょう。Infrastructure as code(IaC) を render.com で実現できるということですね。便利です。

Blueprintsを利用する手順は以下の通りで、とてもシンプルです。

  • ルートディレクトリに render.yaml という名前のファイルを作成する。(このファイルには、RailsのWeb サービスと、アプリケーションで使用されるデータベースに関する情報が含まれます)
  • render.yamlを以下のように編集して、mainブランチに pushしておく
databases:
# mysiteは設定した際の内容を確認して書き換える
  - name: mysite
    databaseName: mysite
    user: mysite

services:
  - type: web
    name: mysite
    env: ruby
    buildCommand: "./bin/render-build.sh"
    startCommand: "bundle exec puma -C config/puma.rb"
    envVars:
      - key: DATABASE_URL
        fromDatabase:
          name: mysite
          property: connectionString
      - key: RAILS_MASTER_KEY
        sync: false
  • pushしたら render.com の DashboardからBlueprintのページに移動して、New Blueprint Instance ボタンをクリックします。

対象のリポジトリを選択し、デプロイ ウィンドウで、RAILS_MASTER_KEY の値を config/master.key ファイルの内容に設定した上で、Update Existing Resourcesをクリックするとデプロイがスタートします。

こんな感じで、単にデプロイするだけであればそんなに大きな労力を割くことなく進めることができるため、Herokuの代替サービスには確かになるなと思いました。

長くなってしまったので今回の記事はここまでにして、次回は render.com を使ったカスタムドメインの設定を書きたいと思います。

【Rails】gem deviseを使ってメール認証を実装した時に落ちるテストの対応

本記事の内容

deviseを使ってメール認証の機能を追加した際に、既存のテストが落ちてしまうという事象に遭遇しました。 今回の記事はそのテストが落ちないように修正した際に、どういった対応をしたのかをまとめたものになります。

状況

  • gem deivseを使ってログイン機能はすでに実装済
  • ログイン機能に関してのrpsecのコードも存在している(before { sign_in user } などのコード)
  • ログイン機能は実装していたが、ユーザーのアカウント登録時にメール認証の機能をつける必要があると判断したため、その機能を追加した
  • メール認証の機能を追加したところ、ログインが関係しているテストが全て落ちるようになった
  • Rubyのバージョンは3.1.2、Railsのバージョンは6.1.6

テストを走らせた時のエラー内容①

Failure/Error: = link_to t('devise.mailer.confirmation_instructions.action'), confirmation_url(@resource, confirmation_token: @token)
      
      ActionView::Template::Error:
        Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true

エラーの原因①

エラーメッセージに書いてある通りではあるんですが、リンク先となるhostがないため、hostパラメータを指定するか、default_url_options[:host]を設定するか、:only_pathをtrueに設定するなどする必要があるようです。

解決策①

エラーメッセージを検索してみるといくつかそれらしい記事が出てきました。 下記の記事にある通り、config/environments/test.rb にhostに関しての情報を追記することで、上記のエラーはなくなりました。

config.action_mailer.default_url_options = { host: "localhost", port: 3000 }

k-koh.hatenablog.com

これで、一件落着、めでたしめでたし...と思ったが、まだテストを走らせてもエラーが出ていたのでそちらも調査...。

テストを走らせた時のエラー内容②

Failure/Error: expect(response).to have_http_status(:ok)
       expected the response to have status code :ok (200) but it was :found (302)

エラーの原因②

ここのエラーが出ている箇所は、ログインした後のユーザーがあるページに遷移した際、そのページが正しく表示されているかをテストしているんですが、200ではなく302(リダイレクト )してしまっているようです。 リダイレクト するということは、そもそもテストデータ上ではログインがうまくいっていないためと思われます。

また、ログイン周りがうまくいかなくなっていることが原因で、データの作成や更新などのテストも複数落ちていました。

解決策②

こちらもたまたま、ほとんど答えが書いてある記事を見つけ、userをログインさせる前に、ユーザーを認証させるためのコードを書く必要がありました。

<変更前>

before { sign_in user } 

<変更後>

# 複数行になったのでbefore do ~ endを使う
before do
  user.confirm # ここを追加
  sign_in user
end

qiita.com

これで、テストも全て通るようになりました!

エラーメッセージをきちんと読んで検索する、ということで今回は解決に至りました👍

標準入出力・ファイル・リダイレクト・パイプについて

はじめに

この記事は私の知識の整理のために、標準入出力・ファイル・リダイレクション・パイプについてまとめたものです。 webアプリの開発をするときにはそこまで意識しないことではありますが、開発者としては抑えておくべき基礎なので、それを自分なりに、他人に説明するくらいのスタンスでまとめてみました。 間違いなどあればご指摘ください!それでは書いていきます。

標準入力

これは、コンピューター上で実行されているプログラムが、何も特別な指定がされていない場合に利用するデータの入力元のことを言います。 少し分かりにくいと思うので、コマンドラインを例にとると

$ ls

とすると、結果が返ってきますよね。この ls が標準入力です。

標準出力

先ほどの標準入力(ls)を入力してEnterキーを押すと

Applications
Creative Cloud Files
Desktop
Documents
Downloads

みたいな感じでその結果が返ってきます。これが、標準出力です。 標準出力は、標準入力がプログラムに渡り、そこから出力される結果ということですね。

10 + 1 = 11 みたいな式があるとしたら、 10と1が標準入力、 10 + 1という演算がプログラム、 11が標準出力 といった具合です。

標準エラー出力

主にプログラムのエラーを表示するために使用されます。 ls コマンドで存在しないファイルを指定した場合、下記のようなエラーメッセージが表示されます。このエラーメッセージは標準エラー出力に表示されています。

$ ls /aaaaaa
ls: /aaaaaa: No such file or directory

ファイル

コンピューター上で管理される情報の単位のこと。ファイルの名前は人間が識別しやすいように名前がつけられています。sample.txthoge.html のようなものがそれに当たります。 ファイルはそれ単体でもコンピューター上に存在するが、XX関連のファイルをまとめておきたい、という場合にフォルダという単位でファイルを格納することもできます。

また、ファイルは主に、プログラムファイル、データファイルに分かれます。 プログラムファイルはJavascriptRubyなどで書かれたファイル(例えば sample.js sample2.rb など)を指し、データファイルはpngやjpgの画像ファイルなど、それ自体はコンピューター上で実行されず、プログラムによって読み込みまれるようなものを指します。

フォルダも管理する上での単位という意味ではファイルと同じですが、フォルダは「フォルダの中にファイルを入れることができ、かつ、フォルダも入れることができる」というのが1つの特徴です。

テキストファイル・バイナリファイルという分類もあり、テキストファイルは人間が識別できる文字や数字で書かれたファイルのことで、バイナリファイルは人間では読めない形式(コンピューターが読む前提の形式)でのファイルのことになります。

リダイレクト

標準入力、標準出力先を変更する機能のこと。 例えば cat コマンドは

$ cat file_name

のようにしてfileの中身を表示しますが、その出力先を変えたり、標準入力の元ファイルを変更したりするのに使うことができます。

リダイレクトは主に >< を使用して入出力をコントロールします。

例えば、ls -l コマンドで表示できる内容を、コマンドライン上に出力するのではなく、result.txt に送りたい、という場合は

ls -l list.txt

とします。これで、ls -l の結果が result.txt に全て入るようになります。書き込まれたかどうか確認するには

cat result.txt

で確認できます。

ただし、標準エラー出力

$ ls /aaaaaa > list.txt
ls: /aaaaaa: No such file or directory

のように単純にリダイレクトしても、コマンド上に表示されてしまうので

$ ls /aaaaaa 2> list.txt

のように 2> をリダイレクトに使うことでファイル内に格納します。

また、「コマンドの結果とエラーメッセージを別々のファイルに出力したい」というケースもあるかと思いますが、その場合は

$ ls /aaaaaa > list.txt 2> error.txt

のようにします。これは、実行結果は list.txt へ、エラーは error.txt へと送られるコマンドです。1行で書けて便利ですね!

コマンドの結果とエラーメッセージを合わせて1つのログファイルにしたい!というときは

$ ls / aaaaaa > result.txt 2>&1

のようにすることで、1つのファイルにまとめて出力できるようになります。

コマンドの意味合いとしては、最初の > が標準出力先を result.txt に設定するためのコマンド、次の 2>標準エラー出力の設定先を設定するためのコマンド、最後の &1 が標準出力と同じファイルへ出力先を指定するためのコマンド、といった具合です。2>&1 で1つのセットとしても良いかもしれません。これも便利です。

リダイレクトをすると、指定したファイル名と同じファイル名がある場合には、特別な設定を何もしなければ、その内容が上書きされてしまいます。

$ echo 10000 > number.txt
$ echo 99999 > number.txt

として、catで内容を表示すると

$ cat number.txt
99999

となり、元の10000は上書きされてしまいます。

上書きを防ぐには >> を使って、ファイルの末尾に追加する、というような処理を使います。

また、シェルのオプションで noclobber というオプションを使うとファイルの上書きの禁止ができるので、それを設定して上書きをさせない設定にするというのも1つの手段です。

パイプ

コマンドは1つ入力して出力させておしまいではありません。複数コマンドをつなげて、より複雑なこともできます。例えば、/binフォルダの中にあるファイルの、ファイルサイズが大きい順の3つを取得する、というようなこともできたりします。

それを実現するために必要なのが、パイプという機能です。

まずは例を見てみましょう。

$ ls -l / > sample_list.txt
$ less sample_list.txt

これでも結果を表示することはできますが、1行で書く方法でパイプを使用します。

$ ls -l | less

この例を見れば想像がつくかもしれませんが、パイプ(記号で表すと | )によって、前のコマンドの結果を次のコマンドに渡すことができるということです。実行結果を渡せるのは便利ですね。

このパイプを、フィルタと呼ばれる標準出力を入力として受け取り、標準出力に出力するコマンドと一緒に使うことで、/binフォルダの中にあるファイルの、ファイルサイズが大きい順の3つを取得する、ということを実際に書いてみます。

使うコマンドは3つで、 du、sort、head のみです。

  • duコマンド→-kオプションを渡すことで、ファイルのサイズをキロバイト数で表示する
  • sortコマンド→昇順(今回は小さい順)に並べる。デフォルトはアルファベット順だが、-nオプションをつけることでサイズ順に並べることができる。-rオプションをつけると逆順になる
  • headコマンド→上から順に取得した結果を表示する -n 3のようにオプションを渡すと上から3つを取得できる

という特徴を使ってコマンドを書くと

$ du -k /bin/* | sort -n -r | head -n 5

となり、出力結果は

720 /bin/ksh
368 /bin/zsh
340 /bin/bash
260 /bin/tcsh
260 /bin/csh

となります。キロバイト数の大きい順に表示され、やりたいことも達成できました。

コマンドラインはあまりちゃんと勉強してこなかったので、勉強すると基礎でも奥が深いなと感じました。

UNIX/Linuxについてまとめてみる

半年で自走できるバックエンドエンジニアになるためにアウトプット用のブログを作りました。 一応、数年コーダーやフロントエンドの開発に携わっていたこともあるので、全くの初心者ではありませんが、壊滅的にネットワークやインフラ、バックエンドのスキルがないため、勉強し始めました。

今回はUNIX/Linuxについてまとめていきます。

UNIXとは?

  • OSの一種である。
  • WindowsUNIXの2つのOSがあるが、大雑把にいうと、違いはGUIがメインかどうか。
  • UNIXのOSのベースはCUI
  • UNIXの中心にはカーネルがある
  • カーネルはCPU、メモリ、ハードウェア割り込みなど、ハードウェアに関することを管理
  • カーネルが中心となり、様々なソフトやドライバ、シェルなどが動いている
  • ちなみにシェルはコマンドインタプリタともいう

ファイルシステム

$ cd hoge

マウント

  • UNIXの場合はファイル構造が全てルートディレクトリから始まる
  • そのため、CD-ROMなどのファイルを指定する場合、ディレクトリを関連づけることでファイル構造を表現する
  • mnt/cdromに対して/develop/romを関連付けるようなイメージ
  • Windowの場合はこの概念がない

mnt/cdromに対して/develop/romを関連付けるようなイメージ、という表現はとてもしっくりきた。今までなんとなくみていたものが繋がった感じ。

シェル

  • キーボードからの入力を受けてそのコマンドを解釈、実行するプログラム
  • ユーザーとカーネルの間に立つ仲介役のようなもの
  • bash,zshなど様々な種類がある
  • どれを使用すべきというのはない
  • 過去に入力したコマンドを記憶するヒストリ機能というものがある
(base) MyMacBookpuro:~ username$ history 5
  542  ssh name@100.00.0.10
  543  ssh-copy-id -i ~/.ssh/id_rsa.pub name@100.00.0.10
  544  ssh-copy-id -i ~/.ssh/id_rsa.pub name@100.00.0.10
  545  ssh-copy-id -i ~/.ssh/id_rsa.pub name@100.00.0.10 -p 3000
  546  history 5
$ !542 

のようにすると一番上に表示されているコマンドを実行できるらしい。こんな機能もあるんだな。

ワイルドカード

  • *(アスタリスク)を使うことで、hogeで始まるファイル名とかを検索できたりする
$ ls hoge*

こうすると

hoge001
hoge002

のようなファイルを検索することができる

パイプ

  • あるコマンドの出力結果を別のコマンドの入力として使う機能 例えば ls コマンドで以下のような結果が出る場合
$ ls

abcd
abbc
acdc

dが入っているものを検索したいとしたら

$ ls | grep d

abcd
acdc

ls コマンドで出力したものを grep コマンドに渡すことで絞り込みを行うことができるようになる。 これは ls の後ろにある |のおかげでそれができるようになる。

シェル変数と環境変数

  • シェル変数は実行中のシェルの中で有効なもので、環境変数は新しいシェルや別のコマンドでも使える
$ HOGE=fuga

のようにするとシェル変数をセットでき、

$ export HOGE=fuga

のようにすると環境変数にセットできる。

なんかいつも何も考えずにexport PATH .... とやっているのもこれだったのだな。なるほど…

ファイルやディレクトリの所有権

  • ファイル、ディレクトリにはアクセス権が存在する
  • 操作するユーザーの立場によって、ファイルやディレクトリの操作を制限することができる

chmod コマンドはそれを設定するためのコマンド

$ chmod [-f] [-R] MODE FILE

のように使う。FILEに指定したファイルやディレクトリへのアクセス権が変更され、変更内容はMODEで受け付けるようになっている MODEは3桁の8進数で表示することができ、一番上の桁から順に、所有者のアクセス権、グループのアクセス権、その他のアクセス権、となっていて

例えばSSH接続する際によく出てくる

$ chmod 600 id_rsa

のような記述は

  • 所有者のアクセス権が6=読み込み権と書き込み権がある
  • グループ、その他はそれぞれ0=権限なし
  • 対象はid_rsa のように指定しているということ。

長くなってしまったので、一旦この辺りで。勉強になった。