diff --git a/README.md b/README.md new file mode 100644 index 0000000..7894671 --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +# nginx_CD_chart + +Helm charts for the demo stack, with three isolated environments: **dev**, **stg**, **prod**. + +``` +nginx_CD_chart/ +├── nginx-chart/ +│ ├── Chart.yaml +│ ├── values.yaml # base defaults (shared) +│ ├── templates/ +│ │ ├── deployment.yaml +│ │ ├── service.yaml +│ │ └── _helpers.tpl +│ └── environments/ +│ ├── dev/ +│ │ ├── values.yaml # dev overrides +│ │ ├── configmap.yaml # dev ConfigMap (plain manifest) +│ │ └── secret.yaml # dev Secret(s) (plain manifest) +│ ├── stg/ +│ │ ├── values.yaml +│ │ ├── configmap.yaml +│ │ └── secret.yaml +│ └── prod/ +│ ├── values.yaml +│ ├── configmap.yaml +│ └── secret.yaml +└── mysql-chart/ + ├── Chart.yaml + ├── values.yaml # base defaults (shared) + ├── templates/ + │ ├── statefulset.yaml + │ └── service.yaml + └── environments/ + ├── dev/ + │ ├── values.yaml + │ ├── configmap.yaml + │ └── secret.yaml + ├── stg/ + │ ├── values.yaml + │ ├── configmap.yaml + │ └── secret.yaml + └── prod/ + ├── values.yaml + ├── configmap.yaml + └── secret.yaml +``` + +## How it works + +For each environment there is a folder under `environments//` containing three files: + +| File | Purpose | How it is applied | +|------|---------|-------------------| +| `values.yaml` | Helm overrides for that env (namespace, replica count, image tag, storage size, resource names) | `helm -f` | +| `configmap.yaml` | Non-secret config (`ConfigMap`), e.g. nginx `default.conf` / mysql settings | `kubectl apply` | +| `secret.yaml` | Credentials (`Secret`), e.g. registry pull secret / mysql passwords | `kubectl apply` | + +The chart's `templates/` stay generic and read the resource **names** from `values.yaml` +(`configMap.name`, `secret.name`), so the same templates render for every environment. + +## Deploy an environment + +Replace `` with `dev`, `stg` or `prod`. + +```bash +# 1. Namespace + ConfigMap + Secret (plain manifests for this env) +kubectl create namespace --dry-run=client -o yaml | kubectl apply -f - +kubectl apply -f nginx-chart/environments//configmap.yaml +kubectl apply -f nginx-chart/environments//secret.yaml +kubectl apply -f mysql-chart/environments//configmap.yaml +kubectl apply -f mysql-chart/environments//secret.yaml + +# 2. The Helm releases (values merged on top of each chart's base values.yaml) +helm upgrade --install mysql ./mysql-chart -n --create-namespace \ + -f mysql-chart/environments//values.yaml + +helm upgrade --install nginx ./nginx-chart -n --create-namespace \ + -f nginx-chart/environments//values.yaml +``` + +Example — deploy **stg**: + +```bash +kubectl apply -f nginx-chart/environments/stg/configmap.yaml +kubectl apply -f nginx-chart/environments/stg/secret.yaml +helm upgrade --install nginx ./nginx-chart -n stg --create-namespace \ + -f nginx-chart/environments/stg/values.yaml +``` + +## Preview the rendered manifests + +```bash +helm template nginx ./nginx-chart -f nginx-chart/environments/stg/values.yaml +helm template mysql ./mysql-chart -f mysql-chart/environments/prod/values.yaml +``` + +## Notes / things to change before real use + +- `secret.yaml` files contain **plaintext** example credentials. For real use, commit + encrypted secrets (e.g. SealedSecrets / SOPS) or create them from CI secrets — never + store production passwords in git. +- `harbor-secret` (docker-registry pull secret) is provided per env with placeholder + credentials; either replace the values or create it in-cluster with + `kubectl create secret docker-registry ...` (command is in the file header). +- The base `values.yaml` defaults to the `dev` namespace, so always pass `-f environments//values.yaml`. diff --git a/mysql-chart/environments/dev/configmap.yaml b/mysql-chart/environments/dev/configmap.yaml new file mode 100644 index 0000000..a6b047d --- /dev/null +++ b/mysql-chart/environments/dev/configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: mysql-config-dev + namespace: dev + labels: + app: mysql + env: dev +data: + MYSQL_DATABASE: demo_dev + MYSQL_USER: demo diff --git a/mysql-chart/environments/dev/secret.yaml b/mysql-chart/environments/dev/secret.yaml new file mode 100644 index 0000000..fb31f52 --- /dev/null +++ b/mysql-chart/environments/dev/secret.yaml @@ -0,0 +1,12 @@ +# MySQL credentials for the DEV environment (referenced by the StatefulSet). +# Replace with real values; for production use a sealed/encrypted secret instead +# of committing plaintext. +apiVersion: v1 +kind: Secret +metadata: + name: mysql-secret-dev + namespace: dev +type: Opaque +stringData: + MYSQL_PASSWORD: demo123 + MYSQL_ROOT_PASSWORD: root123 diff --git a/mysql-chart/environments/dev/values.yaml b/mysql-chart/environments/dev/values.yaml new file mode 100644 index 0000000..51f2656 --- /dev/null +++ b/mysql-chart/environments/dev/values.yaml @@ -0,0 +1,14 @@ +# DEV environment overrides for mysql-chart +namespace: dev + +image: + tag: "8.4" + +storage: + size: 1Gi + +configMap: + name: mysql-config-dev + +secret: + name: mysql-secret-dev diff --git a/mysql-chart/environments/prod/configmap.yaml b/mysql-chart/environments/prod/configmap.yaml new file mode 100644 index 0000000..41d17f8 --- /dev/null +++ b/mysql-chart/environments/prod/configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: mysql-config-prod + namespace: prod + labels: + app: mysql + env: prod +data: + MYSQL_DATABASE: demo_prod + MYSQL_USER: demo diff --git a/mysql-chart/environments/prod/secret.yaml b/mysql-chart/environments/prod/secret.yaml new file mode 100644 index 0000000..c252ae9 --- /dev/null +++ b/mysql-chart/environments/prod/secret.yaml @@ -0,0 +1,12 @@ +# MySQL credentials for the PROD environment (referenced by the StatefulSet). +# Replace with real values; for production use a sealed/encrypted secret instead +# of committing plaintext. +apiVersion: v1 +kind: Secret +metadata: + name: mysql-secret-prod + namespace: prod +type: Opaque +stringData: + MYSQL_PASSWORD: prod123 + MYSQL_ROOT_PASSWORD: prodroot123 diff --git a/mysql-chart/environments/prod/values.yaml b/mysql-chart/environments/prod/values.yaml new file mode 100644 index 0000000..2dd2c20 --- /dev/null +++ b/mysql-chart/environments/prod/values.yaml @@ -0,0 +1,14 @@ +# PROD environment overrides for mysql-chart +namespace: prod + +image: + tag: "8.4" + +storage: + size: 5Gi + +configMap: + name: mysql-config-prod + +secret: + name: mysql-secret-prod diff --git a/mysql-chart/environments/stg/configmap.yaml b/mysql-chart/environments/stg/configmap.yaml new file mode 100644 index 0000000..5fdb302 --- /dev/null +++ b/mysql-chart/environments/stg/configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: mysql-config-stg + namespace: stg + labels: + app: mysql + env: stg +data: + MYSQL_DATABASE: demo_stg + MYSQL_USER: demo diff --git a/mysql-chart/environments/stg/secret.yaml b/mysql-chart/environments/stg/secret.yaml new file mode 100644 index 0000000..28f8987 --- /dev/null +++ b/mysql-chart/environments/stg/secret.yaml @@ -0,0 +1,12 @@ +# MySQL credentials for the STG (staging) environment (referenced by the StatefulSet). +# Replace with real values; for production use a sealed/encrypted secret instead +# of committing plaintext. +apiVersion: v1 +kind: Secret +metadata: + name: mysql-secret-stg + namespace: stg +type: Opaque +stringData: + MYSQL_PASSWORD: stg123 + MYSQL_ROOT_PASSWORD: stgroot123 diff --git a/mysql-chart/environments/stg/values.yaml b/mysql-chart/environments/stg/values.yaml new file mode 100644 index 0000000..a9b0549 --- /dev/null +++ b/mysql-chart/environments/stg/values.yaml @@ -0,0 +1,14 @@ +# STG (staging) environment overrides for mysql-chart +namespace: stg + +image: + tag: "8.4" + +storage: + size: 2Gi + +configMap: + name: mysql-config-stg + +secret: + name: mysql-secret-stg diff --git a/mysql-chart/templates/secret.yaml b/mysql-chart/templates/secret.yaml deleted file mode 100644 index 18bb2f9..0000000 --- a/mysql-chart/templates/secret.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: mysql-secret - namespace: {{ .Values.namespace }} -type: Opaque -stringData: - MYSQL_ROOT_PASSWORD: {{ .Values.mysql.rootPassword }} - MYSQL_PASSWORD: {{ .Values.mysql.password }} diff --git a/mysql-chart/templates/statefulset.yaml b/mysql-chart/templates/statefulset.yaml index 7fede34..064bef9 100644 --- a/mysql-chart/templates/statefulset.yaml +++ b/mysql-chart/templates/statefulset.yaml @@ -1,6 +1,6 @@ apiVersion: apps/v1 kind: StatefulSet -metadata: +metadata: name: mysql namespace: {{ .Values.namespace }} spec: @@ -15,15 +15,20 @@ spec: containers: - name: mysql image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + envFrom: + - configMapRef: + name: {{ .Values.configMap.name }} env: - - name: MYSQL_DATABASE - value: {{ .Values.mysql.database }} - - name: MYSQL_USER - value: {{ .Values.mysql.username }} - name: MYSQL_PASSWORD - valueFrom: {secretKeyRef: {name: mysql-secret,key: MYSQL_PASSWORD}} + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: MYSQL_PASSWORD - name: MYSQL_ROOT_PASSWORD - valueFrom: {secretKeyRef: {name: mysql-secret,key: MYSQL_ROOT_PASSWORD}} + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: MYSQL_ROOT_PASSWORD volumeMounts: - name: mysql-data mountPath: /var/lib/mysql diff --git a/mysql-chart/values.yaml b/mysql-chart/values.yaml index 7105937..3f8abe0 100644 --- a/mysql-chart/values.yaml +++ b/mysql-chart/values.yaml @@ -1,12 +1,31 @@ -namespace: prod +# Base (default) values for mysql-chart. +# +# Environment-specific overrides live in environments//values.yaml and are +# merged on top of this file at deploy time: +# +# helm upgrade --install mysql ./mysql-chart -n --create-namespace \ +# -f mysql-chart/environments//values.yaml +# +# Available environments: dev, stg, prod +# +# NOTE: database credentials are NOT stored here. They live in the environment +# secret (environments//secret.yaml) and the non-secret config lives in +# the environment ConfigMap (environments//configmap.yaml). + +namespace: dev + image: repository: mysql tag: "8.4" -mysql: - database: demo - username: demo - password: demo123 - rootPassword: root123 + storage: storageClass: nfs-client size: 1Gi + +# Names of the ConfigMap / Secret created by environments//configmap.yaml +# and environments//secret.yaml +configMap: + name: mysql-config-dev + +secret: + name: mysql-secret-dev diff --git a/nginx-chart/environments/dev/configmap.yaml b/nginx-chart/environments/dev/configmap.yaml new file mode 100644 index 0000000..96219d8 --- /dev/null +++ b/nginx-chart/environments/dev/configmap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-config-dev + namespace: dev + labels: + app: nginx + env: dev +data: + default.conf: | + server { + listen 80; + server_name nginx.dev.local; + + location / { + return 200 "nginx DEV environment\n"; + add_header Content-Type text/plain; + } + } diff --git a/nginx-chart/environments/dev/secret.yaml b/nginx-chart/environments/dev/secret.yaml new file mode 100644 index 0000000..5f0286a --- /dev/null +++ b/nginx-chart/environments/dev/secret.yaml @@ -0,0 +1,31 @@ +# --------------------------------------------------------------------------- +# Registry pull secret used by the nginx Deployment (imagePullSecrets). +# Replace the credentials with the real registry values, or regenerate with: +# kubectl create secret docker-registry harbor-secret \ +# --docker-server=imageregistry.gen-itech.com \ +# --docker-username=demo --docker-password=demo123 \ +# -n dev --dry-run=client -o yaml +# --------------------------------------------------------------------------- +apiVersion: v1 +kind: Secret +metadata: + name: harbor-secret + namespace: dev +type: kubernetes.io/dockerconfigjson +stringData: + .dockerconfigjson: | + {"auths":{"imageregistry.gen-itech.com":{"username":"demo","password":"demo123","auth":"ZGVtbzpkZW1vMTIz"}}} + +--- +# --------------------------------------------------------------------------- +# Application secret for the nginx container (loaded via envFrom). +# --------------------------------------------------------------------------- +apiVersion: v1 +kind: Secret +metadata: + name: nginx-secret-dev + namespace: dev +type: Opaque +stringData: + APP_ENV: dev + APP_SECRET: change-me-dev diff --git a/nginx-chart/environments/dev/values.yaml b/nginx-chart/environments/dev/values.yaml new file mode 100644 index 0000000..5661406 --- /dev/null +++ b/nginx-chart/environments/dev/values.yaml @@ -0,0 +1,16 @@ +# DEV environment overrides for nginx-chart +namespace: dev + +replicaCount: 1 + +image: + tag: "39" + +ingress: + host: nginx.dev.local + +configMap: + name: nginx-config-dev + +secret: + name: nginx-secret-dev diff --git a/nginx-chart/environments/prod/configmap.yaml b/nginx-chart/environments/prod/configmap.yaml new file mode 100644 index 0000000..a9ccbc0 --- /dev/null +++ b/nginx-chart/environments/prod/configmap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-config-prod + namespace: prod + labels: + app: nginx + env: prod +data: + default.conf: | + server { + listen 80; + server_name nginx.prod.local; + + location / { + return 200 "nginx PROD environment\n"; + add_header Content-Type text/plain; + } + } diff --git a/nginx-chart/environments/prod/secret.yaml b/nginx-chart/environments/prod/secret.yaml new file mode 100644 index 0000000..5afbc11 --- /dev/null +++ b/nginx-chart/environments/prod/secret.yaml @@ -0,0 +1,31 @@ +# --------------------------------------------------------------------------- +# Registry pull secret used by the nginx Deployment (imagePullSecrets). +# Replace the credentials with the real registry values, or regenerate with: +# kubectl create secret docker-registry harbor-secret \ +# --docker-server=imageregistry.gen-itech.com \ +# --docker-username=demo --docker-password=demo123 \ +# -n prod --dry-run=client -o yaml +# --------------------------------------------------------------------------- +apiVersion: v1 +kind: Secret +metadata: + name: harbor-secret + namespace: prod +type: kubernetes.io/dockerconfigjson +stringData: + .dockerconfigjson: | + {"auths":{"imageregistry.gen-itech.com":{"username":"demo","password":"demo123","auth":"ZGVtbzpkZW1vMTIz"}}} + +--- +# --------------------------------------------------------------------------- +# Application secret for the nginx container (loaded via envFrom). +# --------------------------------------------------------------------------- +apiVersion: v1 +kind: Secret +metadata: + name: nginx-secret-prod + namespace: prod +type: Opaque +stringData: + APP_ENV: prod + APP_SECRET: change-me-prod diff --git a/nginx-chart/environments/prod/values.yaml b/nginx-chart/environments/prod/values.yaml new file mode 100644 index 0000000..e54ae6d --- /dev/null +++ b/nginx-chart/environments/prod/values.yaml @@ -0,0 +1,16 @@ +# PROD environment overrides for nginx-chart +namespace: prod + +replicaCount: 3 + +image: + tag: "39" + +ingress: + host: nginx.prod.local + +configMap: + name: nginx-config-prod + +secret: + name: nginx-secret-prod diff --git a/nginx-chart/environments/stg/configmap.yaml b/nginx-chart/environments/stg/configmap.yaml new file mode 100644 index 0000000..4dfdf29 --- /dev/null +++ b/nginx-chart/environments/stg/configmap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-config-stg + namespace: stg + labels: + app: nginx + env: stg +data: + default.conf: | + server { + listen 80; + server_name nginx.stg.local; + + location / { + return 200 "nginx STG environment\n"; + add_header Content-Type text/plain; + } + } diff --git a/nginx-chart/environments/stg/secret.yaml b/nginx-chart/environments/stg/secret.yaml new file mode 100644 index 0000000..e3ab151 --- /dev/null +++ b/nginx-chart/environments/stg/secret.yaml @@ -0,0 +1,31 @@ +# --------------------------------------------------------------------------- +# Registry pull secret used by the nginx Deployment (imagePullSecrets). +# Replace the credentials with the real registry values, or regenerate with: +# kubectl create secret docker-registry harbor-secret \ +# --docker-server=imageregistry.gen-itech.com \ +# --docker-username=demo --docker-password=demo123 \ +# -n stg --dry-run=client -o yaml +# --------------------------------------------------------------------------- +apiVersion: v1 +kind: Secret +metadata: + name: harbor-secret + namespace: stg +type: kubernetes.io/dockerconfigjson +stringData: + .dockerconfigjson: | + {"auths":{"imageregistry.gen-itech.com":{"username":"demo","password":"demo123","auth":"ZGVtbzpkZW1vMTIz"}}} + +--- +# --------------------------------------------------------------------------- +# Application secret for the nginx container (loaded via envFrom). +# --------------------------------------------------------------------------- +apiVersion: v1 +kind: Secret +metadata: + name: nginx-secret-stg + namespace: stg +type: Opaque +stringData: + APP_ENV: stg + APP_SECRET: change-me-stg diff --git a/nginx-chart/environments/stg/values.yaml b/nginx-chart/environments/stg/values.yaml new file mode 100644 index 0000000..a88267c --- /dev/null +++ b/nginx-chart/environments/stg/values.yaml @@ -0,0 +1,16 @@ +# STG (staging) environment overrides for nginx-chart +namespace: stg + +replicaCount: 2 + +image: + tag: "39" + +ingress: + host: nginx.stg.local + +configMap: + name: nginx-config-stg + +secret: + name: nginx-secret-stg diff --git a/nginx-chart/templates/deployment.yaml b/nginx-chart/templates/deployment.yaml index 139cdb1..c8abe09 100644 --- a/nginx-chart/templates/deployment.yaml +++ b/nginx-chart/templates/deployment.yaml @@ -18,9 +18,21 @@ spec: app: nginx spec: imagePullSecrets: - - name: harbor-secret + - name: {{ .Values.imagePullSecrets }} containers: - name: nginx image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - containerPort: 80 \ No newline at end of file + - containerPort: 80 + envFrom: + - secretRef: + name: {{ .Values.secret.name }} + volumeMounts: + - name: nginx-config + mountPath: /etc/nginx/conf.d/default.conf + subPath: default.conf + volumes: + - name: nginx-config + configMap: + name: {{ .Values.configMap.name }} diff --git a/nginx-chart/values.yaml b/nginx-chart/values.yaml index 235ca92..1e0bced 100644 --- a/nginx-chart/values.yaml +++ b/nginx-chart/values.yaml @@ -1,13 +1,38 @@ +# Base (default) values for nginx-chart. +# +# Environment-specific overrides live in environments//values.yaml and are +# merged on top of this file at deploy time: +# +# helm upgrade --install nginx ./nginx-chart -n --create-namespace \ +# -f nginx-chart/environments//values.yaml +# +# Available environments: dev, stg, prod + replicaCount: 1 -namespace: "dev" + +namespace: dev + image: repository: imageregistry.gen-itech.com/demo/applicationtest tag: "39" pullPolicy: IfNotPresent + +# Name of the docker-registry pull secret (created by environments//secret.yaml) +imagePullSecrets: harbor-secret + service: type: ClusterIP port: 80 + ingress: enabled: true className: traefik host: nginx.demo.local + +# Names of the ConfigMap / Secret created by environments//configmap.yaml +# and environments//secret.yaml +configMap: + name: nginx-config-dev + +secret: + name: nginx-secret-dev