将jar包打成docker镜像并部署在Linux上
文章目录
- 1. 准备工作
- 1.1 在Linux上安装docker
- 1.1.1 卸载原有的docker(可选)
- 1.1.2 安装docker
- 1.1.3 启动docker
- 1.2 将Java项目打包成jar包
- 1.3 将jar包上传到Linux上
- 1.4 编写Dockerfile文件
- 1.5 Dockerfile文件知识补充
- 1.5.1 在容器启动时执行多个命令
- 1.5.2 Dockerfile详解
- 2. 构建镜像
- 3. 创建容器并运行
- 4. 测试
- 5. 可能遇到的问题
- 5.1 构建容器时可能遇到的问题
- 5.2 运行容器时可能遇到的问题
- 5.2.1 问题一
- 5.2.2 问题二
更多 Docker 的使用技巧可以查看 Docker 专栏:Docker
本文演示的将 jar 包打成 docker 镜像适合第一次进行类似操作的同学,如果已经有过类似的操作,更建议采用 IDEA + Docker 一键部署 SpringBoot 项目
的方法,具体可以参考我的另一篇博文:IDEA+Docker一键部署项目SpringBoot项目
1. 准备工作
本次演示使用的 Linux 版本为 CentOS 7.6,使用的 jdk 版本为 1.8
1.1 在Linux上安装docker
安装docker有其它更简单的方法,例如利用宝塔一键式安装
考虑到有些小伙伴可能没有使用过宝塔,所以本次演示使用指令的方式安装docker
1.1.1 卸载原有的docker(可选)
当一条命令太长而需要分成多行输入时,可以在行尾使用反斜杠,告诉 Shell 下一行指令实际上是当前命令的延续,而不是一个新的命令
如果你的Linux系统安装过旧版本的Docker,可以使用下面命令卸载
yum remove docker
docker-client
docker-client-latest
docker-common
docker-latest
docker-latest-logrotate
docker-logrotate
docker-selinux
docker-engine-selinux
docker-engine
docker-ce
1.1.2 安装docker
第一步:安装yum工具
yum install -y yum-utils
device-mapper-persistent-data
lvm2 --skip-broken
第二步:更新镜像源
# 设置docker镜像源
yum-config-manager
--add-repo
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's/download.docker.com/mirrors.aliyun.com/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
yum makecache fast
指令的详细解释:
sed
: 流编辑器的命令-i
: 选项告诉sed
直接修改源文件。通常sed
默认只输出修改后的内容到标准输出,而不修改源文件。使用-i
选项后,它会直接修改源文件内容's/download.docker.com/mirrors.aliyun.com/docker-ce/g'
: 这是sed
的替换命令s
: 表示执行替换操作download.docker.com
: 被替换的字符串,即 Docker 官方仓库的 URLmirrors.aliyun.com/docker-ce
: 替换后的字符串,即阿里云提供的 Docker CE(Community Edition)镜像仓库的 URL。注意,由于/
在sed
命令中是特殊字符,所以使用/
来表示字面意义上的/
g
: 全局替换标志,表示替换每一行中所有匹配的字符串,而不是只替换第一个匹配的字符串
/etc/yum.repos.d/docker-ce.repo
: 这是sed
命令要操作的文件路径。这个文件是 Docker CE 的 Yum 仓库配置文件,其中包含了 Docker 软件包的仓库地址
第三步:正式安装
yum install -y docker-ce
docker-ce为docker的社区版本(ce表示community edition)
1.1.3 启动docker
# 启动docker服务
systemctl start docker
# 设置docker服务开机自启
systemctl enable docker
输入以下指令查看docker-ce的版本
docker -v
1.2 将Java项目打包成jar包
本次演示使用的是一个较为简单的 SpringBoot 项目,项目的整体结构如下
HelloWorldController.java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloWorldController {
@GetMapping("/")
public String echo() {
return "Hello, World!
";
}
}
application.yml
server:
port: 16256
用 Maven 将 SpringBoot 项目打包成 jar 包
如果是通过阿里云脚手架创建的 SpringBoot 项目,记得在 pom.xml 文件中把打包插件中的
标签删掉
1.3 将jar包上传到Linux上
将jar包上传到Linux的 /tmp/docker 目录下(你也可以选择上传到其它目录)
如果上传失败,可能是 /tmp/docker 目录没有写入的权限,运行以下指令修改docker目录的权限
cd /tmp
chmod 777 -R docker
1.4 编写Dockerfile文件
在 jar 包所在的目录下,新建一个名为 Dockerfile 的文件,文件内容如下(将docker-demo-0.0.1-SNAPSHOT.jar换成你的jar包的名称)
# 指定基础镜像
FROM java:8-alpine
# 复制文件到镜像中
COPY ./docker-demo-0.0.1-SNAPSHOT.jar /tmp/docker-demo-0.0.1-SNAPSHOT.jar
# 暴露端口
EXPOSE 16256
# 指定容器启动时运行的指令
ENTRYPOINT ["java", "-jar", "/tmp/docker-demo-0.0.1-SNAPSHOT.jar"]
补充:
- java:8-alpine镜像中已经内置了jdk1.8,也配置好了 JAVA_HOME 环境变量
- 如果想复制多个文件到镜像中,可以使用多个COPY指令
- 如果想放行多个端口,可以使用多个EXPOSE指令
- 一个 Dockerfile 只能有一个
ENTRYPOINT
指令(如果想在ENTRYPOINT中执行多条指令,可以参考本文的1.5 Dockerfile文件知识补充 章节 - 注释只能另起一行,不能写在代码后面,否则会报错
- 目标路径最好使用绝对路径,如果目标路径不存在,Docker 会自动创建
- 如果复制的是目录,Docker 会复制目录中的所有内容,包括子目录和文件,但不包括目录本身。如果目录中包含隐藏文件或以点开头的文件,它们也会被复制
注意:
- COPY指令的源文件请使用相对路径,不要使用绝对路径
- 请确保 jar 包在 Dockerfile 文件所在目录或 Dockerfile 文件所在目录的子目录下
1.5 Dockerfile文件知识补充
1.5.1 在容器启动时执行多个命令
一个 Dockerfile 只能有一个 ENTRYPOINT
指令
如果想在容器启动时执行多个命令,可以将这些命令放在一个脚本中,然后在 ENTRYPOINT
中调用这个脚本
# 指定基础镜像
FROM java:8-alpine
# 复制文件到镜像中
COPY ./docker-demo-0.0.1-SNAPSHOT.jar /tmp/docker-demo-0.0.1-SNAPSHOT.jar
COPY ./start.sh /tmp/start.sh
# 暴露端口
EXPOSE 16256
# 赋予脚本文件执行权限
RUN chmod +x /tmp/start.sh
# 指定容器启动时运行的指令
ENTRYPOINT ["/tmp/start.sh"]
start.sh脚本文件的内容如下
#!/bin/ash
# 第一个命令
java -jar /tmp/docker-demo-0.0.1-SNAPSHOT.jar
# 第二个命令(如果需要的话)
echo "Hello, World"
目标路径建议使用绝对路径,如果目标路径不存在,Docker 会自动创建
如果复制的是目录,Docker 会复制目录中的所有内容,包括子目录和文件,但不包括目录本身。如果目录中包含隐藏文件或以点开头的文件,它们也会被复制
1.5.2 Dockerfile详解
参考我的另一篇博文:Dockerfile详解(Dockerfile的基本结构、使用Dockerfile自定义镜像示例、主流编程语言和中间件的基础Docker镜像、编写Dockerfile的最佳实践)
2. 构建镜像
在Dockerfile文件所在的目录下运行指令
docker build -t docker-demo:1.0 ./
指令的解释:
docker build
: Docker 的子命令,用于从 Dockerfile 和上下文构建一个镜像-t
: 用于指定构建的镜像的名称和标签,在上述指令中,docker-demo
是镜像的名称,1.0
是镜像的标签docker-demo:1.0
: 这是指定的镜像名称和标签,冒号:
用于分隔镜像名称和标签./
: 这个参数指定了构建上下文的路径。构建上下文是指 Docker 在构建镜像时能够访问的文件和目录。在上述指令中,./
表示构建上下文为运行指令时所在的目录
3. 创建容器并运行
docker run
--name docker-demo
-p 16256:16256
-d
docker-demo:1.0
指令的详细解释:
docker run
: Docker 的子命令,用于启动一个新容器--name docker-demo
: 这个选项用于指定新容器的名称为docker-demo
,如果没有指定名称,Docker 会为该容器生成一个随机名称-p 16256:16256
: 这个选项用于映射容器的端口到宿主机的端口。16256:16256
表示将容器的16256
端口映射到宿主机的16256
端口。这样,外部网络就可以通过宿主机的16256
端口访问容器内的服务-d
: 这个选项用于让容器在后台运行,如果不加这个选项,容器会占用当前终端,阻止你执行其他命令docker-demo:1.0
: 这是指定要启动的镜像的名称和标签。冒号:
用于分隔镜像名称和标签
4. 测试
在浏览器中访问以下网址(将IP地址改为你的虚拟机的IP地址)
http://192.168.31.129:16256
看到以下页面,证明项目已经成功部署
温馨提示:如果访问失败,可能是虚拟机的防火墙没有开放16256端口
- 如果你使用的是云服务器,请在安全组中放行16256端口
- 如果你安装了宝塔,请在宝塔中放行16256端口
5. 可能遇到的问题
5.1 构建容器时可能遇到的问题
问题复现:
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref db7fbd3d-de65-4abb-a024-61534e7b1c71::m0fc5kkmyd1r862kzq738qidt: "/tmp/docker/docker-demo-0.0.1-SNAPSHOT.jar": not found
问题产生的原因:
- Docker 构建容器时默认会将Dockerfile所在目录以及Dockerfile所在目录的子目录作为构建上下文
- 构建容器时,如果使用或访问了构建上下文以外的目录或文件,Docker将无法访问它们
解决方法:将构建容器所用到的全部文件移到 Dockerfile 文件所在的目录下
5.2 运行容器时可能遇到的问题
5.2.1 问题一
问题复现:no main manifest attribute, in /tmp/JarToDocker-0.0.1-SNAPSHOT.jar
问题产生的原因:Java项目打包出现问题,没有指定启动类
解决方法:参考本文的 1.2 将Java项目打包成jar包 章节
5.2.2 问题二
问题复现:exec /tmp/start.sh: no such file or directory
问题产生的原因以及解决方法:参考我的另一篇文章:docker容器中sh脚本明明存在,启动容器时却一直报错:no such file or directory