最近接到一个繁琐的任务,从来没尝试过,要把现有的代码仓库以及发包流程整合起来,迁移到阿里云云效,然后利用云效的代码管理、CICD持续集成、代码扫描、代码评审...
脑瓜子嗡嗡的,我想现在不挺好的吗,gitlab管理代码,Jenkins发布。可能看上去不是那么现代化,那能咋办,硬扛,老板就是天。
接着开始找资料学习,弄懂大概是咋个回事。。。。。。。
一、前置知识 Docker、k8s
Docker灵感来源于集装箱,最简单并且带有一定错误的认知就是 “Docker 是一种性能非常好的虚拟机”,使用 Linux 内核和内核功能(例如 Cgroups 和 namespaces)来分隔进程,以便各进程相互独立运行。就好似一个个独立的集装箱
Docker 中有三个核心概念:Image、Container、Repository。
- Image: 有领“好人卡”倾向的广大程序猿一定对 镜像 的概念不会陌生。但和 windows 的那种 iso 镜像相比,Docker 中的镜像是分层的,可复用的,而非简单的一堆文件迭在一起(类似于一个压缩包的源码和一个 git 仓库的区别)。
- Container: 容器的存在离不开镜像的支持,他是镜像运行时的一个载体(类似于实例和类的关系)。依托 Docker 的虚拟化技术,给容器创建了独立的端口、进程、文件等“空间”,Container 就是一个与宿机隔离 “容器”。容器可宿主机之间可以进行 port、volumes、network 等的通信。
- Repository: Docker 的仓库和 git 的仓库比较相似,拥有仓库名、tag。在本地构建完镜像之后,即可通过仓库进行镜像的分发。常用的 Docker hub 有 hub.docker.com/ 、 cr.console.aliyun.com/ 等。
用通俗语言描述就是:1、Docker启动构建时会读取项目根目录下的DockerFile
文件,它就好比是一个生产说明书,根据说明书生产出产品(Image镜像)2、Docker隔离出一个单独的容器环境并把生产的产品(Image镜像)放到容器中 3、Docker启动容器中的镜像并暴露一个端口给宿主机
Kubernetes(k8s)是跨主机集群的自动部署、扩展以及运行应用程序容器的开源平台,这些操作包括部署,调度和节点集群间扩展。简单说就是控制编排docker容器
二、前端静态包是怎么跑起来的
Nginx 是一个高性能的HTTP和反向代理web服务器
前端大致的一个工作流程:项目搭建 -> 编码 -> 构建 -> 部署
我们主要讨论部署,这里以vue
为例。在讨论这个问题之前先了解 publicPath
环境准备
- 本地安装
nginx
- 通过
vue-cli
创建一个项目
publicPath
- vuecli cli.vuejs.org/zh/config/#…
- webpack webpack.docschina.org/guides/publ…
这个publicPath
在vue-cli
、webpack
都存在这个api,目的都是为了给构建出来的静态包提供一个自定义公共路径的功能,默认情况都是/
。如果你是用vuecli搭建的项目,在vue.config.js
自定义publicPath就OK,不要在output里配置。
模拟部署测试
1、启动vue项目、构建出dist
包
2、把dist包提取到nginx静态文件夹下
publicPath: '/'
复制代码
注:Mac系统nginx默认安装路径/usr/local/bin
,配置文件路径/usr/local/etc/nginx
,静态文件夹/usr/local/var/www
修改nginx.conf配置
...
location / {
root /usr/local/var/www/dist;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
...
复制代码
3、启动服务 在安装路径下/usr/local/bin
执行
nginx
复制代码
4、浏览器调试
看上图,所有构建的静态资源都放在跟路径,也可以正常访问了,到这里就完成部署了,好像没什么问题。如果是这样的话那就没必要写这篇文章了,且听下文分享
多个静态包部署在同一个域名
在实际开发部署中,不太可能会是一个包有一个单独的域名,而是一个域名下会部署多个包,这种场景再套用上面的配置那就会出问题了,怎么办?
此时就需要派上publicPath
了,通过在域名后拼接一个标识来区分
比如我想在a.b.com
域名下部署projectA、projectB、projectC
http://a.b.com/projectA/
http://a.b.com/projectB/
http://a.b.com/projectC/
现在方案有了,接下来就是编码配置了
vue.config.js
...
publicPath: '/projectA/'
...
复制代码
这个publicPath是作用于资源引用路径上,我们还需要在vue项目访问页面的路径上有所体现,类似http://a.b.com/projectA/
,那就要在router里配置一个公共路径
const router = createRouter({
history: createWebHistory('/projectA/'),
routes: routes
})
复制代码
如果是vue2.x的配套路由的话要在baseUrl里配
可以看到配置的publicPath
在模板index.html文件引用资源时体现了
点开sourses,可以看到图片文件夹不见了,页面空白,可以判断是没有映射到资源
万能的百度发挥作用了,一通检索,做了如下nginx配置
...
location / {
root /usr/local/var/www/dist;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /projectA {
alias /usr/local/var/www/dist;
index index.html index.htm;
try_files $uri $uri/ /projectA/index.html;
}
...
复制代码
vue项目的路由模式,不管是history还是hash模式,配置方式都一样的,不过有一点要注意,如果要发静态包到github pages,history模式好像不行,要用hash模式的路由
此时,也就把开始抛出的疑问解决了。不知道大家有没有别的疑问?root
和 alias
有啥区别?
root
和 alias
的区别
使用alias,实际的路径就是:alias值。
例如,
有一张图片,URL是:www.awaimai.com/static/a.jp…
它在服务器的路径是:/var/www/app/static/a.jpg
那么用root的配置是:
location /static/ {
root /var/www/app/;
}
复制代码
用alias的配置就是:
location /static/ {
alias /var/www/app/static/;
}
复制代码
对于alias,location值可以随便取,例如:
location /hello/ {
alias /var/www/app/static/;
}
复制代码
这样,我们访问图片的地址就是:www.awaimai.com/hello/a.jpg
注意:
很多文章说:alias 后面必须要用 “/” 结束,是错误的,亲测加不加/效果是一样的。
alias在使用正则匹配时,必须捕捉要匹配的内容,并在指定的内容处使用。
alias只能位于location块中,root可以不放在location中。
域名 + /index.html
接着往下,有个这样的链接 http://a.b.com/group/test/index.html
项目结构也是一个vue的项目,原来由于是手动上传到CDN,套了几层目录,现在迁移到云服务用流水线发布。考虑到怕改变了链接有影响,怎样在访问链接不变动的情况顺利的迁移。
1、改造构建产物套几层目录
修改输出目录
vue.config.js
...
outputDir: 'dist/group/test',
...
复制代码
2、正常的发布到nginx静态文件目录下
3、配置nginx
location /group/test/index.html {
root /usr/local/var/www/dist;
index index.html index.htm;
try_files $uri $uri/ /group/test/index.html;
}
复制代码
根据root和alias的区别,
指向路径:/usr/local/var/www/dist/group/test/index.html
nginx配置
nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
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 /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
复制代码
default.conf
server {
listen 80 ;
server_name localhost;
root /usr/share/nginx/html;
index index.html; # 入口文件
charset utf-8; # 编码
location / {
try_files $uri $uri/ /index.html;
}
#location ^~/gatewayApi {
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_buffering off;
# rewrite ^/gatewayApi/(.*)$ /$1 break;
# proxy_pass http://gateway.xxxx.com/;
#}
}
复制代码
include /etc/nginx/conf.d/*.conf;
复制代码
这句代码的意思是部署的时候把default.conf
提到nginx
目录里conf.d
文件夹去,然后自动引入nginx.conf
配置文件中。这个好处就是default.conf
可以写在开发项目里,方便做一些nginx的配置
以上就是本地搭建NGINX环境模拟前端静态包部署的全过程
三、代码迁移
1、登录阿里云云效
2、新建代码仓库
导入方式可以根据原仓库来选择相应的导入方式
这个地方要注意,新建代码仓库
、导入代码库
的用途,一般如果是全新的仓库就是用新建,如果是老仓库使用导入会比较友好,因为云效可以同步原仓库所有的提交记录、分支、tag,不存在断档,非常的安全。但是有一个点需要注意,同步的时候会拉取原仓库代码覆盖云效上的代码,具体细节可以看一下官方推荐的仓库迁移策略
同步完之后,可以进行一些必要的仓库设置:
1、设置保护分支,比如将 master 设置为保护分支,后续开发过程中不能直接向master提交代码,必须通过 合并请求
将改动的代码合到master,还可以做代码审查,降低master代码被污染的风险
- 分支:选择受保护的分支
- 推送规则:
无
不允许任何人直接推送代码到受保护的分支 - 合并规则:默认是只有管理员有权限合
四、搭建 Docker 配置文件 DockerFile
DockerFile
就是 Docker 构建镜像的说明书,他会根据配置文件产出目标镜像
FROM nginx:1.15 # 意思是拉取那个版本的nginx来制作镜像
ADD ./default.conf /etc/nginx/conf.d/ # 将代码仓库根目录下的 default.conf nginx配置文件添加到镜像 nginx /etc/nginx/conf.d/ 目录下
COPY ./dist/ /usr/share/nginx/html/ # 复制前端构建出来的静态包放到镜像nginx /usr/share/nginx/html/ 目录下
复制代码
这里具体的nginx
配置就是第二步讲到前端部署,没明白可以回过头去仔细研读一遍
五、搭建流水线
1、打开导入的代码仓库
2、新建流水线
3、填写流水线配置项(重点)
分别是添加源码、代码扫描、代码构建、代码部署(通常情况下是这四部,当然也可以自定义更多步骤)
添加源码(应用源码、部署代码片段)
代码扫描(主要是做一些代码风格语法的检测,其实省略这一步问题也不大)
代码构建
Nodejs构建
执行命令
执行命令这个功能非常实用灵活,作用就是将当前目录下的default.conf
文件中 'gateway.caibeitv.com'
替换成 GatewayDomain
这个变量,进而可以达到动态的指定后端服务环境,那这个变量在哪设置呢?
命令格式1:sed 's/原字符串/新字符串/' 文件
命令格式2:sed 's/原字符串/新字符串/g' 文件
镜像构建并推送至阿里云镜像仓库
代码部署
执行命令
helm Release
上面相关的参数都在这里设置
配置完毕!!!
六、运行流水线
点击 运行 弹起弹窗,填写运行设置
七、域名解析、负载均衡等访问配置
确认部署的包是否成功跑起来了
--> --> --> 进入相应集群 --> 工作负载/无状态
能看到自己部署上去的节点,说明部署ok,进入详情确认是否成功跑起来了
设置域名
在功能面板搜索关键词 域名
进入
一般来情况,公司运维都会指定一级域名,我们只需找到对应的一级域名,进入添加二级域名,例如 baidu.com
添加记录,也就是设置二级域名, 例如 haha.baidu.com
haha
就是二级域名标识
添加好就是这样的,注意,添加时要指定一个记录值,可以是IP也是是域名,但必须和记录类型对应
这个就是记录类型列表
我这里是设置的 A 类型,指向的是一台负载均衡机器的ip
设置负载均衡
在功能面板搜索关键词 负载均衡
进入
负载均衡实例列表就这样的,上一步设置的域名指向的就是负载均衡实例的IP
到这里,你可能还是不行白,设置的域名怎么就能访问到我们部署的项目呢?继续往下看
我们以这台测试环境的负载均衡为例,点击 添加后端服务器
进入配置
进入后首先是创建虚拟服务器组,这里我们就要回过头来捋一下,当时部署的时候选的是测试集群还是生产集群,如果是部署的测试集群,那我们就要搜索测试集群的节点添加进来,选好,进入下一步,这里需要配置一个端口号,也就是我们在设置流水线的部署阶段设置的端口号(就是暴露给宿主机的端口号)
如果想不起来,看看这张图,瞬间清晰了有没有?
添加好后就长这样
虚拟机组添加好后,下一步添加监听
配置转发策略
就把设置的域名填进去,虚拟机组选择跟上面几步是一样的
到这里基本配置完了,那就体验一下吧
发现还是没有访问不通,完了,心态崩了!!!!!
别慌继续往下看
原因:域名解析进入 负载均衡,默认是先访问80端口,所以需要在监听80端口转发策略里加上当前的域名
再访问一遍,成就感爆棚有没有?
写在后面
这里面没有写搭建集群、创建负载均衡的步骤,是因为这一步是运维早就配置好了,需要了解这两部分是怎么是配的可以去网上看看别人写的文章。