第一部分——Docker篇 第三章 构建自定义镜像

关于系统的改造探索

开篇:系统改造的调研报告

第一部分------Docker篇

第一章 Docker容器
第二章 Docker安装
第三章 构建自定义镜像
第四章 搭建镜像仓库
第五章 容器编排
第六章 容器监控


文章目录


前言

随着业务的发展,传统的架构已经不符合项目的要求了。双活、集群也渐渐提上了日程。。。


前边已经安装好了 Docker 环境,接下来看下 Docker镜像 的内容。Docker镜像 主要分为两种,一种是由第三方公司提供的 公开镜像 , 公开镜像 没啥好说的,直接拉取就能使用。还有一部分是 私有镜像 ,这部分 镜像 需要由公司自己构建,后边内容就对如何构建 私有镜像 进行讨论


一、DockerFile

构建 Docker镜像 最直接的方式就是由官方提供的构建工具------DockerFile 进行构建,只需要按要求编写 DockerFile 文件即可。下边就以一个 SpringBoot 项目为例,来体验下如何使用 DockerFile 构建 镜像

先用Idea 创建一个简单的Springboot 项目。具体步骤想必大家都懂,这里就不赘述了。重点看下 pom.xml 文件。如下:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>docker-demo</artifactId>
    <version>1.0</version>
    <name>docker-demo</name>
    <description>docker测试项目</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <finalName>docker-demo</finalName>
        <plugins>
            <!-- docker插件 -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.2.2</version>
                <configuration>
                    <!-- 镜像名称,'[a-z0-9-_.]'格式 -->
                    <imageName>${project.artifactId}:${project.version}</imageName>
                    <dockerDirectory>${project.basedir}/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                            <include>classes/application.*</include>
                        </resource>
                    </resources>
                    <!--这里用tcp,用提示协议错误-->
                    <dockerHost>http://192.168.233.135:2375</dockerHost>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.example.dockerdemo.DockerDemoApplication</mainClass>
                    <skip>false</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

新建一个文件,名称就叫 Dockerfile ,Docker 通过读取 Dockerfile 文件中的指令来自动构建镜像。通常,一个镜像 基于另一个镜像 ,就像千层饼一样一层套一层。接下来就看下如何把 jar 文件打包成镜像吧。显然,Jdk镜像 是我们的基础 镜像 。Dockerfile 文件内容如下:

bash 复制代码
#引入jdk镜像
FROM openjdk:8-jre-slim
# 作者名
MAINTAINER hqd

#设置中国时区,否则容器内部时间显示美国时间。和实际时间对不上
ENV TZ=PRC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

ADD docker-demo.jar /app.jar
ADD classes/application.* /config/
#创建具有指定名称的安装点,并将其标记为保存来自本机主机或其他容器的外部安装卷
VOLUME config
#实际上并未发布端口。它充当构建映像的人员和运行容器的人员之间的一种文档,有关要发布哪些端口。使用-p进行覆盖
EXPOSE 8080
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar $PARAMS"]

接下来,需要把构建所需的文件放到服务器上(需要Docker环境)。目录结构如下:

而后,执行 Docker 命令进行构建,如下:

bash 复制代码
# .即当前目录,t即tag,为镜像名称
 docker build . -t docker-demo:1.0

如果出现异常,会产生仓库名、标签都是 none 的 镜像 ,即 虚悬镜像:

这时候只需执行清理即可,如下:

bash 复制代码
#清理镜像
docker image prune
#清理系统
docker system prune

二、docker-maven-plugin

通常情况下,现在项目都是用 IDEA + Maven 进行开发,我们更希望直接通过 IDEA 进行远程部署,这时候就需要用到 DockerMaven插件 , DockerMaven插件 插件有好几种,大家可根据项目实际情况进行选择 ,这里使用的是 docker-maven-plugin 。下边来看下 docker-maven-plugin 如何使用的

  1. Docker 开启 2375 端口
    想要远程构建镜像 ,Docker 需要先开启端口进行通信,修改 /etc/docker/daemon.json 文件,如下:
json 复制代码
{
  "registry-mirrors": ["加速地址"],
  //这里配置是让docker信任该地址,否则会提示https安全问题
  "insecure-registries":["harbor-ip:8080","nexus-ip:8082","registry-ip:5000"]
  "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
}

重启 Docker:

bash 复制代码
systemctl daemon-reload
systemctl restart docker
  1. 项目添加 Dockerfile
    再把 Dockerfile 添加到项目中。如下:
  1. 添加 DockerMaven插件
    pom.xml 添加 DockerMaven插件 相关依赖。如下:
xml 复制代码
 <plugin>
     <groupId>com.spotify</groupId>
     <artifactId>docker-maven-plugin</artifactId>
     <version>1.2.2</version>
     <configuration>
         <!-- 镜像名称,'[a-z0-9-_.]'格式 -->
         <imageName>${project.artifactId}:${project.version}</imageName>
         <dockerDirectory>${project.basedir}/docker</dockerDirectory>
         <resources>
             <resource>
                 <targetPath>/</targetPath>
                 <directory>${project.build.directory}</directory>
                 <include>${project.build.finalName}.jar</include>
                 <include>classes/application.*</include>
             </resource>
         </resources>
         <!--这里用tcp,用提示协议错误-->
         <dockerHost>http://服务器Ip:2375</dockerHost>
     </configuration>
 </plugin>

