「The Twelve-Factor APP III．設定」をKubernetes上に置き換えて考えたときの話

## はじめに
最近、とある事情で「[The Twelve-Factor APP Ⅲ.設定](https://12factor.net/ja/config) 」を読みました。
そこで、今、自分が絶賛勉強中であるKubernetesでは、「Ⅲ.設定」の形にするにはどのようにすればよいのか、あるいは何を使えばいいのかを考えてみました。その過程で、Kubernetesの知識、The Twelve-Factor APPの解釈に必要な知識などを一から学習し、本稿では学んだことや参考文献などをまとめてみることにしました。
たらたらと長めの浅い文章を記述したので、結論から見ることをお勧めします。

本稿は、自身の学習過程で参考になったブログ、記事を集めて、補足的な説明を加えたものになっています。深い、小難しい内容ではございません。また個人的な見解が多く散見します。本来の見解とは異なる可能性がありますので、ご了承ください。


## The Twelve-Factor APP Ⅲ.設定について
まず、The Twelve-Factor APPについての説明です。
「[The Twelve-Factor APPのはじめに](https://12factor.net/ja/)」の部分 を引用すると、
>現代では、ソフトウェアは一般にサービスとして提供され、Webアプリケーション や Software as a Service と呼ばれる。Twelve-Factor Appは、次のようなSoftware as a Serviceを作り上げるための方法論である。
・ セットアップ自動化のために 宣言的な フォーマットを使い、プロジェクトに新しく加わった開発者が要する時間とコストを最小化する。
・下層のOSへの 依存関係を明確化 し、実行環境間での 移植性を最大化 する。
・モダンな クラウドプラットフォーム 上への デプロイ に適しており、サーバー管理やシステム管理を不要なものにする。
・開発環境と本番環境の 差異を最小限 にし、アジリティを最大化する 継続的デプロイ を可能にする。
・ツール、アーキテクチャ、開発プラクティスを大幅に変更することなく スケールアップ できる。

感想として、解釈がかなり難しかったです。コスト最小化、移植性とアジリティの最大化、クラウドプラットフォーム上へのデプロイ可能、高度な拡張性、これらを実現できるサービスとは何が必要なのか。そのような方法論をThe Twelve-Factor APPは示していると捉えています。
ここでは、詳細な解釈の説明は省きますが、ざっくりいうと、The Twelve-Factor APP(以下「12Factor」)とは、上記のSoftware as a Serviceを構築する方法として、少なくとも12個の要因が存在し、その要因の指針あるいは方針について書かれたものであると認識しています。

そこで、本題の「12Factor#Ⅲ.設定」についての説明です。
「Ⅲ.設定」では、 「**設定を環境変数に格納する**」と書かれています。ここでいう「設定」とは以下の通りです(引用：https://12factor.net/ja/config)
>・データベース、Memcached、他のバックエンドサービスなどのリソースへのハンドル
・Amazon S3やTwitterなどの外部サービスの認証情報
・デプロイされたホストの正規化されたホスト名など、デプロイごとの値

上記3つに該当する設定情報などは環境変数に格納すべきと記述しています。
実際の開発では、「12Factor#設定」の設定とはどこを指すのか。その判断材料としては、デプロイの間(種々の実行環境ごと)で変わるかどうかであると考えています。設定の定義には、以下の記述を抜粋しました。
>アプリケーションの **設定 は、デプロイ（ステージング、本番、開発環境など）の間で異なり得る唯一のもの**である。

>**アプリケーションは時に設定を定数としてコード内に格納する。****これはTwelve-Factorに違反**している。**Twelve-Factorは 設定をコードから厳密に分離**すること を要求する。**設定はデプロイごとに大きく異なるが、コードはそうではない。**
　　　　　　　　　　　　・・・略・・・
なお、この**“設定”の定義**には、**アプリケーション内部の設定は 含まない ことに注意**する。内部の設定とは、Railsにおけるconfig/routes.rbや、Springにおいてコードモジュールがどう接続されるかなどの設定を指す。この種の設定は**デプロイの間で変わらないため、コードの内部で行うべき**である。
　　　　　　　　　　　　・・・略・・・
**Twelve-Factor Appは設定を 環境変数 に格納する。 環境変数は、コードを変更することなくデプロイごとに簡単に変更できる。**

デプロイごとに変更されうる設定情報をコード内に入れると、デプロイが変化するたびにコードの変更を要求されます。これはコストの最小化、移植性の最大化に反していると考えられます。
コード内に設定情報を入れるのではなく、環境変数に設定情報を格納することにより、コードを変更することなくデプロイごとに簡単に設定の変更が可能であることを示しています。

また、設定ファイルを使用した観点と環境変数を使用した観点を対称的に取り上げて、尚も環境変数に格納すべきであると示しています。
>設定ファイルとは異なり、誤ってリポジトリにチェックインされる可能性はほとんどない。

まとめると、環境変数はデプロイごとに簡単に変更可能で、リポジトリにチェックインされることのない要素を持っているから、設定情報を格納すべきであると解釈しました。

## kubernetesとは
まず、kubernetesってなんだという話で最初に参考させていただいたのは以下の記事です。

>**今さら人に聞けない Kubernetes とは？**
[https://qiita.com/MahoTakara/items/85096f8b2632c802ab22]

Kubernetesのできることやメリット、構成要素(アーキテクチャ)の話をまとめています。インフラ、Docker周りの知識がない私にとっては、正直、当初はむずしかったですが、用語の概念さえを抑えていけば(まだ完璧ではないが)、Kubenetesに対するイメージが浮かび上がってくると思います。

ちなみにDocker周りの知識は以下の参考資料を頼りに学びました。

>**Dockerの基礎をまとめてみた ~ 第一章：コンテナ？Dockerとは？**
https://qiita.com/supaiku2452/items/8b06b774c0e2fce7df92

仮想化についての基本的な説明からDockerが動く仕組みについてまとめられています。仮想化、Dockerについての説明が入門者にとってはわかりやすかったです。Dockerが動く仕組みを理解するには、Linuxにおけるnamespaceとリソース管理(cgroups)の概念の知識が必要でした。

>**Docker/Kubernetes 実践コンテナ開発入門**
https://gihyo.jp/book/2018/978-4-297-10033-9

個人的には、体系的に学びたかったので、「Docker/Kubernetes 実践コンテナ開発入門」を参考に写経しています。感想としてはかなりわかりやすいです。

## Kubernetesと12Factor#Ⅲ.設定の関連性
以上で、Kubernetes と12Factorについて初歩的な知識を少し学びましたと。
では、Kubernetes において、12Factor#Ⅲ.設定はどのようにフィールドに該当するか考えていきます。
###Kubernetes上においてのデプロイとは
上記「The Twelve-Factor APP Ⅲ.設定について」で、設定の定義について自分が解釈したことを記述しました。その上で、設定の定義については、デプロイの間で設定情報が変更されうるかどうかが肝になってくると考えています。ではKubernetesにおいて、デプロイの仕組みはどうなっているか,学習したころを簡単にまとめてみました。

Dockerではイメージとよばれる実行するアプリケーションの設定や構成をまとめたものを基に、コンテナを生成し、アプリケーションを実行するということでした。
Kubernetesでは基本的にPod(コンテナの集合体)やJobなどのリソースの集合体、クラスタを構築してアプリケーションのデプロイを行います。デプロイ構成には、アプリケーションの構成する部品のようなものが必要で、それがリソースにあたり、Kubernetesでは様々なリソースが存在します。

Kubernetesで実行されるアプリケーションは様々なリソースと協調して動作しています。

ここで、12Factor#Ⅲ.設定とKubernetes との対応関係について理解するには、リソースという概念あるいはその種類の知識が必要であることがわかりました。また、Kubernetesでは環境変数をどのように設定および利用しているのかについて注目し始めました。

リソースの種類については、以下を参照しました。
> **Kubernetes の各リソースに対するメモ**
https://qiita.com/apstndb/items/e75c40975183b8aabba6

PodやNodeなどの知識には以下を参照しました。
>**Kubernetes チュートリアル**
https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/explore/explore-intro/
>**k8s pod 概要について自習ノート**
https://qiita.com/MahoTakara/items/f5130bb6e9e493c46c6b



### 環境変数の話

上記の背景から、Kubernetesで環境変数の扱いを学習しました。


Kubernetesでは環境変数の埋め込みは5つリソースによって埋め込めます。

* 静的設定
    * ```sepec.containers[].env```に静的な値を定義
* Pod情報
    * Podの情報を```fieldRef```で参照
* コンテナ情報
    * コンテナ情報を```resourceFiledRef```で参照
* ConfigMapリソースの設定値
    * ConfigMapリソースを``spec.containers[].env```の```valueFrom.configMapKeyRef```で利用
    * 設定とアプリケーションを切り離す・設定を動的に注入することが容易
    * 同一のコンテナイメージを様々な場面・環境で使い回せる
* Secretリソースの機密情報
    * Secretリソースを``spec.containers[].env```の```valueFrom.secretKeyRef```で利用
    * ConfigMap同様、設定とアプリケーションを切り離す・設定を動的に注入することが容易でコンテナイメージの使い回し可能
    * 機密情報を別リソースとして定義しておき、Podからそれを読み込むことができる。
    * マニフェストをGitリポジトリにアップロードすることはできない。(kubesecと呼ばれるOSS使用によりアップロード可能)



## 結論
「The Twelve-Factor APP III．設定」に則ってみると、デプロイごとに変更されうる設定情報は環境変数に格納し、Kubernetesでは、静的設定、Pod、コンテナの情報、Secret、ConfigMapで環境変数を利用できる。
上記でまとめたそれぞれの使い道に合わせて、設定を環境変数に格納しましょうよって話。

## おわりに
Kubernetesの環境変数について一番最初に調べるのが手っ取り早いし、それを記述すべきですが、体系的に理解したことをメモしたかったので、長めの投稿になりました。


## 参考文献
* https://12factor.net/ja/config
* https://qiita.com/MahoTakara/items/85096f8b2632c802ab22
* https://qiita.com/supaiku2452/items/8b06b774c0e2fce7df92
* https://gihyo.jp/book/2018/978-4-297-10033-9
* https://qiita.com/apstndb/items/e75c40975183b8aabba6
* https://qiita.com/MahoTakara/items/f5130bb6e9e493c46c6b
* https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/explore/explore-intro/