はじめに

今回はコンテナオーケストレーションツールの代表格である「Kubernetes」をAuzre上で実行することのできる、「Azure Kubernetes Service(AKS)」について紹介します。
コンテナオーケストレーションツールやKubernetesとは何かについて説明し、AKSを使ってコンテナ化アプリケーションを実行していきます。

Kubernetesとは

Azure Kubernetes Service(AKS)を紹介するにあたって、まずはKubernetesについて説明していきます。

Kubernetesとは

Kubernetesは複数のマシンで構成される環境でのコンテナの実行を管理をするためのツールです。Dockerが単一のマシンに対するコンテナのライフサイクルを提供するのに対し、Kubernetesは複数のマシンにまたがってコンテナの実行を管理するための機能を提供します。DockerではDockerfileを使った方法などでコンテナを作成したり、コンテナをコンテナレジストリに登録したりすることができますが、Kubernetesはあくまでコンテナの実行のみをサポートしています。

Kubernetesの代表的な機能や特徴として、以下のものがあります。

・コンテナオーケストレーション
 コンテナを実行するマシンに障害が発生した場合にコンテナを終了して他のマシン上で自動的に再起動させるセルフヒーリング機能や、負荷などの条件によって稼働するコンテナ数を増減させるオートスケーリングなどのコンテナ管理機能を有しています。

・設定ファイルに理想的なデプロイ状態を記述する「宣言型」
 コンテナ群が最終的にこういう状態で実行していてほしいという情報をマニュフェストファイルと呼ばれる設定ファイルに記述し、それをKubernetesに適用することでコンテナ群を操作する仕組みをとっています。これによりKubernetesのユーザーは、コンテナ群をどのようにKubernetes上にデプロイするかの手順を気にせず、理想的な状態の定義に集中できます。

・高い拡張性
 Kubernetesは大規模なツールですが、構成要素はコンポーネントとして分割されておりそれぞれが拡張可能となっています。Kubernetesではコンポーネントをカスタマイズしたり機能を追加するためのプラグインやAPIなどが用意されており、自分でプラグインを作成したりオープンソースで公開されているものを利用したりすることができます。

Kubernetesの代表的なリソース

Kubernetesの実行環境をKubernetesクラスターと呼びます。Kubernetesクラスター内には「コントロールプレーン」と呼ばれるクラスター全体の管理を行うためのコンポーネントと、「ノード」と呼ばれるコンテナの実行を担当するコンポーネントがあります。

  • Kubernetesクラスターの概要図

以下はノードに対してアプリケーションをデプロイする際に使用する、代表的なリソースの例です。

・ポッド(Pod)
 KubernetesはPodと呼ばれるリソースをデプロイの最小単位として取り扱います。Podは1つまたは複数のコンテナとストレージやネットワーク等の共有リソースをひとまとめにしたもので、Pod単位でノードにデプロイされます。

・デプロイ(Deployment)
 PodはPod単体でノードにデプロイすることができますが、通常はDeploymentと呼ばれるリソースを使ってデプロイを行います。Deploymentを使用することでKubernetesの特徴であるセルフヒーリングやオートスケーリングなどの機能がPodに対して適用されます。

・サービス(Service)
 Pod内で実行されているコンテナアプリケーションのサービスにアクセスするためのリソースがServiceです。Serviceを使用することでPodは他のPodやKubernetes外からアクセス可能になります。Serviceを使用することで、スケールアウトによって同じ機能を持つPodがKubernetesクラスター上に複数存在するような場合に、共通のIPアドレスからアクセスできるようになることからサービスディスカバリとしても機能します。

Azure Kubernetes Serviceとは

Azure Kubernetes Service(AKS)とはKubernetesクラスターをAzureのクラウド上で実行することのできるマネージドサービスです。Kubernetes導入におけるハードルとなっているKubernetesクラスターの構築や監視などをAzureに任せられるため、自前でKubernetes環境を構築する場合に比べて運用管理の手間を減らしてKubernetesを利用できるようになっています。
AKSではノードは仮想マシン(VM)として提供されるため、CPUやメモリ等のVMのリソースの選択肢が多くまた容易にスケールさせることができるようになっています。AKSではKubernetesのデプロイや管理にかかる料金は無料となっており、ノードとして実行しているVMとそれに関連するネットワークやストレージに対する従量課金制となっている点も特徴です。

