公司在一年之内先后使用了无dockers
、docker/k8s
、docker/rancher
三种方式,结合jenkins,进行前端业务代码的部署。
一、传统的方式:无docker
传统的部署方式是:
- jenkins服务器上配置代码git地址、指定分支
- 设置构建执行shell:npm install安装依赖、npm run build执行打包
- 设置构建后执行操作:将上一步打包后的代码通过ssh拷贝到远程目标服务器指定目录上
二、docker/k8s
- jenkins服务器上配置代码git地址、指定分支
- 设置构建执行shell:npm install安装依赖、npm run build执行打包
-
npm run docker
生成镜像文件、推送镜像文件到仓库中,然后生成k8s编排文件 - 设置构建后执行操作:将上一步处理后生成的yaml编排文件通过ssh方式拷贝到k8s master节点指定目录上,然后执行
kubectl delete -f 编排文件
命令停止原容器,kubectl apply -f 编排文件
重新启动容器。
2.1众所周知,k8s编排文件配置项较多,在此不详述各配置项的意义,只提供一种思路,用配置的方式生成编排文件:主要思路是将镜像名称、标签、命名空间和host等信息抽离并模板化,借助json-template/string
来生成模板实例(见下方代码);借助child_process
执行docker build/push
命令(见2.2)。
const fs = require('fs')
const render = require('json-templater/string')
const path = require('path')
const { execSync } = require('child_process')
const options = {
image: '',
imageName: '',
imageTag: '',
nameSpace: '',
fileName: '',
host: ''
}
const argvs = process.argv
const imageIndex = argvs.indexOf('--image')
const nameSpaceIndex = argvs.indexOf('--namespace')
const fileNameIndex = argvs.indexOf('--filename')
const hostIndex = argvs.indexOf('--host')
if (imageIndex > -1) {
options.image = argvs[imageIndex + 1]
if (options.image) {
[options.imageName, options.imageTag] = options.image.split(':')
}
}
if (nameSpaceIndex > -1) {
options.nameSpace = argvs[nameSpaceIndex + 1]
}
if (fileNameIndex > -1) {
options.fileName = argvs[fileNameIndex + 1]
}
if (hostIndex > -1) {
options.host = argvs[hostIndex + 1]
}
const tpl = `#Automatically generated by public/docker/genK8s.js
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{name}}
namespace: {{namespace}}
labels:
app: {{name}}
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: {{name}}
template:
metadata:
labels:
app: {{name}}
spec:
containers:
- name: {{name}}
resources:
limits:
memory: 200Mi
requests:
memory: 200Mi
image: {{image}}
ports:
- containerPort: 80
protocol: TCP
imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: {{name}}
namespace: {{namespace}}
labels:
app: {{name}}
spec:
ports:
- port: 80
targetPort: 80
selector:
app: {{name}}
type: ClusterIP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{name}}-nginx-ingress-{{namespace}}
namespace: {{namespace}}
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/proxy-body-size: "512M"
spec:
rules:
- host: {{host}}
http:
paths:
- path: /{{name}}/(.*)
backend:
serviceName: {{name}}
servicePort: 80
`
const template = render(tpl, {
name: options.fileName,
namespace: options.nameSpace,
image: options.image,
host: options.host
})
const OUTPUT_PATH = path.join(__dirname, `dist/${options.fileName}.yaml`)
// 生成编排文件
fs.writeFileSync(OUTPUT_PATH, template)
// 根据Dockerfile文件将前端构建后的代码打成镜像
execSync(`docker build -t ${options.image} .`)
// 将镜像推送到docker仓库
execSync(`docker push ${options.image}`)
2.2 Dockerfile文件和nginx.conf
# Dockerfile
FROM nginx:1.16-alpine # ngnix镜像
ADD dist/ /usr/share/nginx/html/ # 将本地dist目录下的文件打包镜像中去
COPY nginx.conf /etc/nginx/config.d/ #拷贝nginx配置文件到镜像指定目录下
RUN ls -la /usr/share/nginx/html/*
EXPOSE 80 # 启动容器对外暴露的port
# ngnix配置文件
server {
listen 80;
server_name localhost;
client_max_body_size 512M;
location / {
#跟dockerfile上保持一致
alias /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
}
三、docker/rancher
rancher是k8s的上层应用,可以认为是通过在页面上配置一些选项,自动生成k8s编排文件,并能启动和关闭容器。可以大大简化配置,极大加快部署速度。结合rancher,jenkins构建工程进行相应地变动(jenkins上先行部署rancher)。
- jenkins服务器上配置代码git地址、指定分支
- 设置构建执行shell:npm install安装依赖、npm run build执行打包
- npm run docker生成镜像文件、推送镜像文件到仓库中
- 登录rancher并执行
rancher kubectl patch
命令:
# 设置环境变量
RANCHER_LOGIN_TOKEN="我是token"
RANCHER_API="https://我是rancher api地址"
RANCHER_PROJECT_CODE="工程代码"
#rancher 工作负载名称
DEPLOY_NAME="负载名称"
NAMESPACE="命名空间"
# 设置更新时间(必须)
update_date=`date +'%Y-%m-%d %H:%M:%S'`
p="{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"cattle.io/timestamp\":\"${update_date}\"}}}}}"
# 登录rancher
rancher login $RANCHER_API --token $RANCHER_LOGIN_TOKEN --skip-verify --context $RANCHER_PROJECT_CODE
# 更新deployment
rancher kubectl patch deploy/$DEPLOY_NAME -n $NAMESPACE -p "$p"
# 删除标签为none的镜像
# docker images|grep none|awk '{print $3}'|xargs docker rmi
exit 0
3.1 在rancher 上配置前端项目工作负载
3.2 在rancher 上配置前端项目负载均衡
3.3对外网址的服务器上配置nginx.conf
# 配置rancher_ingress
upstream rancher_ingress {
ip_hash;
server 172.*.*.1 weight=1; # k8s服务器1
server 172.*.*.2 weight=1; # k8s服务器2
server 172.*.*.3 weight=1; # k8s服务器3
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://rancher_ingress/; # 此处配置/目录,对应上一步负载均衡中的访问路径
}