ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

Azure Container Service の Kubernetes に ASP.NET Core アプリケーションをデプロイする

前回の記事では、Azure Container Service に Kubernetes を展開し、nginx をデプロイしました。
gooner.hateblo.jp
今回は、ASP.NET Core アプリケーションをデプロイして、スケールアウトやアプリケーションの更新を試してみます。

ASP.NET Core アプリケーションを作る

先月アップデートされた dotnet コマンドを使って、ASP.NET Core MVC のテンプレートでアプリケーションを作ります。

$ dotnet new mvc -o mvcapp
$ cd mvcapp
$ dotnet restore
$ dotnet build
$ code .

Docker イメージを作りたいので、テンプレートを少し修正します。
まずは、Visual Studio Code を開いて、Dockerfile を追加します。

FROM microsoft/dotnet:1.1.1-sdk
COPY . /app
WORKDIR /app

RUN ["dotnet", "restore"]
RUN ["dotnet", "build"]

EXPOSE 5000/tcp
ENV ASPNETCORE_URLS http://*:5000

ENTRYPOINT ["dotnet","run"]

次に、Dockerfile で環境変数に指定したURL(ポート番号)をアプリケーションの起動時に設定します。
Program.cs を開いて、環境変数から取得した値を UseUrls() メソッドで設定します。

public class Program
{
    public static void Main(string[] args)
    {
        // 環境変数からURLを取得する
        var config = new ConfigurationBuilder()
            .AddEnvironmentVariables("")
            .Build();
        var url = config["ASPNETCORE_URLS"] ?? "http://*:5000";
        
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseUrls(url)           // URLを設定する
            .Build();

        host.Run();
    }
}

Docker イメージをビルドします。

$ docker build -t thara0402/mvcapp:v1 ./

ビルドした Docker イメージを Docker Hub にプッシュします。

$ docker login
Username: thara0402
Password: 
Login Succeeded
$ docker push thara0402/mvcapp:v1

f:id:TonyTonyKun:20170320110613p:plain

ASP.NET Core アプリケーションをデプロイする

Azure Container Service に SSH 接続します。

$ ssh thara@gooner0318mgmt.eastus.cloudapp.azure.com -A

先ほどプッシュした Docker Hub のイメージを使って、Kubernetes に ASP.NET Core アプリケーションをデプロイします。Pod が作成されるので、外部から接続できるように Service で 5000 ポートを公開します。

$ kubectl run mvcapp --image thara0402/mvcapp:v1
deployment "mvcapp" created

$ kubectl get pods
NAME                      READY     STATUS    RESTARTS   AGE
mvcapp-3237912479-6b159   1/1       Running   0          1m

$ kubectl expose deployments mvcapp --port=5000 --type=LoadBalancer
service "mvcapp" exposed

$ kubectl get svc
NAME         CLUSTER-IP   EXTERNAL-IP    PORT(S)          AGE
kubernetes   10.0.0.1     <none>         443/TCP          1h
mvcapp       10.0.47.43   52.168.28.12   5000:32648/TCP   2m

ブラウザで 52.168.28.12:5000 に接続すると、ASP.NET Core MVC のテンプレートが表示されます。

f:id:TonyTonyKun:20170320110631p:plain

ASP.NET Core アプリケーションをスケールアウトする

デプロイした ASP.NET Core アプリケーションをスケールアウトしてみます。

$ kubectl scale deployment mvcapp --replicas=3
deployment "mvcapp" scaled

$ kubectl get deployment
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
mvcapp    3         3         3            3           12m

$ kubectl get pods
NAME                      READY     STATUS    RESTARTS   AGE
mvcapp-3237912479-1mrkl   1/1       Running   0          13s
mvcapp-3237912479-5k3bq   1/1       Running   0          13s
mvcapp-3237912479-6b159   1/1       Running   0          12m

Pod が2つ追加されて、3つにスケールアウトされました。Service がロードバランサーとなり、リクエストを割り振ってくれます。数秒でイメージを複製できるのはコンテナの便利なところです。

ASP.NET Core アプリケーションを更新する

ローカルで ASP.NET Core アプリケーションを更新して、Docker イメージをビルドします。タグは、V2 に変更しています。ビルドした Docker イメージを Docker Hub にプッシュします。

$ docker build -t thara0402/mvcapp:v2 ./
$ docker push thara0402/mvcapp:v2

f:id:TonyTonyKun:20170320110654p:plain

Azure Container Service に SSH 接続して、Pod にデプロイされている Docker イメージを更新します。

