乐趣区

关于docker:使用Docker-ComposeNginxSSH和Github-Actions实现前端自动化部署测试机

开篇,咱们先来看一下远古时代的构建部署流程。想必大家对这个都不生疏:

  • 开发将源码通过编译、压缩打包生成打包文件
  • 将打包生成的文件上传服务器

显然这个流程不仅繁琐,而且效率也不高,开发每次公布都要消耗很长的工夫在部署构建下面。

前面为了解决这个问题,就呈现了CI/CD

接下来咱们来聊一下 什么是 CI/CD?

CI/CDContinuous Intergration/Continuous Deploy 的简称,翻译过去就是 继续集成 / 继续部署CD 也会被解释为继续交付(Continuous Delivery

再具体一点就是:

  • 继续集成:当代码仓库代码产生变更,就会主动对代码进行测试和构建,反馈运行后果。
  • 继续交付:继续交付是在继续集成的根底上,能够将集成后的代码顺次部署到测试环境、预公布环境、生产环境中

聊了这么多,置信很多同学肯定会说:

  • 这个别不都是运维搞的吗?
  • 和业务也不相干啊,理解它有什么用?
  • 全是服务器相干的货色,dockernginx、云服务器啥的,我该怎么学习呢?

很早之前,我也是这么想的,感觉与本人的业务也没啥关系,没有太大的必要去理解。

然而最近我在搞一个 全栈我的项目(做这个我的项目是为了冲破本人的瓶颈)时,就遇到了这些问题,发现陷入了常识盲区。

没方法,只能一顿恶补。

然而当我通过学习这些常识和在我的项目中实际这些流程后,我在知识面上失去了很大的扩大。对操作系统,对理论的构建部署,甚至对工程化领有了全新的意识。

这里也放下后面提到的 全栈我的项目 的架构图吧:

这个大的我的项目以 low code 为外围,囊括了 编辑器前端 编辑器后端 C 端 H5 组件库 组件平台 后盾管理系统前端 后盾管理系统后盾 统计服务 自研 CLI九大零碎。

其中的 编辑器前端 在如何设计实现 H5 营销页面搭建零碎文章中曾经有很具体的阐明。

目前整个我的项目做了 70% 左右,过程中遇到了很多问题,也失去了很大的晋升。后续会有一波文章是对于我的项目中的一个个小点开展的,也都是满满的干货。

回到本篇文章的主题:应用 Docker Compose、Nginx、SSH 和 Github Actions 实现前端自动化部署测试机 。本文是以 后盾管理系统前端 为依靠具体阐明了如何借助 DockernginxGithub CI/CD 能力自动化公布一个 纯前端我的项目。选这个我的项目来解说自动化公布测试机有两个出发点:

  • 后盾管理系统业务较简略,可将重心放在自动化部署流程上
  • 纯前端我的项目更实用于大部分前端同学现状,拿去即用

整体思路

前端代码,打包进去的是动态文件,可用 nginx 做服务。思路:

  • 构建一个 Docker 容器(有nginx
  • dist/ 目录拷贝到 Docker 容器中
  • 启动 nginx 服务
  • 宿主机端口,对应到 Docker 容器端口中,即可拜访

外围代码变动:

  • nginx.conf(给 Docker 容器的 nginx 应用)
  • Dockerfile
  • docker-compose.yml

⚠️ 本文将采纳理论知识和理论相结合的形式,即先讲述一下对应知识点,同时会放一下与此知识点相干的我的项目代码或配置文件。

上面会顺次解说 Dockerdocker-composesshgithub actions 等知识点。

Docker

Docker很早之前,在公众号的一篇文章谁说前端不须要学习 docker?就有过具体阐明。这里简略再论述下。

docker 能够看成是一个高性能的虚拟机,次要用于 linux 环境的虚拟化。开发者能够打包他们的利用以及依赖包到一个可移植的容器中,而后公布到任何风行的 linux 机器上。容器齐全应用沙箱机制,相互之间不会有任何接口。

在容器中你能够做任何服务器能够做的事,例如在有 node 环境的容器中运行 npm run build 打包我的项目,在有 nginx 环境的容器中部署我的项目等等。

centos 上装置 docker

因为这次的云服务器是 centos 的,所以这里就提一下如何在 centos 上装置 docker


$ sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine

$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2

$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

$ sudo yum install docker-ce docker-ce-cli containerd.io

$ sudo systemctl start docker

$ sudo docker run hello-world

dockerfile

docker 应用 Dockerfile 作为配置文件进行镜像的构建,简略看一个 node 利用构建的 dockerfile

FROM node:12.10.0

WORKDIR /usr/app

COPY package*.json ./

RUN npm ci -qy

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

阐明一下每个关键字对应的含意。

FROM

基于这个 Image 开始

WORKDIR

设置工作目录

COPY

复制文件

RUN

新层中执行命令

EXPOSE

申明容器监听端口

CMD

容器启动时执行指令默认值

看下我的项目中的 Dockerfile 文件:

# Dockerfile
FROM nginx

# 将 dist 文件中的内容复制到 /usr/share/nginx/html/ 这个目录上面
# 所以,之前必须执行 npm run build 来打包出 dist 目录,重要!!!COPY dist/ /usr/share/nginx/html/

# 拷贝 nginx 配置文件
COPY nginx.conf /etc/nginx/nginx.conf

# 设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone

# 创立 /admin-fe-access.log,对应到 nginx.conf
CMD touch /admin-fe-access.log && nginx && tail -f /admin-fe-access.log

在这个文件外面,咱们做了上面几件事:

1、咱们用了 NginxDocker image 作为 base image

2、把打包生成的文件夹 dist/ 的全部内容放进 Nginx Docker 的默认 HTML 文件夹,也就是/usr/share/nginx/html/ 外面。

3、把自定义的 Nginx 配置文件 nginx.conf 放进 Nginx Docker 的配置文件夹 /etc/nginx/nginx.conf 中。

4、设置时区。

5、创立 /admin-fe-access.log,启动 nginx 并应用 tail -f 模仿相似 pm2 的阻塞式过程。

这里提到了 nginx.conf 文件:

#nginx 过程数,通常设置成和 cpu 的数量相等
worker_processes auto;

#全局谬误日志定义类型
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#过程 pid 文件
#pid        logs/nginx.pid;

#参考事件模型
events {
    #单个过程最大连接数(最大连接数 = 连接数 + 过程数)worker_connections  1024;
}

#设定 http 服务器
http {
    #文件扩展名与文件类型映射表
    include       mime.types;
    #默认文件类型
    default_type  application/octet-stream;

    #日志格局设定
    #$remote_addr 与 $http_x_forwarded_for 用以记录客户端的 ip 地址;#$remote_user:用来记录客户端用户名称;#$time_local:用来记录拜访工夫与时区;#$request:用来记录申请的 url 与 http 协定;#$status:用来记录申请状态;胜利是 200,#$body_bytes_sent:记录发送给客户端文件主体内容大小;#$http_referer:用来记录从那个页面链接拜访过去的;#$http_user_agent:记录客户浏览器的相干信息;log_format  main  '$remote_addr - $remote_user [$time_local]"$request"''$status $body_bytes_sent "$http_referer" ''"$http_user_agent""$http_x_forwarded_for"';

    # access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    #长连贯超时工夫,单位是秒
    keepalive_timeout  65;

    #gzip  on;

    #设定通过 nginx 上传文件的大小
    client_max_body_size   20m;

    #虚拟主机的配置
    server {
        #监听端口
        listen       80;
        #域名能够有多个,用空格隔开
        server_name  admin-fe;

        #charset koi8-r;

        #定义本虚拟主机的拜访日志
        access_log  /admin-fe-access.log  main; # 留神,在 Dockerfile 中创立 /admin-fe-access.log

        #入口文件的设置
        location / {
            root   /usr/share/nginx/html;   #入口文件的所在目录
            index  index.html index.htm;    #默认入口文件名称
            try_files $uri $uri/ /index.html;
        }
        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {root   html;}
    }
}

外围点就是监听 80 端口,定义日志文件为 admin-fe-access.log,入口文件根目录为/usr/share/nginx/html,这些都是与Dockerfile 中一一对应的。

说完了 Dockerfile 及其相干的配置文件,上面接着来看下 docker 中几个外围的概念。

docker 外围概念

docker中有三个十分重要的概念:

  • 镜像(image)
  • 容器(container)
  • 仓库(repository)

一张图来表明其中的关系:

如果把容器比作轻量的服务器,那么镜像就是创立它的模版,一个 docker 镜像 能够创立多个 容器 ,它们的关系好比 JavaScript 实例 的关系。

镜像(image)常用命令:

  • 下载镜像:docker pull <image-name>:<tag>
  • 查看所有镜像:docker images
  • 删除镜像:docker rmi <image-id>
  • 上传镜像:docker push <username>/<repository>:<tag>

如果 docker images 呈现 repository<none>的状况,能够运行 docker image prune 删除

容器(container)常用命令

  • 启动容器:docker run -p xxx:xxx -v=hostPath:containerPath -d --name <container-name> <image-name>

    • -p 端口映射
    • -v 数据卷,文件映射
    • -d 后盾运行
    • –name 定义容器名称
  • 查看所有容器:docker ps(加 -a 显示暗藏的容器)
  • 进行容器:docker stop <container-id>
  • 删除容器:docker rm <container-id>(加 -f 强制删除)
  • 查看容器信息(如 IP 地址等):docker inspect <container-id>
  • 查看容器日志:docker logs <container-id>
  • 进入容器控制台:docker exec -it <container-id> /bin/sh

镜像构建实现后,能够很容易的在以后宿主上运行,然而,如果须要在其它服务器上应用这个镜像,咱们就须要一个集中的存储、散发镜像的服务,Docker Registry 就是这样的服务。

一个 Docker Registry 中能够蕴含多个仓库(Repository);每个仓库能够蕴含多个标签(Tag);每个标签对应一个镜像。所以说:镜像仓库是 Docker 用来集中寄存镜像文件的中央,相似于咱们之前罕用的代码仓库。

docker-compose

docker-compose我的项目是 Docker 官网的开源我的项目,负责实现对 Docker 容器集群的疾速编排。容许用户通过一个独自的 docker-compose.yml 模板文件(YAML 格局)来定义一组相关联的利用容器为一个我的项目(project)。

应用 compose 的最大长处是你只需在一个文件中定义本人的应用程序栈(即应用程序须要用到的所有服务),而后把这个 YAML 文件放在我的项目的根目录下,与源码一起受版本控制。其他人只需 clone 你的我的项目源码之后就能够疾速启动服务。

通常实用于我的项目所需运行环境(对应多个 docker 容器)较多的场景,例如同时依赖于 nodejsmysqlmongodbredis 等。

这里放下 docker-compose.yml 文件:

version: '3'
services:
  admin-fe:
    build:
      context: .
      dockerfile: Dockerfile
    image: admin-fe # 援用官网 nginx 镜像
    container_name: admin-fe
    ports:
      - 8085:80 # 宿主机能够用 127.0.0.1:8085 即可连贯容器中的数据库

基于上文的 Dockerfile 创立镜像,端口映射是 8085:80,这里的8085 是宿主机端口,80对应的是 nginx 裸露的 80 端口

常用命令

  • 构建容器:docker-compose build <service-name>
  • 启动所有服务器:docker-compose up -d(后盾启动)
  • 进行所有服务:docker-compose down
  • 查看服务:docker-compose ps

ssh 及云服务器

首先说下云服务器,既然要一键部署测试机,那么必定要有台测试机,也就是云服务器,这里我用的是阿里云 CentOS 8.4 64 位 的操作系统。

有了服务器,那怎么登陆呢?

本地登陆云服务器的形式个别有两种,明码登陆和 ssh 登陆。然而如果采纳明码登陆的话,每次都要输出明码,比拟麻烦。这里采纳 ssh 登陆的形式。对于如何免密登录近程服务器,能够参考 SSH 免密登陆配置

尔后每次登陆都能够通过 ssh <username>@<IP> 的形式间接免密登陆了。

云服务器装置指定包

接着要给云服务器装置根底包,在 CentOS 装置指定包个别用的是yum,这个不同于npm

docker

# Step 1: 卸载旧版本
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
# Step 2: 装置必要的一些零碎工具
sudo yum install -y yum-utils
# Step 3: 增加软件源信息,应用阿里云镜像
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 4: 装置 docker-ce
sudo yum install docker-ce docker-ce-cli containerd.io
# Step 5: 开启 docker 服务
sudo systemctl start docker
# Step 6: 运行 hello-world 我的项目
sudo docker run hello-world

如果你像我一样,有 Hello from Docker! 的话那么 Docker 就装置胜利了!

docker-compose

通过拜访 https://github.com/docker/compose/releases/latest 失去最新的 docker-compose 版本(例如:1.27.4),而后执行一下命令装置 docker-compose

# 下载最新版本的 docker-compose 到 /usr/bin 目录下
curl -L https://github.com/docker/compose/releases/download/1.27.4/docker-compose-`uname -s`-`uname -m` -o /usr/bin/docker-compose

# 给 docker-compose 受权
chmod +x /usr/bin/docker-compose

装置完,命令行输出 docker-compose version 来验证是否装置胜利:

node

首先确保能够拜访到EPEL 库,通过运行以下命令来装置:

sudo yum install epel-release

当初能够应用 yum 命令装置 Node.js 了:

sudo yum install nodejs

验证一下:

nginx

yum 装置 nginx 非常简单,输出一条命令即可:

$ sudo yum -y install nginx   # 装置 nginx

git

同样也是应用 yum 来装置:

yum install git

最初来看一下github actions,也是串联起了下面提到的各个点。

github actions

大家晓得,继续集成由很多操作组成,比方拉取代码、执行测试用例、登录近程服务器,公布到第三方服务等等。GitHub 把这些操作就称为 actions

咱们先来理解一下一些 术语

  • workflow(工作流程):继续集成一次运行的过程,就是一个 workflow。
  • job(工作):一个 workflow 由一个或多个 jobs 形成,含意是一次继续集成的运行,能够实现多个工作。
  • step(步骤):每个 job 由多个 step 形成,一步步实现。
  • action(动作):每个 step 能够顺次执行一个或多个命令(action)。

workflow 文件

GitHub Actions 的配置文件叫做 workflow 文件,寄存在代码仓库的 .github/workflows 目录。

workflow 文件采纳 YAML 格局,文件名能够任意取,然而后缀名对立为 .yml,比方deploy.yml。一个库能够有多个 workflow 文件。GitHub 只有发现.github/workflows 目录外面有 .yml 文件,就会主动运行该文件。

workflow 文件的配置字段十分多,这里列举一些根本字段。

name

name字段是 workflow 的名称。

如果省略该字段,默认为以后 workflow 的文件名。

name: deploy for feature_dev

on

on字段指定触发 workflow 的条件,通常是pushpull_request

指定触发事件时,能够限定分支或标签。

on:
  push:
    branches:
      - master

下面代码指定,只有 master 分支产生 push 事件时,才会触发 workflow

jobs

jobs字段,示意要执行的一项或多项工作。其中的 runs-on 字段指定运行所须要的虚拟机环境。

runs-on: ubuntu-latest

steps

steps字段指定每个 Job 的运行步骤,能够蕴含一个或多个步骤。每个步骤都能够指定以下三个字段。

  • jobs.<job_id>.steps.name:步骤名称。
  • jobs.<job_id>.steps.run:该步骤运行的命令或者 action。
  • jobs.<job_id>.steps.env:该步骤所需的环境变量。

上面放一下我的项目中的 .github/workflows/deploy-dev.yml 文件:

name: deploy for feature_dev

on:
  push:
    branches:
      - 'feature_dev'
    paths:
      - '.github/workflows/*'
      - '__test__/**'
      - 'src/**'
      - 'config/*'
      - 'Dockerfile'
      - 'docker-compose.yml'
      - 'nginx.conf'

jobs:
  deploy-dev:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Use Node.js
        uses: actions/setup-node@v1
        with:
          node-version: 14
      - name: lint and test # 测试
         run: |
           npm i
           npm run lint
           npm run test:local
      - name: set ssh key # 长期设置 ssh key
        run: |
          mkdir -p ~/.ssh/
          echo "${{secrets.COSEN_ID_RSA}}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan "106.xx.xx.xx" >> ~/.ssh/known_hosts
      - name: deploy
        run: |
          ssh work@106.xx.xx.xx "
            cd /home/work/choba-lego/admin-fe;
            git remote add origin https://Cosen95:${{secrets.COSEN_TOKEN}}@github.com/Choba-lego/admin-fe.git;
            git checkout feature_dev;
            git config pull.rebase false;
            git pull origin feature_dev;
            git remote remove origin;

            # 构建 prd-dev
            # npm i;
            # npm run build-dev;

            # 启动 docker
            docker-compose build admin-fe; # 和 docker-compose.yml service 名字统一
            docker-compose up -d;
          "
      - name: delete ssh key
        run: rm -rf ~/.ssh/id_rsa

这里概述一下:

1️⃣ 整个流程在代码 pushfeature_dev分支时触发。

2️⃣ 只有一个job,运行在虚拟机环境ubuntu-latest

3️⃣ 第一步应用的是最根底的 action,即actions/checkout@v2,它的作用就是让咱们的workflow 能够拜访到咱们的repo

4️⃣ 第二步是在执行工作流的机器中装置 node,这里应用的actionactions/setup-node@v1

5️⃣ 第三步是执行 linttest

6️⃣ 第四步是长期设置 ssh key,这也是为了下一步登录服务器做筹备。

7️⃣ 第五步是部署,这外面先是 ssh 登录服务器,拉取了最新分支代码,而后装置依赖、打包,最初启动 docker,生成镜像。到这里测试机上就有了Docker 服务。

8️⃣ 最初一步是删除ssh key

最初来 github 看一下残缺的流程:

其中 deploy 阶段算是外围了:

总结

洋洋洒洒写了这么多,也不晓得你看明确了不 😂

如果有任何问题,欢送评论区留言,看到后会第一工夫解答 😊

后续会有很多对于这个我的项目的文章,也请大家多多关注~

退出移动版