Skip to content
This repository was archived by the owner on Aug 4, 2021. It is now read-only.

Commit 4e406dd

Browse files
committed
Initial customizations and added more documentation
1 parent e635c6c commit 4e406dd

17 files changed

+614
-397
lines changed

.dockerignore

+10
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,12 @@
11
node_modules
22
.git
3+
Makefile
4+
manifests
5+
dist
6+
Dockerfile
7+
*.md
8+
.vscode
9+
.DS_Store
10+
.*ignore
11+
.prettierrc
12+
.eslintrc.js

.vscode/launch.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"name": "Launch Program",
11+
"program": "${workspaceFolder}/index.ts",
12+
"preLaunchTask": "tsc: build - tsconfig.json",
13+
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
14+
"smartStep": true
15+
}
16+
]
17+
}

Dockerfile

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
FROM node:12-alpine
1+
FROM node:lts-alpine
22

33
WORKDIR /usr/src/app
44
COPY package*.json ./
55
RUN npm install
66
COPY . .
77

8-
RUN npm run build
8+
RUN npm run build && npm prune --production
99

10-
RUN npm prune --production
11-
12-
CMD [ "node", "dist/index.js" ]
10+
CMD ["npm", "run", "start"]

Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build:
2+
docker image build -t dopplerhq/doppler-k8s-controller .

README.md

+83-11
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,99 @@
11
# Doppler Kubernetes Controller
22

3-
A custom Kubernetes Controller which polls Doppler's servers and updates environment variables automatically.
3+
A custom Kubernetes Controller which polls Doppler's secrets API to automatically create and update a native Kubernetes secret using the `spec.serviceToken` and `spec.secretName` fields from the `dopplersecrets.doppler.com` custom resource.
44

5-
## Motivation
5+
The Kubernetes secret created by the controller is just a regular secret with some Doppler specific labels and annoations.
66

7-
Doppler is a universal secrets manager which offers ease of use to our team in development. However, they don't have a native Kubernetes integration which automatically updates environment variables.
7+
The secret is then used by a deployment to expose the secrets as environment variables using `envFrom:`.
88

9-
This tool aims to solve that issue and to allow secrets editing directly in Doppler.
9+
In essence, a `DopplerSecret` is just a mechanism to create a Kubernetes secret that is used by Deployments, saving the developer from habing to manually do that themselves.
1010

11-
## Installing on a Kubernetes Cluster
11+
## Installation
1212

13-
After downloading this repo, edit the refresh rate as needed in `k8s/manifest.yml` and simply run:
13+
Apply the manifest in `manivests/crd.yml` by running:
1414

1515
```bash
1616
kubectl apply -f ./k8s/manifest.yml
1717
```
1818

19-
An example of a `DopplerSecret` deployment can be found at `k8s/example.yml`.
19+
NOTE: The `crd.yml` defines an environment variables `SYNC_INTERVAL` which can be customized if required (default is once every 5 seconds). This is also the maximum delay between a `DopplerSecret` and the associated Kube secret being created.
2020

21-
## Local Development
21+
## Kubernetes dashboard on Docker for Desktop for viewing resources
2222