$ kubectl set image deployments/mvcapp mvcapp=thara0402/mvcapp:v2

$ kubectl get pods
NAME                      READY     STATUS    RESTARTS   AGE
mvcapp-3312820128-400cp   1/1       Running   0          30s
mvcapp-3312820128-8wz2f   1/1       Running   0          30s
mvcapp-3312820128-tgvll   1/1       Running   0          30s

Pod の名前が変わっていることから、自動的に古い Pod が破棄され、新しい Docker イメージを使った Pod が作成されたことが分かります。
ブラウザで 52.168.28.12:5000 に接続すると、「mvcapp v2」に変更された ASP.NET Core MVC のアプリケーションが表示されます。

f:id:TonyTonyKun:20170320110712p:plain

ASP.NET Core アプリケーションを削除する

最後に、デプロイした ASP.NET Core アプリケーションを削除します。

$ kubectl delete service,deployment mvcapp
service "mvcapp" deleted
deployment "mvcapp" deleted

まとめ

今回は、Kubernetes に ASP.NET Core アプリケーションをデプロイして、スケールアウトやアプリケーションの更新を試してみました。

f:id:TonyTonyKun:20170321003533p:plain

ASP.NET Core アプリケーションの Docker イメージを Docker Hub 経由で、Pod にコンテナをデプロイしました。宣言的なコマンドを実行するだけで、簡単に Pod のレプリケーションを作成し、スケールアウトを構成できます。
ASP.NET Core アプリケーションの更新は、新しい Docker イメージを設定することで、自動的に古い Pod が破棄され、新しい Pod が作成されます。Pod を1つずつ更新したり、スワップする必要もありません。
次回以降は、もう少し実践的な内容を試してみたいと思います。
gooner.hateblo.jp

Azure Container Service で Kubernetes を試してみた

先週、Azure Container Service の Kubernetes 対応が GA したので、試してみました。
azure.microsoft.com

Azure Container Service は、Docker コンテナ上で動かすアプリケーションをホストできるサービスです。コンテナ オーケストレーションである Docker Swarm、DC/OS、Kubernetes を選択でき、コンテナ環境を簡単に構築できます。Azure の仮想マシンや仮想ネットワークなどのインフラストラクチャーの上に、オープンソースのコンテナ オーケストレーションが展開されます。
Kubernetes は、Google が公開しているオープンソースのコンテナ オーケストレーションの1つです。Docker だけでもコンテナーの作成してイメージを展開できますが、複数のコンテナを管理するにはオーケストレーションがあると便利です。

事前準備

Kubernetes を選択した場合のみ、 Azure Active Directory のサービス プリンシパルが必要となります。サービス プリンシパルの作成方法にはいくつかありますが、今回は Docker コンテナで Azure CLI 2.0 を使います。Docker for Mac や Docker for Windows をインストールした環境で、次のコマンドを実行します。

$ docker run -it azuresdk/azure-cli-python:latest bash

Azure にログインします。

$ az login
To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code GZGP8E89A to authenticate.

メッセージに表示されているURLにブラウザでアクセスしてコードを入力し、Azure アカウントでログインします。

次のコマンドの "mySubscriptionID" に Azure のサブスクリプションIDをセットして実行すると、サービス プリンシパルを作成できます。

$ az account set --subscription "mySubscriptionID"
$ az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/mySubscriptionID"
{
  "appId": "e8bbb9a0-xxxx-xxxx-xxxx-8eb054fc5ef2",
  "displayName": "azure-cli-2017-02-26-15-18-01",
  "name": "http://azure-cli-2017-02-26-15-18-01",
  "password": "378022a9-xxxx-xxxx-xxxx-127bb49cb1eb",
  "tenant": "2f2404eb-xxxx-xxxx-xxxx-6454b99e51a5"
}

"appId" と "password" を使いますので、メモしておきます。"password" は、このタイミングでしか取得できません。

Azure Container Service を作成する

Azure ポータルから、New - Compute - Azure Container Service を選択します。Orchestrator で Kubernetes を選択し、リソースグループやロケーションを指定します。

f:id:TonyTonyKun:20170227025056p:plain

DNS Name prefix には任意の名前を指定し、SSH で接続するユーザー名と公開キーを入力します。サービス プリンシパルの "clinet ID" には "appId"、"client secret" には "password" を入力します。

f:id:TonyTonyKun:20170227030435p:plain

Agent の数や仮想マシンのサイズは、初期値のまま進めます。Operating System では、プレビューで対応している Windows Server Container を選択することも可能ですが、今回は Linux を選択します。

f:id:TonyTonyKun:20170227030257p:plain

