Rails 8.1 + SQLite app - 2026-02-04 22:51:42

This commit is contained in:
2026-02-04 22:51:42 +08:00
commit 70f4740359
12 changed files with 699 additions and 0 deletions

65
.gitignore vendored Normal file
View File

@@ -0,0 +1,65 @@
# Rails
*.rbc
capybara-*.html
.rspec
/db/*.sqlite3
/db/*.sqlite3-*
/public/system
/coverage/
/spec/tmp
*.orig
rerun.txt
pickle-email-*.html
# Rails cache
/tmp
/log/*
!/log/.keep
/storage/*
!/storage/.keep
/tmp/*
!/tmp/.keep
# Node modules
/node_modules
/yarn-error.log
yarn-debug.log*
.yarn-integrity
# Ignore bundler config
/.bundle
# Ignore master key
/config/master.key
/config/credentials/*.key
# Ignore assets
/public/assets
/public/packs
/public/packs-test
# Ignore uploaded files
/storage/*
!/storage/.keep
# Ignore precompiled assets
/app/assets/builds/*
!/app/assets/builds/.keep
# Ignore node_modules
node_modules/
# Ignore .env files
.env
.env.*
# Ignore IDE files
.idea/
.vscode/
*.swp
*.swo
*~
# Ignore OS files
.DS_Store
Thumbs.db

39
Dockerfile Normal file
View File

@@ -0,0 +1,39 @@
# 使用Ruby 3.3官方镜像
FROM ruby:3.3-slim
# 安装系统依赖
RUN apt-get update -qq && \
apt-get install -y \
build-essential \
libsqlite3-dev \
nodejs \
npm \
git \
curl && \
rm -rf /var/lib/apt/lists/*
# 设置工作目录
WORKDIR /app
# 安装Rails 8.1
RUN gem install rails -v '8.1.0' --no-document
# 复制启动脚本
COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh
# 复制Gemfile
COPY Gemfile* ./
RUN bundle install || true
# 复制应用代码
COPY . .
# 创建必要的目录
RUN mkdir -p /app/db /app/storage /app/tmp /app/log
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["/app/start.sh"]

46
Gemfile Normal file
View File

@@ -0,0 +1,46 @@
source 'https://rubygems.org'
ruby '~> 3.3.0'
# Rails 8.1
gem 'rails', '~> 8.1.0'
# SQLite数据库
gem 'sqlite3', '~> 2.0'
# Puma web服务器
gem 'puma', '>= 5.0'
# 资源管道
gem 'sprockets-rails'
# JavaScript
gem 'importmap-rails'
# Hotwire
gem 'turbo-rails'
gem 'stimulus-rails'
# JSON API
gem 'jbuilder'
# 时区数据
gem 'tzinfo-data', platforms: %i[ windows jruby ]
# 性能优化
gem 'bootsnap', require: false
group :development, :test do
gem 'debug', platforms: %i[ mri windows ], require: 'debug/prelude'
gem 'brakeman', require: false
gem 'rubocop-rails-omakase', require: false
end
group :development do
gem 'web-console'
end
group :test do
gem 'capybara'
gem 'selenium-webdriver'
end

47
README.md Normal file
View File

@@ -0,0 +1,47 @@
# Rails 8.1 + SQLite 应用
这是一个基于Rails 8.1和SQLite的示例应用部署在JPD K3s集群上。
## 功能特性
- Rails 8.1 最新版本
- SQLite 数据库(持久化存储)
- GitOps自动部署Gitea + ArgoCD
- 域名访问http://r1.jpd.net3w.com
- 代码热更新(本地修改,远程自动部署)
## 目录结构
```
001-rails8/
├── README.md # 本文件
├── Dockerfile # Rails应用容器镜像
├── k8s/ # Kubernetes配置文件
│ ├── deployment.yaml # 部署配置
│ ├── service.yaml # 服务配置
│ ├── ingress.yaml # Ingress配置
│ └── pvc.yaml # 持久化存储配置
├── app/ # Rails应用代码
│ └── ...
└── .gitignore # Git忽略文件
```
## 部署流程
1. 本地开发Rails应用
2. 构建Docker镜像
3. 推送到Gitea仓库
4. ArgoCD自动检测并部署
5. 通过域名访问应用
## 访问地址
- HTTP: http://r1.jpd.net3w.com
- HTTPS: https://r1.jpd.net3w.com
## 开发流程
1. 本地修改代码
2. Git commit & push
3. ArgoCD自动同步
4. 应用自动更新

34
build-and-push.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
# 快速构建和推送镜像脚本
set -e
echo "🔨 构建Docker镜像..."
SSH_PASS="1"
APP_DIR="/home/fei/opk3s/app-project/001-rails8"
cd "$APP_DIR"
# 上传文件到master节点
echo "📤 上传文件到master节点..."
sshpass -p "$SSH_PASS" ssh fei@149.13.91.216 "mkdir -p /tmp/rails-app"
sshpass -p "$SSH_PASS" scp -r ./* fei@149.13.91.216:/tmp/rails-app/
# 构建镜像
echo "🔨 构建Docker镜像..."
sshpass -p "$SSH_PASS" ssh fei@149.13.91.216 "cd /tmp/rails-app && \
echo '$SSH_PASS' | sudo -S docker build -t rails-app:latest . && \
echo '$SSH_PASS' | sudo -S ctr -n k8s.io images import <(sudo docker save rails-app:latest)"
echo "✅ 镜像构建完成"
# 重启Pod
echo "🔄 重启Rails应用..."
sshpass -p "$SSH_PASS" ssh fei@149.13.91.216 "export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && \
kubectl rollout restart deployment/rails-app -n rails-app"
echo "✅ 应用已重启"
echo ""
echo "💡 查看日志:"
echo " sshpass -p '1' ssh fei@149.13.91.216 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && kubectl logs -n rails-app -l app=rails-app -f'"

138
deploy.sh Executable file
View File

@@ -0,0 +1,138 @@
#!/bin/bash
# Rails 8.1 应用部署脚本使用containerd
set -e
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🚀 Rails 8.1 应用GitOps部署"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# 配置
GITEA_URL="http://git.jpd.net3w.com"
GITEA_USER="gitea_admin"
GITEA_PASSWORD="GitAdmin@2026"
REPO_NAME="rails-app"
APP_DIR="/home/fei/opk3s/app-project/001-rails8"
SSH_PASS="1"
cd "$APP_DIR"
echo "📝 步骤 1/5: 初始化Git仓库"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [ ! -d .git ]; then
git init
git config user.name "Admin"
git config user.email "admin@jpd.net3w.com"
echo "✅ Git仓库初始化完成"
else
echo "✅ Git仓库已存在"
fi
echo ""
echo "📝 步骤 2/5: 在Gitea创建仓库"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
curl -X POST "${GITEA_URL}/api/v1/user/repos" \
-u "${GITEA_USER}:${GITEA_PASSWORD}" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"${REPO_NAME}\",
\"description\": \"Rails 8.1 + SQLite Application\",
\"private\": false,
\"auto_init\": false
}" 2>/dev/null && echo "✅ Gitea仓库创建成功" || echo "✅ 仓库已存在"
echo ""
echo "📝 步骤 3/5: 推送代码到Gitea"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
git remote remove origin 2>/dev/null || true
git remote add origin "http://${GITEA_USER}:${GITEA_PASSWORD}@git.jpd.net3w.com/${GITEA_USER}/${REPO_NAME}.git"
git add .
git commit -m "Rails 8.1 + SQLite app - $(date '+%Y-%m-%d %H:%M:%S')" || echo "没有新的更改"
git branch -M main
git push -u origin main --force
echo "✅ 代码已推送到Gitea"
echo ""
echo "📝 步骤 4/5: 部署到K3s集群"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# 上传K8s配置文件
sshpass -p "$SSH_PASS" ssh fei@149.13.91.216 "mkdir -p /tmp/rails-app-k8s"
sshpass -p "$SSH_PASS" scp -r k8s/* fei@149.13.91.216:/tmp/rails-app-k8s/
# 部署到K3s
sshpass -p "$SSH_PASS" ssh fei@149.13.91.216 "export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && \
kubectl create namespace rails-app --dry-run=client -o yaml | kubectl apply -f - && \
kubectl apply -f /tmp/rails-app-k8s/"
echo "✅ 应用已部署到K3s"
echo ""
echo "📝 步骤 5/5: 配置ArgoCD自动同步"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
sshpass -p "$SSH_PASS" ssh fei@149.13.91.216 "export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && \
kubectl apply -f - <<'EOF'
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: rails-app
namespace: argocd
spec:
project: default
source:
repoURL: http://gitea-http.gitea.svc.cluster.local:3000/${GITEA_USER}/${REPO_NAME}.git
targetRevision: main
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: rails-app
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
EOF
"
echo "✅ ArgoCD自动同步已配置"
echo ""
# 检查Pod状态
echo "🔍 检查Pod状态..."
sshpass -p "$SSH_PASS" ssh fei@149.13.91.216 "export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && \
kubectl get pods -n rails-app"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🎉 部署完成!"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "📊 访问信息:"
echo " 应用地址: http://r1.jpd.net3w.com"
echo " HTTPS: https://r1.jpd.net3w.com"
echo " Gitea仓库: ${GITEA_URL}/${GITEA_USER}/${REPO_NAME}"
echo " ArgoCD: http://argocd.jpd.net3w.com"
echo ""
echo "💡 开发流程:"
echo " 1. 本地修改代码"
echo " 2. git add . && git commit -m 'your message'"
echo " 3. git push"
echo " 4. ArgoCD会自动检测并部署约1-2分钟"
echo ""
echo "🔍 查看状态:"
echo " sshpass -p '1' ssh fei@149.13.91.216 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && kubectl get pods -n rails-app'"
echo " sshpass -p '1' ssh fei@149.13.91.216 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && kubectl logs -n rails-app -l app=rails-app -f'"
echo ""
echo "📝 注意:"
echo " 由于使用公共镜像ruby:3.3-slim首次启动可能需要5-10分钟下载镜像"
echo " Pod会自动创建Rails应用并启动"
echo ""

128
k8s/deployment.yaml Normal file
View File

@@ -0,0 +1,128 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: rails-app
namespace: rails-app
labels:
app: rails-app
spec:
replicas: 1
selector:
matchLabels:
app: rails-app
template:
metadata:
labels:
app: rails-app
spec:
containers:
- name: rails
image: ruby:3.3-slim
imagePullPolicy: IfNotPresent
command: ["/bin/bash", "-c"]
args:
- |
apt-get update -qq && apt-get install -y build-essential libsqlite3-dev nodejs npm git curl
gem install rails -v '8.1.0' --no-document
cd /app
if [ ! -f config/database.yml ]; then
rails new . --force --database=sqlite3 --skip-git --skip-bundle
fi
bundle install
rails db:create db:migrate || true
# 创建欢迎页面
cat > app/controllers/welcome_controller.rb <<'RUBY'
class WelcomeController < ApplicationController
def index
@hostname = Socket.gethostname
@rails_version = Rails.version
@ruby_version = RUBY_VERSION
end
end
RUBY
mkdir -p app/views/welcome
cat > app/views/welcome/index.html.erb <<'HTML'
<!DOCTYPE html>
<html>
<head>
<title>Rails 8.1 on K3s</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 0; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; justify-content: center; align-items: center; min-height: 100vh; }
.container { background: white; padding: 40px; border-radius: 10px; box-shadow: 0 10px 40px rgba(0,0,0,0.2); text-align: center; max-width: 600px; }
h1 { color: #667eea; margin-bottom: 20px; }
.status { background: #10b981; color: white; padding: 10px 20px; border-radius: 5px; display: inline-block; margin: 20px 0; }
.info { text-align: left; background: #f3f4f6; padding: 20px; border-radius: 5px; margin-top: 20px; }
.info p { margin: 10px 0; }
.emoji { font-size: 48px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="container">
<div class="emoji">💎</div>
<h1>Rails <%= @rails_version %> on K3s</h1>
<div class="status">✅ 运行正常</div>
<div class="info">
<p><strong>Ruby版本:</strong> <%= @ruby_version %></p>
<p><strong>Rails版本:</strong> <%= @rails_version %></p>
<p><strong>数据库:</strong> SQLite3</p>
<p><strong>Pod主机名:</strong> <%= @hostname %></p>
<p><strong>访问域名:</strong> r1.jpd.net3w.com</p>
<p><strong>部署方式:</strong> GitOps (Gitea + ArgoCD)</p>
<p><strong>集群:</strong> JPD K3s Cluster</p>
</div>
<p style="margin-top: 20px; color: #6b7280;"><%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %></p>
</div>
</body>
</html>
HTML
cat > config/routes.rb <<'RUBY'
Rails.application.routes.draw do
root "welcome#index"
get "up" => "rails/health#show", as: :rails_health_check
end
RUBY
rails server -b 0.0.0.0 -p 3000
ports:
- containerPort: 3000
name: http
env:
- name: RAILS_ENV
value: "development"
- name: RAILS_LOG_TO_STDOUT
value: "true"
volumeMounts:
- name: sqlite-storage
mountPath: /app/db
- name: app-storage
mountPath: /app
livenessProbe:
httpGet:
path: /up
port: 3000
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /up
port: 3000
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
volumes:
- name: sqlite-storage
persistentVolumeClaim:
claimName: rails-sqlite-pvc
- name: app-storage
emptyDir: {}

47
k8s/ingress.yaml Normal file
View File

@@ -0,0 +1,47 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rails-app-http
namespace: rails-app
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
ingressClassName: traefik
rules:
- host: r1.jpd.net3w.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rails-app
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rails-app-https
namespace: rails-app
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
ingressClassName: traefik
tls:
- hosts:
- r1.jpd.net3w.com
secretName: rails-app-tls
rules:
- host: r1.jpd.net3w.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rails-app
port:
number: 80

4
k8s/namespace.yaml Normal file
View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: rails-app

12
k8s/pvc.yaml Normal file
View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rails-sqlite-pvc
namespace: rails-app
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: local-path

16
k8s/service.yaml Normal file
View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: rails-app
namespace: rails-app
labels:
app: rails-app
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 3000
protocol: TCP
name: http
selector:
app: rails-app

123
start.sh Executable file
View File

@@ -0,0 +1,123 @@
#!/bin/bash
# 简化的Rails应用启动脚本
set -e
echo "🚀 启动Rails应用..."
# 如果没有Rails应用创建一个
if [ ! -f config/database.yml ]; then
echo "📝 创建新的Rails应用..."
rails new . --force --database=sqlite3 --skip-git --skip-bundle
fi
# 安装依赖
echo "📦 安装依赖..."
bundle install
# 创建数据库
echo "🗄️ 创建数据库..."
rails db:create db:migrate || true
# 创建示例控制器
if [ ! -f app/controllers/welcome_controller.rb ]; then
echo "📝 创建示例页面..."
cat > app/controllers/welcome_controller.rb <<'RUBY'
class WelcomeController < ApplicationController
def index
@hostname = Socket.gethostname
@rails_version = Rails.version
@ruby_version = RUBY_VERSION
end
end
RUBY
mkdir -p app/views/welcome
cat > app/views/welcome/index.html.erb <<'HTML'
<!DOCTYPE html>
<html>
<head>
<title>Rails 8.1 on K3s</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
text-align: center;
max-width: 600px;
}
h1 {
color: #667eea;
margin-bottom: 20px;
}
.status {
background: #10b981;
color: white;
padding: 10px 20px;
border-radius: 5px;
display: inline-block;
margin: 20px 0;
}
.info {
text-align: left;
background: #f3f4f6;
padding: 20px;
border-radius: 5px;
margin-top: 20px;
}
.info p {
margin: 10px 0;
}
.emoji {
font-size: 48px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="emoji">💎</div>
<h1>Rails <%= @rails_version %> on K3s</h1>
<div class="status">✅ 运行正常</div>
<div class="info">
<p><strong>Ruby版本:</strong> <%= @ruby_version %></p>
<p><strong>Rails版本:</strong> <%= @rails_version %></p>
<p><strong>数据库:</strong> SQLite3</p>
<p><strong>Pod主机名:</strong> <%= @hostname %></p>
<p><strong>访问域名:</strong> r1.jpd.net3w.com</p>
<p><strong>部署方式:</strong> GitOps (Gitea + ArgoCD)</p>
<p><strong>集群:</strong> JPD K3s Cluster</p>
</div>
<p style="margin-top: 20px; color: #6b7280;">
<%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
</p>
</div>
</body>
</html>
HTML
# 配置路由
if ! grep -q "root.*welcome#index" config/routes.rb 2>/dev/null; then
cat > config/routes.rb <<'RUBY'
Rails.application.routes.draw do
root "welcome#index"
get "up" => "rails/health#show", as: :rails_health_check
end
RUBY
fi
fi
# 启动服务器
echo "🌐 启动Rails服务器..."
exec rails server -b 0.0.0.0 -p 3000