芝法酱学习笔记(0.7)——harbor与SpringBoot容器化docker部署

前言

之前我们主要讲的jar包部署。使用jar包部署可能导致不同服务互相争抢资源(隔离性),不同服务可能需要不同的jdk环境,有时也会造成困扰。故在微服务时代,我们通常使用docker部署

一、docker安装

docke相关的知识,其实之前文章也写过,本节主要讲harbor的安装以及与jenkins配合,做容器化部署。故docker相关的讨论会尽可能简略。

1.1 docker安装

安装官方文档的介绍安装即可

1.2 docker-compose安装

docker-compose相关内容,之前文章也写过,故知识点本次略过。

sudo apt-get update
sudo apt-get install docker-compose-plugin
curl -SL https://github.com/docker/compose/releases/download/v2.29.6/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

二、harbor安装

2.1 下载解压

首先,去官网下载离线包,然后拷到/WORK/DOWNLOADS文件夹内
使用以下命令解压:

tar -xzf harbor-offline-installer-v2.9.1.tgz

2.2 nginx配置证书

由于harbor更倾向于用https,所以需要配置nginx的证书

openssl genrsa -out /WORK/APP/nginx/cert/nginx-selfsigned.key 2048 
openssl req -new -key /WORK/APP/nginx/cert/nginx-selfsigned.key -ou
t /WORK/APP/nginx/cert/nginx-selfsigned.csr
openssl x509 -req -days 3650 -in /WORK/APP/nginx/cert/nginx-selfsigned.csr -signkey /WORK/APP/nginx/cert/nginx-selfsigned.key -out /WORK/APP/nginx/cert/nginx-selfsigned.crt -subj "/CN=192.168.0.64"

然后把location部分的配置,单独拎一个文件出来,比如叫shared.conf
分别在http和https的server模块include进来

include /WORK/APP/nginx/conf/shared.conf;

即可完成https的配置。

2.3 harbor配置

编辑harbor.yml,重点编辑以下内容

http:
  # 把端口设置成9090
  port: 9090
# 你没看错,这些先注释掉
#https:
  # https port for harbor, default is 443
  #port: 443
  # The path of cert and key files for nginx
  #certificate: /WORK/APP/nginx/cert/nginx-selfsigned.crt
  #private_key: /WORK/APP/nginx/cert/nginx-selfsigned.key
./prepare
./install

这样harbor就装好了。稍微解释一下,./prepare脚本,就是根据harbor.yml的配置,在当前目录生成相应的配置文件。而install命令,则是创建启动镜像。

2.3.1 安装番外

我尝试了把harbor放在nginx后面,最后还是失败了。
因为harbor的前端访问路径貌似无法配置,这就导致静态资源的加载全部出错。有哪位大佬知道怎么搞的可以私信或评论区回复。

三、docker化项目

3.1 创建一个dockerfile

我们接着之前的项目继续开发。之前的项目已经完成了lib,resource,config等与jar包的分离,并且以shell脚本启动项目,而非直接java -jar,我们的容器化也要支持这些功能(自讨苦吃式学习)。dockerfile创建如下所示
在这里插入图片描述

FROM openjdk:17-jdk-slim

ENV PORT="8081"

RUN mkdir -p /app
WORKDIR /app
EXPOSE 8081
ADD ./target/nbr.jar nbr.jar
ADD ./target/bin bin
RUN chmod +x bin/startup.sh
RUN chmod +x bin/shutdown.sh
VOLUME ["/app/config","/app/resources","/app/logs","/app/lib"]
WORKDIR "/app/bin"
CMD ./startup.sh -p $PORT

需要注意的是,VOLUME 字段表示容器卷,docker中先声明,docker run时再映射到宿主机上。如果这里不声明,docker run -v 的时候就不好用了。

3.2 新的jenkins脚本

很多人搞容器化的时候,喜欢使用docker的maven插件来实现。然而实际上,并没有这种必要。学习成本又高,还有很多限制,也不好调试。不如直接在jenkins里写命令实现。变量向dockerfile传递,可以用–env var_key=var_value来实现。

参数名默认值描述
profiletest环境
appNameapp001部署文件夹
port8081端口
version1.0.0版本
isBuildImgtrue是否编译镜像
isUpdateBinfalse是否更新bin
isUpdateConfigfalse是否更新配置文件
isUpdateLibfalse是否更新lib包
isUpdateStaticfalse是否更新静态资源
isUpdateMapperfalse是否更新mapper
gitTagmastergit分支
import java.text.SimpleDateFormat

