A comprehensive Ruby on Rails blog application with full DevOps pipeline including Docker containerization, Kubernetes deployment, GitOps with ArgoCD, and CI/CD with Tekton Pipelines.
- Overview
- Architecture
- Prerequisites
- Getting Started
- Docker Setup
- Kubernetes Deployment
- ArgoCD GitOps
- Tekton CI/CD Pipeline
- Monitoring & Access
- Troubleshooting
- Repository Structure
This project demonstrates a complete DevOps workflow for a Ruby on Rails blog application:
- Application: Ruby on Rails blog with PostgreSQL database
- Containerization: Docker multi-stage builds
- Orchestration: Kubernetes deployment on Minikube
- GitOps: ArgoCD for continuous deployment
- CI/CD: Tekton Pipelines for automated builds
- Monitoring: Kubernetes Dashboard and ArgoCD UI
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Source Repo βββββΆβ Tekton Pipeline βββββΆβ Docker Hub β
β (ruby_blog) β β (builds image) β β (stores image) β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β GitOps Repo ββββββ ArgoCD βββββΆβ Kubernetes β
β (k8s manifests) β β (syncs changes) β β (runs app) β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
- Docker Desktop (for building images)
- Minikube (local Kubernetes cluster)
- kubectl (Kubernetes CLI)
- Git (version control)
- Docker Hub Account (for image registry)
git clone https://github.com/bankolejohn/ruby_blog.git
cd ruby_blog# Start Minikube with sufficient resources
minikube start --cpus=4 --memory=8192
# Enable required addons
minikube addons enable ingress
minikube addons enable metrics-serverThe application uses a multi-stage Dockerfile for optimized builds:
# Build stage
FROM ruby:3.1-alpine AS builder
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install --without development test
# Production stage
FROM ruby:3.1-alpine
WORKDIR /app
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY . .
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]# Build the Docker image
docker build -t ruby-blog:local .
# Test locally
docker run -p 3000:3000 ruby-blog:localkubectl create namespace ruby-blogkubectl apply -f k8s/postgres-pvc.yaml
kubectl apply -f k8s/postgres-secret.yaml
kubectl apply -f k8s/postgres-deployment.yaml
kubectl apply -f k8s/postgres-service.yamlkubectl apply -f k8s/rails-deployment.yaml
kubectl apply -f k8s/rails-service.yaml
kubectl apply -f k8s/rails-ingress.yaml# Get Minikube IP
minikube ip
# Add to /etc/hosts
echo "$(minikube ip) ruby-blog.local" | sudo tee -a /etc/hosts
# Access at: http://ruby-blog.local# Create namespace
kubectl create namespace argocd
# Install ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Wait for pods to be ready
kubectl wait --for=condition=available --timeout=300s deployment/argocd-server -n argocd# Port forward to access UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Get admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Access at: https://localhost:8080
# Username: admin
# Password: (from above command)kubectl apply -f argocd/ruby-blog-app.yaml# Install Tekton Pipelines
kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
# Install Tekton Dashboard
kubectl apply --filename https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml
# Wait for installation
kubectl wait --for=condition=available --timeout=300s deployment/tekton-pipelines-controller -n tekton-pipelinesCreate Docker Hub Access Token:
- Go to https://hub.docker.com/settings/security
- Create new access token with Read/Write/Delete permissions
- Copy the token (starts with
dckr_pat_)
# Create Docker registry secret
kubectl create secret docker-registry docker-registry-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=YOUR_DOCKERHUB_USERNAME \
--docker-password=YOUR_ACCESS_TOKEN \
--namespace=tekton-pipelines# Apply tasks and pipeline
kubectl apply -f tekton/tasks/
kubectl apply -f tekton/pipelines/
kubectl apply -f tekton/updated-service-account.yaml# Port forward to access dashboard
kubectl port-forward -n tekton-pipelines service/tekton-dashboard 9097:9097
# Access at: http://localhost:9097# Create pipeline run
kubectl apply -f tekton/final-auth-test.yaml
# Monitor progress in dashboard or CLI
kubectl get pipelinerun -n tekton-pipelines- Ruby Blog: http://ruby-blog.local
- ArgoCD: https://localhost:8080
- Tekton Dashboard: http://localhost:9097
- Kubernetes Dashboard: http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
# Check application status
kubectl get pods -n ruby-blog
# View application logs
kubectl logs -f deployment/rails-app -n ruby-blog
# Check ArgoCD applications
kubectl get applications -n argocd
# Monitor pipeline runs
kubectl get pipelinerun -n tekton-pipelines
# Access application shell
kubectl exec -it deployment/rails-app -n ruby-blog -- /bin/shProblem: Pods stuck in Pending state due to insufficient resources
Solution:
# Restart Minikube with more resources
minikube stop
minikube start --cpus=4 --memory=8192
# Check resource usage
kubectl top nodes
kubectl top pods --all-namespacesProblem: UNAUTHORIZED: authentication required when pushing to Docker Hub
Solutions:
- Use Docker Hub Access Token instead of password
- Ensure proper secret configuration:
# Verify secret exists
kubectl get secret docker-registry-secret -n tekton-pipelines
# Recreate secret if needed
kubectl delete secret docker-registry-secret -n tekton-pipelines
kubectl create secret docker-registry docker-registry-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=YOUR_USERNAME \
--docker-password=YOUR_ACCESS_TOKEN \
--namespace=tekton-pipelinesProblem: PodAdmissionFailed due to security policy restrictions
Solution:
# Set privileged security policy for tekton-pipelines namespace
kubectl label namespace tekton-pipelines \
pod-security.kubernetes.io/enforce=privileged \
pod-security.kubernetes.io/audit=privileged \
pod-security.kubernetes.io/warn=privileged --overwriteProblem: Tekton webhook pod stuck in ContainerCreating or Pending
Solutions:
# Check webhook pod status
kubectl get pods -n tekton-pipelines | grep webhook
# Delete and recreate webhook pod
kubectl delete pod -n tekton-pipelines -l app.kubernetes.io/name=webhook
# Wait for new pod to start
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=webhook -n tekton-pipelinesProblem: error resolving dockerfile path in kaniko build
Solution: Ensure correct path structure in kaniko task:
# Correct paths for git-clone + kaniko
workingDir: $(workspaces.source.path)/source
args:
- --dockerfile=./Dockerfile
- --context=dir://$(workspaces.source.path)/sourceProblem: ArgoCD application stuck in "OutOfSync" state
Solutions:
# Force refresh application
kubectl patch app ruby-blog-app -n argocd --type merge -p='{"operation":{"initiatedBy":{"username":"admin"},"sync":{"revision":"HEAD"}}}'
# Check application status
kubectl get app ruby-blog-app -n argocd -o yamlProblem: Cannot access application via ingress
Solutions:
# Ensure ingress addon is enabled
minikube addons enable ingress
# Check ingress controller
kubectl get pods -n ingress-nginx
# Verify ingress resource
kubectl get ingress -n ruby-blog
# Update /etc/hosts with correct Minikube IP
echo "$(minikube ip) ruby-blog.local" | sudo tee -a /etc/hostsProblem: Rails app cannot connect to PostgreSQL
Solutions:
# Check PostgreSQL pod status
kubectl get pods -n ruby-blog | grep postgres
# Verify database secret
kubectl get secret postgres-secret -n ruby-blog -o yaml
# Check service connectivity
kubectl exec -it deployment/rails-app -n ruby-blog -- nc -zv postgres-service 5432Problem: Port forwarding fails or stops working
Solutions:
# Kill existing port forwards
pkill -f "kubectl port-forward"
# Restart port forward with different port
kubectl port-forward -n argocd svc/argocd-server 8081:443
kubectl port-forward -n tekton-pipelines service/tekton-dashboard 9098:9097Problem: PipelineRun failed to finish within "1h0m0s"
Solutions:
# Create PipelineRun with extended timeout
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
spec:
timeouts:
pipeline: "2h0m0s" # Extend to 2 hours
tasks: "1h30m0s" # Per-task timeout
# Check if image was actually built despite timeout
curl -s "https://hub.docker.com/v2/repositories/YOUR_USERNAME/YOUR_REPO/tags/"
# Monitor build progress in real-time
kubectl logs -f -n tekton-pipelines -l tekton.dev/pipelineRun=YOUR_PIPELINE_RUNProblem: stream error: stream ID 3; INTERNAL_ERROR during Docker build
Solutions:
# Check Minikube resource usage
kubectl top nodes
# Clean up resources if memory/CPU > 80%
kubectl delete pipelinerun --all -n tekton-pipelines
kubectl delete pods --field-selector=status.phase=Failed --all-namespaces
# Optimize kaniko for low resources
args:
- --cache=false
- --single-snapshot
- --cleanup
# Restart Minikube if needed
minikube stop && minikube start --cpus=4 --memory=8192Problem: Need to clean up resources for fresh start
Solution:
# Delete all pipeline runs
kubectl delete pipelinerun --all -n tekton-pipelines
# Clean up failed pods
kubectl delete pods --field-selector=status.phase=Failed --all-namespaces
# Restart Minikube if needed
minikube stop && minikube start --cpus=4 --memory=8192ruby_blog/
βββ README.md # This comprehensive guide
βββ Dockerfile # Multi-stage Docker build
βββ Gemfile # Ruby dependencies
βββ app/ # Rails application code
βββ k8s/ # Kubernetes manifests
β βββ postgres-*.yaml # PostgreSQL database
β βββ rails-*.yaml # Rails application
β βββ ingress.yaml # Ingress configuration
βββ argocd/ # ArgoCD configurations
β βββ ruby-blog-app.yaml # ArgoCD application
βββ tekton/ # Tekton CI/CD pipeline
βββ tasks/ # Tekton tasks
βββ pipelines/ # Tekton pipelines
βββ *.yaml # Pipeline runs and configs
- Production Deployment: Adapt configurations for production Kubernetes cluster
- Monitoring: Add Prometheus and Grafana for metrics
- Security: Implement RBAC and security policies
- Backup: Set up database backup strategies
- Scaling: Configure horizontal pod autoscaling
- SSL/TLS: Add certificate management with cert-manager
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.