Docker学习笔记

学习Docker过程中的一些小笔记~~~

文章目录

  • Docker
  • 第一章 Docker
    • 1.1 Docker是什么?
    • 1.2 容器和虚拟机的区别?
    • 1.3 使用Docker的原因
  • 第二章 Docker环境搭建
    • 2.1 Docker的版本
    • 2.2 Docker的安装
    • 2.3 Docker服务的启动
    • 2.4 Docker的服务信息
    • 2.5 Docker的使用
      • 2.5.1 Docker的运行机制
      • 2.5.2 第一个Docker容器
      • 2.5.3 进入Docker容器
      • 2.5.4 客户机访问容器
  • 第三章 Docker 核心组件
    • 3.1 Docker 架构
    • 3.2 Docker核心要素
    • 3.3 镜像
      • 3.3.1 镜像的基本概念
      • 3.3.2 镜像的组成结构
      • 3.3.3 镜像的日常操作
    • 3.4 容器
      • 3.4.1 容器的基本概念
      • 3.4.2 容器的日常操作
    • 3.5 仓库
      • 3.5.1 仓库的基本概念
      • 3.5.2 仓库的日常操作
  • 第四章 Docker使用实例
    • 4.1 Docker安装MySQL
    • 4.2 Docker安装Nginx
    • 4.3 Docker 安装Zookeeper
  • 第五章 Docker自定义镜像
    • 5.1 认识Dockerfile文件
    • 5.2 Dockerfile的基本结构
    • 5.3 Dockerfile指令
    • 5.4 Dockerfile自定义镜像
      • 5.4.1 自定义jdk镜像
      • 5.4.2 自定义Tomcat镜像
      • 5.4.3 自定义mysql镜像
      • 5.4.4 自定义Redis镜像
  • 第六章 Docker应用的部署
    • 6.1 部署一个SpringBoot项目
    • 6.2 Docker部署jar包SpringBoot程序
      • 6.2.1 定义Jar包程序Dockerfile文件
      • 6.2.2 创建和运行Jar包程序的镜像
      • 6.2.3 Jar包程序依赖容器环境准备
      • 6.2.4 运行Docker化的Jar包程序
    • 6.3 Docker部署War包的SpringBoot程序
      • 6.3.1 定义War包程序的Dockerfile文件
      • 6.3.2 构建和运行War包程序的镜像
      • 6.3.3 War包程序依赖容器环境准备
      • 6.3.4 运行Docker化的War包程序

Docker

第一章 Docker

1.1 Docker是什么?

  1. Docker是一个开源的应用容器引擎,是基于Go语言实现的,项目代码托管在Github上https://github.com/docker/docker-ce
  2. Docker技术让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,打包好的容器可以发布到任何流行的Linux服务器上运行,这样就可以解决开发环境和运维环境的不一致的问题,所以容器技术解决了开发和运维之间的矛盾让开发专注于开发,运维专注于运维,不被环境问题所干扰;
  3. Docker彻底释放了虚拟化的威力,极大降低了计算机资源供应的成本,Docker重新定义了程序开发测试、交付和部署,Docker提出了“构建一次,到处运行”的理念,让应用的开发、测试、部署和分发变得更加高效和轻松。
  4. Docker是一种轻量级的操作系统虚拟化解决方案,Docker基础是Linux容器(LXC)技术,在LXC的基础上Docker进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作Docker的容器就像操作一个快速轻量级的虚拟机一样简单;Docker自开源后受到广泛的关注,Docker最早是基于Ubuntu开发的,但后续CentOS、Debian等主流的Linux操作系统都支持Docker;

总结:Docker是对软件和其依赖环境的标准化大包,应用之间相互隔离,共享一个OS Kernel(解决了资源浪费的问题),可以运行于很多主流的操作系统上,同时应当注意:Docker本身不是容器,Docker只是管理容器的引擎。