最後に、ここまでの設定内容を確認して、作成を開始します。

f:id:TonyTonyKun:20170227030500p:plain

数分待つと作成が完了し、リソースグループ内に作成された一覧が表示されます。仮想マシンや仮想ネットワークを利用して、Azure Container Service のクラスターが構築されたことを確認できます。

f:id:TonyTonyKun:20170227033410p:plain

Deployments の "2 Succeeded" のリンクをクリックすると、デプロイされた構成情報を確認できます。SSH 接続するための情報は、SSHMASTER0 から取得できます。

f:id:TonyTonyKun:20170227033433p:plain

Azure Container Service に接続する

Azure Container Service に SSH 接続します。

$ ssh thara@gooer0227mgmt.eastus.cloudapp.azure.com -A

Kubernetes のコマンド ライン クライアントである kubectl を使って、構成を確認してみます。
バージョンを確認すると、Ver.1.5 がデプロイされていることがわかります。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.3", GitCommit:"029c3a408176b55c30846f0faedf56aae5992e9b", GitTreeState:"clean", BuildDate:"2017-02-15T06:40:50Z", GoVersion:"go1.7.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.3", GitCommit:"029c3a408176b55c30846f0faedf56aae5992e9b", GitTreeState:"clean", BuildDate:"2017-02-15T06:34:56Z", GoVersion:"go1.7.4", Compiler:"gc", Platform:"linux/amd64"}

次に、ノードを確認すると、マスターとエージェントの2つの仮想マシンが構成されていることがわかります。

$ kubectl get nodes
NAME                    STATUS                     AGE
k8s-agent-d8d36729-0    Ready                      38m
k8s-master-d8d36729-0   Ready,SchedulingDisabled   38m

nginx をデプロイする

コンテナ上で動かすアプリケーションを手っ取り早く確認したいので nginx をデプロイしてみます。

$ kubectl run nginx --image nginx
deployment "nginx" created

nginx の Docker コンテナが Pod で起動していることを確認します。Pod は、複数のコンテナをまとめて管理できます。Pod 内のコンテナは同じホストにデプロイされるため、複数のコンテナでストレージなどを共有できます。現在の環境は、1つの Pod に1つの nginx コンテナが実行されています。

$ kubectl get pods
NAME                    READY     STATUS    RESTARTS   AGE
nginx-701339712-l7804   1/1       Running   0          3m

nginx の Docker コンテナを外部に80番ポートで公開します。Pod にはプライベートな IP アドレスが割り当てられているので、Service として外部に公開する必要があります。Service には、ロードバランサー的な役割もあります。

$ kubectl expose deployments nginx --port=80 --type=LoadBalancer
service "nginx" exposed

Azure のロードバランサーにルールを追加したりしてるので、設定が反映するまでに少し時間がかかります。

$ kubectl get svc
NAME         CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   10.0.0.1       <none>        443/TCP        1h
nginx        10.0.211.143   <pending>     80:30445/TCP   42s

少し待つと、パブリックIPアドレスが割り当てられます。

$ kubectl get svc
NAME         CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   10.0.0.1       <none>        443/TCP        1h
nginx        10.0.211.143   13.92.95.76   80:30445/TCP   8m

ブラウザでパブリックIPアドレスにアクセスすると、nginx の画面が表示されます。

f:id:TonyTonyKun:20170227031516p:plain

まとめ

Azure Container Service の Kubernetes について、今回の内容を整理します。

f:id:TonyTonyKun:20170321001631p:plain

kubernetes には、複数のコンテナをまとめて管理する Pod があり、外部公開するためのロードバランサーの役割を Service が担います。kubectl コマンドを使うことで、kubernetes を操作できます。
Azure Container Service は、Azure の仮想マシンや仮想ネットワークなどをテンプレート化した環境に kubernetes を配置してくれるので、インフラの構築など面倒なことを考えずに、すぐに kubernetes を使い始めることができます。
今回は初歩的な内容を紹介しましたが、次回以降はもう少し詳しく見ていきたいと思います。
gooner.hateblo.jp

Microsoft MVP for Microsoft Azure を初受賞しました

2017年1月1日付けで、Microsoft Most Valuable Professional (MVP) アワードを初受賞しました。受賞カテゴリは、Microsoft Azure です。

f:id:TonyTonyKun:20170113003210j:plain

日頃お世話になっている皆さまのお陰です。ありがとうございます。
新しい出会いや経験を楽しみながら、技術やアーキテクチャの啓蒙を通じて、社会貢献できるように活動していきたいと思います。