{"id":818,"date":"2020-03-30T19:00:00","date_gmt":"2020-03-30T19:00:00","guid":{"rendered":"http:\/\/bullyrooks.com\/index.php\/2020\/04\/10\/simple-spring-boot-service-to-kubernetes-application-step-19-944a76415384\/"},"modified":"2021-02-04T02:14:54","modified_gmt":"2021-02-04T02:14:54","slug":"simple-spring-boot-service-to-kubernetes-application-step-19-944a76415384","status":"publish","type":"post","link":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-19-944a76415384\/","title":{"rendered":"Put the UI in to Helm"},"content":{"rendered":"\n<p class=\"graf graf--p graf-after--h3 graf--trailing\" id=\"b22a\">Lets take the docker image we just created and wrap it with helm so that we have an easy way to deploy our application.<\/p>\n\n\n\n<h3 class=\"graf graf--h3 graf--leading wp-block-heading\" id=\"6f41\">Create Helm Chart Templates<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"8c08\">We\u2019ve created helm charts before, so lets create a <code class=\"markup--code markup--p-code\">helm <\/code>directory at the frontend root. Then run helm create in that directory<\/p>\n\n\n\n<pre id=\"8aa0\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>helm create medium-customer-manager<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"22ae\">That should build out more than we need. We really only need a few files:<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"1d99\"><code class=\"markup--code markup--p-code\">templates\/deployment.yaml<\/code><\/p>\n\n\n\n<pre id=\"633f\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: \"{{  .Chart.Name }}-deployment\"\n  labels:\n    chart: '{{ .Chart.Name }}-{{ .Chart.Version | replace \"+\" \"_\" }}'\nspec:\n  replicas: {{ .Values.replicaCount }}\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxUnavailable: 0\n      maxSurge: 1\n  selector:\n    matchLabels:\n      app: \"{{  .Chart.Name }}-selector\"\n      version: \"current\"\n  template:\n    metadata:\n      labels:\n        app: \"{{  .Chart.Name }}-selector\"\n        version: \"current\"\n    spec:\n      imagePullSecrets:\n        - name: regcred\n      containers:\n        - name: \"{{  .Chart.Name  }}\"\n          image: \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\"\n          imagePullPolicy: {{ .Values.image.pullPolicy }}\n          volumeMounts:\n            - name: data\n              mountPath: \/data\n            {{- if and (eq .Values.config.type \"file\") (hasKey .Values.config \"content\") }}\n            - name: config-file\n              mountPath: \/usr\/share\/nginx\/html\/config.js\n              subPath: config.js\n            {{- end }}\n          ports:\n            - name: http\n              containerPort: {{ .Values.containerPort }}\n              protocol: TCP\n          env:\n            - name: PORT\n              value : \"{{ .Values.service.servicePort }}\"\n      volumes:\n        - name: data\n          emptyDir: {}\n        {{- if and (eq .Values.config.type \"file\") (hasKey .Values.config \"content\") }}\n        - name: config-file\n          configMap:\n            name: {{ .Chart.Name }}-config\n        {{- end }}<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"9e16\"><code class=\"markup--code markup--p-code\">template\/service.yaml<\/code><\/p>\n\n\n\n<pre id=\"84ff\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>apiVersion: v1\nkind: Service\nmetadata:\n  annotations:\n    prometheus.io\/scrape: 'true'\n  name: \"{{  .Chart.Name }}-service\"\n  labels:\n    chart: \"{{ .Chart.Name }}-{{ .Chart.Version | replace \"+\" \"_\" }}\"\nspec:\n  type: {{ .Values.service.type }}\n  ports:\n  - name: http\n    port: {{ .Values.service.httpPort }}\n    targetPort: http\n  {{- if hasKey .Values.service \"nodePort\" }}\n    nodePort: {{ .Values.service.nodePort }}\n  {{- end }}\n  selector:\n    app: \"{{  .Chart.Name }}-selector\"<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"1025\"><code class=\"markup--code markup--p-code\">template\/customer-manager-configmap.yaml<\/code><\/p>\n\n\n\n<pre id=\"e6d5\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>{{- if and ( eq .Values.config.type \"file\") (hasKey .Values.config \"content\") }}\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Chart.Name }}-config\n  namespace: {{ .Release.Namespace | quote }}\ndata:\n  config.js:\n    {{ toYaml .Values.config.content | indent 4  }}\n{{- end }}<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"f612\"><code class=\"markup--code markup--p-code\">Chart.yaml<\/code><\/p>\n\n\n\n<pre id=\"f727\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>apiVersion: v2\nname: medium-customer-manager\ndescription: A Helm chart for Kubernetes\ntype: application\nversion: 1.0.0<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"7c50\">values.yaml<\/p>\n\n\n\n<pre id=\"7f90\" class=\"wp-block-code graf graf--pre graf-after--p\"><code><em class=\"markup--em markup--pre-em\"># This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n<\/em>replicaCount: 1\nimage:\n  repository: r.cfcr.io\/docketdynamics\/medium-customer-manager\n  tag: \"5556008\"\n  pullPolicy: IfNotPresent\ncontainerPort: 80\nservice:\n  enabled: true\n  httpPort: 80\n  nodePort: 30002\n  type: NodePort\n\nconfig:\n<em class=\"markup--em markup--pre-em\">## Currently only supports file\n<\/em>type: file\n<em class=\"markup--em markup--pre-em\">## Contents of config in YAML\n<\/em>content: |-\n    window.REACT_APP_CUSTOMER_HOST='http:\/\/172.18.51.90\/:30001'<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"a9bd\">Again, you can see that we\u2019re hardcoding in our customer host, which isn\u2019t ideal, but it will get us moving forward. We\u2019ll eventually replace that with an ingress.<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"782a\">The only interesting part is how we\u2019re writing the configuration. We\u2019re following a similar pattern to the spring app where we write a configmap and then use the configmap to write out a configuration file into the pod.<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"0191\">Which reminds me that we need to update our front end application to support that.<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"1a21\">Create <code class=\"markup--code markup--p-code\">public\/config.js<\/code><\/p>\n\n\n\n<pre id=\"1e67\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>window.REACT_APP_CUSTOMER_HOST='HTTP:\/\/localhost:10000'<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"f022\">which is a placeholder file that will eventually be overwritten. Again, this isn\u2019t how we\u2019re going to solve our long term problem, but it will allow us to deploy and test.<\/p>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--p wp-block-heading\" id=\"0348\">Deploy and&nbsp;Test<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"fdaf\">Deploy our front end with<\/p>\n\n\n\n<pre id=\"3974\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>helm install cust-mgr helm\/medium-customer-manager<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"38e4\">Which should find our image we just build in the last section. We can hit our application at <code class=\"markup--code markup--p-code\">http:\/\/&lt;minikube ip&gt;:30002\/<\/code><\/p>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--p wp-block-heading\" id=\"d7c0\">Helm Chart Packaging and Publishing<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"7e66\">Lets add the automation to the pipeline to package the helm chart and publish to our chart registry. Add these steps to the pipeline:<\/p>\n\n\n\n<pre id=\"7b87\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>stages:\n...\n- \"helmpublish\"<\/code><\/pre>\n\n\n\n<pre id=\"2746\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"49ed\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>  HelmChartGetVersion:\n    title: Get Helm Chart Version\n    stage: helmpublish\n    image: codefresh\/cfstep-helm\n    working_directory: '\/codefresh\/volume\/medium-customer-manager'\n    environment:\n      - CHART_PATH=helm\/medium-customer-manager\n      - CHART_NAME=medium-customer-manager\n    commands:\n      - export ACTION=auth\n      - source \/opt\/bin\/release_chart\n      - helm repo add default ${{CF_CTX_CF_HELM_DEFAULT_URL}}\n      - yq .version ${CHART_PATH}\/Chart.yaml\n      - export CURRENT_CHART_VERSION=`helm search default\/${CHART_NAME} | awk 'FNR==2{print $2}' || yq .version ${CHART_PATH}\/Chart.yaml`\n      - echo $CURRENT_CHART_VERSION\n      - cf_export NEW_CHART_VERSION=`echo \"${CURRENT_CHART_VERSION}\" | awk -F. '{$NF = $NF + 1;} 1' | sed 's\/ \/.\/g'`\n      - echo $NEW_CHART_VERSION\n  HelmChartUpdate:\n    title: Update Helm Chart Version\n    stage: helmpublish\n    image: gksoftware\/yq\n    working_directory: '\/codefresh\/volume\/medium-customer-manager'\n    environment:\n      - CHART_PATH=helm\/medium-customer-manager\n      - YAML_PATH=image.tag\n    commands: \n      - echo $NEW_CHART_VERSION\n      - yq w -i ${CHART_PATH}\/Chart.yaml version ${NEW_CHART_VERSION}\n      - echo $CF_SHORT_REVISION\n      - yq w -i ${CHART_PATH}\/values.yaml ${YAML_PATH} '\"${{CF_SHORT_REVISION}}\"'\n  HelmChartPush:\n      title: Push Helm Chart to Chart Repository\n      stage: helmpublish\n      image: codefresh\/cfstep-helm\n      working_directory: '\/codefresh\/volume\/medium-customer-manager'\n      environment:\n        - CHART_REF=helm\/medium-customer-manager\/\n        - ACTION=push<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"ccaf\">Make sure to add the helm registry as and environment variable to your build so that the pipeline can publish the chart.<\/p>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--p wp-block-heading\" id=\"dedb\">Commit<\/h3>\n\n\n\n<pre id=\"66ab\" class=\"wp-block-preformatted graf graf--pre graf-after--h3\">git checkout -b helm\ngit add .\ngit commit -m \"helm chart\"\ngit push\ngit checkout master\ngit merge helm\ngit push<\/pre>\n","protected":false},"excerpt":{"rendered":"<div class=\"entry-summary\">\nLets take the docker image we just created and wrap it with&hellip;\n<\/div>\n<div class=\"link-more\"><a href=\"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-19-944a76415384\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &ldquo;Put the UI in to Helm&rdquo;<\/span>&hellip;<\/a><\/div>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[41],"tags":[79,81],"course":[40],"class_list":["post-818","post","type-post","status-publish","format-standard","hentry","category-software-development","tag-helm","tag-helm-chart","course-spring-with-kubernetes","entry"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":823,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-21-6986a29db37a\/","url_meta":{"origin":818,"position":0},"title":"Simplify Deployment","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"Now that we have multiple components lets simplify our deployment so that we can deploy our complete application in one step. Create an Umbrella\u00a0Chart Create a new git repository called medium-application. This is the repository that will house the helm umbrella chart. Create a directory called helm and run helm\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1176,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/01\/04\/cloud-kube-helm-initialization-and-chart-publishing\/","url_meta":{"origin":818,"position":1},"title":"Cloud Kube | Helm Initialization and Chart Publishing","author":"Bullyrook","date":"January 4, 2022","format":false,"excerpt":"Now that we're producing versioned docker images into our registry lets get helm setup and publish versioned charts. This will allow us to deploy fully configured services into kubernetes. Helm Init I'm assuming that helm is already installed in your development environment, so I'm not going to cover installing it.\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-25.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-25.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-25.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":836,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-11-636b842a3c0f\/","url_meta":{"origin":818,"position":2},"title":"Helm for Deployment","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"We\u2019re about ready to deploy into kubernetes. However, deployment is not exactly straightforward. There are a lot of configuration files that we need to create and maintain in order to explain to the container management system how to deploy our application. We can use tools like kubectl to promote these\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":817,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-20-fe28a586cdc6\/","url_meta":{"origin":818,"position":3},"title":"Creating an Ingress in Kubernetes","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"We\u2019ve got multiple service available for deployment now. Lets allow them to communicate internally and externally with the cluster. We\u2019ll do that by creating an ingress. Current State of Our Application We\u2019re using our services as nodeports which allows us to expose an external port that will map to the\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":822,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-13-c3d437bb7570\/","url_meta":{"origin":818,"position":4},"title":"Automating Deployment (for CICD)","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"Now that we\u2019ve deployed our application, lets reduce some of the manual steps and make our deployments more reproducible with the intent of eventually making them automated for CI\/CD. Publish our Chart to the Chart Repository Normally, we would need to create a helm chart repository, however, codefresh has given\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1188,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/01\/04\/cloud-kube-setup-cloud-hosting\/","url_meta":{"origin":818,"position":5},"title":"Cloud Kube | Setup Cloud Hosting","author":"Bullyrook","date":"January 4, 2022","format":false,"excerpt":"We've got a helm chart and associated docker image. Now we're going to setup a cloud kubernetes provider to deploy our application to. Okteto offers a very generous kubernetes hosting platform that's free for small developer projects. Setup Okteto First register on okteto by creating an account via your github\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-31.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-31.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-31.png?resize=700%2C400&ssl=1 2x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/818","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/comments?post=818"}],"version-history":[{"count":3,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/818\/revisions"}],"predecessor-version":[{"id":913,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/818\/revisions\/913"}],"wp:attachment":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/media?parent=818"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/categories?post=818"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/tags?post=818"},{"taxonomy":"course","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/course?post=818"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}