docker 部署一个Java项目

80 阅读6分钟

镜像

我们一直在使用别人准备好的镜像,那如果我要部署一个Java项目,把它打包为一个镜像该怎么做呢?

镜像结构

要想自己构建镜像,必须先了解镜像的结构。

之前我们说过,镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。

因此,自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成。

举个例子,我们要从0部署一个Java应用,大概流程是这样:

  • 准备一个linux服务(CentOS或者Ubuntu均可)
  • 安装并配置JDK
  • 上传Jar包
  • 运行jar包

那因此,我们打包镜像也是分成这么几步:

  • 准备Linux运行环境(java项目并不需要完整的操作系统,仅仅是基础运行环境即可)
  • 安装并配置JDK
  • 拷贝jar包
  • 配置启动脚本

上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合。

但需要注意的是,镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer(层)。这样,如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。

例如,第一步中需要的Linux运行环境,通用性就很强,所以Docker官方就制作了这样的只包含Linux运行环境的镜像。我们在制作java镜像时,就无需重复制作,直接使用Docker官方提供的CentOS或Ubuntu镜像作为基础镜像。然后再搭建其它层即可,这样逐层搭建,最终整个Java项目的镜像结构如图所示:

image.png

Dockerfile

由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。

我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。

而这种记录镜像结构的文件就称为Dockerfile,其对应的语法可以参考官方文档:docs.docker.com/reference/d…

其中的语法比较多,比较常用的有:

指令说明示例
FROM指定基础镜像FROM centos:6
ENV设置环境变量,可在后面指令使用ENV key value
COPY拷贝本地文件到镜像的指定目录COPY ./xx.jar /tmp/app.jar
RUN执行Linux的shell命令,一般是安装过程的命令RUN yum install gcc
EXPOSE指定容器运行时监听的端口,是给镜像使用者看的EXPOSE 8080
ENTRYPOINT镜像中应用的启动命令,容器运行时调用ENTRYPOINT java -jar xx.jar

例如,要基于Ubuntu镜像来构建一个Java应用,其Dockerfile内容如下:

# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录、容器内时区
ENV JAVA_DIR=/usr/local
ENV TZ=Asia/Shanghai
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 设定时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安装JDK
RUN cd $JAVA_DIR \
 && tar -xf ./jdk8.tar.gz \
 && mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 指定项目监听的端口
EXPOSE 8080
# 入口,java项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]

同学们思考一下:以后我们会有很多很多java项目需要打包为镜像,他们都需要Linux系统环境、JDK环境这两层,只有上面的3层不同(因为jar包不同)。如果每次制作java镜像都重复制作前两层镜像,是不是很麻烦。

所以,就有人提供了基础的系统加JDK环境,我们在此基础上制作java镜像,就可以省去JDK的配置了:

# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]

是不是简单多了。

构建镜像

Dockerfile文件写好以后,就可以利用命令来构建镜像了。

在课前资料中,我们准备好了一个demo项目及对应的Dockerfile:

image.png

首先,我们将课前资料提供的docker-demo.jar包以及Dockerfile拷贝到虚拟机的/root/demo目录:

image.png


这个命令是用于构建 Docker 镜像的。让我详细解释每个部分:

命令结构

docker build -t docker-demo:1.0 .

各部分含义:

  • docker build:Docker 的镜像构建命令
  • -t docker-demo:1.0-t 参数用于指定镜像的标签(tag)
    • docker-demo:镜像名称
    • 1.0:版本标签
  • .:构建上下文路径,表示当前目录

执行过程

  1. 读取 Dockerfile:Docker 会在当前目录查找 Dockerfile 文件
  2. 构建上下文:将当前目录的所有文件发送给 Docker 守护进程
  3. 逐层构建:按照 Dockerfile 的指令逐步构建镜像层
  4. 生成镜像:最终生成名为 docker-demo:1.0 的镜像

使用示例

构建完成后,可以运行该镜像:

docker run -p 8080:80 docker-demo:1.0

注意事项

  • 确保当前目录包含正确的 Dockerfile
  • 可以使用 -f 参数指定其他位置的 Dockerfile
  • 镜像名称和标签遵循命名规范(小写字母、数字、连字符等)

这个命令是 Docker 开发中的基础操作,用于将应用程序打包成可移植的容器镜像。


命令说明:

  • docker build : 就是构建一个docker镜像
  • -t docker-demo:1.0 :-t参数是指定镜像的名称(repository和tag)
  • . : 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录,也可以直接指定Dockerfile目录:
# 直接指定Dockerfile目录
docker build -t docker-demo:1.0 /root/demo

结果:

image.png

查看镜像列表:

# 查看镜像列表:
docker images
# 结果
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
docker-demo   1.0       d6ab0b9e64b9   27 minutes ago   327MB
nginx         latest    605c77e624dd   16 months ago    141MB
mysql         latest    3218b38490ce   17 months ago    516MB

然后尝试运行该镜像:

# 1.创建并运行容器
docker run -d --name dd -p 8080:8080 docker-demo:1.0
# 2.查看容器
dps
# 结果
CONTAINER ID   IMAGE             PORTS                                                  STATUS         NAMES
78a000447b49   docker-demo:1.0   0.0.0.0:8080->8080/tcp, :::8090->8090/tcp              Up 2 seconds   dd
f63cfead8502   mysql             0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   Up 2 hours     mysql

# 3.访问
curl localhost:8080/hello/count
# 结果:
<h5>欢迎访问商城, 这是您第1次访问<h5>

这是一个 Docker 命令,用于在后台运行一个容器。让我详细解释每个部分:

命令分解

docker run - 创建并启动一个新容器

-d - 后台运行(detached mode)

  • 容器会在后台运行,不占用当前终端

--name dd - 为容器指定名称

  • 容器名称设置为 "dd"
  • 便于后续管理(启动、停止、删除等)

-p 8080:8080 - 端口映射

  • 格式:主机端口:容器端口
  • 将主机的 8080 端口映射到容器的 8080 端口

docker-demo:1.0 - 使用的镜像名称和标签

  • 镜像名:docker-demo
  • 标签:1.0(版本号)

执行结果

容器启动后,你可以通过以下方式访问应用:

http://localhost:8080

相关管理命令

# 查看运行中的容器
docker ps

# 查看容器日志
docker logs dd

# 停止容器
docker stop dd

# 启动已停止的容器
docker start dd

# 进入容器内部
docker exec -it dd bash

这个命令常用于部署 Web 应用程序,让外部能够通过主机的 8080 端口访问容器内的服务。