Published on

How To Debug Helm Installs

Authors

When working with Helm charts it can take a bit of fiddling with chart values until you get it right. To debug this process I copy the values.yaml from the original chart and tweak these values.

To get the chart's values file:

  1. Download the Helm chart for example helm fetch stable/gocd -d .
    1. This will download the chart for stable/gocd to the current directory
  2. The chart downloads as a tar which you will need to untar and then copy the values.yaml somewhere
  3. Open the copied file up and delete the values you are not interested in and change the values for the ones you want to try out
    1. Helm will use defaults for values you do not specify
    2. The default values are those that were in the original values.yaml file or if the given chart does something based on a given value in its templates

You can test whether a chart runs without errors using a provided values.yaml file by doing a dry run as follows:

> helm install -f values.yaml stable/gocd --name gocd --namespace pipeline --dry-run
NAME:   gocd

If this release already exists you will get the following error when trying to do a dry run:

Error: a release named gocd already exists.
Run: helm ls --all gocd; to check the status of the release
Or run: helm del --purge gocd; to delete it

If you want to see what is going with Helm in terms of how it is resolving values in the templates then use --dry-run and --debug as below:

> helm install -f values.yaml stable/gocd --name gocd --namespace pipeline --dry-run --debug
[debug] Created tunnel using local port: '38721'

[debug] SERVER: "127.0.0.1:38721"

[debug] Original chart version: ""
[debug] Fetched stable/gocd to /home/youruser/.helm/cache/archive/gocd-1.2.0.tgz

[debug] CHART PATH: /home/youruser/.helm/cache/archive/gocd-1.2.0.tgz

NAME:   gocd
REVISION: 1
RELEASED: Thu Jul 26 17:03:33 2018
CHART: gocd-1.2.0
USER-SUPPLIED VALUES:
server:
  persistence:
    storageClassName: gluster

COMPUTED VALUES:
agent:
  env:
    agentAutoRegisterEnvironemnts: null
    agentAutoRegisterHostname: null
    agentAutoRegisterKey: null
    agentAutoRegisterResources: null
    goAgentBootstrapperArgs: null
    goAgentBootstrapperJvmArgs: null
    goAgentSystemProperties: null
    goServerUrl: null
  healthCheck:
    enabled: false
    failureThreshold: 60
    initialDelaySeconds: 60
    periodSeconds: 60
  image:
    pullPolicy: IfNotPresent
    repository: gocd/gocd-agent-alpine-3.6
    tag: null
  nodeSelector: {}
  persistence:
    accessMode: ReadWriteOnce
    enabled: false
    existingClaim: null
    pvSelector: null
    size: 1Gi
    subpath:
      dockerEntryPoint: scripts
      homego: homego
  replicaCount: 0
  resources: {}
rbac:
  apiVersion: v1beta1
  create: true
  roleRef: null
server:
  enabled: true
  env:
    extraEnvVars:
    - name: GOCD_PLUGIN_INSTALL_kubernetes-elastic-agents
      value: https://github.com/gocd/kubernetes-elastic-agents/releases/download/v1.0.1/kubernetes-elastic-agent-1.0.1-107.jar
    - name: GOCD_PLUGIN_INSTALL_docker-registry-artifact-plugin
      value: https://github.com/gocd/docker-registry-artifact-plugin/releases/download/1.0.0/docker-registry-artifact-plugin-1.0.0-3.jar
    goServerSystemProperties: null
  healthCheck:
    failureThreshold: 10
    initialDelaySeconds: 90
    periodSeconds: 15
  image:
    pullPolicy: IfNotPresent
    repository: gocd/gocd-server
    tag: null
  ingress:
    annotations: null
    enabled: true
    tls: null
  nodeSelector: {}
  persistence:
    accessMode: ReadWriteOnce
    enabled: true
    existingClaim: null
    pvSelector: null
    size: 2Gi
    storageClassName: gluster
    subpath:
      dockerEntryPoint: scripts
      godata: godata
      homego: homego
  resources: {}
  service:
    annotations: null
    httpPort: 8153
    httpsPort: 8154
    nodeHttpPort: null
    nodeHttpsPort: null
    type: NodePort
  shouldPreconfigure: true