Azure Kubernetes Serviceでコンテナ化アプリケーションを実行する

ここからは実際に、AKS上でアプリケーションを稼働させていきます。AKS上にデプロイするアプリケーションとして、前回実装したFlaskのWebアプリケーションおよびRedisを使用します。

コンテナの準備

まずはAKSが使用するWebアプリケーションのコンテナを作成します。前回実装した「app.py」の一部分を変更します。

アプリケーションコードの修正(app.py)

# Flaskのインポート
from flask import Flask
# Redisのインポート
from redis import Redis
import os

# Flaskの使用
app = Flask(__name__)

# Redisの初期化・・・①
redis_server = os.environ['REDIS_SERVER']
redis = Redis(host=redis_server, port=6379)

# 公開するAPIの定義
@app.route('/')
def hello():
    count = redis.incr('hits')
    return 'Hello AKS! {}回目のアクセスです。\n'.format(count)

# アプリケーションの起動(外部公開できる状態で起動)
if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

Redisの初期化処理で接続先となるRedisのホストアドレスの情報を、「REDIS_SERVER」という名前の環境変数から取得したものを参照するようにしています。この環境変数の値は、後ほど説明するマニュフェストファイルの中で設定していきます。また環境変数参照のためにosモジュールを使用するため、「import os」をファイル冒頭に追加しています。

次に実装したアプリケーションをコンテナイメージ化していきます。コンテナ化する際に必要な「Dockerfile」および「requirements.txt」は前回と同じ内容のものとなるため割愛します。コンテナイメージが作成されたら、ACRへイメージをプッシュします。

Webアプリケーションコンテナのイメージ化とACRへのプッシュ

$ docker login zerokara.azurecr.io

$ docker build -t zerokara-aks-webapp:latest .
$ docker tag zerokara-aks-webapp:latest zerokara.azurecr.io/zerokara-aks-webapp:latest
$ docker push zerokara.azurecr.io/zerokara-aks-webapp:latest

イメージをACRにプッシュすることができたら、AKSを作成していきます。

Kubernetesクラスターの作成

Azureポータル上からAKSのKubernetesクラスターを作成していきます。ポータル上部の検索窓で、「AKS」または「Kubernetes」と入力すると表示される「Kubernetes サービス」を選択します。作成したAKSの一覧画面が表示されるので、画面左上または画面下部にある「作成」ボタンを選択し、「Kubernetes クラスターの作成」を選択します。

  • Kubernetesクラスターの作成をはじめる

Kubernetesクラスターの作成画面に遷移するので、基本情報を入力していきます。

AKSクラスターの基本情報入力例

設定項目名 設定値
サブスクリプション 任意のものを入力
リソースグループ 任意のものを入力
クラスターのプリセット構成 Dev/Test ($)
Kubernetesクラスター名 任意のものを入力
地域 任意のものを入力
可用性ゾーン なし
Kubernetesバージョン 規定となっているバージョン(執筆時点では「1.22.11」)
APIサーバーの可用性 99.5%
ノードサイズ Standard B4ms
スケーリング方法 自動スケーリング
ノード数の範囲 1から2

今回はテスト用途でKubernetesクラスターを作成するため、開発やテスト向けに推奨されている構成で設定をするようにしています。基本情報をすべて入力・選択したら、画面上部にある「統合」タブを選択します。なお「ノードプール」、「アクセス」、「ネットワーク」タブの内容についてはデフォルトのままとします。

  • 作成するAKSクラスターの基本情報入力画面

「統合」タブではKubernetesクラスターを他のAzureリソースと連携させることができます。「Azure Container Registry」の項目にある「コンテナーレジストリ」から、Webアプリケーション用のコンテナイメージをプッシュしたコンテナーレジストリを選択します。他の項目はそのままとし、画面下部の「確認および作成」ボタンを選択します。

  • ACRのコンテナーレジストリの選択

