【实战知识】使用Github Action + Nginx实现自动化部署

大家好啊,我是独立开发豆小匠。

先说一下背景~

我的小程序:豆流便签,目前使用云托管部署后端服务,使用轻量级服务器部署数据库和一些中间件。

因此服务器成本:云托管 + 云服务器

云托管每周花费5元,一个月就是50,一年就是500啊,所以这期准备把云托管优化掉!


1. 需求分析

使用云托管的好处是很明显的,可以推送代码后自动化部署。如果转移到云服务器,怎么延续自动化部署的开发体验咧,主要的需求如下:

  1. 自动化部署test分支
  2. 自动化部署master分支
  3. 部署期间服务可用

其中第2、3点都是云托管有的功能,第1点云托管也可以做到。但是,得加钱!也就是多开一个服务。

2. 实现思路

实现主要依赖于GitHub提供的Action workflow工作流和Nginx的自动分发、故障转移。

3. 具体实现

3.1. GitHub Action

简单介绍下Github Action,它允许通过配置文件来自动构建测试部署项目等。

我们本次编写deploy.yml文件定义一个自动化部署的工作流,实现的效果:推送master/test分支到GitHub后,连接云服务器,执行部署脚本

首先在项目根目录创建文件夹.github/workflows,然后新建文件deploy.yml,文件内容如下

bash 复制代码
name: Build and Deploy

on:
  push:
    branches: [master]	# 触发任务的分支

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Build and run Go program
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST_MILK }}	# 服务器地址 @1
          username: ${{ secrets.HOST_ROLE }} # 登陆用户名 @2
          key: ${{ secrets.HOST_KEY }} # 服务器私钥 @3
          port: 22
          script: |
            cd /var/you_code_dir && # 更换成你服务器放代码的地方 @4
            git checkout . && git pull &&
            if [ $? -ne 0 ]; then
              echo "拉取失败,脚本终止"
              exit 1
            fi &&
            echo "pull success"
            chmod +x ./deploy.sh && # 给部署脚本加权限
            ./deploy.sh
            echo "deploy success"

其中,Github Action完成的事情:

  1. 连接云服务器,拉取最新代码
  2. 触发部署脚本deploy.sh

其中上面@1、2、3、4都是需要根据我们实际情况修改的

@1:服务器地址,eg:12.12.12.12

@2:用户名,eg:root

@3 服务器私钥,参考下面的配置步骤

bash 复制代码
# 生成密钥
mkdir -p ~/.ssh && cd ~/.ssh
ssh-keygen

# 公钥复制到authorized_keys文件
cat id_rsa.pub >> authorized_keys

# 加权限
chmod -R 700 ~/.ssh
chmod -R 640 authorized_keys

# 复制私钥
cat id_rsa

# 配置到GitHub

@4:需要先把你的代码拉到服务器的目录(如/var/beanflow-test/),然后切换到对应分支(如master/test) ,这样workflow上直接git pull就能更新到最新的代码。

3.2. deploy脚本

Github Action只是解决了推送代码,怎么通知开始部署的问题。真正的版本发布,需要在shell脚本里执行!

我们把部署脚本文件放在项目根目录,文件名叫deploy.sh,这里的示例脚本是支持使用Dockerfile打包项目,然后启动容器的。

你可以根据你的项目情况,编写对应的Dockerfile文件,或者使用其他方式启动项目,如PM2、supervisorctl 等。

在项目根目录编写deploy.sh文件,内容如下:

bash 复制代码
#!/bin/bash

# 定义要部署的端口
ports=(81 82)

# 定义镜像名称
image_name="beanflow"

# 构建 Docker 镜像
docker build -t $image_name .

# 循环处理每个要部署的端口
for port in "${ports[@]}"
do
    # 检查是否存在对应的容器,存在则删除
    container_id=$(docker ps -aq --filter "name=beanflow-$port")
    if [ -n "$container_id" ]; then
        echo "删除端口 $port 对应的容器:beanflow-$port"
        docker stop $container_id
        docker rm $container_id
    fi

    # 使用docker命令运行容器,每个端口对应一个容器实例
    echo "部署端口 $port"
    docker run -d -p $port:80 --name beanflow-$port $image_name --restart=always
done

这个脚本会在服务器上的代码文件目录打包一个beanflow(豆流)的镜像,然后串行重建81、82端口的容器。

  • 部署两个容器的目的:因为是串行部署,部署期间,至少一个容器可以提供服务,利用nginx,可以对外提供可用的服务。
  • 思考,新服务部署完成,可以只留一个容器服务吗?

3.3. Nginx配置

现在还需要解决的问题:

  1. 流量分发问题,前端需要一个固定的请求地址/端口。
  2. 需要区分不可用的服务,自动转发到可用的服务。

在服务器安装Nginx后,在conf.d目录编写流量转发规则和负载均衡配置,配置文件内容如下:

ini 复制代码
upstream test {
    # 失败一次后,服务会被标记为不健康,流量转发到其他服务器
    server 127.0.0.1:91 max_fails=1 fail_timeout=10s;
    server 127.0.0.1:92 max_fails=1 fail_timeout=10s;
}

upstream live {
    server 127.0.0.1:81 max_fails=1 fail_timeout=10s;
    server 127.0.0.1:82 max_fails=1 fail_timeout=10s;
}

server {
    # test服务使用90端口
    listen 90;
    server_name beanflow.top;

    location / {
        proxy_pass http://test;
    }
}


server {
    # live服务使用80端口
    listen 80;
    server_name beanflow.top;
    
    location / {
        proxy_pass http://live;
    }
}

配置后,需要测试和重启nginx

nginx -t
systemctl reload nginx

至此,只要前端请求服务器的80端口,流量就会打到部署了master分支代码的服务;请求90端口,流量就会打到部署了test分支的服务!


这期就喵到这!收!

哎,还留了个尾巴,nginx可以使用第三方扩展功能进行主动的健康检查。这样的话,新服务部署后,其实可以只保留一个容器就行!收!


相关推荐
沛沛老爹36 分钟前
什么是 DevOps 自动化?
大数据·ci/cd·自动化·自动化运维·devops
北京_宏哥2 小时前
python接口自动化(四十)- logger 日志 - 下(超详解)
python·前端框架·自动化运维
豆豆豆豆变2 天前
docker之compose篇
docker·容器·自动化运维
第八学期13 天前
用Ansible Roles重构LNMP架构(Linux+Nginx+Mariadb+PHP)
linux·nginx·重构·架构·ansible·自动化运维
第八学期14 天前
Ansible Eoles详解
linux·运维·自动化·ansible·自动化运维
第八学期17 天前
Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
linux·运维·自动化·ansible·自动化运维
考虑考虑20 天前
乌班图设置时间
运维·后端·自动化运维
帅儿二郎2 个月前
ELK:日志监控平台部署-基于elastic stack 8版本
linux·运维·elk·自动化运维·elastic·日志监控平台·日志分析平台
concisedistinct2 个月前
在多数据中心环境中,自动化运维如何保证跨区域的一致性?网络延迟导致的数据不一致是否可以完全避免?|自动化运维|跨区域一致性
运维·网络·自动化·自动化运维·数据中心
winkee2 个月前
OpenSSL 使用 pkcs#8 格式来封装密钥
linux·自动化运维·devops