本篇主要讲述springboot以及vue前后端分离项目,使用Jenkins拉取gogs代码仓库源码,构建Docker镜像并推送至Harbor仓库,使用docker 可视化部署工具【portainer】部署生产服项目,编写shell脚本,至于jenkins、harbor、gogs、portainer 请自行安装部署,网上教程较多,比较简单
1、springboot 前后端分离项目,借用jenkins持续集成持续部署工具,使用shell脚本将项目编写好dockerFile 文件,生成镜像,并推送至镜像仓库
#!/bin/sh
# 镜像仓库地址,我这里使用harbor镜像仓库,当然也可以使用阿里云镜像仓库
REGISTRY=hub.ywb.com
# 镜像仓库登录账号
REGISTRY_USER=admin
# 镜像仓库登录密码
REGISTRY_PASS=123456
# 镜像TAG
IMAGE_TAG=$REGISTRY/security
# 镜像名称
IMAGE_NAME=tv-api
# 镜像版本
IMAGE_VER=v2.2-$( date '+%Y%m%d' ).$BUILD_NUMBER
# 构建项目名称
PROJECT_NAME=$JOB_NAME
# 构建项目的目录
PROJECT_DIR=$WORKSPACE
# 构建项目的编译目录
PROJECT_BUILD_DIR=$PROJECT_DIR/target
# 构建项目的服务访问端口
PROJECT_PORT=38101
# 当前日期
DATE=$( date '+%Y/%m/%d %H:%M:%S' )
# 返回值
RETVAL=0
echo "*******************************************************************************************"
# 开始执行构建
echo "$DATE - 开始执行项目构建..."
# 进入构建项目的编译目录
echo "$DATE - 进入项目构建目录 $PROJECT_BUILD_DIR"
cd $PROJECT_BUILD_DIR
# 获取编译后的 jar 包名称
JAR_NAME=$( ls | grep -i "jar" | grep -v grep | head -1 )
# 如果 JAR_NAME 为空
if [ -z "$JAR_NAME" ]; then
echo "$DATE - 未查询到项目 $PROJECT_NAME 编译的结果 $JAR_NAME"
exit $RETVAL
fi
# 如果 JAR_NAME 不存在
if [ ! -f "$PROJECT_BUILD_DIR/$JAR_NAME" ]; then
echo "$DATE - 项目 $PROJECT_NAME 编译的文件 $JAR_NAME 不存在"
exit $RETVAL
fi
echo "$DATE - 成功获取到项目 $PROJECT_NAME 的最终编译文件 $JAR_NAME"
# 创建 Dockerfile
echo "$DATE - 创建 Dockerfile"
cat > Dockerfile <<EOF
FROM openjdk:8
MAINTAINER wanbin.yi@qq.com
# 在宿主机的 /var/lib/docker 目录下创建一个临时文件,并链接到容器的 /tmp,用于数据持久化,因为 springboot 内嵌 tomcat 默认使用 /tmp 作为工作目录
VOLUME /tmp
# 设置工作目录
WORKDIR /root
# 设置时区
RUN bash -c 'echo "Asia/Shanghai" > /etc/timezone'
# 添加 jar 包并检测
ADD $JAR_NAME /root/$JAR_NAME
RUN bash -c 'touch /root/$JAR_NAME'
# 设置 jvm 参数
ENV JAVA_OPTS="
-server
-Xms512m
-Xmx2g
-Xmn1g
-XX:SurvivorRatio=8
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:+UseParallelGC
-XX:ParallelGCThreads=4
-XX:+UseParallelOldGC
-XX:+UseAdaptiveSizePolicy
-XX:+PrintGCDetails
-XX:+PrintTenuringDistribution
-XX:+PrintGCTimeStamps
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/
-Xloggc:/var/run/jvm-gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=10M"
# 为了缩短 tomcat 启动时间,添加一个系统属性指向 “/dev/urandom” 作为 Entropy Source
ENTRYPOINT java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar /root/$JAR_NAME
EXPOSE $PROJECT_PORT
EOF
echo "$DATE - 创建 Dockerfile 完成"
# 构建镜像
# 将镜像名转换为小写
IMAGE_NAME=$IMAGE_NAME | tr '[A-Z]' '[a-z]'
echo "$DATE - 开始构建镜像,镜像名称:$IMAGE_NAME:$IMAGE_VER"
# 判断 docker 镜像中是否已存在,存在则删除之
IMAGE_ID=$( docker images | grep -i "$IMAGE_NAME" | grep -i "$IMAGE_VER" | grep -v grep | awk '{print $3}' | head -1 )
if [ ! -z "$IMAGE_ID" ]; then
echo "$DATE - 检测到镜像 $IMAGE_NAME:$IMAGE_VER 已存在,删除之..."
docker image rm -f $IMAGE_ID
fi
docker build -t $IMAGE_NAME:$IMAGE_VER $PROJECT_BUILD_DIR
echo "$DATE - 构建镜像完成"
# 推送镜像
echo "$DATE - 开始向镜像仓库推送"
docker tag $IMAGE_NAME:$IMAGE_VER $IMAGE_TAG/$IMAGE_NAME:$IMAGE_VER
docker login -u $REGISTRY_USER -p $REGISTRY_PASS $REGISTRY
docker push $IMAGE_TAG/$IMAGE_NAME:$IMAGE_VER
echo "$DATE - 向镜像仓库推送完成,请前往镜像仓库查看:http://$REGISTRY"
echo "$DATE - 执行项目构建完成..."
echo "*******************************************************************************************"
2、vue前端项目,同理使用jenkins生成镜像文件,并推送至镜像仓库
#!/bin/sh
# 镜像仓库地址
REGISTRY=hub.ywb.com
# 镜像仓库登录账号
REGISTRY_USER=dev
# 镜像仓库登录密码
REGISTRY_PASS=123456
# 镜像TAG
IMAGE_TAG=$REGISTRY/demo
# 镜像名称
IMAGE_NAME=pms-web
# 镜像版本
IMAGE_VER=v2.2-$( date '+%Y%m%d' ).$BUILD_NUMBER
# 构建项目名称
PROJECT_NAME=$JOB_NAME
# 构建项目的目录
PROJECT_DIR=$WORKSPACE
# 构建项目的最终编译目录
PROJECT_BUILD_DIR=dist
# 构建项目的正式脚本环境定义
PROJECT_PROFILE=prod
# npm 指令
NPM=npm
# 当前日期
DATE=$( date '+%Y/%m/%d %H:%M:%S' )
# 返回值
RETVAL=0
echo "*******************************************************************************************"
# 开始执行构建
echo "$DATE - 开始执行项目构建..."
# 进入构建项目的构建目录
cd $PROJECT_DIR
echo "$DATE - 进入项目构建目录 $PROJECT_DIR"
# 检测是否有 npm 运行环境
echo "$DATE - 检测主机是否安装 $NPM 运行环境"
type $NPM > /dev/null
if [ $? -eq 0 ]; then
echo "$DATE - 当前主机存在 $NPM 运行环境,$NPM 版本:$( $NPM -v )"
else
echo "$DATE - 主机未安装 $NPM 编译环境,无法完成项目构建"
exit -1
fi
# 执行 npm 初始化,根据项目的 package.json 安装依赖环境
echo "$DATE - 执行 $NPM 初始化,检测并安装项目依赖包,可能需要花费几分种时间,请耐心等待"
$NPM install
echo "$DATE - 完成 $NPM 初始化"
# 执行 npm build,编译最终部署文件
echo "$DATE - 开始执行 $NPM 项目编译"
$NPM run build:$PROJECT_PROFILE
echo "$DATE - 完成 $NPM 项目编译,最终输出目录为:$PROJECT_DIR/$PROJECT_BUILD_DIR"
# 检测项目编译后的目录是否存在
if [ ! -d $PROJECT_BUILD_DIR ]; then
echo "$DATE - 项目编译失败,未成功检测到最终编译目录:$PROJECT_DIR/$PROJECT_BUILD_DIR"
exit -1
fi
echo "$DATE - 成功获取到项目 $PROJECT_NAME 的最终编译目录:$PROJECT_DIR/$PROJECT_BUILD_DIR"
# 创建 nginx.conf
echo "$DATE - 创建 nginx 配置文件 nginx.conf,并计划用此文件替换 nginx 镜像中的 nginx.conf 文件"
cat > nginx.conf <<EOF
# 运行用户,可不设置
user nginx;
# 可开启进程数量,一般设置为和cpu核数一样
worker_processes 2;
# 日志路径和级别。这个设置可以放入全局块,http块,server块,级别依次为:debug|info|notice|warn|error|crit|alert|emerg
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# 最大文件打开数(连接),可设置为系统优化后的ulimit -HSn的结果
worker_rlimit_nofile 5120;
# cpu亲和力配置,让不同的进程使用不同的cpu
worker_cpu_affinity 01 10;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
# 网路连接序列化,防止惊群现象发生,默认为on
accept_mutex on;
# 一个进程是否同时接受多个网络连接,默认为off
multi_accept off;
# 事件驱动模型, select|poll|kqueue|epoll|resig|/dev/poll|eventport
# epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能
use epoll;
# 单个后台worker process进程的最大并发链接数
worker_connections 1024;
}
http {
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;
access_log off;
# 启用压缩
gzip on;
# 文件小于此大小不予压缩
gzip_min_length 1k;
gzip_buffers 4 16k;
# 压缩等级
gzip_comp_level 5;
# 压缩类型
gzip_types text/plain text/css text/javascript image/jpeg image/png image/bmp image/svg+xml font/ttf font/otf font/woff font/woff2 application/pdf application/xml application/json application/x-javascript application/x-httpd-php;
gzip_vary on;
gzip_static on;
# 开启高效传输模式,默认为off,可以在http块,server块,location块
sendfile on;
# 每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限
sendfile_max_chunk 16k;
# 读取客户端请求头缓冲大小
client_header_buffer_size 1k;
# 读取客户端请求体缓冲大小
client_body_buffer_size 16k;
# 客户端允许上传文件的最大值
client_max_body_size 256m;
# 允许把httpresponse header和文件的开始放在一个文件里发布,作用是减少网络报文段的数量
tcp_nopush on;
# 内核会等待将更多的字节组成一个数据包,从而提高I/O性能
tcp_nodelay on;
# 连接超时时间,默认为75s,可以在http,server,location块
keepalive_timeout 65;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
#listen [::]:80;
server_name localhost;
charset utf-8;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
root /usr/share/nginx/html/pc;
index index.htm index.html default.htm default.html;
autoindex on;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
EOF
echo "$DATE - 创建 nginx.conf 完成"
# 创建 Dockerfile
echo "$DATE - 创建 Dockerfile"
cat > Dockerfile <<EOF
FROM nginx
MAINTAINER wanbin.yw@qq.com
COPY nginx.conf /etc/nginx/nginx.conf
COPY $PROJECT_BUILD_DIR/ /usr/share/nginx/html/pc
EOF
echo "$DATE - 创建 Dockerfile 完成"
# 构建镜像
# 将镜像名转换为小写
IMAGE_NAME=$IMAGE_NAME | tr '[A-Z]' '[a-z]'
echo "$DATE - 开始构建镜像,镜像名称:$IMAGE_NAME:$IMAGE_VER"
# 判断 docker 镜像中是否已存在,存在则删除之
IMAGE_ID=$( docker images | grep -i "$IMAGE_NAME" | grep -i "$IMAGE_VER" | grep -v grep | awk '{print $3}' | head -1 )
if [ ! -z "$IMAGE_ID" ]; then
echo "$DATE - 检测到镜像 $IMAGE_NAME:$IMAGE_VER 已存在,删除之..."
docker image rm -f $IMAGE_ID
fi
docker build -t $IMAGE_NAME:$IMAGE_VER $PROJECT_DIR
echo "$DATE - 构建镜像完成"
# 推送镜像
echo "$DATE - 开始向镜像仓库推送"
docker tag $IMAGE_NAME:$IMAGE_VER $IMAGE_TAG/$IMAGE_NAME:$IMAGE_VER
docker login -u $REGISTRY_USER -p $REGISTRY_PASS $REGISTRY
docker push $IMAGE_TAG/$IMAGE_NAME:$IMAGE_VER
echo "$DATE - 向镜像仓库推送完成,请前往镜像仓库查看:http://$REGISTRY"
echo "$DATE - 执行项目构建完成..."
echo "*******************************************************************************************"
3、jenkins构建历史记录
4、最终可以使用docker portainer可视化工具进行项目部署工作,从harbor镜像仓库拉取镜像开始部署