diff --git a/.github/workflows/5-publish-helm-chart.yaml b/.github/workflows/5-publish-helm-chart.yaml new file mode 100644 index 000000000..4e017c950 --- /dev/null +++ b/.github/workflows/5-publish-helm-chart.yaml @@ -0,0 +1,41 @@ +name: 5-Publish Helm chart + +on: + workflow_dispatch: + +concurrency: + group: publish-helm-chart + cancel-in-progress: true + +jobs: + push-helm-charts: + if: github.repository == 'Green-Software-Foundation/carbon-aware-sdk' || vars.ENABLE_HELM_WORKFLOW == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Detect Helm chart version + run: | + CHART_VERSION=`yq .version helm-chart/Chart.yaml` + echo "CHART_VERSION=$CHART_VERSION" >> "$GITHUB_ENV" + + - name: Packaging + run: helm package helm-chart + + - name: Log in to the Container registry + uses: docker/login-action@v2.1.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Push charts to GHCR + run: | + OWNER_LOWER=${GITHUB_REPOSITORY_OWNER,,} + helm push carbon-aware-sdk-${{ env.CHART_VERSION }}.tgz "oci://ghcr.io/$OWNER_LOWER/charts" + shell: bash diff --git a/docs/overview.md b/docs/overview.md index b83998618..8ac7fdac2 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -219,3 +219,144 @@ $ curl -s http://localhost:8080/emissions/forecasts/current?location=westus2 | j For more information on containerization, refer to the markdown in [containerization.md](./containerization.md). + +### Deploy Web API on Kubernetes with Helm + +You can deploy Web API as a Kubernetes application via Helm. GSF provides a chart as an OCI container, so you have to use Helm v3.8.0 or later. + +Following command creates `carbon-aware-sdk` namespace and deploys Web API into it with specified `values.yaml`. + +```bash +$ helm install casdk -n carbon-aware-sdk --create-namespace oci://ghcr.io/green-software-foundation/charts/carbon-aware-sdk --values values.yaml +``` + +`values.yaml` should contain `appsettings.json` which would be used in Web API at least. It should include data source definitions and their credentials. It would be stored as `Secret` resource. + +```yaml +appsettings: |- + { + "DataSources": { + "EmissionsDataSource": "WattTime", + "ForecastDataSource": "WattTime", + "Configurations": { + "WattTime": { + "Type": "WattTime", + "Username": "username", + "Password": "password", + "BaseURL": "https://api2.watttime.org/v2/" + } + } + } + } +``` + +Also you can include following configuration into `values.yaml`. + +```yaml +# Number of replicas +replicaCount: 1 + +image: + repository: ghcr.io/green-software-foundation/carbon-aware-sdk + pullPolicy: IfNotPresent + # You can set specified tag (equivalent with the SDK version in here) + tag: latest + +# Set the value if you want to override the name. +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + className: "" + annotations: {} + hosts: + - host: carbon-aware-sdk.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: carbon-aware-sdk-tls + # hosts: + # - carbon-aware-sdk.local + +resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# appsettings.json +appsettings: |- + { + "DataSources": { + "EmissionsDataSource": "ElectricityMaps", + "ForecastDataSource": "WattTime", + "Configurations": { + "WattTime": { + "Type": "WattTime", + "Username": "username", + "Password": "password", + "BaseURL": "https://api2.watttime.org/v2/", + "Proxy": { + "useProxy": true, + "url": "http://10.10.10.1", + "username": "proxyUsername", + "password": "proxyPassword" + } + }, + "ElectricityMaps": { + "Type": "ElectricityMaps", + "APITokenHeader": "auth-token", + "APIToken": "myAwesomeToken", + "BaseURL": "https://api.electricitymap.org/v3/" + } + } + } + } +``` + +The video in below is demonstration to install Carbon Aware SDK via Helm. Note that installing the SDK from local directory ( ~/github-forked/carbon-aware-sdk/helm-chart ), not an OCI container. + +[!Demonstration to intall Carbon Aware SDK from local with Helm](https://github.com/Green-Software-Foundation/carbon-aware-sdk/assets/7421132/b09d8ab1-642b-442a-882f-abc802153070) diff --git a/samples/helmexample/.helmignore b/helm-chart/.helmignore similarity index 100% rename from samples/helmexample/.helmignore rename to helm-chart/.helmignore diff --git a/samples/helmexample/Chart.yaml b/helm-chart/Chart.yaml similarity index 90% rename from samples/helmexample/Chart.yaml rename to helm-chart/Chart.yaml index 837354aa5..be8609521 100644 --- a/samples/helmexample/Chart.yaml +++ b/helm-chart/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -name: helmexample -description: A Helm chart for Kubernetes +name: carbon-aware-sdk +description: A Helm chart for Carbon Aware SDK # A chart can be either an 'application' or a 'library' chart. # @@ -15,10 +15,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 +version: 1.0.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.16.0" +appVersion: "v1.1.0" diff --git a/samples/helmexample/templates/NOTES.txt b/helm-chart/templates/NOTES.txt similarity index 73% rename from samples/helmexample/templates/NOTES.txt rename to helm-chart/templates/NOTES.txt index ed54c0885..1519667b9 100644 --- a/samples/helmexample/templates/NOTES.txt +++ b/helm-chart/templates/NOTES.txt @@ -6,16 +6,16 @@ {{- end }} {{- end }} {{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "helmexample.fullname" . }}) + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services webapi export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT {{- else if contains "LoadBalancer" .Values.service.type }} NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "helmexample.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "helmexample.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w webapi + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "carbon-aware-sdk.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") echo http://$SERVICE_IP:{{ .Values.service.port }} {{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "helmexample.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "carbon-aware-sdk.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT diff --git a/samples/helmexample/templates/_helpers.tpl b/helm-chart/templates/_helpers.tpl similarity index 72% rename from samples/helmexample/templates/_helpers.tpl rename to helm-chart/templates/_helpers.tpl index 9437334f2..eb34521bb 100644 --- a/samples/helmexample/templates/_helpers.tpl +++ b/helm-chart/templates/_helpers.tpl @@ -1,7 +1,7 @@ {{/* Expand the name of the chart. */}} -{{- define "helmexample.name" -}} +{{- define "carbon-aware-sdk.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} @@ -10,7 +10,7 @@ Create a default fully qualified app name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). If release name contains chart name it will be used as a full name. */}} -{{- define "helmexample.fullname" -}} +{{- define "carbon-aware-sdk.fullname" -}} {{- if .Values.fullnameOverride }} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} {{- else }} @@ -26,16 +26,16 @@ If release name contains chart name it will be used as a full name. {{/* Create chart name and version as used by the chart label. */}} -{{- define "helmexample.chart" -}} +{{- define "carbon-aware-sdk.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Common labels */}} -{{- define "helmexample.labels" -}} -helm.sh/chart: {{ include "helmexample.chart" . }} -{{ include "helmexample.selectorLabels" . }} +{{- define "carbon-aware-sdk.labels" -}} +helm.sh/chart: {{ include "carbon-aware-sdk.chart" . }} +{{ include "carbon-aware-sdk.selectorLabels" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} @@ -45,17 +45,17 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} {{/* Selector labels */}} -{{- define "helmexample.selectorLabels" -}} -app.kubernetes.io/name: {{ include "helmexample.name" . }} +{{- define "carbon-aware-sdk.selectorLabels" -}} +app.kubernetes.io/name: {{ include "carbon-aware-sdk.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{/* Create the name of the service account to use */}} -{{- define "helmexample.serviceAccountName" -}} +{{- define "carbon-aware-sdk.serviceAccountName" -}} {{- if .Values.serviceAccount.create }} -{{- default (include "helmexample.fullname" .) .Values.serviceAccount.name }} +{{- default (include "carbon-aware-sdk.fullname" .) .Values.serviceAccount.name }} {{- else }} {{- default "default" .Values.serviceAccount.name }} {{- end }} diff --git a/samples/helmexample/templates/deployment.yaml b/helm-chart/templates/deployment.yaml similarity index 60% rename from samples/helmexample/templates/deployment.yaml rename to helm-chart/templates/deployment.yaml index 6cd0aef70..3a9891b36 100644 --- a/samples/helmexample/templates/deployment.yaml +++ b/helm-chart/templates/deployment.yaml @@ -1,16 +1,17 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "helmexample.fullname" . }} + name: webapi + namespace: {{ $.Release.Namespace }} labels: - {{- include "helmexample.labels" . | nindent 4 }} + {{- include "carbon-aware-sdk.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: - {{- include "helmexample.selectorLabels" . | nindent 6 }} + {{- include "carbon-aware-sdk.selectorLabels" . | nindent 6 }} template: metadata: {{- with .Values.podAnnotations }} @@ -18,31 +19,47 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} labels: - {{- include "helmexample.selectorLabels" . | nindent 8 }} + {{- include "carbon-aware-sdk.selectorLabels" . | nindent 8 }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: {{ include "helmexample.serviceAccountName" . }} + serviceAccountName: {{ include "carbon-aware-sdk.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} + enableServiceLinks: false containers: - name: {{ .Chart.Name }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.image.pullPolicy }} + imagePullPolicy: {{ . }} + {{- end }} ports: - name: http containerPort: 80 protocol: TCP + volumeMounts: + - name: appsettings + mountPath: /app/appsettings.json + subPath: appsettings.json + readOnly: true livenessProbe: - {{ .Values.monitorConfig.liveness | toYaml | indent 12 | trim }} + httpGet: + path: /health + port: http readinessProbe: - {{ .Values.monitorConfig.readiness | toYaml | indent 12 | trim }} + httpGet: + path: /health + port: http resources: {{- toYaml .Values.resources | nindent 12 }} + volumes: + - name: appsettings + secret: + secretName: appsettings {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/samples/helmexample/templates/hpa.yaml b/helm-chart/templates/hpa.yaml similarity index 80% rename from samples/helmexample/templates/hpa.yaml rename to helm-chart/templates/hpa.yaml index 7ccf2b6d2..f254c9d35 100644 --- a/samples/helmexample/templates/hpa.yaml +++ b/helm-chart/templates/hpa.yaml @@ -1,15 +1,16 @@ {{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2beta1 +apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: - name: {{ include "helmexample.fullname" . }} + name: webapi + namespace: {{ $.Release.Namespace }} labels: - {{- include "helmexample.labels" . | nindent 4 }} + {{- include "carbon-aware-sdk.labels" . | nindent 4 }} spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment - name: {{ include "helmexample.fullname" . }} + name: webapi minReplicas: {{ .Values.autoscaling.minReplicas }} maxReplicas: {{ .Values.autoscaling.maxReplicas }} metrics: diff --git a/samples/helmexample/templates/ingress.yaml b/helm-chart/templates/ingress.yaml similarity index 89% rename from samples/helmexample/templates/ingress.yaml rename to helm-chart/templates/ingress.yaml index 95ed7ec83..4dbd741a9 100644 --- a/samples/helmexample/templates/ingress.yaml +++ b/helm-chart/templates/ingress.yaml @@ -1,5 +1,4 @@ {{- if .Values.ingress.enabled -}} -{{- $fullName := include "helmexample.fullname" . -}} {{- $svcPort := .Values.service.port -}} {{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} @@ -15,9 +14,10 @@ apiVersion: extensions/v1beta1 {{- end }} kind: Ingress metadata: - name: {{ $fullName }} + name: webapi + namespace: {{ $.Release.Namespace }} labels: - {{- include "helmexample.labels" . | nindent 4 }} + {{- include "carbon-aware-sdk.labels" . | nindent 4 }} {{- with .Values.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} @@ -49,11 +49,11 @@ spec: backend: {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} service: - name: {{ $fullName }} + name: webapi port: number: {{ $svcPort }} {{- else }} - serviceName: {{ $fullName }} + serviceName: webapi servicePort: {{ $svcPort }} {{- end }} {{- end }} diff --git a/helm-chart/templates/secret.yaml b/helm-chart/templates/secret.yaml new file mode 100644 index 000000000..a52bfa3ac --- /dev/null +++ b/helm-chart/templates/secret.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: appsettings + namespace: {{ $.Release.Namespace }} + labels: + {{- include "carbon-aware-sdk.labels" . | nindent 4 }} +type: Opaque +stringData: + appsettings.json: {{- .Values.appsettings | toYaml | indent 2 }} diff --git a/samples/helmexample/templates/service.yaml b/helm-chart/templates/service.yaml similarity index 53% rename from samples/helmexample/templates/service.yaml rename to helm-chart/templates/service.yaml index 3a637319e..644c31442 100644 --- a/samples/helmexample/templates/service.yaml +++ b/helm-chart/templates/service.yaml @@ -1,9 +1,10 @@ apiVersion: v1 kind: Service metadata: - name: {{ include "helmexample.fullname" . }} + name: webapi + namespace: {{ $.Release.Namespace }} labels: - {{- include "helmexample.labels" . | nindent 4 }} + {{- include "carbon-aware-sdk.labels" . | nindent 4 }} spec: type: {{ .Values.service.type }} ports: @@ -12,4 +13,4 @@ spec: protocol: TCP name: http selector: - {{- include "helmexample.selectorLabels" . | nindent 4 }} + {{- include "carbon-aware-sdk.selectorLabels" . | nindent 4 }} diff --git a/samples/helmexample/templates/serviceaccount.yaml b/helm-chart/templates/serviceaccount.yaml similarity index 58% rename from samples/helmexample/templates/serviceaccount.yaml rename to helm-chart/templates/serviceaccount.yaml index edb759fb1..f12253289 100644 --- a/samples/helmexample/templates/serviceaccount.yaml +++ b/helm-chart/templates/serviceaccount.yaml @@ -2,11 +2,12 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "helmexample.serviceAccountName" . }} + name: {{ include "carbon-aware-sdk.serviceAccountName" . }} labels: - {{- include "helmexample.labels" . | nindent 4 }} + {{- include "carbon-aware-sdk.labels" . | nindent 4 }} {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} +automountServiceAccountToken: false {{- end }} diff --git a/helm-chart/templates/tests/test-connection.yaml b/helm-chart/templates/tests/test-connection.yaml new file mode 100644 index 000000000..b7b3405f6 --- /dev/null +++ b/helm-chart/templates/tests/test-connection.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + name: webapi-test-connection + namespace: {{ $.Release.Namespace }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['webapi:{{ .Values.service.port }}/health'] + restartPolicy: Never diff --git a/samples/helmexample/values.yaml b/helm-chart/values.yaml similarity index 59% rename from samples/helmexample/values.yaml rename to helm-chart/values.yaml index 877485e7d..3d32c9266 100644 --- a/samples/helmexample/values.yaml +++ b/helm-chart/values.yaml @@ -1,18 +1,17 @@ -# Default values for helmexample. +# Default values for carbon-aware-sdk. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image: - repository: carbonawaretoyacr.azurecr.io/ca_0504 - pullPolicy: IfNotPresent + repository: ghcr.io/green-software-foundation/carbon-aware-sdk + #pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. - tag: "latest" + #tag: latest -imagePullSecrets: [] -nameOverride: "helm-example" -fullnameOverride: "helm-chart-example" +nameOverride: "" +fullnameOverride: "" serviceAccount: # Specifies whether a service account should be created @@ -21,7 +20,7 @@ serviceAccount: annotations: {} # The name of the service account to use. # If not set and create is true, a name is generated using the fullname template - name: "helmexample" + name: "" podAnnotations: {} @@ -47,24 +46,14 @@ ingress: # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" hosts: - - host: chart-example.local + - host: carbon-aware-sdk.local paths: - path: / pathType: ImplementationSpecific tls: [] - # - secretName: chart-example-tls + # - secretName: carbon-aware-sdk-tls # hosts: - # - chart-example.local - -monitorConfig: - liveness: - httpGet: - path: "/health" - port: "http" - readiness: - httpGet: - path: "/health" - port: "http" + # - carbon-aware-sdk.local resources: {} # We usually recommend not to specify default resources and to leave this as a conscious @@ -90,3 +79,32 @@ nodeSelector: {} tolerations: [] affinity: {} + +# /app/appsettings.json +appsettings: |- + { + "DataSources": { + "EmissionsDataSource": "ElectricityMaps", + "ForecastDataSource": "WattTime", + "Configurations": { + "WattTime": { + "Type": "WattTime", + "Username": "username", + "Password": "password", + "BaseURL": "https://api2.watttime.org/v2/", + "Proxy": { + "useProxy": true, + "url": "http://10.10.10.1", + "username": "proxyUsername", + "password": "proxyPassword" + } + }, + "ElectricityMaps": { + "Type": "ElectricityMaps", + "APITokenHeader": "auth-token", + "APIToken": "myAwesomeToken", + "BaseURL": "https://api.electricitymap.org/v3/" + } + } + } + } diff --git a/samples/helmexample/README.md b/samples/helmexample/README.md deleted file mode 100644 index 189c2ed4d..000000000 --- a/samples/helmexample/README.md +++ /dev/null @@ -1,231 +0,0 @@ -# How-To: Deploy to AKS using Helm - -## Setup Dev Environment (optional) - -The easiest way to setup your environment is to use a VSCode dev container. -Suggested setup is with the latest `debian` OS with `az CLI` and `kubectl-helm` -packages enabled. - -## Setup Resource Group in Azure - -1. Create a new Kubernetes service following the default settings -1. Create a container registry -1. Create a key vault - -## Push an image to the container registry - -The following steps illustrates how to push a webservice image in order to be -deployed in AKS using ACR (Azure Container Registry). - -1. Build a `published` image using for instancee the following - [Dockerfile](https://docs.microsoft.com/en-us/dotnet/core/docker/build-container?tabs=windows#create-the-dockerfile) - - ```sh - docker build -t myapp:v1 . - ``` - -1. Login into ACR using the username and password credentials that are needed in - order to push. See Access Keys section of the ACR Portal. - - ```sh - docker login .azurecr.io - ``` - -1. Tag the image following ACR tagging scheme - - ```sh - docker tag myapp .azurecr.io/myapp:v1 - ``` - -1. Push to ACR - - ```sh - docker push .azurecr.io/myapp:v1 - ``` - -After these steps, using Azure's Portal ACR resource an image should be -available under repositories following the naming convention mentioned above. - -### Give cluster access to ACR - -To attach the ACR to the cluster so that the image can be accessed, run - -```bash -az aks update -n -g --attach-acr -``` - -## Create a new Helm chart (optional) - -Run `helm` to ensure you have the helm CLI running properly. Then you can create -a new helm chart by running - -```bash -helm create -``` - -## Setting up the Helm chart - -Once you've got your helm chart open (whether from scratch or existing), the -main files you will likely be working with are `Chart.yaml` and `values.yaml`. - -### Chart.yaml - -In `Chart.yaml`, we won't need to make any changes but make note of the chart -`name`, as you will need to reference it in commands later on. - -### Values.yaml - -In `values.yaml`, we need to change a couple fields. In the `image` section, you -will need to set - -- The `repository` field to be `/` -- The `pullPolicy` field to be `IfNotPresent` (pulls a new image if not present) - or `Always` (pulls a new image every time). -- The `tag` field if you need a particuar tag version - -Set the `nameOverride` and `fullNameOverride` fields to make it easier to -reference your helm chart, and ensure they are not the same. - -In the `serviceAccount` section, ensure that - -- The `name` field is set to the name of the helm chart from `Chart.yaml`. - -In the `monitorConfig` section, you will need to adjust the `liveness` and -`readiness` that the helm chart will ping to ensure the sdk is ready. As a -default, you should set the path to `/health`. - -## Connecting to AKS from Helm - -To connect to AKS you need to be logged into the azure. Run `az login` and -follow the prompts to get access to your azure subscriptions. - -To set the right subscription for the service, run: - -```bash -az account set --subscription -``` - -To give credentials for the resource group to the kubernetes service, run: - -```bash -az aks get-credentials --resource-group --name -``` - -With these two commands, helm should be setup to access AKS and be able to -deploy on it. With the current setup, Helm is not directly accessing the ACR to -pull the image, put instead is going through the cluster (which is why we gave -the cluster authorized access to the ACR in the earlier section). If you do need -helm to access your ACR for any reason, you will need to register it and login -with the following - -```bash -helm registry login \ - --username \ - --password -``` - -The neccessary credentials can be found by opening your ACR in the Azure portal -and going to credentials. - -### Installing your helm chart - -To install your helm chart, you should run - -```bash -helm install / -``` - -(If you run into an error, see the [troubleshooting](#troubleshooting) section. -below.) - -### Deploying your helm chart - -If the installation was successful, helm should give you a console out message -for your to copy and paste to deploy the chart. We've replicated below for quick -reference (you will need to fill in `nameOverride` and `fullNameOverride`): - -```bash -export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=,app.kubernetes.io/instance=" -o jsonpath="{.items[0].metadata.name}") -export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") -echo "Visit http://127.0.0.1:8080 to use your application" -kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT -``` - -If the deployment works properly, you should be able to visit the link they -provide and use it to query the SDK - -## Troubleshooting - -### Error connecting to the kubernetes service - -If you get - -```text -Error: INSTALLATION FAILED: Kubernetes cluster unreachable: Get "http://localhost:8080/version": dial tcp 127.0.0.1:8080: connect: connection refused -``` - -that means that helm cannot connect to kubernetes. Helm connects to kuberentes -either via the $KUBECONFIG env variable, or (if it's not set) looks for the -default location kubectl files are location (`~/.kube/config`). This may occur -the first time to try connecting the helm chart or if you clear the -files/variables. To fix, follow the cli commands in the -[connecting to AKS](#connecting-to-aks-from-helm) section and that should -automatically generate the proper config files. - -### Error installing the helm chart - -If you get -`Error: INSTALLATION FAILED: cannot re-use a name that is still in use` when you -tried to install the helm chart, it means there is still an instance of that -chart installed. If you started this instance, you can simply skip the install -step and continue. If you're unsure that it's the right installation, or you've -made changes, first run `helm uninstall `. Once it's -uninstalled, you can redo the helm install step. - -### Error pulling image - -If there is an issue pulling the image from ACR, the pod will deploy but will -fail to start. If you check the status of the pod (using the kubectl commands -below in the azure portal) you will see the `ImagePullBackOff` status and a note -that the pod has not started. This may be for a couple reasons: - -1. The cluster isn't authorized to access the ACR registry. Ensure you've run - [this command](#give-cluster-access-to-acr). -2. The image reference in helm is incorrect. Review the Values.yaml - [section](#valuesyaml) to ensure you've got the right reference in the - image repository field. - -### Error deploying the helm chart - -If you get an error deploying the helm chart and have ensured the image is -pulling properly, one possible error may be with the liveliness and readiness -probes. If those are failing, the deployment will fail to start properly. Ensure -that the paths provided in the `deployment.yaml` file are valid and that the sdk -can actual spin up correctly. - -### Useful kubectl commands to check on cluster - -- List all deployments in all namespaces: - `kubectl get deployments --all-namespaces=true` -- List details about a specific deployment: - `kubectl describe deployment --namespace ` -- Delete a specific deployment: `kubectl delete deployment ` -- List pods: `kubectl get pods` -- Check on a specific pod: `kubectl describe pod ` -- Get logs on a specific pod: `kubectl logs ` -- Delete a specific pod: `kubectl delete pod ` - -## References - -Helm 3: [docs](https://helm.sh/docs/), -[image docs](https://helm.sh/docs/chart_best_practices/pods/#images) - -MS Docs: -[Creating an ingress controller in AKS](https://docs.microsoft.com/en-us/azure/aks/ingress-basic?tabs=azure-cli), -[Authenticate with ACR from AKS](https://docs.microsoft.com/en-us/azure/aks/cluster-container-registry-integration?tabs=azure-cli#access-with-kubernetes-secret) - -Github Issue: -[Deploying a container from ACR to AKS](https://github.com/MicrosoftDocs/azure-docs/issues/33430) - -ContainIQ: -[Troubleshooting ImagePullBackOff Error](https://www.containiq.com/post/kubernetes-imagepullbackoff) diff --git a/samples/helmexample/templates/tests/test-connection.yaml b/samples/helmexample/templates/tests/test-connection.yaml deleted file mode 100644 index d34f26fb0..000000000 --- a/samples/helmexample/templates/tests/test-connection.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: "{{ include "helmexample.fullname" . }}-test-connection" - labels: - {{- include "helmexample.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": test -spec: - containers: - - name: wget - image: busybox - command: ['wget'] - args: ['{{ include "helmexample.fullname" . }}:{{ .Values.service.port }}'] - restartPolicy: Never