node{

    def remote = [:]
    remote.name = '地下室主机'
    remote.host = '192.168.0.64'
    remote.user = 'root'
    remote.password = '???@1314'
    remote.deploymentHome = "/WORK/APP/study2024-class006"
    remote.allowAnyHosts = true
    remote.harbor = "localhost:9090"

    def app = [:]
    app.codePath = "busy"
    app.name = "study2024-class006"
    app.module = "nbr"
    app.version = "${version}"
    app.cd = "${appName}"
    app.port = "${port}"

    def timestamp = currentBuild.getTimeInMillis()
    def formattedTimestamp = new SimpleDateFormat("yyyy-MM-dd-HH_mm_ss").format(timestamp)


    stage("拉取代码"){
        git branch: "${gitTag}", credentialsId: 'gitSec', url: 'https://gitee.com/hataksumo/study2024-class006.git'
    }


    if(isCompileImage == "true"){
        stage("编译代码"){
            sh """
                cd busy
                mvn clean
                mvn package -pl ${app.module} -am -P${profile} -Dmaven.test.skip=true
            """
        }


        stage("创建镜像"){
            sh """
                cd ${app.codePath}/${app.module}
                docker build -f docker/Dockerfile \
                --build-arg PORT=${app.port} \
                -t ${app.name}-${app.module}:${app.version} .
                docker tag ${app.name}-${app.module}:${app.version} ${remote.harbor}/library/${app.name}-${app.module}:${app.version}
                docker login localhost:9090 -u admin -p Harbor12345
                docker push ${remote.harbor}/library/${app.name}-${app.module}:${app.version}
                docker logout ${remote.harbor}/library/${app.name}-${app.module}:${app.version}
                docker image rm -f ${remote.harbor}/library/${app.name}-${app.module}:${app.version}
                docker image rm -f ${app.name}-${app.module}:${app.version}
            """
        }
    }

    stage("拷贝资源"){
        echo "拷贝创建"

        sshCommand remote: remote, failOnError:false, command: """
            [ -d ${remote.deploymentHome}/${app.cd}] || mkdir -p ${remote.deploymentHome}/${app.cd}
            cd ${remote.deploymentHome}/${app.cd}
            [ -d lib] || mkdir -p lib
            [ -d config] || mkdir -p config
            [ -d resources/static] || mkdir -p resources/static
            [ -d resources/templates] || mkdir -p resources/templates
            [ -d resources/mybatis] || mkdir -p resources/mybatis
        """

        if(isUpdateConfig == "true"){
            echo "删除config"
            sshRemove remote: remote, failOnError:false, path: "${remote.deploymentHome}/${app.cd}/config"
            echo "拷贝lib包"
            sshPut remote: remote, from: "${app.codePath}/${app.module}/target/config", into: "${remote.deploymentHome}/${app.cd}"
        }

        if(isUpdateLib == "true"){
            echo "删除lib包"
            sshRemove remote: remote, failOnError:false, path: "${remote.deploymentHome}/${app.cd}/lib"
            echo "拷贝lib包"
            sshPut remote: remote, from: "${app.codePath}/${app.module}/target/lib", into: "${remote.deploymentHome}/${app.cd}"
        }

        sshCommand remote: remote, failOnError:false, command: "mkdir ${remote.deploymentHome}/${app.cd}/resources"

        if(isUpdateStatic == "true"){
            echo "清除resources/static文件"
            sshRemove remote: remote, failOnError:false, path: "${remote.deploymentHome}/${app.cd}/resources/static"
            echo "拷贝static文件"
            sshPut remote: remote, from: "${app.codePath}/${app.module}/target/resources/static", into: "${remote.deploymentHome}/${app.cd}/resources"
        }

        if(isUpdateMapper == "true"){
            echo "清除resources/mybatis文件"
            sshRemove remote: remote, failOnError:false, path: "${remote.deploymentHome}/${app.cd}/resources/mybatis"
            echo "拷贝mybatis文件"
            sshPut remote: remote, from: "${app.codePath}/${app.module}/target/resources/mybatis", into: "${remote.deploymentHome}/${app.cd}/resources"
        }
    }

    stage("镜像拉取"){
        //docker stop ${app.name}-${app.module}-${appName}
        //此处是不优雅的关闭
        sshCommand remote: remote, failOnError:false, command: """
        docker image rm -f ${remote.harbor}/library/${app.name}-${app.module}:${app.version}
        docker container rm -f ${app.name}-${app.module}-${appName}
        docker login localhost:9090 -u admin -p Harbor12345
        docker pull ${remote.harbor}/library/${app.name}-${app.module}:${app.version}
        docker tag ${remote.harbor}/library/${app.name}-${app.module}:${app.version} ${app.name}-${app.module}:${app.version}
        docker logout
        echo "docker run -it -p ${app.port}:${app.port} --volume ${remote.deploymentHome}/${app.cd}/config:/app/config --volume ${remote.deploymentHome}/${app.cd}/resources:/app/resources --volume ${remote.deploymentHome}/${app.cd}/logs:/app/logs --volume ${remote.deploymentHome}/${app.cd}/lib:/app/lib --env PORT=${app.port} ${app.name}-${app.module}:${app.version} bin/bash"

        docker run -d \
        -p ${app.port}:${app.port} \
        --volume ${remote.deploymentHome}/${app.cd}/config:/app/config \
        --volume ${remote.deploymentHome}/${app.cd}/resources:/app/resources \
        --volume ${remote.deploymentHome}/${app.cd}/logs:/app/logs \
        --volume ${remote.deploymentHome}/${app.cd}/lib:/app/lib \
        --env PORT=${app.port} \
        --name ${app.name}-${app.module}-${appName} \
        ${app.name}-${app.module}:${app.version}
        echo "容器启动完成"
        lsof -i:${app.port}
        """
    }

}

3.3 使用docker-compose

之前的方法,启动和关闭都不是很优雅,拓展性也不强。不如使用docker-compose技术。

3.3.1 compose.yml

compose.yml放入docker文件夹下
在这里插入图片描述

services:
  nbr:
    image: study2024-class006-nbr:${VERSION}
    environment:
      - PORT
      - EXPORT_PORT
      - VERSION
      - APP_NAME
      - CD_PATH
    ports:
      - ${EXPORT_PORT}:${PORT}
    volumes:
      - ${CD_PATH}/config:/app/config
      - ${CD_PATH}/logs:/app/logs
      - ${CD_PATH}/lib:/app/lib
      - ${CD_PATH}/resources/static:/app/resources/static
      - ${CD_PATH}/resources/mybatis:/app/resources/mybatis
      - ${CD_PATH}/resources/template:/app/resources/template
    container_name: study2024-nbr-${APP_NAME}

3.3.2 jenkins修改

  • 更改 “镜像拉取”部分
stage("镜像拉取"){
        //docker stop ${app.name}-${app.module}-${appName}
        //此处是不优雅的关闭
        sshCommand remote: remote, failOnError:false, command: """
        docker image rm -f ${remote.harbor}/library/${app.name}-${app.module}:${app.version}
        docker container rm -f ${app.name}-${app.module}-${appName}
        docker login localhost:9090 -u admin -p Harbor12345
        docker pull ${remote.harbor}/library/${app.name}-${app.module}:${app.version}
        docker tag ${remote.harbor}/library/${app.name}-${app.module}:${app.version} ${app.name}-${app.module}:${app.version}
        docker logout
        cd ${remote.deploymentHome}/${app.cd}
        docker-compose down
        docker-compose up -d
        echo "容器启动完成"
        """
    }
  • 更改 “拷贝资源” 部分
    在尾部添加如下代码:
// 拷贝compose.yml
        sshPut remote: remote, from: "${app.codePath}/${app.module}/target/compose.yml", into: "${remote.deploymentHome}/${app.cd}/compose.yml"
        // 生成evn
        def envContent = """
EXPORT_PORT=${app.port}
PORT=8080
VERSION=${app.version}
APP_NAME=${app.name}-${app.module}-${appName}
CD_PATH=${remote.deploymentHome}/${app.cd}/
"""
        echo "$envContent"
        writeFile(file: "${app.codePath}/${app.module}/target/.env", text: envContent)
        sshPut remote: remote, from: "${app.codePath}/${app.module}/target/.env", into: "${remote.deploymentHome}/${app.cd}/.env"

注意,.env是compose.yml所用的环境变量配置。在docker-compose up的时候,会自动读取该文件

  • pom添加拷贝配置
            <resource>
                <directory>docker</directory>
                <includes>
                    <include>compose.yml</include>
                </includes>
                <targetPath>${project.build.directory}</targetPath>
            </resource>

3.4 错误处理

3.4.1 调试容器

如果项目启动不成功,可以使用docker run -it <镜像名> /bin/bash 进入容器调试

3.4.2 脚本启动的坑

docker的机制,如果执行的脚本没有阻塞,就会退出容器。所以需要在脚本的最后添加这样一句

tail -f "${BASE_DIR}/logs/start.out"

3.4.3 注意运行在容器内

无论是mysql还是redis等中间件的链接,记得不要配localhost,配成内网ip

3.4.4 查看容器

docker inspect 容器Id

四、代码展示

还请众道友移步我的码云

五、一些额外的思考

当项目的打包容器化了,一个jdk-slim的容器都400M,那之前的把lib包分离还有什么意义。
实际上可以把主jar包也映射出去嘛。镜像只构建一回,以后的更新,更jar包就行了。这样的修改才是完整版的容器化打包方案。也就是说,实际的开发,还是原先的jar包打包开发,仅仅是第一次构建了镜像。是不是感觉世界一下就豁然开朗了。哈哈~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891788.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

sherpa-ncnn 语言模型简单对比

在昨天把系统搞崩溃前&#xff0c;对sherpa-ncnn的中文模型做了一个简单的对比。这次使用的分别是sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-13&#xff08;以下简称bilingual-zh-en-2023-02-13&#xff09;和sherpa-ncnn-streaming-zipformer-small-bilingual…

WPF自定义控件实现的几种方法

Windows Presentation Foundation (WPF) 是微软提供的一种用于构建 Windows 应用程序的开发框架。它以其强大的数据绑定、资源管理和可视化效果处理能力而闻名。在WPF中&#xff0c;自定义控件的实现是一个非常重要的方面&#xff0c;几乎所有的应用程序都会或多或少地需要自定…

哪款宠物空气净化器性价比高?希喂、米家和范罗士哪款更好?

这次我真的不是很想抱怨&#xff0c;是我男朋友真的很过分&#xff01;真的很过分&#xff0c;差点让我们两个分道扬镳。先听我说&#xff0c;这不是我和他都嫌家里太安静了吗&#xff0c;每天下班后两个人吃完饭就各玩各的手机&#xff0c;生活太无趣了&#xff0c;加上这几年…

【云从】五、负载均衡CLB

文章目录 1、负载均衡2、云负载均衡CLB3、CLB的组成4、CLB的应用场景 1、负载均衡 互联网发展早期&#xff0c;应用服务单机部署就足以负载所有用户的访问需求 如此&#xff0c;部署和运维都简单&#xff0c;但随着用户和访问量的提高&#xff0c;单台服务器的硬件性能是有上限…

【GESP】C++一级练习BCQM3044,字符形状输出

回到一级知识点&#xff0c;用给定字符按指定形状输出。 题目题解详见&#xff1a;https://www.coderli.com/gesp-1-bcqm3044/ 【GESP】C一级练习BCQM3044&#xff0c;字符形状输出 | OneCoder回到一级知识点&#xff0c;用给定字符按指定形状输出。https://www.coderli.com/…

鸿蒙开发 四十五 鸿蒙状态管理(嵌套对象界面更新)

当运行时的状态变量变化&#xff0c;UI重新渲染&#xff0c;在ArkUI中称为状态管理机制&#xff0c;前提是变量必须被装饰器修饰。不是状态变量的所有更改都会引起刷新&#xff0c;只有可以被框架观测到的更改才会引起UI刷新。其中boolen、string、number类型&#xff0c;可观察…

【项目安全设计】软件系统安全设计规范和标准(doc原件)

1.1安全建设原则 1.2 安全管理体系 1.3 安全管理规范 1.4 数据安全保障措施 1.4.1 数据库安全保障 1.4.2 操作系统安全保障 1.4.3 病毒防治 1.5安全保障措施 1.5.1实名认证保障 1.5.2 接口安全保障 1.5.3 加密传输保障 1.5.4终端安全保障 资料获取&#xff1a;私信或者进主页。…

如何从模块内部运行 Pytest

在 Python 中&#xff0c;pytest 是一个强大的测试框架&#xff0c;用于编写和运行测试用例。通常我们会在命令行中运行 pytest&#xff0c;但是有时你可能希望从模块或脚本的内部运行 pytest&#xff0c;比如为了自动化测试或集成到某个工作流程中。 1、问题背景 当你从模块…

Luatools太难了?保姆级教程来啦!

作为由合宙所提供的调试工具&#xff0c;Luatools支持最新固件获取、固件打包、trace打印、单机烧录等功能 此工具适用于合宙所有 4G 模组和 4G GNSS 模组。 一、下载并安装 &#xff08;一&#xff09;运行环境要求 此工具运行于win7及以上系统;不支持 Mac和 Linux。 &…

三亚旅游微信小程序的设计与实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

vulnhub(15):lemonsqueezy(hydra爆破、计划任务提权)

端口 nmap -Pn -p- 192.168.72.173 ​ PORT STATE SERVICE 80/tcp open http MAC Address: 00:0C:29:B8:2D:FC (VMware) 打点 80端口 主页面是apache2的默认页面&#xff0c;没有robots.txt&#xff0c;我们直接扫描目录 gobuster dir -u http://192.168.72.173/ -w /usr/…

SHELL脚本之输出语句的使用

shell脚本能够给用户显示一些信息&#xff0c;就需要输出语句的使用。 1.echo语句 如上图所示&#xff0c;中英文都可以&#xff0c; 如上图所示&#xff0c;在shell脚本中对于转义符的使用应该加上-e的选项&#xff0c;\n表示换行&#xff0c;\t表示电脑键盘上使用tab键隔开的…

24/10/12 算法笔记 AlexNet

AlexNet采用深度网络结构&#xff0c;由8层组成&#xff0c;包括5个卷积和3个全连接层&#xff0c;这种深度结构使得网络能够学习到更复杂的特征表示 1.ReLU激活函数&#xff1a; 首次成功的在较深的网络中使用ReLU激活函数&#xff0c;解决了梯度消失问题&#xff0c;加快了…

华为国际云:全球领先的云服务解决方案

近年来&#xff0c;随着云计算技术的迅猛发展&#xff0c;越来越多的企业开始拥抱云计算&#xff0c;以实现业务的数字化转型和创新。在众多云服务提供商中&#xff0c;华为国际云凭借其强大的技术实力和全球布局&#xff0c;成为了备受瞩目的明星。那么&#xff0c;华为国际云…

Python连接Oracle

Python连接Oracle 可以使用Oracle提供的官方Python驱动程序cx_Oracle。&#xff1a; cx_Oracle官方驱动程序 安装cx_Oracle驱动程序&#xff1a;首先&#xff0c;确保你已经安装了Python解释器。然后&#xff0c;使用pip命令安装cx_Oracle驱动程序。可以在命令行中运行以下…

如何解决JMeter响应数据乱码?

问题&#xff1a; 解决&#xff1a; 1、找到JMeter安装目录下的bin目录 2、 在bin目录下&#xff0c;打开" jmeter.properties "文件 3、搜索"sampleresult.default.encoding" 4、改成"sampleresult.default.encodingUTF-8"&#xff0c;去掉前面…

L1练习-鸢尾花数据集处理(分类/聚类)

背景 前文&#xff08;《AI 自学 Lesson1 - Sklearn&#xff08;开源Python机器学习包&#xff09;》&#xff09;以鸢尾花数据集的处理为例&#xff0c;本文将完善其代码&#xff0c;在使用 sklearn 的部分工具包基础上&#xff0c;增加部分数据预处理、数据分析和数据可视化…

集合框架09:泛型概述、泛型类、泛型接口

1.泛型概述 泛型的本质是参数化类型&#xff0c;把类型作为参数传递&#xff1b; 常见有泛型类、泛型接口、泛型方法 语法&#xff1a;<T,...> T称为类型占位符&#xff0c;表示一种引用类型&#xff1b; 好处&#xff1a;1.提高代码的重用性&#xff1b;2.防止类型类…

Ubuntu22.04环境下源码安装OpenCV 4.8.1

因为项目需要用OpenCV对yolov8模型进行推理&#xff0c;通过DNN模块&#xff0c;之前本地的OpenCV版本是4.5.4&#xff08;好像安装完ROS2 humble之后系统就自带了opencv&#xff09;&#xff0c;加载onnx模型一直报错&#xff0c;网上查询到需要4.7以上&#xff0c;干脆直接升…

山西农业大学20241014

01-VUE 一 VUE1. VUE2 和 VUE32. VUE概述2.1 构建用户界面2.2 渐进式 3. 创建Vue实例3.1 引入vue -- 下载方式3.2 引入vue方式3.3. 代码演示 4. Vue语法4.1 插值表达式 {{}}4.2 响应式特性4.2.1 响应式4.2.2 如何访问 和 修改data中的数据 5. Vue开发插件 一 VUE 1. VUE2 和 V…