ニートが実務案件にチャレンジした結果、少しだけ人生が好転した話。

<h1>自己紹介</h1>
アラサーの子供部屋おじさんです。大学中退/職歴無し。ついでに言えば恋人も無し。Tech○cade○yの受講歴はあるが転職できたわけでなし、人材価値はほとんどありません。特段語るべくもない日常をダラダラと過ごし、それでもいつか自分の能力を活かすことができたらと一人くすぶっていました。誰の役に立つこともないまま死んでいく恐怖はすごくある。しかしどうしたら良いか分からない。自分には何ができるのかも、何が得意なのかも分からない。学生の頃少しだけweb制作をしていた経験はあるものの、開発に関しては全くの未経験です。当然AWSなど一度も触ったことはなく、ひとり黙々と個人開発をしていたところ、巡り合わせで運よく開発案件に携われる機会を頂きました。開発を仕事にすることが悲願であった自分には、ありがたすぎるチャンスでした。前日はうまく寝付けず、web面談の日時まで何度もトイレに行ったり時間を確認したりと、とにかくソワソワしていたと思います。

<h1>こんな人に読んで欲しい</h1>
・プログラミングスクールを卒業した。
・エンジニアを志望しているが実務経験が無い。
・学歴・キャリアに自信が無い。
・自分は頭が悪いと思っている。
・自分には根性が無いと思っている。
・プログラミングで人生を逆転したい、それが可能だと思っている。

<h1>要件のヒアリング</h1>
個人でプログラミング教育サービスを運営している方から、
「実運用中サービスのデータモニタリング体制を整備して欲しい。」
最初に言われたのがこれです。
課題さえ解決されればそれでよい様子で、これまでの経歴やキャリアは特に問われることがありませんでした。
しかし未経験の私には、「モニタリングって何すんの？」、「意味不明！経験者に頼んでくれ！」自分から応募しておいて、そう思ったことを記憶しています。私は自分でサービスを作ったり、コーディングをしていた経験から、それまでの積み上げを少しくらいは活かせるのではないか？と考えていました。しかし現実は非情。これまでのポートフォリオから流用できそうなものは何ひとつなく、右も左も分からない中絶望してしまいました。クライアントからの要望を具体的にまとめると、データの分析が気軽にできていない現状、分析をする際には本番DBにアクセスせねばならず、KPIの定期モニタリングができていないという課題を解決して欲しいとのことでした。
要件は以下の通りです。

###機能要件
- SQLを自由に叩けること。
- モニタリング指標を変更できること。
- データベースに直接アクセスできること。
- モニタリングの各項目が数字で表されること。
- アクセス権限の設定ができること。

###非機能要件
- 個人情報が閲覧できないこと。
- 読み込み専用であること。
- 本番DBに負荷がかからないこと。
- 画面遷移がスムーズでストレスがないこと。
- エラーやサーバーの死活を検知できること。

![dokugaku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/7b3bc618-7718-b16e-6d30-a7b111d034aa.png)

現状本番DBにはSSH接続した踏み台サーバーを通してMySQLコマンドを実行するより他なく、データの分析が気軽にできないことが問題であるとのこと。
ユーザーに関する情報が視覚化されておらず、分かりにくいということも問題であったようです。


<h1>ソリューション考察</h1>
最初何らかのアプリケーションを構築して、本番環境にどうにか組み込むといったことを想像しました。しかし冷静に考えるとその必要はありません。データモニタリングのツールは市場に複数あり、素人がコーディングしたものが品質で優るはずがないからです。従って、どのツールを導入するべきか考えることが要求されるのだと分かりました。
多くの選択肢がある中、ふとYoutube動画をみていたところBIツールの存在を知りました。
####BIツールとは？
BIツールとは企業が持つさまざまなデータを分析・見える化して、経営や業務に役立てるソフトウェアのこと。調べてみると今回の要件に合致するものもいくつかあるようです。
これは光明が見えたかも知れん！そう思ったことを記憶しています。

###選択肢
・Microsoft PowerBI
基本無料で使えるBIツール。クラウド版も用意されており良さげであったが、SQLを自由に叩けないということで今回は断念した。

