阅读 321

给你的项目聘个“翻译官”

前言📒

最近进入了新的项目组,项目 Git 仓库部署在客户的内网环境中,故本地要使用 OpenVPN 才能使用其 Git 平台。可在实际情况中并不是只有在 clonepush 代码时才会访问其内网,Jenkins 拉取代码时也会访问其内网,说到这儿或许你会想到 Jenkins 中可以配置 HTTP Proxy,如图:

但此 HTTP Proxy 是全局配置,假如对全局流水线配置了代理后,就有可能会导致其他的网络请求不通的情况。所以我们最理想的状态就是只在 clone 代码(即 Checkout SCM)阶段使用代理,但在 JenkinsPlugins Manager 中并未找到相关插件,在网上查到的相关 Docker 镜像也都是全局配置。与此同时,就算有针对某个 stage 使用的代理插件,那么当目标服务器有变动时,我们还需要修改各个项目中的 Jenkinsfile,这相对来说也会比较繁琐。所以小伙伴和我一拍脑袋,决定搞一个代理服务器,如果目标服务器有变动那么只需要改动代理服务器即可。

开工👷‍♂️

首先,来明确一下目标:启动一个 Docker 容器并将相应请求代理到内网服务器。 有了明确的目标,接下来就让我们冷静地分析一波,事实上我们所需要的代理服务器就是一个“翻译官”的角色,需要使双方能畅通的交流。假如我们把目标服务器当成“歪果仁”,本地当成“中国人”,当没有“翻译官”时就“中外友人”是无法正常沟通的(即网络不连通):

学外语

首先我们让“翻译官”学学外语,具备“翻译”的技能!

哎~哎~哎,车歪了歪了!让代理服务器具备“翻译”的能力我们就需要安装 OpenVPN,然后使用 OpenVPN shovpn file 来启动代理。OpenVPN sh 我们可以直接 copy GitHub源码ovpn file 配置请见此文档,这样我们就有了 openvpn.shxx.ovpn 两个文件了,“学外语”就是这么简单!然后我们执行 ./openvpn xx.ovpn 命令,即可看到让我们输入账号密码的交互界面:

但我们希望 run 一个 container 的时候就自动连接到 VPN,而不需要输入用户名密码这种交互,解决这个问题可以在 ovpn file 中添加 auth-user-pass login.conf 配置,login.conf 中就保存的就是登陆所需的用户名和密码。再重新执行上面的命令,会发现 OpenVPN 就能自动连接上了!

然后我们可以使用 curl 命令来试一下是否能访问内网,如果有相应返回值则说明是行得通的🥳

沟通交流

打通代理服务器与内网服务器的隔阂后,”翻译官“就需要将听到的”中文“转述给”歪果仁“,那么我们就需要监听特定端口,并将端口的请求转发到指定 IP,这就需要 SSH 来帮忙了!假如我们想将8080端口的请求转发到目标服务器的80端口上,那么只需要下面这条语句:

ssh -o StrictHostKeyChecking=no -gfNt -L 8080:target:80 localhost
复制代码

当我们执行了上面语句后,代理服务器应该就可以 work 了,各位可以从外部 curl 一下代理服务器,验证一下返回内容是否是期待的内网内容。

Dockerfile

接下来我们就来写 Dockerfile,首先我们需要一个环境来运行各种命令:

FROM debian
复制代码

接下来,需要安装所需的包:

RUN apt-get update && \
    apt-get install -y curl openvpn tini openssh-server && \
复制代码

然后,生成 SSH 秘钥并拷贝到 authorized_keys 文件中:

ssh-keygen -f $HOME/.ssh/id_rsa -t rsa -N '' && \
cat $HOME/.ssh/id_rsa.pub >> $HOME/.ssh/authorized_keys
复制代码

为了使用 openvpn 命令,那么我们需将 openvpn.sh 移入 /bin 目录下:

COPY openvpn.sh /usr/bin/
复制代码

最后我们就可以启动 SSH 服务并转发请求了:

connect.sh

#!/usr/bin/env bash
/etc/init.d/ssh start

ssh -o StrictHostKeyChecking=no -gfNt -L 8080:target:80 localhost

openvpn xx.ovpn
复制代码

完整 Dockerfile

FROM debian

RUN apt-get update && \
    apt-get install -y curl openvpn tini openssh-server && \
    addgroup vpn && \
    rm -rf /tmp/* && \
    ssh-keygen -f $HOME/.ssh/id_rsa -t rsa -N '' && \
    cat $HOME/.ssh/id_rsa.pub >> $HOME/.ssh/authorized_keys

COPY openvpn.sh /usr/bin/

COPY connect.sh /tmp/
COPY xx.ovpn /tmp/
COPY login.conf /tmp/

WORKDIR /tmp

CMD ["sh", "connect.sh"]

复制代码

此时我们 curl 容器 IP 得到的应该是内网的相应内容。后面的操作就是构建镜像并启动一个 container 了,在此就不赘述。需要注意的是 Git 协议的端口是 9418,一般需要同时放开 809418 端口才能使用。同时,需要将流水线的 Git 地址修改为 Docker 容器的地址。

经验小总结🌞

作为项目新人,主动来负责了前端项目基础设施的搭建,并趁机学习了一下 K8s 等知识,顺便总结了一下比较实用的几点:

  • 接着上面的说,假如 CI/CD 都部署在 K8s 或同一个集群中,那么可以将 Docker 容器的 IP 改为内网地址,这样速度会更快。

  • 前端的项目在构建时候一般都会有 yarn && yarn build,加入还有 Soanr 扫描的话可以使用 parallel 语句让二者并行:

    stage('编译项目') {
      parallel {
        stage('项目打包') {
          steps {
            container('node') {
              sh 'yarn'
              sh 'yarn build'
            }
          }
        }
        stage('Sonar扫描') {
          steps {
            container('sonar-scanner') {
              sh "扫描扫扫扫..."
            }
          }
        }
      }
    }
    复制代码
  • 打包镜像执行 docker build 时,会将所有内容都当做 build context 打包进去,对于前端来说一般只需要 dist/build 目录中的打包文件,所以可以使用 .dockerignore 文件将 node_modules 忽略掉,使用方式与 .gitignore 相同,可以看一下 build 的速度改善:

  • 使用 kubectl 可以直接创建 ArgoCD 应用,只需运行:kubectl apply -n argocd -f ./app.yaml

结束语🎬

本文算是一篇个人项目实战的小总(水)结(文)🏊‍♂️

项目比较紧,WebGL 的文章会尽快安排,各位老爷别着急🔥感谢阅读,欢迎关注公众号:Refactor!