feat: Add container registry support and Kustomize foundation
- Add registry secret template for private container registry authentication - Fix frontend deployment to use imagePullSecrets for private registry - Enhance deploy-k8s.sh with registry authentication handling - Add PVC storage size validation to prevent storage reduction errors - Add graceful StatefulSet update error handling - Fix template variable substitution for DOCKER_IMAGE - Remove conflicting static PVC file that had unprocessed template variables - Add Kustomize structure as alternative to shell script templates: - Base configuration with common resources - Development overlay with dev-specific configurations - Support for environment-specific image tags and resource limits Registry setup requires setting REGISTRY_USERNAME, REGISTRY_PASSWORD, and optionally REGISTRY_HOST in .env file for private registry authentication.
This commit is contained in:
45
k8s-kustomize/base/frontend-deployment.yaml
Normal file
45
k8s-kustomize/base/frontend-deployment.yaml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: rxminder-frontend
|
||||||
|
labels:
|
||||||
|
component: frontend
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
component: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
component: frontend
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: rxminder-registry-secret
|
||||||
|
containers:
|
||||||
|
- name: frontend
|
||||||
|
image: frontend-image
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: rxminder-config
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: '32Mi'
|
||||||
|
cpu: '20m'
|
||||||
|
limits:
|
||||||
|
memory: '64Mi'
|
||||||
|
cpu: '40m'
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 30
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
60
k8s-kustomize/base/kustomization.yaml
Normal file
60
k8s-kustomize/base/kustomization.yaml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
name: rxminder-base
|
||||||
|
|
||||||
|
namespace: rxminder
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- frontend-deployment.yaml
|
||||||
|
- frontend-service.yaml
|
||||||
|
- couchdb-statefulset.yaml
|
||||||
|
- couchdb-service.yaml
|
||||||
|
- couchdb-pvc.yaml
|
||||||
|
- ingress.yaml
|
||||||
|
- configmap.yaml
|
||||||
|
- network-policy.yaml
|
||||||
|
- hpa.yaml
|
||||||
|
- db-seed-job.yaml
|
||||||
|
|
||||||
|
# Common labels applied to all resources
|
||||||
|
commonLabels:
|
||||||
|
app: rxminder
|
||||||
|
version: v1.0.0
|
||||||
|
|
||||||
|
# Generate ConfigMap from environment files
|
||||||
|
configMapGenerator:
|
||||||
|
- name: rxminder-config
|
||||||
|
envs:
|
||||||
|
- config.env
|
||||||
|
|
||||||
|
# Generate Secret for CouchDB
|
||||||
|
secretGenerator:
|
||||||
|
- name: couchdb-secret
|
||||||
|
literals:
|
||||||
|
- username=admin
|
||||||
|
- password=changeme
|
||||||
|
type: Opaque
|
||||||
|
|
||||||
|
# Generate registry secret from credentials
|
||||||
|
- name: rxminder-registry-secret
|
||||||
|
files:
|
||||||
|
- .dockerconfigjson=registry-config.json
|
||||||
|
type: kubernetes.io/dockerconfigjson
|
||||||
|
|
||||||
|
# Images to be used (can be overridden in overlays)
|
||||||
|
images:
|
||||||
|
- name: frontend-image
|
||||||
|
newName: gitea-http.taildb3494.ts.net/will/rxminder
|
||||||
|
newTag: latest
|
||||||
|
- name: couchdb-image
|
||||||
|
newName: couchdb
|
||||||
|
newTag: 3.3.2
|
||||||
|
|
||||||
|
# Replicas (can be overridden in overlays)
|
||||||
|
replicas:
|
||||||
|
- name: rxminder-frontend
|
||||||
|
count: 1
|
||||||
|
- name: rxminder-couchdb
|
||||||
|
count: 1
|
||||||
83
k8s-kustomize/overlays/dev/kustomization.yaml
Normal file
83
k8s-kustomize/overlays/dev/kustomization.yaml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
name: rxminder-dev
|
||||||
|
|
||||||
|
namespace: rxminder-dev
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- ../../base
|
||||||
|
|
||||||
|
# Development-specific labels
|
||||||
|
commonLabels:
|
||||||
|
environment: dev
|
||||||
|
|
||||||
|
# Override images for development
|
||||||
|
images:
|
||||||
|
- name: frontend-image
|
||||||
|
newName: gitea-http.taildb3494.ts.net/will/rxminder
|
||||||
|
newTag: dev
|
||||||
|
- name: couchdb-image
|
||||||
|
newName: couchdb
|
||||||
|
newTag: 3.3.2
|
||||||
|
|
||||||
|
# Development replicas (lower for resource conservation)
|
||||||
|
replicas:
|
||||||
|
- name: rxminder-frontend
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
# Development-specific patches
|
||||||
|
patches:
|
||||||
|
- target:
|
||||||
|
kind: Deployment
|
||||||
|
name: rxminder-frontend
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/resources/requests/memory
|
||||||
|
value: "16Mi"
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/resources/limits/memory
|
||||||
|
value: "32Mi"
|
||||||
|
- op: add
|
||||||
|
path: /spec/template/spec/containers/0/env
|
||||||
|
value:
|
||||||
|
- name: NODE_ENV
|
||||||
|
value: "development"
|
||||||
|
- name: LOG_LEVEL
|
||||||
|
value: "debug"
|
||||||
|
|
||||||
|
- target:
|
||||||
|
kind: Ingress
|
||||||
|
name: rxminder-ingress
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/rules/0/host
|
||||||
|
value: "rxminder-dev.local"
|
||||||
|
|
||||||
|
- target:
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
name: rxminder-couchdb-pvc
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/resources/requests/storage
|
||||||
|
value: "1Gi"
|
||||||
|
|
||||||
|
# Development-specific ConfigMap
|
||||||
|
configMapGenerator:
|
||||||
|
- name: rxminder-config
|
||||||
|
literals:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- API_URL=http://rxminder-couchdb-service:5984
|
||||||
|
- LOG_LEVEL=debug
|
||||||
|
- DEBUG=true
|
||||||
|
behavior: replace
|
||||||
|
|
||||||
|
# Development secrets (use weak passwords for dev)
|
||||||
|
secretGenerator:
|
||||||
|
- name: couchdb-secret
|
||||||
|
literals:
|
||||||
|
- username=admin
|
||||||
|
- password=devpass123
|
||||||
|
type: Opaque
|
||||||
|
behavior: replace
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: ${APP_NAME}-couchdb-pvc
|
|
||||||
labels:
|
|
||||||
app: ${APP_NAME}
|
|
||||||
component: database
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
storageClassName: ${STORAGE_CLASS}
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: ${STORAGE_SIZE}
|
|
||||||
@@ -17,9 +17,11 @@ spec:
|
|||||||
app: ${APP_NAME}
|
app: ${APP_NAME}
|
||||||
component: frontend
|
component: frontend
|
||||||
spec:
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: ${APP_NAME}-registry-secret
|
||||||
containers:
|
containers:
|
||||||
- name: frontend
|
- name: frontend
|
||||||
image: ${DOCKER_IMAGE:-gitea-http.taildb3494.ts.net/will/${APP_NAME}:latest}
|
image: ${DOCKER_IMAGE}
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
envFrom:
|
envFrom:
|
||||||
|
|||||||
10
k8s/registry-secret.yaml.template
Normal file
10
k8s/registry-secret.yaml.template
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: ${APP_NAME}-registry-secret
|
||||||
|
labels:
|
||||||
|
app: ${APP_NAME}
|
||||||
|
component: registry
|
||||||
|
type: kubernetes.io/dockerconfigjson
|
||||||
|
data:
|
||||||
|
.dockerconfigjson: ${REGISTRY_AUTH_BASE64}
|
||||||
@@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
# Kubernetes deployment script with environment variable substitution
|
# Kubernetes deployment script with environment variable substitution
|
||||||
# This script processes template files and applies them to Kubernetes
|
# This script processes template files and applies them to Kubernetes
|
||||||
|
#
|
||||||
|
# Registry Authentication Setup:
|
||||||
|
# To pull images from a private registry, set these environment variables:
|
||||||
|
# REGISTRY_USERNAME - Username for the container registry
|
||||||
|
# REGISTRY_PASSWORD - Password/token for the container registry
|
||||||
|
# REGISTRY_HOST - Registry hostname (default: gitea-http.taildb3494.ts.net)
|
||||||
|
#
|
||||||
|
# Example in .env file:
|
||||||
|
# REGISTRY_USERNAME=your-username
|
||||||
|
# REGISTRY_PASSWORD=your-password-or-token
|
||||||
|
# REGISTRY_HOST=gitea-http.taildb3494.ts.net
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -72,6 +83,20 @@ substitute_templates() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Function to create registry authentication
|
||||||
|
create_registry_auth() {
|
||||||
|
if [[ -n "${REGISTRY_USERNAME:-}" && -n "${REGISTRY_PASSWORD:-}" ]]; then
|
||||||
|
local registry_host="${REGISTRY_HOST:-gitea-http.taildb3494.ts.net}"
|
||||||
|
local auth_string=$(echo -n "${REGISTRY_USERNAME}:${REGISTRY_PASSWORD}" | base64 -w 0)
|
||||||
|
local docker_config="{\"auths\":{\"${registry_host}\":{\"auth\":\"${auth_string}\"}}}"
|
||||||
|
export REGISTRY_AUTH_BASE64=$(echo -n "$docker_config" | base64 -w 0)
|
||||||
|
print_info "Registry authentication configured for $registry_host"
|
||||||
|
else
|
||||||
|
print_warning "Registry credentials not provided - skipping registry secret creation"
|
||||||
|
export REGISTRY_AUTH_BASE64=""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Function to validate required environment variables
|
# Function to validate required environment variables
|
||||||
validate_env() {
|
validate_env() {
|
||||||
local required_vars=("INGRESS_HOST")
|
local required_vars=("INGRESS_HOST")
|
||||||
@@ -105,6 +130,44 @@ ensure_namespace() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Function to convert Kubernetes storage units to bytes
|
||||||
|
storage_to_bytes() {
|
||||||
|
local storage="$1"
|
||||||
|
local number=$(echo "$storage" | sed 's/[^0-9]*//g')
|
||||||
|
local unit=$(echo "$storage" | sed 's/[0-9]*//g')
|
||||||
|
|
||||||
|
case "$unit" in
|
||||||
|
"Ki"|"K") echo $((number * 1024)) ;;
|
||||||
|
"Mi"|"M") echo $((number * 1024 * 1024)) ;;
|
||||||
|
"Gi"|"G") echo $((number * 1024 * 1024 * 1024)) ;;
|
||||||
|
"Ti"|"T") echo $((number * 1024 * 1024 * 1024 * 1024)) ;;
|
||||||
|
"") echo "$number" ;;
|
||||||
|
*) echo "0" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if PVC storage can be updated
|
||||||
|
can_update_pvc_storage() {
|
||||||
|
local pvc_file="$1"
|
||||||
|
local pvc_name=$(grep "name:" "$pvc_file" | head -1 | awk '{print $2}')
|
||||||
|
local new_storage=$(grep "storage:" "$pvc_file" | awk '{print $2}')
|
||||||
|
|
||||||
|
# Check if PVC exists
|
||||||
|
if kubectl get pvc "$pvc_name" -n "$NAMESPACE" &> /dev/null; then
|
||||||
|
local current_storage=$(kubectl get pvc "$pvc_name" -n "$NAMESPACE" -o jsonpath='{.status.capacity.storage}')
|
||||||
|
|
||||||
|
# Convert storage sizes to bytes for comparison
|
||||||
|
local current_bytes=$(storage_to_bytes "$current_storage")
|
||||||
|
local new_bytes=$(storage_to_bytes "$new_storage")
|
||||||
|
|
||||||
|
if [[ "$new_bytes" -lt "$current_bytes" ]]; then
|
||||||
|
print_warning "Skipping PVC $pvc_name: cannot reduce storage from $current_storage to $new_storage"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# Function to apply Kubernetes manifests
|
# Function to apply Kubernetes manifests
|
||||||
apply_manifests() {
|
apply_manifests() {
|
||||||
local manifest_dir="$1"
|
local manifest_dir="$1"
|
||||||
@@ -129,8 +192,29 @@ apply_manifests() {
|
|||||||
if [[ -d "$TEMP_DIR" ]]; then
|
if [[ -d "$TEMP_DIR" ]]; then
|
||||||
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
||||||
if [[ -f "$manifest_file" ]]; then
|
if [[ -f "$manifest_file" ]]; then
|
||||||
print_info "Applying template: $(basename "$manifest_file")"
|
local basename_file=$(basename "$manifest_file")
|
||||||
kubectl apply -f "$manifest_file" -n "$NAMESPACE"
|
|
||||||
|
# Special handling for PVC files
|
||||||
|
if [[ "$basename_file" == *"pvc.yaml" ]] && grep -q "kind: PersistentVolumeClaim" "$manifest_file"; then
|
||||||
|
if can_update_pvc_storage "$manifest_file"; then
|
||||||
|
print_info "Applying template: $basename_file"
|
||||||
|
kubectl apply -f "$manifest_file" -n "$NAMESPACE"
|
||||||
|
fi
|
||||||
|
# Special handling for registry secret - skip if no auth provided
|
||||||
|
elif [[ "$basename_file" == *"registry-secret.yaml" ]] && [[ -z "${REGISTRY_AUTH_BASE64:-}" ]]; then
|
||||||
|
print_info "Skipping registry secret: no registry credentials provided"
|
||||||
|
else
|
||||||
|
print_info "Applying template: $basename_file"
|
||||||
|
if ! kubectl apply -f "$manifest_file" -n "$NAMESPACE" 2>/dev/null; then
|
||||||
|
# Handle StatefulSet update failures gracefully
|
||||||
|
if [[ "$basename_file" == *"statefulset.yaml" ]] && grep -q "kind: StatefulSet" "$manifest_file"; then
|
||||||
|
print_warning "StatefulSet update failed (likely due to immutable fields) - continuing deployment"
|
||||||
|
else
|
||||||
|
# Re-run the command to show the actual error for non-StatefulSet resources
|
||||||
|
kubectl apply -f "$manifest_file" -n "$NAMESPACE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -255,9 +339,18 @@ main() {
|
|||||||
# Load environment variables
|
# Load environment variables
|
||||||
load_env "$env_file"
|
load_env "$env_file"
|
||||||
|
|
||||||
|
# Set default values for required variables
|
||||||
|
export APP_NAME="${APP_NAME:-rxminder}"
|
||||||
|
export STORAGE_CLASS="${STORAGE_CLASS:-longhorn}"
|
||||||
|
export STORAGE_SIZE="${STORAGE_SIZE:-5Gi}"
|
||||||
|
export DOCKER_IMAGE="${DOCKER_IMAGE:-gitea-http.taildb3494.ts.net/will/rxminder:latest}"
|
||||||
|
|
||||||
# Set default namespace if not provided in environment
|
# Set default namespace if not provided in environment
|
||||||
NAMESPACE="${NAMESPACE:-rxminder}"
|
NAMESPACE="${NAMESPACE:-rxminder}"
|
||||||
|
|
||||||
|
# Create registry authentication if credentials are provided
|
||||||
|
create_registry_auth
|
||||||
|
|
||||||
# Validate required environment variables
|
# Validate required environment variables
|
||||||
validate_env
|
validate_env
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user