kube2iamの仕組みと使い方

はじめに

SREチームの須恵です。 SREとしてはDocker/Kubernetesを利用した環境の整備を主に推進するかたわら、ときおりフロントエンド開発にも自由に挑戦させてもらったりしています。

今回は、kube2iamの仕組みと使い方について書いてみようと思います。

これは何?

kube2iamとは、Amazon EKS上のPodごとにIAMロールを使い分けられるようにするためのツールです。

github.com

なぜ必要?

Amazon EKSにおいて、クラスターを構成するNodeはEC2インスタンスです。

AWSリソースにアクセスするようなPodを動かしたいとき、Podが持てるAWSリソースへの権限は、EC2インスタンスにアタッチされたインスタンスプロファイルに紐づくIAMロールに準じます。

参考) EC2にIAMRole情報を渡すインスタンスプロファイルを知っていますか? | DevelopersIO

ここで、「異なる種類のAWSリソースを使用する複数のPodを、同じクラスターにデプロイしたい」という状況について考えます。

このとき、クラスターのすべてのNodeに 「各Podが必要とする権限の和集合」を許可することになり、 Podが本来権限を持つべきでないリソースに誤ってアクセスできてしまうリスクが生じます。

そのため、「Node単位」でなく「Pod単位」で権限制御できることにニーズがあります。

どうやって実現?

kube2iamが何を行うのか、おおざっぱに説明すると下記です。

kube2iamなし

AWSに対して何かしたいPod

→コンテナが動作するNodeのEC2メタデータAPI

インスタンスプロファイルに紐づくロールの一時クレデンシャルをコンテナに返す

kube2iamあり

AWSに対して何かしたいPod

メタデータAPIへのリクエストをkube2iamコンテナにリダイレクト

→kube2iamが「何かしたいコンテナ」のアノテーションに記述されたロールを引き受け(Assume)

→当該ロールの一時クレデンシャルをコンテナに返す

kube2iamに使用させるIAMロールの作成

ここから実際にkube2iamを利用するための準備を進めます。

まず下記のポリシーを作成します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "sts:AssumeRole"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

次に、「使用サービス:EC2」のロールを作成し、このポリシーをアタッチします。 ロールを作成したら、信頼関係の編集を行います。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/kubernetes-worker-role" ←ここは各自の値
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

"arn:aws:iam::123456789012:role/kubernetes-worker-role" この部分には、ワーカーノード(にアタッチされたインスタンスプロファイル)のIAMロールを記載します。

ここまでの作業で、ワーカーノードに対して、AssumeRoleができる権限だけを与えました。

RBAC用リソース作成

ここからはKubernetesリソースを作成していきます。 まず作成するのはServiceAccount, ClusterRole, ClusterRoleBindingです。

