25

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.

mchawre
  • 10,744
  • 4
  • 35
  • 57
  • 2
    There is no generic/automatic way, some understanding of how the `Chart.yaml` works is needed. The basics are given by @coderanger, read [the docs](https://helm.sh/docs/developing_charts/#charts) for more info. The things you want to have as variables you will have to define yourself. – sg3s Jun 17 '19 at 14:55
  • 1
    Here is one really good tutorial for converting k8s to helm - https://www.youtube.com/watch?v=ZZVXXEyEzAs – Rahul Wagh Jan 20 '21 at 12:30

4 Answers4

11

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.

coderanger
  • 52,400
  • 4
  • 52
  • 75
  • 4
    Your answer didn't seems much aligned to my question, can you elaborate more. – mchawre Jun 17 '19 at 12:32
  • 2
    Perhaps you think a helm chart is something more complicated than it is? There is nothing to convert, you can use that as the templates data for a chart exactly as is if you want to. – coderanger Jun 17 '19 at 18:45
  • 3
    I think maybe he's asking how to covert the manifest into a template as in segregating configurable to values.yaml – codersofthedark Jul 27 '20 at 15:00
  • I started by creating a helm chart using `helm create`. The `templates` directory has a `deployment.yaml` file that is weird looking (because it is a template), are you suggesting that I overwrite that file with my current `deployment.yaml` file? – PatS Apr 20 '21 at 20:49
9

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 -}}

Artem
  • 371
  • 4
  • 11
1

https://github.com/mailchannels/palinurus/tree/master

This git repo contains a python script which will convert basic yamls to helm charts

Ast
  • 143
  • 7
1

You can use this tools, helmtrans : https://github.com/codeandcode0x/helmtrans . It can transform YAML to Helm Charts automation.

example:

➜ helmtrans yamltohelm -p [source path] -o [output path]