[Infrastructure as Code (IaC) Pulumi] Use Pulumi kubernetes (K8S) Helm Chart to deploy Kubed

Kubed

Kubed by AppsCode is a Kubernetes cluster manager daemon that can sync ConfigMaps/Secrets across Kubernetes namespaces or Clusters.

This article is about how to use Pulumi, kubernetes (K8S) provider, Helm Chart and TypeScript SDK to deploy Kubed within Kubernetes (K8S).

Prerequisites

Usage

Pulumi New

Create the workspace directory.

1
2
3
$ mkdir -p col-example-pulumi-typescript-kubed

$ cd col-example-pulumi-typescript-kubed

Pulumi login into local file system.

1
2
3
$ pulumi login file://.
Logged in to cloudolife as cloudolife (file://.)
or visit https://pulumi.com/docs/reference/install/ for manual instructions and release notes.

Pulumi new a project with kubernetes-typescript SDK.

1
$ pulumi new kubernetes-typescript

The above command will create some files within the current directory.

1
2
3
4
5
6
7
8
tree . -L 1
.
├── node_modules/
├── package.json
├── package.json.lock
├── Pulumi.dev.yaml
├── Pulumi.yaml
└── main.ts

Install js-yaml package to load and parse yaml file.

1
$ npm i js-yaml

Pulumi Configuration

Configure Kubernetes

By default, Pulumi will look for a kubeconfig file in the following locations, just like kubectl:

  • The environment variable: $KUBECONFIG,

  • Or in current user’s default kubeconfig directory: ~/.kube/config

If the kubeconfig file is not in either of these locations, Pulumi will not find it, and it will fail to authenticate against the cluster. Set one of these locations to a valid kubeconfig file, if you have not done so already.

Configure Values.yaml

Edit values.yaml and replace content within {{ }}.

1
2
3
4
5
6
7
# values.yaml

# kubed/values.yaml at v0.12.0 · appscode/kubed
# https://github.com/appscode/kubed/blob/v0.12.0/charts/kubed/values.yaml

# If true, sends usage analytics
enableAnalytics: false

main.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// main.ts

import * as pulumi from "@pulumi/pulumi";

import * as k8s from "@pulumi/kubernetes";

const yaml = require('js-yaml');
const fs = require('fs');

const values = yaml.safeLoad(fs.readFileSync("./values.yaml", 'utf8'))

const charNameKubed = "kubed"

const charKubed = new k8s.helm.v3.Chart(charNameKubed, {
chart: charNameKubed,
version: "0.12.0",
fetchOpts:{
repo: "https://charts.appscode.com/stable/",
},
namespace: "kube-system",
values: values,
})

Pulumi Up

Run pulumi up to create the namespace and pods.

1
$ pulumi up

See pods about kubed.

1
2
$ kubectl get pods -n kube-system | grep kubed
kubed-54f677c9c6-jvv7j 1/1 Running 1 (23h ago) 28h

Pulumi Destroy

Destroy all resources created by Pulumi.

1
$ pulumi destroy

Now, create a ConfigMap called omni in the demo namespace. This will be our source ConfigMap.

1
2
3
4
5
6
7
8
9
10
# cat demo-0.yaml
---
apiVersion: v1
data:
you: only
leave: once
kind: ConfigMap
metadata:
name: omni
namespace: demo

Apply the demo-0.yaml to create ConfigMap.

1
2
3
4
5
$ kubectl apply -f demo-0.yaml
configmap "omni" created

$ kubectl get configmaps --all-namespaces | grep omni
demo omni 2 7m

Now, apply the kubed.appscode.com/sync: “” annotation to ConfigMap omni. Kubed operator will notice that and copy the ConfigMap in all namespaces.

1
2
3
4
5
6
7
8
$ kubectl annotate configmap omni kubed.appscode.com/sync="" -n demo
configmap "omni" annotated

$ kubectl get configmaps --all-namespaces | grep omni
default omni 2 1m
demo omni 2 8m
kube-public omni 2 1m
kube-system omni 2 1m

Namespace Selector

Lets’ change annotation value of source ConfigMap omni.

1
2
3
4
5
$ kubectl annotate configmap omni kubed.appscode.com/sync="app=kubed" -n demo --overwrite
configmap "omni" annotated

$ kubectl get configmaps --all-namespaces | grep omni
demo omni 2 8m

Kubed operator removes the ConfigMap from all namespaces (except source) since no namespace matches the label-selector app=kubed. Now, lets’ apply app=kubed annotation to other namespace. Kubed operator will then sync the ConfigMap to other namespace.

1
2
3
4
5
6
$ kubectl label namespace other app=kubed
namespace "other" labeled

$ kubectl get configmaps --all-namespaces | grep omni
demo omni 2 8m
other omni 2 5m

Restricting Source Namespace

By default, Kubed will watch all namespaces for configmaps and secrets with kubed.appscode.com/sync annotation. But you can restrict the source namespace for configmaps and secrets by passing config.configSourceNamespace value during installation.

1
2
3
4
$ helm install kubed appscode/kubed \
--namespace=kube-system \
--set imagePullPolicy=Always \
--set config.configSourceNamespace=demo

References

[1] appscode/kubed: 🛡️ A Kubernetes Cluster Daemon - https://github.com/appscode/kubed

[2] Kubed by AppsCode - https://appscode.com/products/kubed/v0.12.0/guides/config-syncer/

[3] Kubed by AppsCode - https://appscode.com/products/kubed/v0.12.0/guides/config-syncer/intra-cluster/

[5] Kubernetes Getting Started | Pulumi - https://www.pulumi.com/docs/get-started/kubernetes/

[6] Pulumi - Modern Infrastructure as Code - https://www.pulumi.com/

[7] Kubernetes - https://kubernetes.io/

[8] TypeScript: Typed JavaScript at Any Scale. - https://www.typescriptlang.org/

[9] Helm - https://helm.sh/