🐕

【MS Learn】Helm を使用したアプリケーションとパッケージの管理 と格闘した話

2023/10/06に公開

はじめに

やってみたシリーズです。

今日はこちら
https://learn.microsoft.com/ja-jp/training/modules/aks-app-package-management-using-helm/

Helmとは?
https://knowledge.sakura.ad.jp/23603/
https://qiita.com/sheepland/items/75b647b71c34c7d38804

ムズカシイネー😴

とりあえずやってみます。

手を動かすところだけ記述していきます。
番号とかは飛び飛びになりますので、ご本家様と照らし合わせてみていただけると幸いです。

Azure Cloud Shellのbashで実行しています。

ユニット3: 演習 - 環境を設定する

展開スクリプトを実行する

  1. AKSクラスターを作成します。
Azure Cloud Shell
$ SubscriptionId=$(az account list --query '[0].id' -o tsv)
. <(wget -q -O - https://raw.githubusercontent.com/MicrosoftDocs/mslearn-aks/main/infrastructure/setup/setup.sh ) -s $SubscriptionId -n learn-helm-deploy-aks --use-acr false --install-dot-net false

shellの中身。
https://raw.githubusercontent.com/MicrosoftDocs/mslearn-aks/main/infrastructure/setup/setup.sh

ちなみに途中でやめて再度実行するとちゃんと作業フォルダ消すかmvしてくださいって言ってくれる親切設計です。ステキ。

Azure Cloud Shell
$ SubscriptionId=$(az account list --query '[0].id' -o tsv)
. <(wget -q -O - https://raw.githubusercontent.com/MicrosoftDocs/mslearn-aks/main/infrastructure/setup/setup.sh ) -s $SubscriptionId -n learn-helm-deploy-aks --use-acr false --install-dot-net false
/home/user/clouddrive/mslearn-aks/ already exists!
 
Before running this script, please remove or rename the existing /home/user/clouddrive/mslearn-aks/ directory as follows:
Remove: rm -r /home/user/clouddrive/mslearn-aks/
Rename: mv /home/user/clouddrive/mslearn-aks/ ~/clouddrive/new-name-here/

実行結果

Azure Cloud Shell
WARNING!!! It appears you aren't currently running in a Microsoft Learn sandbox. Any Azure resources provisioned by this script will result in charges to your Azure subscription.
Using Azure resource group learn-helm-deploy-aks-rg.

Downloading code...
++ bash -s infrastructure/deploy/ modules/learn-helm-deploy-aks/src/
++ wget -q -O - https://raw.githubusercontent.com/MicrosoftDocs/mslearn-aks/main/infrastructure/setup/sparsecheckout.sh
Updating origin
remote: Enumerating objects: 308, done.
remote: Counting objects: 100% (174/174), done.
remote: Compressing objects: 100% (163/163), done.
remote: Total 308 (delta 71), reused 20 (delta 3), pack-reused 134
Receiving objects: 100% (308/308), 383.02 KiB | 29.00 KiB/s, done.
Resolving deltas: 100% (93/93), done.
From https://github.com/MicrosoftDocs/mslearn-aks
 * [new branch]      main        -> origin/main
 * [new branch]      oct-refresh -> origin/oct-refresh
 * [new branch]      test        -> origin/test

Switching to subscription xxxxxxxx-xxxxxxxxx-xxxx-xxxxxxxxxxxx...
Switching to subscription xxxxxxxx-xxxxxxxxx-xxxx-xxxxxxxxxxxx...
Creating resource group learn-helm-deploy-aks-rg in location westus2...
 > az group create -n learn-helm-deploy-aks-rg -l westus2 --output none

Creating AKS cluster "learn-helm-deploy-aks" in resource group "learn-helm-deploy-aks-rg" and location "westus2"...
 > az aks create -n learn-helm-deploy-aks -g learn-helm-deploy-aks-rg --node-count 1 --node-vm-size Standard_B2s --vm-set-type VirtualMachineScaleSets -l westus2 --enable-managed-identity --generate-ssh-keys -o json

AKS cluster created.

Getting credentials for AKS...
Merged "learn-helm-deploy-aks" as current context in /home/user/.kube/config

Installing NGINX ingress controller
E1006 01:22:44.196777    2006 memcache.go:287] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E1006 01:22:45.136243    2006 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
namespace/nginx-ingress created
serviceaccount/nginx-ingress created
clusterrole.rbac.authorization.k8s.io/nginx-ingress created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress created
secret/default-server-secret created
configmap/nginx-config created
ingressclass.networking.k8s.io/nginx created
deployment.apps/nginx-ingress created
E1006 01:22:51.141029    2011 memcache.go:287] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E1006 01:22:51.478649    2011 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
service/nginx-ingress created

Getting load balancer public IP
 > az aks list --query "[?name=='learn-helm-deploy-aks'&&resourceGroup=='learn-helm-deploy-aks-rg'].nodeResourceGroup" -o tsv
E1006 01:22:58.318688    2031 memcache.go:287] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E1006 01:22:58.645132    2031 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E1006 01:22:58.809831    2031 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
Waiting for the Load Balancer IP address - Ctrl+C to cancel...
E1006 01:23:05.000944    2038 memcache.go:287] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E1006 01:23:05.338476    2038 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
E1006 01:23:05.504096    2038 memcache.go:121] couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request
Assigned IP address: 40.64.88.82

Nginx ingress controller installed.
Azure Container Registry Information
==================================================================================
cat: /home/user/clouddrive/mslearn-aks/create-acr-exports.txt: No such file or directory
==================================================================================


Azure Container Kubernetes Cluster Information
==================================================================================
export CLUSTER_NAME=learn-helm-deploy-aks
export CLUSTER_SUBS=xxxxxxxx-xxxxxxxxx-xxxx-xxxxxxxxxxxx
export CLUSTER_RG=learn-helm-deploy-aks-rg
export CLUSTER_LOCATION=westus2
export CLUSTER_AKSNODERG=MC_learn-helm-deploy-aks-rg_learn-helm-deploy-aks_westus2
export CLUSTER_LBIP=40.64.88.82
export LEARN_REGISTRY=learn-aks-registry
==================================================================================

cat: /home/user/clouddrive/mslearn-aks/create-acr-exports.txt: No such file or directory

と出てますが、最初の実行コマンドで --use-acr false を渡しているので、作成されないで正解のようです。

couldn't get resource list for metrics.k8s.io/v1beta1: the server is currently unable to handle the request

これもいっぱい出てますが、後のタスクで支障はなかったので今回は無視します。(たぶん)