このServiceAccountはkube2iamのPodがKubernetesAPIサーバーにアクセスする際に利用します。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kube2iam
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kube2iam
rules:
  - apiGroups: [""]
    resources: ["namespaces","pods"]
    verbs: ["get","watch","list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kube2iam
subjects:
- kind: ServiceAccount
  name: kube2iam
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: kube2iam
  apiGroup: rbac.authorization.k8s.io

DaemonSet作成

ここからは、kube2iamのPodを稼働させるための作業です。

「EC2メタデータAPIへのリクエストを奪取する」という役割を遂行するためには、どのノードでリクエストが発生してもよい=すべてのワーカーノードでkube2iamが動作している必要があるので、DaemonSetリソースを作成します。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube2iam
  namespace: kube-system
  labels:
    app: kube2iam
spec:
  selector:
    matchLabels:
      name: kube2iam
  template:
    metadata:
      labels:
        name: kube2iam
    spec:
      serviceAccountName: kube2iam
      hostNetwork: true
      containers:
        - image: jtblin/kube2iam:latest
          imagePullPolicy: Always
          name: kube2iam
          args:
            - "--app-port=8181"
            - "--auto-discover-base-arn"
            - "--iptables=true"
            - "--host-ip=$(HOST_IP)"
            - "--host-interface=eni+"
            - "--verbose"
          env:
            - name: HOST_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          ports:
            - containerPort: 8181
              hostPort: 8181
              name: http
          securityContext:
            privileged: true

https://hub.docker.com/r/jtblin/kube2iam/ このイメージから起動したコンテナを持つPodが各ノードに配置されます。

privilegedが要る理由

--iptables=trueかつprivileged: trueとすることで、EC2メタデータAPIへのアクセスがkube2iamにプロキシされ、直接EC2メタデータAPIにアクセスしないようにすることができます。

kube2iamを利用してPodでロールを使用する

DaemonSetが作成できたら、任意のロールをPodで使用する準備は完了です。

Podのアノテーションiam.amazonaws.com/roleを追加すると、任意のロールをPodで利用できます。

# Sample
apiVersion: v1
kind: Pod
metadata:
  name: aws-cli
  labels:
    name: aws-cli
  annotations:
    iam.amazonaws.com/role: role-arn ←ここです
spec:
  containers:
  - image: fstab/aws-cli
    command:
      - "/home/aws/aws/env/bin/aws"
      - "s3"
      - "ls"
      - "some-bucket"
    name: aws-cli

最後に

続編として、今回セットアップしたkube2iamともう一つのツールを組み合わせ、EKS上のアプリケーションへALBを使ってルーティングを行う方法について書こうと思います。

SREチームも人が少しずつ増えてきました。

オクトではエンジニアを積極採用中です。ぜひ気軽に採用サイトを見てみてください。

engineer.88oct.co.jp

新横断工程表プロジェクトが始まりました!(Nuxt & TypeScript)

新規プロジェクト本格的に始動

どうも、フロントエンドチームの藤井です。

 

いよいよ、ANDPAD施工管理開発チームの目玉の一つである、「横断工程表」というサービス開発が始まりました。3月にリリースした、案件ごとに作れる「工程表」というサービスをより使いやすく改良したものになります。また、もともとANDPAD本体に入っている「横断工程表」というサービスを作り直すものでもあります。

 

この横断工程表では、案件や担当者、現場などを横断で同じ工程表上で見れることを機能として入れていきます。いわゆるガントチャートのようなサービスですね。

 

Nuxtを採用する理由

旧横断工程表はRails + Angular、工程表はRails + Vueという構成でしたが、今回はフロント側はNuxtで一から作り込むことにしました。

 

理由としては、以下のようなものがあります。

  • バックエンド、フロントのそれぞれの責務がはっきり別れていないのでキャッチアップにも時間がかかる
  • モノリシックな構成のため影響範囲がわかりづらく、毎回リリース前の調査やテストに時間がかかる
  • 本体サービスの週一リリースに合わせるため、ちょっとしたフロント側改修も待たなければならない
  • etc...

 

新工程表プロジェクトからの反省点

また「新工程表」サービス開発からの反省点もあります。

  • なぜこのようなストア設計になっているのかわからない
  • なぜ動いているのかわかりにくいコードがある
  • コンポーネント化を適宜行っていないので、ファイルが肥大化してメンテしにくい
  • グローバルスタイルシートへの依存が多く、まさかのスタイルシートとvueファイルの密結合状態
  • APIエンドポイントがいたるところに転がっている
  • Lintがかかっておらず、無秩序なコードがある
  • etc....

 新プロジェクトでの設定

以上のことを踏まえて、今回のプロジェクトでは環境設定から気をつけました。

  • axios-moduleではなく、axiosを使い、APIエンドポイントを`network/apiClient`に集約
  • assets/cssに最低限のスタイルシート(reset.cssやbase.scss)を先に用意し、新規で作ることを禁止
  • constantsやutils、modelsやdirectivesディレクトリを先に作って、ディレクトリ構成で迷わないように準備
  • Atomic Designを採用し、コンポーネントの管理
  • Lintを導入し、さらにhookを使ってcommit時に自動でlintが走るよう設定
  • TypeScriptを導入し、型を意識した設計にしていく
  • READMEにディレクトリ構成や注意点などを明記しておく
  • etc....

 

様々な人が開発に携わるからこそ、様々なことを明示的に残しておく必要があると感じました。

 

このサービスが日の目を見るのは、7月末ごろでしょうか。これからガンガン開発を行っていきます!

 

最後に

一緒に横断工程表を作ってくれる人を募集しています。こちらに弊社の技術スタックなど載っていますので、ぜひ見てみてください!

 

 

 

施工管理チームにおけるVueコンポーネント設計

どうも、施工管理チームのフロントエンドを担当している藤井です。

 

今回うちのチームで取り組んでいるVueプロジェクトのコンポーネント設計の移り変わりについてご紹介したいと思います。

 

別で存在する新規プロジェクトチームの方では、Vue/NuxtやTypeScript使ったりと、色々な取り組みをしているのですが、ANDPADの本体サービスは基本的に、Rails + Angular v1で成り立っています。(jQueryも入ってたりも)

 

そんな中で、実は本体の「(新)工程表」というサービスと「写真出力」という機能の一部は、最近Vue.jsで書かれています。(旧)工程表から(新)工程表への置き換えプロジェクトはだいたい2018年から約1年。そして写真出力の一部の置き換えは2019年の4月から約2ヶ月がかかっております。私がこのチームに入ったのは2019年の3月中旬でして、その際はまだ工程表というサービスのみがVueで作られていました。

 

f:id:yohei-fujii:20190607144908p:plain
(工程表のサンプル画像↑↑)

 

 当時、特にコンポーネント粒度等は仕分けされておりませんでした。そのため、中には1000行を超える巨大なファイルが存在したりしていました。しかし、とはいってもそれは一握りであり、適度に切り分けられ、肥大化していないファイルもありました。

 

その時のコンポーネント設計↓↓

|- components
| |- common
| | |- CommonHeader.vue
| |- workload
| |- WorkLoadItem.vue
| |- WorkLoadModal.vue
| |- .....
|

 

初見で思ったのは「粒度の仕分けもされていないし、メンテナンスしにくいな。」ということです。小さいコンポーネントも大きいものも混在している状態でした。「パーツとか使いまわせるものあるし整理しよう!」ということで、一度Atomic Designを意識した設計に変更しました。

 

|- components
| |- atoms
| |- molecules
| |- organisms
| |- templates
| |- pages
|

 

「よし!綺麗になったぞ!」これで新しく人が携わることになっても、粒度で別れているから理解しやすいだろうと思っていたのです。実際、工程表というサービスだけの時は、問題ありませんでした。

 

めでたし、めでたし!

å¬ãã表æã®ç·æ§ã®ã¤ã©ã¹ãï¼5段éï¼

 

 

しかし、次にANDPADの別の機能をVueで開発しようとなりました。それが「写真出力」のドラッグ&ドロップ機能です。

 

 

f:id:yohei-fujii:20190607145115g:plain

(開発途中のサンプル↑↑)

 

ここで、悩みが始まります。

さて、コンポーネント設計をどうしようかと。

 

今のAtomic Designベースのディレクトリに、写真出力のVueファイルもポコポコと入れていくのがいいかなと思って途中までやっていました。

 

|- components
| |- atoms
| |- molecules
| |- organisms
| |- PhotoOutputEditArea.vue
| |- PhotoOutputSelectArea.vue
| |- ....
| |- WorkloadItemModal.vue
| |- WorkloadChart.vue
| |- ....
| |- templates
| |- PhotoOutput.vue
| |- pages
|

 でも、気づいたのです。

「これ、もしかして他のサービス機能とかもVueで作るってなった時に、中でカオスになるよね・・・・。」同じ粒度だからと言って、どんどん同じディレクトリに入れていくと、今後大きくなってきた時に、様々な違った機能のパーツが混在していくことになります。

 

「まあ、ひとまず2つのサービスでしか使ってないからいいかぁ」その時はあまり深く考えずにそのまま進めました。

 

そして1ヶ月が過ぎます。

 

å¹³æãã令åã«å¤ããã«ã¬ã³ãã¼ã®ã¤ã©ã¹ã

 

 

すると、次に別のチームが「そっちでうまく行ったから、こちらのプロジェクトでもVueを使いたい!」と出てきます。

 

 

さぁここで本格的に頭を悩まします。

 

é ­ãæ±ãã¦æ©ãã§ãã人ã®ã¤ã©ã¹ãï¼ç·æ§ï¼

 

別のチームといっても、同じリポジトリを使っています。管理という面からも、必然とVueファイルは同じディレクトリを使っていくことになります。このままAtomic Designを続けていってもいいのですが、organismsの中に様々なプロジェクトのコンポーネントが混在することになるからです。atomsとmoleculesは共通部品と当初より考えていたのでよかったのですが、流石にorganismsくらいの大きさになると共通部品がほぼありません。混在させても良いのですが、見通しが悪くなります。また、今後どんどん別サービスがvueを採用していく可能性も否めませんので、そうなると整理するためにorganismsの下にまたプロジェクトディレクトリを作ることになります。そうすると、何が起こるかというと、templatesやpagesのディレクトリでも同じプロジェクトディレクトリを作ることになりました。

 

|- components
| |- atoms
| |- molecules
| |- organisms
| |- photoOutput
| |- PhotoOutputEditArea.vue
| |- PhotoOutputSelectArea.vue
| |- ...
| |- workload
| |- WorkloadItemModal.vue
| |- WorkloadChart.vue
| |- ...
| |- ....
| |- templates
| |- photoOutput
| |- PhotoOutput.vue
| |- ....
| |- pages
| |- workload
| |- workload.vue
|

 

うううう、これはやだなぁ。

 

もともとNuxtに切り出すプロジェクトもありますし、その点を考慮し、見やすい設計を模索していました。技術顧問や外部の人にも相談して、行き着いた答えが、「atomsとmoleculesはcomponents配下におくが、organisms以上のコンポーネントは各プロジェクトディレクトリ配下に置く」ということでした。

 

|- components
| |- atoms(共通)
| |- molecules(共通)
| |- photoOutput(独自)
| |- organisms
| |- PhotoOutputEditArea.vue
| |- PhotoOutputSelectArea.vue
| |- ...
| |- templates
| |- PhotoOutput.vue
| |- workload(独自)
|- organisms
| |- WorkloadItemModal.vue
| |- WorkloadChart.vue
| |- ...
| |- pages
| |- workload.vue
|

  

こうすることで、何が良いかというと、粒度の責務の切り分けができるようになりました。atomsとmoleculesは共通パーツとして使うもの。それ以上のoraganismsは各プロジェクトで独自のものというふうに分けることができます。

 

またそれと同時に、一番のメリットは、今後Nuxtへの移行を見据えた際に、移植しやすい構造にもなっております。その際にatomsやmoleculesに関しては、andpad-uiという社内フレームワークに切り出すが可能です。そうすることで、各プロジェクトで持つatomsやmoleculesのパーツは独自の必要最低限のものとなり、コンポーネント管理がしやすくなります。また、統一されたデザインパーツを使うことにより、デザインの統一性が計れることがわかりました。 

 

atomsなどのパーツに関しては、「先にコンポーネントをUIライブラリで作った方が良いのでは?」という意見もあると思います。しかし、以前の経験から先にコンポーネントを準備するということはしないことになりました。というのも、時間をかけてパーツを作っても、結局使わないものが出てくるからです。

 

以前、たくさんのボタンを時間をかけて設計して準備したのですが、結局使われているのはほんの一部ということがありました。

 

リソースが限られている中では、こちらでも紹介されているように、YAGNIって大事だということを身をもって体験しました。

 

qiita.com

 

Nuxt移行の段階で切り出したりすることで、サービス横断で本当に必要なパーツがリストに並ぶということになるのです。

 

 

以上のことから、現在ANDPADのフロントでは、Atomic Designを応用したコンポーネント設計を取り入れてます。今後もっと良い適した設計が現れるかもしれません。その際には柔軟に対応していこうと思います。

 

最近は、社内でフロントエンドに携わる人も増えてきて、社内ルールもまとまってきており、そのことから開発スピードは格段と上がっているように感じます。今後もVue.jsでの置き換え範囲は拡大していく予定です。

 

 

ANDPADのiOSアプリの設計について

iOSアプリの設計について

施工管理アプリANDPADのモバイルアプリ開発をしている山下です。

今回はANDPADで採用しているiOSアプリの設計について書こうと思います。

ANDPADはサービスリリースしてから4年ほど経過しており、ユーザー数も右肩上がりに伸び続けています。アプリもリリースしてから3年半ほど経過して設計を振り返る機会ができたので記事を書いている次第です。

基本的な設計方針としてはMVVMを採用しています。3年半ほど前は、アプリ界隈では比較的新しめの設計だったのですが、今では結構当たり前になっているのかなと思います。構成図はこのような感じです。

     f:id:oct88:20190529171816p:plain

使っている主なライブラリは、

  • RxSwift
  • Realm
  • Alamofire

などです。比較的今でもよく使われているライブラリなので選択は正解だったと思います。

MVVMの部分は、一般的な使い方と基本同じなので説明を割愛します。ApiManagerは、ローカルやサーバー側からのデータ取得を担っています。ScreenUpdateManagerは、複数画面をまたいだ場合のイベント伝搬の責務を担っています。 

建築系で特有の機能をライブラリ化

ANDPADは、iOSだけで5アプリリリースしています。ちなみにAndroidも4アプリリリースしています。Androidアプリの開発も私がやっているのでまた設計の話を別記事で書こうと思います。

 開発当初から、建築業界という広いドメインを扱うサービスなので用途毎に複数のアプリをリリースしようと決めていました。複数のアプリをリリースするにあたり、共通化できそうな機能は独自ライブラリとして切り出す手法を初期段階から行なっていました。同じような機能を実装する場合はOSSのライブラリと同じような感じでライブラリをインストールするとアプリから呼び出せるようになっています。ライブラリの管理はCocoaPodsを使っています。カメラ機能など、建築現場特有の機能などはよく要望を頂くのでライブラリ化することでだいぶ助かっています。

         f:id:oct88:20190530161018p:plain

設計を振り返って

 今回設計を振り返ろうと思ったきっかけは、あるアプリをリニューアルするにあたり現状の設計を見直して改善できる部分を洗い出そうと思ったからです。今までの設計の中で失敗だったなと思ったのは役割があいまいなManagerクラスを作ってしまったことや、色んな場所から呼び出したいモジュールを安易にシングルトンにしてしまったことなどです。次の設計では、このあたりを解決した構成を考えたいと思っています。形になった段階でまた記事を書こうと思います。おたのしみに!では 

積極採用中

弊社では、業務拡大中で最高の設計をしたいiOSアプリ開発者を積極採用しております。みなさまのご応募お待ちしております!!エンジニア採用サイトに募集職種や、会社の雰囲気の分かるインタビュー記事があります。是非ご覧ください。

5月の社員総会を行いました!!

今週の月曜日は月に1度の総会の日でした!

 

各部門より先月からの取り組みや達成率、データなどが全社員に共有されます。

 

「へぇー、そんなことしてるんだ」とか「そういうところにお客さんは喜ぶのかぁ」など、営業チームやCSチームから話を聞いてて、勉強になる所もたくさんあります。

 

さて、もちろん開発部にも発表のセクションがあります!

 

しかもいつもなぜかトップバッター。

 

CTOはこの雰囲気にまだ慣れないと言ってましたw

f:id:yohei-fujii:20190520204448p:plain

 

まずは、CTOから改めてビジョンの共有

 

f:id:yohei-fujii:20190520204603p:plain



日頃、対応に追われていて忘れがちになるものですが、やはり頭に入れておかなければならないことです。何のために今のプロダクトを開発しているのか、ただ単にレンガを積むことになっていないか。最終的にはここに繋がっていることを忘れてはなりません。

 

 

次のスライドの中で、4つのことを「行動」というパートで述べていました。

 

  1. 技術顧問の就任
  2. ミッション設定
  3. ロードマップづくり
  4. KPIの見える化

 

最近オクトでは、開発部それぞれのチームに技術顧問の方に来て頂いております。フロント、インフラ、自動化、etc... それぞれの分野で知見を持っていらっしゃる方々のお力を借りることで、より良いサービス開発に繋げています。

 

またそれだけではなく、個人のミッション設定、チームとしてのロードマップづくり、そしてそこから得られる結果としてのKPIの見える化に取り組むことで、「組織として動くための構造づくり」に繋げています。

 

 

さて、CTOからのお話の後は、各プロダクトそしてエンジニア部門からの発表タイムです。

 

施工管理チーム、ERPチーム、新規開発チームからそれぞれプロジェクトの進捗が発表されます。そしてその後にそれぞれ、フロントエンド、SRE(改善)、インフラ、デザインと発表の時間が取られました。

 

  • 新たな取り組みや挑戦
  • ここ1ヶ月で達成したこと
  • 新メンバーの紹介
  • 導入ツールの説明
  • セキュリティ面での取り組み
  • etc...

 

この総会は開発部だけでなく、営業部やCSなど、他部署の人たちも参加しています。普段開発がどんなことに取り組んでいるのかを知ってもらういい機会でもあります。

 

個人的にはフロントエンドのセクションで話させてもらいましたが、Rails + AngularのプロジェクトにVueを組み込んで、サクサク動いた動画をお見せした時の会場の盛り上がりは気持ちよかったですww 

 

開発部の後は、CS、営業部、人事・総務、マーケティングそしてCEOとお話が続きました。ワクワクするようなお話も多々。

 

 

 

どんな話かって?

 

 

それは近々発表されるかも♪

もしくは入ってみてのお楽しみです♪

 

 

 

総会が終わったら普段はそれで解散なのですが、今回は懇親会が催されました。

 

お酒とお料理が振舞われ、部署を超えての交流タイム〜〜

 

f:id:yohei-fujii:20190520203700p:plain

 

東京だけじゃなく、各支社からも集まっているし、新しくジョインしたメンバーも多いので、オフィスのフリースペースはもうパンパン。

 

 

f:id:yohei-fujii:20190520214051p:plain

 

美味しそうなお食事が並びます!!

みんなテンションUP!

 

f:id:yohei-fujii:20190520203702p:plain

 

 

美味しいつまみに行列

 

 

f:id:yohei-fujii:20190520203703p:plain

 

最後にみんなで集合写真。パシャり!

総会は多くの社員が顔を合わせる日でもあり、交流も多く生まれます。

 

こんな感じで社会変革に取り組みながらもワイワイと楽しく仕事をしています!一緒にANDPADを盛り上げてみませんか?

 

開発メンバー絶賛募集中です!

 

NuxtMeetUp#8 登壇レポート

NuxtMeetUp#8 に参加&登壇してきました!

オクト プロダクトチームの藤井です。普段はフロントエンド機能開発や改善を担当しています。

 

先日、永田町GRIDで開催されたNuxtMeetUp#8に参加してきました!

nuxt-meetup.connpass.com

 

このイベントは会を追うごとに大きくなっており、今回初めて登壇側で出させてもらうことに。知り合いも多くいましたので、あまり緊張することなく楽しめたかなぁと思います。

 

f:id:yohei-fujii:20190509143548j:plain

 

さて、今回発表させてもらいました内容ですが、こちらになります!

 

speakerdeck.com

 

今回の発表目的は、技術説明というよりかは、知見共有になります。

 

入社してから2ヶ月半ほどは、別のNuxtプロジェクトに携わっておりました。しかし、3月ごろから、「本体」と呼ばれるメインのサービスのある機能のフロント部分を担当することになり、その際にNuxtに切り出せないかと「1日検証」した際のお話です。

 

1日で移行なんて無理があると思われた方、全くその通りだと思います。ただ今回の目的は、「移行のための調査」であるので、ざっくりと、どういったところに懸念点等があるのかを探るためでしたので、短時間で良いと判断しました。

 

(詳しくはスライドをご覧下さい)

 

今回ですが、3月の時点でのいきなりの移行は難しいと判断しましたが、諦めた訳ではありません。移行を見据えた開発や修正を引き続き行なっていきます。適宜進捗はこちらのブログで更新していきますので、よろしくお願いします。

 

最後に

こちら弊社のエンジニア採用サイトになります。どんな会社なのか雰囲気を感じて頂ければ幸いです。