• Jenkins+Harbor+gogs+docker+portainer+springboot实现devOps(企业实战)


     

    本篇主要讲述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镜像仓库拉取镜像开始部署

     

     

     

     

  • 相关阅读:
    php 小试 mysql-zmq-plugin 和 pthreads
    svn:previous operation has not finished
    Http Header里的Content-Type
    sublime text使用及常见问题
    Less:优雅的写CSS代码
    gulp:更简单的自动化构建工具
    js实现『加载更多』功能实例
    JSONP浅析
    使用JSSDK集成微信分享遇到的一些坑
    JavaScript模板引擎实例应用
  • 原文地址:https://www.cnblogs.com/ywbmaster/p/15529999.html
Copyright © 2020-2023  润新知