serviceAccount:
  create: true
  name: null

HOOKS:
---
# gocd-test-gpk0a
apiVersion: v1
kind: Pod
metadata:
  name: "gocd-test-gpk0a"
  labels:
    app: gocd
    chart: "gocd-1.2.0"
    release: "gocd"
    heritage: "Tiller"
  annotations:
    "helm.sh/hook": test-success
spec:
  initContainers:
    - name: "test-framework"
      image: "dduportal/bats:0.4.0"
      command:
        - "bash"
        - "-c"
        - |
          set -ex
          # copy bats to tools dir
          cp -R /usr/local/libexec/ /tools/bats/
      volumeMounts:
        - mountPath: /tools
          name: tools
  containers:
    - name: gocd-ui-test
      image: "gocddev/gocd-helm-build:v0.1.0"
      command: ["/tools/bats/bats", "-t", "/tests/run.sh"]
      volumeMounts:
        - mountPath: /tests
          name: tests
          readOnly: true
        - mountPath: /tools
          name: tools
  volumes:
    - name: tests
      configMap:
        name: gocd-tests
    - name: tools
      emptyDir: {}
  restartPolicy: Never
MANIFEST:

---
# Source: gocd/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: gocd
  labels:
    app: gocd
    chart: "gocd-1.2.0"
    release: "gocd"
    heritage: "Tiller"
