使用K8S搭建前端测试环境-基础服务搭建

6次阅读

共计 4291 个字符,预计需要花费 11 分钟才能阅读完成。

我们先制作上一篇文章中提及的两个镜像。

frontend_toolkit 镜像

FROM ubuntu:latest

# 将 nodejs 复制到容器下,防止因网络原因导致镜像打包慢或失败的问题
# 版本按需选择
COPY nodejs_setup_13.x.sh /home/

# 安装 nodejs
RUN bash /home/nodejs_setup_13.x.sh

# 安装基础工具
RUN apt-get install -y git nodejs curl

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -

RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

RUN apt-get update && apt-get install -y yarn vim

服务基础镜像

FROM nginx:latest

WORKDIR /var/wwwroot

# 将 nginx 配置文件复制到容器下
COPY ./gaia/nginx/* /etc/nginx/conf.d/
# 将静态资源复制到访问路径下
COPY ./dist/ /var/wwwroot

EXPOSE 80
server {
  listen 80;
  server_name _;

  # 服务的配置
  location / {
    alias /var/wwwroot/;
    try_files $uri $uri/ /index.html =404;
  }
}

上述 docker 文件编写好后,分别进行 build 即可。

发现和注册服务

通过 K8S 注册一个服务后,如果是做了集群的,可以参考配置 Ingress 来启用服务发现,但我们目前仅使用到单集群单节点的方式,实际上是可以直接通过服务名来访问的。

比如我们部署了一个服务叫 username-func-test-k8s,那么我们可以通过命令curl username-func-test-k8s 来访问到服务本身。

回想我们要的效果是通过 cookie 来识别我们要访问的服务,所以只需要通过配置 nginx 解析 cookie 来做对应的反向代理即可。

这里值得说明的是 nginx 的反向代理是无法支持配置 search 的,也就是说没有办法通过变量的形式直接进行反向代理,比如:

# 这样是不支持的
proxy_pass http://$SVC_NAME/

所以每次有新服务,我们都需要重新配置一条规则,看似需要有一个专门的服务来管理这件事,还记得我们 CI/CD 的最后一个阶段所做的事吗?

没错,它所访问的地址,正是我们的这个服务。可随意搭建一个 http 服务即可,核心逻辑如下:

function updateNginxConfig (conf) {
  // 读取 nginx 模板文件
  const nginxTemplate = _.template(fs.readFileSync('nginx.template', { encoding: 'utf-8'}))
  // 读取服务列表
  const conf = getSvcList()
  // 根据服务列表生成新的 nginx 文件
  fs.writeFileSync('/etc/nginx/conf.d/default.conf', nginxTemplate({ services: conf}))
}

function getSvcList () {
  // 读取 k8s 服务列表,以 json 输出方便使用
  const svcQuery = childProcess.spawnSync('kubectl', ['get', 'svc', '-o', 'json'], {encoding: 'utf-8'})

  if (svcQuery.stdout) {const svc = JSON.parse(svcQuery.stdout)
    // 排除一些基础服务,我们只要符合 `${username}-${branch}-svc` 规则的服务
    const gaiaSvc = svc.items.filter(item => /\w+-(\w+-)*svc/.test(item.metadata.name))
    return gaiaSvc.map(item => ({ name: item.metadata.name}))
  } else {throw new Error(svcQuery.stderr)
  }
}

// 这个接口用于返回符合规则的所有的服务列表
router.get('/', (req, res) => {
  try {return res.status(200).json({list: getSvcList() })
  } catch (err) {return res.status(500).json({msg: err})
  }
})

// CI 中第四个阶段调用的方法
router.post('/', (req, res) => {
  // 生成并更新 nginx 配置文件
  updateNginxConfig()
  // 重启 nginx 服务
  reloadServer()

  return res.status(201).json()})

最后我们来看看 nginx 的模板长什么样子:

server {
  server_name  server.com;
  listen 80;

  proxy_next_upstream off;
  proxy_set_header    X-Real-IP           $remote_addr;
  proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
  proxy_set_header    Host                $host;
  proxy_http_version  1.1;
  proxy_set_header    Connection  "";
  proxy_set_header    Accept-Encoding "";
  charset utf-8;

  location / {
    set $svc '';

    # 获取 cookie 信息
    if ($http_cookie ~* "gaia_svc=(.+?)(?=;|$)") {set $svc $1;}

    # 如果没有指定环境,那么反向代理到一个默认的服务上去,避免出现 50x 错误
    if ($svc = '') {proxy_pass https://10.10.10.10;}

    # 根据 k8s 的服务,循环出判断体,最终根据 cookie 设置的服务名做反向代理
    <% _.forEach(services, function (svc) { %>
    if ($svc = <%= svc.name %>) {proxy_pass http://<%= svc.name %>;}
    <% }) %>

    # 注入环境选择器
    # 我们之前一直没有说明测试人员绑定了这个服务器后,应该怎么切换环境呢?# 其实就是通过这个脚本来完成,我们可以注入一些页面元素,或者通过快捷键唤起环境选择器
    sub_filter_types text/html;
    sub_filter_once on;
    sub_filter '</body>' '<script src="https://server.com/env-selector.js"async></script></body>';
  }

  # 配置环境选择器的路径
  location /env-selector.js {alias /usr/share/nginx/html/js/env-selector.js;}

  // 配置环境选择器所需要用到的接口
  // 这里转发到本地的 get / 接口上,用于获取合法的环境列表
  location /__gaia_env__/ {proxy_pass http://127.0.0.1:3500/;}
}

环境选择器代码如下:

import App from './App.svelte'

const DEFAULT_ENV = [{name: 'beta'}]

document.addEventListener('keydown', function (evt) {
  var key = evt.which || evt.keyCode
  // 当用户按 CTRL+SHIFT+ Q 即可唤起环境选择器
  if (evt.ctrlKey && evt.shiftKey && key == 81) {getEnvList(function (err, data) {if (err) {alert('获取环境列表失败')
      } else {
        const envList = data.list
        const app = new App({
          target: document.body,
          props: {env: DEFAULT_ENV.concat(envList)
          }
        })
        app.$set({app})
      }
    })
  }
})

App.svelte

<script>
  export let env
  export let app

  let selectEnv = ''const gaiaSvc = getCookie("gaia_svc") ||" 原 Beta 环境 ";
  const BETA_ENV = 'beta'

  function handleClick () {if (selectEnv) {selectEnv === BETA_ENV ? deleteCookie('gaia_svc') : setCookie("gaia_svc", selectEnv)
      window.location.reload()}
  }

  function handleClose () {app.$destroy()
  }
</script>

<div id="GaiaEnvSelector">
  <div class="gaiaCaption">
    <span class="gaiaEnvClose" on:click={handleClose}>X</span>
    环境选择
  </div>
  <div class="gaiaCurrentEnv"> 当前环境:<em>{gaiaSvc}</em></div>
  <select class="gaiaSvcSelect" bind:value="{selectEnv}">
    <option value=""> 请选择 </option>
    {#each env as { name}, i}
    <option value="{name}">{name}</option>
    {/each}
  </select>
  <button class="switchEnvBtn" on:click={handleClick}> 切换环境 </button>
</div>

最终,所有步骤均已完成。

使用 K8S 搭建前端测试环境 – 前言
使用 K8S 搭建前端测试环境 – K8S 环境搭建
使用 K8S 搭建前端测试环境 – Gitlab 集成 K8S
使用 K8S 搭建前端测试环境 – 创建 CI/CD
使用 K8S 搭建前端测试环境 – 基础服务搭建
使用 K8S 搭建前端测试环境 – 总结

正文完
 0