ユニット5: 演習 - Helm チャートをインストールする

Helm チャートをフェッチする

  1. Azure Marketplace の Helm リポジトリを追加します。
Azure Cloud Shell
$ helm repo add azure-marketplace https://marketplace.azurecr.io/helm/v1/repo
"azure-marketplace" has been added to your repositories
$ helm repo list
NAME                    URL                                        
azure-marketplace       https://marketplace.azurecr.io/helm/v1/repo

もともと追加されてるようです。

  1. azure-marketplace/aspnet-core チャートを検索します。
Azure Cloud Shell
$ helm search repo aspnet
NAME                            CHART VERSION   APP VERSION     DESCRIPTION                                       
azure-marketplace/aspnet-core   3.5.6           6.0.11          ASP.NET Core is an open-source framework for we...

Helm チャートをデプロイする

  1. ASP.NET Core の Helm チャートをデプロイします。
Azure Cloud Shell
$ helm install aspnet-webapp azure-marketplace/aspnet-core
NAME: aspnet-webapp
LAST DEPLOYED: Fri Oct  6 02:00:47 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: aspnet-core
CHART VERSION: 3.5.6
APP VERSION: 6.0.11

** Please be patient while the chart is being deployed **

ASP.NET Core can be accessed through the following DNS name from within your cluster:

    aspnet-webapp-aspnet-core.default.svc.cluster.local (port 80)

To access ASP.NET Core from outside the cluster execute the following commands:

1. Get the ASP.NET Core URL by running these commands:

    export SERVICE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].port}" services aspnet-webapp-aspnet-core)
    kubectl port-forward --namespace default svc/aspnet-webapp-aspnet-core ${SERVICE_PORT}:${SERVICE_PORT} &
    echo "http://127.0.0.1:${SERVICE_PORT}"

2. Access ASP.NET Core using the obtained URL.

この内容は templates/Notes.txt ファイル から生成されたもののようです。へえ

  1. すべての Helm リリースを一覧表示します。
Azure Cloud Shell
$ helm list
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
aspnet-webapp   default         1               2023-10-06 02:00:47.663873513 +0000 UTC deployed        aspnet-core-3.5.6       6.0.11

リビジョン番号は、リリースを変更するたびに増分されます。

  1. リリースのマニフェスト ファイルを取得します。
Azure Cloud Shell
$ helm get manifest aspnet-webapp
---
# Source: aspnet-core/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: aspnet-webapp-aspnet-core
  namespace: "default"
  labels:
    app.kubernetes.io/name: aspnet-core
    helm.sh/chart: aspnet-core-3.5.6
    app.kubernetes.io/instance: aspnet-webapp
    app.kubernetes.io/managed-by: Helm
  annotations:
---
# Source: aspnet-core/templates/svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: aspnet-webapp-aspnet-core
  namespace: "default"
  labels:
    app.kubernetes.io/name: aspnet-core
    helm.sh/chart: aspnet-core-3.5.6
    app.kubernetes.io/instance: aspnet-webapp
    app.kubernetes.io/managed-by: Helm
  annotations:
spec:
  type: ClusterIP
  sessionAffinity: None
  ports:
    - name: http
      port: 80
      targetPort: http
      nodePort: null
  selector:
    app.kubernetes.io/name: aspnet-core
    app.kubernetes.io/instance: aspnet-webapp
---
# Source: aspnet-core/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: aspnet-webapp-aspnet-core
  namespace: "default"
  labels:
    app.kubernetes.io/name: aspnet-core
    helm.sh/chart: aspnet-core-3.5.6
    app.kubernetes.io/instance: aspnet-webapp
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: aspnet-core
      app.kubernetes.io/instance: aspnet-webapp
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app.kubernetes.io/name: aspnet-core
        helm.sh/chart: aspnet-core-3.5.6
        app.kubernetes.io/instance: aspnet-webapp
        app.kubernetes.io/managed-by: Helm
    spec:
      
      automountServiceAccountToken: true
      serviceAccountName: aspnet-webapp-aspnet-core
      affinity:
        podAffinity:
          
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app.kubernetes.io/name: aspnet-core
                    app.kubernetes.io/instance: aspnet-webapp
                topologyKey: kubernetes.io/hostname
              weight: 1
        nodeAffinity:
          
      initContainers:
        - name: clone-repository
          image: marketplace.azurecr.io/bitnami/git:2.38.1-debian-11-r7
          imagePullPolicy: "IfNotPresent"
          command:
            - /bin/bash
            - -ec
            - |
              [[ -f "/opt/bitnami/scripts/git/entrypoint.sh" ]] && source "/opt/bitnami/scripts/git/entrypoint.sh"
              git clone https://github.com/dotnet/AspNetCore.Docs.git --branch main /repo
          volumeMounts:
            - name: repo
              mountPath: /repo
        - name: dotnet-publish
          image: marketplace.azurecr.io/bitnami/dotnet-sdk:6.0.402-debian-11-r9
          imagePullPolicy: "IfNotPresent"
          workingDir: /repo
          command:
            - /bin/bash
            - -ec
            - |
              cd aspnetcore/fundamentals/servers/kestrel/samples/6.x/KestrelSample
              dotnet publish -o /app 
          volumeMounts:
            - name: app
              mountPath: /app
            - name: repo
              mountPath: /repo
      containers:
        - name: aspnet-core
          image: marketplace.azurecr.io/bitnami/aspnet-core:6.0.11-debian-11-r0
          imagePullPolicy: "IfNotPresent"
          workingDir: /app
          command:
            - dotnet
            - KestrelSample.dll
          env:
            - name: ASPNETCORE_URLS
              value: "http://+:8080"
          ports:
            - name: http
              containerPort: 8080
          livenessProbe:
            tcpSocket:
              port: http
            initialDelaySeconds: 10
            periodSeconds: 20
            timeoutSeconds: 1
            successThreshold: 1
            failureThreshold: 6
          readinessProbe:
            tcpSocket:
              port: http
            initialDelaySeconds: 10
            periodSeconds: 20
            timeoutSeconds: 1
            successThreshold: 1
            failureThreshold: 6
          resources:
            limits: {}
            requests: {}
          volumeMounts:
            - name: app
              mountPath: /app
      volumes:
        - name: app
          emptyDir: {}
        - name: repo
          emptyDir: {}

最近ymlファイルでよく見るアレが出てきました。

チャートの templates フォルダーに 3 つの YAML ファイルがあることに注目してください。
・ServiceAccount
・サービス
・デプロイ

templateフォルダーとは?🤔
となったので、探してみます。

