Skip to content

Commit 0b1cf9b

Browse files
authored
support database connection for mysql/postgres (#5)
* support database connection for mysql/postgres
1 parent 07acf10 commit 0b1cf9b

File tree

12 files changed

+349
-2163
lines changed

12 files changed

+349
-2163
lines changed

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
GITHUB_ORG := $(shell echo ${REPOSITORY} | cut -d "/" -f 2)
77
GITHUB_REPO := $(shell echo ${REPOSITORY} | cut -d "/" -f 3)
88

9-
run:
9+
run: create-db-user
1010
@echo "Set CIRCLECI environment variables\n"
1111
export AWS_ACCESS_KEY_ID=$(shell aws secretsmanager get-secret-value --region ${region} --secret-id=ci-user-aws-keys${randomSeed} | jq -r '.SecretString'| jq -r .access_key_id)
1212
export AWS_SECRET_ACCESS_KEY=$(shell aws secretsmanager get-secret-value --region ${region} --secret-id=ci-user-aws-keys${randomSeed} | jq -r '.SecretString'| jq -r .secret_key)
@@ -17,6 +17,14 @@ run:
1717
curl -X POST https://circleci.com/api/v1.1/project/github/${GITHUB_ORG}/${GITHUB_REPO}/follow?circle-token=${CIRCLECI_API_KEY}
1818
@echo "\nDone"
1919

20+
create-db-user:
21+
export REGION=${region}; \
22+
export SEED=${randomSeed}; \
23+
export PROJECT_NAME=${PROJECT_NAME}; \
24+
export ENVIRONMENT=${ENVIRONMENT}; \
25+
export DATABASE=${database}; \
26+
sh ./db-ops/create-db-user.sh
27+
2028
summary:
2129
@echo "zero-deployable-node-backend:"
2230
@echo "- Repository URL: ${REPOSITORY}"

db-ops/create-db-user.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/sh
2+
3+
# docker image with postgres.mysql client
4+
DOCKER_IMAGE_TAG=commitdev/zero-k8s-utilities:0.0.3
5+
DB_ENDPOINT=database.$PROJECT_NAME
6+
DB_NAME=$(aws rds describe-db-instances --region=$REGION --query "DBInstances[?DBInstanceIdentifier=='$PROJECT_NAME-$ENVIRONMENT'].DBName" | jq -r '.[0]')
7+
SECRET_ID=$(aws secretsmanager list-secrets --region $REGION --query "SecretList[?Name=='$PROJECT_NAME-$ENVIRONMENT-rds-$SEED'].Name" | jq -r ".[0]")
8+
# RDS MASTER
9+
MASTER_RDS_USERNAME=master_user
10+
SECRET_PASSWORD=$(aws secretsmanager get-secret-value --region=$REGION --secret-id=$SECRET_ID | jq -r ".SecretString")
11+
# APPLICATION DB ADMIN
12+
DB_APP_USERNAME=$DB_NAME
13+
DB_APP_PASSWORD=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | base64 | head -c 16)
14+
15+
# Fill in env-vars to db user creation manifest
16+
eval "echo \"$(cat ./db-ops/job-create-db-$DATABASE.yml.tpl)\"" > ./k8s-job-create-db.yml
17+
# the manifest creates 4 things
18+
# 1. Namespace: db-ops
19+
# 2. Secret in db-ops: db-create-users (with master password, and a .sql file
20+
# 3. Job in db-ops: db-create-users (runs the .sql file against the RDS given master_password from env)
21+
# 4. Secret in Application namespace with DB_USERNAME / DB_PASSWORD
22+
kubectl apply -f ./k8s-job-create-db.yml
23+
24+
# Deleting the entire db-ops namespace, leaving ONLY application-namespace's secret behind
25+
kubectl -n db-ops wait --for=condition=complete --timeout=10s job db-create-users
26+
if [ $? -eq 0 ]
27+
then
28+
kubectl get namespace db-ops
29+
else
30+
echo "Failed to create application database user, please see 'kubectl logs -n db-ops -l job-name=db-create-users'"
31+
fi