data:
  preconfigure_server.sh: |-
    #!/bin/bash

    SERVICE_ACCOUNT_PATH=/var/run/secrets/kubernetes.io/serviceaccount
    KUBE_TOKEN=$(<${SERVICE_ACCOUNT_PATH}/token)

    while true
    do
      status_code=$(curl 'http://localhost:8153/go/api/v1/health' -o /dev/null -w "%{http_code}")
      if [ $status_code == 200 ]; then
        break
      fi
      sleep 10
    done

    set -e

    echo "checking if server has already been configured" >> /godata/logs/preconfigure.log

    if [ -f /godata/logs/preconfigure_complete.log ]
    then
      echo "Existing server configuration found in cruise-config.xml. Skipping preconfigure_server scripts." >> /godata/logs/preconfigure.log
      exit 0
    fi

    echo "No configuration found in cruise-config.xml. Using default preconfigure_server scripts to configure server" >> /godata/logs/preconfigure.log

    echo "Trying to create an elastic profile now." >> /godata/logs/preconfigure.log

    (curl --fail -i 'http://localhost:8153/go/api/elastic/profiles' \
      -H 'Accept: application/vnd.go.cd.v1+json' \
      -H 'Content-Type: application/json' \
      -X POST -d '{
        "id": "demo-app",
        "plugin_id": "cd.go.contrib.elasticagent.kubernetes",
        "properties": [
          {
            "key": "Image",
            "value": "gocd/gocd-agent-docker-dind:v18.7.0"
          },
          {
            "key": "PodConfiguration",
            "value": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: pod-name-prefix-{\{ POD_POSTFIX }\}\n  labels:\n    app: web\nspec:\n  containers:\n    - name: gocd-agent-container-{\{ CONTAINER_POSTFIX }\}\n      image: {\{ GOCD_AGENT_IMAGE }\}:{\{ LATEST_VERSION }\}\n      securityContext:\n        privileged: true"
          },
          {
            "key": "SpecifiedUsingPodConfiguration",
            "value": "false"
          },
          {
            "key": "Privileged",
            "value": "true"
          }
        ]
      }' >> /godata/logs/preconfigure.log)

    echo "Trying to configure plugin settings." >> /godata/logs/preconfigure.log

    (curl --fail -i 'http://localhost:8153/go/api/admin/plugin_settings' \
      -H 'Accept: application/vnd.go.cd.v1+json' \
      -H 'Content-Type: application/json' \
      -X POST -d '{
        "plugin_id": "cd.go.contrib.elasticagent.kubernetes",
        "configuration": [
          {
            "key": "go_server_url",
            "value": "https://gocd-server:8154/go"
          },
          {
            "key": "kubernetes_cluster_url",
            "value": "https://'$KUBERNETES_SERVICE_HOST':'$KUBERNETES_SERVICE_PORT_HTTPS'"
          },
          {
            "key": "namespace",
            "value": "pipeline"
          },
          {
            "key": "security_token",
            "value": "'$KUBE_TOKEN'"
          }
        ]
      }' >> /godata/logs/preconfigure.log)

    echo "Trying to creating a hello world pipeline." >> /godata/logs/preconfigure.log

    (curl --fail -i 'http://localhost:8153/go/api/admin/pipelines' \
      -H 'Accept: application/vnd.go.cd.v5+json' \
      -H 'Content-Type: application/json' \
      -X POST -d '{ "group": "sample",
                    "pipeline": {
                      "label_template": "${COUNT}",
                      "name": "hello_world",
                      "materials": [
                        {
                          "type": "git",
                          "attributes": {
                            "url": "https://github.com/gocd-contrib/getting-started-repo",
                            "shallow_clone": true
                          }
                        }
                      ],
                      "stages": [
                        {
                          "name": "default_stage",
                          "jobs": [
                            {
                              "name": "default_job",
                              "elastic_profile_id": "demo-app",
                              "tasks": [
                                {
                                  "type": "exec",
                                  "attributes": {
                                    "command": "echo",
                                    "arguments": [
                                      "Hello World"
                                    ]
                                  }
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  }' >> /godata/logs/preconfigure.log )

    echo "Unpausing the pipeline." >> /godata/logs/preconfigure.log

    (curl --fail -i 'http://localhost:8153/go/api/pipelines/hello_world/unpause' \
           -H 'Accept: application/vnd.go.cd.v1+json' \
           -H 'X-GoCD-Confirm: true' \
           -X POST >> /godata/logs/preconfigure.log)

    echo "Done preconfiguring the GoCD server" > /godata/logs/preconfigure_complete.log
---
# Source: gocd/templates/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: gocd-tests
  labels:
    app: gocd
    chart: "gocd-1.2.0"
    release: "gocd"
    heritage: "Tiller"
data:
  run.sh: |-
    @test "Testing GoCD UI is accessible" {
        curl --connect-timeout 10 --retry 12 --retry-delay 10 --retry-max-time 90 "http://gocd-server:8153/go/auth/login"
    }

    @test "Testing GoCD application is accessible through service" {
      curl --retry 2 --retry-delay 10 --retry-max-time 90 http://gocd-server:8153/go
    }
---
# Source: gocd/templates/gocd-server-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: gocd-server
  labels:
    app: gocd
    chart: "gocd-1.2.0"
    release: "gocd"
    heritage: "Tiller"
    component: server
spec:
  accessModes:
    - "ReadWriteOnce"
  resources:
    requests:
      storage: "2Gi"
---
# Source: gocd/templates/gocd-ea-service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: gocd
  labels:
    chart: "gocd-1.2.0"
    app: "gocd"
    heritage: "Tiller"
    release: "gocd"
---
# Source: gocd/templates/gocd-ea-cluster-role.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: gocd
  labels:
    chart: "gocd-1.2.0"
    app: "gocd"
    heritage: "Tiller"
    release: "gocd"
rules:
- apiGroups: [""]
  resources:
  - pods
  - pods/log
  verbs: ["*"]
- apiGroups: [""]
  resources:
  - nodes
  verbs: ["get", "list"]
- apiGroups: [""]
  resources:
  - events
  verbs: ["list", "watch"]
- apiGroups: [""]
  resources:
  - namespaces
  verbs: ["list", "get"]
---
# Source: gocd/templates/gocd-ea-cluster-role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: gocd
  labels:
    chart: "gocd-1.2.0"
    app: "gocd"
    heritage: "Tiller"
    release: "gocd"
subjects:
- kind: ServiceAccount
  name: gocd
  namespace: pipeline
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: gocd
---
# Source: gocd/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: gocd-server
  annotations:
  labels:
    app: gocd
    chart: "gocd-1.2.0"
    release: "gocd"
    heritage: "Tiller"
    component: server
spec:
  type: NodePort

  ports:
    - port: 8153
      targetPort: 8153
      protocol: TCP
      name: http

    - port: 8154
      targetPort: 8154
      protocol: TCP
      name: https
  selector:
    app: gocd
    release: "gocd"
    component: server
---
# Source: gocd/templates/gocd-agent-deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: gocd-agent
  labels:
    app: gocd
    chart:  "gocd-1.2.0"
    release: "gocd"
    heritage: "Tiller"
    component: agent
spec:
  replicas: 0
  selector:
    matchLabels:
      app: gocd
      release: "gocd"
      component: agent
  template:
    metadata:
      labels:
        app: gocd
        release: "gocd"
        component: agent
    spec:
      containers:
        - name: gocd-agent
          image: "gocd/gocd-agent-alpine-3.6:v18.7.0"
          imagePullPolicy: IfNotPresent
          resources:
            {}

          env:
            - name: GO_SERVER_URL
              value: "https://gocd-server:8154/go"
---
# Source: gocd/templates/gocd-server-deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: gocd-server
  labels:
    app: gocd
    chart: "gocd-1.2.0"
    release: "gocd"
    heritage: "Tiller"
    component: server
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: gocd
      release: "gocd"
      component: server
  template:
    metadata:
      labels:
        app: gocd
        release: "gocd"
        component: server
    spec:
      serviceAccountName: gocd
      volumes:
        - name: goserver-vol
          persistentVolumeClaim:
            claimName: gocd-server
        - name: config-vol
          configMap:
            name: gocd
      containers:
        - name: gocd-server
          image: "gocd/gocd-server:v18.7.0"
          imagePullPolicy: IfNotPresent
          env:
            - name: GOCD_PLUGIN_INSTALL_kubernetes-elastic-agents
              value: https://github.com/gocd/kubernetes-elastic-agents/releases/download/v1.0.1/kubernetes-elastic-agent-1.0.1-107.jar
            - name: GOCD_PLUGIN_INSTALL_docker-registry-artifact-plugin
              value: https://github.com/gocd/docker-registry-artifact-plugin/releases/download/1.0.0/docker-registry-artifact-plugin-1.0.0-3.jar

          ports:
            - containerPort: 8153
            - containerPort: 8154
          livenessProbe:
            httpGet:
              path: /go/api/v1/health
              port: 8153
            initialDelaySeconds: 90
            periodSeconds: 15
            failureThreshold: 10
          readinessProbe:
            httpGet:
              path: /go/api/v1/health
              port: 8153
            initialDelaySeconds: 90
            periodSeconds: 15
            failureThreshold: 10
          volumeMounts:
            - name: goserver-vol
              mountPath: /godata
              subPath: godata
            - name: goserver-vol
              mountPath: /home/go
              subPath: homego
            - name: goserver-vol
              mountPath: /docker-entrypoint.d
              subPath: scripts
            - name: config-vol
              mountPath: /preconfigure_server.sh
              subPath: preconfigure_server.sh
          lifecycle:
            postStart:
              exec:
                command: ["/bin/bash","/preconfigure_server.sh"]
          resources:
            {}
---
# Source: gocd/templates/ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: gocd-server
  labels:
    app: gocd
    chart: "gocd-1.2.0"
    release: "gocd"
    heritage: "Tiller"
    component: server
  annotations:
spec:
  backend:
    serviceName: gocd-server
    servicePort: 8153
  rules: