Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert k8s yaml to helm chart

Right now I'm deploying applications on k8s using yaml files.

Like the one below:

apiVersion: v1
kind: Service
metadata:
  name: serviceA
  namespace: flow
spec:
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: serviceA
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: serviceA-ingress
  namespace: flow
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    kubernetes.io/ingress.class: nginx
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
  - hosts:
    - serviceA.xyz.com
    secretName: letsencrypt-prod
  rules:
  - host: serviceA.xyz.com
    http:
      paths:
      - path: /
        backend:
          serviceName: serviceA
          servicePort: 8080
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: serviceA-config
  namespace: flow
data:
  application-dev.properties: |
    spring.application.name=serviceA-main
    server.port=8080
    logging.level.org.springframework.jdbc.core=debug
    lead.pg.url=serviceB.flow.svc:8080/lead
    task.pg.url=serviceB.flow.svc:8080/task
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: serviceA-deployment
  namespace: flow
spec:
  selector:
    matchLabels:
      app: serviceA
  replicas: 1 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: serviceA
    spec:
      containers:
      - name: serviceA
        image: xyzaccount.dkr.ecr.eu-west-1.amazonaws.com/flow/test:serviceA-v1
        command: [ "java", "-jar", "-agentlib:jdwp=transport=dt_socket,address=9098,server=y,suspend=n", "serviceA-service.jar", "--spring.config.additional-location=/config/application-dev.properties" ]
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: serviceA-application-config
          mountPath: "/config"
          readOnly: true
      volumes:
      - name: serviceA-application-config
        configMap:
          name: serviceA-config
          items:
          - key: application-dev.properties
            path: application-dev.properties
      restartPolicy: Always

Is there any automated way to convert this yaml into helm charts.

Or any other workaround or sample template that I can use to achieve this.

Even if there is no any generic way, then I would like to know how to convert this specific yaml into helm chart.

Also want to know what all things should I keep configurable (I mean convert into variables) as I can't just put these resource in yaml into separate template folder and called it helm chart.

like image 807
mchawre Avatar asked Jun 17 '19 11:06

mchawre


People also ask

How do I get YAML file from Helm chart?

You can use the helm native commands to achieve this. In helm, there is a command called helm template . Using the template command you can convert any helm chart to a YAML manifest. The resultant manifest file will have all the default values set in the helm values.

Are Helm charts YAML files?

What are Helm charts? Helm Charts are simply Kubernetes YAML manifests combined into a single package that can be advertised to your Kubernetes clusters.

Does Helm use YAML?

The version field inside of the Chart. yaml is used by many of the Helm tools, including the CLI.


2 Answers

At heart a Helm chart is still just YAML so to make that a chart, just drop that file under templates/ and add a Chart.yml.

like image 165
coderanger Avatar answered Oct 05 '22 09:10

coderanger


There is no unambiguous way to map k8s YAML to a Helm chart. Because app/chart maintainer should decide:

  • which app parameters can be modified by chart users
  • which of these parameters are mandatory
  • what are default values, etc...

So creation of a Helm chart is a manual process. But it contains a lot of routine steps. For example, most of the chart creators want to:

  • remove the namespace from templates to set it with helm install -n
  • remove fields generated by k8s
  • add helm release name to resource name
  • preserve correct links between templated names
  • move some obvious parameters to values.yaml like:
    • container resources
    • service type and ports
    • configmap/secret values
    • image repo:tag

I've created a CLI called helmify to automate the steps listed above. It reads a list of k8s objects from stdin and creates a helm chart from it.

You can install it with brew brew install arttor/tap/helmify. And then use to generate charts from YAML file:

cat my-app.yaml | helmify mychart

or from directory <my_directory> containing yamls:

awk 'FNR==1 && NR!=1  {print "---"}{print}' /<my_directory>/*.yaml | helmify mychart

Both of the commands will create mychart Helm chart directory from your k8s objects similar to helm create command.

Here is a chart generated by helmify from the yaml published in the question:

mychart
├── Chart.yaml
├── templates
│   ├── _helpers.tpl
│   ├── config.yaml
│   ├── deployment.yaml
│   ├── ingress.yaml
│   └── serviceA.yaml
└── values.yaml

#values.yaml
config:
  applicationDevProperties:
    lead:
      pg:
        url: serviceB.flow.svc:8080/lead
    logging:
      level:
        org:
          springframework:
            jdbc:
              core: debug
    server:
      port: "8080"
    spring:
      application:
        name: serviceA-main
    task:
      pg:
        url: serviceB.flow.svc:8080/task
deployment:
  replicas: 1
image:
  serviceA:
    repository: xyzaccount.dkr.ecr.eu-west-1.amazonaws.com/flow/test
    tag: serviceA-v1
serviceA:
  ports:
    - port: 8080
      targetPort: 8080
  type: ClusterIP
---
# templates/config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "mychart.fullname" . }}-config
  labels:
  {{- include "mychart.labels" . | nindent 4 }}
data:
  application-dev.properties: |
    spring.application.name={{ .Values.config.applicationDevProperties.spring.application.name | quote }}
    server.port={{ .Values.config.applicationDevProperties.server.port | quote }}
    logging.level.org.springframework.jdbc.core={{ .Values.config.applicationDevProperties.logging.level.org.springframework.jdbc.core | quote }}
    lead.pg.url={{ .Values.config.applicationDevProperties.lead.pg.url | quote }}
    task.pg.url={{ .Values.config.applicationDevProperties.task.pg.url | quote }}
---
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "mychart.fullname" . }}-deployment
  labels:
  {{- include "mychart.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.deployment.replicas }}
  selector:
    matchLabels:
      app: serviceA
    {{- include "mychart.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        app: serviceA
      {{- include "mychart.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - command:
            - java
            - -jar
            - -agentlib:jdwp=transport=dt_socket,address=9098,server=y,suspend=n
            - serviceA-service.jar
            - --spring.config.additional-location=/config/application-dev.properties
          image: {{ .Values.image.serviceA.repository }}:{{ .Values.image.serviceA.tag |
                   default .Chart.AppVersion }}
          name: serviceA
          ports:
            - containerPort: 8080
          resources: {}
          volumeMounts:
            - mountPath: /config
              name: serviceA-application-config
              readOnly: true
      restartPolicy: Always
      volumes:
        - configMap:
            items:
              - key: application-dev.properties
                path: application-dev.properties
            name: {{ include "mychart.fullname" . }}-config
          name: serviceA-application-config
---
# templates/ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ include "mychart.fullname" . }}-ingress
  labels:
  {{- include "mychart.labels" . | nindent 4 }}
  annotations:
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  rules:
    - host: serviceA.xyz.com
      http:
        paths:
          - backend:
              serviceName: serviceA
              servicePort: 8080
            path: /
  tls:
    - hosts:
        - serviceA.xyz.com
      secretName: letsencrypt-prod
---
# templates/serviceA.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "mychart.fullname" . }}-serviceA
  labels:
  {{- include "mychart.labels" . | nindent 4 }}
spec:
  type: {{ .Values.serviceA.type }}
  selector:
    app: serviceA
  {{- include "mychart.selectorLabels" . | nindent 4 }}
  ports:
  {{- .Values.serviceA.ports | toYaml | nindent 2 -}}

like image 25
Artem Avatar answered Oct 05 '22 07:10

Artem