db-ops/job-create-db-mysql.yml.tpl

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
apiVersion: v1
2+
kind: Namespace
3+
metadata:
4+
name: db-ops
5+
---
6+
apiVersion: v1
7+
kind: Secret
8+
metadata:
9+
name: db-create-users
10+
namespace: db-ops
11+
type: Opaque
12+
stringData:
13+
create-user.sql: |
14+
CREATE USER '$DB_APP_USERNAME' IDENTIFIED BY '$DB_APP_PASSWORD';
15+
GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_APP_USERNAME';
16+
RDS_MASTER_PASSWORD: $SECRET_PASSWORD
17+
---
18+
apiVersion: v1
19+
kind: Namespace
20+
metadata:
21+
name: $PROJECT_NAME
22+
---
23+
apiVersion: v1
24+
kind: Secret
25+
metadata:
26+
name: $PROJECT_NAME
27+
namespace: $PROJECT_NAME
28+
type: Opaque
29+
stringData:
30+
DATABASE_USERNAME: $DB_APP_USERNAME
31+
DATABASE_PASSWORD: $DB_APP_PASSWORD
32+
---
33+
apiVersion: batch/v1
34+
kind: Job
35+
metadata:
36+
name: db-create-users
37+
namespace: db-ops
38+
spec:
39+
template:
40+
spec:
41+
containers:
42+
- name: create-rds-user
43+
image: $DOCKER_IMAGE_TAG
44+
command:
45+
- sh
46+
args:
47+
- '-c'
48+
- mysql -u$MASTER_RDS_USERNAME -h $DB_ENDPOINT $DB_NAME < /db-ops/create-user.sql
49+
env:
50+
- name: DB_ENDPOINT
51+
value: $DB_ENDPOINT
52+
- name: DB_NAME
53+
value: $DB_NAME
54+
- name: MYSQL_PWD
55+
valueFrom:
56+
secretKeyRef:
57+
name: db-create-users
58+
key: RDS_MASTER_PASSWORD
59+
volumeMounts:
60+
- mountPath: /db-ops/create-user.sql
61+
name: db-create-users
62+
subPath: create-user.sql
63+
volumes:
64+
- name: db-create-users
65+
secret:
66+
secretName: db-create-users
67+
restartPolicy: Never
68+
backoffLimit: 1
69+
---
70+
apiVersion: apps/v1
71+
kind: Deployment
72+
metadata:
73+
name: db-pod
74+
namespace: $PROJECT_NAME
75+
spec:
76+
# this is purposely left at 0 so it can be enabled for troubleshooting purposes
77+
replicas: 0
78+
selector:
79+
matchLabels:
80+
app: db-pod
81+
template:
82+
metadata:
83+
labels:
84+
app: db-pod
85+
spec:
86+
automountServiceAccountToken: false
87+
containers:
88+
- command:
89+
- sh
90+
args:
91+
- "-c"
92+
# long running task so the pod doesn't exit with 0
93+
- tail -f /dev/null
94+
image: $DOCKER_IMAGE_TAG
95+
imagePullPolicy: Always
96+
name: db-pod
97+
env:
98+
- name: DB_ENDPOINT
99+
value: $DB_ENDPOINT
100+
- name: DB_NAME
101+
value: $DB_NAME
102+
- name: DB_USERNAME
103+
valueFrom:
104+
secretKeyRef:
105+
name: $PROJECT_NAME
106+
key: DATABASE_USERNAME
107+
- name: DB_PASSWORD
108+
valueFrom:
109+
secretKeyRef:
110+
name: $PROJECT_NAME
111+
key: DATABASE_PASSWORD
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
apiVersion: v1
2+
kind: Namespace
3+
metadata:
4+
name: db-ops
5+
---
6+
apiVersion: v1
7+
kind: Secret
8+
metadata:
9+
name: db-create-users
10+
namespace: db-ops
11+
type: Opaque
12+
stringData:
13+
create-user.sql: |
14+
create user $DB_APP_USERNAME with encrypted password '$DB_APP_PASSWORD';
15+
grant all privileges on database $DB_NAME to $DB_APP_USERNAME;
16+
RDS_MASTER_PASSWORD: $SECRET_PASSWORD
17+
---
18+
apiVersion: v1
19+
kind: Namespace
20+
metadata:
21+
name: $PROJECT_NAME
22+
---
23+
apiVersion: v1
24+
kind: Secret
25+
metadata:
26+
name: $PROJECT_NAME
27+
namespace: $PROJECT_NAME
28+
type: Opaque
29+
stringData:
30+
DATABASE_USERNAME: $DB_APP_USERNAME
31+
DATABASE_PASSWORD: $DB_APP_PASSWORD
32+
---
33+
apiVersion: batch/v1
34+
kind: Job
35+
metadata:
36+
name: db-create-users
37+
namespace: db-ops
38+
spec:
39+
template:
40+
spec:
41+
containers:
42+
- name: create-rds-user
43+
image: $DOCKER_IMAGE_TAG
44+
command:
45+
- sh
46+
args:
47+
- '-c'
48+
- psql -U$MASTER_RDS_USERNAME -h $DB_ENDPOINT $DB_NAME -a -f/db-ops/create-user.sql > /dev/null
49+
env:
50+
- name: PGPASSWORD
51+
valueFrom:
52+
secretKeyRef:
53+
name: db-create-users
54+
key: RDS_MASTER_PASSWORD
55+
volumeMounts:
56+
- mountPath: /db-ops/create-user.sql
57+
name: db-create-users
58+
subPath: create-user.sql
59+
volumes:
60+
- name: db-create-users
61+
secret:
62+
secretName: db-create-users
63+
restartPolicy: Never
64+
backoffLimit: 1
65+
---
66+
apiVersion: apps/v1
67+
kind: Deployment
68+
metadata:
69+
name: db-pod
70+
namespace: $PROJECT_NAME
71+
spec:
72+
# this is purposely left at 0 so it can be enabled for troubleshooting purposes
73+
replicas: 0
74+
selector:
75+
matchLabels:
76+
app: db-pod
77+
template:
78+
metadata:
79+
labels:
80+
app: db-pod
81+
spec:
82+
automountServiceAccountToken: false
83+
containers:
84+
- command:
85+
- sh
86+
args:
87+
- "-c"
88+
# long running task so the pod doesn't exit with 0
89+
- tail -f /dev/null
90+
image: $DOCKER_IMAGE_TAG
91+
imagePullPolicy: Always
92+
name: db-pod
93+
env:
94+
- name: DB_ENDPOINT
95+
value: $DB_ENDPOINT
96+
- name: DB_NAME
97+
value: $DB_NAME
98+
- name: DB_USERNAME
99+
valueFrom:
100+
secretKeyRef:
101+
name: $PROJECT_NAME
102+
key: DATABASE_USERNAME
103+
- name: DB_PASSWORD
104+
valueFrom:
105+
secretKeyRef:
106+
name: $PROJECT_NAME
107+
key: DATABASE_PASSWORD

