25
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

SIer出身エンジニアがAWS ECS,Terraform, Golang,Nuxt.ts(SPA),gRPCでポートフォリオを作成しました。

新卒未経験でSIer系企業に就職し、しばらくは従順に働いてはいましたが
使われる技術に飽き飽きしていたのと、
運ゲーガチャを回し続ける境遇から抜け出すためにも
自社開発系企業に転職する事を目標に作成していた
ポートフォリオが形になってきたのでここで共有しようと思います。

自己紹介

新卒未経験で入ったSES・受託企業で3年ほど従事し退職済。
Vue,PHP,Java,RDB運用あたりの業務に参画しました。
休日には近隣のIT企業主催の勉強会に参加し、DockerやAWSなどを触っていました。
野球、サッカー観戦と温泉が趣味です。

ポートフォリオ

使用技術

  • フロントエンド
    • Nuxt (2.0.0)
    • TypeScript (3.8.3)
    • Vuetify (フロントエンドFW)
  • バックエンド
    • Go (1.15)
  • インフラ,環境
    • Docker, docker-compose
    • AWS(IAM,VPC,ECS,ECR,RDS,Route53,ELB,S3,CloudWatch)
    • Terraform (インフラコード化)
  • サービス間通信
    • gRPC, Protocol Buffer
    • envoy (gRPC通信のプロキシ)
  • CI/CD
    • CircleCI

それが、こうなった。(インフラ構成図)

PortfolioArchitecture

コンテナ基盤としてECS Fargateを用い、フロント・バックエンド共にDocker化.
gRPCを通信を用いているため、コンテナ間にはenvoyプロキシを配置しています。
ロードバランサーに紐付けたドメインにアクセスする事でアプリを利用でき、
アクセス時のリクエストパスによってルーティングを行っています。

アクセスログをS3,コンテナの標準ログをCloudWatchに格納しています。

各技術の採用理由

  • マイクロサービス
    • ここ最近、モノリスからマイクロに書き換える動きがある
    • 業務でマイクロサービスに関わる事になった時に役立てたい
  • Go
    • シンプルで使いやすい。コーディングスタイルが属人化しにくく、無駄を省ける。
    • interfaceで実装メソッドを管理できる所が好きです。
      (上記、私の思い込みです。実際、メソッドを管理するためにinterfaceを使っているケースはあまり見ない)
    • 将来性の高さ。PHPやRubyなどからGoに移行している企業が増えている。
  • TypeScript
    • 型を使って制御できる
  • Nuxt
    • Vue.jsの業務経験があり、個人的にも扱いやすかった
    • フロントエンドのラーニングコストはかけたくない
  • Vuetify(フロントエンド FW)
    • フロントエンドが弱く、楽をしたかった
    • 詳細な日本語ドキュメントが書かれており、exampleも豊富
  • gRPC
    • Protocol Bufferを用いた軽量通信
  • AWS
    • クラウドサービスの中で1番人気が高い。
    • SecurityGroupにより、通信制御を行える。
  • ALB (Application Load Balancer)
    • リクエストパスを用いてルーティングを行える。
    • gRPC通信に対応している。

工夫した点・頑張った点

業務経験のない技術を多く採用した

上述の通り、モダンな技術を色々使っています。
VueやMySQLを除いて、ほとんどの技術は独学で使い始めた物になります。
Dockerについては、新卒1,2年目の頃に勉強会などに参加して身に付けようとしていたのがとても役立ちました。
さくらインターネットさん、お世話になりました!)

AWSインフラは、コード化した

AWSインフラは、Terraformを用いてコード化しました。
インフラを確認するためにコンソール画面を開かずに済みますし、
リソースの依存関係も明確にする事ができました。

VPCエンドポイントを用いて、プライベートサブネットからのインターネット通信を安価にした

 バックエンドのコンテナはセキュリティの都合もありプライベートサブネットに置いていますが、
最初は「CannotPullContainerError」が発生してました。
 普通、プライベートから通信を行う場合にはNatGatewayを設ける事もありますが、今回はVPCエンドポイントを設定する事でDocker pullやS3へのアップロード等を安価に行えるようになりました。

ECSサービス検出を用いて、サービス間通信を行った

 マイクロサービス構築において、どのようにしてサービス間通信を行うかが課題でした。
サービスを分割する事はできても、それらが連動して動かなければ意味がないです。
 例えば、「投稿情報を返す時に、ユーザーサービスから投稿者の情報を取得する」 「ユーザー退会時にそのユーザーの記事を削除する」などの処理が必要でした。
 あるECSサービスから別サービスにリクエストを送る方法については、公式ドキュメントに記載されています。

つまり、

サービス検出は、A および SRV の DNS レコードタイプをサポートします。DNS レコードは Amazon ECS サービスでタスクが開始または停止する度に、自動で追加および削除されます。Amazon ECS サービスに接続する必要があるタスクまたはアプリケーションは、DNS レコードから既存のタスクを見つけることができます。

サービス検出を設定したら、 YourServiceDiscoveryServiceName.YourServiceDiscoveryNamespace 形式を使用して、Amazon Virtual Private Cloud (Amazon VPC) 内のサービス検出サービスの DNS レコードをクエリします。

