/decode2019-k8s-handson

The Kubernetes hands-on procedure and samples of session CD65 and CD71 in de:code 2019

Primary LanguageShell

Kubernetes ハンズオン手順書

Kubernetes とはどのようなものかステップバイステップで実際に手を動かしながら見ていきます。
このハンズオンでは Kubernetes の最小単位である Pod から見ていき、最終的に Deployment と LoadBalancer Service を使ったアプリケーションのデプロイを体験します。
また、Kubernetes クラスター上のノードを起動している間お金がかかり続けますので、最後の「後片付け」のステップは必ず実行してください。

ハンズオンを進めるための準備

  • ブラウザから手順書(このリポジトリ)を開く
    https://git.io/fjCRU
  • Azure ポータルを開く
    https://portal.azure.com/
  • Azure Cloud Shell を開く(Bash を選択)
  • Azure Cloud Shell でサンプルリポジトリをクローンする
git clone https://github.com/softoika/decode2019-k8s-handson

サンプルリポジトリへ移動

cd decode2019-k8s-handson

リソースグループを作成する

az group create --name decode2019-cd65-71 --location japaneast

リソースグループ上に Kubernetes クラスターを作成する

az aks create --resource-group decode2019-cd65-71 --name k8s-handson --node-count 1 --generate-ssh-keys

作成にはしばらく時間がかかる。以下のコマンドでステータスがSucceededになるまで待つ (Ctrl+C で終了)

watch "az aks show -g decode2019-cd65-71 -n k8s-handson | grep provisioningState"

Kubernetes クラスターに接続するための認証情報を取得する

az aks get-credentials --name k8s-handson --resource-group decode2019-cd65-71

Pod を作成してみる

スクリーンショット 2019-05-30 10 44 54

Pod は Kubernetes における最小単位の環境です。
Pod は 1 つ以上のコンテナを動かす環境で、複数のコンテナを動かす場合同じ Pod 内であれば コンテナは localhost で互いに通信することができます。
Pod のマニフェストファイルの単純な例は以下の通りです。

pod-example.yaml
# /api/v1/namespaces/{namespace}/pods にリクエストを投げる
apiVersion: v1
kind: Pod
metadata:
  name: pod-example
spec:
  containers:
    - name: hello-app-container
      # コンテナイメージを指定
      image: rhanafusa/hello-app:1.0

マニフェストファイルの適用はkubectl applyコマンドを使います。

kubectl apply -f pod-example.yaml

また、kubectl getコマンドで Pod の起動状態を確認できます。

kubectl get pods

kubectl_get_pods

STATUS が Running になったら起動成功

(おまけ) その他よく使うコマンド

# yamlに何を記述できるかコマンドで確認する
kubectl explain pod
kubectl explain pod.spec
kubectl explain pod.spec.containers.ports
# podの詳細や起動履歴を確認する
kubectl describe pods
# アプリケーションのログを確認する
kubectl logs pod-example
# podの中に入る(pod内で有効なコマンドを実行する)
kubectl exec -it pod-example -- bash
kubectl exec -it pod-example -- uname -a

その他コマンドの詳細を知りたければkubectl -hまたはkubectl サブコマンド -hでみれます。
また、公式でコマンドのリファレンスが公開されています。

ReplicaSet を作成してみる

スクリーンショット 2019-05-30 10 45 03

ReplicaSet はその名の通り、Pod のレプリケーションを組んで可用性を高めることができます。
以下は 3 つのレプリカで構成された ReplicaSet の例です。

replicaset-example.yaml
# /apis/apps/v1/namespaces/{namespace}/replicasets にリクエストを投げる
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replicaset-example
spec:
  replicas: 3
  selector:
    # labelの検索条件
    matchLabels:
      app: hello-app
  template:
    # template以下がPodとほとんど同じ
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
        - name: hello-app-container
          image: rhanafusa/hello-app:1.0

適用

kubectl apply -f replicaset-example.yaml

レプリカ数3台でReplicaSetが起動されていることを確認

kubectl get replicaset -o wide

スクリーンショット 2019-05-13 18 59 49

Pod それぞれがハッシュ付きの名前で異なる IP アドレスで起動されている

kubectl get pods -o wide

kubectl_get_pods_-o_wide

ReplicaSet のセルフヒーリングを試してみる

ReplicaSet を組んでいれば Pod に障害が起きて停止しても、すぐに Pod が再作成されていることがわかる。
以下のシェルスクリプトを実行すると、Pod の削除前と削除後で Pod の数が変わっていないことがわかる。

./self-healing-demo.sh