templates/.circleci/config.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,23 @@ jobs:
232232
- run:
233233
name: Deploy
234234
command: |
235-
kubectl create namespace << parameters.namespace >> || echo "Namespace already exists"
235+
DEPLOYMENT=<< parameters.repo >>
236+
NAMESPACE=<< parameters.namespace >>
237+
kubectl create namespace $NAMESPACE || echo "Namespace already exists"
236238
cd kubernetes/overlays/<< parameters.config-environment >>
237239
IMAGE=<< parameters.account-id >>.dkr.ecr.<< parameters.region >>.amazonaws.com/<< parameters.repo >>
238240
kustomize edit set image fake-image=${IMAGE}:${VERSION_TAG}
239-
kustomize build . | kubectl apply -f - -n << parameters.namespace >>
241+
kustomize build . | kubectl apply -f - -n $NAMESPACE
242+
if ! kubectl -n $NAMESPACE rollout status deployment/$DEPLOYMENT -w --timeout=180s ; then
243+
echo "$DEPLOYMENT rollout check failed:"
244+
echo "$DEPLOYMENT deployment:"
245+
kubectl -n $NAMESPACE describe deployment $DEPLOYMENT
246+
echo "$DEPLOYMENT replicaset:"
247+
kubectl -n $NAMESPACE describe rs -l app=$DEPLOYMENT
248+
echo "$DEPLOYMENT pods:"
249+
kubectl -n $NAMESPACE describe pod -l app=$DEPLOYMENT
250+
exit 1
251+
fi
240252
workflows:
241253
version: 2
242254
# The main workflow. Check out the code, build it, push it, deploy to staging, test, deploy to production

templates/.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
DATABASE_ENGINE=
22
DATABASE_HOST=
3-
DATABASE_HOST=
3+
DATABASE_PORT=
44
DATABASE_PASSWORD=
55
DATABASE_USERNAME=
66
DATABASE_NAME=

templates/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
install:
22
npm i
3+
# See https://sequelize.org/master/manual/getting-started.html for supported db drivers
4+
<%if eq (index .Params `database`) "postgres" %>npm i --save pg pg-hstore<% else if eq (index .Params `database`) "mysql" %>npm i --save mysql2<% end %>
35

46
run:
5-
PORT=80 node app.js
7+
PORT=80 node src/app.js

templates/kubernetes/base/deployment.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ spec:
5757
secretKeyRef:
5858
name: cf-keypair
5959
key: private_key
60+
- name: DATABASE_USERNAME
61+
valueFrom:
62+
secretKeyRef:
63+
name: <% .Name %>
64+
key: DATABASE_USERNAME
65+
- name: DATABASE_PASSWORD
66+
valueFrom:
67+
secretKeyRef:
68+
name: <% .Name %>
69+
key: DATABASE_PASSWORD
6070
---
6171
apiVersion: autoscaling/v1
6272
kind: HorizontalPodAutoscaler

0 commit comments

Comments
 (0)