AWS, Docker, CircleCI, Laravelでポートフォリオを作成してみた【参考リンク付き】

#初めに

今回は**<font color="SteelBlue">Docker</font>**, **<font color="SteelBlue">CircleCI</font>**, **<font color="SteelBlue">AWS</font>**等、人気の高まっているインフラ技術を一から学んで、Webアプリを作成してみました。
バックエンドは**<font color="MediumAquaMarine">Laravel</font>**、フロントエンドに**<font color="MediumAquaMarine">Vue.js</font>**等といった構成です。

この記事では、アプリ開発にあたって苦労した点や、
各機能実装の際に参考にした記事や教材についてもご紹介していければと思います。

#アプリの概要

朝活をテーマをしたSNSアプリです。

* 朝活仲間を作り、「コツコツ」継続できる
* 朝活習慣の「コツ」を共有して、朝活の挫折を防ぐ

ことをコンセプトに、「朝活」を文字って**「AsaKotsu」**というサービスを開発しました。
URLはこちら↓です。 よければ、ご自由に動かしてみてください

※現在公開停止中です
~~アプリのURL：https://pf.asakotsu.com~~

GitHubのURL：https://github.com/ngsw877/asakotsu

###使用画面のイメージ

トップページ（投稿一覧とランキング等）
![スクリーンショット 2020-11-16 8.00.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/cf1c1ea2-5a3e-fbcf-ae1b-772e55141b12.png)

タグ毎の投稿一覧
![スクリーンショット 2020-11-22 20.10.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/120b28b4-af86-d23d-ab12-8aa5c6232ba8.png)

投稿詳細と、コメント一覧
![スクリーンショット 2020-11-22 20.05.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/bc44ba04-361b-9817-acc9-2ce9da89fd30.png)

Zoomミーティング一覧
![スクリーンショット 2020-11-16 22.44.58 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/80cb57df-8cf4-9284-8e48-6070c8dc9426.png)

ユーザー詳細画面
![スクリーンショット 2020-11-16 23.06.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/1f5f32c4-ee2c-4842-9fea-c6049c689640.png)

早起き達成時（１日１回まで）
![スクリーンショット 2020-11-22 20.03.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/87a3f6d6-924a-25e6-16e9-12bd39e86b28.png)

無限スクロール
![infinitscroll.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/ea04f26f-d1cb-2610-a236-15f80e31e28e.gif)


###このアプリの特徴

基本的には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で自動デプロイを実現するようにしています。

#インフラ構成図

![AWS_Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/c405b8d3-5864-1674-ec7d-2e041a98ec69.png)


####開発環境、本番環境について
開発環境に`Docker / docker-compose`を使用しており、以下の４つの用途のコンテナを使用しています。

1. Webサーバーのコンテナ： Nginx
1. アプリケーションのコンテナ： PHP / Laravel / Vue.js
1. DBのコンテナ： MySQL
1. DB管理用のコンテナ： PHPMyAdmin

参考リンク：

