自己紹介
初めまして。23新卒で入社いたしました、技術統括本部プラットフォームサービス開発部インフラユニットの菅野です。私は弊社に入社するまではほとんどプログラミングに触れることがありませんでしたが、アプリケーションの下支えであるインフラユニットにて勤務しています。配属されてから2ヵ月間の私の仕事は、「山のように積んである参考書を使った勉強」、「勉強会での技術の学習」、「実際にアプリケーションをデプロイして、業務で使うツールの理解を深める」でした。インフラエンジニアはアプリケーションの開発よりも階層が低い、アプリケーションの土台となるネットワークやサーバーを扱います。それまで触れてこなかったネットワークやサーバーについての基礎知識の習得が仕事の始まりでした。今回はアプリケーションをデプロイしたことに着目して、お伝えしていきます。
はじめに
6月末まで、私はIT研修を受けていました。IT研修の後半では、2人1組で業務用チャットアプリを開発しました。仕様書通りに実装できなかった機能もあり、いまだ開発途中です。例えば、写真添付などの機能を実装する予定です。今回はこのチャットアプリをEKSにデプロイします。デプロイする過程で、Kubernetes、Helm、Terraform、AWS等の実務で使う機能を把握することが目的です。
まずは、使用したツールの説明をし、私が行った作業の流れをstageごとに紹介します。
使用ツール
1. Kubernetes
Kubernetesはコンテナオーケストレーションエンジンです。複数のコンテナをpodという単位で管理します。podが乗る仮想コンピュータがnodeです。Kubernetesは指示された通りに、podを維持します。Kubernetesへの指示はmanifestで行います。今回はチャットアプリ(以降はchatappとします)とデータベースサーバーを管理してもらいます。
参考: Kubernetes
2.Helm
HelmはKubernetesのパッケージマネージャーです。Kubernetesのmanifestをテンプレート化して、Chartとして管理できます。Chartをダウンロードして、手元の環境に適した値を入れることで、誰でもアプリケーションを使えるようになります。アプリケーションによってはリポジトリに公開されています。今回はHelmに併せて、Helmfileというツールを使用します。Helmfileを用いると、コードでChartをダウンロードし、値を入力することができます。今回はchatapp、nginx、image-pull-secretをChartとしてダウンロードするために用いました。image-pull-secretについては、stage4で詳細を説明します。
参考: Helm
参考: Helmfile
3.Terraform
Terraformはコードとして、宣言的にインフラを管理できるツールです。AWS、Azure、Google Cloud Platform (GCP)、Kubernetes、Helm、GitHub、Splunk、Datadogなどさまざまなサービスのリソースをコードで管理できます。また、バージョン管理を簡単に行うことができます。今回はRDSを構築するために使用しました。
参考: Terraform
4. AWS関連
AWSではインフラストラクチャテクノロジーから機械学習、AI、データレイクと分析、IoT などの最新鋭のテクノロジーに至るまで、様々なサービスが提供されています。AWSを利用することでクラウド型のサーバー設計できます。今回はその中でも、EKS、VPC、RDSを主に用いました。
Amazon EKS
AWSでKubernetesを実行するために使用できるマネージドサービスです。EKSを導入すればEC2(AWSの仮想サーバー)と、EC2のリソースを制御する機能が使えます。chatapp、その周辺のデータベースサーバーをEKSにデプロイしました。
参考: Amazon EKS
Amazon VPC
AWS内の論理的に隔離された仮想ネットワークです。VPCに割り当てたIPアドレスのホスト部を割ることで、サブネットを作成することができます。サブネットをインターネットゲートウェイに接続するとパブリックサブネット、接続しないとプライベートサブネットとなります。今回はchatappとデータベースであるRedis、PostgreSQLをプライベートサブネットに置きました。
また、VPCの中でセキュリティグループを作成できます。セキュリティグループはインスタンスのファイアウォールです。
参考:VPC
Amazon RDS
クラウド内でリレーショナルデータベースを簡単に設定、運用、スケールするためのPaaSのクラウドサービスです。今回はchatappのメッセージなどを保持しているPostgreSQL(リレーショナルデータベース)をRDSにデプロイします。
参考: Amazon RDS
チャットアプリデプロイの流れ
stage0: IT研修終了時のチャットアプリの構成
IT研修終了時のchatappは図1の構成になっています。データベースサーバーをコンテナ化して、作業者のマシンのローカルでchatappからアクセスしていました。データベースサーバーにはセッション情報を記録するRedisと、メッセージ、ユーザー情報などを記録するPostgreSQLを用いました。backendサーバーにはExpress.jsを用いて、frontendではVue.jsでブラウザに表示するhtmlを作成していました。また、frontendからbackendへのリクエストにはAxiosを用いていました。
図1 IT研修終了時のchatapp構成
stage1: chatappのコンテナ化と環境変数を設定
chatappとデータベースサーバーをそれぞれ別のコンテナに分離して、起動するようにしました。chatappのコンテナイメージはDockerfileで作成し、ローカルのコンテナイメージを指定してコンテナを起動しています。この時、使用者の環境によって値が変わるものは、使用者ごとに入力できるように、環境変数で設定します。いちいち環境に合わせてソースコードを直してコンテナイメージをビルドし直すのは手間がかかるからです。今回は、EKSにデプロイする際に依存するサーバーのエンドポイントが変わるため、依存サーバーのエンドポイントを環境変数化します。
図2 stage1の構成図
stage2: chatappとデータベースサーバーをKubernetesでコントロール
アクセス数が多かったり、本来予測していない動作を与えられたとき、サーバーのコンテナはダウンします。stage1の段階では、サーバーダウンを人間が検知し、ダウンするごとにコンテナを起動し直す必要があります。しかし毎度毎度人間がコンテナの様子を確認し、PostgreSQL,
Redis,chatappと一つ一つサーバーを起動し直すのは手間です。この問題を解決するために、Kubernetesを導入します。
Kubernetesに維持してほしい状態を指定する際の命令書がmanifestです。deploymentはどのようなリソースをどのように維持するかを指定します。例えばchatappのpodを2個維持してほしいと指定します。serviceはL4ロードバランサー、ingressはL7ロードバランサーです。ingress controllerにはnginxというWebサーバーを用いています。それぞれのmanifestを作成し、masterに指示することで、masterが全体を制御します。
図3 stage2の構成図
initContainerの導入
manifestでmasterに指示を出すと、nginx(ingress)、chatapp、Redis、PostgreSQLが起動します。chatappは起動時、データベースに初期値を投入する必要があります。そこで、データベースが起動し、接続できるようになった後にchatappが起動する必要があります。
データベース、chatappの順で起動させるために、initContainersを導入しました。initContainerはKubernetesの機能の一つです。Pod内でアプリケーションコンテナの前に実行される特別なコンテナです。initContainerの設定は、「chatappコンテナが依存するデータベースサーバーに、ヘルスチェックを目的としたリクエストを断続的に行い、利用可能であるという応答が返却されたら終了する」としました。
stage3: chatappのmanifestをHelmでtemplate化
利用者ごとに一部の設定を変更するだけで、アプリケーションを起動できるようにHelmを導入します。 今回はchatappをtemplate化して、GitLabのリポジトリとして切り出しました。このリポジトリにsshで接続し、Chartをダウンロードし、自分の利用環境に合わせた設定をvalues.yamlに書き込むことにしました。
図4 stage3の構成図
stage4: chatappのコンテナイメージをGitLabコンテナレジストリにアップロード
これまではローカルでビルドしたコンテナイメージを用いてコンテナを起動していました。chatappをAWSにデプロイするために、誰でもアクセスできる場所にコンテナイメージを置く必要があります。そこで、GitLabのコンテナレジストリに保存したコンテナイメージをダウンロードし、コンテナを起動する構成にしました。
GitLabのコンテナレジストリからコンテナイメージを取得するためには認証が必要です。コンテナイメージを置いたリポジトリでレジストリを読み取る認証(デプロイトークン)を発行し、secretで認証情報を定義し、chatappに付与します。このときsecretを与えるchart(image-pull-secret)をGitLabからダウンロードして、使う構成にしました。
stage4までの間、chatapp、image-pull-secret、nginxを外部からダウンロードして使う構成にしています。関連図を図5にまとめました。
図5 コンテナイメージ、チャートの構成図
stage5: chatappをEKSにデプロイ
ついにchatappをEKSにデプロイします。今回はすでに作成されているEKSインスタンスにデプロイする形になります。認証情報などをconfigファイルに書き込み、EKSに向き先を変えたkubeconfigを生成します。また、今までingress controllerとしてnginxを用いていましたが、このEKSで元々使われていた、Istioを代わりに使用します。最後にHelmfileをEKS環境にapplyして、chatappがEKS環境で動くようになりました。
図6 stage5の構成図
stage6: PostgreSQLをRDS上で起動させ、chatappと接続
今まではPostgreSQLのpodを起動し直すたびに、データがリセットされていました。データを永続的に保存しようとすると、手元のマシンのスペックによって上限が決まってしまいます。そこで、ストレージのスケーラビリティに富んでおり、高い可用性があるRDS上にPostgreSQLを置くことにしました。Terraformで、"RDS for PostgreSQL"を置くサブネットとセキュリティグループを設定し、chatappが属するセキュリティグループからのみリクエストを受け付けるように設定しました。RDSのインスタンスタイプやストレージを設定し、インスタンスを起動します。最後にchatappと接続確認しました。これでchatappのデプロイを完了したと言って良いでしょう。
図7 stage6の構成図
結果、学び
今回デプロイしたchatappの物理構成図は図8に示しています。赤く塗りつぶされている枠はセキュリティグループを表しています。1つのRDSインスタンスを、ap-northeast-1aまたはap-northeast-1cのどちらかのサブネットに置くようにしました。データベースのセキュリティグループには、chatappのセキュリティグループからのインバウンドのトラフィックを許可するように設定しました。また、実際のchatappの画面を図9に示しています。
EKSへデプロイしRDSを利用したことで、IT研修で作成したchatappを、より可用性の高い構成にすることができました。また、Kubernetes、Helm、Terraform、AWSの基礎知識を学ぶことができました。chatappのソースコードだけを書いていた際は、手元で動かせることがゴールでした。しかし配属後は、私がパソコンに向き合っていない時でも、常時動く設計にすることがゴールでした。今回、EKSにチャットアプリをデプロイする過程で、障害に耐えうる設計にするという、運用に必須な考え方を学ぶことができました。
図8 chatappの物理構成図
図9 chatappの実際の画面
終わりに
配属後、chatappをデプロイするまでにユニットの皆様から様々なサポートをしていただきました。ツールの勉強会を開いていただいたり、chatappをもっと良くするために意見出しをしていただきました。この場を借りて改めて御礼申し上げます。
IT研修からEKS環境へのデプロイまで、アプリケーションの開発を一気通貫で行いました。ツールを完全に理解する道のりはまだまだ先の長いものだと実感しています。しかし、配布されたパソコンで恐る恐る環境構築を行い、まっさらなエディターにソースコードを書き込んだ2ヵ月前を考えると、大きく前進することができた様に思います。今回得た学びをもとに、日々研鑽し、皆様が安心して使えるサービスを提供できるように頑張ります。ご覧いただきありがとうございました。
IT研修では、私のようなエンジニア志望のプログラミング未経験者が、グッとエンジニアリングの基礎力を成長させることができます。
OPTiMでは随時、エンジニアを募集しております。 www.optim.co.jp