Azure Cloud Shell
$ find . -name "serviceaccount.yaml"
./modules/learn-helm-deploy-aks/src/drone-webapp-chart/templates/serviceaccount.yaml

drone-webapp-chart がチャートのルートフォルダですかね。
yamlの中身を見てみます。

Azure Cloud Shell
$ cat ./modules/learn-helm-deploy-aks/src/drone-webapp-chart/templates/serviceaccount.yaml
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ include "aspnet-core.serviceAccountName" . }}
  labels: {{- include "common.labels.standard" . | nindent 4 }}
    {{- if .Values.commonLabels }}
    {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }}
    {{- end }}
  annotations:
    {{- if .Values.serviceAccount.annotations }}
    {{- include "common.tplvalues.render" ( dict "value" .Values.serviceAccount.annotations "context" $) | nindent 4 }}
    {{- end }}
    {{- if .Values.commonAnnotations }}
    {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
    {{- end }}
{{- end }}

表示されたのとはちょっと違う感じのものが。

これらのファイルは、チャートで使用可能なテンプレートと values.yaml ファイルで使用できる値の組み合わせに基づいてレンダリングされます。

ということなので、表示されたものは変数やらテンプレートやらが解釈された結果なんですね。ふむ。

  1. ポッドがデプロイされていることを確認します。
Azure Cloud Shell
$ kubectl get pods -o wide -w
NAME                                         READY   STATUS    RESTARTS   AGE   IP            NODE                                NOMINATED NODE   READINESS GATES
aspnet-webapp-aspnet-core-67f579d785-lwm79   1/1     Running   0          22m   10.244.0.14   aks-nodepool1-34328761-vmss000000   <none>           <none>

表示出来たらCtrl+C で終了します。

Helm リリースを削除する

  1. Helm リリースを削除します。
Azure Cloud Shell
$ helm delete aspnet-webapp
release "aspnet-webapp" uninstalled

set の値を使用して Helm チャートをインストールする

  1. デプロイ テンプレートの replicaCount を 5 つのレプリカに設定します。
Azure Cloud Shell
$ helm install --set replicaCount=5 aspnet-webapp azure-marketplace/aspnet-core
NAME: aspnet-webapp
LAST DEPLOYED: Fri Oct  6 02:38:27 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: aspnet-core
CHART VERSION: 3.5.6
APP VERSION: 6.0.11

** Please be patient while the chart is being deployed **

ASP.NET Core can be accessed through the following DNS name from within your cluster:

    aspnet-webapp-aspnet-core.default.svc.cluster.local (port 80)

To access ASP.NET Core from outside the cluster execute the following commands:

1. Get the ASP.NET Core URL by running these commands:

    export SERVICE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].port}" services aspnet-webapp-aspnet-core)
    kubectl port-forward --namespace default svc/aspnet-webapp-aspnet-core ${SERVICE_PORT}:${SERVICE_PORT} &
    echo "http://127.0.0.1:${SERVICE_PORT}"

2. Access ASP.NET Core using the obtained URL.

5 つのポッド レプリカがデプロイされていることを確認します。

Azure Cloud Shell
$ kubectl get pods -o wide -w
NAME                                         READY   STATUS     RESTARTS   AGE   IP            NODE                                NOMINATED NODE   READINESS GATES
aspnet-webapp-aspnet-core-67f579d785-5h4kl   0/1     Init:0/2   0          27s   10.244.0.16   aks-nodepool1-34328761-vmss000000   <none>           <none>
aspnet-webapp-aspnet-core-67f579d785-75dqj   0/1     Init:0/2   0          27s   10.244.0.18   aks-nodepool1-34328761-vmss000000   <none>           <none>
aspnet-webapp-aspnet-core-67f579d785-hh4pq   0/1     Init:0/2   0          27s   10.244.0.15   aks-nodepool1-34328761-vmss000000   <none>           <none>
aspnet-webapp-aspnet-core-67f579d785-m9z96   0/1     Init:0/2   0          27s   10.244.0.17   aks-nodepool1-34328761-vmss000000   <none>           <none>
aspnet-webapp-aspnet-core-67f579d785-wtbhx   0/1     Init:0/2   0          27s   10.244.0.19   aks-nodepool1-34328761-vmss000000   <none>           <none>
  1. ワークロードのリリースとすべてのレプリカが削除します。
Azure Cloud Shell
$ helm delete aspnet-webapp
release "aspnet-webapp" uninstalled

ユニット7: 演習 - Helm リリースを管理する

Helm チャートのキャッシュの場所について
  1. $HOME/.cache/helm/repository フォルダーの内容を一覧表示して、aspnet-core-1.3.18.tgz ファイルを見つけます。
Azure Cloud Shell
$ ls $HOME/.cache/helm/repository -l
total 8892
-rw-r--r-- 1 user user   34980 Oct  6 02:38 aspnet-core-3.5.6.tgz
-rw-r--r-- 1 user user    1805 Oct  6 01:57 azure-marketplace-charts.txt
-rw-r--r-- 1 user user 9060672 Oct  6 01:57 azure-marketplace-index.yaml

基本、このディレクトリ内にあるので、何かあればここを参考にする。
今回の演習はすでに解凍展開済なので、ここはスキップ

  1. drone-webapp-chart フォルダーのすべての内容を再帰的に一覧表示して、既存の Helm チャートを調べます。
Azure Cloud Shell
$ cd ~/clouddrive/mslearn-aks/modules/learn-helm-deploy-aks/src
find drone-webapp-chart/ -print
drone-webapp-chart/
drone-webapp-chart/.helmignore
drone-webapp-chart/Chart.yaml
drone-webapp-chart/templates
drone-webapp-chart/templates/deployment.yaml
drone-webapp-chart/templates/extra-list.yaml
drone-webapp-chart/templates/health-ingress.yaml
drone-webapp-chart/templates/hpa.yaml
drone-webapp-chart/templates/ingress.yaml
drone-webapp-chart/templates/NOTES.txt
drone-webapp-chart/templates/pdb.yaml
drone-webapp-chart/templates/service.yaml
drone-webapp-chart/templates/serviceaccount.yaml
drone-webapp-chart/templates/tls-secret.yaml
drone-webapp-chart/templates/_helpers.tpl
drone-webapp-chart/values.yaml

このチャートの次のコンポーネントに注目してください。

・Chart.yaml ファイル (drone-webapp-chart/Chart.yaml)
・values.yaml ファイル (drone-webapp-chart/values.yaml)
・templates/ フォルダー上の多数のテンプレート (drone-webapp-chart/templates)

  1. drone-webapp-chart/Chart.yaml を開いてチャートの依存関係を確認します。