・mackerel
こちらも無料枠が用意された分析ツール。有料版も1800円/月と手軽で導入が楽なのが自慢、しかしこちらもSQLを自由に叩けないため今回は断念。
こんなスライドまで作ってクライアントを懐柔しようと試みたのに、残念でした！
![スクリーンショット 2021-10-08 21.13.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/5a2cea58-0a67-feae-90cd-b0946da2be0f.png)

・Re:dash
無料版も提供されているBIツール。
SQL操作にも対応しておりかなり良さげだったが、英語での操作になること、非エンジニアにはUIが分かりにくいことから泣く泣く選択肢から除外した。

<h1>システム構成</h1>
最終的に提案させて頂いたソリューションです。
比較的シンプルに構成されており、費用が安く済むように工夫しました。
Metabaseを選定したのにも理由があります。非エンジニアにもUIが理解しやすく、操作が直感的であるのが特徴です。

・費用
Metabase 無料
EC2インスタンス×２　=　1500×2 = 3000円
RDSスナップショット　月あたり約1000円
AWS SES ほぼ無料
計　約4000円/月

![Yoshizumi_solution14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/0ba15f5c-4000-163e-15fd-95be770ec0d2.png)

実はこのシステム構成図はVer.14で何度もダメ出しを頂き、都度修正してやっとの思いで提出に至りました。正直胃が痛くなる経験をしました。しかし何度もめげずに提案を繰り返しているうちに、自分でも提案の質が上がっていることを実感。今後にも必ず活かせる経験だと思います。

概要はMetabaseコンテナをEC2に構築し、本番DBから取得したスナップショットと連携することでデータをモニタリングするというもの。個人情報にはマスキング処理を施してあります。モニタリングを担当する人にも、誰からもユーザーの個人情報が閲覧できない仕様になっています。クライアントからは、既存のBIツールをweb上にアップロードする際には、インスタンスのhttps化がされているのが望ましいとのこと。

AWSの基礎学習にはこちらを使いました。

https://www.amazon.co.jp/Amazon-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-%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/dp/4296105442/ref=sr_1_1_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=AWS&qid=1633710093&sr=8-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEyMVNKSFRCWUQxR0gmZW5jcnlwdGVkSWQ9QTA1NTI2NTgzUzU5QkRKMkozTTAmZW5jcnlwdGVkQWRJZD1BVDQyTjdEMjhGVUomd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl

当初は個人情報のマスキングということで「AWS 個人情報　マスキング」のキーワードで検索し、AWS Glueを使うべきだと考えていました。しかし調べているうちにAWS Glueの学習コストが思いの外高いこと、運用まで考えると月々の費用がバカにならない程度にかかってくることが分かりました。悩んでいたところふと「そうだ、必ずしもマスキングという手段にこだわる必要はない。ユーザーネームとe-mail addressを分からないようにすればいいんだ！」という着想に至り、RDSにsql文を流し込むという手段を思いつきました。

```masking.sql

-- usernameのマスキング処理 `dummy_yuji_itadori`で記載
update users set username= replace(username, username, concat('dummy_yuji_itadori',id));

-- emailのマスキング処理 `hogehoge_email`で記載
update users set email= replace(email, left(email,instr(email,'@')- 1), concat('hogehoge_email',id));
```

user_nameとuser_emailに関して、任意の文字列を上書きする処理をしています。

cronによってRDSからスナップショットを取る。
↓
スナップショットからDBを復元。
↓
復元DBにマスキング用のSQLを流し込んだ後rename。
↓
あらかじめMetabaseに登録してあるエンドポイントを指定する。
↓
取得したスナップショットを削除する。

これらをAWSCLIで操作し、cronで定期実行することによって、Metabase側の設定を変更することなくマスキングデータのモニタリングができます。
未経験者ですから、当然cronの存在なんて知りません。業務外で読んでいた書籍が役に立ってくれました。

