Docker是什么-通过部署一个SpringBoot项目到Docker来快速理解它

191 阅读6分钟

Docker是什么

Docker是一个开源的容器化技术,它可以使开发人员将自己的程序打包成一个完整的镜像,这个镜像包含了程序以及它依赖的运行环境,可以任意系统的机器上部署,只要其安装了Docker。下面介绍下Docker和核心的概念

容器化(container)

服务程序部署可以分为三个阶段

  1. 物理机器部署,多个服务部署在物理机器,共享机器的cpu、内存,这种部署方式最简单直接,但是一但某一个服务出现问题,占用cpu资源和内存过高,会影响其他服务的稳定运行。并且服务所以依赖的各种环境和配置都需要在机器配置好才能部署,如果多个机器,工作量翻倍且重复。
  2. 虚拟机部署,为了解决资源共享的问题,可以在物理机器上部署多个虚拟机,每个虚拟机上有独立的操作系统,并且有单独的cpu资源和内存资源,然后在虚拟机上部署服务。但是缺点是每一个虚拟机上都带有独立的操作系统,本身就比较占用资源。并且部署方式和物理部署一样繁琐。
  3. 容器化部署,它的和虚拟机很像,能做到资源隔离,但是它占用的资源很小,它可以将程序所依赖的环境配置打包成一个镜像,每个容器都可以用这个镜像启动服务,无需额外的配置。

镜像(image)

刚才提到可以将程序所依赖的环境和配置打包成一个镜像,那么环境中最重要的就是操作系统的,操作系统可以分为内核空间和用户空间,如果将操作系统全都打包进去,那就和虚拟机没什么区别,因此docker仅仅将用户空间、依赖库、文件系统打包成一个基础镜像(basic image) ,而这个基础镜像是服务运行的基础。

除了基础镜像还不够,服务还有各种依赖项和配置,可以将这些配置和依赖写在dockerfile的yaml格式的文件里,docker通过dockerfile和基础镜像,将我们的服务程序打包成(docker build命令)一个完整的镜像。容器只要有这个镜像就可以完整的运行整个服务,无需进行额外的配置

仓库(registry)

我们打包好了镜像,如果再一个个上传到每个容器中再部署,这样依然很繁琐,于是可以将打包好的镜像推送到( docker push )仓库中,由容器自己拉取(docker pull)并部署。这一个模式和git很类似。官方的镜像仓库Docker hub是共享的,所有人都可以推送和拉取,也可以自己搭建私有的镜像仓库。

Docker Compose

刚才我们知道了将一个服务镜像部署到一个容器中,如果有一个博客系统,可能包含了三个镜像:数据库镜像、后端服务镜像,网关服务镜像之类,我们不能将所有镜像都部署到一个容器中,而是要部署多个容器,并且部署顺序有要求,需要先部署数据库再部署后端服务,在部署网关,并且保证要处于同一网络环境下。

因此docker提供了 compose客户端来实现多个容器的部署,通过编写compese yaml格式的文件来确定启动哪些容器和顺序。

Docker是怎么使用的

Docker 的安装不再细说,这里将介绍如何使用Docker,并介绍一个Java SpringBoot程序打包成镜像并且部署到Docker中去

Java代码

通过spring initializr 快速创建一个springboot项目

编写服务代码和前端代码,这里写了一个简单的查询数据的接口,一个简单的前端页面,前端会请求服务接口,服务查询mysql数据库返回数据,前端展示在页面上。

前端代码

$(document).ready(function() {
  $.ajax({
    url: '/search',
    method: 'GET',
    success: function(response) {
      $('#results').html(response);
    },
    error: function(xhr, status, error) {
      console.error("An error occurred: ", error);
    }
  });
});

打包镜像并部署

创建docker网络,确保两个容器能互相通信
docker network create demo-network
启动mysql镜像

//拉取镜像
docker pull mysql
//启动镜像
docker run --name mysql --network demo-network -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -d mysql:latest

注意 服务代码中jdbc连接host需要改成mysql docker容器的名称,由于我的mysql容器启动名称就叫mysql,这里就需要改成mysql,否则服务项目通过jdbc无法连接mysql。

项目添加Dockerfile文件
#基础镜像
FROM openjdk:17
#工作目录
WORKDIR "/app"
#将当前目录的jar拷贝到容器中
COPY ./target/docker-demo-0.0.1-SNAPSHOT.jar app.jar
#暴露端口
EXPOSE 8080
#容器启动后 启动服务
CMD ["java","-jar","/app/app.jar"]
在项目目录下运行docker命令构建镜像
#打包
mvn clean package
#构建镜像
docker build -t docker-demo:v1 .
#查看构建的镜像
docker images
启动容器

注意需要指定网络

#运行镜像
docker run --name docker-demo --network demo-network -p 8080:8080 -d docker-demo:v1

部署成功

部署之后就可以在docker上看见我们部署的两个容器了

打开浏览器键入localhost:8080

通过docker compose部署

通过docker命令部署的方式比较繁琐,先要创建网络、再逐一部署msyql容器和服务容器,我门可以使用docker compose来部署多个容器

在项目中中间compose.yaml文件

services:
  app:
    image: docker-demo:v1
    ports:
      - 127.0.0.1:8080:8080

  mysql:
    image: mysql:latest
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: root

volumes:
  todo-mysql-data:

启动容器

docker compose up -d --build

此时发现两个服务放在了docker-demo下面了

相对于刚才的部署方式已经很简洁了

Docker是怎么实现的

Docker使用Go语言实现,并且通过Linux的几个关键特性来实现相关功能,Docker通过namepace技术来创建独立的容器

整体架构上Docker是client-server架构,client和server通过restful api进行交互,server可以是本地的也可以是远程

Docker engine

它Docker是client-server的实现,包含了Docker实现的所有组件

  • 长时间运行的守护进程(server)
  • 容器和镜像管理
  • docker client和docker compose客户端

client通过运行各种docker命令提交给守护进程,守护进程执行命令去构建或再registry中下载镜像、管理容器的启动销毁等。