Skip to content
This repository has been archived by the owner on Mar 24, 2023. It is now read-only.

Commit

Permalink
helm POC
Browse files Browse the repository at this point in the history
What I Did
------------

Build out initial support for including a `helm` asset in ship.

How I Did it
------------

- Add `helm` asset, with a single implementation `local`, that points to an already-pulled-down helm chart
- `helm.ChartFetcher` impl is pretty fake for now, since we require the chart source to already be checked out via other `inline` assets
- `helm.Templater` implemented by forking out to a `helm` binary embedded in the container

**Still missing**

- github support
- first-class values support, right now workaround is to use `--set`

How to verify it
------------

- Run the example in `examples/helm/nginx.yml` and verify the chart is rendered correctly
- write a new ship yaml that uses a `helm` asset

Description for the Changelog
------------

Add initial support for inline helm charts

Picture of a Boat (not required but encouraged)
------------

![](https://previews.123rf.com/images/a8452/a84521505/a8452150500029/39901035-the-helm-of-a-sailing-ship.jpg)
  • Loading branch information
dexhorthy committed Jun 13, 2018
1 parent 6203be1 commit 7783359
Show file tree
Hide file tree
Showing 22 changed files with 960 additions and 47 deletions.
17 changes: 16 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,31 @@ RUN go get -u github.com/golang/dep/cmd/dep
RUN go get github.com/golang/mock/gomock
RUN go install github.com/golang/mock/mockgen



RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update || true && \
apt-get install -y apt-transport-https && \
apt-get update && apt-get install -y yarn
apt-get update && apt-get install -y yarn curl

RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get install -y nodejs

ENV HELM_VERSION=v2.9.1
ENV HELM_URL=https://storage.googleapis.com/kubernetes-helm/helm-v2.9.1-linux-amd64.tar.gz
ENV HELM_TGZ=helm-v2.9.1-linux-amd64.tar.gz
ENV HELM=linux-amd64/helm
ENV HELM_SHA256SUM=56ae2d5d08c68d6e7400d462d6ed10c929effac929fedce18d2636a9b4e166ba

RUN curl -fsSLO "${HELM_URL}" \
&& echo "${HELM_SHA256SUM} ${HELM_TGZ}" | sha256sum -c - \
&& tar xvf "$HELM_TGZ" \
&& mv "$HELM" "/usr/local/bin/helm-${HELM_VERSION}" \
&& ln -s "/usr/local/bin/helm-${HELM_VERSION}" /usr/local/bin/helm

ENV PROJECTPATH=/go/src/github.com/replicatedhq/ship


WORKDIR $PROJECTPATH
CMD ["/bin/bash"]
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ _mockgen:
-package docker \
github.com/replicatedhq/ship/pkg/lifecycle/render/docker \
PullURLResolver
mockgen \
-destination pkg/test-mocks/helm/chart_fetcher_mock.go \
-package helm \
github.com/replicatedhq/ship/pkg/lifecycle/render/helm \
ChartFetcher
mockgen \
-destination pkg/test-mocks/helm/templater_mock.go \
-package helm \
github.com/replicatedhq/ship/pkg/lifecycle/render/helm \
Templater
mockgen \
-destination pkg/test-mocks/helm/renderer_mock.go \
-package helm \
github.com/replicatedhq/ship/pkg/lifecycle/render/helm \
Renderer

mockgen: _mockgen fmt

Expand Down
16 changes: 15 additions & 1 deletion deploy/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
FROM alpine:latest
RUN apk add --no-cache ca-certificates && update-ca-certificates
RUN apk add --no-cache ca-certificates curl && update-ca-certificates
COPY ship /ship
ENV IN_CONTAINER 1

ENV HELM_VERSION=v2.9.1
ENV HELM_URL=https://storage.googleapis.com/kubernetes-helm/helm-v2.9.1-linux-amd64.tar.gz
ENV HELM_TGZ=helm-v2.9.1-linux-amd64.tar.gz
ENV HELM=linux-amd64/helm
ENV HELM_SHA256SUM=56ae2d5d08c68d6e7400d462d6ed10c929effac929fedce18d2636a9b4e166ba

RUN curl -fsSLO "${HELM_URL}" \
&& echo "${HELM_SHA256SUM} ${HELM_TGZ}" | sha256sum -c - \
&& tar xvf "$HELM_TGZ" \
&& mv "$HELM" "/usr/local/bin/helm-${HELM_VERSION}" \
&& ln -s "/usr/local/bin/helm-${HELM_VERSION}" /usr/local/bin/helm


LABEL "com.replicated.ship"="true"
WORKDIR /out
ENTRYPOINT [ "/ship" ]
209 changes: 209 additions & 0 deletions examples/helm/nginx.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# nginx helm chart rendering example, using k8s.io/helm/docs/examples/nginx
---
assets:
v1:
- inline:
dest: charts/src/nginx/Chart.yaml
contents: |
name: nginx
description: A basic NGINX HTTP server
version: 0.1.0
kubeVersion: ">=1.2.0"
keywords:
- http
- nginx
- www
- web
home: https://github.com/kubernetes/helm
sources:
- https://hub.docker.com/_/nginx/
maintainers:
- name: technosophos
email: mbutcher@deis.com
- inline:
dest: charts/src/nginx/templates/configmap.yaml
contents: |
# This is a simple example of using a config map to create a single page static site.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "nginx.fullname" . }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "nginx.name" . }}
data:
# When the config map is mounted as a volume, these will be created as files.
index.html: {{ .Values.index | quote }}
test.txt: test
- inline:
dest: charts/src/nginx/templates/deployment.yaml
contents: |
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
# This uses a "fullname" template (see _helpers)
# Basing names on .Release.Name means that the same chart can be installed
# multiple times into the same namespace.
name: {{ template "nginx.fullname" . }}
labels:
# The "heritage" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
# is responsible for.
heritage: {{ .Release.Service }}
# The "release" convention makes it easy to tie a release to all of the
# Kubernetes resources that were created as part of that release.
release: {{ .Release.Name }}
# This makes it easy to audit chart usage.
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "nginx.name" . }}
spec:
replicas: {{ .Values.replicaCount }}
template:
metadata:
{{- if .Values.podAnnotations }}
# Allows custom annotations to be specified
annotations:
{{ toYaml .Values.podAnnotations | indent 8 }}
{{- end }}
labels:
app: {{ template "nginx.name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: {{ template "nginx.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
# This (and the volumes section below) mount the config map as a volume.
volumeMounts:
- mountPath: /usr/share/nginx/html
name: wwwdata-volume
resources:
# Allow chart users to specify resources. Usually, no default should be set, so this is left to be a conscious
# choice to the chart users and avoids that charts don't run out of the box on, e. g., Minikube when high resource
# requests are specified by default.
{{ toYaml .Values.resources | indent 12 }}
{{- if .Values.nodeSelector }}
nodeSelector:
# Node selectors can be important on mixed Windows/Linux clusters.
{{ toYaml .Values.nodeSelector | indent 8 }}
{{- end }}
volumes:
- name: wwwdata-volume
configMap:
name: {{ template "nginx.fullname" . }}
- inline:
dest: charts/src/nginx/templates/_helpers.tpl
contents: |
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "nginx.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
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).
*/}}
{{- define "nginx.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
- inline:
dest: charts/src/nginx/templates/service.yaml
contents: |
apiVersion: v1
kind: Service
metadata:
{{- if .Values.service.annotations }}
annotations:
{{ toYaml .Values.service.annotations | indent 4 }}
{{- end }}
labels:
app: {{ template "nginx.name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: {{ template "nginx.fullname" . }}
spec:
# Provides options for the service so chart users have the full choice
type: "{{ .Values.service.type }}"
clusterIP: "{{ .Values.service.clusterIP }}"
{{- if .Values.service.externalIPs }}
externalIPs:
{{ toYaml .Values.service.externalIPs | indent 4 }}
{{- end }}
{{- if .Values.service.loadBalancerIP }}
loadBalancerIP: "{{ .Values.service.loadBalancerIP }}"
{{- end }}
{{- if .Values.service.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{ toYaml .Values.service.loadBalancerSourceRanges | indent 4 }}
{{- end }}
ports:
- name: http
port: {{ .Values.service.port }}
protocol: TCP
targetPort: http
{{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }}
nodePort: {{ .Values.service.nodePort }}
{{- end }}
selector:
app: {{ template "nginx.name" . }}
release: {{ .Release.Name }}
- inline:
dest: charts/src/nginx/values.yaml
contents: |
# Default values for nginx.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
replicaCount: 1
restartPolicy: Never
# Evaluated by the post-install hook
sleepyTime: "10"
index: >-
<h1>Hello</h1>
<p>This is a test</p>
image:
repository: nginx
tag: 1.11.0
pullPolicy: IfNotPresent
service:
annotations: {}
clusterIP: ""
externalIPs: []
loadBalancerIP: ""
loadBalancerSourceRanges: []
type: ClusterIP
port: 8888
nodePort: ""
podAnnotations: {}
resources: {}
nodeSelector: {}
- helm:
dest: charts/rendered/
local:
chart_root: charts/src/nginx

lifecycle:
v1:
- render: {}
2 changes: 1 addition & 1 deletion hack/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ hack/docs

### NOTE

This is totally copy-pasted from [the support bundle docs generation](https://github.com/replicatedcom/support-bundle) so there may be some extra stuff that doesn't make sense but didn't yet get removed.
This is totally copy-pasted from [the support bundle docs generation](https://github.com/replicatedhq/support-bundle) so there may be some extra stuff that doesn't make sense but didn't yet get removed.

#### TLDR:

Expand Down
26 changes: 22 additions & 4 deletions pkg/api/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ type AssetShared struct {
type Asset struct {
Inline *InlineAsset `json:"inline,omitempty" yaml:"inline,omitempty" hcl:"inline,omitempty"`
Docker *DockerAsset `json:"docker,omitempty" yaml:"docker,omitempty" hcl:"docker,omitempty"`
Github *GithubAsset `json:"github,omitempty" yaml:"github,omitempty" hcl:"github,omitempty"`
GitHub *GitHubAsset `json:"github,omitempty" yaml:"github,omitempty" hcl:"github,omitempty"`
Helm *HelmAsset `json:"helm,omitempty" yaml:"helm,omitempty" hcl:"helm,omitempty"`
}

// InlineAsset is an asset whose contents are specified directly in the Spec
Expand All @@ -30,18 +31,35 @@ type InlineAsset struct {
Contents string `json:"contents" yaml:"contents" hcl:"contents"`
}

// DockerAsset is an asset whose contents are specified directly in the Spec
// DockerAsset is an asset that declares a docker image
type DockerAsset struct {
AssetShared `json:",inline" yaml:",inline" hcl:",inline"`
Image string `json:"image" yaml:"image" hcl:"image"`
Source string `json:"source" yaml:"source" hcl:"source"`
}

// GithubAsset is an asset whose contents are specified directly in the Spec
type GithubAsset struct {
// GitHubAsset is an asset whose contents are specified directly in the Spec
type GitHubAsset struct {
AssetShared `json:",inline" yaml:",inline" hcl:",inline"`
Repo string `json:"repo" yaml:"repo" hcl:"repo"`
Ref string `json:"ref" yaml:"ref" hcl:"ref"`
Path string `json:"path" yaml:"path" hcl:"path"`
Source string `json:"source" yaml:"source" hcl:"source"`
}

// HelmAsset is an asset that declares a helm chart on github
type HelmAsset struct {
AssetShared `json:",inline" yaml:",inline" hcl:",inline"`
Values map[string]string `json:"values" yaml:"values" hcl:"values"`
HelmOpts []string `json:"helm_opts" yaml:"helm_opts" hcl:"helm_opts"`
// Local is an escape hatch, most impls will use github or some sort of ChartMuseum thing
Local *LocalHelmOpts `json:"local,omitempty" yaml:"local,omitempty" hcl:"local,omitempty"`
// coming soon
//GitHub *GitHubAsset `json:"github" yaml:"github" hcl:"github"`
}

// LocalHelmOpts specifies a helm chart that should be templated
// using other assets that are already present at `ChartRoot`
type LocalHelmOpts struct {
ChartRoot string `json:"chart_root" yaml:"chart_root" hcl:"chart_root"`
}
6 changes: 2 additions & 4 deletions pkg/api/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ type Step struct {
Render *Render `json:"render,omitempty" yaml:"render,omitempty" hcl:"render,omitempty"`
}

// Message is a lifeycle step to
// Message is a lifeycle step to print a message
type Message struct {
Contents string `json:"contents" yaml:"contents" hcl:"contents"`
Level string `json:"level,omitempty" yaml:"level,omitempty" hcl:"level,omitempty"`
}

// Render is a lifeycle step to
// Render is a lifeycle step to collect config and render assets
type Render struct {
SkipPlan bool `json:"skip_plan" yaml:"skip_plan" hcl:"skip_plan"`
SkipStateWarning bool `json:"skip_state_warning" yaml:"skip_state_warning" hcl:"skip_state_warning"`
}
2 changes: 1 addition & 1 deletion pkg/lifecycle/render/config/daemonresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (d *DaemonResolver) ResolveConfig(
}
}

return nil, errors.New("couldn't find current render Step")
return nil, errors.New("couldn't find current render Execute")
}

func (d *DaemonResolver) awaitConfigSaved(ctx context.Context, daemonExitedChan chan error) (map[string]interface{}, error) {
Expand Down
Loading

0 comments on commit 7783359

Please sign in to comment.