前言📒
最近进入了新的项目组,项目 Git 仓库部署在客户的内网环境中,故本地要使用 OpenVPN 才能使用其 Git 平台。可在实际情况中并不是只有在 clone 或 push 代码时才会访问其内网,Jenkins 拉取代码时也会访问其内网,说到这儿或许你会想到 Jenkins 中可以配置 HTTP Proxy,如图:
但此 HTTP Proxy 是全局配置,假如对全局流水线配置了代理后,就有可能会导致其他的网络请求不通的情况。所以我们最理想的状态就是只在 clone 代码(即 Checkout SCM)阶段使用代理,但在 Jenkins 的 Plugins Manager 中并未找到相关插件,在网上查到的相关 Docker 镜像也都是全局配置。与此同时,就算有针对某个 stage 使用的代理插件,那么当目标服务器有变动时,我们还需要修改各个项目中的 Jenkinsfile,这相对来说也会比较繁琐。所以小伙伴和我一拍脑袋,决定搞一个代理服务器,如果目标服务器有变动那么只需要改动代理服务器即可。
开工👷♂️
首先,来明确一下目标:启动一个 Docker 容器并将相应请求代理到内网服务器。 有了明确的目标,接下来就让我们冷静地分析一波,事实上我们所需要的代理服务器就是一个“翻译官”的角色,需要使双方能畅通的交流。假如我们把目标服务器当成“歪果仁”,本地当成“中国人”,当没有“翻译官”时就“中外友人”是无法正常沟通的(即网络不连通):
学外语
首先我们让“翻译官”学学外语,具备“翻译”的技能!
哎哎哎,车歪了歪了!让代理服务器具备“翻译”的能力我们就需要安装 OpenVPN,然后使用 OpenVPN sh 和 ovpn file 来启动代理。OpenVPN sh 我们可以直接 copy GitHub 的源码,ovpn file 配置请见此文档,这样我们就有了 openvpn.sh
和 xx.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,一般需要同时放开 80 和 9418 端口才能使用。同时,需要将流水线的 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!