使用Dockerfile来构建服务的镜像,并部署在容器中

构建服务镜像和容器化部署

  • 一、构建服务镜像
    • 1、编写Dockerfile
    • 2、构建脚本
    • 3、启动脚本
  • 二、问题及解决办法
    • 1、no main manifest attribute, in /chatgpt-api-1.0-SNAPSHOT.jar
    • 2、如果是SpringBoot项目,应该这么做:

一、构建服务镜像

1、编写Dockerfile

  • 在项目的根目录下,创建Dockerfile
    在这里插入图片描述
  • 基础写法:
FROM openjdk:8-jre-slim
MAINTAINER Forrest
ENV PARAMS="" TZ=PRC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ADD target/chatgpt-api-1.0-SNAPSHOT.jar /chatgpt-api-1.0-SNAPSHOT.jar
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /chatgpt-api-1.0-SNAPSHOT.jar $PARAMS"]
  • 对上面的每一行进行详细说明:

(1)FROM openjdk:8-jre-slim

基础镜像 【这个镜像包含了 OpenJDK 8 (Java 运行环境)和一个精简版的操作系统。】

(2)MAINTAINER Forrest

镜像的作者

(3)ENV PARAMS="" TZ=PRC

1)设置环境变量
2)PARAMS表示传给main方法的参数。这个PARAMS就相当于public static void main(String[] args) {...}的args。
3)当运行 Docker 容器时,可以通过 -e 参数来覆盖这个环境变量的值,例如:docker run -e PARAMS=“arg1 arg2 arg3” your-image-name。这样,你的 Java 应用启动时就会接收到 “arg1 arg2 arg3” 这些参数,作为 main 方法的参数(args)来使用。
4)TZ表示时区, 设置时区为中国(People’s Republic of China,RPC)

(4)RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

1)这行命令主要是用于设置 Docker 容器内的系统时区。
2)ln 是 Linux 系统中用于创建符号链接(symbolic link)的命令,-s 表示创建软链接,-n 表示如果目标文件已存在,直接覆盖,-f 表示强制执行。所以,ln -snf /usr/share/zoneinfo/$TZ /etc/localtime这条命令的意思是创建一个指向 /usr/share/zoneinfo/$TZ 的链接 /etc/localtime。

在macOS上,查看下/usr/share/zoneinfo/RPC/etc/localtime
在这里插入图片描述
继续查看下/etc/timezone
在这里插入图片描述

很显然,这不是中国时区,因此,为了保险起见,echo $TZ > /etc/timezone把/etc/timezone改为中国时区。

(5)ADD target/chatgpt-api-1.0-SNAPSHOT.jar /chatgpt-api-1.0-SNAPSHOT.jar
在这里插入图片描述

  • 因此,这条命令是把上下文路径(一般是Dockerfile所在的根目录)的target目录下的chatgpt-api-1.0-SNAPSHOT.jar,添加到根目录下。

(6)ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /chatgpt-api-1.0-SNAPSHOT.jar $PARAMS"]

这个命令分解如下:
“sh”:表示使用 shell 环境。用于执行后面跟随的命令。
“-c”:这是传递给 sh 的一个选项,表示后面的字符串是一个需要被 sh 执行的命令。
相当于,在命令行,执行java -jar $JAVA_OPTS /chatgpt-api-1.0-SNAPSHOT.jar $PARAMS

2、构建脚本

IDEA支持通过可视化的方式构建镜像:
在这里插入图片描述

  • 但用shell脚本的方式更灵活,在Dockerfile同一目录下,创建build.sh,代码为:
docker build -f ./Dockerfile -t forrest/chatgpt-api .

(1)docker build:docker构建镜像的命令
(2)-f ./Dockerfile:选择用于构建镜像的Dockerfile文件
(3)-t forrest/chatgpt-api:镜像的名字,开头必须是小写
(4).: 上下文路径(一般是Dockerfile所在的根目录)

3、启动脚本

  • 构建好了后,以本地容器的方式启动,启动脚本start.sh,代码为:
docker run -p 8080:8080 
--name chatgpt-api 
-d forrest/chatgpt-api

二、问题及解决办法

1、no main manifest attribute, in /chatgpt-api-1.0-SNAPSHOT.jar

<build>
    <plugins>
        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <!-- 包含"public static void main(String[] args)"的类 -->
                        <mainClass>com.forrest.learnChatgpt.Application</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

解决办法

  • 局限性:如果是SpringBoot项目,上面这种做法会导致新问题,即java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication

2、如果是SpringBoot项目,应该这么做:

<build>
   <plugins>
       <plugin>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-maven-plugin</artifactId>
       </plugin>
   </plugins>
</build>