【山竹记账后端】4.网站部署上线
大纲链接 §
[toc]
部署上线的时机
- 项目搭建早期就应该部署一个初始可启动的项目服务上线
- 大致跑通整个流程,逐步完善流程
- 方便渐进式地 排查问题 -> 修改代码 -> 实现功能代码
- 每次只需处理少数的 bug,及时揭露风险
1. 购买便宜的云服务器 ⇧
怎么把代码弄上线
- 弄出一个生产环境,用来运行最终代码
买服务器
机型
- 新手选最便宜的,一年到三年即可
- 如果还是觉得贵,可以按使用量付费,用完即毁(切记)
购买阿里云 按量付费 部署流程测试 ⇧
付费类型、可用区 ⇧
按量付费,按量付费实例不支持备案服务,仅作为部署流程测试,用完即停机,并且释放实例;之后重新购买稳定服务提供项目展示
- 付费类型-按量付费;暂时选择最便宜的
- 可用区:上海 可用区O 仅支持 ECS
- 同可用区内网免费:在同一个可用区内,云服务器、数据库(RDS)和对象存储(OSS)之间的内网通信是完全免费的
- 跨可用区流量收费:如果您将应用部署在可用区A,而数据库部署在可用区B(跨可用区高可用架构)
- 虽然能防灾,但云厂商会对这两个可用区之间传输的内网数据收取同地域跨可用区流量费
实例和镜像 ⇧
- 实例价格点击升序排列,选择最便宜的
- 镜像选
Ubantu最新版;不要免费加固,测完即毁
存储云盘 ⇧
- 调整为最低-20G
- 仅勾选-随实例释放
网络和安全组 ⇧
- 选择 按使用流量
- 峰值调整为最低 1M
- 其他选默认,之后可调整
管理设置 ⇧
- 登录凭证
- 登录名
- 密钥对
创建密钥对,导入公钥
ssh-keygen -t rsa -b 4096 -C "- 终端
bash命令cat ~/.ssh/id_rsa.pub粘贴内容
其他实例选项 ⇧
- 实例名称
- 主机名
购买成功跳转到控制台-实例界面
阿里云实例 ⇧
使用
ssh登录实例
- 管理员打开
bash 在实例界面复制公网 ip
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35ssh root@xxx.xxx.xxx.xx The authenticity of host 'xxx.xxx.xxx.xx (xxx.xxx.xxx.xx)' can't be established. ED25519 key fingerprint is SHA256:nb3c1Xzh5c6PTaCB1I5H6DN4U86JA3i1vJ8aIoXs30xsdW8+67CQ. This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])? y Please type 'yes', 'no' or the fingerprint: yes Warning: Permanently added 'xxx.xxx.xxx.xx' (ED25519) to the list of known hosts. Welcome to Ubuntu 26.04.1 LTS (GNU/Linux 7.0.0-30-generic x86_64) * Documentation: https://docs.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro System information as of Mon Sep 14 05:24:27 PM CST 2026 System load: 0.15 Processes: 114 Usage of /: 33.4% of 19.32GB Users logged in: 0 Memory usage: 15% IPv4 address for eth0: xxx.xx.xxx.xxx Swap usage: 0% Expanded Security Maintenance for Applications is not enabled. 0 updates can be applied immediately. 1 additional security update can be applied with ESM Apps. Learn more about enabling ESM Apps service at https://ubuntu.com/esm The list of available updates is more than a week old. To check for new updates run: sudo apt update Welcome to Alibaba Cloud Elastic Compute Service !看到提示 Welcome to Alibaba Cloud Elastic Compute Service !
使用完确认是否已停机,并且释放实例
- 按量计费的实例停机后,云盘也会扣费,释放实例后才不会计费
- 释放实例后,之前的所有操作记录都会消失
购买腾讯云 ⇧
- 略
2. 服务器详细配置 ⇧
配置服务器
- 登录
- 不推荐使用 【用户名 + 密码】 登录,容易忘,不安全
- 推荐使用
ssh-copy-id上传公钥,使用ssh登录
- 防火墙
- 推荐开启 测试端口,如 3000、3001、5000、8000、8080
- 自行选择是否开启重要端口,因为需要备案,如 80、443
登录 ⇧
ssh root@xxx.xxx.xxx.xx- 保存密码登录可使用
ssh-copy-id root@xxx.xxx.xxx.xx
- 保存密码登录可使用
- 已登录,命令行无输入字符,按
Ctrl + D或者输入exit退出登录
防火墙(安全组配置) ⇧
创建安全组 ⇧
- 添加安全组配置
- 添加入栈端口
3000、3001、5000、8000、8080等 - 源
0.0.0.0/0 - 测试端口无需备案,重要端口
80、443需要备案
- 添加入栈端口
用户权限 ⇧
- 用户权限
- 推荐只在
root用户里安装Docker即可 - 每个应用创建一个 独立用户,并加入
docker用户组,方便管理 - 切记用
root用户管理所有应用,容易被攻击
- 推荐只在
- 发行版
- 新手推荐使用
Ubuntu次新版,因为教程多 - 高手自行选择发行版,推荐
CentOS次新版,因为稳定,适合生产环境
- 新手推荐使用
实操:ssh 用户登录保活 ⇧
root@server1: client_loop:send disconnect:Connection reset by peer
ssh默认有超时时间,一段时间后会进入假死状态,终端卡住不能操作- 需要配置连接断开超时设置
运行命令
vim /etc/ssh/sshd_config,在文件末尾添加如下内容:1 2 3 4vim /etc/ssh/sshd_config # 添加 ClientAliveInterval 300 ClientAliveCountMax 5或者普通模式下 打
/Interval- 按
bb连续向前移动单词到#左侧,按x删除#注释; - 移动到 0 按
s删除并编辑,输入300; - 按
Esc退出编辑模式,输入:wq保存退出
- 按
重启
sshd服务
|
|
参考
- SSH连接断开超时设置
- 解决SSH登录Linux长时间不操作就会自动断开问题
- 如何解决ssh远程连接自动断开的问题
- 怎样长时间保持SSH会话连接不断开?
- [原]Linux ssh远程连接断开问题处理办法
- 解决SSH自动断开无响应的问题
root 用户安装 docker ⇧
如果时腾讯云的服务器,默认已经安装好
docker,可以直接使用,这里演示阿里云服务器安装docker
默认去阿里云的镜像源安装
1 2 3 4 5 6# 1. 更新 apt 包索引,并安装依赖包以允许 apt 通过 HTTPS 使用仓库: apt update apt install ca-certificates curl install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc
设置
docker的 apt 仓库
|
|
安装
docker引擎、containerd和docker-compose-plugin等
|
|
验证
docker镜像是否安装成功
|
|
配置镜像源
使用 nano 编辑
/etc/docker/daemon.json文件,添加国内镜像源1 2 3# 使用 nano 编辑 /etc/docker/daemon.json 文件 nano --version nano /etc/docker/daemon.json
将以下内容完整粘贴到文件中:
|
|
- 保存并退出编辑器(nano 编辑器请按 Ctrl+O 回车保存,Ctrl+X 退出)
重新加载配置并重启 Docker 服务:
|
|
参考
- Install Docker Engine on Ubuntu
- 注意不是安装图形界面 Install Docker Desktop on Ubuntu
- Docker Engine (Linux)镜像源
- 阿里云镜像加速器
添加 mangosteen 用户,并加入 docker 用户组,authorized_keys 权限操作 ⇧
|
|
加入
docker用户组
|
|
按
Ctrl + D退出root用户,使用mangosteen用户登录1 2 3 4ssh mangosteen@your_server_ip # 此时登录会报错 # mangosteen@your_server_ip: Permission denied (publickey).
先再次进入
root用户,修改mangosteen用户的authorized_keys权限
|
|
也可以直接复制
root用户的authorized_keys到mangosteen用户的.ssh目录下
|
|
ls按住Alt + .可以切换到上一个目录,按住Alt + ,可以切换到下一个目录;查看当前目录下的文件authorized_keys这个文件是从root用户的~/.ssh/authorized_keys复制过来的,里面是公钥内容- 目前
mangosteen用户时无法访问authorized_keys 需要转交文件的控制权
1 2 3 4 5 6# chown mangosteen:mangosteen /home/mangosteen/.ssh/authorized_keys cd /home/mangosteen/.ssh/ # 查看文件权限 ll -a cd .. chown -R mangosteen:mangosteen .ssh
- 目前
chown命令是改变文件或目录的所有者和所属组-R递归修改目录下的所有文件和子目录mangosteen:mangosteen表示将所有权转交给mangosteen用户和mangosteen用户组.ssh是当前目录下的.ssh目录
此时 运行
ls -a可以看到.ssh目录的所有者和所属组已经变为mangosteen
bash
drwxr-xr-x 2 mangosteen mangosteen 4096 Sep 15 11:27 ./
drwxr-x--- 4 mangosteen mangosteen 4096 Sep 15 11:28 ../
-rw------- 1 mangosteen mangosteen 742 Sep 15 11:27 authorized_keys
此时重新退出再使用
mangosteen用户登录,应该就可以成功登录了
验证
mangosteen用户是否可以使用docker命令1 2docker ps docker run hello-world
购买创建实例后,初始化命令总结 ⇧
|
|
参考
- ubuntu ユーザを追加して sudo 権限をつける
- Add a user
- Creating a New User in Ubuntu
- Linux: Create, or Remove User
- How do I create a new user account?
- How to add existing user to an existing group?
- Linuxでユーザーをグループに追加する
- How to Add User to Group on Ubuntu Linux (Usermod)
- Linux: Add User to Group
- How to Add User to Group on Ubuntu 26.04
注意把不用的服务器停机或释放实例
3. 部署思路 ⇧
配置后端生产环境:步骤 ⇧
- 准备一个新用户
- 准备好
docker - 上传
Dockerfile - 上传源代码
- 用
Dockerfile构建运行环境 - 在运行环境里运行源代码
- 使用
Nginx做转发- 源码会监听端口,假设
3000不直接访问 Nginx监听80,把80的请求转发到3000- 好处是
Nginx可以做 负载均衡、零宕机时间
- 源码会监听端口,假设
配置后端生产环境:版本更新 ⇧
- 上传新
Dockerfile - 上传新源代码
- 用新
Dockerfile构建运行环境 - 在新运行环境里运行新源代码
- 使用
Nginx做转发
配置前端生产环境 ⇧
前端哪有生产环境
- 将代码中的路径替换成
CDN路径 - 上传打包好的
CSSJS文件到CDN,如阿里云OSS、腾讯云COS - 将
html文件上传到后端服务器 - 使用
Nginx处理html文件请求,转发到CDN上的CSSJS文件
CDN只处理静态文件,好处是可以加速访问,减少服务器压力,降低成本CDN节点也离用户更近,会针对用户的地理位置,分配最近的服务器1 2 3/assets/1-xxxx.js # 修改资源前缀 https://cdn.com/jirengu/assets/1-xxx.js
具体实践过程之后处理,目前只处理后端
重点
- 如何做到自动化?
- 有哪些细节之前没有考虑过的?
- 有哪些问题还没有提到?
检查后端服务端口是否被占用
- 启动服务更换端口;或者重启
docker desktop;或者使用以下命令 - Windows杀死占用端口程序的脚本:
- 使用
netstat-aon | findstr 3000找到对应进程 - 使用
taskkill /F /PID 8888杀死对应进程
4. 在 wsl 宿主机里部署(Windows/macOS/Linux都适用) ⇧
4.1 使用 window 作为生产环境 ⇧
添加后端路由根目录 ⇧
定义根目录
config/routes.rb
|
|
创建根目录对应的
Controller
运行命令
bin/rails g controller home index1 2 3 4 5 6bin/rails g controller home index # create app/controllers/home_controller.rb # route get "home/index" # invoke rspec # create spec/requests/home_spec.rb
app/controllers/home_controller.rb
|
|
把源代码放到
windows环境中,/workspaces/oh-my-env2目录下,是否可以直接拷贝
- 源代码目录下有些目录不能拷贝过去
.git等以.开头的隐藏目录,等配置目录不需要拷贝tmp/目录中部分文件也不需要拷贝tmp/cache不需要拷贝,其他文件是需要拷贝的
- 使用
tar命令打包源代码,上传到宿主机(windows)
生产环境打包脚本 pack_for_host.sh ⇧
新建脚本
scripts/pack_for_host.sh
- 需要把打包的产物放到宿主机上,即数据卷目录
/workspaces/oh-my-env2/目录中 使用
tar命令打包源代码,上传到宿主机1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33#!/bin/bash ### 检查目标目录并动态设置基础路径 if [ -d "/IdeaProjects" ]; then BASE_DIR="/IdeaProjects" elif [ -d "/workspaces" ]; then BASE_DIR="/workspaces" else echo "错误: 未找到 /workspaces 或 /IdeaProjects 目录,脚本退出。" exit 1 fi echo "检测到有效目录,使用基础路径: ${BASE_DIR}" # 注意修改 oh-my-env 目录名为你的目录名 dir=oh-my-env-2 # 日期时间格式作为版本号 time=$(date +'%Y%m%d-%H%M%S') # 压缩包文件名称 dist=tmp/mangosteen-$time.tar.gz current_dir=$(dirname $0) deploy_dir=$BASE_DIR/$dir/mangosteen_deploy yes | rm tmp/mangosteen-*.tar.gz; yes | rm $deploy_dir/mangosteen-*.tar.gz; # 打包排除目录 tar --exclude="tmp/cache/*" -czv -f $dist * mkdir -p $deploy_dir cp $current_dir/../config/host.Dockerfile $deploy_dir/Dockerfile cp $current_dir/setup_host.sh $deploy_dir/ mv $dist $deploy_dir echo $time > $deploy_dir/version echo 'DONE!'需要设置目标打包的目录名称
oh-my-env-2日期时间格式作为 版本号
time=$(date +'%Y%m%d-%H%M%S')- 写入版本号文件中:
echo $time > $deploy_dir/version
- 写入版本号文件中:
设置打包目标路径文件
dist=tmp/mangosteen-$time.tar.gz后缀中添加版本号打包排除目录
tar --exclude="tmp/cache/*" -czv -f $dist *$dist是打包目标路径文件*表示所有不以.开头的文件和目录
创建打包目标路径目录
mkdir -p $deploy_dir添加脚本可执行权限
chmod +x $deploy_dir/setup_host.sh直接运行
bin/pack_for_host.sh脚本即可打包源代码到宿主机
目前运行脚本会失败报错
- 因为还需要准备文件
config/host.Dockerfile,在下一节中创建 - 这个文件是给宿主机运行使用的
4.2 创建 host.Dockerfile 宿主机运行镜像 ⇧
|
|
- 尝试使用版本
FROM ruby:3.1.2-slim - 设置环境变量
RAILS_ENV=production - 创建并设置工作代码目录
/mangosteenWORKDIR /mangosteen这一步十分重要,说明后续步骤的工作目录
- 将打包后的源代码 解压到当前工作目录
ADD mangosteen-*.tar.gz ./mangosteen-*.tar.gz会识别类似mangosteen-20260101-010101.tar.gz格式的文件ADD命令会自动解压缩tar包内容到目录中
- 设置镜像源
RUN bundle config mirror.https://rubygems.org https://mirrors.tuna.tsinghua.edu.cn/rubygems- 注意
https://gems.ruby-china.com镜像源已废弃
- 注意
- 设置仅安装生产环境的包
RUN bundle config set --local without 'development test' - 安装依赖
RUN bundle install - 启动服务
- 区别于开发环境
bundle exec rails server - 生产环境使用
puma作为服务器:bundle exec puma - 使用
ENTRYPOINT exec而不是RUN,因为RUN会在构建镜像时执行,而ENTRYPOINT会在容器启动时执行 - 这个
Dockerfile目前只是构建一个可运行的image,即docker build时构建 - 这个
Dockerfile在运行docker run时才运行此条命令 ENTRYPOINT代表入口,即容器启动时执行的命令,仅当运行docker run时才会执行bundle exec puma- 如果使用
RUN会造成docker build永不结束,因为启动服务一直运行不会断开结束
- 区别于开发环境
参考
- ruby docker 官方镜像
rails镜像已废弃
4.3 docker 构建部署启动脚本 setup_host.sh ⇧
bin/setup_host.sh
|
|
- 设置数据库密码
DB_PASSWORD=123456 - 设置容器名称
container_name=mangosteen-prod-1 - 读取版本号
version=$(cat mangosteen_deploy/version)- 即之前
pack_for_host.sh脚本中生成的版本号文件mangosteen_deploy/version中的内容
- 即之前
- 构建镜像
docker build mangosteen_deploy -t mangosteen:$versionmangosteen_deploy是pack_for_host.sh脚本中创建的目录
- 删除运行容器
docker rm -f $container_name - 启动容器
docker run -d -p 3000:3000 --network=network1 -e DB_PASSWORD=$DB_PASSWORD --name=$container_name mangosteen:$version - 创建表
docker exec -it $container_name bin/rails db:create db:migrate - 添加可执行权限
chmod +x bin/*.sh
4.4 总结流程 ⇧
- 在
linux宿主机里运行pack_for_host.sh脚本,把源代码打包,放到宿主机可访问的目录中 host.Dockerfile是宿主机运行的镜像文件,放到宿主机可访问的目录中- 在
window中运行setup_host.sh脚本,将构建启动host.Dockerfile中的镜像
添加可执行权限
|
|
- 查看目录
ls -l mangosteen_deploy/存在四个文件Dockerfile由host.Dockerfile复制而来version版本文件mangosteen-*.tar.gz源代码压缩包setup_host.sh给宿主机运行的脚本
宿主机运行
setup_host.sh脚本
VSCode打开oh-my-env2/目录,注意不是直接打开mangosteen_deploy/目录注意终端必须是
bash需要另外配置;不可使用CMD或者PowerShell1mangosteen_deploy/setup_host.sh查看宿主机
docker desktop客户端中镜像数量找到
mangosteen:xxxxxx-xxxxxx镜像运行
docker ps查看容器是否启动成功如果未找到正在运行的容器使用
docker ps -a查看容器哈希1 2 3 4 5 6docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 922155153e8d mangosteen:20260915-174001 "/bin/sh -c 'exec bu…" About a minute ago Up About a minute 0.0.0.0:3000->3000/tcp, [::]:3000->3000/tcp mangosteen-prod-1 b5ae1c5338bc 56d78e0be2c2 "/bin/sh -c 'while s…" 3 days ago Up 3 hours admiring_mahavira fc760ea83e62 vsc-oh-my-env-2-8356d6c3244aebf25d14130d26591ac417285100f20b188cc73d5dca696ebb75 "/bin/sh -c 'echo Co…" 3 days ago Up 5 hours ecstatic_swirles 5f72b78eb4c3 postgres:14 "docker-entrypoint.s…" 7 days ago Up 9 hours 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp db-for-mangosteen
启动失败查看报错日志
Dockerfile配置语法错误docker logs 922155153e8d查看容器日志找到是否包含
Missing secret_key_base- 需要一些加密配置
需要另外配置生产环境数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40... 2 warnings found (use docker --debug to expand): - JSONArgsRecommended: JSON arguments recommended for ENTRYPOINT to prevent unintended behavior related to OS signals (line 10) - LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 3) View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/mlr1jbnne1sgym5qjbta1639z docker run ... 922155153e8d22110624bdb22323da09ce53a041edaed8212e0f72237d26e505 docker exec db... connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? Couldn't create 'mangosteen_1_production' database. Please check your configuration. bin/rails aborted! ActiveRecord::ConnectionNotEstablished: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? Caused by: PG::ConnectionBad: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket? Tasks: TOP => db:create (See full trace by running task with --trace) What's next: Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug mangosteen-prod-1 Learn more at https://docs.docker.com/go/debug-cli/ DONE!
询问 Gordon 修改文件
mangosteen_deploy/Dockerfile
|
|
询问 Gordon 生成文件
mangosteen_deploy/docker-compose.yml
|
|
总结
- 服务器
- 购买、安装 Docker、创建用户、ssh 登录
- 宿主机部署
- 复制 Dockerfile 到宿主机、打包源代码到宿主机、写自动化脚本
- 把
linux系统中代码放到宿主机 - 宿主机启动另外一个
linux运行(容器) - 得到一个纯净的
ruby-3.1.2环境 - 之前开发环境的依赖太多,不需放在再生产环境中
- 创建的两个脚本
pack_for_host.sh打包脚本setup_host.sh宿主机部署脚本
- 遗留问题:
rails启动报错- 缺少
secret_base_key - 生产环境数据库配置
- 缺少
不会用 vim 怎么办?
- 不会用就千万别尝试,建议使用 nano 代替 vim 命令。
代码使用 Windows,是否适合 macOS / Linux 吗?
- 在
docker容器中 都是 Linux
参考文章
相关文章
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名