ROMANCE DAWN for the new world

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

Azure Container Service (AKS) を試してみた

先週、Azure のマネージドな Kubernetes サービスとして Azure Container Service (AKS) のプレビューがリリースされたので、試してみました。
azure.microsoft.com

Azure Container Service (AKS) を作成する

Azure Container Service (AKS) Documentation - Tutorials, API Reference | Microsoft Docs

公式ドキュメントにも記載されているように、Azure Portal の Cloud Shell を使うと、サクッと試すことができます。
ただ、実際の開発作業で使うことを考えると、ローカルの開発マシンで AKS を操作したいので、Azure CLI の Docker Image を使って試してみます。

Cloud Shell には、Kubectl (Kubernetes のクライアントツール) と Helm (Kubernetes のパッケージマネージャー)がインストール済みですが、 Azure CLI の Docker Image には含まれていません。
そのため、Kubectl と Helm がインストール済みの Dockerfile を書いてみました。

FROM azuresdk/azure-cli-python:2.0.20

# Install kubectl
RUN wget -O /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.8.2/bin/linux/amd64/kubectl \
 && chmod +x /usr/local/bin/kubectl

# Install Helm
RUN wget https://storage.googleapis.com/kubernetes-helm/helm-v2.7.0-linux-amd64.tar.gz \
 && tar -zxvf helm-v2.7.0-linux-amd64.tar.gz \
 && mv linux-amd64/helm /usr/local/bin/helm \
 && rm -rf linux-amd64

ローカルの開発マシンでは、Kubectl と Helm の接続情報、SSH 接続キーをマウントして、この Docker Image を実行します。
develop ディレクトリは、Kubernetes にデプロイする YAML ファイルやカスタムの Helm Chats を想定して、マウントしてます。

$ docker run -it --rm -v ${HOME}/.kube/aks:/root/.kube -v ${HOME}/.helm/aks:/root/.helm -v ${HOME}/.ssh/aks:/root/.ssh -v ${HOME}/develop:/develop thara0402/azure-cli-k8s:latest

Azure CLI にログインします。

$ az login

まだプレビュー中なので、サブスクリプションごとにアクティブ化が必要です。

$ az provider register -n Microsoft.ContainerService

リソースグループを作成します。利用できるリージョンは限られており、まだ日本は使えません。

$ az group create --name aks --location westus2

AKS を作成します。

$ az aks create --resource-group aks --name myK8sCluster --node-count 1 --generate-ssh-keys

kubectl の接続情報をダウンロードします。

$ az aks get-credentials --resource-group=aks --name=myK8sCluster

Agent Node が1つ作成されました。Master Node は、Azure 側に管理を任せているので表示されません。

$ kubectl get nodes
NAME                        STATUS    ROLES     AGE       VERSION
aks-agentpool1-29980149-0   Ready     agent     2d        v1.7.7

Azure Portal で確認すると、2つのリソースグループが作成されています。どちらのリソースグループにも、Master Node の仮想マシンは表示されていません。

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

ASP.NET Core アプリケーションの Docker Image を使って、AKS にデプロイします。

$ kubectl run mvcapp --image thara0402/mvcapp:v1
$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
mvcapp-614172684-tddnb   1/1       Running   0          1m

$ kubectl expose deployments mvcapp --port=5000 --type=LoadBalancer
$ kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)          AGE
kubernetes   ClusterIP      10.0.0.1       <none>           443/TCP          2d
mvcapp       LoadBalancer   10.0.121.196   52.175.213.163   5000:31552/TCP   3m

ブラウザで 52.175.213.163:5000 に接続すると、ASP.NET Core MVC のテンプレートが表示されます。
f:id:TonyTonyKun:20171031035658p:plain
次に、Agent Node の数を3つに増やしてみます。

$ az aks scale --resource-group=aks --name=myK8SCluster --agent-count 3
$ kubectl get nodes
NAME                        STATUS     ROLES     AGE       VERSION
aks-agentpool1-29980149-0   Ready      agent     29m       v1.7.7
aks-agentpool1-29980149-1   Ready      agent     16m       v1.7.7
aks-agentpool1-29980149-2   Ready      agent     16m       v1.7.7