Azure Cloud Shell
$ code drone-webapp-chart/Chart.yaml
drone-webapp-chart/Chart.yaml
apiVersion: v2
appVersion: 0.0.1
description: ASP.NET Core is an open-source framework created by Microsoft for building
  cloud-enabled, modern applications.
home: https://dotnet.microsoft.com/apps/aspnet
icon: https://bitnami.com/assets/stacks/aspnet-core/img/aspnet-core-stack-220x234.png
keywords:
- asp.net
- dotnet
maintainers:
- email: containers@bitnami.com
- name: Bitnami
name: aspnet-core
sources:
- https://github.com/bitnami/bitnami-docker-aspnet-core
annotations:
 category: DeveloperTools
version: 1.3.18
dependencies:  # ここがサブチャート
  - name: common
    version: 1.x.x
    repository: https://marketplace.azurecr.io/helm/v1/repo
    tags:
      - bitnami-common
  1. チャートのすべての依存関係をダウンロードし、更新します。
Azure Cloud Shell
$ helm dependency build ./drone-webapp-chart
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "azure-marketplace" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 1 charts
Downloading common from repo https://marketplace.azurecr.io/helm/v1/repo
Deleting outdated charts
  1. drone-webapp-chart フォルダー内のファイルを調べ、Helm のダウンロードの内容を確認します。
Azure Cloud Shell
$ find drone-webapp-chart/ -print
drone-webapp-chart/
drone-webapp-chart/.helmignore
drone-webapp-chart/Chart.lock
drone-webapp-chart/Chart.yaml
drone-webapp-chart/charts
drone-webapp-chart/charts/common-1.17.0.tgz
drone-webapp-chart/templates
drone-webapp-chart/templates/deployment.yaml
drone-webapp-chart/templates/extra-list.yaml
drone-webapp-chart/templates/health-ingress.yaml
drone-webapp-chart/templates/hpa.yaml
drone-webapp-chart/templates/ingress.yaml
drone-webapp-chart/templates/NOTES.txt
drone-webapp-chart/templates/pdb.yaml
drone-webapp-chart/templates/service.yaml
drone-webapp-chart/templates/serviceaccount.yaml
drone-webapp-chart/templates/tls-secret.yaml
drone-webapp-chart/templates/_helpers.tpl
drone-webapp-chart/values.yaml

common という名前の更新されたサブチャートを charts/ フォルダーで使用できるようになりました。

続けてcommonチャートのファイルを解凍して確認もできますと書いてますが、ここでは割愛。

チャートの values.yaml ファイルを確認する

  1. values.yaml を開きます。
Azure Cloud Shell
$ code ./drone-webapp-chart/values.yaml
  1. image の値を検索して、Web アプリに使用されているイメージを確認します。
drone-webapp-chart/values.yaml
image:
  registry: docker.io
  repository: bitnami/aspnet-core
  tag: 3.1.19-debian-10-r0
  ## Specify a imagePullPolicy
  ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
  ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
  ##
  pullPolicy: IfNotPresent
  ## Optionally specify an array of imagePullSecrets.
  ## Secrets must be manually created in the namespace.
  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
  ## e.g:
  ## pullSecrets:
  ##   - myRegistryKeySecretName
  ##
  pullSecrets: []

これがアプリのベースとなるイメージらしいです。

  1. appFromExternalRepo の値を検索します。 これらの値を使用して、deployment.yaml マニフェスト ファイルを生成します。
drone-webapp-chart/values.yaml
## Enable to download/build ASP.NET Core app from external git repository.
## Do not enable it if your docker image already includes your application
##
appFromExternalRepo:
  ## @param appFromExternalRepo.enabled Enable to download/build ASP.NET Core app from external git repository
  ##
  enabled: true
  clone:
    ## Bitnami Git image version
    ## ref: https://hub.docker.com/r/bitnami/git/tags/
    ## @param appFromExternalRepo.clone.image.registry Git image registry
    ## @param appFromExternalRepo.clone.image.repository Git image repository
    ## @param appFromExternalRepo.clone.image.tag Git image tag (immutable tags are recommended)
    ## @param appFromExternalRepo.clone.image.pullPolicy Git image pull policy
    ## @param appFromExternalRepo.clone.image.pullSecrets Git image pull secrets
    ##
    image:
      registry: docker.io
      repository: bitnami/git
      tag: 2.33.0-debian-10-r28
      ## Specify a imagePullPolicy
      ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
      ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
      ##
      pullPolicy: IfNotPresent
      ## Optionally specify an array of imagePullSecrets.
      ## Secrets must be manually created in the namespace.
      ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
      ## e.g:
      ## pullSecrets:
      ##   - myRegistryKeySecretName
      ##
      pullSecrets: []
    ## @param appFromExternalRepo.clone.repository Git repository to clone
    ##
    repository: https://github.com/MicrosoftDocs/mslearn-aks.git
    ## @param appFromExternalRepo.clone.revision Git revision to checkout
    ##
    revision: main
    ## @param appFromExternalRepo.clone.extraVolumeMounts Add extra volume mounts for the GIT container
    ## Useful to mount keys to connect through ssh. (normally used with extraVolumes)
    ## e.g:
    ## extraVolumeMounts:
    ##   - name: ssh-dir
    ##     mountPath: /root/.ssh/
    ##
    extraVolumeMounts: []
  publish:
    ## Bitnami .NET SDK image version
    ## ref: https://hub.docker.com/r/bitnami/dotnet-sdk/tags/
    ## @param appFromExternalRepo.publish.image.registry .NET SDK image registry
    ## @param appFromExternalRepo.publish.image.repository .NET SDK image repository
    ## @param appFromExternalRepo.publish.image.tag .NET SDK image tag (immutable tags are recommended)
    ## @param appFromExternalRepo.publish.image.pullPolicy .NET SDK image pull policy
    ## @param appFromExternalRepo.publish.image.pullSecrets .NET SDK image pull secrets
    ##
    image:
      registry: docker.io
      repository: bitnami/dotnet-sdk
      tag: 3.1.412-debian-10-r33
      ## Specify a imagePullPolicy
      ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
      ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
      ##
      pullPolicy: IfNotPresent
      ## Optionally specify an array of imagePullSecrets.
      ## Secrets must be manually created in the namespace.
      ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
      ## e.g:
      ## pullSecrets:
      ##   - myRegistryKeySecretName
      ##
      pullSecrets: []
    ## @param appFromExternalRepo.publish.subFolder Sub folder under the Git repository containing the ASP.NET Core app
    ##
    subFolder: modules/learn-helm-deploy-aks/src/drone-webapp
    ## @param appFromExternalRepo.publish.extraFlags Extra flags to be appended to "dotnet publish" command
    ##
    extraFlags: []
  ## @param appFromExternalRepo.startCommand Command used to start ASP.NET Core app
  ##
  startCommand: ["dotnet", "drone-webapp.dll"]
  1. values.yaml ファイル内の ingress の値を検索します。 これらの値を使用して、ingress.yaml マニフェスト ファイルを生成します。
drone-webapp-chart/values.yaml
## Configure the ingress resource that allows you to access the ASP.NET Core app
## ref: http://kubernetes.io/docs/user-guide/ingress/
##
ingress:
  ## @param ingress.enabled Enable ingress record generation for ASP.NET Core
  ##
  enabled: true
  ## @param ingress.pathType Ingress path type
  ##
  pathType: ImplementationSpecific
  ## @param ingress.apiVersion Force Ingress API version (automatically detected if not set)
  ##
  apiVersion: ""
  ## @param ingress.hostname Default host for the ingress resource, a host pointing to this will be created
  ##
  hostname: aspnet-core.local
  ## @param ingress.path Default path for the ingress record
  ##
  path: /
  ## @param ingress.annotations Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations.
  ## For a full list of possible ingress annotations, please see
  ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md
  ## Use this parameter to set the required annotations for cert-manager, see
  ## ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations
  ##
  ## e.g:
  ## annotations:
  ##   kubernetes.io/ingress.class: nginx
  ##   cert-manager.io/cluster-issuer: cluster-issuer-name
  ##
  annotations: {}
  ## @param ingress.tls Enable TLS configuration for the host defined at `ingress.hostname` parameter
  ## TLS certificates will be retrieved from a TLS secret with name: `{{- printf "%s-tls" .Values.ingress.hostname }}`
  ## You can:
  ##   - Use the `ingress.secrets` parameter to create this TLS secret
  ##   - Relay on cert-manager to create it by setting the corresponding annotations
  ##
  tls: false
  ## DEPRECATED: Use ingress.annotations instead of ingress.certManager
  ## certManager: false
  ##

  ## @param ingress.extraHosts An array with additional hostname(s) to be covered with the ingress record
  ## e.g:
  ## extraHosts:
  ##   - name: aspnet-core.local
  ##     path: /
  ##
  extraHosts: []
  ## @param ingress.extraTls TLS configuration for additional hostname(s) to be covered with this ingress record
  ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls
  ## e.g:
  ## extraTls:
  ## - hosts:
  ##     - aspnet-core.local
  ##   secretName: aspnet-core.local-tls
  ##
  extraTls: []
  ## @param ingress.secrets Custom TLS certificates as secrets
  ## NOTE: 'key' and 'certificate' are expected in PEM format
  ## NOTE: 'name' should line up with a 'secretName' set further up
  ## If it is not set and you're using cert-manager, this is unneeded, as it will create a secret for you with valid certificates
  ## If it is not set and you're NOT using cert-manager either, self-signed certificates will be created
  ## It is also possible to create and manage the certificates outside of this helm chart
  ## Please see README.md for more information
  ## e.g:
  ## secrets:
  ##   - name: aspnet-core.local-tls
  ##     key: |-
  ##       -----BEGIN RSA PRIVATE KEY-----
  ##       ...
  ##       -----END RSA PRIVATE KEY-----
  ##     certificate: |-
  ##       -----BEGIN CERTIFICATE-----
  ##       ...
  ##       -----END CERTIFICATE-----
  ##
  secrets: []

deployment.yaml および ingress.yaml テンプレート ファイルを確認する

  1. templates/deployment.yaml を開きます。