完整 pom.xml 配置如下:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>docker-demo</artifactId>
    <version>1.0</version>
    <name>docker-demo</name>
    <description>docker测试项目</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <finalName>docker-demo</finalName>
        <plugins>
            <!-- docker插件 -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.2.2</version>
                <configuration>
                    <!-- 镜像名称,'[a-z0-9-_.]'格式 -->
                    <imageName>${project.artifactId}:${project.version}</imageName>
                    <dockerDirectory>${project.basedir}/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                            <include>classes/application.*</include>
                        </resource>
                    </resources>
                    <!--这里用tcp,用提示协议错误-->
                    <dockerHost>http://192.168.233.135:2375</dockerHost>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.example.dockerdemo.DockerDemoApplication</mainClass>
                    <skip>false</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
  1. 构建镜像
    点击 IDEA 右侧 Maven 进行构建。如下:

三、S2I

DockerMaven插件 虽然简化了 Docker镜像 的构建流程,但是依然要求开发人员必须要懂 Docker、Dockerfile 的相关知识,而此次系统改造的目的:是为了简化开发操作,要求团队中每个人都去学一遍 Docker ,显然学习成本是很大的,已经和此次改造的初衷背离。故而迫切的需要一款构建工具,让开发无需关注 Docker 相关内容,这个工具就是------S2I(Source-to-Image)

下边是官网的简介:

Source-to-Image (S2I) 是一种用于构建可重复生成的 Docker 格式容器镜像的工具。它通过将应用程序源代码注入容器镜像并汇编新镜像来生成可随时运行的镜像。新镜像融合了基础镜像(构建器)和构建的源代码,并可搭配 buildah run 命令使用。S2I 支持递增构建,可重复利用以前下载的依赖项和过去构建的工件等

细节部分这里就不讨论了,有兴趣的小伙伴可以去 官网 自行查看,说一千道一万,不如实操一遍,下面一起来操作下吧

  1. 安装 S2I
    这里选择的版本是 v1.3.0 ,大家根据实际情况选择。确定好版本之后,可以去 Git 下载 S2I,也可以直接用命令进行操作。如下:
bash 复制代码
#下载s2i
wget  https://github.com/openshift/source-to-image/releases/download/v1.3.0/source-to-image-v1.3.0-eed2850f-linux-amd64.tar.gz

#解压到指定目录
mkdir s2i
tar -zxvf source-to-image-v1.3.0-eed2850f-linux-amd64.tar.gz   -C s2i

#移动到系统目录
chmod +x s2i/s2i
mv s2i/s2i /usr/local/bin/

#验证
s2i version

输出如下内容,则代表安装成功

  1. 添加 assemble脚本

S2I 运行时,需要根据脚本内容进行编译、打包、运行等操作。在项目根目录下,新建 .s2i/bin 目录,目录结构如下:

.s2i/bin 目录下,添加 assemble脚本,内容如下:

shell 复制代码
#!/bin/bash  -e

# 打印当前工作目录,以便于调试
echo "当前工作目录是: $(pwd)"

SOURCE_DIR=/tmp/src/

cd $SOURCE_DIR

echo "开始编译,项目目录为:$SOURCE_DIR"
# 编译 Maven 项目
mvn clean package -DskipTests=true -s settings.xml

# 检查编译结果
if [ $? -ne 0 ]; then
  echo "编译失败,退出。。。"
  exit 1
fi

# 可选:清理 Maven 构建过程中生成的文件
# mvn clean

# 复制构建的 jar 文件到指定目录
cp target/*.jar /deployments/app.jar
echo "开始扫描代码。。。"
#扫描代码
#sonar-scanner

# 打印成功信息
echo "编译成功。。。"

相比于 Dockerfile ,Shell 可能对开发更友好一点,assemble脚本 功能也很简单:就是 Maven 清理打包的命令

  1. 添加 run脚本
    如果说 assemble脚本 是打包命令,则 run脚本 就是运行命令,内容如下:
shell 复制代码
#!/bin/bash  -e

cd  /deployments
# 执行 Java 应用
# 假设你的jar文件名为 app.jar 并且已经被复制到了 `/deployments` 目录中
java -jar app.jar

相较于 assemble脚本 ,run脚本 就更简单了,就是平时开发经常接触的 Java命令

除了 assemble 、run 脚本是必须的,其他都是可选的,各个脚本的作用如下:

  1. 构建 镜像
    准备好脚本之后,就可以直接构建 镜像 了,命令如下:
shell 复制代码
#格式为:s2i build 《git地址》 《基础镜像》 《打包镜像名称》,--ref 为git分支 --loglevel 为日志级别
s2i  build  http://hqd:zs20240617@192.168.233.136/hqd/devops-demo.git fabric8/s2i-java  devops-demo  --ref v1 --loglevel 3

输入 docker images 查看镜像是否构建,如下:

S2I 工作流程如下:


总结

在实践的过程中,技术是不断地演进的。最初笔者尝试让开发写 Dockerfile ,但是他们对这部分并不熟悉,与其让所有人都学习一遍 Docker ,不如让他们不在关注这部分内容,把重心放在开发上,所以最终抛弃 Dockerfile , 拥抱 S2I

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
一隅论数智3 天前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
XiHongShi20163 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json