そのため、まずはサービス検出の為のDNSレコードをECSサービスに登録します。

ecs.tf
# サービス検出名前空間
resource "aws_service_discovery_private_dns_namespace" "internal" {
  name = "portfolio.namespace"
  vpc = [サービスを構築しているVPCID]
}

# サービスA サービス検出
resource "aws_service_discovery_service" "service_a" {
  #サービス検出名
  name = "serviceA"

  dns_config {
    namespace_id = aws_service_discovery_private_dns_namespace.internal.id
    #タイプAのDNSレコードを登録する
    dns_records {
      ttl  = 10
      type = "A"
    }

    routing_policy = "MULTIVALUE"
  }
}

#ECSサービスA登録
resource "aws_ecs_service" "service_a" {
  name            = [サービスAの名前]

 [中略]
  service_registries {
    registry_arn = aws_service_discovery_service.service_a.arn
  }
}

マイクロサービスの数に応じて、同様にサービス検出名を登録します。
 そいでenvoyでgRPCのリクエストをルーティングをする時は、AWSの公式ドキュメントの言う通りに [サービス検出名.名前空間] 形式で指定すれば良いです。

envoy.yaml

  clusters:
  - name: service-a-envoy
    connect_timeout: 15s
    type: logical_dns
    http2_protocol_options: {}
    lb_policy: round_robin
    hosts:
    - socket_address:
        # ecs service discovery endpoint for service a
        address: serviceA.portfolio.namespace
        port_value: 8081

  - name: service-b-envoy
    connect_timeout: 15s
    type: logical_dns
    http2_protocol_options: {}
    lb_policy: round_robin
    hosts:
    - socket_address:
        # ecs service discovery endpoint for service b
        address: serviceB.portfolio.namespace
        port_value: 8082

課題点

費用の問題があり、機能の数が少ない。

 バックエンドをマイクロサービス化はできましたが、サービス数が2つしかないのが少々物足りなく感じています。
 サービスを追加するとすれば、以下みたいなのが考えられます。
- 人気のある投稿をしたユーザーにポイントを付与する
- フォロー、コメント、いいねなどをされた際に通知する
- タグをフォローする

が、これらは少々面倒で割愛してしまっています。
面倒というよりも、サービスを追加するとどうしても費用が嵩張る点が大きいです。
マイクロサービスでは、Database per Serviceという考えが浸透している様に、サービス毎にデータベースを運用する事になります。
 そしてそのデータベースこそ、最も費用がかかっているのです。この構成を運用するのに、AWSのコストは毎月150~200ドルくらいかかっていますがそのうち3分の1がRDSの費用です。

データベースを安価に運用する事が大きな課題になっています。
より安価なAuroraを使うとか、NoSQLで運用するなどの手法も引き続きキャッチアップしていきたいなと思います。

RDSのパフォーマンスに不安がある

RDSでたびたび、"Too many connections..."エラーが起こっており、
サービスが停止する事があります。
 パラメーターをいじって、接続をすぐ破棄するように設定をして対応していますが、
トランザクション処理に時間を要する場合があるので実用的ではなく、今の所1番の課題ですね。
SELECT時にRDSに直接リクエストを送るのではなくリードレプリカを用いるとか、Elasticsearchなんかも使えないか検討してみます。(リードレプリカは更に費用がかかるのではないかという懸念もあるので調査したいと思います)

フロントエンドが弱い

私自身、今後もバックエンドやインフラ構築を主戦場にしたいと思っていますし、SIerでの直近の業務でもバックエンドが多かったです。

 とはいえ、これまでフロント側を疎かにしていたのが裏目に出ました。
できるだけ納得の行く形の物を作るために
業務経験のないTypeScriptで書いたり、
storeで状態管理を使ってみて試行錯誤などはしていましたが、
この辺の書き方が自己流になりすぎてやしないかと、
少し心配です。
スタイルもフレームワークに依存している所が不安要素ではあります。
(HTMLやSCCを知らなくても画面作れる所からこそ、フロントエンドFWを使っているのですが)

gRPCのコード生成を自動化できていない

gRPCのコードは、protoファイルを元にコード生成コマンドを叩いて生成するのですが、できればCI化して自動化したいと思っています。ただ、ここはコードの運用の話になるので優先度はそれほど高くはないため妥協しています。

まとめ

 技術的な壁がまだまだありますが、
インフラをコード化してAWS構成を管理できている所や、
Goでマイクロサービスを運用できている所などは強みです。

他にもDockerやCircleCIなど
SIer企業ではなかなか触れない技術を扱えたので結構自信になっています。

 ポートフォリオのおかげでGoを採用している企業さんの書類選考も通りやすくなりましたし、
エージェント経由で業務委託のお声がけもいくつか頂ける様になったので、
引き続き面接対策をしっかりして
目標の企業さんに内定頂ける様に頑張っていきたいと思います。

 ここまで読んでくださり、ありがとうございました。
私と同様に、自社開発系企業への就職を目指している方々のご参考にして頂ければ幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
25
Help us understand the problem. What are the problem?