kustomizeやSecretを利用してJavaアプリケーションをデプロイする

2021年5月20日(木)
深見 圭介

Deploymentマニフェスト

ここからDeploymentマニフェストを見ていきますが、ほとんど同じ設定内容なので、Article サービスのマニフェストを例に見ていきます。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: article
  name: article
spec:
  replicas: 1
  selector:
    matchLabels:
      app: article
  template:
    metadata:
      labels:
        app: article
    spec:
      containers:
      - name: article
        image: article:prod
        envFrom:
        - secretRef:
            name: article-config
        resources:
          requests:
            cpu: 200m
            memory: 512Mi
          limits:
            cpu: '1'
            memory: 2Gi
        ports:
        - name: web
          containerPort: 8080
          protocol: TCP

articleコンテナで利用するコンテナイメージとして、article:prodというイメージ名が指定されています。このフィールドは、kustomizeを利用することでkustomization.yamlのimagesフィールドでの指定によって変更します。kustomization.yamlの以下の箇所です。

images:
- name: article
  newName: registry.gitlab.com/creationline/kubernetes-thinkit-sample1/article

nameフィールドでarticleが指定されており、newNameフィールドに新しいコンテナイメージ名が指定されています。これはコンテナイメージ名としてarticleが指定されている箇所をnewNameで指定されたコンテナイメージ名に置き換えるという設定です。なお、タグ部分(prod)は同じくnewTagフィールドを設定して変更することもできますが、今回はそのままにしています。

articleコンテナのenvFromフィールドでは、SecretやConfigMapから環境変数を読み込みます。このマニフェストの指定ではarticle-configという名前のSecretを読み込んでコンテナの環境変数に設定することを示しています。

envFrom:
- secretRef:
    name: article-config

ただし、この参照は前のセクションで見たように、kustomizeによってsecretGeneratorが生成したSecretの名前に置き換えられます。全体で見るとconfig/article/config.envファイルで設定される環境変数がそのままアプリケーションの環境変数に追加された動作となります。

また、WebSiteサービスのマニフェストでは、対応する箇所が以下のようにconfigMapRefフィールドによりConfigMapを参照しています。ここではリソースの種類(kind)が異なるだけで、ほぼ同じ利用法となります。

envFrom:
- configMapRef:
    name: website-config

ArticleサービスのDeploymentのマニフェストに戻ります。envFromフィールドの後にはresourcesフィールドがあります。

resources:
  requests:
    cpu: 200m
    memory: 512Mi
  limits:
    cpu: '1'
    memory: 2Gi

これは、コンテナに割り当てるマシンリソースの要求(requires)量と制限(limits)量を設定しています。

requiresフィールドに設定されたリソース量は、Podの起動時に、稼働するために必要なリソースとして考慮されます。KubernetesはPodを起動するNodeにそれだけの空き容量があることを確かめてPodを稼働します。そのため、確実に確保したい容量を設定します。

limitsフィールドに設定されたリソース量は、Podの起動時に、その制限量を超えてリソースを消費しないように設定されます。Kubernetesはコンテナランタイムを通じて設定するため、どのようにリソース制限が強制されるかはコンテナランタイムの実装に依存します。一般的にはアプリケーションが余裕を持って稼働できるリソース量を設定します。

CPUリソースの設定は、割り当てるCPU時間を設定します。値1はCPUの1コアを専有する割り当てに相当し、0.1や100mといった指定は1コアの十分の一の割り当てを意味します。メモリーは使用するバイト数で指定しますが、通常はMiやGといった単位を付けて表記することが多いです。

CPUやメモリー以外のリソースの設定に関するそれぞれの詳細は、公式ドキュメントのコンテナのリソース管理に記載があります。

Deployment マニフェストの最後にportsフィールドの設定があります。

ports:
- name: web
  containerPort: 8080
  protocol: TCP

後でServiceリソースからDeploymentへのルーティングを設定しますが、その際にポート番号を直接指定するのではなく、ここで指定したnameフィールドの値を使うことで、コンテナが使うポート番号を変更する際には、このマニフェストの修正だけで済みます。

なお、この記述をしなくても同じクラスタ内からはコンテナの任意のポートにアクセスできます。アクセス制限をしたり許可したりする目的のものではありません。

Service マニフェスト

Serviceのマニフェストファイルservice-article.yamlに移りましょう。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: article
  name: article
spec:
  type: ClusterIP
  selector:
    app: article
  ports:
  - name: web
    port: 8080
    targetPort: web

第3回と名前やラベル以外はそれほど変わりませんが、portsフィールドでnameとtargetPortを指定しています。targetPortフィールドはDeploymentマニフェストでPodテンプレートに設定したポートの名前(nameフィールドの値)を設定して関連付けを明示しています。

nameフィールドは役割を分かりやすくする意味で設定していますが、この後にIngressマニフェストからの参照でも使用します。

Ingressマニフェスト

Ingressのマニフェストファイルingress-article.yamlは、以下のようになっています。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: article
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - http:
      paths:
      - backend:
          service:
            name: article
            port: 
              name: web
        path: /api/articles
        pathType: Prefix

backendのポートの指定をポート番号ではなく名前で指定しています。これはすぐ上のServiceマニフェストの中で設定されたnameフィールドの値を参照しています。また、pathフィールドは/api/articlesとなっています。pathを詳しく指定しているのは、他のサービスとの兼ね合いです。

今回のアプリケーションでは4つのサービスがあり、すべてIngressを用いて外部公開しています。AccessCountサービスは内部サービスであり、外部に公開する必要はありませんが、挙動を確認しやすいよう外部に公開しています。