最後に、Kubernetes Cluster を ver.1.8.1 にバージョンアップしてみます。

$ az aks upgrade --name myK8sCluster --resource-group aks --kubernetes-version 1.8.1
$ kubectl get nodes
NAME                        STATUS     ROLES     AGE       VERSION
aks-agentpool1-29980149-0   Ready      agent     40m       v1.8.1
aks-agentpool1-29980149-1   Ready      agent     30m       v1.8.1
aks-agentpool1-29980149-2   Ready      agent     30m       v1.8.1

Helm を使ってデプロイする

Helm を使ってデプロイしようと試しましたが、エラーが発生してしまいました。

$ helm list
Error: forwarding ports: error upgrading connection: error dialing backend: dial tcp 10.240.0.4:10250: getsockopt: connection refused

調べてみると、Helm の FAQ に該当しそうな Workaround があったのですが、Master Node で作業する必要があり、試すことができませんでした。

helm/install_faq.md at master · kubernetes/helm · GitHub

これ以外にも、Kubernetes Dashboard が表示できなかったりするので、まだプレビューということもあり、もう少し様子をみたいと思います。

まとめ

これまでも Azure Container Service で Kubernetes を展開することはできましたが、どちらかと言うと仮想マシンのテンプレートでした。
ちょっとした動作確認に使う分にはいいですが、本番環境で運用するとなると、IaaS と同等の運用コストがかかります。
AKS は、Google Container Engine (GKE) のようなサービスで、Kubernetes の Master Node の管理を Azure 側に任せてしまい、Agent Node とデプロイするアプリケーションの管理に注力できます。
GA に向けて、クラウドらしい便利なサービスになることを期待したいです。

Azure Container Service の Kubernetes に Helm を使ってアプリケーションをデプロイする

Azure Container Service に Kubernetes を展開して、Helm を使ってアプリケーションをデプロイしてみます。

Helm とは

Kubernetes のパッケージマネージャーです。

docs.helm.sh

Kubernetes にデプロイする YAML ファイルをまとめたパッケージは、Charts と呼ばれます。Helm の公式リポジトリとして、KubeApps が提供されていて、WordPress や Jenkins など100以上のアプリケーションの Charts が公開されています。

Helm をインストールする

こちらのドキュメントに従ってインストールします。

docs.helm.sh

まず、Azure Portal から Azure Container Service を作成します。Kubernetes の Master Node に SSH で接続して、Helm のバイナリをダウンロードします。

$ curl -O https://storage.googleapis.com/kubernetes-helm/helm-v2.6.1-linux-amd64.tar.gz
$ tar -zxvf helm-v2.6.1-linux-amd64.tar.gz
$ sudo mv linux-amd64/helm /usr/local/bin/helm

次に、helm init コマンドを実行します。

$ helm init

これで、Helm のインストールが完了です。

Helm を使って WordPress をデプロイする

KubeApps で公開されている Charts を使って、WordPress をデプロイしてみます。
WordPress の Charts を指定して、helm install コマンドを実行します。

$ helm install --name my-wp stable/wordpress
NAME:   my-wp
LAST DEPLOYED: Sat Sep 23 17:43:09 2017
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/PersistentVolumeClaim
NAME             STATUS  VOLUME                                    CAPACITY  ACCESSMODES  STORAGECLASS  AGE
my-wp-wordpress  Bound   pvc-493f1d91-a03b-11e7-944e-000d3a72a60e  10Gi      RWO          default       13s
my-wp-mariadb    Bound   pvc-4942547b-a03b-11e7-944e-000d3a72a60e  8Gi       RWO          default       13s

==> v1/Service
NAME             CLUSTER-IP    EXTERNAL-IP  PORT(S)                     AGE
my-wp-mariadb    10.0.73.148   <none>       3306/TCP                    13s
my-wp-wordpress  10.0.193.167  <pending>    80:30912/TCP,443:30683/TCP  13s