1.2 容器和虚拟机的区别?

  • 容器是将代码和环境的关系打包在一起的一个集合,而虚拟机是在物理层面上,分出来的一个操作系统。

  • 多个容器可以运行在同一台物理服务器上,并共享一个操作系统的内核资源。多个虚拟机也可以运行在同一台机器上,但每个虚拟机都需要一个完整的操作系统;

  • Docker和传统虚拟化方式的不同之处:

Docker学习笔记_第1张图片
Docker学习笔记_第2张图片

从上面的两个图中便可看出:容器是在本地的操作系统层面上实现虚拟化,直接复用本地主机上的操作系统,不需要单独安装操作系统,而传统的虚拟化技术方式则需要单独安装每个虚拟机的操作系统。

  • Docker和虚拟机的特性对比

    特性 容器 虚拟机
    启动 秒级 分钟级
    硬盘空间 一般为几十MB 一般为10GB
    性能 接近原生 弱于原生
    系统支持量 单机支持上千个容器 一般为几十个
    操作系统 与宿主机共享OS 宿主机OS上运行虚拟机OS

1.3 使用Docker的原因

  1. Docker容器的启动可以在秒级实现,相比传统的虚拟机方式要快很多
  2. Docker对系统资源的利用率很高,一台主机可以同时运行数千个Docker容器
  3. Docker除了运行其中的应用外,基本不消耗额外的系统资源,使得应用的性能很高。传统的虚拟机方式运行10个完全不同的应用可能需要启动10个虚拟机来部署,而Docker只需要启动10个隔离的应用便可
  4. Docker可以更加快速的交付和部署,大量地节约开发、测试、部署的时间,对开发和运维人员来说,通过一次创建或配置,便可以在任意地方正常运行。
  5. 交付、部署:虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化。 DockerDockerfile 中记录了容器构建过程,可在集群中实现快速分发和快速部署
  6. 更加高效的虚拟化,Docker容器几乎可以运行在任意的平台上,包括物理机、虚拟机、服务器等,这种兼容性可以让用户轻松地把一个应用程序从一个平台直接迁移到另一个平台
  7. 安全性: docker 的安全性也更弱。 Docker 的租户 root 和宿主机 root 等同,一旦容器内的用户从普通用户权限提升为root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。虚拟机租户 root 权限和宿主机的 root 虚拟机权限是分离的,并且虚拟机利用如 IntelVT-dVT-xring-1 硬件隔离技术,这种隔离技术可以防止虚拟机突破和彼此交互,而容器至今还没有任何形式的硬件隔离,这使得容器容易受到攻击

第二章 Docker环境搭建

2.1 Docker的版本

Docker从2013年3月20日开始发布Docker0.1;

从2017年3月开始Docker在原来的基础上分为两个分支版本:Docker CE和Docker EE。

Docker CE:社区免费版,可永久免费使用;

Docker EE:企业版,功能更全,更强调安全,需付费

Docker的官方网站:https://www.docker.com

2.2 Docker的安装

Docker是一个管理容器的引擎,由于我使用的是CentOS7,所以我也是使用在该环境下的版本。

Docker支持CentOS6及以后的版本;

CentOS7系统可以直接通过yum进行安装;

安装前可以查看一下系统是否已经安装了Docker:

yum list installed|grep docker

若出现以下内容则表示已经安装好了:

[root@localhost ~]# yum list  installed |grep docker
docker.x86_64                               2:1.13.1-209.git7d71120.el7.centos
docker-client.x86_64                        2:1.13.1-209.git7d71120.el7.centos
docker-common.x86_64                        2:1.13.1-209.git7d71120.el7.centos

若未安装好则可以通过以下命令安装:

yum install docker -y

安装后,使用docker -version查看docker是否下载成功,

docker -version

卸载通过以下命令:

yum remove docker.x86_64 -y
yum remove docker-client.x86_64  -y
yum remove docker-common.x86_64 -y

2.3 Docker服务的启动

安装之后启动Docker服务:

启动:

systemctl start docker 或者 service docker start

停止:

systemctl stop docker 或者 service docker stop

重启:

systemctl restart docker 或者 service docker restart

检查docker进程的运行状态:

systemctl status docker 或者 service docker status

查看docker进程:

[root@localhost ~]# ps -ef|grep docker
root      14218      1  0 05:09 ?        00:00:37 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json --selinux-enabled --log-driver=journald --signature-verification=false --storage-driver overlay2
root      14223  14218  0 05:09 ?        00:00:20 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc --runtime-args --systemd-cgroup=true
root      31472  22910  0 13:09 pts/1    00:00:00 grep --color=auto docker

2.4 Docker的服务信息

docker info : 查看docker的系统信息

docker: 查看所有的帮助信息

docker commond -help:查看某个commond命令的帮助信息

2.5 Docker的使用

2.5.1 Docker的运行机制

Docker不是一个容器,而是一个管理容器的引擎。

Docker的底层运行原理:

启动Docker服务 -> 下载镜像 -> 启动该镜像得到一个容器 -> 容器里运行程序 ;

Docker学习笔记_第3张图片

2.5.2 第一个Docker容器

由上面docker的底层运行逻辑,按如下步骤运行第一个Docker容器:

  1. 将Docker服务启动;

  2. 下载所需要的镜像,Docker运行一个容器前需要本地存在有对应的镜像,如果镜像不存在本地,Docker会从镜像仓库下载(默认的Docker Hub 公共注册服务器中的仓库为:https://hub.docker.com)

    CentOS如何下载(pull)镜像?

    从docker hub官网搜索要使用的镜像,也可以在命令行或者弄个使用命令搜索要使用的镜像,比如

    docker search tomcat
    

    进行搜搜,然后下载所需要的镜像:

    下载镜像:

    docker pull tomcat 或者
    docker pull tomcat:+ 版本号
    

    运行镜像:

    前台运行方式:

    docker run tomcat 
    

    后台运行方式:

    docker run tomcat -d
    

    显示本地已有的镜像:

    docker images
    

Docker学习笔记_第4张图片

在列出的信息中,可以看到几个字段信息

REPOSITORY: 来自哪个仓库,比如 docker.io/tomcat

TAG: 镜像的标记,比如latest

IMAGE ID: 镜像的ID号

CREATED: 创建时间

SIZE: 镜像大小

  1. 启动下载下来的镜像得到一个容器:

    docker run -d docker.io/tomcat 
    

    或者:

    docker run -d  bcc25679a5b4
    

    默认情况下是前台启动,如果需要后台启动,则指定-d参数;

    通过 ps -ef|grep tomcat 查看,检查tomcat 镜像是否启动容器成功;

2.5.3 进入Docker容器

进入容器:

docker exec -it  bcc25679a5b4 bash

i: 表示交互式的,也就是保持标准输入流打开

t: 表示虚拟控制台,分配到一个虚拟控制台

退出容器: exit

2.5.4 客户机访问容器

从客户机上访问容器,需要有端口映射,docker容器默认采用桥接模式与宿主机通信,需要将宿主机的ip端口映射到容器的ip端口上;

停止容器:

docker stop 容器的ID/名称

启动容器:

docker run -d -p 8080:8080 docker.io/tomcat 

第三章 Docker 核心组件

3.1 Docker 架构

Docker使用客户端-服务端(C/S)架构模式,使用远程API来管理和创建Docker容器。

Docker学习笔记_第5张图片

Docker容器通过Docker镜像来创建。

镜像与容器的关系类似于面向对象编程中的类与对象的关系。容器为对象,镜像为类。

3.2 Docker核心要素

​ Docker有三大核心要素:

  • 镜像
  • 容器
  • 仓库

Docker的运行离不开上面几个核心组件的支持。

注意:Docker不是容器,而是管理容器的引擎。

3.3 镜像

3.3.1 镜像的基本概念

Docker镜像就是一个只读的模板,用来创建Docker容器

例如:一个镜像可以包含一个完整的centos操作系统环境,里面仅安装了mysql或用户需要的其他应用程序。

Docker提供了一个非常简单的机制来创建镜像或更新现有的镜像,用户甚至可以直接从其他人处下载一个已经做好的镜像来直接使用。

3.3.2 镜像的组成结构

镜像是由许多层的文件系统叠加而成的,最下面的是一个引导文件系统bootfs,第二层是一个root文件系统rootfs,root文件系统通常是某种操作系统,比如centos、Ubuntn,在root文件系统之上又有很多层文件系统,这些文件系统叠加在一起,构成了docker的镜像;

Docker学习笔记_第6张图片

3.3.3 镜像的日常操作

  1. 下载镜像,比如redis镜像:

    docker pull redis:latest
    

    redis是查询到的镜像名称,latest是镜像的标签tag

    获取一个镜像有两种方式:

    • 一种是从官方镜像仓库下载
    • 一种是自己通过Dockerfile文件构建。

    如果有官方镜像,就不用自己用Dockerfile文件构建了,除非官方没有才自己去Dockerfile文件构建;

  2. 列出已经下载的镜像:

    docker images
    

    或者

    docker images redis
    
  3. 运行的镜像:

    docker run -d redis
    

    其中-d表示在后台运行,然后通过ps -ef|grep redis查看redis的进程

  4. 查看容器镜像的状态:

    docker ps
    

    通过docker exec -it 镜像ID bash 进入redis容器

  5. 删除容器:

    docker rmi redis:版本号
    

    注意:rmi是删除镜像 rm是删除容器

3.4 容器

3.4.1 容器的基本概念

容器是从镜像创建的运行实例。它可以被启动、停止、删除。每个容器都是相互隔离的、保证安全性。可以把每个容器看作一个简易版的Linux环境,包括root用户权限、进程空间、用户空间和网络空间和运行在其中的应用程序。

Docker利用容器来运行应用,镜像是只读的,容器在启动的时候创建一层可写层作为最上层。

Docker学习笔记_第7张图片

3.4.2 容器的日常操作

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态的容器重新启动

  • 通过镜像启动容器:
docker run -d redis
  • 查看运行中的容器:
docker ps
  • 查看所有的容器:
docker ps -a
  • 停止容器:
docker stop 容器的id或容器的名称

已经停止的容器,可以使用命令 docker start 来启动

  • 开启容器:
docker start 容器的id或容器的名称

注意:Docker的容器非常轻量级,很多时候用户都是随时删除和新创建的容器

  • 删除容器:
docker rm 容器的id或容器的名称 -f

-f:表示强制删除

删除容器的时候,容器必须是停止的状态,否则会报错;

  • 进入容器
docker exec -it 容器的id或容器的名称 bash
  • 查看容器的更多信息
docker inspect + 容器的id或容器的名称 查看容器的更多信息
  • 停用全部运行中的容器
docker stop ${docker ps -q}
  • 删除全部容器
docker rm ${docker ps -aq}
  • 一条命令实现停用并删除容器:
docker stop ${docker ps -q} & docker rm ${docker ps -aq}

3.5 仓库

3.5.1 仓库的基本概念

仓库是集中存放镜像文件的场所,有时候会把仓库和仓库注册服务器看作同一事物,不做严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签;

仓库分为公开的仓库和私有的仓库;

最大的公开的仓库是Docker Hub, (https://hub.docker.com)存放了数量庞大的镜像供用户下载;

用户也可以自己在本地网络内创建一个私有仓库,当用户创建了自己的镜像之后就可以用push命令将它上传到公有的或私有的仓库,这样下次在另一台机器上使用这个镜像的时候,只需要从仓库上pull下来即可;

注:Docker仓库的概念和Git类似,注册服务器也类似于Github的托管服务。

3.5.2 仓库的日常操作

用户可以通过docker search命令来查找官方仓库中的镜像:

docker search rabbitmq

可以得到返回带有许多关键字的镜像,其中包括镜像的名字、描述、星级(用于表示该镜像的受欢迎程度)、是否为官方创建、是否自动创建;官方的镜像说明是官方项目组创建和维护的,automated资源允许用户验证镜像的来源和内容;

根据是否是官方提供,可将镜像资源分为两类:

  • 一种类似centos这样的基础镜像,被称为基础或根镜像。这些基础镜像

    由Docker公司创建、验证、支持、提供。这样的镜像往往用单个单词作为名字;

  • 另一种类型则是tianno/centos镜像,由Docker的用户创建并维护的,往往带有用户名前缀。可以通过前缀user_name/来指定使用某个用户提供的镜像,比如tianno用户;

docker pull rabbitmq
docker pull centos

第四章 Docker使用实例

4.1 Docker安装MySQL

  • 下载mysql镜像:

    docker pull mysql:latest
    
  • 启动mysql

    docker run -p 3306:3306 -e MYSQL_DATABASE=workdb -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest
    

    其中-e是指定环境变量

  • 进入容器

    docker exec -it 容器id bash
    
  • 登录Mysql

    mysql -uroot -p
    
  • 修改密码

    ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
    
  • 授权远程登录访问:

    CREATE USER 'Enzo'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
    
    GRANT ALL PRIVILEGES ON *.* TO 'Enzo'@'%';
    

4.2 Docker安装Nginx

  • 下载Nginx镜像

    docker pull nginx
    
    docker run -d -p 80:80 nginx
    
  • 进入容器

    docker exec -it 容器id
    
  • 浏览器访问Nginx

    http://192.168.74.132:80
    
  • Nginx部署静态网站

    将linux的文件拷贝到docker容器的某个目录下

    docker cp /root/test.html 容器id:/usr/share/nginx/html
    

4.3 Docker 安装Zookeeper

  • 下载Zookeeper

    docker pull zookeeper
    docker run -p 2181:2181 -d zookeeper
    
  • 进入容器

    docker exec -it 容器id bash
    

第五章 Docker自定义镜像

5.1 认识Dockerfile文件

Dockerfile用于构建Docker镜像,Dockerfile文件是由一行行命令语句组成,基于这些命令即可以构建一个镜像,比如下面就是一个Dockerfile文件的样例:

FROM openjdk:8
ENV workdir=/root/Enzo_eureka/eureka-server
COPY . ${workdir}
WORKDIR ${workdir}
EXPOSE 8761
CMD ["java","-jar","eureka-server-1.0.jar"]

5.2 Dockerfile的基本结构

一般的,Dockerfile分为四个部分:

  • 基础镜像信息
  • 维护者信息
  • 镜像操作指令
  • 容器启动时执行指令

5.3 Dockerfile指令

  1. FROM

    格式为 FROM或FROM :

    Dockerfile文件的第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次);

  2. MAINTAINER

    格式为MAINTAINER,指定维护者信息

  3. ENV

    格式为ENV, 指定一个环境变量,会被后续RUN指令使用,并在容器运行时保持;

  4. ADD

    格式为ADD;

    复制指定的到容器中的;

  5. EXPOSE

    暴露id口

    格式为 EXPOSE […]

    告诉Docker服务器容器暴露的端口号,供互联系统使用,在启动容器时需要通过 -p映射端口,Docker主机会自动分配一个端口转发到指定的端口;

  6. RUN

    格式为RUN

    RUN指令将在当前镜像基础上执行命令,并提交为新的镜像,

    当命令较长时可以用/来换行

  7. CMD

    指定启动容器时执行的命令,每个Dockerfile只能有一条CMD命令。

    如果执行了多条命令,只有最后一条会被执行

    如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令

5.4 Dockerfile自定义镜像

5.4.1 自定义jdk镜像

FROM centos:latest
MAINTAINER wkcto
ADD jdk-8u121-linux-x64.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_121
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin
CMD java -version

构建镜像:

docker build -t Enzo_jdk1.8.0_121

运行镜像:

docker run -d 镜像id

5.4.2 自定义Tomcat镜像

定义Dockerfile文件:

FROM wkcto_jdk1.8.0_121
MAINTAINER wkcto
ADD apache-tomcat-8.5.35.tar.gz /usr/local
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.35
ENV PATH $PATH:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-8.5.35/bin/catalina.sh run

构建镜像:

docker build -t Enzo_apache-tomcat-8.5.35

运行镜像:

docker run -d 镜像id

5.4.3 自定义mysql镜像

定义Dockerfile文件:

FROM centos:centos6
MAINTAINER wkcto
RUN yum install mysql-server mysql -y
RUN /etc/init.d/mysqld start &&\
    mysql -e "grant all privileges on *.* to 'root'@'%' identified by '123456' WITH GRANT OPTION;"&&\
    mysql -e "grant all privileges on *.* to 'root'@'localhost' identified by '123456' WITH GRANT OPTION;"&&\
    mysql -uroot -p123456 -e"show databases;"
EXPOSE 3306
CMD /usr/bin/mysqld_safe

构建镜像:

docker build -t Enzo_mysql

运行镜像:

docker run -p 3306:3306 -d 镜像id

5.4.4 自定义Redis镜像

定义Dockerfile文件:

FROM centos:latest
MAINTAINER wkcto
RUN yum  install epel-release -y  && yum install redis -y  && yum install net-tools -y
EXPOSE 6379
CMD /usr/bin/redis-server -protected-mode no

构建镜像:

docker build -t Enzo_redis

运行镜像:

docker run -p 6379 -d 镜像id

第六章 Docker应用的部署

6.1 部署一个SpringBoot项目

  • 将开发出来的springboot程序打包成jar包或者war包(注意:在IDEA中将项目打包成jar包时,先点击clear,清空内容,然后直接package,不要进行compile后再进行打包,会影响在Linux上运行项目,即出现类似错误Error: Invalid or corrupt jarfile /opt/springboot-web-1.0.0.jar)
  • 在Linux中建立一个目录,将打包好的jar包或者war包部署到该目录下面
  • 同时在该目录下面定义Dockerfile文件,用于创建项目的镜像

6.2 Docker部署jar包SpringBoot程序

6.2.1 定义Jar包程序Dockerfile文件

FROM openjdk:8
ENV workdir=/root/Enzo_eureka/eureka-server
COPY . ${workdir}
WORKDIR ${workdir}
EXPOSE 8761
CMD ["java","-jar","eureka-server-1.0.jar"]

6.2.2 创建和运行Jar包程序的镜像

构建镜像:

docker build -t springboot-web-jar .

运行容器:

docker run -d 镜像ID号

6.2.3 Jar包程序依赖容器环境准备

运行Redis容器:

docker run -p 6379:6379 -d redis

运行Mysql容器:

docker run -p 3306:3306 -e MYSQL_DATABASE=workdb -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest

修改容器保存:

docker commit 容器id 镜像id

6.2.4 运行Docker化的Jar包程序

可直接通过Windows的浏览器访问,验证SpringBoot项目是否可以正常访问;

6.3 Docker部署War包的SpringBoot程序

6.3.1 定义War包程序的Dockerfile文件

FROM Enzo-tomcat-8.5.24
MAINTAINER Enzo
ADD springboot-web-1.0.0.war /usr/local/apache-tomcat-8.5.24/webapps 
EXPOSE 8080
CMD /usr/local/apache-tomcat-8.5.24/bin/catalina.sh run 

6.3.2 构建和运行War包程序的镜像

构建镜像:

docker build -t springboot-web-war .

6.3.3 War包程序依赖容器环境准备

与上面部署Jar程序依赖的容器环境一样

6.3.4 运行Docker化的War包程序

通过windows的浏览器访问,验证SpringBoot项目是否正常访问;

springboot-web-1.0.0.war -> springboot-web-1.0.0

你可能感兴趣的:(Docker,docker,学习,容器,spring,boot,jar)