xx
Highly customizable GitOps pipeline built with Helm
APPENDIX: The end of Kustomize vs Helm argument
- Helm is a package manager for K8s
- "Package" is called "Chart" in Helm
WHAT: Auditability(Every change is git-trackable) / Security(less priv in CI) HOW: Pull desired state / Sync K8s resources Git → Cluster
flux
fetches git commits and reconsile K8s resources.helm-operator
reconcilesHelmRelease
resources to reconsile K8s resources.
- Fetches git commits to reconcile K8s resources
- Plug-in any K8s manifests builder (kustomize, helm, ksonnet, kubecfg, etc.)
PLUG: Wanna declaratively manage Argo CD projects? Use the community Helm chart
- Limited Customizability
- High Number of Total Moving-Parts
flux
and argocd
has limited extension points.
ex) argocd
supports custom "hooks".
- But the deployment is hard-coded to
kubectl apply
. - How to
helm install
it?
Worth maintaining both CI and CD systems separately? Your team size?
CI (lint, diff, test on PUSH): Travis, CircleCI, Concourse, Jenkins, Argo CI, ...
CD (deploy/sync/reconcile on PULL): Flux, Argo CD, Spinnaker, ...
- Flux
- Argo CD
- MISSING PIECE = Single customizable system that handles both CI and CD
brigade
is K8s scripting system- Basically CI system whose pipelines are written in JavaScript(Turing-Complete!)
https://github.com/brigadecore/brigade
-
brigade(an open, event-driven K8s scripting platform) as an universal workflow engine that runs both CI and GitOps/CD pipelines
-
helmfile to declaratively manage all the apps on K8s. Use whatever you like tho.
- Write the desired state of your cluster
- Edit & develop locally
- Push Git commit
- CI: Test on PR
- CD: Apply on commit to
master
-
Create the demo repository:
git clone git@github.com:mumoshu/brigade-helmfile-chatops.git cd $_ rm -rf .git/ ORG=mumoshu # Replace with your org name! REPO=$ORG/demo-$(</dev/urandom dd ibs=1 obs=1 count=9 | od -tx1 -An | tr -d ' ') git add . git commit -m 'import' hub create $REPO git push origin master
-
Create a GitHub App for Brigade following this guide If you have created one before, discover it in https://github.com/settings/apps
- Navigate to
GitHub App > Private keys > Private key
, generate a private key by clickingGenerate a private key
button, download the private key and set its full path toBRIGADE_GITHUB_APP_KEY
- Navigate to
GitHub App > About
, take a note ofApp ID
, set it toBRIGADE_GITHUB_APP_ID
- Navigate to
GitHub App > Webhook secret (optional)
. Generate a random password and put it there, also set it toBRIGADE_PROJECT_SECRET
-
Set envvars:
export NGROK_TOKEN=<Your ngrok token shown in https://dashboard.ngrok.com/get-started> export BRIGADE_GITHUB_APP_KEY=<Local path to the private key file for TLS client auth from the step 2> export BRIGADE_GITHUB_APP_ID=<App ID from the step 2> export BRIGADE_PROJECT_SECRET=<Webhook (shared) secret from the step 2> export SSH_KEY=$HOME/.ssh/id_rsa (Or whatever ssh private key you want Brigade to use while git-cloning private Git repos) export GITHUB_TOKEN=<Used for updating commit/pull request statuses>
-
Install all the apps onto your cluster:
helm tiller run -- helmfile apply
-
Configure the Brigade GitHub App:
Browse
GitHub > Developer settings > GitHub Apps > <your brigade github app name>
and add setWebhook URL
to your Ngrok endpoint.It woud look like:
https://<random string>.ngrok.io/events/github
-
Configure the GitHub App
Browse
GithHub > Personal settings > Applications > Installed GitHub Apps > <your brigade github app name>
and then click theConfigure
button right next to it.Then add the demo repository for subscription:
SPOILER: We use this locally and remotely:
helmfile.yaml
:
releases:
- name: frontend
chart: flagger/podinfo
namespace: test
values:
- nameOverride: frontend
See helmfile.yaml for the full example.
a.k.a
helm upgrade --install \
frontend flagger/podinfo \
--set nameOverride=frontend`
Run:
# See what will be installed
$ helmfile diff
# Actually install all the things
$ helmfile apply
- Brigade Server
- Brigade GitHub App
- Brigade Project
- In-Cluster Ngrok Tunnel (GitHub Webhooks to Brigade GitHub App
- Other apps for demonstration purpose
Run:
$ git checkout -b change-blah
$ $EDITOR helmfile.yaml
(Again,) Run:
$ helmfile diff
$ helmfile apply
Run:
$ git add helmfile.yaml && \
git commit -m 'Change blah' && \
git push origin master
$ hub pull-request
So that Brigade
(Again) Runs:
$ helmfile diff
Review the PR on GitHub.
- Merge the pull request into
master
so that brigade
pulls the commit and applies it by (AGAIN!) running:$ helmfile apply
Voila! You've implemented GitOps.
The brigade
script looks like:
const { events, Job , Group} = require("brigadier")
const dest = "/workspace"
const image = "mumoshu/helmfile-gitops:dev"
events.on("push", (e, p) => {
console.log(e.payload)
var gh = JSON.parse(e.payload)
if (e.type == "pull_request") {
// Run "helmfile diff" for PRs
run("diff")
} else {
// Run "helmfile apply" for commits to master
run("apply")
}
});
See brigade.js for full example.
function run(cmd) {
var job = new Job(cmd, image)
job.tasks = [
"mkdir -p " + dest,
"cp -a /src/* " + dest,
"cd " + dest,
`helmfile ${cmd}`,
]
job.run()
}
Another GitOps solution that helps!
- Flux
- Argo CD
- Brigade (PROPOSED!)
Try youself!
https://gitpitch.com/mumoshu/helmfile-gitops
"The end of the "Kustomize vs Helm argument"
helm template mychart | kubectl apply -f
helm template mychart --outputs-dir manifests/ && (kustomize build | kubectl apply -f -)
When you want:
helm diff
: Preview changes before applyhelm test
: Run tests included in the charthelm stauts
: List helm-managed resources and the installation notehelm get values
: Which settings I used when installing this?
- (Optionally) Generate K8s manifests from Helm chart
- Patch K8s manifests with Kustomize (JSON Patch and Strategic-Merge Patch available)
- Install the patched manifests with Helm
Shameless Plug: https://github.com/mumoshu/helm-x
helm
:
$ helm install myapp mychart
helm-x
:
$ helm x install myapp mychart
Patch and diff/install/up whatever "as Helm chart":
$ helm x [diff|install|upgrade] --install myapp WHAT --version 1.2.4 \
-f values.yaml \
--strategic-merge-patch path/to/strategicmerge.patch.yaml \
--jsonpatch path/to/json.patch.yaml
WAHT can be:
- Helm chart
- Kustomization
- Directory containing K8s maniefsts
You've got everything!
- GitOps operator (Flux or Argo CD) OR Universal system for running CI and CD pipelines (brigade)
- Universal tool for deploying whatever (helm, kustomize, k8s manifests, helm-x, helmfile)
This section tries to summarize all the possible errors and failures you might encounter while following this demo.
brigade-brigade-github-app-65f85998c9-g29bd brigade-github-app Expected signature "sha1=534be2a1d55133e35fb994c3f88072bae7de23ca" (sum), got "sha1=d895929b47181bed0cddba19d2b7c4de1c4f5869" (hub-signature)
brigade-brigade-github-app-65f85998c9-g29bd brigade-github-app [GIN] 2019/07/02 - 07:18:03 | 403 | 7.3981ms | 140.82.115.70 | POST /events/github
Try updating your Brigade GitHub App's Webhook secret
on GitHub and sharedSecret
on your helm release to match. The hub sigunature is calculated according to that.
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar Warning: Permanently added 'github.com,52.69.186.44' (RSA) to the list of known hosts.
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar Load key "./id_dsa": invalid format
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar git@github.com: Permission denied (publickey).
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar fatal: Could not read from remote repository.
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar Please make sure you have the correct access rights
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar and the repository exists.
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar + test 2 -lt 5
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar + echo 'Command failed. Attempt 2/5. Waiting for 10 seconds before retrying.'
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar + sleep 10
brigade-worker-01ders1ktdajnkzd5r29154e3v vcs-sidecar Command failed. Attempt 2/5. Waiting for 10 seconds before retrying.
@mumoshu
AWS Container Hero
OSS enthusiast maintaining 10+ K8s-related OSS: