From d207146423f61436b39a8060ad21dd7424cc664d Mon Sep 17 00:00:00 2001 From: cialloo Date: Sat, 25 Oct 2025 08:43:42 +0800 Subject: [PATCH] update --- .github/workflows/cd.yml | 83 +++++++++++++ .github/workflows/ci.yml | 46 +++++++ Dockerfile | 40 ++++++ app/etc/blog.yaml | 20 +-- script/cd.sh | 242 +++++++++++++++++++++++++++++++++++++ script/ci.sh | 121 +++++++++++++++++++ script/k8s/deployment.yaml | 94 ++++++++++++++ script/k8s/ingress.yaml | 25 ++++ script/k8s/namespace.yaml | 7 ++ script/k8s/service.yaml | 19 +++ 10 files changed, 687 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/cd.yml create mode 100644 .github/workflows/ci.yml create mode 100644 Dockerfile create mode 100644 script/cd.sh create mode 100644 script/ci.sh create mode 100644 script/k8s/deployment.yaml create mode 100644 script/k8s/ingress.yaml create mode 100644 script/k8s/namespace.yaml create mode 100644 script/k8s/service.yaml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..d76b2b5 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,83 @@ +# Continuous Deployment Workflow +# This workflow deploys your application to Kubernetes cluster +# Trigger: After successful CI build or manual dispatch + +name: CD - Deploy to Kubernetes + +on: + workflow_run: + workflows: ["CI - Build and Push"] + types: + - completed + branches: + - master + workflow_dispatch: + +env: + # Kubernetes configuration + KUBECONFIG_DATA: ${{ secrets.KUBECONFIG_DATA }} + KUBERNETES_URL: ${{ secrets.KUBERNETES_URL }} + KUBERNETES_NAMESPACE: ${{ secrets.KUBERNETES_NAMESPACE }} + KUBERNETES_INGRESS_HOST: ${{ secrets.KUBERNETES_INGRESS_HOST }} + KUBERNETES_DEPLOYMENT_REPLICAS: ${{ secrets.KUBERNETES_DEPLOYMENT_REPLICAS }} + + # Container registry configuration + CONTAINER_REGISTRY_URL: ${{ secrets.CONTAINER_REGISTRY_URL }} + CONTAINER_REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} + CONTAINER_REGISTRY_NAMESPACE: ${{ secrets.CONTAINER_REGISTRY_NAMESPACE }} + CONTAINER_REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} + CONTAINER_IMAGE_NAME: ${{ secrets.CONTAINER_IMAGE_NAME }} + CONTAINER_IMAGE_TAG: ${{ secrets.CONTAINER_IMAGE_TAG }} + FORCE_RESTART: ${{ secrets.KUBERNETES_FORCE_RESTART }} + + # Application configuration + DATABASE_DSN: ${{ secrets.DATABASE_DSN }} + JWT_SECRET: ${{ secrets.JWT_SECRET }} + JWT_ISSUER: ${{ secrets.JWT_ISSUER }} + JWT_EXPIRES_IN: ${{ secrets.JWT_EXPIRES_IN }} + S3_REGION: ${{ secrets.S3_REGION }} + S3_BUCKET: ${{ secrets.S3_BUCKET }} + S3_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} + S3_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} + S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }} + S3_PRESIGNED_URL_EXPIRATION: ${{ secrets.S3_PRESIGNED_URL_EXPIRATION }} + +jobs: + deploy: + name: Deploy to Kubernetes + runs-on: ubuntu-latest + # Only run if CI workflow succeeded or manually dispatched + if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Make CD script executable + run: chmod +x script/cd.sh + + - name: Deploy to Kubernetes + run: ./script/cd.sh deploy + + - name: Deployment Summary + if: success() + run: | + echo "### :white_check_mark: Deployment Successful!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Application:** \`${CONTAINER_IMAGE_NAME}\`" >> $GITHUB_STEP_SUMMARY + echo "**Namespace:** \`${KUBERNETES_NAMESPACE}\`" >> $GITHUB_STEP_SUMMARY + echo "**Image:** \`${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}\`" >> $GITHUB_STEP_SUMMARY + echo "**Database:** Connected" >> $GITHUB_STEP_SUMMARY + echo "**S3 Bucket:** ${S3_BUCKET}" >> $GITHUB_STEP_SUMMARY + echo "**URL:** http://${KUBERNETES_INGRESS_HOST}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "---" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Deployment Time:** $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY + + - name: Deployment Failed + if: failure() + run: | + echo "### :x: Deployment Failed!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Please check the logs above for error details." >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c6847f2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +# Continuous Integration Workflow +# This workflow builds and pushes Docker images to your private registry +# Trigger: Push to master branch or manual dispatch + +name: CI - Build and Push + +on: + push: + branches: + - master + workflow_dispatch: + +env: + CONTAINER_REGISTRY_URL: ${{ secrets.CONTAINER_REGISTRY_URL }} + CONTAINER_REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} + CONTAINER_REGISTRY_NAMESPACE: ${{ secrets.CONTAINER_REGISTRY_NAMESPACE }} + CONTAINER_REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} + CONTAINER_IMAGE_NAME: ${{ secrets.CONTAINER_IMAGE_NAME }} + CONTAINER_IMAGE_TAG: ${{ secrets.CONTAINER_IMAGE_TAG }} + +jobs: + build-and-push: + name: Build and Push Docker Image + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Make CI script executable + run: chmod +x script/ci.sh + + - name: Build Docker image + run: ./script/ci.sh build + + - name: Push Docker image + run: ./script/ci.sh push + + - name: Summary + run: | + echo "### :rocket: Build Complete!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Image:** \`${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Registry:** ${CONTAINER_REGISTRY_URL}" >> $GITHUB_STEP_SUMMARY + echo "**Tag:** ${CONTAINER_IMAGE_TAG}" >> $GITHUB_STEP_SUMMARY diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2564608 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +# Build stage +FROM golang:1.24.4-alpine AS builder + +# Install build dependencies +RUN apk add --no-cache git + +# Set working directory +WORKDIR /build + +# Copy go mod files from root directory +COPY go.mod go.sum ./ + +# Download dependencies +RUN go mod download + +# Copy the entire app directory to maintain the module structure +COPY app/ ./app/ + +# Build the application from the app directory +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o blog ./app/blog.go + +# Production stage +FROM alpine:latest + +# Install ca-certificates for HTTPS +RUN apk --no-cache add ca-certificates + +WORKDIR /root/ + +# Copy binary from builder +COPY --from=builder /build/blog . + +# Copy config file +COPY app/etc/blog.yaml ./etc/ + +# Expose port +EXPOSE 8888 + +# Run the application +CMD ["./blog", "-f", "etc/blog.yaml"] diff --git a/app/etc/blog.yaml b/app/etc/blog.yaml index 847d6f5..1b24796 100644 --- a/app/etc/blog.yaml +++ b/app/etc/blog.yaml @@ -3,17 +3,17 @@ Host: 0.0.0.0 Port: 8888 JWT: - Secret: your-secret-key-change-in-production - Issuer: cialloo-authenticator - ExpiresIn: 604800 # 7 days in seconds + Secret: "${JWT_SECRET}" + Issuer: "${JWT_ISSUER}" + ExpiresIn: "${JWT_EXPIRES_IN}" Database: - DSN: "${DATABASE_DSN}" # postgres: host=localhost port=5432 user=postgres password=your_password dbname=steam_union sslmode=disable + DSN: "${DATABASE_DSN}" S3: - Region: us-east-1 - Bucket: your-bucket-name - AccessKeyID: your-access-key-id - SecretAccessKey: your-secret-access-key - Endpoint: # Optional: for custom S3-compatible endpoints (e.g., MinIO) - PresignedURLExpiration: 3600 # Expiration time in seconds (default 1 hour) + Region: "${S3_REGION}" + Bucket: "${S3_BUCKET}" + AccessKeyID: "${S3_ACCESS_KEY_ID}" + SecretAccessKey: "${S3_SECRET_ACCESS_KEY}" + Endpoint: "${S3_ENDPOINT}" + PresignedURLExpiration: "${S3_PRESIGNED_URL_EXPIRATION}" diff --git a/script/cd.sh b/script/cd.sh new file mode 100644 index 0000000..8458533 --- /dev/null +++ b/script/cd.sh @@ -0,0 +1,242 @@ +#!/bin/bash + +# Continuous Deployment Script for Kubernetes +# This script deploys your application to a Kubernetes cluster + +# ============================================================================= +# Environment Variables (with default values) +# ============================================================================= + +# Kubernetes Configuration +KUBECONFIG_DATA="${KUBECONFIG_DATA:-}" +KUBERNETES_URL="${KUBERNETES_URL:-https://kubernetes.default.svc}" +KUBERNETES_NAMESPACE="${KUBERNETES_NAMESPACE:-default}" +KUBERNETES_INGRESS_HOST="${KUBERNETES_INGRESS_HOST:-blog-api.example.com}" +KUBERNETES_DEPLOYMENT_REPLICAS="${KUBERNETES_DEPLOYMENT_REPLICAS:-2}" + +# Container Registry +CONTAINER_REGISTRY_URL="${CONTAINER_REGISTRY_URL:-127.0.0.1}" +CONTAINER_REGISTRY_USERNAME="${CONTAINER_REGISTRY_USERNAME:-username}" +CONTAINER_REGISTRY_NAMESPACE="${CONTAINER_REGISTRY_NAMESPACE:-username}" +CONTAINER_REGISTRY_PASSWORD="${CONTAINER_REGISTRY_PASSWORD:-password}" +CONTAINER_IMAGE_NAME="${CONTAINER_IMAGE_NAME:-blog}" +CONTAINER_IMAGE_TAG="${CONTAINER_IMAGE_TAG:-latest}" + +# Application Configuration +DATABASE_DSN="${DATABASE_DSN:-postgres://postgres:password@localhost:5432/steam_union?sslmode=disable}" +JWT_SECRET="${JWT_SECRET:-your-secret-key-change-in-production}" +JWT_ISSUER="${JWT_ISSUER:-cialloo-authenticator}" +JWT_EXPIRES_IN="${JWT_EXPIRES_IN:-604800}" +S3_REGION="${S3_REGION:-us-east-1}" +S3_BUCKET="${S3_BUCKET:-your-bucket-name}" +S3_ACCESS_KEY_ID="${S3_ACCESS_KEY_ID:-your-access-key-id}" +S3_SECRET_ACCESS_KEY="${S3_SECRET_ACCESS_KEY:-your-secret-access-key}" +S3_ENDPOINT="${S3_ENDPOINT:-}" +S3_PRESIGNED_URL_EXPIRATION="${S3_PRESIGNED_URL_EXPIRATION:-3600}" +FORCE_RESTART="${FORCE_RESTART:-true}" + +# ============================================================================= +# Functions +# ============================================================================= + +# Print help message +print_help() { + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Environment Variables:" + echo " KUBECONFIG_DATA Kubernetes config data (base64 encoded)" + echo " KUBERNETES_URL Kubernetes API URL (default: https://kubernetes.default.svc)" + echo " KUBERNETES_NAMESPACE Kubernetes namespace (default: default)" + echo " KUBERNETES_INGRESS_HOST Ingress host (default: blog-api.example.com)" + echo " KUBERNETES_DEPLOYMENT_REPLICAS Number of pod replicas (default: 2)" + echo " CONTAINER_REGISTRY_URL Container registry URL (default: 127.0.0.1)" + echo " CONTAINER_REGISTRY_USERNAME Registry username" + echo " CONTAINER_REGISTRY_PASSWORD Registry password" + echo " CONTAINER_IMAGE_NAME Image name (default: blog)" + echo " CONTAINER_IMAGE_TAG Image tag (default: latest)" + echo " DATABASE_DSN Database connection string" + echo " JWT_SECRET JWT secret key" + echo " JWT_ISSUER JWT issuer" + echo " JWT_EXPIRES_IN JWT expiration time in seconds" + echo " S3_REGION S3 region" + echo " S3_BUCKET S3 bucket name" + echo " S3_ACCESS_KEY_ID S3 access key ID" + echo " S3_SECRET_ACCESS_KEY S3 secret access key" + echo " S3_ENDPOINT S3 endpoint (optional)" + echo " S3_PRESIGNED_URL_EXPIRATION Presigned URL expiration in seconds" + echo " FORCE_RESTART Force rollout restart (default: true)" + echo "" + echo "Commands:" + echo " deploy Deploy application to Kubernetes" + echo " help Show this help message (default)" +} + +# Setup kubectl configuration +setup_kubectl() { + echo "Setting up kubectl configuration..." + + if [ -z "${KUBECONFIG_DATA}" ]; then + echo "✗ KUBECONFIG_DATA is not set" + return 1 + fi + + mkdir -p ~/.kube + echo "${KUBECONFIG_DATA}" | base64 -d > ~/.kube/config + chmod 600 ~/.kube/config + + echo "✓ kubectl configured" + return 0 +} + +# Create namespace if it doesn't exist +create_namespace() { + echo "Checking namespace: ${KUBERNETES_NAMESPACE}" + + kubectl get namespace "${KUBERNETES_NAMESPACE}" &> /dev/null + + if [ $? -ne 0 ]; then + echo "Creating namespace: ${KUBERNETES_NAMESPACE}" + kubectl create namespace "${KUBERNETES_NAMESPACE}" + else + echo "✓ Namespace exists: ${KUBERNETES_NAMESPACE}" + fi +} + +# Create image pull secret +create_image_pull_secret() { + echo "Creating image pull secret..." + + kubectl create secret docker-registry regcred \ + --docker-server="${CONTAINER_REGISTRY_URL}" \ + --docker-username="${CONTAINER_REGISTRY_USERNAME}" \ + --docker-password="${CONTAINER_REGISTRY_PASSWORD}" \ + --namespace="${KUBERNETES_NAMESPACE}" \ + --dry-run=client -o yaml | kubectl apply -f - + + echo "✓ Image pull secret created/updated" +} + +# Create or update application secrets +create_app_secrets() { + echo "Creating application secrets..." + + kubectl create secret generic blog-secrets \ + --from-literal=database-dsn="${DATABASE_DSN}" \ + --from-literal=jwt-secret="${JWT_SECRET}" \ + --from-literal=s3-access-key-id="${S3_ACCESS_KEY_ID}" \ + --from-literal=s3-secret-access-key="${S3_SECRET_ACCESS_KEY}" \ + --namespace="${KUBERNETES_NAMESPACE}" \ + --dry-run=client -o yaml | kubectl apply -f - + + echo "✓ Application secrets created/updated" +} + +# Apply Kubernetes manifests +apply_manifests() { + echo "Applying Kubernetes manifests..." + + # Substitute environment variables in manifests + export KUBERNETES_NAMESPACE + export KUBERNETES_INGRESS_HOST + export KUBERNETES_DEPLOYMENT_REPLICAS + export CONTAINER_REGISTRY_URL + export CONTAINER_REGISTRY_NAMESPACE + export CONTAINER_IMAGE_NAME + export CONTAINER_IMAGE_TAG + export JWT_ISSUER + export JWT_EXPIRES_IN + export S3_REGION + export S3_BUCKET + export S3_ENDPOINT + export S3_PRESIGNED_URL_EXPIRATION + + # Apply namespace + envsubst < script/k8s/namespace.yaml | kubectl apply -f - + + # Apply deployment + envsubst < script/k8s/deployment.yaml | kubectl apply -f - + + # Apply service + envsubst < script/k8s/service.yaml | kubectl apply -f - + + # Apply ingress + envsubst < script/k8s/ingress.yaml | kubectl apply -f - + + echo "✓ Manifests applied" +} + +# Wait for deployment to be ready +wait_for_deployment() { + echo "Waiting for deployment to be ready..." + + kubectl rollout status deployment/blog \ + --namespace="${KUBERNETES_NAMESPACE}" \ + --timeout=300s + + if [ $? -eq 0 ]; then + echo "✓ Deployment ready" + return 0 + else + echo "✗ Deployment failed" + return 1 + fi +} + +# Force restart deployment +force_restart_deployment() { + if [ "${FORCE_RESTART}" = "true" ]; then + echo "Forcing deployment restart..." + kubectl rollout restart deployment/blog \ + --namespace="${KUBERNETES_NAMESPACE}" + echo "✓ Deployment restarted" + fi +} + +# Deploy application +deploy() { + echo "==========================================" + echo "Deploying Blog Application" + echo "==========================================" + echo "Namespace: ${KUBERNETES_NAMESPACE}" + echo "Image: ${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}" + echo "Host: ${KUBERNETES_INGRESS_HOST}" + echo "" + + setup_kubectl || return 1 + create_namespace || return 1 + create_image_pull_secret || return 1 + create_app_secrets || return 1 + apply_manifests || return 1 + force_restart_deployment + wait_for_deployment || return 1 + + echo "" + echo "==========================================" + echo "✓ Deployment Successful" + echo "==========================================" + echo "Application URL: http://${KUBERNETES_INGRESS_HOST}" + echo "" + + return 0 +} + +# ============================================================================= +# Main Script +# ============================================================================= + +case "$1" in + deploy) + deploy + exit $? + ;; + help|--help|-h|"") + print_help + exit 0 + ;; + *) + echo "Unknown option: $1" + echo "" + print_help + exit 1 + ;; +esac diff --git a/script/ci.sh b/script/ci.sh new file mode 100644 index 0000000..e81575b --- /dev/null +++ b/script/ci.sh @@ -0,0 +1,121 @@ +#!/bin/bash + +# CI/CD Script for Docker Build and Push +# This script builds a Docker image and pushes it to a private container registry + +# ============================================================================= +# Environment Variables (with default values) +# ============================================================================= +CONTAINER_REGISTRY_URL="${CONTAINER_REGISTRY_URL:-127.0.0.1}" +CONTAINER_REGISTRY_USERNAME="${CONTAINER_REGISTRY_USERNAME:-username}" +CONTAINER_REGISTRY_NAMESPACE="${CONTAINER_REGISTRY_NAMESPACE:-username}" +CONTAINER_REGISTRY_PASSWORD="${CONTAINER_REGISTRY_PASSWORD:-password}" +CONTAINER_IMAGE_NAME="${CONTAINER_IMAGE_NAME:-blog}" +CONTAINER_IMAGE_TAG="${CONTAINER_IMAGE_TAG:-latest}" + +# ============================================================================= +# Functions +# ============================================================================= + +# Print help message +print_help() { + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " build Build Docker image" + echo " push Push Docker image to registry" + echo " help Show this help message (default)" + echo "" + echo "Environment Variables:" + echo " CONTAINER_REGISTRY_URL Registry URL (default: 127.0.0.1)" + echo " CONTAINER_REGISTRY_USERNAME Registry username (default: username)" + echo " CONTAINER_REGISTRY_NAMESPACE Registry namespace (default: username)" + echo " CONTAINER_REGISTRY_PASSWORD Registry password (default: password)" + echo " CONTAINER_IMAGE_NAME Image name (default: blog)" + echo " CONTAINER_IMAGE_TAG Image tag (default: latest)" +} + +# Build Docker image +build_image() { + FULL_IMAGE_NAME="${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}" + + echo "==========================================" + echo "Building Docker Image" + echo "==========================================" + echo "Image: ${FULL_IMAGE_NAME}" + echo "" + + docker build -t "${FULL_IMAGE_NAME}" . + + if [ $? -eq 0 ]; then + echo "" + echo "✓ Build successful: ${FULL_IMAGE_NAME}" + return 0 + else + echo "" + echo "✗ Build failed" + return 1 + fi +} + +# Push Docker image to registry +push_image() { + FULL_IMAGE_NAME="${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}" + + echo "==========================================" + echo "Pushing Docker Image" + echo "==========================================" + echo "Registry: ${CONTAINER_REGISTRY_URL}" + echo "Image: ${FULL_IMAGE_NAME}" + echo "" + + # Login to registry + echo "${CONTAINER_REGISTRY_PASSWORD}" | docker login "${CONTAINER_REGISTRY_URL}" \ + --username "${CONTAINER_REGISTRY_USERNAME}" \ + --password-stdin + + if [ $? -ne 0 ]; then + echo "✗ Registry login failed" + return 1 + fi + + # Push image + docker push "${FULL_IMAGE_NAME}" + + if [ $? -eq 0 ]; then + echo "" + echo "✓ Push successful: ${FULL_IMAGE_NAME}" + docker logout "${CONTAINER_REGISTRY_URL}" + return 0 + else + echo "" + echo "✗ Push failed" + docker logout "${CONTAINER_REGISTRY_URL}" + return 1 + fi +} + +# ============================================================================= +# Main Script +# ============================================================================= + +case "$1" in + build) + build_image + exit $? + ;; + push) + push_image + exit $? + ;; + help|--help|-h|"") + print_help + exit 0 + ;; + *) + echo "Unknown option: $1" + echo "" + print_help + exit 1 + ;; +esac diff --git a/script/k8s/deployment.yaml b/script/k8s/deployment.yaml new file mode 100644 index 0000000..9ef178a --- /dev/null +++ b/script/k8s/deployment.yaml @@ -0,0 +1,94 @@ +# Kubernetes Deployment Configuration +apiVersion: apps/v1 +kind: Deployment +metadata: + name: blog + namespace: ${KUBERNETES_NAMESPACE} + labels: + app: blog +spec: + replicas: ${KUBERNETES_DEPLOYMENT_REPLICAS} + + selector: + matchLabels: + app: blog + + template: + metadata: + labels: + app: blog + spec: + imagePullSecrets: + - name: regcred + + containers: + - name: blog + image: ${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG} + imagePullPolicy: Always + + ports: + - name: http + containerPort: 8888 + protocol: TCP + + readinessProbe: + httpGet: + path: /api/blog/ping + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + + livenessProbe: + httpGet: + path: /api/blog/ping + port: http + initialDelaySeconds: 15 + periodSeconds: 20 + timeoutSeconds: 5 + failureThreshold: 3 + + resources: + requests: + memory: "128Mi" + cpu: "200m" + limits: + memory: "512Mi" + cpu: "1000m" + + env: + - name: TZ + value: "UTC" + - name: DATABASE_DSN + valueFrom: + secretKeyRef: + name: blog-secrets + key: database-dsn + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: blog-secrets + key: jwt-secret + - name: JWT_ISSUER + value: "${JWT_ISSUER}" + - name: JWT_EXPIRES_IN + value: "${JWT_EXPIRES_IN}" + - name: S3_REGION + value: "${S3_REGION}" + - name: S3_BUCKET + value: "${S3_BUCKET}" + - name: S3_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: blog-secrets + key: s3-access-key-id + - name: S3_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: blog-secrets + key: s3-secret-access-key + - name: S3_ENDPOINT + value: "${S3_ENDPOINT}" + - name: S3_PRESIGNED_URL_EXPIRATION + value: "${S3_PRESIGNED_URL_EXPIRATION}" diff --git a/script/k8s/ingress.yaml b/script/k8s/ingress.yaml new file mode 100644 index 0000000..8992d37 --- /dev/null +++ b/script/k8s/ingress.yaml @@ -0,0 +1,25 @@ +# Kubernetes Ingress Configuration for Traefik +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: blog + namespace: ${KUBERNETES_NAMESPACE} + + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: web + + labels: + app: blog + +spec: + rules: + - host: ${KUBERNETES_INGRESS_HOST} + http: + paths: + - path: /api/blog + pathType: Prefix + backend: + service: + name: blog + port: + number: 8888 diff --git a/script/k8s/namespace.yaml b/script/k8s/namespace.yaml new file mode 100644 index 0000000..a3b1961 --- /dev/null +++ b/script/k8s/namespace.yaml @@ -0,0 +1,7 @@ +# Kubernetes Namespace Configuration +apiVersion: v1 +kind: Namespace +metadata: + name: ${KUBERNETES_NAMESPACE} + labels: + name: ${KUBERNETES_NAMESPACE} diff --git a/script/k8s/service.yaml b/script/k8s/service.yaml new file mode 100644 index 0000000..efc289f --- /dev/null +++ b/script/k8s/service.yaml @@ -0,0 +1,19 @@ +# Kubernetes Service Configuration +apiVersion: v1 +kind: Service +metadata: + name: blog + namespace: ${KUBERNETES_NAMESPACE} + labels: + app: blog +spec: + type: ClusterIP + + selector: + app: blog + + ports: + - name: http + port: 8888 + targetPort: http + protocol: TCP