作成するKubernetesクラスターの設定内容のプレビューが表示されるので、内容を確認して画面下部の「作成」ボタンを押下します。

  • Kubernetesクラスター作成の確認

しばらく待つとKubernetesクラスターの作成が完了します。

マニュフェストの作成

Kubernetesクラスターの作成が完了したら、マニュフェストファイルを使ってアプリケーションをAKS上にデプロイしていきます。Azureポータルで先程作成したKubernetesクラスターの画面を表示し、画面上部の「作成」ボタンから「YAMLで作成」を選択します。

  • YAMLを使ったアプリケーションのデプロイ

YAMLのエディターが表示されるので、以下のYAML形式のマニュフェストをエディターに入力して画面下部の「追加」ボタンを選択します。

デプロイするアプリケーションのマニュフェストファイル

# Redis用のデプロイ定義・・・①
apiVersion: apps/v1
kind: Deployment # マニュフェストの種類を指定する・・・①-1
metadata:
  name: zerokara-aks-db
spec:
  replicas: 1 # Podのレプリカ数を指定する・・・①-2
  selector:
    matchLabels:
      app: zerokara-aks-db # 他のリソースが参照するためのラベルを定義する・・・①-3
  template:
    metadata:
      labels:
        app: zerokara-aks-db
    spec:
      nodeSelector:
        "kubernetes.io/os": linux
      containers: # Podで実行するコンテナの情報を記述する・・・①-4
        - name: zerokara-aks-db
          image: mcr.microsoft.com/oss/bitnami/redis:6.0.8
          env:
          - name: ALLOW_EMPTY_PASSWORD
            value: "yes"
          ports:
          - containerPort: 6379
            name: redis
---
# Redis用のサービス定義・・・②
apiVersion: v1
kind: Service # サービスとしてマニュフェストを定義する・・・②-1
metadata:
  name: zerokara-aks-db
spec:
  ports:
  - port: 6379 # 外部に公開するポート番号の指定・・・②-2
  selector:
    app: zerokara-aks-db # サービスに紐付けるPodを参照する・・・②-3
---
# Webアプリケーション用のデプロイ定義・・・③
apiVersion: apps/v1
kind: Deployment
metadata:
  name: zerokara-aks-web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: zerokara-aks-web
  template:
    metadata:
      labels:
        app: zerokara-aks-web
    spec:
      nodeSelector:
        "kubernetes.io/os": linux
      containers:
        - name: zerokara-aks-web
          image: zerokara.azurecr.io/zerokara-aks-webapp:latest # 自身で作成したコンテナイメージを参照・・・③-1
          ports:
            - containerPort: 5000
          env:
            - name: REDIS_SERVER # DBとして使用するRedisのサービス名を環境変数として設定・・・③-2
              value: zerokara-aks-db
---
# Webアプリケーション用のサービス定義・・・④
apiVersion: v1
kind: Service
metadata:
  name: zerokara-aks-web
spec:
  type: LoadBalancer # Kubernetes外からアクセスできるようにLoadBalancerタイプのサービスとする・・・④−1
  ports:
  - port: 80 # 外部に公開するポート番号の指定・・・④-2
    targetPort: 5000 # アクセス先のPodが公開しているポート番号の指定・・・④-3
  selector:
    app: zerokara-aks-web

マニュフェストファイルが正しく追加できると4つのリソース(2つのDeploymentと2つのService)が作成されます。そのためマニュフェストファイルを確認すると、ハイフン(---)で区切られた4つのリソース定義から構成されていることが分かります。ここではマニュフェストファイルの項目について、ポイントとなる部分に絞って説明します。

・データベース(Redis)用のデプロイ定義(①のブロック)
 データベースとして使用するRedisのデプロイ方法について定義したものが①のブロックです。「kind」を「Deployment」とすることで、Podのデプロイ方法についての定義が記述できます(①-1)。「spec」のセクション内に詳細な情報を記述していきます。「spec.replicas」ではPodのレプリカ数を指定できます(①-2)。「spec.selector」ではこのデプロイ定義によって作成されたリソースを他のリソースが参照する際に使用するラベルを設定することができます(①-3)。これは後述するサービスの定義などで使用します。「spec.template」のセクション内ではPodとして実行するコンテナアプリケーションについて指定していきます。「spec.template.spec.containers」のセクション内で実際に使用するRedisのコンテナイメージの参照元となるコンテナレジストリのタグ名やポート番号などについて記述します(①-4)。