23-
Assuming you have a local Kubernetes Cluster (I used Docker Desktop) and [Tilt](https://tilt.dev/), you can simply run this command:
23+
The Kubernetes dashboard is handy for inspecting the state of various resources such as the CRD itself and the logs of the Controller Pod so here is how you can access it if using Docker for Desktop:
2424

25-
```bash
26-
tilt up
25+
Install the Dashboard resources:
26+
27+
```sh
28+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended.yaml
29+
```
30+
31+
Run Kube proxy in order to reach the dashboard:
32+
33+
```sh
34+
kubectl proxy
35+
```
36+
37+
Use `kubectl` to get the token value from the Kube secret that was created when the dashboard was installed and copy it to your clipboard:
38+
39+
```sh
40+
kubectl get secret $(kubectl get secret --namespace kubernetes-dashboard | grep kubernetes-dashboard-token | awk '{print $1}') --namespace ${KUBE_DASHBOARD_NAMESPACE} --template={{.data.token}} | base64 -D | pbcopy
41+
```
42+
43+
Open the dashboard - http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
44+
45+
Paste in your token and you should be good to go!
46+
47+
## Usage
48+
49+
NOTE: The `envsubst` binary is required and can be installed in macOS by running:
50+
51+
```sh
52+
brew install gettext
53+
```
54+
55+
---
56+
57+
To create a `DopplerSecret`, run the following which will substitute the srevice token value and feed the stdout into the `kubectl`:
58+
59+
```sh
60+
# Avoids hard-coding the service token in the manifest and it touching the file system
61+
kubectl apply -f <(SERVICE_TOKEN="XXXXXX" envsubst < example/dopplersecret.yml)
62+
```
63+
64+
Now create the deployment which uses the secret created by the Controller. The `secretName` in the `DopplerSecret` spec is the name of the sercret the controller will create, which will be referenced by the `envFrom.secretRef.name` property.
65+
66+
```sh
67+
kubectl apply -f example/deployment.yml
68+
```
69+
70+
Then in order to test that the deployment Pod had secrets supplied as env vars correctly, run the following which should be the names of all env vars:
71+
72+
```sh
73+
kubectl logs -lapp=doppler-secret-test
2774
```
75+
76+
### Clean up
77+
78+
To remove all resources create, run:
79+
80+
```sh
81+
kubectl delete -f example/deployment.yml
82+
kubectl delete -f example/dopplersecret.yml
83+
kubectl delete secrets doppler-app-secret
84+
```
85+
86+
## Learnings
87+
88+
- Revise deployment strategy. Need to have at least two nodes. Careful of single point of failure, then no secrets will be created.
89+
- Automatically triggering a new deployment when variables is change is a cool idea, but not sure everyone will want that.
90+
- What should happen if a service token is invalidated? Generally speaking, what's our approach to error handling.
91+
- Probably best written in Go
92+
- Max delay of `SYNC_INTERVAL` between `DopplerSecret` created and Kube secret created is the max delay that a deployment will be invalid if deployment is created when `DopplerSecret` is.
93+
94+
## To Do
95+
96+
- Tests!
97+
- Handle case when invalid service token is supplied initially, as secret will not be created
98+
- Use labels and selectors to have a `DopplerSecret` as the owner of the Kube secret
99+
- Add a grace period and a finalizer to `DopplerSecret` so the controller can detect deleted state, remove associated secret, then remove finalizer to have Kube clean it up

Tiltfile

-2
This file was deleted.

example/deployment.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: doppler-secret-test
5+
spec:
6+
replicas: 1
7+
selector:
8+
matchLabels:
9+
app: doppler-secret-test
10+
template:
11+
metadata:
12+
labels:
13+
app: doppler-secret-test
14+
spec:
15+
containers:
16+
- name: doppler-secret-test
17+
image: alpine
18+
command: ['/bin/sh', '-c', 'printenv | sed "s;=.*;;" | sort && sleep 3600'] # Test by printing env var names
19+
imagePullPolicy: IfNotPresent
20+
envFrom:
21+
- secretRef:
22+
name: doppler-app-secret # Should match DopplerSecret spec.secretName
23+
resources:
24+
requests:
25+
memory: '250Mi'
26+
cpu: '250m'
27+
limits:
28+
memory: '500Mi'
29+
cpu: '500m'

example/dopplersecret.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: 'doppler.com/v1'
2+
kind: DopplerSecret
3+
metadata:
4+
name: my-app-secret
5+
namespace: default
6+
spec:
7+
serviceToken: '$SERVICE_TOKEN' # This will be replaced by envsubst so it's never hard-coded and saved to the file system
8+
secretName: doppler-app-secret # Name of the secret the controller will create

k8s/example.yml

-39
This file was deleted.

k8s/manifest.yml

-101
This file was deleted.

0 commit comments

Comments
 (0)