self-healing-demo sh

Deployment を作成してみる

スクリーンショット 2019-05-30 10 45 13

Deployment は ReplicaSet をスケーラブルに扱うためのリソース。

simple-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: simple-deployment
spec:
  replicas: 3
  selector:
  matchLabels:
    app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
        - name: hello-app-container
          image: rhanafusa/hello-app:1.0

Deployment はアプリケーションを更新するときに、後述のローリングアップデートやオートスケーリングなどのデプロイに関する設定を記述することができる。
よって、基本的には Pod や ReplicaSet は Deployment を通して定義すればよいです(Deployment のマニフェストファイルだけ作れば OK)。

Deployment のローリングアップデートを試してみる

Deployment では基本的にローリングアップデートでアプリケーションが順次更新されるため、ダウンタイムなしにアプリケーションを更新することができます。 ローリングアップデートのデモ用マニフェストは以下の通りです。

rolling-update-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rolling-update-deployment
spec:
  ## ローリングアップデートの設定 ##
  # 新規作成されたPodがReadyになってから起動成功と判断するまでの猶予時間
  minReadySeconds: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      # 1台ずつ更新していく
      maxSurge: 1
      maxUnavailable: 0
  ##############################
  replicas: 3
  selector:
  matchLabels:
    app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
        - name: hello-app-container
          image: rhanafusa/hello-app:1.0

それではローリングアップデートを体験してみましょう。
以下のシェルスクリプトを実行してローリングアップデートされていく様子を確認することができます。

./rolling-update-demo.sh

Ctrl + Cでスクリプトを終了できます。
シェルスクリプトの内容を一部抜粋すると以下のようになっています。

# Deploymentを作成
kubectl apply -f rolling-update-deployment.yaml
# コンテナイメージを変更
kubectl set image deployment rolling-update-deployment hello-app-container=rhanafusa/hello-app:1.1

# 新しいReplicaSetが作成されて順次Podが更新されていることを確認
watch kubectl get replicaset

Pod のオートスケーリングを有効にしてみる

レプリカの数は手動で変更することもできますが、以下のようにマニフェストを設定することで Pod の負荷状況に応じて自動でスケールアウトすることができます。

autoscale-example.yaml
## HorizontalAutoscalerの設定
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: autoscale-example
spec:
  # レプリカ数の下限
  minReplicas: 2
  # レプリカ数の上限
  maxReplicas: 5
  # PodのCPUが70%になるように調節する
  targetCPUUtilizationPercentage: 70
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: autoscalable-deployment
---
## 対象のDeploymentの設定
apiVersion: apps/v1
kind: Deployment
metadata:
  name: autoscalable-deployment
spec:
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
        - name: hello-app-container
          image: rhanafusa/hello-app:1.0

Service を作成してみる

スクリーンショット 2019-05-30 10 45 30

Kubernetes 上のアプリケーションを外部に公開するには Service (もしくは Ingress) というリソースを使います。
以下は負荷分散のためのシンプルなロードバランサーの Service の例です。

service-example.yaml
## シンプルなServiceの定義
apiVersion: v1
kind: Service
metadata:
  name: service-example
spec:
  type: LoadBalancer
  ports:
    - protocol: "TCP"
      # 8080番ポートに受けて各Podの8080番ポートに転送する
      port: 8080
      targetPort: 8080
  selector:
    # Deploymentと同じラベルをつける
    app: hello-app
---
## Serviceに対応したDeploymentを定義
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-example-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
        - name: hello-app-container
          image: rhanafusa/hello-app:1.0
          # コンテナのポートを指定
          ports:
            - containerPort: 8080

適用

kubectl apply -f service-example.yaml

Service の EXTERNAL-IP がから特定の IP アドレスになるまで待ちます(Ctrl + Cで終了)

kubectl get services --watch

kubectl_get_services_--watch

EXTERNAL-IP が実 IP になったら、ブラウザでアクセスしてみましょう。(http://<EXTERNAL-IP>:8080/greetingでアクセスできます。)

後片付け

従量課金の場合、ノードが起動している間はお金がかかり続けます。
以下のコマンドを実行して(もしくは Azure Portal の画面上から)、このハンズオンのリソースグループごと消してしまいましょう。

az group delete --name decode2019-cd65-71 --yes --no-wait

今回 Azure Cloud Shell を初めて使った場合 Cloud Shell 用のストレージとリソースグループも作成されています。
僅かではありますが、起動している間お金がかかります。
こちらも普段使っていないのであれば削除しておきましょう。

az group delete --name cloud-shell-storage-southeastasia --yes --no-wait