・データベース(Redis)用のサービス定義(②のブロック)
 ①のブロックでRedisのデプロイ方法について記述したので、そのRedisを他のリソースからアクセスできるようにするためにサービスの定義をセットで行います。サービスの場合は、「kind」を「Service」とします(②-1)。「spec.ports」でこのサービスが公開するポート番号を指定します(②-2)。このポート番号は、①-4で設定したRedisコンテナのポート番号と合わせます。「spec.selector」でこのサービスを経由してアクセスするリソースを決定します(②-3)。ここには先程①-3で設定したラベル名を指定します。

・Webアプリケーション用の定義(③と④のブロック)
 Webアプリケーション用の定義もデータベース用の定義と同様に、「Deployment」と「Service」のセットでマニュフェストを作成します。デプロイ定義では、自身が作成したFlaskのWebアプリケーションをデプロイしたいため、コンテナイメージをプッシュしたACRのタグ名を指定します(③-1)。またコンテナに対して環境変数を設定するようにしています(③-2)。これにはWebアプリケーションのコンテナがデータベースとして使うRedisコンテナの接続先ホスト名を設定します。Kubernetesの場合、サービス名をホスト名とするため②で定義したサービスの名称を環境変数の値として使用します。
 Webアプリケーション用のサービスの定義では、WebブラウザなどKubernetes外からのアクセスを受け付けるために「spec.type」で「LoadBalancer」と指定します(④−1)。LoadBalancer型でサービスを作成すると、AKSがAzure Load Balancerを使ったロードバランサー機能を提供するように内部的に構成されます。これによってサービスにはパブリックIPが割り当てられるようになります。「spec.ports」では2種類のポート番号を定義しています。「spec.ports.port」の方はこのサービスが公開するポート番号の指定(④-2)で、「spec.ports.targetPort」の方はサービスからPodにアクセスする際のPod側のポート番号を指定します(④-3)。この設定により、Webブラウザからアクセスする際はポート80番でアクセスできるためURLでポート番号を明示する必要なくWebアプリケーションにアクセスできるようになります。

デプロイしたアプリケーションの動作確認

マニュフェストファイルの追加によって、定義に従ってAKSのKubernetesクラスター上にアプリケーションがデプロイされているか確認します。Webアプリケーション用のサービスに対してパブリックIPアドレスを割り振るようにしているので、IPアドレスを確認します。
Azureポータルで作成したKubernetesクラスターを表示し、左側のメニューから「サービスとイングレス」を選択します。サービスの一覧の中から「zerokara-aks-web」という名前のサービスを探し、「外部IP」の列に表示されているIPアドレスを選択します。

  • AKS上で実行されているWebアプリケーションの動作確認

Webブラウザで選択したIPアドレスのサイトが表示され、Flaskで実装した内容が表示されることが確認できます。画面をリロードすることでアクセスカウンターも機能していることが確認でき、Redisでのデータ管理も行われていることが分かります。

Kubernetesクラスターの削除

AKSではKubernetesクラスターの実行中はノードとして稼働している仮想マシンに対して課金が行われています。今回のように開発やテスト用途の場合は使用しない時間帯はクラスターを停止するか、削除することで意図しない課金が発生しないように注意して下さい。クラスターの停止および削除は、Azureポータル上で作成したKubernetesクラスターの画面上部から行うことができます。

まとめ

Kubernetesは構成要素が多く他のコンテナ化アプリケーションの実行基盤に比べて学習コストが高いツールですが、Azure Kubernetes Serviceを使用することでKubernetesの構築や運用の手間を削減でき、マニュフェストファイルの作成などアプリケーションの実行に必要な作業に集中することができることが分かったかと思います。