- [絶対に失敗しないDockerでLaravel+Vueの実行環境（LEMP環境）を構築する方法〜前編〜](https://qiita.com/shimotaroo/items/29f7878b01ee4b99b951#8docker-composeyml%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)

- [絶対に失敗しないDockerでLaravel6.8+Vueの実行環境（LEMP環境）を構築する方法〜後編〜](https://qiita.com/shimotaroo/items/679104b7e00dd9f89907)

- [phpMyAdmin on docker が便利すぎる
](https://qiita.com/furu8ma/items/50718efebee20fd24517)

本番環境のAWS上ではECSでデプロイしたかったのですが、
難易度が高く断念・・
ひとまずEC2でのデプロイ経験にも慣れるため、今回はEC2上で環境構築していく形で進めていきました。

####SSL証明書の発行
SSL証明書を発行してHTTPS化も実現したかったため、`ACM(AWS Certificate Manager)`を使用しています。

ACMを使用するためには、EC2に加えて、`ALB(ELB)`や`CloudFront`も必要になってくるため、今回はALBを導入することにしました。
なお、ALBを使用しているものの、~~節約のため~~現状では負荷分散やスケールアウトする程のアクセスが見込まれないため、EC2インスタンスは1つのみ用意しています。
なお、**アドレスバーに鍵マークがついても、Laravel側のプロキシ設定をしないとcssやjsファイルが読み込まれなかったり、ルーティングがhttps化されなくなる**ので要注意な印象。。

参考リンク：
- [AWS：無料でSSL証明書を取得する方法](https://qiita.com/iwaseasahi/items/1687426add4124899fe3)
- [信用するプロキシの設定](https://readouble.com/laravel/6.x/ja/requests.html)
 

####S3バケットへのアップロード
S3は、以下の２つの用途別に用意しています。

1. CircleCIでビルドしたソースを格納

1. EC2上のアプリでアップロードした画像データを格納

2に関しては、S3のバケットポリシーの設定や、Laravel側でS3用パッケージのインストールが必要だったりと意外にやるべきことがありました。

参考リンク：

- [Rails, Laravel(画像アップロード)向けAWS(IAM:ユーザ, S3:バケット)の設定](https://qiita.com/nobu0717/items/4425c02157bc5e88d7b6)
- [LaravelでAWS S3へ画像をアップロードする](https://qiita.com/nobu0717/items/51dfcecda90d3c5958b8)


####Slackへの通知設定
`CodeDeploy`と`SNS`、`Chatbot`を連携して、自動デプロイの開始と終了のタイミングでSlackアカウントに通知が飛んでくるようにしています。なかなか便利。


#機能一覧

* __ユーザー登録関連__
  * 新規登録、プロフィール編集機能
  * ログイン、ログアウト機能
  * かんたんログイン機能（ゲストユーザーログイン）<br>
  　→かんたんログイン機能の実装方法を、こちらの記事にまとめました。<br>
　　[Laravel6系でゲストログイン機能（かんたんログイン）の実装](https://qiita.com/nasuB7373/items/5b00007c4f73dd55e0cb)

* __ZoomAPI連携__
    * 朝活Zoomミーティング機能(CRUD)
      * ミーティングの新規作成、一覧表示、編集、削除機能

* __早起き達成の判定機能__
  * ユーザー毎に目標起床時刻を設定可能（4:00〜10:00まで）
  * 目標起床時間より前に投稿をすることができれば、早起き達成記録が１日分増えます。<br>
    * ※深夜過ぎ等に投稿した場合も早起き成功とならぬよう、<br>
   　  目標起床時間より3時間前に投稿しても無効になるよう対処しています。<br>
       （例）目標起床時間を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図

![AsaKotsu_ERD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/393cb6d0-0b10-918b-f79b-321805de41f8.png)

#### 各テーブルについて

| テーブル名 | 説明 |
|:-:|:-:|
| 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 を使用したデバッグ](https://circleci.com/docs/ja/2.0/ssh-access-jobs/)

##AWSデプロイで苦労したこと

* ACMでのSSL証明書発行
* Laravelで画像をS3にアップロードする設定
* CodeDeployでの、自動デプロイ設定（特にappspec.yml）
* EC2インスタンスのセットアップ

上述した、
[SSL証明書の発行](####SSL証明書の発行)
[S3バケットへのアップロード](####S3バケットへのアップロード)
周りでエラーにハマりがちでした。
また、今回はECSでなくEC2でデプロイすることとしましたが、EC2にSSHログインしてから
インストールしたり設定するファイルが多く、その辺りの作業も大変でした。
この工程を考えると、ますますECSを扱えるようになりたく思いましたね^^;


##フロントエンドで苦労したこと

* UI/UXの調整（Sass）
* Ajax全般

##バックエンドでの苦労

* DB設計
* DBリレーション関連の処理
* PHPUnitでのテスト全般

リレーション周りについては当初なかなか苦戦しました。
どのテーブルとどのテーブルを関連付けるのか、そして関連付けた情報をどうやって取得すれば良いのか？
また、

* $article->user()
* $article->user

例えばこの２つの違いについても重要なポイントと感じました。

PHPUnitのテストコードについては、体系的に学べる情報がなかなか見つからなかったので、情報収集に苦労しましたね。


##ZoomAPI連携で苦労したこと

* Guzzleの理解
* ZoomAPIの理解

アプリ上からZoomミーティングを作成したり編集できる機能をつけることにしましたが、
これまで外部APIを利用したことがなかったこともあり、文法的なものや、API通信の仕組みについて理解するまでが難しく感じました。

実装にあたり、まずLaravelでZoomAPIと通信を行うために、PHPのHTTPクライアントである
**Guzzle**をインストールしました。

参考リンク：

* [Guzzle 7 公式ドキュメント(英語)](https://docs.guzzlephp.org/en/latest/)
* [今時のPHP HTTPクライアントのGuzzleを使ってみた](https://qiita.com/yousan/items/2a4d9eac82c77be8ba8b)

次に、[Zoomアプリマーケットプレイス](https://marketplace.zoom.us/)でアプリを登録し、公式ドキュメントを読んでみるも、英語な上初めはどこのページの何を見れば良いのかわからず苦戦しました。。^^;

しかし、Laravelで、ZoomAPIと通信を行う処理のサンプルコードを紹介している
海外の記事を参考にしたり試行錯誤しているうちに、次第に公式ドキュメントから必要な情報を探せるようにもなってきました。

参考リンク：

* [ZoomAPI 公式ドキュメント(英語)](https://marketplace.zoom.us/docs/api-reference/introduction)
* [Manage Zoom Meeting Rooms through Zoom API with Laravel](https://kim-jangwook.medium.com/manage-zoom-meeting-rooms-through-zoom-api-with-laravel-ff40b89f921b)

ただ、今回Laravel6系でアプリを開発していたため、通常Laravel7系で使用できるGuzzleラッパーが使えず、ややコードを書き換えないといけない点にも苦労しました。


# 参考にした学習教材等

基本的には、**Udemy**と**Techpit**で学習してきました。
この2つはとてもわかりやすいです。
個人的には、Udemyで基礎を学んでから、応用編としてTechpitで手を動かしながら学ぶのが良いと感じました。

###Docker / docker-compose

* [【Udemy】米国AI開発者がゼロから教えるDocker講座
](https://www.udemy.com/course/aidocker/)

###AWS
* [【Udemy】AWS：ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得](https://www.udemy.com/course/aws-and-infra/)<br>　→AWSの基礎を掴むにはとてもわかりやすい教材です（ハンズオン形式）
* [【書籍】Amazon Web Services 基礎からのネットワーク＆サーバー構築　改訂3版](https://www.amazon.co.jp/Amazon-Web-Services-%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%81%AE%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%EF%BC%86%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E6%A7%8B%E7%AF%89-%E6%94%B9%E8%A8%823%E7%89%88-%E5%A4%A7%E6%BE%A4-ebook/dp/B084QQ7TCF/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=aws&qid=1606093752&sr=8-2)<br>　→こちらも良書として有名。わかりやすいですが、上記Udemy教材と内容が似ているので買うのはどちらかで良いかもしれません。
* [【Udemy】これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座（SAA-C02試験対応版）](https://www.udemy.com/course/aws-associate/)<br>　→AWSの理解をより深めたい場合や、AWSの認定資格の勉強もしたい場合等に。


###PHPUnit / CircleCI / AWS
* [【Techpit】Laravel × CircleCI × AWSで学ぶCI/CD](https://www.techpit.jp/courses/78)

###PHP
* [【Udemy】PHP+MySQL（MariaDB） Webサーバーサイドプログラミング入門](https://www.udemy.com/course/php7basic/)

###Laravel
* [【Udemy】PHPからLaravelまで サーバーサイドをとことんやってみよう【初心者から脱初心者へ】【わかりやすさ最重視】](https://www.udemy.com/course/phpbeginnertolaravel/)

###Laravel / Vue.js
* [【Techpit】Laravel(+Vue.js)でSNS風Webサービスを作ろう！](https://www.techpit.jp/courses/11)

###Sass
* [【Udemy】CSSを効率的に書く！フロントエンドエンジニアのための「Sass」講座 ~基礎から実践まで~](https://www.udemy.com/course/sass-for-frontend-engineer/)


#今後の課題

* レスポンシブWebデザイン（スマホ対応）
* デザイン面の改善
* 無限スクロールの不具合修正（読み込まれた投稿のいいねボタンが消える）
* ALBにAuto Scalingを追加し、EC2を冗長化
* ECS(EKS)でのデプロイ
* RDSの冗長化
* インフラのコード化
* テストコードの充実
* 投稿時に別画面へ遷移するのではなく、入力フォームをモーダルで表示させるようにする
* 開始前のZoomミーティング、終了ミーティングのソート機能

まだ課題も多いですが、一つずつ改善してよりブラッシュアップしていきたく思います。


だいぶ長い記事になってしまいましたが、ここまで読んでくださりありがとうございました！^^