From 70f4740359b4456426105da9ea7a8d669e2cf555 Mon Sep 17 00:00:00 2001 From: Admin Date: Wed, 4 Feb 2026 22:51:42 +0800 Subject: [PATCH] Rails 8.1 + SQLite app - 2026-02-04 22:51:42 --- .gitignore | 65 +++++++++++++++++++++ Dockerfile | 39 +++++++++++++ Gemfile | 46 +++++++++++++++ README.md | 47 +++++++++++++++ build-and-push.sh | 34 +++++++++++ deploy.sh | 138 ++++++++++++++++++++++++++++++++++++++++++++ k8s/deployment.yaml | 128 ++++++++++++++++++++++++++++++++++++++++ k8s/ingress.yaml | 47 +++++++++++++++ k8s/namespace.yaml | 4 ++ k8s/pvc.yaml | 12 ++++ k8s/service.yaml | 16 +++++ start.sh | 123 +++++++++++++++++++++++++++++++++++++++ 12 files changed, 699 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Gemfile create mode 100644 README.md create mode 100755 build-and-push.sh create mode 100755 deploy.sh create mode 100644 k8s/deployment.yaml create mode 100644 k8s/ingress.yaml create mode 100644 k8s/namespace.yaml create mode 100644 k8s/pvc.yaml create mode 100644 k8s/service.yaml create mode 100755 start.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a00a991 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0fb2a82 --- /dev/null +++ b/Dockerfile @@ -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"] diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..6f06ada --- /dev/null +++ b/Gemfile @@ -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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..4d47e12 --- /dev/null +++ b/README.md @@ -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. 应用自动更新 diff --git a/build-and-push.sh b/build-and-push.sh new file mode 100755 index 0000000..b687e35 --- /dev/null +++ b/build-and-push.sh @@ -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'" diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..f132007 --- /dev/null +++ b/deploy.sh @@ -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 "" diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 0000000..1872708 --- /dev/null +++ b/k8s/deployment.yaml @@ -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' + + + + Rails 8.1 on K3s + + + +
+
💎
+

Rails <%= @rails_version %> on K3s

+
✅ 运行正常
+
+

Ruby版本: <%= @ruby_version %>

+

Rails版本: <%= @rails_version %>

+

数据库: SQLite3

+

Pod主机名: <%= @hostname %>

+

访问域名: r1.jpd.net3w.com

+

部署方式: GitOps (Gitea + ArgoCD)

+

集群: JPD K3s Cluster

+
+

<%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>

+
+ + + 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: {} diff --git a/k8s/ingress.yaml b/k8s/ingress.yaml new file mode 100644 index 0000000..347d448 --- /dev/null +++ b/k8s/ingress.yaml @@ -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 diff --git a/k8s/namespace.yaml b/k8s/namespace.yaml new file mode 100644 index 0000000..4464ee1 --- /dev/null +++ b/k8s/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: rails-app diff --git a/k8s/pvc.yaml b/k8s/pvc.yaml new file mode 100644 index 0000000..d8c81ba --- /dev/null +++ b/k8s/pvc.yaml @@ -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 diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 0000000..cbe8c56 --- /dev/null +++ b/k8s/service.yaml @@ -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 diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..599faaa --- /dev/null +++ b/start.sh @@ -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' + + + + Rails 8.1 on K3s + + + +
+
💎
+

Rails <%= @rails_version %> on K3s

+
✅ 运行正常
+
+

Ruby版本: <%= @ruby_version %>

+

Rails版本: <%= @rails_version %>

+

数据库: SQLite3

+

Pod主机名: <%= @hostname %>

+

访问域名: r1.jpd.net3w.com

+

部署方式: GitOps (Gitea + ArgoCD)

+

集群: JPD K3s Cluster

+
+

+ <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %> +

+
+ + +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