https://www.amazon.co.jp/%E6%96%B0%E3%81%97%E3%81%84Linux%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E4%B8%89%E5%AE%85-%E8%8B%B1%E6%98%8E/dp/4797380942

作成したシェルスクリプト

```restore-db.sh
#!/bin/bash -l

#スナップショット取得
/usr/bin/aws rds create-db-snapshot \
--db-instance-identifier "de-final-new" \
--db-snapshot-identifier "de-snapshot"

#スナップショットが出来るまで待機
/usr/bin/aws rds wait db-snapshot-completed --db-snapshot-identifier "de-snapshot"

#旧RDSを削除
/usr/bin/aws rds delete-db-instance \
--db-instance-identifier "de-final-new" \
--delete-automated-backups \
--skip-final-snapshot

#RDSが削除されるまで待機
/usr/bin/aws rds wait db-instance-deleted --db-instance-identifier "de-final-new"

#リストア
/usr/bin/aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier "de" \
--db-snapshot-identifier "de-snapshot" \
--availability-zone "ap-northeast-1c" \
--db-subnet-group-name "private-subnet-group" \
--vpc-security-group-ids "sg-0f8c147ccd101dc31" \
--db-instance-class db.t3.micro  \
--publicly-accessible \
--no-multi-az

#RDSが作成されるまで待機
/usr/bin/aws rds wait db-instance-available --db-instance-identifier "de"

#新RDSにマスキング処理を施す

mysql -h de.ckqlzvvitdnb.ap-northeast-1.rds.amazonaws.com dokugaku_engineer < ~/dump/masking.sql

sleep 5

#マスキング後RDSの名称変更
/usr/bin/aws rds modify-db-instance \
--db-instance-identifier "de" \
--new-db-instance-identifier "de-final" \
--apply-immediately

#復元したスナップショットの削除
/usr/bin/aws rds delete-db-snapshot \
--db-snapshot-identifier "de-snapshot" 

```

忘れがちだけど重要なのがスナップショットを削除する工程で、これを忘れるとAWS CLIの方でスナップショット"de"は既に存在しています。というエラーが発生し、最新のスナップショットが取得できなくなります。結果データの更新がされず、BIツールの方で最新データのモニタリングができなくなってしまいます。
ちなみに私は何度もエラーに直面し、何度目かでやっとスナップショットの取得ができていないことに気が付きました。笑


参考にしたページ：
https://dev.classmethod.jp/articles/tsnote-rds-restore-endpoint-001/

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_RestoreFromSnapshot.html

Metabaseには独自ドメインでアクセスすることができ、let's encrypt/certbotでSSL化を実現しています。must用件であったhttps通信を実現するにはどうすればよいか、本当に頭を悩ませました。調べてみると現在のwebサーバーはApacheでなくnginxが主流であること。リバースプロキシという手法が存在していることを知りました。

https://pentacent.medium.com/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71

運用していくことまで考えると、ただEC2にBIツールを立ち上げるよりも、コンテナ内にソフトをインストールしてデプロイする手法が望ましいことが分かりました。基礎学習をしていた書籍にはApacheを使った記述しかなく、nginxの学習はググる以外に道がありません。コンテナの基礎はこちらのサイトを使い学習しました。

https://y-ohgi.com/introduction-docker/

参考記事のタイトルには５分以内と書いてあるけどdocker-compose.ymlの記述は難しく、かなりの時間を割いてしまいました。どうやらEC2のSSL化にはcertbotというソフトウェアを使うのが良さげ。まずは手元の環境でざっと基礎をさらったあと、公式のチュートリアルに取り組み、この知識をコンテナと組み合わせて使う必要があります。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/SSL-on-amazon-linux-2.html

最終的に作成したdocker-compose.ymlファイル

