#初めに
今回は**Docker, CircleCI, AWS等、人気の高まっているインフラ技術を一から学んで、Webアプリを作成してみました。
バックエンドはLaravel、フロントエンドにVue.js**等といった構成です。
この記事では、アプリ開発にあたって苦労した点や、
各機能実装の際に参考にした記事や教材についてもご紹介していければと思います。
#アプリの概要
朝活をテーマをしたSNSアプリです。
- 朝活仲間を作り、「コツコツ」継続できる
- 朝活習慣の「コツ」を共有して、朝活の挫折を防ぐ
ことをコンセプトに、「朝活」を文字って**「AsaKotsu」**というサービスを開発しました。
URLはこちら↓です。 よければ、ご自由に動かしてみてください
※現在公開停止中です
アプリのURL:https://pf.asakotsu.com
GitHubのURL:https://github.com/ngsw877/asakotsu
###使用画面のイメージ
###このアプリの特徴
基本的にはtwitterのような投稿、コメント、いいね、フォロー機能のあるSNSですが、
その他に以下のような特徴のあるアプリです。
- アプリから、朝活Zoomミーティングを作成、編集、削除できる(ZoomAPI連携)
- 目標起床時間を設定して、早起き達成日数を記録することができる
- 早起き達成日数のランキング機能(1ヶ月ごとに集計)
- 投稿にタグ付けし(カテゴリ)、「朝コツ」タグ等で朝活のコツを共有することができる
#使用技術
-
フロントエンド
- Vue.js 2.6.11
- jQuery 3.4.1
- HTML / CSS / Sass / MDBootstrap
-
バックエンド
- PHP 7.4.9
- Laravel 6.18.36
- PHPUnit 8.5.8
- ZoomAPI (guzzlehttp/guzzle 7.0.1)
-
インフラ
- CircleCi
- Docker 19.03.12 / docker-compose 1.26.2
- nginx 1.18
- mysql 5.7.31 / PHPMyAdmin
- AWS ( EC2, ALB, ACM, S3, RDS, CodeDeploy, SNS, Chatbot, CloudFormation, Route53, VPC, EIP, IAM )
サーバーサイドのロジックはPHP/Laravelでプログラミングし、
フロントエンドの細かいデザインはSassで整え、動きを付けたい時はVue.jsやjQueryで実装しました。
開発環境にDocker/docker-composeを使用し、
CI/CDパイプラインに関しては、CircleCIで自動テスト・ビルドを行い、
AWSのCodeDeployで自動デプロイを実現するようにしています。
#インフラ構成図
####開発環境、本番環境について
開発環境にDocker / docker-compose
を使用しており、以下の4つの用途のコンテナを使用しています。
- Webサーバーのコンテナ: Nginx
- アプリケーションのコンテナ: PHP / Laravel / Vue.js
- DBのコンテナ: MySQL
- DB管理用のコンテナ: PHPMyAdmin
参考リンク:
本番環境のAWS上ではECSでデプロイしたかったのですが、
難易度が高く断念・・
ひとまずEC2でのデプロイ経験にも慣れるため、今回はEC2上で環境構築していく形で進めていきました。
####SSL証明書の発行
SSL証明書を発行してHTTPS化も実現したかったため、ACM(AWS Certificate Manager)
を使用しています。
ACMを使用するためには、EC2に加えて、ALB(ELB)
やCloudFront
も必要になってくるため、今回はALBを導入することにしました。
なお、ALBを使用しているものの、節約のため現状では負荷分散やスケールアウトする程のアクセスが見込まれないため、EC2インスタンスは1つのみ用意しています。
なお、アドレスバーに鍵マークがついても、Laravel側のプロキシ設定をしないとcssやjsファイルが読み込まれなかったり、ルーティングがhttps化されなくなるので要注意な印象。。
参考リンク:
####S3バケットへのアップロード
S3は、以下の2つの用途別に用意しています。
-
CircleCIでビルドしたソースを格納
-
EC2上のアプリでアップロードした画像データを格納
2に関しては、S3のバケットポリシーの設定や、Laravel側でS3用パッケージのインストールが必要だったりと意外にやるべきことがありました。
参考リンク:
####Slackへの通知設定
CodeDeploy
とSNS
、Chatbot
を連携して、自動デプロイの開始と終了のタイミングでSlackアカウントに通知が飛んでくるようにしています。なかなか便利。
#機能一覧
-
ユーザー登録関連
- 新規登録、プロフィール編集機能
- ログイン、ログアウト機能
- かんたんログイン機能(ゲストユーザーログイン)
→かんたんログイン機能の実装方法を、こちらの記事にまとめました。
Laravel6系でゲストログイン機能(かんたんログイン)の実装
-
ZoomAPI連携
- 朝活Zoomミーティング機能(CRUD)
- ミーティングの新規作成、一覧表示、編集、削除機能
- 朝活Zoomミーティング機能(CRUD)
-
早起き達成の判定機能
- ユーザー毎に目標起床時刻を設定可能(4:00〜10:00まで)
- 目標起床時間より前に投稿をすることができれば、早起き達成記録が1日分増えます。
- ※深夜過ぎ等に投稿した場合も早起き成功とならぬよう、
目標起床時間より3時間前に投稿しても無効になるよう対処しています。
(例)目標起床時間を07:00に設定した場合、04:00~07:00に投稿できたら早起き達成
- ※深夜過ぎ等に投稿した場合も早起き成功とならぬよう、
-
ユーザーの早起き達成日数のランキング機能(1ヶ月毎)
-
無限スクロール機能 (jQuery / inview.js / ajax)
-
ユーザー投稿関連(CRUD)
-
コメント機能
-
タグ機能 (Vue.js / Vue Tags Input)
-
いいね機能 (Vue.js / ajax)
-
フォロー機能
- フォロー中/フォロワー一覧(ページネーション)
-
フラッシュメッセージ表示機能 (jQuery/ Toastr)
- 投稿、編集、削除、ログイン、ログアウト時にフラッシュメッセージを表示
-
画像アップロード機能 (AWS S3バケット)
-
PHPUnitテスト
-
レスポンシブWebデザイン(※徐々に追加しています)
- ハンバーガーメニュー(jQuery)
#DB設計
ER図
各テーブルについて
テーブル名 | 説明 |
---|---|
users | 登録ユーザー情報 |
follows | フォロー中/フォロワーのユーザー情報 |
achievement_days | ユーザーが早起き達成した日付を、履歴として管理 |
meetings | ユーザーが作成したZoomミーティング情報 |
articles | ユーザー投稿の情報 |
tags | ユーザー投稿のタグ情報 |
article_tags | articleとtagsの中間テーブル |
likes | 投稿への、いいねの情報 |
comments | ユーザー投稿への、コメントの情報 |
早起き達成機能 関連のポイント
usersテーブルのwake_up_time
はユーザーの目標起床時間を意味しています。
この時間よりも早い時間にユーザーが投稿をできれば、その日の早起きが達成となります。
なお、
「目標起床時間が07:00で、深夜1:00に投稿した」
というように、早過ぎる時間にユーザーが投稿した
場合にも早起き達成とならないように設定しています。
その仕組みとして、usersテーブルのrange_of_success
の値が利用されています。
これは、
「目標起床時間より何時間前までに投稿すれば早起き達成となるのか、その範囲を表す整数値」
です。
デフォルトは3
で、例えば目標起床時間を07:00に設定している場合は、その3時間前の
04:00 〜 07:00 の間に投稿できれば早起き達成となります。
こうして早起き達成をすることができたら、achievement_daysテーブルのdate
に達成日の日付が履歴として記録されていきます。
例) 2020-11-22
この日付データを利用して、以下の機能を実現しています。
① 1ヶ月毎の早起き達成日数を算出
② ①の日数を利用したランキング機能
当初は、早起き継続日数のランキングにしようかとも考えていましたが、
ユーザーのモチベーション維持等の観点から1ヶ月毎の早起き達成日数を採用することにしました。
※朝活アプリなので、もともとは目標起床時間04:00~10:00の間しか設定できない仕様ですが、
現在は「早起き達成判定」機能を好きな時間にお試しいただけるよう、時間設定を自由にできるようにしています。
#苦労したこと
開発からデプロイまで、どの工程でももれなくエラーで苦戦しましたがw、
ここでは特に印象に残っている点をまとめます。
##CircleCIで苦労したこと
- CircleCIの設定ファイルである、config.ymlの設定
- 自動ビルド、自動テストの流れの理解
config.ymlの設定においては、だいぶエラーに悩まされました。。
特に、コマンドやパスを指定する時は、パスのルートはどこが起点になっているのかを理解することが重要な印象。
テスト失敗時の対策としては、ビルドされたコンテナにSSHログインしてエラーログを確認し、原因を解消していくようにしていました。
参考リンク: SSH を使用したデバッグ
##AWSデプロイで苦労したこと
- ACMでのSSL証明書発行
- Laravelで画像をS3にアップロードする設定
- CodeDeployでの、自動デプロイ設定(特にappspec.yml)
- EC2インスタンスのセットアップ
上述した、
SSL証明書の発行
S3バケットへのアップロード
周りでエラーにハマりがちでした。
また、今回はECSでなくEC2でデプロイすることとしましたが、EC2にSSHログインしてから
インストールしたり設定するファイルが多く、その辺りの作業も大変でした。
この工程を考えると、ますますECSを扱えるようになりたく思いましたね^^;
##フロントエンドで苦労したこと
- UI/UXの調整(Sass)
- Ajax全般
##バックエンドでの苦労
- DB設計
- DBリレーション関連の処理
- PHPUnitでのテスト全般
リレーション周りについては当初なかなか苦戦しました。
どのテーブルとどのテーブルを関連付けるのか、そして関連付けた情報をどうやって取得すれば良いのか?
また、
- $article->user()
- $article->user
例えばこの2つの違いについても重要なポイントと感じました。
PHPUnitのテストコードについては、体系的に学べる情報がなかなか見つからなかったので、情報収集に苦労しましたね。
##ZoomAPI連携で苦労したこと
- Guzzleの理解
- ZoomAPIの理解
アプリ上からZoomミーティングを作成したり編集できる機能をつけることにしましたが、
これまで外部APIを利用したことがなかったこともあり、文法的なものや、API通信の仕組みについて理解するまでが難しく感じました。
実装にあたり、まずLaravelでZoomAPIと通信を行うために、PHPのHTTPクライアントである
Guzzleをインストールしました。
参考リンク:
次に、Zoomアプリマーケットプレイスでアプリを登録し、公式ドキュメントを読んでみるも、英語な上初めはどこのページの何を見れば良いのかわからず苦戦しました。。^^;
しかし、Laravelで、ZoomAPIと通信を行う処理のサンプルコードを紹介している
海外の記事を参考にしたり試行錯誤しているうちに、次第に公式ドキュメントから必要な情報を探せるようにもなってきました。
参考リンク:
ただ、今回Laravel6系でアプリを開発していたため、通常Laravel7系で使用できるGuzzleラッパーが使えず、ややコードを書き換えないといけない点にも苦労しました。
参考にした学習教材等
基本的には、UdemyとTechpitで学習してきました。
この2つはとてもわかりやすいです。
個人的には、Udemyで基礎を学んでから、応用編としてTechpitで手を動かしながら学ぶのが良いと感じました。
###Docker / docker-compose
###AWS
-
【Udemy】AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得
→AWSの基礎を掴むにはとてもわかりやすい教材です(ハンズオン形式) -
【書籍】Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂3版
→こちらも良書として有名。わかりやすいですが、上記Udemy教材と内容が似ているので買うのはどちらかで良いかもしれません。 -
【Udemy】これだけでOK! AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座(SAA-C02試験対応版)
→AWSの理解をより深めたい場合や、AWSの認定資格の勉強もしたい場合等に。
###PHPUnit / CircleCI / AWS
###PHP
###Laravel
###Laravel / Vue.js
###Sass
#今後の課題
- レスポンシブWebデザイン(スマホ対応)
- デザイン面の改善
- 無限スクロールの不具合修正(読み込まれた投稿のいいねボタンが消える)
- ALBにAuto Scalingを追加し、EC2を冗長化
- ECS(EKS)でのデプロイ
- RDSの冗長化
- インフラのコード化
- テストコードの充実
- 投稿時に別画面へ遷移するのではなく、入力フォームをモーダルで表示させるようにする
- 開始前のZoomミーティング、終了ミーティングのソート機能
まだ課題も多いですが、一つずつ改善してよりブラッシュアップしていきたく思います。
だいぶ長い記事になってしまいましたが、ここまで読んでくださりありがとうございました!^^