Azure Cloud Shell
$ code ./drone-webapp-chart/templates/deployment.yaml
templates/deployment.yaml
apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }}
kind: Deployment
metadata:
  name: {{ include "aspnet-core.fullname" . }}
  labels: {{- include "common.labels.standard" . | nindent 4 }}
    {{- if .Values.commonLabels }}
    {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }}
    {{- end }}
  {{- if .Values.commonAnnotations }}
  annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
  {{- end }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }}
  strategy:
    type: {{ .Values.strategyType }}
    {{- if (eq "Recreate" .Values.strategyType) }}
    rollingUpdate: null
    {{- end }}
  template:
    metadata:
      {{- if .Values.podAnnotations }}
      annotations: {{- include "common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }}
      {{- end }}
      labels: {{- include "common.labels.standard" . | nindent 8 }}
    spec:
      {{- include "aspnet-core.imagePullSecrets" . | nindent 6 }}
      {{- if .Values.hostAliases }}
      hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "aspnet-core.serviceAccountName" . }}
      {{- if .Values.affinity }}
      affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.affinity "context" $) | nindent 8 }}
      {{- else }}
      affinity:
        podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "context" $) | nindent 10 }}
        podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "context" $) | nindent 10 }}
        nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }}
      {{- end }}
      {{- if .Values.nodeSelector }}
      nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.nodeSelector "context" $) | nindent 8 }}
      {{- end }}
      {{- if .Values.tolerations }}
      tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" $) | nindent 8 }}
      {{- end }}
      {{- if .Values.priorityClassName }}
      priorityClassName: {{ .Values.priorityClassName | quote }}
      {{- end }}
      {{- if .Values.podSecurityContext.enabled }}
      securityContext:
        fsGroup: {{ .Values.podSecurityContext.fsGroup }}
        {{- if .Values.podSecurityContext.sysctls }}
        sysctls:
          {{- toYaml .Values.podSecurityContext.sysctls | nindent 10 }}
        {{- end }}
      {{- end }}
      {{- if or .Values.appFromExternalRepo.enabled .Values.initContainers }}
      initContainers:
        {{- if .Values.appFromExternalRepo.enabled }}
        - name: clone-repository
          image: {{ include "aspnet-core.git.image" . }}
          imagePullPolicy: {{ .Values.appFromExternalRepo.clone.image.pullPolicy | quote }}
          command:
            - /bin/bash
            - -ec
            - |
              [[ -f "/opt/bitnami/scripts/git/entrypoint.sh" ]] && source "/opt/bitnami/scripts/git/entrypoint.sh"
              git clone {{ .Values.appFromExternalRepo.clone.repository }} --branch {{ .Values.appFromExternalRepo.clone.revision }} /repo
          volumeMounts:
            - name: repo
              mountPath: /repo
          {{- if .Values.appFromExternalRepo.clone.extraVolumeMounts }}
            {{- include "common.tplvalues.render" (dict "value" .Values.appFromExternalRepo.clone.extraVolumeMounts "context" $) | nindent 12 }}
          {{- end }}
        - name: dotnet-publish
          image: {{ include "aspnet-core.sdk.image" . }}
          imagePullPolicy: {{ .Values.appFromExternalRepo.publish.image.pullPolicy | quote }}
          workingDir: /repo
          command:
            - /bin/bash
            - -ec
            - |
              cd {{ .Values.appFromExternalRepo.publish.subFolder }}
              dotnet publish -o /app {{ .Values.appFromExternalRepo.publish.extraFlags | join " " }}
          volumeMounts:
            - name: app
              mountPath: /app
            - name: repo
              mountPath: /repo
        {{- end }}
        {{- if .Values.initContainers }}
        {{- include "common.tplvalues.render" (dict "value" .Values.initContainers "context" $) | nindent 8 }}
        {{- end }}
      {{- end }}
      containers:
        - name: aspnet-core
          image: {{ include "aspnet-core.image" . }}
          imagePullPolicy: {{ .Values.image.pullPolicy | quote }}
          {{- if .Values.containerSecurityContext.enabled }}
          securityContext:
            runAsUser: {{ .Values.containerSecurityContext.runAsUser }}
          {{- end }}
          {{- if .Values.lifecycleHooks }}
          lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 12 }}
          {{- end }}
          workingDir: /app
          command:
          {{- if .Values.command }}
          {{- include "common.tplvalues.render" (dict "value" .Values.command "context" $) | nindent 12 }}
          {{- else if .Values.appFromExternalRepo.enabled }}
          {{- include "common.tplvalues.render" (dict "value" .Values.appFromExternalRepo.startCommand "context" $) | nindent 12 }}
          {{- else }}
            - dotnet
          {{- end }}
          {{- if .Values.args }}
          args: {{- include "common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 12 }}
          {{- end }}
          env:
            - name: ASPNETCORE_URLS
              value: {{ .Values.bindURLs | quote }}
            {{- range $key, $value := .Values.extraEnvVars }}
            - name: {{ $key }}
              value: "{{ $value }}"
            {{- end }}
          {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }}
          envFrom:
            {{- if .Values.extraEnvVarsCM }}
            - configMapRef:
                name: {{ tpl .Values.extraEnvVarsCM . | quote }}
            {{- end }}
            {{- if .Values.extraEnvVarsSecret }}
            - secretRef:
                name: {{ tpl .Values.extraEnvVarsSecret . | quote }}
            {{- end }}
          {{- end }}
          ports:
            - name: http
              containerPort: {{ .Values.containerPort }}
          {{- if .Values.livenessProbe.enabled }}
          livenessProbe:
            tcpSocket:
              port: http
            initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
            periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
            timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
            successThreshold: {{ .Values.livenessProbe.successThreshold }}
            failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
          {{- else if .Values.customLivenessProbe }}
          livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }}
          {{- end }}
          {{- if .Values.readinessProbe.enabled }}
          readinessProbe:
            tcpSocket:
              port: http
            initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
            periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
            timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
            successThreshold: {{ .Values.readinessProbe.successThreshold }}
            failureThreshold: {{ .Values.readinessProbe.failureThreshold }}
          {{- else if .Values.customReadinessProbe }}
          readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }}
          {{- end }}
          {{- if .Values.resources }}
          resources: {{- toYaml .Values.resources | nindent 12 }}
          {{- end }}
          {{- if or .Values.appFromExternalRepo.enabled .Values.appFromExistingPVC.enabled .Values.extraVolumeMounts }}
          volumeMounts:
            {{- if or .Values.appFromExternalRepo.enabled .Values.appFromExistingPVC.enabled }}
            - name: app
              mountPath: /app
            {{- end }}
            {{- if .Values.extraVolumeMounts }}
            {{- include "common.tplvalues.render" ( dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }}
            {{- end }}
          {{- end }}
        {{- if .Values.sidecars }}
        {{- include "common.tplvalues.render" ( dict "value" .Values.sidecars "context" $) | nindent 8 }}
        {{- end }}
      {{- if or .Values.appFromExternalRepo.enabled .Values.appFromExistingPVC.enabled .Values.extraVolumes }}
      volumes:
        {{- if .Values.extraVolumes }}
        {{- include "common.tplvalues.render" ( dict "value" .Values.extraVolumes "context" $) | nindent 8 }}
        {{- end }}
        {{- if or .Values.appFromExternalRepo.enabled .Values.appFromExistingPVC.enabled }}
        - name: app
        {{- if .Values.appFromExistingPVC.enabled }}
          persistentVolumeClaim:
            claimName: {{ printf "%s" (tpl (default "" .Values.appFromExistingPVC.existingClaim) .) }}
        {{- else }}
          emptyDir: {}
        - name: repo
          emptyDir: {}
        {{- end }}
        {{- end }}
      {{- end }}
  1. templates/ingress.yaml を開きます。
Azure Cloud Shell
$ code ./drone-webapp-chart/templates/ingress.yaml
templates/ingress.yaml
{{- if .Values.ingress.enabled -}}
apiVersion: {{ include "common.capabilities.ingress.apiVersion" . }}
kind: Ingress
metadata:
  name: {{ include "aspnet-core.fullname" . }}
  labels: {{- include "common.labels.standard" . | nindent 4 }}
    {{- if .Values.commonLabels }}
    {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }}
    {{- end }}
  annotations:
    {{- if .Values.ingress.certManager }}
    kubernetes.io/tls-acme: "true"
    {{- end }}
    {{- if .Values.ingress.annotations }}
    {{- include "common.tplvalues.render" ( dict "value" .Values.ingress.annotations "context" $) | nindent 4 }}
    {{- end }}
    {{- if .Values.commonAnnotations }}
    {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
    {{- end }}
spec:
  rules:
    {{- if .Values.ingress.hostname }}
    - host: {{ .Values.ingress.hostname }}
      http:
        paths:
          - path: {{ .Values.ingress.path }}
            {{- if eq "true" (include "common.ingress.supportsPathType" .) }}
            pathType: {{ .Values.ingress.pathType }}
            {{- end }}
            backend: {{- include "common.ingress.backend" (dict "serviceName" (include "aspnet-core.fullname" .) "servicePort" "http" "context" $)  | nindent 14 }}
    {{- end }}
    {{- range .Values.ingress.extraHosts }}
    - host: {{ .name }}
      http:
        paths:
          - path: {{ default "/" .path }}
            backend:
              serviceName: {{ include "aspnet-core.fullname" $ }}
              servicePort: http
    {{- end }}
  {{- if or .Values.ingress.tls .Values.ingress.extraTls .Values.ingress.hosts }}
  tls:
    {{- if .Values.ingress.tls }}
    - hosts:
        - {{ .Values.ingress.hostname }}
      secretName: {{ printf "%s-tls" .Values.ingress.hostname }}
    {{- end }}
    {{- if .Values.ingress.extraTls }}
    {{- toYaml .Values.ingress.extraTls | nindent 4 }}
    {{- end }}
  {{- end }}
{{- end }}

Helm チャートをデプロイする

  1. drone-webapp Helm チャートをデプロイします。
Azure Cloud Shell
$ helm install drone-webapp ./drone-webapp-chart
NAME: drone-webapp
LAST DEPLOYED: Fri Oct  6 03:22:29 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
** Please be patient while the chart is being deployed **

ASP.NET Core can be accessed through the following DNS name from within your cluster:

    drone-webapp-aspnet-core.default.svc.cluster.local (port 80)

To access ASP.NET Core from outside the cluster execute the following commands:

1. Get the ASP.NET Core URL and associate its hostname to your cluster external IP:

   export CLUSTER_IP=$(minikube ip) # On Minikube. Use: `kubectl cluster-info` on others K8s clusters
   echo "ASP.NET Core URL: http://aspnet-core.local"
   echo "$CLUSTER_IP  aspnet-core.local" | sudo tee -a /etc/hosts

2. Access ASP.NET Core using the obtained URL.

インストール プロセスを表示します。

Azure Cloud Shell
$ kubectl get pods -w
NAME                                       READY   STATUS                  RESTARTS   AGE
drone-webapp-aspnet-core-b6f456ffd-pphvl   0/1     Init:InvalidImageName   0          2m23s

READYにならないですね🤔

kubectl describe pod <pod-name> 

でポッドの詳細が見れるようなので調べてみます。

Azure Cloud Shell
$ kubectl describe pod drone-webapp-aspnet-core-b6f456ffd-pphvl
Name:             drone-webapp-aspnet-core-b6f456ffd-pphvl
Namespace:        default
Priority:         0
Service Account:  drone-webapp-aspnet-core
Node:             aks-nodepool1-34328761-vmss000000/10.224.0.4
Start Time:       Fri, 06 Oct 2023 03:22:31 +0000
Labels:           app.kubernetes.io/instance=drone-webapp
                  app.kubernetes.io/managed-by=Helm
                  app.kubernetes.io/name=aspnet-core
                  helm.sh/chart=aspnet-core-1.3.18
                  pod-template-hash=b6f456ffd
Annotations:      <none>
Status:           Pending
IP:               10.244.0.20
IPs:
  IP:           10.244.0.20
Controlled By:  ReplicaSet/drone-webapp-aspnet-core-b6f456ffd
Init Containers:
  clone-repository:
    Container ID:  
    Image:         marketplace.azurecr.io/bitnami/git@<nil>
    Image ID:      
    Port:          <none>
    Host Port:     <none>
    Command:
      /bin/bash
      -ec
      [[ -f "/opt/bitnami/scripts/git/entrypoint.sh" ]] && source "/opt/bitnami/scripts/git/entrypoint.sh"
      git clone https://github.com/MicrosoftDocs/mslearn-aks.git --branch main /repo
      
    State:          Waiting
      Reason:       InvalidImageName
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /repo from repo (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-45tc2 (ro)
  dotnet-publish:
    Container ID:  
    Image:         marketplace.azurecr.io/bitnami/dotnet-sdk@<nil>
    Image ID:      
    Port:          <none>
    Host Port:     <none>
    Command:
      /bin/bash
      -ec
      cd modules/learn-helm-deploy-aks/src/drone-webapp
      dotnet publish -o /app 
      
    State:          Waiting
      Reason:       PodInitializing
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /app from app (rw)
      /repo from repo (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-45tc2 (ro)
Containers:
  aspnet-core:
    Container ID:  
    Image:         marketplace.azurecr.io/bitnami/aspnet-core@<nil>
    Image ID:      
    Port:          8080/TCP
    Host Port:     0/TCP
    Command:
      dotnet
      drone-webapp.dll
    State:          Waiting
      Reason:       PodInitializing
    Ready:          False
    Restart Count:  0
    Liveness:       tcp-socket :http delay=10s timeout=1s period=20s #success=1 #failure=6
    Readiness:      tcp-socket :http delay=10s timeout=1s period=20s #success=1 #failure=6
    Environment:
      ASPNETCORE_URLS:  http://+:8080
    Mounts:
      /app from app (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-45tc2 (ro)
Conditions:
  Type              Status
  Initialized       False 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  app:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:     
    SizeLimit:  <unset>
  repo:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:     
    SizeLimit:  <unset>
  kube-api-access-45tc2:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason         Age                     From               Message
  ----     ------         ----                    ----               -------
  Normal   Scheduled      9m32s                   default-scheduler  Successfully assigned default/drone-webapp-aspnet-core-b6f456ffd-pphvl to aks-nodepool1-34328761-vmss000000
  Warning  Failed         7m24s (x12 over 9m32s)  kubelet            Error: InvalidImageName
  Warning  InspectFailed  4m29s (x26 over 9m32s)  kubelet            Failed to apply default image tag "marketplace.azurecr.io/bitnami/git@<nil>": couldn't parse image reference "marketplace.azurecr.io/bitnami/git@<nil>": invalid reference format

bitnami/git のイメージの指定に失敗しているみたいです。
appFromExternalRepo の imageですかね

drone-webapp-chart/values.yaml
    image:
      registry: docker.io
      repository: bitnami/git
      tag: 2.33.0-debian-10-r28
      ## Specify a imagePullPolicy
      ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
      ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
      ##
      pullPolicy: IfNotPresent
      ## Optionally specify an array of imagePullSecrets.
      ## Secrets must be manually created in the namespace.
      ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
      ## e.g:
      ## pullSecrets:
      ##   - myRegistryKeySecretName
      ##
      pullSecrets: []

イメージはあるようです。
https://hub.docker.com/r/bitnami/git/tags?page=1&name=2.33.0-debian-10-r28

issueが上がってました。
https://github.com/MicrosoftDocs/mslearn-aks/issues/6

drone-webapp-chart/Chart.yaml
dependencies:
  - name: common
    version: 1.10.0
    repository: https://marketplace.azurecr.io/helm/v1/repo
    tags:
      - bitnami-common

もう一度ビルドしようとしたら怒られたので、updateに変えます。

Azure Cloud Shell
$ helm dependency build ./drone-webapp-chart
Error: the lock file (Chart.lock) is out of sync with the dependencies file (Chart.yaml). Please update the dependencies
$ helm dependency update ./drone-webapp-chart
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "azure-marketplace" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 1 charts
Downloading common from repo https://marketplace.azurecr.io/helm/v1/repo
Deleting outdated charts

もう一度installすればよいかと思い、もう一度実行したところ、エラーが出たのでuninstallしてから、再度installします。

helm install error cannot re-use a name that is still in use エラー

このエラーは、同じ名前で同じ名前空間に2つのアプリケーションをインストールしようとしたときに発生します。helmは、すでに使用されている名前を再利用することを防ぐために、このエラーを出します。

Azure Cloud Shell
$ helm list
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
drone-webapp    default         1               2023-10-06 03:22:29.168587723 +0000 UTC deployed        aspnet-core-1.3.18      0.0.1
$ helm uninstall drone-webapp
release "drone-webapp" uninstalled
$ helm install drone-webapp ./drone-webapp-chart
NAME: drone-webapp
LAST DEPLOYED: Fri Oct  6 04:16:51 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
** Please be patient while the chart is being deployed **

ASP.NET Core can be accessed through the following DNS name from within your cluster:

    drone-webapp-aspnet-core.default.svc.cluster.local (port 80)

To access ASP.NET Core from outside the cluster execute the following commands:

1. Get the ASP.NET Core URL and associate its hostname to your cluster external IP:

   export CLUSTER_IP=$(minikube ip) # On Minikube. Use: `kubectl cluster-info` on others K8s clusters
   echo "ASP.NET Core URL: http://aspnet-core.local"
   echo "$CLUSTER_IP  aspnet-core.local" | sudo tee -a /etc/hosts

2. Access ASP.NET Core using the obtained URL.
Azure Cloud Shell
$ kubectl get pods -w
NAME                                        READY   STATUS     RESTARTS   AGE
drone-webapp-aspnet-core-57b6f78bc5-9c2d7   0/1     Init:1/2   0          33s
drone-webapp-aspnet-core-57b6f78bc5-9c2d7   0/1     Init:1/2   0          62s
drone-webapp-aspnet-core-57b6f78bc5-9c2d7   0/1     PodInitializing   0          74s
drone-webapp-aspnet-core-57b6f78bc5-9c2d7   0/1     Running           0          119s

Runningになりました!
残念ながらロードバランサーのIPにアクセスしてもnginxの404のままだったので、issueにある通り、イングレスの修正が必要っぽいですが、見た感じ修正の必要なさそうなんですよね。わからんので諦めます😇

Helm リリースをアップグレードする

新しいバージョンをデプロイするには、helm upgrade だそうです。

  1. Helm のデプロイをすべて一覧表示します。
Azure Cloud Shell
$ helm list
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
drone-webapp    default         1               2023-10-06 04:16:51.8365555 +0000 UTC   deployed        aspnet-core-1.3.18      0.0.1
  1. drone-webapp に関する履歴情報を表示します。
Azure Cloud Shell
$ helm history drone-webapp
REVISION        UPDATED                         STATUS          CHART                   APP VERSION     DESCRIPTION     
1               Fri Oct  6 04:16:51 2023        deployed        aspnet-core-1.3.18      0.0.1           Install complete
  1. Chart.yaml ファイルを開き、アプリケーションのバージョン番号を更新します。
Azure Cloud Shell
$ code ./drone-webapp-chart/Chart.yaml
drone-webapp-chart/Chart.yaml
apiVersion: v2
appVersion: 0.0.2

保存したらアップグレードします。

Azure Cloud Shell
$ helm upgrade drone-webapp ./drone-webapp-chart
Release "drone-webapp" has been upgraded. Happy Helming!
NAME: drone-webapp
LAST DEPLOYED: Fri Oct  6 04:26:27 2023
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:
** Please be patient while the chart is being deployed **

ASP.NET Core can be accessed through the following DNS name from within your cluster:

    drone-webapp-aspnet-core.default.svc.cluster.local (port 80)

To access ASP.NET Core from outside the cluster execute the following commands:

1. Get the ASP.NET Core URL and associate its hostname to your cluster external IP:

   export CLUSTER_IP=$(minikube ip) # On Minikube. Use: `kubectl cluster-info` on others K8s clusters
   echo "ASP.NET Core URL: http://aspnet-core.local"
   echo "$CLUSTER_IP  aspnet-core.local" | sudo tee -a /etc/hosts

2. Access ASP.NET Core using the obtained URL.

リビジョンが2になってる

Azure Cloud Shell
$ helm history drone-webapp
REVISION        UPDATED                         STATUS          CHART                   APP VERSION     DESCRIPTION     
1               Fri Oct  6 04:16:51 2023        superseded      aspnet-core-1.3.18      0.0.1           Install complete
2               Fri Oct  6 04:26:27 2023        deployed        aspnet-core-1.3.18      0.0.2           Upgrade complete

バージョン1は superseded (何かを置き換える、取って代わる、廃止する)になるんですね。

Helm リリースをロールバックする

  1. 対象とするリリースのリビジョン番号を指定して、Helm リリースをロールバックします。
Azure Cloud Shell
$ helm rollback drone-webapp 1
Rollback was a success! Happy Helming!
  1. Helm のデプロイ履歴を確認します。
Azure Cloud Shell
$ helm history drone-webapp
REVISION        UPDATED                         STATUS          CHART                   APP VERSION     DESCRIPTION     
1               Fri Oct  6 04:16:51 2023        superseded      aspnet-core-1.3.18      0.0.1           Install complete
2               Fri Oct  6 04:26:27 2023        superseded      aspnet-core-1.3.18      0.0.2           Upgrade complete
3               Fri Oct  6 04:30:17 2023        deployed        aspnet-core-1.3.18      0.0.1           Rollback to 1

おーロールバックされました🎉

リソースのクリーンアップ

このlearnで生成されたリソースグループをが2つあるので、削除します。

削除されたクラスター コンテキストを削除します。

Azure Cloud Shell
$ kubectl config delete-context learn-helm-deploy-aks
warning: this removed your active context, use "kubectl config use-context" to select a different one
deleted context learn-helm-deploy-aks from /home/user/.kube/config

.NET SDK の変更を元に戻す

.bashrc プロファイル を書き換えてたようなので、もとに戻します。

Azure Cloud Shell
$ cp ~/.bashrc.bak.learn-helm-deploy-aks ~/.bashrc

おわりに

なんとなくはわかったかな?

参考

https://qiita.com/minodisk/items/547741b73763f2bab6b8

Discussion