```docker-compose.yml
version: "3"
services:
  metabase2:
    image: metabase/metabase
    environment:
      MB_DB_TYPE: mysql
      MB_DB_DBNAME: ********-*********
      MB_DB_PORT: 3306
      MB_DB_USER: ********
      MB_DB_PASS: ********
      MB_DB_HOST: ********.ckqlzvvitdnb.ap-northeast-1.rds.amazonaws.com
    volumes:
      - ./metabase-data:/metabase-data
    ports:
      - "3000:3000"
    container_name: metabase2
    restart: always
  web:
    build:
      context: .
      dockerfile: ./containers/web/Dockerfile
    command: /bin/bash -c "envsubst '\$\$NGINX_BACKEND' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"
    environment:
      NGINX_BACKEND: metabase2
    volumes:
      - ./containers/web/default.conf.template:/etc/nginx/conf.d/default.conf.template
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - metabase2
    links:
      - metabase2
    container_name: web
    restart: always
  certbot:
    image: certbot/certbot
    volumes:
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    container_name: certbot
    restart: always

```

これによって
・https通信化されてデプロイされたBIツールから
・本番DBに負荷をかけることなく
・個人情報を保護された最新データの定期モニタリングが実現します。

<h3>ただの感想</h3>
システム構成図は作ったものの、実装の難易度は本当に高かったです。期限が迫ると独り言が増え、精神的に追い詰められる中で成果を出すことが要求されました。何といっても自分は素人ですから。何も知らんのですから。何度も修正を繰り返しクライアントとの合意が取れ、最終ソリューションが決定してからは頑張るのみ！
ひたすらタスクを分解し、こなせるようになるまで細分化しました。
社会人経験が希薄なことから、私は自分には根性が無いし、頭も良くは無いと考えていました。しかし、言うほど自分には何も無いわけではない。気がつけばいつの間にか独り言が「やってやる。ぜってーやってやる。」に変わっていました。意外と自分は粘り強い奴だったんだなあと。加えてクライアントにものすごく感謝しました。こんな自分を発見できたのは、自分に仕事を任せてくれた方あってのこと。何の実績も無かった私とクライアントの間には、いつしか人と人との信頼、絆が出来上がっていました。ダメなところは多々あったし、がっかりさせたことも多かったでしょう。しかしめげずに提案を繰り返しているうちに、指摘したら修正して持ってくる奴だと認識して頂けたのだと思います。
試行錯誤を繰り返してなんとかやり遂げられた喜びはひとしお。最高の達成感を味わうことができました。私は自分の力で誰かの役に立つことができたのです。これ以上の喜びを、私は他に知りません。俺は生きていてもいいのだと。

<h3>まとめ</h3>
public subnetに構築したEC2も、本来ならprivate subnetに配置したかったところ。全体的に粗さが目立つ結果となってしまいました。しかし触ったことのない技術に多く触れ、確かな手応えを感じたのも事実。毎日１０時間近くを学習に使い、大好きだったお酒もアニメも封印してこの課題に没頭する自分を発見しました。不思議なことに、そういったことが頭に入ってこなくなるんですね。動画を見ていても眠くなるし、自分自身の変化に驚かされました。気がつけばもっといいソリューションはないか？と妄想モードに入ってしまっているのです。
やっぱり自分は開発が好きです。
時間が許す限りもっと取り組みたい。
新しい手法にも積極的にチャレンジして、解決できる課題の幅を広げたい。
プロになりたい。
好循環のサイクルを作るために、もっと新しい自分が欲しい。
自分がプログラミングを続ける理由を、自分の中に再発見したように感じます。引き続き学習を継続しますし、もくもく会の主催にも興味が湧きました。次の案件が決まったわけではないし、これからどう生きていけばいいのか依然として不安はあります。巷でいうようにプログラミングで人生逆転！みたいな、上手い話があるわけではありません。ただのニートが実務に入ればいきなりヒーローみたいな、非現実的なことは起こりません。別にヒーローになる必要はないし、魔法もいらなかった。自分で自分を導ける力を、私は既に持っていたのかも知れません。ただ、見落としていただけなのかも。

未経験者の自分にとっても、プログラミングは人生を豊かにしてくれます。少なくとも生きていく方向性は定まりました。
この経験を次に活かし、少しだけ前を向いて生きていけるような気がしています。
私と似た境遇をお持ちの方は連絡をください。力になれるか分かりませんが、一緒になって考えることは私にもできます。