本連載では、使用するKubernetesクラスタへのアクセスをIPアドレスで行うことを想定しているため、Ingressで名前(ホスト名)ベースのルーティングはできません。そこで、パスベースのルーティングを行っています。pathフィールドの値を他のサービスのIngressと並べてみると、以下の通りです。

  • Article
    path: /api/articles
    pathType: Prefix
  • AccessCount
    path: /api/accesscounts
    pathType: Prefix
  • Rank
    path: /api/ranks
    pathType: Prefix
  • WebSite
    path: /
    pathType: Prefix

最初のArticle、AccesCount、Rankサービスはそれぞれ異なるパスを指定しているので、クラスタへ到達したリクエストは、パスが前方一致するIngressにより、それぞれのサービスにルーティングされます。WebSiteサービスはどうでしょうか。前方一致だけであれば、スラッシュ(/)だけなので、すべてのリクエストに一致してしまいそうです。しかし、複数のパスに一致した場合は最も長くパスが一致したものが優先される仕様のため、WebSiteサービスは他のIngressのパスに一致しなかったリクエストがルーティングされます。

サンプルアプリケーションのデプロイ

ここまで、プロダクション環境用のマニフェストを見てきましたが、外部のデータベースを準備する必要があるため、開発用データベースのマニフェストを含んだ開発環境用のマニフェストをデプロイします。

前提条件として、前回デプロイしたtraefikが手順通りデプロイされていることを想定しています。マニフェストは、サンプルアプリケーションのリポジトリのdeployment/develop/kubernetes/ディレクトリに配置されています。アプリケーションの構成は変わりませんが、開発用データベースもマニフェストに含んでいます。

WebSiteサービスの設定ファイルが、マニフェストのルートdeployment/develop/kubernetes/からの相対パスでconfig/website/config.env.sampleにあります。このファイルを同じディレクトリのconfig.envに名前を変えてコピーします。内容は以下のようになっているので、

ARTICLE_BASE_URL_FROM_SERVER=http://article:8080
ARTICLE_BASE_URL_FROM_CLIENT=
RANK_BASE_URL_FROM_SERVER=http://rank:8080
RANK_BASE_URL_FROM_CLIENT=
ARTICLE_BASE_URL_FROM_CLIENTとRANK_BASE_URL_FROM_CLIENTの値を設定します。設定する値はhttp://<ノードのIPアドレス>です。設定した後のconfig.envファイルの例は以下の通りです。
ARTICLE_BASE_URL_FROM_SERVER=http://article:8080
ARTICLE_BASE_URL_FROM_CLIENT=http://203.0.113.10
RANK_BASE_URL_FROM_SERVER=http://rank:8080
RANK_BASE_URL_FROM_CLIENT=http://203.0.113.10

kubectlコマンドが目的のkubernetesクラスタを操作するよう設定されていることを確認して、リポジトリのルートディレクトリに移動し、以下のコマンドを実行します。

kubectl apply -k deployment/develop/kubernetes/

少し待ってkubectlコマンドでPodの動作状況を確認すると、以下のようになると思います。

$ kubectl get po
NAME                           READY   STATUS    RESTARTS   AGE
accesscount-68df6bd68c-jmt8t   1/1     Running   0          2m27s
accesscountdb-0                1/1     Running   0          2m19s
article-569d459544-wclwc       1/1     Running   0          2m27s
articledb-0                    1/1     Running   0          2m7s
rank-99fcd8774-65l2p           1/1     Running   0          2m27s
rankdb-0                       1/1     Running   0          2m15s
website-55f54876dc-6dbbp       1/1     Running   0          2m25s

この状態で、ブラウザにクラスターからアクセスすると、以下のように、まだ記事もランキングもデータがないため表示されません。

リポジトリには、サンプルデータをAPIで投入するスクリプトがあるので、それを使ってデータを作成します。

ARTICLE_URL="http://<ノードのIPアドレス>" ./scripts/post-sample-article.bash
ARTICLE_URL="http://<ノードのIPアドレス>" ACCESSCOUNT_URL="http://<ノードのIPアドレス>" ./scripts/dummy-access-at.bash "<前日日付>"
RANK_URL="http://<ノードのIPアドレス>" ./scripts/update-daily-rank.bash "<前日日付>"

<前日日付>は操作を行う前日の日付をYYYY-MM-DDの形式で指定します。例えば、作業日が2021年5月21日なら前日は2021年5月20日なので2021-05-20と指定します。ブラウザを更新すると、以下のように記事の一覧やランキングが表示されます。

おわりに

今回は、Javaアプリケーションをデプロイしてみました。kustomizeやSecretなど、今まで取り上げていなかったツールやリソースが出てきて少し複雑だったかもしれません。コマンドで指定したディレクトリにあるマニフェストが、ほぼそのままデプロイされたことが確認できたのではないでしょうか。今回の内容を通じて、各マニフェストの新しい内容について理解していただければと思います。

今回は、特にアプリケーションをデプロイすることに注力し、使っていない機能などについては割愛しました。今後の連載では、kustomizeやSecret、ConfigMapといったツール・リソースも取り上げていく予定ですので、お楽しみに!

日立ソリューションズ・クリエイト
日立ソリューションズ・クリエイトに所属し、Webアプリケーション開発に従事したのち、 2019年1月からクリエーションライン株式会社と製造業向けにコンテナ/Kubernetesを活用したデータ分析基盤やIoTアプリケーション基盤の開発に従事。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています