惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Security Blog
Microsoft Security Blog
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
S
SegmentFault 最新的问题
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
人人都是产品经理
人人都是产品经理
美团技术团队
博客园 - 三生石上(FineUI控件)
Jina AI
Jina AI
V
Visual Studio Blog
腾讯CDC
小众软件
小众软件
有赞技术团队
有赞技术团队
博客园 - 聂微东
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
IT之家
IT之家
C
CERT Recently Published Vulnerability Notes
大猫的无限游戏
大猫的无限游戏
T
Threat Research - Cisco Blogs
SecWiki News
SecWiki News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
宝玉的分享
宝玉的分享
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Hacker News
The Hacker News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Troy Hunt's Blog
月光博客
月光博客
雷峰网
雷峰网
T
Tor Project blog
I
Intezer
S
Securelist
罗磊的独立博客
The Register - Security
The Register - Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
NISL@THU
NISL@THU
Google Online Security Blog
Google Online Security Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Cisco Talos Blog
Cisco Talos Blog
云风的 BLOG
云风的 BLOG
www.infosecurity-magazine.com
www.infosecurity-magazine.com
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
Lohrmann on Cybersecurity
The Cloudflare Blog
Attack and Defense Labs
Attack and Defense Labs
P
Privacy International News Feed
W
WeLiveSecurity
Forbes - Security
Forbes - Security
量子位
Last Week in AI
Last Week in AI

Razeen`s Blog

Let's Encrypt 推出 Gen Y 根证书架构:揭示 Web PKI 的五大未来趋势 通过 Wi-Fi 自动备份你的 iPhone 到 Nas 管理培训感悟:从技术视角看管理之路 UPS 一拖多:保护你的 NAS 和 Linux 服务器 从影音中心到 AI 助手:我的50款 Homelab 服务清单 从SSL证书有效期将缩短到47天聊开去 谈谈特斯拉 Model Y 用车一年的感受和费用分析 弃用 Disqus 评论,使用自建 Waline 使用 Prometheus 和 Grafana 搭建你的证书监控面板 服务器迁移记:一次磁盘换板引发的Linux分区与挂载的学习 改善信息来源, 利用 RSS 高效获取资讯 (RSShub + Reeder5 + WeWe RSS) 多种 Docker 镜像拉取解决方案与实践 App分享 | AppCleaner - Mac上的卸载神器 Azure OpenAI API 申请和使用 如何开通 OneKey 虚拟信用卡,并充值消费 如何拥有一个可长期在国内使用的国外手机号码 分享开通 ChatGPT Plus 过程 如何开通 Depay 虚拟信用卡,并充值消费 如何开通欧易Web3钱包, 交易入账 如何5分钟内1块钱注册 ChatGPT 如何注册美区的 Apple ID (2023年/无需科学上网) NAS折腾记(11): NASTool3.0体验和降级 NAS折腾记(10): Docker版本的NASTool配置 NAS折腾记(9): NASTool与微信交互,微信发送消息远程下载电影【多图】 NAS折腾记(8):群晖安装 NASTool 实现影音半自动化【多图】 内网穿透(2):Tailscale 组网实现内网穿透,操作简单,无成本 内网穿透(1):总结了11中内网穿透的方式,总有一种适合你 NAS折腾记(7):从零开始设置(黑)群晖系统 NAS折腾记(6):黑群晖系统安装好后怎么洗白? NAS折腾记(5):群晖硬盘休眠设置与分析 NAS折腾记(4): 20分钟手把手带你完美安装 DS918+ 黑群晖7.1.1 NAS折腾记(3):NAS 装机 NAS折腾记(2):B360-ITX 双M.2 双2.5G网口 6 SATA主版 开箱 NAS折腾记(1):328元的4盘位Nas机箱开箱 Openwrt + Clash 全局科学上网 Newifi3 刷入 OpenWrt 固件 v21.02 利用 Markdown 画一些流程图、时序图、甘特图等 Homelab(8): 搭建自用 Gitlab 与 Docker 仓库 Nginx Tcp 转发保留客户端真实 IP (PROXY Protocol) Homelab (7):IPSec VPN(基于证书认证)客户端设置 Homelab (6): 基于自签发证书的 IPSec VPN 搭建 Homelab (5): DDNS 动态域名解析 Homelab (4): Linux 服务器基础环境准备 Homelab (3): 整体网络与基础硬件介绍 Go学习笔记(十)老项目迁移 go module 大型灾难记录 Github Actions 初体验之自动化部署 Hexo 博客 记一次 Nginx DNS 缓存导致转发问题 Homelab (2): 电信悦me网关修改桥接模式,路由器拨号 Homelab (1):5分钟上手黑群晖 NAS 终极 Bash 脚本指南 Typora 自动上传图片到七牛云 Ubuntu 20.04 LTS 有线网卡驱动安装 折腾 Ubuntu 20.04 LTS 开发环境 Go学习笔记(九) 计时器的生命周期[译] 利用 git hook 规范你的代码与 commit message 规范 git commit message 与自动化版本控制 超详细 vim 配置 (with MacVim) Golang 中的 RESTful API 最佳实践 折腾服务器(开篇) 我的第一台个人服务器 Newifi3 实现低成本家庭级科学上网 Go学习笔记(八) | 使用 os/exec 执行命令 如何用 Go 调用 Windows API Mac OS 自动根据 WI-FI 名字改变网络位置 关于 Docker 清理 MIME Types 速查表 Go学习笔记(七) | 理解OAuth 2.0并实现一个客户端 我又又又把博客迁移了 Go学习笔记(六) | 使用swaggo自动生成Restful API文档 Go学习笔记(五) | 使用代码片段(snippets)提高编码效率 书单 - 2018 IPFS 初体验,利用 IPFS 托管你的静态网站 记一次 PostgreSQL LIKE 索引优化,联合字段 LIKE 查询优化。 Disqus 添加有趣的 Reactions 的功能 TLS 1.3 详解 (RFC 8446解读) gRPC在Go中的使用(三)gRPC实现TLS加密通信与流模式 gRPC在Go中的使用(二)gRPC实现简单通讯 gRPC在Go中的使用(一)Protocol Buffers语法与相关使用 CentOS 安装 tshark 抓包工具 Go学习笔记(四) | win上使用VSCode搭建Go开发环境 日常 Postgres 数据库点滴记录 简单了解 PKCS 规范 美食篇 | DIY戚风蛋糕(烤箱做蛋糕) Go学习笔记(三) | 怎么写Go基准测试(性能测试) TLS1.3正式更新,为Nginx添加TLS1.3的支持 一次诡异的数据库删除 GitHub Pages自定义域名开启HTTPS 证书透明度是什么?它是怎么工作的? Go学习笔记(二) | 我对 recover 的一点误解 搭建证书透明度(certificate-transparency)日志服务之从入门到放弃 修复远程登陆 Centos 时,出现 UTF-8 Warning HTTPS篇之SSL握手过程详解 Go学习笔记(一) | postgres与golang点点滴滴 AWS 命令行界面(aws-cli)从安装到快速上手 数字证书分类及怎么区分各类数字证书 常用 linux 命令小结(一)文件目录操作 云服务器搭建 hexo 博客,git hooks自动更新 SSH 免密登陆, SSH Config 配置 Golang CGO Mac 交叉编译 Windows 使用 goose 让数据库迁移更加轻松 开始使用Ghost
部署一个自己的 Running Page
2025-04-10 · via Razeen`s Blog

关注 Running Page 项目很久了,今天终于把它部署在我博客上了。Running Page 是一个将运动数据可视化的开源项目,它支持汇总运动记录、生成热力图,并与MapBox结合展示路线。 本文将分享如何通过GitLab CI/CD自动化构建静态页面,并集成苹果快捷指令一键触发部署。

搭建准备

官方支持了 Vercel(推荐)和 GitHub Pages 自动部署,但个人还是比较喜欢跑在自己的服务器上,正好自己搭建了Gitlab, 于是就小折腾了一番。

准备的环境有:

  • Gitlab CE 仓库:之前在家搭建了一个私有的,用来托管日常自己写的代码和自动部署博客;

  • Gitlab Runner: 安装一个 Gitlab Runn 来跑工作流;

  • 服务器:Racknerd上买了个小机来跑我的博客;

  • 跑步数据: 官方支持了很多平台的跑步数据导入,我主力用的是 keep, 准备好账号/密码就好了。

image-20250412092600972

构建页面

导入仓库

Gitlab 有个很好用的功能,可以直接导入Github的项目,利用这个功能,就能将 Running Page 的仓库导入到私有的仓库了。

我在导入的时候出现了两次导入失败的情况,可能是网络的问题,重试后就成功导入了

image-20250412165736786

自定义修改

Running Page 是支持自定义站点标题等信息的,官方文档写的很细致的,这里不展开了。

不过修改的内容,建议切换到一个自己的分支,进行修改,方便后面的维护与更新。

最近 ChatGPT 生图的功能非常👍,我按照原来的风格我重新做了个 Logo 😄 logo

另外注意一点,如果想放在站点的子目录(如 /running/),需要设置一下环境变量PATH_PREFIX, 或直接修改vite.config.tsbase base: process.env.PATH_PREFIX || '/running/'

构建与部署

接下来就是使用 CI/CD 自动构建了。直接使用官方仓库的 Dockerfile 就可以完成静态页面的构建,那这部分步骤就很清晰了。

graph LR
    B[使用Docker构建] --> C[从Docker中复制静态页面]
    C --> D[静态页面保存构建产物]
    D --> E[rsync推送页面到服务器]

为了安全,我们先将我们的密码/服务器私钥设置到项目下的 Setting > CI/CD > Variables中,我这里加了三个

  • keep 登陆手机号KEEP_LOGIN_PHONE
  • keep 登陆密码 KEEP_LOGIN_PASSWORD
  • 博客服务器的私钥 BLOG_SSH_PRIVATE_KEY (可以生成一个专用的私钥用来部署, 注意提前在服务器配置好公钥)

在添加变量的时候可以将 Masked钩上,Protect variable 不要随便勾选,除非你讲你自己的分支设置成保护分支,不然构建的时候获取不到值。

到这里就写好这个简易的.gitlab-ci.yml了。

image: docker:latest

stages:
  - build
  - deploy

build:
  stage: build
  tags:
    - linux01
  script:
    # 构建 Docker 镜像
    - docker build --build-arg app=Keep --build-arg keep_phone_number=$KEEP_LOGIN_PHONE --build-arg keep_password=$KEEP_LOGIN_PASSWORD --build-arg YOUR_NAME="Razeen" -t running-page:$CI_COMMIT_SHA .
    
    # 创建临时容器来获取构建产物
    - docker create --name temp_container running-page:$CI_COMMIT_SHA
    - docker cp temp_container:/usr/share/nginx/html ./dist
    - docker rm temp_container
    
    # 保存构建产物
    - mkdir -p artifacts
    - cp -r dist/* artifacts/
  artifacts:
    paths:
      - artifacts/
    expire_in: 1 week
  allow_failure: false

deploy:
  stage: deploy
  tags:
    - homelab01
  script:
    - mkdir -p ~/.ssh
    - echo "$BLOG_SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ls -la ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n" > ~/.ssh/config
    - chmod 600 ~/.ssh/config
    
    # 使用 rsync 同步文件
    # 'ssh -p 2222' 如果SSH是非常规端口
    - rsync -avz -e 'ssh -p 2222' --delete artifacts/ root@118.93.29.15:/www/running/
  dependencies:
    - build
  allow_failure: false

同时,服务器配置好的nginx路径。

    location /running {
        root                        /www/;
        index                       index.html index.htm;
    }

快捷方式触发

上面的 CI/CD 配置写好了,但没加触发条件。为了方便记录,我这里使用了苹果的快捷方式来触发。

在项目下 Settings > C1/CD > Pipeline trigger tokens 中,可以添加一个工作流触发的 Token, 然后可以通过 POST 对应的URL触发了,如

# https://git.isw.app/ => gitlab 地址 
# 25 => 项目ID
# REF_NAME => 分支 或 tag (我这里触发的分支)
# glptt-xxxxx => 工作流触发 token 
https://git.razeen.app/api/v4/projects/25/ref/REF_NAME/trigger/pipeline?token=glptt-xxxxx

接着,我们使用 获取URL内容 的组件来触发工作流,注意请求方式使用POST。再加个弹窗展示返回内容。给快捷方式选个LOGO,保存,设置快捷方式到桌面。这样一键触发就制作好了。

image-20250412165609885

再在 CI/CD配置中加上对应的触发条件。这里加上了页面触发和触发器触发。

# 简化触发器配置
workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "trigger"
      when: always
    - if: $CI_PIPELINE_SOURCE == "web"
      when: always

自动同步代码

之前的步骤已经完成自动构建和部署了,但我还希望我本地的代码能和 GitHub 的保持持续的同步,需要时和自己的分支合并就可更新自己的Page了。

Gitlab 自带 Mirroring repositories 功能,能自动将本地代码与指定远程保持一致,但 CE 版本只能同步推送,这里就需要用CI实现一下。

sync-upstream:
  stage: sync
  tags:
    - m1max
  script:
    # 配置 Git
    - git config --global user.name "GitLab CI"
    - git config --global user.email "gitlab-ci@isw.app"
    
    # 克隆仓库
    # REPO_TOKEN 在项目下的 Setting > Access Tokens 中添加一个Token, 并设置到CI/CD的环境变量中去
    # 需要 read_repository, write_repository 的权限
    # CI 开头的环境变量是CI自带的,不用设置
    - git clone https://oauth2:${REPO_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git repo
    - cd repo
    
    # 确保在 master 分支
    - git checkout master
    
    # 添加上游仓库
    - git remote add upstream https://github.com/yihong0618/running_page.git
    
    # 获取上游更新
    - git fetch upstream
    
    # 合并上游更新到本地 master 分支
    - git merge upstream/master -m "Merge upstream changes"
    
    # 推送到 GitLab 仓库
    - git push https://oauth2:${REPO_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git master

此外,为了持续更新,在后台再加个订单调度。为了不和build/deploy 冲突,添加两个条件来区分构建和同步的场景。

  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $SYNC_ONLY == "true"
      when: always
    - if: $CI_PIPELINE_SOURCE == "web" && $CI_JOB_NAME == "sync-upstream"
      when: always

image-20250412165248283

总结

至此,基本全部实现了。以后每次跑完步就可以触发一下更新上去了。为了身体健康,为了热力图效果,运动起来!!

详细配置

老习惯,最后贴一下全部的配置。.gitlab-ci.yml。防止多个构建和并发同时执行,加了一个resource_group

image: docker:latest

stages:
  - sync
  - build
  - deploy

variables:
  GIT_STRATEGY: clone

# 简化触发器配置
workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "trigger"
      when: always
    - if: $CI_PIPELINE_SOURCE == "web"
      when: always
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: always

.build_template: &build_template
  resource_group: running-page-pipeline
  interruptible: false

deploy:
  <<: *build_template
  stage: deploy
  tags:
    - homelab01
  script:
    - mkdir -p ~/.ssh
    - echo "$BLOG_SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ls -la ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n" > ~/.ssh/config
    - chmod 600 ~/.ssh/config
    - rsync -avz -e 'ssh -p 2222' --delete artifacts/ root@118.93.29.15:/www/running/
  dependencies:
    - build
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $SYNC_ONLY == "true"
      when: never
    - if: $CI_PIPELINE_SOURCE == "web" && $CI_JOB_NAME == "sync-upstream"
      when: never
    - when: always
  allow_failure: false

build:
  <<: *build_template
  stage: build
  tags:
    - linux01
  script:
    - docker build --build-arg app=Keep --build-arg keep_phone_number=$KEEP_LOGIN_PHONE --build-arg keep_password=$KEEP_LOGIN_PASSWORD --build-arg YOUR_NAME="Razeen" -t running-page:$CI_COMMIT_SHA .
    - docker create --name temp_container running-page:$CI_COMMIT_SHA
    - docker cp temp_container:/usr/share/nginx/html ./dist
    - docker rm temp_container
    - mkdir -p artifacts
    - cp -r dist/* artifacts/
  artifacts:
    paths:
      - artifacts/
    expire_in: 1 week
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - activities/
      - assets/
      - GPX_OUT/
      - TCX_OUT/
      - FIT_OUT/
      - Workouts/
      - run_page/data.db
      - src/static/activities.json
      - imported.json
    policy: pull-push
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $SYNC_ONLY == "true"
      when: never
    - if: $CI_PIPELINE_SOURCE == "web" && $CI_JOB_NAME == "sync-upstream"
      when: never
    - when: always
  allow_failure: false
  
sync-upstream:
  stage: sync
  resource_group: repo-sync
  tags:
    - m1max
  script:
    - git config --global user.name "GitLab CI"
    - git config --global user.email "gitlab-ci@isw.app"
    - git clone https://oauth2:${REPO_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git repo
    - cd repo
    - git checkout master
    - git remote add upstream https://github.com/yihong0618/running_page.git
    - git fetch upstream
    - git merge upstream/master -m "Merge upstream changes"
    - git push https://oauth2:${REPO_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git master
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $SYNC_ONLY == "true"
      when: always
    - if: $CI_PIPELINE_SOURCE == "web" && $CI_JOB_NAME == "sync-upstream"
      when: always
  allow_failure: true

配置中用了三个runner的 tag, homelab01linux01 跑在家里服务器上,m1max 跑在本地电脑上,需要按照好对应的 git 等命令。