==> v1beta1/Deployment
NAME             DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
my-wp-mariadb    1        1        1           0          13s
my-wp-wordpress  1        1        1           0          13s

==> v1/Secret
NAME             TYPE    DATA  AGE
my-wp-wordpress  Opaque  3     14s
my-wp-mariadb    Opaque  2     14s

==> v1/ConfigMap
NAME           DATA  AGE
my-wp-mariadb  1     14s

NOTES:
1. Get the WordPress URL:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w my-wp-wordpress'

  export SERVICE_IP=$(kubectl get svc --namespace default my-wp-wordpress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP/admin

2. Login with the following credentials to see your blog

  echo Username: user
  echo Password: $(kubectl get secret --namespace default my-wp-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)

WordPress と MariaDB がデプロイされたことが分かります。Kubernetes の5つのオブジェクトで構成されています。

  • PersistentVolumeClaim
  • Service
  • Deployment
  • Secret
  • ConfigMap

これらのオブジェクトを1つのパッケージとして、Helm Install コマンドだけでデプロイできました。Charts の内容は、GitHub で確認することができます。

github.com

数分待つと、デプロイが完了するので、サービスの EXTERNAL IP にブラウザからアクセスしてみます。

f:id:TonyTonyKun:20170930163933p:plain

削除するときは、Helm delete コマンドを使います。

$ helm delete my-wp --purge

Helm Charts を作ってみる

自分が作った ASP.NET Core のアプリケーションをデプロイする Charts を作ってみます。
helm create コマンドを実行すると、Charts のテンプレートが作成されます。

$ helm create mvcapp

f:id:TonyTonyKun:20170930164003p:plain

deployment.yaml と service.yaml を確認します。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    metadata:
      labels:
        app: {{ template "fullname" . }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: {{ .Values.service.internalPort }}
        livenessProbe:
          httpGet:
            path: /
            port: {{ .Values.service.internalPort }}
        readinessProbe:
          httpGet:
            path: /
            port: {{ .Values.service.internalPort }}
        resources:
{{ toYaml .Values.resources | indent 12 }}
apiVersion: v1
kind: Service
metadata:
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
spec:
  type: {{ .Values.service.type }}
  ports:
  - port: {{ .Values.service.externalPort }}
    targetPort: {{ .Values.service.internalPort }}
    protocol: TCP
    name: {{ .Values.service.name }}
  selector:
    app: {{ template "fullname" . }}

この yaml を見ると分かるように、Charts に対して外部からパラメータを指定できるようになっています。
values.yaml を編集して、ASP.NET Core のアプリケーションをデプロイできるようにします。

replicaCount: 1
image:
  repository: thara0402/mvcapp
  tag: v1
  pullPolicy: IfNotPresent
service:
  name: mvcapp-service
  type: LoadBalancer
  externalPort: 80
  internalPort: 5000
resources:

この Charts を指定して、helm install コマンドを実行します。

$ helm install --name my-mvc ./mvcapp
NAME:   my-mvc
LAST DEPLOYED: Sat Sep 23 17:43:18 2017
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME           CLUSTER-IP    EXTERNAL-IP  PORT(S)       AGE
my-mvc-mvcapp  10.0.124.120  <pending>    80:30617/TCP  4s

==> v1beta1/Deployment
NAME           DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
my-mvc-mvcapp  1        1        1           0          4s


NOTES:
1. Get the application URL by running these commands:
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get svc -w my-mvc-mvcapp'
  export SERVICE_IP=$(kubectl get svc --namespace default my-mvc-mvcapp -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP:80

ASP.NET Core アプリケーションがデプロイされたことを確認できます。

f:id:TonyTonyKun:20170930164049p:plain

まとめ

Kubernetes に Helm を使って、アプリケーションをデプロイしてみました。
使いたいアプリケーションが KubeApps にあればすぐにデプロイできますし、自分で Charts を作ることもできます。Kubernetes の Service や Deployment だけなく、アプリとデータベースをまとめることもできます。
Helm は、Kubernetes にデプロイするアプリケーションを管理できる便利なツールなので、積極的に活用していきたいです。

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